关于SMC instruction指令执行level的讨论
前段时间在分析kvm armv8部分源码的时候,发现一个很奇怪的smcc指令
include/linux/arm-smccc.h
arm_smccc_1_1_invoke
* 399 * This is a variadic macro taking one to eight source arguments, and 400 * an optional return structure. 401 * 402 * @a0-a7: arguments passed in registers 0 to 7 403 * @res: result values from registers 0 to 3 404 * 405 * This macro will make either an HVC call or an SMC call depending on the 406 * current SMCCC conduit. If no valid conduit is available then -1 407 * (SMCCC_RET_NOT_SUPPORTED) is returned in @res.a0 (if supplied). 408 * 409 * The return value also provides the conduit that was used. 410 */ 411 #define arm_smccc_1_1_invoke(...) ({ \ 412 int method = arm_smccc_1_1_get_conduit(); \ 413 switch (method) { \ 414 case SMCCC_CONDUIT_HVC: \ 415 arm_smccc_1_1_hvc(__VA_ARGS__); \ 416 break; \ 417 case SMCCC_CONDUIT_SMC: // 不太明白为什么在EL1状态能执行SMC指令能够有效。\ 418 arm_smccc_1_1_smc(__VA_ARGS__); \ 419 break; \ 420 default: \ 421 __fail_smccc_1_1(__VA_ARGS__); \ 422 method = SMCCC_CONDUIT_NONE; \ 423 break; \ 424 } \ 425 method; \ 426 }) 427 428 #endif /*__ASSEMBLY__*/
337 #define __arm_smccc_1_1(inst, ...) \ 338 do { \ 339 register unsigned long r0 asm("r0"); \ 340 register unsigned long r1 asm("r1"); \ 341 register unsigned long r2 asm("r2"); \ 342 register unsigned long r3 asm("r3"); \ 343 __declare_args(__count_args(__VA_ARGS__), __VA_ARGS__); \ 344 asm volatile(inst "\n" : \ 345 "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3) \ 346 __constraints(__count_args(__VA_ARGS__))); \ 347 if (___res) \ 348 *___res = (typeof(*___res)){r0, r1, r2, r3}; \ 349 } while (0) 350 351 /* 352 * arm_smccc_1_1_smc() - make an SMCCC v1.1 compliant SMC call 353 * 354 * This is a variadic macro taking one to eight source arguments, and 355 * an optional return structure. 356 * 357 * @a0-a7: arguments passed in registers 0 to 7 358 * @res: result values from registers 0 to 3 359 * 360 * This macro is used to make SMC calls following SMC Calling Convention v1.1. 361 * The content of the supplied param are copied to registers 0 to 7 prior 362 * to the SMC instruction. The return values are updated with the content 363 * from register 0 to 3 on return from the SMC instruction if not NULL. 364 */ 365 #define arm_smccc_1_1_smc(...) __arm_smccc_1_1(SMCCC_SMC_INST, __VA_ARGS__)
当时kernel正好作为guest os运行在EL1上,觉得很奇怪的是,为什么EL1状态下能trap smccc指令进入到
EL3状态,觉得很疑惑,就查找了下手册,找到了如下解释才弄明白。
The SMC instruction is used to generate a synchronous exception that is handled by Secure Monitor code running in EL3.
Arguments and return values are passed in registers. After being handled by the Secure Monitor, calls that result from the i
nstructions can be passed on to a Trusted OS or some other entity in the secure software stack.
The HVC instruction is used to generate a synchronous exception that is handled by a hypervisor running in EL2.
Arguments and return values are passed in registers. Hypervisors can also trap SMC calls that are made by Guest Operating
Systems (at EL1), which allows the calls to be emulated, passed through, or denied as appropriate.
Hypervisors can also trap SMC calls that are made by Guest Operating Systems (at EL1), which allows the calls
to be emulated, passed through, or denied as appropriate.
参考:ARM_DEN0028B_SMC_Calling_Convention.pdf