From 8016da21b56d5ab1da855037cd0f0e034e2404bf Mon Sep 17 00:00:00 2001 From: jljusten Date: Thu, 10 Nov 2011 22:04:19 +0000 Subject: [PATCH] OvmfPkg: Add CsmSupportLib This library installs the legacy interrupt, region and platform support required for CSM support drivers. Signed-off-by: jljusten Reviewed-by: geekboy15a git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12681 6f19259b-4bc3-4df7-8a09-765794883524 --- OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.c | 38 + OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.h | 55 + OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.inf | 54 + OvmfPkg/Csm/CsmSupportLib/LegacyInterrupt.c | 196 ++++ OvmfPkg/Csm/CsmSupportLib/LegacyInterrupt.h | 119 +++ OvmfPkg/Csm/CsmSupportLib/LegacyPlatform.c | 1066 +++++++++++++++++++ OvmfPkg/Csm/CsmSupportLib/LegacyPlatform.h | 104 ++ OvmfPkg/Csm/CsmSupportLib/LegacyRegion.c | 466 ++++++++ OvmfPkg/Csm/CsmSupportLib/LegacyRegion.h | 219 ++++ OvmfPkg/OvmfPkgIa32.dsc | 3 + OvmfPkg/OvmfPkgIa32X64.dsc | 3 + OvmfPkg/OvmfPkgX64.dsc | 3 + 12 files changed, 2326 insertions(+) create mode 100644 OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.c create mode 100644 OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.h create mode 100644 OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.inf create mode 100644 OvmfPkg/Csm/CsmSupportLib/LegacyInterrupt.c create mode 100644 OvmfPkg/Csm/CsmSupportLib/LegacyInterrupt.h create mode 100644 OvmfPkg/Csm/CsmSupportLib/LegacyPlatform.c create mode 100644 OvmfPkg/Csm/CsmSupportLib/LegacyPlatform.h create mode 100644 OvmfPkg/Csm/CsmSupportLib/LegacyRegion.c create mode 100644 OvmfPkg/Csm/CsmSupportLib/LegacyRegion.h diff --git a/OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.c b/OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.c new file mode 100644 index 0000000000..c0b0252b9c --- /dev/null +++ b/OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.c @@ -0,0 +1,38 @@ +/** @file + Platform CSM Support Library + + Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are + licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CsmSupportLib.h" + +/** + The constructor function for the platform CSM support library + + @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. + +**/ +RETURN_STATUS +EFIAPI +CsmSupportLibConstructor ( + VOID + ) +{ + LegacyRegionInit (); + + LegacyInterruptInstall (); + + LegacyBiosPlatformInstall (); + + return EFI_SUCCESS; +} + diff --git a/OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.h b/OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.h new file mode 100644 index 0000000000..e3b6e8c628 --- /dev/null +++ b/OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.h @@ -0,0 +1,55 @@ +/** @file + Platform CSM Support Library + + Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are + licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _CSM_SUPPORT_LIB_H_ +#define _CSM_SUPPORT_LIB_H_ + +#include + +/** + Initialize Legacy Region support + + @retval EFI_SUCCESS Successfully initialized + +**/ +EFI_STATUS +LegacyRegionInit ( + VOID + ); + +/** + Initialize Legacy Interrupt support + + @retval EFI_SUCCESS Successfully initialized + +**/ +EFI_STATUS +LegacyInterruptInstall ( + VOID + ); + +/** + Initialize Legacy Platform support + + @retval EFI_SUCCESS Successfully initialized + +**/ +EFI_STATUS +LegacyBiosPlatformInstall ( + VOID + ); + +#endif + diff --git a/OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.inf b/OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.inf new file mode 100644 index 0000000000..34cadb2b65 --- /dev/null +++ b/OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.inf @@ -0,0 +1,54 @@ +## @file +# Platform CSM Support Library +# +# Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CsmSupportLib + FILE_GUID = 04e03541-4663-417d-93f6-976378247d61 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = CsmSupportLib + + CONSTRUCTOR = CsmSupportLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + CsmSupportLib.c + LegacyInterrupt.c + LegacyRegion.c + LegacyPlatform.c + +[Packages] + MdePkg/MdePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + +[Protocols] + gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiDiskInfoProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiLegacyBiosPlatformProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiLegacyBiosProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiLegacyInterruptProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiLegacyRegion2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiPciIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED + +[LibraryClasses] + BaseLib + PciLib + IoLib + diff --git a/OvmfPkg/Csm/CsmSupportLib/LegacyInterrupt.c b/OvmfPkg/Csm/CsmSupportLib/LegacyInterrupt.c new file mode 100644 index 0000000000..cd984174ab --- /dev/null +++ b/OvmfPkg/Csm/CsmSupportLib/LegacyInterrupt.c @@ -0,0 +1,196 @@ +/** @file + Legacy Interrupt Support + + Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are + licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "LegacyInterrupt.h" + +// +// Handle for the Legacy Interrupt Protocol instance produced by this driver +// +STATIC EFI_HANDLE mLegacyInterruptHandle = NULL; + +// +// The Legacy Interrupt Protocol instance produced by this driver +// +STATIC EFI_LEGACY_INTERRUPT_PROTOCOL mLegacyInterrupt = { + GetNumberPirqs, + GetLocation, + ReadPirq, + WritePirq +}; + +STATIC UINT8 PirqReg[MAX_PIRQ_NUMBER] = { PIRQA, PIRQB, PIRQC, PIRQD, PIRQE, PIRQF, PIRQG, PIRQH }; + + +/** + Return the number of PIRQs supported by this chipset. + + @param[in] This Pointer to LegacyInterrupt Protocol + @param[out] NumberPirqs The pointer to return the max IRQ number supported + + @retval EFI_SUCCESS Max PIRQs successfully returned + +**/ +EFI_STATUS +EFIAPI +GetNumberPirqs ( + IN EFI_LEGACY_INTERRUPT_PROTOCOL *This, + OUT UINT8 *NumberPirqs + ) +{ + *NumberPirqs = MAX_PIRQ_NUMBER; + + return EFI_SUCCESS; +} + + +/** + Return PCI location of this device. + $PIR table requires this info. + + @param[in] This - Protocol instance pointer. + @param[out] Bus - PCI Bus + @param[out] Device - PCI Device + @param[out] Function - PCI Function + + @retval EFI_SUCCESS Bus/Device/Function returned + +**/ +EFI_STATUS +EFIAPI +GetLocation ( + IN EFI_LEGACY_INTERRUPT_PROTOCOL *This, + OUT UINT8 *Bus, + OUT UINT8 *Device, + OUT UINT8 *Function + ) +{ + *Bus = LEGACY_INT_BUS; + *Device = LEGACY_INT_DEV; + *Function = LEGACY_INT_FUNC; + + return EFI_SUCCESS; +} + + +/** + Builds the PCI configuration address for the register specified by PirqNumber + + @param[in] PirqNumber - The PIRQ number to build the PCI configuration address for + + @return The PCI Configuration address for the PIRQ +**/ +UINTN +GetAddress ( + UINT8 PirqNumber + ) +{ + return PCI_LIB_ADDRESS( + LEGACY_INT_BUS, + LEGACY_INT_DEV, + LEGACY_INT_FUNC, + PirqReg[PirqNumber] + ); +} + +/** + Read the given PIRQ register + + @param[in] This Protocol instance pointer + @param[in] PirqNumber The Pirq register 0 = A, 1 = B etc + @param[out] PirqData Value read + + @retval EFI_SUCCESS Decoding change affected. + @retval EFI_INVALID_PARAMETER Invalid PIRQ number + +**/ +EFI_STATUS +EFIAPI +ReadPirq ( + IN EFI_LEGACY_INTERRUPT_PROTOCOL *This, + IN UINT8 PirqNumber, + OUT UINT8 *PirqData + ) +{ + if (PirqNumber >= MAX_PIRQ_NUMBER) { + return EFI_INVALID_PARAMETER; + } + + *PirqData = PciRead8 (GetAddress (PirqNumber)); + *PirqData = (UINT8) (*PirqData & 0x7f); + + return EFI_SUCCESS; +} + + +/** + Write the given PIRQ register + + @param[in] This Protocol instance pointer + @param[in] PirqNumber The Pirq register 0 = A, 1 = B etc + @param[out] PirqData Value to write + + @retval EFI_SUCCESS Decoding change affected. + @retval EFI_INVALID_PARAMETER Invalid PIRQ number + +**/ +EFI_STATUS +EFIAPI +WritePirq ( + IN EFI_LEGACY_INTERRUPT_PROTOCOL *This, + IN UINT8 PirqNumber, + IN UINT8 PirqData + ) +{ + if (PirqNumber >= MAX_PIRQ_NUMBER) { + return EFI_INVALID_PARAMETER; + } + + PciWrite8 (GetAddress (PirqNumber), PirqData); + return EFI_SUCCESS; +} + + +/** + Initialize Legacy Interrupt support + + @retval EFI_SUCCESS Successfully initialized + +**/ +EFI_STATUS +LegacyInterruptInstall ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Make sure the Legacy Interrupt Protocol is not already installed in the system + // + ASSERT_PROTOCOL_ALREADY_INSTALLED(NULL, &gEfiLegacyInterruptProtocolGuid); + + // + // Make a new handle and install the protocol + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mLegacyInterruptHandle, + &gEfiLegacyInterruptProtocolGuid, + &mLegacyInterrupt, + NULL + ); + ASSERT_EFI_ERROR(Status); + + return Status; +} + diff --git a/OvmfPkg/Csm/CsmSupportLib/LegacyInterrupt.h b/OvmfPkg/Csm/CsmSupportLib/LegacyInterrupt.h new file mode 100644 index 0000000000..193e48bad2 --- /dev/null +++ b/OvmfPkg/Csm/CsmSupportLib/LegacyInterrupt.h @@ -0,0 +1,119 @@ +/** @file + Legacy Region Support + + Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are + licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _LEGACY_INTERRUPT_H_ +#define _LEGACY_INTERRUPT_H_ + +#include + +#include + +#include +#include +#include + +#define LEGACY_INT_BUS 0 +#define LEGACY_INT_DEV 1 +#define LEGACY_INT_FUNC 0 + +#define PIRQN 0x00 // PIRQ Null +#define PIRQA 0x60 +#define PIRQB 0x61 +#define PIRQC 0x62 +#define PIRQD 0x63 +#define PIRQE 0x68 +#define PIRQF 0x69 +#define PIRQG 0x6A +#define PIRQH 0x6B + +#define MAX_PIRQ_NUMBER 8 + +/** + Return the number of PIRQs supported by this chipset. + + @param[in] This Pointer to LegacyInterrupt Protocol + @param[out] NumberPirqs The pointer to return the max IRQ number supported + + @retval EFI_SUCCESS Max PIRQs successfully returned + +**/ +EFI_STATUS +EFIAPI +GetNumberPirqs ( + IN EFI_LEGACY_INTERRUPT_PROTOCOL *This, + OUT UINT8 *NumberPirqs + ); + +/** + Return PCI location of this device. + $PIR table requires this info. + + @param[in] This - Protocol instance pointer. + @param[out] Bus - PCI Bus + @param[out] Device - PCI Device + @param[out] Function - PCI Function + + @retval EFI_SUCCESS Bus/Device/Function returned + +**/ +EFI_STATUS +EFIAPI +GetLocation ( + IN EFI_LEGACY_INTERRUPT_PROTOCOL *This, + OUT UINT8 *Bus, + OUT UINT8 *Device, + OUT UINT8 *Function + ); + +/** + Read the given PIRQ register + + @param[in] This Protocol instance pointer + @param[in] PirqNumber The Pirq register 0 = A, 1 = B etc + @param[out] PirqData Value read + + @retval EFI_SUCCESS Decoding change affected. + @retval EFI_INVALID_PARAMETER Invalid PIRQ number + +**/ +EFI_STATUS +EFIAPI +ReadPirq ( + IN EFI_LEGACY_INTERRUPT_PROTOCOL *This, + IN UINT8 PirqNumber, + OUT UINT8 *PirqData + ); + +/** + Write the given PIRQ register + + @param[in] This Protocol instance pointer + @param[in] PirqNumber The Pirq register 0 = A, 1 = B etc + @param[out] PirqData Value to write + + @retval EFI_SUCCESS Decoding change affected. + @retval EFI_INVALID_PARAMETER Invalid PIRQ number + +**/ +EFI_STATUS +EFIAPI +WritePirq ( + IN EFI_LEGACY_INTERRUPT_PROTOCOL *This, + IN UINT8 PirqNumber, + IN UINT8 PirqData + ); + +#endif + diff --git a/OvmfPkg/Csm/CsmSupportLib/LegacyPlatform.c b/OvmfPkg/Csm/CsmSupportLib/LegacyPlatform.c new file mode 100644 index 0000000000..af8896ae90 --- /dev/null +++ b/OvmfPkg/Csm/CsmSupportLib/LegacyPlatform.c @@ -0,0 +1,1066 @@ +/** @file + Legacy BIOS Platform support + + Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are + licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "LegacyPlatform.h" + +EFI_SETUP_BBS_MAP mSetupBbsMap[] = { + { 1, 2, 1, 1 }, // ATA HardDrive + { 2, 3, 1, 1 }, // ATAPI CDROM + { 3, 0x80, 2, 0 }, // PXE + { 4, 1, 0, 6 }, // USB Floppy + { 4, 2, 0, 6 }, // USB HDD + { 4, 3, 0, 6 }, // USB CD + { 4, 1, 0, 0 }, // USB ZIP Bugbug since Class/SubClass code is uninitialized + { 4, 2, 0, 0 } // USB ZIP Bugbug since Class/SubClass code is uninitialized +}; + +// +// Global variables for System ROMs +// +#define SYSTEM_ROM_FILE_GUID \ +{ 0x1547B4F3, 0x3E8A, 0x4FEF, 0x81, 0xC8, 0x32, 0x8E, 0xD6, 0x47, 0xAB, 0x1A } + +#define NULL_ROM_FILE_GUID \ +{ 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + +SYSTEM_ROM_TABLE mSystemRomTable[] = { + { SYSTEM_ROM_FILE_GUID, 1 }, + { NULL_ROM_FILE_GUID, 0 } +}; + +EFI_HANDLE mVgaHandles[0x20]; +EFI_HANDLE mDiskHandles[0x20]; +EFI_HANDLE mIsaHandles[0x20]; + +EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY IrqPriorityTable[MAX_IRQ_PRIORITY_ENTRIES] = { + {0x0B,0}, + {0x09,0}, + {0x0A,0}, + {0x05,0}, + {0x07,0}, + {0x00,0}, + {0x00,0} +}; + +// +// PIRQ Table +// - Slot numbering will be used to update the bus number and determine bridge +// to check to get bus number. The Slot number - 1 is an index into a decode +// table to get the bridge information. +// +EFI_LEGACY_PIRQ_TABLE PirqTableHead = { + { + EFI_LEGACY_PIRQ_TABLE_SIGNATURE, // UINT32 Signature + 0x00, // UINT8 MinorVersion + 0x01, // UINT8 MajorVersion + 0x0000, // UINT16 TableSize + 0x00, // UINT8 Bus + 0x08, // UINT8 DevFun + 0x0000, // UINT16 PciOnlyIrq + 0x8086, // UINT16 CompatibleVid + 0x122e, // UINT16 CompatibleDid + 0x00000000, // UINT32 Miniport + { // UINT8 Reserved[11] + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 + }, + 0x00, // UINT8 Checksum + }, + { + // -- Pin 1 -- -- Pin 2 -- -- Pin 3 -- -- Pin 4 -- + // Bus Dev Reg Map Reg Map Reg Map Reg Map + + 0x00,0x08,0x60,0xDEB8,0x61,0xDEB8,0x62,0xDEB8,0x63,0xDEB8,0x00,0x00, + 0x00,0x10,0x61,0xDEB8,0x62,0xDEB8,0x63,0xDEB8,0x60,0xDEB8,0x01,0x00, + 0x00,0x18,0x62,0xDEB8,0x63,0xDEB8,0x60,0xDEB8,0x61,0xDEB8,0x02,0x00, + 0x00,0x20,0x63,0xDEB8,0x60,0xDEB8,0x61,0xDEB8,0x62,0xDEB8,0x03,0x00, + 0x00,0x28,0x60,0xDEB8,0x61,0xDEB8,0x62,0xDEB8,0x63,0xDEB8,0x04,0x00, + 0x00,0x30,0x61,0xDEB8,0x62,0xDEB8,0x63,0xDEB8,0x60,0xDEB8,0x05,0x00, + } +}; + +LEGACY_BIOS_PLATFORM_INSTANCE mPrivateData; +EFI_HANDLE mImageHandle = NULL; + +/** + Return the handles and assorted information for the specified PCI Class code + + @param[in] PciClasses Array of PCI_CLASS_RECORD to find terminated with ClassCode 0xff + @param[in,out] DeviceTable Table to place handles etc in. + @param[in,out] DeviceIndex Number of devices found + @param[in] DeviceFlags FALSE if a valid legacy ROM is required, TRUE otherwise. + + @retval EFI_SUCCESS One or more devices found + @retval EFI_NOT_FOUND No device found + +**/ +EFI_STATUS +FindAllDeviceTypes ( + IN PCI_CLASS_RECORD *PciClasses, + IN OUT DEVICE_STRUCTURE *DeviceTable, + IN OUT UINT16 *DeviceIndex, + IN BOOLEAN DeviceFlags + ) +{ + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + UINTN StartIndex; + PCI_TYPE00 PciConfigHeader; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINTN Flags; + EFI_STATUS Status; + UINTN Index2; + + // + // Get legacy BIOS protocol as it is required to deal with Option ROMs. + // + StartIndex = *DeviceIndex; + Status = gBS->LocateProtocol ( + &gEfiLegacyBiosProtocolGuid, + NULL, + (VOID**)&LegacyBios + ); + ASSERT_EFI_ERROR (Status); + + // + // Get all PCI handles and check them to generate a list of matching devices. + // + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + for (Index = 0; Index < HandleCount; Index++) { + gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiPciIoProtocolGuid, + (VOID**)&PciIo + ); + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (PciConfigHeader) / sizeof (UINT32), + &PciConfigHeader + ); + for (Index2 = 0; PciClasses[Index2].Class != 0xff; Index2++) { + if ((PciConfigHeader.Hdr.ClassCode[2] == PciClasses[Index2].Class) && + (PciConfigHeader.Hdr.ClassCode[1] == PciClasses[Index2].SubClass)) { + LegacyBios->CheckPciRom ( + LegacyBios, + HandleBuffer[Index], + NULL, + NULL, + &Flags + ); + + // + // Verify that results of OPROM check match request. + // The two valid requests are: + // DeviceFlags = 0 require a valid legacy ROM + // DeviceFlags = 1 require either no ROM or a valid legacy ROM + // + if ( + ((DeviceFlags != 0) && (Flags == NO_ROM)) || + ((Flags & (ROM_FOUND | VALID_LEGACY_ROM)) == (ROM_FOUND | VALID_LEGACY_ROM)) + ) { + DeviceTable->Handle = HandleBuffer[Index]; + DeviceTable->Vid = PciConfigHeader.Hdr.VendorId; + DeviceTable->Did = PciConfigHeader.Hdr.DeviceId; + DeviceTable->SvId = PciConfigHeader.Device.SubsystemVendorID; + DeviceTable->SysId = PciConfigHeader.Device.SubsystemID; + ++ *DeviceIndex; + DeviceTable++; + } + } + } + } + + // + // Free any allocated buffers + // + gBS->FreePool (HandleBuffer); + + if (*DeviceIndex != StartIndex) { + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } +} + +/** + Load and initialize the Legacy BIOS SMM handler. + + @param This The protocol instance pointer. + @param EfiToLegacy16BootTable A pointer to Legacy16 boot table. + + @retval EFI_SUCCESS SMM code loaded. + @retval EFI_DEVICE_ERROR SMM code failed to load + +**/ +EFI_STATUS +EFIAPI +SmmInit ( + IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, + IN VOID *EfiToLegacy16BootTable + ) +{ + return EFI_SUCCESS; +} + +/** + Finds the device path that should be used as the primary display adapter. + + @param VgaHandle - The handle of the video device + +**/ +VOID +GetSelectedVgaDeviceInfo ( + OUT EFI_HANDLE *VgaHandle + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; + UINT8 MinBus; + UINT8 MaxBus; + UINTN Segment; + UINTN Bus; + UINTN Device; + UINTN Function; + UINTN SelectedAddress; + UINTN CurrentAddress; + + // + // Initialize return to 'not found' state + // + *VgaHandle = NULL; + + // + // Initialize variable states. Ths is important for selecting the VGA device + // if multiple devices exist behind a single bridge. + // + HandleCount = 0; + HandleBuffer = NULL; + SelectedAddress = PCI_LIB_ADDRESS(0xff, 0x1f, 0x7, 0); + + // + // The bus range to search for a VGA device in. + // + MinBus = MaxBus = 0; + + // + // Start to check all the pci io to find all possible VGA device + // + HandleCount = 0; + HandleBuffer = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return; + } + + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID**)&PciIo); + if (!EFI_ERROR (Status)) { + // + // Detemine if this is in the correct bus range. + // + Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function); + if (EFI_ERROR(Status) || (Bus < MinBus || Bus > MaxBus)) { + continue; + } + + // + // Read device information. + // + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (Pci) / sizeof (UINT32), + &Pci + ); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Make sure the device is a VGA device. + // + if (!IS_PCI_VGA (&Pci)) { + continue; + } + DEBUG ((EFI_D_INFO, + "PCI VGA: 0x%04x:0x%04x\n", + Pci.Hdr.VendorId, + Pci.Hdr.DeviceId + )); + + // + // Currently we use the lowest numbered bus/device/function if multiple + // devices are found in the target bus range. + // + CurrentAddress = PCI_LIB_ADDRESS(Bus, Device, Function, 0); + if (CurrentAddress < SelectedAddress) { + SelectedAddress = CurrentAddress; + *VgaHandle = HandleBuffer[Index]; + } + } + } + + FreePool (HandleBuffer); +} + + +/** + Returns a buffer of handles for the requested subfunction. + + @param This The protocol instance pointer. + @param Mode Specifies what handle to return. See EFI_GET_PLATFORM_HANDLE_MODE enum. + @param Type Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum. + @param HandleBuffer Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum. + @param HandleCount Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum. + @param AdditionalData Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum. + + @retval EFI_SUCCESS Handle is valid. + @retval EFI_UNSUPPORTED Mode is not supported on the platform. + @retval EFI_NOT_FOUND Handle is not known. + +**/ +EFI_STATUS +EFIAPI +GetPlatformHandle ( + IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, + IN EFI_GET_PLATFORM_HANDLE_MODE Mode, + IN UINT16 Type, + OUT EFI_HANDLE **HandleBuffer, + OUT UINTN *HandleCount, + OUT VOID **AdditionalData OPTIONAL + ) +{ + DEVICE_STRUCTURE LocalDevice[0x40]; + UINT32 LocalIndex; + UINT32 Index; + DEVICE_STRUCTURE TempDevice; + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + UINTN Segment; + UINTN Bus; + UINTN Device; + UINTN Function; + HDD_INFO *HddInfo; + PCI_TYPE00 PciConfigHeader; + UINT32 HddIndex; + EFI_HANDLE IdeHandle; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + PCI_CLASS_RECORD ClassLists[10]; + UINTN PriorityIndex; + + static BOOLEAN bConnected = FALSE; + + LocalIndex = 0x00; + HddInfo = NULL; + HddIndex = 0; + + Status = gBS->LocateProtocol ( + &gEfiLegacyBiosProtocolGuid, + NULL, + (VOID**)&LegacyBios + ); + + // + // Process mode specific operations + // + switch (Mode) { + case EfiGetPlatformVgaHandle: + // + // Get the handle for the currently selected VGA device. + // + GetSelectedVgaDeviceInfo (&mVgaHandles[0]); + *HandleBuffer = &mVgaHandles[0]; + *HandleCount = (mVgaHandles[0] != NULL) ? 1 : 0; + return EFI_SUCCESS; + case EfiGetPlatformIdeHandle: + IdeHandle = NULL; + if (AdditionalData != NULL) { + HddInfo = (HDD_INFO *) *AdditionalData; + } + + // + // Locate all found block io devices + // + ClassLists[0].Class = PCI_CLASS_MASS_STORAGE; + ClassLists[0].SubClass = PCI_CLASS_MASS_STORAGE_SCSI; + ClassLists[1].Class = PCI_CLASS_MASS_STORAGE; + ClassLists[1].SubClass = PCI_CLASS_MASS_STORAGE_IDE; + ClassLists[2].Class = PCI_CLASS_MASS_STORAGE; + ClassLists[2].SubClass = PCI_CLASS_MASS_STORAGE_RAID; + ClassLists[3].Class = PCI_CLASS_MASS_STORAGE; + ClassLists[3].SubClass = PCI_CLASS_MASS_STORAGE_SATADPA; + ClassLists[4].Class = 0xff; + FindAllDeviceTypes (ClassLists, LocalDevice, (UINT16 *) &LocalIndex, TRUE); + if (LocalIndex == 0) { + return EFI_NOT_FOUND; + } + + // + // Make sure all IDE controllers are connected. This is necessary + // in NO_CONFIG_CHANGE boot path to ensure IDE controller is correctly + // initialized and all IDE drives are enumerated + // + if (!bConnected) { + for (Index = 0; Index < LocalIndex; Index++) { + gBS->ConnectController (LocalDevice[Index].Handle, NULL, NULL, TRUE); + } + } + + // + // Locate onboard controllers. + // + for (Index = 0; Index < LocalIndex; Index++) { + if (LocalDevice[Index].Vid == V_INTEL_VENDOR_ID) { + if (LocalDevice[Index].Did == V_PIIX4_IDE_DEVICE_ID) { + IdeHandle = LocalDevice[Index].Handle; + } + } + } + + // + // Set the IDE contorller as primary devices. + // + PriorityIndex = 0; + for (Index = 0; Index < LocalIndex; Index++) { + if (LocalDevice[Index].Handle == IdeHandle && PriorityIndex == 0) { + TempDevice = LocalDevice[PriorityIndex]; + LocalDevice[PriorityIndex] = LocalDevice[Index]; + LocalDevice[Index] = TempDevice; + PriorityIndex++; + break; + } + } + + // + // Copy over handles and update return values. + // + for (Index = 0; Index < LocalIndex; Index++) { + mDiskHandles[Index] = LocalDevice[Index].Handle; + } + *HandleBuffer = &mDiskHandles[0]; + *HandleCount = LocalIndex; + + // + // We have connected all IDE controllers once. No more needed + // + bConnected = TRUE; + + // + // Log all onboard controllers. + // + for (Index = 0; (Index < LocalIndex) && (AdditionalData != NULL); Index++) { + if ((LocalDevice[Index].Handle != NULL) && + (LocalDevice[Index].Handle == IdeHandle)) { + Status = gBS->HandleProtocol ( + LocalDevice[Index].Handle, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (PciConfigHeader) / sizeof (UINT32), + &PciConfigHeader + ); + if (!EFI_ERROR (Status)) { + PciIo->GetLocation ( + PciIo, + &Segment, + &Bus, + &Device, + &Function + ); + + // + // Be sure to only fill out correct information based on platform + // configureation. + // + HddInfo[HddIndex].Status |= HDD_PRIMARY; + HddInfo[HddIndex].Bus = (UINT32)Bus; + HddInfo[HddIndex].Device = (UINT32)Device; + HddInfo[HddIndex].Function = (UINT32)Function; + HddInfo[HddIndex + 1].Status |= HDD_SECONDARY; + HddInfo[HddIndex + 1].Bus = (UINT32)Bus; + HddInfo[HddIndex + 1].Device = (UINT32)Device; + HddInfo[HddIndex + 1].Function = (UINT32)Function; + + // + // Primary controller data + // + if ((PciConfigHeader.Hdr.ClassCode[0] & 0x01) != 0) { + HddInfo[HddIndex].CommandBaseAddress = + (UINT16)(PciConfigHeader.Device.Bar[0] & 0xfffc); + HddInfo[HddIndex].ControlBaseAddress = + (UINT16)((PciConfigHeader.Device.Bar[1] & 0xfffc)+2); + HddInfo[HddIndex].BusMasterAddress = + (UINT16)(PciConfigHeader.Device.Bar[4] & 0xfffc); + HddInfo[HddIndex].HddIrq = PciConfigHeader.Device.InterruptLine; + } else { + HddInfo[HddIndex].HddIrq = 14; + HddInfo[HddIndex].CommandBaseAddress = 0x1f0; + HddInfo[HddIndex].ControlBaseAddress = 0x3f6; + HddInfo[HddIndex].BusMasterAddress = 0; + } + HddIndex++; + + // + // Secondary controller data + // + if ((PciConfigHeader.Hdr.ClassCode[0] & 0x04) != 0) { + HddInfo[HddIndex].CommandBaseAddress = + (UINT16)(PciConfigHeader.Device.Bar[2] & 0xfffc); + HddInfo[HddIndex].ControlBaseAddress = + (UINT16)((PciConfigHeader.Device.Bar[3] & 0xfffc)+2); + HddInfo[HddIndex].BusMasterAddress = + (UINT16)(HddInfo[HddIndex].BusMasterAddress + 8); + HddInfo[HddIndex].HddIrq = PciConfigHeader.Device.InterruptLine; + } else { + HddInfo[HddIndex].HddIrq = 15; + HddInfo[HddIndex].CommandBaseAddress = 0x170; + HddInfo[HddIndex].ControlBaseAddress = 0x376; + HddInfo[HddIndex].BusMasterAddress = 0; + } + HddIndex++; + } + } + } + return EFI_SUCCESS; + case EfiGetPlatformIsaBusHandle: + ClassLists[0].Class = (UINT8) PCI_CLASS_BRIDGE; + ClassLists[0].SubClass = (UINT8) PCI_CLASS_BRIDGE_ISA_PDECODE; + ClassLists[1].Class = (UINT8) PCI_CLASS_BRIDGE; + ClassLists[1].SubClass = (UINT8) PCI_CLASS_BRIDGE_ISA; + ClassLists[2].Class = 0xff; + + // + // Locate all found block io devices + // + FindAllDeviceTypes (ClassLists, LocalDevice, (UINT16 *) (&LocalIndex), TRUE); + if (LocalIndex == 0) { + return EFI_NOT_FOUND; + } + + // + // Find our ISA bridge. + // + for (Index = 0; Index < LocalIndex; Index++) { + if (LocalDevice[Index].Vid == V_INTEL_VENDOR_ID) { + TempDevice = LocalDevice[0]; + LocalDevice[0] = LocalDevice[Index]; + LocalDevice[Index] = TempDevice; + } + } + + // + // Perform copy and update return values. + // + for (Index = 0; Index < LocalIndex; Index++) { + mIsaHandles[Index] = LocalDevice[Index].Handle; + } + *HandleBuffer = &mIsaHandles[0]; + *HandleCount = LocalIndex; + return EFI_SUCCESS; + case EfiGetPlatformUsbHandle: + default: + return EFI_UNSUPPORTED; + }; +} + +/** + Allows platform to perform any required action after a LegacyBios operation. + Invokes the specific sub function specified by Mode. + + @param This The protocol instance pointer. + @param Mode Specifies what handle to return. See EFI_GET_PLATFORM_HOOK_MODE enum. + @param Type Mode specific. See EFI_GET_PLATFORM_HOOK_MODE enum. + @param DeviceHandle Mode specific. See EFI_GET_PLATFORM_HOOK_MODE enum. + @param ShadowAddress Mode specific. See EFI_GET_PLATFORM_HOOK_MODE enum. + @param Compatibility16Table Mode specific. See EFI_GET_PLATFORM_HOOK_MODE enum. + @param AdditionalData Mode specific. See EFI_GET_PLATFORM_HOOK_MODE enum. + + @retval EFI_SUCCESS The operation performed successfully. Mode specific. + @retval EFI_UNSUPPORTED Mode is not supported on the platform. + +**/ +EFI_STATUS +EFIAPI +PlatformHooks ( + IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, + IN EFI_GET_PLATFORM_HOOK_MODE Mode, + IN UINT16 Type, + OUT EFI_HANDLE DeviceHandle, OPTIONAL + IN OUT UINTN *Shadowaddress, OPTIONAL + IN EFI_COMPATIBILITY16_TABLE *Compatibility16Table, OPTIONAL + OUT VOID **AdditionalData OPTIONAL + ) +{ + EFI_IA32_REGISTER_SET Regs; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + EFI_STATUS Status; + + switch (Mode) { + case EfiPlatformHookPrepareToScanRom: + Status = gBS->LocateProtocol ( + &gEfiLegacyBiosProtocolGuid, + NULL, + (VOID**)&LegacyBios + ); + + // + // Set the 80x25 Text VGA Mode + // + Regs.H.AH = 0x00; + Regs.H.AL = 0x03; + Status = LegacyBios->Int86 (LegacyBios, 0x10, &Regs); + return Status; + case EfiPlatformHookShadowServiceRoms: + return EFI_SUCCESS; + case EfiPlatformHookAfterRomInit: + default: + return EFI_UNSUPPORTED; + }; +} + +/** + Returns information associated with PCI IRQ routing. + This function returns the following information associated with PCI IRQ routing: + * An IRQ routing table and number of entries in the table. + * The $PIR table and its size. + * A list of PCI IRQs and the priority order to assign them. + + @param This The protocol instance pointer. + @param RoutingTable The pointer to PCI IRQ Routing table. + This location is the $PIR table minus the header. + @param RoutingTableEntries The number of entries in table. + @param LocalPirqTable $PIR table. + @param PirqTableSize $PIR table size. + @param LocalIrqPriorityTable A list of interrupts in priority order to assign. + @param IrqPriorityTableEntries The number of entries in the priority table. + + @retval EFI_SUCCESS Data was successfully returned. + +**/ +EFI_STATUS +EFIAPI +GetRoutingTable ( + IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, + OUT VOID **RoutingTable, + OUT UINTN *RoutingTableEntries, + OUT VOID **LocalPirqTable, OPTIONAL + OUT UINTN *PirqTableSize, OPTIONAL + OUT VOID **LocalIrqPriorityTable, OPTIONAL + OUT UINTN *IrqPriorityTableEntries OPTIONAL + ) +{ + UINT16 PTableSize; + UINT32 Index; + UINT8 Bus; + UINT8 Device; + UINT8 Function; + UINT8 Checksum; + UINT8 *Ptr; + EFI_STATUS Status; + EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt; + + Checksum = 0; + + if (LocalPirqTable != NULL) { + PTableSize = sizeof (EFI_LEGACY_PIRQ_TABLE_HEADER) + + sizeof (EFI_LEGACY_IRQ_ROUTING_ENTRY) * MAX_IRQ_ROUTING_ENTRIES; + + Status = gBS->LocateProtocol ( + &gEfiLegacyInterruptProtocolGuid, + NULL, + (VOID**)&LegacyInterrupt + ); + ASSERT_EFI_ERROR (Status); + LegacyInterrupt->GetLocation ( + LegacyInterrupt, + &Bus, + &Device, + &Function + ); + + // + // Update fields in $PIR table header + // + PirqTableHead.PirqTable.TableSize = PTableSize; + PirqTableHead.PirqTable.Bus = Bus; + PirqTableHead.PirqTable.DevFun = (UINT8) ((Device << 3) + Function); + Ptr = (UINT8 *) (&PirqTableHead); + + // + // Calculate checksum. + // + for (Index = 0; Index < PTableSize; Index++) { + Checksum = (UINT8) (Checksum + (UINT8) *Ptr); + Ptr += 1; + } + Checksum = (UINT8) (0x00 - Checksum); + PirqTableHead.PirqTable.Checksum = Checksum; + + // + // Update return values. + // + *LocalPirqTable = (VOID *) (&PirqTableHead); + *PirqTableSize = PTableSize; + } + + // + // More items to return. + // + *RoutingTable = PirqTableHead.IrqRoutingEntry; + *RoutingTableEntries = MAX_IRQ_ROUTING_ENTRIES; + if (LocalIrqPriorityTable != NULL) { + *LocalIrqPriorityTable = IrqPriorityTable; + *IrqPriorityTableEntries = MAX_IRQ_PRIORITY_ENTRIES; + } + + return EFI_SUCCESS; +} + +/** + Finds the binary data or other platform information. + + @param This The protocol instance pointer. + @param Mode Specifies what data to return. See See EFI_GET_PLATFORM_INFO_MODE enum. + @param Table Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. + @param TableSize Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. + @param Location Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. + @param Alignment Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. + @param LegacySegment Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. + @param LegacyOffset Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. + + @retval EFI_SUCCESS Data returned successfully. + @retval EFI_UNSUPPORTED Mode is not supported on the platform. + @retval EFI_NOT_FOUND Binary image or table not found. + +**/ +EFI_STATUS +EFIAPI +GetPlatformInfo ( + IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, + IN EFI_GET_PLATFORM_INFO_MODE Mode, + OUT VOID **Table, + OUT UINTN *TableSize, + OUT UINTN *Location, + OUT UINTN *Alignment, + IN UINT16 LegacySegment, + IN UINT16 LegacyOffset + ) +{ + EFI_STATUS Status; + UINTN Index; + + switch (Mode) { + case EfiGetPlatformBinarySystemRom: + // + // Loop through table of System rom descriptions + // + for (Index = 0; mSystemRomTable[Index].Valid != 0; Index++) { + Status = GetSectionFromFv ( + &mSystemRomTable[Index].FileName, + EFI_SECTION_RAW, + 0, + Table, + (UINTN *) TableSize + ); + if (EFI_ERROR (Status)) { + continue; + } + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; + case EfiGetPlatformBinaryOem16Data: + case EfiGetPlatformBinaryMpTable: + case EfiGetPlatformBinaryOemIntData: + case EfiGetPlatformBinaryOem32Data: + case EfiGetPlatformBinaryTpmBinary: + case EfiGetPlatformPciExpressBase: + default: + return EFI_UNSUPPORTED; + }; +} + +/** + Translates the given PIRQ accounting for bridge. + This function translates the given PIRQ back through all buses, if required, + and returns the true PIRQ and associated IRQ. + + @param This The protocol instance pointer. + @param PciBus The PCI bus number for this device. + @param PciDevice The PCI device number for this device. + @param PciFunction The PCI function number for this device. + @param Pirq Input is PIRQ reported by device, and output is true PIRQ. + @param PciIrq The IRQ already assigned to the PIRQ, or the IRQ to be + assigned to the PIRQ. + + @retval EFI_SUCCESS The PIRQ was translated. + +**/ +EFI_STATUS +EFIAPI +TranslatePirq ( + IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, + IN UINTN PciBus, + IN UINTN PciDevice, + IN UINTN PciFunction, + IN OUT UINT8 *Pirq, + OUT UINT8 *PciIrq + ) +{ + EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt; + EFI_STATUS Status; + UINTN Index; + UINTN Index1; + UINT8 LocalPirq; + UINT8 PirqData; + UINT8 MatchData; + + Status = gBS->LocateProtocol ( + &gEfiLegacyInterruptProtocolGuid, + NULL, + (VOID**)&LegacyInterrupt + ); + ASSERT_EFI_ERROR (Status); + LocalPirq = (UINT8) (*Pirq); + + for (Index = 0; Index < MAX_IRQ_ROUTING_ENTRIES; Index++) { + if ((PirqTableHead.IrqRoutingEntry[Index].Bus == PciBus) && + (PirqTableHead.IrqRoutingEntry[Index].Device == PciDevice)) { + LocalPirq = (UINT8) (PirqTableHead.IrqRoutingEntry[Index].PirqEntry[LocalPirq].Pirq & 0x0f); + if (LocalPirq > 4) { + LocalPirq -= 4; + } + + LegacyInterrupt->ReadPirq (LegacyInterrupt, LocalPirq, &PirqData); + MatchData = PCI_UNUSED; + while (PirqData == 0) { + for (Index1 = 0; Index1 < MAX_IRQ_PRIORITY_ENTRIES; Index1++) { + if ((IrqPriorityTable[Index1].Used == MatchData) && + (IrqPriorityTable[Index1].Irq != 0)) { + PirqData = IrqPriorityTable[Index1].Irq; + IrqPriorityTable[Index1].Used = 0xff; + LegacyInterrupt->WritePirq ( + LegacyInterrupt, + LocalPirq, + PirqData + ); + break; + } + } + + if (PirqData == 0) { + + // + // No unused interrpts, so start reusing them. + // + MatchData = (UINT8) (~MatchData); + } + } + + *PciIrq = PirqData; + *Pirq = LocalPirq; + } + } + + return EFI_SUCCESS; +} + + +/** + Attempt to legacy boot the BootOption. If the EFI contexted has been + compromised this function will not return. + + @param This The protocol instance pointer. + @param BbsDevicePath The EFI Device Path from BootXXXX variable. + @param BbsTable The Internal BBS table. + @param LoadOptionSize The size of LoadOption in size. + @param LoadOption The LoadOption from BootXXXX variable + @param EfiToLegacy16BootTable A pointer to BootTable structure + + @retval EFI_SUCCESS Ready to boot. + +**/ +EFI_STATUS +EFIAPI +PrepareToBoot ( + IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, + IN BBS_BBS_DEVICE_PATH *BbsDevicePath, + IN VOID *BbsTable, + IN UINT32 LoadOptionsSize, + IN VOID *LoadOptions, + IN VOID *EfiToLegacy16BootTable + ) +{ + BBS_TABLE *LocalBbsTable; + EFI_TO_COMPATIBILITY16_BOOT_TABLE *Legacy16BootTable; + DEVICE_PRODUCER_DATA_HEADER *SioPtr; + UINT16 DevicePathType; + UINT16 Index; + UINT16 Priority; + + // + // Initialize values + // + Priority = 0; + Legacy16BootTable = (EFI_TO_COMPATIBILITY16_BOOT_TABLE*) EfiToLegacy16BootTable; + + // + // Set how Gate A20 is gated by hardware + // + SioPtr = &Legacy16BootTable->SioData; + SioPtr->Flags.A20Kybd = 1; + SioPtr->Flags.A20Port90 = 1; + SioPtr->MousePresent = 1; + + LocalBbsTable = BbsTable; + + // + // There are 2 cases that must be covered. + // Case 1: Booting to a legacy OS - BbsDevicePath is non-NULL. + // Case 2: Booting to an EFI aware OS - BbsDevicePath is NULL. + // We need to perform the PrepareToBoot function to assign + // drive numbers to HDD devices to allow the shell or EFI + // to access them. + // + if (BbsDevicePath != NULL) { + DevicePathType = BbsDevicePath->DeviceType; + } else { + DevicePathType = BBS_HARDDISK; + } + + // + // Skip the boot devices where priority is set by BDS and set the next one + // + for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) { + if ((LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) && + (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY) && + (LocalBbsTable[Index].BootPriority != BBS_LOWEST_PRIORITY) && + (Priority <= LocalBbsTable[Index].BootPriority)) { + Priority = (UINT16) (LocalBbsTable[Index].BootPriority + 1); + } + } + + switch (DevicePathType) { + case BBS_FLOPPY: + case BBS_HARDDISK: + case BBS_CDROM: + case BBS_EMBED_NETWORK: + for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) { + if ((LocalBbsTable[Index].BootPriority == BBS_UNPRIORITIZED_ENTRY) && + (LocalBbsTable[Index].DeviceType == DevicePathType)) { + LocalBbsTable[Index].BootPriority = Priority; + ++Priority; + } + } + break; + case BBS_BEV_DEVICE: + for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) { + if ((LocalBbsTable[Index].BootPriority == BBS_UNPRIORITIZED_ENTRY) && + (LocalBbsTable[Index].Class == 01) && + (LocalBbsTable[Index].SubClass == 01)) { + LocalBbsTable[Index].BootPriority = Priority; + ++Priority; + } + } + break; + case BBS_USB: + case BBS_PCMCIA: + case BBS_UNKNOWN: + default: + break; + }; + + // + // Set priority for rest of devices + // + for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) { + if (LocalBbsTable[Index].BootPriority == BBS_UNPRIORITIZED_ENTRY) { + LocalBbsTable[Index].BootPriority = Priority; + ++Priority; + } + } + + return EFI_SUCCESS; +} + + +/** + Initialize Legacy Platform support + + @retval EFI_SUCCESS Successfully initialized + +**/ +EFI_STATUS +LegacyBiosPlatformInstall ( + VOID + ) +{ + EFI_STATUS Status; + LEGACY_BIOS_PLATFORM_INSTANCE *Private; + + mImageHandle = gImageHandle; + Private = &mPrivateData; + + // + // Grab a copy of all the protocols we depend on. + // + Private->Signature = LEGACY_BIOS_PLATFORM_INSTANCE_SIGNATURE; + Private->LegacyBiosPlatform.GetPlatformInfo = GetPlatformInfo; + Private->LegacyBiosPlatform.GetPlatformHandle = GetPlatformHandle; + Private->LegacyBiosPlatform.SmmInit = SmmInit; + Private->LegacyBiosPlatform.PlatformHooks = PlatformHooks; + Private->LegacyBiosPlatform.GetRoutingTable = GetRoutingTable; + Private->LegacyBiosPlatform.TranslatePirq = TranslatePirq; + Private->LegacyBiosPlatform.PrepareToBoot = PrepareToBoot; + Private->ImageHandle = gImageHandle; + + // + // Make a new handle and install the protocol + // + Private->Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Private->Handle, + &gEfiLegacyBiosPlatformProtocolGuid, + EFI_NATIVE_INTERFACE, + &Private->LegacyBiosPlatform + ); + return Status; +} + diff --git a/OvmfPkg/Csm/CsmSupportLib/LegacyPlatform.h b/OvmfPkg/Csm/CsmSupportLib/LegacyPlatform.h new file mode 100644 index 0000000000..a4654a446b --- /dev/null +++ b/OvmfPkg/Csm/CsmSupportLib/LegacyPlatform.h @@ -0,0 +1,104 @@ +/** @file + Legacy BIOS Platform support + + Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are + licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef LEGACY_BIOS_PLATFORM_H_ +#define LEGACY_BIOS_PLATFORM_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// +// PIRQ information constants. +// +#define MAX_IRQ_ROUTING_ENTRIES 6 +#define MAX_IRQ_PRIORITY_ENTRIES 7 + +#define V_INTEL_VENDOR_ID 0x8086 +#define V_PIIX4_IDE_DEVICE_ID 0x7010 + +// +// Type declarations +// +typedef struct { + UINT8 SetupValue; + UINT16 DeviceType; + UINT8 Class; + UINT8 SubClass; +} EFI_SETUP_BBS_MAP; + +typedef struct { + UINT8 Class; + UINT8 SubClass; +} PCI_CLASS_RECORD; + +typedef struct { + EFI_LEGACY_PIRQ_TABLE_HEADER PirqTable; + EFI_LEGACY_IRQ_ROUTING_ENTRY IrqRoutingEntry[MAX_IRQ_ROUTING_ENTRIES]; +} EFI_LEGACY_PIRQ_TABLE; + +typedef struct { + EFI_HANDLE Handle; + UINT16 Vid; + UINT16 Did; + UINT16 SvId; + UINT16 SysId; +} DEVICE_STRUCTURE; + +typedef struct { + EFI_GUID FileName; + UINTN Valid; +} SYSTEM_ROM_TABLE; + +typedef struct { + UINT32 Signature; + EFI_HANDLE Handle; + EFI_LEGACY_BIOS_PLATFORM_PROTOCOL LegacyBiosPlatform; + EFI_HANDLE ImageHandle; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; +} LEGACY_BIOS_PLATFORM_INSTANCE; + +#define LEGACY_BIOS_PLATFORM_INSTANCE_SIGNATURE SIGNATURE_32('P','B','I','O') + +#define LEGACY_BIOS_PLATFORM_INSTANCE_FROM_THIS(this) \ + CR (this, \ + LEGACY_BIOS_PLATFORM_INSTANCE, \ + LegacyBiosPlatform, \ + LEGACY_BIOS_PLATFORM_INSTANCE_SIGNATURE \ + ) + +#endif + diff --git a/OvmfPkg/Csm/CsmSupportLib/LegacyRegion.c b/OvmfPkg/Csm/CsmSupportLib/LegacyRegion.c new file mode 100644 index 0000000000..44d340be68 --- /dev/null +++ b/OvmfPkg/Csm/CsmSupportLib/LegacyRegion.c @@ -0,0 +1,466 @@ +/** @file + Legacy Region Support + + Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are + licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "LegacyRegion.h" + +// +// 440 PAM map. +// +// PAM Range Offset Bits Operation +// =============== ====== ==== =============================================================== +// 0xC0000-0xC3FFF 0x5a 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal +// 0xC4000-0xC7FFF 0x5a 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal +// 0xC8000-0xCBFFF 0x5b 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal +// 0xCC000-0xCFFFF 0x5b 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal +// 0xD0000-0xD3FFF 0x5c 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal +// 0xD4000-0xD7FFF 0x5c 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal +// 0xD8000-0xDBFFF 0x5d 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal +// 0xDC000-0xDFFFF 0x5d 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal +// 0xE0000-0xE3FFF 0x5e 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal +// 0xE4000-0xE7FFF 0x5e 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal +// 0xE8000-0xEBFFF 0x5f 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal +// 0xEC000-0xEFFFF 0x5f 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal +// 0xF0000-0xFFFFF 0x59 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal +// +STATIC LEGACY_MEMORY_SECTION_INFO mSectionArray[] = { + {0xC0000, SIZE_16KB, FALSE, FALSE}, + {0xC4000, SIZE_16KB, FALSE, FALSE}, + {0xC8000, SIZE_16KB, FALSE, FALSE}, + {0xCC000, SIZE_16KB, FALSE, FALSE}, + {0xD0000, SIZE_16KB, FALSE, FALSE}, + {0xD4000, SIZE_16KB, FALSE, FALSE}, + {0xD8000, SIZE_16KB, FALSE, FALSE}, + {0xDC000, SIZE_16KB, FALSE, FALSE}, + {0xE0000, SIZE_16KB, FALSE, FALSE}, + {0xE4000, SIZE_16KB, FALSE, FALSE}, + {0xE8000, SIZE_16KB, FALSE, FALSE}, + {0xEC000, SIZE_16KB, FALSE, FALSE}, + {0xF0000, SIZE_64KB, FALSE, FALSE} +}; + +STATIC PAM_REGISTER_VALUE mRegisterValues[] = { + {REG_PAM1_OFFSET, 0x01, 0x02}, + {REG_PAM1_OFFSET, 0x10, 0x20}, + {REG_PAM2_OFFSET, 0x01, 0x02}, + {REG_PAM2_OFFSET, 0x10, 0x20}, + {REG_PAM3_OFFSET, 0x01, 0x02}, + {REG_PAM3_OFFSET, 0x10, 0x20}, + {REG_PAM4_OFFSET, 0x01, 0x02}, + {REG_PAM4_OFFSET, 0x10, 0x20}, + {REG_PAM5_OFFSET, 0x01, 0x02}, + {REG_PAM5_OFFSET, 0x10, 0x20}, + {REG_PAM6_OFFSET, 0x01, 0x02}, + {REG_PAM6_OFFSET, 0x10, 0x20}, + {REG_PAM0_OFFSET, 0x10, 0x20} +}; + +// +// Handle used to install the Legacy Region Protocol +// +STATIC EFI_HANDLE mHandle = NULL; + +// +// Instance of the Legacy Region Protocol to install into the handle database +// +STATIC EFI_LEGACY_REGION2_PROTOCOL mLegacyRegion2 = { + LegacyRegion2Decode, + LegacyRegion2Lock, + LegacyRegion2BootLock, + LegacyRegion2Unlock, + LegacyRegionGetInfo +}; + +STATIC +EFI_STATUS +LegacyRegionManipulationInternal ( + IN UINT32 Start, + IN UINT32 Length, + IN BOOLEAN *ReadEnable, + IN BOOLEAN *WriteEnable, + OUT UINT32 *Granularity + ) +{ + UINT32 EndAddress; + UINTN Index; + UINTN StartIndex; + + // + // Validate input parameters. + // + if (Length == 0 || Granularity == NULL) { + return EFI_INVALID_PARAMETER; + } + EndAddress = Start + Length - 1; + if ((Start < PAM_BASE_ADDRESS) || EndAddress > PAM_LIMIT_ADDRESS) { + return EFI_INVALID_PARAMETER; + } + + // + // Loop to find the start PAM. + // + StartIndex = 0; + for (Index = 0; Index < (sizeof(mSectionArray) / sizeof (mSectionArray[0])); Index++) { + if ((Start >= mSectionArray[Index].Start) && (Start < (mSectionArray[Index].Start + mSectionArray[Index].Length))) { + StartIndex = Index; + break; + } + } + ASSERT (Index < (sizeof(mSectionArray) / sizeof (mSectionArray[0]))); + + // + // Program PAM until end PAM is encountered + // + for (Index = StartIndex; Index < (sizeof(mSectionArray) / sizeof (mSectionArray[0])); Index++) { + if (ReadEnable != NULL) { + if (*ReadEnable) { + PciOr8 ( + PCI_LIB_ADDRESS(PAM_PCI_BUS, PAM_PCI_DEV, PAM_PCI_FUNC, mRegisterValues[Index].PAMRegOffset), + mRegisterValues[Index].ReadEnableData + ); + } else { + PciAnd8 ( + PCI_LIB_ADDRESS(PAM_PCI_BUS, PAM_PCI_DEV, PAM_PCI_FUNC, mRegisterValues[Index].PAMRegOffset), + (UINT8) (~mRegisterValues[Index].ReadEnableData) + ); + } + } + if (WriteEnable != NULL) { + if (*WriteEnable) { + PciOr8 ( + PCI_LIB_ADDRESS(PAM_PCI_BUS, PAM_PCI_DEV, PAM_PCI_FUNC, mRegisterValues[Index].PAMRegOffset), + mRegisterValues[Index].WriteEnableData + ); + } else { + PciAnd8 ( + PCI_LIB_ADDRESS(PAM_PCI_BUS, PAM_PCI_DEV, PAM_PCI_FUNC, mRegisterValues[Index].PAMRegOffset), + (UINT8) (~mRegisterValues[Index].WriteEnableData) + ); + } + } + + // + // If the end PAM is encountered, record its length as granularity and jump out. + // + if ((EndAddress >= mSectionArray[Index].Start) && (EndAddress < (mSectionArray[Index].Start + mSectionArray[Index].Length))) { + *Granularity = mSectionArray[Index].Length; + break; + } + } + ASSERT (Index < (sizeof(mSectionArray) / sizeof (mSectionArray[0]))); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +LegacyRegionGetInfoInternal ( + OUT UINT32 *DescriptorCount, + OUT LEGACY_MEMORY_SECTION_INFO **Descriptor + ) +{ + UINTN Index; + UINT8 PamValue; + + // + // Check input parameters + // + if (DescriptorCount == NULL || Descriptor == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Fill in current status of legacy region. + // + *DescriptorCount = sizeof(mSectionArray) / sizeof (mSectionArray[0]); + for (Index = 0; Index < *DescriptorCount; Index++) { + PamValue = PciRead8 (PCI_LIB_ADDRESS(PAM_PCI_BUS, PAM_PCI_DEV, PAM_PCI_FUNC, mRegisterValues[Index].PAMRegOffset)); + mSectionArray[Index].ReadEnabled = FALSE; + if ((PamValue & mRegisterValues[Index].ReadEnableData) != 0) { + mSectionArray[Index].ReadEnabled = TRUE; + } + mSectionArray[Index].WriteEnabled = FALSE; + if ((PamValue & mRegisterValues[Index].WriteEnableData) != 0) { + mSectionArray[Index].WriteEnabled = TRUE; + } + } + + *Descriptor = mSectionArray; + return EFI_SUCCESS; +} + +/** + Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region. + + If the On parameter evaluates to TRUE, this function enables memory reads in the address range + Start to (Start + Length - 1). + If the On parameter evaluates to FALSE, this function disables memory reads in the address range + Start to (Start + Length - 1). + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param Start[in] The beginning of the physical address of the region whose attributes + should be modified. + @param Length[in] The number of bytes of memory whose attributes should be modified. + The actual number of bytes modified may be greater than the number + specified. + @param Granularity[out] The number of bytes in the last region affected. This may be less + than the total number of bytes affected if the starting address + was not aligned to a region's starting address or if the length + was greater than the number of bytes in the first region. + @param On[in] Decode / Non-Decode flag. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegion2Decode ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + IN UINT32 Start, + IN UINT32 Length, + OUT UINT32 *Granularity, + IN BOOLEAN *On + ) +{ + return LegacyRegionManipulationInternal (Start, Length, On, NULL, Granularity); +} + + +/** + Modify the hardware to disallow memory attribute changes in a region. + + This function makes the attributes of a region read only. Once a region is boot-locked with this + function, the read and write attributes of that region cannot be changed until a power cycle has + reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect. + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param Start[in] The beginning of the physical address of the region whose + attributes should be modified. + @param Length[in] The number of bytes of memory whose attributes should be modified. + The actual number of bytes modified may be greater than the number + specified. + @param Granularity[out] The number of bytes in the last region affected. This may be less + than the total number of bytes affected if the starting address was + not aligned to a region's starting address or if the length was + greater than the number of bytes in the first region. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + @retval EFI_UNSUPPORTED The chipset does not support locking the configuration registers in + a way that will not affect memory regions outside the legacy memory + region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegion2BootLock ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + IN UINT32 Start, + IN UINT32 Length, + OUT UINT32 *Granularity + ) +{ + if ((Start < 0xC0000) || ((Start + Length - 1) > 0xFFFFF)) { + return EFI_INVALID_PARAMETER; + } + + return EFI_UNSUPPORTED; +} + + +/** + Modify the hardware to disallow memory writes in a region. + + This function changes the attributes of a memory range to not allow writes. + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param Start[in] The beginning of the physical address of the region whose + attributes should be modified. + @param Length[in] The number of bytes of memory whose attributes should be modified. + The actual number of bytes modified may be greater than the number + specified. + @param Granularity[out] The number of bytes in the last region affected. This may be less + than the total number of bytes affected if the starting address was + not aligned to a region's starting address or if the length was + greater than the number of bytes in the first region. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegion2Lock ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + IN UINT32 Start, + IN UINT32 Length, + OUT UINT32 *Granularity + ) +{ + BOOLEAN WriteEnable; + + WriteEnable = FALSE; + return LegacyRegionManipulationInternal (Start, Length, NULL, &WriteEnable, Granularity); +} + + +/** + Modify the hardware to allow memory writes in a region. + + This function changes the attributes of a memory range to allow writes. + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param Start[in] The beginning of the physical address of the region whose + attributes should be modified. + @param Length[in] The number of bytes of memory whose attributes should be modified. + The actual number of bytes modified may be greater than the number + specified. + @param Granularity[out] The number of bytes in the last region affected. This may be less + than the total number of bytes affected if the starting address was + not aligned to a region's starting address or if the length was + greater than the number of bytes in the first region. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegion2Unlock ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + IN UINT32 Start, + IN UINT32 Length, + OUT UINT32 *Granularity + ) +{ + BOOLEAN WriteEnable; + + WriteEnable = TRUE; + return LegacyRegionManipulationInternal (Start, Length, NULL, &WriteEnable, Granularity); +} + +/** + Get region information for the attributes of the Legacy Region. + + This function is used to discover the granularity of the attributes for the memory in the legacy + region. Each attribute may have a different granularity and the granularity may not be the same + for all memory ranges in the legacy region. + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param DescriptorCount[out] The number of region descriptor entries returned in the Descriptor + buffer. + @param Descriptor[out] A pointer to a pointer used to return a buffer where the legacy + region information is deposited. This buffer will contain a list of + DescriptorCount number of region descriptors. This function will + provide the memory for the buffer. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegionGetInfo ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + OUT UINT32 *DescriptorCount, + OUT EFI_LEGACY_REGION_DESCRIPTOR **Descriptor + ) +{ + LEGACY_MEMORY_SECTION_INFO *SectionInfo; + UINT32 SectionCount; + EFI_LEGACY_REGION_DESCRIPTOR *DescriptorArray; + UINTN Index; + UINTN DescriptorIndex; + + // + // Get section numbers and information + // + LegacyRegionGetInfoInternal (&SectionCount, &SectionInfo); + + // + // Each section has 3 descriptors, corresponding to readability, writeability, and lock status. + // + DescriptorArray = AllocatePool (sizeof (EFI_LEGACY_REGION_DESCRIPTOR) * SectionCount * 3); + if (DescriptorArray == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + DescriptorIndex = 0; + for (Index = 0; Index < SectionCount; Index++) { + DescriptorArray[DescriptorIndex].Start = SectionInfo[Index].Start; + DescriptorArray[DescriptorIndex].Length = SectionInfo[Index].Length; + DescriptorArray[DescriptorIndex].Granularity = SectionInfo[Index].Length; + if (SectionInfo[Index].ReadEnabled) { + DescriptorArray[DescriptorIndex].Attribute = LegacyRegionDecoded; + } else { + DescriptorArray[DescriptorIndex].Attribute = LegacyRegionNotDecoded; + } + DescriptorIndex++; + + // + // Create descriptor for writeability, according to lock status + // + DescriptorArray[DescriptorIndex].Start = SectionInfo[Index].Start; + DescriptorArray[DescriptorIndex].Length = SectionInfo[Index].Length; + DescriptorArray[DescriptorIndex].Granularity = SectionInfo[Index].Length; + if (SectionInfo[Index].WriteEnabled) { + DescriptorArray[DescriptorIndex].Attribute = LegacyRegionWriteEnabled; + } else { + DescriptorArray[DescriptorIndex].Attribute = LegacyRegionWriteDisabled; + } + DescriptorIndex++; + + // + // Chipset does not support bootlock. + // + DescriptorArray[DescriptorIndex].Start = SectionInfo[Index].Start; + DescriptorArray[DescriptorIndex].Length = SectionInfo[Index].Length; + DescriptorArray[DescriptorIndex].Granularity = SectionInfo[Index].Length; + DescriptorArray[DescriptorIndex].Attribute = LegacyRegionNotLocked; + DescriptorIndex++; + } + + *DescriptorCount = (UINT32) DescriptorIndex; + *Descriptor = DescriptorArray; + + return EFI_SUCCESS; +} + +/** + Initialize Legacy Region support + + @retval EFI_SUCCESS Successfully initialized + +**/ +EFI_STATUS +LegacyRegionInit ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Install the Legacy Region Protocol on a new handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mHandle, + &gEfiLegacyRegion2ProtocolGuid, &mLegacyRegion2, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + diff --git a/OvmfPkg/Csm/CsmSupportLib/LegacyRegion.h b/OvmfPkg/Csm/CsmSupportLib/LegacyRegion.h new file mode 100644 index 0000000000..805df8656f --- /dev/null +++ b/OvmfPkg/Csm/CsmSupportLib/LegacyRegion.h @@ -0,0 +1,219 @@ +/** @file + Legacy Region Support + + Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are + licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _LEGACY_REGION_DXE_H_ +#define _LEGACY_REGION_DXE_H_ + +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#define PAM_PCI_BUS 0 +#define PAM_PCI_DEV 0 +#define PAM_PCI_FUNC 0 + +#define REG_PAM0_OFFSET 0x59 // Programmable Attribute Map 0 +#define REG_PAM1_OFFSET 0x5a // Programmable Attribute Map 1 +#define REG_PAM2_OFFSET 0x5b // Programmable Attribute Map 2 +#define REG_PAM3_OFFSET 0x5c // Programmable Attribute Map 3 +#define REG_PAM4_OFFSET 0x5d // Programmable Attribute Map 4 +#define REG_PAM5_OFFSET 0x5e // Programmable Attribute Map 5 +#define REG_PAM6_OFFSET 0x5f // Programmable Attribute Map 6 + +#define PAM_BASE_ADDRESS 0xc0000 +#define PAM_LIMIT_ADDRESS BASE_1MB + +// +// Describes Legacy Region blocks and status. +// +typedef struct { + UINT32 Start; + UINT32 Length; + BOOLEAN ReadEnabled; + BOOLEAN WriteEnabled; +} LEGACY_MEMORY_SECTION_INFO; + +// +// Provides a map of the PAM registers and bits used to set Read/Write access. +// +typedef struct { + UINT8 PAMRegOffset; + UINT8 ReadEnableData; + UINT8 WriteEnableData; +} PAM_REGISTER_VALUE; + +/** + Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region. + + If the On parameter evaluates to TRUE, this function enables memory reads in the address range + Start to (Start + Length - 1). + If the On parameter evaluates to FALSE, this function disables memory reads in the address range + Start to (Start + Length - 1). + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param Start[in] The beginning of the physical address of the region whose attributes + should be modified. + @param Length[in] The number of bytes of memory whose attributes should be modified. + The actual number of bytes modified may be greater than the number + specified. + @param Granularity[out] The number of bytes in the last region affected. This may be less + than the total number of bytes affected if the starting address + was not aligned to a region's starting address or if the length + was greater than the number of bytes in the first region. + @param On[in] Decode / Non-Decode flag. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegion2Decode ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + IN UINT32 Start, + IN UINT32 Length, + OUT UINT32 *Granularity, + IN BOOLEAN *On + ); + +/** + Modify the hardware to disallow memory writes in a region. + + This function changes the attributes of a memory range to not allow writes. + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param Start[in] The beginning of the physical address of the region whose + attributes should be modified. + @param Length[in] The number of bytes of memory whose attributes should be modified. + The actual number of bytes modified may be greater than the number + specified. + @param Granularity[out] The number of bytes in the last region affected. This may be less + than the total number of bytes affected if the starting address was + not aligned to a region's starting address or if the length was + greater than the number of bytes in the first region. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegion2Lock ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + IN UINT32 Start, + IN UINT32 Length, + OUT UINT32 *Granularity + ); + +/** + Modify the hardware to disallow memory attribute changes in a region. + + This function makes the attributes of a region read only. Once a region is boot-locked with this + function, the read and write attributes of that region cannot be changed until a power cycle has + reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect. + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param Start[in] The beginning of the physical address of the region whose + attributes should be modified. + @param Length[in] The number of bytes of memory whose attributes should be modified. + The actual number of bytes modified may be greater than the number + specified. + @param Granularity[out] The number of bytes in the last region affected. This may be less + than the total number of bytes affected if the starting address was + not aligned to a region's starting address or if the length was + greater than the number of bytes in the first region. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + @retval EFI_UNSUPPORTED The chipset does not support locking the configuration registers in + a way that will not affect memory regions outside the legacy memory + region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegion2BootLock ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + IN UINT32 Start, + IN UINT32 Length, + OUT UINT32 *Granularity + ); + +/** + Modify the hardware to allow memory writes in a region. + + This function changes the attributes of a memory range to allow writes. + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param Start[in] The beginning of the physical address of the region whose + attributes should be modified. + @param Length[in] The number of bytes of memory whose attributes should be modified. + The actual number of bytes modified may be greater than the number + specified. + @param Granularity[out] The number of bytes in the last region affected. This may be less + than the total number of bytes affected if the starting address was + not aligned to a region's starting address or if the length was + greater than the number of bytes in the first region. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegion2Unlock ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + IN UINT32 Start, + IN UINT32 Length, + OUT UINT32 *Granularity + ); + +/** + Get region information for the attributes of the Legacy Region. + + This function is used to discover the granularity of the attributes for the memory in the legacy + region. Each attribute may have a different granularity and the granularity may not be the same + for all memory ranges in the legacy region. + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param DescriptorCount[out] The number of region descriptor entries returned in the Descriptor + buffer. + @param Descriptor[out] A pointer to a pointer used to return a buffer where the legacy + region information is deposited. This buffer will contain a list of + DescriptorCount number of region descriptors. This function will + provide the memory for the buffer. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegionGetInfo ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + OUT UINT32 *DescriptorCount, + OUT EFI_LEGACY_REGION_DESCRIPTOR **Descriptor + ); + +#endif + diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index f6413c2b6f..b85bb1d1fd 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -322,6 +322,9 @@ IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf { TimerLib|OvmfPkg/Library/AcpiTimerLib/AcpiTimerLib.inf +!ifdef $(CSM_ENABLE) + NULL|OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.inf +!endif } OvmfPkg/BlockMmioToBlockIoDxe/BlockIo.inf diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc index a6767280e3..04d8aeb748 100644 --- a/OvmfPkg/OvmfPkgIa32X64.dsc +++ b/OvmfPkg/OvmfPkgIa32X64.dsc @@ -324,6 +324,9 @@ IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf { TimerLib|OvmfPkg/Library/AcpiTimerLib/AcpiTimerLib.inf +!ifdef $(CSM_ENABLE) + NULL|OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.inf +!endif } OvmfPkg/BlockMmioToBlockIoDxe/BlockIo.inf diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc index 83c399cfc7..75d48480ab 100644 --- a/OvmfPkg/OvmfPkgX64.dsc +++ b/OvmfPkg/OvmfPkgX64.dsc @@ -323,6 +323,9 @@ IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf { TimerLib|OvmfPkg/Library/AcpiTimerLib/AcpiTimerLib.inf +!ifdef $(CSM_ENABLE) + NULL|OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.inf +!endif } OvmfPkg/BlockMmioToBlockIoDxe/BlockIo.inf -- 2.39.2