#include "pci.h" #include "string.h" #include "stdio.h" #include "stdlib.h" #include "drivers/video/vga.h" #include "drivers/net/rtl8139.h" #define NOF_BUSES 8 #define NOF_DEVICES_PER_BUS 32 #define NOF_FUNCTIONS_PER_DEVICE 8 #define NOF_BARS 6 #define PCI_VENDOR_ID 0x00 #define PCI_DEVICE_ID 0x02 #define PCI_REVISION 0x08 #define PCI_INTERFACE 0x09 #define PCI_SUBCLASS 0x0A #define PCI_CLASS 0x0B #define PCI_HEADER_TYPE 0x0E #define PCI_BAR_BASE 0x10 void pci_controller_init( pci_controller_t *controller ) { memset( controller, 0, sizeof( pci_controller_t ) ); port32_init( &controller->command_port, 0xCF8 ); port32_init( &controller->data_port, 0xCFC ); } static uint32_t compute_id( uint16_t bus, uint16_t device, uint16_t function, uint32_t offset ) { uint32_t id; id = ( 0x01 << 31 ) | ( ( bus & 0xFF ) << 16 ) | ( ( device & 0x1F ) << 11 ) | ( ( function & 0x07 ) << 8 ) | ( offset & 0xFC ); return id; } uint16_t pci_controller_read( pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset ) { uint32_t id = compute_id( bus, device, function, offset ); port32_write( &controller->command_port, id ); uint32_t data = port32_read( &controller->data_port ); // we get 256 byte data blocks aligned to 32-bit addresses // for each offset data = data >> ( ( 8 * ( offset % 4 ) ) & 0xFFFF ); return data; } void pci_controller_write( pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset, uint32_t data ) { uint32_t id = compute_id( bus, device, function, offset ); port32_write( &controller->command_port, id ); port32_write( &controller->data_port, data ); } static int get_nof_functions( pci_controller_t *controller, uint16_t bus, uint16_t device ) { uint8_t data = pci_controller_read( controller, bus, device, 0, PCI_HEADER_TYPE ); if( data & 0x80 ) { return NOF_FUNCTIONS_PER_DEVICE; } else { return 1; } } void pci_controller_scan_and_register( pci_controller_t *controller, driver_manager_t *driver_manager, interrupt_t *interrupt, void *context ) { for( int bus = 0; bus < NOF_BUSES; bus++ ) { for( int device = 0; device < NOF_DEVICES_PER_BUS; device++ ) { int nof_functions = get_nof_functions( controller, bus, device ); for( int function = 0; function < nof_functions; function++ ) { pci_device_descriptor_t device_descriptor; pci_device_descriptor_init( &device_descriptor, controller, bus, device, function ); // no device if( device_descriptor.device_id == 0x0 || device_descriptor.device_id == 0xFFFF ) { continue; } printf( "%X:%X.%d: %X:%X (interface: %X, class %X:%X, rev: %d)\n", bus, device, function, device_descriptor.vendor_id, device_descriptor.device_id, device_descriptor.interface_id, device_descriptor.class_id, device_descriptor.subclass_id, device_descriptor.revision_id ); uint8_t header_type = pci_controller_read( controller, bus, device, function, PCI_HEADER_TYPE ) & 0x7F; int max_nof_bars = NOF_BARS; if( header_type & 0x01 ) { max_nof_bars = 2; } for( int bar_number = 0; bar_number < max_nof_bars; bar_number++ ) { pci_base_address_register_t bar; pci_base_address_register_init( &bar, controller, bus, device, function, bar_number ); if( bar.type == BASE_ADDRESS_REGISTER_TYPE_IO && bar.addr ) { device_descriptor.port_base = (uint32_t)bar.addr; } } driver_t *driver = pci_device_get_driver( &device_descriptor, interrupt, context ); if( driver ) { driver_manager_add_driver( driver_manager, driver ); } } } } } void pci_device_descriptor_init( pci_device_descriptor_t *descriptor, pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function ) { memset( descriptor, 0, sizeof( pci_device_descriptor_t ) ); descriptor->vendor_id = pci_controller_read( controller, bus, device, function, PCI_VENDOR_ID ); descriptor->device_id = pci_controller_read( controller, bus, device, function, PCI_DEVICE_ID ); descriptor->class_id = pci_controller_read( controller, bus, device, function, PCI_CLASS ); descriptor->subclass_id = pci_controller_read( controller, bus, device, function, PCI_SUBCLASS ); descriptor->interface_id = pci_controller_read( controller, bus, device, function, PCI_INTERFACE ); descriptor->revision_id = pci_controller_read( controller, bus, device, function, PCI_REVISION ); } void pci_base_address_register_init( pci_base_address_register_t *base_address_register, pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint16_t bar ) { memset( base_address_register, 0, sizeof( pci_base_address_register_t ) ); uint32_t val = pci_controller_read( controller, bus, device, function, PCI_BAR_BASE + sizeof( uint32_t ) * bar ); // bit 0 indicates whether we are I/O or memory mapped base_address_register->type = ( val & 0x01 ) ? BASE_ADDRESS_REGISTER_TYPE_IO : BASE_ADDRESS_REGISTER_TYPE_MEMORY_MAPPED; switch( base_address_register->type ) { case BASE_ADDRESS_REGISTER_TYPE_IO: base_address_register->addr = (uint8_t *)( val & 0xFFFC ); base_address_register->prefetchable = false; break; case BASE_ADDRESS_REGISTER_TYPE_MEMORY_MAPPED: switch( val << 1 & 0x03 ) { case 0x00: // 32-bit mode break; case 0x01: // 20-bit mode break; case 0x02: // 64-bit mode break; } break; } } driver_t *pci_device_get_driver( pci_device_descriptor_t *descriptor, interrupt_t *interrupt, void *context ) { driver_t *driver = NULL; // find a specific device switch( descriptor->vendor_id ) { case 0x10ec: // Realtek Semiconductor switch( descriptor->device_id ) { case 0x8139: // RTL8139 driver = (driver_t *)malloc( sizeof( rtl8139_t ) ); rtl8139_init( (rtl8139_t *)driver, interrupt, context ); break; } break; case 0x8086: // Intel break; default: break; } // find a generic driver switch( descriptor->class_id ) { case 0x03: // graphics switch( descriptor->subclass_id ) { case 0x00: // Generic VGA driver = (driver_t *)malloc( sizeof( vga_t ) ); vga_init( (vga_t *)driver, interrupt, context ); break; } break; default: // no driver found break; } return driver; }