windows-nt/Source/XPSP1/NT/base/hals/acpidtct.c
2020-09-26 16:20:57 +08:00

366 lines
9.3 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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