Last active
March 16, 2025 23:06
-
-
Save thomascswalker/235345323fdb2cb8e29231544583962f to your computer and use it in GitHub Desktop.
OSDev Scheduler Problem
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| static uint32_t i = 0; | |
| static uint32_t j = 0; | |
| void process1() | |
| { | |
| while (1) | |
| { | |
| printf("Process 1 is running: %d\n", i++); | |
| } | |
| } | |
| void process2() | |
| { | |
| while (1) | |
| { | |
| printf("Process 2 is running: %d\n", j++); | |
| } | |
| } | |
| EXTERN void kmain(MultibootInfo* info, uint32_t magic) | |
| { | |
| ... | |
| Scheduler::add(process1); | |
| Scheduler::add(process2); | |
| while (1) | |
| { | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| void PIT::callback(CPUState* regs) | |
| { | |
| Scheduler::schedule(); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| section .text | |
| global switchContext | |
| ; switchContext - Switches the CPU context from the current | |
| ; process to the next process. | |
| ; Parameters: | |
| ; prev - Pointer to the CPUState structure of the current process. | |
| ; next - Pointer to the CPUState structure of the next process. | |
| ; | |
| switchContext: | |
| cli | |
| ; Move the pointers to prev and next from the stack into | |
| ; registers edi and esi, respectively. | |
| mov edi, [esp + 4] ; EDI ← pointer to CPUState "prev" | |
| mov esi, [esp + 8] ; ESI ← pointer to CPUState "next" | |
| ; -------------------------------------- ; | |
| ; Store the current CPUState (into prev) ; | |
| ; -------------------------------------- ; | |
| ; Save segment registers into prev CPUState: | |
| mov [edi + 0], gs ; Save gs (offset 0) | |
| mov [edi + 4], fs ; Save fs (offset 4) | |
| mov [edi + 8], es ; Save es (offset 8) | |
| mov [edi + 12], ds ; Save ds (offset 12) | |
| ; Save general-purpose registers using pusha. | |
| pushfd ; Push EFLAGS on stack | |
| pusha ; Push general-purpose registers | |
| ; At this point, the stack looks like (top-to-bottom): | |
| ; EDI, ESI, EBP, ESP, EBX, EDX, ECX, EAX, then EFLAGS. | |
| pop dword [edi + 24] ; Pop EBP into prev->ebp | |
| pop dword [edi + 28] ; Pop original ESP into prev->esp | |
| pop dword [edi + 32] ; Pop EBX into prev->ebx | |
| pop dword [edi + 36] ; Pop EDX into prev->edx | |
| pop dword [edi + 40] ; Pop ECX into prev->ecx | |
| pop dword [edi + 44] ; Pop EAX into prev->eax | |
| pop dword [edi + 64] ; Pop EFLAGS into prev->eFlags | |
| ; ---------------------- ; | |
| ; Load the next CPUState ; | |
| ; ---------------------- ; | |
| ; Restore segment registers from next CPUState: | |
| mov gs, [esi + 0] ; Load gs from next->gs | |
| mov fs, [esi + 4] ; Load fs from next->fs | |
| mov es, [esi + 8] ; Load es from next->es | |
| mov ds, [esi + 12] ; Load ds from next->ds | |
| ; Restore base pointer and stack pointer from next CPUState. | |
| mov ebp, [esi + 24] ; Next->ebp | |
| mov esp, [esi + 28] ; Next->esp | |
| ; Restore general-purpose registers in the reverse stack order. | |
| mov ebx, [esi + 32] ; Next->ebx | |
| mov edx, [esi + 36] ; Next->edx | |
| mov ecx, [esi + 40] ; Next->ecx | |
| mov eax, [esi + 44] ; Next->eax | |
| ; Restore EFLAGS from next CPUState. | |
| push dword [esi + 64] ; Push next->eFlags on stack | |
| popfd ; Pop EFLAGS from stack | |
| ; --------------------------------------- ; | |
| ; Jump to the instruction pointer of next ; | |
| ; --------------------------------------- ; | |
| sti | |
| jmp dword [esi + 56] ; Jump to next->eip |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| static List<Process*> g_queue; | |
| static uint32_t g_nextPID = 0; // Contains the next free PID | |
| void Scheduler::add(EntryPoint func) | |
| { | |
| Process* process = (Process*)std::malloc(sizeof(Process)); | |
| process->func = func; // Set the function pointer | |
| process->pid = g_nextPID++; // Assign a unique PID | |
| process->stack = (uint8_t*)std::malloc(STACK_SIZE); // Allocate a stack for the process | |
| CPUState* frame = (CPUState*)((uint32_t)process->stack + STACK_SIZE); | |
| process->state = frame; // Set the CPU state for the process | |
| // Set the instruction pointer to the function | |
| frame->eip = (uint32_t)func; | |
| // Set the stack pointer to the top of the stack | |
| frame->esp = (uint32_t)(process->stack + STACK_SIZE - sizeof(CPUState)); | |
| // Set the interrupt flag (IF) and reserved flag (RF) | |
| frame->eFlags = 0x202; | |
| frame->userEsp = (uint32_t)(process->stack + STACK_SIZE - sizeof(CPUState)); | |
| // Set general-purpose registers | |
| frame->ebp = 0; | |
| frame->eax = 0; | |
| frame->ebx = 0; | |
| frame->ecx = 0; | |
| frame->edx = 0; | |
| frame->edi = 0; | |
| frame->esi = 0; | |
| // Set the segment registers | |
| frame->cs = SEG_KERNEL_CODE; | |
| frame->ss = SEG_KERNEL_DATA; | |
| frame->ds = SEG_KERNEL_DATA; | |
| frame->es = SEG_KERNEL_DATA; | |
| frame->fs = SEG_KERNEL_DATA; | |
| frame->gs = SEG_KERNEL_DATA; | |
| g_queue.addBack(process); | |
| } | |
| void Scheduler::schedule() | |
| { | |
| if (g_queue.isEmpty()) | |
| { | |
| return; | |
| } | |
| auto curr = g_queue.getFront(); | |
| if (!curr) | |
| { | |
| return; | |
| } | |
| auto next = curr->getNext(); | |
| if (curr == next) | |
| { | |
| return; | |
| } | |
| Process* currProc = curr->getValue(); | |
| Process* nextProc = next->getValue(); | |
| debug("Switching processes from %d to %d", currProc->pid, nextProc->pid); | |
| switchContext(currProc->state, nextProc->state); | |
| g_queue.rotate(1); | |
| } | |
| Process* System::Scheduler::getCurrentProcess() { return g_queue.getFront()->getValue(); } | |
| uint32_t System::Scheduler::getProcessCount() { return g_queue.size(); } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define SEG_KERNEL_CODE 0x08 | |
| #define SEG_KERNEL_DATA 0x10 | |
| #define SEG_USER_CODE 0x1B | |
| #define SEG_USER_DATA 0x23 | |
| struct CPUState | |
| { | |
| uint32_t gs, fs, es, ds; // Offsets 0, 4, 8, 12 | |
| uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // OFfsets 16, 20, 24, 28, 32, 36, 40, 44 | |
| uint32_t intNo, errCode; // Offsets 48, 52 | |
| uint32_t eip, cs, eFlags, userEsp, ss; // Offsets 56, 60, 64, 68, 72 | |
| }; | |
| // Defined in `scheduling.s`. | |
| EXTERN void switchContext(CPUState* prev, CPUState* next); | |
| namespace Scheduler | |
| { | |
| void add(EntryPoint func); | |
| void schedule(); | |
| Process* getCurrentProcess(); | |
| uint32_t getProcessCount(); | |
| }; // namespace Scheduler |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment