diff --git a/src/hulk/cpu.d b/src/hulk/cpu.d index aa3af81..c46fae6 100644 --- a/src/hulk/cpu.d +++ b/src/hulk/cpu.d @@ -254,8 +254,7 @@ void cpuid1(uint * ebx, uint * ecx, uint * edx) __asm("cpuid", "=*{ebx},=*{ecx},=*{edx},{eax}", ebx, ecx, edx, 1u); } -void swint(int swint_id)() +void swint(ubyte swint_id)() { - static assert((0 <= swint_id) && (swint_id <= 255)); - mixin(`__asm("int $$`, swint_id, `", "");`); + mixin(`__asm("int $$`, cast(int)cast(uint)swint_id, `", "");`); } diff --git a/src/hulk/him.d b/src/hulk/him.d index 23ad3d2..22affb5 100644 --- a/src/hulk/him.d +++ b/src/hulk/him.d @@ -236,6 +236,7 @@ struct Him mov %rsp, %rbp mov %rsp, %rsi and $$0xFFFFFFFFFFFFFFF0, %rsp + mov %rsp, %rdx mov %rax, %rdi movabs $$isr, %rax callq *%rax @@ -273,10 +274,13 @@ struct Him * 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) +public extern(C) ulong * isr(ulong vector, ulong * stack_frame, ulong * rsp) { interrupt_level++; - Thread.current_thread.stack_pointer = stack_frame; + if (interrupt_level == 1) + { + Thread.current_thread.stack_pointer = stack_frame; + } if ((vector >= INT_APIC_BASE) && (vector < (INT_APIC_BASE + INT_APIC_COUNT))) { Apic.isr(vector); @@ -292,6 +296,10 @@ public extern(C) ulong * isr(ulong vector, ulong * stack_frame) Apic.isr(vector); break; + case INT_KERNEL_SWINT: + Thread.handle_swint(stack_frame); + break; + default: Fb.rect(0, 0, Fb.width, Kfont.line_height, 0xCC0000u); Klog.writefln("\n **** Unhandled ISR %u ****", vector); @@ -310,5 +318,12 @@ public extern(C) ulong * isr(ulong vector, ulong * stack_frame) } Thread.current_thread = Thread.current_thread.list_next; interrupt_level--; - return Thread.current_thread.stack_pointer; + if (interrupt_level == 0) + { + return Thread.current_thread.stack_pointer; + } + else + { + return rsp; + } } diff --git a/src/hulk/hulk.d b/src/hulk/hulk.d index 1df1528..a19d0c2 100644 --- a/src/hulk/hulk.d +++ b/src/hulk/hulk.d @@ -92,11 +92,22 @@ void hulk_start() /* Run kernel tests. */ Test.run(); Klog.writefln("\a5HULK Initialization Complete!"); - + Thread.start(&th); /* Idle loop. */ Time.msleep(1); + Time.msleep(500); + Klog.writefln("Main thread!"); for (;;) { hlt(); } } + +void th() +{ + for (;;) + { + Klog.writefln("Hello from thread."); + Time.msleep(1000); + } +} diff --git a/src/hulk/thread.d b/src/hulk/thread.d index 6019bc8..536a28c 100644 --- a/src/hulk/thread.d +++ b/src/hulk/thread.d @@ -10,12 +10,15 @@ import hulk.memory; import hulk.list; import hulk.cpu; import hulk.hurl; +import ldc.llvmasm; struct Thread { /* TODO: currently kernel thread stack size is fixed. */ enum STACK_SIZE = 16 * 1024; + enum ulong INT_TCTRL_YIELD = 0; + /** Interrupt stack template. */ static immutable __gshared ulong[ISF_COUNT] interrupt_stack_template = [ 0x16161616_16161616u, /* RBP */ @@ -41,8 +44,8 @@ struct Thread Gdt.SELECTOR_KERNEL_DATA, /* SS */ ]; - /** List of all kernel threads. */ - private static __gshared Thread * threads; + /** List of all runnable kernel threads. */ + private static __gshared Thread * runnable_threads; /** Currently executing kernel thread. */ static __gshared Thread * current_thread; @@ -62,11 +65,9 @@ struct Thread public void initialize(void function() fn) { list_init(); - if (threads == null) - { - threads = &this; - } + suspend_interrupts(); list_insert_after(current_thread); + resume_interrupts(); stack_addr = A1.allocate(STACK_SIZE); ulong * stack_top = cast(ulong *)(stack_addr + STACK_SIZE); stack_pointer = stack_top - ISF_COUNT; @@ -77,15 +78,12 @@ struct Thread } /** - * Initialize main kernel thread. + * Initialize first kernel thread. */ - public void initialize_main_thread() + public void initialize_first_thread() { list_init(); - if (threads == null) - { - threads = &this; - } + runnable_threads = &this; stack_addr = cast(void *)(Hurl.HULK_STACK_TOP - STACK_SIZE); } @@ -95,7 +93,7 @@ struct Thread public static void initialize() { Thread * thread = A1.allocate!Thread(); - thread.initialize_main_thread(); + thread.initialize_first_thread(); current_thread = thread; } @@ -110,6 +108,36 @@ struct Thread { Thread * thread = A1.allocate!Thread(); thread.initialize(fn); + swint(INT_TCTRL_YIELD); return thread; } + + /** + * Trigger a thread management software interrupt. + */ + public static void swint(T1)(T1 v1) + { + mixin(`__asm("int $$`, cast(int)INT_KERNEL_SWINT, `", "{rax}", v1);`); + } + + /** + * Handle a thread management software interrupt. + * + * This function is called in interrupt context. + * + * @param stack_frame + * Pointer to the stack frame. + */ + public static void handle_swint(ulong * stack_frame) + { + switch (stack_frame[ISF_RAX]) + { + case INT_TCTRL_YIELD: + Thread.current_thread = Thread.current_thread.list_next; + break; + + default: + break; + } + } }