| /** @file | |
| Dxe ResetSystem library implementation. | |
| Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <Base.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/DxeServicesTableLib.h> | |
| #include <Library/UefiBootServicesTableLib.h> | |
| #include <Library/UefiLib.h> | |
| #include <Library/UefiRuntimeLib.h> // EfiConvertPointer() | |
| #include "ResetSystemAcpiGed.h" | |
| /** | |
| Modifies the attributes to Runtime type for a page size memory region. | |
| @param BaseAddress Specified start address | |
| @retval EFI_SUCCESS The attributes were set for the memory region. | |
| @retval EFI_INVALID_PARAMETER Length is zero. | |
| @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory | |
| resource range specified by BaseAddress and Length. | |
| @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource | |
| range specified by BaseAddress and Length. | |
| @retval EFI_ACCESS_DEFINED The attributes for the memory resource range specified by | |
| BaseAddress and Length cannot be modified. | |
| @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of | |
| the memory resource range. | |
| @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol is | |
| not available yet. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| SetMemoryAttributesRunTime ( | |
| UINTN Address | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; | |
| Address &= ~EFI_PAGE_MASK; | |
| Status = gDS->GetMemorySpaceDescriptor (Address, &Descriptor); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_INFO, "%a: GetMemorySpaceDescriptor failed\n", __func__)); | |
| return Status; | |
| } | |
| if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeNonExistent) { | |
| Status = gDS->AddMemorySpace ( | |
| EfiGcdMemoryTypeMemoryMappedIo, | |
| Address, | |
| EFI_PAGE_SIZE, | |
| EFI_MEMORY_UC | EFI_MEMORY_RUNTIME | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_INFO, "%a: AddMemorySpace failed\n", __func__)); | |
| return Status; | |
| } | |
| Status = gDS->SetMemorySpaceAttributes ( | |
| Address, | |
| EFI_PAGE_SIZE, | |
| EFI_MEMORY_RUNTIME | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_INFO, "%a:%d SetMemorySpaceAttributes failed\n", __func__, __LINE__)); | |
| return Status; | |
| } | |
| } else if (!(Descriptor.Attributes & EFI_MEMORY_RUNTIME)) { | |
| Status = gDS->SetMemorySpaceAttributes ( | |
| Address, | |
| EFI_PAGE_SIZE, | |
| Descriptor.Attributes | EFI_MEMORY_RUNTIME | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_INFO, "%a:%d SetMemorySpaceAttributes failed\n", __func__, __LINE__)); | |
| return Status; | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Find the power manager related info from ACPI table | |
| @retval RETURN_SUCCESS Successfully find out all the required information. | |
| @retval RETURN_NOT_FOUND Failed to find the required info. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| GetPowerManagerByParseAcpiInfo ( | |
| VOID | |
| ) | |
| { | |
| EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt = NULL; | |
| EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp = NULL; | |
| EFI_ACPI_DESCRIPTION_HEADER *Xsdt = NULL; | |
| EFI_ACPI_DESCRIPTION_HEADER *Rsdt = NULL; | |
| UINT32 *Entry32 = NULL; | |
| UINTN Entry32Num; | |
| UINT32 *Signature = NULL; | |
| UINTN Idx; | |
| EFI_STATUS Status; | |
| Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, (VOID **)&Rsdp); | |
| if (EFI_ERROR (Status)) { | |
| Status = EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid, (VOID **)&Rsdp); | |
| } | |
| if (EFI_ERROR (Status) || (Rsdp == NULL)) { | |
| DEBUG ((DEBUG_ERROR, "EFI_ERROR or Rsdp == NULL\n")); | |
| return RETURN_NOT_FOUND; | |
| } | |
| Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->RsdtAddress; | |
| Entry32 = (UINT32 *)(UINTN)(Rsdt + 1); | |
| Entry32Num = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) >> 2; | |
| for (Idx = 0; Idx < Entry32Num; Idx++) { | |
| Signature = (UINT32 *)(UINTN)Entry32[Idx]; | |
| if (*Signature == EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) { | |
| Fadt = (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *)Signature; | |
| DEBUG ((DEBUG_INFO, "Found Fadt in Rsdt\n")); | |
| goto Done; | |
| } | |
| } | |
| Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)Rsdp->XsdtAddress; | |
| Entry32 = (UINT32 *)(Xsdt + 1); | |
| Entry32Num = (Xsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) >> 2; | |
| for (Idx = 0; Idx < Entry32Num; Idx++) { | |
| Signature = (UINT32 *)(UINTN)Entry32[Idx]; | |
| if (*Signature == EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) { | |
| Fadt = (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *)Signature; | |
| DEBUG ((DEBUG_INFO, "Found Fadt in Xsdt\n")); | |
| goto Done; | |
| } | |
| } | |
| DEBUG ((DEBUG_ERROR, " Fadt Not Found\n")); | |
| return RETURN_NOT_FOUND; | |
| Done: | |
| mPowerManager.ResetRegAddr = Fadt->ResetReg.Address; | |
| mPowerManager.ResetValue = Fadt->ResetValue; | |
| mPowerManager.SleepControlRegAddr = Fadt->SleepControlReg.Address; | |
| mPowerManager.SleepStatusRegAddr = Fadt->SleepStatusReg.Address; | |
| return RETURN_SUCCESS; | |
| } | |
| /** | |
| This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE | |
| event. It converts a pointer to a new virtual address. | |
| @param[in] Event Event whose notification function is being invoked. | |
| @param[in] Context Pointer to the notification function's context | |
| **/ | |
| STATIC | |
| VOID | |
| ResetSystemLibAddressChangeEvent ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| EfiConvertPointer (0, (VOID **)&mPowerManager.SleepControlRegAddr); | |
| EfiConvertPointer (0, (VOID **)&mPowerManager.SleepStatusRegAddr); | |
| EfiConvertPointer (0, (VOID **)&mPowerManager.ResetRegAddr); | |
| } | |
| /** | |
| Notification function of ACPI Table change. | |
| This is a notification function registered on ACPI Table change event. | |
| It saves the Century address stored in ACPI FADT table. | |
| @param Event Event whose notification function is being invoked. | |
| @param Context Pointer to the notification function's context. | |
| **/ | |
| STATIC | |
| VOID | |
| AcpiNotificationEvent ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = GetPowerManagerByParseAcpiInfo (); | |
| if (EFI_ERROR (Status)) { | |
| return; | |
| } | |
| DEBUG ((DEBUG_INFO, "%a: sleepControl %llx\n", __func__, mPowerManager.SleepControlRegAddr)); | |
| ASSERT (mPowerManager.SleepControlRegAddr); | |
| Status = SetMemoryAttributesRunTime (mPowerManager.SleepControlRegAddr); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_INFO, "%a:%d\n", __func__, __LINE__)); | |
| return; | |
| } | |
| DEBUG ((DEBUG_INFO, "%a: sleepStatus %llx\n", __func__, mPowerManager.SleepStatusRegAddr)); | |
| ASSERT (mPowerManager.SleepStatusRegAddr); | |
| Status = SetMemoryAttributesRunTime (mPowerManager.SleepStatusRegAddr); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_INFO, "%a:%d\n", __func__, __LINE__)); | |
| return; | |
| } | |
| DEBUG ((DEBUG_INFO, "%a: ResetReg %llx\n", __func__, mPowerManager.ResetRegAddr)); | |
| ASSERT (mPowerManager.ResetRegAddr); | |
| Status = SetMemoryAttributesRunTime (mPowerManager.ResetRegAddr); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_INFO, "%a:%d\n", __func__, __LINE__)); | |
| } | |
| return; | |
| } | |
| /** | |
| The constructor function to Register ACPI Table change event and Address Change Event. | |
| @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ResetSystemLibConstructor ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_EVENT Event; | |
| EFI_EVENT ResetSystemVirtualNotifyEvent; | |
| Status = gBS->CreateEventEx ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_CALLBACK, | |
| AcpiNotificationEvent, | |
| NULL, | |
| &gEfiAcpiTableGuid, | |
| &Event | |
| ); | |
| // | |
| // Register SetVirtualAddressMap () notify function | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, | |
| TPL_NOTIFY, | |
| ResetSystemLibAddressChangeEvent, | |
| NULL, | |
| &ResetSystemVirtualNotifyEvent | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } |