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>
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 + static uint32_t orom_ids[64]; 1.34 + static int nr_roms; 1.35 + 1.36 + /* Avoid duplicate ROMs. */ 1.37 + for ( i = 0; i < nr_roms; i++ ) 1.38 + if ( orom_ids[i] == (vendor_id | ((uint32_t)device_id << 16)) ) 1.39 + return 0; 1.40 1.41 - if ( (vendor_id == 0xffff) && (device_id == 0xffff) ) 1.42 - continue; 1.43 - 1.44 - /* We're only interested in NICs. */ 1.45 - if ( class != 0x0200 ) 1.46 - continue; 1.47 + rom = roms; 1.48 + for ( ; ; ) 1.49 + { 1.50 + /* Invalid signature means we're out of option ROMs. */ 1.51 + if ( strncmp((char *)rom->signature, "\x55\xaa", 2) || 1.52 + (rom->rom_size == 0) ) 1.53 + break; 1.54 1.55 - rom = (struct option_rom_header *)etherboot; 1.56 - for ( ; ; ) 1.57 - { 1.58 - /* Invalid signature means we're out of option ROMs. */ 1.59 - if ( strncmp((char *)rom->signature, "\x55\xaa", 2) || 1.60 - (rom->rom_size == 0) ) 1.61 - break; 1.62 + /* Invalid checksum means we're out of option ROMs. */ 1.63 + csum = 0; 1.64 + for ( i = 0; i < (rom->rom_size * 512); i++ ) 1.65 + csum += ((uint8_t *)rom)[i]; 1.66 + if ( csum != 0 ) 1.67 + break; 1.68 1.69 - /* Invalid checksum means we're out of option ROMs. */ 1.70 - csum = 0; 1.71 - for ( i = 0; i < (rom->rom_size * 512); i++ ) 1.72 - csum += ((uint8_t *)rom)[i]; 1.73 - if ( csum != 0 ) 1.74 - break; 1.75 + /* Check the PCI PnP header (if any) for a match. */ 1.76 + pcih = (struct option_rom_pci_header *) 1.77 + ((char *)rom + rom->pci_header_offset); 1.78 + if ( (rom->pci_header_offset != 0) && 1.79 + !strncmp((char *)pcih->signature, "PCIR", 4) && 1.80 + (pcih->vendor_id == vendor_id) && 1.81 + (pcih->device_id == device_id) ) 1.82 + goto found; 1.83 1.84 - /* Check the PCI PnP header (if any) for a match. */ 1.85 - pcih = (struct option_rom_pci_header *) 1.86 - ((char *)rom + rom->pci_header_offset); 1.87 - if ( (rom->pci_header_offset != 0) && 1.88 - !strncmp((char *)pcih->signature, "PCIR", 4) && 1.89 - (pcih->vendor_id == vendor_id) && 1.90 - (pcih->device_id == device_id) ) 1.91 - goto found; 1.92 - 1.93 - rom = (struct option_rom_header *) 1.94 - ((char *)rom + rom->rom_size * 512); 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,