/** @file Boot service DXE ASL update library implementation. These functions in this file can be called during DXE and cannot be called during runtime or in SMM which should use a RT or SMM library. This library uses the ACPI Support protocol. Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include // // Function implementations // static EFI_ACPI_SDT_PROTOCOL *mAcpiSdt = NULL; static EFI_ACPI_TABLE_PROTOCOL *mAcpiTable = NULL; /** Initialize the ASL update library state. This must be called at the beginning of the function calls in this library. @retval EFI_SUCCESS - The function completed successfully. **/ EFI_STATUS InitializeAslUpdateLib ( VOID ) { EFI_STATUS Status; /// /// Locate ACPI tables /// Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **) &mAcpiSdt); ASSERT_EFI_ERROR (Status); Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &mAcpiTable); ASSERT_EFI_ERROR (Status); return Status; } /** This function uses the ACPI SDT protocol to locate an ACPI SSDT table. @param[in] TableId - Pointer to an ASCII string containing the OEM Table ID from the ACPI table header @param[in] TableIdSize - Length of the TableId to match. Table ID are 8 bytes long, this function will consider it a match if the first TableIdSize bytes match @param[in, out] Table - Updated with a pointer to the table @param[in, out] Handle - AcpiSupport protocol table handle for the table found @retval EFI_SUCCESS - The function completed successfully. @retval EFI_NOT_FOUND - Failed to locate AcpiTable. @retval EFI_NOT_READY - Not ready to locate AcpiTable. **/ EFI_STATUS LocateAcpiTableByOemTableId ( IN UINT8 *TableId, IN UINT8 TableIdSize, IN OUT EFI_ACPI_DESCRIPTION_HEADER **Table, IN OUT UINTN *Handle ) { EFI_STATUS Status; INTN Index; EFI_ACPI_TABLE_VERSION Version; EFI_ACPI_DESCRIPTION_HEADER *OrgTable; if (mAcpiSdt == NULL) { InitializeAslUpdateLib (); if (mAcpiSdt == NULL) { return EFI_NOT_READY; } } /// /// Locate table with matching ID /// Version = 0; Index = 0; do { Status = mAcpiSdt->GetAcpiTable (Index, (EFI_ACPI_SDT_HEADER **)&OrgTable, &Version, Handle); if (Status == EFI_NOT_FOUND) { break; } ASSERT_EFI_ERROR (Status); Index++; } while (CompareMem (&(OrgTable->OemTableId), TableId, TableIdSize)); if (Status != EFI_NOT_FOUND) { *Table = AllocateCopyPool (OrgTable->Length, OrgTable); ASSERT (*Table); } /// /// If we found the table, there will be no error. /// return Status; } /** This procedure will update immediate value assigned to a Name. @param[in] AslSignature - The signature of Operation Region that we want to update. @param[in] Buffer - source of data to be written over original aml @param[in] Length - length of data to be overwritten @retval EFI_SUCCESS - The function completed successfully. @retval EFI_NOT_FOUND - Failed to locate AcpiTable. @retval EFI_NOT_READY - Not ready to locate AcpiTable. **/ EFI_STATUS EFIAPI UpdateNameAslCode ( IN UINT32 AslSignature, IN VOID *Buffer, IN UINTN Length ) { EFI_STATUS Status; EFI_ACPI_DESCRIPTION_HEADER *Table; UINT8 *CurrPtr; UINT32 *Signature; UINT8 *DsdtPointer; UINT8 *EndPointer; UINTN Handle; UINT8 DataSize; if (mAcpiTable == NULL) { InitializeAslUpdateLib (); if (mAcpiTable == NULL) { return EFI_NOT_READY; } } /// /// Locate table with matching ID /// Handle = 0; Status = LocateAcpiTableBySignature ( EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, (EFI_ACPI_DESCRIPTION_HEADER **) &Table, &Handle ); if (EFI_ERROR (Status)) { return Status; } /// /// Point to the beginning of the DSDT table /// CurrPtr = (UINT8 *) Table; if (CurrPtr == NULL) { return EFI_NOT_FOUND; } /// /// Loop through the ASL looking for values that we must fix up. /// EndPointer = CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length; for (DsdtPointer = CurrPtr; DsdtPointer < EndPointer; DsdtPointer++) { /// /// Get a pointer to compare for signature /// Signature = (UINT32 *) DsdtPointer; /// /// Check if this is the Device Object signature we are looking for /// if ((*Signature) == AslSignature) { /// /// Look for Name Encoding /// if (*(DsdtPointer-1) == AML_NAME_OP) { /// /// Check if size of new and old data is the same /// DataSize = *(DsdtPointer+4); if ((Length == 1 && DataSize == 0xA) || (Length == 2 && DataSize == 0xB) || (Length == 4 && DataSize == 0xC)) { CopyMem (DsdtPointer+5, Buffer, Length); } else if (Length == 1 && ((*(UINT8*) Buffer) == 0 || (*(UINT8*) Buffer) == 1) && (DataSize == 0 || DataSize == 1)) { CopyMem (DsdtPointer+4, Buffer, Length); } else { FreePool (Table); return EFI_BAD_BUFFER_SIZE; } Status = mAcpiTable->UninstallAcpiTable ( mAcpiTable, Handle ); Handle = 0; Status = mAcpiTable->InstallAcpiTable ( mAcpiTable, Table, Table->Length, &Handle ); FreePool (Table); return Status; } } } return EFI_NOT_FOUND; } /** This procedure will update immediate value assigned to a Name in SSDT table. @param[in] TableId - Pointer to an ASCII string containing the OEM Table ID from the ACPI table header @param[in] TableIdSize - Length of the TableId to match. Table ID are 8 bytes long, this function @param[in] AslSignature - The signature of Operation Region that we want to update. @param[in] Buffer - source of data to be written over original aml @param[in] Length - length of data to be overwritten @retval EFI_UNSUPPORTED The function is not supported in this library. **/ EFI_STATUS EFIAPI UpdateSsdtNameAslCode ( IN UINT8 *TableId, IN UINT8 TableIdSize, IN UINT32 AslSignature, IN VOID *Buffer, IN UINTN Length ) { return EFI_UNSUPPORTED; } /** This procedure will update the name of ASL Method. @param[in] AslSignature - The signature of Operation Region that we want to update. @param[in] Buffer - source of data to be written over original aml @param[in] Length - length of data to be overwritten @retval EFI_UNSUPPORTED The function is not supported in this library. **/ EFI_STATUS EFIAPI UpdateMethodAslCode ( IN UINT32 AslSignature, IN VOID *Buffer, IN UINTN Length ) { return EFI_UNSUPPORTED; } /** This function uses the ACPI SDT protocol to locate an ACPI table. It is really only useful for finding tables that only have a single instance, e.g. FADT, FACS, MADT, etc. It is not good for locating SSDT, etc. Matches are determined by finding the table with ACPI table that has a matching signature. @param[in] Signature - Pointer to an ASCII string containing the OEM Table ID from the ACPI table header @param[in, out] Table - Updated with a pointer to the table @param[in, out] Handle - AcpiSupport protocol table handle for the table found @retval EFI_SUCCESS - The function completed successfully. @retval EFI_NOT_FOUND - Failed to locate AcpiTable. @retval EFI_NOT_READY - Not ready to locate AcpiTable. **/ EFI_STATUS EFIAPI LocateAcpiTableBySignature ( IN UINT32 Signature, IN OUT EFI_ACPI_DESCRIPTION_HEADER **Table, IN OUT UINTN *Handle ) { EFI_STATUS Status; INTN Index; EFI_ACPI_TABLE_VERSION Version; EFI_ACPI_DESCRIPTION_HEADER *OrgTable; if (mAcpiSdt == NULL) { InitializeAslUpdateLib (); if (mAcpiSdt == NULL) { return EFI_NOT_READY; } } /// /// Locate table with matching ID /// Version = 0; Index = 0; do { Status = mAcpiSdt->GetAcpiTable (Index, (EFI_ACPI_SDT_HEADER **)&OrgTable, &Version, Handle); if (Status == EFI_NOT_FOUND) { break; } ASSERT_EFI_ERROR (Status); Index++; } while (OrgTable->Signature != Signature); if (Status != EFI_NOT_FOUND) { *Table = AllocateCopyPool (OrgTable->Length, OrgTable); ASSERT (*Table); } /// /// If we found the table, there will be no error. /// return Status; }