Problem enumerating PCI devices--only finds northbridge!

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
kurtmweber
Posts: 10
Joined: Tue Aug 18, 2020 6:55 pm

Problem enumerating PCI devices--only finds northbridge!

Post 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;
}
Octocontrabass
Member
Member
Posts: 5759
Joined: Mon Mar 25, 2013 7:01 pm

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

Post by Octocontrabass »

Where did you define asm_out_d(), asm_in_d(), PCI_CONFIG_ADDRESS_PORT, and PCI_CONFIG_DATA_PORT?
Octocontrabass
Member
Member
Posts: 5759
Joined: Mon Mar 25, 2013 7:01 pm

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

Post 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.
kurtmweber
Posts: 10
Joined: Tue Aug 18, 2020 6:55 pm

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

Post 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.
Octocontrabass
Member
Member
Posts: 5759
Joined: Mon Mar 25, 2013 7:01 pm

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

Post 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.)
Post Reply