ArmPkg/ArmMonitorLib: Implement SMCCC protocol correctly and directly

The SMCCC protocol stipulates the following:
- on AARCH64, 18 arguments can be passed, and 18 values can be returned,
  via registers X0-x17;
- on ARM, 8 arguments can be passed, and 8 values can be returned.

This makes ArmSmcLib and ArmHvcLib as implemented currently unsuitable
for use with SMCCC services in general, although for PSCI in particular,
they work fine.

The dependency on both ArmSmcLib and ArmHvcLib is also impractical
because it requires every platform that consumes ArmMonitorLib to
provide resolutions for each, even though most platforms will only ever
need one of these (and the choice is made at compile time)

So let's drop these dependencies, and re-implement the asm helpers from
scratch. Note that the only difference is the actual instruction used
-HVC vs SMC- and so all other code can be shared.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
Ard Biesheuvel 2024-07-24 23:33:08 +02:00 committed by mergify[bot]
parent 43130ae403
commit b1bce5e564
5 changed files with 145 additions and 40 deletions

View File

@ -23,6 +23,18 @@ typedef struct {
UINTN Arg5;
UINTN Arg6;
UINTN Arg7;
#ifdef MDE_CPU_AARCH64
UINTN Arg8;
UINTN Arg9;
UINTN Arg10;
UINTN Arg11;
UINTN Arg12;
UINTN Arg13;
UINTN Arg14;
UINTN Arg15;
UINTN Arg16;
UINTN Arg17;
#endif
} ARM_MONITOR_ARGS;
/** Monitor call.

View File

@ -0,0 +1,79 @@
//
// Copyright (c) 2024, Google Llc. All rights reserved.
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
//
#include <AsmMacroIoLibV8.h>
/** Monitor call.
An HyperVisor Call (HVC) or System Monitor Call (SMC) will be issued
depending on the default conduit. PcdMonitorConduitHvc determines the type
of the call: if true, do an HVC.
@param [in,out] Args Arguments for the HVC/SMC.
**/
ASM_FUNC(ArmMonitorCall)
// Create a stack frame
stp x29, x30, [sp, #-16]!
mov x29, sp
// Preserve X0 for later use
mov x30, x0
// Load the SMCCC arguments values into the appropriate registers
ldp x0, x1, [x30, #0]
ldp x2, x3, [x30, #16]
ldp x4, x5, [x30, #32]
ldp x6, x7, [x30, #48]
ldp x8, x9, [x30, #64]
ldp x10, x11, [x30, #80]
ldp x12, x13, [x30, #96]
ldp x14, x15, [x30, #112]
ldp x16, x17, [x30, #128]
#if !defined(_PCD_VALUE_PcdMonitorConduitHvc)
#error
#elif _PCD_VALUE_PcdMonitorConduitHvc == 0
smc #0
#elif _PCD_VALUE_PcdMonitorConduitHvc == 1
hvc #0
#else
#error
#endif
// A SMCCC SMC64/HVC64 call can return up to 18 values.
stp x0, x1, [x30, #0]
stp x2, x3, [x30, #16]
stp x4, x5, [x30, #32]
stp x6, x7, [x30, #48]
stp x8, x9, [x30, #64]
stp x10, x11, [x30, #80]
stp x12, x13, [x30, #96]
stp x14, x15, [x30, #112]
stp x16, x17, [x30, #128]
// Clear return values from registers
mov x0, xzr
mov x1, xzr
mov x2, xzr
mov x3, xzr
mov x4, xzr
mov x5, xzr
mov x6, xzr
mov x7, xzr
mov x8, xzr
mov x9, xzr
mov x10, xzr
mov x11, xzr
mov x12, xzr
mov x13, xzr
mov x14, xzr
mov x15, xzr
mov x16, xzr
mov x17, xzr
ldp x29, x30, [sp], #16
ret

View File

@ -0,0 +1,49 @@
//
// Copyright (c) 2024, Google Llc. All rights reserved.
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
//
#include <AsmMacroIoLib.h>
/** Monitor call.
An HyperVisor Call (HVC) or System Monitor Call (SMC) will be issued
depending on the default conduit. PcdMonitorConduitHvc determines the type
of the call: if true, do an HVC.
@param [in,out] Args Arguments for the HVC/SMC.
**/
ASM_FUNC(ArmMonitorCall)
push {r4-r7}
// Preserve R0 for later use
mov ip, r0
// Load the SMCCC arguments values into the appropriate registers
ldm r0, {r0-r7}
#if !defined(_PCD_VALUE_PcdMonitorConduitHvc)
#error
#elif _PCD_VALUE_PcdMonitorConduitHvc == 0
.arch_extension sec
smc #0
#elif _PCD_VALUE_PcdMonitorConduitHvc == 1
.arch_extension virt
hvc #0
#else
#error
#endif
// A SMCCC SMC32/HVC32 call can return up to 8 values.
stm ip, {r0-r7}
// Clear return values from registers
mov r0, #0
mov r1, #0
mov r2, #0
mov r3, #0
pop {r4-r7}
bx lr

View File

@ -1,34 +0,0 @@
/** @file
Arm Monitor Library.
Copyright (c) 2022, Arm Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Library/ArmHvcLib.h>
#include <Library/ArmMonitorLib.h>
#include <Library/ArmSmcLib.h>
#include <Library/PcdLib.h>
/** Monitor call.
An HyperVisor Call (HVC) or System Monitor Call (SMC) will be issued
depending on the default conduit. PcdMonitorConduitHvc determines the type
of the call: if true, do an HVC.
@param [in,out] Args Arguments for the HVC/SMC.
**/
VOID
EFIAPI
ArmMonitorCall (
IN OUT ARM_MONITOR_ARGS *Args
)
{
if (FixedPcdGetBool (PcdMonitorConduitHvc)) {
ArmCallHvc ((ARM_HVC_ARGS *)Args);
} else {
ArmCallSmc ((ARM_SMC_ARGS *)Args);
}
}

View File

@ -14,16 +14,15 @@
VERSION_STRING = 1.0
LIBRARY_CLASS = ArmMonitorLib
[Sources]
ArmMonitorLib.c
[Sources.ARM]
Arm/ArmMonitorLib.S
[Sources.AARCH64]
AArch64/ArmMonitorLib.S
[Packages]
ArmPkg/ArmPkg.dec
MdePkg/MdePkg.dec
[LibraryClasses]
ArmHvcLib
ArmSmcLib
[Pcd]
gArmTokenSpaceGuid.PcdMonitorConduitHvc