diff --git a/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c b/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c index 7c54fc5791..27ef7b90a5 100644 --- a/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c +++ b/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c @@ -32,6 +32,17 @@ InstallDevicePathCallback ( VOID ); +STATIC +VOID +LoadVideoRom ( + ); + +STATIC +EFI_STATUS +PciRomLoadEfiDriversFromRomImage ( + IN EFI_PHYSICAL_ADDRESS Rom, + IN UINTN RomSize + ); // // BDS Platform Functions @@ -58,6 +69,7 @@ Returns: { DEBUG ((EFI_D_INFO, "PlatformBdsInit\n")); InstallDevicePathCallback (); + LoadVideoRom (); } @@ -1203,3 +1215,175 @@ LockKeyboards ( { return EFI_UNSUPPORTED; } + + +STATIC +VOID +LoadVideoRom ( + ) +{ + PCI_DATA_STRUCTURE *Pcir; + UINTN RomSize; + + // + // The virtual machines sometimes load the video rom image + // directly at the legacy video BIOS location of C000:0000, + // and do not implement the PCI expansion ROM feature. + // + Pcir = (PCI_DATA_STRUCTURE *) (UINTN) 0xc0000; + RomSize = Pcir->ImageLength * 512; + PciRomLoadEfiDriversFromRomImage (0xc0000, RomSize); +} + + +STATIC +EFI_STATUS +PciRomLoadEfiDriversFromRomImage ( + IN EFI_PHYSICAL_ADDRESS Rom, + IN UINTN RomSize + ) +{ + CHAR16 *FileName; + EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader; + PCI_DATA_STRUCTURE *Pcir; + UINTN ImageIndex; + UINTN RomOffset; + UINT32 ImageSize; + UINT16 ImageOffset; + EFI_HANDLE ImageHandle; + EFI_STATUS Status; + EFI_STATUS retStatus; + EFI_DEVICE_PATH_PROTOCOL *FilePath; + BOOLEAN SkipImage; + UINT32 DestinationSize; + UINT32 ScratchSize; + UINT8 *Scratch; + VOID *ImageBuffer; + VOID *DecompressedImageBuffer; + UINT32 ImageLength; + EFI_DECOMPRESS_PROTOCOL *Decompress; + + FileName = L"PciRomInMemory"; + + //FileName = L"PciRom Addr=0000000000000000"; + //HexToString (&FileName[12], Rom, 16); + + ImageIndex = 0; + retStatus = EFI_NOT_FOUND; + RomOffset = (UINTN) Rom; + + do { + + EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (UINTN) RomOffset; + + if (EfiRomHeader->Signature != 0xaa55) { + return retStatus; + } + + Pcir = (PCI_DATA_STRUCTURE *) (UINTN) (RomOffset + EfiRomHeader->PcirOffset); + ImageSize = Pcir->ImageLength * 512; + + if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) && + (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) ) { + + if ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) || + (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ) { + + ImageOffset = EfiRomHeader->EfiImageHeaderOffset; + ImageSize = EfiRomHeader->InitializationSize * 512; + + ImageBuffer = (VOID *) (UINTN) (RomOffset + ImageOffset); + ImageLength = ImageSize - ImageOffset; + DecompressedImageBuffer = NULL; + + // + // decompress here if needed + // + SkipImage = FALSE; + if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { + SkipImage = TRUE; + } + + if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { + Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress); + if (EFI_ERROR (Status)) { + SkipImage = TRUE; + } else { + SkipImage = TRUE; + Status = Decompress->GetInfo ( + Decompress, + ImageBuffer, + ImageLength, + &DestinationSize, + &ScratchSize + ); + if (!EFI_ERROR (Status)) { + DecompressedImageBuffer = NULL; + DecompressedImageBuffer = AllocatePool (DestinationSize); + if (DecompressedImageBuffer != NULL) { + Scratch = AllocatePool (ScratchSize); + if (Scratch != NULL) { + Status = Decompress->Decompress ( + Decompress, + ImageBuffer, + ImageLength, + DecompressedImageBuffer, + DestinationSize, + Scratch, + ScratchSize + ); + if (!EFI_ERROR (Status)) { + ImageBuffer = DecompressedImageBuffer; + ImageLength = DestinationSize; + SkipImage = FALSE; + } + + gBS->FreePool (Scratch); + } + } + } + } + } + + if (!SkipImage) { + + // + // load image and start image + // + + FilePath = FileDevicePath (NULL, FileName); + + Status = gBS->LoadImage ( + FALSE, + gImageHandle, + FilePath, + ImageBuffer, + ImageLength, + &ImageHandle + ); + if (!EFI_ERROR (Status)) { + Status = gBS->StartImage (ImageHandle, NULL, NULL); + if (!EFI_ERROR (Status)) { + retStatus = Status; + } + } + if (FilePath != NULL) { + gBS->FreePool (FilePath); + } + } + + if (DecompressedImageBuffer != NULL) { + gBS->FreePool (DecompressedImageBuffer); + } + + } + } + + RomOffset = RomOffset + ImageSize; + ImageIndex++; + } while (((Pcir->Indicator & 0x80) == 0x00) && ((RomOffset - (UINTN) Rom) < RomSize)); + + return retStatus; +} + + diff --git a/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.h b/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.h index dc28515878..ef433c2370 100644 --- a/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.h +++ b/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.h @@ -29,7 +29,7 @@ Abstract: #include #include #include -//#include +#include #include #include @@ -47,6 +47,7 @@ Abstract: #include #include +#include #include #include diff --git a/OvmfPkg/Library/PlatformBdsLib/PlatformBdsLib.inf b/OvmfPkg/Library/PlatformBdsLib/PlatformBdsLib.inf index 1534ac8fc6..4689a79183 100644 --- a/OvmfPkg/Library/PlatformBdsLib/PlatformBdsLib.inf +++ b/OvmfPkg/Library/PlatformBdsLib/PlatformBdsLib.inf @@ -55,3 +55,6 @@ [Pcd.IA32, Pcd.X64] gEfiMdePkgTokenSpaceGuid.PcdFSBClock +[Protocols] + gEfiDecompressProtocolGuid +