From d21f2609e373308527ad8669a0622c24c895eb06 Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Thu, 12 Feb 2026 21:29:02 -0300 Subject: [PATCH] refactor: extract x86 kernel stack setup and register accessors from scheduler to arch layer - New include/arch_process.h: arch-agnostic prototypes for arch_kstack_init(), arch_regs_set_retval(), arch_regs_set_ustack() - New src/arch/x86/arch_process.c: x86 implementation (EFLAGS 0x202, cdecl stack frame layout matching context_switch in process.S) - scheduler.c: process_create_kernel, process_fork_create, process_clone_create now use arch_kstack_init() instead of inline x86 stack manipulation - scheduler.c: process_clone_create uses arch_regs_set_retval/arch_regs_set_ustack instead of direct .eax/.useresp access No x86-specific constants or register names remain in scheduler.c. --- .gitignore | 1 + include/arch_process.h | 35 +++++++++++++++++++++++++ src/arch/x86/arch_process.c | 52 +++++++++++++++++++++++++++++++++++++ src/kernel/scheduler.c | 36 +++++++------------------ 4 files changed, 98 insertions(+), 26 deletions(-) create mode 100644 include/arch_process.h create mode 100644 src/arch/x86/arch_process.c diff --git a/.gitignore b/.gitignore index d541280..1beace5 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ supplementary-material *.swp *~ third_party/ +user/doom/doomgeneric diff --git a/include/arch_process.h b/include/arch_process.h new file mode 100644 index 0000000..424ece9 --- /dev/null +++ b/include/arch_process.h @@ -0,0 +1,35 @@ +#ifndef ARCH_PROCESS_H +#define ARCH_PROCESS_H + +#include +#include "interrupts.h" + +/* + * arch_kstack_init — Prepare a kernel stack for a brand-new process/thread + * so that context_switch will resume into wrapper(arg). + * + * stack_top : pointer to the TOP of the kernel stack (base + size). + * wrapper : function that context_switch's "ret" will jump to + * (e.g. thread_wrapper). + * arg : argument passed to wrapper (e.g. actual entry point or + * fork_child_trampoline). + * + * Returns the initial SP value to store in proc->sp. + */ +uintptr_t arch_kstack_init(void* stack_top, + void (*wrapper)(void (*)(void)), + void (*arg)(void)); + +/* + * Set the "return value" register in a saved trapframe. + * On x86 this is EAX; on ARM it would be R0, etc. + */ +void arch_regs_set_retval(struct registers* regs, uint32_t val); + +/* + * Set the user-mode stack pointer in a saved trapframe. + * On x86 this is useresp; on ARM it would be SP_usr, etc. + */ +void arch_regs_set_ustack(struct registers* regs, uintptr_t sp); + +#endif /* ARCH_PROCESS_H */ diff --git a/src/arch/x86/arch_process.c b/src/arch/x86/arch_process.c new file mode 100644 index 0000000..08c9f7e --- /dev/null +++ b/src/arch/x86/arch_process.c @@ -0,0 +1,52 @@ +#include "arch_process.h" +#include "arch/x86/idt.h" + +#if defined(__i386__) + +/* + * x86 kernel stack layout expected by context_switch (process.S): + * + * context_switch saves: pushf, push edi, esi, ebx, ebp + * context_switch restores: popf, pop edi, esi, ebx, ebp, ret + * + * So for a NEW process we build a fake frame that context_switch will + * "restore": + * + * sp -> [EFLAGS 0x202] <- popf (IF=1, reserved bit 1) + * [EDI 0] <- pop edi + * [ESI 0] <- pop esi + * [EBX 0] <- pop ebx + * [EBP 0] <- pop ebp + * [wrapper addr] <- ret jumps here + * [0 (fake retaddr for wrapper)] + * [arg] <- first argument to wrapper (cdecl) + */ +uintptr_t arch_kstack_init(void* stack_top, + void (*wrapper)(void (*)(void)), + void (*arg)(void)) +{ + uint32_t* sp = (uint32_t*)stack_top; + + *--sp = (uint32_t)(uintptr_t)arg; /* argument for wrapper */ + *--sp = 0; /* fake return address */ + *--sp = (uint32_t)(uintptr_t)wrapper; /* ret target */ + *--sp = 0; /* EBP */ + *--sp = 0; /* EBX */ + *--sp = 0; /* ESI */ + *--sp = 0; /* EDI */ + *--sp = 0x202; /* EFLAGS: IF=1 */ + + return (uintptr_t)sp; +} + +void arch_regs_set_retval(struct registers* regs, uint32_t val) +{ + if (regs) regs->eax = val; +} + +void arch_regs_set_ustack(struct registers* regs, uintptr_t sp) +{ + if (regs) regs->useresp = (uint32_t)sp; +} + +#endif /* __i386__ */ diff --git a/src/kernel/scheduler.c b/src/kernel/scheduler.c index ae87d43..a77b0b4 100644 --- a/src/kernel/scheduler.c +++ b/src/kernel/scheduler.c @@ -9,6 +9,7 @@ #include "errno.h" #include "hal/cpu.h" #include "hal/usermode.h" +#include "arch_process.h" #include struct process* current_process = NULL; @@ -446,13 +447,8 @@ struct process* process_fork_create(uintptr_t child_as, const struct registers* } proc->kernel_stack = (uint32_t*)stack; - uint32_t* sp = (uint32_t*)((uint8_t*)stack + 4096); - *--sp = (uint32_t)fork_child_trampoline; - *--sp = 0; - *--sp = (uint32_t)thread_wrapper; - *--sp = 0; *--sp = 0; *--sp = 0; *--sp = 0; - *--sp = 0x202; /* EFLAGS: IF=1, reserved bit 1 */ - proc->sp = (uintptr_t)sp; + proc->sp = arch_kstack_init((uint8_t*)stack + 4096, + thread_wrapper, fork_child_trampoline); proc->next = ready_queue_head; proc->prev = ready_queue_tail; @@ -574,11 +570,11 @@ struct process* process_clone_create(uint32_t clone_flags, proc->has_user_regs = 1; proc->user_regs = *child_regs; - proc->user_regs.eax = 0; /* child returns 0 */ + arch_regs_set_retval(&proc->user_regs, 0); /* child returns 0 */ - /* If child_stack specified, override ESP */ + /* If child_stack specified, override user stack pointer */ if (child_stack) { - proc->user_regs.useresp = (uint32_t)child_stack; + arch_regs_set_ustack(&proc->user_regs, child_stack); } /* Allocate kernel stack */ @@ -593,13 +589,8 @@ struct process* process_clone_create(uint32_t clone_flags, } proc->kernel_stack = (uint32_t*)kstack; - uint32_t* sp = (uint32_t*)((uint8_t*)kstack + 4096); - *--sp = (uint32_t)clone_child_trampoline; - *--sp = 0; - *--sp = (uint32_t)thread_wrapper; - *--sp = 0; *--sp = 0; *--sp = 0; *--sp = 0; - *--sp = 0x202; /* EFLAGS: IF=1, reserved bit 1 */ - proc->sp = (uintptr_t)sp; + proc->sp = arch_kstack_init((uint8_t*)kstack + 4096, + thread_wrapper, clone_child_trampoline); /* Insert into process list */ proc->next = ready_queue_head; @@ -742,15 +733,8 @@ struct process* process_create_kernel(void (*entry_point)(void)) { proc->kernel_stack = (uint32_t*)stack; - uint32_t* sp = (uint32_t*)((uint8_t*)stack + 4096); - - *--sp = (uint32_t)entry_point; - *--sp = 0; - *--sp = (uint32_t)thread_wrapper; - *--sp = 0; *--sp = 0; *--sp = 0; *--sp = 0; - *--sp = 0x202; /* EFLAGS: IF=1, reserved bit 1 */ - - proc->sp = (uintptr_t)sp; + proc->sp = arch_kstack_init((uint8_t*)stack + 4096, + thread_wrapper, entry_point); proc->next = ready_queue_head; proc->prev = ready_queue_tail; -- 2.43.0