656 lines
15 KiB
C
656 lines
15 KiB
C
/*++
|
||
|
||
Copyright (c) 1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
reg.c
|
||
|
||
Abstract:
|
||
|
||
These functions access the registry
|
||
|
||
Author:
|
||
|
||
Stephane Plante (splante)
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
03-Jun-97 Initial Revision
|
||
|
||
--*/
|
||
|
||
#include "pch.h"
|
||
#include "amlreg.h"
|
||
#include <stdio.h>
|
||
|
||
//
|
||
// This controls wether or not the various tables will be dumped to the
|
||
// registry
|
||
//
|
||
UCHAR DoAcpiTableDump = 0xFF;
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#define alloc_text(PAGE,ACPIRegLocalCopyString)
|
||
#define alloc_text(PAGE,ACPIRegDumpAcpiTable)
|
||
#define alloc_text(PAGE,ACPIRegDumpAcpiTables)
|
||
#define alloc_text(PAGE,ACPIRegReadEntireAcpiTable)
|
||
#define alloc_text(PAGE,ACPIRegReadAMLRegistryEntry)
|
||
#endif
|
||
|
||
|
||
PUCHAR
|
||
ACPIRegLocalCopyString (
|
||
PUCHAR Destination,
|
||
PUCHAR Source,
|
||
ULONG MaxLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
A little routine to copy short strings, since using sprintf here is
|
||
like hitting a tack with a sledgehammer. Terminates when a null or
|
||
the max length is reached, whichever comes first. Translates blanks
|
||
to underscores, since everyone hates blanks embedded in registry keys.
|
||
|
||
Arguments:
|
||
|
||
Destination - Where to copy the string to
|
||
Source - Source string pointer
|
||
MaxLength - Max number of bytes to copy
|
||
|
||
Return Value:
|
||
|
||
Returns the destination pointer incremented past the copied string
|
||
|
||
__*/
|
||
{
|
||
ULONG i;
|
||
|
||
|
||
for (i = 0; i < MaxLength; i++) {
|
||
|
||
if (Source[i] == 0) {
|
||
break;
|
||
|
||
} else if (Source[i] == ' ') { // Translate blanks to underscores
|
||
Destination [i] = '_';
|
||
|
||
} else {
|
||
Destination [i] = Source[i];
|
||
}
|
||
}
|
||
|
||
Destination [i] = 0;
|
||
return (Destination + i);
|
||
}
|
||
|
||
BOOLEAN
|
||
ACPIRegReadAMLRegistryEntry(
|
||
IN PVOID *Table,
|
||
IN BOOLEAN MemoryMapped
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This reads a table from the registry
|
||
|
||
Arguments:
|
||
|
||
Table - Where to store the pointer to the table. If non-null, this
|
||
contains a pointer to where the Original Table is stored
|
||
MemorMapped - Indicates wether or not the table is memory mapped and should
|
||
be unmapped once we are done with it
|
||
|
||
Return Value:
|
||
|
||
TRUE - Success
|
||
FALSE - Failure
|
||
|
||
__*/
|
||
{
|
||
BOOLEAN rc = FALSE;
|
||
HANDLE revisionKey = NULL;
|
||
HANDLE tableIdKey = NULL;
|
||
NTSTATUS status;
|
||
PDESCRIPTION_HEADER header = (PDESCRIPTION_HEADER) *Table;
|
||
PUCHAR key = NULL; // ACPI_PARAMETERS_REGISTRY_KEY;
|
||
PUCHAR buffer;
|
||
ULONG action;
|
||
ULONG bytesRead;
|
||
ULONG baseSize;
|
||
ULONG totalSize;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Build a full path name to the thing we want in the registry
|
||
//
|
||
baseSize = strlen( ACPI_PARAMETERS_REGISTRY_KEY);
|
||
totalSize = baseSize + ACPI_MAX_TABLE_STRINGS + 4;
|
||
|
||
buffer = key = ExAllocatePool( PagedPool, totalSize );
|
||
if (key == NULL) {
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
//
|
||
// Generate the path name to the key. This avoids a costly sprintf
|
||
//
|
||
RtlZeroMemory( buffer, totalSize );
|
||
RtlCopyMemory(
|
||
buffer,
|
||
ACPI_PARAMETERS_REGISTRY_KEY,
|
||
baseSize
|
||
);
|
||
buffer += baseSize;
|
||
*buffer++ = '\\';
|
||
|
||
//
|
||
// Table Signature (Up to 4 byte string)
|
||
//
|
||
buffer = ACPIRegLocalCopyString (buffer, (PUCHAR) &header->Signature, ACPI_MAX_SIGNATURE);
|
||
*buffer++ = '\\';
|
||
|
||
//
|
||
// OEM ID field (Up to 6 byte string)
|
||
//
|
||
buffer = ACPIRegLocalCopyString (buffer, (PUCHAR) &header->OEMID, ACPI_MAX_OEM_ID);
|
||
*buffer++ = '\\';
|
||
|
||
//
|
||
// OEM Table ID field (Up to 8 byte string)
|
||
//
|
||
buffer = ACPIRegLocalCopyString (buffer, (PUCHAR) &header->OEMTableID, ACPI_MAX_TABLE_ID);
|
||
*buffer = 0; // Terminate
|
||
|
||
ACPIPrint ((
|
||
ACPI_PRINT_REGISTRY,
|
||
"ReadAMLRegistryEntry: opening key: %s\n",
|
||
key));
|
||
|
||
//
|
||
// Open the <TableId>/OemId>/<OemTableId> key
|
||
//
|
||
status = OSOpenHandle(key, NULL, &tableIdKey);
|
||
if ( !NT_SUCCESS(status) ) {
|
||
|
||
ACPIPrint ((
|
||
ACPI_PRINT_WARNING,
|
||
"ReadAMLRegistryEntry: failed to open AML registry entry (rc=%x)\n",
|
||
status));
|
||
goto ReadAMLRegistryEntryExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Find the largest subkey that is equal or greater than the ROM
|
||
// BIOS version of the table
|
||
//
|
||
status = OSOpenLargestSubkey(
|
||
tableIdKey,
|
||
&revisionKey,
|
||
header->OEMRevision
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
ACPIPrint ((
|
||
ACPI_PRINT_WARNING,
|
||
"ReadAMLRegistryEntry: no valid <OemRevision> key (rc=%#08lx)\n",
|
||
status));
|
||
goto ReadAMLRegistryEntryExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Get the Action value for this table, which tells us what to do with
|
||
// the table
|
||
//
|
||
bytesRead = sizeof(action);
|
||
status = OSReadRegValue(
|
||
"Action",
|
||
revisionKey,
|
||
&action,
|
||
&bytesRead
|
||
);
|
||
if (!NT_SUCCESS(status) || bytesRead != sizeof(action)) {
|
||
|
||
ACPIPrint( (
|
||
ACPI_PRINT_CRITICAL,
|
||
"ReadAMLRegistryEntry: read action value = %#08lx. BytesRead=%d\n",
|
||
status, bytesRead
|
||
) );
|
||
action = ACTION_LOAD_TABLE; // Default action
|
||
|
||
}
|
||
|
||
//
|
||
// Do the action
|
||
//
|
||
switch (action) {
|
||
case ACTION_LOAD_TABLE:
|
||
//
|
||
// Overload entire ROM table
|
||
//
|
||
status = ACPIRegReadEntireAcpiTable(revisionKey, Table, MemoryMapped);
|
||
if (NT_SUCCESS( status ) ) {
|
||
|
||
rc = TRUE;
|
||
|
||
}
|
||
break;
|
||
|
||
case ACTION_LOAD_ROM:
|
||
case ACTION_LOAD_NOTHING:
|
||
//
|
||
// Nothing to do for these cases (return FALSE however);
|
||
//
|
||
break;
|
||
|
||
default:
|
||
//
|
||
// Unsupported actions (return FALSE)
|
||
//
|
||
ACPIPrint( (
|
||
ACPI_PRINT_CRITICAL,
|
||
"ReadAMLRegistryEntry: Unsupported action value (action=%d)\n",
|
||
action
|
||
) );
|
||
break;
|
||
|
||
}
|
||
|
||
//
|
||
// Always close the open keys
|
||
//
|
||
ReadAMLRegistryEntryExit:
|
||
if (key != NULL) {
|
||
|
||
ExFreePool( key );
|
||
|
||
}
|
||
if (tableIdKey != NULL) {
|
||
|
||
OSCloseHandle( tableIdKey );
|
||
|
||
}
|
||
if (revisionKey != NULL) {
|
||
|
||
OSCloseHandle( revisionKey );
|
||
|
||
|
||
}
|
||
return rc;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIRegReadEntireAcpiTable (
|
||
IN HANDLE RevisionKey,
|
||
IN PVOID *Table,
|
||
IN BOOLEAN MemoryMapped
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads the table from the registry into memory
|
||
|
||
Arguments:
|
||
|
||
RevisionKey - Handle to the key containing the table
|
||
Table - Pointer to the pointer to the table
|
||
MemorymMapped - If True, indicates that we need to MmUnmapIo the table
|
||
otherwise, if False, we do no free the table (the
|
||
memory is static)
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PUCHAR buffer;
|
||
PVOID table;
|
||
UCHAR value[9];
|
||
ULONG bytesRead;
|
||
ULONG index = 0;
|
||
ULONG entry;
|
||
PREGISTRY_HEADER entryHeader;
|
||
PDESCRIPTION_HEADER descHeader = (PDESCRIPTION_HEADER) *Table;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// We need an 8k buffer
|
||
//
|
||
buffer = ExAllocatePool( PagedPool, 8 * 1024 );
|
||
if (buffer == NULL) {
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
//
|
||
// Repeat this forever
|
||
//
|
||
for (index = 0; ;index++) {
|
||
|
||
//
|
||
// This is the first data value
|
||
//
|
||
sprintf(value, "%08lx", index );
|
||
|
||
//
|
||
// Read the entry header to get the size of the table. This is stored
|
||
// before the actual table
|
||
//
|
||
bytesRead = 8 * 1024;
|
||
status = OSReadRegValue(
|
||
value,
|
||
RevisionKey,
|
||
buffer,
|
||
&bytesRead
|
||
);
|
||
if (!NT_SUCCESS(status) ) {
|
||
|
||
//
|
||
// Not being able to read the table isn't a failure case
|
||
//
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
} else if (bytesRead < sizeof(REGISTRY_HEADER) ) {
|
||
|
||
//
|
||
// Not being to read the proper number of bytes is
|
||
//
|
||
ACPIPrint( (
|
||
ACPI_PRINT_CRITICAL,
|
||
"ReadEntireAcpiTable: read registry header (bytes=%d)\n",
|
||
bytesRead
|
||
) );
|
||
return STATUS_UNSUCCESSFUL;
|
||
|
||
}
|
||
|
||
//
|
||
// Loop while we still have bytes to process
|
||
//
|
||
for (entry = 0;
|
||
entry < bytesRead;
|
||
entry += (entryHeader->Length + sizeof(REGISTRY_HEADER) )
|
||
) {
|
||
|
||
//
|
||
// Grab a pointer to the entry record
|
||
//
|
||
entryHeader = (PREGISTRY_HEADER) &(buffer[entry]);
|
||
|
||
//
|
||
// Crack the record
|
||
//
|
||
if (entryHeader->Length == 0) {
|
||
|
||
//
|
||
// Special Case
|
||
//
|
||
if (entryHeader->Offset != descHeader->Length) {
|
||
|
||
//
|
||
// Must change the table size
|
||
//
|
||
table = ExAllocatePoolWithTag(
|
||
NonPagedPool,
|
||
entryHeader->Offset,
|
||
ACPI_SHARED_TABLE_POOLTAG
|
||
);
|
||
if (table == NULL) {
|
||
|
||
ExFreePool( buffer );
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
//
|
||
// How much do we have to copy?
|
||
//
|
||
RtlCopyMemory(
|
||
table,
|
||
*Table,
|
||
min( entryHeader->Offset, descHeader->Length )
|
||
);
|
||
|
||
//
|
||
// Free the old table based on wether or not its mm mapped
|
||
//
|
||
if (MemoryMapped) {
|
||
|
||
MmUnmapIoSpace(*Table, descHeader->Length);
|
||
|
||
} else {
|
||
|
||
ExFreePool( *Table );
|
||
|
||
}
|
||
|
||
//
|
||
// Remember the address of the new table
|
||
//
|
||
descHeader = (PDESCRIPTION_HEADER) *Table = table;
|
||
|
||
}
|
||
|
||
//
|
||
// Done with this record
|
||
//
|
||
continue;
|
||
|
||
}
|
||
|
||
//
|
||
// Patch the memory
|
||
//
|
||
ASSERT( entryHeader->Offset < descHeader->Length );
|
||
RtlCopyMemory(
|
||
( (PUCHAR) *Table) + entryHeader->Offset,
|
||
(PUCHAR) entryHeader + sizeof( REGISTRY_HEADER ),
|
||
entryHeader->Length
|
||
);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Normal exit
|
||
//
|
||
if (buffer != NULL) {
|
||
|
||
ExFreePool( buffer );
|
||
}
|
||
return status;
|
||
|
||
}
|
||
|
||
/****************************************************************************
|
||
*
|
||
* DumpAcpiTable
|
||
* Write an ACPI Table to the registry
|
||
*
|
||
* Not exported.
|
||
*
|
||
* ENTRY: pszName - Name of the table to write (4 byte string)
|
||
* Table - Pointer to table data
|
||
* Length - of the table
|
||
* Header - Pointer to the table header
|
||
*
|
||
* EXIT: NONE
|
||
*
|
||
***************************************************************************/
|
||
VOID
|
||
ACPIRegDumpAcpiTable (
|
||
PSZ pszName,
|
||
PVOID Table,
|
||
ULONG Length,
|
||
PDESCRIPTION_HEADER Header
|
||
)
|
||
{
|
||
//NTSTATUS status;
|
||
UCHAR buffer [80] = "\\Registry\\Machine\\Hardware\\ACPI";
|
||
HANDLE hSubKey;
|
||
HANDLE hPrefixKey;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Create /Registry/Machine/Hardware/ACPI subkey
|
||
//
|
||
if ( !NT_SUCCESS(OSCreateHandle (buffer, NULL, &hPrefixKey) ) ) {
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Create table name subkey (DSDT, FACP, FACS, or RSDT) - 4 bytes
|
||
//
|
||
if ( !NT_SUCCESS(OSCreateHandle (pszName, hPrefixKey, &hSubKey) ) ) {
|
||
goto DumpAcpiTableExit;
|
||
}
|
||
|
||
//
|
||
// For tables with headers, add subkeys for
|
||
// <OemId>/<OemTableID>/<OemRevision>
|
||
//
|
||
if (Header) {
|
||
|
||
OSCloseHandle(hPrefixKey);
|
||
hPrefixKey = hSubKey;
|
||
|
||
//
|
||
// OEM ID field (6 byte string)
|
||
//
|
||
ACPIRegLocalCopyString (buffer, Header->OEMID, ACPI_MAX_OEM_ID);
|
||
if ( !NT_SUCCESS(OSCreateHandle (buffer, hPrefixKey, &hSubKey) ) ) {
|
||
goto DumpAcpiTableExit;
|
||
}
|
||
|
||
OSCloseHandle (hPrefixKey);
|
||
hPrefixKey = hSubKey;
|
||
|
||
//
|
||
// OEM Table ID field (8 byte string)
|
||
//
|
||
ACPIRegLocalCopyString (buffer, Header->OEMTableID, ACPI_MAX_TABLE_ID);
|
||
if ( !NT_SUCCESS(OSCreateHandle (buffer, hPrefixKey, &hSubKey) ) ) {
|
||
goto DumpAcpiTableExit;
|
||
}
|
||
|
||
OSCloseHandle (hPrefixKey);
|
||
hPrefixKey = hSubKey;
|
||
|
||
//
|
||
// OEM Revision field (4 byte number)
|
||
//
|
||
sprintf (buffer, "%.8x", Header->OEMRevision);
|
||
if ( !NT_SUCCESS(OSCreateHandle (buffer, hPrefixKey, &hSubKey) ) ) {
|
||
goto DumpAcpiTableExit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Finally, write the entire table
|
||
//
|
||
OSWriteRegValue ("00000000", hSubKey, Table, Length);
|
||
|
||
//
|
||
// Delete open handles
|
||
//
|
||
OSCloseHandle (hSubKey);
|
||
DumpAcpiTableExit:
|
||
OSCloseHandle (hPrefixKey);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
/****************************************************************************
|
||
*
|
||
* DumpAcpiTables
|
||
* Write the ACPI Tables to the registry. Should be called only
|
||
* after table pointers have been initialized.
|
||
*
|
||
* Not exported.
|
||
*
|
||
* ENTRY: NONE
|
||
* EXIT: NONE.
|
||
*
|
||
***************************************************************************/
|
||
VOID
|
||
ACPIRegDumpAcpiTables (VOID)
|
||
{
|
||
PDSDT dsdt = AcpiInformation->DiffSystemDescTable;
|
||
PFACS facs = AcpiInformation->FirmwareACPIControlStructure;
|
||
PFADT fadt = AcpiInformation->FixedACPIDescTable;
|
||
PRSDT rsdt = AcpiInformation->RootSystemDescTable;
|
||
|
||
|
||
if (DoAcpiTableDump) {
|
||
|
||
ACPIPrint ((
|
||
ACPI_PRINT_REGISTRY,
|
||
"DumpAcpiTables: Writing DSDT/FACS/FADT/RSDT to registry\n"));
|
||
|
||
if (dsdt) {
|
||
|
||
ACPIRegDumpAcpiTable(
|
||
"DSDT",
|
||
dsdt,
|
||
dsdt->Header.Length,
|
||
&(dsdt->Header)
|
||
);
|
||
|
||
}
|
||
|
||
if (facs) {
|
||
|
||
ACPIRegDumpAcpiTable(
|
||
"FACS",
|
||
facs,
|
||
facs->Length,
|
||
NULL
|
||
);
|
||
|
||
}
|
||
|
||
if (fadt) {
|
||
|
||
ACPIRegDumpAcpiTable(
|
||
"FADT",
|
||
fadt,
|
||
fadt->Header.Length,
|
||
&(fadt->Header)
|
||
);
|
||
|
||
}
|
||
|
||
if (rsdt) {
|
||
|
||
ACPIRegDumpAcpiTable(
|
||
"RSDT",
|
||
rsdt,
|
||
rsdt->Header.Length,
|
||
&(rsdt->Header)
|
||
);
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
|