112891Swpaul/*
212891Swpaul * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
312891Swpaul *
450479Speter * SPDX-License-Identifier: GPL-2.0-only
512891Swpaul */
612891Swpaul
712891Swpaul#pragma once
812891Swpaul
912891Swpaul#include <config.h>
1012891Swpaul
1112891Swpaul#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
1212891Swpaul
1312891Swpaul#include <arch/object/vcpu.h>
14194968Sbrian#include <drivers/timer/arm_generic.h>
15194968Sbrian
16194968Sbrian/* Note that the HCR_DC for ARMv8 disables S1 translation if enabled */
17194968Sbrian#ifdef CONFIG_DISABLE_WFI_WFE_TRAPS
1812891Swpaul/* Trap SMC and override CPSR.AIF */
1912891Swpaul#define HCR_COMMON ( HCR_VM | HCR_RW | HCR_AMO | HCR_IMO | HCR_FMO )
2012891Swpaul#else
21194968Sbrian/* Trap WFI/WFE/SMC and override CPSR.AIF */
22194968Sbrian#define HCR_COMMON ( HCR_TWI | HCR_TWE | HCR_VM | HCR_RW | HCR_AMO | HCR_IMO | HCR_FMO )
23194968Sbrian#endif
24194968Sbrian
25194968Sbrian/* Allow native tasks to run at EL0, but restrict access */
2612891Swpaul#define HCR_NATIVE ( HCR_COMMON | HCR_TGE | HCR_TVM | HCR_TTLB | HCR_DC \
2712891Swpaul                   | HCR_TAC | HCR_SWIO |  HCR_TSC | HCR_IMO | HCR_FMO | HCR_AMO)
28194968Sbrian#define HCR_VCPU   ( HCR_COMMON | HCR_TSC)
29194968Sbrian
30194968Sbrian#define SCTLR_EL1_UCI       BIT(26)     /* Enable EL0 access to DC CVAU, DC CIVAC, DC CVAC,
31194968Sbrian                                           and IC IVAU in AArch64 state   */
32194968Sbrian#define SCTLR_EL1_C         BIT(2)      /* Enable data and unified caches */
33194968Sbrian#define SCTLR_EL1_I         BIT(12)     /* Enable instruction cache       */
34194968Sbrian#define SCTLR_EL1_CP15BEN   BIT(5)      /* AArch32 CP15 barrier enable    */
3512891Swpaul#define SCTLR_EL1_UTC       BIT(15)     /* Enable EL0 access to CTR_EL0   */
3612891Swpaul#define SCTLR_EL1_NTWI      BIT(16)     /* WFI executed as normal         */
3712891Swpaul#define SCTLR_EL1_NTWE      BIT(18)     /* WFE executed as normal         */
3819161Swpaul
3919161Swpaul/* Disable MMU, SP alignment check, and alignment check */
40194968Sbrian/* A57 default value */
41194968Sbrian#define SCTLR_EL1_RES      0x30d00800   /* Reserved value */
4219161Swpaul#define SCTLR_EL1          ( SCTLR_EL1_RES | SCTLR_EL1_CP15BEN | SCTLR_EL1_UTC \
4319161Swpaul                           | SCTLR_EL1_NTWI | SCTLR_EL1_NTWE )
44194968Sbrian#define SCTLR_EL1_NATIVE   (SCTLR_EL1 | SCTLR_EL1_C | SCTLR_EL1_I | SCTLR_EL1_UCI)
45194968Sbrian#define SCTLR_EL1_VM       (SCTLR_EL1 | SCTLR_EL1_UCI)
46194968Sbrian#define SCTLR_DEFAULT      SCTLR_EL1_NATIVE
47194968Sbrian
4819161Swpaul#define UNKNOWN_FAULT       0x2000000
4919161Swpaul#define ESR_EC_TFP          0x7         /* Trap instructions that access FPU registers */
5012891Swpaul#define ESR_EC_CPACR        0x18        /* Trap access to CPACR                        */
5112891Swpaul#define ESR_EC(x)           (((x) & 0xfc000000) >> 26)
5212891Swpaul
5312891Swpaul#define VTCR_EL2_T0SZ(x)    ((x) & 0x3f)
5412891Swpaul#define VTCR_EL2_SL0(x)     (((x) & 0x3) << 6)
5512891Swpaul#define VTCR_EL2_IRGN0(x)   (((x) & 0x3) << 8)
5612891Swpaul#define VTCR_EL2_ORGN0(x)   (((x) & 0x3) << 10)
5715426Swpaul#define VTCR_EL2_SH0(x)     (((x) & 0x3) << 12)
5833100Swpaul#define VTCR_EL2_TG0(x)     (((x) & 0x3) << 14)
5912891Swpaul#define VTCR_EL2_PS(x)      (((x) & 0x7) << 16)
6017220Sadam
6117220Sadam/* Physical address size */
6212891Swpaul#define PS_4G               0
6315426Swpaul#define PS_64G              1
6413398Swpaul#define PS_1T               2
6513896Swpaul#define PS_4T               3
6612891Swpaul#define PS_16T              4
6713896Swpaul#define PS_256T             5
6813896Swpaul
6913896Swpaul/* Translation granule size */
7012891Swpaul#define TG0_4K              0
7133100Swpaul#define TG0_64K             1
7212891Swpaul#define TG0_16K             2
7317220Sadam
7417220Sadam#define ID_AA64MMFR0_EL1_PARANGE(x) ((x) & 0xf)
7515426Swpaul#define ID_AA64MMFR0_TGRAN4(x)      (((x) >> 28u) & 0xf)
7615426Swpaul
7712891Swpaul/* Shareability attributes */
7831110Swpaul#define SH0_NONE            0
7912891Swpaul#define SH0_OUTER           2
8031110Swpaul#define SH0_INNER           3
8131110Swpaul
8231110Swpaul/* Cacheability attributes */
8312891Swpaul#define NORMAL_NON_CACHEABLE    0
8412891Swpaul#define NORMAL_WB_WA_CACHEABLE  1 /* write-back, write-allocate      */
8512891Swpaul#define NORMAL_WT_CACHEABLE     2 /* write-through                   */
8612891Swpaul#define NORMAL_WB_NWA_CACHEABLE 3 /* write-back, no write-allocate   */
8772091Sasmodai
8812891Swpaul/* Start level  */
8912891Swpaul#define SL0_4K_L2       0         /* 4K, start at level 2 */
9012891Swpaul#define SL0_4K_L1       1         /* 4K, start at level 1 */
9112891Swpaul#define SL0_4K_L0       2         /* 4K, start at level 0 */
9212891Swpaul
9337819Sphk#define REG_SCTLR_EL1       "sctlr_el1"
9437819Sphk#define REG_TTBR0_EL1       "ttbr0_el1"
9512891Swpaul#define REG_TTBR1_EL1       "ttbr1_el1"
9612891Swpaul#define REG_TCR_EL1         "tcr_el1"
9712891Swpaul#define REG_MAIR_EL1        "mair_el1"
9812891Swpaul#define REG_AMAIR_EL1       "amair_el1"
9912891Swpaul#define REG_CONTEXTIDR_EL1  "contextidr_el1"
10012891Swpaul#define REG_ACTLR_EL1       "actlr_el1"
10112891Swpaul#define REG_AFSR0_EL1       "afsr0_el1"
10212891Swpaul#define REG_AFSR1_EL1       "afsr1_el1"
10312891Swpaul#define REG_ESR_EL1         "esr_el1"
10412891Swpaul#define REG_FAR_EL1         "far_el1"
10512891Swpaul#define REG_ISR_EL1         "isr_el1"
10612891Swpaul#define REG_VBAR_EL1        "vbar_el1"
10712891Swpaul#define REG_TPIDR_EL1       "tpidr_el1"
108145801Sume#define REG_SP_EL1          "sp_el1"
10912891Swpaul#define REG_ELR_EL1         "elr_el1"
11012891Swpaul#define REG_SPSR_EL1        "spsr_el1"
11112891Swpaul#define REG_CPACR_EL1       "cpacr_el1"
11212891Swpaul#define REG_CNTV_TVAL_EL0   "cntv_tval_el0"
113112458Srobert#define REG_CNTV_CTL_EL0    "cntv_ctl_el0"
11412891Swpaul#define REG_CNTV_CVAL_EL0   "cntv_cval_el0"
11576621Sgshapiro#define REG_CNTVOFF_EL2     "cntvoff_el2"
11615426Swpaul#define REG_CNTKCTL_EL1     "cntkctl_el1"
11712891Swpaul#define REG_HCR_EL2         "hcr_el2"
11812891Swpaul#define REG_VTCR_EL2        "vtcr_el2"
11912891Swpaul#define REG_VMPIDR_EL2      "vmpidr_el2"
12012891Swpaul#define REG_ID_AA64MMFR0_EL1 "id_aa64mmfr0_el1"
12112891Swpaul
12212891Swpaul/* for EL1 SCTLR */
12312891Swpaulstatic inline word_t getSCTLR(void)
12412891Swpaul{
12516732Swpaul    return readSystemControlRegister();
12690320Smarkm}
12712891Swpaul
128194968Sbrianstatic inline void setSCTLR(word_t sctlr)
129194968Sbrian{
130194968Sbrian    writeSystemControlRegister(sctlr);
131194968Sbrian}
132194968Sbrian
133194968Sbrianstatic inline word_t readTTBR0(void)
134194968Sbrian{
135194968Sbrian    word_t reg;
136194968Sbrian    MRS(REG_TTBR0_EL1, reg);
137194968Sbrian    return reg;
138194968Sbrian}
13931110Swpaul
14031110Swpaulstatic inline void writeTTBR0(word_t reg)
14131110Swpaul{
142112458Srobert    MSR(REG_TTBR0_EL1, reg);
14331110Swpaul}
14431110Swpaul
14531110Swpaulstatic inline word_t readTTBR1(void)
14631110Swpaul{
14731110Swpaul    word_t reg;
14831110Swpaul    MRS(REG_TTBR1_EL1, reg);
14931110Swpaul    return reg;
15031110Swpaul}
15131110Swpaul
15231110Swpaulstatic inline void writeTTBR1(word_t reg)
15331110Swpaul{
15431110Swpaul    MSR(REG_TTBR1_EL1, reg);
15531110Swpaul}
15631110Swpaul
15731110Swpaulstatic inline word_t readTCR(void)
15831110Swpaul{
15931110Swpaul    word_t reg;
16031110Swpaul    MRS(REG_TCR_EL1, reg);
16131110Swpaul    return reg;
16231110Swpaul}
16331110Swpaul
16431110Swpaulstatic inline void writeTCR(word_t reg)
16531110Swpaul{
16631110Swpaul    MSR(REG_TCR_EL1, reg);
16731110Swpaul}
16831110Swpaul
169194968Sbrianstatic inline word_t readMAIR(void)
170194968Sbrian{
171194968Sbrian    word_t reg;
17231110Swpaul    MRS(REG_MAIR_EL1, reg);
17331110Swpaul    return reg;
17431110Swpaul}
17531110Swpaul
17631110Swpaulstatic inline void writeMAIR(word_t reg)
17731110Swpaul{
17831110Swpaul    MSR(REG_MAIR_EL1, reg);
17931110Swpaul}
18031110Swpaul
18131110Swpaulstatic inline word_t readAMAIR(void)
18231110Swpaul{
18331110Swpaul    word_t reg;
18490320Smarkm    MRS(REG_AMAIR_EL1, reg);
18531110Swpaul    return reg;
18631110Swpaul}
18731110Swpaul
18831110Swpaulstatic inline void writeAMAIR(word_t reg)
189145801Sume{
190145801Sume    MSR(REG_AMAIR_EL1, reg);
191145801Sume}
192145801Sume
193145801Sumestatic inline word_t readCIDR(void)
194145801Sume{
19531110Swpaul    uint32_t reg;
19612891Swpaul    MRS(REG_CONTEXTIDR_EL1, reg);
19712891Swpaul    return (word_t)reg;
19812891Swpaul}
19912891Swpaul
200145801Sumestatic inline void writeCIDR(word_t reg)
20112891Swpaul{
20212891Swpaul    MSR(REG_CONTEXTIDR_EL1, (uint32_t)reg);
20312891Swpaul}
20412891Swpaul
20512891Swpaulstatic inline word_t readACTLR(void)
206194968Sbrian{
20712891Swpaul    word_t reg;
20812891Swpaul    MRS(REG_ACTLR_EL1, reg);
20912891Swpaul    return reg;
21012891Swpaul}
21112891Swpaul
21215426Swpaulstatic inline void writeACTLR(word_t reg)
21312891Swpaul{
21412891Swpaul    MSR(REG_ACTLR_EL1, reg);
21512891Swpaul}
21616118Swpaul
21716118Swpaulstatic inline word_t readAFSR0(void)
21816118Swpaul{
21916118Swpaul    uint32_t reg;
22016118Swpaul    MRS(REG_AFSR0_EL1, reg);
22116118Swpaul    return (word_t)reg;
22216118Swpaul}
22316118Swpaul
22416118Swpaulstatic inline void writeAFSR0(word_t reg)
22516118Swpaul{
22616118Swpaul    MSR(REG_AFSR0_EL1, (uint32_t)reg);
227194968Sbrian}
228194968Sbrian
229194968Sbrianstatic inline word_t readAFSR1(void)
230194968Sbrian{
23116118Swpaul    uint32_t reg;
23216118Swpaul    MRS(REG_AFSR1_EL1, reg);
23316118Swpaul    return (word_t)reg;
23431110Swpaul}
23531110Swpaul
23631110Swpaulstatic inline void writeAFSR1(word_t reg)
23731110Swpaul{
23831110Swpaul    MSR(REG_AFSR1_EL1, (uint32_t)reg);
23931110Swpaul}
24031110Swpaul
24131110Swpaulstatic inline word_t readESR(void)
24231110Swpaul{
24331110Swpaul    uint32_t reg;
24431110Swpaul    MRS(REG_ESR_EL1, reg);
24531110Swpaul    return (word_t)reg;
24648199Sn_hibma}
24731110Swpaul
24831110Swpaulstatic inline void writeESR(word_t reg)
24931110Swpaul{
25015426Swpaul    MSR(REG_ESR_EL1, (uint32_t)reg);
25115426Swpaul}
25217220Sadam
25317481Sadamstatic inline word_t readFAR(void)
25433100Swpaul{
25533100Swpaul    word_t reg;
25615426Swpaul    MRS(REG_FAR_EL1, reg);
25716044Swpaul    return reg;
25816044Swpaul}
25912891Swpaul
26015426Swpaulstatic inline void writeFAR(word_t reg)
26112891Swpaul{
26212891Swpaul    MSR(REG_FAR_EL1, reg);
263116301Sru}
264116301Sru
26533100Swpaul/* ISR is read-only */
26633100Swpaulstatic inline word_t readISR(void)
26715426Swpaul{
26812891Swpaul    uint32_t reg;
26912891Swpaul    MRS(REG_ISR_EL1, reg);
27012891Swpaul    return (word_t)reg;
27112891Swpaul}
27212891Swpaul
27331110Swpaulstatic inline word_t readVBAR(void)
27431110Swpaul{
27531110Swpaul    word_t reg;
276116301Sru    MRS(REG_VBAR_EL1, reg);
277116301Sru    return reg;
27833100Swpaul}
27915426Swpaul
28017268Speterstatic inline void writeVBAR(word_t reg)
28112891Swpaul{
28231110Swpaul    MSR(REG_VBAR_EL1, reg);
28312891Swpaul}
28412891Swpaul
28512891Swpaulstatic inline word_t readSP_EL1(void)
28631110Swpaul{
28731110Swpaul    word_t reg;
28831110Swpaul    MRS(REG_SP_EL1, reg);
289116301Sru    return reg;
290116301Sru}
29133100Swpaul
29215426Swpaulstatic inline void writeSP_EL1(word_t reg)
29312891Swpaul{
29412891Swpaul    MSR(REG_SP_EL1, reg);
29531110Swpaul}
29612891Swpaul
29712891Swpaulstatic inline word_t readELR_EL1(void)
29812891Swpaul{
29912891Swpaul    word_t reg;
30031110Swpaul    MRS(REG_ELR_EL1, reg);
30131110Swpaul    return reg;
30231110Swpaul}
303116301Sru
304116301Srustatic inline void writeELR_EL1(word_t reg)
30533100Swpaul{
30615426Swpaul    MSR(REG_ELR_EL1, reg);
30712891Swpaul}
30812891Swpaul
30931110Swpaulstatic inline word_t readSPSR_EL1(void)
31012891Swpaul{
31112891Swpaul    word_t reg;
31212891Swpaul    MRS(REG_SPSR_EL1, reg);
31312891Swpaul    return reg;
31431110Swpaul}
31531110Swpaul
31631110Swpaulstatic inline void writeSPSR_EL1(word_t reg)
317116301Sru{
318116301Sru    MSR(REG_SPSR_EL1, reg);
31933100Swpaul}
32015426Swpaul
32112891Swpaulstatic inline word_t readCPACR_EL1(void)
32212891Swpaul{
32331110Swpaul    word_t reg;
32412891Swpaul    MRS(REG_CPACR_EL1, reg);
32512891Swpaul    return reg;
32612891Swpaul}
32712891Swpaul
32831110Swpaulstatic inline void writeCPACR_EL1(word_t reg)
32931110Swpaul{
33031110Swpaul    MSR(REG_CPACR_EL1, reg);
331116301Sru}
33232775Ssteve
333116301Srustatic inline word_t readCNTV_TVAL_EL0(void)
33433100Swpaul{
33515426Swpaul    word_t reg;
33612891Swpaul    MRS(REG_CNTV_TVAL_EL0, reg);
33712891Swpaul    return reg;
33831110Swpaul}
33912891Swpaul
34012891Swpaulstatic inline void writeCNTV_TVAL_EL0(word_t reg)
34112891Swpaul{
34212891Swpaul    MSR(REG_CNTV_TVAL_EL0, reg);
34331110Swpaul}
34431110Swpaul
34531110Swpaulstatic inline word_t readCNTV_CTL_EL0(void)
346116301Sru{
34732775Ssteve    word_t reg;
348116301Sru    MRS(REG_CNTV_CTL_EL0, reg);
34933100Swpaul    return reg;
35015426Swpaul}
35112891Swpaul
35212891Swpaulstatic inline void writeCNTV_CTL_EL0(word_t reg)
35331110Swpaul{
35412891Swpaul    MSR(REG_CNTV_CTL_EL0, reg);
35512891Swpaul}
35612891Swpaul
35712891Swpaulstatic inline word_t readCNTV_CVAL_EL0(void)
358116301Sru{
359116301Sru    word_t reg;
36033100Swpaul    MRS(REG_CNTV_CVAL_EL0, reg);
36115426Swpaul    return reg;
36212891Swpaul}
36312891Swpaul
36412891Swpaulstatic inline void writeCNTV_CVAL_EL0(word_t reg)
36515426Swpaul{
36612891Swpaul    MSR(REG_CNTV_CVAL_EL0, reg);
36712891Swpaul}
368116301Sru
36933100Swpaulstatic inline word_t readCNTVOFF_EL2(void)
37033100Swpaul{
37115426Swpaul    word_t reg;
37212891Swpaul    MRS(REG_CNTVOFF_EL2, reg);
37312891Swpaul    return reg;
37412891Swpaul}
37512891Swpaul
376145801Sumestatic inline void writeCNTVOFF_EL2(word_t reg)
377145801Sume{
378145801Sume    MSR(REG_CNTVOFF_EL2, reg);
379145801Sume}
380145801Sume
381145801Sumestatic inline word_t readCNTKCTL_EL1(void)
382145801Sume{
383145801Sume    word_t reg;
384145801Sume    MRS(REG_CNTKCTL_EL1, reg);
385145801Sume    return reg;
386145801Sume}
387145801Sume
388145801Sumestatic inline void writeCNTKCTL_EL1(word_t reg)
389145801Sume{
390145801Sume    MSR(REG_CNTKCTL_EL1, reg);
391145801Sume}
392145801Sume
393145801Sumestatic inline word_t readVMPIDR_EL2(void)
394145801Sume{
395145801Sume    word_t reg;
396145801Sume    MRS(REG_VMPIDR_EL2, reg);
397145801Sume    return reg;
398145801Sume}
399145801Sume
400145801Sumestatic inline void writeVMPIDR_EL2(word_t reg)
401145801Sume{
402145801Sume    MSR(REG_VMPIDR_EL2, reg);
403145801Sume}
40412891Swpaul
40512891Swpaulstatic word_t vcpu_hw_read_reg(word_t reg_index)
406116301Sru{
40732775Ssteve    word_t reg = 0;
40832775Ssteve    switch (reg_index) {
40912891Swpaul    case seL4_VCPUReg_SCTLR:
410116301Sru        return getSCTLR();
411116301Sru    case seL4_VCPUReg_TTBR0:
41233100Swpaul        return readTTBR0();
41315426Swpaul    case seL4_VCPUReg_TTBR1:
41412891Swpaul        return readTTBR1();
41512891Swpaul    case seL4_VCPUReg_TCR:
41612891Swpaul        return readTCR();
41712891Swpaul    case seL4_VCPUReg_MAIR:
41812891Swpaul        return readMAIR();
41912891Swpaul    case seL4_VCPUReg_AMAIR:
420116301Sru        return readAMAIR();
42133100Swpaul    case seL4_VCPUReg_CIDR:
42233100Swpaul        return readCIDR();
42315426Swpaul    case seL4_VCPUReg_ACTLR:
42412891Swpaul        return readACTLR();
42512891Swpaul    case seL4_VCPUReg_CPACR:
42612891Swpaul        return readCPACR_EL1();
42712891Swpaul    case seL4_VCPUReg_AFSR0:
42812891Swpaul        return readAFSR0();
42912891Swpaul    case seL4_VCPUReg_AFSR1:
430116301Sru        return readAFSR1();
43132775Ssteve    case seL4_VCPUReg_ESR:
43232775Ssteve        return readESR();
43312891Swpaul    case seL4_VCPUReg_FAR:
434116301Sru        return readFAR();
43533100Swpaul    case seL4_VCPUReg_ISR:
43615426Swpaul        return readISR();
43712891Swpaul    case seL4_VCPUReg_VBAR:
43812891Swpaul        return readVBAR();
43912891Swpaul    case seL4_VCPUReg_TPIDR_EL1:
44012891Swpaul        return readTPIDR_EL1();
44112891Swpaul    case seL4_VCPUReg_SP_EL1:
44212891Swpaul        return readSP_EL1();
443116301Sru    case seL4_VCPUReg_ELR_EL1:
44433100Swpaul        return readELR_EL1();
44533100Swpaul    case seL4_VCPUReg_SPSR_EL1:
44615426Swpaul        return readSPSR_EL1();
44712891Swpaul    case seL4_VCPUReg_CNTV_CTL:
44812891Swpaul        return readCNTV_CTL_EL0();
44912891Swpaul    case seL4_VCPUReg_CNTV_CVAL:
45012891Swpaul        return readCNTV_CVAL_EL0();
45112891Swpaul    case seL4_VCPUReg_CNTVOFF:
45212891Swpaul        return readCNTVOFF_EL2();
453116301Sru    case seL4_VCPUReg_CNTKCTL_EL1:
45432775Ssteve        return readCNTKCTL_EL1();
45532775Ssteve#ifdef ENABLE_SMP_SUPPORT
45612891Swpaul    case seL4_VCPUReg_VMPIDR_EL2:
457116301Sru        return readVMPIDR_EL2();
45833100Swpaul#endif /* ENABLE_SMP_SUPPORT */
45915426Swpaul    default:
46012891Swpaul        fail("ARM/HYP: Invalid register index");
46112891Swpaul    }
46212891Swpaul
46312891Swpaul    return reg;
46412891Swpaul}
46512891Swpaul
466116301Srustatic void vcpu_hw_write_reg(word_t reg_index, word_t reg)
46733100Swpaul{
46833100Swpaul    switch (reg_index) {
46915426Swpaul    case seL4_VCPUReg_SCTLR:
47012891Swpaul        return setSCTLR(reg);
47112891Swpaul    case seL4_VCPUReg_TTBR0:
47212891Swpaul        return writeTTBR0(reg);
47312891Swpaul    case seL4_VCPUReg_TTBR1:
47412891Swpaul        return writeTTBR1(reg);
47512891Swpaul    case seL4_VCPUReg_TCR:
476116301Sru        return writeTCR(reg);
47732775Ssteve    case seL4_VCPUReg_MAIR:
47833300Swpaul        return writeMAIR(reg);
47933300Swpaul    case seL4_VCPUReg_AMAIR:
48033536Swpaul        return writeAMAIR(reg);
48133300Swpaul    case seL4_VCPUReg_CIDR:
48233300Swpaul        return writeCIDR(reg);
483116301Sru    case seL4_VCPUReg_ACTLR:
484116301Sru        return writeACTLR(reg);
48533100Swpaul    case seL4_VCPUReg_CPACR:
48615426Swpaul        return writeCPACR_EL1(reg);
48712891Swpaul    case seL4_VCPUReg_AFSR0:
48812891Swpaul        return writeAFSR0(reg);
48912891Swpaul    case seL4_VCPUReg_AFSR1:
490159394Smaxim        return writeAFSR1(reg);
491112458Srobert    case seL4_VCPUReg_ESR:
492116301Sru        return writeESR(reg);
493116301Sru    case seL4_VCPUReg_FAR:
494116301Sru        return writeFAR(reg);
495112458Srobert    case seL4_VCPUReg_ISR:
496112458Srobert        /* ISR is read-only */
497112458Srobert        return;
498112458Srobert    case seL4_VCPUReg_VBAR:
49912891Swpaul        return writeVBAR(reg);
50012891Swpaul    case seL4_VCPUReg_TPIDR_EL1:
50112891Swpaul        return writeTPIDR_EL1(reg);
50231110Swpaul    case seL4_VCPUReg_SP_EL1:
50331110Swpaul        return writeSP_EL1(reg);
50431110Swpaul    case seL4_VCPUReg_ELR_EL1:
505116301Sru        return writeELR_EL1(reg);
50633100Swpaul    case seL4_VCPUReg_SPSR_EL1:
50733100Swpaul        return writeSPSR_EL1(reg);
50815426Swpaul    case seL4_VCPUReg_CNTV_CTL:
50912891Swpaul        return writeCNTV_CTL_EL0(reg);
51012891Swpaul    case seL4_VCPUReg_CNTV_CVAL:
51131110Swpaul        return writeCNTV_CVAL_EL0(reg);
51212891Swpaul    case seL4_VCPUReg_CNTVOFF:
51312891Swpaul        return writeCNTVOFF_EL2(reg);
51412891Swpaul    case seL4_VCPUReg_CNTKCTL_EL1:
51512891Swpaul        return writeCNTKCTL_EL1(reg);
51612891Swpaul#ifdef ENABLE_SMP_SUPPORT
51762210Sbrian    case seL4_VCPUReg_VMPIDR_EL2:
518116301Sru        return writeVMPIDR_EL2(reg);
51912891Swpaul#endif /* ENABLE_SMP_SUPPORT */
520116301Sru    default:
52162210Sbrian        fail("ARM/HYP: Invalid register index");
522116301Sru    }
52312891Swpaul
52412891Swpaul    return;
52512891Swpaul}
52612891Swpaul
52712891Swpaulstatic inline void vcpu_init_vtcr(void)
528116301Sru{
529116301Sru
53050159Swpaul    /* check that the processor supports the configuration */
53133100Swpaul    uint32_t val;
53215426Swpaul    MRS(REG_ID_AA64MMFR0_EL1, val);
53312891Swpaul    uint32_t pa_range = ID_AA64MMFR0_EL1_PARANGE(val);
53412891Swpaul    if (config_set(CONFIG_ARM_PA_SIZE_BITS_40) && pa_range < PS_1T) {
53512891Swpaul        fail("Processor does not support a 40 bit PA");
53615426Swpaul    }
53712891Swpaul    if (config_set(CONFIG_ARM_PA_SIZE_BITS_44) && pa_range < PS_16T) {
53812891Swpaul        fail("Processor does not support a 44 bit PA");
539116301Sru    }
540116301Sru    uint32_t granule = ID_AA64MMFR0_TGRAN4(val);
54150159Swpaul    if (granule) {
54233100Swpaul        fail("Processor does not support 4KB");
54315426Swpaul    }
54412891Swpaul
54512891Swpaul    /* Set up the stage-2 translation control register for cores supporting 44-bit PA */
54612891Swpaul    uint32_t vtcr_el2;
54712891Swpaul#ifdef CONFIG_ARM_PA_SIZE_BITS_40
54812891Swpaul    vtcr_el2 = VTCR_EL2_T0SZ(24);                            // 40-bit input IPA
54912891Swpaul    vtcr_el2 |= VTCR_EL2_PS(PS_1T);                          // 40-bit PA size
550116301Sru    vtcr_el2 |= VTCR_EL2_SL0(SL0_4K_L1);                     // 4KiB, start at level 1
551116301Sru#else
55250159Swpaul    vtcr_el2 = VTCR_EL2_T0SZ(20);                            // 44-bit input IPA
55333100Swpaul    vtcr_el2 |= VTCR_EL2_PS(PS_16T);                         // 44-bit PA size
55415426Swpaul    vtcr_el2 |= VTCR_EL2_SL0(SL0_4K_L0);                     // 4KiB, start at level 0
55512891Swpaul#endif
55612891Swpaul    vtcr_el2 |= VTCR_EL2_IRGN0(NORMAL_WB_WA_CACHEABLE);      // inner write-back, read/write allocate
55712891Swpaul    vtcr_el2 |= VTCR_EL2_ORGN0(NORMAL_WB_WA_CACHEABLE);      // outer write-back, read/write allocate
55812891Swpaul    vtcr_el2 |= VTCR_EL2_SH0(SH0_INNER);                     // inner shareable
55912891Swpaul    vtcr_el2 |= VTCR_EL2_TG0(TG0_4K);                        // 4KiB page size
56012891Swpaul    vtcr_el2 |= BIT(31);                                     // reserved as 1
561116301Sru
562116301Sru    MSR(REG_VTCR_EL2, vtcr_el2);
56350159Swpaul    isb();
56433100Swpaul}
56515426Swpaul
56612891Swpaulstatic inline void armv_vcpu_boot_init(void)
56712891Swpaul{
56812891Swpaul    word_t hcr_el2 = 0;
56912891Swpaul
570157722Sru    vcpu_init_vtcr();
57112891Swpaul
57216732Swpaul    hcr_el2 = HCR_NATIVE;
57333100Swpaul    MSR(REG_HCR_EL2, hcr_el2);
57433100Swpaul    isb();
57515426Swpaul
57612891Swpaul    /* set the SCTLR_EL1 for running native seL4 threads */
57712891Swpaul    MSR(REG_SCTLR_EL1, SCTLR_EL1_NATIVE);
57812891Swpaul    isb();
57912891Swpaul}
58012891Swpaul
58112891Swpaulstatic inline void armv_vcpu_save(vcpu_t *vcpu, UNUSED bool_t active)
58231110Swpaul{
58331110Swpaul    vcpu_save_reg_range(vcpu, seL4_VCPUReg_TTBR0, seL4_VCPUReg_SPSR_EL1);
58431110Swpaul}
585116301Sru
586116301Srustatic inline void vcpu_enable(vcpu_t *vcpu)
58750159Swpaul{
58833100Swpaul    MSR(REG_HCR_EL2, HCR_VCPU);
58915426Swpaul    isb();
59012891Swpaul    vcpu_restore_reg(vcpu, seL4_VCPUReg_SCTLR);
59112891Swpaul    isb();
59231110Swpaul
59312891Swpaul    set_gic_vcpu_ctrl_hcr(vcpu->vgic.hcr);
59412891Swpaul#ifdef CONFIG_HAVE_FPU
59512891Swpaul    vcpu_restore_reg(vcpu, seL4_VCPUReg_CPACR);
59612891Swpaul#endif
59731110Swpaul    /* Restore virtual timer state */
59831110Swpaul    restore_virt_timer(vcpu);
59931110Swpaul}
600116301Sru
601116301Srustatic inline void vcpu_disable(vcpu_t *vcpu)
60250159Swpaul{
60333100Swpaul
60415426Swpaul    uint32_t hcr;
60512891Swpaul    dsb();
60612891Swpaul    if (likely(vcpu)) {
60731110Swpaul        hcr = get_gic_vcpu_ctrl_hcr();
60817266Speter        vcpu->vgic.hcr = hcr;
60931110Swpaul        vcpu_save_reg(vcpu, seL4_VCPUReg_SCTLR);
610194968Sbrian#ifdef CONFIG_HAVE_FPU
611194968Sbrian        vcpu_save_reg(vcpu, seL4_VCPUReg_CPACR);
612194968Sbrian#endif
613194968Sbrian        isb();
614194968Sbrian    }
615194968Sbrian    /* Turn off the VGIC */
616194968Sbrian    set_gic_vcpu_ctrl_hcr(0);
617194968Sbrian    isb();
618194968Sbrian
619194968Sbrian    /* Stage 1 MMU off */
620194968Sbrian    setSCTLR(SCTLR_DEFAULT);
621194968Sbrian    isb();
622194968Sbrian    MSR(REG_HCR_EL2, HCR_NATIVE);
623194968Sbrian    isb();
624194968Sbrian
625194968Sbrian#ifdef CONFIG_HAVE_FPU
626194968Sbrian    /* Allow FPU instructions in EL0 and EL1 for native
627194968Sbrian     * threads by setting the CPACR_EL1. The CPTR_EL2 is
628194968Sbrian     * used to trap the FPU instructions to EL2.
629194968Sbrian     */
630194968Sbrian    enableFpuEL01();
631194968Sbrian#endif
632194968Sbrian    if (likely(vcpu)) {
633194968Sbrian        /* Save virtual timer state */
634194968Sbrian        save_virt_timer(vcpu);
635194968Sbrian        /* Mask the virtual timer interrupt */
636194968Sbrian        maskInterrupt(true, CORE_IRQ_TO_IRQT(CURRENT_CPU_INDEX(), INTERRUPT_VTIMER_EVENT));
637194968Sbrian    }
638194968Sbrian}
639194968Sbrian
64090320Smarkmstatic inline void armv_vcpu_init(vcpu_t *vcpu)
64117266Speter{
642116301Sru    vcpu_write_reg(vcpu, seL4_VCPUReg_SCTLR, SCTLR_EL1_VM);
64317266Speter}
64417266Speter
64517266Speterstatic inline bool_t armv_handleVCPUFault(word_t hsr)
64617266Speter{
64717266Speter#ifdef CONFIG_HAVE_FPU
64817266Speter    if ((ESR_EC(hsr) == ESR_EC_TFP || ESR_EC(hsr) == ESR_EC_CPACR) && !isFpuEnable()) {
64917266Speter        handleFPUFault();
65017266Speter        setNextPC(NODE_STATE(ksCurThread), getRestartPC(NODE_STATE(ksCurThread)));
65117266Speter        return true;
652116301Sru    }
65333100Swpaul#endif
65433100Swpaul
65517266Speter    if (hsr == UNKNOWN_FAULT) {
65617266Speter        handleUserLevelFault(getESR(), 0);
65717266Speter        return true;
658    }
659
660    return false;
661}
662
663#endif /* End of CONFIG_ARM_HYPERVISOR_SUPPORT */
664
665
666