summaryrefslogtreecommitdiff
path: root/Core/EM/CsmOptOut/CsmOptOut.c
diff options
context:
space:
mode:
Diffstat (limited to 'Core/EM/CsmOptOut/CsmOptOut.c')
-rw-r--r--Core/EM/CsmOptOut/CsmOptOut.c1039
1 files changed, 1039 insertions, 0 deletions
diff --git a/Core/EM/CsmOptOut/CsmOptOut.c b/Core/EM/CsmOptOut/CsmOptOut.c
new file mode 100644
index 0000000..b5056cd
--- /dev/null
+++ b/Core/EM/CsmOptOut/CsmOptOut.c
@@ -0,0 +1,1039 @@
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2011, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+
+///**********************************************************************
+// $Header: /Alaska/SOURCE/Modules/CsmOptOut/CsmOptOut.c 15 11/01/13 9:25p Artems $
+//
+// $Revision: 15 $
+//
+// $Date: 11/01/13 9:25p $
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Modules/CsmOptOut/CsmOptOut.c $
+//
+// 15 11/01/13 9:25p Artems
+// [TAG] EIP126445
+// [Category] Improvement
+// [Description] Added UEFI Only option for OpROMS of unknown types
+// [Files] CsmOptOut.c CsmOptOut.sd CsmOptOut.sdl CsmOptOut.uni
+//
+// 14 7/30/12 10:22a Artems
+// [TAG] EIP N/A
+// [Category] Bug Fix
+// [Severity] Minor
+// [Symptom] Can't disable legacy OpROM execution
+// [RootCause] CsmOptOut didn't check if anybody already disabled OpROM
+// executio
+// [Solution] Added check of ExecuteThisOpROM flag
+// [Files] CsmOptOut.c
+//
+// 13 6/20/12 6:05p Artems
+// [TAG] EIP83692
+// [Category] Improvement
+// [Description] CSM OptOut setup page grayed out if secure boot is
+// enabled
+// CSM OptOut PlatformOverride protocol modified to fix SCT bugs
+// Removed support for Launch CSM "Auto" option
+// [Files] CsmOptOut.c CsmOptOut.mak CsmOptOut.sd CsmOptOut.sdl
+// CsmOptOut.uni CsmOptOutRuntime.c CsmOptOutSetup.c
+//
+// 12 5/21/12 4:46p Artems
+// [TAG] EIP86097
+// [Category] Improvement
+// [Description] Separate control for loading UEFI Oprom Driver
+// [Files] CsmOptOut.c CsmOptOut.mak PciBus.c
+// CsmOptOut.sdl
+//
+// 11 5/10/12 5:42p Artems
+// [TAG] EIP87316
+// [Category] Improvement
+// [Description] Revert previous changes, as the improvement were made
+// in FixedBootOrder module
+// [Files] CsmOptOut.c
+//
+// 10 4/18/12 4:41p Artems
+// [TAG] EIP87316
+// [Category] Improvement
+// [Description] If legacy boot device is filtered it still appears in
+// boot order maintained by FixedBootOrder module
+// [Files] CsmOptOut.c
+//
+// 9 4/05/12 5:14p Artems
+// Removed eLinks to ConnectVga and ConnectEverything. Implemented
+// Platform specific override protocol instead to control OpROM execution
+// sequence
+//
+// 8 3/16/12 6:06p Artems
+// Fixed bug in CsmOptOutConnectEverything function - not all handles were
+// connected
+//
+// 7 3/16/12 5:15p Artems
+// EIP 82586: CSM must not be loaded if Secure Boot is enabled
+//
+// 6 1/27/12 4:34p Artems
+// Restored change killed by previous check-in
+//
+// 5 1/23/12 7:02p Artems
+// Added OpROM handling for PCI devices other than Network, Mass storage
+// or Video
+// Behavior is same as in previous Core versions
+//
+// 3 11/28/11 1:42p Artems
+// EIP 75876: Trying to use Setup variable before NVRAM driver is
+// available
+//
+// 2 11/14/11 3:37p Artems
+// Removed unnecessary Trace
+//
+// 1 11/12/11 2:57p Artems
+// Initial check-in
+//
+//**********************************************************************
+//<AMI_FHDR_START>
+//
+// Name: CsmOptOut.c
+//
+// Description: This is main file of the CsmOptOut module
+//
+//<AMI_FHDR_END>
+//**********************************************************************
+
+
+//----------------------------------------------------------------------------
+
+#include <Token.h>
+#include <AmiDxeLib.h>
+#include <Setup.h>
+#include <BootOptions.h>
+#include <AmiLoadCsmPolicy.h>
+#include <Protocol\CsmPlatform.h>
+#include <Protocol\PciIo.h>
+#include <Protocol\DriverBinding.h>
+#include <Protocol\PlatformDriverOverride.h>
+#include <Protocol\BusSpecificDriverOverride.h>
+#include <Protocol\GraphicsOutput.h>
+
+#define DEFAULT_HANDLE_BUFFER_SIZE 0x40
+typedef struct {
+ UINTN TotalSize;
+ UINTN CurrentSize;
+ EFI_HANDLE *Array;
+} HANDLE_BUFFER;
+
+HANDLE_BUFFER ThunkHandles;
+HANDLE_BUFFER NonThunkHandles;
+static EFI_HANDLE SharedGopHandle = 0;
+static BOOLEAN UefiGopDisconnected = FALSE;
+static BOOLEAN ProceedToBoot = FALSE;
+
+
+EFI_STATUS CsmOptOutGetDriver(
+ IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN OUT EFI_HANDLE *DriverImageHandle
+);
+
+EFI_STATUS CsmOptOutGetDriverWorker(
+ IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN OUT EFI_HANDLE *DriverImageHandle
+);
+
+EFI_STATUS CsmOptOutGetDriverPath(
+ IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DriverImagePath
+) { return EFI_UNSUPPORTED; }
+
+EFI_STATUS CsmOptOutDriverLoaded(
+ IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverImagePath,
+ IN EFI_HANDLE DriverImageHandle
+) { return EFI_UNSUPPORTED; }
+
+static EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL CsmOptOutPlatformDriverOverride = {
+ CsmOptOutGetDriver,
+ CsmOptOutGetDriverPath,
+ CsmOptOutDriverLoaded
+};
+
+
+//----------------------------------------------------------------------------
+
+static EFI_GUID SetupGuid = SETUP_GUID;
+static EFI_GUID AmiLoadCsmGuid = AMI_LOAD_CSM_GUID;
+static EFI_GUID OpRomStartEndProtocolGuid = OPROM_START_END_PROTOCOL_GUID;
+static EFI_GUID AmiCsmThunkProtocolGuid = AMI_CSM_THUNK_PROTOCOL_GUID;
+static EFI_GUID AmiOpromPolicyProtocolGuid = AMI_OPROM_POLICY_PROTOCOL_GUID;
+extern EFI_GUID BdsAllDriversConnectedProtocolGuid;
+
+UINT8 CurrentCsmState;
+VOID *ProcessOpRomRegistration;
+VOID *DriverBindingRegistration;
+static UINTN CurrentCount = 0;
+static EFI_HANDLE CurrentHandle = 0;
+static EFI_HANDLE LastReturnedImageHandle = 0;
+static BOOLEAN TransactionInProgress;
+static BOOLEAN ThunkFirst;
+
+typedef EFI_STATUS (OEM_CHECK_UEFI_OPROM_POLICY) (EFI_HANDLE PciHandle);
+extern OEM_CHECK_UEFI_OPROM_POLICY OEM_CHECK_UEFI_OPROM_POLICY_LIST EndOfList;
+OEM_CHECK_UEFI_OPROM_POLICY* OemCheckUefiOpromPolicyList[] = { OEM_CHECK_UEFI_OPROM_POLICY_LIST NULL };
+
+EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *BusSpecific = NULL;
+
+typedef struct CSM_OPTOUT_SETUP_DATA {
+ UINT8 CsmLaunchPolicy;
+ UINT8 BootOptionFilter;
+ UINT8 PxeOpRom;
+ UINT8 MassStorageOpRom;
+ UINT8 VideoOpRom;
+/*
+ We added the following field to preserve functionality existed in previous
+ PciBus versions. For PCI devices other than Network,Mass Storage or Video
+ value of following field will determine OpROM behavior as before.
+*/
+ UINT8 OldOpRom;
+} CSM_OPTOUT_SETUP_DATA;
+
+CSM_OPTOUT_SETUP_DATA CsmOptOutSetupData = {
+ DEFAULT_CSM_LAUNCH_POLICY,
+ DEFAULT_BOOT_OPTION_FILTERING_POLICY,
+ DEFAULT_PXE_OPROM_POLICY,
+ DEFAULT_MASS_STORAGE_OPROM_POLICY,
+ DEFAULT_VIDEO_OPROM_POLICY,
+ 1
+};
+
+EFI_STATUS CheckUefiOpRomPolicy(
+ IN AMI_OPROM_POLICY_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle
+);
+
+AMI_OPROM_POLICY_PROTOCOL AmiOpRomPolicyProtocol = {
+ CheckUefiOpRomPolicy
+};
+
+EFI_STATUS AddHandle(
+ IN OUT HANDLE_BUFFER *Target,
+ EFI_HANDLE Handle
+);
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+//
+// Procedure: CsmOptOutFilter
+//
+// Description: This function filters available boot options based on Setup
+// control value
+//
+// Input:
+// IN BOOT_DEVICE *Device - pointer to boot device
+//
+// Output:
+// TRUE - boot option will be removed from boot list
+// FALSE - boot option won't be removed from boot list
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+BOOLEAN CsmOptOutFilter(
+ IN BOOT_DEVICE *Device
+)
+{
+ BOOLEAN Result = FALSE;
+
+ if(CurrentCsmState == 0) //CSM is disabled on current boot - no need to filter boot options
+ return Result;
+
+ switch (CsmOptOutSetupData.BootOptionFilter) {
+ case 0: // Enable all boot options
+ break;
+
+ case 1: // Disable UEFI boot options
+ Result = (Device->BbsEntry == NULL);
+ break;
+
+ case 2: // Disable Legacy boot options
+ Result = (Device->BbsEntry != NULL);
+ break;
+
+ default:
+ break;
+ }
+ return Result;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: GetOpRomPolicy
+//
+// Description: This function returns OpROM policy for given PCI class of the device
+//
+// Input:
+// UINT8 PciClass - class of PCI device to check
+//
+// Output:
+// UINT8 - policy (0-disable all, 1-disable Legacy, 2-disable UEFI, 3-Legacy before UEFI
+// 4-UEFI before Legacy)
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+UINT8 GetOpRomPolicy(
+ IN UINT8 PciClass
+)
+{
+ UINT8 Policy = 0xff;
+
+ switch(PciClass) {
+ case PCI_CL_NETWORK:
+ Policy = CsmOptOutSetupData.PxeOpRom;
+ break;
+
+ case PCI_CL_MASS_STOR:
+ Policy = CsmOptOutSetupData.MassStorageOpRom;
+ break;
+
+ case PCI_CL_DISPLAY:
+ Policy = CsmOptOutSetupData.VideoOpRom;
+ break;
+
+ default:
+/*
+ For PCI devices with PCI class different from Network, Mass Storage or Video
+ behavior will be as in previous versions of PciBus driver - UEFI OpROM will
+ be executed first or not executed at all
+*/
+#if OLD_OPROM_POLICY_SUPPORT
+ Policy = (CsmOptOutSetupData.OldOpRom == 1) ? 4 : 2;
+#else
+ Policy = CsmOptOutSetupData.OldOpRom;
+#endif
+ break;
+ }
+ return Policy;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: CheckOpRomExecution
+//
+// Description: This function determines should OpROM be executed
+//
+// Input:
+// UINT8 PciClass - class of PCI device to check
+// BOOLEAN UefiOprom - TRUE if verifying UEFI OpROM, FALSE for Legacy OpROM
+//
+// Output:
+// EFI_SUCCESS - OpROM should be executed
+// EFI_UNSUPPORTED - OpROM should not be executed
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS CheckOpRomExecution(
+ IN UINT8 PciClass,
+ IN BOOLEAN UefiOprom
+)
+{
+ UINT8 Policy;
+ BOOLEAN Result = TRUE;
+
+ Policy = GetOpRomPolicy(PciClass);
+
+ switch(Policy) {
+ case 0: //all OpROMs are disabled
+ Result = FALSE;
+ break;
+
+ case 1: //only UEFI OpROMs are enabled
+ Result = (UefiOprom) ? TRUE : FALSE;
+ break;
+
+ case 2: //only Legacy OpROMs are enabled
+ Result = (UefiOprom) ? FALSE : TRUE;
+ break;
+
+ default: //all OpROMs are enabled
+ break;
+ }
+ return (Result) ? EFI_SUCCESS : EFI_UNSUPPORTED;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: DisconnectUefiGop
+//
+// Description: This function disconnects native UEFI GOP driver before
+// executing legacy video BIOS
+//
+// Input:
+// IN EFI_PCI_IO_PROTOCOL *PciIo - instance of PciIo protocol on handle,
+// that have to be disconnected
+//
+// Output:
+// EFI_SUCCESS - driver was disconnected
+// EFI_UNSUPPORTED - driver can't be disconnected
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS DisconnectUefiGop(
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+)
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ EFI_HANDLE TmpHandle;
+ UINTN Count;
+ UINTN i;
+ VOID *Interface;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *Entries;
+ UINT64 Capabilities;
+
+/* first find corresponding handle */
+ Status = pBS->LocateHandleBuffer(ByProtocol, &gEfiPciIoProtocolGuid, NULL, &Count, &Handles);
+ if(EFI_ERROR(Status))
+ return Status;
+
+ for(i = 0; i < Count; i++) {
+ Status = pBS->HandleProtocol(Handles[i], &gEfiPciIoProtocolGuid, &Interface);
+ if(EFI_ERROR(Status))
+ continue;
+
+ if((VOID *)PciIo == Interface) {
+ SharedGopHandle = Handles[i];
+ break;
+ }
+ }
+ pBS->FreePool(Handles);
+
+ if(i == Count) //no matches
+ return EFI_NOT_FOUND;
+
+/* now find child handle where Gop is installed */
+ Status = pBS->OpenProtocolInformation(SharedGopHandle, &gEfiPciIoProtocolGuid, &Entries, &Count);
+ if(EFI_ERROR(Status))
+ return Status;
+
+ for(i = 0; i < Count; i++) {
+ if(!(Entries[i].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER))
+ continue;
+
+ Status = pBS->HandleProtocol(Entries[i].ControllerHandle, &gEfiGraphicsOutputProtocolGuid, &Interface);
+ if(!EFI_ERROR(Status)) {
+ TmpHandle = Entries[i].AgentHandle;
+ break;
+ }
+ }
+ pBS->FreePool(Entries);
+
+ if(i == Count) //no matches
+ return EFI_NOT_FOUND;
+
+/* now check if AgentHandle is our CSM thunk */
+ Status = pBS->HandleProtocol(TmpHandle, &AmiCsmThunkProtocolGuid, &Interface);
+ if(!EFI_ERROR(Status))
+ return EFI_SUCCESS;
+
+ Status = pBS->DisconnectController(SharedGopHandle, NULL, NULL);
+/* we have to restore PCI attributes so video BIOS can be executed */
+ Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationSupported,
+ 0, &Capabilities);
+ Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationEnable,
+ Capabilities & EFI_PCI_DEVICE_ENABLE, NULL);
+ return Status;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: ProcessOpRomCallback
+//
+// Description: This callback will be called before and after installing legacy OpROM
+//
+// Input:
+// IN EFI_EVENT Event - Callback event
+// IN VOID *Context - pointer to calling context
+//
+// Output: None
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+VOID ProcessOpRomCallback(
+ IN EFI_EVENT Event,
+ IN VOID *Context
+)
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ UINTN Size = sizeof(EFI_HANDLE);
+ CSM_PLATFORM_POLICY_DATA *OpRomStartEndProtocol;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 PciClassCode;
+
+ Status = pBS->LocateHandle(ByRegisterNotify, NULL, ProcessOpRomRegistration, &Size, &Handle);
+ ASSERT_EFI_ERROR(Status);
+ if (EFI_ERROR(Status))
+ return;
+
+ Status = pBS->HandleProtocol(Handle, &OpRomStartEndProtocolGuid, &OpRomStartEndProtocol);
+ ASSERT_EFI_ERROR(Status);
+ if (EFI_ERROR(Status))
+ return;
+
+ if(OpRomStartEndProtocol == NULL) { //post-process OpROM callback
+ if(UefiGopDisconnected && !ProceedToBoot)
+/* if this is last OpROM, and Gop was disconnected and we're not on legacy boot path */
+ pBS->ConnectController(SharedGopHandle, NULL, NULL, TRUE);
+ return;
+ }
+
+//check if someone already disabled execution of this OpROM
+ if(OpRomStartEndProtocol->PciIo == NULL || OpRomStartEndProtocol->ExecuteThisRom == FALSE)
+ return;
+
+ PciIo = OpRomStartEndProtocol->PciIo;
+ Status = PciIo->Pci.Read(PciIo, EfiPciIoWidthUint8, 0xB, 1, &PciClassCode);
+ if (EFI_ERROR(Status))
+ return;
+
+ Status = CheckOpRomExecution(PciClassCode, FALSE);
+ if(EFI_ERROR(Status)) {
+ OpRomStartEndProtocol->ExecuteThisRom = FALSE;
+ return;
+ }
+
+/* OK, we're decided to execute OpROM */
+ OpRomStartEndProtocol->ExecuteThisRom = TRUE;
+
+ if(PciClassCode == PCI_CL_DISPLAY) {
+ Status = DisconnectUefiGop(PciIo);
+ /*
+ we are executing video OpROM even if we can't disconnect
+ native UEFI driver - possible bug
+ */
+ if(!EFI_ERROR(Status))
+ UefiGopDisconnected = TRUE;
+ }
+ return;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: LocateHandlesCallback
+//
+// Description: This callback executed every time DriverBinding is installed
+//
+// Input:
+// IN EFI_EVENT Event - Callback event
+// IN VOID *Context - pointer to calling context
+//
+// Output: None
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+VOID LocateHandlesCallback(
+ IN EFI_EVENT Event,
+ IN VOID *Context
+)
+{
+ EFI_STATUS Status;
+ EFI_STATUS Status1;
+ UINTN Count = sizeof(EFI_HANDLE);
+ EFI_HANDLE Handle;
+ VOID *DummyInterface;
+
+ do {
+ Status = pBS->LocateHandle(ByRegisterNotify,
+ NULL,
+ DriverBindingRegistration,
+ &Count,
+ &Handle);
+ if(!EFI_ERROR(Status)) {
+ Status1 = pBS->HandleProtocol(Handle,
+ &AmiCsmThunkProtocolGuid,
+ &DummyInterface);
+ if(EFI_ERROR(Status1)) {
+ Status = AddHandle(&NonThunkHandles, Handle);
+ } else {
+ Status = AddHandle(&ThunkHandles, Handle);
+ }
+ }
+ } while (!EFI_ERROR(Status));
+
+ return;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: InitHandleBuffer
+//
+// Description: This function allocates buffer to store DriverBinding handles
+//
+// Input:
+// IN OUT HANDLE_BUFFER *Target - pointer to buffer to be initialized
+//
+// Output:
+// EFI_STATUS
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS InitHandleBuffer(
+ IN OUT HANDLE_BUFFER *Target
+)
+{
+ EFI_STATUS Status;
+
+ Status = pBS->AllocatePool(EfiBootServicesData,
+ sizeof(EFI_HANDLE) * DEFAULT_HANDLE_BUFFER_SIZE,
+ (VOID **)&(Target->Array));
+ if(!EFI_ERROR(Status)) {
+ Target->TotalSize = DEFAULT_HANDLE_BUFFER_SIZE;
+ Target->CurrentSize = 0;
+ }
+ return Status;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: IncreaseHandleBuffer
+//
+// Description: This function increases and reallocates buffer to store
+// DriverBinding handles
+//
+// Input:
+// IN OUT HANDLE_BUFFER *Target - pointer to buffer to be increased
+//
+// Output:
+// EFI_STATUS
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS IncreaseHandleBuffer(
+ IN OUT HANDLE_BUFFER *Target
+)
+{
+ EFI_STATUS Status;
+ VOID *NewArray;
+
+ Status = pBS->AllocatePool(EfiBootServicesData,
+ sizeof(EFI_HANDLE) * (Target->TotalSize + DEFAULT_HANDLE_BUFFER_SIZE),
+ &NewArray);
+ if(!EFI_ERROR(Status)) {
+ MemCpy(NewArray, Target->Array, sizeof(EFI_HANDLE) * Target->CurrentSize);
+ Target->TotalSize += DEFAULT_HANDLE_BUFFER_SIZE;
+
+ pBS->FreePool(Target->Array);
+ Target->Array = (EFI_HANDLE *)NewArray;
+ }
+ return Status;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: AddHandle
+//
+// Description: This function stores handles in allocated buffer
+//
+// Input:
+// IN OUT HANDLE_BUFFER *Target - pointer to buffer to store handle in
+// EFI_HANDLE Handle - handle to be stored
+//
+// Output:
+// EFI_STATUS
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS AddHandle(
+ IN OUT HANDLE_BUFFER *Target,
+ EFI_HANDLE Handle
+)
+{
+ EFI_STATUS Status;
+
+ if(Target->CurrentSize >= Target->TotalSize) {
+ Status = IncreaseHandleBuffer(Target);
+ if(EFI_ERROR(Status))
+ return Status;
+ }
+
+ Target->Array[Target->CurrentSize] = Handle;
+ Target->CurrentSize++;
+ return EFI_SUCCESS;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: ProceedToBootCallback
+//
+// Description: This callback executed when all drivers are connected and system
+// proceeds to boot
+//
+// Input:
+// IN EFI_EVENT Event - Callback event
+// IN VOID *Context - pointer to calling context
+//
+// Output: None
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+VOID ProceedToBootCallback(
+ IN EFI_EVENT Event,
+ IN VOID *Context
+)
+{
+ ProceedToBoot = TRUE;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: CsmOptOutEntry
+//
+// Description:
+// This function is CsmOptOut driver entry point
+//
+// Input:
+// IN EFI_HANDLE ImageHandle - Image handle
+// IN EFI_SYSTEM_TABLE *SystemTable - pointer to system table
+//
+// Output:
+// EFI_SUCCESS - Function executed successfully
+// EFI_ERROR - Some error occured during execution
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS CsmOptOutEntry(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+)
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ SETUP_DATA SetupData;
+ UINTN Size = sizeof(SETUP_DATA);
+ EFI_EVENT OptOutEvent;
+ VOID *Registration;
+
+ Status = pRS->GetVariable(L"Setup", &SetupGuid, NULL, &Size, &SetupData);
+
+ if(!EFI_ERROR(Status)) {
+ CsmOptOutSetupData.CsmLaunchPolicy = SetupData.CsmLaunchPolicy;
+ CsmOptOutSetupData.BootOptionFilter = SetupData.BootOptionFilter;
+ CsmOptOutSetupData.PxeOpRom = SetupData.PxeOpRom;
+ CsmOptOutSetupData.MassStorageOpRom = SetupData.MassStorageOpRom;
+ CsmOptOutSetupData.VideoOpRom = SetupData.VideoOpRom;
+ CsmOptOutSetupData.OldOpRom = SetupData.OldOpRom;
+ }
+
+//Determine current CSM state based on whether AmiLoadCsmGuid protocol is installed
+ Size = sizeof(EFI_HANDLE);
+ Status = pBS->LocateHandle(ByProtocol, &AmiLoadCsmGuid, NULL, &Size, &Handle);
+ CurrentCsmState = (EFI_ERROR(Status)) ? 0 : 1;
+
+ if(CurrentCsmState == 1) {
+ Status = RegisterProtocolCallback(&OpRomStartEndProtocolGuid,
+ ProcessOpRomCallback,
+ NULL,
+ &OptOutEvent,
+ &ProcessOpRomRegistration);
+ if(EFI_ERROR(Status))
+ return Status;
+
+ Status = RegisterProtocolCallback(&BdsAllDriversConnectedProtocolGuid,
+ ProceedToBootCallback,
+ NULL,
+ &OptOutEvent,
+ &Registration);
+ if(EFI_ERROR(Status))
+ return Status;
+
+ /* Init platform driver override protocol */
+ Status = InitHandleBuffer(&ThunkHandles);
+ if(EFI_ERROR(Status))
+ return Status;
+
+ Status = InitHandleBuffer(&NonThunkHandles);
+ if(EFI_ERROR(Status))
+ return Status;
+
+ Status = RegisterProtocolCallback(&gEfiDriverBindingProtocolGuid,
+ LocateHandlesCallback,
+ NULL,
+ &OptOutEvent,
+ &DriverBindingRegistration);
+ if(EFI_ERROR(Status))
+ return Status;
+
+ /*call callback manually to get already registered handles */
+ LocateHandlesCallback(OptOutEvent, NULL);
+
+ Status = pBS->InstallMultipleProtocolInterfaces(&Handle,
+ &AmiOpromPolicyProtocolGuid,
+ &AmiOpRomPolicyProtocol,
+ &gEfiPlatformDriverOverrideProtocolGuid,
+ &CsmOptOutPlatformDriverOverride,
+ NULL);
+ } else {
+//Reset Boot option filter to avoid situation, when no boot options are available
+ CsmOptOutSetupData.BootOptionFilter = 0;
+//Set video policy to UEFI only
+ CsmOptOutSetupData.VideoOpRom = 1;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: GetUefiOpRomPolicy
+//
+// Description:
+// This function is HII driver entry point
+//
+// Input:
+// IN EFI_HANDLE ImageHandle - Image handle
+// IN EFI_SYSTEM_TABLE *SystemTable - pointer to system table
+//
+// Output:
+// EFI_SUCCESS - Function executed successfully, HII protocols installed
+// EFI_ERROR - Some error occured during execution
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS CheckUefiOpRomPolicy(
+ IN AMI_OPROM_POLICY_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle
+)
+{
+ UINT32 i;
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 PciClass;
+
+ for(i = 0; OemCheckUefiOpromPolicyList[i] != NULL; i++) {
+ Status = OemCheckUefiOpromPolicyList[i](PciHandle);
+ if(Status == EFI_SUCCESS || Status == EFI_UNSUPPORTED)
+ return Status;
+ }
+
+ Status = pBS->HandleProtocol(PciHandle, &gEfiPciIoProtocolGuid, &PciIo);
+ if(EFI_ERROR(Status))
+ return Status;
+
+ Status = PciIo->Pci.Read(PciIo, EfiPciIoWidthUint8, 0xB, 1, &PciClass);
+
+ return (EFI_ERROR(Status))? Status : CheckOpRomExecution(PciClass, TRUE);
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: GetBusSpecificHandle
+//
+// Description: This function returns bus-specific handle for given controller
+//
+// Input:
+// IN EFI_HANDLE ControllerHandle - handle of the controller
+// IN OUT EFI_HANDLE *DriverImageHandle - pointer to returned handle placeholder
+//
+// Output:
+// EFI_SUCCESS - handle returned
+// EFI_NOT_FOUND - handle not found
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS GetBusSpecificHandle(
+ IN EFI_HANDLE ControllerHandle,
+ IN OUT EFI_HANDLE *DriverImageHandle
+)
+{
+ EFI_STATUS Status;
+
+ if(BusSpecific == NULL) {
+ Status = pBS->HandleProtocol(
+ ControllerHandle,
+ &gEfiBusSpecificDriverOverrideProtocolGuid,
+ &BusSpecific);
+ if(EFI_ERROR(Status))
+ return Status;
+ }
+
+ return BusSpecific->GetDriver(BusSpecific, DriverImageHandle);
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: IsManageable
+//
+// Description: This function returns if given PCI device class supports
+// controlled UEFI/Legacy OpROM execution sequence
+//
+// Input:
+// IN UINT8 PciClass - class of the device
+//
+// Output:
+// TRUE - controlled sequence supported
+// FALSE - controlled sequence not supported
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+BOOLEAN IsManageable(
+ IN UINT8 PciClass
+)
+{
+ if(PciClass == PCI_CL_DISPLAY ||
+ PciClass == PCI_CL_NETWORK ||
+ PciClass == PCI_CL_MASS_STOR)
+ return TRUE;
+
+ return FALSE;
+}
+
+VOID UpdateTransaction(
+ IN EFI_STATUS Status,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE DriverImageHandle
+)
+{
+ if(!EFI_ERROR(Status)) {
+ TransactionInProgress = TRUE;
+ CurrentHandle = ControllerHandle;
+ LastReturnedImageHandle = DriverImageHandle;
+ } else {
+ TransactionInProgress = FALSE;
+ CurrentHandle = NULL;
+ LastReturnedImageHandle = NULL;
+ }
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: CsmOptOutGetDriver
+//
+// Description: Implementation of Platform Drive Override protocol
+// GetDriver function
+//
+// Input:
+// IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This - pointer to the instance of
+// the protocol
+// IN EFI_HANDLE ControllerHandle - handle of controller for which to retrieve
+// DriverBinding handle
+// IN OUT EFI_HANDLE *DriverImageHandle - pointer to returned handle placeholder
+//
+// Output:
+// EFI_SUCCESS - handle returned
+// EFI_NOT_FOUND - handle not found
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS CsmOptOutGetDriver(
+ IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN OUT EFI_HANDLE *DriverImageHandle
+)
+{
+ EFI_STATUS Status;
+ if(TransactionInProgress) {
+ if(*DriverImageHandle != LastReturnedImageHandle ||
+ ControllerHandle != CurrentHandle) {
+ Status = EFI_INVALID_PARAMETER;
+ UpdateTransaction(Status, NULL, NULL);
+ return Status;
+ }
+ }
+
+ Status = CsmOptOutGetDriverWorker(This, ControllerHandle, DriverImageHandle);
+ UpdateTransaction(Status, ControllerHandle, *DriverImageHandle);
+ return Status;
+}
+
+EFI_STATUS CsmOptOutGetDriverWorker(
+ IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN OUT EFI_HANDLE *DriverImageHandle
+)
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 PciClass;
+ UINT8 Policy;
+
+ if(ControllerHandle == NULL)
+ return EFI_INVALID_PARAMETER;
+
+ if(*DriverImageHandle == NULL) { //This is first call
+ Status = pBS->HandleProtocol(ControllerHandle, &gEfiPciIoProtocolGuid, &PciIo);
+ if(EFI_ERROR(Status))
+ return EFI_NOT_FOUND; //we don't care about non pci handles
+
+ Status = PciIo->Pci.Read(PciIo, EfiPciIoWidthUint8, 0xB, 1, &PciClass);
+ if(EFI_ERROR(Status))
+ return EFI_NOT_FOUND;
+
+ Policy = GetOpRomPolicy(PciClass);
+ if(Policy == 0) //OpROM execution is disabled
+ return EFI_NOT_FOUND;
+
+ /* check if this pci class supported for controlled OpROM
+ execution sequence
+ */
+ if(!IsManageable(PciClass))
+ return EFI_NOT_FOUND;
+
+ ThunkFirst = (Policy == 2 || Policy == 3) ? TRUE : FALSE;
+ }
+
+ if(ThunkFirst) {
+ if(CurrentCount < ThunkHandles.CurrentSize) {
+ *DriverImageHandle = ThunkHandles.Array[CurrentCount];
+ CurrentCount++;
+ return EFI_SUCCESS;
+ } else {
+ CurrentCount = 0; //reset counter
+ return EFI_NOT_FOUND;
+ }
+ } else {
+/* first get handles provided by bus specific override protocol */
+ if((UINTN)BusSpecific != 0xfffffffa) {
+ Status = GetBusSpecificHandle(ControllerHandle, DriverImageHandle);
+ if(!EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ (UINTN)BusSpecific = 0xfffffffa; //set flag we're done with bus specific override
+ }
+/* now get other Driver binding handles except those with thunk protocol */
+ if(CurrentCount < NonThunkHandles.CurrentSize) {
+ *DriverImageHandle = NonThunkHandles.Array[CurrentCount];
+ CurrentCount++;
+ return EFI_SUCCESS;
+ } else {
+ CurrentCount = 0;
+ (UINTN)BusSpecific = 0; //set flag we need to start from bus specific next time we're called
+ }
+ }
+ return EFI_NOT_FOUND;
+}
+
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2011, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************