From 059676e4faef29ebe50549ed9cd80b6f68a0d556 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 7 Jun 2024 18:39:43 +0200 Subject: ArmVirtPkg/ArmVirtQemu: Implement ArmMonitorLib for QEMU specifically Whether SMCCC calls use HVC or SMC generally depends on the exception level that the firmware executes at, but also on whether or not EL2 is implemented. This is almost always known at build time, which is why the default ArmMonitorLib used to model this as a feature PCD. However, on QEMU, things are not that simple. However, SMCCC specifies that the conduit is the same as the one used for PSCI calls (which has been retrofitted into SMCCC when it was defined). Given that QEMU provides this information via the device tree, let's use it to select the conduit, using a special ArmMonitorLib implementation. This also removes the need to set the associated PCD at runtime, given that its updated value will no longer be used. Signed-off-by: Ard Biesheuvel --- ArmVirtPkg/ArmVirtQemu.dsc | 2 + ArmVirtPkg/ArmVirtQemuKernel.dsc | 2 + .../ArmVirtQemuMonitorLib/ArmVirtQemuMonitorLib.c | 95 ++++++++++++++++++++++ .../ArmVirtQemuMonitorLib.inf | 39 +++++++++ ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.c | 12 --- 5 files changed, 138 insertions(+), 12 deletions(-) create mode 100644 ArmVirtPkg/Library/ArmVirtQemuMonitorLib/ArmVirtQemuMonitorLib.c create mode 100644 ArmVirtPkg/Library/ArmVirtQemuMonitorLib/ArmVirtQemuMonitorLib.inf diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc index 565b5c4..fa4f0ca 100644 --- a/ArmVirtPkg/ArmVirtQemu.dsc +++ b/ArmVirtPkg/ArmVirtQemu.dsc @@ -92,6 +92,8 @@ TpmPlatformHierarchyLib|SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLibNull/PeiDxeTpmPlatformHierarchyLib.inf !endif + ArmMonitorLib|ArmVirtPkg/Library/ArmVirtQemuMonitorLib/ArmVirtQemuMonitorLib.inf + [LibraryClasses.AARCH64] ArmPlatformLib|ArmVirtPkg/Library/ArmPlatformLibQemu/ArmPlatformLibQemu.inf diff --git a/ArmVirtPkg/ArmVirtQemuKernel.dsc b/ArmVirtPkg/ArmVirtQemuKernel.dsc index a8c3336..a1bafba 100644 --- a/ArmVirtPkg/ArmVirtQemuKernel.dsc +++ b/ArmVirtPkg/ArmVirtQemuKernel.dsc @@ -82,6 +82,8 @@ TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf TpmPlatformHierarchyLib|SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLibNull/PeiDxeTpmPlatformHierarchyLib.inf + ArmMonitorLib|ArmVirtPkg/Library/ArmVirtQemuMonitorLib/ArmVirtQemuMonitorLib.inf + [LibraryClasses.common.DXE_DRIVER] AcpiPlatformLib|OvmfPkg/Library/AcpiPlatformLib/DxeAcpiPlatformLib.inf ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf diff --git a/ArmVirtPkg/Library/ArmVirtQemuMonitorLib/ArmVirtQemuMonitorLib.c b/ArmVirtPkg/Library/ArmVirtQemuMonitorLib/ArmVirtQemuMonitorLib.c new file mode 100644 index 0000000..1c8b18d --- /dev/null +++ b/ArmVirtPkg/Library/ArmVirtQemuMonitorLib/ArmVirtQemuMonitorLib.c @@ -0,0 +1,95 @@ +/** @file + Arm Monitor Library that chooses the conduit based on the PSCI node in the + device tree provided by QEMU + + Copyright (c) 2022, Arm Limited. All rights reserved.
+ Copyright (c) 2024, Google LLC. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +STATIC UINT32 mArmSmcccMethod; + +/** Library constructor. + + Assign the global variable mArmSmcccMethod based on the PSCI node in the + device tree. +**/ +RETURN_STATUS +EFIAPI +ArmVirtQemuMonitorLibConstructor ( + VOID + ) +{ + EFI_STATUS Status; + FDT_CLIENT_PROTOCOL *FdtClient; + CONST VOID *Prop; + + Status = gBS->LocateProtocol ( + &gFdtClientProtocolGuid, + NULL, + (VOID **)&FdtClient + ); + ASSERT_EFI_ERROR (Status); + + Status = FdtClient->FindCompatibleNodeProperty ( + FdtClient, + "arm,psci-0.2", + "method", + &Prop, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (AsciiStrnCmp (Prop, "hvc", 3) == 0) { + mArmSmcccMethod = 1; + } else if (AsciiStrnCmp (Prop, "smc", 3) == 0) { + mArmSmcccMethod = 2; + } else { + DEBUG (( + DEBUG_ERROR, + "%a: Unknown SMCCC method \"%a\"\n", + __func__, + Prop + )); + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +/** Monitor call. + + An HyperVisor Call (HVC) or System Monitor Call (SMC) will be issued + depending on the default conduit. + + @param [in,out] Args Arguments for the HVC/SMC. +**/ +VOID +EFIAPI +ArmMonitorCall ( + IN OUT ARM_MONITOR_ARGS *Args + ) +{ + if (mArmSmcccMethod == 1) { + ArmCallHvc ((ARM_HVC_ARGS *)Args); + } else if (mArmSmcccMethod == 2) { + ArmCallSmc ((ARM_SMC_ARGS *)Args); + } else { + ASSERT ((mArmSmcccMethod == 1) || (mArmSmcccMethod == 2)); + } +} diff --git a/ArmVirtPkg/Library/ArmVirtQemuMonitorLib/ArmVirtQemuMonitorLib.inf b/ArmVirtPkg/Library/ArmVirtQemuMonitorLib/ArmVirtQemuMonitorLib.inf new file mode 100644 index 0000000..e43ba21 --- /dev/null +++ b/ArmVirtPkg/Library/ArmVirtQemuMonitorLib/ArmVirtQemuMonitorLib.inf @@ -0,0 +1,39 @@ +## @file +# Arm Monitor Library that chooses the conduit based on the PSCI node in the +# device tree provided by QEMU +# +# Copyright (c) 2022, Arm Limited. All rights reserved.
+# Copyright (c) 2024, Google LLC. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 1.29 + BASE_NAME = ArmVirtQemuMonitorLib + FILE_GUID = 09f50ee5-2aa2-42b9-a2a0-090faeefed2b + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ArmMonitorLib|DXE_DRIVER DXE_RUNTIME_DRIVER + CONSTRUCTOR = ArmVirtQemuMonitorLibConstructor + +[Sources] + ArmVirtQemuMonitorLib.c + +[Packages] + ArmPkg/ArmPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + ArmHvcLib + ArmSmcLib + BaseLib + DebugLib + UefiBootServicesTableLib + +[Protocols] + gFdtClientProtocolGuid ## CONSUMES + +[Depex] + gFdtClientProtocolGuid diff --git a/ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.c b/ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.c index b8e9208..3c80f05 100644 --- a/ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.c +++ b/ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.c @@ -226,17 +226,5 @@ PlatformPeim ( BuildFvHob (PcdGet64 (PcdFvBaseAddress), PcdGet32 (PcdFvSize)); - #ifdef MDE_CPU_AARCH64 - // - // Set the SMCCC conduit to SMC if executing at EL2, which is typically the - // exception level that services HVCs rather than the one that invokes them. - // - if (ArmReadCurrentEL () == AARCH64_EL2) { - Status = PcdSetBoolS (PcdMonitorConduitHvc, FALSE); - ASSERT_EFI_ERROR (Status); - } - - #endif - return EFI_SUCCESS; } -- cgit v1.1