summaryrefslogtreecommitdiff
path: root/ArmPkg
diff options
context:
space:
mode:
authorArd Biesheuvel <ardb@kernel.org>2024-07-24 23:33:08 +0200
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2024-07-25 14:41:09 +0000
commitb1bce5e5649840159d54eb8bffa4fa3d4fae8ee6 (patch)
tree555ddb5602c085d1cc7635aa4701396c8685fb9d /ArmPkg
parent43130ae4034cdcf0fa0ff928105fbe3e52d9f628 (diff)
downloadedk2-b1bce5e5649840159d54eb8bffa4fa3d4fae8ee6.zip
edk2-b1bce5e5649840159d54eb8bffa4fa3d4fae8ee6.tar.gz
edk2-b1bce5e5649840159d54eb8bffa4fa3d4fae8ee6.tar.bz2
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>
Diffstat (limited to 'ArmPkg')
-rw-r--r--ArmPkg/Include/Library/ArmMonitorLib.h12
-rw-r--r--ArmPkg/Library/ArmMonitorLib/AArch64/ArmMonitorLib.S79
-rw-r--r--ArmPkg/Library/ArmMonitorLib/Arm/ArmMonitorLib.S49
-rw-r--r--ArmPkg/Library/ArmMonitorLib/ArmMonitorLib.c34
-rw-r--r--ArmPkg/Library/ArmMonitorLib/ArmMonitorLib.inf11
5 files changed, 145 insertions, 40 deletions
diff --git a/ArmPkg/Include/Library/ArmMonitorLib.h b/ArmPkg/Include/Library/ArmMonitorLib.h
index d6e13b6..1192ee2 100644
--- a/ArmPkg/Include/Library/ArmMonitorLib.h
+++ b/ArmPkg/Include/Library/ArmMonitorLib.h
@@ -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.
diff --git a/ArmPkg/Library/ArmMonitorLib/AArch64/ArmMonitorLib.S b/ArmPkg/Library/ArmMonitorLib/AArch64/ArmMonitorLib.S
new file mode 100644
index 0000000..a99adf0
--- /dev/null
+++ b/ArmPkg/Library/ArmMonitorLib/AArch64/ArmMonitorLib.S
@@ -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
diff --git a/ArmPkg/Library/ArmMonitorLib/Arm/ArmMonitorLib.S b/ArmPkg/Library/ArmMonitorLib/Arm/ArmMonitorLib.S
new file mode 100644
index 0000000..9029059
--- /dev/null
+++ b/ArmPkg/Library/ArmMonitorLib/Arm/ArmMonitorLib.S
@@ -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
diff --git a/ArmPkg/Library/ArmMonitorLib/ArmMonitorLib.c b/ArmPkg/Library/ArmMonitorLib/ArmMonitorLib.c
deleted file mode 100644
index 72f7129..0000000
--- a/ArmPkg/Library/ArmMonitorLib/ArmMonitorLib.c
+++ /dev/null
@@ -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);
- }
-}
diff --git a/ArmPkg/Library/ArmMonitorLib/ArmMonitorLib.inf b/ArmPkg/Library/ArmMonitorLib/ArmMonitorLib.inf
index f504cb8..06fbab2 100644
--- a/ArmPkg/Library/ArmMonitorLib/ArmMonitorLib.inf
+++ b/ArmPkg/Library/ArmMonitorLib/ArmMonitorLib.inf
@@ -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