1716 lines
50 KiB
C
1716 lines
50 KiB
C
/** @file
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012 - 2020, Insyde Software Corporation. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
#include "LegacyBiosInterface.h"
|
|
|
|
#include <Protocol/MpService.h>
|
|
|
|
#include <OemServices/Kernel.h>
|
|
#include <Library/DxeOemSvcKernelLib.h>
|
|
#include "KernelSetupConfig.h"
|
|
|
|
#include <IndustryStandard/Pci.h>
|
|
#include <IndustryStandard/Acpi10.h>
|
|
|
|
#include <Protocol/PciIo.h>
|
|
#include <Protocol/PciRootBridgeIo.h>
|
|
#include <Protocol/LegacyBiosPlatform.h>
|
|
#include <Register/LocalApic.h>
|
|
#include <Register/Cpuid.h>
|
|
|
|
#ifndef MSR_IA32_APIC_BASE_ADDRESS
|
|
#define MSR_IA32_APIC_BASE_ADDRESS 0x1B
|
|
#endif
|
|
|
|
typedef struct {
|
|
UINT32 RegEax;
|
|
UINT32 RegEbx;
|
|
UINT32 RegEcx;
|
|
UINT32 RegEdx;
|
|
} EFI_CPUID_REGISTER;
|
|
|
|
typedef struct {
|
|
UINTN Seg;
|
|
UINTN Bus;
|
|
UINTN Dev;
|
|
UINTN Fun;
|
|
} EFI_PCI_LOCATION;
|
|
|
|
typedef struct {
|
|
EFI_HANDLE Handle;
|
|
PCI_TYPE01 ConfigHeader;
|
|
EFI_PCI_LOCATION Location;
|
|
} EFI_PCI_BRIDGE_INFO;
|
|
|
|
BOOLEAN mLegacyMpInstalled = FALSE;
|
|
|
|
EFI_LEGACY_MP_TABLE_ENTRY_EXT_SYS_ADDR_SPACE_MAPPING mExtSysAddrMapping[] = {
|
|
{0x80, 0x14, 0, 0, 0, 0x1000}
|
|
};
|
|
|
|
EFI_LEGACY_MP_TABLE_ENTRY_EXT_COMPAT_BUS_ADDR_SPACE_MODIFIER mExtBusAddrModifier[] = {
|
|
{0x82, 0x8, 0x0, {0, 0}, 0},
|
|
{0x82, 0x8, 0x0, {0, 0}, 1}
|
|
};
|
|
|
|
typedef struct {
|
|
EFI_PROCESSOR_INFORMATION Info;
|
|
BOOLEAN Valid;
|
|
} LEGACY_MP_TABLE_PROCESSOR_INFORMATION;
|
|
|
|
/**
|
|
Get Bus number from root bridge.
|
|
|
|
@param PciRootBridgeIo This is a PciRootBridgeIo protocol
|
|
@param BusId Bus Number
|
|
|
|
@retval EFI_SUCCESS Retrieve the Minmal Bus number sucess;
|
|
|
|
**/
|
|
EFI_STATUS
|
|
GetBusNumber (
|
|
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
|
|
OUT UINT8 *BusId
|
|
)
|
|
{
|
|
UINT8 *pData;
|
|
|
|
if (PciRootBridgeIo == NULL) {
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **)&pData);
|
|
while (!(*pData == ADDRESS_SPACE_DESCRIPTOR_END_TAG || \
|
|
*pData != ADDRESS_SPACE_DESCRIPTOR_HEAD_TAG)) {
|
|
|
|
if (*(UINT64 *)(pData + ADDRESS_SPACE_DESCRIPTOR_ADDR_LENGTH_OFFSET) != 0) {
|
|
if ((*(pData + ADDRESS_SPACE_DESCRIPTOR_RESOURCE_TYPE_OFFSET)) == ACPI_ADDRESS_SPACE_TYPE_BUS) {
|
|
*BusId = (UINT8)(*(UINT64 *)(pData + ADDRESS_SPACE_DESCRIPTOR_ADDR_RANGE_MIN_OFFSET));
|
|
break;
|
|
}
|
|
}
|
|
pData += ADDRESS_SPACE_DESCRIPTOR_TOTAL_LENGTH;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
To check current Bus entry is for Legacy Bus or not
|
|
|
|
@param pEntry The data pointer of Entry
|
|
|
|
@retval TRUE Current Bus entry is for Legacy Bus
|
|
@retval FALSE Current Bus entry is not for Legacy Bus
|
|
|
|
**/
|
|
BOOLEAN
|
|
IsLegacyBus(
|
|
IN EFI_LEGACY_MP_TABLE_ENTRY_BUS *pEntry
|
|
)
|
|
{
|
|
return (AsciiStrnCmp (pEntry->TypeString, EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_ISA, sizeof(pEntry->TypeString)) == 0 ||
|
|
AsciiStrnCmp (pEntry->TypeString, EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_EISA, sizeof(pEntry->TypeString)) == 0 );
|
|
}
|
|
|
|
|
|
/**
|
|
Assign a Bus ID for Legacy Bus
|
|
|
|
@param pStartEntry The data pointer of Entry
|
|
@param BusCount The number of Bus Entries
|
|
|
|
**/
|
|
VOID
|
|
AssignLegacyBusId (
|
|
IN EFI_LEGACY_MP_TABLE_ENTRY_BUS *pStartEntry,
|
|
IN UINTN BusCount
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINT8 LastId;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_BUS *pEntry;
|
|
|
|
LastId = 0;
|
|
pEntry = pStartEntry;
|
|
for (Index = 0; Index < BusCount; Index++) {
|
|
if (!IsLegacyBus (pEntry)) {
|
|
if (pEntry->Id > LastId ) {
|
|
LastId = pEntry->Id;
|
|
}
|
|
}
|
|
pEntry++;
|
|
}
|
|
|
|
pEntry = pStartEntry;
|
|
for (Index = 0; Index < BusCount; Index++) {
|
|
if (IsLegacyBus (pEntry)) {
|
|
LastId++;
|
|
pEntry->Id = LastId;
|
|
}
|
|
pEntry++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
Insert a new bus entry into MP table in increasing order
|
|
|
|
@param pEntry The data pointer of Entry
|
|
@param TotalEntries The Totol number of BusEntries that Built.
|
|
@param EntryToIns One item is ready to insert the Bus Entry
|
|
|
|
@retval EFI_SUCCESS Update entry success
|
|
|
|
**/
|
|
EFI_STATUS
|
|
InsertBusEntries (
|
|
IN EFI_LEGACY_MP_TABLE_ENTRY_BUS *BusStartEntry,
|
|
IN OUT UINT8 *BusCount,
|
|
IN EFI_LEGACY_MP_TABLE_ENTRY_BUS *EntryToIns
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINTN Index2;
|
|
UINT8 BuiltEntry;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_BUS *PosToIns;
|
|
|
|
BuiltEntry = *BusCount;
|
|
(*BusCount)++;
|
|
|
|
if (IsLegacyBus (EntryToIns)) {
|
|
|
|
PosToIns = (BusStartEntry + BuiltEntry);
|
|
|
|
CopyMem (
|
|
PosToIns,
|
|
EntryToIns,
|
|
sizeof(EFI_LEGACY_MP_TABLE_ENTRY_BUS));
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
if (BuiltEntry == 0) {
|
|
CopyMem (BusStartEntry, EntryToIns, sizeof(EFI_LEGACY_MP_TABLE_ENTRY_BUS));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
for (Index = 0; Index < BuiltEntry; Index++) {
|
|
PosToIns = (BusStartEntry + Index);
|
|
if (IsLegacyBus (PosToIns)) {
|
|
break;
|
|
}
|
|
|
|
if (EntryToIns->Id < PosToIns->Id) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (Index2 = BuiltEntry; Index2 > Index; Index2--) {
|
|
PosToIns = (BusStartEntry + Index2);
|
|
CopyMem (PosToIns, PosToIns - 1, sizeof(EFI_LEGACY_MP_TABLE_ENTRY_BUS));
|
|
}
|
|
PosToIns = (BusStartEntry + Index2);
|
|
CopyMem (PosToIns, EntryToIns, sizeof(EFI_LEGACY_MP_TABLE_ENTRY_BUS));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Creat one Bus Item into BusEntry
|
|
|
|
Arguments:
|
|
@param pEntry The data pointer of Entry
|
|
@param TotalEntries The Totol number of BusEntries that Built.
|
|
@param BusId Bus Number
|
|
@param DeviceType A device type obtains from ClassCode
|
|
|
|
@retval EFI_SUCCESS Update entry success
|
|
|
|
**/
|
|
EFI_STATUS
|
|
CreateOneBusEntry (
|
|
IN OUT EFI_LEGACY_MP_TABLE_ENTRY_BUS *BusStartEntry,
|
|
IN OUT UINT8 *BusCount,
|
|
IN UINT8 BusId,
|
|
IN UINT8 DeviceType
|
|
)
|
|
{
|
|
EFI_LEGACY_MP_TABLE_ENTRY_BUS TempEntry;
|
|
|
|
TempEntry.EntryType = EFI_LEGACY_MP_TABLE_ENTRY_TYPE_BUS;
|
|
TempEntry.Id = BusId;
|
|
|
|
switch (DeviceType) {
|
|
|
|
case PCI_CLASS_BRIDGE_ISA:
|
|
//
|
|
// ISA
|
|
//
|
|
CopyMem (
|
|
TempEntry.TypeString,
|
|
EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_ISA,
|
|
sizeof(TempEntry.TypeString));
|
|
//
|
|
// Assign 0 for legacy bus, it will be re-assign to proper bus id at the end
|
|
//
|
|
TempEntry.Id = 0;
|
|
break;
|
|
|
|
case PCI_CLASS_BRIDGE_EISA:
|
|
//
|
|
// EISA
|
|
//
|
|
CopyMem (
|
|
TempEntry.TypeString,
|
|
EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_EISA,
|
|
sizeof(TempEntry.TypeString));
|
|
|
|
TempEntry.Id = 0;
|
|
break;
|
|
|
|
case PCI_CLASS_BRIDGE_HOST:
|
|
case PCI_CLASS_BRIDGE_P2P:
|
|
//
|
|
// P2P
|
|
//
|
|
CopyMem (
|
|
TempEntry.TypeString,
|
|
EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_PCI,
|
|
sizeof(TempEntry.TypeString));
|
|
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Unsupported
|
|
//
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
InsertBusEntries (BusStartEntry, BusCount, &TempEntry);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Update the Processor Entries, Report Cpu in order, by Modern or Legacy ordering
|
|
|
|
@param pEntry The data pointer of Entry
|
|
@param TotalEntries Return the total entry number in MP Table
|
|
@param ApicBaseAddress The base address of Local Apic
|
|
|
|
@retval EFI_SUCCESS Update entry success
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UpdateProcessorEntries (
|
|
IN OUT UINT8 **pEntry,
|
|
IN OUT UINTN *TotalEntries,
|
|
IN UINT32 ApicBaseAddress
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_PROCESSOR *ProcessEntry;
|
|
EFI_CPUID_REGISTER CpuidRegisters;
|
|
UINT32 ApicVersion32;
|
|
UINT8 Version;
|
|
EFI_MP_SERVICES_PROTOCOL *MpService;
|
|
UINTN NumberOfCPUs;
|
|
UINTN NumberOfEnabledCPUs;
|
|
EFI_PROCESSOR_INFORMATION MpContext;
|
|
EFI_PROCESSOR_INFORMATION *MpArray;
|
|
UINTN ArraySize;
|
|
UINTN TotalCpu;
|
|
UINTN Index;
|
|
UINTN VarSize;
|
|
UINT8 LegacyModern;
|
|
EFI_GUID SystemConfigurationGuid = SYSTEM_CONFIGURATION_GUID;
|
|
LEGACY_MP_TABLE_PROCESSOR_INFORMATION *Cpu;
|
|
LEGACY_MP_TABLE_PROCESSOR_INFORMATION *pData;
|
|
UINT32 MaxPkg;
|
|
UINT32 MaxCore;
|
|
UINT32 MaxThread;
|
|
UINT32 PkgIdx;
|
|
UINT32 CoreIdx;
|
|
|
|
NumberOfEnabledCPUs = 0;
|
|
NumberOfCPUs = 0;
|
|
VarSize = 1;
|
|
TotalCpu = 0;
|
|
ArraySize = 0;
|
|
MaxPkg = 0;
|
|
MaxCore = 0;
|
|
MaxThread = 0;
|
|
MpArray = NULL;
|
|
Cpu = NULL;
|
|
|
|
ProcessEntry = (EFI_LEGACY_MP_TABLE_ENTRY_PROCESSOR *)(*pEntry);
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiMpServiceProtocolGuid,
|
|
NULL,
|
|
(VOID **)&MpService);
|
|
|
|
if (Status != EFI_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Determine the number of processors
|
|
//
|
|
Status = MpService->GetNumberOfProcessors (MpService, &NumberOfCPUs, &NumberOfEnabledCPUs);
|
|
|
|
if (Status != EFI_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
MpArray = AllocatePool (sizeof(EFI_PROCESSOR_INFORMATION) * NumberOfCPUs);
|
|
if (MpArray == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
ZeroMem (MpArray, sizeof(EFI_PROCESSOR_INFORMATION) * NumberOfCPUs);
|
|
|
|
ApicVersion32 = *(UINT32 *)(UINTN)(ApicBaseAddress + APIC_REGISTER_APIC_VERSION_OFFSET);
|
|
Version = (UINT8)(ApicVersion32 & 0xFF);
|
|
AsmCpuid (CPUID_VERSION_INFO, &CpuidRegisters.RegEax, &CpuidRegisters.RegEbx, &CpuidRegisters.RegEcx, &CpuidRegisters.RegEdx);
|
|
|
|
for (Index = 0; Index < NumberOfCPUs; Index++) {
|
|
|
|
Status = MpService->GetProcessorInfo (
|
|
MpService,
|
|
Index,
|
|
&MpContext);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
goto Entry_Error;
|
|
}
|
|
|
|
//
|
|
// Collecting all processor's infomation
|
|
//
|
|
CopyMem (
|
|
&MpArray[Index],
|
|
&MpContext,
|
|
sizeof(EFI_PROCESSOR_INFORMATION));
|
|
//
|
|
// Determine maximum Package, Core, Thread number by Location info
|
|
//
|
|
if (MpContext.Location.Package > MaxPkg) {
|
|
MaxPkg = MpContext.Location.Package;
|
|
}
|
|
if (MpContext.Location.Core > MaxCore) {
|
|
MaxCore = MpContext.Location.Core;
|
|
}
|
|
if (MpContext.Location.Thread > MaxThread) {
|
|
MaxThread = MpContext.Location.Thread;
|
|
}
|
|
}
|
|
|
|
MaxPkg++;
|
|
MaxCore++;
|
|
MaxThread++;
|
|
|
|
ArraySize = (UINTN)(sizeof(LEGACY_MP_TABLE_PROCESSOR_INFORMATION)*(MaxPkg)*(MaxCore)*(MaxThread));
|
|
|
|
Cpu = AllocatePool (ArraySize);
|
|
if (Cpu == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Entry_Error;
|
|
}
|
|
|
|
ZeroMem (Cpu, ArraySize);
|
|
|
|
for (Index = 0; Index < NumberOfCPUs; Index++) {
|
|
|
|
pData = Cpu + (MpArray[Index].Location.Package * MaxCore * MaxThread) \
|
|
+ (MpArray[Index].Location.Core * MaxThread) \
|
|
+ MpArray[Index].Location.Thread;
|
|
|
|
if (pData->Valid) {
|
|
//
|
|
// Skip if there is a valid info exist in same location.
|
|
//
|
|
continue;
|
|
}
|
|
CopyMem (&pData->Info,
|
|
&MpArray[Index],
|
|
sizeof(EFI_PROCESSOR_INFORMATION));
|
|
pData->Valid = TRUE;
|
|
}
|
|
|
|
//
|
|
// Determine what ordering type is used, by variable "MpTableCpuOrdering".
|
|
// If platform does not has this variable, handle it as Modern ordering.
|
|
//
|
|
Status = gRT->GetVariable (
|
|
L"MpTableCpuOrdering",
|
|
&SystemConfigurationGuid,
|
|
NULL,
|
|
&VarSize,
|
|
&LegacyModern);
|
|
|
|
if (LegacyModern == MADT_MODERN_MODE || Status != EFI_SUCCESS) {
|
|
//
|
|
// By Modern ordering
|
|
//
|
|
for (PkgIdx = 0; PkgIdx < MaxPkg; PkgIdx++) {
|
|
for (CoreIdx = 0; CoreIdx < MaxCore; CoreIdx++) {
|
|
|
|
pData = Cpu + (PkgIdx*MaxCore*MaxThread) + (CoreIdx*MaxThread);
|
|
|
|
if (!(pData->Info.StatusFlag & PROCESSOR_HEALTH_STATUS_BIT) || !pData->Valid) {
|
|
//
|
|
// Don't report unhealthy processor or data is invalid
|
|
//
|
|
continue;
|
|
}
|
|
|
|
ProcessEntry->Ver = Version;
|
|
|
|
CopyMem (
|
|
&(ProcessEntry->Signature),
|
|
&(CpuidRegisters.RegEax),
|
|
sizeof(UINT32));
|
|
|
|
CopyMem (
|
|
&(ProcessEntry->Features),
|
|
&(CpuidRegisters.RegEdx),
|
|
sizeof(UINT32));
|
|
|
|
ProcessEntry->EntryType = EFI_LEGACY_MP_TABLE_ENTRY_TYPE_PROCESSOR;
|
|
|
|
ProcessEntry->Id = (UINT8)pData->Info.ProcessorId;
|
|
ProcessEntry->Flags.Bsp = pData->Info.StatusFlag & PROCESSOR_AS_BSP_BIT;
|
|
ProcessEntry->Flags.Enabled = (pData->Info.StatusFlag & PROCESSOR_ENABLED_BIT) >> 1;
|
|
|
|
ProcessEntry++;
|
|
TotalCpu++;
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// By Legacy ordering
|
|
//
|
|
for (CoreIdx = 0; CoreIdx < MaxCore; CoreIdx++) {
|
|
for (PkgIdx = 0; PkgIdx < MaxPkg; PkgIdx++) {
|
|
|
|
pData = Cpu + (PkgIdx*MaxCore*MaxThread) + (CoreIdx*MaxThread);
|
|
|
|
if (!(pData->Info.StatusFlag & PROCESSOR_HEALTH_STATUS_BIT) || !pData->Valid) {
|
|
//
|
|
// Don't report unhealthy processor or data is invalid
|
|
//
|
|
continue;
|
|
}
|
|
|
|
ProcessEntry->Ver = Version;
|
|
|
|
CopyMem (
|
|
&(ProcessEntry->Signature),
|
|
&(CpuidRegisters.RegEax),
|
|
sizeof(UINT32));
|
|
|
|
CopyMem (
|
|
&(ProcessEntry->Features),
|
|
&(CpuidRegisters.RegEdx),
|
|
sizeof(UINT32));
|
|
|
|
ProcessEntry->EntryType = EFI_LEGACY_MP_TABLE_ENTRY_TYPE_PROCESSOR;
|
|
|
|
ProcessEntry->Id = (UINT8)pData->Info.ProcessorId;
|
|
ProcessEntry->Flags.Bsp = pData->Info.StatusFlag & PROCESSOR_AS_BSP_BIT;
|
|
ProcessEntry->Flags.Enabled = (pData->Info.StatusFlag & PROCESSOR_ENABLED_BIT) >> 1;
|
|
|
|
ProcessEntry++;
|
|
TotalCpu++;
|
|
}
|
|
}
|
|
}
|
|
|
|
*TotalEntries += TotalCpu;
|
|
(*pEntry) = (UINT8 *)ProcessEntry;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
Entry_Error:
|
|
|
|
if (MpArray != NULL) {
|
|
FreePool (MpArray);
|
|
}
|
|
if (Cpu != NULL) {
|
|
FreePool (Cpu);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Update the Bus Entries
|
|
|
|
Arguments:
|
|
@param pEntry The data pointer of Entry
|
|
@param TotalEntries Return the total entry number in MP Table
|
|
@param HandleCount The total number of Handle with Pci IO protocol
|
|
@param HandleBuffer The Buffer's pointer
|
|
|
|
@retval EFI_SUCCESS Update entry success
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UpdateBusEntries (
|
|
IN OUT UINT8 **pEntry,
|
|
IN OUT UINTN *TotalEntries,
|
|
IN UINTN PciBridgeInfoCount,
|
|
IN EFI_PCI_BRIDGE_INFO *PciBridgeInfoBuffer,
|
|
IN UINTN RootBridgeHandleCount,
|
|
IN EFI_HANDLE *RootBridgeHandleBuffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
|
|
UINTN Index;
|
|
UINT8 DeviceType;
|
|
UINT8 BusId;
|
|
UINT8 BusCount;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_BUS *BusStartEntry;
|
|
|
|
BusCount = 0;
|
|
BusStartEntry = (EFI_LEGACY_MP_TABLE_ENTRY_BUS *)(*pEntry);
|
|
|
|
if (PciBridgeInfoBuffer != NULL) {
|
|
for (Index = 0; Index < PciBridgeInfoCount; Index++) {
|
|
|
|
if (PciBridgeInfoBuffer[Index].ConfigHeader.Hdr.ClassCode[2] != PCI_CLASS_BRIDGE) {
|
|
continue;
|
|
}
|
|
|
|
if (PciBridgeInfoBuffer[Index].ConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_HOST) {
|
|
continue;
|
|
}
|
|
|
|
DeviceType = PciBridgeInfoBuffer[Index].ConfigHeader.Hdr.ClassCode[1];
|
|
BusId = PciBridgeInfoBuffer[Index].ConfigHeader.Bridge.SecondaryBus;
|
|
|
|
CreateOneBusEntry(BusStartEntry, &BusCount, BusId, DeviceType);
|
|
}
|
|
}
|
|
|
|
if (RootBridgeHandleBuffer != NULL) {
|
|
for (Index = 0; Index < RootBridgeHandleCount; Index++) {
|
|
|
|
Status = gBS->HandleProtocol (
|
|
RootBridgeHandleBuffer[Index],
|
|
&gEfiPciRootBridgeIoProtocolGuid,
|
|
(VOID **)&PciRootBridgeIo);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
Status = GetBusNumber (PciRootBridgeIo, &BusId);
|
|
if (EFI_ERROR(Status)) {
|
|
continue;
|
|
}
|
|
|
|
DeviceType = PCI_CLASS_BRIDGE_HOST;
|
|
CreateOneBusEntry(BusStartEntry, &BusCount, BusId, DeviceType);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Re-assign to proper bus id
|
|
//
|
|
AssignLegacyBusId (BusStartEntry, BusCount);
|
|
|
|
*TotalEntries += BusCount;
|
|
(*pEntry) = (UINT8 *)(BusStartEntry + BusCount);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Update the I/O APIC Entries
|
|
|
|
@param pEntry The data pointer of Entry
|
|
@param TotalEntries Return the total entry number in MP Table
|
|
|
|
@retval EFI_SUCCESS Update entry success
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UpdateIoApicEntries (
|
|
IN OUT UINT8 **pEntry,
|
|
IN OUT UINTN *TotalEntries,
|
|
IN UINTN NumOfIoApic,
|
|
IN EFI_LEGACY_MP_TABLE_ENTRY_IOAPIC *pIoApicEntry
|
|
)
|
|
{
|
|
EFI_LEGACY_MP_TABLE_ENTRY_IOAPIC *IoApicEntry;
|
|
UINTN Index;
|
|
|
|
if (pIoApicEntry == NULL) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
IoApicEntry = (EFI_LEGACY_MP_TABLE_ENTRY_IOAPIC *)(*pEntry);
|
|
|
|
for (Index = 0; Index < NumOfIoApic; Index++) {
|
|
|
|
if (pIoApicEntry->EntryType != EFI_LEGACY_MP_TABLE_ENTRY_TYPE_IOAPIC) {
|
|
pIoApicEntry++;
|
|
continue;
|
|
}
|
|
|
|
CopyMem (
|
|
IoApicEntry,
|
|
pIoApicEntry,
|
|
sizeof(EFI_LEGACY_MP_TABLE_ENTRY_IOAPIC));
|
|
|
|
pIoApicEntry++;
|
|
(*TotalEntries)++;
|
|
IoApicEntry++;
|
|
}
|
|
|
|
*pEntry = (UINT8 *)IoApicEntry;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Check the PCI bridge exist or not.
|
|
|
|
@param pIoApicIntEntrySlot Slot entry
|
|
@param BusStartEntries The pointer of first Bus entry
|
|
@param PciBridgeInfoCount Array size of the PciBridgeInfo array
|
|
@param PciBridgeInfoBuffer A array carrying on PciBridgeInfo.
|
|
@param Index Position in the PciBridgeInfo array.
|
|
|
|
@retval EFI_SUCCESS Find a legacy bus entry
|
|
@retval EFI_NOT_FOUND does not find a legacy bus entry
|
|
**/
|
|
EFI_STATUS
|
|
CheckDeviceStatus (
|
|
IN MP_TABLE_ENTRY_IO_INT_SLOT *pIoApicIntEntrySlot,
|
|
IN UINTN PciBridgeInfoCount,
|
|
IN EFI_PCI_BRIDGE_INFO *PciBridgeInfoBuffer,
|
|
OUT UINTN *PciBridgeInfoIndex
|
|
)
|
|
{
|
|
UINTN FirstCell, LastCell;
|
|
UINTN HandleAddress, EntryAddress;
|
|
UINTN CurrentMid, FormerMid;
|
|
|
|
EntryAddress = EFI_PCI_ADDRESS (pIoApicIntEntrySlot->BridgeBus, pIoApicIntEntrySlot->BridgeDev, pIoApicIntEntrySlot->BridgeFunc, 0);
|
|
|
|
LastCell = PciBridgeInfoCount - 1;
|
|
FirstCell = 0;
|
|
CurrentMid = (FirstCell + LastCell) / 2;
|
|
FormerMid = FirstCell;
|
|
|
|
do {
|
|
FormerMid = CurrentMid;
|
|
HandleAddress = EFI_PCI_ADDRESS (PciBridgeInfoBuffer[CurrentMid].Location.Bus, PciBridgeInfoBuffer[CurrentMid].Location.Dev, PciBridgeInfoBuffer[CurrentMid].Location.Fun, 0);
|
|
|
|
if (EntryAddress == HandleAddress) {
|
|
*PciBridgeInfoIndex = CurrentMid;
|
|
return EFI_SUCCESS;
|
|
}
|
|
else if(EntryAddress > HandleAddress) {
|
|
FirstCell = CurrentMid + 1;
|
|
}
|
|
else {
|
|
LastCell = CurrentMid - 1;
|
|
}
|
|
|
|
CurrentMid = (FirstCell + LastCell) / 2;
|
|
} while (FormerMid != CurrentMid);
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Search the first legacy Bus entry
|
|
|
|
@param BusStartEntries The pointer of first Bus entry
|
|
@param PciBridgeInfoCount This is a array size of the PciBridgeInfo array
|
|
@param PciBridgeInfoBuffer This is a array carrying on PciBridgeInfo.
|
|
@param LegacyBusId The bus id of Legacy bus.
|
|
|
|
@retval EFI_SUCCESS Find a legacy bus entry
|
|
@retval EFI_NOT_FOUND does not find a legacy bus entry
|
|
**/
|
|
EFI_STATUS
|
|
LocateLegacyBus (
|
|
IN EFI_LEGACY_MP_TABLE_ENTRY_BUS *BusStartEntries,
|
|
IN UINTN PciBridgeInfoCount,
|
|
IN EFI_PCI_BRIDGE_INFO *PciBridgeInfoBuffer,
|
|
OUT UINT8 *LegacyBusId
|
|
)
|
|
{
|
|
UINTN Index;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_BUS *BusEntries;
|
|
|
|
//
|
|
// Legacy Bus
|
|
//
|
|
for (Index = 0; Index < PciBridgeInfoCount; Index++) {
|
|
|
|
if (PciBridgeInfoBuffer[Index].ConfigHeader.Hdr.ClassCode[2] != PCI_CLASS_BRIDGE) {
|
|
continue;
|
|
}
|
|
|
|
BusEntries = BusStartEntries;
|
|
switch (PciBridgeInfoBuffer[Index].ConfigHeader.Hdr.ClassCode[1]) {
|
|
|
|
case PCI_CLASS_BRIDGE_EISA:
|
|
while (BusEntries->EntryType == EFI_LEGACY_MP_TABLE_ENTRY_TYPE_BUS) {
|
|
if (AsciiStrnCmp (BusEntries->TypeString, EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_EISA, sizeof(BusEntries->TypeString)) == 0) {
|
|
*LegacyBusId = BusEntries->Id;
|
|
return EFI_SUCCESS;
|
|
}
|
|
BusEntries++;
|
|
}
|
|
break;
|
|
|
|
case PCI_CLASS_BRIDGE_ISA:
|
|
while (BusEntries->EntryType == EFI_LEGACY_MP_TABLE_ENTRY_TYPE_BUS) {
|
|
if (AsciiStrnCmp (BusEntries->TypeString, EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_ISA, sizeof(BusEntries->TypeString)) == 0) {
|
|
*LegacyBusId = BusEntries->Id;
|
|
return EFI_SUCCESS;
|
|
break;
|
|
}
|
|
BusEntries++;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Non-Legacy
|
|
//
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
|
|
/**
|
|
Update the I/O Interrupt Assignment Entries
|
|
|
|
@param pEntry The data pointer of Entry
|
|
@param TotalEntries Return the total entry number in MP Table
|
|
@param BusStartEntries The pointer of first Bus entry
|
|
@param PciBridgeInfoCount This is a array size of the PciBridgeInfo array
|
|
@param PciBridgeInfoBuffer This is a array carrying on PciBridgeInfo.
|
|
@param NumOfIoApic The quantity of IoApic entry
|
|
@param pIoApicEntry The array of IoApic Entry
|
|
@param NumOfIoApicIntLegacy The quantity of Interrupt Entry on legacy bus.
|
|
@param pIoApicIntEntryLegacyHead The array of Interrupt Entry on legacy bus.
|
|
@param NumOfIoApicInt The quantity of Interrupt Entry on the first bus.
|
|
@param pIoApicIntEntryHead The array of Interrupt Entry on the first bus.
|
|
@param NumOfIoApicIntSlot The quantity of Interrupt Entry on the slot
|
|
@param pIoApicIntEntrySlotHead The array of Interrupt Entry on the slot
|
|
|
|
@retval EFI_SUCCESS Update entry success
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UpdateIoApicIntEntries (
|
|
IN OUT UINT8 **pEntry,
|
|
IN OUT UINTN *TotalEntries,
|
|
IN EFI_LEGACY_MP_TABLE_ENTRY_BUS *BusStartEntries,
|
|
IN UINTN PciBridgeInfoCount,
|
|
IN EFI_PCI_BRIDGE_INFO *PciBridgeInfoBuffer,
|
|
IN UINTN NumOfIoApic,
|
|
IN EFI_LEGACY_MP_TABLE_ENTRY_IOAPIC *pIoApicEntry,
|
|
IN UINTN NumOfIoApicIntLegacy,
|
|
IN EFI_LEGACY_MP_TABLE_ENTRY_IO_INT *pIoApicIntEntryLegacyHead,
|
|
IN UINTN NumOfIoApicInt,
|
|
IN EFI_LEGACY_MP_TABLE_ENTRY_IO_INT *pIoApicIntEntryHead,
|
|
IN UINTN NumOfIoApicIntSlot,
|
|
IN MP_TABLE_ENTRY_IO_INT_SLOT *pIoApicIntEntrySlotHead
|
|
)
|
|
{
|
|
EFI_STATUS LegacyBusStatus, DeviceStatus;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_IO_INT *IoApicIntEntry;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_IO_INT *pIoApicIntEntry;
|
|
MP_TABLE_ENTRY_IO_INT_SLOT *pIoApicIntEntrySlot;
|
|
UINTN EntryIndex;
|
|
UINTN PciBridgeInfoIndex;
|
|
UINT8 LegacyBusId;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_IO_INT *pIoApicIntEntryLegacy;
|
|
UINTN IoApicIndex;
|
|
UINTN CommonCount, CommonIndex;
|
|
UINTN FormerAddress, CurrentAddress;
|
|
|
|
LegacyBusId = 0;
|
|
|
|
if (pIoApicEntry == NULL || pIoApicIntEntryLegacyHead == NULL || \
|
|
pIoApicIntEntryHead == NULL || pIoApicIntEntrySlotHead == NULL) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
IoApicIntEntry = (EFI_LEGACY_MP_TABLE_ENTRY_IO_INT *)(*pEntry);
|
|
|
|
//
|
|
// Legacy Bus
|
|
//
|
|
LegacyBusStatus = LocateLegacyBus (
|
|
BusStartEntries,
|
|
PciBridgeInfoCount,
|
|
PciBridgeInfoBuffer,
|
|
&LegacyBusId);
|
|
|
|
for (IoApicIndex = 0; IoApicIndex < NumOfIoApic; IoApicIndex++) {
|
|
pIoApicIntEntryLegacy = pIoApicIntEntryLegacyHead;
|
|
if (!EFI_ERROR(LegacyBusStatus) && NumOfIoApicIntLegacy > 0) {
|
|
for (EntryIndex = 0; EntryIndex < NumOfIoApicIntLegacy; EntryIndex++) {
|
|
if (pIoApicIntEntryLegacy->EntryType != EFI_LEGACY_MP_TABLE_ENTRY_TYPE_IO_INT || \
|
|
pIoApicIntEntryLegacy->DestApicId != pIoApicEntry[IoApicIndex].Id) {
|
|
|
|
pIoApicIntEntryLegacy++;
|
|
continue;
|
|
}
|
|
|
|
CopyMem (
|
|
IoApicIntEntry,
|
|
pIoApicIntEntryLegacy,
|
|
sizeof(EFI_LEGACY_MP_TABLE_ENTRY_IO_INT));
|
|
|
|
IoApicIntEntry->SourceBusId = LegacyBusId;
|
|
pIoApicIntEntryLegacy++;
|
|
(*TotalEntries)++;
|
|
IoApicIntEntry++;
|
|
}
|
|
|
|
}
|
|
(*pEntry) = (UINT8 *)(IoApicIntEntry);
|
|
|
|
//
|
|
// Built-in
|
|
//
|
|
pIoApicIntEntry = pIoApicIntEntryHead;
|
|
for (EntryIndex = 0; EntryIndex < NumOfIoApicInt; EntryIndex++) {
|
|
if (pIoApicIntEntry->EntryType != EFI_LEGACY_MP_TABLE_ENTRY_TYPE_IO_INT || \
|
|
pIoApicIntEntry->DestApicId != pIoApicEntry[IoApicIndex].Id) {
|
|
|
|
pIoApicIntEntry++;
|
|
continue;
|
|
}
|
|
|
|
CopyMem (
|
|
IoApicIntEntry,
|
|
pIoApicIntEntry,
|
|
sizeof(EFI_LEGACY_MP_TABLE_ENTRY_IO_INT));
|
|
|
|
pIoApicIntEntry++;
|
|
(*TotalEntries)++;
|
|
IoApicIntEntry++;
|
|
}
|
|
|
|
(*pEntry) = (UINT8 *)(IoApicIntEntry);
|
|
|
|
//
|
|
// Pci Slot
|
|
//
|
|
if (NumOfIoApicIntSlot == 0) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
pIoApicIntEntrySlot = pIoApicIntEntrySlotHead;
|
|
|
|
for (EntryIndex = 0; EntryIndex < NumOfIoApicIntSlot; EntryIndex += CommonCount) {
|
|
|
|
CommonCount = 1;
|
|
|
|
if (pIoApicIntEntrySlot->SlotIrqTable.DestApicId != pIoApicEntry[IoApicIndex].Id) {
|
|
pIoApicIntEntrySlot++;
|
|
continue;
|
|
}
|
|
|
|
DeviceStatus = CheckDeviceStatus (pIoApicIntEntrySlot, PciBridgeInfoCount, PciBridgeInfoBuffer, &PciBridgeInfoIndex);
|
|
|
|
FormerAddress = (UINTN) EFI_PCI_ADDRESS (pIoApicIntEntrySlot[0].BridgeBus, pIoApicIntEntrySlot[0].BridgeDev, pIoApicIntEntrySlot[0].BridgeFunc, pIoApicIntEntrySlot[0].SlotIrqTable.SourceBusId);
|
|
CurrentAddress = FormerAddress;
|
|
while ((EntryIndex + CommonCount < NumOfIoApicIntSlot) && (FormerAddress == CurrentAddress)) {
|
|
CurrentAddress = (UINTN) EFI_PCI_ADDRESS (pIoApicIntEntrySlot[CommonCount].BridgeBus, pIoApicIntEntrySlot[CommonCount].BridgeDev, pIoApicIntEntrySlot[CommonCount].BridgeFunc, pIoApicIntEntrySlot[CommonCount].SlotIrqTable.SourceBusId);
|
|
if (FormerAddress == CurrentAddress) {
|
|
CommonCount++;
|
|
}
|
|
}
|
|
|
|
if (!EFI_ERROR(DeviceStatus)) {
|
|
for (CommonIndex = 0; CommonIndex < CommonCount; CommonIndex++) {
|
|
pIoApicIntEntrySlot->SlotIrqTable.SourceBusId = PciBridgeInfoBuffer[PciBridgeInfoIndex].ConfigHeader.Bridge.SecondaryBus;
|
|
|
|
CopyMem (
|
|
IoApicIntEntry,
|
|
&pIoApicIntEntrySlot->SlotIrqTable,
|
|
sizeof(EFI_LEGACY_MP_TABLE_ENTRY_IO_INT));
|
|
|
|
(*TotalEntries)++;
|
|
IoApicIntEntry++;
|
|
pIoApicIntEntrySlot++;
|
|
}
|
|
|
|
}
|
|
else {
|
|
pIoApicIntEntrySlot += CommonCount;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
(*pEntry) = (UINT8 *)(IoApicIntEntry);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Update the Local Interrupt Assignment Entries
|
|
|
|
@param pEntry The data pointer of Entry
|
|
@param TotalEntries Return the total entry number in MP Table
|
|
|
|
@retval EFI_SUCCESS Update entry success
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UpdateLocalApicIntEntries (
|
|
IN OUT UINT8 **pEntry,
|
|
IN OUT UINTN *TotalEntries,
|
|
IN UINTN NumOfLocalApicInt,
|
|
IN EFI_LEGACY_MP_TABLE_ENTRY_LOCAL_INT *pLocalApicIntEntry
|
|
)
|
|
{
|
|
EFI_LEGACY_MP_TABLE_ENTRY_LOCAL_INT *LocalApicIntEntry;
|
|
UINTN Index;
|
|
|
|
if (pLocalApicIntEntry == NULL) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
LocalApicIntEntry = (EFI_LEGACY_MP_TABLE_ENTRY_LOCAL_INT *)(*pEntry);
|
|
|
|
for (Index = 0; Index < NumOfLocalApicInt; Index++) {
|
|
|
|
if (pLocalApicIntEntry->EntryType != EFI_LEGACY_MP_TABLE_ENTRY_TYPE_LOCAL_INT) {
|
|
pLocalApicIntEntry++;
|
|
continue;
|
|
}
|
|
|
|
CopyMem (
|
|
LocalApicIntEntry,
|
|
pLocalApicIntEntry,
|
|
sizeof(EFI_LEGACY_MP_TABLE_ENTRY_LOCAL_INT));
|
|
|
|
pLocalApicIntEntry++;
|
|
(*TotalEntries)++;
|
|
LocalApicIntEntry++;
|
|
|
|
}
|
|
|
|
(*pEntry) = (UINT8 *)(LocalApicIntEntry);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Update the extended System Address Space Mapping Entries
|
|
|
|
@param pEntry The data pointer of Entry
|
|
@param HandleCount The total number of Handles with Pci IO protocol
|
|
@param HandleBuffer The Buffer's pointer
|
|
|
|
@retval EFI_SUCCESS Update entry success
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UpdateExtSysAddrMappingEntries (
|
|
IN OUT UINT8 **pEntry,
|
|
IN UINTN BridgeHandleCount,
|
|
IN EFI_HANDLE *BridgeHandleBuffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
|
|
UINT8 *pData;
|
|
UINTN NumOfExtSysAddrMapping;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_EXT_SYS_ADDR_SPACE_MAPPING *pExtBusAddrMapping;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_EXT_SYS_ADDR_SPACE_MAPPING *TempEntry;
|
|
|
|
TempEntry = (EFI_LEGACY_MP_TABLE_ENTRY_EXT_SYS_ADDR_SPACE_MAPPING *)(*pEntry);
|
|
|
|
NumOfExtSysAddrMapping = sizeof(mExtSysAddrMapping) / sizeof(mExtSysAddrMapping[0]);
|
|
pExtBusAddrMapping = &mExtSysAddrMapping[0];
|
|
|
|
for (Index = 0; Index < NumOfExtSysAddrMapping; Index++) {
|
|
|
|
if (pExtBusAddrMapping->EntryType != EFI_LEGACY_MP_TABLE_ENTRY_EXT_TYPE_SYS_ADDR_SPACE_MAPPING) {
|
|
pExtBusAddrMapping++;
|
|
continue;
|
|
}
|
|
|
|
CopyMem (
|
|
TempEntry,
|
|
pExtBusAddrMapping,
|
|
sizeof(EFI_LEGACY_MP_TABLE_ENTRY_EXT_SYS_ADDR_SPACE_MAPPING));
|
|
pExtBusAddrMapping++;
|
|
TempEntry++;
|
|
}
|
|
|
|
for (Index = 0; Index < BridgeHandleCount; Index++) {
|
|
|
|
Status = gBS->HandleProtocol (
|
|
BridgeHandleBuffer[Index],
|
|
&gEfiPciRootBridgeIoProtocolGuid,
|
|
(VOID **)&PciRootBridgeIo);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **)&pData);
|
|
while (!(*pData == ADDRESS_SPACE_DESCRIPTOR_END_TAG || \
|
|
*pData != ADDRESS_SPACE_DESCRIPTOR_HEAD_TAG)) {
|
|
|
|
if (*(UINT64 *)(pData + ADDRESS_SPACE_DESCRIPTOR_ADDR_LENGTH_OFFSET) != 0) {
|
|
|
|
TempEntry->EntryType = EFI_LEGACY_MP_TABLE_ENTRY_EXT_TYPE_SYS_ADDR_SPACE_MAPPING;
|
|
TempEntry->Length = sizeof(EFI_LEGACY_MP_TABLE_ENTRY_EXT_SYS_ADDR_SPACE_MAPPING);
|
|
Status = GetBusNumber (PciRootBridgeIo, &TempEntry->BusId);
|
|
if (EFI_ERROR(Status)) {
|
|
continue;
|
|
}
|
|
|
|
switch (*(pData + ADDRESS_SPACE_DESCRIPTOR_RESOURCE_TYPE_OFFSET)) {
|
|
|
|
case ACPI_ADDRESS_SPACE_TYPE_MEM:
|
|
TempEntry->AddressType = EfiLegacyMpTableEntryExtSysAddrSpaceMappingMemory;
|
|
break;
|
|
|
|
case ACPI_ADDRESS_SPACE_TYPE_IO:
|
|
TempEntry->AddressType = EfiLegacyMpTableEntryExtSysAddrSpaceMappingIo;
|
|
break;
|
|
|
|
default:
|
|
pData += ADDRESS_SPACE_DESCRIPTOR_TOTAL_LENGTH;
|
|
continue;
|
|
|
|
}
|
|
TempEntry->AddressBase = *(UINT64 *)(pData + ADDRESS_SPACE_DESCRIPTOR_ADDR_RANGE_MIN_OFFSET);
|
|
TempEntry->AddressLength = *(UINT64 *)(pData + ADDRESS_SPACE_DESCRIPTOR_ADDR_LENGTH_OFFSET);
|
|
TempEntry++;
|
|
|
|
}
|
|
pData += ADDRESS_SPACE_DESCRIPTOR_TOTAL_LENGTH;
|
|
|
|
}
|
|
}
|
|
|
|
(*pEntry) = (UINT8 *)(TempEntry);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
EFI_STATUS
|
|
CreateOneExtBusHierarchyDscEntry (
|
|
IN OUT EFI_LEGACY_MP_TABLE_ENTRY_EXT_BUS_HIERARCHY **TempEntry,
|
|
IN UINT8 ParentBus,
|
|
IN UINT8 BusId
|
|
)
|
|
{
|
|
(*TempEntry)->EntryType = EFI_LEGACY_MP_TABLE_ENTRY_EXT_TYPE_BUS_HIERARCHY;
|
|
(*TempEntry)->Length = sizeof(EFI_LEGACY_MP_TABLE_ENTRY_EXT_BUS_HIERARCHY);
|
|
(*TempEntry)->ParentBus = (UINT8)ParentBus;
|
|
(*TempEntry)->BusId = (UINT8)BusId;
|
|
(*TempEntry)->BusInfo.SubtractiveDecode = 1;
|
|
|
|
(*TempEntry)++;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Update the extended Bus Hierarchy Descriptor Entry
|
|
|
|
@param pEntry The data pointer of Entry
|
|
@param BusStartEntries The pointer of first Bus entry
|
|
@param HandleCount The total number of Handles with Pci IO protocol
|
|
@param HandleBuffer The Buffer's pointer
|
|
|
|
@retval EFI_SUCCESS Update entry success
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UpdateExtBusHierarchyDscEntries (
|
|
IN OUT UINT8 **pEntry,
|
|
IN EFI_LEGACY_MP_TABLE_ENTRY_BUS *BusStartEntries,
|
|
IN UINTN PciBridgeInfoCount,
|
|
IN EFI_PCI_BRIDGE_INFO *PciBridgeInfoBuffer
|
|
)
|
|
{
|
|
UINTN Index;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_EXT_BUS_HIERARCHY *TempEntry;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_BUS *BusEntries;
|
|
|
|
if (PciBridgeInfoCount == 0) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
TempEntry = (EFI_LEGACY_MP_TABLE_ENTRY_EXT_BUS_HIERARCHY *)(*pEntry);
|
|
|
|
for (Index = 0; Index < PciBridgeInfoCount; Index++) {
|
|
|
|
if (PciBridgeInfoBuffer[Index].ConfigHeader.Hdr.ClassCode[2] != PCI_CLASS_BRIDGE) {
|
|
continue;
|
|
}
|
|
|
|
BusEntries = BusStartEntries;
|
|
switch (PciBridgeInfoBuffer[Index].ConfigHeader.Hdr.ClassCode[1]) {
|
|
|
|
case PCI_CLASS_BRIDGE_EISA:
|
|
while (BusEntries->EntryType == EFI_LEGACY_MP_TABLE_ENTRY_TYPE_BUS) {
|
|
if (AsciiStrnCmp (BusEntries->TypeString, EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_EISA, sizeof(BusEntries->TypeString)) == 0) {
|
|
CreateOneExtBusHierarchyDscEntry (
|
|
&TempEntry,
|
|
(UINT8)PciBridgeInfoBuffer[Index].Location.Bus,
|
|
(UINT8) BusEntries->Id
|
|
);
|
|
break;
|
|
}
|
|
BusEntries++;
|
|
}
|
|
break;
|
|
|
|
case PCI_CLASS_BRIDGE_ISA:
|
|
while (BusEntries->EntryType == EFI_LEGACY_MP_TABLE_ENTRY_TYPE_BUS) {
|
|
if (AsciiStrnCmp (BusEntries->TypeString, EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_ISA, sizeof(BusEntries->TypeString)) == 0) {
|
|
CreateOneExtBusHierarchyDscEntry (
|
|
&TempEntry,
|
|
(UINT8)PciBridgeInfoBuffer[Index].Location.Bus,
|
|
(UINT8) BusEntries->Id
|
|
);
|
|
break;
|
|
}
|
|
BusEntries++;
|
|
}
|
|
break;
|
|
|
|
case PCI_CLASS_BRIDGE_P2P:
|
|
|
|
if (PciBridgeInfoBuffer[Index].ConfigHeader.Hdr.ClassCode[0] == 0x01) {
|
|
CreateOneExtBusHierarchyDscEntry (
|
|
&TempEntry,
|
|
(UINT8)PciBridgeInfoBuffer[Index].Location.Bus,
|
|
(UINT8) PciBridgeInfoBuffer[Index].ConfigHeader.Bridge.SecondaryBus
|
|
);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Unsupported
|
|
//
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
(*pEntry) = (UINT8 *)(TempEntry);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Update the extended Compatibility Bus Address Space Modifier Entry
|
|
|
|
@param pEntry The data pointer of Entry
|
|
|
|
@retval EFI_SUCCESS Update entry success
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UpdateExtCompatBusAddrModifierEntries (
|
|
IN OUT UINT8 **pEntry
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINTN NumOfExtBusAddrModifier;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_EXT_COMPAT_BUS_ADDR_SPACE_MODIFIER *pExtBusAddrModifier;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_EXT_COMPAT_BUS_ADDR_SPACE_MODIFIER *ExtBusAddrModifier;
|
|
|
|
ExtBusAddrModifier = (EFI_LEGACY_MP_TABLE_ENTRY_EXT_COMPAT_BUS_ADDR_SPACE_MODIFIER *)(*pEntry);
|
|
|
|
NumOfExtBusAddrModifier = sizeof(mExtBusAddrModifier) / sizeof(mExtBusAddrModifier[0]);
|
|
pExtBusAddrModifier = &mExtBusAddrModifier[0];
|
|
|
|
for (Index = 0; Index < NumOfExtBusAddrModifier; Index++) {
|
|
|
|
if (pExtBusAddrModifier->EntryType != EFI_LEGACY_MP_TABLE_ENTRY_EXT_TYPE_COMPAT_BUS_ADDR_SPACE_MODIFIER) {
|
|
pExtBusAddrModifier++;
|
|
continue;
|
|
}
|
|
|
|
CopyMem (ExtBusAddrModifier, pExtBusAddrModifier, sizeof(EFI_LEGACY_MP_TABLE_ENTRY_EXT_COMPAT_BUS_ADDR_SPACE_MODIFIER));
|
|
pExtBusAddrModifier++;
|
|
ExtBusAddrModifier++;
|
|
}
|
|
|
|
(*pEntry) = (UINT8 *)(ExtBusAddrModifier);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
Retrieve Bridge Handle from PciIo Handle Buffer.
|
|
|
|
@param **BridgeHandleBuffer return the bridge handle buffer
|
|
@param BridgeHandleCount return the number of bridge handle.
|
|
|
|
@retval EFI_SUCCESS Create Buffer success
|
|
@retval EFI_OUT_OF_RESOURCES Not enought momory space.
|
|
@retval EFI_NOT_FOUND Locate PciIo failure.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
LocateBridgeHandleBuffer (
|
|
OUT EFI_PCI_BRIDGE_INFO **BridgeHandleBuffer,
|
|
OUT UINTN *BridgeHandleCount
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
UINTN PciIoHandleCount;
|
|
EFI_HANDLE *PciIoHandleBuffer = NULL;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiPciIoProtocolGuid,
|
|
NULL,
|
|
&PciIoHandleCount,
|
|
&PciIoHandleBuffer);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
*BridgeHandleCount = 0;
|
|
*BridgeHandleBuffer = AllocatePool (PciIoHandleCount * sizeof (EFI_PCI_BRIDGE_INFO));
|
|
if (*BridgeHandleBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
for (Index = 0; Index < PciIoHandleCount; Index++) {
|
|
|
|
Status = gBS->HandleProtocol (
|
|
PciIoHandleBuffer[Index],
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID **)&PciIo);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
PciIo->Pci.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
0,
|
|
sizeof((*BridgeHandleBuffer)[*BridgeHandleCount].ConfigHeader) / sizeof(UINT32),
|
|
&(*BridgeHandleBuffer)[*BridgeHandleCount].ConfigHeader);
|
|
|
|
if ((*BridgeHandleBuffer)[*BridgeHandleCount].ConfigHeader.Hdr.ClassCode[2] != PCI_CLASS_BRIDGE) {
|
|
continue;
|
|
}
|
|
|
|
(*BridgeHandleBuffer)[*BridgeHandleCount].Handle = PciIoHandleBuffer[Index];
|
|
|
|
PciIo->GetLocation (
|
|
PciIo,
|
|
&(*BridgeHandleBuffer)[*BridgeHandleCount].Location.Seg,
|
|
&(*BridgeHandleBuffer)[*BridgeHandleCount].Location.Bus,
|
|
&(*BridgeHandleBuffer)[*BridgeHandleCount].Location.Dev,
|
|
&(*BridgeHandleBuffer)[*BridgeHandleCount].Location.Fun
|
|
);
|
|
|
|
(*BridgeHandleCount)++;
|
|
}
|
|
|
|
if (PciIoHandleBuffer != NULL) {
|
|
FreePool (PciIoHandleBuffer);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Create the Mp table in E F -Segment
|
|
|
|
@param Private Legacy BIOS Instance data
|
|
|
|
@retval EFI_SUCCESS Create Table success
|
|
@retval EFI_OUT_OF_RESOURCES Not enought momory space.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
CreateMpTable (
|
|
IN LEGACY_BIOS_INSTANCE *Private
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_IA32_REGISTER_SET Regs;
|
|
EFI_LEGACY_MP_TABLE_FLOATING_POINTER *TempMpTablePointer;
|
|
EFI_LEGACY_MP_TABLE_HEADER *PcmpEntry;
|
|
UINT8 *TempMpTable;
|
|
UINT8 *pEntry;
|
|
UINT16 MpTableTotalSize;
|
|
UINT16 ExtTableLength;
|
|
UINT16 BaseTableLength;
|
|
UINT8 CheckSum;
|
|
UINT16 Index;
|
|
UINT8 *PcmpTableAddress;
|
|
UINT8 *MpTablePtrAddress;
|
|
UINT8 *ExtEntriesPtrAddr;
|
|
UINT8 *BaseEntriesPtrAddr;
|
|
UINTN TotalEntries;
|
|
UINT64 ApicBaseReg;
|
|
UINTN PciBridgeInfoCount;
|
|
EFI_PCI_BRIDGE_INFO *PciBridgeInfoBuffer;
|
|
UINTN RootBridgeHandleCount;
|
|
EFI_HANDLE *RootBridgeHandleBuffer;
|
|
UINTN CharNumOfOemIdString;
|
|
CHAR8 *pOemIdStringEntry;
|
|
UINTN CharNumOfProductIdString;
|
|
CHAR8 *pProductIdStringEntry;
|
|
UINTN NumOfIoApic;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_IOAPIC *pIoApicEntry;
|
|
UINTN NumOfIoApicIntLegacy;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_IO_INT *pIoApicIntEntryLegacyHead;
|
|
UINTN NumOfIoApicInt;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_IO_INT *pIoApicIntEntryHead;
|
|
UINTN NumOfIoApicIntSlot;
|
|
MP_TABLE_ENTRY_IO_INT_SLOT *pIoApicIntEntrySlotHead;
|
|
UINTN NumOfLocalApicInt;
|
|
EFI_LEGACY_MP_TABLE_ENTRY_LOCAL_INT *pLocalApicIntEntry;
|
|
|
|
if (mLegacyMpInstalled) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
TempMpTablePointer = NULL;
|
|
TempMpTable = NULL;
|
|
PciBridgeInfoBuffer = NULL;
|
|
RootBridgeHandleBuffer = NULL;
|
|
pOemIdStringEntry = NULL;
|
|
pProductIdStringEntry = NULL;
|
|
pIoApicEntry = NULL;
|
|
pIoApicIntEntryLegacyHead = NULL;
|
|
pIoApicIntEntryHead = NULL;
|
|
pIoApicIntEntrySlotHead = NULL;
|
|
pLocalApicIntEntry = NULL;
|
|
MpTableTotalSize = 0;
|
|
ExtTableLength = 0;
|
|
BaseTableLength = 0;
|
|
TotalEntries = 0;
|
|
NumOfIoApic = 0;
|
|
NumOfIoApicInt = 0;
|
|
NumOfIoApicIntSlot = 0;
|
|
NumOfIoApicIntLegacy = 0;
|
|
NumOfLocalApicInt = 0;
|
|
//
|
|
// Allocate temporary MP Table Pointer structure
|
|
//
|
|
TempMpTablePointer = AllocatePool (sizeof(EFI_LEGACY_MP_TABLE_FLOATING_POINTER));
|
|
if (TempMpTablePointer == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Error;
|
|
}
|
|
|
|
ZeroMem (TempMpTablePointer, sizeof(EFI_LEGACY_MP_TABLE_FLOATING_POINTER));
|
|
|
|
//
|
|
// Update MP Table Pointer structure
|
|
//
|
|
TempMpTablePointer->Signature = EFI_LEGACY_MP_TABLE_FLOATING_POINTER_SIGNATURE;
|
|
|
|
TempMpTablePointer->Length = sizeof(EFI_LEGACY_MP_TABLE_FLOATING_POINTER) / 16;
|
|
|
|
TempMpTablePointer->SpecRev = EFI_LEGACY_MP_TABLE_REV_1_4;
|
|
|
|
//
|
|
// Allocate temporary MP Table
|
|
//
|
|
TempMpTable = AllocatePool ((1 << 16));
|
|
if (TempMpTable == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Error;
|
|
}
|
|
|
|
ZeroMem (TempMpTable, (1 << 16));
|
|
PcmpEntry = (EFI_LEGACY_MP_TABLE_HEADER *)TempMpTable;
|
|
|
|
//
|
|
// Update MP Table Pointer structure
|
|
//
|
|
PcmpEntry->Signature = EFI_LEGACY_MP_TABLE_HEADER_SIGNATURE;
|
|
|
|
ApicBaseReg = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);
|
|
PcmpEntry->LocalApicAddress = (UINT32)(ApicBaseReg & 0xffffff000);
|
|
|
|
PcmpEntry->SpecRev = TempMpTablePointer->SpecRev;
|
|
|
|
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcPrepareInstallMpTable \n"));
|
|
Status = OemSvcPrepareInstallMpTable (
|
|
&CharNumOfOemIdString,
|
|
&pOemIdStringEntry,
|
|
&CharNumOfProductIdString,
|
|
&pProductIdStringEntry,
|
|
&NumOfIoApic,
|
|
&pIoApicEntry,
|
|
&NumOfIoApicIntLegacy,
|
|
&pIoApicIntEntryLegacyHead,
|
|
&NumOfIoApicInt,
|
|
&pIoApicIntEntryHead,
|
|
&NumOfIoApicIntSlot,
|
|
&pIoApicIntEntrySlotHead,
|
|
&NumOfLocalApicInt,
|
|
&pLocalApicIntEntry
|
|
);
|
|
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcPrepareInstallMpTable Status: %r\n", Status));
|
|
if (Status != EFI_MEDIA_CHANGED) {
|
|
goto Error;
|
|
}
|
|
CopyMem (PcmpEntry->OemId, pOemIdStringEntry, sizeof(PcmpEntry->OemId));
|
|
CopyMem (PcmpEntry->OemProductId, pProductIdStringEntry, sizeof(PcmpEntry->OemProductId));
|
|
|
|
pEntry = (UINT8 *)(PcmpEntry + 1);
|
|
|
|
Status = LocateBridgeHandleBuffer (&PciBridgeInfoBuffer, &PciBridgeInfoCount);
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiPciRootBridgeIoProtocolGuid,
|
|
NULL,
|
|
&RootBridgeHandleCount,
|
|
&RootBridgeHandleBuffer);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Base Table Entries
|
|
//
|
|
Status = UpdateProcessorEntries (
|
|
&pEntry,
|
|
&TotalEntries,
|
|
PcmpEntry->LocalApicAddress
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
BaseEntriesPtrAddr = pEntry;
|
|
|
|
Status = UpdateBusEntries (
|
|
&pEntry,
|
|
&TotalEntries,
|
|
PciBridgeInfoCount,
|
|
PciBridgeInfoBuffer,
|
|
RootBridgeHandleCount,
|
|
RootBridgeHandleBuffer
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
Status = UpdateIoApicEntries (&pEntry, &TotalEntries, NumOfIoApic, pIoApicEntry);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
Status = UpdateIoApicIntEntries (
|
|
&pEntry,
|
|
&TotalEntries,
|
|
(EFI_LEGACY_MP_TABLE_ENTRY_BUS *)BaseEntriesPtrAddr,
|
|
PciBridgeInfoCount,
|
|
PciBridgeInfoBuffer,
|
|
NumOfIoApic,
|
|
pIoApicEntry,
|
|
NumOfIoApicIntLegacy,
|
|
pIoApicIntEntryLegacyHead,
|
|
NumOfIoApicInt,
|
|
pIoApicIntEntryHead,
|
|
NumOfIoApicIntSlot,
|
|
pIoApicIntEntrySlotHead
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
Status = UpdateLocalApicIntEntries (&pEntry, &TotalEntries, NumOfLocalApicInt, pLocalApicIntEntry);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
ExtEntriesPtrAddr = pEntry;
|
|
BaseTableLength = (UINT16)(ExtEntriesPtrAddr - (UINT8 *)PcmpEntry);
|
|
|
|
//
|
|
// Extended Table Entries
|
|
//
|
|
Status = UpdateExtSysAddrMappingEntries (&pEntry, RootBridgeHandleCount, RootBridgeHandleBuffer);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
Status = UpdateExtBusHierarchyDscEntries (
|
|
&pEntry,
|
|
(EFI_LEGACY_MP_TABLE_ENTRY_BUS *)BaseEntriesPtrAddr,
|
|
PciBridgeInfoCount,
|
|
PciBridgeInfoBuffer);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
Status = UpdateExtCompatBusAddrModifierEntries (&pEntry);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Assume E F segment already unlock.
|
|
//
|
|
|
|
PcmpEntry->EntryCount = (UINT16)TotalEntries;
|
|
|
|
ExtTableLength = (UINT16)(pEntry - ExtEntriesPtrAddr);
|
|
|
|
MpTableTotalSize = (UINT16)(pEntry - TempMpTable);
|
|
|
|
PcmpEntry->BaseTableLength = BaseTableLength;
|
|
|
|
PcmpEntry->ExtendedTableLength = ExtTableLength;
|
|
|
|
CheckSum = 0;
|
|
for (Index = 0; Index < ExtTableLength; Index++) {
|
|
CheckSum = (UINT8)(CheckSum + ((UINT8*)(ExtEntriesPtrAddr))[Index]);
|
|
}
|
|
PcmpEntry->ExtendedChecksum = (UINT8)(0 - CheckSum);
|
|
|
|
CheckSum = 0;
|
|
for (Index = 0; Index < BaseTableLength; Index++) {
|
|
CheckSum = (UINT8)(CheckSum + ((UINT8*)(PcmpEntry))[Index]);
|
|
}
|
|
PcmpEntry->Checksum = (UINT8)(0 - CheckSum);
|
|
|
|
//
|
|
// Get MP table address and fill data
|
|
//
|
|
ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
|
|
|
|
Regs.X.AX = Legacy16GetTableAddress;
|
|
Regs.X.CX = (UINT16)MpTableTotalSize;
|
|
Regs.X.BX = 1;
|
|
LegacyBiosFarCall86 (
|
|
&Private->LegacyBios,
|
|
Private->Legacy16CallSegment,
|
|
Private->Legacy16CallOffset,
|
|
&Regs,
|
|
NULL,
|
|
0);
|
|
if (Regs.X.AX != 0) {
|
|
Regs.X.AX = Legacy16GetTableAddress;
|
|
Regs.X.CX = (UINT16)MpTableTotalSize;
|
|
Regs.X.BX = 2;
|
|
LegacyBiosFarCall86 (
|
|
&Private->LegacyBios,
|
|
Private->Legacy16CallSegment,
|
|
Private->Legacy16CallOffset,
|
|
&Regs,
|
|
NULL,
|
|
0);
|
|
if (Regs.X.AX != 0) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
PcmpTableAddress = (UINT8 *)(UINTN)(Regs.X.DS*16 + Regs.X.BX);
|
|
|
|
CopyMem ((VOID *)PcmpTableAddress, (VOID *)TempMpTable, (UINTN)MpTableTotalSize);
|
|
|
|
TempMpTablePointer->PhysicalAddress = (UINT32)(UINTN)PcmpTableAddress;
|
|
|
|
TempMpTablePointer->Checksum = 0;
|
|
CheckSum = 0;
|
|
for (Index = 0; Index < sizeof(EFI_LEGACY_MP_TABLE_FLOATING_POINTER); Index++) {
|
|
CheckSum = (UINT8)(CheckSum + ((UINT8*)(TempMpTablePointer))[Index]);
|
|
}
|
|
|
|
TempMpTablePointer->Checksum = (UINT8)(0 - CheckSum);
|
|
|
|
//
|
|
// Get MP table floating pointer address and fill data
|
|
//
|
|
ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
|
|
|
|
Regs.X.AX = Legacy16GetTableAddress;
|
|
Regs.X.CX = (UINT16)sizeof(EFI_LEGACY_MP_TABLE_FLOATING_POINTER);
|
|
Regs.X.BX = 1;
|
|
LegacyBiosFarCall86 (
|
|
&Private->LegacyBios,
|
|
Private->Legacy16CallSegment,
|
|
Private->Legacy16CallOffset,
|
|
&Regs,
|
|
NULL,
|
|
0);
|
|
|
|
if (Regs.X.AX != 0) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Error;
|
|
}
|
|
|
|
MpTablePtrAddress = (UINT8 *)(UINTN)(Regs.X.DS*16 + Regs.X.BX);
|
|
|
|
CopyMem ((VOID *)MpTablePtrAddress, (VOID *)TempMpTablePointer, (UINTN)sizeof(EFI_LEGACY_MP_TABLE_FLOATING_POINTER));
|
|
|
|
mLegacyMpInstalled = TRUE;
|
|
Status = EFI_SUCCESS;
|
|
Error:
|
|
if (PciBridgeInfoBuffer != NULL) {
|
|
FreePool (PciBridgeInfoBuffer);
|
|
}
|
|
if (RootBridgeHandleBuffer != NULL) {
|
|
FreePool (RootBridgeHandleBuffer);
|
|
}
|
|
if (TempMpTablePointer != NULL) {
|
|
FreePool (TempMpTablePointer);
|
|
}
|
|
if (TempMpTable != NULL) {
|
|
FreePool (TempMpTable);
|
|
}
|
|
return Status;
|
|
}
|