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,
78 PT_BAR_MEM64_HIGH } pt_bar_type_t;
90 struct pt_exp_rom_base {
98 uint8_t config_space[256];
99 struct pci_config_header real_hdr;
100 } __attribute__((packed));
102 struct pt_bar phys_bars[6];
103 struct pt_bar virt_bars[6];
106 struct pt_exp_rom_base phys_exp_rom_base;
107 struct pt_exp_rom_base virt_exp_rom_base;
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 inline bool is_pci_mem64_high_bar(struct pt_bar *prev_pbar)
162 return ((prev_pbar) &&
163 (prev_pbar->type == PT_BAR_MEM64_LOW));
168 static int pci_exp_rom_base_init(struct pci_device *pci_dev) {
170 struct vm_device *dev = (struct vm_device *)(pci_dev->priv_data);
171 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
172 const uint32_t exp_rom_base_reg = 12;
173 union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
174 uint32_t exp_rom_base_val = 0;
175 uint32_t max_val = 0;
177 uint32_t *dst = ((uint32_t *)(&(pci_dev->config_space[4 * exp_rom_base_reg])));
179 struct pt_exp_rom_base *pexp_rom_base = &(state->phys_exp_rom_base);
180 // struct pt_exp_rom_base *vexp_rom_base = &(state->virt_exp_rom_base);
182 // should read from cached header
183 pci_addr.reg = exp_rom_base_reg;
185 exp_rom_base_val = pci_cfg_read32(pci_addr.value);
186 pexp_rom_base->val = exp_rom_base_val;
188 max_val = exp_rom_base_val | PCI_EXP_ROM_BASE_MASK;
190 // Cycle the physical bar, to determine the actual size
191 // Disable irqs, to try to prevent accesses to the space via a interrupt handler
192 // This is not SMP safe!!
193 // What we probably want to do is write a 0 to the command register
194 //irq_state = v3_irq_save();
196 pci_cfg_write32(pci_addr.value, max_val);
197 max_val = pci_cfg_read32(pci_addr.value);
198 pci_cfg_write32(pci_addr.value, exp_rom_base_val);
200 //v3_irq_restore(irq_state);
204 PrintDebug("The real device doesn't implement the Exp_Rom_Base\n");
207 // if its a memory region, setup passthrough mem mapping
208 pexp_rom_base->addr = PCI_EXP_ROM_BASE(exp_rom_base_val);
209 pexp_rom_base->size = ~PCI_EXP_ROM_BASE(max_val) + 1;
211 PrintDebug("Adding 32 bit PCI mem region: start=0x%x, end=0x%x\n",
212 pexp_rom_base->addr, pexp_rom_base->addr + pexp_rom_base->size);
214 v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY,
216 pexp_rom_base->addr + pexp_rom_base->size - 1,
217 pexp_rom_base->addr);
221 // Initially the virtual bars match the physical ones
222 memcpy(&(state->virt_exp_rom_base), &(state->phys_exp_rom_base), sizeof(struct pt_exp_rom_base));
224 PrintDebug("exp_rom_base_val=0x%x\n", exp_rom_base_val);
226 PrintDebug("phys exp_rom_base: addr=0x%x, size=%u\n",
228 pexp_rom_base->size);
230 PrintDebug("virt exp_rom_base: addr=0x%x, size=%u\n",
231 state->virt_exp_rom_base.addr,
232 state->virt_exp_rom_base.size);
235 // Update the pci subsystem versions
236 *dst = exp_rom_base_val;
242 // We initialize this
243 static int pci_bar_init(int bar_num, uint32_t * dst, void * private_data) {
244 struct vm_device * dev = (struct vm_device *)private_data;
245 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
246 const uint32_t bar_base_reg = 4;
247 union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
248 uint32_t bar_val = 0;
249 uint32_t max_val = 0;
250 //addr_t irq_state = 0;
251 struct pt_bar * pbar = &(state->phys_bars[bar_num]);
252 // struct pt_bar * vbar = &(state->virt_bars[bar_num]);
254 struct pt_bar *prev_pbar = bar_num > 0 ?
255 (&(state->phys_bars[bar_num - 1])) :
258 struct pt_bar *prev_vbar = bar_num > 0 ?
259 (&(state->virt_bars[bar_num - 1])) :
262 // should read from cached header
263 pci_addr.reg = bar_base_reg + bar_num;
265 PrintDebug("PCI Address = 0x%x\n", pci_addr.value);
267 bar_val = pci_cfg_read32(pci_addr.value);
270 if (is_pci_mem64_high_bar(prev_pbar)) {
272 max_val = PCI_MEM64_HIGH_MASK32;
274 pci_cfg_write32(pci_addr.value, max_val);
275 max_val = pci_cfg_read32(pci_addr.value);
276 pci_cfg_write32(pci_addr.value, bar_val);
278 pbar->type = PT_BAR_MEM64_HIGH;
279 pbar->addr = PCI_MEM64_BASE_HIGH(bar_val);
281 uint64_t mem64_bar_size =
282 (~(PCI_MEM64_BASE((((uint64_t)max_val) << PCI_MEM64_BASE_HIGH_SHIFT) | (prev_pbar->size)))) + 1;
286 (mem64_bar_size >> PCI_MEM64_BASE_HIGH_SHIFT) &
287 PCI_MEM64_HIGH_MASK32;
288 prev_pbar->size = (uint32_t)mem64_bar_size;
289 prev_vbar->size = (uint32_t)mem64_bar_size;
291 uint64_t mem64_addr =
292 (((uint64_t)(pbar->addr)) << PCI_MEM64_BASE_HIGH_SHIFT) |
295 PrintDebug("Adding 64 bit PCI mem region: start=0x%llx, end=0x%llx\n",
296 mem64_addr, mem64_addr + mem64_bar_size);
299 if ((ret = (v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY,
301 mem64_addr + mem64_bar_size - 1,
304 PrintDebug("Fail to insert shadow region (0x%llx, 0x%llx) -> 0x%llx\n",
306 mem64_addr + mem64_bar_size - 1,
318 if ((bar_val & 0x3) == 0x1) {
322 pbar->type = PT_BAR_IO;
323 pbar->addr = PCI_IO_BASE(bar_val);
325 max_val = bar_val | PCI_IO_MASK;
327 // Cycle the physical bar, to determine the actual size
328 // Disable irqs, to try to prevent accesses to the space via a interrupt handler
329 // This is not SMP safe!!
330 // What we probably want to do is write a 0 to the command register
331 //irq_state = v3_irq_save();
333 pci_cfg_write32(pci_addr.value, max_val);
334 max_val = pci_cfg_read32(pci_addr.value);
335 pci_cfg_write32(pci_addr.value, bar_val);
337 //v3_irq_restore(irq_state);
339 V3_Print("max_val = %x\n", max_val);
341 pbar->size = (uint16_t)~PCI_IO_BASE(max_val) + 1;
344 V3_Print("IO Bar with %d (%x) ports %x->%x\n", pbar->size, pbar->size, pbar->addr, pbar->addr + pbar->size);
345 // setup a set of null io hooks
346 // This allows the guest to do passthrough IO to these ports
347 // While still reserving them in the IO map
348 for (i = 0; i < pbar->size; i++) {
349 v3_hook_io_port(dev->vm, pbar->addr + i, NULL, NULL, NULL);
354 // might be memory, might be nothing
356 max_val = bar_val | PCI_MEM_MASK;
358 // Cycle the physical bar, to determine the actual size
359 // Disable irqs, to try to prevent accesses to the space via a interrupt handler
360 // This is not SMP safe!!
361 // What we probably want to do is write a 0 to the command register
362 //irq_state = v3_irq_save();
364 pci_cfg_write32(pci_addr.value, max_val);
365 max_val = pci_cfg_read32(pci_addr.value);
366 pci_cfg_write32(pci_addr.value, bar_val);
368 //v3_irq_restore(irq_state);
372 pbar->type = PT_BAR_NONE;
375 // if its a memory region, setup passthrough mem mapping
377 if ((bar_val & 0x6) == 0x0) {
379 pbar->type = PT_BAR_MEM32;
380 pbar->addr = PCI_MEM32_BASE(bar_val);
381 pbar->size = ~PCI_MEM32_BASE(max_val) + 1;
383 PrintDebug("Adding 32 bit PCI mem region: start=0x%x, end=0x%x\n",
384 pbar->addr, pbar->addr + pbar->size);
386 v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY,
388 pbar->addr + pbar->size - 1,
391 } else if ((bar_val & 0x6) == 0x2) {
393 pbar->type = PT_BAR_MEM24;
394 pbar->addr = PCI_MEM24_BASE(bar_val);
395 pbar->size = ~PCI_MEM24_BASE(max_val) + 1;
397 v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY,
399 pbar->addr + pbar->size - 1,
402 } else if ((bar_val & 0x6) == 0x4) {
405 PrintError("64 Bit PCI bars not supported\n");
410 pbar->type = PT_BAR_MEM64_LOW;
411 pbar->addr = PCI_MEM32_BASE(bar_val);
412 /*temperary size, which will be corrected
413 in the MEM_HIGH bar initialization*/
414 pbar->size = PCI_MEM32_BASE(max_val);
417 PrintError("Invalid Memory bar type\n");
426 // Initially the virtual bars match the physical ones
427 memcpy(&(state->virt_bars[bar_num]), &(state->phys_bars[bar_num]), sizeof(struct pt_bar));
429 PrintDebug("bar_num=%d, bar_val=0x%x\n", bar_num, bar_val);
431 PrintDebug("phys bar type=%d, addr=0x%x, size=%d\n",
432 pbar->type, pbar->addr,
435 PrintDebug("virt bar type=%d, addr=0x%x, size=%d\n",
436 state->virt_bars[bar_num].type, state->virt_bars[bar_num].addr,
437 state->virt_bars[bar_num].size);
439 // Update the pci subsystem versions
445 static int pt_io_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data) {
446 struct pt_bar * pbar = (struct pt_bar *)priv_data;
447 int port_offset = port % pbar->size;
450 *(uint8_t *)dst = v3_inb(pbar->addr + port_offset);
451 } else if (length == 2) {
452 *(uint16_t *)dst = v3_inw(pbar->addr + port_offset);
453 } else if (length == 4) {
454 *(uint32_t *)dst = v3_indw(pbar->addr + port_offset);
456 PrintError("Invalid PCI passthrough IO Redirection size read\n");
464 static int pt_io_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data) {
465 struct pt_bar * pbar = (struct pt_bar *)priv_data;
466 int port_offset = port % pbar->size;
469 v3_outb(pbar->addr + port_offset, *(uint8_t *)src);
470 } else if (length == 2) {
471 v3_outw(pbar->addr + port_offset, *(uint16_t *)src);
472 } else if (length == 4) {
473 v3_outdw(pbar->addr + port_offset, *(uint32_t *)src);
475 PrintError("Invalid PCI passthrough IO Redirection size write\n");
487 static int pci_bar_write(int bar_num, uint32_t * src, void * private_data) {
488 struct vm_device * dev = (struct vm_device *)private_data;
489 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
491 struct pt_bar * pbar = &(state->phys_bars[bar_num]);
492 struct pt_bar * vbar = &(state->virt_bars[bar_num]);
494 PrintDebug("Bar update: bar_num=%d, src=0x%x\n", bar_num,*src);
495 PrintDebug("vbar is size=%u, type=%d, addr=0x%x, val=0x%x\n",vbar->size, vbar->type, vbar->addr, vbar->val);
496 PrintDebug("pbar is size=%u, type=%d, addr=0x%x, val=0x%x\n",pbar->size, pbar->type, pbar->addr, pbar->val);
500 if (vbar->type == PT_BAR_NONE) {
502 } else if (vbar->type == PT_BAR_IO) {
506 for (i = 0; i < vbar->size; i++) {
507 if (v3_unhook_io_port(dev->vm, vbar->addr + i) == -1) {
508 PrintError("Could not unhook previously hooked port.... %d (0x%x)\n",
509 vbar->addr + i, vbar->addr + i);
514 PrintDebug("Setting IO Port range size=%d\n", pbar->size);
516 // clear the low bits to match the size
517 *src &= ~(pbar->size - 1);
520 *src |= (pbar->val & ~PCI_IO_MASK);
522 vbar->addr = PCI_IO_BASE(*src);
524 PrintDebug("Cooked src=0x%x\n", *src);
526 PrintDebug("Rehooking passthrough IO ports starting at %d (0x%x)\n",
527 vbar->addr, vbar->addr);
529 if (vbar->addr == pbar->addr) {
530 // Map the io ports as passthrough
531 for (i = 0; i < pbar->size; i++) {
532 v3_hook_io_port(dev->vm, pbar->addr + i, NULL, NULL, NULL);
535 // We have to manually handle the io redirection
536 for (i = 0; i < vbar->size; i++) {
537 v3_hook_io_port(dev->vm, vbar->addr + i, pt_io_read, pt_io_write, pbar);
540 } else if (vbar->type == PT_BAR_MEM32) {
541 // remove old mapping
542 struct v3_shadow_region * old_reg = v3_get_shadow_region(dev->vm, V3_MEM_CORE_ANY, vbar->addr);
544 if (old_reg == NULL) {
546 PrintError("Could not find PCI Passthrough memory redirection region (addr=0x%x)\n", vbar->addr);
550 v3_delete_shadow_region(dev->vm, old_reg);
552 // clear the low bits to match the size
553 *src &= ~(pbar->size - 1);
556 *src |= (pbar->val & ~PCI_MEM_MASK);
558 PrintDebug("Cooked src=0x%x\n", *src);
560 vbar->addr = PCI_MEM32_BASE(*src);
562 PrintDebug("Adding pci Passthrough remapping: start=0x%x, size=%d, end=0x%x\n",
563 vbar->addr, vbar->size, vbar->addr + vbar->size);
565 v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY,
567 vbar->addr + vbar->size - 1,
570 } else if (vbar->type == PT_BAR_MEM64_LOW) {
573 PrintDebug("Uncooked MEM64_LOW src=0x%x\n", *src);
575 // clear the low bits to match the size
576 *src &= ~(pbar->size - 1);
579 *src |= (pbar->val & ~PCI_MEM_MASK);
581 PrintDebug("Cooked MEM64_LOW src=0x%x\n", *src);
583 vbar->addr = PCI_MEM32_BASE(*src);
585 } else if (vbar->type == PT_BAR_MEM64_HIGH) {
588 // remove old mapping
591 PrintError("The first bar register could not be of type PT_BAR_MEM64_HIGH\n");
595 struct pt_bar * prev_pbar = &(state->phys_bars[bar_num - 1]);
596 struct pt_bar * prev_vbar = &(state->virt_bars[bar_num - 1]);
599 addr_t valid_vbar_mem64_addr =
600 (addr_t)(((((uint64_t)vbar->addr) << PCI_MEM64_BASE_HIGH_SHIFT) &
601 (PCI_MEM64_HIGH_MASK64)) |
604 struct v3_shadow_region * old_reg =
605 v3_get_shadow_region(dev->vm, V3_MEM_CORE_ANY, valid_vbar_mem64_addr);
607 if (old_reg == NULL) {
609 PrintError("Could not find PCI Passthrough memory redirection region (addr=0x%lx)\n", valid_vbar_mem64_addr);
614 v3_delete_shadow_region(dev->vm, old_reg);
617 ((((uint64_t)(*src)) << PCI_MEM64_BASE_HIGH_SHIFT) &
618 (PCI_MEM64_HIGH_MASK64)) |
621 uint64_t mem64_bar_size =
622 ((((uint64_t)(pbar->size)) << PCI_MEM64_BASE_HIGH_SHIFT) &
623 (PCI_MEM64_HIGH_MASK64)) |
626 // clear the low bits to match the size
627 mem64_src &= ~(mem64_bar_size - 1);
629 uint64_t mem64_pbar_val =
630 ((((uint64_t)(pbar->val)) << PCI_MEM64_BASE_HIGH_SHIFT) &
631 (PCI_MEM64_HIGH_MASK64)) |
635 mem64_src |= (mem64_pbar_val & ~PCI_MEM64_MASK);
637 PrintDebug("Cooked mem64_src=0x%llx\n", mem64_src);
639 prev_vbar->val = (uint32_t)mem64_src;
641 *src = (uint32_t)((mem64_src & PCI_MEM64_HIGH_MASK64) >>
642 PCI_MEM64_BASE_HIGH_SHIFT);
644 uint64_t mem64_vbar_addr = PCI_MEM64_BASE(mem64_src);
645 prev_vbar->addr = (uint32_t)(mem64_vbar_addr);
647 (uint32_t)(((uint64_t)(mem64_vbar_addr)) >> PCI_MEM64_BASE_HIGH_SHIFT);
649 PrintDebug("Adding pci Passthrough remapping: start=0x%llx, size=0x%llu, end=0x%llx\n",
650 mem64_vbar_addr, mem64_bar_size, mem64_vbar_addr + mem64_bar_size);
652 uint64_t mem64_pbar_addr =
653 (((uint64_t)(pbar->addr)) << PCI_MEM64_BASE_HIGH_SHIFT) |
657 if ((ret = (v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY,
659 mem64_vbar_addr + mem64_bar_size - 1,
660 mem64_pbar_addr)))) {
661 PrintDebug("Fail to insert shadow region (0x%llx, 0x%llx) -> 0x%llx\n",
663 mem64_vbar_addr + mem64_bar_size - 1,
670 PrintError("Unhandled Pasthrough PCI Bar type %d\n", vbar->type);
680 #if 0 //Zheng: 03/19/2010
681 static int pt_config_update(uint_t reg_num, void * src, uint_t length, void * private_data) {
682 struct vm_device * dev = (struct vm_device *)private_data;
683 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
684 union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
686 pci_addr.reg = reg_num;
689 pci_cfg_write8(pci_addr.value, *(uint8_t *)src);
690 } else if (length == 2) {
691 pci_cfg_write16(pci_addr.value, *(uint16_t *)src);
692 } else if (length == 4) {
693 pci_cfg_write32(pci_addr.value, *(uint32_t *)src);
700 #endif //old pt_config_update
704 static int pt_config_update(uint_t reg_num, void * src, uint_t length, void * private_data) {
705 struct vm_device * dev = (struct vm_device *)private_data;
706 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
707 union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
709 pci_addr.reg = reg_num >> 2;
710 uint32_t org_val = pci_cfg_read32(pci_addr.value);
711 uint_t offset = reg_num & 0x3;
713 uint32_t cooked_val = org_val;
715 *(((uint8_t *)(&cooked_val)) + offset) = *((uint8_t *)src);
716 } else if (length == 2) {
717 *((uint16_t *)(((uint8_t *)(&cooked_val)) + offset)) = *((uint16_t *)src);
718 } else if (length == 4) {
719 *((uint32_t *)(((uint8_t *)(&cooked_val)) + offset)) = *((uint32_t *)src);
722 pci_cfg_write32(pci_addr.value, cooked_val);
724 *(((uint32_t *)(state->pci_dev->config_space)) + pci_addr.reg) = pci_cfg_read32(pci_addr.value);
732 static int pci_exp_rom_base_write(struct pci_device *pci_dev) {
733 struct vm_device * dev = (struct vm_device *)(pci_dev->priv_data);
734 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
736 struct pt_exp_rom_base * pexp_rom_base = &(state->phys_exp_rom_base);
737 struct pt_exp_rom_base * vexp_rom_base = &(state->virt_exp_rom_base);
739 const uint32_t exp_rom_base_reg = 12;
740 uint32_t *src = ((uint32_t *)(&(pci_dev->config_space[4 * exp_rom_base_reg])));
742 PrintDebug("exp_rom_base update: src=0x%x\n", *src);
743 PrintDebug("vexp_rom_base is size=%u, addr=0x%x, val=0x%x\n",vexp_rom_base->size, vexp_rom_base->addr, vexp_rom_base->val);
744 PrintDebug("pexp_rom_base is size=%u, addr=0x%x, val=0x%x\n",pexp_rom_base->size, pexp_rom_base->addr, pexp_rom_base->val);
746 if (pexp_rom_base->size) {
747 // remove old mapping
748 struct v3_shadow_region * old_reg = v3_get_shadow_region(dev->vm, V3_MEM_CORE_ANY, vexp_rom_base->addr);
750 if (old_reg == NULL) {
752 PrintError("Could not find PCI Passthrough exp_rom_base redirection region (addr=0x%x)\n", vexp_rom_base->addr);
757 v3_delete_shadow_region(dev->vm, old_reg);
760 // clear the low bits to match the size
761 *src &= ~(pexp_rom_base->size - 1);
764 *src |= (pexp_rom_base->val & ~PCI_MEM_MASK);
766 PrintDebug("Cooked src=0x%x\n", *src);
767 vexp_rom_base->addr = PCI_EXP_ROM_BASE(*src);
770 if (pexp_rom_base->size) {
771 PrintDebug("Adding pci Passthrough exp_rom_base remapping: start=0x%x, size=%u, end=0x%x\n",
772 vexp_rom_base->addr, vexp_rom_base->size, vexp_rom_base->addr + vexp_rom_base->size);
776 if ((ret = v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY,
778 vexp_rom_base->addr + vexp_rom_base->size - 1,
779 pexp_rom_base->addr))) {
780 PrintError("Fail to add pci Passthrough exp_rom_base remapping: start=0x%x, size=%u, end=0x%x\n",
781 vexp_rom_base->addr, vexp_rom_base->size, vexp_rom_base->addr + vexp_rom_base->size);
788 vexp_rom_base->val = *src;
794 static int find_real_pci_dev(uint16_t vendor_id, uint16_t device_id, struct pt_dev_state * state) {
795 union pci_addr_reg pci_addr = {0x80000000};
803 } __attribute__((packed));
804 } __attribute__((packed)) pci_hdr = {0};
806 //PrintDebug("Scanning PCI busses for vendor=%x, device=%x\n", vendor_id, device_id);
807 for (i = 0, pci_addr.bus = 0; i < PCI_BUS_MAX; i++, pci_addr.bus++) {
808 for (j = 0, pci_addr.dev = 0; j < PCI_DEV_MAX; j++, pci_addr.dev++) {
809 for (k = 0, pci_addr.func = 0; k < PCI_FN_MAX; k++, pci_addr.func++) {
811 v3_outdw(PCI_CFG_ADDR, pci_addr.value);
812 pci_hdr.value = v3_indw(PCI_CFG_DATA);
814 //PrintDebug("\bus=%d, tvendor=%x, device=%x\n", pci_addr.bus, pci_hdr.vendor, pci_hdr.device);
816 if ((pci_hdr.vendor == vendor_id) && (pci_hdr.device == device_id)) {
817 uint32_t * cfg_space = (uint32_t *)&state->real_hdr;
819 state->phys_pci_addr = pci_addr;
821 // Copy the configuration space to the local cached version
822 for (m = 0, pci_addr.reg = 0; m < PCI_HDR_SIZE; m += 4, pci_addr.reg++) {
823 cfg_space[pci_addr.reg] = pci_cfg_read32(pci_addr.value);
827 PrintDebug("Found device %x:%x (bus=%d, dev=%d, func=%d)\n",
828 vendor_id, device_id,
829 pci_addr.bus, pci_addr.dev, pci_addr.func);
842 static int setup_virt_pci_dev(struct v3_vm_info * vm_info, struct vm_device * dev) {
843 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
844 struct pci_device * pci_dev = NULL;
845 struct v3_pci_bar bars[6];
849 for (i = 0; i < 6; i++) {
850 bars[i].type = PCI_BAR_PASSTHROUGH;
851 bars[i].private_data = dev;
852 bars[i].bar_init = pci_bar_init;
853 bars[i].bar_write = pci_bar_write;
857 pci_dev = v3_pci_register_device(state->pci_bus,
863 pci_exp_rom_base_write,
866 pci_dev = v3_pci_register_device(state->pci_bus,
870 pt_config_update, NULL, NULL,
872 #endif //if 0 old v3_pci_register_device
874 // This will overwrite the bar registers.. but that should be ok.
875 memcpy(pci_dev->config_space, (uint8_t *)&(state->real_hdr), sizeof(struct pci_config_header));
877 state->pci_dev = pci_dev;
880 pci_exp_rom_base_init(pci_dev);
882 v3_sym_map_pci_passthrough(vm_info, pci_dev->bus_num, pci_dev->dev_num, pci_dev->fn_num);
889 static struct v3_device_ops dev_ops = {
898 static int irq_handler(struct v3_vm_info * vm, struct v3_interrupt * intr, void * private_data) {
899 struct vm_device * dev = (struct vm_device *)private_data;
900 struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
904 static long irq_time = 0;
907 if(irq_time % 10 == 0)
908 PrintError("Handling IRQ %d, time: %ld\n", intr->irq, irq_time);
910 PrintError("Handling IRQ %d, time: %ld\n", intr->irq, irq_time);
913 // PrintDebug("Handling E1000 IRQ %d\n", intr->irq);
915 v3_pci_raise_irq(state->pci_bus, 0, state->pci_dev);
917 V3_ACK_IRQ(intr->irq);
925 static int passthrough_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
926 struct pt_dev_state * state = V3_Malloc(sizeof(struct pt_dev_state));
927 struct vm_device * dev = NULL;
928 struct vm_device * pci = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
929 char * name = v3_cfg_val(cfg, "name");
932 memset(state, 0, sizeof(struct pt_dev_state));
935 PrintError("Could not find PCI device\n");
939 state->pci_bus = pci;
940 strncpy(state->name, name, 32);
943 dev = v3_allocate_device(name, &dev_ops, state);
945 if (v3_attach_device(vm, dev) == -1) {
946 PrintError("Could not attach device %s\n", name);
951 if (find_real_pci_dev(atox(v3_cfg_val(cfg, "vendor_id")),
952 atox(v3_cfg_val(cfg, "device_id")),
954 PrintError("Could not find PCI Device %s:%s\n",
955 v3_cfg_val(cfg, "vendor_id"),
956 v3_cfg_val(cfg, "device_id"));
960 setup_virt_pci_dev(vm, dev);
962 v3_hook_irq(vm, atoi(v3_cfg_val(cfg, "irq")), irq_handler, dev);
963 // v3_hook_irq(info, 64, irq_handler, dev);
971 device_register("PCI_PASSTHROUGH", passthrough_init)