aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVolker RĂ¼melin <vr_qemu@t-online.de>2021-06-04 20:01:19 +0200
committerKevin O'Connor <kevin@koconnor.net>2021-06-09 11:05:18 -0400
commitf501bcbeef616c40125889b657f7ff42eeec8a8d (patch)
tree9c8d1ee61c4690fcca7fa5cee9e064c03aa3e28c
parent7292e4a0a8f58333ccbd2d0d47242f9865083c9c (diff)
downloadseabios-hppa-f501bcbeef616c40125889b657f7ff42eeec8a8d.zip
seabios-hppa-f501bcbeef616c40125889b657f7ff42eeec8a8d.tar.gz
seabios-hppa-f501bcbeef616c40125889b657f7ff42eeec8a8d.tar.bz2
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.c8
1 files changed, 7 insertions, 1 deletions
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 @@ __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: