147e07394SAndrew Turner /*-
247e07394SAndrew Turner * SPDX-License-Identifier: BSD-2-Clause
347e07394SAndrew Turner *
447e07394SAndrew Turner * Copyright (c) 2021 Andrew Turner
547e07394SAndrew Turner *
647e07394SAndrew Turner * This work was supported by Innovate UK project 105694, "Digital Security
747e07394SAndrew Turner * by Design (DSbD) Technology Platform Prototype".
847e07394SAndrew Turner *
947e07394SAndrew Turner * Redistribution and use in source and binary forms, with or without
1047e07394SAndrew Turner * modification, are permitted provided that the following conditions
1147e07394SAndrew Turner * are met:
1247e07394SAndrew Turner * 1. Redistributions of source code must retain the above copyright
1347e07394SAndrew Turner * notice, this list of conditions and the following disclaimer.
1447e07394SAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright
1547e07394SAndrew Turner * notice, this list of conditions and the following disclaimer in the
1647e07394SAndrew Turner * documentation and/or other materials provided with the distribution.
1747e07394SAndrew Turner *
1847e07394SAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1947e07394SAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2047e07394SAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2147e07394SAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2247e07394SAndrew Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2347e07394SAndrew Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2447e07394SAndrew Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2547e07394SAndrew Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2647e07394SAndrew Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2747e07394SAndrew Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2847e07394SAndrew Turner * SUCH DAMAGE.
2947e07394SAndrew Turner */
3047e07394SAndrew Turner
3147e07394SAndrew Turner #include <sys/cdefs.h>
3247e07394SAndrew Turner #include <sys/types.h>
3347e07394SAndrew Turner #include <sys/proc.h>
3447e07394SAndrew Turner
3547e07394SAndrew Turner #include <machine/armreg.h>
3647e07394SAndrew Turner
3747e07394SAndrew Turner #include "arm64.h"
3847e07394SAndrew Turner #include "hyp.h"
3947e07394SAndrew Turner
4047e07394SAndrew Turner struct hypctx;
4147e07394SAndrew Turner
423d61bcf1SAndrew Turner uint64_t VMM_HYP_FUNC(do_call_guest)(struct hypctx *);
4347e07394SAndrew Turner
4447e07394SAndrew Turner static void
vmm_hyp_reg_store(struct hypctx * hypctx,struct hyp * hyp,bool guest)4547e07394SAndrew Turner vmm_hyp_reg_store(struct hypctx *hypctx, struct hyp *hyp, bool guest)
4647e07394SAndrew Turner {
4747e07394SAndrew Turner uint64_t dfr0;
4847e07394SAndrew Turner
4947e07394SAndrew Turner /* Store the guest VFP registers */
5047e07394SAndrew Turner if (guest) {
5147e07394SAndrew Turner /* Store the timer registers */
527861ecd1SAndrew Turner hypctx->vtimer_cpu.cntkctl_el1 =
537861ecd1SAndrew Turner READ_SPECIALREG(EL1_REG(CNTKCTL));
5447e07394SAndrew Turner hypctx->vtimer_cpu.virt_timer.cntx_cval_el0 =
557861ecd1SAndrew Turner READ_SPECIALREG(EL0_REG(CNTV_CVAL));
5647e07394SAndrew Turner hypctx->vtimer_cpu.virt_timer.cntx_ctl_el0 =
577861ecd1SAndrew Turner READ_SPECIALREG(EL0_REG(CNTV_CTL));
5847e07394SAndrew Turner
5947e07394SAndrew Turner /* Store the GICv3 registers */
6047e07394SAndrew Turner hypctx->vgic_v3_regs.ich_eisr_el2 =
6147e07394SAndrew Turner READ_SPECIALREG(ich_eisr_el2);
6247e07394SAndrew Turner hypctx->vgic_v3_regs.ich_elrsr_el2 =
6347e07394SAndrew Turner READ_SPECIALREG(ich_elrsr_el2);
6447e07394SAndrew Turner hypctx->vgic_v3_regs.ich_hcr_el2 =
6547e07394SAndrew Turner READ_SPECIALREG(ich_hcr_el2);
6647e07394SAndrew Turner hypctx->vgic_v3_regs.ich_misr_el2 =
6747e07394SAndrew Turner READ_SPECIALREG(ich_misr_el2);
6847e07394SAndrew Turner hypctx->vgic_v3_regs.ich_vmcr_el2 =
6947e07394SAndrew Turner READ_SPECIALREG(ich_vmcr_el2);
7047e07394SAndrew Turner switch (hypctx->vgic_v3_regs.ich_lr_num - 1) {
7147e07394SAndrew Turner #define STORE_LR(x) \
7247e07394SAndrew Turner case x: \
7347e07394SAndrew Turner hypctx->vgic_v3_regs.ich_lr_el2[x] = \
7447e07394SAndrew Turner READ_SPECIALREG(ich_lr ## x ##_el2)
7547e07394SAndrew Turner STORE_LR(15);
7647e07394SAndrew Turner STORE_LR(14);
7747e07394SAndrew Turner STORE_LR(13);
7847e07394SAndrew Turner STORE_LR(12);
7947e07394SAndrew Turner STORE_LR(11);
8047e07394SAndrew Turner STORE_LR(10);
8147e07394SAndrew Turner STORE_LR(9);
8247e07394SAndrew Turner STORE_LR(8);
8347e07394SAndrew Turner STORE_LR(7);
8447e07394SAndrew Turner STORE_LR(6);
8547e07394SAndrew Turner STORE_LR(5);
8647e07394SAndrew Turner STORE_LR(4);
8747e07394SAndrew Turner STORE_LR(3);
8847e07394SAndrew Turner STORE_LR(2);
8947e07394SAndrew Turner STORE_LR(1);
9047e07394SAndrew Turner default:
9147e07394SAndrew Turner STORE_LR(0);
9247e07394SAndrew Turner #undef STORE_LR
9347e07394SAndrew Turner }
9447e07394SAndrew Turner
9547e07394SAndrew Turner switch (hypctx->vgic_v3_regs.ich_apr_num - 1) {
9647e07394SAndrew Turner #define STORE_APR(x) \
9747e07394SAndrew Turner case x: \
9847e07394SAndrew Turner hypctx->vgic_v3_regs.ich_ap0r_el2[x] = \
9947e07394SAndrew Turner READ_SPECIALREG(ich_ap0r ## x ##_el2); \
10047e07394SAndrew Turner hypctx->vgic_v3_regs.ich_ap1r_el2[x] = \
10147e07394SAndrew Turner READ_SPECIALREG(ich_ap1r ## x ##_el2)
10247e07394SAndrew Turner STORE_APR(3);
10347e07394SAndrew Turner STORE_APR(2);
10447e07394SAndrew Turner STORE_APR(1);
10547e07394SAndrew Turner default:
10647e07394SAndrew Turner STORE_APR(0);
10747e07394SAndrew Turner #undef STORE_APR
10847e07394SAndrew Turner }
10947e07394SAndrew Turner }
11047e07394SAndrew Turner
11147e07394SAndrew Turner dfr0 = READ_SPECIALREG(id_aa64dfr0_el1);
11247e07394SAndrew Turner switch (ID_AA64DFR0_BRPs_VAL(dfr0) - 1) {
11347e07394SAndrew Turner #define STORE_DBG_BRP(x) \
11447e07394SAndrew Turner case x: \
11547e07394SAndrew Turner hypctx->dbgbcr_el1[x] = \
11647e07394SAndrew Turner READ_SPECIALREG(dbgbcr ## x ## _el1); \
11747e07394SAndrew Turner hypctx->dbgbvr_el1[x] = \
11847e07394SAndrew Turner READ_SPECIALREG(dbgbvr ## x ## _el1)
11947e07394SAndrew Turner STORE_DBG_BRP(15);
12047e07394SAndrew Turner STORE_DBG_BRP(14);
12147e07394SAndrew Turner STORE_DBG_BRP(13);
12247e07394SAndrew Turner STORE_DBG_BRP(12);
12347e07394SAndrew Turner STORE_DBG_BRP(11);
12447e07394SAndrew Turner STORE_DBG_BRP(10);
12547e07394SAndrew Turner STORE_DBG_BRP(9);
12647e07394SAndrew Turner STORE_DBG_BRP(8);
12747e07394SAndrew Turner STORE_DBG_BRP(7);
12847e07394SAndrew Turner STORE_DBG_BRP(6);
12947e07394SAndrew Turner STORE_DBG_BRP(5);
13047e07394SAndrew Turner STORE_DBG_BRP(4);
13147e07394SAndrew Turner STORE_DBG_BRP(3);
13247e07394SAndrew Turner STORE_DBG_BRP(2);
13347e07394SAndrew Turner STORE_DBG_BRP(1);
13447e07394SAndrew Turner default:
13547e07394SAndrew Turner STORE_DBG_BRP(0);
13647e07394SAndrew Turner #undef STORE_DBG_BRP
13747e07394SAndrew Turner }
13847e07394SAndrew Turner
13947e07394SAndrew Turner switch (ID_AA64DFR0_WRPs_VAL(dfr0) - 1) {
14047e07394SAndrew Turner #define STORE_DBG_WRP(x) \
14147e07394SAndrew Turner case x: \
14247e07394SAndrew Turner hypctx->dbgwcr_el1[x] = \
14347e07394SAndrew Turner READ_SPECIALREG(dbgwcr ## x ## _el1); \
14447e07394SAndrew Turner hypctx->dbgwvr_el1[x] = \
14547e07394SAndrew Turner READ_SPECIALREG(dbgwvr ## x ## _el1)
14647e07394SAndrew Turner STORE_DBG_WRP(15);
14747e07394SAndrew Turner STORE_DBG_WRP(14);
14847e07394SAndrew Turner STORE_DBG_WRP(13);
14947e07394SAndrew Turner STORE_DBG_WRP(12);
15047e07394SAndrew Turner STORE_DBG_WRP(11);
15147e07394SAndrew Turner STORE_DBG_WRP(10);
15247e07394SAndrew Turner STORE_DBG_WRP(9);
15347e07394SAndrew Turner STORE_DBG_WRP(8);
15447e07394SAndrew Turner STORE_DBG_WRP(7);
15547e07394SAndrew Turner STORE_DBG_WRP(6);
15647e07394SAndrew Turner STORE_DBG_WRP(5);
15747e07394SAndrew Turner STORE_DBG_WRP(4);
15847e07394SAndrew Turner STORE_DBG_WRP(3);
15947e07394SAndrew Turner STORE_DBG_WRP(2);
16047e07394SAndrew Turner STORE_DBG_WRP(1);
16147e07394SAndrew Turner default:
16247e07394SAndrew Turner STORE_DBG_WRP(0);
16347e07394SAndrew Turner #undef STORE_DBG_WRP
16447e07394SAndrew Turner }
16547e07394SAndrew Turner
16647e07394SAndrew Turner /* Store the PMU registers */
16747e07394SAndrew Turner hypctx->pmcr_el0 = READ_SPECIALREG(pmcr_el0);
16847e07394SAndrew Turner hypctx->pmccntr_el0 = READ_SPECIALREG(pmccntr_el0);
16947e07394SAndrew Turner hypctx->pmccfiltr_el0 = READ_SPECIALREG(pmccfiltr_el0);
17047e07394SAndrew Turner hypctx->pmcntenset_el0 = READ_SPECIALREG(pmcntenset_el0);
17147e07394SAndrew Turner hypctx->pmintenset_el1 = READ_SPECIALREG(pmintenset_el1);
17247e07394SAndrew Turner hypctx->pmovsset_el0 = READ_SPECIALREG(pmovsset_el0);
17347e07394SAndrew Turner hypctx->pmuserenr_el0 = READ_SPECIALREG(pmuserenr_el0);
17447e07394SAndrew Turner switch ((hypctx->pmcr_el0 & PMCR_N_MASK) >> PMCR_N_SHIFT) {
17547e07394SAndrew Turner #define STORE_PMU(x) \
17647e07394SAndrew Turner case (x + 1): \
17747e07394SAndrew Turner hypctx->pmevcntr_el0[x] = \
17847e07394SAndrew Turner READ_SPECIALREG(pmevcntr ## x ## _el0); \
17947e07394SAndrew Turner hypctx->pmevtyper_el0[x] = \
18047e07394SAndrew Turner READ_SPECIALREG(pmevtyper ## x ## _el0)
18147e07394SAndrew Turner STORE_PMU(30);
18247e07394SAndrew Turner STORE_PMU(29);
18347e07394SAndrew Turner STORE_PMU(28);
18447e07394SAndrew Turner STORE_PMU(27);
18547e07394SAndrew Turner STORE_PMU(26);
18647e07394SAndrew Turner STORE_PMU(25);
18747e07394SAndrew Turner STORE_PMU(24);
18847e07394SAndrew Turner STORE_PMU(23);
18947e07394SAndrew Turner STORE_PMU(22);
19047e07394SAndrew Turner STORE_PMU(21);
19147e07394SAndrew Turner STORE_PMU(20);
19247e07394SAndrew Turner STORE_PMU(19);
19347e07394SAndrew Turner STORE_PMU(18);
19447e07394SAndrew Turner STORE_PMU(17);
19547e07394SAndrew Turner STORE_PMU(16);
19647e07394SAndrew Turner STORE_PMU(15);
19747e07394SAndrew Turner STORE_PMU(14);
19847e07394SAndrew Turner STORE_PMU(13);
19947e07394SAndrew Turner STORE_PMU(12);
20047e07394SAndrew Turner STORE_PMU(11);
20147e07394SAndrew Turner STORE_PMU(10);
20247e07394SAndrew Turner STORE_PMU(9);
20347e07394SAndrew Turner STORE_PMU(8);
20447e07394SAndrew Turner STORE_PMU(7);
20547e07394SAndrew Turner STORE_PMU(6);
20647e07394SAndrew Turner STORE_PMU(5);
20747e07394SAndrew Turner STORE_PMU(4);
20847e07394SAndrew Turner STORE_PMU(3);
20947e07394SAndrew Turner STORE_PMU(2);
21047e07394SAndrew Turner STORE_PMU(1);
21147e07394SAndrew Turner STORE_PMU(0);
21247e07394SAndrew Turner default: /* N == 0 when only PMCCNTR_EL0 is available */
21347e07394SAndrew Turner break;
21447e07394SAndrew Turner #undef STORE_PMU
21547e07394SAndrew Turner }
21647e07394SAndrew Turner
21747e07394SAndrew Turner /* Store the special to from the trapframe */
21847e07394SAndrew Turner hypctx->tf.tf_sp = READ_SPECIALREG(sp_el1);
21947e07394SAndrew Turner hypctx->tf.tf_elr = READ_SPECIALREG(elr_el2);
22047e07394SAndrew Turner hypctx->tf.tf_spsr = READ_SPECIALREG(spsr_el2);
22147e07394SAndrew Turner if (guest) {
22247e07394SAndrew Turner hypctx->tf.tf_esr = READ_SPECIALREG(esr_el2);
22320eabb33SAndrew Turner hypctx->par_el1 = READ_SPECIALREG(par_el1);
22447e07394SAndrew Turner }
22547e07394SAndrew Turner
22647e07394SAndrew Turner /* Store the guest special registers */
22747e07394SAndrew Turner hypctx->sp_el0 = READ_SPECIALREG(sp_el0);
22847e07394SAndrew Turner hypctx->tpidr_el0 = READ_SPECIALREG(tpidr_el0);
22947e07394SAndrew Turner hypctx->tpidrro_el0 = READ_SPECIALREG(tpidrro_el0);
23047e07394SAndrew Turner hypctx->tpidr_el1 = READ_SPECIALREG(tpidr_el1);
23147e07394SAndrew Turner
23247e07394SAndrew Turner hypctx->actlr_el1 = READ_SPECIALREG(actlr_el1);
23347e07394SAndrew Turner hypctx->csselr_el1 = READ_SPECIALREG(csselr_el1);
23447e07394SAndrew Turner hypctx->mdccint_el1 = READ_SPECIALREG(mdccint_el1);
23547e07394SAndrew Turner hypctx->mdscr_el1 = READ_SPECIALREG(mdscr_el1);
2367861ecd1SAndrew Turner
2377861ecd1SAndrew Turner if (guest_or_nonvhe(guest)) {
2387861ecd1SAndrew Turner hypctx->elr_el1 = READ_SPECIALREG(EL1_REG(ELR));
2397861ecd1SAndrew Turner hypctx->vbar_el1 = READ_SPECIALREG(EL1_REG(VBAR));
2407861ecd1SAndrew Turner
2417861ecd1SAndrew Turner hypctx->afsr0_el1 = READ_SPECIALREG(EL1_REG(AFSR0));
2427861ecd1SAndrew Turner hypctx->afsr1_el1 = READ_SPECIALREG(EL1_REG(AFSR1));
2437861ecd1SAndrew Turner hypctx->amair_el1 = READ_SPECIALREG(EL1_REG(AMAIR));
2447861ecd1SAndrew Turner hypctx->contextidr_el1 = READ_SPECIALREG(EL1_REG(CONTEXTIDR));
2457861ecd1SAndrew Turner hypctx->cpacr_el1 = READ_SPECIALREG(EL1_REG(CPACR));
2467861ecd1SAndrew Turner hypctx->esr_el1 = READ_SPECIALREG(EL1_REG(ESR));
2477861ecd1SAndrew Turner hypctx->far_el1 = READ_SPECIALREG(EL1_REG(FAR));
2487861ecd1SAndrew Turner hypctx->mair_el1 = READ_SPECIALREG(EL1_REG(MAIR));
2497861ecd1SAndrew Turner hypctx->sctlr_el1 = READ_SPECIALREG(EL1_REG(SCTLR));
2507861ecd1SAndrew Turner hypctx->spsr_el1 = READ_SPECIALREG(EL1_REG(SPSR));
2517861ecd1SAndrew Turner hypctx->tcr_el1 = READ_SPECIALREG(EL1_REG(TCR));
25247e07394SAndrew Turner /* TODO: Support when this is not res0 */
25347e07394SAndrew Turner hypctx->tcr2_el1 = 0;
2547861ecd1SAndrew Turner hypctx->ttbr0_el1 = READ_SPECIALREG(EL1_REG(TTBR0));
2557861ecd1SAndrew Turner hypctx->ttbr1_el1 = READ_SPECIALREG(EL1_REG(TTBR1));
2567861ecd1SAndrew Turner }
25747e07394SAndrew Turner
25847e07394SAndrew Turner hypctx->cptr_el2 = READ_SPECIALREG(cptr_el2);
25947e07394SAndrew Turner hypctx->hcr_el2 = READ_SPECIALREG(hcr_el2);
26047e07394SAndrew Turner hypctx->vpidr_el2 = READ_SPECIALREG(vpidr_el2);
26147e07394SAndrew Turner hypctx->vmpidr_el2 = READ_SPECIALREG(vmpidr_el2);
262*32111003SHarry Moulton
263*32111003SHarry Moulton #ifndef VMM_VHE
264*32111003SHarry Moulton /* hcrx_el2 depends on feat_hcx */
265*32111003SHarry Moulton uint64_t mmfr1 = READ_SPECIALREG(id_aa64mmfr1_el1);
266*32111003SHarry Moulton if (ID_AA64MMFR1_HCX_VAL(mmfr1) >> ID_AA64MMFR1_HCX_SHIFT) {
267*32111003SHarry Moulton hypctx->hcrx_el2 = READ_SPECIALREG(MRS_REG_ALT_NAME(HCRX_EL2));
268*32111003SHarry Moulton }
269*32111003SHarry Moulton #endif
27047e07394SAndrew Turner }
27147e07394SAndrew Turner
27247e07394SAndrew Turner static void
vmm_hyp_reg_restore(struct hypctx * hypctx,struct hyp * hyp,bool guest)27347e07394SAndrew Turner vmm_hyp_reg_restore(struct hypctx *hypctx, struct hyp *hyp, bool guest)
27447e07394SAndrew Turner {
27547e07394SAndrew Turner uint64_t dfr0;
27647e07394SAndrew Turner
27747e07394SAndrew Turner /* Restore the special registers */
2786b17f49dSAndrew Turner WRITE_SPECIALREG(hcr_el2, hypctx->hcr_el2);
279*32111003SHarry Moulton
280*32111003SHarry Moulton if (guest_or_nonvhe(guest)) {
281*32111003SHarry Moulton uint64_t mmfr1 = READ_SPECIALREG(id_aa64mmfr1_el1);
282*32111003SHarry Moulton if (ID_AA64MMFR1_HCX_VAL(mmfr1) >> ID_AA64MMFR1_HCX_SHIFT) {
283*32111003SHarry Moulton WRITE_SPECIALREG(MRS_REG_ALT_NAME(HCRX_EL2), hypctx->hcrx_el2);
284*32111003SHarry Moulton }
285*32111003SHarry Moulton }
2866b17f49dSAndrew Turner isb();
2876b17f49dSAndrew Turner
28847e07394SAndrew Turner WRITE_SPECIALREG(sp_el0, hypctx->sp_el0);
28947e07394SAndrew Turner WRITE_SPECIALREG(tpidr_el0, hypctx->tpidr_el0);
29047e07394SAndrew Turner WRITE_SPECIALREG(tpidrro_el0, hypctx->tpidrro_el0);
29147e07394SAndrew Turner WRITE_SPECIALREG(tpidr_el1, hypctx->tpidr_el1);
29247e07394SAndrew Turner
29347e07394SAndrew Turner WRITE_SPECIALREG(actlr_el1, hypctx->actlr_el1);
29447e07394SAndrew Turner WRITE_SPECIALREG(csselr_el1, hypctx->csselr_el1);
29547e07394SAndrew Turner WRITE_SPECIALREG(mdccint_el1, hypctx->mdccint_el1);
29647e07394SAndrew Turner WRITE_SPECIALREG(mdscr_el1, hypctx->mdscr_el1);
2977861ecd1SAndrew Turner
2987861ecd1SAndrew Turner if (guest_or_nonvhe(guest)) {
2997861ecd1SAndrew Turner WRITE_SPECIALREG(EL1_REG(ELR), hypctx->elr_el1);
3007861ecd1SAndrew Turner WRITE_SPECIALREG(EL1_REG(VBAR), hypctx->vbar_el1);
3017861ecd1SAndrew Turner
3027861ecd1SAndrew Turner WRITE_SPECIALREG(EL1_REG(AFSR0), hypctx->afsr0_el1);
3037861ecd1SAndrew Turner WRITE_SPECIALREG(EL1_REG(AFSR1), hypctx->afsr1_el1);
3047861ecd1SAndrew Turner WRITE_SPECIALREG(EL1_REG(AMAIR), hypctx->amair_el1);
3057861ecd1SAndrew Turner WRITE_SPECIALREG(EL1_REG(CONTEXTIDR), hypctx->contextidr_el1);
3067861ecd1SAndrew Turner WRITE_SPECIALREG(EL1_REG(CPACR), hypctx->cpacr_el1);
3077861ecd1SAndrew Turner WRITE_SPECIALREG(EL1_REG(ESR), hypctx->esr_el1);
3087861ecd1SAndrew Turner WRITE_SPECIALREG(EL1_REG(FAR), hypctx->far_el1);
3097861ecd1SAndrew Turner WRITE_SPECIALREG(EL1_REG(MAIR), hypctx->mair_el1); //
3107861ecd1SAndrew Turner
3117861ecd1SAndrew Turner WRITE_SPECIALREG(EL1_REG(SCTLR), hypctx->sctlr_el1);
3127861ecd1SAndrew Turner WRITE_SPECIALREG(EL1_REG(SPSR), hypctx->spsr_el1);
3137861ecd1SAndrew Turner WRITE_SPECIALREG(EL1_REG(TCR), hypctx->tcr_el1);
31447e07394SAndrew Turner /* TODO: tcr2_el1 */
3157861ecd1SAndrew Turner WRITE_SPECIALREG(EL1_REG(TTBR0), hypctx->ttbr0_el1);
3167861ecd1SAndrew Turner WRITE_SPECIALREG(EL1_REG(TTBR1), hypctx->ttbr1_el1);
3177861ecd1SAndrew Turner }
31847e07394SAndrew Turner
31920eabb33SAndrew Turner if (guest) {
32020eabb33SAndrew Turner WRITE_SPECIALREG(par_el1, hypctx->par_el1);
32120eabb33SAndrew Turner }
32220eabb33SAndrew Turner
32347e07394SAndrew Turner WRITE_SPECIALREG(cptr_el2, hypctx->cptr_el2);
32447e07394SAndrew Turner WRITE_SPECIALREG(vpidr_el2, hypctx->vpidr_el2);
32547e07394SAndrew Turner WRITE_SPECIALREG(vmpidr_el2, hypctx->vmpidr_el2);
32647e07394SAndrew Turner
32747e07394SAndrew Turner /* Load the special regs from the trapframe */
32847e07394SAndrew Turner WRITE_SPECIALREG(sp_el1, hypctx->tf.tf_sp);
32947e07394SAndrew Turner WRITE_SPECIALREG(elr_el2, hypctx->tf.tf_elr);
33047e07394SAndrew Turner WRITE_SPECIALREG(spsr_el2, hypctx->tf.tf_spsr);
33147e07394SAndrew Turner
33247e07394SAndrew Turner /* Restore the PMU registers */
33347e07394SAndrew Turner WRITE_SPECIALREG(pmcr_el0, hypctx->pmcr_el0);
33447e07394SAndrew Turner WRITE_SPECIALREG(pmccntr_el0, hypctx->pmccntr_el0);
33547e07394SAndrew Turner WRITE_SPECIALREG(pmccfiltr_el0, hypctx->pmccfiltr_el0);
33647e07394SAndrew Turner /* Clear all events/interrupts then enable them */
33747e07394SAndrew Turner WRITE_SPECIALREG(pmcntenclr_el0, 0xfffffffful);
33847e07394SAndrew Turner WRITE_SPECIALREG(pmcntenset_el0, hypctx->pmcntenset_el0);
33947e07394SAndrew Turner WRITE_SPECIALREG(pmintenclr_el1, 0xfffffffful);
34047e07394SAndrew Turner WRITE_SPECIALREG(pmintenset_el1, hypctx->pmintenset_el1);
34147e07394SAndrew Turner WRITE_SPECIALREG(pmovsclr_el0, 0xfffffffful);
34247e07394SAndrew Turner WRITE_SPECIALREG(pmovsset_el0, hypctx->pmovsset_el0);
34347e07394SAndrew Turner
34447e07394SAndrew Turner switch ((hypctx->pmcr_el0 & PMCR_N_MASK) >> PMCR_N_SHIFT) {
34547e07394SAndrew Turner #define LOAD_PMU(x) \
34647e07394SAndrew Turner case (x + 1): \
34747e07394SAndrew Turner WRITE_SPECIALREG(pmevcntr ## x ## _el0, \
34847e07394SAndrew Turner hypctx->pmevcntr_el0[x]); \
34947e07394SAndrew Turner WRITE_SPECIALREG(pmevtyper ## x ## _el0, \
35047e07394SAndrew Turner hypctx->pmevtyper_el0[x])
35147e07394SAndrew Turner LOAD_PMU(30);
35247e07394SAndrew Turner LOAD_PMU(29);
35347e07394SAndrew Turner LOAD_PMU(28);
35447e07394SAndrew Turner LOAD_PMU(27);
35547e07394SAndrew Turner LOAD_PMU(26);
35647e07394SAndrew Turner LOAD_PMU(25);
35747e07394SAndrew Turner LOAD_PMU(24);
35847e07394SAndrew Turner LOAD_PMU(23);
35947e07394SAndrew Turner LOAD_PMU(22);
36047e07394SAndrew Turner LOAD_PMU(21);
36147e07394SAndrew Turner LOAD_PMU(20);
36247e07394SAndrew Turner LOAD_PMU(19);
36347e07394SAndrew Turner LOAD_PMU(18);
36447e07394SAndrew Turner LOAD_PMU(17);
36547e07394SAndrew Turner LOAD_PMU(16);
36647e07394SAndrew Turner LOAD_PMU(15);
36747e07394SAndrew Turner LOAD_PMU(14);
36847e07394SAndrew Turner LOAD_PMU(13);
36947e07394SAndrew Turner LOAD_PMU(12);
37047e07394SAndrew Turner LOAD_PMU(11);
37147e07394SAndrew Turner LOAD_PMU(10);
37247e07394SAndrew Turner LOAD_PMU(9);
37347e07394SAndrew Turner LOAD_PMU(8);
37447e07394SAndrew Turner LOAD_PMU(7);
37547e07394SAndrew Turner LOAD_PMU(6);
37647e07394SAndrew Turner LOAD_PMU(5);
37747e07394SAndrew Turner LOAD_PMU(4);
37847e07394SAndrew Turner LOAD_PMU(3);
37947e07394SAndrew Turner LOAD_PMU(2);
38047e07394SAndrew Turner LOAD_PMU(1);
38147e07394SAndrew Turner LOAD_PMU(0);
38247e07394SAndrew Turner default: /* N == 0 when only PMCCNTR_EL0 is available */
38347e07394SAndrew Turner break;
38447e07394SAndrew Turner #undef LOAD_PMU
38547e07394SAndrew Turner }
38647e07394SAndrew Turner
38747e07394SAndrew Turner dfr0 = READ_SPECIALREG(id_aa64dfr0_el1);
38847e07394SAndrew Turner switch (ID_AA64DFR0_BRPs_VAL(dfr0) - 1) {
38947e07394SAndrew Turner #define LOAD_DBG_BRP(x) \
39047e07394SAndrew Turner case x: \
39147e07394SAndrew Turner WRITE_SPECIALREG(dbgbcr ## x ## _el1, \
39247e07394SAndrew Turner hypctx->dbgbcr_el1[x]); \
39347e07394SAndrew Turner WRITE_SPECIALREG(dbgbvr ## x ## _el1, \
39447e07394SAndrew Turner hypctx->dbgbvr_el1[x])
39547e07394SAndrew Turner LOAD_DBG_BRP(15);
39647e07394SAndrew Turner LOAD_DBG_BRP(14);
39747e07394SAndrew Turner LOAD_DBG_BRP(13);
39847e07394SAndrew Turner LOAD_DBG_BRP(12);
39947e07394SAndrew Turner LOAD_DBG_BRP(11);
40047e07394SAndrew Turner LOAD_DBG_BRP(10);
40147e07394SAndrew Turner LOAD_DBG_BRP(9);
40247e07394SAndrew Turner LOAD_DBG_BRP(8);
40347e07394SAndrew Turner LOAD_DBG_BRP(7);
40447e07394SAndrew Turner LOAD_DBG_BRP(6);
40547e07394SAndrew Turner LOAD_DBG_BRP(5);
40647e07394SAndrew Turner LOAD_DBG_BRP(4);
40747e07394SAndrew Turner LOAD_DBG_BRP(3);
40847e07394SAndrew Turner LOAD_DBG_BRP(2);
40947e07394SAndrew Turner LOAD_DBG_BRP(1);
41047e07394SAndrew Turner default:
41147e07394SAndrew Turner LOAD_DBG_BRP(0);
41247e07394SAndrew Turner #undef LOAD_DBG_BRP
41347e07394SAndrew Turner }
41447e07394SAndrew Turner
41547e07394SAndrew Turner switch (ID_AA64DFR0_WRPs_VAL(dfr0) - 1) {
41647e07394SAndrew Turner #define LOAD_DBG_WRP(x) \
41747e07394SAndrew Turner case x: \
41847e07394SAndrew Turner WRITE_SPECIALREG(dbgwcr ## x ## _el1, \
41947e07394SAndrew Turner hypctx->dbgwcr_el1[x]); \
42047e07394SAndrew Turner WRITE_SPECIALREG(dbgwvr ## x ## _el1, \
42147e07394SAndrew Turner hypctx->dbgwvr_el1[x])
42247e07394SAndrew Turner LOAD_DBG_WRP(15);
42347e07394SAndrew Turner LOAD_DBG_WRP(14);
42447e07394SAndrew Turner LOAD_DBG_WRP(13);
42547e07394SAndrew Turner LOAD_DBG_WRP(12);
42647e07394SAndrew Turner LOAD_DBG_WRP(11);
42747e07394SAndrew Turner LOAD_DBG_WRP(10);
42847e07394SAndrew Turner LOAD_DBG_WRP(9);
42947e07394SAndrew Turner LOAD_DBG_WRP(8);
43047e07394SAndrew Turner LOAD_DBG_WRP(7);
43147e07394SAndrew Turner LOAD_DBG_WRP(6);
43247e07394SAndrew Turner LOAD_DBG_WRP(5);
43347e07394SAndrew Turner LOAD_DBG_WRP(4);
43447e07394SAndrew Turner LOAD_DBG_WRP(3);
43547e07394SAndrew Turner LOAD_DBG_WRP(2);
43647e07394SAndrew Turner LOAD_DBG_WRP(1);
43747e07394SAndrew Turner default:
43847e07394SAndrew Turner LOAD_DBG_WRP(0);
43947e07394SAndrew Turner #undef LOAD_DBG_WRP
44047e07394SAndrew Turner }
44147e07394SAndrew Turner
44247e07394SAndrew Turner if (guest) {
44347e07394SAndrew Turner /* Load the timer registers */
4447861ecd1SAndrew Turner WRITE_SPECIALREG(EL1_REG(CNTKCTL),
4457861ecd1SAndrew Turner hypctx->vtimer_cpu.cntkctl_el1);
4467861ecd1SAndrew Turner WRITE_SPECIALREG(EL0_REG(CNTV_CVAL),
44747e07394SAndrew Turner hypctx->vtimer_cpu.virt_timer.cntx_cval_el0);
4487861ecd1SAndrew Turner WRITE_SPECIALREG(EL0_REG(CNTV_CTL),
44947e07394SAndrew Turner hypctx->vtimer_cpu.virt_timer.cntx_ctl_el0);
45047e07394SAndrew Turner WRITE_SPECIALREG(cnthctl_el2, hyp->vtimer.cnthctl_el2);
45147e07394SAndrew Turner WRITE_SPECIALREG(cntvoff_el2, hyp->vtimer.cntvoff_el2);
45247e07394SAndrew Turner
45347e07394SAndrew Turner /* Load the GICv3 registers */
45447e07394SAndrew Turner WRITE_SPECIALREG(ich_hcr_el2, hypctx->vgic_v3_regs.ich_hcr_el2);
45547e07394SAndrew Turner WRITE_SPECIALREG(ich_vmcr_el2,
45647e07394SAndrew Turner hypctx->vgic_v3_regs.ich_vmcr_el2);
45747e07394SAndrew Turner switch (hypctx->vgic_v3_regs.ich_lr_num - 1) {
45847e07394SAndrew Turner #define LOAD_LR(x) \
45947e07394SAndrew Turner case x: \
46047e07394SAndrew Turner WRITE_SPECIALREG(ich_lr ## x ##_el2, \
46147e07394SAndrew Turner hypctx->vgic_v3_regs.ich_lr_el2[x])
46247e07394SAndrew Turner LOAD_LR(15);
46347e07394SAndrew Turner LOAD_LR(14);
46447e07394SAndrew Turner LOAD_LR(13);
46547e07394SAndrew Turner LOAD_LR(12);
46647e07394SAndrew Turner LOAD_LR(11);
46747e07394SAndrew Turner LOAD_LR(10);
46847e07394SAndrew Turner LOAD_LR(9);
46947e07394SAndrew Turner LOAD_LR(8);
47047e07394SAndrew Turner LOAD_LR(7);
47147e07394SAndrew Turner LOAD_LR(6);
47247e07394SAndrew Turner LOAD_LR(5);
47347e07394SAndrew Turner LOAD_LR(4);
47447e07394SAndrew Turner LOAD_LR(3);
47547e07394SAndrew Turner LOAD_LR(2);
47647e07394SAndrew Turner LOAD_LR(1);
47747e07394SAndrew Turner default:
47847e07394SAndrew Turner LOAD_LR(0);
47947e07394SAndrew Turner #undef LOAD_LR
48047e07394SAndrew Turner }
48147e07394SAndrew Turner
48247e07394SAndrew Turner switch (hypctx->vgic_v3_regs.ich_apr_num - 1) {
48347e07394SAndrew Turner #define LOAD_APR(x) \
48447e07394SAndrew Turner case x: \
48547e07394SAndrew Turner WRITE_SPECIALREG(ich_ap0r ## x ##_el2, \
48647e07394SAndrew Turner hypctx->vgic_v3_regs.ich_ap0r_el2[x]); \
48747e07394SAndrew Turner WRITE_SPECIALREG(ich_ap1r ## x ##_el2, \
48847e07394SAndrew Turner hypctx->vgic_v3_regs.ich_ap1r_el2[x])
48947e07394SAndrew Turner LOAD_APR(3);
49047e07394SAndrew Turner LOAD_APR(2);
49147e07394SAndrew Turner LOAD_APR(1);
49247e07394SAndrew Turner default:
49347e07394SAndrew Turner LOAD_APR(0);
49447e07394SAndrew Turner #undef LOAD_APR
49547e07394SAndrew Turner }
49647e07394SAndrew Turner }
49747e07394SAndrew Turner }
49847e07394SAndrew Turner
49947e07394SAndrew Turner static uint64_t
vmm_hyp_call_guest(struct hyp * hyp,struct hypctx * hypctx)50047e07394SAndrew Turner vmm_hyp_call_guest(struct hyp *hyp, struct hypctx *hypctx)
50147e07394SAndrew Turner {
50247e07394SAndrew Turner struct hypctx host_hypctx;
50347e07394SAndrew Turner uint64_t cntvoff_el2;
50447e07394SAndrew Turner uint64_t ich_hcr_el2, ich_vmcr_el2, cnthctl_el2, cntkctl_el1;
50547e07394SAndrew Turner uint64_t ret;
50647e07394SAndrew Turner uint64_t s1e1r, hpfar_el2;
50747e07394SAndrew Turner bool hpfar_valid;
50847e07394SAndrew Turner
50947e07394SAndrew Turner vmm_hyp_reg_store(&host_hypctx, NULL, false);
51047e07394SAndrew Turner
51147e07394SAndrew Turner /* Save the host special registers */
51247e07394SAndrew Turner cnthctl_el2 = READ_SPECIALREG(cnthctl_el2);
51347e07394SAndrew Turner cntkctl_el1 = READ_SPECIALREG(cntkctl_el1);
51447e07394SAndrew Turner cntvoff_el2 = READ_SPECIALREG(cntvoff_el2);
51547e07394SAndrew Turner
51647e07394SAndrew Turner ich_hcr_el2 = READ_SPECIALREG(ich_hcr_el2);
51747e07394SAndrew Turner ich_vmcr_el2 = READ_SPECIALREG(ich_vmcr_el2);
51847e07394SAndrew Turner
51947e07394SAndrew Turner vmm_hyp_reg_restore(hypctx, hyp, true);
52047e07394SAndrew Turner
52147e07394SAndrew Turner /* Load the common hypervisor registers */
52247e07394SAndrew Turner WRITE_SPECIALREG(vttbr_el2, hyp->vttbr_el2);
52347e07394SAndrew Turner
52447e07394SAndrew Turner host_hypctx.mdcr_el2 = READ_SPECIALREG(mdcr_el2);
52547e07394SAndrew Turner WRITE_SPECIALREG(mdcr_el2, hypctx->mdcr_el2);
52647e07394SAndrew Turner
52747e07394SAndrew Turner /* Call into the guest */
5283d61bcf1SAndrew Turner ret = VMM_HYP_FUNC(do_call_guest)(hypctx);
52947e07394SAndrew Turner
53047e07394SAndrew Turner WRITE_SPECIALREG(mdcr_el2, host_hypctx.mdcr_el2);
53147e07394SAndrew Turner isb();
53247e07394SAndrew Turner
53347e07394SAndrew Turner /* Store the exit info */
53447e07394SAndrew Turner hypctx->exit_info.far_el2 = READ_SPECIALREG(far_el2);
53547e07394SAndrew Turner vmm_hyp_reg_store(hypctx, hyp, true);
53647e07394SAndrew Turner
53747e07394SAndrew Turner hpfar_valid = true;
53847e07394SAndrew Turner if (ret == EXCP_TYPE_EL1_SYNC) {
53947e07394SAndrew Turner switch (ESR_ELx_EXCEPTION(hypctx->tf.tf_esr)) {
54047e07394SAndrew Turner case EXCP_INSN_ABORT_L:
54147e07394SAndrew Turner case EXCP_DATA_ABORT_L:
54247e07394SAndrew Turner /*
54347e07394SAndrew Turner * The hpfar_el2 register is valid for:
54447e07394SAndrew Turner * - Translation and Access faults.
54547e07394SAndrew Turner * - Translation, Access, and permission faults on
54647e07394SAndrew Turner * the translation table walk on the stage 1 tables.
54747e07394SAndrew Turner * - A stage 2 Address size fault.
54847e07394SAndrew Turner *
54947e07394SAndrew Turner * As we only need it in the first 2 cases we can just
55047e07394SAndrew Turner * exclude it on permission faults that are not from
55147e07394SAndrew Turner * the stage 1 table walk.
55247e07394SAndrew Turner *
55347e07394SAndrew Turner * TODO: Add a case for Arm erratum 834220.
55447e07394SAndrew Turner */
55547e07394SAndrew Turner if ((hypctx->tf.tf_esr & ISS_DATA_S1PTW) != 0)
55647e07394SAndrew Turner break;
55747e07394SAndrew Turner switch (hypctx->tf.tf_esr & ISS_DATA_DFSC_MASK) {
55847e07394SAndrew Turner case ISS_DATA_DFSC_PF_L1:
55947e07394SAndrew Turner case ISS_DATA_DFSC_PF_L2:
56047e07394SAndrew Turner case ISS_DATA_DFSC_PF_L3:
56147e07394SAndrew Turner hpfar_valid = false;
56247e07394SAndrew Turner break;
56347e07394SAndrew Turner }
56447e07394SAndrew Turner break;
56547e07394SAndrew Turner }
56647e07394SAndrew Turner }
56747e07394SAndrew Turner if (hpfar_valid) {
56847e07394SAndrew Turner hypctx->exit_info.hpfar_el2 = READ_SPECIALREG(hpfar_el2);
56947e07394SAndrew Turner } else {
57047e07394SAndrew Turner /*
57147e07394SAndrew Turner * TODO: There is a risk the at instruction could cause an
57247e07394SAndrew Turner * exception here. We should handle it & return a failure.
57347e07394SAndrew Turner */
57447e07394SAndrew Turner s1e1r =
57547e07394SAndrew Turner arm64_address_translate_s1e1r(hypctx->exit_info.far_el2);
57647e07394SAndrew Turner if (PAR_SUCCESS(s1e1r)) {
57747e07394SAndrew Turner hpfar_el2 = (s1e1r & PAR_PA_MASK) >> PAR_PA_SHIFT;
57847e07394SAndrew Turner hpfar_el2 <<= HPFAR_EL2_FIPA_SHIFT;
57947e07394SAndrew Turner hypctx->exit_info.hpfar_el2 = hpfar_el2;
58047e07394SAndrew Turner } else {
58147e07394SAndrew Turner ret = EXCP_TYPE_REENTER;
58247e07394SAndrew Turner }
58347e07394SAndrew Turner }
58447e07394SAndrew Turner
58547e07394SAndrew Turner vmm_hyp_reg_restore(&host_hypctx, NULL, false);
58647e07394SAndrew Turner
58747e07394SAndrew Turner /* Restore the host special registers */
58847e07394SAndrew Turner WRITE_SPECIALREG(ich_hcr_el2, ich_hcr_el2);
58947e07394SAndrew Turner WRITE_SPECIALREG(ich_vmcr_el2, ich_vmcr_el2);
59047e07394SAndrew Turner
59147e07394SAndrew Turner WRITE_SPECIALREG(cnthctl_el2, cnthctl_el2);
59247e07394SAndrew Turner WRITE_SPECIALREG(cntkctl_el1, cntkctl_el1);
59347e07394SAndrew Turner WRITE_SPECIALREG(cntvoff_el2, cntvoff_el2);
59447e07394SAndrew Turner
59547e07394SAndrew Turner return (ret);
59647e07394SAndrew Turner }
59747e07394SAndrew Turner
5983d61bcf1SAndrew Turner VMM_STATIC uint64_t
VMM_HYP_FUNC(enter_guest)5993d61bcf1SAndrew Turner VMM_HYP_FUNC(enter_guest)(struct hyp *hyp, struct hypctx *hypctx)
6003d61bcf1SAndrew Turner {
6013d61bcf1SAndrew Turner uint64_t ret;
6023d61bcf1SAndrew Turner
6033d61bcf1SAndrew Turner do {
6043d61bcf1SAndrew Turner ret = vmm_hyp_call_guest(hyp, hypctx);
6053d61bcf1SAndrew Turner } while (ret == EXCP_TYPE_REENTER);
6063d61bcf1SAndrew Turner
6073d61bcf1SAndrew Turner return (ret);
6083d61bcf1SAndrew Turner }
6093d61bcf1SAndrew Turner
6103d61bcf1SAndrew Turner VMM_STATIC uint64_t
VMM_HYP_FUNC(read_reg)6113d61bcf1SAndrew Turner VMM_HYP_FUNC(read_reg)(uint64_t reg)
61247e07394SAndrew Turner {
61347e07394SAndrew Turner switch (reg) {
61447e07394SAndrew Turner case HYP_REG_ICH_VTR:
61547e07394SAndrew Turner return (READ_SPECIALREG(ich_vtr_el2));
61647e07394SAndrew Turner case HYP_REG_CNTHCTL:
61747e07394SAndrew Turner return (READ_SPECIALREG(cnthctl_el2));
61847e07394SAndrew Turner }
61947e07394SAndrew Turner
62047e07394SAndrew Turner return (0);
62147e07394SAndrew Turner }
62247e07394SAndrew Turner
6233d61bcf1SAndrew Turner VMM_STATIC void
VMM_HYP_FUNC(clean_s2_tlbi)6243d61bcf1SAndrew Turner VMM_HYP_FUNC(clean_s2_tlbi)(void)
62547e07394SAndrew Turner {
62647e07394SAndrew Turner dsb(ishst);
62747e07394SAndrew Turner __asm __volatile("tlbi alle1is");
62847e07394SAndrew Turner dsb(ish);
62947e07394SAndrew Turner }
63047e07394SAndrew Turner
6313d61bcf1SAndrew Turner VMM_STATIC void
VMM_HYP_FUNC(s2_tlbi_range)6323d61bcf1SAndrew Turner VMM_HYP_FUNC(s2_tlbi_range)(uint64_t vttbr, vm_offset_t sva, vm_offset_t eva,
63347e07394SAndrew Turner bool final_only)
63447e07394SAndrew Turner {
63547e07394SAndrew Turner uint64_t end, r, start;
63647e07394SAndrew Turner uint64_t host_vttbr;
6375577bb2fSAndrew Turner #ifdef VMM_VHE
6385577bb2fSAndrew Turner uint64_t host_tcr;
6395577bb2fSAndrew Turner #endif
6405577bb2fSAndrew Turner
6415577bb2fSAndrew Turner #ifdef VMM_VHE
6425577bb2fSAndrew Turner dsb(ishst);
6435577bb2fSAndrew Turner #endif
64447e07394SAndrew Turner
64547e07394SAndrew Turner #define TLBI_VA_SHIFT 12
64647e07394SAndrew Turner #define TLBI_VA_MASK ((1ul << 44) - 1)
64747e07394SAndrew Turner #define TLBI_VA(addr) (((addr) >> TLBI_VA_SHIFT) & TLBI_VA_MASK)
64847e07394SAndrew Turner #define TLBI_VA_L3_INCR (L3_SIZE >> TLBI_VA_SHIFT)
64947e07394SAndrew Turner
65047e07394SAndrew Turner /* Switch to the guest vttbr */
65147e07394SAndrew Turner /* TODO: Handle Cortex-A57/A72 erratum 131936 */
65247e07394SAndrew Turner host_vttbr = READ_SPECIALREG(vttbr_el2);
65347e07394SAndrew Turner WRITE_SPECIALREG(vttbr_el2, vttbr);
65447e07394SAndrew Turner isb();
65547e07394SAndrew Turner
6565577bb2fSAndrew Turner #ifdef VMM_VHE
6575577bb2fSAndrew Turner host_tcr = READ_SPECIALREG(tcr_el2);
6585577bb2fSAndrew Turner WRITE_SPECIALREG(tcr_el2, host_tcr & ~HCR_TGE);
6595577bb2fSAndrew Turner isb();
6605577bb2fSAndrew Turner #endif
6615577bb2fSAndrew Turner
66247e07394SAndrew Turner /*
66347e07394SAndrew Turner * The CPU can cache the stage 1 + 2 combination so we need to ensure
66447e07394SAndrew Turner * the stage 2 is invalidated first, then when this has completed we
66547e07394SAndrew Turner * invalidate the stage 1 TLB. As we don't know which stage 1 virtual
66647e07394SAndrew Turner * addresses point at the stage 2 IPA we need to invalidate the entire
66747e07394SAndrew Turner * stage 1 TLB.
66847e07394SAndrew Turner */
66947e07394SAndrew Turner
67047e07394SAndrew Turner start = TLBI_VA(sva);
67147e07394SAndrew Turner end = TLBI_VA(eva);
67247e07394SAndrew Turner for (r = start; r < end; r += TLBI_VA_L3_INCR) {
67347e07394SAndrew Turner /* Invalidate the stage 2 TLB entry */
67447e07394SAndrew Turner if (final_only)
67547e07394SAndrew Turner __asm __volatile("tlbi ipas2le1is, %0" : : "r"(r));
67647e07394SAndrew Turner else
67747e07394SAndrew Turner __asm __volatile("tlbi ipas2e1is, %0" : : "r"(r));
67847e07394SAndrew Turner }
67947e07394SAndrew Turner /* Ensure the entry has been invalidated */
68047e07394SAndrew Turner dsb(ish);
68147e07394SAndrew Turner /* Invalidate the stage 1 TLB. */
68247e07394SAndrew Turner __asm __volatile("tlbi vmalle1is");
68347e07394SAndrew Turner dsb(ish);
68447e07394SAndrew Turner isb();
68547e07394SAndrew Turner
6865577bb2fSAndrew Turner #ifdef VMM_VHE
6875577bb2fSAndrew Turner WRITE_SPECIALREG(tcr_el2, host_tcr);
6885577bb2fSAndrew Turner isb();
6895577bb2fSAndrew Turner #endif
6905577bb2fSAndrew Turner
69147e07394SAndrew Turner /* Switch back to the host vttbr */
69247e07394SAndrew Turner WRITE_SPECIALREG(vttbr_el2, host_vttbr);
69347e07394SAndrew Turner isb();
69447e07394SAndrew Turner }
69547e07394SAndrew Turner
6963d61bcf1SAndrew Turner VMM_STATIC void
VMM_HYP_FUNC(s2_tlbi_all)6973d61bcf1SAndrew Turner VMM_HYP_FUNC(s2_tlbi_all)(uint64_t vttbr)
69847e07394SAndrew Turner {
69947e07394SAndrew Turner uint64_t host_vttbr;
70047e07394SAndrew Turner
7015577bb2fSAndrew Turner #ifdef VMM_VHE
7025577bb2fSAndrew Turner dsb(ishst);
7035577bb2fSAndrew Turner #endif
7045577bb2fSAndrew Turner
70547e07394SAndrew Turner /* Switch to the guest vttbr */
70647e07394SAndrew Turner /* TODO: Handle Cortex-A57/A72 erratum 131936 */
70747e07394SAndrew Turner host_vttbr = READ_SPECIALREG(vttbr_el2);
70847e07394SAndrew Turner WRITE_SPECIALREG(vttbr_el2, vttbr);
70947e07394SAndrew Turner isb();
71047e07394SAndrew Turner
71147e07394SAndrew Turner __asm __volatile("tlbi vmalls12e1is");
71247e07394SAndrew Turner dsb(ish);
71347e07394SAndrew Turner isb();
71447e07394SAndrew Turner
71547e07394SAndrew Turner /* Switch back t othe host vttbr */
71647e07394SAndrew Turner WRITE_SPECIALREG(vttbr_el2, host_vttbr);
71747e07394SAndrew Turner isb();
71847e07394SAndrew Turner }
719