@@ -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;
}
@@ -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 */
@@ -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. */