Ryzen/AmiModulePkg/CSM/CsmOpROM.c
2022-12-23 15:14:44 +08:00

2111 lines
67 KiB
C

//***********************************************************************
//* *
//* Copyright (c) 1985-2021, American Megatrends International LLC. *
//* *
//* All rights reserved. Subject to AMI licensing agreement. *
//* *
//***********************************************************************
/** @file CsmOpROM.c
CSM ROM placement and execution interface routines
**/
#include "Csm.h"
#include "Token.h"
#include <AmiDxeLib.h>
#include "Pci.h"
#include <Protocol/PciIo.h>
#include "Setup.h"
#include <Protocol/AmiCsmOpromPolicy.h>
extern UINT8 *gNextRomAddress;
extern AMI_CSM_EXECUTED_PCI_ROM *gExecutedRomsPci;
extern SAVED_PCI_ROM *gSavedOprom;
extern SETUP_DATA gSetup;
AMI_CSM_OPROM_POLICY_PROTOCOL *gCsmPolicy = NULL;
EFI_HANDLE gVgaHandle = NULL;
BOOLEAN gBbsUpdateInProgress = FALSE;
BOOLEAN gDoNotUpdateBbsTable = FALSE;
BOOLEAN BeenHere = FALSE;
//
// gSetTxtMode
// ff - initial value
// 0 - switching to text mode is needed
// 1 - switching is needed, restoration is not
// 2 - neither switching nor restoration is needed
//
extern UINT8 gSetTxtMode;
extern BOOLEAN gServiceRomsExecuted;
#pragma pack(push, 1)
// EFI Load Option needed for call to LegacyBios->LegacyBoot()
static struct {
EFI_LOAD_OPTION LoadOption;
CHAR16 Description[10];
BBS_BBS_DEVICE_PATH BbsDevicePath;
EFI_DEVICE_PATH_PROTOCOL DevicePathEnd;
} DummyLoadOption = {
{ // EFI_LOAD_OPTION LoadOption
0, // Attributes (UINT32)
sizeof (BBS_BBS_DEVICE_PATH)
+ sizeof (EFI_DEVICE_PATH_PROTOCOL), // FilePathListLength (UINT16)
},
L"DummyLoad", // Description
{ // BbsDevicePath
{ // Header
BBS_DEVICE_PATH, // Type
BBS_BBS_DP, // Subtype
{ sizeof(BBS_BBS_DEVICE_PATH) } // Length
},
BBS_HARDDISK, // DeviceType
0, // StatusFlags
{0}, // String
},
{ // DevicePathEnd
END_DEVICE_PATH, // Type
END_ENTIRE_SUBTYPE, // SubType
{ sizeof(EFI_DEVICE_PATH_PROTOCOL) } // Size
}
};
#pragma pack(pop)
/**
Tests PCI ROM for Legacy PCI ROM compatibility.
@retval TRUE Image is valid
@retval FALSE Image is not valid
@note
From PCI Fw Specification 3.0, 5.2.1.21. Backward Compatibility of Option ROMs Page # 86.
It is also possible to have two separate ROM images for the same PCI device: one for PCI 2.1
System Firmware and one for PCI 3.0 compliance. In this case, the PCI 2.1 Option ROM image
must appear first in the sequence of images. PCI 3.0 System Firmware will first search for a
PCI 3.0 Option ROM image and only use the PCI 2.1 Option ROM image if no PCI 3.0 Option ROM
image is found.
**/
BOOLEAN
IsValidLegacyPciOpROM (
IN UINT32 VidDid, // PCI vendor ID/Device ID
IN OUT VOID **Image, // Pointer to the beginning of PCI Option ROM
IN OUT UINTN *Size // Input: PciIo->RomSize, Output: OpROM size in bytes
)
{
PCI_DATA_STRUCTURE *pcir;
BOOLEAN IsLastImage = FALSE;
UINT8 *RomStart = *Image;
UINT32 RomSize = 0;
BOOLEAN FoundLegacyRom = FALSE;
UINTN RomEnd = (UINTN)*Image + *Size;
for(; !IsLastImage && ((UINTN)RomStart < RomEnd); ) {
//
// Check for 55AA in the beginning of the image
//
if (((LEGACY_OPT_ROM_HEADER*)RomStart)->Signature != 0xaa55) {
RomStart += 512;
continue;
}
//
// Validate "PCIR" data
//
pcir = (PCI_DATA_STRUCTURE *)(RomStart + *(UINT16*)(RomStart + 0x18));
if (pcir->Signature != 0x52494350) return FALSE; // "PCIR"
IsLastImage = pcir->Indicator & 0x80;
// Code Type Description
// 0x00 Intel IA-32, PC-AT compatible
// 0x01 Open Firmware standard for PCI
// 0x02 Hewlett-Packard PA RISC
// 0x03 EFI Image
// 0x04-0xFF Reserved
//
if (pcir->CodeType == 0) { // IA-32, PC-AT compatible
if (pcir->Revision != 3 && FoundLegacyRom)
{
// More than one legacy OpROM is present with revision less
// than 3.0; return the pointer and the size of the previous one.
// Image and Size are updated when FoundLegacyRom became TRUE.
// This implements backward compatibility mentioned in the notes
// above.
//
return TRUE;
}
// Validate the ROM size
RomSize = pcir->ImageLength << 9;
if (RomSize <= 0x1fe00)
{
UINT32 HeaderRomSize = ((LEGACY_OPT_ROM_HEADER*)RomStart)->Size512 << 9;
if (HeaderRomSize > RomSize) RomSize = HeaderRomSize;
}
else
{
DEBUG((DEBUG_INFO, "CSM: Found unusually large legacy Option ROM (%d Bytes) - loading ", RomSize));
if (CSM_ALLOW_LARGE_OPROMS == 0)
{
DEBUG((DEBUG_INFO, "skipped.\n"));
RomSize = 0;
} else DEBUG((DEBUG_INFO, "allowed.\n"));
}
if (RomSize == 0) return FALSE;
*Image = RomStart;
*Size = (UINTN)RomSize;
if (pcir->Revision == 3) return TRUE;
FoundLegacyRom = TRUE;
RomStart += RomSize;
continue;
}
// Non-legacy ROM; find the size from "PCIR" structure
RomSize = pcir->ImageLength << 9;
RomStart += RomSize;
}
return FoundLegacyRom;
}
/**
This routine is called after every OpROM (BBS or non-BBS) is
executed. It updates the locations of EBDA in SAVED_PCI_ROM.ebdaAddr
fields after OpROM expands EBDA.
@param AddrChange The size of EBDA created by the OpROM
@note When this function is called SAVED_PCI_ROM structure will not have
the current OpROM information inserted; gSavedOprom is pointing to NULL
located right after the last valid entry (1st entry is also NULL).
**/
VOID
UpdateEbdaMap(UINT32 AddrChange)
{
SAVED_PCI_ROM *SavedOprom;
if (gSavedOprom == NULL) return;
//
// for every SAVED_PCI_ROM update ebdaAddr
//
for (SavedOprom=gSavedOprom-1; SavedOprom->Address; SavedOprom--) {
if (SavedOprom->isEbda && SavedOprom->rtDataAddr) {
SavedOprom->rtDataAddr -= AddrChange;
}
}
}
/**
This routine saves Oprom that was just executed to the next
gSavedOprom data field; gSavedOprom is incremented.
@param Rom Address and size or runtime data taken during ROM initialization
@note Saving Oprom data is only required for the option ROMs that
produce BCV because of early BCV execution; it should not be
called for non-BBS compliant OpROMs, for those OpROMs related
memory context will be the same til the system is booted.
**/
VOID
SaveOprom (
UINT8 *Rom,
UINT8 *RtDataAddr,
UINT32 RtDataSize,
BOOLEAN IsEbda,
UINT32 EbdaOffset
)
{
UINTN RomSize = ((LEGACY_OPT_ROM_HEADER*)Rom)->Size512 << 9;
if (RomSize==0) return;
pBS->AllocatePool(EfiBootServicesData, RomSize, (VOID**)&gSavedOprom->Data);
pBS->CopyMem(gSavedOprom->Data, Rom, RomSize);
gSavedOprom->Address = Rom;
//
// Save runtime data associated with this ROM
//
if (RtDataSize) {
ASSERT(RtDataAddr); // if size is not zero, address must not be zero
gSavedOprom->rtDataAddr = RtDataAddr;
gSavedOprom->rtDataSize = RtDataSize;
gSavedOprom->isEbda = IsEbda;
gSavedOprom->ebdaOffset = EbdaOffset;
pBS->AllocatePool(EfiBootServicesData, RtDataSize, (VOID**)&gSavedOprom->rtData);
pBS->CopyMem(gSavedOprom->rtData, RtDataAddr, RtDataSize);
}
gSavedOprom++; // Points to zero address/data now.
}
/**
Checks if the platform allows BCV execution; if so, executes BCV and logs
the status of HW interrupt changes.
**/
EFI_STATUS
ExecuteBcv (
BIOS_INFO *BiosInfo,
UINT8 *PciCfg,
UINT16 BcvSeg,
UINT16 BcvOfs,
UINT8 *Disk
)
{
EFI_STATUS Status;
UINTN TotalDevices;
UINT32 *DeviceList;
UINTN Counter;
EFI_IA32_REGISTER_SET RegSet;
UINT8 Irq;
UINT32 *volatile Ivt = (UINT32*)0;
UINT32 IrqHandler = 0;
static EFI_LEGACY_BIOS_EXT_PROTOCOL *LegacyBiosExt = NULL;
if (LegacyBiosExt == NULL) {
Status = pBS->LocateProtocol(&gEfiLegacyBiosExtProtocolGuid, NULL, (VOID**)&LegacyBiosExt);
ASSERT_EFI_ERROR(Status);
}
Status = LegacyBiosExt->GetPlatformInfoEx(LegacyBiosExt,
EfiGetBcvSkipDeviceList,
(VOID**)&DeviceList,
&TotalDevices,
NULL, NULL, 0, 0);
ASSERT_EFI_ERROR(Status);
if (EFI_ERROR(Status)) return Status;
if (TotalDevices > 0 && *DeviceList == 0xffffffff) return EFI_UNSUPPORTED; // Force to skip BCV execution
for (Counter = 0; Counter < TotalDevices; Counter++)
{
if (*(UINT32*)PciCfg == DeviceList[Counter]) return EFI_UNSUPPORTED;
}
// Get the hardware interrupt vector and its handler pointer
Irq = *(PciCfg+0x3C);
if (Irq > 0 && Irq < 0xF)
{
Status = BiosInfo->i8259->GetVector (BiosInfo->i8259, Irq, &Irq); // irq has INT number
ASSERT_EFI_ERROR(Status);
ACCESS_PAGE0_CODE(
IrqHandler = Ivt[Irq];
);
}
//
// Execute BCV
//
pBS->SetMem (&RegSet, sizeof (EFI_IA32_REGISTER_SET), 0);
RegSet.X.ES = BiosInfo->Csm16Header->PnPInstallationCheckSegment;
RegSet.X.DI = BiosInfo->Csm16Header->PnPInstallationCheckOffset;
FarCall86 (&BiosInfo->iBios,
BcvSeg,
BcvOfs,
&RegSet,
NULL,
0);
ACCESS_PAGE0_CODE(
if (IrqHandler && (Ivt[Irq] != IrqHandler)) {
*Disk |= 0x40; // Indicate BCV has hooked HW IRQ
}
);
return EFI_SUCCESS;
}
/**
Check PCI ROM for PnP structures and inserts BCV/BEV devices
into BBS table.
**/
VOID
FetchBbsBootDevices(
BIOS_INFO *BiosInfo,
UINT8 *Rom,
UINT8 *PciCfgOfs8,
UINTN Bus, UINTN Dev, UINTN Fun,
UINT8 *DiskFrom,
BOOLEAN NewInt18,
BOOLEAN NewInt19)
{
UINT16 BbsDevType, bbsDevType;
PCI_PNP_EXPANSION_HEADER *PnpHdr;
UINT16 PnpSeg = (UINT16)((UINTN)Rom >> 4);
UINT16 PnpOfs;
BBS_TABLE *BbsTable = BiosInfo->BbsTable;
UINT8 BbsCount;
UINT32 *volatile ivt = (UINT32*)0;
UINT8 i, Checksum;
if (gDoNotUpdateBbsTable) return;
gBbsUpdateInProgress = TRUE;
BbsCount = BiosInfo->BbsEntriesNo;
//
// Get BBS device type
//
DEBUG((DEBUG_INFO, "FetchBbsBootDevices: B%x/D%x/F%x, ClassCode %x\n", Bus, Dev, Fun, *(PciCfgOfs8+0xB)));
if (Bus|Dev|Fun) {
switch (*(PciCfgOfs8+0xB)) { // class code
case PCI_CL_SYSTEM_PERIPHERALS:
if(*(PciCfgOfs8+0xA) == PCI_CL_SYSTEM_PERIPHERALS_SCL_SD) {
BbsDevType = BBS_HARDDISK;
} else {
BbsDevType = BBS_UNKNOWN;
}
break;
case PCI_CL_MASS_STOR:
case PCI_CL_I2O: BbsDevType = BBS_HARDDISK; break;
case PCI_CL_NETWORK: BbsDevType = BBS_EMBED_NETWORK; break;
case PCI_CL_BRIDGE: BbsDevType = BBS_EMBED_NETWORK; //for nVIDIA MCP55 LAN device is bridge mode
break;
case PCI_CL_SER_BUS: BbsDevType = BBS_BEV_DEVICE; break;
default: BbsDevType = BBS_UNKNOWN;
}
} else {
BbsDevType = BBS_EMBED_NETWORK; // Service ROMs
}
//
// Get PnP information from ROM header and fill BBS structures
//
PnpOfs = *((UINT16*)(Rom + 0x1A));// Offset of the 1st PnP header
for (;;PnpOfs = (UINT16)PnpHdr->NextHeaderOffset) {
if (gDoNotUpdateBbsTable) break;
PnpHdr = (PCI_PNP_EXPANSION_HEADER*) (Rom + PnpOfs);
if (*((UINT32*)PnpHdr) != 0x506E5024) break; // "$PnP"
//
// Calculate the CheckSum and check if table is valid
//
Checksum = 0;
for (i = 0; i < sizeof(PCI_PNP_EXPANSION_HEADER); i++){
Checksum += *(((UINT8*)PnpHdr) + i);
}
if (Checksum) continue;
if (PnpHdr->BCV == 0 && PnpHdr->BEV == 0 &&
!(NewInt18 || NewInt19)) continue;
//
// Change BbsType from BBS_HARDDISK to BBS_CDROM if BCV==0 and BEV!=0
//
bbsDevType = BbsDevType;
if (BbsDevType == BBS_HARDDISK && (!PnpHdr->BCV) && PnpHdr->BEV) {
bbsDevType = BBS_CDROM;
}
if (PnpHdr->BCV != 0) {
bbsDevType = BBS_HARDDISK;
}
BbsTable[BbsCount].DeviceType = bbsDevType;
BbsTable[BbsCount].Bus = (UINT32)Bus;
BbsTable[BbsCount].Device = (UINT32)Dev;
BbsTable[BbsCount].Function = (UINT32)Fun;
BbsTable[BbsCount].Class = *(PciCfgOfs8+0xB);
BbsTable[BbsCount].SubClass = *(PciCfgOfs8+0xA);
BbsTable[BbsCount].DescStringSegment = PnpSeg;
BbsTable[BbsCount].DescStringOffset = PnpHdr->ProductNamePtr;
BbsTable[BbsCount].MfgStringSegment = PnpSeg;
BbsTable[BbsCount].MfgStringOffset = PnpHdr->MfgPtr;
BbsTable[BbsCount].BootPriority = BBS_UNPRIORITIZED_ENTRY;
BbsTable[BbsCount].BootHandlerSegment = PnpSeg;
ACCESS_PAGE0_CODE(
if (NewInt18) {
BbsTable[BbsCount].AdditionalIrq18Handler = ivt[0x18];
BbsTable[BbsCount].BootHandlerOffset = (UINT16)ivt[0x18];
}
if (NewInt19) {
BbsTable[BbsCount].AdditionalIrq19Handler = ivt[0x19];
BbsTable[BbsCount].BootHandlerOffset = (UINT16)ivt[0x19];
}
);
if (PnpHdr->BCV) {
BbsTable[BbsCount].BootHandlerOffset = PnpHdr->BCV;
ExecuteBcv(BiosInfo, PciCfgOfs8, PnpSeg, PnpHdr->BCV, DiskFrom);
}
if (PnpHdr->BEV && !(NewInt18 || NewInt19)) {
BbsTable[BbsCount].BootHandlerOffset = PnpHdr->BEV;
}
if (gSetup.I19Trap == 0 && NewInt19) {
DEBUG((DEBUG_INFO, "CSM: trapped int19 execution postponed.\n"));
// clear up the BBS table, leave only the one entry that traps INT19
// block any further BBS table updates
for (i = 0; i < BbsCount; i++) {
BbsTable[i].BootPriority = BBS_IGNORE_ENTRY;
}
gDoNotUpdateBbsTable = TRUE;
}
BbsCount++;
}
//
// Update number of BBS entries
//
BiosInfo->BbsEntriesNo = BbsCount;
gBbsUpdateInProgress = FALSE;
}
/**
Verifies whether the passed PCI ROM image is PCI 3.0 compatible.
If so, returns the projected (runtime) size of this ROM.
@retval TRUE image is PCI 3.0 compliant ROM, size is updated
@retval FALSE image is not PCI 3.0 compliant ROM, size remains untouched.
**/
BOOLEAN
Check30ROM(
IN VOID *RomLocation,
IN OUT UINTN *Size,
IN EFI_HANDLE PciHandle
)
{
PCI_DATA_STRUCTURE *pcir;
EFI_STATUS Status;
static UINT32 pci30pretender[] = {
0x00041103, // Adaptec 1200 (did 0004 vid 1103)
0x444d8086, // Intel ROBSON Technology card (444D)
0x444e8086, // Intel ROBSON Technology card (444E)
0x26818086 // Intel AHCI Option ROM
};
//
// Check for 55AA in the beginning of the image
//
if (((LEGACY_OPT_ROM_HEADER*)RomLocation)->Signature != 0xAA55) return FALSE;
//
// Validate "PCIR" data
//
pcir = (PCI_DATA_STRUCTURE *)((UINT8*)RomLocation + *(UINT16*)((UINT8*)RomLocation + 0x18));
if (pcir->Signature != 0x52494350) return FALSE; // "PCIR"
if (pcir->Revision == 3) {
UINT8 i; // check for the OpROMs that are faking PCI3.0 compatibility
UINT32 VidDid;
EFI_PCI_IO_PROTOCOL *PciIo;
if (PciHandle != NULL) {
Status = pBS->HandleProtocol(PciHandle, &gEfiPciIoProtocolGuid, (VOID**)&PciIo);
ASSERT(PciIo);
if (EFI_ERROR(Status)) return FALSE;
Status = PciIo->Pci.Read(PciIo, EfiPciIoWidthUint32,
0, // offset
1, // width
&VidDid);
ASSERT_EFI_ERROR(Status);
for (i=0; i<(sizeof(pci30pretender)/sizeof(pci30pretender[0])); i++) {
if (pci30pretender[i] == VidDid) return FALSE;
}
}
*Size = pcir->Reserved1 << 9; // Follow PCI.H definitions
return TRUE;
}
return FALSE;
}
/**
Tests to see if a traditional PCI ROM exists for this device
@param This Indicates the EFI_LEGACY_BIOS_PROTOCOL instance.
@param PciHandle The handle for this device. Type EFI_HANDLE is defined in
@param InstallProtocolInterface() in the EFI 1.10 Specification.
@param RomImage Pointer to the ROM image.
@param RomSize The size of the ROM image.
@param Flags The type of ROM discovered. Multiple bits can be set, as follows:
00 = No ROM
01 = ROM Found
02 = ROM is a valid legacy ROM
@retval EFI_SUCCESS A traditional OpROM is available for this device.
@retval EFI_UNSUPPORTED A traditional OpROM is not supported.
**/
EFI_STATUS
EFIAPI
CheckPciRom (
IN EFI_LEGACY_BIOS_PROTOCOL *This,
IN EFI_HANDLE PciHandle,
OUT VOID **RomImage, OPTIONAL
OUT UINTN *RomSize, OPTIONAL
OUT UINTN *Flags
)
{
EFI_PCI_IO_PROTOCOL *pPciIo;
UINT32 VidDid;
VOID *PciRom;
UINTN PciRomSize = 0;
EFI_STATUS Status;
BOOLEAN ValidRom = FALSE;
UINTN RomStatus = 0;
PCI_STD_DEVICE Pci;
AMI_CSM_EXECUTED_PCI_ROM *ExecutedRom = gExecutedRomsPci-1;
AMI_CSM_EXECUTED_PCI_ROM *er;
UINTN PciSegment, PciBus, PciDeviceNumber, PciFunction;
Status = pBS->HandleProtocol(PciHandle, &gEfiPciIoProtocolGuid, (VOID**)&pPciIo);
if (EFI_ERROR(Status) || (&pPciIo == NULL)) return EFI_UNSUPPORTED;
PciRom = pPciIo->RomImage;
Status = pPciIo->Pci.Read(pPciIo,
EfiPciIoWidthUint32,
0, // offset
1, // width
&VidDid);
ASSERT_EFI_ERROR(Status);
if (PciRom) {
// the following structure is defined in AmiModulePkg_33 as AMI_PCI_OPROM_VALIDATION_DATA
// the GUID used for signaling is defined in AmiModulePkg_32 as gAmiPciOpromDataProtocolGuid
// as AmiModulePkg is adopted by the majority of the projects, these definitions can be used
// instead of the local ones (below).
struct _PCI_OPROM_VALIDATION_DATA {
BOOLEAN OemPciRomOverride;
EFI_HANDLE Handle;
VOID *PciRom;
UINTN PciRomSize;
BOOLEAN RomIsValid;
} CsmPciOpromData;
static EFI_GUID gPciOpromDataProtocolGuid = {
0x30965142, 0xfc5a, 0x4e6e, { 0x94, 0xdb, 0xbb, 0xa4, 0x41, 0xb3, 0x68, 0x51 }
};
PciRomSize = (UINTN)pPciIo->RomSize;
ValidRom = IsValidLegacyPciOpROM(VidDid, &PciRom, &PciRomSize);
// See if OEM needs to override ROM data
CsmPciOpromData.OemPciRomOverride = FALSE;
CsmPciOpromData.Handle = PciHandle;
CsmPciOpromData.PciRom = PciRom;
CsmPciOpromData.PciRomSize = PciRomSize;
CsmPciOpromData.RomIsValid = ValidRom;
SignalProtocolEvent(&gPciOpromDataProtocolGuid, &CsmPciOpromData);
if (CsmPciOpromData.OemPciRomOverride)
{
PciRom = CsmPciOpromData.PciRom;
PciRomSize = CsmPciOpromData.PciRomSize;
ValidRom = CsmPciOpromData.RomIsValid;
}
RomStatus = ValidRom? 2 : 1;
}
if (!ValidRom) {
Status = GetPlatformPciEmbeddedRom(pPciIo, &PciRom, &PciRomSize);
if (EFI_ERROR(Status)) {
Status = FindEmbeddedRom(OPROM_MODULEID, (UINT16)VidDid,
*((UINT16*)&VidDid+1), &PciRom, &PciRomSize);
}
//
// Check whether the identified ROM is a legacy OptionROM,
// and correspondingly modify the value of "RomStatus".
// Note: PciRomSize is initialized here
if (!EFI_ERROR(Status)) {
ValidRom = IsValidLegacyPciOpROM(VidDid, &PciRom, &PciRomSize);
RomStatus = ValidRom? 2 : 1;
}
}
if(!ValidRom) {
Status = pPciIo->GetLocation(pPciIo,
&PciSegment, &PciBus, &PciDeviceNumber, &PciFunction);
ASSERT_EFI_ERROR(Status);
if (EFI_ERROR(Status)) return EFI_UNSUPPORTED;
//
// Sd option rom can handle all the function on one time
// So if any of one of the function on device already launched option
// no need to launch the option rom for other functions.
//
for (er = ExecutedRom; er->Seg | er->Bus | er->Dev | er->Fun; er--) {
if (er->Seg == PciSegment && er->Bus == PciBus &&
er->Dev == PciDeviceNumber) {
break;
}
}
//
//SD option can handle all the function. So don't launch option for other functions.
//
if(!(er->Seg | er->Bus | er->Dev | er->Fun)) {
Status = pPciIo->Pci.Read (pPciIo,
EfiPciIoWidthUint32,
0,
sizeof (Pci) / sizeof (UINT32),
&Pci);
ASSERT_EFI_ERROR(Status);
if (EFI_ERROR(Status)) return EFI_UNSUPPORTED;
//
// Check For SD controller. If it's SD controller find SD Option ROM and launch it.
//
if ( Pci.Header.ClassCode[1] == PCI_CL_SYSTEM_PERIPHERALS_SCL_SD && \
Pci.Header.ClassCode[2] == PCI_CL_SYSTEM_PERIPHERALS ) {
Status=FindEmbeddedRom( CSM16_MODULEID, CSM16_VENDORID, CSM16_SD_BOOT_DID, &PciRom, &PciRomSize);
if (!EFI_ERROR(Status)) {
ValidRom = IsValidLegacyPciOpROM(VidDid, &PciRom, &PciRomSize);
RomStatus = ValidRom? 2 : 1;
}
}
}
}
*Flags = RomStatus;
if (RomStatus == 2) {
if (RomImage != NULL) *RomImage = PciRom;
if (RomSize != NULL) *RomSize = PciRomSize;
return EFI_SUCCESS;
}
return EFI_UNSUPPORTED;
}
/**
Returns the first VGA controller handle from PciIo device list.
@retval PCI VGA controller PciIo handle
**/
EFI_STATUS FindAnyVga(
OUT EFI_HANDLE* hVga
)
{
EFI_HANDLE *HandleBuffer;
UINTN n, HandleCount;
EFI_STATUS Status;
UINT8 dData[4];
EFI_PCI_IO_PROTOCOL *PciIo;
EFI_STATUS VgaStatus = EFI_NOT_FOUND;
//
// Locate all PciIo handles
//
Status = pBS->LocateHandleBuffer (
ByProtocol,
&gEfiPciIoProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer);
ASSERT_EFI_ERROR(Status);
if (EFI_ERROR (Status)) {
return Status;
}
for (n = 0 ; n < HandleCount; n++) {
Status = pBS->HandleProtocol (
HandleBuffer[n],
&gEfiPciIoProtocolGuid,
(VOID**)&PciIo); // Get PciIo protocol
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR(Status)) break;
Status = PciIo->Pci.Read(
PciIo,
EfiPciIoWidthUint32,
8, // offset
1, // width
dData);
ASSERT_EFI_ERROR(Status);
if (EFI_ERROR(Status)) break;
if (dData[3]==PCI_CL_DISPLAY) {
*hVga = HandleBuffer[n];
VgaStatus = EFI_SUCCESS;
break;
}
}
pBS->FreePool(HandleBuffer);
return VgaStatus;
}
/**
Reports whether OpROM for a given PciIo already executed.
**/
AMI_CSM_EXECUTED_PCI_ROM*
PciRomAlreadyExecuted(
IN EFI_PCI_IO_PROTOCOL *PciIo
)
{
UINTN Seg, Bus, Dev, Fun;
AMI_CSM_EXECUTED_PCI_ROM *ExecutedRom;
EFI_STATUS Status;
Status = PciIo->GetLocation(PciIo, &Seg, &Bus, &Dev, &Fun);
ASSERT_EFI_ERROR(Status);
for (ExecutedRom = gExecutedRomsPci-1;
ExecutedRom->Seg | ExecutedRom->Bus | ExecutedRom->Dev | ExecutedRom->Fun;
ExecutedRom--)
{
if (ExecutedRom->Seg == Seg && ExecutedRom->Bus == Bus &&
ExecutedRom->Dev == Dev && ExecutedRom->Fun == Fun) {
return ExecutedRom;
}
}
return NULL;
}
/**
This function manages the ability of the Option ROM to control several PCI
devices in the system.
For example, SCSI Option ROM designed for the multi-channel SCSI adaptor
usually controls all the channels even though they are different PCI
functions of the same device. Likewise, NIC Option ROM may be able to control
several NICs located on different PCI devices or even on different PCI buses.
@param PciIo - PCI I/O protocol of the PCI device whose Option ROM is about
to be executed
@param PciCfgData - byte array of device's PCI configuration space (registers 0..3f)
@retval EFI_SUCCESS Option ROM is okay execute
@retval EFI_ALREADY_STARTED Option ROM must be skipped
@note
Function code flow:
1) Execute OEM porting hook to see if OEM overrides the default device enable
policy. If so, return EFI_ALREADY_STARTED.
2) Enable all function of the given PciIo.
3) Enable all PCI devices with the same VID/DID as in given PciIo.
4) Return EFI_SUCCESS indicating "greenlight" for Option ROM execution.
**/
EFI_STATUS
CheckEnablePciSiblings(
EFI_PCI_IO_PROTOCOL *PciIo,
UINT8 *PciCfgData
)
{
EFI_STATUS Status;
AMI_CSM_EXECUTED_PCI_ROM *ExecutedRom = gExecutedRomsPci-1;
EFI_HANDLE *HandleBuffer;
UINTN Count;
UINTN HandleCount;
UINTN PciSegment, PciBus, PciDeviceNumber, PciFunction;
UINTN Seg, Bus, Dev, Func;
EFI_PCI_IO_PROTOCOL *CurrentPciIo;
UINT64 Capabilities;
UINT32 VidDid;
UINT8 PciCfgData1[40];
Status = pBS->LocateHandleBuffer (ByProtocol, &gEfiPciIoProtocolGuid,
NULL, &HandleCount, &HandleBuffer);
ASSERT_EFI_ERROR(Status);
Status = CheckOemPciSiblings(PciIo, ExecutedRom);
if (Status == EFI_SUCCESS) return EFI_ALREADY_STARTED;
Status = EnableOemPciSiblings(PciIo);
if (Status == EFI_SUCCESS) return EFI_SUCCESS;
Status = PciIo->GetLocation(PciIo, &Seg, &Bus, &Dev, &Func);
ASSERT_EFI_ERROR(Status);
for (Count = 0; Count < HandleCount; Count++) {
Status = pBS->HandleProtocol (HandleBuffer[Count], &gEfiPciIoProtocolGuid, (VOID**)&CurrentPciIo);
ASSERT_EFI_ERROR(Status);
Status = CurrentPciIo->GetLocation(CurrentPciIo,
&PciSegment, &PciBus, &PciDeviceNumber, &PciFunction);
ASSERT_EFI_ERROR(Status);
// Check if it is the same device
if (PciBus == Bus && PciDeviceNumber == Dev && PciFunction == Func) continue;
Status = CurrentPciIo->Pci.Read(CurrentPciIo, EfiPciIoWidthUint32, 0, 1, &VidDid);
ASSERT_EFI_ERROR(Status);
// Do not do anything else for VGA; if multiple VGA is enabled at the same time,
// OS might have a problem. EIP60317.
Status = CurrentPciIo->Pci.Read(CurrentPciIo, EfiPciIoWidthUint8, 0, 40, PciCfgData1);
ASSERT_EFI_ERROR(Status);
if (PciCfgData1[0xb] == PCI_CL_DISPLAY) continue;
// Check if it is a different function of the same device or if VID/DID is the same
if ((PciBus == Bus && PciDeviceNumber == Dev)
|| (*(UINT32*)PciCfgData == VidDid)) {
Status = CurrentPciIo->Attributes (CurrentPciIo,
EfiPciIoAttributeOperationSupported, 0,
&Capabilities); // Get device capabilities
ASSERT_EFI_ERROR(Status);
Status = CurrentPciIo->Attributes (CurrentPciIo,
EfiPciIoAttributeOperationEnable,
Capabilities & EFI_PCI_DEVICE_ENABLE,
NULL); // Enable device
ASSERT_EFI_ERROR(Status);
DEBUG((DEBUG_INFO,
"CSM OPROM: device B%x/d%x/F%x was enabled for B%x/d%x/F%x OPROM execution.\n",
PciBus, PciDeviceNumber, PciFunction, Bus, Dev, Func));
}
}
return EFI_SUCCESS;
}
/**
This is CLP execution protocol function that is called by any driver that
needs to perform device configuration using Command Line Protocol.
@param PciIo Command Line Protocol instance pointer
@param CmdInputLine Pointer to a null-terminated input string
@param CmdResponseBuffer Pointer to command output buffer
@param CmdStatus CLP command execution status
@retval EFI_SUCCESS Execution succeeded, result is in CmdStatus
@retval Any other value Error status of the execution
**/
EFI_STATUS
EFIAPI
ClpExecute (
IN EFI_CLP_PROTOCOL *This,
IN OUT UINT8 *CmdInputLine,
IN OUT UINT8 *CmdResponseBuffer,
OUT UINT32 *CmdStatus
)
{
EFI_STATUS Status;
BOOLEAN FarCallStatus;
EFI_IA32_REGISTER_SET RegSet;
static EFI_LEGACY_BIOS_PROTOCOL *LegacyBios = NULL;
EFI_PCI_IO_PROTOCOL *PciIo;
UINTN Seg, Bus, Dev, Fun;
// Get LegacyBios protocol for FarCall86 execution
if (LegacyBios == NULL) {
Status = pBS->LocateProtocol(&gEfiLegacyBiosProtocolGuid, NULL, (VOID**)&LegacyBios);
ASSERT_EFI_ERROR(Status);
if (EFI_ERROR(Status)) {
return Status;
}
}
// Get PciIo protocol for the PCI bus/dev/func information
Status = pBS->HandleProtocol(This->Handle, &gEfiPciIoProtocolGuid, (VOID**)&PciIo);
ASSERT_EFI_ERROR(Status);
if (EFI_ERROR(Status)) {
return Status;
}
PciIo->GetLocation(PciIo, &Seg, &Bus, &Dev, &Fun);
// Prepare the registers for CLP execution
pBS->SetMem(&RegSet, sizeof (EFI_IA32_REGISTER_SET), 0);
RegSet.H.AH = (UINT8)Bus;
RegSet.H.AL = ((UINT8)Dev << 3) | (UINT8)Fun;
RegSet.E.EDI = (UINT32)(UINTN)CmdInputLine;
RegSet.E.ESI = (UINT32)(UINTN)CmdResponseBuffer;
// Execute CLP command
FarCallStatus = FarCall86 (LegacyBios,
This->EntrySeg,
This->EntryOfs,
&RegSet,
NULL,
0);
if (FarCallStatus == FALSE) {
Status = EFI_SUCCESS;
*CmdStatus = RegSet.E.EAX;
} else {
Status = EFI_DEVICE_ERROR;
}
return Status;
}
/**
This function is initializing and installing the CLP protocol.
@param Handle PCI device handle
@param Csm16DOT Option ROM related data structure
@retval EFI_SUCCESS CLP protocol successfully installed
@retval EFI_UNSUPPORTED CLP protocol can not be installed on this device
**/
EFI_STATUS
InitClp (
IN EFI_HANDLE Handle,
IN EFI_DISPATCH_OPROM_TABLE *Csm16DOT
)
{
UINT8 *RomLocation;
PCI_PCIR30_DATA_STRUCTURE *Pcir;
EFI_CLP_PROTOCOL *ClpProtocol;
EFI_STATUS Status;
static EFI_GUID guidClp = EFI_CLP_PROTOCOL_GUID;
RomLocation = (UINT8*)(UINTN)((UINT32)Csm16DOT->OpromSegment << 4);
Pcir = (PCI_PCIR30_DATA_STRUCTURE *)(RomLocation + *(UINT16*)(RomLocation + 0x18));
if (Pcir->Signature != 0x52494350) {
DEBUG((DEBUG_INFO, "Init CLP: PCIR signature is missing."));
return EFI_UNSUPPORTED;
}
if (Pcir->Revision < 3) {
DEBUG((DEBUG_INFO, "Init CLP: CLP support requires PCI version 3.0 or above."));
return EFI_UNSUPPORTED;
}
if (Pcir->ClpEntryPoint == 0) {
DEBUG((DEBUG_INFO, "Init CLP: CLP entry point is not present."));
return EFI_UNSUPPORTED;
}
if (Handle == NULL) {
DEBUG((DEBUG_INFO, "Init CLP: CLP ROM must be associated with PCI device."));
return EFI_UNSUPPORTED;
}
Status = pBS->AllocatePool(EfiBootServicesData, sizeof(EFI_CLP_PROTOCOL), (VOID**)&ClpProtocol);
ASSERT_EFI_ERROR(Status);
ClpProtocol->Handle = Handle;
ClpProtocol->EntrySeg = Csm16DOT->OpromSegment;
ClpProtocol->EntryOfs = Pcir->ClpEntryPoint;
ClpProtocol->Execute = ClpExecute;
return pBS->InstallProtocolInterface(
&Handle, &guidClp, EFI_NATIVE_INTERFACE, ClpProtocol);
}
/**
Executes a given ROM using parameters pre-defined as input in
EFI_DISPATCH_OPROM_TABLE data structure.
@param CoreBiosInfo The pointer to the BIOS_INFO variable
@param PciIo PCI IO handle, NULL for non-PCI ROMs
@param Csm16DOT ROM execution input parameters
@param NextRomAddress The location in the shadow that will have the run-time image
of the ROM
@param IsVga Video ROM indicator
@retval NewRomSize Run-time size of the ROM, in Bytes
@retval ProcessBootDevices Indicator of the new bootable devices found during
ROM execution
**/
EFI_STATUS
CsmInstallRom (
IN BIOS_INFO *CoreBiosInfo,
IN EFI_HANDLE Handle,
IN EFI_DISPATCH_OPROM_TABLE *Csm16DOT,
IN UINTN NextRomAddress,
IN BOOLEAN IsVga,
OUT UINT32 *NewRomSize,
OUT BOOLEAN *ProcessBootDevices
)
{
UINT16 ebdaSeg1, ebdaSeg2; // ebda pointer before and after OpROM execution
UINT16 baseMem1, baseMem2; // 40:13 before and after OpROM execution
UINT32 ebdaSize1, ebdaSize2; // ebda size before and after OpROM execution
BOOLEAN IsEbda;
UINT8 ebdaSizeKB;
EFI_IA32_REGISTER_SET RegSet;
UINT16 RegBX;
UINT8 *RtData = NULL;
UINT32 RtDataSize;
UINT32 RtRomSize;
EFI_STATUS Status;
UINT32 CurrentInt10 = 0;
UINT32 EbdaOffset;
EFI_PCI_IO_PROTOCOL *PciIo = NULL;
UINT64 Capabilities;
UINTN SetTxtMode;
if (!IsVga)
{
LockConsole();
// Call LegacyBiosPlatform to get the VGA switching policy override
// by default gSetTxtMode will be set to CSM_DEFAULT_VMODE_SWITCHING
//
if (Handle != NULL)
{
Status = pBS->HandleProtocol (
Handle,
&gEfiPciIoProtocolGuid,
(VOID**)&PciIo);
ASSERT_EFI_ERROR (Status);
}
Status = GetOpromVideoSwitchingMode(PciIo, CSM_DEFAULT_VMODE_SWITCHING, &SetTxtMode);
if (EFI_ERROR(Status))
{
SetTxtMode = CSM_DEFAULT_VMODE_SWITCHING;
}
else
{
ASSERT((SetTxtMode == 0) || (SetTxtMode == 1) || (SetTxtMode == 2));
}
gSetTxtMode = (UINT8)SetTxtMode;
if (!BeenHere || (gSetTxtMode == 0))
{
DisconnectSerialIO();
}
if (!BeenHere && (gSetTxtMode == 1))
{
// Keep gVgaHandle connected, quietly change the video mode
//
RegSet.X.AX = 3;
Int86 (&CoreBiosInfo->iBios, 0x10, &RegSet);
}
BeenHere = TRUE;
if (gSetTxtMode == 0)
{
// Disconnect controller and enable legacy VGA MEM/IO
//
Status = pBS->DisconnectController(gVgaHandle, NULL, NULL);
ASSERT_EFI_ERROR(Status);
Status = pBS->HandleProtocol (
gVgaHandle,
&gEfiPciIoProtocolGuid,
(VOID**)&PciIo);
ASSERT_EFI_ERROR(Status);
Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationSupported, 0,
&Capabilities);
ASSERT_EFI_ERROR(Status);
// Enable VGA legacy MEM/IO access
//
PciIo->Attributes (PciIo, EfiPciIoAttributeOperationEnable,
(Capabilities & EFI_PCI_DEVICE_ENABLE)
| EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO,
NULL);
}
// Set a dummy INT10 handler if gSetTxtMode is set to 2
//
if (gSetTxtMode == 2)
{
CurrentInt10 = *(UINT32*)(UINTN)0x40;
*(UINT32*)(UINTN)0x40 = 0xf000f065; // legacy int10
}
}
// Initialize CLP (Command Line Protocol) support for this ROM
//
InitClp(Handle, Csm16DOT);
// Save the current EBDA location to check if OpROM modifies it
//
ebdaSeg1 = *(UINT16*)(UINTN)0x40e;
ebdaSizeKB = *(UINT8*)((UINTN)ebdaSeg1<<4);
ebdaSize1 = (UINTN)ebdaSizeKB << 10;
ASSERT(ebdaSizeKB); // should be initialized, can not be 0
baseMem1 = *(UINT16*)(UINTN)0x413;
// Execute OpROM
//
pBS->SetMem(&RegSet, sizeof (EFI_IA32_REGISTER_SET), 0);
RegSet.X.AX = Legacy16DispatchOprom;
RegSet.X.ES = EFI_SEGMENT (Csm16DOT);
RegSet.X.BX = EFI_OFFSET (Csm16DOT);
FarCall86 (&CoreBiosInfo->iBios,
CoreBiosInfo->Csm16EntrySeg,
CoreBiosInfo->Csm16EntryOfs,
&RegSet,
NULL,
0);
RegBX = RegSet.X.BX;
// Get the run-time Option ROM size right away; note that the value of
// OpROMSeg:0002 can change later, for example after BCV execution (noticed
// on NetCell PCI SATA RAID card).
RtRomSize = ((LEGACY_OPT_ROM_HEADER*)NextRomAddress)->Size512 * 0x200;
DEBUG((DEBUG_INFO, "InstallRom...Run-time ROM Size = %x Bytes\n", RtRomSize));
// Update EBDA map
ebdaSeg2 = *(UINT16*)(UINTN)0x40e;
ebdaSize2 = *(UINT8*)((UINTN)ebdaSeg2<<4) << 10;
RtDataSize = 0;
if (ebdaSeg1 > ebdaSeg2) {
RtDataSize = ebdaSize2 - ebdaSize1; // #of bytes taken by this OpROM
UpdateEbdaMap((UINT32)(ebdaSeg1 - ebdaSeg2) << 4);
}
// Check for a ROM size not being FF
if (RtRomSize == 0x1fe00) RtRomSize = 0;
// Prepare the output parameters
*ProcessBootDevices = (RegBX == 0 && RtRomSize != 0);
*NewRomSize = RtRomSize;
if (IsVga) return EFI_SUCCESS; // Done for VBIOS
if (gSetTxtMode != 1) {
UnlockConsole();
}
// Restore video mode if needed
// gSetTxtMode:
// 0: reconnect VGA controller
// 1: do nothing
// 2: restore fake INT10 vector
// Note that at first pass gSetTxtMode is either 0 or 2; in case of 0 it is
// reassigned using CSM_DEFAULT_VMODE_SWITCHING and OEM override.
if (gSetTxtMode == 2) {
*(UINT32*)(UINTN)0x40 = CurrentInt10;
}
if (gSetTxtMode == 0) {
pBS->DisconnectController(gVgaHandle, NULL, NULL);
pBS->ConnectController(gVgaHandle, NULL, NULL, TRUE);
}
if (gSetTxtMode != 1) {
ConnectSerialIO();
}
// Update BBS device count
if (CoreBiosInfo->BbsEntriesNo != Csm16DOT->NumberBbsEntries) {
// CSM16 had inserted some BBS entries for non-BBS devices
CoreBiosInfo->BbsEntriesNo = Csm16DOT->NumberBbsEntries;
}
// Process boot devices
if (RegBX == 0 && RtRomSize != 0) { // Either BBS OpROM or no bootable devices connected
// Save the BBS compliant OpROM memory context here. Note that saving Oprom
// data is only required for the option ROMs that produce BCV because of early
// BCV execution; it should not be called for non-BBS compliant OpROMs, for
// those OpROMs memory context will be the same til the system is booted.
if (RtDataSize) {
// EBDA was allocated, calculate the address
IsEbda = TRUE;
RtData = (UINT8*)(((UINTN)ebdaSeg2<<4) + ((UINTN)ebdaSizeKB<<10));
} else {
// EBDA was not allocated; verify data is not requested
// by a blind update of 40:13. This memory allocation method
// was observed on OpROM by Adaptec 39160, FW ver V2.55.0.
IsEbda = FALSE;
baseMem2 = *(UINT16*)(UINTN)0x413;
RtDataSize = (UINT32)(baseMem1-baseMem2)<<10;
if (RtDataSize) {
RtData = (UINT8*)((UINTN)baseMem2<<10);
}
}
EbdaOffset = IsEbda? (UINT32)ebdaSizeKB<<10 : 0;
SaveOprom ((UINT8*)NextRomAddress, RtData, RtDataSize, IsEbda, EbdaOffset);
}
return EFI_SUCCESS;
}
/**
Shadows an OpROM
@param This Indicates the EFI_LEGACY_BIOS_PROTOCOL instance.
@param PciHandle The PCI PC-AT* OpROM from this device's ROM BAR will be loaded
@param RomImage A PCI PC-AT ROM image. This argument is non-NULL if there is
no hardware associated with the ROM and thus no PciHandle;
otherwise it must be NULL. An example is the PXE base code.
@param Flags The type of ROM discovered. Multiple bits can be set, as follows:
00 = No ROM.
01 = ROM found.
02 = ROM is a valid legacy ROM.
@param DiskStart Disk number of the first device hooked by the ROM. If DiskStart is
the same as DiskEnd, no disks were hooked.
@param DiskEnd Disk number of the last device hooked by the ROM.
@param RomShadowAddress Shadow address of PC-AT ROM.
@param ShadowedRomSize Size in bytes of RomShadowAddress.
@retval EFI_SUCCESS The OpROM was shadowed
@retval EFI_UNSUPPORTED The PciHandle was not found
**/
EFI_STATUS
EFIAPI
InstallPciRom (
IN EFI_LEGACY_BIOS_PROTOCOL *This,
IN EFI_HANDLE PciHandle,
IN VOID **RomImage,
OUT UINTN *Flags,
OUT UINT8 *DiskStart, OPTIONAL
OUT UINT8 *DiskEnd, OPTIONAL
OUT VOID **RomShadowAddress, OPTIONAL
OUT UINT32 *ShadowedRomSize OPTIONAL
)
{
EFI_STATUS Status, Status1 = EFI_SUCCESS;
VOID* RomLocation;
EFI_PHYSICAL_ADDRESS Rom30Address = 0;
UINTN RomSize, Rom30Size = 0;
EFI_DISPATCH_OPROM_TABLE *Csm16DOT;
UINTN PciSegment, PciBus, PciDeviceNumber, PciFunction;
BIOS_INFO *CoreBiosInfo = (BIOS_INFO*)This;
UINT32 NewRomSize = 0;
BOOLEAN IsVga = FALSE;
UINT8 DiskFrom = 0x80;
UINT8 DiskTo = 0x80;
UINT8 PciCfgData[0x40];
EFI_HANDLE *VgaHandlePtr = &gVgaHandle;
UINTN VgaHandleCount;
EFI_PCI_IO_PROTOCOL *PciIo = NULL;
UINT64 Capabilities;
BOOLEAN is30ROM = FALSE;
UINT32 LockUnlockAddr, LockUnlockSize;
// CSM_PLATFORM_PROTOCOL *CsmPlatformProtocol;
UINTN LowMem4KPages = 0;
AMI_CSM_EXECUTED_PCI_ROM *ExecutedRom = NULL;
BOOLEAN ProcessBootDevices;
UINT32 *volatile ivt = (UINT32*)0;
UINT32 Int18;
UINT32 Int19;
static BOOLEAN Int19Trapped = FALSE;
UINT32 NumberAlreadyExecutedPciRoms;
static BOOLEAN RecursiveVgaInstall = FALSE;
//
// Handle separately HW independent OpROMs, e.g. PXE
//
if (PciHandle == NULL) {
IsVga = FALSE;
PciSegment = 0; PciBus = 0; PciDeviceNumber = 0; PciFunction = 0;
}
else {
Status = pBS->HandleProtocol (
PciHandle,
&gEfiPciIoProtocolGuid,
(VOID**)&PciIo); // Get PciIo protocol
ASSERT_EFI_ERROR (Status);
//
// NOTE: The following call will check whether the LegacyOpROM
// has already been executed for PciIo. If so, it returns EFI_SUCCESS.
//
ExecutedRom = PciRomAlreadyExecuted(PciIo);
if (ExecutedRom != NULL) {
*Flags = ExecutedRom->Flags;
if (DiskStart) *DiskStart = ExecutedRom->DiskFrom;
if (DiskEnd) *DiskEnd = ExecutedRom->DiskTo;
if (RomShadowAddress) *RomShadowAddress = ExecutedRom->RomAddress;
if (ShadowedRomSize) *ShadowedRomSize = ExecutedRom->RomSize;
return EFI_SUCCESS;
}
// Verify the number of already executed PCI ROMs does not exceed MAX_EXECUTED_OPROMS
NumberAlreadyExecutedPciRoms = 0;
for (
ExecutedRom = gExecutedRomsPci-1;
ExecutedRom->Seg | ExecutedRom->Bus | ExecutedRom->Dev | ExecutedRom->Fun;
NumberAlreadyExecutedPciRoms++, ExecutedRom--
){}
if (NumberAlreadyExecutedPciRoms >= MAX_EXECUTED_OPROMS)
{
return EFI_OUT_OF_RESOURCES;
}
Status = PciIo->Pci.Read(
PciIo,
EfiPciIoWidthUint8,
0, // offset
0x40, // width
PciCfgData);
ASSERT_EFI_ERROR(Status);
if (PciCfgData[0xB]==PCI_CL_OLD && PciCfgData[0xA]==PCI_CL_OLD_SCL_VGA) {
IsVga = TRUE;
}
if (PciCfgData[0xB]==PCI_CL_DISPLAY && PciCfgData[0xA]==PCI_CL_DISPLAY_SCL_VGA) {
IsVga = TRUE;
}
Status = CheckEnablePciSiblings(PciIo, PciCfgData);
if (EFI_ERROR(Status)) return Status;
Status = PciIo->GetLocation(PciIo,
&PciSegment, &PciBus, &PciDeviceNumber, &PciFunction);
ASSERT_EFI_ERROR(Status);
}
if (Int19Trapped && !IsVga) {
return EFI_UNSUPPORTED;
}
// Notify others about ROM execution, see if any driver objects
Status = PreProcessOpRom(PciHandle, RomImage);
if (EFI_ERROR(Status)) {
PostProcessOpRom();
return Status;
}
if (IsVga) {
if (CoreBiosInfo->hVga != NULL) {
//
// More than one legacy video is not supported
// We return EFI_SUCCESS so that Video Thunk driver start function
// does not fail.
//
PostProcessOpRom();
return EFI_SUCCESS;
}
Status = CoreBiosInfo->iBiosPlatform->GetPlatformHandle(
CoreBiosInfo->iBiosPlatform,
EfiGetPlatformVgaHandle,
0,
&VgaHandlePtr,
&VgaHandleCount,
NULL);
if (!EFI_ERROR(Status)) { // Platform returned VGA handle
if (PciHandle != *VgaHandlePtr) { // Not the one requested by platform
PostProcessOpRom();
return EFI_UNSUPPORTED;
}
}
}
else { // Not VGA
if (CoreBiosInfo->hVga == NULL) {
EFI_PCI_IO_PROTOCOL *VgaPciIo = NULL;
//
// The control is passed to this routine to install non-VGA OpROM and VGA BIOS is
// not yet installed. This could happen in the following scenarios:
// 1) Video is controlled by Efi native video driver
// 2) BDS is connecting mass storage before consoles
// 3) The system is headless (no video controller)
//
// We will try to find video and launch its oprom; for case #1 we will disconnect
// the native driver and reconnect it after OpROM is executed.
//
// There will be a single attempt to find and execute VGA Option ROM through recursive InstallPciRom
// execution; a "RecursiveVgaAttempted" guard will prevent any deeper recursive calls.
//
if (!RecursiveVgaInstall) {
Status = CoreBiosInfo->iBiosPlatform->GetPlatformHandle(
CoreBiosInfo->iBiosPlatform,
EfiGetPlatformVgaHandle,
0,
&VgaHandlePtr,
&VgaHandleCount,
NULL);
if (EFI_ERROR(Status)) { // Platform did not return VGA handle, try to find one
Status1 = FindAnyVga(VgaHandlePtr);
}
if (!EFI_ERROR(Status) || !EFI_ERROR(Status1)) { // Found VGA - enable it and launch OpROM
Status = pBS->HandleProtocol (
*VgaHandlePtr,
&gEfiPciIoProtocolGuid,
(VOID**)&VgaPciIo); // Get PciIo protocol
ASSERT_EFI_ERROR(Status);
Status = VgaPciIo->Attributes (VgaPciIo,
EfiPciIoAttributeOperationSupported, 0,
&Capabilities); // Get device capabilities
ASSERT_EFI_ERROR(Status);
Status = VgaPciIo->Attributes (VgaPciIo,
EfiPciIoAttributeOperationEnable,
Capabilities & EFI_PCI_DEVICE_ENABLE,
NULL); // Enable device
ASSERT_EFI_ERROR(Status);
RecursiveVgaInstall = TRUE;
InstallPciRom(This, // Recursive call
*VgaHandlePtr, NULL, Flags,
NULL, NULL, NULL, NULL);
}
}
}
}
VgaHandlePtr = &gVgaHandle;
if (IsVga) {
ASSERT(PciIo != NULL);
Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationGet, 0,
&Capabilities); // Get device capabilities
ASSERT_EFI_ERROR(Status);
Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationEnable,
Capabilities | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO,
NULL); // Enable VGA legacy MEM/IO access
ASSERT_EFI_ERROR(Status);
CoreBiosInfo->hVga = PciHandle;
*VgaHandlePtr = PciHandle;
}
//
// Get the ROM image location
//
if (PciHandle != NULL) {
Status = CheckPciRom (This, PciHandle, &RomLocation, &RomSize, Flags);
if (EFI_ERROR(Status) || (RomLocation == NULL)) {
PostProcessOpRom();
return EFI_UNSUPPORTED;
}
is30ROM = Check30ROM(RomLocation, &Rom30Size, PciHandle);
}
else { // ROM is not associated with PCI device
RomLocation = *RomImage;
RomSize = ((LEGACY_OPT_ROM_HEADER*)RomLocation)->Size512 * 0x200;
if (RomSize == 0) {
PostProcessOpRom();
return EFI_UNSUPPORTED;
}
is30ROM = Check30ROM(RomLocation, &Rom30Size, NULL);
}
//
// For PCI3.0 compliant ROMs reserve base memory for ROM Init code
//
if (is30ROM) {
Rom30Address = 0xA0000;
LowMem4KPages = RomSize >> 12; // Number of 4KB units
if (RomSize % 0x1000) {
LowMem4KPages++;
}
Status = pBS->AllocatePages(AllocateMaxAddress,
EfiBootServicesData,
LowMem4KPages,
&Rom30Address);
ASSERT_EFI_ERROR(Status);
if (EFI_ERROR(Status)) {
PostProcessOpRom();
DEVICE_ERROR_CODE(DXE_LEGACY_OPROM_NO_SPACE, EFI_ERROR_MAJOR, PciHandle);
return EFI_OUT_OF_RESOURCES;
}
if (Rom30Address < 0x8000) {
PostProcessOpRom();
Status = EFI_OUT_OF_RESOURCES;
DEBUG((DEBUG_ERROR, "Can not execute PCI 3.0 OPROM: out of Base Memory.\n"));
DEVICE_ERROR_CODE(DXE_LEGACY_OPROM_NO_SPACE, EFI_ERROR_MAJOR, PciHandle);
goto ReturnErrorStatus;
}
}
PROGRESS_CODE(DXE_LEGACY_OPROM_INIT);
//
// Check for the room in shadow for this ROM and copy it from RomLocation.
//
{
UINTN SizeInShadow = is30ROM? Rom30Size : RomSize;
UINTN CopyToAddress = is30ROM? (UINTN)Rom30Address : (UINTN)gNextRomAddress;
if(((UINTN)(gNextRomAddress) + SizeInShadow) > OPROM_MAX_ADDRESS){
PostProcessOpRom();
DEBUG((DEBUG_ERROR, "Can not execute PCI OPROM: out of resources. RomAddr %x RomSize %x\n", gNextRomAddress, SizeInShadow));
Status = EFI_OUT_OF_RESOURCES;
DEVICE_ERROR_CODE(DXE_LEGACY_OPROM_NO_SPACE, EFI_ERROR_MAJOR, PciHandle);
goto ReturnErrorStatus;
}
Status = UnlockShadow(gNextRomAddress, SizeInShadow, &LockUnlockAddr, &LockUnlockSize);
ASSERT_EFI_ERROR(Status);
//
// Initilize the size field to 0.
//
((LEGACY_OPT_ROM_HEADER*)gNextRomAddress)->Size512=0;
pBS->CopyMem((VOID*)CopyToAddress, RomLocation, RomSize);
}
ACCESS_PAGE0_CODE(
DiskFrom = *(UINT8*)(UINTN)0x475 + 0x80;
);
Csm16DOT = &CoreBiosInfo->Thunk->DispatchOpromTable;
Csm16DOT->PnPInstallationCheckSegment = CoreBiosInfo->Csm16Header->PnPInstallationCheckSegment;
Csm16DOT->PnPInstallationCheckOffset = CoreBiosInfo->Csm16Header->PnPInstallationCheckOffset;
if (is30ROM) {
Csm16DOT->OpromSegment = (UINT16)(Shr64(Rom30Address, 4));
Csm16DOT->RuntimeSegment = (UINT16)((UINTN)gNextRomAddress >> 4);
}
else {
Csm16DOT->OpromSegment = (UINT16)((UINTN)gNextRomAddress >> 4);
Csm16DOT->RuntimeSegment = 0;
}
Csm16DOT->PciBus = (UINT8)PciBus;
Csm16DOT->PciDeviceFunction = (UINT8)(PciDeviceNumber << 3 | PciFunction);
Csm16DOT->NumberBbsEntries = CoreBiosInfo->BbsEntriesNo;
Csm16DOT->BbsTablePointer = (UINT32)(UINTN)(CoreBiosInfo->BbsTable);
DEBUG((DEBUG_INFO, "OptionROM for B%x/D%x/F%x is executed from %x:0003\n",
PciBus, PciDeviceNumber, PciFunction, Csm16DOT->OpromSegment));
// Save INT18 and INT19 to be able to see its trapping after ROM execution
ACCESS_PAGE0_CODE(
Int19 = ivt[0x19];
Int18 = ivt[0x18];
Status = CsmInstallRom(CoreBiosInfo, PciHandle,
Csm16DOT, (UINTN)gNextRomAddress, IsVga, &NewRomSize, &ProcessBootDevices);
Int19Trapped = Int19 != ivt[0x19];
if (ProcessBootDevices) {
FetchBbsBootDevices(CoreBiosInfo,
gNextRomAddress,
PciCfgData,
PciBus,
PciDeviceNumber,
PciFunction,
&DiskFrom,
Int18 != ivt[0x18],
Int19 != ivt[0x19]);
}
// Restore INT18 and INT19
ivt[0x18] = Int18;
ivt[0x19] = Int19;
DiskTo = (DiskFrom & 0xc0) + *(UINT8*)(UINTN)0x475;
);
PostProcessOpRom();
if (is30ROM) {
//
// For PCI3.0 do necessary things with Setup Routine here, then
// free Rom30Address memory
//
pBS->FreePages(Rom30Address, LowMem4KPages);
}
if (!is30ROM) {
if (RomSize > NewRomSize) {
pBS->SetMem(gNextRomAddress+NewRomSize, RomSize-NewRomSize, 0xFF);
}
}
Status = LockShadow(LockUnlockAddr, LockUnlockSize);
ASSERT_EFI_ERROR(Status);
//
// Make the rom size 2K aligned
//
if (NewRomSize % 0x800) {
NewRomSize += (0x800 - (NewRomSize % 0x800));
}
//
// Return OPTIONAL parameters: updated disks, oprom address and size.
//
if (DiskStart) *DiskStart = DiskFrom;
if (DiskEnd) *DiskEnd = DiskTo;
if (RomShadowAddress) *RomShadowAddress = gNextRomAddress;
if (ShadowedRomSize) *ShadowedRomSize = NewRomSize;
//
// Update the list of Executed Roms
//
if (PciHandle) {
gExecutedRomsPci->Seg = PciSegment;
gExecutedRomsPci->Bus = PciBus;
gExecutedRomsPci->Dev = PciDeviceNumber;
gExecutedRomsPci->Fun = PciFunction;
gExecutedRomsPci->Flags = *Flags;
gExecutedRomsPci->DiskFrom = DiskFrom;
gExecutedRomsPci->DiskTo = DiskTo;
gExecutedRomsPci->RomAddress = gNextRomAddress;
gExecutedRomsPci->RomSize = NewRomSize;
gExecutedRomsPci++;
}
DEBUG((DEBUG_INFO, "PCI OPROM(handle %x, %x/%x/%x): addr %x, size %x\n",
PciHandle, PciBus, PciDeviceNumber, PciFunction, gNextRomAddress, NewRomSize));
gNextRomAddress += NewRomSize;
if (Int19Trapped && !IsVga && (gSetup.I19Trap == 1))
{
if (gSetTxtMode == 1)
{
if (gVgaHandle != NULL)
{
DEBUG((DEBUG_INFO, "Reconnecting video and serial before calling INT19 trap.\n"));
pBS->DisconnectController(gVgaHandle, NULL, NULL);
pBS->ConnectController(gVgaHandle, NULL, NULL, TRUE);
ConnectSerialIO();
}
UnlockConsole();
}
// Signal READY_TO_BOOT event
{
EFI_EVENT ReadyToBootEvent;
Status = CreateReadyToBootEvent(
TPL_CALLBACK, NULL, NULL, &ReadyToBootEvent
);
if (!EFI_ERROR(Status)) {
pBS->SignalEvent(ReadyToBootEvent);
pBS->CloseEvent(ReadyToBootEvent);
}
}
LegacyBoot (
&CoreBiosInfo->iBios,
&(DummyLoadOption.BbsDevicePath),
sizeof(DummyLoadOption),
&DummyLoadOption
);
ASSERT(FALSE); // CONTROL MUST NOT BE GIVEN BACK HERE
// If by any chance we are here, we have to do the needful:
pRS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
}
return EFI_SUCCESS;
ReturnErrorStatus:
if (LowMem4KPages != 0) {
pBS->FreePages(Rom30Address, LowMem4KPages);
}
return Status;
}
/**
Returns the available shadow RAM address out of the given range.
@param AddrMin Min address
@param AddrMax Max address
@param Size Range size, in Bytes
@param Alignment Range alignment
@retval EFI_SUCCESS AddrMin variable contains the available address
@retval EFI_OUT_OF_RESOURCES The requested memory range is not available in
the shadow RAM
@note
This function does not reserve or allocate memory in the shadow RAM
**/
EFI_STATUS
EFIAPI
GetShadowRamAddress(
IN OUT UINT32 *AddrMin,
IN UINT32 AddrMax,
IN UINT32 Size,
IN UINT32 Alignment
)
{
UINT32 Addr = *AddrMin;
UINT32 Aln;
if (Addr > AddrMax) return EFI_INVALID_PARAMETER;
if (Size == 0x00) return EFI_INVALID_PARAMETER;
if (Alignment > OPROM_MAX_ADDRESS) return EFI_INVALID_PARAMETER;
if (AddrMax + Size > (OPROM_MAX_ADDRESS + 1)) return EFI_OUT_OF_RESOURCES;
if (AddrMax < (UINT32)(UINTN)gNextRomAddress) return EFI_OUT_OF_RESOURCES;
if(Alignment != 0) Alignment--;
Aln = ~Alignment;
if (Addr < (UINT32)(UINTN)gNextRomAddress) {
Addr = (UINT32)(UINTN)gNextRomAddress;
}
if ((Alignment !=0) && (Addr & Aln)) {
if ( (Addr & Aln) != Addr){
Addr += (Alignment+1);
Addr &= Aln;
}
}
gNextRomAddress = (UINT8 *)(UINTN)(Addr + Size);
*AddrMin = Addr;
return EFI_SUCCESS;
}
/**
Executes ISA Option ROM
@param This Indicates the EFI_LEGACY_BIOS_PROTOCOL instance.
RomAddress Location of the Option ROM
@retval EFI_SUCCESS ROM was successfully executed
@retval EFI_OUT_OF_RESOURCES Shadow RAM full, ROM was not executed
**/
EFI_STATUS
EFIAPI
InstallIsaRom(
IN EFI_LEGACY_BIOS_EXT_PROTOCOL *This,
IN UINTN RomAddress
)
{
UINTN RomSize;
BOOLEAN ProcessBootDevices;
EFI_STATUS Status;
EFI_DISPATCH_OPROM_TABLE *Csm16DOT;
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
BIOS_INFO *CoreBiosInfo;
UINT8 PciCfgData[0x40] = {0};
UINT8 DiskFrom = 0x80;
UINT32 *volatile ivt = (UINT32*)0;
UINT32 Int18;
UINT32 Int19;
UINT32 LockUnlockAddr, LockUnlockSize;
// Validate ISA ROM
if (((LEGACY_OPT_ROM_HEADER*)RomAddress)->Signature != 0xAA55) {
DEBUG((DEBUG_ERROR, "Can not execute ISA ROM: missing 0xAA55 signature.\n"));
return EFI_UNSUPPORTED;
}
// See if ROM fits in the shadow
RomSize = ((LEGACY_OPT_ROM_HEADER*)RomAddress)->Size512 << 9;
if((RomAddress + RomSize) > OPROM_MAX_ADDRESS) {
DEBUG((DEBUG_ERROR, "Can not execute ISA ROM: won't fit in the shadow memory.\n"));
return EFI_OUT_OF_RESOURCES;
}
// Get BIOS_INFO variable pointer
Status = pBS->LocateProtocol(&gEfiLegacyBiosProtocolGuid, NULL, (VOID**)&LegacyBios);
ASSERT_EFI_ERROR(Status);
CoreBiosInfo = (BIOS_INFO*)LegacyBios;
//
// Execute platform pre-OpROM function
//
Status = PreProcessOpRom(NULL, (VOID*)&RomAddress);
if (EFI_ERROR(Status)) {
PostProcessOpRom();
return Status;
}
PROGRESS_CODE(DXE_LEGACY_OPROM_INIT);
//
// Check for the room in shadow for this ROM and copy it from RomLocation.
//
{
UINTN SizeInShadow = RomSize;
UINTN CopyToAddress = RomAddress;
UINTN TempRomAddress = 0;
Status = pBS->AllocatePool(EfiBootServicesData, RomSize, (VOID**)&TempRomAddress);
if (EFI_ERROR(Status)) {
DEBUG((DEBUG_ERROR, "Can not copy ISA ROM to memory: insufficient memory space.\n"));
return EFI_OUT_OF_RESOURCES;
}
pBS->CopyMem(&TempRomAddress, &CopyToAddress, SizeInShadow);
ASSERT_EFI_ERROR(Status);
Status = UnlockShadow((UINT8*)&CopyToAddress, SizeInShadow, &LockUnlockAddr, &LockUnlockSize);
ASSERT_EFI_ERROR(Status);
pBS->CopyMem(&CopyToAddress, &TempRomAddress, SizeInShadow);
DEBUG((DEBUG_INFO, "Copy ISA ROM to shadow memory address %x.\n", CopyToAddress));
pBS->FreePages(TempRomAddress, SizeInShadow);
}
ACCESS_PAGE0_CODE(
DiskFrom = *(UINT8*)(UINTN)0x475 + 0x80;
);
Csm16DOT = &CoreBiosInfo->Thunk->DispatchOpromTable;
Csm16DOT->OpromSegment = (UINT16)(RomAddress >> 4);
Csm16DOT->NumberBbsEntries = CoreBiosInfo->BbsEntriesNo;
Csm16DOT->BbsTablePointer = (UINT32)(UINTN)(CoreBiosInfo->BbsTable);
DEBUG((DEBUG_INFO, "OptionROM for ISA Device is executed from %x:0003\n", Csm16DOT->OpromSegment));
ACCESS_PAGE0_CODE(
// Save INT18 and INT19 to be able to see its trapping after ROM execution
Int19 = ivt[0x19];
Int18 = ivt[0x18];
Status = CsmInstallRom(CoreBiosInfo, NULL,
Csm16DOT, RomAddress, FALSE, NULL, &ProcessBootDevices);
if (ProcessBootDevices) {
FetchBbsBootDevices(CoreBiosInfo,
(UINT8*)RomAddress,
PciCfgData,
0,
0,
0,
&DiskFrom,
Int18 != ivt[0x18],
Int19 != ivt[0x19]);
}
// Restore INT18 and INT19
ivt[0x18] = Int18;
ivt[0x19] = Int19;
);
PostProcessOpRom();
Status = LockShadow(LockUnlockAddr, LockUnlockSize);
ASSERT_EFI_ERROR(Status);
return Status;
}
/**
Allows external agents to force loading of all legacy OpROMs.
This function can be invoked before GetBbsInfo() to ensure all
devices are counted.
@param This Indicates the EFI_LEGACY_BIOS_PROTOCOL instance.
@retval EFI_SUCCESS OpROMs are shadowed successfully.
**/
EFI_STATUS
EFIAPI
ShadowAllLegacyOproms (
IN EFI_LEGACY_BIOS_PROTOCOL *This
)
{
EFI_HANDLE *HandleBuffer;
UINTN n, HandleCount;
EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
BIOS_INFO *CoreBiosInfo = (BIOS_INFO*)This;
UINT64 Capabilities;
UINTN Flags;
UINT8 dData[4];
//
// Locate all PciIo handles
//
Status = pBS->LocateHandleBuffer (
ByProtocol,
&gEfiPciIoProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer);
ASSERT_EFI_ERROR(Status);
if (EFI_ERROR (Status)) {
return Status;
}
for (n = 0; n < HandleCount; n++) {
Status = pBS->HandleProtocol (HandleBuffer[n], &gEfiPciIoProtocolGuid, (VOID**)&PciIo);
ASSERT_EFI_ERROR(Status);
if (PciRomAlreadyExecuted(PciIo)) continue;
//
// Skip the VGA devices: the active VGA controller might have
// been already enabled, all other VGA controllers have to be disabled.
//
if (CoreBiosInfo->hVga != NULL) {
Status = PciIo->Pci.Read(
PciIo,
EfiPciIoWidthUint32,
8, // offset
1, // width
&dData);
ASSERT_EFI_ERROR(Status);
if (dData[3]==PCI_CL_DISPLAY) continue;
}
//
// See if device has OpROM, if so - enable device and istlall OpROM; assume
// CSM has already assinged IRQ and programmed IRQ router and register 3C
//
Status = CheckPciRom(This, HandleBuffer[n], NULL, NULL, &Flags);
if (EFI_ERROR(Status) || (Flags != 2)) continue; // No OpROM or OpROM is invalid
Status = PciIo->Attributes (PciIo,
EfiPciIoAttributeOperationSupported, 0,
&Capabilities); // Get device capabilities
ASSERT_EFI_ERROR(Status);
Status = PciIo->Attributes (PciIo,
EfiPciIoAttributeOperationEnable,
Capabilities & EFI_PCI_DEVICE_ENABLE,
NULL); // Enable device
if (EFI_ERROR(Status)) continue;
InstallPciRom(This,
HandleBuffer[n], NULL, &Flags,
NULL, NULL, NULL, NULL);
}
pBS->FreePool(HandleBuffer);
if (!gServiceRomsExecuted) {
//
// Launch service ROMs
//
CoreBiosInfo->iBiosPlatform->PlatformHooks(
CoreBiosInfo->iBiosPlatform,
EfiPlatformHookShadowServiceRoms,
0, NULL, NULL, NULL, NULL);
gServiceRomsExecuted = TRUE;
}
return EFI_SUCCESS;
}
/**
This function notifies other drivers about Option ROM execution. Drivers
may reject this ROM execution.
@param
EFI_PCI_IO_PROTOCOL *PciIo - OPTIONAL - PCI device PciIo instance, NULL for
non-PCI ROMs.
@retval EFI_SUCCESS run the option rom for this device
@retval EFI_ABORTED code determined to not run Oprom for this device
**/
EFI_STATUS PreProcessOpRom (
IN EFI_HANDLE PciHandle,
IN VOID **RomImage
)
{
AMI_CSM_PLATFORM_POLICY_DATA CsmOpromPolicyData;
EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
PciIo = NULL;
Status = EFI_SUCCESS;
if (PciHandle != NULL) {
Status = pBS->HandleProtocol(PciHandle, &gEfiPciIoProtocolGuid, (VOID**)&PciIo);
ASSERT_EFI_ERROR(Status);
if (EFI_ERROR(Status)) return EFI_ABORTED;
}
// See if any callback function wishes to cancel this OpROM execution
CsmOpromPolicyData.PciIo = PciIo;
CsmOpromPolicyData.Rom = RomImage;
CsmOpromPolicyData.ExecuteThisRom = TRUE;
#if AMI_MODULE_PKG_VERSION > 32
CsmOpromPolicyData.PciHandle = PciHandle;
#endif
if (gCsmPolicy == NULL) {
Status = pBS->LocateProtocol(&gAmiCsmOpromPolicyProtocolGuid, NULL, (VOID**)&gCsmPolicy);
}
if (!EFI_ERROR(Status)) {
gCsmPolicy->ProcessOpRom(&CsmOpromPolicyData);
}
SignalProtocolEvent(&gOpromStartEndProtocolGuid, &CsmOpromPolicyData);
return ( CsmOpromPolicyData.ExecuteThisRom == FALSE) ? EFI_ABORTED : EFI_SUCCESS;
}
/**
This function signals the event of the end of Option ROM execution.
@note
This function is using the same GUID as PreprocessOprom function; for the
callback function the indication of the END of the Oprom would be NULL context.
**/
EFI_STATUS PostProcessOpRom ()
{
if (gCsmPolicy == NULL) {
pBS->LocateProtocol(&gAmiCsmOpromPolicyProtocolGuid, NULL, (VOID**)&gCsmPolicy);
}
if (gCsmPolicy != NULL) {
gCsmPolicy->ProcessOpRom(NULL);
}
// signal the OpromStartEndProtocolGuid event
SignalProtocolEvent(&gOpromStartEndProtocolGuid, NULL);
return EFI_SUCCESS;
}