#define PCI_HDR_SIZE 256
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 43)
+#define IOMMU_FOUND() iommu_present(&pci_bus_type)
+#define IOMMU_DOMAIN_ALLOC() iommu_domain_alloc(&pci_bus_type)
+#else
+#define IOMMU_FOUND() iommu_found()
+#define IOMMU_DOMAIN_ALLOC() iommu_domain_alloc()
+#endif
+
+
static int setup_hw_pci_dev(struct host_pci_device * host_dev) {
int ret = 0;
host_dev->hw_dev.dev = dev;
host_dev->hw_dev.intx_disabled = 1;
- spin_lock_init(&(host_dev->hw_dev.intx_lock));
+ palacios_spinlock_init(&(host_dev->hw_dev.intx_lock));
if (pci_enable_device(dev)) {
printk("Could not enable Device\n");
if (flags & IORESOURCE_IO) {
bar->type = PT_BAR_IO;
} else if (flags & IORESOURCE_MEM) {
- if (flags & IORESOURCE_MEM_64) {
- printk("ERROR: 64 Bit BARS not yet supported\n");
- bar->type = PT_BAR_NONE;
+ if ((flags & IORESOURCE_MEM_64)) {
+ // this should never happen with i==5, but it
+ // is technically an OOB access without the modulo
+ struct v3_host_pci_bar * hi_bar = &(v3_dev->bars[(i + 1) % 6]);
+
+ bar->type = PT_BAR_MEM64_LO;
+
+ hi_bar->type = PT_BAR_MEM64_HI;
+ hi_bar->size = bar->size;
+ hi_bar->addr = bar->addr;
+ hi_bar->cacheable = ((flags & IORESOURCE_CACHEABLE) != 0);
+ hi_bar->prefetchable = ((flags & IORESOURCE_PREFETCH) != 0);
+
+ i++;
} else if (flags & IORESOURCE_DMA) {
bar->type = PT_BAR_MEM24;
} else {
int rom_size = pci_resource_len(dev, PCI_ROM_RESOURCE);
if (rom_size > 0) {
- unsigned long flags;
+ //unsigned long flags;
v3_dev->exp_rom.size = rom_size;
v3_dev->exp_rom.addr = pci_resource_start(dev, PCI_ROM_RESOURCE);
- flags = pci_resource_flags(dev, PCI_ROM_RESOURCE);
+ // flags = pci_resource_flags(dev, PCI_ROM_RESOURCE);
v3_dev->exp_rom.type = PT_EXP_ROM;
/* HARDCODED for now but this will need to depend on IOMMU support detection */
- if (iommu_found()) {
+ if (IOMMU_FOUND()) {
printk("Setting host PCI device (%s) as IOMMU\n", host_dev->name);
v3_dev->iface = IOMMU;
} else {
// printk("Host PCI IRQ handler (%d)\n", irq);
- spin_lock(&(host_dev->hw_dev.intx_lock));
+ palacios_spinlock_lock(&(host_dev->hw_dev.intx_lock));
disable_irq_nosync(irq);
host_dev->hw_dev.intx_disabled = 1;
- spin_unlock(&(host_dev->hw_dev.intx_lock));
+ palacios_spinlock_unlock(&(host_dev->hw_dev.intx_lock));
V3_host_pci_raise_irq(&(host_dev->v3_dev), 0);
}
host_dev->hw_dev.num_msix_vecs = 0;
- kfree(host_dev->hw_dev.msix_entries);
+ palacios_free(host_dev->hw_dev.msix_entries);
pci_disable_msix(dev);
// printk("Acking IRQ vector %d\n", vector);
- spin_lock_irqsave(&(host_dev->hw_dev.intx_lock), flags);
+ palacios_spinlock_lock_irqsave(&(host_dev->hw_dev.intx_lock), flags);
// printk("Enabling IRQ %d\n", dev->irq);
enable_irq(dev->irq);
host_dev->hw_dev.intx_disabled = 0;
- spin_unlock_irqrestore(&(host_dev->hw_dev.intx_lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(host_dev->hw_dev.intx_lock), flags);
return 0;
}
struct v3_host_pci_dev * v3_dev = &(host_dev->v3_dev);
struct pci_dev * dev = host_dev->hw_dev.dev;
- spin_lock_irqsave(&lock, flags);
+ palacios_spinlock_lock_irqsave(&lock, flags);
if (host_dev->hw_dev.in_use == 0) {
host_dev->hw_dev.in_use = 1;
} else {
ret = -1;
}
- spin_unlock_irqrestore(&lock, flags);
+ palacios_spinlock_unlock_irqrestore(&lock, flags);
if (v3_dev->iface == IOMMU) {
struct v3_guest_mem_region region;
int flags = 0;
+ uintptr_t gpa = 0;
- host_dev->hw_dev.iommu_domain = iommu_domain_alloc();
+ host_dev->hw_dev.iommu_domain = IOMMU_DOMAIN_ALLOC();
- if (V3_get_guest_mem_region(v3_ctx, ®ion) == -1) {
- printk("Error getting VM memory region for IOMMU support\n");
- return -1;
- }
+ while (V3_get_guest_mem_region(v3_ctx, ®ion, gpa)) {
- printk("Memory region: start=%p, end=%p\n", (void *)region.start, (void *)region.end);
+ printk("Memory region: start=%p, end=%p\n", (void *)region.start, (void *)region.end);
- flags = IOMMU_READ | IOMMU_WRITE; // Need to see what IOMMU_CACHE means
+ flags = IOMMU_READ | IOMMU_WRITE; // Need to see what IOMMU_CACHE means
- /* This version could be wrong */
+ /* This version could be wrong */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
- // Guest VAs start at zero and go to end of memory
- iommu_map_range(host_dev->hw_dev.iommu_domain, 0, region.start, (region.end - region.start), flags);
+ // Guest VAs start at zero and go to end of memory
+ iommu_map_range(host_dev->hw_dev.iommu_domain, 0, region.start, (region.end - region.start), flags);
#else
- /* Linux actually made the interface worse... Now you can only map memory in powers of 2 (meant to only be pages...) */
- {
- u64 size = region.end - region.start;
- u32 page_size = 512 * 4096; // assume large 64bit pages (2MB)
- u64 dpa = 0; // same as gpa
- u64 hpa = region.start;
-
- do {
- if (size < page_size) {
- page_size = 4096; // less than a 2MB granularity, so we switch to small pages (4KB)
- }
-
- printk("Mapping IOMMU region dpa=%p hpa=%p (size=%d)\n", (void *)dpa, (void *)hpa, page_size);
-
- if (iommu_map(host_dev->hw_dev.iommu_domain, dpa, hpa,
- get_order(page_size), flags)) {
- printk("ERROR: Could not map sub region (DPA=%p) (HPA=%p) (order=%d)\n",
- (void *)dpa, (void *)hpa, get_order(page_size));
- break;
- }
-
- hpa += page_size;
- dpa += page_size;
-
- size -= page_size;
- } while (size);
- }
+ /* Linux actually made the interface worse... Now you can only map memory in powers of 2 (meant to only be pages...) */
+ {
+ u64 size = region.end - region.start;
+ u32 page_size = 512 * 4096; // assume large 64bit pages (2MB)
+ u64 hpa = region.start;
+
+ do {
+ if (size < page_size) {
+ page_size = 4096; // less than a 2MB granularity, so we switch to small pages (4KB)
+ }
+
+ printk("Mapping IOMMU region gpa=%p hpa=%p (size=%d)\n", (void *)gpa, (void *)hpa, page_size);
+
+ if (iommu_map(host_dev->hw_dev.iommu_domain, gpa, hpa,
+ get_order(page_size), flags)) {
+ printk("ERROR: Could not map sub region (GPA=%p) (HPA=%p) (order=%d)\n",
+ (void *)gpa, (void *)hpa, get_order(page_size));
+ break;
+ }
+
+ hpa += page_size;
+ gpa += page_size;
+
+ size -= page_size;
+ } while (size > 0);
+ }
#endif
+ }
if (iommu_attach_device(host_dev->hw_dev.iommu_domain, &(dev->dev))) {
printk("ERROR attaching host PCI device to IOMMU domain\n");
return 0;
}
+
+
+//
+// Should be a matching teardown function here, otherwise we
+// are at least leaking the lock from the lockchecker's perspective
+// we would like to be able to do a palacios_spinlock_deinit() here...