Multitasking & Scheduling
TilekarOS supports preemptive multitasking for Ring 0 (Kernel) and Ring 3 (User) tasks.
1. Task Structure (task_t)
A task tracks:
- ID: Unique process identifier (TID).
- State: READY, RUNNING, ZOMBIE.
- Kernel Stack: Pointer to the current stack pointer of the task.
- Address Space: Page Directory physical address (
CR3). - Privilege: Kernel (0) or User (3).
2. Task Lifecycle
Creation (task_create)
When a task is created, the kernel:
- Allocates a
task_tand a 4KB kernel stack. - Prepares the stack frame to simulate an interrupt return (
iret). - Initializes registers so the task starts execution at
task_wrapper.
Execution Wrapper (task_wrapper)
Every task begins in task_wrapper.
- For User Tasks, it handles the transition to Ring 3 using
iret. - For Kernel Tasks, it simply calls the entry point.
- When the task finishes, it automatically calls
task_exit().
Exiting (task_exit)
When a task exits, it is removed from the ready queue and placed into a Zombie List.
- Zombie List: Exited tasks cannot free their own kernel stack while they are still using it.
- Delayed Cleanup: The next task to be scheduled calls
cleanup_zombies(), which performs the actualkfreeon the exited task'stask_tand kernel stack. - System Halt: If the last remaining task exits, the kernel enters an infinite
hltloop.
3. Context Switching
A context switch occurs during a timer interrupt (preemption) or a manual task_yield().
context_switch(current_esp, next_esp, next_cr3, intr_num)
The switch is performed in assembly (task.asm) and is highly optimized:
- Simulate Interrupt: Since
context_switchis a regular call, it pops the return EIP and pushes a "fake" interrupt frame (EFLAGS,CS,EIP) so that it can return viairet. - Save Current Context: Saves all registers (
pushad, segment registers) onto the current task's stack. - Page Directory Switch: Checks if the
next_cr3is different from the current one. If so, it loads the newCR3. This avoids unnecessary TLB flushes if switching between threads in the same process. - Stack Switch: Updates the current task's
task_twith its currentESPand then loads thenext_espinto theESPregister. - PIC EOI: If the switch was triggered by a hardware interrupt (
intr_num >= 32), it callspic_send_eoibefore restoring the next task's state. - Restore Context: Pops the segment and general-purpose registers of the new task.
- Return: Executes
iret, which jumps to the next task's savedEIPand restores itsEFLAGS.
4. User Mode (Ring 3)
The kernel transitions to User Mode using the iret instruction within task_wrapper (for new tasks) or when returning from a syscall/interrupt.
Ring 3 Transition Logic:
- TSS: The global Task State Segment is updated with the task's
esp0(top of its kernel stack) during every context switch. This allows the CPU to find the kernel stack when an interrupt occurs in Ring 3. - User Stack: For user tasks, a separate stack is mapped at
0xB0000000in their private address space. - The Jump:
- Sets segment registers (
DS,ES,FS,GS) to the user data selector (0x23). - Pushes the User Stack Segment (
0x23), the User Stack Pointer,EFLAGS(with interrupts enabled), the User Code Segment (0x1B), and the entry pointEIP. - Executes
iret.
- Sets segment registers (