mirror of https://github.com/acidanthera/audk.git
1721 lines
48 KiB
C
1721 lines
48 KiB
C
/*++
|
|
|
|
Copyright (c) 2006 - 2007, Intel Corporation
|
|
All rights reserved. This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
Module Name:
|
|
|
|
BdsPlatform.c
|
|
|
|
Abstract:
|
|
|
|
This file include all platform action which can be customized
|
|
by IBV/OEM.
|
|
|
|
--*/
|
|
|
|
#include "BdsPlatform.h"
|
|
|
|
#define IS_PCI_ISA_PDECODE(_p) IS_CLASS3 (_p, PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_ISA_PDECODE, 0)
|
|
|
|
CHAR16 mFirmwareVendor[] = L"TianoCore.org";
|
|
extern BOOLEAN gConnectAllHappened;
|
|
extern USB_CLASS_FORMAT_DEVICE_PATH gUsbClassKeyboardDevicePath;
|
|
//
|
|
// BDS Platform Functions
|
|
//
|
|
|
|
VOID
|
|
GetSystemTablesFromHob (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Find GUID'ed HOBs that contain EFI_PHYSICAL_ADDRESS of ACPI, SMBIOS, MPs tables
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Returns:
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HOB_HANDOFF_INFO_TABLE *HobList;
|
|
EFI_HOB_HANDOFF_INFO_TABLE *HobStart;
|
|
EFI_PHYSICAL_ADDRESS *Table;
|
|
UINTN Index;
|
|
EFI_GUID *TableGuidArray[] = {
|
|
&gEfiAcpi20TableGuid, &gEfiAcpiTableGuid, &gEfiSmbiosTableGuid, &gEfiMpsTableGuid
|
|
};
|
|
|
|
//
|
|
// Get Hob List
|
|
//
|
|
Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, (VOID *) &HobList);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Iteratively add ACPI Table, SMBIOS Table, MPS Table to EFI System Table
|
|
//
|
|
for (Index = 0; Index < sizeof (TableGuidArray) / sizeof (*TableGuidArray); ++Index) {
|
|
HobStart = HobList;
|
|
Table = NULL;
|
|
Table = GetNextGuidHob (TableGuidArray[Index], &HobStart);
|
|
if (!EFI_ERROR (Status)) {
|
|
if (Table != NULL) {
|
|
//
|
|
// Check if Mps Table/Smbios Table/Acpi Table exists in E/F seg,
|
|
// According to UEFI Spec, we should make sure Smbios table,
|
|
// ACPI table and Mps tables kept in memory of specified type
|
|
//
|
|
ConvertSystemTable(TableGuidArray[Index], &Table);
|
|
gBS->InstallConfigurationTable (TableGuidArray[Index], (VOID *)Table);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
#define EFI_LDR_MEMORY_DESCRIPTOR_GUID \
|
|
{ 0x7701d7e5, 0x7d1d, 0x4432, 0xa4, 0x68, 0x67, 0x3d, 0xab, 0x8a, 0xde, 0x60 }
|
|
|
|
EFI_GUID gEfiLdrMemoryDescriptorGuid = EFI_LDR_MEMORY_DESCRIPTOR_GUID;
|
|
|
|
#pragma pack(1)
|
|
|
|
typedef struct {
|
|
EFI_HOB_GUID_TYPE Hob;
|
|
UINTN MemDescCount;
|
|
EFI_MEMORY_DESCRIPTOR *MemDesc;
|
|
} MEMORY_DESC_HOB;
|
|
|
|
#pragma pack()
|
|
|
|
#if 0
|
|
VOID
|
|
PrintMemoryMap (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_MEMORY_DESCRIPTOR *MemMap;
|
|
EFI_MEMORY_DESCRIPTOR *MemMapPtr;
|
|
UINTN MemMapSize;
|
|
UINTN MapKey, DescriptorSize;
|
|
UINTN Index;
|
|
UINT32 DescriptorVersion;
|
|
UINT64 Bytes;
|
|
EFI_STATUS Status;
|
|
|
|
MemMapSize = 0;
|
|
MemMap = NULL;
|
|
Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion);
|
|
ASSERT (Status == EFI_BUFFER_TOO_SMALL);
|
|
MemMapSize += EFI_PAGE_SIZE;
|
|
Status = gBS->AllocatePool (EfiBootServicesData, MemMapSize, &MemMap);
|
|
ASSERT (Status == EFI_SUCCESS);
|
|
Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion);
|
|
ASSERT (Status == EFI_SUCCESS);
|
|
MemMapPtr = MemMap;
|
|
|
|
ASSERT (DescriptorVersion == EFI_MEMORY_DESCRIPTOR_VERSION);
|
|
|
|
for (Index = 0; Index < MemMapSize / DescriptorSize; Index ++) {
|
|
Bytes = LShiftU64 (MemMap->NumberOfPages, 12);
|
|
DEBUG ((EFI_D_ERROR, "%lX-%lX %lX %lX %X\n",
|
|
MemMap->PhysicalStart,
|
|
MemMap->PhysicalStart + Bytes - 1,
|
|
MemMap->NumberOfPages,
|
|
MemMap->Attribute,
|
|
(UINTN)MemMap->Type));
|
|
MemMap = (EFI_MEMORY_DESCRIPTOR *)((UINTN)MemMap + DescriptorSize);
|
|
}
|
|
|
|
gBS->FreePool (MemMapPtr);
|
|
}
|
|
#endif
|
|
|
|
VOID
|
|
UpdateMemoryMap (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HOB_HANDOFF_INFO_TABLE *HobList;
|
|
VOID *Table;
|
|
MEMORY_DESC_HOB MemoryDescHob;
|
|
UINTN Index;
|
|
EFI_PHYSICAL_ADDRESS Memory;
|
|
|
|
//
|
|
// Get Hob List
|
|
//
|
|
Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, (VOID *) &HobList);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
Table = GetNextGuidHob (&gEfiLdrMemoryDescriptorGuid, &HobList);
|
|
MemoryDescHob.MemDescCount = *(UINTN *)Table;
|
|
MemoryDescHob.MemDesc = *(EFI_MEMORY_DESCRIPTOR **)((UINTN)Table + sizeof(UINTN));
|
|
|
|
//
|
|
// Add ACPINVS, ACPIReclaim, and Reserved memory to MemoryMap
|
|
//
|
|
for (Index = 0; Index < MemoryDescHob.MemDescCount; Index++) {
|
|
if (MemoryDescHob.MemDesc[Index].PhysicalStart < 0x100000) {
|
|
continue;
|
|
}
|
|
if (MemoryDescHob.MemDesc[Index].PhysicalStart >= 0x100000000) {
|
|
continue;
|
|
}
|
|
if ((MemoryDescHob.MemDesc[Index].Type == EfiReservedMemoryType) ||
|
|
(MemoryDescHob.MemDesc[Index].Type == EfiRuntimeServicesData) ||
|
|
(MemoryDescHob.MemDesc[Index].Type == EfiRuntimeServicesCode) ||
|
|
(MemoryDescHob.MemDesc[Index].Type == EfiACPIReclaimMemory) ||
|
|
(MemoryDescHob.MemDesc[Index].Type == EfiACPIMemoryNVS)) {
|
|
DEBUG ((EFI_D_ERROR, "PhysicalStart - 0x%x, ", MemoryDescHob.MemDesc[Index].PhysicalStart));
|
|
DEBUG ((EFI_D_ERROR, "PageNumber - 0x%x, ", MemoryDescHob.MemDesc[Index].NumberOfPages));
|
|
DEBUG ((EFI_D_ERROR, "Type - 0x%x\n", MemoryDescHob.MemDesc[Index].Type));
|
|
if ((MemoryDescHob.MemDesc[Index].Type == EfiRuntimeServicesData) ||
|
|
(MemoryDescHob.MemDesc[Index].Type == EfiRuntimeServicesCode)) {
|
|
//
|
|
// Skip RuntimeSevicesData and RuntimeServicesCode, they are BFV
|
|
//
|
|
continue;
|
|
}
|
|
Status = gDS->AddMemorySpace (
|
|
EfiGcdMemoryTypeSystemMemory,
|
|
MemoryDescHob.MemDesc[Index].PhysicalStart,
|
|
LShiftU64 (MemoryDescHob.MemDesc[Index].NumberOfPages, EFI_PAGE_SHIFT),
|
|
MemoryDescHob.MemDesc[Index].Attribute
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "AddMemorySpace fail!\n"));
|
|
if ((MemoryDescHob.MemDesc[Index].Type == EfiACPIReclaimMemory) ||
|
|
(MemoryDescHob.MemDesc[Index].Type == EfiACPIMemoryNVS)) {
|
|
//
|
|
// For EfiACPIReclaimMemory and EfiACPIMemoryNVS, it must success.
|
|
// For EfiReservedMemoryType, there maybe overlap. So skip check here.
|
|
//
|
|
// ASSERT_EFI_ERROR (Status);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
Memory = MemoryDescHob.MemDesc[Index].PhysicalStart;
|
|
Status = gBS->AllocatePages (
|
|
AllocateAddress,
|
|
MemoryDescHob.MemDesc[Index].Type,
|
|
(UINTN)MemoryDescHob.MemDesc[Index].NumberOfPages,
|
|
&Memory
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "AllocatePages fail!\n"));
|
|
//
|
|
// For the page added, it must be allocated.
|
|
//
|
|
// ASSERT_EFI_ERROR (Status);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
EFI_STATUS
|
|
DisableUsbLegacySupport(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Disabble the USB legacy Support in all Ehci and Uhci.
|
|
This function assume all PciIo handles have been created in system.
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Returns:
|
|
EFI_SUCCESS
|
|
EFI_NOT_FOUND
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE *HandleArray;
|
|
UINTN HandleArrayCount;
|
|
UINTN Index;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
UINT8 Class[3];
|
|
UINT16 Command;
|
|
UINT32 HcCapParams;
|
|
UINT32 ExtendCap;
|
|
UINT32 Value;
|
|
UINT32 TimeOut;
|
|
|
|
//
|
|
// Find the usb host controller
|
|
//
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiPciIoProtocolGuid,
|
|
NULL,
|
|
&HandleArrayCount,
|
|
&HandleArray
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
for (Index = 0; Index < HandleArrayCount; Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
HandleArray[Index],
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID **)&PciIo
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// Find the USB host controller controller
|
|
//
|
|
Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class);
|
|
if (!EFI_ERROR (Status)) {
|
|
if ((PCI_CLASS_SERIAL == Class[2]) &&
|
|
(PCI_CLASS_SERIAL_USB == Class[1])) {
|
|
if (PCI_CLASSC_PI_UHCI == Class[0]) {
|
|
//
|
|
// Found the UHCI, then disable the legacy support
|
|
//
|
|
Command = 0;
|
|
Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0xC0, 1, &Command);
|
|
} else if (PCI_CLASSC_PI_EHCI == Class[0]) {
|
|
//
|
|
// Found the EHCI, then disable the legacy support
|
|
//
|
|
Status = PciIo->Mem.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
0, //EHC_BAR_INDEX
|
|
(UINT64) 0x08, //EHC_HCCPARAMS_OFFSET
|
|
1,
|
|
&HcCapParams
|
|
);
|
|
|
|
ExtendCap = (HcCapParams >> 8) & 0xFF;
|
|
//
|
|
// Disable the SMI in USBLEGCTLSTS firstly
|
|
//
|
|
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap + 0x4, 1, &Value);
|
|
Value &= 0xFFFF0000;
|
|
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, ExtendCap + 0x4, 1, &Value);
|
|
|
|
//
|
|
// Get EHCI Ownership from legacy bios
|
|
//
|
|
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
|
|
Value |= (0x1 << 24);
|
|
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
|
|
|
|
TimeOut = 40;
|
|
while (TimeOut--) {
|
|
gBS->Stall (500);
|
|
|
|
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
|
|
|
|
if ((Value & 0x01010000) == 0x01000000) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
return Status;
|
|
}
|
|
gBS->FreePool (HandleArray);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
PlatformBdsInit (
|
|
IN EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Platform Bds init. Incude the platform firmware vendor, revision
|
|
and so crc check.
|
|
|
|
Arguments:
|
|
|
|
PrivateData - The EFI_BDS_ARCH_PROTOCOL_INSTANCE instance
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// set firmwarevendor, here can be IBV/OEM customize
|
|
//
|
|
gST->FirmwareVendor = AllocateRuntimeCopyPool (
|
|
sizeof (mFirmwareVendor),
|
|
&mFirmwareVendor
|
|
);
|
|
ASSERT (gST->FirmwareVendor != NULL);
|
|
|
|
gST->FirmwareRevision = 0;
|
|
|
|
//
|
|
// Fixup Tasble CRC after we updated Firmware Vendor and Revision
|
|
//
|
|
gBS->CalculateCrc32 ((VOID *) gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);
|
|
}
|
|
|
|
UINT64
|
|
GetPciExpressBaseAddressForRootBridge (
|
|
IN UINTN HostBridgeNumber,
|
|
IN UINTN RootBridgeNumber
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine is to get PciExpress Base Address for this RootBridge
|
|
|
|
Arguments:
|
|
HostBridgeNumber - The number of HostBridge
|
|
RootBridgeNumber - The number of RootBridge
|
|
|
|
Returns:
|
|
UINT64 - PciExpressBaseAddress for this HostBridge and RootBridge
|
|
|
|
--*/
|
|
{
|
|
EFI_PCI_EXPRESS_BASE_ADDRESS_INFORMATION *PciExpressBaseAddressInfo;
|
|
UINTN BufferSize;
|
|
UINT32 Index;
|
|
UINT32 Number;
|
|
VOID *HobList;
|
|
EFI_STATUS Status;
|
|
|
|
BufferSize = 0;
|
|
//
|
|
// Get Hob List from configuration table
|
|
//
|
|
Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList);
|
|
if (EFI_ERROR (Status)) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Get PciExpressAddressInfo Hob
|
|
//
|
|
PciExpressBaseAddressInfo = NULL;
|
|
PciExpressBaseAddressInfo = GetNextGuidHob (&gEfiPciExpressBaseAddressGuid, &HobList);
|
|
|
|
//
|
|
// Search the PciExpress Base Address in the Hob for current RootBridge
|
|
//
|
|
Number = (UINT32)(BufferSize / sizeof(EFI_PCI_EXPRESS_BASE_ADDRESS_INFORMATION));
|
|
for (Index = 0; Index < Number; Index++) {
|
|
if ((PciExpressBaseAddressInfo[Index].HostBridgeNumber == HostBridgeNumber) &&
|
|
(PciExpressBaseAddressInfo[Index].RootBridgeNumber == RootBridgeNumber)) {
|
|
return PciExpressBaseAddressInfo[Index].PciExpressBaseAddress;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Do not find the PciExpress Base Address in the Hob
|
|
//
|
|
return 0;
|
|
}
|
|
|
|
VOID
|
|
PatchPciRootBridgeDevicePath (
|
|
IN UINTN HostBridgeNumber,
|
|
IN UINTN RootBridgeNumber,
|
|
IN PLATFORM_ROOT_BRIDGE_DEVICE_PATH *RootBridge
|
|
)
|
|
{
|
|
UINT64 PciExpressBase;
|
|
|
|
PciExpressBase = GetPciExpressBaseAddressForRootBridge (HostBridgeNumber, RootBridgeNumber);
|
|
|
|
if (PciExpressBase != 0) {
|
|
RootBridge->PciRootBridge.HID = EISA_PNP_ID(0x0A08);
|
|
}
|
|
}
|
|
|
|
EFI_STATUS
|
|
ConnectRootBridge (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Connect RootBridge
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Connect RootBridge successfully.
|
|
EFI_STATUS - Connect RootBridge fail.
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE RootHandle;
|
|
|
|
//
|
|
// Patch Pci Root Bridge Device Path
|
|
//
|
|
PatchPciRootBridgeDevicePath (0, 0, &gPlatformRootBridge0);
|
|
|
|
//
|
|
// Make all the PCI_IO protocols on PCI Seg 0 show up
|
|
//
|
|
BdsLibConnectDevicePath (gPlatformRootBridges[0]);
|
|
|
|
Status = gBS->LocateDevicePath (
|
|
&gEfiDevicePathProtocolGuid,
|
|
&gPlatformRootBridges[0],
|
|
&RootHandle
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gBS->ConnectController (RootHandle, NULL, NULL, FALSE);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
PrepareLpcBridgeDevicePath (
|
|
IN EFI_HANDLE DeviceHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add IsaKeyboard to ConIn,
|
|
add IsaSerial to ConOut, ConIn, ErrOut.
|
|
LPC Bridge: 06 01 00
|
|
|
|
Arguments:
|
|
|
|
DeviceHandle - Handle of PCIIO protocol.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut.
|
|
EFI_STATUS - No LPC bridge is added.
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
|
|
|
DevicePath = NULL;
|
|
Status = gBS->HandleProtocol (
|
|
DeviceHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
&DevicePath
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
TempDevicePath = DevicePath;
|
|
|
|
//
|
|
// Register Keyboard
|
|
//
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);
|
|
|
|
BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL);
|
|
|
|
//
|
|
// Register COM1
|
|
//
|
|
DevicePath = TempDevicePath;
|
|
gPnp16550ComPortDeviceNode.UID = 0;
|
|
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
|
|
|
|
BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL);
|
|
BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL);
|
|
BdsLibUpdateConsoleVariable (VarErrorOut, DevicePath, NULL);
|
|
|
|
//
|
|
// Register COM2
|
|
//
|
|
DevicePath = TempDevicePath;
|
|
gPnp16550ComPortDeviceNode.UID = 1;
|
|
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
|
|
|
|
BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL);
|
|
BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL);
|
|
BdsLibUpdateConsoleVariable (VarErrorOut, DevicePath, NULL);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
#if (EFI_SPECIFICATION_VERSION >= 0x00020000)
|
|
EFI_STATUS
|
|
GetGopDevicePath (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,
|
|
OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath
|
|
)
|
|
{
|
|
UINTN Index;
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE PciDeviceHandle;
|
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;
|
|
UINTN GopHandleCount;
|
|
EFI_HANDLE *GopHandleBuffer;
|
|
|
|
if (PciDevicePath == NULL || GopDevicePath == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Initialize the GopDevicePath to be PciDevicePath
|
|
//
|
|
*GopDevicePath = PciDevicePath;
|
|
TempPciDevicePath = PciDevicePath;
|
|
|
|
Status = gBS->LocateDevicePath (
|
|
&gEfiDevicePathProtocolGuid,
|
|
&TempPciDevicePath,
|
|
&PciDeviceHandle
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Try to connect this handle, so that GOP dirver could start on this
|
|
// device and create child handles with GraphicsOutput Protocol installed
|
|
// on them, then we get device paths of these child handles and select
|
|
// them as possible console device.
|
|
//
|
|
gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiGraphicsOutputProtocolGuid,
|
|
NULL,
|
|
&GopHandleCount,
|
|
&GopHandleBuffer
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// Add all the child handles as possible Console Device
|
|
//
|
|
for (Index = 0; Index < GopHandleCount; Index++) {
|
|
Status = gBS->HandleProtocol (GopHandleBuffer[Index], &gEfiDevicePathProtocolGuid, &TempDevicePath);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
if (CompareMem (
|
|
PciDevicePath,
|
|
TempDevicePath,
|
|
GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH
|
|
) == 0) {
|
|
//
|
|
// In current implementation, we only enable one of the child handles
|
|
// as console device, i.e. sotre one of the child handle's device
|
|
// path to variable "ConOut"
|
|
// In futhure, we could select all child handles to be console device
|
|
//
|
|
|
|
*GopDevicePath = TempDevicePath;
|
|
|
|
//
|
|
// Delete the PCI device's path that added by GetPlugInPciVgaDevicePath()
|
|
// Add the integrity GOP device path.
|
|
//
|
|
BdsLibUpdateConsoleVariable (VarConsoleOutDev, NULL, PciDevicePath);
|
|
BdsLibUpdateConsoleVariable (VarConsoleOutDev, TempDevicePath, NULL);
|
|
}
|
|
}
|
|
gBS->FreePool (GopHandleBuffer);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
EFI_STATUS
|
|
PreparePciVgaDevicePath (
|
|
IN EFI_HANDLE DeviceHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add PCI VGA to ConOut.
|
|
PCI VGA: 03 00 00
|
|
|
|
Arguments:
|
|
|
|
DeviceHandle - Handle of PCIIO protocol.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - PCI VGA is added to ConOut.
|
|
EFI_STATUS - No PCI VGA device is added.
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
#if (EFI_SPECIFICATION_VERSION >= 0x00020000)
|
|
EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
|
|
#endif
|
|
|
|
DevicePath = NULL;
|
|
Status = gBS->HandleProtocol (
|
|
DeviceHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
&DevicePath
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
#if (EFI_SPECIFICATION_VERSION >= 0x00020000)
|
|
GetGopDevicePath (DevicePath, &GopDevicePath);
|
|
DevicePath = GopDevicePath;
|
|
#endif
|
|
|
|
BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
PreparePciSerialDevicePath (
|
|
IN EFI_HANDLE DeviceHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add PCI Serial to ConOut, ConIn, ErrOut.
|
|
PCI Serial: 07 00 02
|
|
|
|
Arguments:
|
|
|
|
DeviceHandle - Handle of PCIIO protocol.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut.
|
|
EFI_STATUS - No PCI Serial device is added.
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
|
|
DevicePath = NULL;
|
|
Status = gBS->HandleProtocol (
|
|
DeviceHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
&DevicePath
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
|
|
|
|
BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL);
|
|
BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL);
|
|
BdsLibUpdateConsoleVariable (VarErrorOut, DevicePath, NULL);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
DetectAndPreparePlatformPciDevicePath (
|
|
BOOLEAN DetectVgaOnly
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
|
|
|
|
Arguments:
|
|
|
|
DetectVgaOnly - Only detect VGA device if it's TRUE.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - PCI Device check and Console variable update successfully.
|
|
EFI_STATUS - PCI Device check or Console variable update fail.
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN HandleCount;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN Index;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
PCI_TYPE00 Pci;
|
|
|
|
//
|
|
// Start to check all the PciIo to find all possible device
|
|
//
|
|
HandleCount = 0;
|
|
HandleBuffer = NULL;
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiPciIoProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, &PciIo);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check for all PCI device
|
|
//
|
|
Status = PciIo->Pci.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
0,
|
|
sizeof (Pci) / sizeof (UINT32),
|
|
&Pci
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
if (!DetectVgaOnly) {
|
|
//
|
|
// Here we decide whether it is LPC Bridge
|
|
//
|
|
if ((IS_PCI_LPC (&Pci)) ||
|
|
((IS_PCI_ISA_PDECODE (&Pci)) && (Pci.Hdr.VendorId == 0x8086) && (Pci.Hdr.DeviceId == 0x7110))) {
|
|
//
|
|
// Add IsaKeyboard to ConIn,
|
|
// add IsaSerial to ConOut, ConIn, ErrOut
|
|
//
|
|
PrepareLpcBridgeDevicePath (HandleBuffer[Index]);
|
|
continue;
|
|
}
|
|
//
|
|
// Here we decide which Serial device to enable in PCI bus
|
|
//
|
|
if (IS_PCI_16550SERIAL (&Pci)) {
|
|
//
|
|
// Add them to ConOut, ConIn, ErrOut.
|
|
//
|
|
PreparePciSerialDevicePath (HandleBuffer[Index]);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Here we decide which VGA device to enable in PCI bus
|
|
//
|
|
if (IS_PCI_VGA (&Pci)) {
|
|
//
|
|
// Add them to ConOut.
|
|
//
|
|
PreparePciVgaDevicePath (HandleBuffer[Index]);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
gBS->FreePool (HandleBuffer);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
PlatformBdsConnectConsole (
|
|
IN BDS_CONSOLE_CONNECT_ENTRY *PlatformConsole
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Connect the predefined platform default console device. Always try to find
|
|
and enable the vga device if have.
|
|
|
|
Arguments:
|
|
|
|
PlatformConsole - Predfined platform default console device array.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Success connect at least one ConIn and ConOut
|
|
device, there must have one ConOut device is
|
|
active vga device.
|
|
|
|
EFI_STATUS - Return the status of
|
|
BdsLibConnectAllDefaultConsoles ()
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
EFI_DEVICE_PATH_PROTOCOL *VarConout;
|
|
EFI_DEVICE_PATH_PROTOCOL *VarConin;
|
|
UINTN DevicePathSize;
|
|
|
|
//
|
|
// Connect RootBridge
|
|
//
|
|
ConnectRootBridge ();
|
|
|
|
VarConout = BdsLibGetVariableAndSize (
|
|
VarConsoleOut,
|
|
&gEfiGlobalVariableGuid,
|
|
&DevicePathSize
|
|
);
|
|
VarConin = BdsLibGetVariableAndSize (
|
|
VarConsoleInp,
|
|
&gEfiGlobalVariableGuid,
|
|
&DevicePathSize
|
|
);
|
|
if (VarConout == NULL || VarConin == NULL) {
|
|
//
|
|
// Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
|
|
//
|
|
DetectAndPreparePlatformPciDevicePath (FALSE);
|
|
|
|
//
|
|
// Have chance to connect the platform default console,
|
|
// the platform default console is the minimue device group
|
|
// the platform should support
|
|
//
|
|
for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {
|
|
//
|
|
// Update the console variable with the connect type
|
|
//
|
|
if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
|
|
BdsLibUpdateConsoleVariable (VarConsoleInp, PlatformConsole[Index].DevicePath, NULL);
|
|
}
|
|
if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
|
|
BdsLibUpdateConsoleVariable (VarConsoleOut, PlatformConsole[Index].DevicePath, NULL);
|
|
}
|
|
if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
|
|
BdsLibUpdateConsoleVariable (VarErrorOut, PlatformConsole[Index].DevicePath, NULL);
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// Only detect VGA device and add them to ConOut
|
|
//
|
|
DetectAndPreparePlatformPciDevicePath (TRUE);
|
|
}
|
|
|
|
//
|
|
// The ConIn devices connection will start the USB bus, should disable all
|
|
// Usb legacy support firstly.
|
|
// Caution: Must ensure the PCI bus driver has been started. Since the
|
|
// ConnectRootBridge() will create all the PciIo protocol, it's safe here now
|
|
//
|
|
Status = DisableUsbLegacySupport();
|
|
|
|
//
|
|
// Connect the all the default console with current cosole variable
|
|
//
|
|
Status = BdsLibConnectAllDefaultConsoles ();
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
PlatformBdsConnectSequence (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Connect with predeined platform connect sequence,
|
|
the OEM/IBV can customize with their own connect sequence.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
UINTN Index;
|
|
|
|
Index = 0;
|
|
|
|
//
|
|
// Here we can get the customized platform connect sequence
|
|
// Notes: we can connect with new variable which record the
|
|
// last time boots connect device path sequence
|
|
//
|
|
while (gPlatformConnectSequence[Index] != NULL) {
|
|
//
|
|
// Build the platform boot option
|
|
//
|
|
BdsLibConnectDevicePath (gPlatformConnectSequence[Index]);
|
|
Index++;
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
PlatformBdsGetDriverOption (
|
|
IN OUT LIST_ENTRY *BdsDriverLists
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Load the predefined driver option, OEM/IBV can customize this
|
|
to load their own drivers
|
|
|
|
Arguments:
|
|
|
|
BdsDriverLists - The header of the driver option link list.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
UINTN Index;
|
|
|
|
Index = 0;
|
|
|
|
//
|
|
// Here we can get the customized platform driver option
|
|
//
|
|
while (gPlatformDriverOption[Index] != NULL) {
|
|
//
|
|
// Build the platform boot option
|
|
//
|
|
BdsLibRegisterNewOption (BdsDriverLists, gPlatformDriverOption[Index], NULL, L"DriverOrder");
|
|
Index++;
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
PlatformBdsDiagnostics (
|
|
IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel,
|
|
IN BOOLEAN QuietBoot
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Perform the platform diagnostic, such like test memory. OEM/IBV also
|
|
can customize this fuction to support specific platform diagnostic.
|
|
|
|
Arguments:
|
|
|
|
MemoryTestLevel - The memory test intensive level
|
|
|
|
QuietBoot - Indicate if need to enable the quiet boot
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Here we can decide if we need to show
|
|
// the diagnostics screen
|
|
// Notes: this quiet boot code should be remove
|
|
// from the graphic lib
|
|
//
|
|
if (QuietBoot) {
|
|
EnableQuietBootEx (&gEfiDefaultBmpLogoGuid, mBdsImageHandle);
|
|
//
|
|
// Perform system diagnostic
|
|
//
|
|
Status = BdsMemoryTest (MemoryTestLevel);
|
|
if (EFI_ERROR (Status)) {
|
|
DisableQuietBoot ();
|
|
}
|
|
|
|
return ;
|
|
}
|
|
//
|
|
// Perform system diagnostic
|
|
//
|
|
Status = BdsMemoryTest (MemoryTestLevel);
|
|
}
|
|
|
|
VOID
|
|
PlatformBdsPolicyBehavior (
|
|
IN EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData,
|
|
IN OUT LIST_ENTRY *DriverOptionList,
|
|
IN OUT LIST_ENTRY *BootOptionList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The function will excute with as the platform policy, current policy
|
|
is driven by boot mode. IBV/OEM can customize this code for their specific
|
|
policy action.
|
|
|
|
Arguments:
|
|
|
|
PrivateData - The EFI_BDS_ARCH_PROTOCOL_INSTANCE instance
|
|
|
|
DriverOptionList - The header of the driver option link list
|
|
|
|
BootOptionList - The header of the boot option link list
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT16 Timeout;
|
|
EFI_EVENT UserInputDurationTime;
|
|
LIST_ENTRY *Link;
|
|
BDS_COMMON_OPTION *BootOption;
|
|
UINTN Index;
|
|
EFI_INPUT_KEY Key;
|
|
EFI_TPL OldTpl;
|
|
|
|
//
|
|
// Init the time out value
|
|
//
|
|
Timeout = BdsLibGetTimeout ();
|
|
|
|
//
|
|
// Load the driver option as the driver option list
|
|
//
|
|
PlatformBdsGetDriverOption (DriverOptionList);
|
|
|
|
//
|
|
// Get current Boot Mode
|
|
//
|
|
Status = BdsLibGetBootMode (&PrivateData->BootMode);
|
|
DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", PrivateData->BootMode));
|
|
|
|
//
|
|
// Go the different platform policy with different boot mode
|
|
// Notes: this part code can be change with the table policy
|
|
//
|
|
ASSERT (PrivateData->BootMode == BOOT_WITH_FULL_CONFIGURATION);
|
|
//
|
|
// Connect platform console
|
|
//
|
|
Status = PlatformBdsConnectConsole (gPlatformConsole);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Here OEM/IBV can customize with defined action
|
|
//
|
|
PlatformBdsNoConsoleAction ();
|
|
}
|
|
//
|
|
// Create a 300ms duration event to ensure user has enough input time to enter Setup
|
|
//
|
|
Status = gBS->CreateEvent (
|
|
EFI_EVENT_TIMER,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&UserInputDurationTime
|
|
);
|
|
ASSERT (Status == EFI_SUCCESS);
|
|
Status = gBS->SetTimer (UserInputDurationTime, TimerRelative, 3000000);
|
|
ASSERT (Status == EFI_SUCCESS);
|
|
//
|
|
// Memory test and Logo show
|
|
//
|
|
PlatformBdsDiagnostics (IGNORE, TRUE);
|
|
|
|
//
|
|
// Perform some platform specific connect sequence
|
|
//
|
|
PlatformBdsConnectSequence ();
|
|
|
|
//
|
|
// Give one chance to enter the setup if we
|
|
// have the time out
|
|
//
|
|
if (Timeout != 0) {
|
|
PlatformBdsEnterFrontPage (Timeout, FALSE);
|
|
}
|
|
|
|
//
|
|
//BdsLibConnectAll ();
|
|
//BdsLibEnumerateAllBootOption (BootOptionList);
|
|
|
|
//
|
|
// Please uncomment above ConnectAll and EnumerateAll code and remove following first boot
|
|
// checking code in real production tip.
|
|
//
|
|
// In BOOT_WITH_FULL_CONFIGURATION boot mode, should always connect every device
|
|
// and do enumerate all the default boot options. But in development system board, the boot mode
|
|
// cannot be BOOT_ASSUMING_NO_CONFIGURATION_CHANGES because the machine box
|
|
// is always open. So the following code only do the ConnectAll and EnumerateAll at first boot.
|
|
//
|
|
Status = BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder");
|
|
if (EFI_ERROR(Status)) {
|
|
//
|
|
// If cannot find "BootOrder" variable, it may be first boot.
|
|
// Try to connect all devices and enumerate all boot options here.
|
|
//
|
|
BdsLibConnectAll ();
|
|
BdsLibEnumerateAllBootOption (BootOptionList);
|
|
}
|
|
|
|
//
|
|
// To give the User a chance to enter Setup here, if user set TimeOut is 0.
|
|
// BDS should still give user a chance to enter Setup
|
|
//
|
|
// Connect first boot option, and then check user input before exit
|
|
//
|
|
for (Link = BootOptionList->ForwardLink; Link != BootOptionList;Link = Link->ForwardLink) {
|
|
BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
|
|
if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {
|
|
//
|
|
// skip the header of the link list, becuase it has no boot option
|
|
//
|
|
continue;
|
|
} else {
|
|
//
|
|
// Make sure the boot option device path connected, but ignore the BBS device path
|
|
//
|
|
if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {
|
|
BdsLibConnectDevicePath (BootOption->DevicePath);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check whether the user input after the duration time has expired
|
|
//
|
|
OldTpl = EfiGetCurrentTpl();
|
|
gBS->RestoreTPL (TPL_APPLICATION);
|
|
gBS->WaitForEvent (1, &UserInputDurationTime, &Index);
|
|
gBS->CloseEvent (UserInputDurationTime);
|
|
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
|
|
gBS->RaiseTPL (OldTpl);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// Enter Setup if user input
|
|
//
|
|
Timeout = 0xffff;
|
|
PlatformBdsEnterFrontPage (Timeout, FALSE);
|
|
}
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
VOID
|
|
PlatformBdsBootSuccess (
|
|
IN BDS_COMMON_OPTION *Option
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Hook point after a boot attempt succeeds. We don't expect a boot option to
|
|
return, so the EFI 1.0 specification defines that you will default to an
|
|
interactive mode and stop processing the BootOrder list in this case. This
|
|
is alos a platform implementation and can be customized by IBV/OEM.
|
|
|
|
Arguments:
|
|
|
|
Option - Pointer to Boot Option that succeeded to boot.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
CHAR16 *TmpStr;
|
|
|
|
//
|
|
// If Boot returned with EFI_SUCCESS and there is not in the boot device
|
|
// select loop then we need to pop up a UI and wait for user input.
|
|
//
|
|
TmpStr = Option->StatusString;
|
|
if (TmpStr != NULL) {
|
|
BdsLibOutputStrings (gST->ConOut, TmpStr, Option->Description, L"\n\r", NULL);
|
|
gBS->FreePool (TmpStr);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
PlatformBdsBootFail (
|
|
IN BDS_COMMON_OPTION *Option,
|
|
IN EFI_STATUS Status,
|
|
IN CHAR16 *ExitData,
|
|
IN UINTN ExitDataSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Hook point after a boot attempt fails.
|
|
|
|
Arguments:
|
|
|
|
Option - Pointer to Boot Option that failed to boot.
|
|
|
|
Status - Status returned from failed boot.
|
|
|
|
ExitData - Exit data returned from failed boot.
|
|
|
|
ExitDataSize - Exit data size returned from failed boot.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
CHAR16 *TmpStr;
|
|
|
|
//
|
|
// If Boot returned with failed status then we need to pop up a UI and wait
|
|
// for user input.
|
|
//
|
|
TmpStr = Option->StatusString;
|
|
if (TmpStr != NULL) {
|
|
BdsLibOutputStrings (gST->ConOut, TmpStr, Option->Description, L"\n\r", NULL);
|
|
gBS->FreePool (TmpStr);
|
|
}
|
|
|
|
}
|
|
|
|
EFI_STATUS
|
|
PlatformBdsNoConsoleAction (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is remained for IBV/OEM to do some platform action,
|
|
if there no console device can be connected.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Direct return success now.
|
|
|
|
--*/
|
|
{
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ConvertSystemTable (
|
|
IN EFI_GUID *TableGuid,
|
|
IN OUT VOID **Table
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Convert ACPI Table /Smbios Table /MP Table if its location is lower than Address:0x100000
|
|
Assumption here:
|
|
As in legacy Bios, ACPI/Smbios/MP table is required to place in E/F Seg,
|
|
So here we just check if the range is E/F seg,
|
|
and if Not, assume the Memory type is EfiACPIReclaimMemory/EfiACPIMemoryNVS
|
|
|
|
Arguments:
|
|
TableGuid - Guid of the table
|
|
Table - pointer to the table
|
|
|
|
Returns:
|
|
EFI_SUCEESS - Convert Table successfully
|
|
Other - Failed
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *AcpiHeader;
|
|
UINTN AcpiTableLen;
|
|
|
|
//
|
|
// If match acpi guid (1.0, 2.0, or later), Convert ACPI table according to version.
|
|
//
|
|
AcpiHeader = (VOID*)(UINTN)(*(UINT64 *)(*Table));
|
|
|
|
if (CompareGuid(TableGuid, &gEfiAcpiTableGuid) || CompareGuid(TableGuid, &gEfiAcpi20TableGuid)){
|
|
if (((EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiHeader)->Reserved == 0x00){
|
|
//
|
|
// If Acpi 1.0 Table, then RSDP structure doesn't contain Length field, use structure size
|
|
//
|
|
AcpiTableLen = sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
|
|
} else if (((EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiHeader)->Reserved >= 0x02){
|
|
//
|
|
// If Acpi 2.0 or later, use RSDP Length fied.
|
|
//
|
|
AcpiTableLen = ((EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiHeader)->Length;
|
|
} else {
|
|
//
|
|
// Invalid Acpi Version, return
|
|
//
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
Status = ConvertAcpiTable (AcpiTableLen, Table);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// If matches smbios guid, convert Smbios table.
|
|
//
|
|
if (CompareGuid(TableGuid, &gEfiSmbiosTableGuid)){
|
|
Status = ConvertSmbiosTable (Table);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// If the table is MP table?
|
|
//
|
|
if (CompareGuid(TableGuid, &gEfiMpsTableGuid)){
|
|
Status = ConvertMpsTable (Table);
|
|
return Status;
|
|
}
|
|
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
UINT8
|
|
GetBufferCheckSum (
|
|
IN VOID * Buffer,
|
|
IN UINTN Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Caculate buffer checksum (8-bit)
|
|
|
|
Arguments:
|
|
Buffer - Pointer to Buffer that to be caculated
|
|
Length - How many bytes are to be caculated
|
|
|
|
Returns:
|
|
Checksum of the buffer
|
|
|
|
--*/
|
|
{
|
|
UINT8 CheckSum;
|
|
UINT8 *Ptr8;
|
|
|
|
CheckSum = 0;
|
|
Ptr8 = (UINT8 *) Buffer;
|
|
|
|
while (Length > 0) {
|
|
CheckSum = (UINT8) (CheckSum + *Ptr8++);
|
|
Length--;
|
|
}
|
|
|
|
return ((0xFF - CheckSum) + 1);
|
|
}
|
|
|
|
EFI_STATUS
|
|
ConvertAcpiTable (
|
|
IN UINTN TableLen,
|
|
IN OUT VOID **Table
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Convert RSDP of ACPI Table if its location is lower than Address:0x100000
|
|
Assumption here:
|
|
As in legacy Bios, ACPI table is required to place in E/F Seg,
|
|
So here we just check if the range is E/F seg,
|
|
and if Not, assume the Memory type is EfiACPIReclaimMemory/EfiACPIMemoryNVS
|
|
|
|
Arguments:
|
|
TableLen - Acpi RSDP length
|
|
Table - pointer to the table
|
|
|
|
Returns:
|
|
EFI_SUCEESS - Convert Table successfully
|
|
Other - Failed
|
|
|
|
--*/
|
|
{
|
|
VOID *AcpiTableOri;
|
|
VOID *AcpiTableNew;
|
|
EFI_STATUS Status;
|
|
EFI_PHYSICAL_ADDRESS BufferPtr;
|
|
|
|
|
|
AcpiTableOri = (VOID *)(UINTN)(*(UINT64*)(*Table));
|
|
if (((UINTN)AcpiTableOri < 0x100000) && ((UINTN)AcpiTableOri > 0xE0000)) {
|
|
BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
|
|
Status = gBS->AllocatePages (
|
|
AllocateMaxAddress,
|
|
EfiACPIMemoryNVS,
|
|
EFI_SIZE_TO_PAGES(TableLen),
|
|
&BufferPtr
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
AcpiTableNew = (VOID *)(UINTN)BufferPtr;
|
|
CopyMem (AcpiTableNew, AcpiTableOri, TableLen);
|
|
} else {
|
|
AcpiTableNew = AcpiTableOri;
|
|
}
|
|
//
|
|
// Change configuration table Pointer
|
|
//
|
|
*Table = AcpiTableNew;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ConvertSmbiosTable (
|
|
IN OUT VOID **Table
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert Smbios Table if the Location of the SMBios Table is lower than Addres 0x100000
|
|
Assumption here:
|
|
As in legacy Bios, Smbios table is required to place in E/F Seg,
|
|
So here we just check if the range is F seg,
|
|
and if Not, assume the Memory type is EfiACPIMemoryNVS/EfiRuntimeServicesData
|
|
Arguments:
|
|
Table - pointer to the table
|
|
|
|
Returns:
|
|
EFI_SUCEESS - Convert Table successfully
|
|
Other - Failed
|
|
|
|
--*/
|
|
{
|
|
SMBIOS_TABLE_ENTRY_POINT *SmbiosTableNew;
|
|
SMBIOS_TABLE_ENTRY_POINT *SmbiosTableOri;
|
|
EFI_STATUS Status;
|
|
UINT32 SmbiosEntryLen;
|
|
UINT32 BufferLen;
|
|
EFI_PHYSICAL_ADDRESS BufferPtr;
|
|
|
|
SmbiosTableNew = NULL;
|
|
SmbiosTableOri = NULL;
|
|
|
|
//
|
|
// Get Smibos configuration Table
|
|
//
|
|
SmbiosTableOri = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN)(*(UINT64*)(*Table));
|
|
|
|
if ((SmbiosTableOri == NULL) ||
|
|
((UINTN)SmbiosTableOri > 0x100000) ||
|
|
((UINTN)SmbiosTableOri < 0xF0000)){
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// Relocate the Smibos memory
|
|
//
|
|
BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
|
|
if (SmbiosTableOri->SmbiosBcdRevision != 0x21) {
|
|
SmbiosEntryLen = SmbiosTableOri->EntryPointLength;
|
|
} else {
|
|
//
|
|
// According to Smbios Spec 2.4, we should set entry point length as 0x1F if version is 2.1
|
|
//
|
|
SmbiosEntryLen = 0x1F;
|
|
}
|
|
BufferLen = SmbiosEntryLen + SYS_TABLE_PAD(SmbiosEntryLen) + SmbiosTableOri->TableLength;
|
|
Status = gBS->AllocatePages (
|
|
AllocateMaxAddress,
|
|
EfiACPIMemoryNVS,
|
|
EFI_SIZE_TO_PAGES(BufferLen),
|
|
&BufferPtr
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
SmbiosTableNew = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN)BufferPtr;
|
|
CopyMem (
|
|
SmbiosTableNew,
|
|
SmbiosTableOri,
|
|
SmbiosEntryLen
|
|
);
|
|
//
|
|
// Get Smbios Structure table address, and make sure the start address is 32-bit align
|
|
//
|
|
BufferPtr += SmbiosEntryLen + SYS_TABLE_PAD(SmbiosEntryLen);
|
|
CopyMem (
|
|
(VOID *)(UINTN)BufferPtr,
|
|
(VOID *)(UINTN)(SmbiosTableOri->TableAddress),
|
|
SmbiosTableOri->TableLength
|
|
);
|
|
SmbiosTableNew->TableAddress = (UINT32)BufferPtr;
|
|
SmbiosTableNew->IntermediateChecksum = 0;
|
|
SmbiosTableNew->IntermediateChecksum =
|
|
GetBufferCheckSum ((UINT8*)SmbiosTableNew + 0x10, SmbiosEntryLen -0x10);
|
|
//
|
|
// Change the SMBIOS pointer
|
|
//
|
|
*Table = SmbiosTableNew;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ConvertMpsTable (
|
|
IN OUT VOID **Table
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert MP Table if the Location of the SMBios Table is lower than Addres 0x100000
|
|
Assumption here:
|
|
As in legacy Bios, MP table is required to place in E/F Seg,
|
|
So here we just check if the range is E/F seg,
|
|
and if Not, assume the Memory type is EfiACPIMemoryNVS/EfiRuntimeServicesData
|
|
Arguments:
|
|
Table - pointer to the table
|
|
|
|
Returns:
|
|
EFI_SUCEESS - Convert Table successfully
|
|
Other - Failed
|
|
|
|
--*/
|
|
{
|
|
UINT32 Data32;
|
|
UINT32 FPLength;
|
|
EFI_LEGACY_MP_TABLE_FLOATING_POINTER *MpsFloatingPointerOri;
|
|
EFI_LEGACY_MP_TABLE_FLOATING_POINTER *MpsFloatingPointerNew;
|
|
EFI_LEGACY_MP_TABLE_HEADER *MpsTableOri;
|
|
EFI_LEGACY_MP_TABLE_HEADER *MpsTableNew;
|
|
VOID *OemTableOri;
|
|
VOID *OemTableNew;
|
|
EFI_STATUS Status;
|
|
EFI_PHYSICAL_ADDRESS BufferPtr;
|
|
|
|
//
|
|
// Get MP configuration Table
|
|
//
|
|
MpsFloatingPointerOri = (EFI_LEGACY_MP_TABLE_FLOATING_POINTER *)(UINTN)(*(UINT64*)(*Table));
|
|
if (!(((UINTN)MpsFloatingPointerOri <= 0x100000) &&
|
|
((UINTN)MpsFloatingPointerOri >= 0xF0000))){
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// Get Floating pointer structure length
|
|
//
|
|
FPLength = MpsFloatingPointerOri->Length * 16;
|
|
Data32 = FPLength + SYS_TABLE_PAD (FPLength);
|
|
MpsTableOri = (EFI_LEGACY_MP_TABLE_HEADER *)(UINTN)(MpsFloatingPointerOri->PhysicalAddress);
|
|
if (MpsTableOri != NULL) {
|
|
Data32 += MpsTableOri->BaseTableLength;
|
|
Data32 += MpsTableOri->ExtendedTableLength;
|
|
if (MpsTableOri->OemTablePointer != 0x00) {
|
|
Data32 += SYS_TABLE_PAD (Data32);
|
|
Data32 += MpsTableOri->OemTableSize;
|
|
}
|
|
} else {
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// Relocate memory
|
|
//
|
|
BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
|
|
Status = gBS->AllocatePages (
|
|
AllocateMaxAddress,
|
|
EfiACPIMemoryNVS,
|
|
EFI_SIZE_TO_PAGES(Data32),
|
|
&BufferPtr
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
MpsFloatingPointerNew = (EFI_LEGACY_MP_TABLE_FLOATING_POINTER *)(UINTN)BufferPtr;
|
|
CopyMem (MpsFloatingPointerNew, MpsFloatingPointerOri, FPLength);
|
|
//
|
|
// If Mp Table exists
|
|
//
|
|
if (MpsTableOri != NULL) {
|
|
//
|
|
// Get Mps table length, including Ext table
|
|
//
|
|
BufferPtr = BufferPtr + FPLength + SYS_TABLE_PAD (FPLength);
|
|
MpsTableNew = (EFI_LEGACY_MP_TABLE_HEADER *)(UINTN)BufferPtr;
|
|
CopyMem (MpsTableNew, MpsTableOri, MpsTableOri->BaseTableLength + MpsTableOri->ExtendedTableLength);
|
|
|
|
if ((MpsTableOri->OemTableSize != 0x0000) && (MpsTableOri->OemTablePointer != 0x0000)){
|
|
BufferPtr += MpsTableOri->BaseTableLength + MpsTableOri->ExtendedTableLength;
|
|
BufferPtr += SYS_TABLE_PAD (BufferPtr);
|
|
OemTableNew = (VOID *)(UINTN)BufferPtr;
|
|
OemTableOri = (VOID *)(UINTN)MpsTableOri->OemTablePointer;
|
|
CopyMem (OemTableNew, OemTableOri, MpsTableOri->OemTableSize);
|
|
MpsTableNew->OemTablePointer = (UINT32)(UINTN)OemTableNew;
|
|
}
|
|
MpsTableNew->Checksum = 0;
|
|
MpsTableNew->Checksum = GetBufferCheckSum (MpsTableNew, MpsTableOri->BaseTableLength);
|
|
MpsFloatingPointerNew->PhysicalAddress = (UINT32)(UINTN)MpsTableNew;
|
|
MpsFloatingPointerNew->Checksum = 0;
|
|
MpsFloatingPointerNew->Checksum = GetBufferCheckSum (MpsFloatingPointerNew, FPLength);
|
|
}
|
|
//
|
|
// Change the pointer
|
|
//
|
|
*Table = MpsFloatingPointerNew;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|