/*++ Copyright (c) 1991 - 2001 Microsoft Corporation Module Name: ### #### ##### #### #### ##### ##### ### ## # ## ## ## ## # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ####### ## ##### ## ## ##### ##### ## ## ## # ## ## ## ## # ## ## ## ## #### ## #### ## #### ## ## Abstract: ACPI functions for querying the fixed ACPI tables. Author: Wesley Witt (wesw) 22-April-2002 Environment: Kernel mode only. Notes: This code was taken from the HAL. --*/ #include "internal.h" #include #define rgzMultiFunctionAdapter L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter" #define rgzAcpiConfigurationData L"Configuration Data" #define rgzAcpiIdentifier L"Identifier" #define rgzBIOSIdentifier L"ACPI BIOS" NTSTATUS WdAcpiGetRegistryValue( IN HANDLE KeyHandle, IN PWSTR ValueName, OUT PKEY_VALUE_PARTIAL_INFORMATION *Information ) /*++ Routine Description: This routine is invoked to retrieve the data for a registry key's value. This is done by querying the value of the key with a zero-length buffer to determine the size of the value, and then allocating a buffer and actually querying the value into the buffer. It is the responsibility of the caller to free the buffer. Arguments: KeyHandle - Supplies the key handle whose value is to be queried ValueName - Supplies the null-terminated Unicode name of the value. Information - Returns a pointer to the allocated data buffer. Return Value: The function value is the final status of the query operation. --*/ { UNICODE_STRING unicodeString; NTSTATUS status; PKEY_VALUE_PARTIAL_INFORMATION infoBuffer; ULONG keyValueLength; RtlInitUnicodeString( &unicodeString, ValueName ); // // Figure out how big the data value is so that a buffer of the // appropriate size can be allocated. // status = ZwQueryValueKey( KeyHandle, &unicodeString, KeyValuePartialInformation, (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 = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePoolWithTag(NonPagedPool, keyValueLength, 'IPCA'); if (!infoBuffer) { return STATUS_INSUFFICIENT_RESOURCES; } // // Query the data for the key value. // status = ZwQueryValueKey( KeyHandle, &unicodeString, KeyValuePartialInformation, infoBuffer, keyValueLength, &keyValueLength ); if (!NT_SUCCESS( status )) { ExFreePool( infoBuffer ); return status; } // // Everything worked, so simply return the address of the allocated // buffer to the caller, who is now responsible for freeing it. // *Information = infoBuffer; return STATUS_SUCCESS; } NTSTATUS WdAcpiFindRsdt ( OUT PACPI_BIOS_MULTI_NODE *AcpiMulti ) /*++ Routine Description: This function looks into the registry to find the ACPI RSDT, which was stored there by ntdetect.com. Arguments: RsdtPtr - Pointer to a buffer that contains the ACPI Root System Description Pointer Structure. The caller is responsible for freeing this buffer. Note: This is returned in non-paged pool. Return Value: A NTSTATUS code to indicate the result of the initialization. --*/ { UNICODE_STRING unicodeString, unicodeValueName, biosId; OBJECT_ATTRIBUTES objectAttributes; HANDLE hMFunc, hBus; WCHAR wbuffer[10]; ULONG i, length; PWSTR p; PKEY_VALUE_PARTIAL_INFORMATION valueInfo; NTSTATUS status; BOOLEAN same; PCM_PARTIAL_RESOURCE_LIST prl; PCM_PARTIAL_RESOURCE_DESCRIPTOR prd; PACPI_BIOS_MULTI_NODE multiNode; ULONG multiNodeSize; // // Look in the registry for the "ACPI BIOS bus" data // RtlInitUnicodeString (&unicodeString, rgzMultiFunctionAdapter); InitializeObjectAttributes (&objectAttributes, &unicodeString, OBJ_CASE_INSENSITIVE, NULL, // handle NULL); status = ZwOpenKey (&hMFunc, KEY_READ, &objectAttributes); if (!NT_SUCCESS(status)) { return status; } unicodeString.Buffer = wbuffer; unicodeString.MaximumLength = sizeof(wbuffer); RtlInitUnicodeString(&biosId, rgzBIOSIdentifier); for (i = 0; TRUE; i++) { RtlIntegerToUnicodeString (i, 10, &unicodeString); InitializeObjectAttributes ( &objectAttributes, &unicodeString, OBJ_CASE_INSENSITIVE, hMFunc, NULL); status = ZwOpenKey (&hBus, KEY_READ, &objectAttributes); if (!NT_SUCCESS(status)) { // // Out of Multifunction adapter entries... // ZwClose (hMFunc); return STATUS_UNSUCCESSFUL; } // // Check the Indentifier to see if this is an ACPI BIOS entry // status = WdAcpiGetRegistryValue (hBus, rgzAcpiIdentifier, &valueInfo); if (!NT_SUCCESS (status)) { ZwClose (hBus); continue; } p = (PWSTR) ((PUCHAR) valueInfo->Data); unicodeValueName.Buffer = p; unicodeValueName.MaximumLength = (USHORT)valueInfo->DataLength; length = valueInfo->DataLength; // // Determine the real length of the ID string // while (length) { if (p[length / sizeof(WCHAR) - 1] == UNICODE_NULL) { length -= 2; } else { break; } } unicodeValueName.Length = (USHORT)length; same = RtlEqualUnicodeString(&biosId, &unicodeValueName, TRUE); ExFreePool(valueInfo); if (!same) { ZwClose (hBus); continue; } status = WdAcpiGetRegistryValue(hBus, rgzAcpiConfigurationData, &valueInfo); ZwClose (hBus); if (!NT_SUCCESS(status)) { continue ; } prl = (PCM_PARTIAL_RESOURCE_LIST)(valueInfo->Data); prd = &prl->PartialDescriptors[0]; multiNode = (PACPI_BIOS_MULTI_NODE)((PCHAR) prd + sizeof(CM_PARTIAL_RESOURCE_LIST)); break; } multiNodeSize = sizeof(ACPI_BIOS_MULTI_NODE) + ((ULONG)(multiNode->Count - 1) * sizeof(ACPI_E820_ENTRY)); *AcpiMulti = (PACPI_BIOS_MULTI_NODE) ExAllocatePoolWithTag(NonPagedPool, multiNodeSize, 'IPCA'); if (*AcpiMulti == NULL) { ExFreePool(valueInfo); return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory(*AcpiMulti, multiNode, multiNodeSize); ExFreePool(valueInfo); return STATUS_SUCCESS; } PVOID WdGetAcpiTable( IN ULONG Signature ) /*++ Routine Description: This routine will retrieve any table referenced in the ACPI RSDT. Arguments: Signature - Target table signature Return Value: pointer to a copy of the table, or NULL if not found --*/ { PACPI_BIOS_MULTI_NODE multiNode; NTSTATUS status; ULONG entry, rsdtEntries; PDESCRIPTION_HEADER header; PHYSICAL_ADDRESS physicalAddr; PRSDT rsdt; ULONG rsdtSize; PVOID table = NULL; // // Get the physical address of the RSDT from the Registry // status = WdAcpiFindRsdt(&multiNode); if (!NT_SUCCESS(status)) { return NULL; } // // Map down header to get total RSDT table size // header = (PDESCRIPTION_HEADER) MmMapIoSpace(multiNode->RsdtAddress, sizeof(DESCRIPTION_HEADER), MmNonCached); if (!header) { return NULL; } rsdtSize = header->Length; MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER)); // // Map down entire RSDT table // rsdt = (PRSDT) MmMapIoSpace(multiNode->RsdtAddress, rsdtSize, MmNonCached); ExFreePool(multiNode); if (!rsdt) { return NULL; } // // Do a sanity check on the RSDT. // if ((rsdt->Header.Signature != RSDT_SIGNATURE) && (rsdt->Header.Signature != XSDT_SIGNATURE)) { goto GetAcpiTableEnd; } // // Calculate the number of entries in the RSDT. // rsdtEntries = rsdt->Header.Signature == XSDT_SIGNATURE ? NumTableEntriesFromXSDTPointer(rsdt) : NumTableEntriesFromRSDTPointer(rsdt); // // Look down the pointer in each entry to see if it points to // the table we are looking for. // for (entry = 0; entry < rsdtEntries; entry++) { if (rsdt->Header.Signature == XSDT_SIGNATURE) { physicalAddr = ((PXSDT)rsdt)->Tables[entry]; } else { physicalAddr.HighPart = 0; physicalAddr.LowPart = (ULONG)rsdt->Tables[entry]; } // // Map down the header, check the signature // header = (PDESCRIPTION_HEADER) MmMapIoSpace(physicalAddr, sizeof(DESCRIPTION_HEADER), MmNonCached); if (!header) { goto GetAcpiTableEnd; } if (header->Signature == Signature) { table = ExAllocatePoolWithTag(PagedPool, header->Length, 'IPCA'); if (table) { RtlCopyMemory(table, header, header->Length); } MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER)); break; } MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER)); } GetAcpiTableEnd: MmUnmapIoSpace(rsdt, rsdtSize); return table; }