[PATCH v6 1/6] arm64: smccc: Add support for SMCCCv1.2 extended input/output registers
Michael Kelley
mikelley at microsoft.com
Wed May 5 08:28:56 PDT 2021
From: Sudeep Holla <sudeep.holla at arm.com> Sent: Wednesday, May 5, 2021 2:39 AM
>
> SMCCC v1.2 allows x8-x17 to be used as parameter registers and x4—x17
> to be used as result registers in SMC64/HVC64. Arm Firmware Framework
> for Armv8-A specification makes use of x0-x7 as parameter and result
> registers. There are other users like Hyper-V who intend to use beyond
> x0-x7 as well.
>
> Current SMCCC interface in the kernel just use x0-x7 as parameter and
> x0-x3 as result registers as required by SMCCCv1.0. Let us add new
> interface to support this extended set of input/output registers namely
> x0-x17 as both parameter and result registers.
>
> Cc: Michael Kelley <mikelley at microsoft.com>
> Cc: Will Deacon <will at kernel.org>
> Cc: Mark Rutland <mark.rutland at arm.com>
> Cc:Catalin Marinas <catalin.marinas at arm.com>
> Signed-off-by: Sudeep Holla <sudeep.holla at arm.com>
> ---
> arch/arm64/kernel/asm-offsets.c | 9 ++++++
> arch/arm64/kernel/smccc-call.S | 57 +++++++++++++++++++++++++++++++++
> include/linux/arm-smccc.h | 55 +++++++++++++++++++++++++++++++
> 3 files changed, 121 insertions(+)
>
> diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
> index 0cb34ccb6e73..74321bc9a459 100644
> --- a/arch/arm64/kernel/asm-offsets.c
> +++ b/arch/arm64/kernel/asm-offsets.c
> @@ -138,6 +138,15 @@ int main(void)
> DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2));
> DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id));
> DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state));
> + DEFINE(ARM_SMCCC_1_2_REGS_X0_OFFS, offsetof(struct arm_smccc_1_2_regs, a0));
> + DEFINE(ARM_SMCCC_1_2_REGS_X2_OFFS, offsetof(struct arm_smccc_1_2_regs, a2));
> + DEFINE(ARM_SMCCC_1_2_REGS_X4_OFFS, offsetof(struct arm_smccc_1_2_regs, a4));
> + DEFINE(ARM_SMCCC_1_2_REGS_X6_OFFS, offsetof(struct arm_smccc_1_2_regs, a6));
> + DEFINE(ARM_SMCCC_1_2_REGS_X8_OFFS, offsetof(struct arm_smccc_1_2_regs, a8));
> + DEFINE(ARM_SMCCC_1_2_REGS_X10_OFFS, offsetof(struct
> arm_smccc_1_2_regs, a10));
> + DEFINE(ARM_SMCCC_1_2_REGS_X12_OFFS, offsetof(struct
> arm_smccc_1_2_regs, a12));
> + DEFINE(ARM_SMCCC_1_2_REGS_X14_OFFS, offsetof(struct
> arm_smccc_1_2_regs, a14));
> + DEFINE(ARM_SMCCC_1_2_REGS_X16_OFFS, offsetof(struct
> arm_smccc_1_2_regs, a16));
> BLANK();
> DEFINE(HIBERN_PBE_ORIG, offsetof(struct pbe, orig_address));
> DEFINE(HIBERN_PBE_ADDR, offsetof(struct pbe, address));
> diff --git a/arch/arm64/kernel/smccc-call.S b/arch/arm64/kernel/smccc-call.S
> index d62447964ed9..7d79c5062c5d 100644
> --- a/arch/arm64/kernel/smccc-call.S
> +++ b/arch/arm64/kernel/smccc-call.S
> @@ -43,3 +43,60 @@ SYM_FUNC_START(__arm_smccc_hvc)
> SMCCC hvc
> SYM_FUNC_END(__arm_smccc_hvc)
> EXPORT_SYMBOL(__arm_smccc_hvc)
> +
> + .macro SMCCC_1_2 instr
> + /* Save `res` and free a GPR that won't be clobbered */
> + 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]
> +
> + \instr #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
> +.endm
> +
> +/*
> + * void arm_smccc_1_2_hvc(struct arm_smccc_1_2_regs *args,
> + * struct arm_smccc_1_2_regs *res);
> + */
> +SYM_FUNC_START(arm_smccc_1_2_hvc)
> + SMCCC_1_2 hvc
> +SYM_FUNC_END(arm_smccc_1_2_hvc)
> +EXPORT_SYMBOL(arm_smccc_1_2_hvc)
I've tested the new arm_smccc_1_2_hvc() function in the context
of Linux guests making hypercalls on Hyper-V for ARM64, and it
works as intended. But note that my test case only uses X0 thru X7.
Tested-by: Michael Kelley <mikelley at microsoft.com>
Reviewed-by: Michael Kelley <mikelley at microsoft.com>
More information about the linux-arm-kernel
mailing list