More safely handle nested interrupts. Switch to newly created thread immediately.
144 lines
3.7 KiB
D
144 lines
3.7 KiB
D
/**
|
|
* 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;
|
|
}
|
|
}
|
|
}
|