//++ // // 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); } }