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, Jack Lange <jarusl@cs.northwestern.edu>
11 * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
21 /* This is the generic passthrough PCI virtual device */
24 * The basic idea is that we do not change the hardware PCI configuration
25 * Instead we modify the guest environment to map onto the physical configuration
27 * The pci subsystem handles most of the configuration space, except for the bar registers.
28 * We handle them here, by either letting them go directly to hardware or remapping through virtual hooks
30 * Memory Bars are always remapped via the shadow map,
31 * IO Bars are selectively remapped through hooks if the guest changes them
34 #include <palacios/vmm.h>
35 #include <palacios/vmm_dev_mgr.h>
36 #include <palacios/vmm_sprintf.h>
37 #include <palacios/vmm_lowlevel.h>
38 #include <palacios/vm_guest.h> // must include this to avoid dependency issue
39 #include <palacios/vmm_sym_iface.h>
41 #include <devices/pci.h>
42 #include <devices/pci_types.h>
45 // Hardcoded... Are these standard??
46 #define PCI_CFG_ADDR 0xcf8
47 #define PCI_CFG_DATA 0xcfc
50 #define PCI_DEV_MAX 32
53 #define PCI_DEVICE 0x0
54 #define PCI_PCI_BRIDGE 0x1
55 #define PCI_CARDBUS_BRIDGE 0x2
57 #define PCI_HDR_SIZE 256
70 } __attribute__((packed));
71 } __attribute__((packed));
74 typedef enum { PT_BAR_NONE,
79 PT_BAR_MEM64_HIGH } pt_bar_type_t;
91 uint8_t config_space[256];
92 struct pci_config_header real_hdr;
93 } __attribute__((packed));
95 struct pt_bar phys_bars[6];
96 struct pt_bar virt_bars[6];
99 struct vm_device * pci_bus;
100 struct pci_device * pci_dev;
102 union pci_addr_reg phys_pci_addr;
108 static inline uint32_t pci_cfg_read32(uint32_t addr) {
109 v3_outdw(PCI_CFG_ADDR, addr);
110 return v3_indw(PCI_CFG_DATA);
115 static inline void pci_cfg_write32(uint32_t addr, uint32_t val) {
116 v3_outdw(PCI_CFG_ADDR, addr);
117 v3_outdw(PCI_CFG_DATA, val);
122 static inline uint16_t pci_cfg_read16(uint32_t addr) {
123 v3_outw(PCI_CFG_ADDR, addr);
124 return v3_inw(PCI_CFG_DATA);
129 static inline void pci_cfg_write16(uint32_t addr, uint16_t val) {
130 v3_outw(PCI_CFG_ADDR, addr);
131 v3_outw(PCI_CFG_DATA, val);
136 static inline uint8_t pci_cfg_read8(uint32_t addr) {
137 v3_outb(PCI_CFG_ADDR, addr);
138 return v3_inb(PCI_CFG_DATA);
143 static inline void pci_cfg_write8(uint32_t addr, uint8_t val) {
144 v3_outb(PCI_CFG_ADDR, addr);
145 v3_outb(PCI_CFG_DATA, val);
149 // We initialize this
150 static int pci_bar_init(int bar_num, uint32_t * dst,void * private_data) {
151 struct vm_device * dev = (struct vm_device *)private_data;
152 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
153 const uint32_t bar_base_reg = 4;
154 union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
155 uint32_t bar_val = 0;
156 uint32_t max_val = 0;
157 //addr_t irq_state = 0;
158 struct pt_bar * pbar = &(state->phys_bars[bar_num]);
161 // should read from cached header
162 pci_addr.reg = bar_base_reg + bar_num;
164 PrintDebug("PCI Address = 0x%x\n", pci_addr.value);
166 bar_val = pci_cfg_read32(pci_addr.value);
169 if ((bar_val & 0x3) == 0x1) {
173 pbar->type = PT_BAR_IO;
174 pbar->addr = PCI_IO_BASE(bar_val);
176 max_val = bar_val | PCI_IO_MASK;
178 // Cycle the physical bar, to determine the actual size
179 // Disable irqs, to try to prevent accesses to the space via a interrupt handler
180 // This is not SMP safe!!
181 // What we probably want to do is write a 0 to the command register
182 //irq_state = v3_irq_save();
184 pci_cfg_write32(pci_addr.value, max_val);
185 max_val = pci_cfg_read32(pci_addr.value);
186 pci_cfg_write32(pci_addr.value, bar_val);
188 //v3_irq_restore(irq_state);
190 V3_Print("max_val = %x\n", max_val);
192 pbar->size = (uint16_t)~PCI_IO_BASE(max_val) + 1;
195 V3_Print("IO Bar with %d (%x) ports %x->%x\n", pbar->size, pbar->size, pbar->addr, pbar->addr + pbar->size);
196 // setup a set of null io hooks
197 // This allows the guest to do passthrough IO to these ports
198 // While still reserving them in the IO map
199 for (i = 0; i < pbar->size; i++) {
200 v3_hook_io_port(dev->vm, pbar->addr + i, NULL, NULL, NULL);
205 // might be memory, might be nothing
207 max_val = bar_val | PCI_MEM_MASK;
209 // Cycle the physical bar, to determine the actual size
210 // Disable irqs, to try to prevent accesses to the space via a interrupt handler
211 // This is not SMP safe!!
212 // What we probably want to do is write a 0 to the command register
213 //irq_state = v3_irq_save();
215 pci_cfg_write32(pci_addr.value, max_val);
216 max_val = pci_cfg_read32(pci_addr.value);
217 pci_cfg_write32(pci_addr.value, bar_val);
219 //v3_irq_restore(irq_state);
223 pbar->type = PT_BAR_NONE;
226 // if its a memory region, setup passthrough mem mapping
228 if ((bar_val & 0x6) == 0x0) {
230 pbar->type = PT_BAR_MEM32;
231 pbar->addr = PCI_MEM32_BASE(bar_val);
232 pbar->size = ~PCI_MEM32_BASE(max_val) + 1;
234 PrintDebug("Adding 32 bit PCI mem region: start=0x%x, end=0x%x\n",
235 pbar->addr, pbar->addr + pbar->size);
237 v3_add_shadow_mem(dev->vm,
239 pbar->addr + pbar->size - 1,
242 } else if ((bar_val & 0x6) == 0x2) {
244 pbar->type = PT_BAR_MEM24;
245 pbar->addr = PCI_MEM24_BASE(bar_val);
246 pbar->size = ~PCI_MEM24_BASE(max_val) + 1;
248 v3_add_shadow_mem(dev->vm,
250 pbar->addr + pbar->size - 1,
253 } else if ((bar_val & 0x6) == 0x4) {
255 PrintError("64 Bit PCI bars not supported\n");
258 PrintError("Invalid Memory bar type\n");
266 // Initially the virtual bars match the physical ones
267 memcpy(&(state->virt_bars[bar_num]), &(state->phys_bars[bar_num]), sizeof(struct pt_bar));
269 PrintDebug("bar_num=%d, bar_val=0x%x\n", bar_num, bar_val);
271 PrintDebug("phys bar type=%d, addr=0x%x, size=%d\n",
272 pbar->type, pbar->addr,
275 PrintDebug("virt bar type=%d, addr=0x%x, size=%d\n",
276 state->virt_bars[bar_num].type, state->virt_bars[bar_num].addr,
277 state->virt_bars[bar_num].size);
279 // Update the pci subsystem versions
285 static int pt_io_read(uint16_t port, void * dst, uint_t length, void * priv_data) {
286 struct pt_bar * pbar = (struct pt_bar *)priv_data;
287 int port_offset = port % pbar->size;
290 *(uint8_t *)dst = v3_inb(pbar->addr + port_offset);
291 } else if (length == 2) {
292 *(uint16_t *)dst = v3_inw(pbar->addr + port_offset);
293 } else if (length == 4) {
294 *(uint32_t *)dst = v3_indw(pbar->addr + port_offset);
296 PrintError("Invalid PCI passthrough IO Redirection size read\n");
304 static int pt_io_write(uint16_t port, void * src, uint_t length, void * priv_data) {
305 struct pt_bar * pbar = (struct pt_bar *)priv_data;
306 int port_offset = port % pbar->size;
309 v3_outb(pbar->addr + port_offset, *(uint8_t *)src);
310 } else if (length == 2) {
311 v3_outw(pbar->addr + port_offset, *(uint16_t *)src);
312 } else if (length == 4) {
313 v3_outdw(pbar->addr + port_offset, *(uint32_t *)src);
315 PrintError("Invalid PCI passthrough IO Redirection size write\n");
327 static int pci_bar_write(int bar_num, uint32_t * src, void * private_data) {
328 struct vm_device * dev = (struct vm_device *)private_data;
329 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
331 struct pt_bar * pbar = &(state->phys_bars[bar_num]);
332 struct pt_bar * vbar = &(state->virt_bars[bar_num]);
334 PrintDebug("Bar update: bar_num=%d, src=0x%x\n", bar_num,*src);
335 PrintDebug("vbar is size=%u, type=%d, addr=0x%x, val=0x%x\n",vbar->size, vbar->type, vbar->addr, vbar->val);
336 PrintDebug("pbar is size=%u, type=%d, addr=0x%x, val=0x%x\n",pbar->size, pbar->type, pbar->addr, pbar->val);
340 if (vbar->type == PT_BAR_NONE) {
342 } else if (vbar->type == PT_BAR_IO) {
346 for (i = 0; i < vbar->size; i++) {
347 if (v3_unhook_io_port(dev->vm, vbar->addr + i) == -1) {
348 PrintError("Could not unhook previously hooked port.... %d (0x%x)\n",
349 vbar->addr + i, vbar->addr + i);
354 PrintDebug("Setting IO Port range size=%d\n", pbar->size);
356 // clear the low bits to match the size
357 *src &= ~(pbar->size - 1);
360 *src |= (pbar->val & ~PCI_IO_MASK);
362 vbar->addr = PCI_IO_BASE(*src);
364 PrintDebug("Cooked src=0x%x\n", *src);
366 PrintDebug("Rehooking passthrough IO ports starting at %d (0x%x)\n",
367 vbar->addr, vbar->addr);
369 if (vbar->addr == pbar->addr) {
370 // Map the io ports as passthrough
371 for (i = 0; i < pbar->size; i++) {
372 v3_hook_io_port(dev->vm, pbar->addr + i, NULL, NULL, NULL);
375 // We have to manually handle the io redirection
376 for (i = 0; i < vbar->size; i++) {
377 v3_hook_io_port(dev->vm, vbar->addr + i, pt_io_read, pt_io_write, pbar);
380 } else if (vbar->type == PT_BAR_MEM32) {
381 // remove old mapping
382 struct v3_shadow_region * old_reg = v3_get_shadow_region(dev->vm, vbar->addr);
384 if (old_reg == NULL) {
386 PrintError("Could not find PCI Passthrough memory redirection region (addr=0x%x)\n", vbar->addr);
390 v3_delete_shadow_region(dev->vm, old_reg);
392 // clear the low bits to match the size
393 *src &= ~(pbar->size - 1);
396 *src |= (pbar->val & ~PCI_MEM_MASK);
398 PrintDebug("Cooked src=0x%x\n", *src);
400 vbar->addr = PCI_MEM32_BASE(*src);
402 PrintDebug("Adding pci Passthrough remapping: start=0x%x, size=%d, end=0x%x\n",
403 vbar->addr, vbar->size, vbar->addr + vbar->size);
405 v3_add_shadow_mem(dev->vm,
407 vbar->addr + vbar->size - 1,
411 PrintError("Unhandled Pasthrough PCI Bar type %d\n", vbar->type);
423 static int pt_config_update(uint_t reg_num, void * src, uint_t length, void * private_data) {
424 struct vm_device * dev = (struct vm_device *)private_data;
425 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
426 union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
428 pci_addr.reg = reg_num;
431 pci_cfg_write8(pci_addr.value, *(uint8_t *)src);
432 } else if (length == 2) {
433 pci_cfg_write16(pci_addr.value, *(uint16_t *)src);
434 } else if (length == 4) {
435 pci_cfg_write32(pci_addr.value, *(uint32_t *)src);
444 static int find_real_pci_dev(uint16_t vendor_id, uint16_t device_id, struct pt_dev_state * state) {
445 union pci_addr_reg pci_addr = {0x80000000};
453 } __attribute__((packed));
454 } __attribute__((packed)) pci_hdr = {0};
457 //PrintDebug("Scanning PCI busses for vendor=%x, device=%x\n", vendor_id, device_id);
458 for (i = 0, pci_addr.bus = 0; i < PCI_BUS_MAX; i++, pci_addr.bus++) {
459 for (j = 0, pci_addr.dev = 0; j < PCI_DEV_MAX; j++, pci_addr.dev++) {
460 for (k = 0, pci_addr.func = 0; k < PCI_FN_MAX; k++, pci_addr.func++) {
462 v3_outdw(PCI_CFG_ADDR, pci_addr.value);
463 pci_hdr.value = v3_indw(PCI_CFG_DATA);
465 //PrintDebug("\bus=%d, tvendor=%x, device=%x\n", pci_addr.bus, pci_hdr.vendor, pci_hdr.device);
467 if ((pci_hdr.vendor == vendor_id) && (pci_hdr.device == device_id)) {
468 uint32_t * cfg_space = (uint32_t *)&state->real_hdr;
470 state->phys_pci_addr = pci_addr;
472 // Copy the configuration space to the local cached version
473 for (m = 0, pci_addr.reg = 0; m < PCI_HDR_SIZE; m += 4, pci_addr.reg++) {
474 cfg_space[pci_addr.reg] = pci_cfg_read32(pci_addr.value);
478 PrintDebug("Found device %x:%x (bus=%d, dev=%d, func=%d)\n",
479 vendor_id, device_id,
480 pci_addr.bus, pci_addr.dev, pci_addr.func);
493 static int setup_virt_pci_dev(struct guest_info * info, struct vm_device * dev) {
494 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
495 struct pci_device * pci_dev = NULL;
496 struct v3_pci_bar bars[6];
500 for (i = 0; i < 6; i++) {
501 bars[i].type = PCI_BAR_PASSTHROUGH;
502 bars[i].private_data = dev;
503 bars[i].bar_init = pci_bar_init;
504 bars[i].bar_write = pci_bar_write;
507 pci_dev = v3_pci_register_device(state->pci_bus,
511 pt_config_update, NULL, NULL,
514 // This will overwrite the bar registers.. but that should be ok.
515 memcpy(pci_dev->config_space, (uint8_t *)&(state->real_hdr), sizeof(struct pci_config_header));
517 state->pci_dev = pci_dev;
519 v3_sym_map_pci_passthrough(info, pci_dev->bus_num, pci_dev->dev_num, pci_dev->fn_num);
526 static struct v3_device_ops dev_ops = {
535 static int irq_handler(struct guest_info * info, struct v3_interrupt * intr, void * private_data) {
536 struct vm_device * dev = (struct vm_device *)private_data;
537 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
539 // PrintDebug("Handling E1000 IRQ %d\n", intr->irq);
541 v3_pci_raise_irq(state->pci_bus, 0, state->pci_dev);
543 V3_ACK_IRQ(intr->irq);
551 static int passthrough_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
552 struct pt_dev_state * state = V3_Malloc(sizeof(struct pt_dev_state));
553 struct vm_device * dev = NULL;
554 struct vm_device * pci = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
555 char * name = v3_cfg_val(cfg, "name");
557 memset(state, 0, sizeof(struct pt_dev_state));
560 PrintError("Could not find PCI device\n");
564 state->pci_bus = pci;
565 strncpy(state->name, name, 32);
568 dev = v3_allocate_device(name, &dev_ops, state);
570 if (v3_attach_device(vm, dev) == -1) {
571 PrintError("Could not attach device %s\n", name);
576 if (find_real_pci_dev(atox(v3_cfg_val(cfg, "vendor_id")),
577 atox(v3_cfg_val(cfg, "device_id")),
579 PrintError("Could not find PCI Device %s:%s\n",
580 v3_cfg_val(cfg, "vendor_id"),
581 v3_cfg_val(cfg, "device_id"));
585 setup_virt_pci_dev(vm, dev);
587 v3_hook_irq(vm, atoi(v3_cfg_val(cfg, "irq")), irq_handler, dev);
588 // v3_hook_irq(info, 64, irq_handler, dev);
596 device_register("PCI_PASSTHROUGH", passthrough_init)