/** @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; | |
} |