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_symspy.h>
41 #include <devices/pci.h>
42 #include <devices/pci_types.h>
44 // Hardcoded... Are these standard??
45 #define PCI_CFG_ADDR 0xcf8
46 #define PCI_CFG_DATA 0xcfc
49 #define PCI_DEV_MAX 32
52 #define PCI_DEVICE 0x0
53 #define PCI_PCI_BRIDGE 0x1
54 #define PCI_CARDBUS_BRIDGE 0x2
56 #define PCI_HDR_SIZE 256
69 } __attribute__((packed));
70 } __attribute__((packed));
73 typedef enum { PT_BAR_NONE,
79 PT_EXP_ROM } pt_bar_type_t;
85 /* We store 64 bit memory bar addresses in the high BAR
86 * because they are the last to be updated
87 * This means that the addr field must be 64 bits
99 uint8_t config_space[256];
100 struct pci_config_header real_hdr;
101 } __attribute__((packed));
103 struct pt_bar phys_bars[6];
104 struct pt_bar virt_bars[6];
106 struct pt_bar phys_exp_rom;
107 struct pt_bar virt_exp_rom;
109 struct vm_device * pci_bus;
110 struct pci_device * pci_dev;
112 union pci_addr_reg phys_pci_addr;
118 static inline uint32_t pci_cfg_read32(uint32_t addr) {
119 v3_outdw(PCI_CFG_ADDR, addr);
120 return v3_indw(PCI_CFG_DATA);
125 static inline void pci_cfg_write32(uint32_t addr, uint32_t val) {
126 v3_outdw(PCI_CFG_ADDR, addr);
127 v3_outdw(PCI_CFG_DATA, val);
132 static inline uint16_t pci_cfg_read16(uint32_t addr) {
133 v3_outw(PCI_CFG_ADDR, addr);
134 return v3_inw(PCI_CFG_DATA);
139 static inline void pci_cfg_write16(uint32_t addr, uint16_t val) {
140 v3_outw(PCI_CFG_ADDR, addr);
141 v3_outw(PCI_CFG_DATA, val);
146 static inline uint8_t pci_cfg_read8(uint32_t addr) {
147 v3_outb(PCI_CFG_ADDR, addr);
148 return v3_inb(PCI_CFG_DATA);
153 static inline void pci_cfg_write8(uint32_t addr, uint8_t val) {
154 v3_outb(PCI_CFG_ADDR, addr);
155 v3_outb(PCI_CFG_DATA, val);
160 static int pci_exp_rom_init(struct vm_device * dev, struct pt_dev_state * state) {
161 struct pci_device * pci_dev = state->pci_dev;
162 const uint32_t exp_rom_base_reg = 12;
163 union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
164 uint32_t max_val = 0;
165 uint32_t rom_val = 0;
166 struct pt_bar * prom = &(state->phys_exp_rom);
167 struct pt_bar * vrom = &(state->virt_exp_rom);
169 // should read from cached header
170 pci_addr.reg = exp_rom_base_reg;
172 rom_val = pci_cfg_read32(pci_addr.value);
175 prom->type = PT_EXP_ROM;
177 max_val = rom_val | PCI_EXP_ROM_MASK;
179 // Cycle the physical bar, to determine the actual size
180 // Disable irqs, to try to prevent accesses to the space via a interrupt handler
181 // This is not SMP safe!!
182 // What we probably want to do is write a 0 to the command register
183 //irq_state = v3_irq_save();
185 pci_cfg_write32(pci_addr.value, max_val);
186 max_val = pci_cfg_read32(pci_addr.value);
187 pci_cfg_write32(pci_addr.value, rom_val);
189 //v3_irq_restore(irq_state);
191 prom->type = PT_EXP_ROM;
192 prom->addr = PCI_EXP_ROM_BASE(rom_val);
193 prom->size = ~PCI_EXP_ROM_BASE(max_val) + 1;
195 PrintDebug(VM_NONE, VCORE_NONE, "Adding 32 bit PCI mem region: start=%p, end=%p\n",
196 (void *)(addr_t)prom->addr,
197 (void *)(addr_t)(prom->addr + prom->size));
199 if ((prom->val & 0x1) == 0x1) {
200 // only map shadow memory if the ROM is enabled
202 v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY,
204 prom->addr + prom->size - 1,
208 // Initially the virtual location matches the physical ones
209 memcpy(&(state->virt_exp_rom), &(state->phys_exp_rom), sizeof(struct pt_bar));
211 PrintDebug(VM_NONE, VCORE_NONE, "exp_rom_val=0x%x\n", rom_val);
213 PrintDebug(VM_NONE, VCORE_NONE, "phys exp_rom: addr=%p, size=%u\n",
214 (void *)(addr_t)prom->addr,
217 PrintDebug(VM_NONE, VCORE_NONE, "virt exp_rom: addr=%p, size=%u\n",
218 (void *)(addr_t)vrom->addr,
221 // Update the pci subsystem versions
222 pci_dev->config_header.expansion_rom_address = rom_val;
228 // We initialize this
229 static int pci_bar_init(int bar_num, uint32_t * dst, void * private_data) {
230 struct vm_device * dev = (struct vm_device *)private_data;
231 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
232 const uint32_t bar_base_reg = 4;
233 union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
234 uint32_t bar_val = 0;
235 uint32_t max_val = 0;
236 //addr_t irq_state = 0;
237 struct pt_bar * pbar = &(state->phys_bars[bar_num]);
239 // should read from cached header
240 pci_addr.reg = bar_base_reg + bar_num;
242 PrintDebug(VM_NONE, VCORE_NONE, "PCI Address = 0x%x\n", pci_addr.value);
244 bar_val = pci_cfg_read32(pci_addr.value);
247 // We preset this type when we encounter a MEM64 Low BAR
248 if (pbar->type == PT_BAR_MEM64_HI) {
249 struct pt_bar * lo_pbar = &(state->phys_bars[bar_num - 1]);
251 max_val = PCI_MEM64_MASK_HI;
253 pci_cfg_write32(pci_addr.value, max_val);
254 max_val = pci_cfg_read32(pci_addr.value);
255 pci_cfg_write32(pci_addr.value, bar_val);
257 pbar->addr = PCI_MEM64_BASE_HI(bar_val);
259 pbar->addr |= lo_pbar->addr;
261 // Executive Decision: We will not support devices with memory mapped regions over 4GB
262 // The right way to do this would be to change 'size' to the order (power of 2) of the region
263 pbar->size += lo_pbar->size;
265 PrintDebug(VM_NONE, VCORE_NONE, "Adding 64 bit PCI mem region: start=0x%p, end=0x%p\n",
266 (void *)(addr_t)pbar->addr,
267 (void *)(addr_t)(pbar->addr + pbar->size));
270 if (v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY, pbar->addr,
271 pbar->addr + pbar->size - 1, pbar->addr) == -1) {
273 PrintError(VM_NONE, VCORE_NONE, "Fail to insert shadow region (0x%p, 0x%p) -> 0x%p\n",
274 (void *)(addr_t)pbar->addr,
275 (void *)(addr_t)(pbar->addr + pbar->size - 1),
276 (void *)(addr_t)pbar->addr);
280 } else if ((bar_val & 0x3) == 0x1) {
284 pbar->type = PT_BAR_IO;
285 pbar->addr = PCI_IO_BASE(bar_val);
287 max_val = bar_val | PCI_IO_MASK;
289 // Cycle the physical bar, to determine the actual size
290 // Disable irqs, to try to prevent accesses to the space via a interrupt handler
291 // This is not SMP safe!!
292 // What we probably want to do is write a 0 to the command register
293 //irq_state = v3_irq_save();
295 pci_cfg_write32(pci_addr.value, max_val);
296 max_val = pci_cfg_read32(pci_addr.value);
297 pci_cfg_write32(pci_addr.value, bar_val);
299 //v3_irq_restore(irq_state);
301 V3_Print(VM_NONE, VCORE_NONE, "max_val = %x\n", max_val);
303 pbar->size = (uint16_t)~PCI_IO_BASE(max_val) + 1;
306 V3_Print(VM_NONE, VCORE_NONE, "IO Bar with %d (%x) ports %x->%x\n", pbar->size, pbar->size,
307 (uint32_t)pbar->addr, (uint32_t)pbar->addr + pbar->size);
308 // setup a set of null io hooks
309 // This allows the guest to do passthrough IO to these ports
310 // While still reserving them in the IO map
311 for (i = 0; i < pbar->size; i++) {
312 v3_hook_io_port(dev->vm, pbar->addr + i, NULL, NULL, NULL);
317 // might be memory, might be nothing
319 max_val = bar_val | PCI_MEM_MASK;
321 // Cycle the physical bar, to determine the actual size
322 // Disable irqs, to try to prevent accesses to the space via a interrupt handler
323 // This is not SMP safe!!
324 // What we probably want to do is write a 0 to the command register
325 //irq_state = v3_irq_save();
327 pci_cfg_write32(pci_addr.value, max_val);
328 max_val = pci_cfg_read32(pci_addr.value);
329 pci_cfg_write32(pci_addr.value, bar_val);
331 //v3_irq_restore(irq_state);
335 pbar->type = PT_BAR_NONE;
338 // if its a memory region, setup passthrough mem mapping
340 if ((bar_val & 0x6) == 0x0) {
342 pbar->type = PT_BAR_MEM32;
343 pbar->addr = PCI_MEM32_BASE(bar_val);
344 pbar->size = ~PCI_MEM32_BASE(max_val) + 1;
346 PrintDebug(VM_NONE, VCORE_NONE, "Adding 32 bit PCI mem region: start=%p, end=%p\n",
347 (void *)(addr_t)pbar->addr,
348 (void *)(addr_t)(pbar->addr + pbar->size));
350 v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY,
352 pbar->addr + pbar->size - 1,
355 } else if ((bar_val & 0x6) == 0x2) {
357 pbar->type = PT_BAR_MEM24;
358 pbar->addr = PCI_MEM24_BASE(bar_val);
359 pbar->size = ~PCI_MEM24_BASE(max_val) + 1;
361 v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY,
363 pbar->addr + pbar->size - 1,
366 } else if ((bar_val & 0x6) == 0x4) {
367 struct pt_bar * hi_pbar = &(state->phys_bars[bar_num + 1]);
369 pbar->type = PT_BAR_MEM64_LO;
370 hi_pbar->type = PT_BAR_MEM64_HI;
372 // Set the low bits, only for temporary storage until we calculate the high BAR
373 pbar->addr = PCI_MEM64_BASE_LO(bar_val);
374 pbar->size = ~PCI_MEM64_BASE_LO(max_val) + 1;
377 PrintError(VM_NONE, VCORE_NONE, "Invalid Memory bar type\n");
385 // Initially the virtual bars match the physical ones
386 memcpy(&(state->virt_bars[bar_num]), &(state->phys_bars[bar_num]), sizeof(struct pt_bar));
388 PrintDebug(VM_NONE, VCORE_NONE, "bar_num=%d, bar_val=0x%x\n", bar_num, bar_val);
390 PrintDebug(VM_NONE, VCORE_NONE, "phys bar type=%d, addr=%p, size=%d\n",
391 pbar->type, (void *)(addr_t)pbar->addr,
394 PrintDebug(VM_NONE, VCORE_NONE, "virt bar type=%d, addr=%p, size=%d\n",
395 state->virt_bars[bar_num].type, (void *)(addr_t)state->virt_bars[bar_num].addr,
396 state->virt_bars[bar_num].size);
398 // Update the pci subsystem versions
404 static int pt_io_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data) {
405 struct pt_bar * pbar = (struct pt_bar *)priv_data;
406 int port_offset = port % pbar->size;
409 *(uint8_t *)dst = v3_inb(pbar->addr + port_offset);
410 } else if (length == 2) {
411 *(uint16_t *)dst = v3_inw(pbar->addr + port_offset);
412 } else if (length == 4) {
413 *(uint32_t *)dst = v3_indw(pbar->addr + port_offset);
415 PrintError(core->vm_info, core, "Invalid PCI passthrough IO Redirection size read\n");
423 static int pt_io_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data) {
424 struct pt_bar * pbar = (struct pt_bar *)priv_data;
425 int port_offset = port % pbar->size;
428 v3_outb(pbar->addr + port_offset, *(uint8_t *)src);
429 } else if (length == 2) {
430 v3_outw(pbar->addr + port_offset, *(uint16_t *)src);
431 } else if (length == 4) {
432 v3_outdw(pbar->addr + port_offset, *(uint32_t *)src);
434 PrintError(core->vm_info, core, "Invalid PCI passthrough IO Redirection size write\n");
446 static int pci_bar_write(int bar_num, uint32_t * src, void * private_data) {
447 struct vm_device * dev = (struct vm_device *)private_data;
448 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
450 struct pt_bar * pbar = &(state->phys_bars[bar_num]);
451 struct pt_bar * vbar = &(state->virt_bars[bar_num]);
453 PrintDebug(VM_NONE, VCORE_NONE, "Bar update: bar_num=%d, src=0x%x\n", bar_num, *src);
454 PrintDebug(VM_NONE, VCORE_NONE, "vbar is size=%u, type=%d, addr=%p, val=0x%x\n",
455 vbar->size, vbar->type, (void *)(addr_t)vbar->addr, vbar->val);
456 PrintDebug(VM_NONE, VCORE_NONE, "pbar is size=%u, type=%d, addr=%p, val=0x%x\n",
457 pbar->size, pbar->type, (void *)(addr_t)pbar->addr, pbar->val);
461 if (vbar->type == PT_BAR_NONE) {
463 } else if (vbar->type == PT_BAR_IO) {
467 for (i = 0; i < vbar->size; i++) {
468 if (v3_unhook_io_port(dev->vm, vbar->addr + i) == -1) {
469 PrintError(VM_NONE, VCORE_NONE, "Could not unhook previously hooked port.... %d (0x%x)\n",
470 (uint32_t)vbar->addr + i, (uint32_t)vbar->addr + i);
475 PrintDebug(VM_NONE, VCORE_NONE, "Setting IO Port range size=%d\n", pbar->size);
477 // clear the low bits to match the size
478 *src &= ~(pbar->size - 1);
481 *src |= (pbar->val & ~PCI_IO_MASK);
483 vbar->addr = PCI_IO_BASE(*src);
485 PrintDebug(VM_NONE, VCORE_NONE, "Cooked src=0x%x\n", *src);
487 PrintDebug(VM_NONE, VCORE_NONE, "Rehooking passthrough IO ports starting at %d (0x%x)\n",
488 (uint32_t)vbar->addr, (uint32_t)vbar->addr);
490 if (vbar->addr == pbar->addr) {
491 // Map the io ports as passthrough
492 for (i = 0; i < pbar->size; i++) {
493 v3_hook_io_port(dev->vm, pbar->addr + i, NULL, NULL, NULL);
496 // We have to manually handle the io redirection
497 for (i = 0; i < vbar->size; i++) {
498 v3_hook_io_port(dev->vm, vbar->addr + i, pt_io_read, pt_io_write, pbar);
501 } else if (vbar->type == PT_BAR_MEM32) {
502 // remove old mapping
503 struct v3_mem_region * old_reg = v3_get_mem_region(dev->vm, V3_MEM_CORE_ANY, vbar->addr);
505 if (old_reg == NULL) {
507 PrintError(VM_NONE, VCORE_NONE, "Could not find PCI Passthrough memory redirection region (addr=0x%x)\n", (uint32_t)vbar->addr);
511 v3_delete_mem_region(dev->vm, old_reg);
513 // clear the low bits to match the size
514 *src &= ~(pbar->size - 1);
517 *src |= (pbar->val & ~PCI_MEM_MASK);
519 PrintDebug(VM_NONE, VCORE_NONE, "Cooked src=0x%x\n", *src);
521 vbar->addr = PCI_MEM32_BASE(*src);
523 PrintDebug(VM_NONE, VCORE_NONE, "Adding pci Passthrough remapping: start=0x%x, size=%d, end=0x%x\n",
524 (uint32_t)vbar->addr, vbar->size, (uint32_t)vbar->addr + vbar->size);
526 v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY,
528 vbar->addr + vbar->size - 1,
531 } else if (vbar->type == PT_BAR_MEM64_LO) {
532 // We only store the written values here, the actual reconfig comes when the high BAR is updated
534 // clear the low bits to match the size
535 *src &= ~(pbar->size - 1);
538 *src |= (pbar->val & ~PCI_MEM_MASK);
540 // Temp storage, used when hi bar is written
541 vbar->addr = PCI_MEM64_BASE_LO(*src);
543 } else if (vbar->type == PT_BAR_MEM64_HI) {
544 struct pt_bar * lo_vbar = &(state->virt_bars[bar_num - 1]);
545 struct v3_mem_region * old_reg = v3_get_mem_region(dev->vm, V3_MEM_CORE_ANY, vbar->addr);
547 if (old_reg == NULL) {
549 PrintError(VM_NONE, VCORE_NONE, "Could not find PCI Passthrough memory redirection region (addr=%p)\n",
550 (void *)(addr_t)vbar->addr);
554 // remove old mapping
555 v3_delete_mem_region(dev->vm, old_reg);
557 // We don't set size, because we assume region is less than 4GB
560 *src |= (pbar->val & ~PCI_MEM64_MASK_HI);
562 vbar->addr = PCI_MEM64_BASE_HI(*src);
564 vbar->addr += lo_vbar->addr;
566 PrintDebug(VM_NONE, VCORE_NONE, "Adding pci Passthrough remapping: start=%p, size=%p, end=%p\n",
567 (void *)(addr_t)vbar->addr, (void *)(addr_t)vbar->size,
568 (void *)(addr_t)(vbar->addr + vbar->size));
570 if (v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY, vbar->addr,
571 vbar->addr + vbar->size - 1, pbar->addr) == -1) {
573 PrintDebug(VM_NONE, VCORE_NONE, "Fail to insert shadow region (%p, %p) -> %p\n",
574 (void *)(addr_t)vbar->addr,
575 (void *)(addr_t)(vbar->addr + vbar->size - 1),
576 (void *)(addr_t)pbar->addr);
581 PrintError(VM_NONE, VCORE_NONE, "Unhandled Pasthrough PCI Bar type %d\n", vbar->type);
591 static int pt_config_update(struct pci_device * pci_dev, uint_t reg_num, void * src, uint_t length, void * private_data) {
592 struct vm_device * dev = (struct vm_device *)private_data;
593 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
594 union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
596 pci_addr.reg = reg_num >> 2;
599 pci_cfg_write8(pci_addr.value, *(uint8_t *)src);
600 } else if (length == 2) {
601 pci_cfg_write16(pci_addr.value, *(uint16_t *)src);
602 } else if (length == 4) {
603 pci_cfg_write32(pci_addr.value, *(uint32_t *)src);
610 /* This is really iffy....
611 * It was totally broken before, but it's _not_ totally fixed now
612 * The Expansion rom can be enabled/disabled via software using the low order bit
613 * We should probably handle that somehow here...
615 static int pt_exp_rom_write(struct pci_device * pci_dev, uint32_t * src, void * priv_data) {
616 struct vm_device * dev = (struct vm_device *)(priv_data);
617 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
619 struct pt_bar * prom = &(state->phys_exp_rom);
620 struct pt_bar * vrom = &(state->virt_exp_rom);
622 PrintDebug(VM_NONE, VCORE_NONE, "exp_rom update: src=0x%x\n", *src);
623 PrintDebug(VM_NONE, VCORE_NONE, "vrom is size=%u, addr=0x%x, val=0x%x\n", vrom->size, (uint32_t)vrom->addr, vrom->val);
624 PrintDebug(VM_NONE, VCORE_NONE, "prom is size=%u, addr=0x%x, val=0x%x\n", prom->size, (uint32_t)prom->addr, prom->val);
626 // only remove old mapping if present, I.E. if the rom was enabled previously
627 if ((vrom->val & 0x1) == 0x1) {
628 struct v3_mem_region * old_reg = v3_get_mem_region(dev->vm, V3_MEM_CORE_ANY, vrom->addr);
630 if (old_reg == NULL) {
632 PrintError(VM_NONE, VCORE_NONE, "Could not find PCI Passthrough exp_rom_base redirection region (addr=0x%x)\n", (uint32_t)vrom->addr);
636 v3_delete_mem_region(dev->vm, old_reg);
639 // clear the low bits to match the size
640 *src &= ~(prom->size - 1);
643 *src |= (prom->val & ~PCI_EXP_ROM_MASK);
645 PrintDebug(VM_NONE, VCORE_NONE, "Cooked src=0x%x\n", *src);
647 vrom->addr = PCI_EXP_ROM_BASE(*src);
650 if ((prom->val & 0x1) == 0x1) {
651 PrintDebug(VM_NONE, VCORE_NONE, "Adding pci Passthrough exp_rom_base remapping: start=0x%x, size=%u, end=0x%x\n",
652 (uint32_t)vrom->addr, vrom->size, (uint32_t)vrom->addr + vrom->size);
654 if (v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY, vrom->addr,
655 vrom->addr + vrom->size - 1, prom->addr) == -1) {
656 PrintError(VM_NONE, VCORE_NONE, "Failed to remap pci exp_rom: start=0x%x, size=%u, end=0x%x\n",
657 (uint32_t)vrom->addr, vrom->size, (uint32_t)vrom->addr + vrom->size);
668 static int find_real_pci_dev(uint16_t vendor_id, uint16_t device_id, struct pt_dev_state * state) {
669 union pci_addr_reg pci_addr = {0x80000000};
677 } __attribute__((packed));
678 } __attribute__((packed)) pci_hdr = {0};
680 //PrintDebug(VM_NONE, VCORE_NONE, "Scanning PCI busses for vendor=%x, device=%x\n", vendor_id, device_id);
681 for (i = 0, pci_addr.bus = 0; i < PCI_BUS_MAX; i++, pci_addr.bus++) {
682 for (j = 0, pci_addr.dev = 0; j < PCI_DEV_MAX; j++, pci_addr.dev++) {
683 for (k = 0, pci_addr.func = 0; k < PCI_FN_MAX; k++, pci_addr.func++) {
685 v3_outdw(PCI_CFG_ADDR, pci_addr.value);
686 pci_hdr.value = v3_indw(PCI_CFG_DATA);
688 //PrintDebug(VM_NONE, VCORE_NONE, "\bus=%d, tvendor=%x, device=%x\n", pci_addr.bus, pci_hdr.vendor, pci_hdr.device);
690 if ((pci_hdr.vendor == vendor_id) && (pci_hdr.device == device_id)) {
691 uint32_t * cfg_space = (uint32_t *)&state->real_hdr;
693 state->phys_pci_addr = pci_addr;
695 // Copy the configuration space to the local cached version
696 for (m = 0, pci_addr.reg = 0; m < PCI_HDR_SIZE; m += 4, pci_addr.reg++) {
697 cfg_space[pci_addr.reg] = pci_cfg_read32(pci_addr.value);
701 PrintDebug(VM_NONE, VCORE_NONE, "Found device %x:%x (bus=%d, dev=%d, func=%d)\n",
702 vendor_id, device_id,
703 pci_addr.bus, pci_addr.dev, pci_addr.func);
716 static int setup_virt_pci_dev(struct v3_vm_info * vm_info, struct vm_device * dev) {
717 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
718 struct pci_device * pci_dev = NULL;
719 struct v3_pci_bar bars[6];
723 for (i = 0; i < 6; i++) {
724 bars[i].type = PCI_BAR_PASSTHROUGH;
725 bars[i].private_data = dev;
726 bars[i].bar_init = pci_bar_init;
727 bars[i].bar_write = pci_bar_write;
730 pci_dev = v3_pci_register_device(state->pci_bus,
741 // This will overwrite the bar registers.. but that should be ok.
742 memcpy(pci_dev->config_space, (uint8_t *)&(state->real_hdr), sizeof(struct pci_config_header));
744 state->pci_dev = pci_dev;
746 pci_exp_rom_init(dev, state);
748 v3_sym_map_pci_passthrough(vm_info, pci_dev->bus_num, pci_dev->dev_num, pci_dev->fn_num);
755 static struct v3_device_ops dev_ops = {
761 static int irq_handler(struct v3_vm_info * vm, struct v3_interrupt * intr, void * private_data) {
762 struct vm_device * dev = (struct vm_device *)private_data;
763 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
766 v3_pci_raise_irq(state->pci_bus, state->pci_dev, 0);
768 V3_ACK_IRQ(intr->irq);
776 static int passthrough_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
777 struct pt_dev_state * state = V3_Malloc(sizeof(struct pt_dev_state));
778 struct vm_device * dev = NULL;
779 struct vm_device * pci = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
780 char * dev_id = v3_cfg_val(cfg, "ID");
783 PrintError(vm, VCORE_NONE, "Cannot allocate in init\n");
787 memset(state, 0, sizeof(struct pt_dev_state));
790 PrintError(vm, VCORE_NONE, "Could not find PCI device\n");
794 state->pci_bus = pci;
795 strncpy(state->name, dev_id, 32);
798 dev = v3_add_device(vm, dev_id, &dev_ops, state);
801 PrintError(vm, VCORE_NONE, "Could not attach device %s\n", dev_id);
807 if (find_real_pci_dev(atox(v3_cfg_val(cfg, "vendor_id")),
808 atox(v3_cfg_val(cfg, "device_id")),
810 PrintError(vm, VCORE_NONE, "Could not find PCI Device %s:%s\n",
811 v3_cfg_val(cfg, "vendor_id"),
812 v3_cfg_val(cfg, "device_id"));
813 v3_remove_device(dev);
817 setup_virt_pci_dev(vm, dev);
819 v3_hook_irq(vm, atoi(v3_cfg_val(cfg, "irq")), irq_handler, dev);
820 // v3_hook_irq(info, 64, irq_handler, dev);
828 device_register("PCI_PASSTHROUGH", passthrough_init)