You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
420 lines
10 KiB
420 lines
10 KiB
/*++
|
|
|
|
Copyright (c) 1991 - 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
### #### ##### #### #### ##### #####
|
|
### ## # ## ## ## ## # ## ## ## ##
|
|
## ## ## ## ## ## ## ## ## ## ##
|
|
## ## ## ## ## ## ## ## ## ## ##
|
|
####### ## ##### ## ## ##### #####
|
|
## ## ## # ## ## ## ## # ## ##
|
|
## ## #### ## #### ## #### ## ##
|
|
|
|
Abstract:
|
|
|
|
ACPI functions for querying the fixed ACPI tables.
|
|
|
|
Author:
|
|
|
|
Wesley Witt (wesw) 22-April-2002
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Notes:
|
|
|
|
This code was taken from the HAL.
|
|
|
|
--*/
|
|
|
|
#include "internal.h"
|
|
#include <ntacpi.h>
|
|
|
|
|
|
|
|
#define rgzMultiFunctionAdapter L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter"
|
|
#define rgzAcpiConfigurationData L"Configuration Data"
|
|
#define rgzAcpiIdentifier L"Identifier"
|
|
#define rgzBIOSIdentifier L"ACPI BIOS"
|
|
|
|
|
|
|
|
NTSTATUS
|
|
WdAcpiGetRegistryValue(
|
|
IN HANDLE KeyHandle,
|
|
IN PWSTR ValueName,
|
|
OUT PKEY_VALUE_PARTIAL_INFORMATION *Information
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to retrieve the data for a registry key's value.
|
|
This is done by querying the value of the key with a zero-length buffer
|
|
to determine the size of the value, and then allocating a buffer and
|
|
actually querying the value into the buffer.
|
|
|
|
It is the responsibility of the caller to free the buffer.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Supplies the key handle whose value is to be queried
|
|
|
|
ValueName - Supplies the null-terminated Unicode name of the value.
|
|
|
|
Information - Returns a pointer to the allocated data buffer.
|
|
|
|
Return Value:
|
|
|
|
The function value is the final status of the query operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING unicodeString;
|
|
NTSTATUS status;
|
|
PKEY_VALUE_PARTIAL_INFORMATION infoBuffer;
|
|
ULONG keyValueLength;
|
|
|
|
RtlInitUnicodeString( &unicodeString, ValueName );
|
|
|
|
//
|
|
// Figure out how big the data value is so that a buffer of the
|
|
// appropriate size can be allocated.
|
|
//
|
|
|
|
status = ZwQueryValueKey( KeyHandle,
|
|
&unicodeString,
|
|
KeyValuePartialInformation,
|
|
(PVOID) NULL,
|
|
0,
|
|
&keyValueLength );
|
|
if (status != STATUS_BUFFER_OVERFLOW &&
|
|
status != STATUS_BUFFER_TOO_SMALL) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Allocate a buffer large enough to contain the entire key data value.
|
|
//
|
|
|
|
infoBuffer = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePoolWithTag(NonPagedPool,
|
|
keyValueLength,
|
|
'IPCA');
|
|
if (!infoBuffer) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Query the data for the key value.
|
|
//
|
|
|
|
status = ZwQueryValueKey( KeyHandle,
|
|
&unicodeString,
|
|
KeyValuePartialInformation,
|
|
infoBuffer,
|
|
keyValueLength,
|
|
&keyValueLength );
|
|
if (!NT_SUCCESS( status )) {
|
|
ExFreePool( infoBuffer );
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Everything worked, so simply return the address of the allocated
|
|
// buffer to the caller, who is now responsible for freeing it.
|
|
//
|
|
|
|
*Information = infoBuffer;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
WdAcpiFindRsdt (
|
|
OUT PACPI_BIOS_MULTI_NODE *AcpiMulti
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function looks into the registry to find the ACPI RSDT,
|
|
which was stored there by ntdetect.com.
|
|
|
|
Arguments:
|
|
|
|
RsdtPtr - Pointer to a buffer that contains the ACPI
|
|
Root System Description Pointer Structure.
|
|
The caller is responsible for freeing this
|
|
buffer. Note: This is returned in non-paged
|
|
pool.
|
|
|
|
Return Value:
|
|
|
|
A NTSTATUS code to indicate the result of the initialization.
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING unicodeString, unicodeValueName, biosId;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
HANDLE hMFunc, hBus;
|
|
WCHAR wbuffer[10];
|
|
ULONG i, length;
|
|
PWSTR p;
|
|
PKEY_VALUE_PARTIAL_INFORMATION valueInfo;
|
|
NTSTATUS status;
|
|
BOOLEAN same;
|
|
PCM_PARTIAL_RESOURCE_LIST prl;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
|
|
PACPI_BIOS_MULTI_NODE multiNode;
|
|
ULONG multiNodeSize;
|
|
|
|
|
|
//
|
|
// Look in the registry for the "ACPI BIOS bus" data
|
|
//
|
|
|
|
RtlInitUnicodeString (&unicodeString, rgzMultiFunctionAdapter);
|
|
InitializeObjectAttributes (&objectAttributes,
|
|
&unicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL, // handle
|
|
NULL);
|
|
|
|
|
|
status = ZwOpenKey (&hMFunc, KEY_READ, &objectAttributes);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
unicodeString.Buffer = wbuffer;
|
|
unicodeString.MaximumLength = sizeof(wbuffer);
|
|
RtlInitUnicodeString(&biosId, rgzBIOSIdentifier);
|
|
|
|
for (i = 0; TRUE; i++) {
|
|
RtlIntegerToUnicodeString (i, 10, &unicodeString);
|
|
InitializeObjectAttributes (
|
|
&objectAttributes,
|
|
&unicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
hMFunc,
|
|
NULL);
|
|
|
|
status = ZwOpenKey (&hBus, KEY_READ, &objectAttributes);
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Out of Multifunction adapter entries...
|
|
//
|
|
|
|
ZwClose (hMFunc);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//
|
|
// Check the Indentifier to see if this is an ACPI BIOS entry
|
|
//
|
|
|
|
status = WdAcpiGetRegistryValue (hBus, rgzAcpiIdentifier, &valueInfo);
|
|
if (!NT_SUCCESS (status)) {
|
|
ZwClose (hBus);
|
|
continue;
|
|
}
|
|
|
|
p = (PWSTR) ((PUCHAR) valueInfo->Data);
|
|
unicodeValueName.Buffer = p;
|
|
unicodeValueName.MaximumLength = (USHORT)valueInfo->DataLength;
|
|
length = valueInfo->DataLength;
|
|
|
|
//
|
|
// Determine the real length of the ID string
|
|
//
|
|
|
|
while (length) {
|
|
if (p[length / sizeof(WCHAR) - 1] == UNICODE_NULL) {
|
|
length -= 2;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
unicodeValueName.Length = (USHORT)length;
|
|
same = RtlEqualUnicodeString(&biosId, &unicodeValueName, TRUE);
|
|
ExFreePool(valueInfo);
|
|
if (!same) {
|
|
ZwClose (hBus);
|
|
continue;
|
|
}
|
|
|
|
status = WdAcpiGetRegistryValue(hBus, rgzAcpiConfigurationData, &valueInfo);
|
|
ZwClose (hBus);
|
|
if (!NT_SUCCESS(status)) {
|
|
continue ;
|
|
}
|
|
|
|
prl = (PCM_PARTIAL_RESOURCE_LIST)(valueInfo->Data);
|
|
prd = &prl->PartialDescriptors[0];
|
|
multiNode = (PACPI_BIOS_MULTI_NODE)((PCHAR) prd + sizeof(CM_PARTIAL_RESOURCE_LIST));
|
|
|
|
|
|
break;
|
|
}
|
|
|
|
multiNodeSize = sizeof(ACPI_BIOS_MULTI_NODE) +
|
|
((ULONG)(multiNode->Count - 1) * sizeof(ACPI_E820_ENTRY));
|
|
|
|
*AcpiMulti = (PACPI_BIOS_MULTI_NODE)
|
|
ExAllocatePoolWithTag(NonPagedPool,
|
|
multiNodeSize,
|
|
'IPCA');
|
|
if (*AcpiMulti == NULL) {
|
|
ExFreePool(valueInfo);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlCopyMemory(*AcpiMulti, multiNode, multiNodeSize);
|
|
|
|
ExFreePool(valueInfo);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
PVOID
|
|
WdGetAcpiTable(
|
|
IN ULONG Signature
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will retrieve any table referenced in the ACPI
|
|
RSDT.
|
|
|
|
Arguments:
|
|
|
|
Signature - Target table signature
|
|
|
|
Return Value:
|
|
|
|
pointer to a copy of the table, or NULL if not found
|
|
|
|
--*/
|
|
{
|
|
PACPI_BIOS_MULTI_NODE multiNode;
|
|
NTSTATUS status;
|
|
ULONG entry, rsdtEntries;
|
|
PDESCRIPTION_HEADER header;
|
|
PHYSICAL_ADDRESS physicalAddr;
|
|
PRSDT rsdt;
|
|
ULONG rsdtSize;
|
|
PVOID table = NULL;
|
|
|
|
|
|
//
|
|
// Get the physical address of the RSDT from the Registry
|
|
//
|
|
|
|
status = WdAcpiFindRsdt(&multiNode);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Map down header to get total RSDT table size
|
|
//
|
|
|
|
header = (PDESCRIPTION_HEADER) MmMapIoSpace(multiNode->RsdtAddress, sizeof(DESCRIPTION_HEADER), MmNonCached);
|
|
|
|
if (!header) {
|
|
return NULL;
|
|
}
|
|
|
|
rsdtSize = header->Length;
|
|
MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER));
|
|
|
|
|
|
//
|
|
// Map down entire RSDT table
|
|
//
|
|
|
|
rsdt = (PRSDT) MmMapIoSpace(multiNode->RsdtAddress, rsdtSize, MmNonCached);
|
|
|
|
ExFreePool(multiNode);
|
|
|
|
if (!rsdt) {
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Do a sanity check on the RSDT.
|
|
//
|
|
|
|
if ((rsdt->Header.Signature != RSDT_SIGNATURE) &&
|
|
(rsdt->Header.Signature != XSDT_SIGNATURE)) {
|
|
|
|
goto GetAcpiTableEnd;
|
|
}
|
|
|
|
|
|
//
|
|
// Calculate the number of entries in the RSDT.
|
|
//
|
|
|
|
rsdtEntries = rsdt->Header.Signature == XSDT_SIGNATURE ?
|
|
NumTableEntriesFromXSDTPointer(rsdt) :
|
|
NumTableEntriesFromRSDTPointer(rsdt);
|
|
|
|
|
|
//
|
|
// Look down the pointer in each entry to see if it points to
|
|
// the table we are looking for.
|
|
//
|
|
|
|
for (entry = 0; entry < rsdtEntries; entry++) {
|
|
|
|
if (rsdt->Header.Signature == XSDT_SIGNATURE) {
|
|
physicalAddr = ((PXSDT)rsdt)->Tables[entry];
|
|
} else {
|
|
physicalAddr.HighPart = 0;
|
|
physicalAddr.LowPart = (ULONG)rsdt->Tables[entry];
|
|
}
|
|
|
|
//
|
|
// Map down the header, check the signature
|
|
//
|
|
|
|
header = (PDESCRIPTION_HEADER) MmMapIoSpace(physicalAddr, sizeof(DESCRIPTION_HEADER), MmNonCached);
|
|
|
|
if (!header) {
|
|
goto GetAcpiTableEnd;
|
|
}
|
|
|
|
if (header->Signature == Signature) {
|
|
|
|
table = ExAllocatePoolWithTag(PagedPool, header->Length, 'IPCA');
|
|
|
|
if (table) {
|
|
RtlCopyMemory(table, header, header->Length);
|
|
}
|
|
|
|
MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER));
|
|
break;
|
|
}
|
|
|
|
MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER));
|
|
}
|
|
|
|
|
|
GetAcpiTableEnd:
|
|
|
|
MmUnmapIoSpace(rsdt, rsdtSize);
|
|
return table;
|
|
|
|
}
|