blob: b982bf90a1a86b6cf7401cd457a86e4475b4610b [file] [log] [blame]
Andrew Scull18c78fc2018-08-20 12:57:41 +01001#include "hf/api.h"
2#include "hf/cpu.h"
3#include "hf/dlog.h"
4#include "hf/vm.h"
5
Andrew Scullf35a5c92018-08-07 18:09:46 +01006#include "vmapi/hf/call.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +01007
8#include "msr.h"
Andrew Scull18c78fc2018-08-20 12:57:41 +01009#include "psci.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010010
11struct hvc_handler_return {
Andrew Scullc0e569a2018-10-02 18:05:21 +010012 uint64_t user_ret;
Wedson Almeida Filho87009642018-07-02 10:20:07 +010013 struct vcpu *new;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010014};
15
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +010016int32_t smc(size_t arg0, size_t arg1, size_t arg2, size_t arg3);
17void cpu_entry(struct cpu *c);
18
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010019void irq_current(void)
20{
21 dlog("IRQ from current\n");
Andrew Scull7364a8e2018-07-19 15:39:29 +010022 for (;;) {
23 /* do nothing */
24 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010025}
26
27void sync_current_exception(uint64_t esr, uint64_t elr)
28{
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010029 switch (esr >> 26) {
30 case 0x25: /* EC = 100101, Data abort. */
Andrew Scull4f170f52018-07-19 12:58:20 +010031 dlog("Data abort: pc=0x%x, esr=0x%x, ec=0x%x", elr, esr,
32 esr >> 26);
Andrew Scull7364a8e2018-07-19 15:39:29 +010033 if (!(esr & (1u << 10))) { /* Check FnV bit. */
Andrew Scull4f170f52018-07-19 12:58:20 +010034 dlog(", far=0x%x, hpfar=0x%x", read_msr(far_el2),
35 read_msr(hpfar_el2) << 8);
Andrew Scull7364a8e2018-07-19 15:39:29 +010036 } else {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010037 dlog(", far=invalid");
Andrew Scull7364a8e2018-07-19 15:39:29 +010038 }
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010039
40 dlog("\n");
Andrew Scull7364a8e2018-07-19 15:39:29 +010041 for (;;) {
42 /* do nothing */
43 }
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010044
45 default:
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +010046 dlog("Unknown current sync exception pc=0x%x, esr=0x%x, "
47 "ec=0x%x\n",
48 elr, esr, esr >> 26);
Andrew Scull7364a8e2018-07-19 15:39:29 +010049 for (;;) {
50 /* do nothing */
51 }
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010052 }
Andrew Scull7364a8e2018-07-19 15:39:29 +010053 for (;;) {
54 /* do nothing */
55 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010056}
57
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +010058/**
59 * Handles PSCI requests received via HVC or SMC instructions from the primary
60 * VM only.
61 *
62 * Returns true if the request was a PSCI one, false otherwise.
63 */
64static bool psci_handler(uint32_t func, size_t arg0, size_t arg1, size_t arg2,
Andrew Scullc0e569a2018-10-02 18:05:21 +010065 int32_t *ret)
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +010066{
67 struct cpu *c;
68 int32_t sret;
69
70 switch (func & ~PSCI_CONVENTION_MASK) {
71 case PSCI_VERSION:
72 /* Version is 0.2. */
73 *ret = 2;
74 break;
75
76 case PSCI_MIGRATE_INFO_TYPE:
77 /* Trusted OS does not require migration. */
78 *ret = 2;
79 break;
80
81 case PSCI_SYSTEM_OFF:
82 smc(PSCI_SYSTEM_OFF, 0, 0, 0);
83 for (;;) {
84 }
85 break;
86
87 case PSCI_SYSTEM_RESET:
88 smc(PSCI_SYSTEM_RESET, 0, 0, 0);
89 for (;;) {
90 }
91 break;
92
93 case PSCI_AFFINITY_INFO:
94 c = cpu_find(arg0);
95 if (!c) {
96 *ret = PSCI_RETURN_INVALID_PARAMETERS;
97 break;
98 }
99
100 if (arg1 != 0) {
101 *ret = PSCI_RETURN_NOT_SUPPORTED;
102 break;
103 }
104
105 sl_lock(&c->lock);
106 if (c->is_on) {
107 *ret = 0; /* ON */
108 } else {
109 *ret = 1; /* OFF */
110 }
111 sl_unlock(&c->lock);
112 break;
113
114 case PSCI_CPU_OFF:
115 cpu_off(cpu());
116 smc(PSCI_CPU_OFF, 0, 0, 0);
117 for (;;) {
118 }
119 break;
120
121 case PSCI_CPU_ON:
122 c = cpu_find(arg0);
123 if (!c) {
124 *ret = PSCI_RETURN_INVALID_PARAMETERS;
125 break;
126 }
127
Andrew Scull1b8d0442018-08-06 15:47:04 +0100128 if (cpu_on(c, ipa_init(arg1), arg2)) {
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100129 *ret = PSCI_RETURN_ALREADY_ON;
130 break;
131 }
132
133 /*
134 * There's a race when turning a CPU on when it's in the
135 * process of turning off. We need to loop here while it is
136 * reported that the CPU is on (because it's about to turn
137 * itself off).
138 */
139 do {
140 sret = smc(PSCI_CPU_ON, arg0, (size_t)&cpu_entry,
141 (size_t)c);
142 } while (sret == PSCI_RETURN_ALREADY_ON);
143
144 if (sret == PSCI_RETURN_SUCCESS) {
145 *ret = PSCI_RETURN_SUCCESS;
146 } else {
147 dlog("Unexpected return from PSCI_CPU_ON: 0x%x\n",
148 sret);
149 *ret = PSCI_RETURN_INTERNAL_FAILURE;
150 }
151 break;
152
153 default:
154 return false;
155 }
156
157 return true;
158}
159
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100160struct hvc_handler_return hvc_handler(size_t arg0, size_t arg1, size_t arg2,
161 size_t arg3)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100162{
163 struct hvc_handler_return ret;
164
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100165 ret.new = NULL;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100166
Andrew Scullc0e569a2018-10-02 18:05:21 +0100167 if (cpu()->current->vm->id == HF_PRIMARY_VM_ID) {
168 int32_t psci_ret;
169 if (psci_handler(arg0, arg1, arg2, arg3, &psci_ret)) {
170 ret.user_ret = psci_ret;
171 return ret;
172 }
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100173 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100174
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100175 switch ((uint32_t)arg0 & ~PSCI_CONVENTION_MASK) {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100176 case HF_VM_GET_COUNT:
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100177 ret.user_ret = api_vm_get_count();
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100178 break;
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100179
180 case HF_VCPU_GET_COUNT:
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100181 ret.user_ret = api_vcpu_get_count(arg1);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100182 break;
183
184 case HF_VCPU_RUN:
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100185 ret.user_ret = api_vcpu_run(arg1, arg2, &ret.new);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100186 break;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100187
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100188 case HF_VM_CONFIGURE:
Andrew Scull265ada92018-07-30 15:19:01 +0100189 ret.user_ret = api_vm_configure(ipa_init(arg1), ipa_init(arg2));
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100190 break;
191
192 case HF_RPC_REQUEST:
193 ret.user_ret = api_rpc_request(arg1, arg2);
194 break;
195
196 case HF_RPC_READ_REQUEST:
197 ret.user_ret = api_rpc_read_request(arg1, &ret.new);
198 break;
199
200 case HF_RPC_ACK:
201 ret.user_ret = api_rpc_ack();
202 break;
203
204 case HF_RPC_REPLY:
205 ret.user_ret = api_rpc_reply(arg1, arg2, &ret.new);
206 break;
207
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100208 default:
209 ret.user_ret = -1;
210 }
211
212 return ret;
213}
214
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100215struct vcpu *irq_lower(void)
216{
217 /* TODO: Only switch if we know the interrupt was not for the secondary
218 * VM. */
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100219 /* Switch back to primary VM, interrupts will be handled there. */
Andrew Scull6bca35e2018-10-02 12:05:32 +0100220 return api_yield();
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100221}
222
223struct vcpu *sync_lower_exception(uint64_t esr)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100224{
225 struct cpu *c = cpu();
226 struct vcpu *vcpu = c->current;
Andrew Scullc0e569a2018-10-02 18:05:21 +0100227 int32_t ret;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100228
229 switch (esr >> 26) {
230 case 0x01: /* EC = 000001, WFI or WFE. */
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100231 /* Check TI bit of ISS, 0 = WFI, 1 = WFE. */
Andrew Scull7364a8e2018-07-19 15:39:29 +0100232 if (esr & 1) {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100233 return NULL;
Andrew Scull7364a8e2018-07-19 15:39:29 +0100234 }
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100235 return api_wait_for_interrupt();
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100236
237 case 0x24: /* EC = 100100, Data abort. */
Andrew Scull4f170f52018-07-19 12:58:20 +0100238 dlog("Data abort: pc=0x%x, esr=0x%x, ec=0x%x", vcpu->regs.pc,
239 esr, esr >> 26);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100240 if (!(esr & (1u << 10))) { /* Check FnV bit. */
Andrew Scull4f170f52018-07-19 12:58:20 +0100241 dlog(", far=0x%x, hpfar=0x%x", read_msr(far_el2),
242 read_msr(hpfar_el2) << 8);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100243 } else {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100244 dlog(", far=invalid");
Andrew Scull7364a8e2018-07-19 15:39:29 +0100245 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100246
247 dlog("\n");
Andrew Scull7364a8e2018-07-19 15:39:29 +0100248 for (;;) {
249 /* do nothing */
250 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100251
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100252 case 0x20: /* EC = 100000, Instruction abort. */
253 dlog("Instruction abort: pc=0x%x, esr=0x%x, ec=0x%x",
254 vcpu->regs.pc, esr, esr >> 26);
255 if (!(esr & (1u << 10))) { /* Check FnV bit. */
256 dlog(", far=0x%x, hpfar=0x%x", read_msr(far_el2),
257 read_msr(hpfar_el2) << 8);
258 } else {
259 dlog(", far=invalid");
260 }
261
262 dlog(", vttbr_el2=0x%x", read_msr(vttbr_el2));
263 dlog("\n");
264 for (;;) {
265 /* do nothing */
266 }
267
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100268 case 0x17: /* EC = 010111, SMC instruction. */
Andrew Scull19503262018-09-20 14:48:39 +0100269 if (vcpu->vm->id != HF_PRIMARY_VM_ID ||
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100270 !psci_handler(vcpu->regs.r[0], vcpu->regs.r[1],
271 vcpu->regs.r[2], vcpu->regs.r[3], &ret)) {
272 dlog("Unsupported SMC call: 0x%x\n", vcpu->regs.r[0]);
273 ret = -1;
274 }
275
276 /* Skip the SMC instruction. */
277 vcpu->regs.pc += (esr & (1u << 25)) ? 4 : 2;
278 break;
279
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100280 default:
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100281 dlog("Unknown lower sync exception pc=0x%x, esr=0x%x, "
282 "ec=0x%x\n",
Andrew Scull4f170f52018-07-19 12:58:20 +0100283 vcpu->regs.pc, esr, esr >> 26);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100284 for (;;) {
285 /* do nothing */
286 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100287 }
288
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100289 vcpu->regs.r[0] = ret;
290
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100291 return NULL;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100292}