Skip to contentSkip to conversation

: PCI ROM support.

PATCH In review Gianni Tedesco 2 participants 5 messages Jun 2, 2004 – Jun 3, 2004

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 : PCI ROM support.

Attached is a preliminary patch which adds support for ROM resources to the PCI subsystem as a 7th resource. It's fairly self explanatory, but for some reason in my guest Linux OS, ROM resources are all sized to 2KB (but unassigned and disabled) even if the ROM base address register (@0x30) is all zeros... Not sure if it's just the version of lspci I'm using...

There is probably an obvious bug that Fabrice can spot ;)

Signature · 3 lines
// Gianni Tedesco (gianni at scaramanga dot co dot uk)
lynx --source www.scaramanga.co.uk/scaramanga.asc | gpg --import
8646BE7D: 6D9F 2287 870E A2C9 8F60 3A3C 91B5 7669 8646 BE7D
hw/pci.c +30 -12
diff -urN qemu.orig/hw/pci.c qemu.pci-roms/hw/pci.c
@@ -100,7 +100,7 @@
 {
     PCIIORegion *r;
 
-    if ((unsigned int)region_num >= 6)
+    if ((unsigned int)region_num >= PCI_NUM_REGIONS)
         return;
     r = &pci_dev->io_regions[region_num];
     r->addr = -1;
@@ -125,16 +125,21 @@
 {
     PCIIORegion *r;
     int cmd, i;
-    uint32_t last_addr, new_addr;
+    uint32_t last_addr, new_addr, config_ofs;
     
     cmd = le16_to_cpu(*(uint16_t *)(d->config + PCI_COMMAND));
-    for(i = 0; i < 6; i++) {
+    for(i = 0; i < PCI_NUM_REGIONS; i++) {
         r = &d->io_regions[i];
+        if ( i == PCI_ROM_SLOT ) {
+            config_ofs = 0x30;
+        }else{
+            config_ofs = 0x10 + i * 4;
+        }
         if (r->size != 0) {
             if (r->type & PCI_ADDRESS_SPACE_IO) {
                 if (cmd & PCI_COMMAND_IO) {
                     new_addr = le32_to_cpu(*(uint32_t *)(d->config + 
-                                                         0x10 + i * 4));
+                                                         config_ofs));
                     new_addr = new_addr & ~(r->size - 1);
                     last_addr = new_addr + r->size - 1;
                     /* NOTE: we have only 64K ioports on PC */
@@ -148,7 +153,7 @@
             } else {
                 if (cmd & PCI_COMMAND_MEMORY) {
                     new_addr = le32_to_cpu(*(uint32_t *)(d->config + 
-                                                         0x10 + i * 4));
+                                                         config_ofs));
                     new_addr = new_addr & ~(r->size - 1);
                     last_addr = new_addr + r->size - 1;
                     /* NOTE: we do not support wrapping */
@@ -216,18 +221,22 @@
     int can_write, i;
     uint32_t end, addr;
 
-    if (len == 4 && (address >= 0x10 && address < 0x10 + 4 * 6)) {
+    if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) || address == 0x30) ) {
         PCIIORegion *r;
         int reg;
 
-        reg = (address - 0x10) >> 2;
+        if ( address == 0x30 ) {
+            reg = PCI_ROM_SLOT;
+        }else{
+            reg = (address - 0x10) >> 2;
+        }
         r = &d->io_regions[reg];
         if (r->size == 0)
             goto default_config;
         /* compute the stored value */
         val &= ~(r->size - 1);
         val |= r->type;
-        *(uint32_t *)(d->config + 0x10 + reg * 4) = cpu_to_le32(val);
+        *(uint32_t *)(d->config + address) = cpu_to_le32(val);
         pci_update_mappings(d);
         return;
     }
@@ -812,7 +821,7 @@
     if (d->config[PCI_INTERRUPT_PIN] != 0) {
         printf("      IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]);
     }
-    for(i = 0;i < 6; i++) {
+    for(i = 0;i < PCI_NUM_REGIONS; i++) {
         r = &d->io_regions[i];
         if (r->size != 0) {
             printf("      BAR%d: ", i);
@@ -934,13 +943,22 @@
 {
     PCIIORegion *r;
     uint16_t cmd;
+    uint32_t ofs;
 
-    pci_config_writel(d, 0x10 + region_num * 4, addr);
+    if ( region_num == PCI_ROM_SLOT ) {
+        ofs = 0x30;
+    }else{
+        ofs = 0x10 + region_num * 4;
+    }
+
+    pci_config_writel(d, ofs, addr);
     r = &d->io_regions[region_num];
 
     /* enable memory mappings */
     cmd = pci_config_readw(d, PCI_COMMAND);
-    if (r->type & PCI_ADDRESS_SPACE_IO)
+    if ( region_num == PCI_ROM_SLOT )
+        cmd |= 2;
+    else if (r->type & PCI_ADDRESS_SPACE_IO)
         cmd |= 1;
     else
         cmd |= 2;
@@ -977,7 +995,7 @@
         break;
     default:
         /* default memory mappings */
-        for(i = 0; i < 6; i++) {
+        for(i = 0; i < PCI_NUM_REGIONS; i++) {
             r = &d->io_regions[i];
             if (r->size) {
                 if (r->type & PCI_ADDRESS_SPACE_IO)
vl.h +4 -1
diff -urN qemu.orig/vl.h qemu.pci-roms/vl.h
@@ -381,6 +381,7 @@
 
 #define PCI_ADDRESS_SPACE_MEM		0x00
 #define PCI_ADDRESS_SPACE_IO		0x01
+#define PCI_ADDRESS_SPACE_ROM		0x02 /* not a real flag */
 #define PCI_ADDRESS_SPACE_MEM_PREFETCH	0x08
 
 typedef struct PCIIORegion {
@@ -390,6 +391,8 @@
     PCIMapIORegionFunc *map_func;
 } PCIIORegion;
 
+#define PCI_ROM_SLOT 6
+#define PCI_NUM_REGIONS 7
 struct PCIDevice {
     /* PCI config space */
     uint8_t config[256];
@@ -398,7 +401,7 @@
     int bus_num;
     int devfn;
     char name[64];
-    PCIIORegion io_regions[6];
+    PCIIORegion io_regions[PCI_NUM_REGIONS];
     
     /* do not access the following fields */
     PCIConfigReadFunc *config_read;
#1 lore raw

Hi,

I commited a variant of your patch - try it. I also added support for opaque data on all memory I/Os.

Fabrice.

Quoted 8 lines · Gianni Tedesco

Attached is a preliminary patch which adds support for ROM resources to the PCI subsystem as a 7th resource. It's fairly self explanatory, but for some reason in my guest Linux OS, ROM resources are all sized to 2KB (but unassigned and disabled) even if the ROM base address register (@0x30) is all zeros... Not sure if it's just the version of lspci I'm using...

There is probably an obvious bug that Fabrice can spot ;)

#2 lore raw
Quoted 4 lines · Fabrice Bellard

Hi,

I commited a variant of your patch - try it. I also added support for opaque data on all memory I/Os.

Thanks Fabrice, that does everything I need now and the opaque data on memory I/Os is very neat. I shall be ready to post a more complete version of my pciproxy patch soon. Just one minor niggle regarding the ROM code.

I notice you preserve the ROM enable bit, thats useful :)

However this still isn't solving my wierd problem with lspci on Linux showing all devices as having a 2KB unassigned, disabled ROM chip where normally it wouldnt print anything. In the config space the ROM bar is 0x00000000...

How are the BARs sized, by writing 0xffffffff over them then re-reading once? It doesn't mention anything in the i440FX manual... Just waffles on about the PMC extended register space.

Signature · 3 lines
// Gianni Tedesco (gianni at scaramanga dot co dot uk)
lynx --source www.scaramanga.co.uk/scaramanga.asc | gpg --import
8646BE7D: 6D9F 2287 870E A2C9 8F60 3A3C 91B5 7669 8646 BE7D
#3 lore raw
Quoted 4 lines · Gianni Tedesco

However this still isn't solving my wierd problem with lspci on Linux showing all devices as having a 2KB unassigned, disabled ROM chip where normally it wouldnt print anything. In the config space the ROM bar is 0x00000000...

It is fixed now (an unassigned BAR/ROM should be hardwired to zero).

Quoted 2 lines

How are the BARs sized, by writing 0xffffffff over them then re-reading once?

Yes.

Fabrice.

#4 lore raw
Quoted 8 lines · Fabrice Bellard
Quoted 4 lines · Gianni Tedesco

However this still isn't solving my wierd problem with lspci on Linux showing all devices as having a 2KB unassigned, disabled ROM chip where normally it wouldnt print anything. In the config space the ROM bar is 0x00000000...

It is fixed now (an unassigned BAR/ROM should be hardwired to zero).

Cool, yes, that fixes it for me.

Thanks.

Signature · 3 lines
// Gianni Tedesco (gianni at scaramanga dot co dot uk)
lynx --source www.scaramanga.co.uk/scaramanga.asc | gpg --import
8646BE7D: 6D9F 2287 870E A2C9 8F60 3A3C 91B5 7669 8646 BE7D