/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (C) 2018 Alexandru Elisei <[email protected]>4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#include <sys/cdefs.h>28#include <sys/types.h>29#include <sys/systm.h>30#include <sys/kernel.h>31#include <sys/lock.h>3233#include <machine/armreg.h>34#include <machine/cpu.h>35#include <machine/hypervisor.h>3637#include "arm64.h"38#include "reset.h"3940/*41* Make the architecturally UNKNOWN value 0. As a bonus, we don't have to42* manually set all those RES0 fields.43*/44#define ARCH_UNKNOWN 045#define set_arch_unknown(reg) (memset(&(reg), ARCH_UNKNOWN, sizeof(reg)))4647void48reset_vm_el01_regs(void *vcpu)49{50struct hypctx *el2ctx;5152el2ctx = vcpu;5354set_arch_unknown(el2ctx->tf);5556set_arch_unknown(el2ctx->actlr_el1);57set_arch_unknown(el2ctx->afsr0_el1);58set_arch_unknown(el2ctx->afsr1_el1);59set_arch_unknown(el2ctx->amair_el1);60set_arch_unknown(el2ctx->contextidr_el1);61set_arch_unknown(el2ctx->cpacr_el1);62set_arch_unknown(el2ctx->csselr_el1);63set_arch_unknown(el2ctx->elr_el1);64set_arch_unknown(el2ctx->esr_el1);65set_arch_unknown(el2ctx->far_el1);66set_arch_unknown(el2ctx->mair_el1);67set_arch_unknown(el2ctx->mdccint_el1);68set_arch_unknown(el2ctx->mdscr_el1);69set_arch_unknown(el2ctx->par_el1);7071/*72* Guest starts with:73* ~SCTLR_M: MMU off74* ~SCTLR_C: data cache off75* SCTLR_CP15BEN: memory barrier instruction enable from EL0; RAO/WI76* ~SCTLR_I: instruction cache off77*/78el2ctx->sctlr_el1 = SCTLR_RES1;79el2ctx->sctlr_el1 &= ~SCTLR_M & ~SCTLR_C & ~SCTLR_I;80el2ctx->sctlr_el1 |= SCTLR_CP15BEN;8182set_arch_unknown(el2ctx->sp_el0);83set_arch_unknown(el2ctx->tcr_el1);84set_arch_unknown(el2ctx->tpidr_el0);85set_arch_unknown(el2ctx->tpidr_el1);86set_arch_unknown(el2ctx->tpidrro_el0);87set_arch_unknown(el2ctx->ttbr0_el1);88set_arch_unknown(el2ctx->ttbr1_el1);89set_arch_unknown(el2ctx->vbar_el1);90set_arch_unknown(el2ctx->spsr_el1);9192set_arch_unknown(el2ctx->dbgbcr_el1);93set_arch_unknown(el2ctx->dbgbvr_el1);94set_arch_unknown(el2ctx->dbgwcr_el1);95set_arch_unknown(el2ctx->dbgwvr_el1);9697el2ctx->pmcr_el0 = READ_SPECIALREG(pmcr_el0) & PMCR_N_MASK;98/* PMCR_LC is unknown when AArch32 is supported or RES1 otherwise */99el2ctx->pmcr_el0 |= PMCR_LC;100set_arch_unknown(el2ctx->pmccntr_el0);101set_arch_unknown(el2ctx->pmccfiltr_el0);102set_arch_unknown(el2ctx->pmuserenr_el0);103set_arch_unknown(el2ctx->pmselr_el0);104set_arch_unknown(el2ctx->pmxevcntr_el0);105set_arch_unknown(el2ctx->pmcntenset_el0);106set_arch_unknown(el2ctx->pmintenset_el1);107set_arch_unknown(el2ctx->pmovsset_el0);108memset(el2ctx->pmevcntr_el0, 0, sizeof(el2ctx->pmevcntr_el0));109memset(el2ctx->pmevtyper_el0, 0, sizeof(el2ctx->pmevtyper_el0));110}111112void113reset_vm_el2_regs(void *vcpu)114{115struct hypctx *el2ctx;116uint64_t cpu_aff, vcpuid;117118el2ctx = vcpu;119vcpuid = vcpu_vcpuid(el2ctx->vcpu);120121/*122* Set the Hypervisor Configuration Register:123*124* HCR_RW: use AArch64 for EL1125* HCR_TID3: handle ID registers in the vmm to privide a common126* set of featers on all vcpus127* HCR_TWI: Trap WFI to the hypervisor128* HCR_BSU_IS: barrier instructions apply to the inner shareable129* domain130* HCR_FB: broadcast maintenance operations131* HCR_AMO: route physical SError interrupts to EL2132* HCR_IMO: route physical IRQ interrupts to EL2133* HCR_FMO: route physical FIQ interrupts to EL2134* HCR_SWIO: turn set/way invalidate into set/way clean and135* invalidate136* HCR_VM: use stage 2 translation137*/138el2ctx->hcr_el2 = HCR_RW | HCR_TID3 | HCR_TWI | HCR_BSU_IS | HCR_FB |139HCR_AMO | HCR_IMO | HCR_FMO | HCR_SWIO | HCR_VM;140if (in_vhe()) {141el2ctx->hcr_el2 |= HCR_E2H;142}143144/* Set the Extended Hypervisor Configuration Register */145el2ctx->hcrx_el2 = 0;146/* TODO: Trap all extensions we don't support */147el2ctx->mdcr_el2 = MDCR_EL2_TDOSA | MDCR_EL2_TDRA | MDCR_EL2_TPMS |148MDCR_EL2_TTRF;149/* PMCR_EL0.N is read from MDCR_EL2.HPMN */150el2ctx->mdcr_el2 |= (el2ctx->pmcr_el0 & PMCR_N_MASK) >> PMCR_N_SHIFT;151152el2ctx->vmpidr_el2 = VMPIDR_EL2_RES1;153/* The guest will detect a multi-core, single-threaded CPU */154el2ctx->vmpidr_el2 &= ~VMPIDR_EL2_U & ~VMPIDR_EL2_MT;155/*156* Generate the guest MPIDR value. We only support 16 CPUs at affinity157* level 0 to simplify the vgicv3 driver (see writing sgi1r_el1).158*/159cpu_aff = (vcpuid & 0xf) << MPIDR_AFF0_SHIFT |160((vcpuid >> 4) & 0xff) << MPIDR_AFF1_SHIFT |161((vcpuid >> 12) & 0xff) << MPIDR_AFF2_SHIFT |162((vcpuid >> 20) & 0xff) << MPIDR_AFF3_SHIFT;163el2ctx->vmpidr_el2 |= cpu_aff;164165/* Use the same CPU identification information as the host */166el2ctx->vpidr_el2 = CPU_IMPL_TO_MIDR(CPU_IMPL_ARM);167el2ctx->vpidr_el2 |= CPU_VAR_TO_MIDR(0);168el2ctx->vpidr_el2 |= CPU_ARCH_TO_MIDR(0xf);169el2ctx->vpidr_el2 |= CPU_PART_TO_MIDR(CPU_PART_FOUNDATION);170el2ctx->vpidr_el2 |= CPU_REV_TO_MIDR(0);171172/*173* Don't trap accesses to CPACR_EL1, trace, SVE, Advanced SIMD174* and floating point functionality to EL2.175*/176if (in_vhe())177el2ctx->cptr_el2 = CPTR_E2H_TRAP_ALL | CPTR_E2H_FPEN;178else179el2ctx->cptr_el2 = CPTR_TRAP_ALL & ~CPTR_TFP;180el2ctx->cptr_el2 &= ~CPTR_TCPAC;181/*182* Disable interrupts in the guest. The guest OS will re-enable183* them.184*/185el2ctx->tf.tf_spsr = PSR_D | PSR_A | PSR_I | PSR_F;186/* Use the EL1 stack when taking exceptions to EL1 */187el2ctx->tf.tf_spsr |= PSR_M_EL1h;188}189190191