1/* SPDX-License-Identifier: GPL-2.0-only */ 2/* 3 * Copyright (c) 2015, Linaro Limited 4 */ 5#include <linux/linkage.h> 6#include <linux/arm-smccc.h> 7 8#include <asm/asm-offsets.h> 9#include <asm/assembler.h> 10#include <asm/thread_info.h> 11 12/* 13 * If we have SMCCC v1.3 and (as is likely) no SVE state in 14 * the registers then set the SMCCC hint bit to say there's no 15 * need to preserve it. Do this by directly adjusting the SMCCC 16 * function value which is already stored in x0 ready to be called. 17 */ 18SYM_FUNC_START(__arm_smccc_sve_check) 19 20 ldr_l x16, smccc_has_sve_hint 21 cbz x16, 2f 22 23 get_current_task x16 24 ldr x16, [x16, #TSK_TI_FLAGS] 25 tbnz x16, #TIF_FOREIGN_FPSTATE, 1f // Any live FP state? 26 tbnz x16, #TIF_SVE, 2f // Does that state include SVE? 27 281: orr x0, x0, ARM_SMCCC_1_3_SVE_HINT 29 302: ret 31SYM_FUNC_END(__arm_smccc_sve_check) 32EXPORT_SYMBOL(__arm_smccc_sve_check) 33 34 .macro SMCCC instr 35alternative_if ARM64_SVE 36 bl __arm_smccc_sve_check 37alternative_else_nop_endif 38 \instr #0 39 ldr x4, [sp] 40 stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS] 41 stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS] 42 ldr x4, [sp, #8] 43 cbz x4, 1f /* no quirk structure */ 44 ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS] 45 cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6 46 b.ne 1f 47 str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS] 481: ret 49 .endm 50 51/* 52 * void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, 53 * unsigned long a3, unsigned long a4, unsigned long a5, 54 * unsigned long a6, unsigned long a7, struct arm_smccc_res *res, 55 * struct arm_smccc_quirk *quirk) 56 */ 57SYM_FUNC_START(__arm_smccc_smc) 58 SMCCC smc 59SYM_FUNC_END(__arm_smccc_smc) 60EXPORT_SYMBOL(__arm_smccc_smc) 61 62/* 63 * void arm_smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2, 64 * unsigned long a3, unsigned long a4, unsigned long a5, 65 * unsigned long a6, unsigned long a7, struct arm_smccc_res *res, 66 * struct arm_smccc_quirk *quirk) 67 */ 68SYM_FUNC_START(__arm_smccc_hvc) 69 SMCCC hvc 70SYM_FUNC_END(__arm_smccc_hvc) 71EXPORT_SYMBOL(__arm_smccc_hvc) 72 73 .macro SMCCC_1_2 instr 74 /* Save `res` and free a GPR that won't be clobbered */ 75 stp x1, x19, [sp, #-16]! 76 77 /* Ensure `args` won't be clobbered while loading regs in next step */ 78 mov x19, x0 79 80 /* Load the registers x0 - x17 from the struct arm_smccc_1_2_regs */ 81 ldp x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS] 82 ldp x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS] 83 ldp x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS] 84 ldp x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS] 85 ldp x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS] 86 ldp x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS] 87 ldp x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS] 88 ldp x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS] 89 ldp x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS] 90 91 \instr #0 92 93 /* Load the `res` from the stack */ 94 ldr x19, [sp] 95 96 /* Store the registers x0 - x17 into the result structure */ 97 stp x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS] 98 stp x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS] 99 stp x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS] 100 stp x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS] 101 stp x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS] 102 stp x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS] 103 stp x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS] 104 stp x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS] 105 stp x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS] 106 107 /* Restore original x19 */ 108 ldp xzr, x19, [sp], #16 109 ret 110.endm 111 112/* 113 * void arm_smccc_1_2_hvc(const struct arm_smccc_1_2_regs *args, 114 * struct arm_smccc_1_2_regs *res); 115 */ 116SYM_FUNC_START(arm_smccc_1_2_hvc) 117 SMCCC_1_2 hvc 118SYM_FUNC_END(arm_smccc_1_2_hvc) 119EXPORT_SYMBOL(arm_smccc_1_2_hvc) 120 121/* 122 * void arm_smccc_1_2_smc(const struct arm_smccc_1_2_regs *args, 123 * struct arm_smccc_1_2_regs *res); 124 */ 125SYM_FUNC_START(arm_smccc_1_2_smc) 126 SMCCC_1_2 smc 127SYM_FUNC_END(arm_smccc_1_2_smc) 128EXPORT_SYMBOL(arm_smccc_1_2_smc) 129