From 0e894f0a16ab34f52ea53adc8841be0edde594d3 Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Thu, 12 Feb 2026 03:21:08 -0300 Subject: [PATCH] fix: save/restore EFLAGS in context_switch instead of forcing sti after schedule() context_switch now uses pushf/popf to properly save and restore the EFLAGS register (including the IF bit) across context switches. This replaces the unconditional hal_cpu_enable_interrupts() call after context_switch in schedule(), which broke the interrupt-state semantics for callers that needed atomicity. All process creation functions (fork, clone, kernel thread) now push EFLAGS=0x202 (IF=1) onto the initial stack so new processes start with interrupts enabled via popf in context_switch. --- src/arch/x86/process.S | 11 ++++++----- src/kernel/scheduler.c | 6 +++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/arch/x86/process.S b/src/arch/x86/process.S index d847e0a2..f2eac6da 100644 --- a/src/arch/x86/process.S +++ b/src/arch/x86/process.S @@ -20,19 +20,20 @@ context_switch: push %ebx push %esi push %edi + pushf /* Save EFLAGS (including IF) */ /* 2. Save the old ESP */ - /* Get the location of old_esp_ptr. - Stack is: [RetAddr] [old_esp_ptr] [new_esp] - ESP points to EDI (last push) */ + /* Stack is: [RetAddr] [old_esp_ptr] [new_esp] + 5 pushes (20 bytes) + ESP points to EFLAGS (last push) */ - mov 20(%esp), %eax /* EAX = old_esp_ptr */ + mov 24(%esp), %eax /* EAX = old_esp_ptr */ mov %esp, (%eax) /* *old_esp_ptr = ESP */ /* 3. Switch to the NEW process stack */ - mov 24(%esp), %esp /* ESP = new_esp */ + mov 28(%esp), %esp /* ESP = new_esp */ /* 4. Restore state of the NEW process */ + popf /* Restore EFLAGS (including IF) from saved context */ pop %edi pop %esi pop %ebx diff --git a/src/kernel/scheduler.c b/src/kernel/scheduler.c index 522ffe62..bc138f5b 100644 --- a/src/kernel/scheduler.c +++ b/src/kernel/scheduler.c @@ -415,6 +415,7 @@ struct process* process_fork_create(uintptr_t child_as, const struct registers* *--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->next = ready_queue_head; @@ -568,6 +569,7 @@ struct process* process_clone_create(uint32_t clone_flags, *--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; /* Insert into process list */ @@ -709,6 +711,7 @@ struct process* process_create_kernel(void (*entry_point)(void)) { *--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; @@ -807,7 +810,8 @@ void schedule(void) { context_switch(&prev->sp, current_process->sp); - hal_cpu_enable_interrupts(); + /* EFLAGS (including IF) is now restored by context_switch via popf, + * so we no longer force-enable interrupts here. */ } void process_sleep(uint32_t ticks) { -- 2.43.0