Page 1 of 1

Is my PCI device listing is valid?

Posted: Sat Oct 08, 2016 11:26 am
by osdever
I've decided to implement basic PCI support, so I wrote the code, it works, but I don't know its validity: there's no network interface, no graphics card, almost nothing! Here's my code:

Code: Select all

//PCI support, yes!
#include <arch/i686/pci.h>
#include <arch/i686/io.h>
#include <stdint.h>
#include <stdio.h>
//pci_read_confspc_word(): Returns 16-bit value from PCI Configuration Space of specified device at specified offset.
uint16_t pci_read_confspc_word(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset)
{
	uint32_t addr;
	uint32_t bus32 = bus;
	uint32_t slot32 = slot;
	uint32_t func32 = function;
	addr = (uint32_t)((bus32 << 16) | (slot32 << 11) |
           (func32 << 8) | (offset & 0xfc) | ((uint32_t)0x80000000)); //yes, this line is copied from osdev
	outl(PCI_ADDRESS_PORT, addr);
	return (uint16_t)((inl(PCI_DATA_PORT) >> ((offset & 2) * 8)) & 0xffff); //this too... I'm too lazy to write them
}
static struct {
	uint8_t dev_class, dev_subclass; //added dev_ to prevent errors in C++
	const char *name;
} pci_device_type_strings[] = {
	{0x00, 0x00, "Unknown device"},
	{0x00, 0x01, "VGA-compatible Device"},
	{0x01, 0x00, "SCSI Bus Controller"},
	{0x01, 0x01, "IDE Controller"},
	{0x01, 0x02, "Floppy Disk Controller"},
	{0x01, 0x03, "IPI Bus Controller"},
	{0x01, 0x04, "RAID Controller"},
	{0x01, 0x05, "ATA Controller"},
	{0x01, 0x06, "SATA Controller"},
	{0x01, 0x07, "Serial Attached SCSI Controller"},
	{0x01, 0x80, "Other Mass Storage Controller"},
	{0x02, 0x00, "Ethernet Controller"},
	{0x02, 0x01, "Token Ring Controller"},
	{0x02, 0x02, "FDDI Controller"},
	{0x02, 0x03, "ATM Controller"},
	{0x02, 0x04, "ISDN Controller"},
	{0x02, 0x05, "WorldFip Controller"},
	{0x02, 0x06, "PICMG 2.14 Multi Computing"},
	{0x02, 0x80, "Other Network Controller"},
	{0x03, 0x00, "VGA-compatible Controller"},
	{0x03, 0x01, "XGA Controller"},
	{0x03, 0x02, "3D Controller"},
	{0x03, 0x80, "Other Display Controller"},
	{0x04, 0x00, "Video Device"},
	{0x04, 0x01, "Audio Device"},
	{0x04, 0x02, "Computer Telephony Device"},
	{0x04, 0x80, "Other Multimedia Device"},
	{0x05, 0x00, "RAM Controller"},
	{0x05, 0x01, "Flash Controller"},
	{0x05, 0x80, "Other Memory Controller"},
	{0x06, 0x00, "Host Bridge"},
	{0x06, 0x01, "ISA Bridge"},
	{0x06, 0x02, "EISA Bridge"},
	{0x06, 0x03, "MCA Bridge"},
	{0x06, 0x04, "PCI-to-PCI Bridge"},
	{0x06, 0x05, "PCMCIA Bridge"},
	{0x06, 0x06, "NuBus Bridge"},
	{0x06, 0x07, "CardBus Bridge"},
	{0x06, 0x08, "RACEWay Bridge"},
	{0x06, 0x09, "PCI-to-PCI Bridge (Semi-Transparent)"},
	{0x06, 0x0A, "InfiniBand-to-PCI Host Bridge"},
	{0x06, 0x80, "Other Bridge Device"},
	{0x07, 0x00, "Serial Controller"},
	{0x07, 0x01, "Parallel Port"},
	{0x07, 0x02, "Multiport Serial Controller"},
	{0x07, 0x03, "Generic Modem"},
	{0x07, 0x04, "IEEE 488.1/2 (GPIB) Controller"},
	{0x07, 0x05, "Smart Card"},
	{0x07, 0x80, "Other Communication Device"},
	{0x08, 0x00, "Programmable Interrupt Controller"},
	{0x08, 0x01, "DMA Controller"},
	{0x08, 0x02, "System Timer"},
	{0x08, 0x03, "Real-Time Clock"},
	{0x08, 0x04, "Generic PCI Hot-Plug Controller"},
	{0x08, 0x80, "Other System Peripheral"},
	{0x09, 0x00, "Keyboard Controller"},
	{0x09, 0x01, "Digitizer"},
	{0x09, 0x02, "Mouse Controller"},
	{0x09, 0x03, "Scanner Controller"},
	{0x09, 0x04, "Gameport Controller"},
	{0x09, 0x80, "Other Input Controller"},
	{0x0A, 0x00, "Generic Docking Station"},
	{0x0A, 0x80, "Other Docking Station"},
	{0x0B, 0x00, "i386 CPU"},
	{0x0B, 0x01, "i486 CPU"},
	{0x0B, 0x02, "Pentium CPU"},
	{0x0B, 0x10, "Alpha CPU"},
	{0x0B, 0x20, "PowerPC CPU"},
	{0x0B, 0x30, "MIPS CPU"},
	{0x0B, 0x40, "Co-processor"},
	{0x0C, 0x00, "FireWire Controller"},
	{0x0C, 0x01, "ACCESS.bus Controller"},
	{0x0C, 0x02, "SSA Controller"},
	{0x0C, 0x03, "USB Controller"},
	{0x0C, 0x04, "Fibre Channel"},
	{0x0C, 0x05, "SMBus"},
	{0x0C, 0x06, "InfiniBand"},
	{0x0C, 0x07, "IPMI SMIC Interface"},
	{0x0C, 0x08, "SERCOS Interface"},
	{0x0C, 0x09, "CANbus Interface"},
	{0x0D, 0x00, "iRDA Compatible Controller"},
	{0x0D, 0x01, "Consumer IR Controller"},
	{0x0D, 0x10, "RF Controller"},
	{0x0D, 0x11, "Bluetooth Controller"},
	{0x0D, 0x12, "Broadband Controller"},
	{0x0D, 0x20, "802.11a (Wi-Fi) Ethernet Controller"},
	{0x0D, 0x21, "802.11b (Wi-Fi) Ethernet Controller"},
	{0x0D, 0x80, "Other Wireless Controller"},
	
	{0x00, 0x00, NULL} //here array ends
};
uint8_t pci_get_class(uint8_t bus, uint8_t slot, uint8_t function)
{
	return (uint8_t) (pci_read_confspc_word(bus, slot, function, 5) >> 8) /* shifting to leave only class id in the variable. */;
}
uint8_t pci_get_subclass(uint8_t bus, uint8_t slot, uint8_t function)
{
	return (uint8_t) pci_read_confspc_word(bus, slot, function, 5);
}
uint8_t pci_get_hdr_type(uint8_t bus, uint8_t slot, uint8_t function)
{
	return (uint8_t) pci_read_confspc_word(bus, slot, function, 7);
}
uint16_t pci_get_vendor(uint8_t bus, uint8_t slot, uint8_t function)
{
	return pci_read_confspc_word(bus, slot, function, 0);
}
const char *pci_get_device_type(uint8_t dev_class, uint8_t dev_subclass)
{
	for(int i=0; pci_device_type_strings[i].name != NULL; i++)
		if(pci_device_type_strings[i].dev_class == dev_class && pci_device_type_strings[i].dev_subclass == dev_subclass)
			return pci_device_type_strings[i].name;
	return NULL;
}
void list_pci()
{
	uint8_t clid;
	uint8_t sclid;
	uint16_t vendor;
	for(unsigned bus = 0; bus < 256; bus++)
	{
		for(unsigned slot = 0; slot < 32; slot++)
		{
			unsigned func = 0;
			clid = pci_get_class(bus, slot, func);
			sclid = pci_get_subclass(bus, slot, func);
			vendor = pci_get_vendor(bus, slot, func);
			if(clid != 0xFF && vendor != 0xFFFF)
				printf("Vendor: 0x%x, device: %s %d %d\n", vendor, pci_get_device_type(clid, sclid), sclid, clid);
			if((pci_get_hdr_type(bus, slot, func) & 0x80) == 0)
			for(func = 1; func < 8; func++)
			{
				clid = pci_get_class(bus, slot, func);
				sclid = pci_get_subclass(bus, slot, func);
				vendor = pci_get_vendor(bus, slot, func);
				if(clid != 0xFF && vendor != 0xFFFF)
					printf("Vendor: 0x%x, device: %s %d %d\n", vendor, pci_get_device_type(clid, sclid), sclid, clid);
			}
		}
	}
}
Output on QEMU doesn't seems to be valid, on Bochs some magic happens: output looks valid, but only if I add dev_class++; to pci_get_device_type. QEMU and Bochs output is in post.

Re: Is my PCI device listing is valid?

Posted: Sat Oct 08, 2016 12:26 pm
by Octacone
I don't see anything weird in there. Because different emulators have different devices on different locations of different types.

Re: Is my PCI device listing is valid?

Posted: Sat Oct 08, 2016 12:35 pm
by osdever
octacone wrote:I don't see anything weird in there. Because different emulators have different devices on different locations of different types.
I know, but is listing on QEMU is valid? You have network controllers and more on your scrs, but I'm not.

Re: Is my PCI device listing is valid?

Posted: Sat Oct 08, 2016 12:48 pm
by osdever
Added network controller in QEMU args, now it found it, but it displays as IPI Bus Controller.

Re: Is my PCI device listing is valid?

Posted: Sat Oct 08, 2016 4:24 pm
by jnc100
Your vendor ID is correct, but your class and subclass IDs are wrong. In particular, you are probably using the wrong offset for your pci read function. If you are using the pciConfigReadWord function from the wiki page, you probably want offset 10 for this 16 bit value (rather than 5 as you are using).

Regards,
John.

Re: Is my PCI device listing is valid?

Posted: Sun Oct 09, 2016 12:42 am
by osdever
jnc100 wrote:Your vendor ID is correct, but your class and subclass IDs are wrong. In particular, you are probably using the wrong offset for your pci read function. If you are using the pciConfigReadWord function from the wiki page, you probably want offset 10 for this 16 bit value (rather than 5 as you are using).

Regards,
John.
Thanks! I thought that it uses offset in words, not bytes ;)

Re: Is my PCI device listing is valid?

Posted: Sun Oct 09, 2016 12:57 am
by osdever
It works! Thanks.