PCI PIC IRQs

Discussions about using non Windows and Linux guests such as FreeBSD, DOS, OS/2, OpenBSD, etc.
Post Reply
Ch40zz
Posts: 7
Joined: 4. Mar 2016, 16:35

PCI PIC IRQs

Post by Ch40zz »

Hello!
Im using Virtualbox on my Windows Host to code my own Operating System.
Im testing it on many different virtual machines and I've got a problem with it on Virtualbox.

The problem:
My OS is using different PCI devices.
I used the status code of the PCI devices to make sure the interrupt was triggered from this particular device in my interrupt handler incase the BIOS maps the IRQs to the same offset (0xA/0xB..)
Virtualbox BIOS is nice and maps all 3 devices to 3 different IRQs so no IRQ sharing is happening.
The problem is, I still have to check whether a device has triggered that particular IRQ or not.
I made sure my code is correct by testing it on QEMU and VMWare, both set the 3rd bit (0x8) as expected but Virtualbox doesnt, which results in unhandled IRQs.

Thanks for your time and thanks in advance!
Last edited by Ch40zz on 5. Mar 2016, 01:02, edited 1 time in total.
mpack
Site Moderator
Posts: 39134
Joined: 4. Sep 2008, 17:09
Primary OS: MS Windows 10
VBox Version: PUEL
Guest OSses: Mostly XP

Re: PCI PIC IRQs

Post by mpack »

What does this question have to do with "Windows Hosts"? Moving it to "Other Guests".
michaln
Oracle Corporation
Posts: 2973
Joined: 19. Dec 2007, 15:45
Primary OS: MS Windows 7
VBox Version: PUEL
Guest OSses: Any and all
Contact:

Re: PCI PIC IRQs

Post by michaln »

What's an "IRQ offset"? What's "3rd flag"?

FYI, "this code works on qemu and VMware" is very far from "this code is correct". Try it on real hardware to get some idea whether it actually works or not. It's possible to write quite broken code that still runs in VMs.
Ch40zz
Posts: 7
Joined: 4. Mar 2016, 16:35

Re: PCI PIC IRQs

Post by Ch40zz »

Well, thanks for the replies.
Im 100% sure it works because Im just reading a 2 byte value, and everything else is correct (all the other data I read from PCI devices, on all vms).
With IRQ offset I meant the offset from a remapped base IRQ (in my case 0x20) because I remapped the IRQs above exceptions.
3rd flag was a typo, I meant third bit, which is the Interrupt Status.
michaln
Oracle Corporation
Posts: 2973
Joined: 19. Dec 2007, 15:45
Primary OS: MS Windows 7
VBox Version: PUEL
Guest OSses: Any and all
Contact:

Re: PCI PIC IRQs

Post by michaln »

Okay, so if you're so convinced your code is correct, what exactly is the VirtualBox bug? And for bonus points, why does Windows/Linux/Solaris/etc. not have a problem with it... If you could point to the code in VirtualBox that you believe is wrong, that would be wonderful.

You seem to be assuming that it must be obvious to everyone what you're talking about. Well, it's not. If you could show some actual code, that would probably clarify things considerably.

I'm not saying you're wrong, I just don't understand what it is you're trying to say. I am however going to make a bold guess that someone calling themselves 'Chaozz' in 1337-speak does not have a whole lot of experience with reporting software problems.
Ch40zz
Posts: 7
Joined: 4. Mar 2016, 16:35

Re: PCI PIC IRQs

Post by Ch40zz »

Well theres not too much to add but I will summarize it again to make it more clear.
The computer has got a PIC which notifies me when an interrupt occurs.
PCI devices can get 4 different IRQs assigned, depending on the BIOS.
Those PCI devices have a special structure:

Image

In my PCI driver Im reading this data to parse it with my device drivers.
When an interrupt occurs, the 3rd bit in the status register will normally be set for the device which triggered it (word@0x6).
In Virtualbox this bit is never set, even when this device just triggered an interrupt.

So why this doesnt effect other OS'?
Because modern OS' use ACPI and AML to get this information which is just insane for a hobby OS.

Heres a little code that Im using in the interrupt handler for each device:

Code: Select all

uint16_t status = pci_read_word(device.bus, device.slot, device.function, 6);
if(!(status & (1 << 3)))
	return false;
And the actual readfunction:

Code: Select all

uint16_t pci_read_word(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset)
{
	uint32_t address = (uint32_t)(((uint32_t)lbus << 16) | ((uint32_t)lslot << 11) | ((uint32_t)lfunc << 8) | ((uint32_t)offset & 0xFC) | 0x80000000);
	outl(0xCF8, address);
	
	return (uint16_t)((inl(0xCFC) >> ((offset & 2) * 8)) & 0xFFFF);
}
As you can see, when the third bit is not set (aka no interrupt occured for this device) I will simply return from the handler.
The handler is called for all devices which were registered to the occured IRQ.
Last edited by mpack on 5. Mar 2016, 11:58, edited 1 time in total.
Reason: Replace partial image link with URL.
michaln
Oracle Corporation
Posts: 2973
Joined: 19. Dec 2007, 15:45
Primary OS: MS Windows 7
VBox Version: PUEL
Guest OSses: Any and all
Contact:

Re: PCI PIC IRQs

Post by michaln »

OK, now I understand what you're talking about. Thanks for clearing it up. You're reading the status register in the device's PCI configuration space. That's very interesting.

This has zilch to do with ACPI. You can disable ACPI in VirtualBox and observe that Windows, Linux, etc. will happily keep working. The reason of course is that they never look at the PCI status register to check for pending interrupts. And the reason no OS looks at those bits is that this bit was not defined at all up to and including PCI specification 2.2. So... for any device confirming to PCI 2.2 or older, this approach has zero chance of working.

The other problem is that even when a device supports PCI 2.3 or newer, the interrupt status bit is read-only. So it needs to be cleared somewhere else, in some device-specific register... which probably also provides the pending interrupt information. So poking around the status register in the config space is a waste of time even when the status bit is actually there.
Ch40zz
Posts: 7
Joined: 4. Mar 2016, 16:35

Re: PCI PIC IRQs

Post by Ch40zz »

Thanks for the answer.
How should I determinate which device triggered which IRQ then?
Osdev had an article about it and stated that I have to use the APIC combined with ACPI incase the BIOS remapped the IRQs.

EDIT: It looks like all new OS' are using the IO-APIC.
When I disable it in Virtualbox Windows and Linux just crash, so I will look into that.
Thanks for the answer :)
michaln
Oracle Corporation
Posts: 2973
Joined: 19. Dec 2007, 15:45
Primary OS: MS Windows 7
VBox Version: PUEL
Guest OSses: Any and all
Contact:

Re: PCI PIC IRQs

Post by michaln »

Ch40zz wrote:How should I determinate which device triggered which IRQ then?
You need some device-specific code (i.e. a driver) which understands a given device's registers and can determine whether an interrupt is pending and handle it. If you ask me about a specific device I can tell you how to check for pending interrupts.
When I disable it in Virtualbox Windows and Linux just crash, so I will look into that.
That very much depends on which version of Windows/Linux you're talking about. Some require an I/O APIC, some don't (generally 64-bit versions require I/O APIC and 32-bit don't). And some can handle changes after installation and some can't (XP is especially bad).
Ch40zz
Posts: 7
Joined: 4. Mar 2016, 16:35

Re: PCI PIC IRQs

Post by Ch40zz »

Thanks alot!
Im using The AC97 soundcard and the AMD PCnet fast III (Am79C973).
How can I identify which IRQ came from which of those 2 devices?
Couldn't find any info about that specific question anywhere :(
michaln
Oracle Corporation
Posts: 2973
Joined: 19. Dec 2007, 15:45
Primary OS: MS Windows 7
VBox Version: PUEL
Guest OSses: Any and all
Contact:

Re: PCI PIC IRQs

Post by michaln »

You must not have been looking very hard :) For the Intel AC'97 controller, you need the Intel ICH 2 or so datasheet. For the PCnet, you need the Am79C973 datasheet.

For Intel AC'97, the GLOB_STA register (NABMBAR + 30h) contains interrupt status bits. The interrupts must be cleared by writing the corresponding x_SR register (NABMBAR + 06h/16h/26h).

For the PCnet, register CSR0 bit 7 (INTR) is the aggregate interrupt flag. To clear it, all individual pending interrupt sources must be checked/cleared (listed in the documentation). Those bits are in CSR0 and CSR7.
Ch40zz
Posts: 7
Joined: 4. Mar 2016, 16:35

Re: PCI PIC IRQs

Post by Ch40zz »

michaln wrote:You must not have been looking very hard :) For the Intel AC'97 controller, you need the Intel ICH 2 or so datasheet. For the PCnet, you need the Am79C973 datasheet.

For Intel AC'97, the GLOB_STA register (NABMBAR + 30h) contains interrupt status bits. The interrupts must be cleared by writing the corresponding x_SR register (NABMBAR + 06h/16h/26h).

For the PCnet, register CSR0 bit 7 (INTR) is the aggregate interrupt flag. To clear it, all individual pending interrupt sources must be checked/cleared (listed in the documentation). Those bits are in CSR0 and CSR7.
Oh Im totally dumb :D
I thought theres another global way for those devices, but actually Im using BOTH of the mentioned ways already.
Just have to add 2 lines and it works perfectly, thanks alot!
michaln
Oracle Corporation
Posts: 2973
Joined: 19. Dec 2007, 15:45
Primary OS: MS Windows 7
VBox Version: PUEL
Guest OSses: Any and all
Contact:

Re: PCI PIC IRQs

Post by michaln »

Glad to hear that.

Note that the AMD PCnet-FAST III is actually a PCI 2.2 compliant device. If the PCnet's PCI status register really reports interrupts in qemu and/or VMware, they're doing it wrong because the datasheet clearly says bit 3 is hardwired to zero and has no function.

The same is actually true of the ICH AC'97 PCI status register. Bit 3 is documented by Intel as having no function. So... that's why you can't use it for anything :)
Ch40zz
Posts: 7
Joined: 4. Mar 2016, 16:35

Re: PCI PIC IRQs

Post by Ch40zz »

michaln wrote:Glad to hear that.

Note that the AMD PCnet-FAST III is actually a PCI 2.2 compliant device. If the PCnet's PCI status register really reports interrupts in qemu and/or VMware, they're doing it wrong because the datasheet clearly says bit 3 is hardwired to zero and has no function.

The same is actually true of the ICH AC'97 PCI status register. Bit 3 is documented by Intel as having no function. So... that's why you can't use it for anything :)
Makes sense, just weird they both failed to implement it as real hardware behaves..
Thanks for the help, learned another lesson when reading data sheets :D
Post Reply