audk/OvmfPkg/Csm/CsmSupportLib/LegacyPlatform.c

1087 lines
36 KiB
C

/** @file
Legacy BIOS Platform support
Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#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. This 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)) {
//
// Determine 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 ((
DEBUG_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
// configuration.
//
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 interrupts, 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;
}