Page 1 of 1

Problem enumerating PCI devices--only finds northbridge!

Posted: Tue Aug 18, 2020 8:05 pm
by kurtmweber
I'm running on qemu, and info qtree shows both the i440FX and PIIX3, as well as numerous other devices (IDE controller, e1000, vga, and USB UHCI), but when I enumerate PCI devices I only get the i440FX. Right now, I'm doing an inefficient but conceptually simple method of scanning every possible function # (without bothering to check if it's meaningful for a given device--I understand this will cause non-multifunction devices to show up multiple times, at the moment I'm just trying to keep the code simple until I get more comfortable with this) on every possible device on every possible bus, and all I get is bus 0, device 0 = vendor 8086, device 1237.

pci_scan() is the function that does the scanning:

Code: Select all

void pci_scan(){
	uint8_t bus = 0, device = 0, function = 0;
	uint32_t register_dword;
	uint16_t device_id, vendor_id;
	uint8_t class_code, subclass_code;
	
	kprintf("Scanning for PCI devices...\n");
	
	for (bus = 0; bus <= 255; bus++){
		for (device = 0; device <= 31; device++){
			for (function = 0; function <= 7; function++){
				asm_out_d(PCI_CONFIG_ADDRESS_PORT, pci_config_address_build(0, function, device, bus, 1));
				register_dword = asm_in_d(PCI_CONFIG_DATA_PORT);
				
				vendor_id = (uint16_t)(register_dword & 0x0000FFFF);
				device_id = (uint16_t)(register_dword >> 16);
				
				if (vendor_id != 0xFFFF){
					kprintf("PCI device found at %#hX:%#hX, vendor %#X, device %#X\n", bus, device, vendor_id, device_id);
					asm_out_d(PCI_CONFIG_ADDRESS_PORT, pci_config_address_build(0x08, function, device, bus, 1));
					register_dword = asm_in_d(PCI_CONFIG_DATA_PORT);
				}
			}
		}
	}
	
	return;
}
and pci_config_address_build(), which assembles the dword that's sent to the config data port:

Code: Select all

uint32_t pci_config_address_build(uint8_t offset, uint8_t function, uint8_t device, uint8_t bus, uint8_t enabled){
	uint32_t r;
	
	r |= (uint32_t)enabled << 31;
	r |= (uint32_t)bus << 16;
	r |= (uint32_t)device << 11;
	r |= (uint32_t)function << 8;
	r |= (uint32_t)offset;
	
	return r;
}

Re: Problem enumerating PCI devices--only finds northbridge!

Posted: Tue Aug 18, 2020 8:37 pm
by Octocontrabass
Where did you define asm_out_d(), asm_in_d(), PCI_CONFIG_ADDRESS_PORT, and PCI_CONFIG_DATA_PORT?

Re: Problem enumerating PCI devices--only finds northbridge!

Posted: Tue Aug 18, 2020 10:55 pm
by Octocontrabass
kurtmweber wrote:

Code: Select all

	uint32_t r;
	r |= (uint32_t)enabled << 31;
You've got an uninitialized variable there. Perhaps replace |= with = to fix it.

Re: Problem enumerating PCI devices--only finds northbridge!

Posted: Tue Aug 18, 2020 11:19 pm
by kurtmweber
Ugh, of course it was something silly and obvious like that! It's always the small things that your own eyes pass over because you wrote it and know what it's supposed to do...

Thanks so much!

There was also an (equally silly on my part) infinite loop in pci_scan() because I had forgotten that since bus was an 8-bit unsigned int, it would always be <= 255 so the outer loop would never terminate. Fixed that too and now it works great.

Re: Problem enumerating PCI devices--only finds northbridge!

Posted: Tue Aug 18, 2020 11:24 pm
by Octocontrabass
Try adjusting your compiler's warning settings. Both GCC and Clang can emit warnings for things like that, which might save you some time debugging in the future. ("-Wall" is a good starting point.)