]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
fix: save/restore EFLAGS in context_switch instead of forcing sti after schedule()
authorTulio A M Mendes <[email protected]>
Thu, 12 Feb 2026 06:21:08 +0000 (03:21 -0300)
committerTulio A M Mendes <[email protected]>
Fri, 13 Feb 2026 02:44:55 +0000 (23:44 -0300)
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
src/kernel/scheduler.c

index b1528a99320f2345bb1f34aa089136d850e36c00..df6d3f59a595bcec3eb137a1a6bb7aaf298465dc 100644 (file)
@@ -11,19 +11,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
index 654f07d92de15200692a509e19d49ed637982f1d..766c49db521d333ada79b58c976aefcb34aa622c 100644 (file)
@@ -406,6 +406,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;
@@ -559,6 +560,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 */
@@ -700,6 +702,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;
 
@@ -798,7 +801,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) {