diff --git a/src/hulk/hulk.d b/src/hulk/hulk.d index 4322c50..d59a8db 100644 --- a/src/hulk/hulk.d +++ b/src/hulk/hulk.d @@ -26,6 +26,7 @@ import hulk.usb; import hulk.pit; import hulk.time; import hulk.test; +import hulk.thread; extern extern(C) __gshared ubyte _hulk_bss_size; @@ -33,7 +34,7 @@ extern extern(C) __gshared ubyte _hulk_bss_size; private __gshared HulkHeader hulk_header = { &_hulk_bss_size, /* hulk_bss_size */ &hulk_start, /* entry */ - 16u * 1024u, /* stack_size */ + Thread.STACK_SIZE, /* stack_size */ Hurl.HULK_BASE, /* virt_base */ Hurl.HULK_STACK_TOP, /* virt_stack_top */ Hurl.HULK_FRAMEBUFFER, /* virt_fb_buffer */ @@ -88,6 +89,7 @@ void hulk_start() Pit.initialize(); Pci.initialize(); Usb.initialize(); + Thread.initialize(); resume_interrupts(); diff --git a/src/hulk/idt.d b/src/hulk/idt.d index 80f1a86..ce2ee9e 100644 --- a/src/hulk/idt.d +++ b/src/hulk/idt.d @@ -11,11 +11,12 @@ import hulk.klog; import hulk.apic; import hulk.cpu; import hulk.kfont; +import hulk.thread; struct Idt { /** Interrupt stack frame indices. */ - private static enum + public static enum { ISF_RBP, ISF_R15, @@ -147,7 +148,7 @@ struct Idt mov $$", isr, ", %rdi movabs $$isr, %rax callq *%rax - mov %rbp, %rsp + mov %rax, %rsp popq %rbp popq %r15 popq %r14 @@ -184,8 +185,15 @@ struct Idt } } -public extern(C) void isr(ulong vector, ulong * stack_frame) +/** + * Interrupt service routine. + * + * This function returns the stack pointer of the thread to execute when + * returning from this function. + */ +public extern(C) ulong * isr(ulong vector, ulong * stack_frame) { + Thread.current_thread.stack_pointer = stack_frame; if ((vector >= Idt.INT_APIC_BASE) && (vector < (Idt.INT_APIC_BASE + Idt.INT_APIC_COUNT))) { Apic.isr(vector); @@ -217,4 +225,5 @@ public extern(C) void isr(ulong vector, ulong * stack_frame) } } } + return Thread.current_thread.stack_pointer; } diff --git a/src/hulk/thread.d b/src/hulk/thread.d new file mode 100644 index 0000000..9ab703a --- /dev/null +++ b/src/hulk/thread.d @@ -0,0 +1,102 @@ +/** + * Kernel thread functionality. + */ +module hulk.thread; + +import hulk.hurl.a1; +import hulk.idt; +import hulk.gdt; +import hulk.memory; +import hulk.list; +import hulk.cpu; +import hulk.hurl; + +struct Thread +{ + /* TODO: currently kernel thread stack size is fixed. */ + enum STACK_SIZE = 16 * 1024; + + /** List of all kernel threads. */ + private static __gshared List!Thread threads; + + /** Currently executing kernel thread. */ + static __gshared Thread * current_thread; + + /** Current kernel thread stack pointer. */ + ulong * stack_pointer; + static assert(stack_pointer.offsetof == 0); + + /** Base address of kernel thread stack. */ + void * stack_addr; + + /** Interrupt stack template. */ + static immutable __gshared ulong[Idt.ISF_COUNT] interrupt_stack_template = [ + 0x16161616_16161616u, /* RBP */ + 0x15151515_15151515u, /* R15 */ + 0x14141414_14141414u, /* R14 */ + 0x13131313_13131313u, /* R13 */ + 0x12121212_12121212u, /* R12 */ + 0x11111111_11111111u, /* R11 */ + 0x10101010_10101010u, /* R10 */ + 0x09090909_09090909u, /* R9 */ + 0x08080808_08080808u, /* R8 */ + 0x06060606_06060606u, /* RDI */ + 0x05050505_05050505u, /* RSI */ + 0x04040404_04040404u, /* RDX */ + 0x03030303_03030303u, /* RCX */ + 0x02020202_02020202u, /* RBX */ + 0x01010101_01010101u, /* RAX */ + 0u, /* Error Code */ + 0u, /* RIP */ + Gdt.SELECTOR_KERNEL_CODE, /* CS */ + 0u, /* RFLAGS */ + 0u, /* RSP */ + Gdt.SELECTOR_KERNEL_DATA, /* SS */ + ]; + + /** + * Initialize a kernel thread. + */ + public void initialize(void function() fn) + { + stack_addr = A1.allocate(STACK_SIZE); + ulong * stack_top = cast(ulong *)(stack_addr + STACK_SIZE); + stack_pointer = stack_top - Idt.ISF_COUNT; + memcpy64(stack_pointer, &interrupt_stack_template[0], Idt.ISF_COUNT); + stack_pointer[Idt.ISF_RIP] = cast(ulong)fn; + stack_pointer[Idt.ISF_RFLAGS] = read_rflags(); + stack_pointer[Idt.ISF_RSP] = cast(ulong)stack_top; + } + + /** + * Initialize main kernel thread. + */ + public void initialize_main_thread() + { + stack_addr = cast(void *)(Hurl.HULK_STACK_TOP - STACK_SIZE); + } + + /** + * Initialize kernel threading. + */ + public static void initialize() + { + Thread * thread = A1.allocate!Thread(); + thread.initialize_main_thread(); + current_thread = thread; + } + + /** + * Create and start a kernel thread. + * + * TODO: fn must not return. + * TODO: threads are always runnable. + * TODO: threads cannot be destroyed. + */ + public static Thread * start(void function() fn) + { + Thread * thread = A1.allocate!Thread(); + thread.initialize(fn); + return thread; + } +}