windows-nt/Source/XPSP1/NT/base/busdrv/acpi/driver/shared/reg.c
2020-09-26 16:20:57 +08:00

656 lines
15 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:
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)
);
}
}
}