diff mbox

[2/2] device-assignment: Allow PCI to manage the option ROM

Message ID 1286550772.3016.49.camel@x201 (mailing list archive)
State New, archived
Headers show

Commit Message

Alex Williamson Oct. 8, 2010, 3:12 p.m. UTC
None
diff mbox

Patch

diff --git a/hw/device-assignment.c b/hw/device-assignment.c
index 26cb797..94561ef 100644
--- a/hw/device-assignment.c
+++ b/hw/device-assignment.c
@@ -1622,6 +1622,7 @@  void add_assigned_devices(PCIBus *bus, const char **devices, int n_devices)
 static void assigned_dev_load_option_rom(AssignedDevice *dev)
 {
     char name[32], rom_file[64];
+    size_t size;
     FILE *fp;
     uint8_t val;
     struct stat st;
@@ -1654,20 +1655,23 @@  static void assigned_dev_load_option_rom(AssignedDevice *dev)
     if (fwrite(&val, 1, 1, fp) != 1) {
         goto close_rom;
     }
+
+    fseek(fp, 0, SEEK_END);
+    size = ftell(fp);
     fseek(fp, 0, SEEK_SET);
 
     snprintf(name, sizeof(name), "%s.rom", dev->dev.qdev.info->name);
-    dev->dev.rom_offset = qemu_ram_alloc(&dev->dev.qdev, name, st.st_size);
+    dev->dev.rom_offset = qemu_ram_alloc(&dev->dev.qdev, name, size);
+    dev->dev.rom_size = size;
     ptr = qemu_get_ram_ptr(dev->dev.rom_offset);
-    memset(ptr, 0xff, st.st_size);
 
-    if (!fread(ptr, 1, st.st_size, fp)) {
+    if (!fread(ptr, 1, size, fp)) {
         fprintf(stderr, "pci-assign: Cannot read from host %s\n"
                 "\tDevice option ROM contents are probably invalid "
                 "(check dmesg).\n\tSkip option ROM probe with rombar=0, "
                 "or load from file with romfile=\n", rom_file);
         qemu_ram_free(dev->dev.rom_offset);
-        dev->dev.rom_offset = 0;
+        dev->dev.rom_offset = dev->dev.rom_size = 0;
         goto close_rom;
     }
 
diff --git a/hw/pci.c b/hw/pci.c
index 07e9661..bd15eb7 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1973,9 +1973,49 @@  static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
     return next;
 }
 
-void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr, pcibus_t size, int type)
+static uint32_t rom_readb(void *opaque, target_phys_addr_t addr)
 {
-    cpu_register_physical_memory(addr, size, pdev->rom_offset);
+    PCIDevice *pdev = opaque;
+
+    if (addr > pdev->rom_size)
+         return 0xff;
+
+    return *(uint8_t *)qemu_get_ram_ptr(pdev->rom_offset + addr);
+}
+
+static uint32_t rom_readw(void *opaque, target_phys_addr_t addr)
+{
+    PCIDevice *pdev = opaque;
+
+    if (addr > pdev->rom_size)
+         return 0xffff;
+
+    return *(uint16_t *)qemu_get_ram_ptr(pdev->rom_offset + addr);
+}
+
+static uint32_t rom_readl(void *opaque, target_phys_addr_t addr)
+{
+    PCIDevice *pdev = opaque;
+
+    if (addr > pdev->rom_size)
+         return 0xffffffff;
+
+    return *(uint32_t *)qemu_get_ram_ptr(pdev->rom_offset + addr);
+}
+
+static CPUReadMemoryFunc * const rom_reads[] = {
+    &rom_readb, &rom_readw, &rom_readl
+};
+
+static CPUWriteMemoryFunc * const rom_writes[] = { NULL, NULL, NULL };
+
+void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr,
+                        pcibus_t size, int type)
+{
+    int m;
+
+    m = cpu_register_io_memory(rom_reads, rom_writes, pdev);
+    cpu_register_physical_memory(addr, size, m);
 }
 
 /* Add an option rom for the device */
@@ -2016,9 +2056,7 @@  static int pci_add_option_rom(PCIDevice *pdev)
                      __FUNCTION__, pdev->romfile);
         return -1;
     }
-    if (size & (size - 1)) {
-        size = 1 << qemu_fls(size);
-    }
+    pdev->rom_size = size;
 
     if (pdev->qdev.info->vmsd)
         snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->vmsd->name);
@@ -2030,6 +2068,11 @@  static int pci_add_option_rom(PCIDevice *pdev)
     load_image(path, ptr);
     qemu_free(path);
 
+    /* Round up size for the BAR */
+    if (size & (size - 1)) {
+        size = 1 << qemu_fls(size);
+    }
+
     pci_register_bar(pdev, PCI_ROM_SLOT, size,
                      0, pci_map_option_rom);
 
@@ -2042,7 +2085,7 @@  static void pci_del_option_rom(PCIDevice *pdev)
         return;
 
     qemu_ram_free(pdev->rom_offset);
-    pdev->rom_offset = 0;
+    pdev->rom_offset = pdev->rom_size = 0;
 }
 
 /* Reserve space and add capability to the linked list in pci config space */
diff --git a/hw/pci.h b/hw/pci.h
index 9ee8db3..ed87b1a 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -187,6 +187,7 @@  struct PCIDevice {
     /* Location of option rom */
     char *romfile;
     ram_addr_t rom_offset;
+    size_t rom_size;
     uint32_t rom_bar;
 
     /* How much space does an MSIX table need. */