execution_state_switch.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <stdbool.h>
  7. #include <string.h>
  8. #include <arch_helpers.h>
  9. #include <context.h>
  10. #include <lib/el3_runtime/context_mgmt.h>
  11. #include <lib/psci/psci.h>
  12. #include <lib/utils.h>
  13. #include <plat/arm/common/plat_arm.h>
  14. #include <smccc_helpers.h>
  15. /*
  16. * Handle SMC from a lower exception level to switch its execution state
  17. * (either from AArch64 to AArch32, or vice versa).
  18. *
  19. * smc_fid:
  20. * SMC function ID - either ARM_SIP_SVC_STATE_SWITCH_64 or
  21. * ARM_SIP_SVC_STATE_SWITCH_32.
  22. * pc_hi, pc_lo:
  23. * PC upon re-entry to the calling exception level; width dependent on the
  24. * calling exception level.
  25. * cookie_hi, cookie_lo:
  26. * Opaque pointer pairs received from the caller to pass it back, upon
  27. * re-entry.
  28. * handle:
  29. * Handle to saved context.
  30. */
  31. int arm_execution_state_switch(unsigned int smc_fid,
  32. uint32_t pc_hi,
  33. uint32_t pc_lo,
  34. uint32_t cookie_hi,
  35. uint32_t cookie_lo,
  36. void *handle)
  37. {
  38. bool caller_64, thumb = false, from_el2;
  39. unsigned int el, endianness;
  40. u_register_t spsr, pc, scr, sctlr;
  41. entry_point_info_t ep;
  42. cpu_context_t *ctx = (cpu_context_t *) handle;
  43. el3_state_t *el3_ctx = get_el3state_ctx(ctx);
  44. /* Validate supplied entry point */
  45. pc = (u_register_t) (((uint64_t) pc_hi << 32) | pc_lo);
  46. if (arm_validate_ns_entrypoint(pc) != 0)
  47. goto invalid_param;
  48. /* That the SMC originated from NS is already validated by the caller */
  49. /*
  50. * Disallow state switch if any of the secondaries have been brought up.
  51. */
  52. if (psci_secondaries_brought_up() != 0)
  53. goto exec_denied;
  54. spsr = read_ctx_reg(el3_ctx, CTX_SPSR_EL3);
  55. caller_64 = (GET_RW(spsr) == MODE_RW_64);
  56. if (caller_64) {
  57. /*
  58. * If the call originated from AArch64, expect 32-bit pointers when
  59. * switching to AArch32.
  60. */
  61. if ((pc_hi != 0U) || (cookie_hi != 0U))
  62. goto invalid_param;
  63. pc = pc_lo;
  64. /* Instruction state when entering AArch32 */
  65. thumb = (pc & 1U) != 0U;
  66. } else {
  67. /* Construct AArch64 PC */
  68. pc = (((u_register_t) pc_hi) << 32) | pc_lo;
  69. }
  70. /* Make sure PC is 4-byte aligned, except for Thumb */
  71. if (((pc & 0x3U) != 0U) && !thumb)
  72. goto invalid_param;
  73. /*
  74. * EL3 controls register width of the immediate lower EL only. Expect
  75. * this request from EL2/Hyp unless:
  76. *
  77. * - EL2 is not implemented;
  78. * - EL2 is implemented, but was disabled. This can be inferred from
  79. * SCR_EL3.HCE.
  80. */
  81. from_el2 = caller_64 ? (GET_EL(spsr) == MODE_EL2) :
  82. (GET_M32(spsr) == MODE32_hyp);
  83. scr = read_ctx_reg(el3_ctx, CTX_SCR_EL3);
  84. if (!from_el2) {
  85. /* The call is from NS privilege level other than HYP */
  86. /*
  87. * Disallow switching state if there's a Hypervisor in place;
  88. * this request must be taken up with the Hypervisor instead.
  89. */
  90. if ((scr & SCR_HCE_BIT) != 0U)
  91. goto exec_denied;
  92. }
  93. /*
  94. * Return to the caller using the same endianness. Extract
  95. * endianness bit from the respective system control register
  96. * directly.
  97. */
  98. sctlr = from_el2 ? read_sctlr_el2() : read_sctlr_el1();
  99. endianness = ((sctlr & SCTLR_EE_BIT) != 0U) ? 1U : 0U;
  100. /* Construct SPSR for the exception state we're about to switch to */
  101. if (caller_64) {
  102. unsigned long long impl;
  103. /*
  104. * Switching from AArch64 to AArch32. Ensure this CPU implements
  105. * the target EL in AArch32.
  106. */
  107. impl = from_el2 ? el_implemented(2) : el_implemented(1);
  108. if (impl != EL_IMPL_A64_A32)
  109. goto exec_denied;
  110. /* Return to the equivalent AArch32 privilege level */
  111. el = from_el2 ? MODE32_hyp : MODE32_svc;
  112. spsr = SPSR_MODE32((u_register_t) el,
  113. thumb ? SPSR_T_THUMB : SPSR_T_ARM,
  114. endianness, DISABLE_ALL_EXCEPTIONS);
  115. } else {
  116. /*
  117. * Switching from AArch32 to AArch64. Since it's not possible to
  118. * implement an EL as AArch32-only (from which this call was
  119. * raised), it's safe to assume AArch64 is also implemented.
  120. */
  121. el = from_el2 ? MODE_EL2 : MODE_EL1;
  122. spsr = SPSR_64((u_register_t) el, MODE_SP_ELX,
  123. DISABLE_ALL_EXCEPTIONS);
  124. }
  125. /*
  126. * Use the context management library to re-initialize the existing
  127. * context with the execution state flipped. Since the library takes
  128. * entry_point_info_t pointer as the argument, construct a dummy one
  129. * with PC, state width, endianness, security etc. appropriately set.
  130. * Other entries in the entry point structure are irrelevant for
  131. * purpose.
  132. */
  133. zeromem(&ep, sizeof(ep));
  134. ep.pc = pc;
  135. ep.spsr = (uint32_t) spsr;
  136. SET_PARAM_HEAD(&ep, PARAM_EP, VERSION_1,
  137. ((unsigned int) ((endianness != 0U) ? EP_EE_BIG :
  138. EP_EE_LITTLE)
  139. | NON_SECURE | EP_ST_DISABLE));
  140. /*
  141. * Re-initialize the system register context, and exit EL3 as if for the
  142. * first time. State switch is effectively a soft reset of the
  143. * calling EL.
  144. */
  145. cm_init_my_context(&ep);
  146. cm_prepare_el3_exit_ns();
  147. /*
  148. * State switch success. The caller of SMC wouldn't see the SMC
  149. * returning. Instead, execution starts at the supplied entry point,
  150. * with context pointers populated in registers 0 and 1.
  151. */
  152. SMC_RET2(handle, cookie_hi, cookie_lo);
  153. invalid_param:
  154. SMC_RET1(handle, STATE_SW_E_PARAM);
  155. exec_denied:
  156. /* State switch denied */
  157. SMC_RET1(handle, STATE_SW_E_DENIED);
  158. }