1/** 2 * \file PCI bus 3 * 4 * Virtual PCI bus implementation. 5 */ 6 7/* 8 * Copyright (c) 2009, ETH Zurich. 9 * All rights reserved. 10 * 11 * This file is distributed under the terms in the attached LICENSE file. 12 * If you do not find this file, copies can be found by writing to: 13 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 14 */ 15 16#include <stdlib.h> 17 18#include "vmkitmon.h" 19#include "pci.h" 20#include "pci_devices.h" 21 22#define INVALID 0xffffffff 23 24int pci_handle_pio_write(struct pci *pci, uint16_t port, enum opsize size, 25 uint32_t val) 26{ 27 assert(pci != NULL); 28 29 switch(port) { 30 case 0xcf8: // PCI config address port 31 VMKIT_PCI_DEBUG("wrote %x to 0xcf8\n", val); 32 if(size == OPSIZE_32) { 33 pci->address.raw = val; 34 } else { 35 VMKIT_PCI_DEBUG("ignoring write (not 32bit opsize)\n"); 36 } 37 break; 38 39 case 0xcfc: // PCI config data port 40 case 0xcfd: 41 case 0xcfe: 42 case 0xcff: 43 44 if(port != 0xcfc) { 45 printf("!!!!!!!!!!!!!!!!! Unaligned write !!!!!!!!!!!!!!!\n"); 46 } 47 48 VMKIT_PCI_DEBUG("wrote %x to 0x%x\n", val, port); 49 { 50 int busnr = pci->address.d.bus_nr; 51 int device = pci->address.d.dev_nr; 52 struct pci_bus *bus = pci->bus[busnr]; 53 54 if(bus == NULL) { 55 break; 56 } 57 58 struct pci_device *dev = bus->device[device]; 59 60 if(dev != NULL) { 61 dev->confspace_write(dev, pci->address, size, val); 62 } 63 } 64 break; 65 66 default: 67 VMKIT_PCI_DEBUG("write to invalid port\n"); 68 break; 69 } 70 71 return 0; 72} 73 74int pci_handle_pio_read(struct pci *pci, uint16_t port, enum opsize size, 75 uint32_t *val) 76{ 77 assert(pci != NULL); 78 79 switch(port) { 80 case 0xcf8: // PCI config address port 81 *val = pci->address.raw; 82 VMKIT_PCI_DEBUG("read from 0xcf8: %x\n", *val); 83 break; 84 85 case 0xcfc: // PCI config data port 86 case 0xcfd: 87 case 0xcfe: 88 case 0xcff: 89 { 90 int busnr = pci->address.d.bus_nr; 91 int device = pci->address.d.dev_nr; 92 struct pci_bus *bus = pci->bus[busnr]; 93 94 if(bus == NULL) { 95 *val = INVALID; 96 break; 97 } 98 99 struct pci_device *dev = bus->device[device]; 100 101 if(dev != NULL) { 102 dev->confspace_read(dev, pci->address, size, val); 103 } else { 104 *val = INVALID; 105 } 106 } 107 108 // Shift on unaligned read (masking is done later) 109 *val >>= (port - 0xcfc) * 8; 110 111 VMKIT_PCI_DEBUG("read %x from 0x%x\n", *val, port); 112 break; 113 114 default: 115 VMKIT_PCI_DEBUG("read from invalid port\n"); 116 break; 117 } 118 119 return 0; 120} 121 122static struct pci_bus *pci_new_bus(void) 123{ 124 struct pci_bus *bus = calloc(1, sizeof(struct pci_bus)); 125 return bus; 126} 127 128struct pci *pci_new(void) 129{ 130 struct pci *pci = calloc(1, sizeof(struct pci)); 131 132 pci->bus[0] = pci_new_bus(); 133 134 // Put a host-bridge on the bus (Linux expects to find one) 135 struct pci_device *bridge = pci_hostbridge_new(); 136 pci_attach_device(pci, 0, 0, bridge); 137 138 return pci; 139} 140 141int pci_attach_device(struct pci *pci, uint8_t busnr, uint8_t devnr, 142 struct pci_device *device) 143{ 144 struct pci_bus *bus = pci->bus[busnr]; 145 146 if(bus == NULL) { 147 return -1; 148 } 149 150 if(bus->device[devnr] != NULL) { 151 return -2; 152 } 153 154 bus->device[devnr] = device; 155 return 0; 156} 157