xref: /freebsd/sys/arm64/vmm/vmm_hyp.c (revision 32111003c3087389cc5e50949ee3a26c4e7b26c4)
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