[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] hvmloader: Load physical PCI option ROMs where available.



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1227534208 0
# Node ID 521d4d90f6e31c76a01546b91ad88960800114d9
# Parent  612218519cb5f27d6bcd967ddbe0c93236de5c05
hvmloader: Load physical PCI option ROMs where available.

Signed-off-by: Shan Haitao <Haitao.shan@xxxxxxxxx>
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
 tools/firmware/hvmloader/hvmloader.c |  195 ++++++++++++++++++++++++-----------
 1 files changed, 138 insertions(+), 57 deletions(-)

diff -r 612218519cb5 -r 521d4d90f6e3 tools/firmware/hvmloader/hvmloader.c
--- a/tools/firmware/hvmloader/hvmloader.c      Mon Nov 24 11:17:44 2008 +0000
+++ b/tools/firmware/hvmloader/hvmloader.c      Mon Nov 24 13:43:28 2008 +0000
@@ -322,60 +322,55 @@ static void pci_setup(void)
 }
 
 /*
- * Scan the PCI bus for the first NIC supported by etherboot, and copy
- * the corresponding rom data to *copy_rom_dest. Returns the length of the
- * selected rom, or 0 if no NIC found.
+ * Scan the list of Option ROMs at @roms for one which supports 
+ * PCI (@vendor_id, @device_id). If one is found, copy it to @dest and
+ * return its size rounded up to a multiple 2kB. This function will not
+ * copy ROMs beyond address 0xE0000.
  */
-static int scan_etherboot_nic(void *copy_rom_dest)
+#define round_option_rom(x) (((x) + 2047) & ~2047)
+static int scan_option_rom(
+    uint16_t vendor_id, uint16_t device_id, void *roms, uint32_t dest)
 {
     struct option_rom_header *rom;
     struct option_rom_pnp_header *pnph;
     struct option_rom_pci_header *pcih;
-    uint32_t devfn;
-    uint16_t class, vendor_id, device_id;
     uint8_t csum;
     int i;
 
-    for ( devfn = 0; devfn < 128; devfn++ )
-    {
-        class     = pci_readw(devfn, PCI_CLASS_DEVICE);
-        vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
-        device_id = pci_readw(devfn, PCI_DEVICE_ID);
-
-        if ( (vendor_id == 0xffff) && (device_id == 0xffff) )
-            continue;
-
-        /* We're only interested in NICs. */
-        if ( class != 0x0200 )
-            continue;
-
-        rom = (struct option_rom_header *)etherboot;
-        for ( ; ; )
-        {
-            /* Invalid signature means we're out of option ROMs. */
-            if ( strncmp((char *)rom->signature, "\x55\xaa", 2) ||
-                 (rom->rom_size == 0) )
-                break;
-
-            /* Invalid checksum means we're out of option ROMs. */
-            csum = 0;
-            for ( i = 0; i < (rom->rom_size * 512); i++ )
-                csum += ((uint8_t *)rom)[i];
-            if ( csum != 0 )
-                break;
-
-            /* Check the PCI PnP header (if any) for a match. */
-            pcih = (struct option_rom_pci_header *)
-                ((char *)rom + rom->pci_header_offset);
-            if ( (rom->pci_header_offset != 0) &&
-                 !strncmp((char *)pcih->signature, "PCIR", 4) &&
-                 (pcih->vendor_id == vendor_id) &&
-                 (pcih->device_id == device_id) )
-                goto found;
-
-            rom = (struct option_rom_header *)
-                ((char *)rom + rom->rom_size * 512);
-        }
+    static uint32_t orom_ids[64];
+    static int nr_roms;
+
+    /* Avoid duplicate ROMs. */
+    for ( i = 0; i < nr_roms; i++ )
+        if ( orom_ids[i] == (vendor_id | ((uint32_t)device_id << 16)) )
+            return 0;
+
+    rom = roms;
+    for ( ; ; )
+    {
+        /* Invalid signature means we're out of option ROMs. */
+        if ( strncmp((char *)rom->signature, "\x55\xaa", 2) ||
+             (rom->rom_size == 0) )
+            break;
+
+        /* Invalid checksum means we're out of option ROMs. */
+        csum = 0;
+        for ( i = 0; i < (rom->rom_size * 512); i++ )
+            csum += ((uint8_t *)rom)[i];
+        if ( csum != 0 )
+            break;
+
+        /* Check the PCI PnP header (if any) for a match. */
+        pcih = (struct option_rom_pci_header *)
+            ((char *)rom + rom->pci_header_offset);
+        if ( (rom->pci_header_offset != 0) &&
+             !strncmp((char *)pcih->signature, "PCIR", 4) &&
+             (pcih->vendor_id == vendor_id) &&
+             (pcih->device_id == device_id) )
+            goto found;
+
+        rom = (struct option_rom_header *)
+            ((char *)rom + rom->rom_size * 512);
     }
 
     return 0;
@@ -392,15 +387,95 @@ static int scan_etherboot_nic(void *copy
                    ((char *)rom + pnph->next_header_offset))
                 : ((struct option_rom_pnp_header *)NULL));
 
-    printf("Loading PXE ROM ...\n");
+    printf("Loading PCI Option ROM ...\n");
     if ( (pnph != NULL) && (pnph->manufacturer_name_offset != 0) )
         printf(" - Manufacturer: %s\n",
                (char *)rom + pnph->manufacturer_name_offset);
     if ( (pnph != NULL) && (pnph->product_name_offset != 0) )
         printf(" - Product name: %s\n",
                (char *)rom + pnph->product_name_offset);
-    memcpy(copy_rom_dest, rom, rom->rom_size * 512);
-    return rom->rom_size * 512;
+
+    if ( (dest + rom->rom_size * 512) > 0xe0000u )
+    {
+        printf("Option ROM size %x exceeds available space\n",
+               rom->rom_size * 512);
+        return 0;
+    }
+
+    orom_ids[nr_roms++] = vendor_id | ((uint32_t)device_id << 16);
+    memcpy((void *)dest, rom, rom->rom_size * 512);
+    return round_option_rom(rom->rom_size * 512);
+}
+
+/*
+ * Scan the PCI bus for the first NIC supported by etherboot, and copy
+ * the corresponding rom data to *copy_rom_dest. Returns the length of the
+ * selected rom, or 0 if no NIC found.
+ */
+static int scan_etherboot_nic(uint32_t copy_rom_dest)
+{
+    uint32_t devfn;
+    uint16_t class, vendor_id, device_id;
+
+    for ( devfn = 0; devfn < 128; devfn++ )
+    {
+        class     = pci_readw(devfn, PCI_CLASS_DEVICE);
+        vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
+        device_id = pci_readw(devfn, PCI_DEVICE_ID);
+
+        /* We're only interested in NICs. */
+        if ( (vendor_id != 0xffff) &&
+             (device_id != 0xffff) &&
+             (class == 0x0200) )
+            return scan_option_rom(
+                vendor_id, device_id, etherboot, copy_rom_dest);
+    }
+
+    return 0;
+}
+
+/*
+ * Scan the PCI bus for the devices that have an option ROM, and copy
+ * the corresponding rom data to rom_phys_addr.
+ */
+static int pci_load_option_roms(uint32_t rom_base_addr)
+{
+    uint32_t devfn, option_rom_addr, rom_phys_addr = rom_base_addr;
+    uint16_t vendor_id, device_id;
+    uint8_t class;
+
+    for ( devfn = 0; devfn < 128; devfn++ )
+    {
+        class     = pci_readb(devfn, PCI_CLASS_DEVICE + 1);
+        vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
+        device_id = pci_readw(devfn, PCI_DEVICE_ID);
+
+        if ( (vendor_id == 0xffff) && (device_id == 0xffff) )
+            continue;
+
+        /*
+         * Currently only scan options from mass storage devices and serial
+         * bus controller (Fibre Channel included).
+         */
+        if ( (class != 0x1) && (class != 0xc) )
+            continue;
+
+        option_rom_addr = pci_readl(devfn, PCI_ROM_ADDRESS);
+        if ( !option_rom_addr )
+            continue;
+
+        /* Ensure Expansion Bar is enabled before copying */
+        pci_writel(devfn, PCI_ROM_ADDRESS, option_rom_addr | 0x1);
+
+        rom_phys_addr += scan_option_rom(
+            vendor_id, device_id, (void *)(option_rom_addr & ~2047),
+            rom_phys_addr);
+
+        /* Restore the default original value of Expansion Bar */
+        pci_writel(devfn, PCI_ROM_ADDRESS, option_rom_addr);
+    }
+
+    return rom_phys_addr - rom_base_addr;
 }
 
 /* Replace possibly erroneous memory-size CMOS fields with correct values. */
@@ -461,8 +536,9 @@ static uint16_t init_xen_platform_io_bas
 
 int main(void)
 {
-    int vgabios_sz = 0, etherboot_sz = 0, rombios_sz, smbios_sz;
-    uint32_t etherboot_phys_addr, vga_ram = 0;
+    int option_rom_sz = 0, vgabios_sz = 0, etherboot_sz = 0;
+    int rombios_sz, smbios_sz;
+    uint32_t etherboot_phys_addr, option_rom_phys_addr, vga_ram = 0;
     uint16_t xen_pfiob;
 
     printf("HVM Loader\n");
@@ -497,13 +573,13 @@ int main(void)
         printf("Loading Cirrus VGABIOS ...\n");
         memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
                vgabios_cirrusvga, sizeof(vgabios_cirrusvga));
-        vgabios_sz = sizeof(vgabios_cirrusvga);
+        vgabios_sz = round_option_rom(sizeof(vgabios_cirrusvga));
         break;
     case VGA_std:
         printf("Loading Standard VGABIOS ...\n");
         memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
                vgabios_stdvga, sizeof(vgabios_stdvga));
-        vgabios_sz = sizeof(vgabios_stdvga);
+        vgabios_sz = round_option_rom(sizeof(vgabios_stdvga));
         break;
     default:
         printf("No emulated VGA adaptor ...\n");
@@ -516,10 +592,11 @@ int main(void)
         printf("VGA RAM at %08x\n", vga_ram);
     }
 
-    /* Ethernet ROM is placed after VGA ROM, on next 2kB boundary. */
-    etherboot_phys_addr =
-        (VGABIOS_PHYSICAL_ADDRESS + vgabios_sz + 2047) & ~2047;
-    etherboot_sz = scan_etherboot_nic((void *)etherboot_phys_addr);
+    etherboot_phys_addr = VGABIOS_PHYSICAL_ADDRESS + vgabios_sz;
+    etherboot_sz = scan_etherboot_nic(etherboot_phys_addr);
+
+    option_rom_phys_addr = etherboot_phys_addr + etherboot_sz;
+    option_rom_sz = pci_load_option_roms(option_rom_phys_addr);
 
     if ( get_acpi_enabled() )
     {
@@ -538,6 +615,10 @@ int main(void)
         printf(" %05x-%05x: Etherboot ROM\n",
                etherboot_phys_addr,
                etherboot_phys_addr + etherboot_sz - 1);
+    if ( option_rom_sz )
+        printf(" %05x-%05x: PCI Option ROMs\n",
+               option_rom_phys_addr,
+               option_rom_phys_addr + option_rom_sz - 1);
     if ( smbios_sz )
         printf(" %05x-%05x: SMBIOS tables\n",
                SMBIOS_PHYSICAL_ADDRESS,

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.