OvmfPkg/LoongArchVirt: Add reset system library

This library provides interface related to restart and shudown the
LoongArch64 virtual machine.

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Dongyan Qian <qiandongyan@loongson.cn>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Xianglai Li <lixianglai@loongson.cn>
Co-authored-by: Bibo Mao <maobibo@loongson.cn>
This commit is contained in:
Chao Li 2024-06-14 17:08:46 +08:00 committed by mergify[bot]
parent 79835e08f5
commit c63d90085b
6 changed files with 637 additions and 0 deletions

View File

@ -0,0 +1,151 @@
/** @file
Base ResetSystem library implementation.
Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/QemuFwCfgLib.h>
#include "ResetSystemAcpiGed.h"
/**
Get configuration item data by the firmware configuration file name.
@param[in] Name - Name of file to look up.
@return VOID* The Pointer of Value of Firmware Configuration item read.
**/
STATIC
VOID *
GetFwCfgData (
CONST CHAR8 *Name
)
{
FIRMWARE_CONFIG_ITEM FwCfgItem;
EFI_STATUS Status;
UINTN FwCfgSize;
VOID *Data;
Status = QemuFwCfgFindFile (Name, &FwCfgItem, &FwCfgSize);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a %d read %s error Status %d \n", __func__, __LINE__, Name, Status));
return NULL;
}
Data = AllocatePool (FwCfgSize);
if (Data == NULL) {
return NULL;
}
QemuFwCfgSelectItem (FwCfgItem);
QemuFwCfgReadBytes (FwCfgSize, Data);
return Data;
}
/**
Find the power manager related info from ACPI table
@retval EFI_SUCCESS Successfully find out all the required information.
@retval EFI_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;
VOID *AcpiTables = NULL;
UINT32 *Entry32 = NULL;
UINTN Entry32Num;
UINT32 *Signature = NULL;
UINTN Idx;
Rsdp = GetFwCfgData ("etc/acpi/rsdp");
if (Rsdp == NULL) {
DEBUG ((DEBUG_ERROR, "%a %d read etc/acpi/rsdp error \n", __func__, __LINE__));
return EFI_NOT_FOUND;
}
AcpiTables = GetFwCfgData ("etc/acpi/tables");
if (AcpiTables == NULL) {
DEBUG ((DEBUG_ERROR, "%a %d read etc/acpi/tables error \n", __func__, __LINE__));
FreePool (Rsdp);
return EFI_NOT_FOUND;
}
Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)AcpiTables + Rsdp->RsdtAddress);
Entry32 = (UINT32 *)(Rsdt + 1);
Entry32Num = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) >> 2;
for (Idx = 0; Idx < Entry32Num; Idx++) {
Signature = (UINT32 *)((UINTN)Entry32[Idx] + (UINTN)AcpiTables);
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 *)((UINTN)AcpiTables + 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] + (UINTN)AcpiTables);
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;
}
}
FreePool (Rsdp);
FreePool (AcpiTables);
DEBUG ((DEBUG_ERROR, " Fadt Not Found\n"));
return EFI_NOT_FOUND;
Done:
mPowerManager.ResetRegAddr = Fadt->ResetReg.Address;
mPowerManager.ResetValue = Fadt->ResetValue;
mPowerManager.SleepControlRegAddr = Fadt->SleepControlReg.Address;
mPowerManager.SleepStatusRegAddr = Fadt->SleepStatusReg.Address;
FreePool (Rsdp);
FreePool (AcpiTables);
return EFI_SUCCESS;
}
/**
The constructor function to initialize mPowerManager.
@retval EFI_SUCCESS Initialize mPowerManager success.
@retval EFI_NOT_FOUND Failed to initialize mPowerManager.
**/
EFI_STATUS
EFI_API
ResetSystemLibConstructor (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
Status = GetPowerManagerByParseAcpiInfo ();
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "%a:%d\n", __func__, __LINE__));
}
ASSERT (mPowerManager.SleepControlRegAddr);
ASSERT (mPowerManager.SleepStatusRegAddr);
ASSERT (mPowerManager.ResetRegAddr);
return Status;
}

View File

@ -0,0 +1,35 @@
## @file
# Base library instance for ResetSystem library class for LoongArch
#
# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
[Defines]
INF_VERSION = 1.29
BASE_NAME = ResetSystemLib
FILE_GUID = BA521997-9016-32B5-65DF-EA5F560A3837
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = ResetSystemLib|SEC PEI_CORE PEIM DXE_CORE
CONSTRUCTOR = ResetSystemLibConstructor
#
# VALID_ARCHITECTURES = LOONGARCH64
#
[Sources]
BaseResetSystemAcpiGed.c
ResetSystemAcpiGed.c
[Packages]
MdeModulePkg/MdeModulePkg.dec
MdePkg/MdePkg.dec
OvmfPkg/OvmfPkg.dec
[LibraryClasses]
DebugLib
MemoryAllocationLib
QemuFwCfgLib

View File

@ -0,0 +1,262 @@
/** @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;
}

View File

@ -0,0 +1,41 @@
## @file
# DXE library instance for ResetSystem library class for LoongArch.
#
# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
[Defines]
INF_VERSION = 1.29
BASE_NAME = ResetSystemLib
FILE_GUID = F05197D5-5827-AA61-FB2D-BC69259F17A9
MODULE_TYPE = DXE_RUNTIME_DRIVER
VERSION_STRING = 1.0
LIBRARY_CLASS = ResetSystemLib|DXE_DRIVER DXE_RUNTIME_DRIVER SMM_CORE DXE_SMM_DRIVER UEFI_DRIVER UEFI_APPLICATION
CONSTRUCTOR = ResetSystemLibConstructor
#
# VALID_ARCHITECTURES = LOONGARCH64
#
[Sources]
DxeResetSystemAcpiGed.c
ResetSystemAcpiGed.c
[Packages]
MdeModulePkg/MdeModulePkg.dec
MdePkg/MdePkg.dec
OvmfPkg/OvmfPkg.dec
[LibraryClasses]
DebugLib
DxeServicesTableLib
UefiBootServicesTableLib
UefiLib
UefiRuntimeLib
[Guids]
gEfiAcpi10TableGuid ## PRODUCES ## SystemTable
gEfiAcpiTableGuid ## PRODUCES ## SystemTable

View File

@ -0,0 +1,125 @@
/** @file
ResetSystem library implementation.
Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Library/BaseLib.h> // CpuDeadLoop()
#include <Library/DebugLib.h>
#include <Library/IoLib.h>
#include <Library/ResetSystemLib.h> // ResetCold()
#include "ResetSystemAcpiGed.h"
POWER_MANAGER mPowerManager;
/**
Calling this function causes a system-wide reset. This sets
all circuitry within the system to its initial state. This type of reset
is asynchronous to system operation and operates without regard to
cycle boundaries.
System reset should not return, if it returns, it means the system does
not support cold reset.
**/
STATIC VOID
AcpiGedReset (
VOID
)
{
MmioWrite8 (
(UINTN)mPowerManager.ResetRegAddr,
mPowerManager.ResetValue
);
CpuDeadLoop ();
}
/**
This function causes the system to enter a power state equivalent
to the ACPI S5 states.
* */
STATIC VOID
AcpiGedShutdown (
VOID
)
{
MmioWrite8 (
(UINTN)mPowerManager.SleepControlRegAddr,
(1 << 5) /* enable bit */ |
(5 << 2) /* typ == S5 */
);
CpuDeadLoop ();
}
/**
This function causes a system-wide reset (cold reset), in which
all circuitry within the system returns to its initial state. This type of
reset is asynchronous to system operation and operates without regard to
cycle boundaries.
If this function returns, it means that the system does not support cold
reset.
**/
VOID EFIAPI
ResetCold (
VOID
)
{
AcpiGedReset ();
}
/**
This function causes a system-wide initialization (warm reset), in which all
processors are set to their initial state. Pending cycles are not corrupted.
If this function returns, it means that the system does not support warm
reset.
**/
VOID EFIAPI
ResetWarm (
VOID
)
{
AcpiGedReset ();
}
/**
This function causes a systemwide reset. The exact type of the reset is
defined by the EFI_GUID that follows the Null-terminated Unicode string passed
into ResetData. If the platform does not recognize the EFI_GUID in ResetData
the platform must pick a supported reset type to perform.The platform may
optionally log the parameters from any non-normal reset that occurs.
@param[in] DataSize The size, in bytes, of ResetData.
@param[in] ResetData The data buffer starts with a Null-terminated string,
followed by the EFI_GUID.
**/
VOID
EFIAPI
ResetPlatformSpecific (
IN UINTN DataSize,
IN VOID *ResetData
)
{
AcpiGedReset ();
}
/**
This function causes the system to enter a power state equivalent
to the ACPI G2/S5 or G3 states.
If this function returns, it means that the system does not support shut down
reset.
**/
VOID EFIAPI
ResetShutdown (
VOID
)
{
AcpiGedShutdown ();
}

View File

@ -0,0 +1,23 @@
/** @file
ResetSystem lib head file.
Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef RESET_SYSTEM_ACPI_GED_H_
#define RESET_SYSTEM_ACPI_GED_H_
#include <Base.h>
typedef struct {
UINT64 SleepControlRegAddr;
UINT64 SleepStatusRegAddr;
UINT64 ResetRegAddr;
UINT8 ResetValue;
} POWER_MANAGER;
extern POWER_MANAGER mPowerManager;
#endif // RESET_SYSTEM_ACPI_GED_H_