PCI: info qtree v/s brute force enumeration

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
sunnysideup
Member
Member
Posts: 106
Joined: Sat Feb 08, 2020 11:11 am
Libera.chat IRC: sunnysideup

PCI: info qtree v/s brute force enumeration

Post by sunnysideup »

I have written a simple PCI driver (nothing fancy... Just reads and writes to PCI config space and a function for brute force enumeration).

My brute force enumeration gives me this (I do the bus*device loops, and ignore reads which give me all 1s):

Code: Select all

Bus: 0x0	Slot: 0x0	Vendor: 0x8086	Device: 0x1237	Class: 0x6	Subclass: 0x0	Header: 0x0
Bus: 0x0	Slot: 0x1	Vendor: 0x8086	Device: 0x7000	Class: 0x6	Subclass: 0x1	Header: 0x80
Bus: 0x0	Slot: 0x2	Vendor: 0x1234	Device: 0x1111	Class: 0x3	Subclass: 0x0	Header: 0x0
Bus: 0x0	Slot: 0x3	Vendor: 0x8086	Device: 0x100E	Class: 0x2	Subclass: 0x0	Header: 0x0
I wanted to check the validity of this, and did a `info qtree` on my qemu console.

Code: Select all

bus: main-system-bus
  type System
  dev: hpet, id ""
    gpio-in "" 2
    gpio-out "" 1
    gpio-out "sysbus-irq" 32
    timers = 3 (0x3)
    msi = false
    hpet-intcap = 4 (0x4)
    hpet-offset-saved = true
    mmio 00000000fed00000/0000000000000400
  dev: ioapic, id ""
    gpio-in "" 24
    version = 32 (0x20)
    mmio 00000000fec00000/0000000000001000
  dev: i440FX-pcihost, id ""
    pci-hole64-size = 2147483648 (2 GiB)
    short_root_bus = 0 (0x0)
    x-pci-hole64-fix = true
    x-config-reg-migration-enabled = true
    bus: pci.0
      type PCI
      dev: PIIX4_PM, id ""
        smb_io_base = 1792 (0x700)
        disable_s3 = 0 (0x0)
        disable_s4 = 0 (0x0)
        s4_val = 2 (0x2)
        acpi-pci-hotplug-with-bridge-support = true
        memory-hotplug-support = true
        addr = 01.3
        romfile = ""
        rombar = 1 (0x1)
        multifunction = false
        x-pcie-lnksta-dllla = true
        x-pcie-extcap-init = true
        failover_pair_id = ""
        class Bridge, addr 00:01.3, pci id 8086:7113 (sub 1af4:1100)
        bus: i2c
          type i2c-bus
          dev: smbus-eeprom, id ""
            address = 87 (0x57)
          dev: smbus-eeprom, id ""
            address = 86 (0x56)
          dev: smbus-eeprom, id ""
            address = 85 (0x55)
          dev: smbus-eeprom, id ""
            address = 84 (0x54)
          dev: smbus-eeprom, id ""
            address = 83 (0x53)
          dev: smbus-eeprom, id ""
            address = 82 (0x52)
          dev: smbus-eeprom, id ""
            address = 81 (0x51)
          dev: smbus-eeprom, id ""
            address = 80 (0x50)
      dev: piix3-ide, id ""
        addr = 01.1
        romfile = ""
        rombar = 1 (0x1)
        multifunction = false
        x-pcie-lnksta-dllla = true
        x-pcie-extcap-init = true
        failover_pair_id = ""
        class IDE controller, addr 00:01.1, pci id 8086:7010 (sub 1af4:1100)
        bar 4: i/o at 0xc040 [0xc04f]
        bus: ide.1
          type IDE
          dev: ide-cd, id ""
            drive = "ide1-cd0"
            logical_block_size = 512 (512 B)
            physical_block_size = 512 (512 B)
            min_io_size = 0 (0 B)
            opt_io_size = 0 (0 B)
            discard_granularity = 512 (512 B)
            write-cache = "auto"
            share-rw = false
            rerror = "auto"
            werror = "auto"
            ver = "2.5+"
            wwn = 0 (0x0)
            serial = "QM00003"
            model = ""
            unit = 0 (0x0)
        bus: ide.0
          type IDE
      dev: e1000, id ""
        mac = "52:54:00:12:34:56"
        netdev = "hub0port0"
        autonegotiation = true
        mitigation = true
        extra_mac_registers = true
        migrate_tso_props = true
        addr = 03.0
        romfile = "efi-e1000.rom"
        rombar = 1 (0x1)
        multifunction = false
        x-pcie-lnksta-dllla = true
        x-pcie-extcap-init = true
        failover_pair_id = ""
        class Ethernet controller, addr 00:03.0, pci id 8086:100e (sub 1af4:1100)
        bar 0: mem at 0xfebc0000 [0xfebdffff]
        bar 1: i/o at 0xc000 [0xc03f]
        bar 6: mem at 0xffffffffffffffff [0x3fffe]
      dev: VGA, id ""
        vgamem_mb = 16 (0x10)
        mmio = true
        qemu-extended-regs = true
        edid = true
        xres = 1024 (0x400)
        yres = 768 (0x300)
        xmax = 0 (0x0)
        ymax = 0 (0x0)
        global-vmstate = false
        addr = 02.0
        romfile = "vgabios-stdvga.bin"
        rombar = 1 (0x1)
        multifunction = false
        x-pcie-lnksta-dllla = true
        x-pcie-extcap-init = true
        failover_pair_id = ""
        class VGA controller, addr 00:02.0, pci id 1234:1111 (sub 1af4:1100)
        bar 0: mem at 0xfd000000 [0xfdffffff]
        bar 2: mem at 0xfebf0000 [0xfebf0fff]
        bar 6: mem at 0xffffffffffffffff [0xfffe]
      dev: PIIX3, id ""
        addr = 01.0
        romfile = ""
        rombar = 1 (0x1)
        multifunction = true
        x-pcie-lnksta-dllla = true
        x-pcie-extcap-init = true
        failover_pair_id = ""
        class ISA bridge, addr 00:01.0, pci id 8086:7000 (sub 1af4:1100)
        bus: isa.0
          type ISA
          dev: port92, id ""
            gpio-out "a20" 1
          dev: vmmouse, id ""
          dev: vmport, id ""
            x-read-set-eax = true
            x-signal-unsupported-cmd = true
            x-report-vmx-type = true
            x-cmds-v2 = true
            vmware-vmx-version = 6 (0x6)
            vmware-vmx-type = 2 (0x2)
          dev: i8042, id ""
            gpio-out "a20" 1
            isa irqs 1,12
          dev: isa-fdc, id ""
            iobase = 1008 (0x3f0)
            irq = 6 (0x6)
            dma = 2 (0x2)
            driveA = ""
            driveB = ""
            check_media_rate = true
            fdtypeA = "auto"
            fdtypeB = "auto"
            fallback = "288"
            isa irq 6
            bus: floppy-bus.0
              type floppy-bus
              dev: floppy, id ""
                unit = 0 (0x0)
                drive = "floppy0"
                logical_block_size = 512 (512 B)
                physical_block_size = 512 (512 B)
                min_io_size = 0 (0 B)
                opt_io_size = 0 (0 B)
                discard_granularity = 4294967295 (4 GiB)
                write-cache = "auto"
                share-rw = false
                drive-type = "288"
          dev: isa-parallel, id ""
            index = 0 (0x0)
            iobase = 888 (0x378)
            irq = 7 (0x7)
            chardev = "parallel0"
            isa irq 7
          dev: isa-serial, id ""
            index = 0 (0x0)
            iobase = 1016 (0x3f8)
            irq = 4 (0x4)
            chardev = "serial0"
            wakeup = 0 (0x0)
            isa irq 4
          dev: i8257, id ""
            base = 192 (0xc0)
            page-base = 136 (0x88)
            pageh-base = -1 (0xffffffffffffffff)
            dshift = 1 (0x1)
          dev: i8257, id ""
            base = 0 (0x0)
            page-base = 128 (0x80)
            pageh-base = -1 (0xffffffffffffffff)
            dshift = 0 (0x0)
          dev: isa-pcspk, id ""
            audiodev = ""
            iobase = 97 (0x61)
            migrate = true
          dev: isa-pit, id ""
            gpio-in "" 1
            gpio-out "" 1
            iobase = 64 (0x40)
          dev: mc146818rtc, id ""
            gpio-out "" 1
            base_year = 0 (0x0)
            lost_tick_policy = "discard"
          dev: isa-i8259, id ""
            gpio-in "" 8
            gpio-out "" 1
            iobase = 160 (0xa0)
            elcr_addr = 1233 (0x4d1)
            elcr_mask = 222 (0xde)
            master = false
          dev: isa-i8259, id ""
            gpio-in "" 8
            gpio-out "" 1
            iobase = 32 (0x20)
            elcr_addr = 1232 (0x4d0)
            elcr_mask = 248 (0xf8)
            master = true
      dev: i440FX, id ""
        addr = 00.0
        romfile = ""
        rombar = 1 (0x1)
        multifunction = false
        x-pcie-lnksta-dllla = true
        x-pcie-extcap-init = true
        failover_pair_id = ""
        class Host bridge, addr 00:00.0, pci id 8086:1237 (sub 1af4:1100)
  dev: fw_cfg_io, id ""
    dma_enabled = true
    x-file-slots = 32 (0x20)
    acpi-mr-restore = true
  dev: kvmvapic, id ""
If my interpretation is correct, my brute force function shows the i440FX as a device (I thought it was supposed to be a bridge device? The header must be 0x1? Since it is the host bridge (not PCI-PCI or PCI-Cardbus bridge, I'm guessing that the header is of type 0?)
We also have the PIIX3, which is shown as a multifunction PCI device.
We have the qemu VGA device, and the ethernet controller.

* Why aren't the PIIX3-ide device, and the PIIX4_PM shown? Does it look like I have a bug in my brute force function?
* We don't have any PCI to PCI bridges on this system, and this is why all the devices reside on pci bridge 0. Am I correct?
* What is the difference between the i440FX device (8086:1237) and the i440FX-pcihost (this spawns the PCI bus 0?)



This is my pci enumeration code:

Code: Select all

void brute_force_pci()
{
     uint16_t bus;
     uint8_t device;

     for(bus = 0; bus < BUS_PER_DOMAIN; bus++) 
	 {
         for(device = 0; device < DEVICE_PER_BUS; device++) 
		 {
			 uint32_t val = pci_config_read(bus,device,0,0);
			 if (val == (uint32_t)PCI_INV) continue;
			 qemu_puts("\r\nBus: ");QEMU_HEX(bus);
			 qemu_puts("\tSlot: ");QEMU_HEX(device);

			 val = PCI_READ_WORD(bus,device,0,PCI_ENDPT_VENDOR_ID);
			 qemu_puts("\tVendor: ");QEMU_HEX(val);
			 val = PCI_READ_WORD(bus,device,0,PCI_ENDPT_DEVICE_ID);
			 qemu_puts("\tDevice: ");QEMU_HEX(val);

			 val = PCI_READ_BYTE(bus,device,0,PCI_ENDPT_CLASS);
			 qemu_puts("\tClass: ");QEMU_HEX(val);
			 val = PCI_READ_BYTE(bus,device,0,PCI_ENDPT_SUBCLASS);
			 qemu_puts("\tSubclass: ");QEMU_HEX(val);

			 val = PCI_READ_BYTE(bus,device,0,PCI_ENDPT_HEADER_TYPE);
			 qemu_puts("\tHeader: ");QEMU_HEX(val);
         }
     }
}


Edit: I think those devices would be listed as functions of device 0:1.
thewrongchristian
Member
Member
Posts: 426
Joined: Tue Apr 03, 2018 2:44 am

Re: PCI: info qtree v/s brute force enumeration

Post by thewrongchristian »

sunnysideup wrote:I have written a simple PCI driver (nothing fancy... Just reads and writes to PCI config space and a function for brute force enumeration).

My brute force enumeration gives me this (I do the bus*device loops, and ignore reads which give me all 1s):

Code: Select all

...
Bus: 0x0	Slot: 0x1	Vendor: 0x8086	Device: 0x7000	Class: 0x6	Subclass: 0x1	Header: 0x80
...
I wanted to check the validity of this, and did a `info qtree` on my qemu console.

Code: Select all

...
  dev: i440FX-pcihost, id ""
    pci-hole64-size = 2147483648 (2 GiB)
    short_root_bus = 0 (0x0)
    x-pci-hole64-fix = true
    x-config-reg-migration-enabled = true
    bus: pci.0
      type PCI
      dev: PIIX4_PM, id ""
        smb_io_base = 1792 (0x700)
        disable_s3 = 0 (0x0)
        disable_s4 = 0 (0x0)
        s4_val = 2 (0x2)
        acpi-pci-hotplug-with-bridge-support = true
        memory-hotplug-support = true
        addr = 01.3
        romfile = ""
        rombar = 1 (0x1)
        multifunction = false
        x-pcie-lnksta-dllla = true
        x-pcie-extcap-init = true
        failover_pair_id = ""
        class Bridge, addr 00:01.3, pci id 8086:7113 (sub 1af4:1100)
        bus: i2c
          type i2c-bus
          dev: smbus-eeprom, id ""
            address = 87 (0x57)
          dev: smbus-eeprom, id ""
            address = 86 (0x56)
          dev: smbus-eeprom, id ""
            address = 85 (0x55)
          dev: smbus-eeprom, id ""
            address = 84 (0x54)
          dev: smbus-eeprom, id ""
            address = 83 (0x53)
          dev: smbus-eeprom, id ""
            address = 82 (0x52)
          dev: smbus-eeprom, id ""
            address = 81 (0x51)
          dev: smbus-eeprom, id ""
            address = 80 (0x50)
      dev: piix3-ide, id ""
        addr = 01.1
        romfile = ""
        rombar = 1 (0x1)
        multifunction = false
        x-pcie-lnksta-dllla = true
        x-pcie-extcap-init = true
        failover_pair_id = ""
        class IDE controller, addr 00:01.1, pci id 8086:7010 (sub 1af4:1100)
        bar 4: i/o at 0xc040 [0xc04f]
        bus: ide.1
          type IDE
          dev: ide-cd, id ""
            drive = "ide1-cd0"
            logical_block_size = 512 (512 B)
            physical_block_size = 512 (512 B)
            min_io_size = 0 (0 B)
            opt_io_size = 0 (0 B)
            discard_granularity = 512 (512 B)
            write-cache = "auto"
            share-rw = false
            rerror = "auto"
            werror = "auto"
            ver = "2.5+"
            wwn = 0 (0x0)
            serial = "QM00003"
            model = ""
            unit = 0 (0x0)
        bus: ide.0
          type IDE
...
      dev: PIIX3, id ""
        addr = 01.0
        romfile = ""
        rombar = 1 (0x1)
        multifunction = true
        x-pcie-lnksta-dllla = true
        x-pcie-extcap-init = true
        failover_pair_id = ""
        class ISA bridge, addr 00:01.0, pci id 8086:7000 (sub 1af4:1100)
        bus: isa.0
          type ISA
          dev: port92, id ""
            gpio-out "a20" 1
          dev: vmmouse, id ""
          dev: vmport, id ""
            x-read-set-eax = true
            x-signal-unsupported-cmd = true
            x-report-vmx-type = true
            x-cmds-v2 = true
            vmware-vmx-version = 6 (0x6)
            vmware-vmx-type = 2 (0x2)
          dev: i8042, id ""
            gpio-out "a20" 1
            isa irqs 1,12
          dev: isa-fdc, id ""
            iobase = 1008 (0x3f0)
            irq = 6 (0x6)
            dma = 2 (0x2)
            driveA = ""
            driveB = ""
            check_media_rate = true
            fdtypeA = "auto"
            fdtypeB = "auto"
            fallback = "288"
            isa irq 6
            bus: floppy-bus.0
              type floppy-bus
              dev: floppy, id ""
                unit = 0 (0x0)
                drive = "floppy0"
                logical_block_size = 512 (512 B)
                physical_block_size = 512 (512 B)
                min_io_size = 0 (0 B)
                opt_io_size = 0 (0 B)
                discard_granularity = 4294967295 (4 GiB)
                write-cache = "auto"
                share-rw = false
                drive-type = "288"
          dev: isa-parallel, id ""
            index = 0 (0x0)
            iobase = 888 (0x378)
            irq = 7 (0x7)
            chardev = "parallel0"
            isa irq 7
          dev: isa-serial, id ""
            index = 0 (0x0)
            iobase = 1016 (0x3f8)
            irq = 4 (0x4)
            chardev = "serial0"
            wakeup = 0 (0x0)
            isa irq 4
          dev: i8257, id ""
            base = 192 (0xc0)
            page-base = 136 (0x88)
            pageh-base = -1 (0xffffffffffffffff)
            dshift = 1 (0x1)
          dev: i8257, id ""
            base = 0 (0x0)
            page-base = 128 (0x80)
            pageh-base = -1 (0xffffffffffffffff)
            dshift = 0 (0x0)
          dev: isa-pcspk, id ""
            audiodev = ""
            iobase = 97 (0x61)
            migrate = true
          dev: isa-pit, id ""
            gpio-in "" 1
            gpio-out "" 1
            iobase = 64 (0x40)
          dev: mc146818rtc, id ""
            gpio-out "" 1
            base_year = 0 (0x0)
            lost_tick_policy = "discard"
          dev: isa-i8259, id ""
            gpio-in "" 8
            gpio-out "" 1
            iobase = 160 (0xa0)
            elcr_addr = 1233 (0x4d1)
            elcr_mask = 222 (0xde)
            master = false
          dev: isa-i8259, id ""
            gpio-in "" 8
            gpio-out "" 1
            iobase = 32 (0x20)
            elcr_addr = 1232 (0x4d0)
            elcr_mask = 248 (0xf8)
            master = true
      dev: i440FX, id ""
        addr = 00.0
        romfile = ""
        rombar = 1 (0x1)
        multifunction = false
        x-pcie-lnksta-dllla = true
        x-pcie-extcap-init = true
        failover_pair_id = ""
        class Host bridge, addr 00:00.0, pci id 8086:1237 (sub 1af4:1100)
...
If my interpretation is correct, my brute force function shows the i440FX as a device (I thought it was supposed to be a bridge device? The header must be 0x1? Since it is the host bridge (not PCI-PCI or PCI-Cardbus bridge, I'm guessing that the header is of type 0?)
We also have the PIIX3, which is shown as a multifunction PCI device.
We have the qemu VGA device, and the ethernet controller.

* Why aren't the PIIX3-ide device, and the PIIX4_PM shown? Does it look like I have a bug in my brute force function?
You've missed a level of probing.

Each PCI device may have multiple functions, given by bit 7 of the header being set.

So, the device at PCI 00:01 (8086:7000) is a multi-function device, which includes PIIX3-ide and PIIX4_PM as functions (addresses 00:01.1 and 00:01.3 respectively).
* We don't have any PCI to PCI bridges on this system, and this is why all the devices reside on pci bridge 0. Am I correct?
Yes.
* What is the difference between the i440FX device (8086:1237) and the i440FX-pcihost (this spawns the PCI bus 0?)
I think the i440FX device is the northbridge, which will contain the root PCI controller as well as the memory controller (these functions tend to be included in the CPU these days), and i440FX-pcihost is the southbridge, which is what provides the PC compatible device personality that connects to the IO devices like the IDE channels and ISA bus peripherals.
Post Reply