366 lines
9.7 KiB
C
366 lines
9.7 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1997 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
acpidtct.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This file pulls the ACPI Root Ssytem Description
|
|||
|
Pointer out of the registry. It was put there
|
|||
|
either by ntdetect.com or by one ARC firmware or
|
|||
|
another.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Jake Oshins (jakeo) 6-Feb-1997
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode only.
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include "halp.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"
|
|||
|
|
|||
|
PHYSICAL_ADDRESS HalpAcpiRsdt;
|
|||
|
|
|||
|
// from ntrtl.h
|
|||
|
NTSYSAPI
|
|||
|
BOOLEAN
|
|||
|
NTAPI
|
|||
|
RtlEqualUnicodeString(
|
|||
|
PUNICODE_STRING String1,
|
|||
|
PUNICODE_STRING String2,
|
|||
|
BOOLEAN CaseInSensitive
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
// internal definitions
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
HalpAcpiGetRegistryValue(
|
|||
|
IN HANDLE KeyHandle,
|
|||
|
IN PWSTR ValueName,
|
|||
|
OUT PKEY_VALUE_PARTIAL_INFORMATION *Information
|
|||
|
);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(INIT,HalpAcpiFindRsdtPhase0)
|
|||
|
#pragma alloc_text(PAGELK,HalpAcpiGetRegistryValue)
|
|||
|
#pragma alloc_text(PAGELK,HalpAcpiFindRsdt)
|
|||
|
#endif
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
HalpAcpiFindRsdtPhase0(
|
|||
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function reads the Root System Description Pointer from
|
|||
|
the ACPI BIOS node in the arc tree. It puts whatever it finds
|
|||
|
into HalpAcpiRsdt.
|
|||
|
|
|||
|
This function is suitable for being called during Phase 0 or
|
|||
|
Phase 1 only. The LoaderBlock is destroyed after that.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PCONFIGURATION_COMPONENT_DATA RsdtComponent = NULL;
|
|||
|
PCONFIGURATION_COMPONENT_DATA Component = NULL;
|
|||
|
PCONFIGURATION_COMPONENT_DATA Resume = NULL;
|
|||
|
PCM_PARTIAL_RESOURCE_LIST Prl;
|
|||
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR Prd;
|
|||
|
ACPI_BIOS_MULTI_NODE UNALIGNED *Rsdp;
|
|||
|
|
|||
|
while (Component = KeFindConfigurationNextEntry(LoaderBlock->ConfigurationRoot,AdapterClass,
|
|||
|
MultiFunctionAdapter,NULL,&Resume)) {
|
|||
|
if (!(strcmp(Component->ComponentEntry.Identifier,"ACPI BIOS"))) {
|
|||
|
RsdtComponent = Component;
|
|||
|
break;
|
|||
|
}
|
|||
|
Resume = Component;
|
|||
|
}
|
|||
|
|
|||
|
//if RsdtComponent is still NULL, we didn't find node
|
|||
|
if (!RsdtComponent) {
|
|||
|
DbgPrint("**** HalpAcpiFindRsdtPhase0: did NOT find RSDT\n");
|
|||
|
return STATUS_NOT_FOUND;
|
|||
|
}
|
|||
|
|
|||
|
Prl = (PCM_PARTIAL_RESOURCE_LIST)(RsdtComponent->ConfigurationData);
|
|||
|
Prd = &Prl->PartialDescriptors[0];
|
|||
|
|
|||
|
Rsdp = (PACPI_BIOS_MULTI_NODE)((PCHAR) Prd + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
|||
|
|
|||
|
HalpAcpiRsdt.QuadPart = Rsdp->RsdtAddress.QuadPart;
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
HalpAcpiFindRsdt (
|
|||
|
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;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// 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)) {
|
|||
|
DbgPrint("AcpiBios:Can not open MultifunctionAdapter registry key.\n");
|
|||
|
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...
|
|||
|
//
|
|||
|
|
|||
|
DbgPrint("AcpiBios: ACPI BIOS MultifunctionAdapter registry key not found.\n");
|
|||
|
ZwClose (hMFunc);
|
|||
|
return STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check the Indentifier to see if this is an ACPI BIOS entry
|
|||
|
//
|
|||
|
|
|||
|
status = HalpAcpiGetRegistryValue (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 = HalpAcpiGetRegistryValue(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;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
HalpAcpiGetRegistryValue(
|
|||
|
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;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
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 = 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;
|
|||
|
}
|