singrdk/base/boot/SingLdrPc/blacpi.cpp

758 lines
17 KiB
C++

//++
//
// Copyright (c) Microsoft Corporation
//
// Module Name:
//
// blacpi.cpp
//
// Abstract:
//
// This module implements ACPI support for the boot loader environment.
//
// Environment:
//
// Boot loader.
//
//--
#include "bl.h"
#pragma pack(1)
//
// Generic Address Structure (GAS)
//
#define ACPI_GAS_MEMORY 0
#define ACPI_GAS_IO 1
#define ACPI_GAS_PCI 2
#define ACPI_GAS_ACCESS_SIZE_UNDEFINED 0
#define ACPI_GAS_ACCESS_SIZE_BYTE 1
#define ACPI_GAS_ACCESS_SIZE_WORD 2
#define ACPI_GAS_ACCESS_SIZE_DWORD 3
#define ACPI_GAS_ACCESS_SIZE_QWORD 4
typedef struct _ACPI_GAS {
UINT8 AddressSpaceId;
UINT8 RegisterBitWidth;
UINT8 RegisterBitOffset;
UINT8 AccessSize;
UINT64 Address;
} ACPI_GAS, *PACPI_GAS;
C_ASSERT(sizeof(ACPI_GAS) == 12);
//
// Root System Description Pointer (RSDP)
//
typedef struct _ACPI_RSDP {
CHAR Signature[8];
UINT8 Checksum;
CHAR OemId[6];
UINT8 Revision;
UINT32 RsdtAddress;
UINT32 Length;
UINT64 XsdtAddress;
UINT8 ExtendedChecksum;
UINT8 Reserved[3];
} ACPI_RSDP, *PACPI_RSDP;
C_ASSERT(sizeof(ACPI_RSDP) == 36);
//
// Root System Description Table (RSDT)
//
typedef struct _ACPI_RSDT {
UINT8 Signature[4];
UINT32 Length;
UINT8 Revision;
UINT8 Checksum;
UINT8 OemId[6];
UINT8 OemTableId[8];
UINT32 OemRevision;
UINT32 CreatorId;
UINT32 CreatorRevision;
UINT32 Entry[];
} ACPI_RSDT, *PACPI_RSDT;
C_ASSERT(sizeof(ACPI_RSDT) == 36);
//
// Multiple APIC Description Table (MADT)
//
typedef struct _ACPI_MADT {
UINT8 Signature[4];
UINT32 Length;
UINT8 Revision;
UINT8 Checksum;
UINT8 OemId[6];
UINT8 OemTableId[8];
UINT32 OemRevision;
UINT32 CreatorId;
UINT32 CreatorRevision;
UINT32 LocalApicAddress;
UINT32 Flags;
UINT8 ApicStructures[];
} ACPI_MADT, *PACPI_MADT;
C_ASSERT(sizeof(ACPI_MADT) == 44);
#define ACPI_APIC_TYPE_PROCESSOR_LOCAL 0
typedef struct _ACPI_MADT_ENTRY {
UINT8 Type;
UINT8 Length;
} ACPI_MADT_ENTRY, *PACPI_MADT_ENTRY;
typedef struct _ACPI_PROCESSOR_LOCAL_APIC {
UINT8 Type;
UINT8 Length;
UINT8 AcpiProcessorId;
UINT8 ApicId;
union {
struct {
UINT32 Enabled:1;
UINT32 Reserved:31;
} s1;
UINT32 Flags;
} u1;
} ACPI_PROCESSOR_LOCAL_APIC, *PACPI_PROCESSOR_LOCAL_APIC;
C_ASSERT(sizeof(ACPI_PROCESSOR_LOCAL_APIC) == 8);
//
//System Resource Affinity Table (SRAT)
//
typedef struct _ACPI_SRAT {
UINT8 Signature[4];
UINT32 Length;
UINT8 Revision;
UINT8 Checksum;
UINT8 OemId[6];
UINT8 OemTableId[8];
UINT32 OemRevision;
UINT32 CreatorId;
UINT32 CreatorRevision;
UINT8 Reserved[12];
UINT8 SratStructures[];
} ACPI_SRAT, *PACPI_SRAT;
C_ASSERT(sizeof(ACPI_SRAT) == 48);
#define ACPI_SRAT_TYPE_PROC_AFFINITY_ENTRY 0
#define ACPI_SRAT_TYPE_MEM_AFFINITY_ENTRY 1
typedef ACPI_MADT_ENTRY ACPI_SRAT_ENTRY;
typedef PACPI_MADT_ENTRY PACPI_SRAT_ENTRY;
typedef struct _ACPI_SRAT_PROC_AFFINITY_ENTRY {
UINT8 Type;
UINT8 Length;
UINT8 ProximityDomainLowEightBits;
UINT8 ApicID;
UINT32 Flags;
UINT8 LocalApicEid;
UINT8 ProximityDomainHighTwentyFourBits[3];
UINT32 Reserved;
} ACPI_SRAT_PROC_AFFINITY_ENTRY, *PACPI_SRAT_PROC_AFFINITY_ENTRY;
typedef struct _ACPI_SRAT_MEM_AFFINITY_ENTRY {
UINT8 Type;
UINT8 Length;
UINT32 ProximityDomain;
UINT8 Reserved[2];
UINT32 BaseAddressLow;
UINT32 BaseAddressHigh;
UINT32 LengthLow;
UINT32 LengthHigh;
UINT32 Reserved2;
UINT32 Flags;
UINT8 Reserved3[8];
} ACPI_SRAT_MEM_AFFINITY_ENTRY, *PACPI_SRAT_MEM_AFFINITY_ENTRY;
//
// Fixed ACPI Description Table (FADT)
//
#define ACPI_FADT_FLAGS_RESET_SUPPORTED 0x400
typedef struct _ACPI_FADT {
UINT8 Signature[4];
UINT32 Length;
UINT8 Revision;
UINT8 Checksum;
UINT8 OemId[6];
UINT8 OemTableId[8];
UINT32 OemRevision;
UINT32 CreatorId;
UINT32 CreatorRevision;
UINT8 Data1[112-36];
UINT32 Flags;
ACPI_GAS ResetRegister;
UINT8 ResetValue;
UINT8 Data2[244-129];
} ACPI_FADT, *PACPI_FADT;
C_ASSERT(FIELD_OFFSET(ACPI_FADT, Flags) == 112);
C_ASSERT(FIELD_OFFSET(ACPI_FADT, ResetRegister) == 116);
C_ASSERT(FIELD_OFFSET(ACPI_FADT, ResetValue) == 128);
C_ASSERT(sizeof(ACPI_FADT) == 244);
#pragma pack()
PACPI_FADT BlAcpiFadt;
PACPI_MADT BlAcpiMadt;
UINT32 BlAcpiNumberOfProcessors;
PACPI_RSDP BlAcpiRsdp;
PVOID BlAcpiRsdpAddress;
PACPI_RSDT BlAcpiRsdt;
PACPI_SRAT BlAcpiSrat;
PACPI_RSDP
BlAcpiLocateRsdp(
VOID
)
//++
//
// Routine Description:
//
// This function locates the ACPI RSDP structure.
//
// Return Value:
//
// ACPI RSDP structure, if located.
// NULL, otherwise.
//
//--
{
ULONG_PTR End;
PACPI_RSDP Rsdp;
ULONG_PTR Start;
Start = 0xE0000;
End = 0x100000;
while (Start < End) {
Rsdp = (PACPI_RSDP) Start;
if ((Rsdp->Signature[0] == 'R') &&
(Rsdp->Signature[1] == 'S') &&
(Rsdp->Signature[2] == 'D') &&
(Rsdp->Signature[3] == ' ') &&
(Rsdp->Signature[4] == 'P') &&
(Rsdp->Signature[5] == 'T') &&
(Rsdp->Signature[6] == 'R') &&
(Rsdp->Signature[7] == ' ') &&
(BlRtlComputeChecksum8(Rsdp, 20) == 0)
) {
return Rsdp;
}
Start += 0x10;
}
Start = (ULONG_PTR) BlMmExtendedBiosDataArea;
End = Start + 0x10000;
while (Start < End) {
Rsdp = (PACPI_RSDP) Start;
if ((Rsdp->Signature[0] == 'R') &&
(Rsdp->Signature[1] == 'S') &&
(Rsdp->Signature[2] == 'D') &&
(Rsdp->Signature[3] == ' ') &&
(Rsdp->Signature[4] == 'P') &&
(Rsdp->Signature[5] == 'T') &&
(Rsdp->Signature[6] == 'R') &&
(Rsdp->Signature[7] == ' ') &&
(BlRtlComputeChecksum8(Rsdp, 20) == 0)
) {
return Rsdp;
}
Start += 0x10;
}
return NULL;
}
PACPI_RSDT
BlAcpiLocateRsdt(
PACPI_RSDP Rsdp
)
//++
//
// Routine Description:
//
// This function locates the ACPI RSDT structure.
//
// Arguments:
//
// Rsdp - Supplies a pointer to the ACPI RSDP structure.
//
// Return Value:
//
// ACPI RSDT structure, if located.
// NULL, otherwise.
//
//--
{
PACPI_RSDT Rsdt;
Rsdt = (PACPI_RSDT) (ULONG_PTR) Rsdp->RsdtAddress;
if (Rsdt == NULL) {
return NULL;
}
if ((Rsdt->Signature[0] == 'R') &&
(Rsdt->Signature[1] == 'S') &&
(Rsdt->Signature[2] == 'D') &&
(Rsdt->Signature[3] == 'T') &&
(Rsdt->Length >= sizeof(ACPI_RSDT)) &&
(BlRtlComputeChecksum8(Rsdt, Rsdt->Length) == 0)) {
return Rsdt;
}
return NULL;
}
PACPI_MADT
BlAcpiLocateMadt(
PACPI_RSDT Rsdt
)
//++
//
// Routine Description:
//
// This function locates the ACPI MADT structure.
//
// Arguments:
//
// Rsdt - Supplies a pointer to the ACPI RSDT structure.
//
// Return Value:
//
// ACPI MADT structure, if located.
// NULL, otherwise.
//
//--
{
UINT32 Index;
PACPI_MADT Madt;
UINT32 NumberOfTables;
NumberOfTables = (Rsdt->Length - FIELD_OFFSET(ACPI_RSDT, Entry)) / sizeof(Rsdt->Entry[0]);
for (Index = 0; Index < NumberOfTables; Index += 1) {
Madt = (PACPI_MADT) (ULONG_PTR) Rsdt->Entry[Index];
if ((Madt->Signature[0] == 'A') &&
(Madt->Signature[1] == 'P') &&
(Madt->Signature[2] == 'I') &&
(Madt->Signature[3] == 'C') &&
(Madt->Length >= sizeof(ACPI_MADT)) &&
(BlRtlComputeChecksum8(Madt, Madt->Length) == 0)) {
return Madt;
}
}
return NULL;
}
PACPI_SRAT
BlAcpiLocateSrat(
PACPI_RSDT Rsdt
)
//++
//
// Routine Description:
//
// This function locates the ACPI SRAT structure.
//
// Arguments:
//
// Rsdt - Supplies a pointer to the ACPI RSDT structure.
//
// Return Value:
//
// ACPI SRAT structure, if located.
// NULL, otherwise.
//
//--
{
UINT32 Index;
PACPI_SRAT Srat;
UINT32 NumberOfTables;
NumberOfTables = (Rsdt->Length - FIELD_OFFSET(ACPI_RSDT, Entry)) / sizeof(Rsdt->Entry[0]);
for (Index = 0; Index < NumberOfTables; Index += 1) {
Srat = (PACPI_SRAT) (ULONG_PTR) Rsdt->Entry[Index];
if ((Srat->Signature[0] == 'S') &&
(Srat->Signature[1] == 'R') &&
(Srat->Signature[2] == 'A') &&
(Srat->Signature[3] == 'T') &&
(Srat->Length >= sizeof(ACPI_SRAT)) &&
(BlRtlComputeChecksum8(Srat, Srat->Length) == 0)) {
#if ACPI_VERBOSE
BlRtlPrintf("ACPI: Found SRAT Table\n");
#endif
return Srat;
}
}
return NULL;
}
VOID
BlAcpiDumpSratEntries(
VOID
)
//++
//
// Routine Description:
//
// This function prints out the SRAT table.
//--
{
PACPI_SRAT_ENTRY Entry;
PCHAR Limit;
PACPI_SRAT_PROC_AFFINITY_ENTRY ProcAffinityEntry;
PACPI_SRAT_MEM_AFFINITY_ENTRY MemAffinityEntry;
PCHAR Next;
UINT32 hbits;
UINT32 totalbits;
if (BlAcpiSrat == NULL) {
BlRtlPrintf("ACPI: No Srat??\n");
return;
}
#if ACPI_VERBOSE
BlRtlPrintf("SRAT:\n");
#endif
Next = (PCHAR) &BlAcpiSrat->SratStructures[0];
Limit = ((PCHAR) BlAcpiSrat) + BlAcpiSrat->Length;
while (Next < Limit) {
Entry = (PACPI_SRAT_ENTRY) Next;
if ((Entry->Type == ACPI_SRAT_TYPE_PROC_AFFINITY_ENTRY) &&
(Entry->Length >= sizeof(ACPI_SRAT_PROC_AFFINITY_ENTRY))) {
ProcAffinityEntry = (PACPI_SRAT_PROC_AFFINITY_ENTRY) Next;
#if ACPI_VERBOSE
BlRtlPrintf(" Processor:\n");
#endif
hbits = 0;
hbits += ProcAffinityEntry->ProximityDomainHighTwentyFourBits[0] << 24;
hbits += ProcAffinityEntry->ProximityDomainHighTwentyFourBits[1] << 16;
hbits += ProcAffinityEntry->ProximityDomainHighTwentyFourBits[2] << 8;
totalbits = hbits | ProcAffinityEntry->ProximityDomainLowEightBits;
#if ACPI_VERBOSE
BlRtlPrintf(" HighDomain 0x%06x LowDomain 0x%02x totalbits 0x%08x\n",
hbits, ProcAffinityEntry->ProximityDomainLowEightBits,
totalbits);
BlRtlPrintf(" ApicID: %d flags 0x%08x\n", ProcAffinityEntry->ApicID,
ProcAffinityEntry->Flags);
#endif
}
else if ((Entry->Type == ACPI_SRAT_TYPE_MEM_AFFINITY_ENTRY) &&
(Entry->Length >= sizeof(ACPI_SRAT_MEM_AFFINITY_ENTRY))) {
MemAffinityEntry = (PACPI_SRAT_MEM_AFFINITY_ENTRY) Next;
#if ACPI_VERBOSE
BlRtlPrintf(" Memory:\n");
BlRtlPrintf(" BaseAddress 0x%08x.%08x .. 0x%08x.%08x",
MemAffinityEntry->BaseAddressHigh, MemAffinityEntry->BaseAddressLow,
MemAffinityEntry->LengthHigh, MemAffinityEntry->LengthLow);
BlRtlPrintf(" Domain %d Flags 0x%08x\n",
MemAffinityEntry->ProximityDomain,
MemAffinityEntry->Flags);
#endif
}
Next += Entry->Length;
}
}
UINT32
BlAcpiGetNumberOfProcessors(
VOID
)
//++
//
// Routine Description:
//
// This function returns the number of processors.
//
// Return Value:
//
// Number of processors.
//
//--
{
PACPI_MADT_ENTRY Entry;
PCHAR Limit;
PACPI_PROCESSOR_LOCAL_APIC LocalApic;
PCHAR Next;
UINT32 NumberOfProcessors;
if (BlAcpiMadt == NULL) {
return 1;
}
Next = (PCHAR) &BlAcpiMadt->ApicStructures[0];
Limit = ((PCHAR) BlAcpiMadt) + BlAcpiMadt->Length;
NumberOfProcessors = 0;
while (Next < Limit) {
Entry = (PACPI_MADT_ENTRY) Next;
if ((Entry->Type == ACPI_APIC_TYPE_PROCESSOR_LOCAL) &&
(Entry->Length >= sizeof(ACPI_PROCESSOR_LOCAL_APIC))) {
LocalApic = (PACPI_PROCESSOR_LOCAL_APIC) Next;
if (LocalApic->u1.s1.Enabled != FALSE) {
#if ACPI_VERBOSE
BlRtlPrintf("ACPI: AcpiProcessorId=%u , LocalApicId=%u\n",
LocalApic->AcpiProcessorId,
LocalApic->ApicId);
#endif
NumberOfProcessors += 1;
}
}
Next += Entry->Length;
}
return NumberOfProcessors;
}
PACPI_FADT
BlAcpiLocateFadt(
PACPI_RSDT Rsdt
)
//++
//
// Routine Description:
//
// This function locates the ACPI FADT structure.
//
// Arguments:
//
// Rsdt - Supplies a pointer to the ACPI RSDT structure.
//
// Return Value:
//
// ACPI FADT structure, if located.
// NULL, otherwise.
//
//--
{
PACPI_FADT Fadt;
UINT32 Index;
UINT32 NumberOfTables;
NumberOfTables = (Rsdt->Length - FIELD_OFFSET(ACPI_RSDT, Entry)) / sizeof(Rsdt->Entry[0]);
for (Index = 0; Index < NumberOfTables; Index += 1) {
Fadt = (PACPI_FADT) (ULONG_PTR) Rsdt->Entry[Index];
if ((Fadt->Signature[0] == 'F') &&
(Fadt->Signature[1] == 'A') &&
(Fadt->Signature[2] == 'C') &&
(Fadt->Signature[3] == 'P') &&
(BlRtlComputeChecksum8(Fadt, Fadt->Length) == 0)) {
return Fadt;
}
}
return NULL;
}
VOID
BlAcpiResetSystem(
VOID
)
//++
//
// Routine Description:
//
// This function resets the system through the ACPI reset register.
//
//--
{
if ((BlAcpiFadt->Revision < 2) ||
(BlAcpiFadt->Length < (FIELD_OFFSET(ACPI_FADT, ResetValue) + sizeof(UINT8))) ||
((BlAcpiFadt->Flags & ACPI_FADT_FLAGS_RESET_SUPPORTED) == 0)
) {
#if ACPI_VERBOSE
BlRtlPrintf("ACPI: Reset register is not supported! [FADT v%u]\n", BlAcpiFadt->Revision);
#endif
return;
}
#if ACPI_VERBOSE
BlRtlPrintf("ACPI: Reset register type is %u.\n", BlAcpiFadt->ResetRegister.AddressSpaceId);
#endif
switch (BlAcpiFadt->ResetRegister.AddressSpaceId) {
case ACPI_GAS_IO: {
BlRtlWritePort8((UINT16) BlAcpiFadt->ResetRegister.Address, BlAcpiFadt->ResetValue);
break;
}
}
}
VOID
BlAcpiInitialize(
VOID
)
//++
//
// Routine Description:
//
// This function initializes ACPI support for the boot loader.
//
//--
{
BlAcpiRsdp = BlAcpiLocateRsdp();
if (BlAcpiRsdp == NULL) {
BlRtlPrintf("ACPI: No RSDP!\n");
BlRtlHalt();
}
BlAcpiRsdpAddress = (PVOID) BlAcpiRsdp;
BlAcpiRsdt = BlAcpiLocateRsdt(BlAcpiRsdp);
if (BlAcpiRsdt == NULL) {
BlRtlPrintf("ACPI: No RSDT!\n");
BlRtlHalt();
}
BlAcpiFadt = BlAcpiLocateFadt(BlAcpiRsdt);
if (BlAcpiFadt == NULL) {
BlRtlPrintf("ACPI: No FADT!\n");
BlRtlHalt();
}
BlAcpiMadt = BlAcpiLocateMadt(BlAcpiRsdt);
if (BlAcpiMadt == NULL) {
BlAcpiNumberOfProcessors = 1;
} else {
BlAcpiNumberOfProcessors = BlAcpiGetNumberOfProcessors();
}
if (BlAcpiNumberOfProcessors == 0) {
BlRtlPrintf("ACPI: No local APIC!\n");
BlRtlHalt();
}
BlAcpiSrat = BlAcpiLocateSrat(BlAcpiRsdt);
if (BlAcpiSrat != NULL) {
BlAcpiDumpSratEntries();
}
#if ACPI_VERBOSE
BlRtlPrintf("ACPI: RSDP @ %p\n"
"ACPI: RSDT @ %p\n"
"ACPI: FADT @ %p [Revision=%u , Length=%u]\n"
"ACPI: MADT @ %p\n"
"ACPI: %u processor(s)\n",
BlAcpiRsdp,
BlAcpiRsdt,
BlAcpiFadt,
BlAcpiFadt->Revision,
BlAcpiFadt->Length,
BlAcpiMadt,
BlAcpiNumberOfProcessors);
#endif
//
// Map APIC page uncached.
//
if ((BlAcpiMadt != NULL) && (BlAcpiMadt->LocalApicAddress != 0)) {
#if ACPI_VERBOSE
BlRtlPrintf("ACPI: APIC mapped @ %p.\n", BlAcpiMadt->LocalApicAddress);
#endif
BlMmMapVirtualRange((PVOID) (ULONG_PTR) BlAcpiMadt->LocalApicAddress,
(PVOID) (ULONG_PTR) BlAcpiMadt->LocalApicAddress,
PAGE_SIZE,
TRUE,
FALSE,
FALSE);
}
}