arm-smccc.h 10.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright (c) 2015, Linaro Limited
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */
#ifndef __LINUX_ARM_SMCCC_H
#define __LINUX_ARM_SMCCC_H

17 18
#include <uapi/linux/const.h>

19 20 21 22 23 24
/*
 * This file provides common defines for ARM SMC Calling Convention as
 * specified in
 * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
 */

25 26
#define ARM_SMCCC_STD_CALL	        _AC(0,U)
#define ARM_SMCCC_FAST_CALL	        _AC(1,U)
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
#define ARM_SMCCC_TYPE_SHIFT		31

#define ARM_SMCCC_SMC_32		0
#define ARM_SMCCC_SMC_64		1
#define ARM_SMCCC_CALL_CONV_SHIFT	30

#define ARM_SMCCC_OWNER_MASK		0x3F
#define ARM_SMCCC_OWNER_SHIFT		24

#define ARM_SMCCC_FUNC_MASK		0xFFFF

#define ARM_SMCCC_IS_FAST_CALL(smc_val)	\
	((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT))
#define ARM_SMCCC_IS_64(smc_val) \
	((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT))
#define ARM_SMCCC_FUNC_NUM(smc_val)	((smc_val) & ARM_SMCCC_FUNC_MASK)
#define ARM_SMCCC_OWNER_NUM(smc_val) \
	(((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK)

#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \
	(((type) << ARM_SMCCC_TYPE_SHIFT) | \
	((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \
	(((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \
	((func_num) & ARM_SMCCC_FUNC_MASK))

#define ARM_SMCCC_OWNER_ARCH		0
#define ARM_SMCCC_OWNER_CPU		1
#define ARM_SMCCC_OWNER_SIP		2
#define ARM_SMCCC_OWNER_OEM		3
#define ARM_SMCCC_OWNER_STANDARD	4
#define ARM_SMCCC_OWNER_TRUSTED_APP	48
#define ARM_SMCCC_OWNER_TRUSTED_APP_END	49
#define ARM_SMCCC_OWNER_TRUSTED_OS	50
#define ARM_SMCCC_OWNER_TRUSTED_OS_END	63

62 63 64
#define ARM_SMCCC_QUIRK_NONE		0
#define ARM_SMCCC_QUIRK_QCOM_A6		1 /* Save/restore register a6 */

65 66 67 68 69 70 71 72 73 74 75 76 77
#define ARM_SMCCC_VERSION_1_0		0x10000
#define ARM_SMCCC_VERSION_1_1		0x10001

#define ARM_SMCCC_VERSION_FUNC_ID					\
	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
			   ARM_SMCCC_SMC_32,				\
			   0, 0)

#define ARM_SMCCC_ARCH_FEATURES_FUNC_ID					\
	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
			   ARM_SMCCC_SMC_32,				\
			   0, 1)

78 79 80 81 82
#define ARM_SMCCC_ARCH_WORKAROUND_1					\
	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
			   ARM_SMCCC_SMC_32,				\
			   0, 0x8000)

83 84 85 86 87
#define ARM_SMCCC_ARCH_WORKAROUND_2					\
	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
			   ARM_SMCCC_SMC_32,				\
			   0, 0x7fff)

88 89 90 91
#ifndef __ASSEMBLY__

#include <linux/linkage.h>
#include <linux/types.h>
92 93 94 95 96 97 98 99 100 101 102 103
/**
 * struct arm_smccc_res - Result from SMC/HVC call
 * @a0-a3 result values from registers 0 to 3
 */
struct arm_smccc_res {
	unsigned long a0;
	unsigned long a1;
	unsigned long a2;
	unsigned long a3;
};

/**
104 105 106 107 108 109 110 111 112 113 114 115 116 117
 * struct arm_smccc_quirk - Contains quirk information
 * @id: quirk identification
 * @state: quirk specific information
 * @a6: Qualcomm quirk entry for returning post-smc call contents of a6
 */
struct arm_smccc_quirk {
	int	id;
	union {
		unsigned long a6;
	} state;
};

/**
 * __arm_smccc_smc() - make SMC calls
118 119
 * @a0-a7: arguments passed in registers 0 to 7
 * @res: result values from registers 0 to 3
120
 * @quirk: points to an arm_smccc_quirk, or NULL when no quirks are required.
121 122 123 124
 *
 * This function is used to make SMC calls following SMC Calling Convention.
 * The content of the supplied param are copied to registers 0 to 7 prior
 * to the SMC instruction. The return values are updated with the content
125 126
 * from register 0 to 3 on return from the SMC instruction.  An optional
 * quirk structure provides vendor specific behavior.
127
 */
128
asmlinkage void __arm_smccc_smc(unsigned long a0, unsigned long a1,
129 130
			unsigned long a2, unsigned long a3, unsigned long a4,
			unsigned long a5, unsigned long a6, unsigned long a7,
131
			struct arm_smccc_res *res, struct arm_smccc_quirk *quirk);
132 133

/**
134
 * __arm_smccc_hvc() - make HVC calls
135 136
 * @a0-a7: arguments passed in registers 0 to 7
 * @res: result values from registers 0 to 3
137
 * @quirk: points to an arm_smccc_quirk, or NULL when no quirks are required.
138 139 140 141
 *
 * This function is used to make HVC calls following SMC Calling
 * Convention.  The content of the supplied param are copied to registers 0
 * to 7 prior to the HVC instruction. The return values are updated with
142 143
 * the content from register 0 to 3 on return from the HVC instruction.  An
 * optional quirk structure provides vendor specific behavior.
144
 */
145
asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
146 147
			unsigned long a2, unsigned long a3, unsigned long a4,
			unsigned long a5, unsigned long a6, unsigned long a7,
148 149 150 151 152 153 154 155 156
			struct arm_smccc_res *res, struct arm_smccc_quirk *quirk);

#define arm_smccc_smc(...) __arm_smccc_smc(__VA_ARGS__, NULL)

#define arm_smccc_smc_quirk(...) __arm_smccc_smc(__VA_ARGS__)

#define arm_smccc_hvc(...) __arm_smccc_hvc(__VA_ARGS__, NULL)

#define arm_smccc_hvc_quirk(...) __arm_smccc_hvc(__VA_ARGS__)
157

158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
/* SMCCC v1.1 implementation madness follows */
#ifdef CONFIG_ARM64

#define SMCCC_SMC_INST	"smc	#0"
#define SMCCC_HVC_INST	"hvc	#0"

#elif defined(CONFIG_ARM)
#include <asm/opcodes-sec.h>
#include <asm/opcodes-virt.h>

#define SMCCC_SMC_INST	__SMC(0)
#define SMCCC_HVC_INST	__HVC(0)

#endif

#define ___count_args(_0, _1, _2, _3, _4, _5, _6, _7, _8, x, ...) x

#define __count_args(...)						\
	___count_args(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)

#define __constraint_write_0						\
	"+r" (r0), "=&r" (r1), "=&r" (r2), "=&r" (r3)
#define __constraint_write_1						\
	"+r" (r0), "+r" (r1), "=&r" (r2), "=&r" (r3)
#define __constraint_write_2						\
	"+r" (r0), "+r" (r1), "+r" (r2), "=&r" (r3)
#define __constraint_write_3						\
	"+r" (r0), "+r" (r1), "+r" (r2), "+r" (r3)
#define __constraint_write_4	__constraint_write_3
#define __constraint_write_5	__constraint_write_4
#define __constraint_write_6	__constraint_write_5
#define __constraint_write_7	__constraint_write_6

#define __constraint_read_0
#define __constraint_read_1
#define __constraint_read_2
#define __constraint_read_3
#define __constraint_read_4	"r" (r4)
#define __constraint_read_5	__constraint_read_4, "r" (r5)
#define __constraint_read_6	__constraint_read_5, "r" (r6)
#define __constraint_read_7	__constraint_read_6, "r" (r7)

#define __declare_arg_0(a0, res)					\
	struct arm_smccc_res   *___res = res;				\
202
	register unsigned long r0 asm("r0") = (u32)a0;			\
203 204 205 206 207
	register unsigned long r1 asm("r1");				\
	register unsigned long r2 asm("r2");				\
	register unsigned long r3 asm("r3")

#define __declare_arg_1(a0, a1, res)					\
208
	typeof(a1) __a1 = a1;						\
209
	struct arm_smccc_res   *___res = res;				\
210
	register unsigned long r0 asm("r0") = (u32)a0;			\
211
	register unsigned long r1 asm("r1") = __a1;			\
212 213 214 215
	register unsigned long r2 asm("r2");				\
	register unsigned long r3 asm("r3")

#define __declare_arg_2(a0, a1, a2, res)				\
216 217
	typeof(a1) __a1 = a1;						\
	typeof(a2) __a2 = a2;						\
218
	struct arm_smccc_res   *___res = res;				\
219
	register unsigned long r0 asm("r0") = (u32)a0;			\
220 221
	register unsigned long r1 asm("r1") = __a1;			\
	register unsigned long r2 asm("r2") = __a2;			\
222 223 224
	register unsigned long r3 asm("r3")

#define __declare_arg_3(a0, a1, a2, a3, res)				\
225 226 227
	typeof(a1) __a1 = a1;						\
	typeof(a2) __a2 = a2;						\
	typeof(a3) __a3 = a3;						\
228
	struct arm_smccc_res   *___res = res;				\
229
	register unsigned long r0 asm("r0") = (u32)a0;			\
230 231 232
	register unsigned long r1 asm("r1") = __a1;			\
	register unsigned long r2 asm("r2") = __a2;			\
	register unsigned long r3 asm("r3") = __a3
233 234

#define __declare_arg_4(a0, a1, a2, a3, a4, res)			\
235
	typeof(a4) __a4 = a4;						\
236
	__declare_arg_3(a0, a1, a2, a3, res);				\
237
	register unsigned long r4 asm("r4") = __a4
238 239

#define __declare_arg_5(a0, a1, a2, a3, a4, a5, res)			\
240
	typeof(a5) __a5 = a5;						\
241
	__declare_arg_4(a0, a1, a2, a3, a4, res);			\
242
	register unsigned long r5 asm("r5") = __a5
243 244

#define __declare_arg_6(a0, a1, a2, a3, a4, a5, a6, res)		\
245
	typeof(a6) __a6 = a6;						\
246
	__declare_arg_5(a0, a1, a2, a3, a4, a5, res);			\
247
	register unsigned long r6 asm("r6") = __a6
248 249

#define __declare_arg_7(a0, a1, a2, a3, a4, a5, a6, a7, res)		\
250
	typeof(a7) __a7 = a7;						\
251
	__declare_arg_6(a0, a1, a2, a3, a4, a5, a6, res);		\
252
	register unsigned long r7 asm("r7") = __a7
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308

#define ___declare_args(count, ...) __declare_arg_ ## count(__VA_ARGS__)
#define __declare_args(count, ...)  ___declare_args(count, __VA_ARGS__)

#define ___constraints(count)						\
	: __constraint_write_ ## count					\
	: __constraint_read_ ## count					\
	: "memory"
#define __constraints(count)	___constraints(count)

/*
 * We have an output list that is not necessarily used, and GCC feels
 * entitled to optimise the whole sequence away. "volatile" is what
 * makes it stick.
 */
#define __arm_smccc_1_1(inst, ...)					\
	do {								\
		__declare_args(__count_args(__VA_ARGS__), __VA_ARGS__);	\
		asm volatile(inst "\n"					\
			     __constraints(__count_args(__VA_ARGS__)));	\
		if (___res)						\
			*___res = (typeof(*___res)){r0, r1, r2, r3};	\
	} while (0)

/*
 * arm_smccc_1_1_smc() - make an SMCCC v1.1 compliant SMC call
 *
 * This is a variadic macro taking one to eight source arguments, and
 * an optional return structure.
 *
 * @a0-a7: arguments passed in registers 0 to 7
 * @res: result values from registers 0 to 3
 *
 * This macro is used to make SMC calls following SMC Calling Convention v1.1.
 * The content of the supplied param are copied to registers 0 to 7 prior
 * to the SMC instruction. The return values are updated with the content
 * from register 0 to 3 on return from the SMC instruction if not NULL.
 */
#define arm_smccc_1_1_smc(...)	__arm_smccc_1_1(SMCCC_SMC_INST, __VA_ARGS__)

/*
 * arm_smccc_1_1_hvc() - make an SMCCC v1.1 compliant HVC call
 *
 * This is a variadic macro taking one to eight source arguments, and
 * an optional return structure.
 *
 * @a0-a7: arguments passed in registers 0 to 7
 * @res: result values from registers 0 to 3
 *
 * This macro is used to make HVC calls following SMC Calling Convention v1.1.
 * The content of the supplied param are copied to registers 0 to 7 prior
 * to the HVC instruction. The return values are updated with the content
 * from register 0 to 3 on return from the HVC instruction if not NULL.
 */
#define arm_smccc_1_1_hvc(...)	__arm_smccc_1_1(SMCCC_HVC_INST, __VA_ARGS__)

309 310 311 312 313
/* Return codes defined in ARM DEN 0070A */
#define SMCCC_RET_SUCCESS			0
#define SMCCC_RET_NOT_SUPPORTED			-1
#define SMCCC_RET_NOT_REQUIRED			-2

314
#endif /*__ASSEMBLY__*/
315
#endif /*__LINUX_ARM_SMCCC_H*/