diff options
author | Volker RĂ¼melin <vr_qemu@t-online.de> | 2021-06-04 20:01:19 +0200 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2021-06-09 11:05:18 -0400 |
commit | f501bcbeef616c40125889b657f7ff42eeec8a8d (patch) | |
tree | 9c8d1ee61c4690fcca7fa5cee9e064c03aa3e28c | |
parent | 7292e4a0a8f58333ccbd2d0d47242f9865083c9c (diff) | |
download | seabios-f501bcbeef616c40125889b657f7ff42eeec8a8d.tar.gz |
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.
ps2_keyboard_setup()
|
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();
# 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>
-rw-r--r-- | src/stacks.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/src/stacks.c b/src/stacks.c index 2fe1bfbd..df323259 100644 --- a/src/stacks.c +++ b/src/stacks.c @@ -549,6 +549,8 @@ __end_thread(struct thread_info *old) dprintf(1, "All threads complete.\n"); } +void VISIBLE16 check_irqs(void); + // Create a new thread and start executing 'func' in it. void run_thread(void (*func)(void*), void *data) @@ -564,6 +566,7 @@ run_thread(void (*func)(void*), void *data) 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 @@ run_thread(void (*func)(void*), void *data) " popl %%ebp\n" // restore %ebp " retl\n" // restore pc "1:\n" - : "+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(); return; fail: |