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.
 
 
 
 
 
 

520 lines
14 KiB

extern "C" {
#include <ntosp.h>
#include <zwapi.h>
#include <ntacpi.h>
#include <acpitabl.h>
}
#define KEY_MULTIFUNCTION L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultiFunctionAdapter"
#define VALUE_IDENTIFIER L"Identifier"
#define VALUE_CONFIGURATION_DATA L"Configuration Data"
#define ACPI_BIOS_ID L"ACPI BIOS"
BOOLEAN
PciOpenKey(
IN PWSTR KeyName,
IN HANDLE ParentHandle,
OUT PHANDLE Handle,
OUT PNTSTATUS Status
)
/*++
Description:
Open a registry key.
Arguments:
KeyName Name of the key to be opened.
ParentHandle Pointer to the parent handle (OPTIONAL)
Handle Pointer to a handle to recieve the opened key.
Return Value:
TRUE is key successfully opened, FALSE otherwise.
--*/
{
UNICODE_STRING nameString;
OBJECT_ATTRIBUTES nameAttributes;
NTSTATUS localStatus;
PAGED_CODE();
RtlInitUnicodeString(&nameString, KeyName);
InitializeObjectAttributes(&nameAttributes,
&nameString,
OBJ_CASE_INSENSITIVE,
ParentHandle,
(PSECURITY_DESCRIPTOR)NULL
);
localStatus = ZwOpenKey(Handle,
KEY_READ,
&nameAttributes
);
if (Status != NULL) {
//
// Caller wants underlying status.
//
*Status = localStatus;
}
//
// Return status converted to a boolean, TRUE if
// successful.
//
return NT_SUCCESS(localStatus);
}
NTSTATUS
PciGetRegistryValue(
IN PWSTR ValueName,
IN PWSTR KeyName,
IN HANDLE ParentHandle,
OUT PVOID *Buffer,
OUT ULONG *Length
)
{
NTSTATUS status;
HANDLE keyHandle;
ULONG neededLength;
ULONG actualLength;
UNICODE_STRING unicodeValueName;
PKEY_VALUE_PARTIAL_INFORMATION info;
if (!PciOpenKey(KeyName, ParentHandle, &keyHandle, &status)) {
return status;
}
unicodeValueName.Buffer = ValueName;
unicodeValueName.MaximumLength = (wcslen(ValueName) + 1) * sizeof(WCHAR);
unicodeValueName.Length = unicodeValueName.MaximumLength - sizeof(WCHAR);
//
// Find out how much memory we need for this.
//
status = ZwQueryValueKey(
keyHandle,
&unicodeValueName,
KeyValuePartialInformation,
NULL,
0,
&neededLength
);
if (status == STATUS_BUFFER_TOO_SMALL) {
//
// Get memory to return the data in. Note this includes
// a header that we really don't want.
//
info = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePool( PagedPool, neededLength );
if (info == NULL) {
ZwClose(keyHandle);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Get the data.
//
status = ZwQueryValueKey(
keyHandle,
&unicodeValueName,
KeyValuePartialInformation,
info,
neededLength,
&actualLength
);
if (!NT_SUCCESS(status)) {
ExFreePool(info);
ZwClose(keyHandle);
return status;
}
//
// Subtract out the header size and get memory for just
// the data we want.
//
neededLength -= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
*Buffer = ExAllocatePool( PagedPool, neededLength );
if (*Buffer == NULL) {
ExFreePool(info);
ZwClose(keyHandle);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Copy data sans header.
//
RtlCopyMemory(*Buffer, info->Data, neededLength);
ExFreePool(info);
if (Length) {
*Length = neededLength;
}
} else {
if (NT_SUCCESS(status)) {
//
// We don't want to report success when this happens.
//
status = STATUS_UNSUCCESSFUL;
}
}
ZwClose(keyHandle);
return status;
}
NTSTATUS
PciAcpiFindRsdt (
OUT PACPI_BIOS_MULTI_NODE *AcpiMulti
)
{
PKEY_FULL_INFORMATION multiKeyInformation = NULL;
PKEY_BASIC_INFORMATION keyInfo = NULL;
PKEY_VALUE_PARTIAL_INFORMATION identifierValueInfo = NULL;
UNICODE_STRING unicodeString;
HANDLE keyMultifunction = NULL, keyTable = NULL;
PCM_PARTIAL_RESOURCE_LIST prl = NULL;
PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
PACPI_BIOS_MULTI_NODE multiNode;
ULONG multiNodeSize;
ULONG i, length, maxKeyLength, identifierValueLen;
BOOLEAN result;
NTSTATUS status;
//
// Open the multifunction key
//
result = PciOpenKey(KEY_MULTIFUNCTION,
NULL,
&keyMultifunction,
&status);
if (!result) {
goto Cleanup;
}
//
// Do allocation of buffers up front
//
//
// Determine maximum size of a keyname under the multifunction key
//
status = ZwQueryKey(keyMultifunction,
KeyFullInformation,
NULL,
sizeof(multiKeyInformation),
&length);
if (status != STATUS_BUFFER_TOO_SMALL) {
goto Cleanup;
}
multiKeyInformation = (PKEY_FULL_INFORMATION)ExAllocatePool( PagedPool, length );
if (multiKeyInformation == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
status = ZwQueryKey(keyMultifunction,
KeyFullInformation,
multiKeyInformation,
length,
&length);
if (!NT_SUCCESS(status)) {
goto Cleanup;
}
// includes space for a terminating null that will be added later.
maxKeyLength = multiKeyInformation->MaxNameLen +
sizeof(KEY_BASIC_INFORMATION) + sizeof(WCHAR);
//
// Allocate buffer used for storing subkeys that we are enumerated
// under multifunction.
//
keyInfo = (PKEY_BASIC_INFORMATION)ExAllocatePool( PagedPool, maxKeyLength );
if (keyInfo == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
//
// Allocate buffer large enough to store a value containing REG_SZ
// 'ACPI BIOS'. We hope to find such a value under one of the
// multifunction subkeys
//
identifierValueLen = sizeof(ACPI_BIOS_ID) + sizeof(KEY_VALUE_PARTIAL_INFORMATION);
identifierValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool( PagedPool, identifierValueLen );
if (identifierValueInfo == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
//
// Enumerate subkeys of multifunction key looking for keys with an
// Identifier value of "ACPI BIOS". If we find one, look for the
// irq routing table in the tree below.
//
i = 0;
do {
status = ZwEnumerateKey(keyMultifunction,
i,
KeyBasicInformation,
keyInfo,
maxKeyLength,
&length);
if (NT_SUCCESS(status)) {
//
// Found a key, now we need to open it and check the
// 'Identifier' value to see if it is 'ACPI BIOS'
//
keyInfo->Name[keyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
result = PciOpenKey(keyInfo->Name,
keyMultifunction,
&keyTable,
&status);
if (result) {
//
// Checking 'Identifier' value to see if it contains 'ACPI BIOS'
//
RtlInitUnicodeString(&unicodeString, VALUE_IDENTIFIER);
status = ZwQueryValueKey(keyTable,
&unicodeString,
KeyValuePartialInformation,
identifierValueInfo,
identifierValueLen,
&length);
if (NT_SUCCESS(status) &&
RtlEqualMemory((PCHAR)identifierValueInfo->Data,
ACPI_BIOS_ID,
identifierValueInfo->DataLength))
{
//
// This is the ACPI BIOS key. Try to get Configuration Data
// This is the key we were looking
// for so regardless of success, break out.
//
ZwClose(keyTable);
status = PciGetRegistryValue(VALUE_CONFIGURATION_DATA,
keyInfo->Name,
keyMultifunction,
(PVOID*)&prl,
&length);
break;
}
ZwClose(keyTable);
}
} else {
//
// If not NT_SUCCESS, only alowable value is
// STATUS_NO_MORE_ENTRIES,... otherwise, someone
// is playing with the keys as we enumerate
//
break;
}
i++;
}
while (status != STATUS_NO_MORE_ENTRIES);
if (NT_SUCCESS(status) && prl) {
prd = &prl->PartialDescriptors[0];
multiNode = (PACPI_BIOS_MULTI_NODE)((PCHAR) prd + sizeof(CM_PARTIAL_RESOURCE_LIST));
multiNodeSize = sizeof(ACPI_BIOS_MULTI_NODE) + ((ULONG)(multiNode->Count - 1) * sizeof(ACPI_E820_ENTRY));
*AcpiMulti = (PACPI_BIOS_MULTI_NODE) ExAllocatePool( NonPagedPool, multiNodeSize );
if (*AcpiMulti == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlCopyMemory(*AcpiMulti, multiNode, multiNodeSize);
}
Cleanup:
if (identifierValueInfo != NULL) {
ExFreePool(identifierValueInfo);
}
if (keyInfo != NULL) {
ExFreePool(keyInfo);
}
if (multiKeyInformation != NULL) {
ExFreePool(multiKeyInformation);
}
if (keyMultifunction != NULL) {
ZwClose(keyMultifunction);
}
if (prl) {
ExFreePool(prl);
}
return status;
}
PVOID
PciGetAcpiTable(
void
)
/*++
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;
ULONG Signature = WDTT_SIGNATURE;
//
// Get the physical address of the RSDT from the Registry
//
status = PciAcpiFindRsdt(&multiNode);
if (!NT_SUCCESS(status)) {
DbgPrint("AcpiFindRsdt() Failed!\n");
return NULL;
}
//
// Map down header to get total RSDT table size
//
header = (PDESCRIPTION_HEADER) MmMapIoSpace(multiNode->RsdtAddress, sizeof(DESCRIPTION_HEADER), MmCached);
if (!header) {
return NULL;
}
rsdtSize = header->Length;
MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER));
//
// Map down entire RSDT table
//
rsdt = (PRSDT) MmMapIoSpace(multiNode->RsdtAddress, rsdtSize, MmCached);
ExFreePool(multiNode);
if (!rsdt) {
return NULL;
}
//
// Do a sanity check on the RSDT.
//
if ((rsdt->Header.Signature != RSDT_SIGNATURE) &&
(rsdt->Header.Signature != XSDT_SIGNATURE)) {
DbgPrint("RSDT table contains invalid signature\n");
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), MmCached);
if (!header) {
goto GetAcpiTableEnd;
}
if (header->Signature == Signature) {
table = ExAllocatePool( PagedPool, header->Length );
if (table) {
RtlCopyMemory(table, header, header->Length);
}
MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER));
break;
}
MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER));
}
GetAcpiTableEnd:
MmUnmapIoSpace(rsdt, rsdtSize);
return table;
}