BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / commit / d46e09a34ca8cd546f3a4312976cf3b6a5a55ccf

// Related

Nucleus

Barry Improved context switching and interrupt handling d46e09a (3 years, 2 months ago)
diff --git a/include/nucleus/cpu.h b/include/nucleus/cpu.h
index b8293b8..b1e4cae 100644
--- a/include/nucleus/cpu.h
+++ b/include/nucleus/cpu.h
@@ -7,10 +7,13 @@ typedef unsigned int cpu_t;
 
 /* Structure for an Interrupt Frame */
 struct InterruptFrame {
-	uint32_t eip, cs, eflags;
+	uint32_t ds;
+	uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
+	uint32_t intnum, err;
+	uint32_t eip, cs, eflags, useresp, ss;
 };
 
-typedef void (*exc_handler_t)(struct InterruptFrame *, uint32_t);
+typedef void (*exc_handler_t)(struct InterruptFrame *);
 typedef void (*int_handler_t)(struct InterruptFrame *);
 
 extern int apic;
diff --git a/include/nucleus/task.h b/include/nucleus/task.h
index 17b5c09..1e91a33 100644
--- a/include/nucleus/task.h
+++ b/include/nucleus/task.h
@@ -104,6 +104,5 @@ void unblock_task(Task *task);
 Task *find_task(pid_t tid);
 void schedule(void);
 pid_t clone(int flags);
-int syscall_handler(int num, uintptr_t args);
 
 #endif
diff --git a/kernel/idt.c b/kernel/idt.c
index d835d15..a9f7c79 100644
--- a/kernel/idt.c
+++ b/kernel/idt.c
@@ -21,7 +21,7 @@ static struct IDTEntry {
 	uint16_t offsetHigher;
 } __attribute__((packed)) *IDT;
 
-void (**exceptions)(struct InterruptFrame *, uint32_t);
+void (**exceptions)(struct InterruptFrame *);
 void (**interrupts)(struct InterruptFrame *);
 
 /* Install an IDT Entry */
@@ -35,294 +35,57 @@ install_idt_entry(uint8_t num, void *addr)
 	IDT[num].offsetHigher = (uintptr_t) addr >> 16;
 }
 
-/* First level generic exception handler */
-static void
-exc_handler(int num, struct InterruptFrame *frame, uint32_t err)
-{
-	asm volatile("cli");
-
-	if (!exceptions[num]) {
-		panic("Failed to handle exception %d (%#.8x)",
-		      num, err);
-	}
-
-	ASSERT(exceptions[num]);
-	exceptions[num](frame, err);
-
-	/* Send APIC EOI */
-	if (apic)
-		LAPIC(0xB0) = 0;
-
-	asm volatile("sti");
-}
-
-/* First level generic interrupt handler */
-static void
-int_handler(int num, struct InterruptFrame *frame)
+/* Generic ISR handler */
+void
+isr_handler(struct InterruptFrame frame)
 {
-	asm volatile("cli");
+	if (!exceptions[frame.intnum] && frame.intnum < 32)
+		panic("[CPU#%d] Failed to handle exception %d (%#.8x) @ %#.8x",
+		      CPUID, frame.intnum, frame.err, frame.eip);
 
-	if (interrupts[num - 32])
-		interrupts[num - 32](frame);
+	/* Run registered handler */
+	if (exceptions[frame.intnum])
+		exceptions[frame.intnum](&frame);
 
 	/* Send EOI */
-	if (num >= 32 + 8)
+	if (frame.intnum >= 40 && frame.intnum < 48)
 		outb(0xA0, 0x20);
-	outb(0x20, 0x20);
-	/* Send APIC EOI*/
-	if (apic)
-		LAPIC(0xB0) = 0;
-
-	asm volatile("sti");
-}
-
-/* Exceptions */
-__attribute__((interrupt))
-static void
-exc0(struct InterruptFrame *frame)
-{
-	exc_handler(0, frame, 0);
-}
-__attribute__((interrupt))
-static void
-exc1(struct InterruptFrame *frame)
-{
-	exc_handler(1, frame, 0);
-}
-__attribute__((interrupt))
-static void
-exc2(struct InterruptFrame *frame)
-{
-	exc_handler(2, frame, 0);
-}
-__attribute__((interrupt))
-static void
-exc3(struct InterruptFrame *frame)
-{
-	exc_handler(3, frame, 0);
-}
-__attribute__((interrupt))
-static void
-exc4(struct InterruptFrame *frame)
-{
-	exc_handler(4, frame, 0);
-}
-__attribute__((interrupt))
-static void
-exc5(struct InterruptFrame *frame)
-{
-	exc_handler(5, frame, 0);
-}
-__attribute__((interrupt))
-static void
-exc6(struct InterruptFrame *frame)
-{
-	exc_handler(6, frame, 0);
-}
-__attribute__((interrupt))
-static void
-exc7(struct InterruptFrame *frame)
-{
-	exc_handler(7, frame, 0);
-}
-__attribute__((interrupt))
-static void
-exc8(struct InterruptFrame *frame, uint32_t err)
-{
-	exc_handler(8, frame, err);
-}
-__attribute__((interrupt))
-static void
-exc9(struct InterruptFrame *frame)
-{
-	exc_handler(9, frame, 0);
-}
-__attribute__((interrupt))
-static void
-exc10(struct InterruptFrame *frame, uint32_t err)
-{
-	exc_handler(10, frame, err);
-}
-__attribute__((interrupt))
-static void
-exc11(struct InterruptFrame *frame, uint32_t err)
-{
-	exc_handler(11, frame, err);
-}
-__attribute__((interrupt))
-static void
-exc12(struct InterruptFrame *frame, uint32_t err)
-{
-	exc_handler(12, frame, err);
-}
-__attribute__((interrupt))
-static void
-exc13(struct InterruptFrame *frame, uint32_t err)
-{
-	exc_handler(13, frame, err);
-}
-__attribute__((interrupt))
-static void
-exc14(struct InterruptFrame *frame, uint32_t err)
-{
-	exc_handler(14, frame, err);
-}
-__attribute__((interrupt))
-static void
-exc15(struct InterruptFrame *frame)
-{
-	exc_handler(15, frame, 0);
-}
-__attribute__((interrupt))
-static void
-exc16(struct InterruptFrame *frame)
-{
-	exc_handler(16, frame, 0);
-}
-__attribute__((interrupt))
-static void
-exc17(struct InterruptFrame *frame, uint32_t err)
-{
-	exc_handler(17, frame, err);
-}
-__attribute__((interrupt))
-static void
-exc18(struct InterruptFrame *frame)
-{
-	exc_handler(18, frame, 0);
-}
-__attribute__((interrupt))
-static void
-exc19(struct InterruptFrame *frame)
-{
-	exc_handler(19, frame, 0);
-}
-__attribute__((interrupt))
-static void
-exc20(struct InterruptFrame *frame)
-{
-	exc_handler(20, frame, 0);
-}
-__attribute__((interrupt))
-static void
-exc30(struct InterruptFrame *frame)
-{
-	exc_handler(30, frame, 0);
-}
-__attribute__((interrupt))
-static void
-exc128(struct InterruptFrame *frame)
-{
-	uintptr_t esi, *eax;
-	asm volatile(
-		"mov %%esi, %0;"
-		"lea -12(%%ebp), %1;"
-		: "=r" (esi), "=r" (eax));
-	*eax = syscall_handler(*eax, esi);
+	if (frame.intnum >= 32 && frame.intnum < 48)
+		outb(0x20, 0x20);
 
 	/* Send APIC EOI */
 	if (apic)
 		LAPIC(0xB0) = 0;
 }
 
-/* Interrupts */
-__attribute__((interrupt))
-static void
-int0(struct InterruptFrame *frame)
-{
-	int_handler(32, frame);
-}
-__attribute__((interrupt))
-static void
-int1(struct InterruptFrame *frame)
-{
-	int_handler(33, frame);
-}
-__attribute__((interrupt))
-static void
-int2(struct InterruptFrame *frame)
-{
-	int_handler(34, frame);
-}
-__attribute__((interrupt))
-static void
-int3(struct InterruptFrame *frame)
-{
-	int_handler(35, frame);
-}
-__attribute__((interrupt))
-static void
-int4(struct InterruptFrame *frame)
-{
-	int_handler(36, frame);
-}
-__attribute__((interrupt))
-static void
-int5(struct InterruptFrame *frame)
-{
-	int_handler(37, frame);
-}
-__attribute__((interrupt))
-static void
-int6(struct InterruptFrame *frame)
-{
-	int_handler(38, frame);
-}
-__attribute__((interrupt))
-static void
-int7(struct InterruptFrame *frame)
-{
-	int_handler(39, frame);
-}
-__attribute__((interrupt))
-static void
-int8(struct InterruptFrame *frame)
-{
-	int_handler(40, frame);
-}
-__attribute__((interrupt))
-static void
-int9(struct InterruptFrame *frame)
-{
-	int_handler(41, frame);
-}
-__attribute__((interrupt))
-static void
-int10(struct InterruptFrame *frame)
-{
-	int_handler(42, frame);
-}
-__attribute__((interrupt))
-static void
-int11(struct InterruptFrame *frame)
-{
-	int_handler(43, frame);
-}
-__attribute__((interrupt))
-static void
-int12(struct InterruptFrame *frame)
-{
-	int_handler(44, frame);
-}
-__attribute__((interrupt))
-static void
-int13(struct InterruptFrame *frame)
-{
-	int_handler(45, frame);
-}
-__attribute__((interrupt))
-static void
-int14(struct InterruptFrame *frame)
+/* Register an exception handler */
+void
+register_exception(int num, exc_handler_t addr)
 {
-	int_handler(46, frame);
+	if ((num >= 0 && num < 32) || num >= 48)
+		exceptions[num] = addr;
 }
-__attribute__((interrupt))
-static void
-int15(struct InterruptFrame *frame)
+
+/* Register an interrupt handler */
+void
+register_interrupt(int num, int_handler_t addr)
 {
-	int_handler(47, frame);
+	if (num >= 0 && num < 16)
+		interrupts[num] = addr;
 }
 
+/* Exceptions */
+extern char exc0[],  exc1[],  exc2[],  exc3[],  exc4[],  exc5[],  exc6[],
+            exc7[],  exc8[],  exc9[],  exc10[], exc11[], exc12[], exc13[],
+            exc14[], exc15[], exc16[], exc17[], exc18[], exc19[], exc20[],
+            exc30[];
+/* Interrutps */
+extern char exc32[], exc33[], exc34[], exc35[], exc36[], exc37[], exc38[],
+            exc39[], exc40[], exc41[], exc42[], exc43[], exc44[], exc45[],
+            exc46[], exc47[];
+/* System Call */
+extern char exc128[];
+
 /* Initialise the IDT */
 void
 init_idt(void)
@@ -354,22 +117,22 @@ init_idt(void)
 	install_idt_entry(30, exc30);
 
 	/* Install interrupts */
-	install_idt_entry(32, int0);
-	install_idt_entry(33, int1);
-	install_idt_entry(34, int2);
-	install_idt_entry(35, int3);
-	install_idt_entry(36, int4);
-	install_idt_entry(37, int5);
-	install_idt_entry(38, int6);
-	install_idt_entry(39, int7);
-	install_idt_entry(40, int8);
-	install_idt_entry(41, int9);
-	install_idt_entry(42, int10);
-	install_idt_entry(43, int11);
-	install_idt_entry(44, int12);
-	install_idt_entry(45, int13);
-	install_idt_entry(46, int14);
-	install_idt_entry(47, int15);
+	install_idt_entry(32, exc32);
+	install_idt_entry(33, exc33);
+	install_idt_entry(34, exc34);
+	install_idt_entry(35, exc35);
+	install_idt_entry(36, exc36);
+	install_idt_entry(37, exc37);
+	install_idt_entry(38, exc38);
+	install_idt_entry(39, exc39);
+	install_idt_entry(40, exc40);
+	install_idt_entry(41, exc41);
+	install_idt_entry(42, exc42);
+	install_idt_entry(43, exc43);
+	install_idt_entry(44, exc44);
+	install_idt_entry(45, exc45);
+	install_idt_entry(46, exc46);
+	install_idt_entry(47, exc47);
 
 	/* Install system call handler */
 	install_idt_entry(128, exc128);
@@ -389,19 +152,3 @@ cpu_load_idt(void)
 	};
 	asm volatile("lidt %0" :: "m" (ptr));
 }
-
-/* Register an exception handler */
-void
-register_exception(int num, exc_handler_t addr)
-{
-	if (num >= 0 && num < 32)
-		exceptions[num] = addr;
-}
-
-/* Register an interrupt handler */
-void
-register_interrupt(int num, int_handler_t addr)
-{
-	if (num >= 0 && num < 224)
-		interrupts[num] = addr;
-}
diff --git a/kernel/isr.S b/kernel/isr.S
new file mode 100644
index 0000000..c807e7b
--- /dev/null
+++ b/kernel/isr.S
@@ -0,0 +1,94 @@
+/*
+ * This file contains the interrupt service routine stubs.  For the most part
+ * they just call into the generic handlers after setting up the stack for them.
+ */
+
+.extern isr_handler
+
+/* Exception with an error */
+.macro exc_err num
+.globl exc\num
+exc\num:
+	cli
+	push $\num
+	jmp isr_stub
+.endm
+/* Exception without an error */
+.macro exc_noerr num
+.globl exc\num
+exc\num:
+	cli
+	push $0
+	push $\num
+	jmp isr_stub
+.endm
+
+/* Exceptions */
+EXC_NOERR 0
+EXC_NOERR 1
+EXC_NOERR 2
+EXC_NOERR 3
+EXC_NOERR 4
+EXC_NOERR 5
+EXC_NOERR 6
+EXC_NOERR 7
+EXC_ERR   8
+EXC_NOERR 9
+EXC_ERR   10
+EXC_ERR   11
+EXC_ERR   12
+EXC_ERR   13
+EXC_ERR   14
+EXC_NOERR 15
+EXC_NOERR 16
+EXC_ERR   17
+EXC_NOERR 18
+EXC_NOERR 19
+EXC_NOERR 20
+EXC_NOERR 30
+/* Interrupts */
+EXC_NOERR 32
+EXC_NOERR 33
+EXC_NOERR 34
+EXC_NOERR 35
+EXC_NOERR 36
+EXC_NOERR 37
+EXC_NOERR 38
+EXC_NOERR 39
+EXC_NOERR 40
+EXC_NOERR 41
+EXC_NOERR 42
+EXC_NOERR 43
+EXC_NOERR 44
+EXC_NOERR 45
+EXC_NOERR 46
+EXC_NOERR 47
+/* System Call */
+EXC_NOERR 128
+
+/* Generic ISR stub */
+isr_stub:
+	pusha
+	mov %ds, %ax
+	pushl %eax
+
+	/* Switch to kernel segments */
+	mov $0x10, %ax
+	mov %ax, %ds
+	mov %ax, %es
+	mov %ax, %fs
+	mov %ax, %gs
+
+	call isr_handler
+
+	/* Restore original segments */
+	popl %ebx
+	mov %bx, %ds
+	mov %bx, %es
+	mov %bx, %fs
+	mov %bx, %gs
+
+	popa
+	addl $8, %esp
+	sti
+	iret
diff --git a/kernel/main.c b/kernel/main.c
index 5d95c4a..bf1fd8c 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -18,7 +18,7 @@
 #include "acpi/acpi.h"
 
 extern char _bss[], _end[];
-void page_fault_handler(struct InterruptFrame *frame, uint32_t err);
+void page_fault_handler(struct InterruptFrame *frame);
 
 /* Per-CPU Setup */
 void
diff --git a/kernel/panic.c b/kernel/panic.c
index a489a0a..2c07d24 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -30,8 +30,6 @@ panic(char *fmt, ...)
 	outb(0xE9, '\n');
 
 	/* Halt processor */
-	asm volatile("cli");
-	while (1)
-		asm volatile("hlt");
+	while (1) asm volatile("cli; hlt");
 	__builtin_unreachable();
 }
diff --git a/memory/fault.c b/memory/fault.c
index e916368..5f94b55 100644
--- a/memory/fault.c
+++ b/memory/fault.c
@@ -44,9 +44,6 @@ copy_on_write(VMRegion *region, uintptr_t addr)
 		inode = back->inode;
 		page = find_page(inode->pages, offset);
 	}
-	if (!page) {
-		panic("no page! %#.8x = %#.8x", addr, get_page(addr));
-	}
 	ASSERT(page);
 
 	/* Determine what to do */
@@ -174,21 +171,21 @@ not_present_write(VMRegion *region, uintptr_t addr)
 
 /* Page fault handler */
 void
-page_fault_handler(struct InterruptFrame *frame, uint32_t err)
+page_fault_handler(struct InterruptFrame *frame)
 {
 	uintptr_t addr;
 	asm volatile("mov %%cr2, %0" : "=r" (addr));
-	uint8_t present = err & (1 << 0);
-	uint8_t write   = err & (1 << 1);
-	uint8_t user    = err & (1 << 2);
+	uint8_t present = frame->err & (1 << 0);
+	uint8_t write   = frame->err & (1 << 1);
+	uint8_t user    = frame->err & (1 << 2);
 
 	/* Iterate VM Regions */
 	VMRegion *region = find_region(addr);
 	/* Not in a region */
 	if (__builtin_expect(!region, 0)) {
 		page_t pg = get_page(addr);
-		panic("Page Fault [%d:%d] (%#.8x -> %#.8x [tbl:%d, pg:%d][%#.8x], %s, %s, %s)",
-		      current->tgid, current->tid, frame->eip,
+		panic("[CPU#%d] Page Fault [%d:%d] (%#.8x -> %#.8x [tbl:%d, pg:%d][%#.8x], %s, %s, %s)",
+		      CPUID, current->tgid, current->tid, frame->eip,
 		      addr, (addr >> 12) / 1024, (addr >> 12) % 1024, pg,
 		      present ? "present" : "not present",
 		      write ? "write" : "read",
@@ -208,13 +205,13 @@ page_fault_handler(struct InterruptFrame *frame, uint32_t err)
 
 /* Early (pre-VFS/tasking) page fault handler */
 void
-early_page_fault_handler(struct InterruptFrame *frame, uint32_t err)
+early_page_fault_handler(struct InterruptFrame *frame)
 {
 	uintptr_t addr;
 	asm volatile("mov %%cr2, %0" : "=r" (addr));
-	uint8_t present = err & (1 << 0);
-	uint8_t write   = err & (1 << 1);
-	uint8_t user    = err & (1 << 2);
+	uint8_t present = frame->err & (1 << 0);
+	uint8_t write   = frame->err & (1 << 1);
+	uint8_t user    = frame->err & (1 << 2);
 	if (!PAGE_ADDR(addr))
 		panic("Null dereference @ %#.8x (CPU#%d)", frame->eip, CPUID);
 	ASSERT(!present);
diff --git a/memory/paging.h b/memory/paging.h
index 284d0e3..eb7c75f 100644
--- a/memory/paging.h
+++ b/memory/paging.h
@@ -7,6 +7,6 @@
 
 extern page_t zeroFrame;
 
-void early_page_fault_handler(struct InterruptFrame *frame, uint32_t err);
+void early_page_fault_handler(struct InterruptFrame *frame);
 
 #endif
diff --git a/task/clone.c b/task/clone.c
index fe0ad88..93c0b94 100644
--- a/task/clone.c
+++ b/task/clone.c
@@ -62,9 +62,12 @@ clone(int flags)
 	child->pageDir = clone_dir();
 
 	/* Split tasks here */
-	child->eip = (uintptr_t) &&end;
+	asm volatile("mov %%esi, %0" : "=r" (child->esi));
+	asm volatile("mov %%edi, %0" : "=r" (child->edi));
+	asm volatile("mov %%ebx, %0" : "=r" (child->ebx));
 	asm volatile("mov %%esp, %0" : "=r" (child->esp));
 	asm volatile("mov %%ebp, %0" : "=r" (child->ebp));
+	child->eip = (uintptr_t) &&end;
 	add(readyQueue[child->priority], child);
 	tid = child->tid;
 	put(child);
diff --git a/task/scheduler.c b/task/scheduler.c
index 485301e..b35192c 100644
--- a/task/scheduler.c
+++ b/task/scheduler.c
@@ -11,6 +11,10 @@
 
 #define PRIORITY_COUNT 6
 
+void context_switch(uintptr_t eip, page_dir_t pagedir,
+                    uintptr_t esi, uintptr_t edi, uintptr_t ebx,
+                    uintptr_t ebp, uintptr_t esp);
+
 ObjectList *readyQueue[PRIORITY_COUNT];
 
 /* Switch to a task */
@@ -20,6 +24,9 @@ switch_to_task(Task *task)
 	/* Save current task state */
 	if (__builtin_expect(!!current, 1)) {
 		lock(current);
+		asm volatile("mov %%esi, %0" : "=r" (current->esi));
+		asm volatile("mov %%edi, %0" : "=r" (current->edi));
+		asm volatile("mov %%ebx, %0" : "=r" (current->ebx));
 		asm volatile("mov %%esp, %0" : "=r" (current->esp));
 		asm volatile("mov %%ebp, %0" : "=r" (current->ebp));
 		current->eip = (uintptr_t) &&end;
@@ -28,22 +35,9 @@ switch_to_task(Task *task)
 	}
 
 	/* Switch to new context */
-	uintptr_t eip, esp, ebp;
 	current = task; /* Given reference, so no get() */
-	eip = current->eip;
-	esp = current->esp;
-	ebp = current->ebp;
-	asm volatile (
-		"cli;"
-		"movl %0, %%ecx;"
-		"movl %1, %%esp;"
-		"movl %2, %%ebp;"
-		"movl %3, %%cr3;"
-		"sti;"
-		"jmp *%%ecx"
-		:: "g" (eip), "g" (esp),
-		   "g" (ebp), "g" (current->pageDir)
-	);
+	context_switch(current->eip, current->pageDir, current->esi,
+	               current->edi, current->ebx, current->ebp, current->esp);
 end:
 	/* This prevents GCC from optimising the jump to be after the return */
 	asm volatile("":::"memory");
diff --git a/task/switch.S b/task/switch.S
new file mode 100644
index 0000000..5ef5437
--- /dev/null
+++ b/task/switch.S
@@ -0,0 +1,21 @@
+/*
+ * This file contains the context switch routine.  This routine will switch the
+ * current context, but will not save any state, so it should only be called by
+ * the scheduler.  Since the stack and page directory will get switched, care
+ * must be taken to read and set the registers in the correct order.
+ */
+
+/* Perform a context switch */
+.globl context_switch
+context_switch:
+	cli
+	mov 4(%esp), %ecx
+	mov 8(%esp), %eax
+	mov 12(%esp), %esi
+	mov 16(%esp), %edi
+	mov 20(%esp), %ebx
+	mov 24(%esp), %ebp
+	mov 28(%esp), %esp
+	mov %eax, %cr3
+	sti
+	jmp *%ecx
diff --git a/task/syscall.c b/task/syscall.c
index e0b2d23..8e33ef4 100644
--- a/task/syscall.c
+++ b/task/syscall.c
@@ -87,9 +87,11 @@ struct SyscallEntry syscalls[] = {
 };
 
 /* Handle a syscall */
-int
-syscall_handler(int num, uintptr_t args)
+void
+syscall_handler(struct InterruptFrame *frame)
 {
+	int num = frame->eax;
+	uintptr_t args = frame->esi;
 	int ret = -EINVAL;
 	enter_syscall_context(num);
 
@@ -115,5 +117,5 @@ syscall_handler(int num, uintptr_t args)
 
 end:
 	exit_syscall_context();
-	return ret;
+	frame->eax = ret;
 }
diff --git a/task/task.c b/task/task.c
index 597df30..69af014 100644
--- a/task/task.c
+++ b/task/task.c
@@ -14,6 +14,7 @@
 
 void init_scheduler(void);
 void timer_handler(struct InterruptFrame *frame);
+void syscall_handler(struct InterruptFrame *frame);
 
 static void task_new(Object *);
 static void task_delete(Object *);
@@ -110,7 +111,7 @@ init_tasking(void)
 
 	init_scheduler();
 	register_interrupt(0, timer_handler);
-
+	register_exception(128, syscall_handler);
 }
 
 /* Get the current task's PID */