339 lines
8.6 KiB
C
339 lines
8.6 KiB
C
|
|
|||
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1990, 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
hwpmbiosc.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This modules contains ACPI BIOS C supporting routines
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Jake Oshins (jakeo) 6-Feb-1997
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Real mode.
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "hwdetect.h"
|
|||
|
#include <string.h>
|
|||
|
#include "acpibios.h"
|
|||
|
|
|||
|
typedef struct {
|
|||
|
ULONG ErrorFlag;
|
|||
|
ULONG Key;
|
|||
|
ULONG Size;
|
|||
|
struct {
|
|||
|
ULONG BaseAddrLow;
|
|||
|
ULONG BaseAddrHigh;
|
|||
|
ULONG SizeLow;
|
|||
|
ULONG SizeHigh;
|
|||
|
ULONG MemoryType;
|
|||
|
} Descriptor;
|
|||
|
} E820Frame;
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
Int15E820 (
|
|||
|
E820Frame *Frame
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
Int15E980 (
|
|||
|
PLEGACY_GEYSERVILLE_INT15 Info
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HwGetAcpiBiosData(
|
|||
|
IN FPUCHAR *Configuration,
|
|||
|
OUT PUSHORT Length
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine checks to see if an ACPI BIOS is present. If it is,
|
|||
|
then it returns the ACPI Root System Description Pointer.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Configuration - structure that holds ACPI pointer
|
|||
|
Length - length of that structure
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if ACPI BIOS is present, FALSE otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG romAddr, romEnd;
|
|||
|
FPUCHAR current;
|
|||
|
FPULONG EbdaAddr;
|
|||
|
FPACPI_BIOS_INSTALLATION_CHECK header;
|
|||
|
UCHAR sum, node = 0;
|
|||
|
USHORT i, nodeSize;
|
|||
|
USHORT numE820Blocks, e820BlockIndex;
|
|||
|
BOOLEAN complete;
|
|||
|
FPACPI_E820_ENTRY e820Blocks;
|
|||
|
E820Frame Frame;
|
|||
|
LEGACY_GEYSERVILLE_INT15 geyservilleInfo;
|
|||
|
BOOLEAN geyservillePresent;
|
|||
|
|
|||
|
enum PASS { PASS1 = 0, PASS2, MAX_PASSES } pass;
|
|||
|
|
|||
|
//
|
|||
|
// 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.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Earlier, we stored the address of the EBDA in address
|
|||
|
// DOS_BEGIN_SEGMENT << 4 : EBIOS_INFO_OFFSET
|
|||
|
//
|
|||
|
MAKE_FP(EbdaAddr, ((DOS_BEGIN_SEGMENT << 4) + EBIOS_INFO_OFFSET));
|
|||
|
MAKE_FP(current, *EbdaAddr);
|
|||
|
|
|||
|
if (*EbdaAddr == 0) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
romAddr = *EbdaAddr;
|
|||
|
romEnd = romAddr + 1024;
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// On the second pass, we search (physical) memory 0xE0000
|
|||
|
// to 0xF0000.
|
|||
|
|
|||
|
MAKE_FP(current, ACPI_BIOS_START);
|
|||
|
romAddr = ACPI_BIOS_START;
|
|||
|
romEnd = ACPI_BIOS_END;
|
|||
|
}
|
|||
|
|
|||
|
while (romAddr < romEnd) {
|
|||
|
|
|||
|
header = (FPACPI_BIOS_INSTALLATION_CHECK)current;
|
|||
|
|
|||
|
//
|
|||
|
// 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 += current[i];
|
|||
|
}
|
|||
|
if (sum == 0) {
|
|||
|
pass = MAX_PASSES; // leave 'for' loop
|
|||
|
break; // leave 'while' loop
|
|||
|
}
|
|||
|
#if DBG
|
|||
|
BlPrint("GetAcpiBiosData: Checksum fails\n");
|
|||
|
#endif
|
|||
|
}
|
|||
|
romAddr += ACPI_BIOS_HEADER_INCREMENT;
|
|||
|
MAKE_FP(current, romAddr);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (romAddr >= romEnd) {
|
|||
|
#if DBG
|
|||
|
BlPrint("GetAcpiBiosData: RSDT pointer not found\n");
|
|||
|
#endif
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Now header points at the RSDP. So we can move on to collecting the
|
|||
|
// E820 blocks.
|
|||
|
//
|
|||
|
|
|||
|
numE820Blocks = 20;
|
|||
|
|
|||
|
while (TRUE) {
|
|||
|
|
|||
|
e820Blocks =
|
|||
|
(FPACPI_E820_ENTRY)HwAllocateHeap(
|
|||
|
sizeof(ACPI_E820_ENTRY) * numE820Blocks,
|
|||
|
FALSE);
|
|||
|
|
|||
|
if (!e820Blocks) {
|
|||
|
#if DBG
|
|||
|
BlPrint("GetAcpiBiosData: Out of heap space.\n");
|
|||
|
#endif
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
e820BlockIndex = 0;
|
|||
|
Frame.Key = 0;
|
|||
|
complete = FALSE;
|
|||
|
|
|||
|
while (!complete) {
|
|||
|
|
|||
|
#if DBG
|
|||
|
BlPrint("Searching for E820 block # %d.\n", e820BlockIndex);
|
|||
|
#endif
|
|||
|
|
|||
|
if (e820BlockIndex == numE820Blocks) {
|
|||
|
HwFreeHeap(sizeof(ACPI_E820_ENTRY) * numE820Blocks);
|
|||
|
numE820Blocks += 20;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set up the context.
|
|||
|
//
|
|||
|
|
|||
|
Frame.Size = sizeof (Frame.Descriptor);
|
|||
|
|
|||
|
Int15E820 (&Frame);
|
|||
|
|
|||
|
if (Frame.ErrorFlag || Frame.Size < sizeof (Frame.Descriptor)) {
|
|||
|
|
|||
|
//
|
|||
|
// The BIOS just didn't do it.
|
|||
|
//
|
|||
|
|
|||
|
#if DBG
|
|||
|
BlPrint("The BIOS failed the E820 call\n");
|
|||
|
#endif
|
|||
|
complete = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Copy the data from the Frame into the array.
|
|||
|
//
|
|||
|
|
|||
|
e820Blocks[e820BlockIndex].Base.LowPart = Frame.Descriptor.BaseAddrLow;
|
|||
|
e820Blocks[e820BlockIndex].Base.HighPart = Frame.Descriptor.BaseAddrHigh;
|
|||
|
e820Blocks[e820BlockIndex].Length.LowPart = Frame.Descriptor.SizeLow;
|
|||
|
e820Blocks[e820BlockIndex].Length.HighPart = Frame.Descriptor.SizeHigh;
|
|||
|
e820Blocks[e820BlockIndex].Type = Frame.Descriptor.MemoryType;
|
|||
|
e820Blocks[e820BlockIndex].Reserved = 0;
|
|||
|
|
|||
|
#if DBG
|
|||
|
BlPrint("Base: %x%x Len: %x%x Type: %x\n",
|
|||
|
(USHORT)(Frame.Descriptor.BaseAddrLow >> 16),
|
|||
|
(USHORT)(Frame.Descriptor.BaseAddrLow & 0xffff),
|
|||
|
(USHORT)(Frame.Descriptor.SizeLow >> 16),
|
|||
|
(USHORT)(Frame.Descriptor.SizeLow & 0xffff),
|
|||
|
(USHORT)(Frame.Descriptor.MemoryType));
|
|||
|
#endif
|
|||
|
|
|||
|
e820BlockIndex++;
|
|||
|
|
|||
|
if (Frame.Key == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// This was the last descriptor
|
|||
|
//
|
|||
|
complete = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (complete) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#if DBG
|
|||
|
BlPrint("Finished with %d E820 descriptors\n", e820BlockIndex);
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Check for Geyserville
|
|||
|
//
|
|||
|
|
|||
|
if (geyservillePresent = Int15E980(&geyservilleInfo)) {
|
|||
|
geyservilleInfo.Signature = 'GS';
|
|||
|
}
|
|||
|
|
|||
|
#if DBG
|
|||
|
BlPrint("GetAcpiBiosData: Geyserville is %s present.\n",
|
|||
|
geyservillePresent ? "" : "not");
|
|||
|
|
|||
|
if (geyservillePresent) {
|
|||
|
BlPrint("GetAcpiBiosData: Geyserville command port: %x.\n",
|
|||
|
geyservilleInfo.CommandPortAddress);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Now we know how big the lump of data is going to be.
|
|||
|
//
|
|||
|
|
|||
|
nodeSize = sizeof(ACPI_BIOS_MULTI_NODE) + DATA_HEADER_SIZE +
|
|||
|
(sizeof(ACPI_E820_ENTRY) * (e820BlockIndex - 1)) +
|
|||
|
(geyservillePresent ? sizeof(LEGACY_GEYSERVILLE_INT15) : 0);
|
|||
|
|
|||
|
current = (FPUCHAR) HwAllocateHeap(nodeSize, FALSE);
|
|||
|
if (!current) {
|
|||
|
#if DBG
|
|||
|
BlPrint("GetAcpiBiosData: Out of heap space.\n");
|
|||
|
#endif
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Collect ACPI Bios installation check data and device node data.
|
|||
|
//
|
|||
|
|
|||
|
((FPACPI_BIOS_MULTI_NODE)(current + DATA_HEADER_SIZE))->RsdtAddress.HighPart = 0;
|
|||
|
((FPACPI_BIOS_MULTI_NODE)(current + DATA_HEADER_SIZE))->RsdtAddress.LowPart =
|
|||
|
header->RsdtAddress;
|
|||
|
|
|||
|
((FPACPI_BIOS_MULTI_NODE)(current + DATA_HEADER_SIZE))->Count = e820BlockIndex;
|
|||
|
((FPACPI_BIOS_MULTI_NODE)(current + DATA_HEADER_SIZE))->Reserved = 0;
|
|||
|
|
|||
|
_fmemcpy (&(((FPACPI_BIOS_MULTI_NODE)(current + DATA_HEADER_SIZE))->E820Entry[0]),
|
|||
|
(FPUCHAR)e820Blocks,
|
|||
|
sizeof(ACPI_E820_ENTRY) * e820BlockIndex
|
|||
|
);
|
|||
|
|
|||
|
if (geyservillePresent) {
|
|||
|
|
|||
|
//
|
|||
|
// Append Geyserville information to the end of the block.
|
|||
|
//
|
|||
|
|
|||
|
_fmemcpy(&(((FPACPI_BIOS_MULTI_NODE)(current + DATA_HEADER_SIZE))->E820Entry[e820BlockIndex]),
|
|||
|
&geyservilleInfo,
|
|||
|
sizeof(geyservilleInfo));
|
|||
|
}
|
|||
|
|
|||
|
*Configuration = current;
|
|||
|
*Length = nodeSize;
|
|||
|
|
|||
|
#if DBG
|
|||
|
BlPrint("ACPI BIOS found at 0x%x:%x. RdstAddress is 0x%x:%x\n",
|
|||
|
(USHORT)(romAddr >> 16),
|
|||
|
(USHORT)(romAddr),
|
|||
|
(USHORT)(header->RsdtAddress >> 16),
|
|||
|
(USHORT)(header->RsdtAddress)
|
|||
|
);
|
|||
|
#endif
|
|||
|
return TRUE;
|
|||
|
}
|