stacks: call check_irqs() in run_thread()

The comment above the yield() function suggests that yield()
allows interrupts for a short time. But yield() only briefly
enables interrupts if seabios was built without CONFIG_THREADS
or if yield() is called from the main thread. In order to
guarantee that the interrupts were enabled once before yield()
returns in a background thread, the main thread must call
check_irqs() before or after every thread switch. The function
run_thread() also switches threads, but the call to check_irqs()
was forgotten. Add the missing check_irqs() call.

This fixes PS/2 keyboard initialization failures.

The code in src/hw/ps2port.c relies on yield() to briefly enable
interrupts. There is a comment above the yield() function in
__ps2_command(), where the author left a remark why the call to
yield() is actually needed.

Here is one of the call sequences leading to a PS/2 keyboard
initialization failure.

  ret = i8042_command(I8042_CMD_CTL_TEST, param);
  # This command will register an interrupt if the PS/2 device
  # controller raises interrupts for replies to a controller
  # command.
  ret = ps2_kbd_command(ATKBD_CMD_RESET_BAT, param);
    ps2_command(0, command, param);
      ret = __ps2_command(aux, command, param);
        // Flush any interrupts already pending.
        # yield() doesn't flush interrupts if the main thread
        # hasn't reached wait_threads().
        ret = ps2_sendbyte(aux, command, 1000);
        # Reset the PS/2 keyboard controller and wait for
        # PS2_RET_ACK.
        ret = ps2_recvbyte(aux, 0, 4000);
          for (;;) {
            status = inb(PORT_PS2_STATUS);
            # I8042_STR_OBF isn't set because the keyboard self
            # test reply is still on wire.
            # After a few yield()s the keyboard interrupt fires
            # and clears the I8042_STR_OBF status bit. If the
            # keyboard self test reply arrives before the
            # interrupt fires the keyboard reply is lost and
            # ps2_recvbyte() returns after the timeout.

Signed-off-by: Volker RĂ¼melin <>
diff --git a/src/stacks.c b/src/stacks.c
index 2fe1bfb..df32325 100644
--- a/src/stacks.c
+++ b/src/stacks.c
@@ -549,6 +549,8 @@
         dprintf(1, "All threads complete.\n");
+void VISIBLE16 check_irqs(void);
 // Create a new thread and start executing 'func' in it.
 run_thread(void (*func)(void*), void *data)
@@ -564,6 +566,7 @@
     dprintf(DEBUG_thread, "/%08x\\ Start thread\n", (u32)thread);
     thread->stackpos = (void*)thread + THREADSTACKSIZE;
     struct thread_info *cur = getCurThread();
+    struct thread_info *edx = cur;
     hlist_add_after(&thread->node, &cur->node);
     asm volatile(
         // Start thread
@@ -582,9 +585,12 @@
         "  popl %%ebp\n"                // restore %ebp
         "  retl\n"                      // restore pc
-        : "+a"(data), "+c"(func), "+b"(thread), "+d"(cur)
+        : "+a"(data), "+c"(func), "+b"(thread), "+d"(edx)
         : "m"(*(u8*)__end_thread), "m"(MainThread)
         : "esi", "edi", "cc", "memory");
+    if (cur == &MainThread)
+        // Permit irqs to fire
+        check_irqs();