blob: 83d94cf2892b865aaae4e7e351577c3236417214 [file] [log] [blame]
/** @file
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "LegacyBiosInterface.h"
#include <IndustryStandard/Pci.h>
#define BOOT_LEGACY_OS 0
#define BOOT_EFI_OS 1
#define BOOT_UNCONVENTIONAL_DEVICE 2
UINT32 mLoadOptionsSize = 0;
UINTN mBootMode = BOOT_LEGACY_OS;
VOID *mLoadOptions = NULL;
BBS_BBS_DEVICE_PATH *mBbsDevicePathPtr = NULL;
BBS_BBS_DEVICE_PATH mBbsDevicePathNode;
UDC_ATTRIBUTES mAttributes = { 0, 0, 0, 0 };
UINTN mBbsEntry = 0;
VOID *mBeerData = NULL;
VOID *mServiceAreaData = NULL;
UINT64 mLowWater = 0xffffffffffffffffULL;
extern BBS_TABLE *mBbsTable;
extern VOID *mRuntimeSmbiosEntryPoint;
extern EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint;
extern EFI_PHYSICAL_ADDRESS mStructureTableAddress;
/**
Print the BBS Table.
@param BbsTable The BBS table.
**/
VOID
PrintBbsTable (
IN BBS_TABLE *BbsTable
)
{
UINT16 Index;
UINT16 SubIndex;
CHAR8 *String;
DEBUG ((DEBUG_INFO, "\n"));
DEBUG ((DEBUG_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n"));
DEBUG ((DEBUG_INFO, "=================================================================\n"));
for (Index = 0; Index < MAX_BBS_ENTRIES; Index++) {
//
// Filter
//
if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
continue;
}
DEBUG ((
DEBUG_INFO,
" %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x",
(UINTN)Index,
(UINTN)BbsTable[Index].BootPriority,
(UINTN)BbsTable[Index].Bus,
(UINTN)BbsTable[Index].Device,
(UINTN)BbsTable[Index].Function,
(UINTN)BbsTable[Index].Class,
(UINTN)BbsTable[Index].SubClass,
(UINTN)BbsTable[Index].DeviceType,
(UINTN)*(UINT16 *)&BbsTable[Index].StatusFlags
));
DEBUG ((
DEBUG_INFO,
" %04x:%04x %04x:%04x %04x:%04x",
(UINTN)BbsTable[Index].BootHandlerSegment,
(UINTN)BbsTable[Index].BootHandlerOffset,
(UINTN)BbsTable[Index].MfgStringSegment,
(UINTN)BbsTable[Index].MfgStringOffset,
(UINTN)BbsTable[Index].DescStringSegment,
(UINTN)BbsTable[Index].DescStringOffset
));
//
// Print DescString
//
String = (CHAR8 *)(((UINTN)BbsTable[Index].DescStringSegment << 4) + BbsTable[Index].DescStringOffset);
if (String != NULL) {
DEBUG ((DEBUG_INFO, " ("));
for (SubIndex = 0; String[SubIndex] != 0; SubIndex++) {
DEBUG ((DEBUG_INFO, "%c", String[SubIndex]));
}
DEBUG ((DEBUG_INFO, ")"));
}
DEBUG ((DEBUG_INFO, "\n"));
}
DEBUG ((DEBUG_INFO, "\n"));
return;
}
/**
Print the BBS Table.
@param HddInfo The HddInfo table.
**/
VOID
PrintHddInfo (
IN HDD_INFO *HddInfo
)
{
UINTN Index;
DEBUG ((DEBUG_INFO, "\n"));
for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
DEBUG ((DEBUG_INFO, "Index - %04x\n", Index));
DEBUG ((DEBUG_INFO, " Status - %04x\n", (UINTN)HddInfo[Index].Status));
DEBUG ((DEBUG_INFO, " B/D/F - %02x/%02x/%02x\n", (UINTN)HddInfo[Index].Bus, (UINTN)HddInfo[Index].Device, (UINTN)HddInfo[Index].Function));
DEBUG ((DEBUG_INFO, " Command - %04x\n", HddInfo[Index].CommandBaseAddress));
DEBUG ((DEBUG_INFO, " Control - %04x\n", HddInfo[Index].ControlBaseAddress));
DEBUG ((DEBUG_INFO, " BusMaster - %04x\n", HddInfo[Index].BusMasterAddress));
DEBUG ((DEBUG_INFO, " HddIrq - %02x\n", HddInfo[Index].HddIrq));
DEBUG ((DEBUG_INFO, " IdentifyDrive[0].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[0].Raw[0]));
DEBUG ((DEBUG_INFO, " IdentifyDrive[1].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[1].Raw[0]));
}
DEBUG ((DEBUG_INFO, "\n"));
return;
}
/**
Print the PCI Interrupt Line and Interrupt Pin registers.
**/
VOID
PrintPciInterruptRegister (
VOID
)
{
EFI_STATUS Status;
UINTN Index;
EFI_HANDLE *Handles;
UINTN HandleNum;
EFI_PCI_IO_PROTOCOL *PciIo;
UINT8 Interrupt[2];
UINTN Segment;
UINTN Bus;
UINTN Device;
UINTN Function;
gBS->LocateHandleBuffer (
ByProtocol,
&gEfiPciIoProtocolGuid,
NULL,
&HandleNum,
&Handles
);
Bus = 0;
Device = 0;
Function = 0;
DEBUG ((DEBUG_INFO, "\n"));
DEBUG ((DEBUG_INFO, " bb/dd/ff interrupt line interrupt pin\n"));
DEBUG ((DEBUG_INFO, "======================================\n"));
for (Index = 0; Index < HandleNum; Index++) {
Status = gBS->HandleProtocol (Handles[Index], &gEfiPciIoProtocolGuid, (VOID **)&PciIo);
if (!EFI_ERROR (Status)) {
Status = PciIo->Pci.Read (
PciIo,
EfiPciIoWidthUint8,
PCI_INT_LINE_OFFSET,
2,
Interrupt
);
}
if (!EFI_ERROR (Status)) {
Status = PciIo->GetLocation (
PciIo,
&Segment,
&Bus,
&Device,
&Function
);
}
if (!EFI_ERROR (Status)) {
DEBUG ((
DEBUG_INFO,
" %02x/%02x/%02x 0x%02x 0x%02x\n",
Bus,
Device,
Function,
Interrupt[0],
Interrupt[1]
));
}
}
DEBUG ((DEBUG_INFO, "\n"));
if (Handles != NULL) {
FreePool (Handles);
}
}
/**
Identify drive data must be updated to actual parameters before boot.
@param IdentifyDriveData ATA Identify Data
**/
VOID
UpdateIdentifyDriveData (
IN UINT8 *IdentifyDriveData
);
/**
Update SIO data.
@param Private Legacy BIOS Instance data
@retval EFI_SUCCESS Removable media not present
**/
EFI_STATUS
UpdateSioData (
IN LEGACY_BIOS_INSTANCE *Private
)
{
EFI_STATUS Status;
UINTN Index;
UINTN Index1;
UINT8 LegacyInterrupts[16];
EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable;
UINTN RoutingTableEntries;
EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY *IrqPriorityTable;
UINTN NumberPriorityEntries;
EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
UINT8 HddIrq;
UINT16 LegacyInt;
UINT16 LegMask;
UINT32 Register;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
EFI_ISA_IO_PROTOCOL *IsaIo;
LegacyInt = 0;
HandleBuffer = NULL;
EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
LegacyBiosBuildSioData (Private);
SetMem (LegacyInterrupts, sizeof (LegacyInterrupts), 0);
//
// Create list of legacy interrupts.
//
for (Index = 0; Index < 4; Index++) {
LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Serial[Index].Irq;
}
for (Index = 4; Index < 7; Index++) {
LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Parallel[Index - 4].Irq;
}
LegacyInterrupts[7] = EfiToLegacy16BootTable->SioData.Floppy.Irq;
//
// Get Legacy Hdd IRQs. If native mode treat as PCI
//
for (Index = 0; Index < 2; Index++) {
HddIrq = EfiToLegacy16BootTable->HddInfo[Index].HddIrq;
if ((HddIrq != 0) && ((HddIrq == 15) || (HddIrq == 14))) {
LegacyInterrupts[Index + 8] = HddIrq;
}
}
Private->LegacyBiosPlatform->GetRoutingTable (
Private->LegacyBiosPlatform,
(VOID *)&RoutingTable,
&RoutingTableEntries,
NULL,
NULL,
(VOID **)&IrqPriorityTable,
&NumberPriorityEntries
);
//
// Remove legacy interrupts from the list of PCI interrupts available.
//
for (Index = 0; Index <= 0x0b; Index++) {
for (Index1 = 0; Index1 <= NumberPriorityEntries; Index1++) {
if (LegacyInterrupts[Index] != 0) {
LegacyInt = (UINT16)(LegacyInt | (1 << LegacyInterrupts[Index]));
if (LegacyInterrupts[Index] == IrqPriorityTable[Index1].Irq) {
IrqPriorityTable[Index1].Used = LEGACY_USED;
}
}
}
}
Private->Legacy8259->GetMask (
Private->Legacy8259,
&LegMask,
NULL,
NULL,
NULL
);
//
// Set SIO interrupts and disable mouse. Let mouse driver
// re-enable it.
//
LegMask = (UINT16)((LegMask &~LegacyInt) | 0x1000);
Private->Legacy8259->SetMask (
Private->Legacy8259,
&LegMask,
NULL,
NULL,
NULL
);
//
// Disable mouse in keyboard controller
//
Register = 0xA7;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiIsaIoProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
return Status;
}
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiIsaIoProtocolGuid,
(VOID **)&IsaIo
);
ASSERT_EFI_ERROR (Status);
IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, 0x64, 1, &Register);
}
if (HandleBuffer != NULL) {
FreePool (HandleBuffer);
}
return EFI_SUCCESS;
}
/**
Identify drive data must be updated to actual parameters before boot.
This requires updating the checksum, if it exists.
@param IdentifyDriveData ATA Identify Data
@param Checksum checksum of the ATA Identify Data
@retval EFI_SUCCESS checksum calculated
@retval EFI_SECURITY_VIOLATION IdentifyData invalid
**/
EFI_STATUS
CalculateIdentifyDriveChecksum (
IN UINT8 *IdentifyDriveData,
OUT UINT8 *Checksum
)
{
UINTN Index;
UINT8 LocalChecksum;
LocalChecksum = 0;
*Checksum = 0;
if (IdentifyDriveData[510] != 0xA5) {
return EFI_SECURITY_VIOLATION;
}
for (Index = 0; Index < 512; Index++) {
LocalChecksum = (UINT8)(LocalChecksum + IdentifyDriveData[Index]);
}
*Checksum = LocalChecksum;
return EFI_SUCCESS;
}
/**
Identify drive data must be updated to actual parameters before boot.
@param IdentifyDriveData ATA Identify Data
**/
VOID
UpdateIdentifyDriveData (
IN UINT8 *IdentifyDriveData
)
{
UINT16 NumberCylinders;
UINT16 NumberHeads;
UINT16 NumberSectorsTrack;
UINT32 CapacityInSectors;
UINT8 OriginalChecksum;
UINT8 FinalChecksum;
EFI_STATUS Status;
ATAPI_IDENTIFY *ReadInfo;
//
// Status indicates if Integrity byte is correct. Checksum should be
// 0 if valid.
//
ReadInfo = (ATAPI_IDENTIFY *)IdentifyDriveData;
Status = CalculateIdentifyDriveChecksum (IdentifyDriveData, &OriginalChecksum);
if (OriginalChecksum != 0) {
Status = EFI_SECURITY_VIOLATION;
}
//
// If NumberCylinders = 0 then do data(Controller present but don drive attached).
//
NumberCylinders = ReadInfo->Raw[1];
if (NumberCylinders != 0) {
ReadInfo->Raw[54] = NumberCylinders;
NumberHeads = ReadInfo->Raw[3];
ReadInfo->Raw[55] = NumberHeads;
NumberSectorsTrack = ReadInfo->Raw[6];
ReadInfo->Raw[56] = NumberSectorsTrack;
//
// Copy Multisector info and set valid bit.
//
ReadInfo->Raw[59] = (UINT16)(ReadInfo->Raw[47] + 0x100);
CapacityInSectors = (UINT32)((UINT32)(NumberCylinders) * (UINT32)(NumberHeads) * (UINT32)(NumberSectorsTrack));
ReadInfo->Raw[57] = (UINT16)(CapacityInSectors >> 16);
ReadInfo->Raw[58] = (UINT16)(CapacityInSectors & 0xffff);
if (Status == EFI_SUCCESS) {
//
// Forece checksum byte to 0 and get new checksum.
//
ReadInfo->Raw[255] &= 0xff;
CalculateIdentifyDriveChecksum (IdentifyDriveData, &FinalChecksum);
//
// Force new checksum such that sum is 0.
//
FinalChecksum = (UINT8)((UINT8)0 - FinalChecksum);
ReadInfo->Raw[255] = (UINT16)(ReadInfo->Raw[255] | (FinalChecksum << 8));
}
}
}
/**
Identify drive data must be updated to actual parameters before boot.
Do for all drives.
@param Private Legacy BIOS Instance data
**/
VOID
UpdateAllIdentifyDriveData (
IN LEGACY_BIOS_INSTANCE *Private
)
{
UINTN Index;
HDD_INFO *HddInfo;
HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];
for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
//
// Each controller can have 2 devices. Update for each device
//
if ((HddInfo[Index].Status & HDD_MASTER_IDE) != 0) {
UpdateIdentifyDriveData ((UINT8 *)(&HddInfo[Index].IdentifyDrive[0].Raw[0]));
}
if ((HddInfo[Index].Status & HDD_SLAVE_IDE) != 0) {
UpdateIdentifyDriveData ((UINT8 *)(&HddInfo[Index].IdentifyDrive[1].Raw[0]));
}
}
}
/**
Enable ide controller. This gets disabled when LegacyBoot.c is about
to run the Option ROMs.
@param Private Legacy BIOS Instance data
**/
VOID
EnableIdeController (
IN LEGACY_BIOS_INSTANCE *Private
)
{
EFI_PCI_IO_PROTOCOL *PciIo;
EFI_STATUS Status;
EFI_HANDLE IdeController;
UINT8 ByteBuffer;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
Status = Private->LegacyBiosPlatform->GetPlatformHandle (
Private->LegacyBiosPlatform,
EfiGetPlatformIdeHandle,
0,
&HandleBuffer,
&HandleCount,
NULL
);
if (!EFI_ERROR (Status)) {
IdeController = HandleBuffer[0];
Status = gBS->HandleProtocol (
IdeController,
&gEfiPciIoProtocolGuid,
(VOID **)&PciIo
);
ByteBuffer = 0x1f;
if (!EFI_ERROR (Status)) {
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x04, 1, &ByteBuffer);
}
}
}
/**
Enable ide controller. This gets disabled when LegacyBoot.c is about
to run the Option ROMs.
@param Private Legacy BIOS Instance data
**/
VOID
EnableAllControllers (
IN LEGACY_BIOS_INSTANCE *Private
)
{
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
UINTN Index;
EFI_PCI_IO_PROTOCOL *PciIo;
PCI_TYPE01 PciConfigHeader;
EFI_STATUS Status;
//
//
//
EnableIdeController (Private);
//
// Assumption is table is built from low bus to high bus numbers.
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiPciIoProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
ASSERT_EFI_ERROR (Status);
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiPciIoProtocolGuid,
(VOID **)&PciIo
);
ASSERT_EFI_ERROR (Status);
PciIo->Pci.Read (
PciIo,
EfiPciIoWidthUint32,
0,
sizeof (PciConfigHeader) / sizeof (UINT32),
&PciConfigHeader
);
//
// We do not enable PPB here. This is for HotPlug Consideration.
// The Platform HotPlug Driver is responsible for Padding enough hot plug
// resources. It is also responsible for enable this bridge. If it
// does not pad it. It will cause some early Windows fail to installation.
// If the platform driver does not pad resource for PPB, PPB should be in
// un-enabled state to let Windows know that this PPB is not configured by
// BIOS. So Windows will allocate default resource for PPB.
//
// The reason for why we enable the command register is:
// The CSM will use the IO bar to detect some IRQ status, if the command
// is disabled, the IO resource will be out of scope.
// For example:
// We installed a legacy IRQ handle for a PCI IDE controller. When IRQ
// comes up, the handle will check the IO space to identify is the
// controller generated the IRQ source.
// If the IO command is not enabled, the IRQ handler will has wrong
// information. It will cause IRQ storm when the correctly IRQ handler fails
// to run.
//
if (!(IS_PCI_VGA (&PciConfigHeader) ||
IS_PCI_OLD_VGA (&PciConfigHeader) ||
IS_PCI_IDE (&PciConfigHeader) ||
IS_PCI_P2P (&PciConfigHeader) ||
IS_PCI_P2P_SUB (&PciConfigHeader) ||
IS_PCI_LPC (&PciConfigHeader)))
{
PciConfigHeader.Hdr.Command |= 0x1f;
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 4, 1, &PciConfigHeader.Hdr.Command);
}
}
}
/**
The following routines are identical in operation, so combine
for code compaction:
EfiGetPlatformBinaryGetMpTable
EfiGetPlatformBinaryGetOemIntData
EfiGetPlatformBinaryGetOem32Data
EfiGetPlatformBinaryGetOem16Data
@param This Protocol instance pointer.
@param Id Table/Data identifier
@retval EFI_SUCCESS Success
@retval EFI_INVALID_PARAMETER Invalid ID
@retval EFI_OUT_OF_RESOURCES no resource to get data or table
**/
EFI_STATUS
LegacyGetDataOrTable (
IN EFI_LEGACY_BIOS_PROTOCOL *This,
IN EFI_GET_PLATFORM_INFO_MODE Id
)
{
VOID *Table;
UINT32 TablePtr;
UINTN TableSize;
UINTN Alignment;
UINTN Location;
EFI_STATUS Status;
EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
EFI_COMPATIBILITY16_TABLE *Legacy16Table;
EFI_IA32_REGISTER_SET Regs;
LEGACY_BIOS_INSTANCE *Private;
Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
LegacyBiosPlatform = Private->LegacyBiosPlatform;
Legacy16Table = Private->Legacy16Table;
//
// Phase 1 - get an address allocated in 16-bit code
//
while (TRUE) {
switch (Id) {
case EfiGetPlatformBinaryMpTable:
case EfiGetPlatformBinaryOemIntData:
case EfiGetPlatformBinaryOem32Data:
case EfiGetPlatformBinaryOem16Data:
{
Status = LegacyBiosPlatform->GetPlatformInfo (
LegacyBiosPlatform,
Id,
(VOID *)&Table,
&TableSize,
&Location,
&Alignment,
0,
0
);
DEBUG ((DEBUG_INFO, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN)Id, Status));
DEBUG ((DEBUG_INFO, " Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN)Table, (UINTN)TableSize, (UINTN)Location, (UINTN)Alignment));
break;
}
default:
{
return EFI_INVALID_PARAMETER;
}
}
if (EFI_ERROR (Status)) {
return Status;
}
ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
Regs.X.AX = Legacy16GetTableAddress;
Regs.X.CX = (UINT16)TableSize;
Regs.X.BX = (UINT16)Location;
Regs.X.DX = (UINT16)Alignment;
Private->LegacyBios.FarCall86 (
This,
Private->Legacy16CallSegment,
Private->Legacy16CallOffset,
&Regs,
NULL,
0
);
if (Regs.X.AX != 0) {
DEBUG ((DEBUG_ERROR, "Table ID %x length insufficient\n", Id));
return EFI_OUT_OF_RESOURCES;
} else {
break;
}
}
//
// Phase 2 Call routine second time with address to allow address adjustment
//
Status = LegacyBiosPlatform->GetPlatformInfo (
LegacyBiosPlatform,
Id,
(VOID *)&Table,
&TableSize,
&Location,
&Alignment,
Regs.X.DS,
Regs.X.BX
);
switch (Id) {
case EfiGetPlatformBinaryMpTable:
{
Legacy16Table->MpTablePtr = (UINT32)(Regs.X.DS * 16 + Regs.X.BX);
Legacy16Table->MpTableLength = (UINT32)TableSize;
DEBUG ((DEBUG_INFO, "MP table in legacy region - %x\n", (UINTN)Legacy16Table->MpTablePtr));
break;
}
case EfiGetPlatformBinaryOemIntData:
{
Legacy16Table->OemIntSegment = Regs.X.DS;
Legacy16Table->OemIntOffset = Regs.X.BX;
DEBUG ((DEBUG_INFO, "OemInt table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->OemIntSegment, (UINTN)Legacy16Table->OemIntOffset));
break;
}
case EfiGetPlatformBinaryOem32Data:
{
Legacy16Table->Oem32Segment = Regs.X.DS;
Legacy16Table->Oem32Offset = Regs.X.BX;
DEBUG ((DEBUG_INFO, "Oem32 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem32Segment, (UINTN)Legacy16Table->Oem32Offset));
break;
}
case EfiGetPlatformBinaryOem16Data:
{
//
// Legacy16Table->Oem16Segment = Regs.X.DS;
// Legacy16Table->Oem16Offset = Regs.X.BX;
DEBUG ((DEBUG_INFO, "Oem16 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem16Segment, (UINTN)Legacy16Table->Oem16Offset));
break;
}
default:
{
return EFI_INVALID_PARAMETER;
}
}
if (EFI_ERROR (Status)) {
return Status;
}
//
// Phase 3 Copy table to final location
//
TablePtr = (UINT32)(Regs.X.DS * 16 + Regs.X.BX);
CopyMem (
(VOID *)(UINTN)TablePtr,
Table,
TableSize
);
return EFI_SUCCESS;
}
/**
Copy SMBIOS table to EfiReservedMemoryType of memory for legacy boot.
**/
VOID
CreateSmbiosTableInReservedMemory (
VOID
)
{
SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure;
if ((mRuntimeSmbiosEntryPoint == NULL) ||
(mReserveSmbiosEntryPoint == 0) ||
(mStructureTableAddress == 0))
{
return;
}
EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *)mRuntimeSmbiosEntryPoint;
//
// Copy SMBIOS Entry Point Structure
//
CopyMem (
(VOID *)(UINTN)mReserveSmbiosEntryPoint,
EntryPointStructure,
EntryPointStructure->EntryPointLength
);
//
// Copy SMBIOS Structure Table into EfiReservedMemoryType memory
//
CopyMem (
(VOID *)(UINTN)mStructureTableAddress,
(VOID *)(UINTN)EntryPointStructure->TableAddress,
EntryPointStructure->TableLength
);
//
// Update TableAddress in Entry Point Structure
//
EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN)mReserveSmbiosEntryPoint;
EntryPointStructure->TableAddress = (UINT32)(UINTN)mStructureTableAddress;
//
// Fixup checksums in the Entry Point Structure
//
EntryPointStructure->IntermediateChecksum = 0;
EntryPointStructure->EntryPointStructureChecksum = 0;
EntryPointStructure->IntermediateChecksum =
CalculateCheckSum8 (
(UINT8 *)EntryPointStructure + OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString),
EntryPointStructure->EntryPointLength - OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString)
);
EntryPointStructure->EntryPointStructureChecksum =
CalculateCheckSum8 ((UINT8 *)EntryPointStructure, EntryPointStructure->EntryPointLength);
}
/**
Assign drive number to legacy HDD drives prior to booting an EFI
aware OS so the OS can access drives without an EFI driver.
Note: BBS compliant drives ARE NOT available until this call by
either shell or EFI.
@param This Protocol instance pointer.
@retval EFI_SUCCESS Drive numbers assigned
**/
EFI_STATUS
GenericLegacyBoot (
IN EFI_LEGACY_BIOS_PROTOCOL *This
)
{
EFI_STATUS Status;
LEGACY_BIOS_INSTANCE *Private;
EFI_IA32_REGISTER_SET Regs;
EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
UINTN CopySize;
VOID *AcpiPtr;
HDD_INFO *HddInfo;
HDD_INFO *LocalHddInfo;
UINTN Index;
EFI_COMPATIBILITY16_TABLE *Legacy16Table;
UINT32 *BdaPtr;
UINT16 HddCount;
UINT16 BbsCount;
BBS_TABLE *LocalBbsTable;
UINT32 *BaseVectorMaster;
EFI_TIME BootTime;
UINT32 LocalTime;
EFI_HANDLE IdeController;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
VOID *AcpiTable;
UINTN ShadowAddress;
UINT32 Granularity;
LocalHddInfo = NULL;
HddCount = 0;
BbsCount = 0;
LocalBbsTable = NULL;
Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
DEBUG_CODE (
DEBUG ((DEBUG_ERROR, "Start of legacy boot\n"));
);
Legacy16Table = Private->Legacy16Table;
EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
HddInfo = &EfiToLegacy16BootTable->HddInfo[0];
LegacyBiosPlatform = Private->LegacyBiosPlatform;
EfiToLegacy16BootTable->MajorVersion = EFI_TO_LEGACY_MAJOR_VERSION;
EfiToLegacy16BootTable->MinorVersion = EFI_TO_LEGACY_MINOR_VERSION;
//
// If booting to a legacy OS then force HDD drives to the appropriate
// boot mode by calling GetIdeHandle.
// A reconnect -r can force all HDDs back to native mode.
//
IdeController = NULL;
if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
Status = LegacyBiosPlatform->GetPlatformHandle (
Private->LegacyBiosPlatform,
EfiGetPlatformIdeHandle,
0,
&HandleBuffer,
&HandleCount,
NULL
);
if (!EFI_ERROR (Status)) {
IdeController = HandleBuffer[0];
}
}
//
// Unlock the Legacy BIOS region
//
Private->LegacyRegion->UnLock (
Private->LegacyRegion,
0xE0000,
0x20000,
&Granularity
);
//
// Reconstruct the Legacy16 boot memory map
//
LegacyBiosBuildE820 (Private, &CopySize);
if (CopySize > Private->Legacy16Table->E820Length) {
ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
Regs.X.AX = Legacy16GetTableAddress;
Regs.X.BX = (UINT16)0x0; // Any region
Regs.X.CX = (UINT16)CopySize;
Regs.X.DX = (UINT16)0x4; // Alignment
Private->LegacyBios.FarCall86 (
&Private->LegacyBios,
Private->Legacy16Table->Compatibility16CallSegment,
Private->Legacy16Table->Compatibility16CallOffset,
&Regs,
NULL,
0
);
Private->Legacy16Table->E820Pointer = (UINT32)(Regs.X.DS * 16 + Regs.X.BX);
Private->Legacy16Table->E820Length = (UINT32)CopySize;
if (Regs.X.AX != 0) {
DEBUG ((DEBUG_ERROR, "Legacy16 E820 length insufficient\n"));
return EFI_OUT_OF_RESOURCES;
} else {
CopyMem (
(VOID *)(UINTN)Private->Legacy16Table->E820Pointer,
Private->E820Table,
CopySize
);
}
} else {
CopyMem (
(VOID *)(UINTN)Private->Legacy16Table->E820Pointer,
Private->E820Table,
CopySize
);
Private->Legacy16Table->E820Length = (UINT32)CopySize;
}
//
// We do not ASSERT if SmbiosTable not found. It is possible that a platform does not produce SmbiosTable.
//
if (mReserveSmbiosEntryPoint == 0) {
DEBUG ((DEBUG_INFO, "Smbios table is not found!\n"));
}
CreateSmbiosTableInReservedMemory ();
EfiToLegacy16BootTable->SmbiosTable = (UINT32)(UINTN)mReserveSmbiosEntryPoint;
AcpiTable = NULL;
Status = EfiGetSystemConfigurationTable (
&gEfiAcpi20TableGuid,
&AcpiTable
);
if (EFI_ERROR (Status)) {
Status = EfiGetSystemConfigurationTable (
&gEfiAcpi10TableGuid,
&AcpiTable
);
}
//
// We do not ASSERT if AcpiTable not found. It is possible that a platform does not produce AcpiTable.
//
if (AcpiTable == NULL) {
DEBUG ((DEBUG_INFO, "ACPI table is not found!\n"));
}
EfiToLegacy16BootTable->AcpiTable = (UINT32)(UINTN)AcpiTable;
//
// Get RSD Ptr table rev at offset 15 decimal
// Rev = 0 Length is 20 decimal
// Rev != 0 Length is UINT32 at offset 20 decimal
//
if (AcpiTable != NULL) {
AcpiPtr = AcpiTable;
if (*((UINT8 *)AcpiPtr + 15) == 0) {
CopySize = 20;
} else {
AcpiPtr = ((UINT8 *)AcpiPtr + 20);
CopySize = (*(UINT32 *)AcpiPtr);
}
CopyMem (
(VOID *)(UINTN)Private->Legacy16Table->AcpiRsdPtrPointer,
AcpiTable,
CopySize
);
}
//
// Make sure all PCI Interrupt Line register are programmed to match 8259
//
PciProgramAllInterruptLineRegisters (Private);
//
// Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters
// can lock it.
//
Private->LegacyRegion->UnLock (
Private->LegacyRegion,
Private->BiosStart,
Private->LegacyBiosImageSize,
&Granularity
);
//
// Configure Legacy Device Magic
//
// Only do this code if booting legacy OS
//
if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
UpdateSioData (Private);
}
//
// Setup BDA and EBDA standard areas before Legacy Boot
//
ACCESS_PAGE0_CODE (
LegacyBiosCompleteBdaBeforeBoot (Private);
);
LegacyBiosCompleteStandardCmosBeforeBoot (Private);
//
// We must build IDE data, if it hasn't been done, before PciShadowRoms
// to insure EFI drivers are connected.
//
LegacyBiosBuildIdeData (Private, &HddInfo, 1);
UpdateAllIdentifyDriveData (Private);
//
// Clear IO BAR, if IDE controller in legacy mode.
//
InitLegacyIdeController (IdeController);
//
// Generate number of ticks since midnight for BDA. DOS requires this
// for its time. We have to make assumptions as to how long following
// code takes since after PciShadowRoms PciIo is gone. Place result in
// 40:6C-6F
//
// Adjust value by 1 second.
//
gRT->GetTime (&BootTime, NULL);
LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;
LocalTime += 1;
//
// Multiply result by 18.2 for number of ticks since midnight.
// Use 182/10 to avoid floating point math.
//
LocalTime = (LocalTime * 182) / 10;
ACCESS_PAGE0_CODE (
BdaPtr = (UINT32 *)(UINTN)0x46C;
*BdaPtr = LocalTime;
);
//
// Shadow PCI ROMs. We must do this near the end since this will kick
// of Native EFI drivers that may be needed to collect info for Legacy16
//
// WARNING: PciIo is gone after this call.
//
PciShadowRoms (Private);
//
// Shadow PXE base code, BIS etc.
//
Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);
ShadowAddress = Private->OptionRom;
Private->LegacyBiosPlatform->PlatformHooks (
Private->LegacyBiosPlatform,
EfiPlatformHookShadowServiceRoms,
0,
0,
&ShadowAddress,
Legacy16Table,
NULL
);
Private->OptionRom = (UINT32)ShadowAddress;
//
// Register Legacy SMI Handler
//
LegacyBiosPlatform->SmmInit (
LegacyBiosPlatform,
EfiToLegacy16BootTable
);
//
// Let platform code know the boot options
//
LegacyBiosGetBbsInfo (
This,
&HddCount,
&LocalHddInfo,
&BbsCount,
&LocalBbsTable
);
DEBUG_CODE (
PrintPciInterruptRegister ();
PrintBbsTable (LocalBbsTable);
PrintHddInfo (LocalHddInfo);
);
//
// If drive wasn't spun up then BuildIdeData may have found new drives.
// Need to update BBS boot priority.
//
for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
if ((LocalHddInfo[Index].IdentifyDrive[0].Raw[0] != 0) &&
(LocalBbsTable[2 * Index + 1].BootPriority == BBS_IGNORE_ENTRY)
)
{
LocalBbsTable[2 * Index + 1].BootPriority = BBS_UNPRIORITIZED_ENTRY;
}
if ((LocalHddInfo[Index].IdentifyDrive[1].Raw[0] != 0) &&
(LocalBbsTable[2 * Index + 2].BootPriority == BBS_IGNORE_ENTRY)
)
{
LocalBbsTable[2 * Index + 2].BootPriority = BBS_UNPRIORITIZED_ENTRY;
}
}
Private->LegacyRegion->UnLock (
Private->LegacyRegion,
0xc0000,
0x40000,
&Granularity
);
LegacyBiosPlatform->PrepareToBoot (
LegacyBiosPlatform,
mBbsDevicePathPtr,
mBbsTable,
mLoadOptionsSize,
mLoadOptions,
(VOID *)&Private->IntThunk->EfiToLegacy16BootTable
);
//
// If no boot device return to BDS
//
if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
for (Index = 0; Index < BbsCount; Index++) {
if ((LocalBbsTable[Index].BootPriority != BBS_DO_NOT_BOOT_FROM) &&
(LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) &&
(LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY))
{
break;
}
}
if (Index == BbsCount) {
return EFI_DEVICE_ERROR;
}
}
//
// Let the Legacy16 code know the device path type for legacy boot
//
EfiToLegacy16BootTable->DevicePathType = mBbsDevicePathPtr->DeviceType;
//
// Copy MP table, if it exists.
//
LegacyGetDataOrTable (This, EfiGetPlatformBinaryMpTable);
if (!Private->LegacyBootEntered) {
//
// Copy OEM INT Data, if it exists. Note: This code treats any data
// as a bag of bits and knows nothing of the contents nor cares.
// Contents are IBV specific.
//
LegacyGetDataOrTable (This, EfiGetPlatformBinaryOemIntData);
//
// Copy OEM16 Data, if it exists.Note: This code treats any data
// as a bag of bits and knows nothing of the contents nor cares.
// Contents are IBV specific.
//
LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem16Data);
//
// Copy OEM32 Data, if it exists.Note: This code treats any data
// as a bag of bits and knows nothing of the contents nor cares.
// Contents are IBV specific.
//
LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem32Data);
}
//
// Call into Legacy16 code to prepare for INT 19h
//
ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
Regs.X.AX = Legacy16PrepareToBoot;
//
// Pass in handoff data
//
Regs.X.ES = NORMALIZE_EFI_SEGMENT ((UINTN)EfiToLegacy16BootTable);
Regs.X.BX = NORMALIZE_EFI_OFFSET ((UINTN)EfiToLegacy16BootTable);
Private->LegacyBios.FarCall86 (
This,
Private->Legacy16CallSegment,
Private->Legacy16CallOffset,
&Regs,
NULL,
0
);
if (Regs.X.AX != 0) {
return EFI_DEVICE_ERROR;
}
//
// Lock the Legacy BIOS region
//
Private->LegacyRegion->Lock (
Private->LegacyRegion,
0xc0000,
0x40000,
&Granularity
);
if ((Private->Legacy16Table->TableLength >= OFFSET_OF (EFI_COMPATIBILITY16_TABLE, HiPermanentMemoryAddress)) &&
((Private->Legacy16Table->UmaAddress != 0) && (Private->Legacy16Table->UmaSize != 0)))
{
//
// Here we could reduce UmaAddress down as far as Private->OptionRom, taking into
// account the granularity of the access control.
//
DEBUG ((
DEBUG_INFO,
"Unlocking UMB RAM region 0x%x-0x%x\n",
Private->Legacy16Table->UmaAddress,
Private->Legacy16Table->UmaAddress + Private->Legacy16Table->UmaSize
));
Private->LegacyRegion->UnLock (
Private->LegacyRegion,
Private->Legacy16Table->UmaAddress,
Private->Legacy16Table->UmaSize,
&Granularity
);
}
//
// Lock attributes of the Legacy Region if chipset supports
//
Private->LegacyRegion->BootLock (
Private->LegacyRegion,
0xc0000,
0x40000,
&Granularity
);
//
// Call into Legacy16 code to do the INT 19h
//
EnableAllControllers (Private);
if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
//
// Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT
//
EfiSignalEventLegacyBoot ();
//
// Report Status Code to indicate legacy boot event was signalled
//
REPORT_STATUS_CODE (
EFI_PROGRESS_CODE,
(EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT)
);
DEBUG ((DEBUG_INFO, "Legacy INT19 Boot...\n"));
//
// Disable DXE Timer while executing in real mode
//
Private->Timer->SetTimerPeriod (Private->Timer, 0);
//
// Save and disable interrupt of debug timer
//
SaveAndSetDebugTimerInterrupt (FALSE);
//
// Put the 8259 into its legacy mode by reprogramming the vector bases
//
Private->Legacy8259->SetVectorBase (Private->Legacy8259, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE);
//
// PC History
// The original PC used INT8-F for master PIC. Since these mapped over
// processor exceptions TIANO moved the master PIC to INT68-6F.
// We need to set these back to the Legacy16 unexpected interrupt(saved
// in LegacyBios.c) since some OS see that these have values different from
// what is expected and invoke them. Since the legacy OS corrupts EFI
// memory, there is no handler for these interrupts and OS blows up.
//
// We need to save the TIANO values for the rare case that the Legacy16
// code cannot boot but knows memory hasn't been destroyed.
//
// To compound the problem, video takes over one of these INTS and must be
// be left.
// @bug - determine if video hooks INT(in which case we must find new
// set of TIANO vectors) or takes it over.
//
//
ACCESS_PAGE0_CODE (
BaseVectorMaster = (UINT32 *)(sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
for (Index = 0; Index < 8; Index++) {
Private->ThunkSavedInt[Index] = BaseVectorMaster[Index];
if (Private->ThunkSeg == (UINT16)(BaseVectorMaster[Index] >> 16)) {
BaseVectorMaster[Index] = (UINT32)(Private->BiosUnexpectedInt);
}
}
);
ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
Regs.X.AX = Legacy16Boot;
Private->LegacyBios.FarCall86 (
This,
Private->Legacy16CallSegment,
Private->Legacy16CallOffset,
&Regs,
NULL,
0
);
ACCESS_PAGE0_CODE (
BaseVectorMaster = (UINT32 *)(sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
for (Index = 0; Index < 8; Index++) {
BaseVectorMaster[Index] = Private->ThunkSavedInt[Index];
}
);
}
Private->LegacyBootEntered = TRUE;
if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
//
// Should never return unless never passed control to 0:7c00(first stage
// OS loader) and only then if no bootable device found.
//
return EFI_DEVICE_ERROR;
} else {
//
// If boot to EFI then expect to return to caller
//
return EFI_SUCCESS;
}
}
/**
Assign drive number to legacy HDD drives prior to booting an EFI
aware OS so the OS can access drives without an EFI driver.
Note: BBS compliant drives ARE NOT available until this call by
either shell or EFI.
@param This Protocol instance pointer.
@param BbsCount Number of BBS_TABLE structures
@param BbsTable List BBS entries
@retval EFI_SUCCESS Drive numbers assigned
**/
EFI_STATUS
EFIAPI
LegacyBiosPrepareToBootEfi (
IN EFI_LEGACY_BIOS_PROTOCOL *This,
OUT UINT16 *BbsCount,
OUT BBS_TABLE **BbsTable
)
{
EFI_STATUS Status;
EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
LEGACY_BIOS_INSTANCE *Private;
Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
mBootMode = BOOT_EFI_OS;
mBbsDevicePathPtr = NULL;
Status = GenericLegacyBoot (This);
*BbsTable = (BBS_TABLE *)(UINTN)EfiToLegacy16BootTable->BbsTable;
*BbsCount = (UINT16)(sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE));
return Status;
}
/**
To boot from an unconventional device like parties and/or execute HDD diagnostics.
@param This Protocol instance pointer.
@param Attributes How to interpret the other input parameters
@param BbsEntry The 0-based index into the BbsTable for the parent
device.
@param BeerData Pointer to the 128 bytes of ram BEER data.
@param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The
caller must provide a pointer to the specific Service
Area and not the start all Service Areas.
@retval EFI_INVALID_PARAMETER if error. Does NOT return if no error.
***/
EFI_STATUS
EFIAPI
LegacyBiosBootUnconventionalDevice (
IN EFI_LEGACY_BIOS_PROTOCOL *This,
IN UDC_ATTRIBUTES Attributes,
IN UINTN BbsEntry,
IN VOID *BeerData,
IN VOID *ServiceAreaData
)
{
EFI_STATUS Status;
EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
LEGACY_BIOS_INSTANCE *Private;
UD_TABLE *UcdTable;
UINTN Index;
UINT16 BootPriority;
BBS_TABLE *BbsTable;
BootPriority = 0;
Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
mBootMode = BOOT_UNCONVENTIONAL_DEVICE;
mBbsDevicePathPtr = &mBbsDevicePathNode;
mAttributes = Attributes;
mBbsEntry = BbsEntry;
mBeerData = BeerData, mServiceAreaData = ServiceAreaData;
EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
//
// Do input parameter checking
//
if ((Attributes.DirectoryServiceValidity == 0) &&
(Attributes.RabcaUsedFlag == 0) &&
(Attributes.ExecuteHddDiagnosticsFlag == 0)
)
{
return EFI_INVALID_PARAMETER;
}
if (((Attributes.DirectoryServiceValidity != 0) && (ServiceAreaData == NULL)) ||
(((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag) != 0) && (BeerData == NULL))
)
{
return EFI_INVALID_PARAMETER;
}
UcdTable = (UD_TABLE *)AllocatePool (
sizeof (UD_TABLE)
);
if (NULL == UcdTable) {
return EFI_OUT_OF_RESOURCES;
}
EfiToLegacy16BootTable->UnconventionalDeviceTable = (UINT32)(UINTN)UcdTable;
UcdTable->Attributes = Attributes;
UcdTable->BbsTableEntryNumberForParentDevice = (UINT8)BbsEntry;
//
// Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM
// to assign drive numbers but bot boot from. Only newly created entries
// will be valid.
//
BbsTable = (BBS_TABLE *)(UINTN)EfiToLegacy16BootTable->BbsTable;
for (Index = 0; Index < EfiToLegacy16BootTable->NumberBbsEntries; Index++) {
BbsTable[Index].BootPriority = BBS_DO_NOT_BOOT_FROM;
}
//
// If parent is onboard IDE then assign controller & device number
// else they are 0.
//
if (BbsEntry < MAX_IDE_CONTROLLER * 2) {
UcdTable->DeviceNumber = (UINT8)((BbsEntry - 1) % 2);
}
if (BeerData != NULL) {
CopyMem (
(VOID *)UcdTable->BeerData,
BeerData,
(UINTN)128
);
}
if (ServiceAreaData != NULL) {
CopyMem (
(VOID *)UcdTable->ServiceAreaData,
ServiceAreaData,
(UINTN)64
);
}
//
// For each new entry do the following:
// 1. Increment current number of BBS entries
// 2. Copy parent entry to new entry.
// 3. Zero out BootHandler Offset & segment
// 4. Set appropriate device type. BEV(0x80) for HDD diagnostics
// and Floppy(0x01) for PARTIES boot.
// 5. Assign new priority.
//
if ((Attributes.ExecuteHddDiagnosticsFlag) != 0) {
EfiToLegacy16BootTable->NumberBbsEntries += 1;
CopyMem (
(VOID *)&BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,
(VOID *)&BbsTable[BbsEntry].BootPriority,
sizeof (BBS_TABLE)
);
BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0;
BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;
BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x80;
UcdTable->BbsTableEntryNumberForHddDiag = (UINT8)(EfiToLegacy16BootTable->NumberBbsEntries - 1);
BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;
BootPriority += 1;
//
// Set device type as BBS_TYPE_DEV for PARTIES diagnostic
//
mBbsDevicePathNode.DeviceType = BBS_TYPE_BEV;
}
if (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag)) != 0) {
EfiToLegacy16BootTable->NumberBbsEntries += 1;
CopyMem (
(VOID *)&BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,
(VOID *)&BbsTable[BbsEntry].BootPriority,
sizeof (BBS_TABLE)
);
BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0;
BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;
BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x01;
UcdTable->BbsTableEntryNumberForBoot = (UINT8)(EfiToLegacy16BootTable->NumberBbsEntries - 1);
BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;
//
// Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy
//
mBbsDevicePathNode.DeviceType = BBS_TYPE_FLOPPY;
}
//
// Build the BBS Device Path for this boot selection
//
mBbsDevicePathNode.Header.Type = BBS_DEVICE_PATH;
mBbsDevicePathNode.Header.SubType = BBS_BBS_DP;
SetDevicePathNodeLength (&mBbsDevicePathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));
mBbsDevicePathNode.StatusFlag = 0;
mBbsDevicePathNode.String[0] = 0;
Status = GenericLegacyBoot (This);
return Status;
}
/**
Attempt to legacy boot the BootOption. If the EFI contexted has been
compromised this function will not return.
@param This Protocol instance pointer.
@param BbsDevicePath EFI Device Path from BootXXXX variable.
@param LoadOptionsSize Size of LoadOption in size.
@param LoadOptions LoadOption from BootXXXX variable
@retval EFI_SUCCESS Removable media not present
**/
EFI_STATUS
EFIAPI
LegacyBiosLegacyBoot (
IN EFI_LEGACY_BIOS_PROTOCOL *This,
IN BBS_BBS_DEVICE_PATH *BbsDevicePath,
IN UINT32 LoadOptionsSize,
IN VOID *LoadOptions
)
{
EFI_STATUS Status;
mBbsDevicePathPtr = BbsDevicePath;
mLoadOptionsSize = LoadOptionsSize;
mLoadOptions = LoadOptions;
mBootMode = BOOT_LEGACY_OS;
Status = GenericLegacyBoot (This);
return Status;
}
/**
Convert EFI Memory Type to E820 Memory Type.
@param Type EFI Memory Type
@return ACPI Memory Type for EFI Memory Type
**/
EFI_ACPI_MEMORY_TYPE
EfiMemoryTypeToE820Type (
IN UINT32 Type
)
{
switch (Type) {
case EfiLoaderCode:
case EfiLoaderData:
case EfiBootServicesCode:
case EfiBootServicesData:
case EfiConventionalMemory:
//
// The memory of EfiRuntimeServicesCode and EfiRuntimeServicesData are
// usable memory for legacy OS, because legacy OS is not aware of EFI runtime concept.
// In ACPI specification, EfiRuntimeServiceCode and EfiRuntimeServiceData
// should be mapped to AddressRangeReserved. This statement is for UEFI OS, not for legacy OS.
//
case EfiRuntimeServicesCode:
case EfiRuntimeServicesData:
return EfiAcpiAddressRangeMemory;
case EfiPersistentMemory:
return EfiAddressRangePersistentMemory;
case EfiACPIReclaimMemory:
return EfiAcpiAddressRangeACPI;
case EfiACPIMemoryNVS:
return EfiAcpiAddressRangeNVS;
//
// All other types map to reserved.
// Adding the code just waists FLASH space.
//
// case EfiReservedMemoryType:
// case EfiUnusableMemory:
// case EfiMemoryMappedIO:
// case EfiMemoryMappedIOPortSpace:
// case EfiPalCode:
//
default:
return EfiAcpiAddressRangeReserved;
}
}
/**
Build the E820 table.
@param Private Legacy BIOS Instance data
@param Size Size of E820 Table
@retval EFI_SUCCESS It should always work.
**/
EFI_STATUS
LegacyBiosBuildE820 (
IN LEGACY_BIOS_INSTANCE *Private,
OUT UINTN *Size
)
{
EFI_STATUS Status;
EFI_E820_ENTRY64 *E820Table;
EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;
EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;
EFI_MEMORY_DESCRIPTOR *EfiEntry;
EFI_MEMORY_DESCRIPTOR *NextEfiEntry;
EFI_MEMORY_DESCRIPTOR TempEfiEntry;
UINTN EfiMemoryMapSize;
UINTN EfiMapKey;
UINTN EfiDescriptorSize;
UINT32 EfiDescriptorVersion;
UINTN Index;
EFI_PEI_HOB_POINTERS Hob;
EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
UINTN TempIndex;
UINTN IndexSort;
UINTN TempNextIndex;
EFI_E820_ENTRY64 TempE820;
EFI_ACPI_MEMORY_TYPE TempType;
BOOLEAN ChangedFlag;
UINTN Above1MIndex;
UINT64 MemoryBlockLength;
E820Table = (EFI_E820_ENTRY64 *)Private->E820Table;
//
// Get the EFI memory map.
//
EfiMemoryMapSize = 0;
EfiMemoryMap = NULL;
Status = gBS->GetMemoryMap (
&EfiMemoryMapSize,
EfiMemoryMap,
&EfiMapKey,
&EfiDescriptorSize,
&EfiDescriptorVersion
);
ASSERT (Status == EFI_BUFFER_TOO_SMALL);
do {
//
// Use size returned for the AllocatePool.
// We don't just multiply by 2 since the "for" loop below terminates on
// EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwise
// we process bogus entries and create bogus E820 entries.
//
EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *)AllocatePool (EfiMemoryMapSize);
ASSERT (EfiMemoryMap != NULL);
Status = gBS->GetMemoryMap (
&EfiMemoryMapSize,
EfiMemoryMap,
&EfiMapKey,
&EfiDescriptorSize,
&EfiDescriptorVersion
);
if (EFI_ERROR (Status)) {
FreePool (EfiMemoryMap);
}
} while (Status == EFI_BUFFER_TOO_SMALL);
ASSERT_EFI_ERROR (Status);
//
// Punch in the E820 table for memory less than 1 MB.
// Assume ZeroMem () has been done on data structure.
//
//
// First entry is 0 to (640k - EBDA)
//
ACCESS_PAGE0_CODE (
E820Table[0].BaseAddr = 0;
E820Table[0].Length = (UINT64)((*(UINT16 *)(UINTN)0x40E) << 4);
E820Table[0].Type = EfiAcpiAddressRangeMemory;
);
//
// Second entry is (640k - EBDA) to 640k
//
E820Table[1].BaseAddr = E820Table[0].Length;
E820Table[1].Length = (UINT64)((640 * 1024) - E820Table[0].Length);
E820Table[1].Type = EfiAcpiAddressRangeReserved;
//
// Third Entry is legacy BIOS
// DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas
// to page in memory under 1MB.
// Omit region from 0xE0000 to start of BIOS, if any. This can be
// used for a multiple reasons including OPROMS.
//
//
// The CSM binary image size is not the actually size that CSM binary used,
// to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary.
//
E820Table[2].BaseAddr = 0xE0000;
E820Table[2].Length = 0x20000;
E820Table[2].Type = EfiAcpiAddressRangeReserved;
Above1MIndex = 2;
//
// Process the EFI map to produce E820 map;
//
//
// Sort memory map from low to high
//
EfiEntry = EfiMemoryMap;
NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)EfiMemoryMap + EfiMemoryMapSize);
while (EfiEntry < EfiMemoryMapEnd) {
while (NextEfiEntry < EfiMemoryMapEnd) {
if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {
CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
}
NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);
}
EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
}
EfiEntry = EfiMemoryMap;
EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)EfiMemoryMap + EfiMemoryMapSize);
for (Index = Above1MIndex; (EfiEntry < EfiMemoryMapEnd) && (Index < EFI_MAX_E820_ENTRY - 1); ) {
MemoryBlockLength = (UINT64)(LShiftU64 (EfiEntry->NumberOfPages, 12));
if ((EfiEntry->PhysicalStart + MemoryBlockLength) < 0x100000) {
//
// Skip the memory block if under 1MB
//
} else {
if (EfiEntry->PhysicalStart < 0x100000) {
//
// When the memory block spans below 1MB, ensure the memory block start address is at least 1MB
//
MemoryBlockLength -= 0x100000 - EfiEntry->PhysicalStart;
EfiEntry->PhysicalStart = 0x100000;
}
//
// Convert memory type to E820 type
//
TempType = EfiMemoryTypeToE820Type (EfiEntry->Type);
if ((E820Table[Index].Type == TempType) && (EfiEntry->PhysicalStart == (E820Table[Index].BaseAddr + E820Table[Index].Length))) {
//
// Grow an existing entry
//
E820Table[Index].Length += MemoryBlockLength;
} else {
//
// Make a new entry
//
++Index;
E820Table[Index].BaseAddr = EfiEntry->PhysicalStart;
E820Table[Index].Length = MemoryBlockLength;
E820Table[Index].Type = TempType;
}
}
EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
}
FreePool (EfiMemoryMap);
//
// Process the reserved memory map to produce E820 map ;
//
for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
if ((Hob.Raw != NULL) && (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR)) {
ResourceHob = Hob.ResourceDescriptor;
if (((ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO) ||
(ResourceHob->ResourceType == EFI_RESOURCE_FIRMWARE_DEVICE) ||
(ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_RESERVED)) &&
(ResourceHob->PhysicalStart > 0x100000) &&
(Index < EFI_MAX_E820_ENTRY - 1))
{
++Index;
E820Table[Index].BaseAddr = ResourceHob->PhysicalStart;
E820Table[Index].Length = ResourceHob->ResourceLength;
E820Table[Index].Type = EfiAcpiAddressRangeReserved;
}
}
}
Index++;
Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;
Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;
Private->NumberE820Entries = (UINT32)Index;
*Size = (UINTN)(Index * sizeof (EFI_E820_ENTRY64));
//
// Sort E820Table from low to high
//
for (TempIndex = 0; TempIndex < Index; TempIndex++) {
ChangedFlag = FALSE;
for (TempNextIndex = 1; TempNextIndex < Index - TempIndex; TempNextIndex++) {
if (E820Table[TempNextIndex - 1].BaseAddr > E820Table[TempNextIndex].BaseAddr) {
ChangedFlag = TRUE;
TempE820.BaseAddr = E820Table[TempNextIndex - 1].BaseAddr;
TempE820.Length = E820Table[TempNextIndex - 1].Length;
TempE820.Type = E820Table[TempNextIndex - 1].Type;
E820Table[TempNextIndex - 1].BaseAddr = E820Table[TempNextIndex].BaseAddr;
E820Table[TempNextIndex - 1].Length = E820Table[TempNextIndex].Length;
E820Table[TempNextIndex - 1].Type = E820Table[TempNextIndex].Type;
E820Table[TempNextIndex].BaseAddr = TempE820.BaseAddr;
E820Table[TempNextIndex].Length = TempE820.Length;
E820Table[TempNextIndex].Type = TempE820.Type;
}
}
if (!ChangedFlag) {
break;
}
}
//
// Remove the overlap range
//
for (TempIndex = 1; TempIndex < Index; TempIndex++) {
if ((E820Table[TempIndex - 1].BaseAddr <= E820Table[TempIndex].BaseAddr) &&
((E820Table[TempIndex - 1].BaseAddr + E820Table[TempIndex - 1].Length) >=
(E820Table[TempIndex].BaseAddr +E820Table[TempIndex].Length)))
{
//
// Overlap range is found
//
ASSERT (E820Table[TempIndex - 1].Type == E820Table[TempIndex].Type);
if (TempIndex == Index - 1) {
E820Table[TempIndex].BaseAddr = 0;
E820Table[TempIndex].Length = 0;
E820Table[TempIndex].Type = (EFI_ACPI_MEMORY_TYPE)0;
Index--;
break;
} else {
for (IndexSort = TempIndex; IndexSort < Index - 1; IndexSort++) {
E820Table[IndexSort].BaseAddr = E820Table[IndexSort + 1].BaseAddr;
E820Table[IndexSort].Length = E820Table[IndexSort + 1].Length;
E820Table[IndexSort].Type = E820Table[IndexSort + 1].Type;
}
Index--;
}
}
}
Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;
Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;
Private->NumberE820Entries = (UINT32)Index;
*Size = (UINTN)(Index * sizeof (EFI_E820_ENTRY64));
//
// Determine OS usable memory above 1MB
//
Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb = 0x0000;
for (TempIndex = Above1MIndex; TempIndex < Index; TempIndex++) {
if ((E820Table[TempIndex].BaseAddr >= 0x100000) && (E820Table[TempIndex].BaseAddr < 0x100000000ULL)) {
// not include above 4G memory
//
// ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables.
//
if ((E820Table[TempIndex].Type == EfiAcpiAddressRangeMemory) || (E820Table[TempIndex].Type == EfiAcpiAddressRangeACPI)) {
Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb += (UINT32)(E820Table[TempIndex].Length);
} else {
break; // break at first not normal memory, because SMM may use reserved memory.
}
}
}
Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb = Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb;
//
// Print DEBUG information
//
for (TempIndex = 0; TempIndex < Index; TempIndex++) {
DEBUG ((
DEBUG_INFO,
"E820[%2d]: 0x%016lx - 0x%016lx, Type = %d\n",
TempIndex,
E820Table[TempIndex].BaseAddr,
(E820Table[TempIndex].BaseAddr + E820Table[TempIndex].Length),
E820Table[TempIndex].Type
));
}
return EFI_SUCCESS;
}
/**
Fill in the standard BDA and EBDA stuff prior to legacy Boot
@param Private Legacy BIOS Instance data
@retval EFI_SUCCESS It should always work.
**/
EFI_STATUS
LegacyBiosCompleteBdaBeforeBoot (
IN LEGACY_BIOS_INSTANCE *Private
)
{
BDA_STRUC *Bda;
UINT16 MachineConfig;
DEVICE_PRODUCER_DATA_HEADER *SioPtr;
Bda = (BDA_STRUC *)((UINTN)0x400);
MachineConfig = 0;
SioPtr = &(Private->IntThunk->EfiToLegacy16BootTable.SioData);
Bda->Com1 = SioPtr->Serial[0].Address;
Bda->Com2 = SioPtr->Serial[1].Address;
Bda->Com3 = SioPtr->Serial[2].Address;
Bda->Com4 = SioPtr->Serial[3].Address;
if (SioPtr->Serial[0].Address != 0x00) {
MachineConfig += 0x200;
}
if (SioPtr->Serial[1].Address != 0x00) {
MachineConfig += 0x200;
}
if (SioPtr->Serial[2].Address != 0x00) {
MachineConfig += 0x200;
}
if (SioPtr->Serial[3].Address != 0x00) {
MachineConfig += 0x200;
}
Bda->Lpt1 = SioPtr->Parallel[0].Address;
Bda->Lpt2 = SioPtr->Parallel[1].Address;
Bda->Lpt3 = SioPtr->Parallel[2].Address;
if (SioPtr->Parallel[0].Address != 0x00) {
MachineConfig += 0x4000;
}
if (SioPtr->Parallel[1].Address != 0x00) {
MachineConfig += 0x4000;
}
if (SioPtr->Parallel[2].Address != 0x00) {
MachineConfig += 0x4000;
}
Bda->NumberOfDrives = (UINT8)(Bda->NumberOfDrives + Private->IdeDriveCount);
if (SioPtr->Floppy.NumberOfFloppy != 0x00) {
MachineConfig = (UINT16)(MachineConfig + 0x01 + (SioPtr->Floppy.NumberOfFloppy - 1) * 0x40);
Bda->FloppyXRate = 0x07;
}
Bda->Lpt1_2Timeout = 0x1414;
Bda->Lpt3_4Timeout = 0x1414;
Bda->Com1_2Timeout = 0x0101;
Bda->Com3_4Timeout = 0x0101;
//
// Force VGA and Coprocessor, indicate 101/102 keyboard
//
MachineConfig = (UINT16)(MachineConfig + 0x00 + 0x02 + (SioPtr->MousePresent * 0x04));
Bda->MachineConfig = MachineConfig;
return EFI_SUCCESS;
}
/**
Fill in the standard BDA for Keyboard LEDs
@param This Protocol instance pointer.
@param Leds Current LED status
@retval EFI_SUCCESS It should always work.
**/
EFI_STATUS
EFIAPI
LegacyBiosUpdateKeyboardLedStatus (
IN EFI_LEGACY_BIOS_PROTOCOL *This,
IN UINT8 Leds
)
{
LEGACY_BIOS_INSTANCE *Private;
BDA_STRUC *Bda;
UINT8 LocalLeds;
EFI_IA32_REGISTER_SET Regs;
Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
ACCESS_PAGE0_CODE (
Bda = (BDA_STRUC *)((UINTN)0x400);
LocalLeds = Leds;
Bda->LedStatus = (UINT8)((Bda->LedStatus &~0x07) | LocalLeds);
LocalLeds = (UINT8)(LocalLeds << 4);
Bda->ShiftStatus = (UINT8)((Bda->ShiftStatus &~0x70) | LocalLeds);
LocalLeds = (UINT8)(Leds & 0x20);
Bda->KeyboardStatus = (UINT8)((Bda->KeyboardStatus &~0x20) | LocalLeds);
);
//
// Call into Legacy16 code to allow it to do any processing
//
ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
Regs.X.AX = Legacy16SetKeyboardLeds;
Regs.H.CL = Leds;
Private->LegacyBios.FarCall86 (
&Private->LegacyBios,
Private->Legacy16Table->Compatibility16CallSegment,
Private->Legacy16Table->Compatibility16CallOffset,
&Regs,
NULL,
0
);
return EFI_SUCCESS;
}
/**
Fill in the standard CMOS stuff prior to legacy Boot
@param Private Legacy BIOS Instance data
@retval EFI_SUCCESS It should always work.
**/
EFI_STATUS
LegacyBiosCompleteStandardCmosBeforeBoot (
IN LEGACY_BIOS_INSTANCE *Private
)
{
UINT8 Bda;
UINT8 Floppy;
UINT32 Size;
//
// Update CMOS locations
// 10 floppy
// 12,19,1A - ignore as OS don't use them and there is no standard due
// to large capacity drives
// CMOS 14 = BDA 40:10 plus bit 3(display enabled)
//
ACCESS_PAGE0_CODE (
Bda = (UINT8)(*((UINT8 *)((UINTN)0x410)) | BIT3);
);
//
// Force display enabled
//
Floppy = 0x00;
if ((Bda & BIT0) != 0) {
Floppy = BIT6;
}
//
// Check if 2.88MB floppy set
//
if ((Bda & (BIT7 | BIT6)) != 0) {
Floppy = (UINT8)(Floppy | BIT1);
}
LegacyWriteStandardCmos (CMOS_10, Floppy);
LegacyWriteStandardCmos (CMOS_14, Bda);
//
// Force Status Register A to set rate selection bits and divider
//
LegacyWriteStandardCmos (CMOS_0A, 0x26);
//
// redo memory size since it can change
//
Size = (15 * SIZE_1MB) >> 10;
if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) {
Size = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10;
}
LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF));
LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF));
LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8));
LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8));
LegacyCalculateWriteStandardCmosChecksum ();
return EFI_SUCCESS;
}
/**
Relocate this image under 4G memory for IPF.
@param ImageHandle Handle of driver image.
@param SystemTable Pointer to system table.
@retval EFI_SUCCESS Image successfully relocated.
@retval EFI_ABORTED Failed to relocate image.
**/
EFI_STATUS
RelocateImageUnder4GIfNeeded (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
return EFI_SUCCESS;
}