1/*
2 * Copyright 2018, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
8 * See "LICENSE_GPLv2.txt" for details.
9 *
10 * @TAG(DATA61_GPL)
11 */
12
13#ifndef __ARCH_ARMV_VCPU_H_
14#define __ARCH_ARMV_VCPU_H_
15
16#include <config.h>
17
18#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
19
20#include <arch/object/vcpu.h>
21
22/* Trap WFI/WFE/SMC and override CPSR.AIF */
23#define HCR_COMMON ( HCR_TSC | HCR_TWE | HCR_TWI | HCR_AMO | HCR_IMO \
24                   | HCR_FMO | HCR_DC  | HCR_VM)
25/* Allow native tasks to run at PL1, but restrict access */
26#define HCR_NATIVE ( HCR_COMMON | HCR_TGE | HCR_TVM | HCR_TTLB | HCR_TCACHE \
27                   | HCR_TAC | HCR_SWIO)
28#define HCR_VCPU   (HCR_COMMON)
29
30/* Amongst other things we set the caches to enabled by default. This
31 * may cause problems when booting guests that expect caches to be
32 * disabled */
33#define SCTLR_DEFAULT 0xc5187c
34#define ACTLR_DEFAULT 0x40
35
36static inline word_t
37get_lr_svc(void)
38{
39    word_t ret;
40    asm ("mrs %[ret], lr_svc" : [ret]"=r"(ret));
41    return ret;
42}
43
44static inline void
45set_lr_svc(word_t val)
46{
47    asm ("msr lr_svc, %[val]" :: [val]"r"(val));
48}
49
50static inline word_t
51get_sp_svc(void)
52{
53    word_t ret;
54    asm ("mrs %[ret], sp_svc" : [ret]"=r"(ret));
55    return ret;
56}
57
58static inline void
59set_sp_svc(word_t val)
60{
61    asm ("msr sp_svc, %[val]" :: [val]"r"(val));
62}
63
64static inline word_t
65get_spsr_svc(void)
66{
67    word_t ret;
68    asm ("mrs %[ret], spsr_svc" : [ret]"=r"(ret));
69    return ret;
70}
71
72static inline void
73set_spsr_svc(word_t val)
74{
75    asm ("msr spsr_svc, %[val]" :: [val]"r"(val));
76}
77
78static inline word_t
79get_lr_abt(void)
80{
81    word_t ret;
82    asm ("mrs %[ret], lr_abt" : [ret]"=r"(ret));
83    return ret;
84}
85
86static inline void
87set_lr_abt(word_t val)
88{
89    asm ("msr lr_abt, %[val]" :: [val]"r"(val));
90}
91
92static inline word_t
93get_sp_abt(void)
94{
95    word_t ret;
96    asm ("mrs %[ret], sp_abt" : [ret]"=r"(ret));
97    return ret;
98}
99
100static inline void
101set_sp_abt(word_t val)
102{
103    asm ("msr sp_abt, %[val]" :: [val]"r"(val));
104}
105
106static inline word_t
107get_spsr_abt(void)
108{
109    word_t ret;
110    asm ("mrs %[ret], spsr_abt" : [ret]"=r"(ret));
111    return ret;
112}
113
114static inline void
115set_spsr_abt(word_t val)
116{
117    asm ("msr spsr_abt, %[val]" :: [val]"r"(val));
118}
119
120static inline word_t
121get_lr_und(void)
122{
123    word_t ret;
124    asm ("mrs %[ret], lr_und" : [ret]"=r"(ret));
125    return ret;
126}
127
128static inline void
129set_lr_und(word_t val)
130{
131    asm ("msr lr_und, %[val]" :: [val]"r"(val));
132}
133
134static inline word_t
135get_sp_und(void)
136{
137    word_t ret;
138    asm ("mrs %[ret], sp_und" : [ret]"=r"(ret));
139    return ret;
140}
141
142static inline void
143set_sp_und(word_t val)
144{
145    asm ("msr sp_und, %[val]" :: [val]"r"(val));
146}
147
148static inline word_t
149get_spsr_und(void)
150{
151    word_t ret;
152    asm ("mrs %[ret], spsr_und" : [ret]"=r"(ret));
153    return ret;
154}
155
156static inline void
157set_spsr_und(word_t val)
158{
159    asm ("msr spsr_und, %[val]" :: [val]"r"(val));
160}
161
162static inline word_t
163get_lr_irq(void)
164{
165    word_t ret;
166    asm ("mrs %[ret], lr_irq" : [ret]"=r"(ret));
167    return ret;
168}
169
170static inline void
171set_lr_irq(word_t val)
172{
173    asm ("msr lr_irq, %[val]" :: [val]"r"(val));
174}
175
176static inline word_t
177get_sp_irq(void)
178{
179    word_t ret;
180    asm ("mrs %[ret], sp_irq" : [ret]"=r"(ret));
181    return ret;
182}
183
184static inline void
185set_sp_irq(word_t val)
186{
187    asm ("msr sp_irq, %[val]" :: [val]"r"(val));
188}
189
190static inline word_t
191get_spsr_irq(void)
192{
193    word_t ret;
194    asm ("mrs %[ret], spsr_irq" : [ret]"=r"(ret));
195    return ret;
196}
197
198static inline void
199set_spsr_irq(word_t val)
200{
201    asm ("msr spsr_irq, %[val]" :: [val]"r"(val));
202}
203
204static inline word_t
205get_lr_fiq(void)
206{
207    word_t ret;
208    asm ("mrs %[ret], lr_fiq" : [ret]"=r"(ret));
209    return ret;
210}
211
212static inline void
213set_lr_fiq(word_t val)
214{
215    asm ("msr lr_fiq, %[val]" :: [val]"r"(val));
216}
217
218static inline word_t
219get_sp_fiq(void)
220{
221    word_t ret;
222    asm ("mrs %[ret], sp_fiq" : [ret]"=r"(ret));
223    return ret;
224}
225
226static inline void
227set_sp_fiq(word_t val)
228{
229    asm ("msr sp_fiq, %[val]" :: [val]"r"(val));
230}
231
232static inline word_t
233get_spsr_fiq(void)
234{
235    word_t ret;
236    asm ("mrs %[ret], spsr_fiq" : [ret]"=r"(ret));
237    return ret;
238}
239
240static inline void
241set_spsr_fiq(word_t val)
242{
243    asm ("msr spsr_fiq, %[val]" :: [val]"r"(val));
244}
245
246static inline word_t
247get_r8_fiq(void)
248{
249    word_t ret;
250    asm ("mrs %[ret], r8_fiq" : [ret]"=r"(ret));
251    return ret;
252}
253
254static inline void
255set_r8_fiq(word_t val)
256{
257    asm ("msr r8_fiq, %[val]" :: [val]"r"(val));
258}
259
260static inline word_t
261get_r9_fiq(void)
262{
263    word_t ret;
264    asm ("mrs %[ret], r9_fiq" : [ret]"=r"(ret));
265    return ret;
266}
267
268static inline void
269set_r9_fiq(word_t val)
270{
271    asm ("msr r9_fiq, %[val]" :: [val]"r"(val));
272}
273
274static inline word_t
275get_r10_fiq(void)
276{
277    word_t ret;
278    asm ("mrs %[ret], r10_fiq" : [ret]"=r"(ret));
279    return ret;
280}
281
282static inline void
283set_r10_fiq(word_t val)
284{
285    asm ("msr r10_fiq, %[val]" :: [val]"r"(val));
286}
287
288static inline word_t
289get_r11_fiq(void)
290{
291    word_t ret;
292    asm ("mrs %[ret], r11_fiq" : [ret]"=r"(ret));
293    return ret;
294}
295
296static inline void
297set_r11_fiq(word_t val)
298{
299    asm ("msr r11_fiq, %[val]" :: [val]"r"(val));
300}
301
302static inline word_t
303get_r12_fiq(void)
304{
305    word_t ret;
306    asm ("mrs %[ret], r12_fiq" : [ret]"=r"(ret));
307    return ret;
308}
309
310static inline void
311set_r12_fiq(word_t val)
312{
313    asm ("msr r12_fiq, %[val]" :: [val]"r"(val));
314}
315static inline word_t
316get_cntv_tval(void)
317{
318    word_t ret = 0;
319    MRC(CNTV_TVAL, ret);
320    return ret;
321}
322
323static inline void
324set_cntv_tval(word_t val)
325{
326    MCR(CNTV_TVAL, val);
327}
328
329static inline word_t
330get_cntv_ctl(void)
331{
332    word_t ret = 0;
333    MRC(CNTV_CTL, ret);
334    return ret;
335}
336
337static inline void
338set_cntv_ctl(word_t val)
339{
340    MCR(CNTV_CTL, val);
341}
342
343
344static word_t
345vcpu_hw_read_reg(word_t reg_index)
346{
347    word_t reg = 0;
348    switch (reg_index) {
349    case seL4_VCPUReg_SCTLR:
350        return getSCTLR();
351    case seL4_VCPUReg_ACTLR:
352        return getACTLR();
353    case seL4_VCPUReg_TTBCR:
354        return readTTBCR();
355    case seL4_VCPUReg_TTBR0:
356        return readTTBR0();
357    case seL4_VCPUReg_TTBR1:
358        return readTTBR1();
359    case seL4_VCPUReg_DACR:
360        return readDACR();
361    case seL4_VCPUReg_DFSR:
362        return getDFSR();
363    case seL4_VCPUReg_IFSR:
364        return getIFSR();
365    case seL4_VCPUReg_ADFSR:
366        return getADFSR();
367    case seL4_VCPUReg_AIFSR:
368        return getAIFSR();
369    case seL4_VCPUReg_DFAR:
370        return getDFAR();
371    case seL4_VCPUReg_IFAR:
372        return getIFAR();
373    case seL4_VCPUReg_PRRR:
374        return getPRRR();
375    case seL4_VCPUReg_NMRR:
376        return getNMRR();
377    case seL4_VCPUReg_CIDR:
378        return getCIDR();
379    case seL4_VCPUReg_TPIDRPRW:
380        return readTPIDRPRW();
381    case seL4_VCPUReg_FPEXC:
382        return reg;
383    case seL4_VCPUReg_CNTV_TVAL:
384        return get_cntv_tval();
385    case seL4_VCPUReg_CNTV_CTL:
386        return get_cntv_ctl();
387    case seL4_VCPUReg_LRsvc:
388        return get_lr_svc();
389    case seL4_VCPUReg_SPsvc:
390        return get_sp_svc();
391    case seL4_VCPUReg_LRabt:
392        return get_lr_abt();
393    case seL4_VCPUReg_SPabt:
394        return get_sp_abt();
395    case seL4_VCPUReg_LRund:
396        return get_lr_und();
397    case seL4_VCPUReg_SPund:
398        return get_sp_und();
399    case seL4_VCPUReg_LRirq:
400        return get_lr_irq();
401    case seL4_VCPUReg_SPirq:
402        return get_sp_irq();
403    case seL4_VCPUReg_LRfiq:
404        return get_lr_fiq();
405    case seL4_VCPUReg_SPfiq:
406        return get_sp_fiq();
407    case seL4_VCPUReg_R8fiq:
408        return get_r8_fiq();
409    case seL4_VCPUReg_R9fiq:
410        return get_r9_fiq();
411    case seL4_VCPUReg_R10fiq:
412        return get_r10_fiq();
413    case seL4_VCPUReg_R11fiq:
414        return get_r11_fiq();
415    case seL4_VCPUReg_R12fiq:
416        return get_r12_fiq();
417    case seL4_VCPUReg_SPSRsvc:
418        return get_spsr_svc();
419    case seL4_VCPUReg_SPSRabt:
420        return get_spsr_abt();
421    case seL4_VCPUReg_SPSRund:
422        return get_spsr_und();
423    case seL4_VCPUReg_SPSRirq:
424        return get_spsr_irq();
425    case seL4_VCPUReg_SPSRfiq:
426        return get_spsr_fiq();
427    default:
428        fail("ARM/HYP: Invalid register index");
429    }
430}
431
432static void
433vcpu_hw_write_reg(word_t reg_index, word_t reg)
434{
435    switch (reg_index) {
436    case seL4_VCPUReg_SCTLR:
437        setSCTLR(reg);
438        break;
439    case seL4_VCPUReg_ACTLR:
440        setACTLR(reg);
441        break;
442    case seL4_VCPUReg_TTBCR:
443        writeTTBCR(reg);
444        break;
445    case seL4_VCPUReg_TTBR0:
446        writeTTBR0(reg);
447        break;
448    case seL4_VCPUReg_TTBR1:
449        writeTTBR1(reg);
450        break;
451    case seL4_VCPUReg_DACR:
452        writeDACR(reg);
453        break;
454    case seL4_VCPUReg_DFSR:
455        setDFSR(reg);
456        break;
457    case seL4_VCPUReg_IFSR:
458        setIFSR(reg);
459        break;
460    case seL4_VCPUReg_ADFSR:
461        setADFSR(reg);
462        break;
463    case seL4_VCPUReg_AIFSR:
464        setAIFSR(reg);
465        break;
466    case seL4_VCPUReg_DFAR:
467        setDFAR(reg);
468        break;
469    case seL4_VCPUReg_IFAR:
470        setIFAR(reg);
471        break;
472    case seL4_VCPUReg_PRRR:
473        setPRRR(reg);
474        break;
475    case seL4_VCPUReg_NMRR:
476        setNMRR(reg);
477        break;
478    case seL4_VCPUReg_CIDR:
479        setCIDR(reg);
480        break;
481    case seL4_VCPUReg_TPIDRPRW:
482        writeTPIDRPRW(reg);
483        break;
484    case seL4_VCPUReg_FPEXC:
485        break;
486    case seL4_VCPUReg_CNTV_TVAL:
487        set_cntv_tval(reg);
488        break;
489    case seL4_VCPUReg_CNTV_CTL:
490        set_cntv_ctl(reg);
491        break;
492    case seL4_VCPUReg_LRsvc:
493        set_lr_svc(reg);
494        break;
495    case seL4_VCPUReg_SPsvc:
496        set_sp_svc(reg);
497        break;
498    case seL4_VCPUReg_LRabt:
499        set_lr_abt(reg);
500        break;
501    case seL4_VCPUReg_SPabt:
502        set_sp_abt(reg);
503        break;
504    case seL4_VCPUReg_LRund:
505        set_lr_und(reg);
506        break;
507    case seL4_VCPUReg_SPund:
508        set_sp_und(reg);
509        break;
510    case seL4_VCPUReg_LRirq:
511        set_lr_irq(reg);
512        break;
513    case seL4_VCPUReg_SPirq:
514        set_sp_irq(reg);
515        break;
516    case seL4_VCPUReg_LRfiq:
517        set_lr_fiq(reg);
518        break;
519    case seL4_VCPUReg_SPfiq:
520        set_sp_fiq(reg);
521        break;
522    case seL4_VCPUReg_R8fiq:
523        set_r8_fiq(reg);
524        break;
525    case seL4_VCPUReg_R9fiq:
526        set_r9_fiq(reg);
527        break;
528    case seL4_VCPUReg_R10fiq:
529        set_r10_fiq(reg);
530        break;
531    case seL4_VCPUReg_R11fiq:
532        set_r11_fiq(reg);
533        break;
534    case seL4_VCPUReg_R12fiq:
535        set_r12_fiq(reg);
536        break;
537    case seL4_VCPUReg_SPSRsvc:
538        set_spsr_svc(reg);
539        break;
540    case seL4_VCPUReg_SPSRabt:
541        set_spsr_abt(reg);
542        break;
543    case seL4_VCPUReg_SPSRund:
544        set_spsr_und(reg);
545        break;
546    case seL4_VCPUReg_SPSRirq:
547        set_spsr_irq(reg);
548        break;
549    case seL4_VCPUReg_SPSRfiq:
550        set_spsr_fiq(reg);
551        break;
552    default:
553        fail("ARM/HYP: Invalid register index");
554    }
555}
556
557#endif /* End of CONFIG_ARM_HYPERVISOR_SUPPORT */
558
559
560#endif
561
562