/** * Kernel thread functionality. */ module hulk.thread; import hulk.hurl.a1; import hulk.him; import hulk.gdt; 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 */ 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 */ ]; /** List of all runnable kernel threads. */ private static __gshared Thread * runnable_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; mixin List!Thread; /** * Initialize a kernel thread. */ public void initialize(void function() fn) { list_init(); 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; memcpy64(stack_pointer, &interrupt_stack_template[0], ISF_COUNT); stack_pointer[ISF_RIP] = cast(ulong)fn; stack_pointer[ISF_RFLAGS] = read_rflags(); stack_pointer[ISF_RSP] = cast(ulong)stack_top; } /** * Initialize first kernel thread. */ public void initialize_first_thread() { list_init(); runnable_threads = &this; stack_addr = cast(void *)(Hurl.HULK_STACK_TOP - STACK_SIZE); } /** * Initialize kernel threading. */ public static void initialize() { Thread * thread = A1.allocate!Thread(); thread.initialize_first_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); 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; } } }