AHCI interrupt is 255? (VirtualBox; EFI boot)

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
nakst
Member
Member
Posts: 51
Joined: Sun Jan 17, 2016 7:57 am

AHCI interrupt is 255? (VirtualBox; EFI boot)

Post by nakst »

Hello,

When I boot my operating system in VirtualBox using BIOS boot, the PCI configuration space reports the interrupt pin to be 1 and the interrupt line to be 11.
However when I use UEFI to boot the kernel, the interrupt line is reported as 255, which I don't think is possible? (I've called ExitBootServices, I don't think the UEFI firmware should be messing with anything..?)
My ATA driver functions fine with both BIOS and UEFI boot.

It's possible I might be overwriting something in my UEFI bootloader, or it's possible I'm just missing something obvious.

Does anyone know what might be happening and, if so, what I can do fix it?
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: AHCI interrupt is 255? (VirtualBox; EFI boot)

Post by nullplan »

Wiki wrote:Interrupt Line: Specifies which input of the system interrupt controllers the device's interrupt pin is connected to and is implemented by any device that makes use of an interrupt pin. For the x86 architecture this register corresponds to the PIC IRQ numbers 0-15 (and not I/O APIC IRQ numbers) and a value of 0xFF defines no connection.
OK, so somehow in UEFI mode you're not connected to an IRQ. I would suggest looking up the ACPI tables for this. It is possible the value is simply not initialized in UEFI mode. In BIOS mode it would make sense for older OSes to use the old PIC pair, and therefore for BIOS to set up the interrupt line value, but in UEFI mode you are all but required to use ACPI, which contains the pin routing tables. I am not totally familiar with all this, but I think you need to run a method call _PIC with an argument of 0 if you use the PIC or 1 if you use the APIC, and then run the correct _PRT method. I just have no idea how to find the correct _PRT method.

Anyway, the _PRT method will return return a weird data structure telling you which interrupt pin corresponds to which global interrupt number. If you use the PIC pair, that's the same as the IRQ number. For APIC you might need to look up, which APIC is meant from the MADT, if you have more than one I/O APIC.
Carpe diem!
User avatar
nakst
Member
Member
Posts: 51
Joined: Sun Jan 17, 2016 7:57 am

Re: AHCI interrupt is 255? (VirtualBox; EFI boot)

Post by nakst »

Okay, so I'm now getting the interrupt line information from the ACPI tables, using ACPICA.

(Side note: the newest version of VirtualBox now reports the interrupt line as 10 instead of 255, despite still sending it to a different line :shock: )

This is what I'm doing:
  • Look up the "\_SB_.PCI0" device.
  • Call "_PRT" on it using "AcpiGetIrqRoutingTable".
  • For each entry, call "_CRS" on the source device using "AcpiGetCurrentResources". Record the first interrupt from the resource list, and store it as follows

    Code: Select all

    pciIRQLines[prtTableEntry->Address >> 16][prtTableEntry->Pin] = interrupt;
  • (I note that there is an entry for each of the 4 pins for each device slot.)
  • Then to determine the corresponding interrupt line for a PCI device,

    Code: Select all

    uint8_t mappedLine = pciIRQLines[pciDevice->slot][pciDevice->interruptPin - 1];
This appears to get the right interrupts in Qemu and VirtualBox, although I haven't tested it on real hardware yet.

However, I'm concerned by the following statement in the Wiki's article on PCI:
With time manufacturers started to use mainly INTA#, forgetting the existence of other pins. So you will likely have 18 devices on INTA# and 2 on INTB#. Motherboard manufacturers decided take the situation in control. So at boot the INTx# are remapped, so that you will have 5 devices for INTA#, 5 for INTB#, 5 for INTC#, and 5 for INTD# (in the best case). That's great! IRQs are balanced and IRQ sharing is reduced. The only problem is that you don't know what devices where mapped. If you read the Interrupt Pin you still get INTA#. You now need to parse the MP Tables or the ACPI ones to solve the mess. Good luck.
Is this accurate? If so, where do I get this information from?

As noted earlier, the IRQ routing table from ACPI gives me a different entry for each pin. Is perhaps using the pin given in the PCI table to select the entry from the routing table already doing what this is referring to?

Thanks.
Post Reply