blob: 5068cdfcb762afca3312288ed4ba735716e36bcb [file] [log] [blame]
Jeenu Viswambharanbc1a9292017-02-16 14:55:15 +00001/*
2 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <arch_helpers.h>
32#include <arm_sip_svc.h>
33#include <context.h>
34#include <context_mgmt.h>
35#include <plat_arm.h>
36#include <psci.h>
37#include <smcc_helpers.h>
38#include <string.h>
39#include <utils.h>
40
41/*
42 * Handle SMC from a lower exception level to switch its execution state
43 * (either from AArch64 to AArch32, or vice versa).
44 *
45 * smc_fid:
46 * SMC function ID - either ARM_SIP_SVC_STATE_SWITCH_64 or
47 * ARM_SIP_SVC_STATE_SWITCH_32.
48 * pc_hi, pc_lo:
49 * PC upon re-entry to the calling exception level; width dependent on the
50 * calling exception level.
51 * cookie_hi, cookie_lo:
52 * Opaque pointer pairs received from the caller to pass it back, upon
53 * re-entry.
54 * handle:
55 * Handle to saved context.
56 */
57int arm_execution_state_switch(unsigned int smc_fid,
58 uint32_t pc_hi,
59 uint32_t pc_lo,
60 uint32_t cookie_hi,
61 uint32_t cookie_lo,
62 void *handle)
63{
64 /* Execution state can be switched only if EL3 is AArch64 */
65#ifdef AARCH64
66 int caller_64, from_el2, el, endianness, thumb = 0;
67 u_register_t spsr, pc, scr, sctlr;
68 entry_point_info_t ep;
69 cpu_context_t *ctx = (cpu_context_t *) handle;
70 el3_state_t *el3_ctx = get_el3state_ctx(ctx);
71
72 /* That the SMC originated from NS is already validated by the caller */
73
74 /*
75 * Disallow state switch if any of the secondaries have been brought up.
76 */
77 if (psci_secondaries_brought_up())
78 goto exec_denied;
79
80 spsr = read_ctx_reg(el3_ctx, CTX_SPSR_EL3);
81 caller_64 = (GET_RW(spsr) == MODE_RW_64);
82
83 if (caller_64) {
84 /*
85 * If the call originated from AArch64, expect 32-bit pointers when
86 * switching to AArch32.
87 */
88 if ((pc_hi != 0) || (cookie_hi != 0))
89 goto invalid_param;
90
91 pc = pc_lo;
92
93 /* Instruction state when entering AArch32 */
94 thumb = pc & 1;
95 } else {
96 /* Construct AArch64 PC */
97 pc = (((u_register_t) pc_hi) << 32) | pc_lo;
98 }
99
100 /* Make sure PC is 4-byte aligned, except for Thumb */
101 if ((pc & 0x3) && !thumb)
102 goto invalid_param;
103
104 /*
105 * EL3 controls register width of the immediate lower EL only. Expect
106 * this request from EL2/Hyp unless:
107 *
108 * - EL2 is not implemented;
109 * - EL2 is implemented, but was disabled. This can be inferred from
110 * SCR_EL3.HCE.
111 */
112 from_el2 = caller_64 ? (GET_EL(spsr) == MODE_EL2) :
113 (GET_M32(spsr) == MODE32_hyp);
114 scr = read_ctx_reg(el3_ctx, CTX_SCR_EL3);
115 if (!from_el2) {
116 /* The call is from NS privilege level other than HYP */
117
118 /*
119 * Disallow switching state if there's a Hypervisor in place;
120 * this request must be taken up with the Hypervisor instead.
121 */
122 if (scr & SCR_HCE_BIT)
123 goto exec_denied;
124 }
125
126 /*
127 * Return to the caller using the same endianness. Extract
128 * endianness bit from the respective system control register
129 * directly.
130 */
131 sctlr = from_el2 ? read_sctlr_el2() : read_sctlr_el1();
132 endianness = !!(sctlr & SCTLR_EE_BIT);
133
134 /* Construct SPSR for the exception state we're about to switch to */
135 if (caller_64) {
136 int impl;
137
138 /*
139 * Switching from AArch64 to AArch32. Ensure this CPU implements
140 * the target EL in AArch32.
141 */
142 impl = from_el2 ? EL_IMPLEMENTED(2) : EL_IMPLEMENTED(1);
143 if (impl != EL_IMPL_A64_A32)
144 goto exec_denied;
145
146 /* Return to the equivalent AArch32 privilege level */
147 el = from_el2 ? MODE32_hyp : MODE32_svc;
148 spsr = SPSR_MODE32(el, thumb ? SPSR_T_THUMB : SPSR_T_ARM,
149 endianness, DISABLE_ALL_EXCEPTIONS);
150 } else {
151 /*
152 * Switching from AArch32 to AArch64. Since it's not possible to
153 * implement an EL as AArch32-only (from which this call was
154 * raised), it's safe to assume AArch64 is also implemented.
155 */
156 el = from_el2 ? MODE_EL2 : MODE_EL1;
157 spsr = SPSR_64(el, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
158 }
159
160 /*
161 * Use the context management library to re-initialize the existing
162 * context with the execution state flipped. Since the library takes
163 * entry_point_info_t pointer as the argument, construct a dummy one
164 * with PC, state width, endianness, security etc. appropriately set.
165 * Other entries in the entry point structure are irrelevant for
166 * purpose.
167 */
168 zeromem(&ep, sizeof(ep));
169 ep.pc = pc;
170 ep.spsr = spsr;
171 SET_PARAM_HEAD(&ep, PARAM_EP, VERSION_1,
172 ((endianness ? EP_EE_BIG : EP_EE_LITTLE) | NON_SECURE |
173 EP_ST_DISABLE));
174
175 /*
176 * Re-initialize the system register context, and exit EL3 as if for the
177 * first time. State switch is effectively a soft reset of the
178 * calling EL.
179 */
180 cm_init_my_context(&ep);
181 cm_prepare_el3_exit(NON_SECURE);
182
183 /*
184 * State switch success. The caller of SMC wouldn't see the SMC
185 * returning. Instead, execution starts at the supplied entry point,
186 * with context pointers populated in registers 0 and 1.
187 */
188 SMC_RET2(handle, cookie_hi, cookie_lo);
189
190invalid_param:
191 SMC_RET1(handle, STATE_SW_E_PARAM);
192
193exec_denied:
194#endif
195 /* State switch denied */
196 SMC_RET1(handle, STATE_SW_E_DENIED);
197}