ia64/xen-unstable

changeset 18827:521d4d90f6e3

hvmloader: Load physical PCI option ROMs where available.

Signed-off-by: Shan Haitao <Haitao.shan@intel.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Nov 24 13:43:28 2008 +0000 (2008-11-24)
parents 612218519cb5
children e7c421510be9
files tools/firmware/hvmloader/hvmloader.c
line diff
     1.1 --- a/tools/firmware/hvmloader/hvmloader.c	Mon Nov 24 11:17:44 2008 +0000
     1.2 +++ b/tools/firmware/hvmloader/hvmloader.c	Mon Nov 24 13:43:28 2008 +0000
     1.3 @@ -322,60 +322,55 @@ static void pci_setup(void)
     1.4  }
     1.5  
     1.6  /*
     1.7 - * Scan the PCI bus for the first NIC supported by etherboot, and copy
     1.8 - * the corresponding rom data to *copy_rom_dest. Returns the length of the
     1.9 - * selected rom, or 0 if no NIC found.
    1.10 + * Scan the list of Option ROMs at @roms for one which supports 
    1.11 + * PCI (@vendor_id, @device_id). If one is found, copy it to @dest and
    1.12 + * return its size rounded up to a multiple 2kB. This function will not
    1.13 + * copy ROMs beyond address 0xE0000.
    1.14   */
    1.15 -static int scan_etherboot_nic(void *copy_rom_dest)
    1.16 +#define round_option_rom(x) (((x) + 2047) & ~2047)
    1.17 +static int scan_option_rom(
    1.18 +    uint16_t vendor_id, uint16_t device_id, void *roms, uint32_t dest)
    1.19  {
    1.20      struct option_rom_header *rom;
    1.21      struct option_rom_pnp_header *pnph;
    1.22      struct option_rom_pci_header *pcih;
    1.23 -    uint32_t devfn;
    1.24 -    uint16_t class, vendor_id, device_id;
    1.25      uint8_t csum;
    1.26      int i;
    1.27  
    1.28 -    for ( devfn = 0; devfn < 128; devfn++ )
    1.29 -    {
    1.30 -        class     = pci_readw(devfn, PCI_CLASS_DEVICE);
    1.31 -        vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
    1.32 -        device_id = pci_readw(devfn, PCI_DEVICE_ID);
    1.33 -
    1.34 -        if ( (vendor_id == 0xffff) && (device_id == 0xffff) )
    1.35 -            continue;
    1.36 -
    1.37 -        /* We're only interested in NICs. */
    1.38 -        if ( class != 0x0200 )
    1.39 -            continue;
    1.40 +    static uint32_t orom_ids[64];
    1.41 +    static int nr_roms;
    1.42  
    1.43 -        rom = (struct option_rom_header *)etherboot;
    1.44 -        for ( ; ; )
    1.45 -        {
    1.46 -            /* Invalid signature means we're out of option ROMs. */
    1.47 -            if ( strncmp((char *)rom->signature, "\x55\xaa", 2) ||
    1.48 -                 (rom->rom_size == 0) )
    1.49 -                break;
    1.50 +    /* Avoid duplicate ROMs. */
    1.51 +    for ( i = 0; i < nr_roms; i++ )
    1.52 +        if ( orom_ids[i] == (vendor_id | ((uint32_t)device_id << 16)) )
    1.53 +            return 0;
    1.54  
    1.55 -            /* Invalid checksum means we're out of option ROMs. */
    1.56 -            csum = 0;
    1.57 -            for ( i = 0; i < (rom->rom_size * 512); i++ )
    1.58 -                csum += ((uint8_t *)rom)[i];
    1.59 -            if ( csum != 0 )
    1.60 -                break;
    1.61 +    rom = roms;
    1.62 +    for ( ; ; )
    1.63 +    {
    1.64 +        /* Invalid signature means we're out of option ROMs. */
    1.65 +        if ( strncmp((char *)rom->signature, "\x55\xaa", 2) ||
    1.66 +             (rom->rom_size == 0) )
    1.67 +            break;
    1.68  
    1.69 -            /* Check the PCI PnP header (if any) for a match. */
    1.70 -            pcih = (struct option_rom_pci_header *)
    1.71 -                ((char *)rom + rom->pci_header_offset);
    1.72 -            if ( (rom->pci_header_offset != 0) &&
    1.73 -                 !strncmp((char *)pcih->signature, "PCIR", 4) &&
    1.74 -                 (pcih->vendor_id == vendor_id) &&
    1.75 -                 (pcih->device_id == device_id) )
    1.76 -                goto found;
    1.77 +        /* Invalid checksum means we're out of option ROMs. */
    1.78 +        csum = 0;
    1.79 +        for ( i = 0; i < (rom->rom_size * 512); i++ )
    1.80 +            csum += ((uint8_t *)rom)[i];
    1.81 +        if ( csum != 0 )
    1.82 +            break;
    1.83  
    1.84 -            rom = (struct option_rom_header *)
    1.85 -                ((char *)rom + rom->rom_size * 512);
    1.86 -        }
    1.87 +        /* Check the PCI PnP header (if any) for a match. */
    1.88 +        pcih = (struct option_rom_pci_header *)
    1.89 +            ((char *)rom + rom->pci_header_offset);
    1.90 +        if ( (rom->pci_header_offset != 0) &&
    1.91 +             !strncmp((char *)pcih->signature, "PCIR", 4) &&
    1.92 +             (pcih->vendor_id == vendor_id) &&
    1.93 +             (pcih->device_id == device_id) )
    1.94 +            goto found;
    1.95 +
    1.96 +        rom = (struct option_rom_header *)
    1.97 +            ((char *)rom + rom->rom_size * 512);
    1.98      }
    1.99  
   1.100      return 0;
   1.101 @@ -392,15 +387,95 @@ static int scan_etherboot_nic(void *copy
   1.102                     ((char *)rom + pnph->next_header_offset))
   1.103                  : ((struct option_rom_pnp_header *)NULL));
   1.104  
   1.105 -    printf("Loading PXE ROM ...\n");
   1.106 +    printf("Loading PCI Option ROM ...\n");
   1.107      if ( (pnph != NULL) && (pnph->manufacturer_name_offset != 0) )
   1.108          printf(" - Manufacturer: %s\n",
   1.109                 (char *)rom + pnph->manufacturer_name_offset);
   1.110      if ( (pnph != NULL) && (pnph->product_name_offset != 0) )
   1.111          printf(" - Product name: %s\n",
   1.112                 (char *)rom + pnph->product_name_offset);
   1.113 -    memcpy(copy_rom_dest, rom, rom->rom_size * 512);
   1.114 -    return rom->rom_size * 512;
   1.115 +
   1.116 +    if ( (dest + rom->rom_size * 512) > 0xe0000u )
   1.117 +    {
   1.118 +        printf("Option ROM size %x exceeds available space\n",
   1.119 +               rom->rom_size * 512);
   1.120 +        return 0;
   1.121 +    }
   1.122 +
   1.123 +    orom_ids[nr_roms++] = vendor_id | ((uint32_t)device_id << 16);
   1.124 +    memcpy((void *)dest, rom, rom->rom_size * 512);
   1.125 +    return round_option_rom(rom->rom_size * 512);
   1.126 +}
   1.127 +
   1.128 +/*
   1.129 + * Scan the PCI bus for the first NIC supported by etherboot, and copy
   1.130 + * the corresponding rom data to *copy_rom_dest. Returns the length of the
   1.131 + * selected rom, or 0 if no NIC found.
   1.132 + */
   1.133 +static int scan_etherboot_nic(uint32_t copy_rom_dest)
   1.134 +{
   1.135 +    uint32_t devfn;
   1.136 +    uint16_t class, vendor_id, device_id;
   1.137 +
   1.138 +    for ( devfn = 0; devfn < 128; devfn++ )
   1.139 +    {
   1.140 +        class     = pci_readw(devfn, PCI_CLASS_DEVICE);
   1.141 +        vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
   1.142 +        device_id = pci_readw(devfn, PCI_DEVICE_ID);
   1.143 +
   1.144 +        /* We're only interested in NICs. */
   1.145 +        if ( (vendor_id != 0xffff) &&
   1.146 +             (device_id != 0xffff) &&
   1.147 +             (class == 0x0200) )
   1.148 +            return scan_option_rom(
   1.149 +                vendor_id, device_id, etherboot, copy_rom_dest);
   1.150 +    }
   1.151 +
   1.152 +    return 0;
   1.153 +}
   1.154 +
   1.155 +/*
   1.156 + * Scan the PCI bus for the devices that have an option ROM, and copy
   1.157 + * the corresponding rom data to rom_phys_addr.
   1.158 + */
   1.159 +static int pci_load_option_roms(uint32_t rom_base_addr)
   1.160 +{
   1.161 +    uint32_t devfn, option_rom_addr, rom_phys_addr = rom_base_addr;
   1.162 +    uint16_t vendor_id, device_id;
   1.163 +    uint8_t class;
   1.164 +
   1.165 +    for ( devfn = 0; devfn < 128; devfn++ )
   1.166 +    {
   1.167 +        class     = pci_readb(devfn, PCI_CLASS_DEVICE + 1);
   1.168 +        vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
   1.169 +        device_id = pci_readw(devfn, PCI_DEVICE_ID);
   1.170 +
   1.171 +        if ( (vendor_id == 0xffff) && (device_id == 0xffff) )
   1.172 +            continue;
   1.173 +
   1.174 +        /*
   1.175 +         * Currently only scan options from mass storage devices and serial
   1.176 +         * bus controller (Fibre Channel included).
   1.177 +         */
   1.178 +        if ( (class != 0x1) && (class != 0xc) )
   1.179 +            continue;
   1.180 +
   1.181 +        option_rom_addr = pci_readl(devfn, PCI_ROM_ADDRESS);
   1.182 +        if ( !option_rom_addr )
   1.183 +            continue;
   1.184 +
   1.185 +        /* Ensure Expansion Bar is enabled before copying */
   1.186 +        pci_writel(devfn, PCI_ROM_ADDRESS, option_rom_addr | 0x1);
   1.187 +
   1.188 +        rom_phys_addr += scan_option_rom(
   1.189 +            vendor_id, device_id, (void *)(option_rom_addr & ~2047),
   1.190 +            rom_phys_addr);
   1.191 +
   1.192 +        /* Restore the default original value of Expansion Bar */
   1.193 +        pci_writel(devfn, PCI_ROM_ADDRESS, option_rom_addr);
   1.194 +    }
   1.195 +
   1.196 +    return rom_phys_addr - rom_base_addr;
   1.197  }
   1.198  
   1.199  /* Replace possibly erroneous memory-size CMOS fields with correct values. */
   1.200 @@ -461,8 +536,9 @@ static uint16_t init_xen_platform_io_bas
   1.201  
   1.202  int main(void)
   1.203  {
   1.204 -    int vgabios_sz = 0, etherboot_sz = 0, rombios_sz, smbios_sz;
   1.205 -    uint32_t etherboot_phys_addr, vga_ram = 0;
   1.206 +    int option_rom_sz = 0, vgabios_sz = 0, etherboot_sz = 0;
   1.207 +    int rombios_sz, smbios_sz;
   1.208 +    uint32_t etherboot_phys_addr, option_rom_phys_addr, vga_ram = 0;
   1.209      uint16_t xen_pfiob;
   1.210  
   1.211      printf("HVM Loader\n");
   1.212 @@ -497,13 +573,13 @@ int main(void)
   1.213          printf("Loading Cirrus VGABIOS ...\n");
   1.214          memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
   1.215                 vgabios_cirrusvga, sizeof(vgabios_cirrusvga));
   1.216 -        vgabios_sz = sizeof(vgabios_cirrusvga);
   1.217 +        vgabios_sz = round_option_rom(sizeof(vgabios_cirrusvga));
   1.218          break;
   1.219      case VGA_std:
   1.220          printf("Loading Standard VGABIOS ...\n");
   1.221          memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
   1.222                 vgabios_stdvga, sizeof(vgabios_stdvga));
   1.223 -        vgabios_sz = sizeof(vgabios_stdvga);
   1.224 +        vgabios_sz = round_option_rom(sizeof(vgabios_stdvga));
   1.225          break;
   1.226      default:
   1.227          printf("No emulated VGA adaptor ...\n");
   1.228 @@ -516,10 +592,11 @@ int main(void)
   1.229          printf("VGA RAM at %08x\n", vga_ram);
   1.230      }
   1.231  
   1.232 -    /* Ethernet ROM is placed after VGA ROM, on next 2kB boundary. */
   1.233 -    etherboot_phys_addr =
   1.234 -        (VGABIOS_PHYSICAL_ADDRESS + vgabios_sz + 2047) & ~2047;
   1.235 -    etherboot_sz = scan_etherboot_nic((void *)etherboot_phys_addr);
   1.236 +    etherboot_phys_addr = VGABIOS_PHYSICAL_ADDRESS + vgabios_sz;
   1.237 +    etherboot_sz = scan_etherboot_nic(etherboot_phys_addr);
   1.238 +
   1.239 +    option_rom_phys_addr = etherboot_phys_addr + etherboot_sz;
   1.240 +    option_rom_sz = pci_load_option_roms(option_rom_phys_addr);
   1.241  
   1.242      if ( get_acpi_enabled() )
   1.243      {
   1.244 @@ -538,6 +615,10 @@ int main(void)
   1.245          printf(" %05x-%05x: Etherboot ROM\n",
   1.246                 etherboot_phys_addr,
   1.247                 etherboot_phys_addr + etherboot_sz - 1);
   1.248 +    if ( option_rom_sz )
   1.249 +        printf(" %05x-%05x: PCI Option ROMs\n",
   1.250 +               option_rom_phys_addr,
   1.251 +               option_rom_phys_addr + option_rom_sz - 1);
   1.252      if ( smbios_sz )
   1.253          printf(" %05x-%05x: SMBIOS tables\n",
   1.254                 SMBIOS_PHYSICAL_ADDRESS,