Leaked source code of windows server 2003
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

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