windows-nt/Source/XPSP1/NT/base/busdrv/acpi/driver/nt/reg.c

1040 lines
23 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
regcd.c
Abstract:
This contains all of the registry munging code of the NT-specific
side of the ACPI driver
Author:
Stephane Plante (splante)
Environment:
Kernel mode only.
Revision History:
31-Mar-96 Initial Revision
--*/
#include "pch.h"
NTSTATUS
OSOpenUnicodeHandle(
PUNICODE_STRING UnicodeKey,
HANDLE ParentHandle,
PHANDLE ChildHandle
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,OSCloseHandle)
#pragma alloc_text(PAGE,OSCreateHandle)
#pragma alloc_text(PAGE,OSGetRegistryValue)
#pragma alloc_text(PAGE,OSOpenHandle)
#pragma alloc_text(PAGE,OSOpenUnicodeHandle)
#pragma alloc_text(PAGE,OSOpenLargestSubkey)
#pragma alloc_text(PAGE,OSReadAcpiConfigurationData)
#pragma alloc_text(PAGE,OSReadRegValue)
#pragma alloc_text(PAGE,OSWriteRegValue)
#endif
WCHAR rgzAcpiBiosIdentifier[] = L"ACPI BIOS";
WCHAR rgzAcpiConfigurationDataIdentifier[] = L"Configuration Data";
WCHAR rgzAcpiMultiFunctionAdapterIdentifier[] = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultiFunctionAdapter";
WCHAR rgzAcpiRegistryIdentifier[] = L"Identifier";
NTSTATUS
OSCloseHandle(
HANDLE Key
)
{
//
// Call the function that will close the handle now...
//
PAGED_CODE();
return ZwClose( Key );
}
NTSTATUS
OSCreateHandle(
PSZ KeyName,
HANDLE ParentHandle,
PHANDLE ChildHandle
)
/*++
Routine Description:
Creates a registry key for writting
Arguments:
KeyName - Name of the key to create
ParentHandle - Handle of parent key
ChildHandle - Pointer to where the handle is returned
Return Value:
Status of create/open
--*/
{
ANSI_STRING ansiKey;
NTSTATUS status;
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING unicodeKey;
PAGED_CODE();
ACPIDebugEnter("OSCreateHandle");
//
// We need to convert the given narrow character string into unicode
//
RtlInitAnsiString( &ansiKey, KeyName );
status = RtlAnsiStringToUnicodeString( &unicodeKey, &ansiKey, TRUE );
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSCreateHandle: RtlAnsiStringToUnicodeString = %#08lx\n",
status
) );
return status;
}
//
// Initialize the OBJECT Attributes to a known value
//
RtlZeroMemory( &objectAttributes, sizeof(OBJECT_ATTRIBUTES) );
InitializeObjectAttributes(
&objectAttributes,
&unicodeKey,
OBJ_CASE_INSENSITIVE,
ParentHandle,
NULL
);
//
// Create the key here
//
*ChildHandle = 0;
status = ZwCreateKey(
ChildHandle,
KEY_WRITE,
&objectAttributes,
0,
NULL,
REG_OPTION_NON_VOLATILE,
NULL
);
//
// We no longer care about the Key after this point...
//
RtlFreeUnicodeString( &unicodeKey );
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_REGISTRY,
"OSCreateHandle: ZwCreateKey = %#08lx\n",
status
) );
}
return status;
ACPIDebugExit("OSCreateHandle");
}
NTSTATUS
OSGetRegistryValue(
IN HANDLE ParentHandle,
IN PWSTR ValueName,
OUT PKEY_VALUE_PARTIAL_INFORMATION_ALIGN64 *Information
)
{
NTSTATUS status;
PKEY_VALUE_PARTIAL_INFORMATION_ALIGN64 infoBuffer;
ULONG keyValueLength;
UNICODE_STRING unicodeString;
PAGED_CODE();
ACPIDebugEnter("OSGetRegistryValue");
RtlInitUnicodeString( &unicodeString, ValueName );
//
// Figure out how big the data value is so that we can allocate the
// proper sized buffer
//
status = ZwQueryValueKey(
ParentHandle,
&unicodeString,
KeyValuePartialInformationAlign64,
(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,
ACPI_STRING_POOLTAG
);
if (infoBuffer == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Now query the data again and this time it will work
//
status = ZwQueryValueKey(
ParentHandle,
&unicodeString,
KeyValuePartialInformationAlign64,
(PVOID) infoBuffer,
keyValueLength,
&keyValueLength
);
if (!NT_SUCCESS(status)) {
ExFreePool( infoBuffer );
return status;
}
//
// Everything worked - so simply return the address of the allocated
// structure buffer to the caller, who is now responsible for freeing it
//
*Information = infoBuffer;
return STATUS_SUCCESS;
ACPIDebugExit("OSGetRegistryValue");
}
NTSTATUS
OSOpenHandle(
PSZ KeyName,
HANDLE ParentHandle,
PHANDLE ChildHandle
)
{
ANSI_STRING ansiKey;
NTSTATUS status;
UNICODE_STRING unicodeKey;
PAGED_CODE();
ACPIDebugEnter("OSOpenHandle");
//
// We need to convert the given narrow character string into unicode
//
RtlInitAnsiString( &ansiKey, KeyName );
status = RtlAnsiStringToUnicodeString( &unicodeKey, &ansiKey, TRUE );
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSOpenHandle: RtlAnsiStringToUnicodeString = %#08lx\n",
status
) );
return status;
}
status = OSOpenUnicodeHandle( &unicodeKey, ParentHandle, ChildHandle );
//
// We no longer care about the Key after this point...
//
RtlFreeUnicodeString( &unicodeKey );
return status;
ACPIDebugExit("OSOpenHandle");
}
NTSTATUS
OSOpenUnicodeHandle(
PUNICODE_STRING UnicodeKey,
HANDLE ParentHandle,
PHANDLE ChildHandle
)
{
NTSTATUS status;
OBJECT_ATTRIBUTES objectAttributes;
PAGED_CODE();
//
// Initialize the OBJECT Attributes to a known value
//
RtlZeroMemory( &objectAttributes, sizeof(OBJECT_ATTRIBUTES) );
InitializeObjectAttributes(
&objectAttributes,
UnicodeKey,
OBJ_CASE_INSENSITIVE,
ParentHandle,
NULL
);
//
// Open the key here
//
status = ZwOpenKey(
ChildHandle,
KEY_READ,
&objectAttributes
);
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_REGISTRY,
"OSOpenUnicodeHandle: ZwOpenKey = %#08lx\n",
status
) );
}
return status;
}
NTSTATUS
OSOpenLargestSubkey(
HANDLE ParentHandle,
PHANDLE ChildHandle,
ULONG RomVersion
)
/*++
Routine Description:
Open the largest (numerically) subkey under the given parent key.
Arguments:
ParentHandle - Handle to the parent key
ChildHandle - Pointer to where the handle is returned
RomVersion - Minimum version number that is acceptable
Return Value:
Status of open
--*/
{
NTSTATUS status;
UNICODE_STRING unicodeName;
PKEY_BASIC_INFORMATION keyInformation;
ULONG resultLength;
ULONG i;
HANDLE workingDir = NULL;
HANDLE largestDir = NULL;
ULONG largestRev = 0;
ULONG thisRev = 0;
PAGED_CODE();
ACPIDebugEnter( "OSOpenLargestSubkey" );
keyInformation = ExAllocatePoolWithTag(
PagedPool,
512,
ACPI_MISC_POOLTAG
);
if (keyInformation == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Traverse all subkeys
//
for (i = 0; ; i++) {
//
// Get a subkey
//
status = ZwEnumerateKey(
ParentHandle,
i,
KeyBasicInformation,
keyInformation,
512,
&resultLength
);
if (!NT_SUCCESS(status)) { // Fail when no more subkeys
break;
}
//
// Create a UNICODE_STRING using the counted string passed back to
// us in the information structure, and convert to an integer.
//
unicodeName.Length = (USHORT) keyInformation->NameLength;
unicodeName.MaximumLength = (USHORT) keyInformation->NameLength;
unicodeName.Buffer = keyInformation->Name;
RtlUnicodeStringToInteger(&unicodeName, 16, &thisRev);
//
// Save this one if it is the largest
//
if ( (workingDir == NULL) || thisRev > largestRev) {
//
// We'll just open the target rather than save
// away the name to open later
//
status = OSOpenUnicodeHandle(
&unicodeName,
ParentHandle,
&workingDir
);
if ( NT_SUCCESS(status) ) {
if (largestDir) {
OSCloseHandle (largestDir); // Close previous
}
largestDir = workingDir; // Save handle
largestRev = thisRev; // Save version number
}
}
}
//
// Done with KeyInformation
//
ExFreePool( keyInformation );
//
// No subkey found/opened, this is a problem
//
if (largestDir == NULL) {
return ( NT_SUCCESS(status) ? STATUS_UNSUCCESSFUL : status );
}
//
// Use the subkey only if it the revision is equal or greater than the
// ROM version
//
if (largestRev < RomVersion) {
OSCloseHandle (largestDir);
return STATUS_REVISION_MISMATCH;
}
*ChildHandle = largestDir; // Return handle to subkey
return STATUS_SUCCESS;
ACPIDebugExit( "OSOpenLargestSubkey" );
}
NTSTATUS
OSReadAcpiConfigurationData(
PKEY_VALUE_PARTIAL_INFORMATION_ALIGN64 *KeyInfo
)
/*++
Routine Description:
This very specialized routine looks in the Registry and tries to find
the information that was written there by ntdetect. It returns a pointer
to the keyvalue that will then be processed by the caller to find the
pointer to the RSDT and the E820 memory table
Arguments:
KeyInfo - Where to store the pointer to the information from the registry
Return Value:
NTSTATUS
--*/
{
BOOLEAN sameId;
HANDLE functionHandle;
HANDLE multiHandle;
NTSTATUS status;
ULONG i;
ULONG length;
UNICODE_STRING biosId;
UNICODE_STRING functionId;
UNICODE_STRING registryId;
WCHAR wbuffer[4];
ASSERT( KeyInfo != NULL );
if (KeyInfo == NULL) {
return STATUS_INVALID_PARAMETER;
}
*KeyInfo = NULL;
//
// Open the handle for the MultiFunctionAdapter
//
RtlInitUnicodeString( &functionId, rgzAcpiMultiFunctionAdapterIdentifier );
status = OSOpenUnicodeHandle(
&functionId,
NULL,
&multiHandle
);
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSReadAcpiConfigurationData: Cannot open MFA Handle = %08lx\n",
status
) );
ACPIBreakPoint();
return status;
}
//
// Initialize the unicode strings we will need shortly
//
RtlInitUnicodeString( &biosId, rgzAcpiBiosIdentifier );
functionId.Buffer = wbuffer;
functionId.MaximumLength = sizeof(wbuffer);
//
// Loop until we run out of children in the MFA node
//
for (i = 0; i < 999; i++) {
//
// Open the subkey
//
RtlIntegerToUnicodeString(i, 10, &functionId );
status = OSOpenUnicodeHandle(
&functionId,
multiHandle,
&functionHandle
);
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSReadAcpiConfigurationData: Cannot open MFA %ws = %08lx\n",
functionId.Buffer,
status
) );
ACPIBreakPoint();
OSCloseHandle( multiHandle );
return status;
}
//
// Check the identifier to see if this is an ACPI BIOS entry
//
status = OSGetRegistryValue(
functionHandle,
rgzAcpiRegistryIdentifier,
KeyInfo
);
if (!NT_SUCCESS(status)) {
OSCloseHandle( functionHandle );
continue;
}
//
// Convert the key information into a unicode string
//
registryId.Buffer = (PWSTR) ( (PUCHAR) (*KeyInfo)->Data);
registryId.MaximumLength = (USHORT) ( (*KeyInfo)->DataLength );
length = ( (*KeyInfo)->DataLength ) / sizeof(WCHAR);
//
// Determine the real length of the ID string
//
while (length) {
if (registryId.Buffer[length-1] == UNICODE_NULL) {
length--;
continue;
}
break;
}
registryId.Length = (USHORT) ( length * sizeof(WCHAR) );
//
// Compare the bios string and the registry string
//
sameId = RtlEqualUnicodeString( &biosId, &registryId, TRUE );
//
// We are done with this information at this point
//
ExFreePool( *KeyInfo );
//
// Did the two strings match
//
if (sameId == FALSE) {
OSCloseHandle( functionHandle );
continue;
}
//
// Read the configuration data from the entry
//
status = OSGetRegistryValue(
functionHandle,
rgzAcpiConfigurationDataIdentifier,
KeyInfo
);
//
// We are done with the function handle, no matter what
//
OSCloseHandle( functionHandle );
//
// Did we read what we wanted to?
//
if (!NT_SUCCESS(status)) {
continue;
}
//
// At this point, we don't need the bus handle
//
OSCloseHandle( multiHandle );
return STATUS_SUCCESS;
}
//
// If we got here, then there is nothing to return
//
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSReadAcpiConfigurationData - Could not find entry\n"
) );
ACPIBreakPoint();
return STATUS_OBJECT_NAME_NOT_FOUND;
}
NTSTATUS
OSReadRegValue(
PSZ ValueName,
HANDLE ParentHandle,
PUCHAR Buffer,
PULONG BufferSize
)
/*++
Routine Description:
This function is responsible for returning the data in the specified value
over to the calling function.
Arguments:
ValueName - What we are looking for
ParentHandle - Our Parent Handle
Buffer - Where to store the data
BufferSize - Length of the buffer and where to store the # read
Return Value:
NTSTATUS
--*/
{
ANSI_STRING ansiValue;
HANDLE localHandle = NULL;
NTSTATUS status;
PKEY_VALUE_PARTIAL_INFORMATION_ALIGN64 data = NULL;
ULONG currentLength = 0;
ULONG desiredLength = 0;
UNICODE_STRING unicodeValue;
PAGED_CODE();
ACPIDebugEnter( "OSReadRegValue" );
//
// First, try to open a handle to the key
//
if (ParentHandle == NULL) {
status= OSOpenHandle(
ACPI_PARAMETERS_REGISTRY_KEY,
0,
&localHandle
);
if (!NT_SUCCESS(status) || localHandle == NULL) {
ACPIPrint( (
ACPI_PRINT_WARNING,
"OSReadRegValue: OSOpenHandle = %#08lx\n",
status
) );
return (ULONG) status;
}
} else {
localHandle = ParentHandle;
}
//
// Now that we have an open handle, we can convert the value to a
// unicode string and query it
//
RtlInitAnsiString( &ansiValue, ValueName );
status = RtlAnsiStringToUnicodeString( &unicodeValue, &ansiValue, TRUE );
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSReadRegValue: RtlAnsiStringToUnicodeString = %#08lx\n",
status
) );
if (ParentHandle == NULL) {
OSCloseHandle( localHandle );
}
return status;
}
//
// Next, we need to figure out how much memore we need to hold the
// entire key
//
status = ZwQueryValueKey(
localHandle,
&unicodeValue,
KeyValuePartialInformationAlign64,
data,
currentLength,
&desiredLength
);
//
// We expect this to fail with STATUS_BUFFER_OVERFLOW, so lets make
// sure that this is what happened
//
if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL) {
ACPIPrint( (
ACPI_PRINT_WARNING,
"OSReadRegValue: ZwQueryValueKey = %#08lx\n",
status
) );
//
// Free resources
//
RtlFreeUnicodeString( &unicodeValue );
if (ParentHandle == NULL) {
OSCloseHandle( localHandle );
}
return (NT_SUCCESS(status) ? STATUS_UNSUCCESSFUL : status);
}
while (status == STATUS_BUFFER_OVERFLOW ||
status == STATUS_BUFFER_TOO_SMALL) {
//
// Set the new currentLength
//
currentLength = desiredLength;
//
// Allocate a correctly sized buffer
//
data = ExAllocatePoolWithTag(
PagedPool,
currentLength,
ACPI_MISC_POOLTAG
);
if (data == NULL) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSReadRegValue: ExAllocatePool(NonPagedPool,%#08lx) failed\n",
desiredLength
) );
RtlFreeUnicodeString( &unicodeValue );
if (ParentHandle == NULL) {
OSCloseHandle( localHandle );
}
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Actually try to read the entire key now
//
status = ZwQueryValueKey(
localHandle,
&unicodeValue,
KeyValuePartialInformationAlign64,
data,
currentLength,
&desiredLength
);
//
// If we don't have enough resources, lets just loop again
//
if (status == STATUS_BUFFER_OVERFLOW ||
status == STATUS_BUFFER_TOO_SMALL) {
//
// Make sure to free the old buffer -- otherwise, we could
// have a major memory leak
//
ExFreePool( data );
continue;
}
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_FAILURE,
"OSReadRegValue: ZwQueryValueKey = %#08lx\n",
status
) );
RtlFreeUnicodeString( &unicodeValue );
if (ParentHandle == NULL) {
OSCloseHandle( localHandle );
}
ExFreePool( data );
return status;
}
//
// Done
//
break;
} // while (status == ...
//
// Free Resources
//
RtlFreeUnicodeString( &unicodeValue );
if (ParentHandle == NULL) {
OSCloseHandle( localHandle );
}
//
// The value read from the registry is a UNICODE Value, however
// we are asked for an ANSI string. So we just work the conversion
// backwards
//
if ( data->Type == REG_SZ ||
data->Type == REG_MULTI_SZ) {
RtlInitUnicodeString( &unicodeValue, (PWSTR) data->Data );
status = RtlUnicodeStringToAnsiString( &ansiValue, &unicodeValue, TRUE);
ExFreePool( data );
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSReadRegValue: RtlAnsiStringToUnicodeString = %#08lx\n",
status
) );
return (ULONG) status;
}
//
// Is our buffer big enough?
//
if ( *BufferSize < ansiValue.MaximumLength) {
ACPIPrint( (
ACPI_PRINT_WARNING,
"OSReadRegValue: %#08lx < %#08lx\n",
*BufferSize,
ansiValue.MaximumLength
) );
RtlFreeAnsiString( &ansiValue );
return (ULONG) STATUS_BUFFER_OVERFLOW;
} else {
//
// Set the returned size
//
*BufferSize = ansiValue.MaximumLength;
}
//
// Copy the required information
//
RtlCopyMemory( Buffer, ansiValue.Buffer, *BufferSize);
RtlFreeAnsiString( &ansiValue );
} else if ( *BufferSize >= data->DataLength) {
//
// Copy the memory
//
RtlCopyMemory( Buffer, data->Data, data->DataLength );
*BufferSize = data->DataLength;
ExFreePool( data );
} else {
ExFreePool( data );
return STATUS_BUFFER_OVERFLOW;
}
//
// Done
//
return STATUS_SUCCESS;
ACPIDebugExit( "OSReadRegValue" );
}
NTSTATUS
OSWriteRegValue(
PSZ ValueName,
HANDLE Handle,
PVOID Data,
ULONG DataSize
)
/*++
Routine Description:
Creates a value item in a registry key, and writes data to it
Arguments:
ValueName - Name of the value item to create
Handle - Handle of the parent key
Data - Raw data to be written to the value
DataSize - Size of the data to write
Return Value:
Status of create/write
--*/
{
ANSI_STRING ansiKey;
NTSTATUS status;
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING unicodeKey;
PAGED_CODE();
ACPIDebugEnter("OSWriteRegValue");
//
// We need to convert the given narrow character string into unicode
//
RtlInitAnsiString( &ansiKey, ValueName );
status = RtlAnsiStringToUnicodeString( &unicodeKey, &ansiKey, TRUE );
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSWriteRegValue: RtlAnsiStringToUnicodeString = %#08lx\n",
status
) );
return status;
}
//
// Create the value
//
status = ZwSetValueKey(
Handle,
&unicodeKey,
0,
REG_BINARY,
Data,
DataSize
);
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_REGISTRY,
"OSRegWriteValue: ZwSetValueKey = %#08lx\n",
status
) );
}
//
// We no longer care about the Key after this point...
//
RtlFreeUnicodeString( &unicodeKey );
return status;
ACPIDebugExit("OSRegWriteValue");
}