blob: dd75be00f676095c56246460b14d1412b47ec404 [file] [log] [blame]
/** @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;
}