[SOLVED] Keyboard IRQ from IOAPIC seems to be EOIed only when IRQ number is equal to interrupt vector
[SOLVED] Keyboard IRQ from IOAPIC seems to be EOIed only when IRQ number is equal to interrupt vector
Hello there,
I am developing an operating system written in Zig. You can find the bootloader, the kernel and a simple "development environment" in an organization on codeberg: https://codeberg.org/loup-os.
In the kernel, I am currently working on paging. However, I found a solution to an old "bug" which happened to me: the interrupt vector number seems to be misaligned on the stack, so there were always some funny interrupt vector numbers.
As I fixed that bug, remapping the interrupts from the IOAPIC was worth it because now I was able to control those numbers. But now, there are some weird things happening: when I press a key in QEMU (which I use for testing), I get indeed notified "received interrupt 49", which is my offset (48) plus the keyboard IRQ (1). The keyboard handler is able to handle it and get the scan code via port I/O. Then, the handler sends first an EOI signal to the I/O APIC (if you didn't know that, take a look at the linux kernel) and then to the Local APIC. When sending it to the I/O APIC, you need, as far as I know, the IRQ number.
However, I don't get any second keyboard interrupt when sending either the IRQ number or the interrupt vector number. So I retried it using the old version where the keyboard interrupt was mapped to interrupt vector 1 (which isn't a good idea because 1 is already the debug interrupt, but to test it I could do that) and it worked.
If you want to take a look at my current implementation, you should look at the IDT and I/O APIC code. Can anyone here help me?
I am developing an operating system written in Zig. You can find the bootloader, the kernel and a simple "development environment" in an organization on codeberg: https://codeberg.org/loup-os.
In the kernel, I am currently working on paging. However, I found a solution to an old "bug" which happened to me: the interrupt vector number seems to be misaligned on the stack, so there were always some funny interrupt vector numbers.
As I fixed that bug, remapping the interrupts from the IOAPIC was worth it because now I was able to control those numbers. But now, there are some weird things happening: when I press a key in QEMU (which I use for testing), I get indeed notified "received interrupt 49", which is my offset (48) plus the keyboard IRQ (1). The keyboard handler is able to handle it and get the scan code via port I/O. Then, the handler sends first an EOI signal to the I/O APIC (if you didn't know that, take a look at the linux kernel) and then to the Local APIC. When sending it to the I/O APIC, you need, as far as I know, the IRQ number.
However, I don't get any second keyboard interrupt when sending either the IRQ number or the interrupt vector number. So I retried it using the old version where the keyboard interrupt was mapped to interrupt vector 1 (which isn't a good idea because 1 is already the debug interrupt, but to test it I could do that) and it worked.
If you want to take a look at my current implementation, you should look at the IDT and I/O APIC code. Can anyone here help me?
Last edited by sfiedler on Tue Jul 16, 2024 2:27 am, edited 1 time in total.
-
- Member
- Posts: 5568
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Keyboard IRQ from IOAPIC seems to be EOIed only when IRQ number is equal to interrupt vector
Sending an EOI to the IOAPIC is only necessary if you've set the EOI broadcast suppression bit (bit 12) in the Spurious-Interrupt Vector Register in the local APIC. Maybe I've overlooked something, but I don't see any code to access that register.sfiedler wrote: ↑Wed Jul 03, 2024 10:24 amThen, the handler sends first an EOI signal to the I/O APIC (if you didn't know that, take a look at the linux kernel) and then to the Local APIC.
Local APIC EOI broadcast suppression and the IOAPIC EOI register are optional features. You need to make sure both exist before you can use them.
Re: Keyboard IRQ from IOAPIC seems to be EOIed only when IRQ number is equal to interrupt vector
I didn't know that sending the I/O APIC EOI is only needed in special cases, thanks for that!
I took a look (again) at the OSDev Wiki Article about the (local) APIC and set that spurious interrupt vector register to 0xff, as recommended. I also removed the line of code which sends the EOI to the I/O APIC. The issue persists.
EDIT: Just for the sake of knowing it, I set the interrupt vector number to the IRQ number again (so keyboard => interrupt 1) and "deactivated" the debug interrupt (by not handling it). Like magic, it worked! But this isn't a solution.
I took a look (again) at the OSDev Wiki Article about the (local) APIC and set that spurious interrupt vector register to 0xff, as recommended. I also removed the line of code which sends the EOI to the I/O APIC. The issue persists.
EDIT: Just for the sake of knowing it, I set the interrupt vector number to the IRQ number again (so keyboard => interrupt 1) and "deactivated" the debug interrupt (by not handling it). Like magic, it worked! But this isn't a solution.
-
- Member
- Posts: 5568
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Keyboard IRQ from IOAPIC seems to be EOIed only when IRQ number is equal to interrupt vector
Is the IOAPIC configured for edge or level trigger? If it's edge trigger, you need to send the EOI before you read the byte from the PS/2 controller. If it's level trigger, you need to send the EOI after you read the byte.
What state are the interrupt controllers in when it gets stuck? Use "info pic" in the QEMU monitor to check.
What state are the interrupt controllers in when it gets stuck? Use "info pic" in the QEMU monitor to check.
Re: Keyboard IRQ from IOAPIC seems to be EOIed only when IRQ number is equal to interrupt vector
Thanks for that! I knew there was something about those trigger modes but I didn't find much documentation about that in the OSDev wiki.Octocontrabass wrote: ↑Thu Jul 04, 2024 5:09 pm Is the IOAPIC configured for edge or level trigger? If it's edge trigger, you need to send the EOI before you read the byte from the PS/2 controller. If it's level trigger, you need to send the EOI after you read the byte.
Octocontrabass wrote: ↑Thu Jul 04, 2024 5:09 pm What state are the interrupt controllers in when it gets stuck? Use "info pic" in the QEMU monitor to check.
Code: Select all
ioapic0: ver=0x20 id=0x00 sel=0x3f (redir[23])
pin 0 0x0000000000010030 dest=0 vec=48 active-hi edge masked fixed physical
pin 1 0x0000000000000031 dest=0 vec=49 active-hi edge fixed physical
pin 2 0x0000000000010032 dest=0 vec=50 active-hi edge masked fixed physical
pin 3 0x0000000000010033 dest=0 vec=51 active-hi edge masked fixed physical
pin 4 0x0000000000010034 dest=0 vec=52 active-hi edge masked fixed physical
pin 5 0x0000000000010035 dest=0 vec=53 active-hi edge masked fixed physical
pin 6 0x0000000000010036 dest=0 vec=54 active-hi edge masked fixed physical
pin 7 0x0000000000010037 dest=0 vec=55 active-hi edge masked fixed physical
pin 8 0x0000000000010038 dest=0 vec=56 active-hi edge masked fixed physical
pin 9 0x0000000000010039 dest=0 vec=57 active-hi edge masked fixed physical
pin 10 0x000000000001003a dest=0 vec=58 active-hi edge masked fixed physical
pin 11 0x000000000001003b dest=0 vec=59 active-hi edge masked fixed physical
pin 12 0x000000000001003c dest=0 vec=60 active-hi edge masked fixed physical
pin 13 0x000000000001003d dest=0 vec=61 active-hi edge masked fixed physical
pin 14 0x000000000001003e dest=0 vec=62 active-hi edge masked fixed physical
pin 15 0x000000000001003f dest=0 vec=63 active-hi edge masked fixed physical
pin 16 0x0000000000010040 dest=0 vec=64 active-hi edge masked fixed physical
pin 17 0x0000000000010041 dest=0 vec=65 active-hi edge masked fixed physical
pin 18 0x0000000000010042 dest=0 vec=66 active-hi edge masked fixed physical
pin 19 0x0000000000010043 dest=0 vec=67 active-hi edge masked fixed physical
pin 20 0x0000000000010044 dest=0 vec=68 active-hi edge masked fixed physical
pin 21 0x0000000000010045 dest=0 vec=69 active-hi edge masked fixed physical
pin 22 0x0000000000010046 dest=0 vec=70 active-hi edge masked fixed physical
pin 23 0x0000000000010047 dest=0 vec=71 active-hi edge masked fixed physical
IRR (none)
Remote IRR (none)
-
- Member
- Posts: 5568
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Keyboard IRQ from IOAPIC seems to be EOIed only when IRQ number is equal to interrupt vector
The IOAPIC status looks reasonable, but what about the local APIC?
Re: Keyboard IRQ from IOAPIC seems to be EOIed only when IRQ number is equal to interrupt vector
"info lapic" puts out:Octocontrabass wrote: ↑Fri Jul 05, 2024 2:36 pm The IOAPIC status looks reasonable, but what about the local APIC?
Code: Select all
dumping local APIC state for CPU 0
LVT0 0x00000700 active-hi edge ExtINT (vec 0)
LVT1 0x00000400 active-hi edge NMI
LVTPC 0x00010000 active-hi edge masked Fixed (vec 0)
LVTERR 0x00010000 active-hi edge masked Fixed (vec 0)
LVTTHMR 0x00010000 active-hi edge masked Fixed (vec 0)
LVTT 0x00030020 active-hi edge masked periodic Fixed (vec 32)
Timer DCR=0xb (divide by 1) initial_count = 10000000 current_count = 2125649
SPIV 0x0000010f APIC enabled, focus=off, spurious vec 15
ICR 0x00000000 physical edge de-assert no-shorthand
ICR2 0x00000000 cpu 0 (APIC ID)
ESR 0x00000000
ISR 49
IRR 49
APR 0x00 TPR 0x00 DFR 0x0f LDR 0x00 PPR 0x30
-
- Member
- Posts: 5568
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Keyboard IRQ from IOAPIC seems to be EOIed only when IRQ number is equal to interrupt vector
The local APIC hasn't received your EOI.
The local APIC accepts only aligned 32-bit reads and writes. Anything else is undefined behavior.
Re: Keyboard IRQ from IOAPIC seems to be EOIed only when IRQ number is equal to interrupt vector
When I simply change the types to "u32", everything stops working. But in my paging code (which I enabled locally), physFromVirt returns null for the Local APIC base. Mapping any page creates a page fault. Now, at least I have something I can work on .
EDIT: physFromVirt returning null was a wrong "else" in my program (I had a double if and the else should have been in the first branch, but I had it in the second), now it's fixed and it returns 0xfdc0000000. Only thing is: I don't know what I should do with that…
EDIT: physFromVirt returning null was a wrong "else" in my program (I had a double if and the else should have been in the first branch, but I had it in the second), now it's fixed and it returns 0xfdc0000000. Only thing is: I don't know what I should do with that…
Re: Keyboard IRQ from IOAPIC seems to be EOIed only when IRQ number is equal to interrupt vector
And now I gave my OS just some time without doing anything in my OS, and it just works!