blob: 83b4b0165cf58387b49c0cc8e013c50df5d56fe1 [file] [log] [blame]
Andrew Scull18834872018-10-12 11:48:09 +01001/*
2 * Copyright 2018 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Andrew Scull18c78fc2018-08-20 12:57:41 +010017#include "hf/api.h"
18#include "hf/cpu.h"
19#include "hf/dlog.h"
20#include "hf/vm.h"
21
Andrew Scullf35a5c92018-08-07 18:09:46 +010022#include "vmapi/hf/call.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010023
24#include "msr.h"
Andrew Scull18c78fc2018-08-20 12:57:41 +010025#include "psci.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010026
27struct hvc_handler_return {
Andrew Scull37402872018-10-24 14:23:06 +010028 uintreg_t user_ret;
Wedson Almeida Filho87009642018-07-02 10:20:07 +010029 struct vcpu *new;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010030};
31
Andrew Scull37402872018-10-24 14:23:06 +010032int32_t smc(uintreg_t arg0, uintreg_t arg1, uintreg_t arg2, uintreg_t arg3);
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +010033void cpu_entry(struct cpu *c);
34
Wedson Almeida Filho00df6c72018-10-18 11:19:24 +010035static struct vcpu *current(void)
36{
37 return (struct vcpu *)read_msr(tpidr_el2);
38}
39
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010040void irq_current(void)
41{
42 dlog("IRQ from current\n");
Andrew Scull7364a8e2018-07-19 15:39:29 +010043 for (;;) {
44 /* do nothing */
45 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010046}
47
Andrew Scull37402872018-10-24 14:23:06 +010048void sync_current_exception(uintreg_t esr, uintreg_t elr)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010049{
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010050 switch (esr >> 26) {
51 case 0x25: /* EC = 100101, Data abort. */
Andrew Scull4f170f52018-07-19 12:58:20 +010052 dlog("Data abort: pc=0x%x, esr=0x%x, ec=0x%x", elr, esr,
53 esr >> 26);
Andrew Scull7364a8e2018-07-19 15:39:29 +010054 if (!(esr & (1u << 10))) { /* Check FnV bit. */
Andrew Scull0a029e82018-11-23 16:48:08 +000055 dlog(", far=0x%x", read_msr(far_el2));
Andrew Scull7364a8e2018-07-19 15:39:29 +010056 } else {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010057 dlog(", far=invalid");
Andrew Scull7364a8e2018-07-19 15:39:29 +010058 }
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010059
60 dlog("\n");
Andrew Scull7364a8e2018-07-19 15:39:29 +010061 for (;;) {
62 /* do nothing */
63 }
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010064
65 default:
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +010066 dlog("Unknown current sync exception pc=0x%x, esr=0x%x, "
67 "ec=0x%x\n",
68 elr, esr, esr >> 26);
Andrew Scull7364a8e2018-07-19 15:39:29 +010069 for (;;) {
70 /* do nothing */
71 }
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010072 }
Andrew Scull7364a8e2018-07-19 15:39:29 +010073 for (;;) {
74 /* do nothing */
75 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010076}
77
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +010078/**
79 * Handles PSCI requests received via HVC or SMC instructions from the primary
80 * VM only.
81 *
82 * Returns true if the request was a PSCI one, false otherwise.
83 */
Andrew Scull37402872018-10-24 14:23:06 +010084static bool psci_handler(uint32_t func, uintreg_t arg0, uintreg_t arg1,
85 uintreg_t arg2, int32_t *ret)
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +010086{
87 struct cpu *c;
88 int32_t sret;
89
90 switch (func & ~PSCI_CONVENTION_MASK) {
91 case PSCI_VERSION:
92 /* Version is 0.2. */
93 *ret = 2;
94 break;
95
96 case PSCI_MIGRATE_INFO_TYPE:
97 /* Trusted OS does not require migration. */
98 *ret = 2;
99 break;
100
101 case PSCI_SYSTEM_OFF:
102 smc(PSCI_SYSTEM_OFF, 0, 0, 0);
103 for (;;) {
104 }
105 break;
106
107 case PSCI_SYSTEM_RESET:
108 smc(PSCI_SYSTEM_RESET, 0, 0, 0);
109 for (;;) {
110 }
111 break;
112
113 case PSCI_AFFINITY_INFO:
114 c = cpu_find(arg0);
115 if (!c) {
116 *ret = PSCI_RETURN_INVALID_PARAMETERS;
117 break;
118 }
119
120 if (arg1 != 0) {
121 *ret = PSCI_RETURN_NOT_SUPPORTED;
122 break;
123 }
124
125 sl_lock(&c->lock);
126 if (c->is_on) {
127 *ret = 0; /* ON */
128 } else {
129 *ret = 1; /* OFF */
130 }
131 sl_unlock(&c->lock);
132 break;
133
134 case PSCI_CPU_OFF:
Wedson Almeida Filho00df6c72018-10-18 11:19:24 +0100135 cpu_off(current()->cpu);
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100136 smc(PSCI_CPU_OFF, 0, 0, 0);
137 for (;;) {
138 }
139 break;
140
141 case PSCI_CPU_ON:
142 c = cpu_find(arg0);
143 if (!c) {
144 *ret = PSCI_RETURN_INVALID_PARAMETERS;
145 break;
146 }
147
Andrew Scull1b8d0442018-08-06 15:47:04 +0100148 if (cpu_on(c, ipa_init(arg1), arg2)) {
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100149 *ret = PSCI_RETURN_ALREADY_ON;
150 break;
151 }
152
153 /*
154 * There's a race when turning a CPU on when it's in the
155 * process of turning off. We need to loop here while it is
156 * reported that the CPU is on (because it's about to turn
157 * itself off).
158 */
159 do {
Andrew Scull37402872018-10-24 14:23:06 +0100160 sret = smc(PSCI_CPU_ON, arg0, (uintreg_t)&cpu_entry,
161 (uintreg_t)c);
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100162 } while (sret == PSCI_RETURN_ALREADY_ON);
163
164 if (sret == PSCI_RETURN_SUCCESS) {
165 *ret = PSCI_RETURN_SUCCESS;
166 } else {
167 dlog("Unexpected return from PSCI_CPU_ON: 0x%x\n",
168 sret);
169 *ret = PSCI_RETURN_INTERNAL_FAILURE;
170 }
171 break;
172
173 default:
174 return false;
175 }
176
177 return true;
178}
179
Andrew Scull37402872018-10-24 14:23:06 +0100180struct hvc_handler_return hvc_handler(uintreg_t arg0, uintreg_t arg1,
181 uintreg_t arg2, uintreg_t arg3)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100182{
183 struct hvc_handler_return ret;
184
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100185 ret.new = NULL;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100186
Wedson Almeida Filho00df6c72018-10-18 11:19:24 +0100187 if (current()->vm->id == HF_PRIMARY_VM_ID) {
Andrew Scullc0e569a2018-10-02 18:05:21 +0100188 int32_t psci_ret;
189 if (psci_handler(arg0, arg1, arg2, arg3, &psci_ret)) {
190 ret.user_ret = psci_ret;
191 return ret;
192 }
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100193 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100194
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100195 switch ((uint32_t)arg0 & ~PSCI_CONVENTION_MASK) {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100196 case HF_VM_GET_COUNT:
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100197 ret.user_ret = api_vm_get_count();
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100198 break;
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100199
200 case HF_VCPU_GET_COUNT:
Wedson Almeida Filho00df6c72018-10-18 11:19:24 +0100201 ret.user_ret = api_vcpu_get_count(arg1, current());
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100202 break;
203
204 case HF_VCPU_RUN:
Andrew Scull6d2db332018-10-10 15:28:17 +0100205 ret.user_ret = hf_vcpu_run_return_encode(
Wedson Almeida Filho00df6c72018-10-18 11:19:24 +0100206 api_vcpu_run(arg1, arg2, current(), &ret.new));
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100207 break;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100208
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100209 case HF_VM_CONFIGURE:
Wedson Almeida Filho00df6c72018-10-18 11:19:24 +0100210 ret.user_ret = api_vm_configure(ipa_init(arg1), ipa_init(arg2),
211 current());
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100212 break;
213
Andrew Scullaa039b32018-10-04 15:02:26 +0100214 case HF_MAILBOX_SEND:
Wedson Almeida Filho00df6c72018-10-18 11:19:24 +0100215 ret.user_ret =
216 api_mailbox_send(arg1, arg2, current(), &ret.new);
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100217 break;
218
Andrew Scullaa039b32018-10-04 15:02:26 +0100219 case HF_MAILBOX_RECEIVE:
Andrew Scull6d2db332018-10-10 15:28:17 +0100220 ret.user_ret = hf_mailbox_receive_return_encode(
Wedson Almeida Filho00df6c72018-10-18 11:19:24 +0100221 api_mailbox_receive(arg1, current(), &ret.new));
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100222 break;
223
Andrew Scullaa039b32018-10-04 15:02:26 +0100224 case HF_MAILBOX_CLEAR:
Wedson Almeida Filho00df6c72018-10-18 11:19:24 +0100225 ret.user_ret = api_mailbox_clear(current());
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100226 break;
227
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100228 default:
229 ret.user_ret = -1;
230 }
231
232 return ret;
233}
234
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100235struct vcpu *irq_lower(void)
236{
237 /* TODO: Only switch if we know the interrupt was not for the secondary
238 * VM. */
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100239 /* Switch back to primary VM, interrupts will be handled there. */
Wedson Almeida Filho00df6c72018-10-18 11:19:24 +0100240 return api_yield(current());
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100241}
242
Andrew Scull37402872018-10-24 14:23:06 +0100243struct vcpu *sync_lower_exception(uintreg_t esr)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100244{
Wedson Almeida Filho00df6c72018-10-18 11:19:24 +0100245 struct vcpu *vcpu = current();
Andrew Scullc0e569a2018-10-02 18:05:21 +0100246 int32_t ret;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100247
248 switch (esr >> 26) {
249 case 0x01: /* EC = 000001, WFI or WFE. */
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100250 /* Check TI bit of ISS, 0 = WFI, 1 = WFE. */
Andrew Scull7364a8e2018-07-19 15:39:29 +0100251 if (esr & 1) {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100252 return NULL;
Andrew Scull7364a8e2018-07-19 15:39:29 +0100253 }
Wedson Almeida Filho00df6c72018-10-18 11:19:24 +0100254 return api_wait_for_interrupt(current());
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100255
256 case 0x24: /* EC = 100100, Data abort. */
Andrew Scull4f170f52018-07-19 12:58:20 +0100257 dlog("Data abort: pc=0x%x, esr=0x%x, ec=0x%x", vcpu->regs.pc,
258 esr, esr >> 26);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100259 if (!(esr & (1u << 10))) { /* Check FnV bit. */
Andrew Scull4f170f52018-07-19 12:58:20 +0100260 dlog(", far=0x%x, hpfar=0x%x", read_msr(far_el2),
261 read_msr(hpfar_el2) << 8);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100262 } else {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100263 dlog(", far=invalid");
Andrew Scull7364a8e2018-07-19 15:39:29 +0100264 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100265
266 dlog("\n");
Andrew Scull7364a8e2018-07-19 15:39:29 +0100267 for (;;) {
268 /* do nothing */
269 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100270
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100271 case 0x20: /* EC = 100000, Instruction abort. */
272 dlog("Instruction abort: pc=0x%x, esr=0x%x, ec=0x%x",
273 vcpu->regs.pc, esr, esr >> 26);
274 if (!(esr & (1u << 10))) { /* Check FnV bit. */
275 dlog(", far=0x%x, hpfar=0x%x", read_msr(far_el2),
276 read_msr(hpfar_el2) << 8);
277 } else {
278 dlog(", far=invalid");
279 }
280
281 dlog(", vttbr_el2=0x%x", read_msr(vttbr_el2));
282 dlog("\n");
283 for (;;) {
284 /* do nothing */
285 }
286
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100287 case 0x17: /* EC = 010111, SMC instruction. */
Andrew Scull19503262018-09-20 14:48:39 +0100288 if (vcpu->vm->id != HF_PRIMARY_VM_ID ||
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100289 !psci_handler(vcpu->regs.r[0], vcpu->regs.r[1],
290 vcpu->regs.r[2], vcpu->regs.r[3], &ret)) {
291 dlog("Unsupported SMC call: 0x%x\n", vcpu->regs.r[0]);
292 ret = -1;
293 }
294
295 /* Skip the SMC instruction. */
296 vcpu->regs.pc += (esr & (1u << 25)) ? 4 : 2;
297 break;
298
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100299 default:
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100300 dlog("Unknown lower sync exception pc=0x%x, esr=0x%x, "
301 "ec=0x%x\n",
Andrew Scull4f170f52018-07-19 12:58:20 +0100302 vcpu->regs.pc, esr, esr >> 26);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100303 for (;;) {
304 /* do nothing */
305 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100306 }
307
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100308 vcpu->regs.r[0] = ret;
309
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100310 return NULL;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100311}