On Mon, Sep 15, 2014 at 08:02:04PM +0200, Laszlo Ersek wrote: > >> It is actually extremely relevant, the irq_pin field. I'm not exactly > >> sure how just yet, but it is. Maybe check the interrupt routing in OSX > >> somehow? Do you have a dmesg-like log in OSX, with a PRT dump from the > >> DSDT, and messages about interrupt routing setup? Do you have in OSX > >> anything that corresponds to /proc/interrupts under Linux? > > > > Actually, even more exciting: > > > > diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c > > index 3b3ebcd..d61656e 100644 > > --- a/hw/usb/hcd-uhci.c > > +++ b/hw/usb/hcd-uhci.c > > @@ -1335,21 +1335,21 @@ static UHCIInfo uhci_info[] = { > > .vendor_id = PCI_VENDOR_ID_INTEL, > > .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1, > > .revision = 0x03, > > - .irq_pin = 0, > > + .irq_pin = 1, > > .unplug = false, > > },{ > > .name = "ich9-usb-uhci2", /* 00:1d.1 */ > > .vendor_id = PCI_VENDOR_ID_INTEL, > > .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2, > > .revision = 0x03, > > - .irq_pin = 1, > > + .irq_pin = 2, > > .unplug = false, > > },{ > > .name = "ich9-usb-uhci3", /* 00:1d.2 */ > > .vendor_id = PCI_VENDOR_ID_INTEL, > > .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3, > > .revision = 0x03, > > - .irq_pin = 2, > > + .irq_pin = 3, > > .unplug = false, > > },{ > > .name = "ich9-usb-uhci4", /* 00:1a.0 */ > > > > Turns out, anything with an irq_pin <= 1 won't show up when osx is > > booted on q35 with ovmf (but osx + q35 works if booted via Chameleon).
OK, so I forgot to articulate that with the above patch, I'm seeing *both* uhci2 and uhci3, but not uhci1. Basically, if uhciX has an irq_pin less than 2, it won't show up in OSX if booted with ovmf. We're no longer looking at PIIX, this is q35 with ovmf or without. > > > > DSDT looks identical across the ovmf vs. chameleon divide. > > Now I'm curious. What's this chameleon thing? (Yes, I did find the > homepage. Apparently the lead developer is a fellow Hungarian. A small > world.) I'm surprised how you can get the same DSDT under both OVMF and > chameleon. Assuming you run a recent OVMF on a recent QEMU, the DSDT > exposed to the guest will originate from QEMU. This is confirmed by your > q35.log that you sent me in private (due to its size) previously: > ... > > I've got no clue how you can end up with the exact same DSDT under > chameleon, unless it has a client for QEMU's fw_cfg ACPI linker/loader. Chameleon is a multistage bootloader which can be started by a PC-BIOS based machine, and which can then load OSX's /mach_kernel file from the root directory of the main HFS+ partition (as opposed to loading and running /System/Library/CoreServices/boot.efi, which is how an EFI compatible BIOS would do it natively. With qemu, I'm "side-loading" Chameleon's stage-2 loader. I.e., I won't bother loading all the stages via the bios from the hard drive. Instead, I add "-kernel chameleon_stage2_loader" to the qemu command line, which bypasses all earlier stages. While Chameleon *can* override the DSDT of its underlying machine by accessing a .plist config file dropped into the root of the OS X file system (i.e., that's how it's done on a hackintosh), in my case I don't need to do that, as QEMU already provides a perfectly adequate DSDT, so Chameleon just leaves it alone and proceeds to boot the mach kernel. I downloaded a DSDT ripper for the Mac (DSDTEditor_Mac.zip) I found via from some forum or another (insanelymac.com or osx86project.org or tonymacx86.com, don't remember precisely anymore) and dumped the DSDT from inside OSX after having booted it with Chameleon-on-top-of-SeaBIOS on one hand, or OVMF on the other. They look identical. It's just that when using ovmf, the uhci irq_pin less-than-two invisibility thing kicks in for some weird reason I'm still looking for :) > In fact I think that should be *precisely* the difference here. The PCI > interrupt routing table (_PRT) in the DSDT describes a two-level > mapping. (I've probably forgotten most of the details, sorry.) First, it > maps each PCI (bus, dev, pin) triplet to a PNP0C0F ("PCI interrupt > link") device. We usually call these LNKA, LNKB, LNC, LNKD, LNKS on > i440fx; there are more on q35. Then, each LNKx specifies a set of > possible legacy interrupts that the link can be programmed for / > assigned to. At runtime, the OS programs each of the interrupt links to > one of its allowed legacy interrupts, and then all the pins (across > buses and functions) that are connected to that interrupt link will > trigger that interrupt. The OS usually tries to come up with a mapping > (from LNKx to IRQ) so that interrupt sharing is minimized. > > Here's an example from my i440fx Fedora 20 VM. > > (1) The dmesg says first > > ACPI: PCI Interrupt Link [LNKA] (IRQs 5 10 *11) > ACPI: PCI Interrupt Link [LNKB] (IRQs 5 10 *11) > ACPI: PCI Interrupt Link [LNKC] (IRQs 5 *10 11) > ACPI: PCI Interrupt Link [LNKD] (IRQs 5 *10 11) > ACPI: PCI Interrupt Link [LNKS] (IRQs *9) > > This displays what IRQs the _PRT in the DSDT allows for each of the LNKx > links, and the asterisks show (IIRC) what elements of those sets are > selected (programmed) when Linux inherits the hardware. > > (2) Later it logs > > ACPI: PCI Interrupt Link [LNKC] enabled at IRQ 10 > ACPI: PCI Interrupt Link [LNKD] enabled at IRQ 11 > ACPI: PCI Interrupt Link [LNKA] enabled at IRQ 11 > ACPI: PCI Interrupt Link [LNKB] enabled at IRQ 10 > > Let's call this mapping LNK_IRQ(). > > (3) Then look for the uchi controllers: > > uhci_hcd 0000:00:07.0: irq 10, io base 0x0000c0c0 > uhci_hcd 0000:00:07.1: irq 11, io base 0x0000c0a0 > uhci_hcd 0000:00:07.2: irq 11, io base 0x0000c080 > > And /proc/interrupts is consistent with that: > > CPU0 CPU1 > 10: 6 25 IO-APIC-fasteoi ehci_hcd:usb1, uhci_hcd:usb2 > 11: 0 0 IO-APIC-fasteoi uhci_hcd:usb3, > uhci_hcd:usb4, virtio2 > > These last two blocks are *results*. > > Again, this is the result of composing two functions: > > device_interrupt = LNK_IRQ(PRT(bus, dev, pin)) > > PRT() comes from the DSDT, and maps (bus, dev, pin) to a link, while > LNK_IRQ() comes from the OS (the actual link -> IRQ assignment), and is > restricted to the possibilities offered in the DSDT. > > The PRT that QEMU generates follows a rotating pattern (it is not > restricted by physical circuits). As you go from one PCI device to the > next, the same LNKA - LNKD links are distributed over the device's pins, > but the sequence is shifted by one. The idea is that most PCI devices > use only their first pin (INTA), and placing such devices "beside" each > other should nicely iterate over all links, evenly. > > Thus far I didn't speak about functions of the same PCI device. I didn't > do that because I'm uneducated (even more than in the above :)). The > basic idea is that different functions of the device will use different > pins. Most devices are single-function, hence they usually stick with > INTA. If you've got a multifunction device, then the functions will use > separate pins. > > For example, if I dump and decompile the DSDT in the guest, for bus 0 > device 7, I get, from the PRT: > > Package (0x04) { 0x0007FFFF, Zero, LNKC, Zero }, <-- pin 0 / INTA > Package (0x04) { 0x0007FFFF, One, LNKD, Zero }, <-- pin 1 / INTB > Package (0x04) { 0x0007FFFF, 0x02, LNKA, Zero }, <-- pin 2 / INTC > Package (0x04) { 0x0007FFFF, 0x03, LNKB, Zero }, <-- pin 3 / INTD > > Let's put it all together, for a QEMU command line with > > -device > ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x7 > -device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,addr=0x7.0x1 > -device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,addr=0x7.0x2 > > dev & func, pin, set interrupt link IRQ programmed > set on qemu in qemu for dev & pin, by Linux for > cmdline source set in DSDT link > ----------- -------- -------------- -------------- > 07.0 0 LNKC 10 > 07.1 1 LNKD 11 > 07.2 2 LNKA 11 > > The first two columns are input parameters (from the command line and > from the source code). The third colum is the result of evaluating PRT() > on the input params. The fourth column is the result of evaluating > Linux's LNK_IRQ() function on the third column. > > (Note that all of the above is for i440fx, not q35, but the method is > similar.) Thanks for this crash course, this is really useful stuff to know! > Ultimately, I think that the difference between OVMF and chameleon is > the following: when booting OSX with chameleon, QEMU's rotating _PRT is > not exposed to OSX, because chameleon doesn't know how to download and > interpret the necessary fw_cfg blobs. (What _PRT OSX decides to use > then, I can't imagine.) But when you boot OSX with OVMF, then QEMU's > _PRT is exposed to OSX, and OSX, seeing the PCI bus/device/func > addresses of the UHCI controllers, *and* seeing their respective PINs, > *and* seeing their respective LNKx links (from the DSDT), maps the > function to some interrupt that kills the device. > > This is consistent with your results (if you change the PINs in the > source code, things work). It would be interesting to see what happens > if you shuffle the PCI addresses of the UHCI controllers. > > ... Hm. You did mention in the thread starter that chameleon runs on top > of SeaBIOS. SeaBIOS does have an ACPI linker/loader client, which would > explain why you see the same DSDT. The only thing that could differ > between the two cases is the LNK_IRQ() assignment then (ie. how OSX > chooses to map PCI interrupt links to IRQs), and I don't know why that > would be different. A /proc/interrupts table would be useful, again. > > (Sorry about all the crazy errors I must have said above about PCI, ACPI > etc etc etc. Even if it turns out to be incorrect to some degree, if it > helps others help you, then it wasn't in vain.) Since the DSDT as seen by the guest is identical regardless of whether I boot via ovmf or seabios+chameleon, I assume the results of all these mappings should end up being the same. I'll look for as close an equivalent of "cat /proc/interrupts" on os x as I can find, and try to sanity-check this assumption. Thanks, --Gabriel