From d6d1bdfefafff50b7b6d15d218c0a188570be541 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sat, 10 Jun 2017 21:26:24 +0200 Subject: some big renames into subdirs of aspects updated README removed size_t in sys/types.h and sys/types.h itself, size_t is in stddef.h --- src/hardware/pci.c | 187 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 src/hardware/pci.c (limited to 'src/hardware/pci.c') diff --git a/src/hardware/pci.c b/src/hardware/pci.c new file mode 100644 index 0000000..6b124b2 --- /dev/null +++ b/src/hardware/pci.c @@ -0,0 +1,187 @@ +#include "pci.h" + +#include "string.h" +#include "stdio.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 ); +} + +void pci_controller_scan_and_register( pci_controller_t *controller, driver_manager_t *driver_manager, interrupt_t *interrupt ) +{ + for( int bus = 0; bus < NOF_BUSES; bus++ ) { + for( int device = 0; device < NOF_DEVICES_PER_BUS; device++ ) { + // TODO: detect single/multi function device from header + for( int function = 0; function < NOF_FUNCTIONS_PER_DEVICE; 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 ); + 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 ) +{ + // find a specific device + switch( descriptor->vendor_id ) { + case 0x10ec: // Realtek Semiconductor + switch( descriptor->device_id ) { + case 0x8029: // RTL-8029 + 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: // VGA + break; + } + break; + + default: // no driver found + break; + } + return NULL; +} -- cgit v1.2.3-54-g00ecf