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