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 <ardb@kernel.org>
This commit is contained in:
Ard Biesheuvel 2024-06-07 18:39:43 +02:00 committed by mergify[bot]
parent 5bea691233
commit 059676e4fa
5 changed files with 138 additions and 12 deletions

View File

@ -92,6 +92,8 @@
TpmPlatformHierarchyLib|SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLibNull/PeiDxeTpmPlatformHierarchyLib.inf TpmPlatformHierarchyLib|SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLibNull/PeiDxeTpmPlatformHierarchyLib.inf
!endif !endif
ArmMonitorLib|ArmVirtPkg/Library/ArmVirtQemuMonitorLib/ArmVirtQemuMonitorLib.inf
[LibraryClasses.AARCH64] [LibraryClasses.AARCH64]
ArmPlatformLib|ArmVirtPkg/Library/ArmPlatformLibQemu/ArmPlatformLibQemu.inf ArmPlatformLib|ArmVirtPkg/Library/ArmPlatformLibQemu/ArmPlatformLibQemu.inf

View File

@ -82,6 +82,8 @@
TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
TpmPlatformHierarchyLib|SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLibNull/PeiDxeTpmPlatformHierarchyLib.inf TpmPlatformHierarchyLib|SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLibNull/PeiDxeTpmPlatformHierarchyLib.inf
ArmMonitorLib|ArmVirtPkg/Library/ArmVirtQemuMonitorLib/ArmVirtQemuMonitorLib.inf
[LibraryClasses.common.DXE_DRIVER] [LibraryClasses.common.DXE_DRIVER]
AcpiPlatformLib|OvmfPkg/Library/AcpiPlatformLib/DxeAcpiPlatformLib.inf AcpiPlatformLib|OvmfPkg/Library/AcpiPlatformLib/DxeAcpiPlatformLib.inf
ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf

View File

@ -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.<BR>
Copyright (c) 2024, Google LLC. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <PiDxe.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/ArmHvcLib.h>
#include <Library/ArmMonitorLib.h>
#include <Library/ArmSmcLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/FdtClient.h>
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));
}
}

View File

@ -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.<BR>
# Copyright (c) 2024, Google LLC. All rights reserved.<BR>
#
# 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

View File

@ -226,17 +226,5 @@ PlatformPeim (
BuildFvHob (PcdGet64 (PcdFvBaseAddress), PcdGet32 (PcdFvSize)); 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; return EFI_SUCCESS;
} }