blob: 88aaf38710b5646a2c2fe8cc88e06c2e11a7df76 [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 {
Wedson Almeida Filho87009642018-07-02 10:20:07 +010012 long user_ret;
13 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,
65 long *ret)
66{
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 Scull19503262018-09-20 14:48:39 +0100167 if (cpu()->current->vm->id == HF_PRIMARY_VM_ID &&
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100168 psci_handler(arg0, arg1, arg2, arg3, &ret.user_ret)) {
169 return ret;
170 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100171
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100172 switch ((uint32_t)arg0 & ~PSCI_CONVENTION_MASK) {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100173 case HF_VM_GET_COUNT:
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100174 ret.user_ret = api_vm_get_count();
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100175 break;
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100176
177 case HF_VCPU_GET_COUNT:
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100178 ret.user_ret = api_vcpu_get_count(arg1);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100179 break;
180
181 case HF_VCPU_RUN:
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100182 ret.user_ret = api_vcpu_run(arg1, arg2, &ret.new);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100183 break;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100184
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100185 case HF_VM_CONFIGURE:
Andrew Scull265ada92018-07-30 15:19:01 +0100186 ret.user_ret = api_vm_configure(ipa_init(arg1), ipa_init(arg2));
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100187 break;
188
189 case HF_RPC_REQUEST:
190 ret.user_ret = api_rpc_request(arg1, arg2);
191 break;
192
193 case HF_RPC_READ_REQUEST:
194 ret.user_ret = api_rpc_read_request(arg1, &ret.new);
195 break;
196
197 case HF_RPC_ACK:
198 ret.user_ret = api_rpc_ack();
199 break;
200
201 case HF_RPC_REPLY:
202 ret.user_ret = api_rpc_reply(arg1, arg2, &ret.new);
203 break;
204
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100205 default:
206 ret.user_ret = -1;
207 }
208
209 return ret;
210}
211
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100212struct vcpu *irq_lower(void)
213{
214 /* TODO: Only switch if we know the interrupt was not for the secondary
215 * VM. */
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100216 /* Switch back to primary VM, interrupts will be handled there. */
Andrew Scull6bca35e2018-10-02 12:05:32 +0100217 return api_yield();
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100218}
219
220struct vcpu *sync_lower_exception(uint64_t esr)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100221{
222 struct cpu *c = cpu();
223 struct vcpu *vcpu = c->current;
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100224 long ret;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100225
226 switch (esr >> 26) {
227 case 0x01: /* EC = 000001, WFI or WFE. */
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100228 /* Check TI bit of ISS, 0 = WFI, 1 = WFE. */
Andrew Scull7364a8e2018-07-19 15:39:29 +0100229 if (esr & 1) {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100230 return NULL;
Andrew Scull7364a8e2018-07-19 15:39:29 +0100231 }
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100232 return api_wait_for_interrupt();
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100233
234 case 0x24: /* EC = 100100, Data abort. */
Andrew Scull4f170f52018-07-19 12:58:20 +0100235 dlog("Data abort: pc=0x%x, esr=0x%x, ec=0x%x", vcpu->regs.pc,
236 esr, esr >> 26);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100237 if (!(esr & (1u << 10))) { /* Check FnV bit. */
Andrew Scull4f170f52018-07-19 12:58:20 +0100238 dlog(", far=0x%x, hpfar=0x%x", read_msr(far_el2),
239 read_msr(hpfar_el2) << 8);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100240 } else {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100241 dlog(", far=invalid");
Andrew Scull7364a8e2018-07-19 15:39:29 +0100242 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100243
244 dlog("\n");
Andrew Scull7364a8e2018-07-19 15:39:29 +0100245 for (;;) {
246 /* do nothing */
247 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100248
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100249 case 0x20: /* EC = 100000, Instruction abort. */
250 dlog("Instruction abort: pc=0x%x, esr=0x%x, ec=0x%x",
251 vcpu->regs.pc, esr, esr >> 26);
252 if (!(esr & (1u << 10))) { /* Check FnV bit. */
253 dlog(", far=0x%x, hpfar=0x%x", read_msr(far_el2),
254 read_msr(hpfar_el2) << 8);
255 } else {
256 dlog(", far=invalid");
257 }
258
259 dlog(", vttbr_el2=0x%x", read_msr(vttbr_el2));
260 dlog("\n");
261 for (;;) {
262 /* do nothing */
263 }
264
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100265 case 0x17: /* EC = 010111, SMC instruction. */
Andrew Scull19503262018-09-20 14:48:39 +0100266 if (vcpu->vm->id != HF_PRIMARY_VM_ID ||
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100267 !psci_handler(vcpu->regs.r[0], vcpu->regs.r[1],
268 vcpu->regs.r[2], vcpu->regs.r[3], &ret)) {
269 dlog("Unsupported SMC call: 0x%x\n", vcpu->regs.r[0]);
270 ret = -1;
271 }
272
273 /* Skip the SMC instruction. */
274 vcpu->regs.pc += (esr & (1u << 25)) ? 4 : 2;
275 break;
276
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100277 default:
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100278 dlog("Unknown lower sync exception pc=0x%x, esr=0x%x, "
279 "ec=0x%x\n",
Andrew Scull4f170f52018-07-19 12:58:20 +0100280 vcpu->regs.pc, esr, esr >> 26);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100281 for (;;) {
282 /* do nothing */
283 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100284 }
285
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100286 vcpu->regs.r[0] = ret;
287
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100288 return NULL;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100289}