1 /*++ 2 3 Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR> 4 This program and the accompanying materials 5 are licensed and made available under the terms and conditions of the BSD License 6 which accompanies this distribution. The full text of the license may be found at 7 http://opensource.org/licenses/bsd-license.php 8 9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12 Module Name: 13 14 PciRomTable.c 15 16 Abstract: 17 18 Option Rom Support for PCI Bus Driver 19 20 Revision History 21 22 --*/ 23 24 #include "PciBus.h" 25 26 typedef struct { 27 EFI_HANDLE ImageHandle; 28 UINTN Seg; 29 UINT8 Bus; 30 UINT8 Dev; 31 UINT8 Func; 32 } EFI_PCI_ROM_IMAGE_MAPPING; 33 34 UINTN mNumberOfPciRomImages = 0; 35 UINTN mMaxNumberOfPciRomImages = 0; 36 EFI_PCI_ROM_IMAGE_MAPPING *mRomImageTable = NULL; 37 38 CHAR16 mHexDigit[17] = L"0123456789ABCDEF"; 39 40 VOID 41 PciRomAddImageMapping ( 42 IN EFI_HANDLE ImageHandle, 43 IN UINTN Seg, 44 IN UINT8 Bus, 45 IN UINT8 Dev, 46 IN UINT8 Func 47 ) 48 49 { 50 EFI_PCI_ROM_IMAGE_MAPPING *TempMapping; 51 52 if (mNumberOfPciRomImages >= mMaxNumberOfPciRomImages) { 53 54 mMaxNumberOfPciRomImages += 0x20; 55 56 TempMapping = NULL; 57 TempMapping = AllocatePool (mMaxNumberOfPciRomImages * sizeof (EFI_PCI_ROM_IMAGE_MAPPING)); 58 if (TempMapping == NULL) { 59 return ; 60 } 61 62 CopyMem (TempMapping, mRomImageTable, mNumberOfPciRomImages * sizeof (EFI_PCI_ROM_IMAGE_MAPPING)); 63 64 if (mRomImageTable != NULL) { 65 gBS->FreePool (mRomImageTable); 66 } 67 68 mRomImageTable = TempMapping; 69 } 70 71 mRomImageTable[mNumberOfPciRomImages].ImageHandle = ImageHandle; 72 mRomImageTable[mNumberOfPciRomImages].Seg = Seg; 73 mRomImageTable[mNumberOfPciRomImages].Bus = Bus; 74 mRomImageTable[mNumberOfPciRomImages].Dev = Dev; 75 mRomImageTable[mNumberOfPciRomImages].Func = Func; 76 mNumberOfPciRomImages++; 77 } 78 79 VOID 80 HexToString ( 81 CHAR16 *String, 82 UINTN Value, 83 UINTN Digits 84 ) 85 86 { 87 for (; Digits > 0; Digits--, String++) { 88 *String = mHexDigit[((Value >> (4*(Digits-1))) & 0x0f)]; 89 } 90 } 91 92 EFI_STATUS 93 PciRomLoadEfiDriversFromRomImage ( 94 IN EFI_DRIVER_BINDING_PROTOCOL *This, 95 IN EFI_PCI_OPTION_ROM_DESCRIPTOR *PciOptionRomDescriptor 96 ) 97 /*++ 98 99 Routine Description: 100 Command entry point. 101 102 Arguments: 103 ImageHandle The image handle. 104 SystemTable The system table. 105 106 Returns: 107 EFI_SUCCESS - The command completed successfully 108 EFI_INVALID_PARAMETER - Command usage error 109 EFI_UNSUPPORTED - Protocols unsupported 110 EFI_OUT_OF_RESOURCES - Out of memory 111 Other value - Unknown error 112 113 --*/ 114 { 115 VOID *RomBar; 116 UINTN RomSize; 117 CHAR16 *FileName; 118 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader; 119 PCI_DATA_STRUCTURE *Pcir; 120 UINTN ImageIndex; 121 UINTN RomBarOffset; 122 UINT32 ImageSize; 123 UINT16 ImageOffset; 124 EFI_HANDLE ImageHandle; 125 EFI_STATUS Status; 126 EFI_STATUS retStatus; 127 EFI_DEVICE_PATH_PROTOCOL *FilePath; 128 BOOLEAN SkipImage; 129 UINT32 DestinationSize; 130 UINT32 ScratchSize; 131 UINT8 *Scratch; 132 VOID *ImageBuffer; 133 VOID *DecompressedImageBuffer; 134 UINT32 ImageLength; 135 EFI_DECOMPRESS_PROTOCOL *Decompress; 136 UINT32 InitializationSize; 137 138 RomBar = (VOID *) (UINTN) PciOptionRomDescriptor->RomAddress; 139 RomSize = (UINTN) PciOptionRomDescriptor->RomLength; 140 FileName = L"PciRom Seg=00000000 Bus=00 Dev=00 Func=00 Image=0000"; 141 142 HexToString (&FileName[11], PciOptionRomDescriptor->Seg, 8); 143 HexToString (&FileName[24], PciOptionRomDescriptor->Bus, 2); 144 HexToString (&FileName[31], PciOptionRomDescriptor->Dev, 2); 145 HexToString (&FileName[39], PciOptionRomDescriptor->Func, 2); 146 147 ImageIndex = 0; 148 retStatus = EFI_NOT_FOUND; 149 RomBarOffset = (UINTN) RomBar; 150 151 do { 152 153 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (UINTN) RomBarOffset; 154 155 156 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { 157 return retStatus; 158 } 159 160 // 161 // If the pointer to the PCI Data Structure is invalid, no further images can be located. 162 // The PCI Data Structure must be DWORD aligned. 163 // 164 if (EfiRomHeader->PcirOffset == 0 || 165 (EfiRomHeader->PcirOffset & 3) != 0 || 166 RomBarOffset - (UINTN)RomBar + EfiRomHeader->PcirOffset + sizeof (PCI_DATA_STRUCTURE) > RomSize) { 167 break; 168 } 169 Pcir = (PCI_DATA_STRUCTURE *) (UINTN) (RomBarOffset + EfiRomHeader->PcirOffset); 170 // 171 // If a valid signature is not present in the PCI Data Structure, no further images can be located. 172 // 173 if (Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) { 174 break; 175 } 176 ImageSize = Pcir->ImageLength * 512; 177 if (RomBarOffset - (UINTN)RomBar + ImageSize > RomSize) { 178 break; 179 } 180 181 if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) && 182 (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) && 183 ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) || 184 (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER))) { 185 186 ImageOffset = EfiRomHeader->EfiImageHeaderOffset; 187 InitializationSize = EfiRomHeader->InitializationSize * 512; 188 189 if (InitializationSize <= ImageSize && ImageOffset < InitializationSize) { 190 191 ImageBuffer = (VOID *) (UINTN) (RomBarOffset + ImageOffset); 192 ImageLength = InitializationSize - ImageOffset; 193 DecompressedImageBuffer = NULL; 194 195 // 196 // decompress here if needed 197 // 198 SkipImage = FALSE; 199 if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { 200 SkipImage = TRUE; 201 } 202 203 if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { 204 Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress); 205 if (EFI_ERROR (Status)) { 206 SkipImage = TRUE; 207 } else { 208 SkipImage = TRUE; 209 Status = Decompress->GetInfo ( 210 Decompress, 211 ImageBuffer, 212 ImageLength, 213 &DestinationSize, 214 &ScratchSize 215 ); 216 if (!EFI_ERROR (Status)) { 217 DecompressedImageBuffer = NULL; 218 DecompressedImageBuffer = AllocatePool (DestinationSize); 219 if (DecompressedImageBuffer != NULL) { 220 Scratch = AllocatePool (ScratchSize); 221 if (Scratch != NULL) { 222 Status = Decompress->Decompress ( 223 Decompress, 224 ImageBuffer, 225 ImageLength, 226 DecompressedImageBuffer, 227 DestinationSize, 228 Scratch, 229 ScratchSize 230 ); 231 if (!EFI_ERROR (Status)) { 232 ImageBuffer = DecompressedImageBuffer; 233 ImageLength = DestinationSize; 234 SkipImage = FALSE; 235 } 236 237 gBS->FreePool (Scratch); 238 } 239 } 240 } 241 } 242 } 243 244 if (!SkipImage) { 245 246 // 247 // load image and start image 248 // 249 250 HexToString (&FileName[48], ImageIndex, 4); 251 FilePath = FileDevicePath (NULL, FileName); 252 253 Status = gBS->LoadImage ( 254 FALSE, 255 This->ImageHandle, 256 FilePath, 257 ImageBuffer, 258 ImageLength, 259 &ImageHandle 260 ); 261 if (!EFI_ERROR (Status)) { 262 Status = gBS->StartImage (ImageHandle, NULL, NULL); 263 if (!EFI_ERROR (Status)) { 264 PciRomAddImageMapping ( 265 ImageHandle, 266 PciOptionRomDescriptor->Seg, 267 PciOptionRomDescriptor->Bus, 268 PciOptionRomDescriptor->Dev, 269 PciOptionRomDescriptor->Func 270 ); 271 retStatus = Status; 272 } 273 } 274 if (FilePath != NULL) { 275 gBS->FreePool (FilePath); 276 } 277 } 278 279 if (DecompressedImageBuffer != NULL) { 280 gBS->FreePool (DecompressedImageBuffer); 281 } 282 283 } 284 } 285 286 RomBarOffset = RomBarOffset + ImageSize; 287 ImageIndex++; 288 } while (((Pcir->Indicator & 0x80) == 0x00) && ((RomBarOffset - (UINTN) RomBar) < RomSize)); 289 290 return retStatus; 291 } 292 293 EFI_STATUS 294 PciRomLoadEfiDriversFromOptionRomTable ( 295 IN EFI_DRIVER_BINDING_PROTOCOL *This, 296 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo 297 ) 298 /*++ 299 300 Routine Description: 301 302 Arguments: 303 304 Returns: 305 306 --*/ 307 { 308 EFI_STATUS Status; 309 EFI_PCI_OPTION_ROM_TABLE *PciOptionRomTable; 310 EFI_PCI_OPTION_ROM_DESCRIPTOR *PciOptionRomDescriptor; 311 UINTN Index; 312 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; 313 UINT16 MinBus; 314 UINT16 MaxBus; 315 316 Status = EfiGetSystemConfigurationTable (&gEfiPciOptionRomTableGuid, (VOID **) &PciOptionRomTable); 317 if (EFI_ERROR (Status)) { 318 return EFI_NOT_FOUND; 319 } 320 321 Status = EFI_NOT_FOUND; 322 323 for (Index = 0; Index < PciOptionRomTable->PciOptionRomCount; Index++) { 324 PciOptionRomDescriptor = &PciOptionRomTable->PciOptionRomDescriptors[Index]; 325 if (!PciOptionRomDescriptor->DontLoadEfiRom) { 326 if (PciOptionRomDescriptor->Seg == PciRootBridgeIo->SegmentNumber) { 327 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors); 328 if (EFI_ERROR (Status)) { 329 return Status; 330 } 331 332 PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL); 333 if ((MinBus <= PciOptionRomDescriptor->Bus) && (PciOptionRomDescriptor->Bus <= MaxBus)) { 334 Status = PciRomLoadEfiDriversFromRomImage (This, PciOptionRomDescriptor); 335 PciOptionRomDescriptor->DontLoadEfiRom |= 2; 336 } 337 } 338 } 339 } 340 341 return Status; 342 } 343 344 EFI_STATUS 345 PciRomGetRomResourceFromPciOptionRomTable ( 346 IN EFI_DRIVER_BINDING_PROTOCOL *This, 347 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, 348 PCI_IO_DEVICE *PciIoDevice 349 ) 350 /*++ 351 352 Routine Description: 353 354 Arguments: 355 356 Returns: 357 358 --*/ 359 { 360 EFI_STATUS Status; 361 EFI_PCI_OPTION_ROM_TABLE *PciOptionRomTable; 362 EFI_PCI_OPTION_ROM_DESCRIPTOR *PciOptionRomDescriptor; 363 UINTN Index; 364 365 Status = EfiGetSystemConfigurationTable (&gEfiPciOptionRomTableGuid, (VOID **) &PciOptionRomTable); 366 if (EFI_ERROR (Status)) { 367 return EFI_NOT_FOUND; 368 } 369 370 for (Index = 0; Index < PciOptionRomTable->PciOptionRomCount; Index++) { 371 PciOptionRomDescriptor = &PciOptionRomTable->PciOptionRomDescriptors[Index]; 372 if (PciOptionRomDescriptor->Seg == PciRootBridgeIo->SegmentNumber && 373 PciOptionRomDescriptor->Bus == PciIoDevice->BusNumber && 374 PciOptionRomDescriptor->Dev == PciIoDevice->DeviceNumber && 375 PciOptionRomDescriptor->Func == PciIoDevice->FunctionNumber ) { 376 377 PciIoDevice->PciIo.RomImage = (VOID *) (UINTN) PciOptionRomDescriptor->RomAddress; 378 PciIoDevice->PciIo.RomSize = (UINTN) PciOptionRomDescriptor->RomLength; 379 } 380 } 381 382 for (Index = 0; Index < mNumberOfPciRomImages; Index++) { 383 if (mRomImageTable[Index].Seg == PciRootBridgeIo->SegmentNumber && 384 mRomImageTable[Index].Bus == PciIoDevice->BusNumber && 385 mRomImageTable[Index].Dev == PciIoDevice->DeviceNumber && 386 mRomImageTable[Index].Func == PciIoDevice->FunctionNumber ) { 387 388 AddDriver (PciIoDevice, mRomImageTable[Index].ImageHandle); 389 } 390 } 391 392 return EFI_SUCCESS; 393 } 394