Ring 0 multithreading
Posted: Thu Jan 08, 2026 1:15 am
Hello everyone,
I’ll start with some context. Over the past two weeks, I’ve been working on implementing ring 0 multithreading. My goal is to understand how kernel-level multitasking works internally before moving on to user-mode multitasking (and user mode in general). Unfortunately, I’ve reached a point where I seem to have hit a wall in the implementation.
My current multithreading design works as follows:
1) A timer interrupt fires. As a result, the CPU automatically pushes EFLAGS, CS, and EIP onto the current kernel stack. In addition, my interrupt stub saves all general-purpose registers and the data segment register onto the stack.
2) Control is transferred to a general interrupt handler, which in turn calls the timer interrupt handler. This handler invokes the scheduler.
3) The scheduler saves the current context (which was pushed onto the stack in step 1) into the current TCB (thread control block). It then selects the next TCB and replaces the context saved on the stack with the new thread’s context.
4) Control returns from the general interrupt handler. The interrupt stub restores the general-purpose registers and the data segment register (which were updated in step 3), and finally executes iret to resume execution.
After several scheduling cycles, the system eventually triggers a page fault at what appears to be a random address. I suspect that this is caused by an incorrect restoration or modification of registers during step 4, but I haven’t been able to pinpoint the exact issue.
Does anyone have an idea what could cause this behavior or what I should focus on debugging?
Source code:
https://github.com/sDos280/MyOS
I’ll start with some context. Over the past two weeks, I’ve been working on implementing ring 0 multithreading. My goal is to understand how kernel-level multitasking works internally before moving on to user-mode multitasking (and user mode in general). Unfortunately, I’ve reached a point where I seem to have hit a wall in the implementation.
My current multithreading design works as follows:
1) A timer interrupt fires. As a result, the CPU automatically pushes EFLAGS, CS, and EIP onto the current kernel stack. In addition, my interrupt stub saves all general-purpose registers and the data segment register onto the stack.
2) Control is transferred to a general interrupt handler, which in turn calls the timer interrupt handler. This handler invokes the scheduler.
3) The scheduler saves the current context (which was pushed onto the stack in step 1) into the current TCB (thread control block). It then selects the next TCB and replaces the context saved on the stack with the new thread’s context.
4) Control returns from the general interrupt handler. The interrupt stub restores the general-purpose registers and the data segment register (which were updated in step 3), and finally executes iret to resume execution.
Code: Select all
isr_common_stub:
pusha // Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
mov ax, ds // Lower 16-bits of eax = ds.
push eax // save the data segment descriptor
mov ax, 0x10 // load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
call isr_stub_handler
pop ebx // reload the original data segment descriptor
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
popa // Pops edi,esi,ebp...
add esp, 8 // Cleans up the pushed error code and pushed ISR number
sti
iret // pops 5 things at once: CS, EIP, EFLAGSCode: Select all
typedef struct cpu_status_struct {
uint32_t ds;
// Pushed by pusha.
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
uint32_t int_no, err_code;
// Pushed by the processor automatically.
uint32_t eip, cs, eflags;
} cpu_status_t;Does anyone have an idea what could cause this behavior or what I should focus on debugging?
Source code:
https://github.com/sDos280/MyOS