|
|
/*++
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, ®istryId, 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"); }
|