/** @file | |
Legacy BIOS Platform support | |
Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> | |
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. 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)) { | |
// | |
// 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; | |
} | |