351 lines
8.2 KiB
C
351 lines
8.2 KiB
C
/*++
|
||
|
||
Copyright (c) 1997 Microsoft Corporation
|
||
All rights reserved
|
||
|
||
Module Name:
|
||
|
||
acpisetd.c
|
||
|
||
Abstract:
|
||
|
||
This module detects an ACPI system. It
|
||
is included into setup so that setup
|
||
can figure out which HAL to load
|
||
|
||
Author:
|
||
|
||
Jake Oshins (jakeo) - Feb. 7, 1997.
|
||
|
||
Environment:
|
||
|
||
Textmode setup.
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
#include "bootx86.h"
|
||
|
||
#include "stdlib.h"
|
||
#include "string.h"
|
||
|
||
VOID
|
||
BlPrint(
|
||
PCHAR cp,
|
||
...
|
||
);
|
||
|
||
|
||
#ifdef DEBUG
|
||
#undef DEBUG_PRINT
|
||
#define DEBUG_PRINT BlPrint
|
||
#else
|
||
#define DEBUG_PRINT
|
||
#endif
|
||
|
||
typedef struct _ACPI_BIOS_INSTALLATION_CHECK {
|
||
UCHAR Signature[8]; // "RSD PTR" (ascii)
|
||
UCHAR Checksum;
|
||
UCHAR OemId[6]; // An OEM-supplied string
|
||
UCHAR reserved; // must be 0
|
||
ULONG RsdtAddress; // 32-bit physical address of RSDT
|
||
} ACPI_BIOS_INSTALLATION_CHECK, *PACPI_BIOS_INSTALLATION_CHECK;
|
||
|
||
#include "acpitabl.h"
|
||
|
||
PRSDP BlRsdp;
|
||
PRSDT BlRsdt;
|
||
PXSDT BlXsdt;
|
||
BOOLEAN BlLegacyFree = FALSE;
|
||
|
||
PDESCRIPTION_HEADER
|
||
BlFindACPITable(
|
||
IN PCHAR TableName,
|
||
IN ULONG TableLength
|
||
);
|
||
|
||
// from boot\detect\i386\acpibios.h
|
||
//
|
||
// Acpi BIOS Installation check
|
||
//
|
||
#define ACPI_BIOS_START 0xE0000
|
||
#define ACPI_BIOS_END 0xFFFFF
|
||
#define ACPI_BIOS_HEADER_INCREMENT 16
|
||
|
||
VOID
|
||
BlFindRsdp (
|
||
VOID
|
||
)
|
||
#define EBDA_SEGMENT_PTR 0x40e
|
||
{
|
||
ULONG romAddr, romEnd;
|
||
PACPI_BIOS_INSTALLATION_CHECK header;
|
||
UCHAR sum, node = 0;
|
||
USHORT i, nodeSize;
|
||
ULONG EbdaSegmentPtr;
|
||
ULONG EbdaPhysicalAdd = 0;
|
||
PUCHAR EbdaVirtualAdd = 0;
|
||
PHYSICAL_ADDRESS paddr;
|
||
enum PASS { PASS1 = 0, PASS2, MAX_PASSES } pass;
|
||
USHORT count = 0;
|
||
|
||
//
|
||
// Search on 16 byte boundaries for the signature of the
|
||
// Root System Description Table structure.
|
||
//
|
||
for (pass = PASS1; pass < MAX_PASSES; pass++) {
|
||
|
||
if (pass == PASS1) {
|
||
|
||
//
|
||
// On the first pass, we search the first 1K of the
|
||
// Extended BIOS data area. The EBDA segment address
|
||
// is available at physical address 40:0E.
|
||
//
|
||
|
||
paddr.QuadPart = 0;
|
||
EbdaSegmentPtr = (ULONG) MmMapIoSpace( paddr,
|
||
PAGE_SIZE,
|
||
TRUE);
|
||
|
||
EbdaSegmentPtr += EBDA_SEGMENT_PTR;
|
||
EbdaPhysicalAdd = *((PUSHORT)EbdaSegmentPtr);
|
||
EbdaPhysicalAdd = EbdaPhysicalAdd << 4;
|
||
|
||
if (EbdaPhysicalAdd) {
|
||
paddr.HighPart = 0;
|
||
paddr.LowPart = EbdaPhysicalAdd;
|
||
EbdaVirtualAdd = MmMapIoSpace( paddr,
|
||
2 * PAGE_SIZE,
|
||
TRUE);
|
||
}
|
||
|
||
if (!EbdaVirtualAdd) {
|
||
continue;
|
||
}
|
||
|
||
romAddr = (ULONG)EbdaVirtualAdd;
|
||
romEnd = romAddr + 1024;
|
||
|
||
} else {
|
||
//
|
||
// On the second pass, we search (physical) memory 0xE0000
|
||
// to 0xF0000.
|
||
|
||
paddr.LowPart = ACPI_BIOS_START;
|
||
romAddr = (ULONG)MmMapIoSpace(paddr,
|
||
ACPI_BIOS_END - ACPI_BIOS_START,
|
||
TRUE);
|
||
|
||
romEnd = romAddr + (ACPI_BIOS_END - ACPI_BIOS_START);
|
||
}
|
||
|
||
while (romAddr < romEnd) {
|
||
|
||
header = (PACPI_BIOS_INSTALLATION_CHECK)romAddr;
|
||
|
||
//
|
||
// Signature to match is the string "RSD PTR ".
|
||
//
|
||
|
||
if (header->Signature[0] == 'R' && header->Signature[1] == 'S' &&
|
||
header->Signature[2] == 'D' && header->Signature[3] == ' ' &&
|
||
header->Signature[4] == 'P' && header->Signature[5] == 'T' &&
|
||
header->Signature[6] == 'R' && header->Signature[7] == ' ' ) {
|
||
|
||
sum = 0;
|
||
for (i = 0; i < sizeof(ACPI_BIOS_INSTALLATION_CHECK); i++) {
|
||
sum += ((PUCHAR)romAddr)[i];
|
||
}
|
||
if (sum == 0) {
|
||
pass = MAX_PASSES; // leave 'for' loop
|
||
break; // leave 'while' loop
|
||
}
|
||
}
|
||
|
||
romAddr += ACPI_BIOS_HEADER_INCREMENT;
|
||
}
|
||
}
|
||
|
||
if (romAddr >= romEnd) {
|
||
BlRsdp = NULL;
|
||
BlRsdt = NULL;
|
||
return;
|
||
}
|
||
|
||
BlRsdp = (PRSDP)romAddr;
|
||
paddr.LowPart = BlRsdp->RsdtAddress;
|
||
BlRsdt = MmMapIoSpace(paddr, sizeof(RSDT), TRUE);
|
||
BlRsdt = MmMapIoSpace(paddr, BlRsdt->Header.Length, TRUE);
|
||
|
||
#ifdef ACPI_20_COMPLIANT
|
||
if (BlRsdp->Revision > 1) {
|
||
|
||
//
|
||
// ACPI 2.0 BIOS
|
||
//
|
||
|
||
BlXsdt = MmMapIoSpace(paddr, sizeof(XSDT), TRUE);
|
||
BlXsdt = MmMapIoSpace(paddr, BlXsdt->Header.Length, TRUE);
|
||
}
|
||
#endif
|
||
return;
|
||
}
|
||
|
||
BOOLEAN
|
||
BlDetectLegacyFreeBios(
|
||
VOID
|
||
)
|
||
{
|
||
PFADT fadt;
|
||
|
||
if (BlLegacyFree) {
|
||
return TRUE;
|
||
}
|
||
|
||
BlFindRsdp();
|
||
|
||
if (BlRsdt) {
|
||
|
||
fadt = (PFADT)BlFindACPITable("FACP", sizeof(FADT));
|
||
|
||
if (fadt == NULL) {
|
||
return FALSE;
|
||
}
|
||
|
||
if ((fadt->Header.Revision < 2) ||
|
||
(fadt->Header.Length <= 116)) {
|
||
|
||
//
|
||
// The BIOS is earlier than the legacy-free
|
||
// additions.
|
||
//
|
||
return FALSE;
|
||
}
|
||
|
||
if (!(fadt->boot_arch & I8042)) {
|
||
BlLegacyFree = TRUE;
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
PDESCRIPTION_HEADER
|
||
BlFindACPITable(
|
||
IN PCHAR TableName,
|
||
IN ULONG TableLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Given a table name, finds that table in the ACPI BIOS
|
||
|
||
Arguments:
|
||
|
||
TableName - Supplies the table name
|
||
|
||
TableLength - Supplies the length of the table to map
|
||
|
||
Return Value:
|
||
|
||
Pointer to the table if found
|
||
|
||
NULL if the table is not found
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Signature;
|
||
PFADT Fadt;
|
||
PDESCRIPTION_HEADER Header;
|
||
ULONG TableCount;
|
||
ULONG i;
|
||
PHYSICAL_ADDRESS paddr = {0};
|
||
|
||
Signature = *((ULONG UNALIGNED *)TableName);
|
||
if (Signature == RSDT_SIGNATURE) {
|
||
return(&BlRsdt->Header);
|
||
} else if (Signature == XSDT_SIGNATURE) {
|
||
return(&BlXsdt->Header);
|
||
} else if (Signature == DSDT_SIGNATURE) {
|
||
Fadt = (PFADT)BlFindACPITable("FACP", sizeof(PFADT));
|
||
if (Fadt == NULL) {
|
||
return(NULL);
|
||
}
|
||
if (BlXsdt) {
|
||
paddr = Fadt->x_dsdt;
|
||
} else {
|
||
#if defined(_X86_)
|
||
paddr.LowPart = Fadt->dsdt;
|
||
#else
|
||
paddr.QuadPart = Fadt->dsdt;
|
||
#endif
|
||
}
|
||
Header = MmMapIoSpace(paddr, TableLength, TRUE);
|
||
return(Header);
|
||
} else {
|
||
|
||
//
|
||
// Make sure...
|
||
//
|
||
if( !BlRsdt ) {
|
||
BlFindRsdp();
|
||
}
|
||
|
||
if( BlRsdt ) {
|
||
|
||
TableCount = BlXsdt ?
|
||
NumTableEntriesFromXSDTPointer(BlXsdt) :
|
||
NumTableEntriesFromRSDTPointer(BlRsdt);
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
if( TableCount > 0x100 ) {
|
||
return(NULL);
|
||
}
|
||
|
||
for (i=0;i<TableCount;i++) {
|
||
|
||
|
||
if (BlXsdt) {
|
||
|
||
paddr = BlXsdt->Tables[i];
|
||
|
||
} else {
|
||
|
||
#if defined(_X86_)
|
||
paddr.HighPart = 0;
|
||
paddr.LowPart = BlRsdt->Tables[i];
|
||
#else
|
||
paddr.QuadPart = BlRsdt->Tables[i];
|
||
#endif
|
||
}
|
||
|
||
Header = MmMapIoSpace(paddr, sizeof(DESCRIPTION_HEADER), TRUE);
|
||
if (Header == NULL) {
|
||
return(NULL);
|
||
}
|
||
if (Header->Signature == Signature) {
|
||
//
|
||
// if we need to map more than just the DESCRIPTION_HEADER, do that before
|
||
// returning. Check to see if the end of the table lies past the page
|
||
// boundary the header lies on. If so, we will have to map it.
|
||
//
|
||
if ( ((paddr.LowPart + TableLength) & ~(PAGE_SIZE - 1)) >
|
||
((paddr.LowPart + sizeof(DESCRIPTION_HEADER)) & ~(PAGE_SIZE - 1)) ) {
|
||
Header = MmMapIoSpace(paddr, TableLength, TRUE);
|
||
}
|
||
return(Header);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return(NULL);
|
||
}
|