2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2008, Peter Dinda <pdinda@northwestern.edu>
11 * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * Author: Peter Dinda <pdinda@northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20 #include <geekos/malloc.h>
21 #include <geekos/pci.h>
22 #include <geekos/io.h>
23 #include <geekos/debug.h>
25 #define PCI_CONFIG_ADDRESS 0xcf8 // 32 bit, little endian
26 #define PCI_CONFIG_DATA 0xcfc // 32 bit, little endian
28 #define PCI_MAX_NUM_BUSES 4
31 struct pci_device_config {
37 uchar_t class_code[3]; // in order: programming interface, subclass, class code
39 #define PROG_INTERFACE(x) ((x)[0])
40 #define SUBCLASS(x) ((x)[1])
41 #define CLASSCODE(x) ((x)[2])
44 uchar_t cache_line_size;
46 uchar_t header_type; // bits 6-0: 00: other, 01: pci-pci bridge, 02: pci-cardbus; bit 7: 1=multifunction
48 #define HEADER_TYPE(x) ((x) & 0x7f)
50 #define PCI_DEVICE 0x0
51 #define PCI_PCI_BRIDGE 0x1
52 #define PCI_CARDBUS_BRIDGE 0x2
54 #define MULTIFUNCTION(x) ((x) & 0x80)
56 #define IS_DEVICE(x) (HEADER_TYPE(x) == 0x0)
57 #define IS_PCI_PCI_BRIDGE(x) (HEADER_TYPE(x) == 0x1)
58 #define IS_PCI_CARDBUS_BRIDGE(x) (HEADER_TYPE(x) == 0x2)
64 // header = 00 (Device)
68 #define IS_IO_ADDR(x) ((x) & 0x1)
69 #define IS_MEM_ADDR(x) (!((x) & 0x1))
70 #define GET_IO_ADDR(x) (((uint_t)(x)) & 0xfffffffc)
71 #define GET_MEM_ADDR(x) (((uint_t)(x)) & 0xfffffff0)
72 #define GET_MEM_TYPE(x) (((x) & 0x6) >> 2)
73 #define GET_MEM_PREFETCHABLE(x) ((x) & 0x8)
75 uint_t cardbus_cis_pointer;
76 ushort_t subsystem_vendor_id;
77 ushort_t subsystem_id;
78 uint_t expansion_rom_address;
79 uchar_t cap_ptr; // capabilities list offset in config space
81 uchar_t intr_line; // 00=none, 01=IRQ1, etc.
82 uchar_t intr_pin; // 00=none, otherwise INTA# to INTD#
83 uchar_t min_grant; // min busmaster time - units of 250ns
84 uchar_t max_latency; // units of 250ns - busmasters
85 uint_t device_data[48];
86 } __attribute__((__packed__)) pci_device_config;
88 // header = 01 (pci-pci bridge)
91 uchar_t primary_bus; // the one closer to the processor
92 uchar_t secondary_bus; // the one further away
93 uchar_t subordinate_bus;
94 uchar_t secondary_lat_timer;
97 ushort_t secondary_status;
99 ushort_t memory_limit;
100 ushort_t prefetchable_memory_base;
101 ushort_t prefetchable_memory_limit;
102 uint_t prefetchable_memory_base_upper; // for 64 bit?
103 uint_t prefetchable_memory_limit_upper;
104 ushort_t io_base_upper; // upper 16
105 ushort_t io_limit_upper;
107 uint_t expansion_rom_address;
111 uint_t device_data[48];
112 } __attribute__((__packed__)) pci_pci_bridge_config;
115 // header = 02 (pci-cardbus bridge)
117 uint_t cardbus_base_addr;
120 ushort_t secondary_status;
123 uchar_t subordinate_bus;
124 uchar_t cardbus_lat_timer;
126 uint_t memory_limit0;
128 uint_t memory_limit1;
130 ushort_t io_base0_upper;
132 ushort_t io_limit0_upper;
134 ushort_t io_base1_upper;
136 ushort_t io_limit1_upper;
140 ushort_t subsystem_vendor_id;
141 ushort_t subsystem_device_id;
142 uint_t legacy_16bit_base_addr;
143 uint_t reserved2[14];
144 uint_t device_data[32];
145 } __attribute__((__packed__)) pci_cardbus_bridge_config;
147 } __attribute__((__packed__)) u;
153 struct pci_bus * next;
155 struct pci_device * device_list;
161 struct pci_bus * bus;
162 struct pci_device * next;
164 struct pci_device_config config;
169 struct pci_bus * bus_list;
173 static uint_t ReadPCIDWord(uint_t bus, uint_t dev, uint_t func, uint_t offset) {
177 address = ((bus << 16) | (dev << 11) |
178 (func << 8) | (offset & 0xfc) | ((uint_t)0x80000000));
180 Out_DWord(PCI_CONFIG_ADDRESS, address);
181 data = In_DWord(PCI_CONFIG_DATA);
187 static ushort_t ReadPCIWord(uint_t bus, uint_t dev, uint_t func, uint_t offset) {
188 return (ushort_t) (ReadPCIDWord(bus, dev, func, offset) >> ((offset & 0x2) * 8));
192 static struct pci * NewPCI() {
193 struct pci * p = (struct pci *)Malloc(sizeof(struct pci));
199 static void AddPCIBus(struct pci * p, struct pci_bus * bus) {
200 bus->next = p->bus_list;
205 static struct pci_bus * NewPCIBus(struct pci * p) {
206 struct pci_bus * pb = (struct pci_bus *)Malloc(sizeof(struct pci_bus));
207 pb->device_list = NULL;
208 pb->number = (p->num_buses);
213 static void AddPCIDevice(struct pci_bus * b, struct pci_device * d) {
215 d->next = b->device_list;
219 static struct pci_device * NewPCIDevice(struct pci_bus * pb) {
220 struct pci_device *pd = (struct pci_device *)Malloc(sizeof(struct pci_device));
227 static void GetPCIDeviceConfig(uint_t bus, uint_t dev, uint_t fn, struct pci_device * d) {
228 uint_t numdwords = (sizeof(struct pci_device_config) / 4);
230 uint_t * p = (uint_t *)&(d->config);
232 for (i = 0; i < numdwords; i++) {
233 p[i] = ReadPCIDWord(bus, dev, fn, i * 4);
234 PrintBoth("Reading Config Word %d (val=%x)\n", i * 4, p[i]);
240 static struct pci * ScanPCI() {
243 struct pci * thepci = NewPCI();
244 struct pci_bus * thebus;
246 for (bus = 0; bus < PCI_MAX_NUM_BUSES; bus++) {
248 // Are there any devices on the bus?
249 for (dev = 0; dev < 32; dev++) {
250 vendor = ReadPCIWord(bus, dev, 0, 0);
252 if (vendor != 0xffff) {
261 // There are devices. Create a bus.
262 thebus = NewPCIBus(thepci);
263 thebus->number = bus;
266 // Add the devices to the bus
267 for (dev = 0; dev < 32; dev++) {
268 for (fn = 0; fn < 7; fn++) {
270 vendor = ReadPCIWord(bus, dev, fn, 0);
272 if (vendor != 0xffff) {
273 struct pci_device * thedev = NewPCIDevice(thebus);
275 thedev->number = dev;
276 thedev->function = fn;
278 GetPCIDeviceConfig(bus, dev, fn, thedev);
280 AddPCIDevice(thebus, thedev);
285 AddPCIBus(thepci,thebus);
292 static void PrintPCIShared(struct pci_device * thedev) {
293 PrintBoth(" Slot: %u.%u\n", thedev->number, thedev->function);
294 PrintBoth(" vendor_id: 0x%x\n", (uint_t) thedev->config.vendor_id);
295 PrintBoth(" device_id: 0x%x\n", (uint_t) thedev->config.device_id);
296 PrintBoth(" command: 0x%x\n", (uint_t) thedev->config.command);
297 PrintBoth(" status: 0x%x\n", (uint_t) thedev->config.status);
298 PrintBoth(" revision: 0x%x\n", (uint_t) thedev->config.revision);
299 PrintBoth(" class_code: 0x%x%x%x (prog_interface 0x%x, subclass 0x%x, classcode 0x%x)\n",
300 (uint_t) thedev->config.class_code[0],
301 (uint_t) thedev->config.class_code[1],
302 (uint_t) thedev->config.class_code[2],
303 (uint_t) PROG_INTERFACE(thedev->config.class_code),
304 (uint_t) SUBCLASS(thedev->config.class_code),
305 (uint_t) CLASSCODE(thedev->config.class_code) );
306 PrintBoth(" cache_line_size: 0x%x\n", (uint_t) thedev->config.cache_line_size);
307 PrintBoth(" latency_time: 0x%x\n", (uint_t) thedev->config.latency_time);
308 PrintBoth(" header_type: 0x%x (%s%s)\n", (uint_t) thedev->config.header_type,
309 HEADER_TYPE(thedev->config.header_type)==PCI_DEVICE ? "PCI Device" :
310 HEADER_TYPE(thedev->config.header_type)==PCI_PCI_BRIDGE ? "PCI-PCI Bridge" :
311 HEADER_TYPE(thedev->config.header_type)==PCI_CARDBUS_BRIDGE ? "PCI-Cardbus Bridge" : "UNKNOWN",
312 MULTIFUNCTION(thedev->config.header_type) ? " Multifunction" : ""
314 PrintBoth(" BIST: 0x%x\n", (uint_t) thedev->config.BIST);
317 static void PrintPCIDevice(struct pci_device * thedev) {
320 PrintBoth(" PCI Device:\n");
322 PrintPCIShared(thedev);
324 for (i = 0; i < 6; i++) {
325 PrintBoth(" BAR[%d]: 0x%x (", i, (uint_t) thedev->config.u.pci_device_config.BAR[i]);
327 if (IS_IO_ADDR(thedev->config.u.pci_device_config.BAR[i])) {
329 PrintBoth("IO Address 0x%x)\n", GET_IO_ADDR(thedev->config.u.pci_device_config.BAR[i]));
331 } else if (IS_MEM_ADDR(thedev->config.u.pci_device_config.BAR[i])) {
333 PrintBoth("Memory Address 0x%x type=0x%x%s\n",
334 GET_MEM_ADDR(thedev->config.u.pci_device_config.BAR[i]),
335 GET_MEM_TYPE(thedev->config.u.pci_device_config.BAR[i]),
336 GET_MEM_PREFETCHABLE(thedev->config.u.pci_device_config.BAR[i]) ? " prefetchable)" : ")");
339 PrintBoth("UNKNOWN)\n");
343 PrintBoth(" cardbus_cis_ptr: 0x%x\n", (uint_t) thedev->config.u.pci_device_config.cardbus_cis_pointer);
344 PrintBoth(" subsystem_vendor: 0x%x\n", (uint_t) thedev->config.u.pci_device_config.subsystem_vendor_id);
345 PrintBoth(" subsystem_id: 0x%x\n", (uint_t) thedev->config.u.pci_device_config.subsystem_id);
346 PrintBoth(" exp_rom_address: 0x%x\n", (uint_t) thedev->config.u.pci_device_config.expansion_rom_address);
347 PrintBoth(" cap ptr 0x%x\n", (uint_t) thedev->config.u.pci_device_config.cap_ptr);
349 for (i = 0; i < 7; i++) {
350 PrintBoth(" reserved[%d]: 0x%x\n", i, (uint_t) thedev->config.u.pci_device_config.reserved[i]);
353 PrintBoth(" intr_line: 0x%x\n", (uint_t) thedev->config.u.pci_device_config.intr_line);
354 PrintBoth(" intr_pin: 0x%x\n", (uint_t) thedev->config.u.pci_device_config.intr_pin);
355 PrintBoth(" min_grant: 0x%x\n", (uint_t) thedev->config.u.pci_device_config.min_grant);
356 PrintBoth(" max_latency: 0x%x\n", (uint_t) thedev->config.u.pci_device_config.max_latency);
358 for (i = 0; i < 48; i++) {
359 PrintBoth(" device_data[%d]: 0x%x\n", i, (uint_t) thedev->config.u.pci_device_config.device_data[i]);
363 static void PrintPCIPCIBridge(struct pci_device * thedev) {
366 PrintBoth(" PCI-PCI Bridge:\n");
368 PrintPCIShared(thedev);
370 for (i = 0; i < 2; i++) {
372 PrintBoth(" BAR[%d]: 0x%x (", i, (uint_t) thedev->config.u.pci_pci_bridge_config.BAR[i]);
374 if (IS_IO_ADDR(thedev->config.u.pci_pci_bridge_config.BAR[i])) {
376 PrintBoth("IO Address 0x%x)\n", GET_IO_ADDR(thedev->config.u.pci_pci_bridge_config.BAR[i]));
378 } else if (IS_MEM_ADDR(thedev->config.u.pci_pci_bridge_config.BAR[i])) {
380 PrintBoth("Memory Address 0x%x type=0x%x%s\n",
381 GET_MEM_ADDR(thedev->config.u.pci_pci_bridge_config.BAR[i]),
382 GET_MEM_TYPE(thedev->config.u.pci_pci_bridge_config.BAR[i]),
383 GET_MEM_PREFETCHABLE(thedev->config.u.pci_pci_bridge_config.BAR[i]) ? " prefetchable)" : ")");
386 PrintBoth("UNKNOWN)\n");
390 PrintBoth(" primary_bus: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.primary_bus);
391 PrintBoth(" secondary_bus: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.secondary_bus);
392 PrintBoth(" subordinate_bus: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.subordinate_bus);
393 PrintBoth(" second_lat_timer: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.secondary_lat_timer);
394 PrintBoth(" io_base: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.io_base);
395 PrintBoth(" io_limit: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.io_limit);
396 PrintBoth(" secondary_status: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.secondary_status);
397 PrintBoth(" memory_base: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.memory_base);
398 PrintBoth(" memory_limit: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.memory_limit);
399 PrintBoth(" prefetch_base: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.prefetchable_memory_base);
400 PrintBoth(" prefetch_limit: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.prefetchable_memory_limit);
401 PrintBoth(" prefetch_base_up: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.prefetchable_memory_base_upper);
402 PrintBoth(" prefetch_limit_u: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.prefetchable_memory_limit_upper);
403 PrintBoth(" memory_limit: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.memory_limit);
404 PrintBoth(" memory_limit: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.memory_limit);
405 PrintBoth(" io_base_up: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.io_base_upper);
406 PrintBoth(" io_limit_up: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.io_limit_upper);
407 PrintBoth(" reserved: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.reserved);
408 PrintBoth(" exp_rom_address: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.expansion_rom_address);
409 PrintBoth(" intr_line: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.intr_line);
410 PrintBoth(" intr_pin: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.intr_pin);
412 for (i = 0; i < 48; i++) {
413 PrintBoth(" device_data[%d]: 0x%x\n", i, (uint_t) thedev->config.u.pci_pci_bridge_config.device_data[i]);
417 static void PrintPCICardbusBridge(struct pci_device * thedev) {
420 PrintBoth(" PCI-Cardbus Bridge:\n");
422 PrintPCIShared(thedev);
424 PrintBoth(" cardbus_base_add: 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.cardbus_base_addr);
425 PrintBoth(" cap_ptr: 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.cap_ptr);
426 PrintBoth(" reserved: 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.reserved);
427 PrintBoth(" secondary_status 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.secondary_status);
428 PrintBoth(" pci_bus: 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.pci_bus);
429 PrintBoth(" cardbus_bus: 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.cardbus_bus);
430 PrintBoth(" subordinate_bus: 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.subordinate_bus);
431 PrintBoth(" cardbus_lat_time: 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.cardbus_lat_timer);
432 PrintBoth(" memory_base0 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.memory_base0);
433 PrintBoth(" memory_limit0 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.memory_limit0);
434 PrintBoth(" memory_base1 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.memory_base1);
435 PrintBoth(" memory_limit1 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.memory_limit1);
436 PrintBoth(" io_base0 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.io_base0);
437 PrintBoth(" io_base0_up 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.io_base0_upper);
438 PrintBoth(" io_limit0 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.io_limit0);
439 PrintBoth(" io_limit0_up 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.io_limit0_upper);
440 PrintBoth(" io_base1 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.io_base1);
441 PrintBoth(" io_base1_up 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.io_base1_upper);
442 PrintBoth(" io_limit1 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.io_limit1);
443 PrintBoth(" io_limit1_up 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.io_limit1_upper);
444 PrintBoth(" intr_line: 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.intr_line);
445 PrintBoth(" intr_pin: 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.intr_pin);
446 PrintBoth(" bridge_ctl: 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.bridge_ctl);
447 PrintBoth(" subsys_vend_id: 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.subsystem_vendor_id);
448 PrintBoth(" subsys_dev_id: 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.subsystem_device_id);
449 PrintBoth(" legacy16_base: 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.legacy_16bit_base_addr);
451 for (i = 0; i < 14; i++) {
452 PrintBoth(" reserved2[%d]: 0x%x\n",
453 (uint_t)thedev->config.u.pci_cardbus_bridge_config.reserved2[i]);
456 for (i = 0; i < 48; i++) {
457 PrintBoth(" device_data[%d]: 0x%x\n", i,
458 (uint_t)thedev->config.u.pci_cardbus_bridge_config.device_data[i]);
462 static void PrintPCIUnknown(struct pci_device * thedev) {
463 PrintBoth(" PCI Unknown Element\n");
464 PrintPCIShared(thedev);
467 static void PrintPCIElement(struct pci_device * thedev) {
468 switch (HEADER_TYPE(thedev->config.header_type)) {
471 PrintPCIDevice(thedev);
475 PrintPCIPCIBridge(thedev);
478 case PCI_CARDBUS_BRIDGE:
479 PrintPCICardbusBridge(thedev);
483 PrintPCIUnknown(thedev);
489 static void PrintPCIBus(struct pci_bus * thebus) {
490 struct pci_device * thedev;
492 PrintBoth(" PCI Bus:\n");
493 PrintBoth(" Number: %u\n",thebus->number);
495 thedev = thebus->device_list;
498 PrintPCIElement(thedev);
499 thedev = thedev->next;
503 static void PrintPCI(struct pci * thepci) {
504 struct pci_bus * thebus;
506 PrintBoth("PCI Configuration:\n");
507 PrintBoth(" Number of Buses: %u\n", thepci->num_buses);
509 thebus = thepci->bus_list;
513 thebus = thebus->next;