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;
|
||
}
|