kernel/pci.c (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
#include <stdint.h>
#include "assembly.h"
#include "core.h"
#include "list.h"
#include "memory.h"
#define CONFIG_ADDR_ENABLE (31)
#define CONFIG_ADDR_BUS (16)
#define CONFIG_ADDR_PORT (11)
#define CONFIG_ADDR_FUNC (8)
#define CONFIG_ADDR_REG (0)
#define VENDOR_DEVICE_ID_REGISTER (0x00)
#define VENDOR_ID_BIT_MASK (0x0000FFFF)
#define VENDOR_ID_BIT_SHIFT (0)
#define DEVICE_ID_BIT_MASK (0xFFFF0000)
#define DEVICE_ID_BIT_SHIFT (16)
#define CLASS_CODE_REGISTER (0x08)
#define CLASS_CODE_BIT_MASK (0xFF000000)
#define CLASS_CODE_BIT_SHIFT (24)
#define SUBCLASS_CODE_BIT_MASK (0x00FF0000)
#define SUBCLASS_CODE_BIT_SHIFT (16)
#define HEADER_TYPE_REGISTER (0x0C)
#define HEADER_TYPE_BIT_MASK (0x00FF0000)
#define HEADER_TYPE_BIT_SHIFT (16)
struct pci_device {
uint8_t bus;
uint8_t port;
uint16_t vendor_id;
uint16_t device_id;
uint8_t class_code;
uint8_t subclass_code;
uint8_t header_type;
struct list_node node;
};
struct list pci_devices = LIST_INIT();
static int pci_read_register(struct pci_device *dev, uint8_t func, uint8_t reg, uint32_t *res) {
uint32_t config_addr = 0;
config_addr |= (1U << CONFIG_ADDR_ENABLE);
config_addr |= (uint32_t)(dev->bus) << CONFIG_ADDR_BUS;
config_addr |= (uint32_t)(dev->port) << CONFIG_ADDR_PORT;
config_addr |= (uint32_t)(func) << CONFIG_ADDR_FUNC;
config_addr |= (uint32_t)(reg) << CONFIG_ADDR_REG;
outl(config_addr, 0xCF8);
*res = inl(0xCFC);
return 0;
}
int pci_init(void) {
int num_devices = 0;
for (int bus = 0; bus < 256; bus++) {
for (int port = 0; port < 256; port++) {
struct pci_device dev = {
.bus = (uint8_t)(bus),
.port = (uint8_t)(port),
};
uint32_t reg_value = 0;
pci_read_register(&dev, 0, VENDOR_DEVICE_ID_REGISTER, ®_value);
uint16_t vendor_id =
(reg_value & VENDOR_ID_BIT_MASK) >> VENDOR_ID_BIT_SHIFT;
uint16_t device_id =
(reg_value & DEVICE_ID_BIT_MASK) >> DEVICE_ID_BIT_SHIFT;
if (vendor_id == 0xFFFF) {
continue;
}
struct pci_device *list_entry = malloc(sizeof(struct pci_device));
list_entry->bus = dev.bus;
list_entry->port = dev.port;
list_entry->vendor_id = vendor_id;
list_entry->device_id = device_id;
pci_read_register(&dev, 0, CLASS_CODE_REGISTER, ®_value);
list_entry->class_code =
(reg_value & CLASS_CODE_BIT_MASK) >> CLASS_CODE_BIT_SHIFT;
list_entry->subclass_code =
(reg_value & SUBCLASS_CODE_BIT_MASK) >> SUBCLASS_CODE_BIT_SHIFT;
pci_read_register(&dev, 0, HEADER_TYPE_REGISTER, ®_value);
list_entry->header_type =
(reg_value & HEADER_TYPE_BIT_MASK) >> HEADER_TYPE_BIT_SHIFT;
list_append(&pci_devices, &(list_entry->node));
num_devices++;
}
}
printk("\nfound %i PCI devices:\n", num_devices);
struct pci_device *entry;
LIST_FOR_EACH_ENTRY(&pci_devices, struct pci_device, node, entry) {
printk(
"- bus: %x\n"
" port: %x\n"
" vendor id: %x\n"
" device id: %x\n"
" class: %x\n"
" subclass: %x\n"
" header type: %x\n",
entry->bus, entry->port,
entry->vendor_id, entry->device_id,
entry->class_code, entry->subclass_code,
entry->header_type);
}
return 0;
}