]> xenbits.xensource.com Git - xen.git/commitdiff
xen/arm: smccc: add support for SMCCCv1.2 extended input/output registers
authorJens Wiklander <jens.wiklander@linaro.org>
Mon, 17 Jul 2023 07:20:46 +0000 (09:20 +0200)
committerJulien Grall <jgrall@amazon.com>
Thu, 20 Jul 2023 22:20:04 +0000 (23:20 +0100)
SMCCC v1.2 [1] AArch64 allows x0-x17 to be used as both parameter
registers and result registers for the SMC and HVC instructions.

Arm Firmware Framework for Armv8-A specification makes use of x0-x7 as
parameter and result registers.

Let us add new interface to support this extended set of input/output
registers.

This is based on 3fdc0cb59d97 ("arm64: smccc: Add support for SMCCCv1.2
extended input/output registers") by Sudeep Holla from the Linux kernel

The SMCCC version reported to the VM is bumped to 1.2 in order to support
handling FF-A messages.

[1] https://developer.arm.com/documentation/den0028/c/?lang=en

Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Reviewed-by: Luca Fancellu <luca.fancellu@arm.com>
Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>
Acked-by: Julien Grall <jgrall@amazon.com>
xen/arch/arm/arm64/asm-offsets.c
xen/arch/arm/arm64/smc.S
xen/arch/arm/include/asm/smccc.h
xen/arch/arm/vsmc.c

index 7226cd9b2eb0b684e20eaa0162c35b87d44fe42d..7adb67a1b81a14c0467a44d7999069d8a3a43075 100644 (file)
@@ -57,6 +57,15 @@ void __dummy__(void)
    BLANK();
    OFFSET(SMCCC_RES_a0, struct arm_smccc_res, a0);
    OFFSET(SMCCC_RES_a2, struct arm_smccc_res, a2);
+   OFFSET(ARM_SMCCC_1_2_REGS_X0_OFFS, struct arm_smccc_1_2_regs, a0);
+   OFFSET(ARM_SMCCC_1_2_REGS_X2_OFFS, struct arm_smccc_1_2_regs, a2);
+   OFFSET(ARM_SMCCC_1_2_REGS_X4_OFFS, struct arm_smccc_1_2_regs, a4);
+   OFFSET(ARM_SMCCC_1_2_REGS_X6_OFFS, struct arm_smccc_1_2_regs, a6);
+   OFFSET(ARM_SMCCC_1_2_REGS_X8_OFFS, struct arm_smccc_1_2_regs, a8);
+   OFFSET(ARM_SMCCC_1_2_REGS_X10_OFFS, struct arm_smccc_1_2_regs, a10);
+   OFFSET(ARM_SMCCC_1_2_REGS_X12_OFFS, struct arm_smccc_1_2_regs, a12);
+   OFFSET(ARM_SMCCC_1_2_REGS_X14_OFFS, struct arm_smccc_1_2_regs, a14);
+   OFFSET(ARM_SMCCC_1_2_REGS_X16_OFFS, struct arm_smccc_1_2_regs, a16);
 }
 
 /*
index 91bae62dd4d2372b42fbe5399fb515dea8355f97..fc6b676e2ee3812b7c5004bb94471779e932b620 100644 (file)
@@ -27,3 +27,45 @@ ENTRY(__arm_smccc_1_0_smc)
         stp     x2, x3, [x4, #SMCCC_RES_a2]
 1:
         ret
+
+/*
+ * void arm_smccc_1_2_smc(const struct arm_smccc_1_2_regs *args,
+ *                        struct arm_smccc_1_2_regs *res)
+ */
+ENTRY(arm_smccc_1_2_smc)
+    /* Save `res` and free a GPR that won't be clobbered by SMC call */
+    stp     x1, x19, [sp, #-16]!
+
+    /* Ensure `args` won't be clobbered while loading regs in next step */
+    mov        x19, x0
+
+    /* Load the registers x0 - x17 from the struct arm_smccc_1_2_regs */
+    ldp        x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS]
+    ldp        x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS]
+    ldp        x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS]
+    ldp        x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS]
+    ldp        x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS]
+    ldp        x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS]
+    ldp        x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS]
+    ldp        x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS]
+    ldp        x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS]
+
+    smc #0
+
+    /* Load the `res` from the stack */
+    ldr        x19, [sp]
+
+    /* Store the registers x0 - x17 into the result structure */
+    stp        x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS]
+    stp        x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS]
+    stp        x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS]
+    stp        x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS]
+    stp        x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS]
+    stp        x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS]
+    stp        x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS]
+    stp        x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS]
+    stp        x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS]
+
+    /* Restore original x19 */
+    ldp     xzr, x19, [sp], #16
+    ret
index b3dbeecc90ad2ed10065ba75aaf2dafaa9b65974..1adcd37443c7e03ab9dfd54c709bae80655b612b 100644 (file)
@@ -33,6 +33,7 @@
 
 #define ARM_SMCCC_VERSION_1_0   SMCCC_VERSION(1, 0)
 #define ARM_SMCCC_VERSION_1_1   SMCCC_VERSION(1, 1)
+#define ARM_SMCCC_VERSION_1_2   SMCCC_VERSION(1, 2)
 
 /*
  * This file provides common defines for ARM SMC Calling Convention as
@@ -265,6 +266,45 @@ void __arm_smccc_1_0_smc(register_t a0, register_t a1, register_t a2,
         else                                                    \
             arm_smccc_1_0_smc(__VA_ARGS__);                     \
     } while ( 0 )
+
+/*
+ * struct arm_smccc_1_2_regs - Arguments for or Results from SMC call
+ * @a0-a17 argument values from registers 0 to 17
+ */
+struct arm_smccc_1_2_regs {
+    unsigned long a0;
+    unsigned long a1;
+    unsigned long a2;
+    unsigned long a3;
+    unsigned long a4;
+    unsigned long a5;
+    unsigned long a6;
+    unsigned long a7;
+    unsigned long a8;
+    unsigned long a9;
+    unsigned long a10;
+    unsigned long a11;
+    unsigned long a12;
+    unsigned long a13;
+    unsigned long a14;
+    unsigned long a15;
+    unsigned long a16;
+    unsigned long a17;
+};
+
+/*
+ * arm_smccc_1_2_smc() - make SMC calls
+ * @args: arguments passed via struct arm_smccc_1_2_regs
+ * @res: result values via struct arm_smccc_1_2_regs
+ *
+ * This function is used to make SMC calls following SMC Calling Convention
+ * v1.2 or above. The content of the supplied param are copied from the
+ * structure to registers prior to the SMC instruction. The return values
+ * are updated with the content from registers on return from the SMC
+ * instruction.
+ */
+void arm_smccc_1_2_smc(const struct arm_smccc_1_2_regs *args,
+                       struct arm_smccc_1_2_regs *res);
 #endif /* CONFIG_ARM_64 */
 
 #endif /* __ASSEMBLY__ */
index 7335276f3fa1d0ab8b0bd440a1ab4f0d40412722..cd68fa80e98aa8d816cc003c9e6df7d47fc5cd58 100644 (file)
@@ -85,7 +85,7 @@ static bool handle_arch(struct cpu_user_regs *regs)
     switch ( fid )
     {
     case ARM_SMCCC_VERSION_FID:
-        set_user_reg(regs, 0, ARM_SMCCC_VERSION_1_1);
+        set_user_reg(regs, 0, ARM_SMCCC_VERSION_1_2);
         return true;
 
     case ARM_SMCCC_ARCH_FEATURES_FID: