The comment above the yield() function suggests that yield() allows interrupts for a short time. Currently this is only true if seabios was built without CONFIG_THREADS or if yield() is called from the main thread. Change the code to always call check_irqs() in yield().
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.
ps2_keyboard_setup() | ret = i8042_command(I8042_CMD_KBD_DISABLE, NULL); # 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(); # 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. | yield(); # 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 vr_qemu@t-online.de --- src/stacks.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/src/stacks.c b/src/stacks.c index 2fe1bfb..70e8283 100644 --- a/src/stacks.c +++ b/src/stacks.c @@ -623,9 +623,25 @@ yield(void) return; } struct thread_info *cur = getCurThread(); - if (cur == &MainThread) - // Permit irqs to fire + struct thread_info *mt = &MainThread; + + // Permit irqs to fire + if (cur == mt) { check_irqs(); + } else { + asm volatile( + " pushl %%ebp\n" // backup %ebp + " movl %%esp, %%esi\n" + " movl (%%eax), %%esp\n" // switch to MainThread stack + " pushl %%esi\n" // backup current thread stack pointer + " calll %1\n" // check_irqs(); + " popl %%esi\n" + " movl %%esi, %%esp\n" // switch back to current thread stack + " popl %%ebp\n" // restore %ebp + : "+a"(mt) + : "m"(check_irqs) + : "ebx", "ecx", "edx", "esi", "edi", "cc", "memory"); + }
// Switch to the next thread switch_next(cur);