147e07394SAndrew Turner /*-
247e07394SAndrew Turner * SPDX-License-Identifier: BSD-2-Clause
347e07394SAndrew Turner *
447e07394SAndrew Turner * Copyright (C) 2018 Alexandru Elisei <alexandru.elisei@gmail.com>
547e07394SAndrew Turner *
647e07394SAndrew Turner * Redistribution and use in source and binary forms, with or without
747e07394SAndrew Turner * modification, are permitted provided that the following conditions
847e07394SAndrew Turner * are met:
947e07394SAndrew Turner * 1. Redistributions of source code must retain the above copyright
1047e07394SAndrew Turner * notice, this list of conditions and the following disclaimer.
1147e07394SAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright
1247e07394SAndrew Turner * notice, this list of conditions and the following disclaimer in the
1347e07394SAndrew Turner * documentation and/or other materials provided with the distribution.
1447e07394SAndrew Turner *
1547e07394SAndrew Turner * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1647e07394SAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1747e07394SAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1847e07394SAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
1947e07394SAndrew Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2047e07394SAndrew Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2147e07394SAndrew Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2247e07394SAndrew Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2347e07394SAndrew Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2447e07394SAndrew Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2547e07394SAndrew Turner * SUCH DAMAGE.
2647e07394SAndrew Turner */
2747e07394SAndrew Turner
2847e07394SAndrew Turner #include <sys/cdefs.h>
2947e07394SAndrew Turner #include <sys/types.h>
3047e07394SAndrew Turner #include <sys/systm.h>
3147e07394SAndrew Turner #include <sys/kernel.h>
3247e07394SAndrew Turner #include <sys/lock.h>
3347e07394SAndrew Turner
3447e07394SAndrew Turner #include <machine/armreg.h>
3547e07394SAndrew Turner #include <machine/cpu.h>
3647e07394SAndrew Turner #include <machine/hypervisor.h>
3747e07394SAndrew Turner
3847e07394SAndrew Turner #include "arm64.h"
3947e07394SAndrew Turner #include "reset.h"
4047e07394SAndrew Turner
4147e07394SAndrew Turner /*
4247e07394SAndrew Turner * Make the architecturally UNKNOWN value 0. As a bonus, we don't have to
4347e07394SAndrew Turner * manually set all those RES0 fields.
4447e07394SAndrew Turner */
4547e07394SAndrew Turner #define ARCH_UNKNOWN 0
4647e07394SAndrew Turner #define set_arch_unknown(reg) (memset(&(reg), ARCH_UNKNOWN, sizeof(reg)))
4747e07394SAndrew Turner
4847e07394SAndrew Turner void
reset_vm_el01_regs(void * vcpu)4947e07394SAndrew Turner reset_vm_el01_regs(void *vcpu)
5047e07394SAndrew Turner {
5147e07394SAndrew Turner struct hypctx *el2ctx;
5247e07394SAndrew Turner
5347e07394SAndrew Turner el2ctx = vcpu;
5447e07394SAndrew Turner
5547e07394SAndrew Turner set_arch_unknown(el2ctx->tf);
5647e07394SAndrew Turner
5747e07394SAndrew Turner set_arch_unknown(el2ctx->actlr_el1);
5847e07394SAndrew Turner set_arch_unknown(el2ctx->afsr0_el1);
5947e07394SAndrew Turner set_arch_unknown(el2ctx->afsr1_el1);
6047e07394SAndrew Turner set_arch_unknown(el2ctx->amair_el1);
6147e07394SAndrew Turner set_arch_unknown(el2ctx->contextidr_el1);
6247e07394SAndrew Turner set_arch_unknown(el2ctx->cpacr_el1);
6347e07394SAndrew Turner set_arch_unknown(el2ctx->csselr_el1);
6447e07394SAndrew Turner set_arch_unknown(el2ctx->elr_el1);
6547e07394SAndrew Turner set_arch_unknown(el2ctx->esr_el1);
6647e07394SAndrew Turner set_arch_unknown(el2ctx->far_el1);
6747e07394SAndrew Turner set_arch_unknown(el2ctx->mair_el1);
6847e07394SAndrew Turner set_arch_unknown(el2ctx->mdccint_el1);
6947e07394SAndrew Turner set_arch_unknown(el2ctx->mdscr_el1);
7047e07394SAndrew Turner set_arch_unknown(el2ctx->par_el1);
7147e07394SAndrew Turner
7247e07394SAndrew Turner /*
7347e07394SAndrew Turner * Guest starts with:
7447e07394SAndrew Turner * ~SCTLR_M: MMU off
7547e07394SAndrew Turner * ~SCTLR_C: data cache off
7647e07394SAndrew Turner * SCTLR_CP15BEN: memory barrier instruction enable from EL0; RAO/WI
7747e07394SAndrew Turner * ~SCTLR_I: instruction cache off
7847e07394SAndrew Turner */
7947e07394SAndrew Turner el2ctx->sctlr_el1 = SCTLR_RES1;
8047e07394SAndrew Turner el2ctx->sctlr_el1 &= ~SCTLR_M & ~SCTLR_C & ~SCTLR_I;
8147e07394SAndrew Turner el2ctx->sctlr_el1 |= SCTLR_CP15BEN;
8247e07394SAndrew Turner
8347e07394SAndrew Turner set_arch_unknown(el2ctx->sp_el0);
8447e07394SAndrew Turner set_arch_unknown(el2ctx->tcr_el1);
8547e07394SAndrew Turner set_arch_unknown(el2ctx->tpidr_el0);
8647e07394SAndrew Turner set_arch_unknown(el2ctx->tpidr_el1);
8747e07394SAndrew Turner set_arch_unknown(el2ctx->tpidrro_el0);
8847e07394SAndrew Turner set_arch_unknown(el2ctx->ttbr0_el1);
8947e07394SAndrew Turner set_arch_unknown(el2ctx->ttbr1_el1);
9047e07394SAndrew Turner set_arch_unknown(el2ctx->vbar_el1);
9147e07394SAndrew Turner set_arch_unknown(el2ctx->spsr_el1);
9247e07394SAndrew Turner
9347e07394SAndrew Turner set_arch_unknown(el2ctx->dbgbcr_el1);
9447e07394SAndrew Turner set_arch_unknown(el2ctx->dbgbvr_el1);
9547e07394SAndrew Turner set_arch_unknown(el2ctx->dbgwcr_el1);
9647e07394SAndrew Turner set_arch_unknown(el2ctx->dbgwvr_el1);
9747e07394SAndrew Turner
9847e07394SAndrew Turner el2ctx->pmcr_el0 = READ_SPECIALREG(pmcr_el0) & PMCR_N_MASK;
9947e07394SAndrew Turner /* PMCR_LC is unknown when AArch32 is supported or RES1 otherwise */
10047e07394SAndrew Turner el2ctx->pmcr_el0 |= PMCR_LC;
10147e07394SAndrew Turner set_arch_unknown(el2ctx->pmccntr_el0);
10247e07394SAndrew Turner set_arch_unknown(el2ctx->pmccfiltr_el0);
10347e07394SAndrew Turner set_arch_unknown(el2ctx->pmcntenset_el0);
10447e07394SAndrew Turner set_arch_unknown(el2ctx->pmintenset_el1);
10547e07394SAndrew Turner set_arch_unknown(el2ctx->pmovsset_el0);
10647e07394SAndrew Turner set_arch_unknown(el2ctx->pmuserenr_el0);
10747e07394SAndrew Turner memset(el2ctx->pmevcntr_el0, 0, sizeof(el2ctx->pmevcntr_el0));
10847e07394SAndrew Turner memset(el2ctx->pmevtyper_el0, 0, sizeof(el2ctx->pmevtyper_el0));
10947e07394SAndrew Turner }
11047e07394SAndrew Turner
11147e07394SAndrew Turner void
reset_vm_el2_regs(void * vcpu)11247e07394SAndrew Turner reset_vm_el2_regs(void *vcpu)
11347e07394SAndrew Turner {
11447e07394SAndrew Turner struct hypctx *el2ctx;
11547e07394SAndrew Turner uint64_t cpu_aff, vcpuid;
11647e07394SAndrew Turner
11747e07394SAndrew Turner el2ctx = vcpu;
11847e07394SAndrew Turner vcpuid = vcpu_vcpuid(el2ctx->vcpu);
11947e07394SAndrew Turner
12047e07394SAndrew Turner /*
12147e07394SAndrew Turner * Set the Hypervisor Configuration Register:
12247e07394SAndrew Turner *
12347e07394SAndrew Turner * HCR_RW: use AArch64 for EL1
12447e07394SAndrew Turner * HCR_TID3: handle ID registers in the vmm to privide a common
12547e07394SAndrew Turner * set of featers on all vcpus
12647e07394SAndrew Turner * HCR_TWI: Trap WFI to the hypervisor
12747e07394SAndrew Turner * HCR_BSU_IS: barrier instructions apply to the inner shareable
12847e07394SAndrew Turner * domain
12947e07394SAndrew Turner * HCR_FB: broadcast maintenance operations
13047e07394SAndrew Turner * HCR_AMO: route physical SError interrupts to EL2
13147e07394SAndrew Turner * HCR_IMO: route physical IRQ interrupts to EL2
13247e07394SAndrew Turner * HCR_FMO: route physical FIQ interrupts to EL2
13347e07394SAndrew Turner * HCR_SWIO: turn set/way invalidate into set/way clean and
13447e07394SAndrew Turner * invalidate
13547e07394SAndrew Turner * HCR_VM: use stage 2 translation
13647e07394SAndrew Turner */
13747e07394SAndrew Turner el2ctx->hcr_el2 = HCR_RW | HCR_TID3 | HCR_TWI | HCR_BSU_IS | HCR_FB |
13847e07394SAndrew Turner HCR_AMO | HCR_IMO | HCR_FMO | HCR_SWIO | HCR_VM;
139387f878aSAndrew Turner if (in_vhe()) {
140387f878aSAndrew Turner el2ctx->hcr_el2 |= HCR_E2H;
141387f878aSAndrew Turner }
14247e07394SAndrew Turner
143*32111003SHarry Moulton /* Set the Extended Hypervisor Configuration Register */
144*32111003SHarry Moulton el2ctx->hcrx_el2 = 0;
14547e07394SAndrew Turner /* TODO: Trap all extensions we don't support */
14647e07394SAndrew Turner el2ctx->mdcr_el2 = 0;
14747e07394SAndrew Turner /* PMCR_EL0.N is read from MDCR_EL2.HPMN */
14847e07394SAndrew Turner el2ctx->mdcr_el2 |= (el2ctx->pmcr_el0 & PMCR_N_MASK) >> PMCR_N_SHIFT;
14947e07394SAndrew Turner
15047e07394SAndrew Turner el2ctx->vmpidr_el2 = VMPIDR_EL2_RES1;
15147e07394SAndrew Turner /* The guest will detect a multi-core, single-threaded CPU */
15247e07394SAndrew Turner el2ctx->vmpidr_el2 &= ~VMPIDR_EL2_U & ~VMPIDR_EL2_MT;
15347e07394SAndrew Turner /*
15447e07394SAndrew Turner * Generate the guest MPIDR value. We only support 16 CPUs at affinity
15547e07394SAndrew Turner * level 0 to simplify the vgicv3 driver (see writing sgi1r_el1).
15647e07394SAndrew Turner */
15747e07394SAndrew Turner cpu_aff = (vcpuid & 0xf) << MPIDR_AFF0_SHIFT |
15847e07394SAndrew Turner ((vcpuid >> 4) & 0xff) << MPIDR_AFF1_SHIFT |
15947e07394SAndrew Turner ((vcpuid >> 12) & 0xff) << MPIDR_AFF2_SHIFT |
16047e07394SAndrew Turner ((vcpuid >> 20) & 0xff) << MPIDR_AFF3_SHIFT;
16147e07394SAndrew Turner el2ctx->vmpidr_el2 |= cpu_aff;
16247e07394SAndrew Turner
16347e07394SAndrew Turner /* Use the same CPU identification information as the host */
16447e07394SAndrew Turner el2ctx->vpidr_el2 = CPU_IMPL_TO_MIDR(CPU_IMPL_ARM);
16547e07394SAndrew Turner el2ctx->vpidr_el2 |= CPU_VAR_TO_MIDR(0);
16647e07394SAndrew Turner el2ctx->vpidr_el2 |= CPU_ARCH_TO_MIDR(0xf);
16747e07394SAndrew Turner el2ctx->vpidr_el2 |= CPU_PART_TO_MIDR(CPU_PART_FOUNDATION);
16847e07394SAndrew Turner el2ctx->vpidr_el2 |= CPU_REV_TO_MIDR(0);
16947e07394SAndrew Turner
17047e07394SAndrew Turner /*
17147e07394SAndrew Turner * Don't trap accesses to CPACR_EL1, trace, SVE, Advanced SIMD
17247e07394SAndrew Turner * and floating point functionality to EL2.
17347e07394SAndrew Turner */
174387f878aSAndrew Turner if (in_vhe())
175d5463136SAndrew Turner el2ctx->cptr_el2 = CPTR_E2H_TRAP_ALL | CPTR_E2H_FPEN;
176387f878aSAndrew Turner else
177d5463136SAndrew Turner el2ctx->cptr_el2 = CPTR_TRAP_ALL & ~CPTR_TFP;
178d5463136SAndrew Turner el2ctx->cptr_el2 &= ~CPTR_TCPAC;
17947e07394SAndrew Turner /*
18047e07394SAndrew Turner * Disable interrupts in the guest. The guest OS will re-enable
18147e07394SAndrew Turner * them.
18247e07394SAndrew Turner */
18347e07394SAndrew Turner el2ctx->tf.tf_spsr = PSR_D | PSR_A | PSR_I | PSR_F;
18447e07394SAndrew Turner /* Use the EL1 stack when taking exceptions to EL1 */
18547e07394SAndrew Turner el2ctx->tf.tf_spsr |= PSR_M_EL1h;
18647e07394SAndrew Turner }
187