From nobody Mon Jul 6 15:24:41 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4gv7Sp3TY4z6kDhp for ; Mon, 06 Jul 2026 15:24:42 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4gv7Sn5TDpz3D92 for ; Mon, 06 Jul 2026 15:24:41 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1783351481; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=KC/Ywicje4OjAY/Ln4WEhYDm9gxidKL53IuPjCB4ruA=; b=CGWKocuiOsp91lZQ3pEUX8Xursri6hAQsZCf4pBCLxJ6bg/JSxDarStnOP9m+81tLsWR5q UCSRXCDFqTi/zFi6lSWJR5hRkt2rgX8AKNhoRu69kYw9b7gtVWnrIgL8/S01enGDIu9U4n oc8vslMo00nHvj2BpSeHW0qMD5BQJpn7nWTn7rDsGaQNIMvvyhFQWkJXTFQk+mNHaWS93/ AFNXivlYEEHnqnD3TUbfEWuOdKixdvJe9H/tujyCPNs/pF6QNIIIbJ1gPeKslUhCQjPkpa LVDZAMKBAWnPE5mPKdNNrnpnNLUOOKHQgkUVcQaIvT+5RNXeL4+BtvGOQsIzVA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1783351481; a=rsa-sha256; cv=none; b=HIeJ32+jFPYVseLdZwJqefUTRqtQNYndzkTNMvZhFa0Ddx6/8xMfcZuny6wZdyelYmuwZC pzEKGkpmsZRdvo55IH9IVIiBAd/No3zJoTB6a+1oFgnexla3ap3ypvmvKPQIpNWE6UYMpK fAI1GCYXvX7Vmd0374R/pWpAxLqVe1SVasBdkXo2cwl/Wj+RjVAwyFepUtzuQZgr9q+oMy 8H/etbR1WDU/wEGV6ZqFRTk2OjQsCL+zFEdyaDPuu+QHRFFhheFl6pM3+rPFVpGj7DV0hi j0pnemFY6C2ip/Lv/f2pH3gO1VE5ruINJ8pZeG77VAkUcHNreEt+0us4/Jyh6g== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1783351481; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=KC/Ywicje4OjAY/Ln4WEhYDm9gxidKL53IuPjCB4ruA=; b=I30fMgPUWt5eiOFEXZTR+/MFMwfPkNPgU6kSHb6AEGlhdy2wkk2UEiXaLUYFS3hPmU0N1w VhmQNyV7ilA8JTZrAYpXrM6GgHsfY+st2nF1YlTljTye8FCzMhIIVoWn+NvlVbcbkzfCMw MCf9A35vvKlqgImZUn/csp3bfz4qFfhz0xGF/UuBQeUPZanDUTpyt+Q2RydVKP05tWmjoC rXQnC+wozse82+O1dlCG9lMqEeyI2pUc0tl9WTbHT+2TUFliVFTGHuF3r1RaPI2E85equG RfTZ0g6uur0Q3LLvr913xQ05uggm6JAAPmpCX1PpspKoGGb8kImh83cDs97/Kg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4gv7Sn4XVWz18wN for ; Mon, 06 Jul 2026 15:24:41 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 1bcdc by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 06 Jul 2026 15:24:41 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Kajetan Puchalski From: Andrew Turner Subject: git: e3cd6d104783 - main - arm64/vmm: Refactor vmm_hyp.c List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: andrew X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: e3cd6d1047831f58bf704d207ba559c21af63e03 Auto-Submitted: auto-generated Date: Mon, 06 Jul 2026 15:24:41 +0000 Message-Id: <6a4bc8b9.1bcdc.4863c95b@gitrepo.freebsd.org> The branch main has been updated by andrew: URL: https://cgit.FreeBSD.org/src/commit/?id=e3cd6d1047831f58bf704d207ba559c21af63e03 commit e3cd6d1047831f58bf704d207ba559c21af63e03 Author: Kajetan Puchalski AuthorDate: 2026-07-06 14:17:31 +0000 Commit: Andrew Turner CommitDate: 2026-07-06 15:18:30 +0000 arm64/vmm: Refactor vmm_hyp.c Refactor vmm_hyp.c to split register reload logic by type of register, streamline the implementation and improve readability. Signed-off-by: Kajetan Puchalski Reviewed by: andrew Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D56553 --- sys/arm64/vmm/arm64.h | 6 + sys/arm64/vmm/vmm_hyp.c | 406 +++++++++++++++++++++++++++--------------------- 2 files changed, 234 insertions(+), 178 deletions(-) diff --git a/sys/arm64/vmm/arm64.h b/sys/arm64/vmm/arm64.h index b90cc9d8d15f..2b69f86da321 100644 --- a/sys/arm64/vmm/arm64.h +++ b/sys/arm64/vmm/arm64.h @@ -229,6 +229,12 @@ struct hypctx { uint64_t hfgrtr2_el2; uint64_t hfgwtr2_el2; + /* Storage for *host* timer registers */ + struct { + uint64_t cnthctl_el2; + uint64_t cntvoff_el2; + } host_timer_regs; + struct hyp *hyp; struct vcpu *vcpu; struct { diff --git a/sys/arm64/vmm/vmm_hyp.c b/sys/arm64/vmm/vmm_hyp.c index 469ae8b90d9e..25b04d14dca8 100644 --- a/sys/arm64/vmm/vmm_hyp.c +++ b/sys/arm64/vmm/vmm_hyp.c @@ -41,85 +41,9 @@ struct hypctx; uint64_t VMM_HYP_FUNC(do_call_guest)(struct hypctx *); static void -vmm_hyp_reg_store(struct hypctx *hypctx, struct hyp *hyp, bool guest, - bool ecv_poff) +vmm_hyp_reg_store_pmu_debug(struct hypctx *hypctx, bool guest) { uint64_t dfr0; - - if (guest) { - /* Store the timer registers */ - hypctx->vtimer_cpu.cntkctl_el1 = - READ_SPECIALREG(EL1_REG(CNTKCTL)); - hypctx->vtimer_cpu.virt_timer.cntx_cval_el0 = - READ_SPECIALREG(EL0_REG(CNTV_CVAL)); - hypctx->vtimer_cpu.virt_timer.cntx_ctl_el0 = - READ_SPECIALREG(EL0_REG(CNTV_CTL)); - } - if (guest_or_nonvhe(guest) && ecv_poff) { - /* - * If we have ECV then the guest could modify these registers. - * If VHE is enabled then the kernel will see a different view - * of the registers, so doesn't need to handle them. - */ - hypctx->vtimer_cpu.phys_timer.cntx_cval_el0 = - READ_SPECIALREG(EL0_REG(CNTP_CVAL)); - hypctx->vtimer_cpu.phys_timer.cntx_ctl_el0 = - READ_SPECIALREG(EL0_REG(CNTP_CTL)); - } - - if (guest) { - /* Store the GICv3 registers */ - hypctx->vgic_v3_regs.ich_eisr_el2 = - READ_SPECIALREG(ich_eisr_el2); - hypctx->vgic_v3_regs.ich_elrsr_el2 = - READ_SPECIALREG(ich_elrsr_el2); - hypctx->vgic_v3_regs.ich_hcr_el2 = - READ_SPECIALREG(ich_hcr_el2); - hypctx->vgic_v3_regs.ich_misr_el2 = - READ_SPECIALREG(ich_misr_el2); - hypctx->vgic_v3_regs.ich_vmcr_el2 = - READ_SPECIALREG(ich_vmcr_el2); - switch (hypctx->vgic_v3_regs.ich_lr_num - 1) { -#define STORE_LR(x) \ - case x: \ - hypctx->vgic_v3_regs.ich_lr_el2[x] = \ - READ_SPECIALREG(ich_lr ## x ##_el2) - STORE_LR(15); - STORE_LR(14); - STORE_LR(13); - STORE_LR(12); - STORE_LR(11); - STORE_LR(10); - STORE_LR(9); - STORE_LR(8); - STORE_LR(7); - STORE_LR(6); - STORE_LR(5); - STORE_LR(4); - STORE_LR(3); - STORE_LR(2); - STORE_LR(1); - default: - STORE_LR(0); -#undef STORE_LR - } - - switch (hypctx->vgic_v3_regs.ich_apr_num - 1) { -#define STORE_APR(x) \ - case x: \ - hypctx->vgic_v3_regs.ich_ap0r_el2[x] = \ - READ_SPECIALREG(ich_ap0r ## x ##_el2); \ - hypctx->vgic_v3_regs.ich_ap1r_el2[x] = \ - READ_SPECIALREG(ich_ap1r ## x ##_el2) - STORE_APR(3); - STORE_APR(2); - STORE_APR(1); - default: - STORE_APR(0); -#undef STORE_APR - } - } - hypctx_write_sys_reg(hypctx, DBGCLAIMSET_EL1, READ_SPECIALREG(dbgclaimset_el1)); @@ -242,12 +166,113 @@ vmm_hyp_reg_store(struct hypctx *hypctx, struct hyp *hyp, bool guest, #undef STORE_PMU } + if (!guest) + hypctx->mdcr_el2 = READ_SPECIALREG(mdcr_el2); +} + +static void +vmm_hyp_reg_store_vgic(struct hypctx *hypctx, bool guest) +{ + hypctx->vgic_v3_regs.ich_hcr_el2 = READ_SPECIALREG(ich_hcr_el2); + hypctx->vgic_v3_regs.ich_vmcr_el2 = READ_SPECIALREG(ich_vmcr_el2); + + if (!guest) + return; + + /* Store the GICv3 registers */ + hypctx->vgic_v3_regs.ich_eisr_el2 = READ_SPECIALREG(ich_eisr_el2); + hypctx->vgic_v3_regs.ich_elrsr_el2 = READ_SPECIALREG(ich_elrsr_el2); + hypctx->vgic_v3_regs.ich_misr_el2 = READ_SPECIALREG(ich_misr_el2); + + switch (hypctx->vgic_v3_regs.ich_lr_num - 1) { +#define STORE_LR(x) \ +case x: \ + hypctx->vgic_v3_regs.ich_lr_el2[x] = \ + READ_SPECIALREG(ich_lr ## x ##_el2) + STORE_LR(15); + STORE_LR(14); + STORE_LR(13); + STORE_LR(12); + STORE_LR(11); + STORE_LR(10); + STORE_LR(9); + STORE_LR(8); + STORE_LR(7); + STORE_LR(6); + STORE_LR(5); + STORE_LR(4); + STORE_LR(3); + STORE_LR(2); + STORE_LR(1); + default: + STORE_LR(0); +#undef STORE_LR + } + + switch (hypctx->vgic_v3_regs.ich_apr_num - 1) { +#define STORE_APR(x) \ +case x: \ + hypctx->vgic_v3_regs.ich_ap0r_el2[x] = \ + READ_SPECIALREG(ich_ap0r ## x ##_el2); \ + hypctx->vgic_v3_regs.ich_ap1r_el2[x] = \ + READ_SPECIALREG(ich_ap1r ## x ##_el2) + STORE_APR(3); + STORE_APR(2); + STORE_APR(1); + default: + STORE_APR(0); +#undef STORE_APR + } +} + +static void +vmm_hyp_reg_store_timer(struct hypctx *hypctx, struct hyp *hyp, bool guest) +{ + bool ecv_poff; + + if (guest) { + /* Store the timer registers */ + hypctx->vtimer_cpu.cntkctl_el1 = + READ_SPECIALREG(EL1_REG(CNTKCTL)); + hypctx->vtimer_cpu.virt_timer.cntx_cval_el0 = + READ_SPECIALREG(EL0_REG(CNTV_CVAL)); + hypctx->vtimer_cpu.virt_timer.cntx_ctl_el0 = + READ_SPECIALREG(EL0_REG(CNTV_CTL)); + } else { + hypctx->vtimer_cpu.cntkctl_el1 = + READ_SPECIALREG(cntkctl_el1); + hypctx->host_timer_regs.cnthctl_el2 = + READ_SPECIALREG(cnthctl_el2); + hypctx->host_timer_regs.cntvoff_el2 = + READ_SPECIALREG(cntvoff_el2); + } + + ecv_poff = (hyp->vtimer.cnthctl_el2 & CNTHCTL_ECV_EN) != 0; + + if (guest_or_nonvhe(guest) && ecv_poff) { + /* + * If we have ECV then the guest could modify these registers. + * If VHE is enabled then the kernel will see a different view + * of the registers, so doesn't need to handle them. + */ + hypctx->vtimer_cpu.phys_timer.cntx_cval_el0 = + READ_SPECIALREG(EL0_REG(CNTP_CVAL)); + hypctx->vtimer_cpu.phys_timer.cntx_ctl_el0 = + READ_SPECIALREG(EL0_REG(CNTP_CTL)); + } +} + +static void +vmm_hyp_reg_store_special(struct hypctx *hypctx, struct hyp *hyp, bool guest) +{ /* Store the special to from the trapframe */ hypctx->tf.tf_sp = READ_SPECIALREG(sp_el1); hypctx->tf.tf_elr = READ_SPECIALREG(elr_el2); hypctx->tf.tf_spsr = READ_SPECIALREG(spsr_el2); + if (guest) { hypctx->tf.tf_esr = READ_SPECIALREG(esr_el2); + hypctx->exit_info.far_el2 = READ_SPECIALREG(far_el2); hypctx_write_sys_reg(hypctx, PAR_EL1, READ_SPECIALREG(par_el1)); } @@ -301,21 +326,26 @@ vmm_hyp_reg_store(struct hypctx *hypctx, struct hyp *hyp, bool guest, hypctx->hcr_el2 = READ_SPECIALREG(hcr_el2); hypctx->vpidr_el2 = READ_SPECIALREG(vpidr_el2); hypctx->vmpidr_el2 = READ_SPECIALREG(vmpidr_el2); + +#ifndef VMM_VHE + if (!guest) { + if ((hyp->feats & HYP_FEAT_HCX) != 0) + hypctx->hcrx_el2 = + READ_SPECIALREG(MRS_REG_ALT_NAME(HCRX_EL2)); + } +#endif } static void -vmm_hyp_reg_restore(struct hypctx *hypctx, struct hyp *hyp, bool guest, - bool ecv_poff) +vmm_hyp_reg_restore_special(struct hypctx *hypctx, struct hyp *hyp, bool guest) { - uint64_t dfr0; - - /* Restore the special registers */ WRITE_SPECIALREG(hcr_el2, hypctx->hcr_el2); - if (guest) { + if (guest_or_nonvhe(guest)) { if ((hyp->feats & HYP_FEAT_HCX) != 0) WRITE_SPECIALREG(HCRX_EL2_REG, hypctx->hcrx_el2); } + isb(); #ifdef VMM_VHE @@ -396,6 +426,12 @@ vmm_hyp_reg_restore(struct hypctx *hypctx, struct hyp *hyp, bool guest, WRITE_SPECIALREG(sp_el1, hypctx->tf.tf_sp); WRITE_SPECIALREG(elr_el2, hypctx->tf.tf_elr); WRITE_SPECIALREG(spsr_el2, hypctx->tf.tf_spsr); +} + +static void +vmm_hyp_reg_restore_pmu_debug(struct hypctx *hypctx) +{ + uint64_t dfr0; /* Restore the PMU registers */ WRITE_SPECIALREG(pmcr_el0, @@ -421,7 +457,8 @@ vmm_hyp_reg_restore(struct hypctx *hypctx, struct hyp *hyp, bool guest, WRITE_SPECIALREG(pmovsset_el0, hypctx_read_sys_reg(hypctx, PMOVSSET_EL0)); - switch ((hypctx_read_sys_reg(hypctx, PMCR_EL0) & PMCR_N_MASK) >> PMCR_N_SHIFT) { + switch ((hypctx_read_sys_reg(hypctx, PMCR_EL0) & PMCR_N_MASK) >> + PMCR_N_SHIFT) { #define LOAD_PMU(x) \ case (x + 1): \ WRITE_SPECIALREG(pmevcntr ## x ## _el0, \ @@ -522,17 +559,23 @@ vmm_hyp_reg_restore(struct hypctx *hypctx, struct hyp *hyp, bool guest, LOAD_DBG_WRP(0); #undef LOAD_DBG_WRP } +} + +static void +vmm_hyp_reg_restore_timer(struct hypctx *hypctx, struct hyp *hyp, bool guest) +{ + bool ecv_poff; + ecv_poff = (hyp->vtimer.cnthctl_el2 & CNTHCTL_ECV_EN) != 0; if (guest) { - /* Load the timer registers */ + WRITE_SPECIALREG(cnthctl_el2, hyp->vtimer.cnthctl_el2); + WRITE_SPECIALREG(cntvoff_el2, hyp->vtimer.cntvoff_el2); WRITE_SPECIALREG(EL1_REG(CNTKCTL), hypctx->vtimer_cpu.cntkctl_el1); WRITE_SPECIALREG(EL0_REG(CNTV_CVAL), hypctx->vtimer_cpu.virt_timer.cntx_cval_el0); WRITE_SPECIALREG(EL0_REG(CNTV_CTL), hypctx->vtimer_cpu.virt_timer.cntx_ctl_el0); - WRITE_SPECIALREG(cnthctl_el2, hyp->vtimer.cnthctl_el2); - WRITE_SPECIALREG(cntvoff_el2, hyp->vtimer.cntvoff_el2); if (ecv_poff) { /* @@ -543,6 +586,12 @@ vmm_hyp_reg_restore(struct hypctx *hypctx, struct hyp *hyp, bool guest, hyp->vtimer.cntvoff_el2); isb(); } + } else { + WRITE_SPECIALREG(cnthctl_el2, + hypctx->host_timer_regs.cnthctl_el2); + WRITE_SPECIALREG(cntvoff_el2, + hypctx->host_timer_regs.cntvoff_el2); + WRITE_SPECIALREG(cntkctl_el1, hypctx->vtimer_cpu.cntkctl_el1); } if (guest_or_nonvhe(guest) && ecv_poff) { /* @@ -555,38 +604,45 @@ vmm_hyp_reg_restore(struct hypctx *hypctx, struct hyp *hyp, bool guest, WRITE_SPECIALREG(EL0_REG(CNTP_CTL), hypctx->vtimer_cpu.phys_timer.cntx_ctl_el0); } +} - if (guest) { - /* Load the GICv3 registers */ - WRITE_SPECIALREG(ich_hcr_el2, hypctx->vgic_v3_regs.ich_hcr_el2); - WRITE_SPECIALREG(ich_vmcr_el2, - hypctx->vgic_v3_regs.ich_vmcr_el2); - switch (hypctx->vgic_v3_regs.ich_lr_num - 1) { -#define LOAD_LR(x) \ - case x: \ - WRITE_SPECIALREG(ich_lr ## x ##_el2, \ - hypctx->vgic_v3_regs.ich_lr_el2[x]) - LOAD_LR(15); - LOAD_LR(14); - LOAD_LR(13); - LOAD_LR(12); - LOAD_LR(11); - LOAD_LR(10); - LOAD_LR(9); - LOAD_LR(8); - LOAD_LR(7); - LOAD_LR(6); - LOAD_LR(5); - LOAD_LR(4); - LOAD_LR(3); - LOAD_LR(2); - LOAD_LR(1); - default: - LOAD_LR(0); +static void +vmm_hyp_reg_restore_vgic(struct hypctx *hypctx, bool guest) +{ + /* Load the GICv3 registers */ + WRITE_SPECIALREG(ich_hcr_el2, hypctx->vgic_v3_regs.ich_hcr_el2); + WRITE_SPECIALREG(ich_vmcr_el2, + hypctx->vgic_v3_regs.ich_vmcr_el2); + + if (!guest) + return; + + switch (hypctx->vgic_v3_regs.ich_lr_num - 1) { +#define LOAD_LR(x) \ +case x: \ + WRITE_SPECIALREG(ich_lr ## x ##_el2, \ + hypctx->vgic_v3_regs.ich_lr_el2[x]) + LOAD_LR(15); + LOAD_LR(14); + LOAD_LR(13); + LOAD_LR(12); + LOAD_LR(11); + LOAD_LR(10); + LOAD_LR(9); + LOAD_LR(8); + LOAD_LR(7); + LOAD_LR(6); + LOAD_LR(5); + LOAD_LR(4); + LOAD_LR(3); + LOAD_LR(2); + LOAD_LR(1); + default: + LOAD_LR(0); #undef LOAD_LR - } + } - switch (hypctx->vgic_v3_regs.ich_apr_num - 1) { + switch (hypctx->vgic_v3_regs.ich_apr_num - 1) { #define LOAD_APR(x) \ case x: \ WRITE_SPECIALREG(ich_ap0r ## x ##_el2, \ @@ -599,64 +655,35 @@ vmm_hyp_reg_restore(struct hypctx *hypctx, struct hyp *hyp, bool guest, default: LOAD_APR(0); #undef LOAD_APR - } } } -static uint64_t -vmm_hyp_call_guest(struct hyp *hyp, struct hypctx *hypctx) +static void +vmm_hyp_reg_store(struct hypctx *hypctx, struct hyp *hyp, bool guest) { - struct hypctx host_hypctx; - uint64_t cntvoff_el2; - uint64_t ich_hcr_el2, ich_vmcr_el2, cnthctl_el2, cntkctl_el1; -#ifndef VMM_VHE - uint64_t hcrx_el2; -#endif - uint64_t ret; - uint64_t s1e1r, hpfar_el2; - bool ecv_poff, hpfar_valid; - - /* Allows uniform implementation of guest and host register reloads */ - host_hypctx.vncr_regs = hypctx->host_vncr_regs; -#ifndef VMM_VHE - host_hypctx.el2_vncr_addr = hypctx->el2_host_vncr_addr; -#endif - - ecv_poff = (hyp->vtimer.cnthctl_el2 & CNTHCTL_ECV_EN) != 0; - vmm_hyp_reg_store(&host_hypctx, NULL, false, ecv_poff); -#ifndef VMM_VHE - if ((hyp->feats & HYP_FEAT_HCX) != 0) - hcrx_el2 = READ_SPECIALREG(MRS_REG_ALT_NAME(HCRX_EL2)); -#endif - - /* Save the host special registers */ - cnthctl_el2 = READ_SPECIALREG(cnthctl_el2); - cntkctl_el1 = READ_SPECIALREG(cntkctl_el1); - cntvoff_el2 = READ_SPECIALREG(cntvoff_el2); - - ich_hcr_el2 = READ_SPECIALREG(ich_hcr_el2); - ich_vmcr_el2 = READ_SPECIALREG(ich_vmcr_el2); - - vmm_hyp_reg_restore(hypctx, hyp, true, ecv_poff); - - /* Load the common hypervisor registers */ - WRITE_SPECIALREG(vttbr_el2, hyp->vttbr_el2); - - host_hypctx.mdcr_el2 = READ_SPECIALREG(mdcr_el2); - WRITE_SPECIALREG(mdcr_el2, hypctx->mdcr_el2); - - /* Call into the guest */ - ret = VMM_HYP_FUNC(do_call_guest)(hypctx); + vmm_hyp_reg_store_vgic(hypctx, guest); + vmm_hyp_reg_store_timer(hypctx, hyp, guest); + vmm_hyp_reg_store_pmu_debug(hypctx, guest); + vmm_hyp_reg_store_special(hypctx, hyp, guest); +} - WRITE_SPECIALREG(mdcr_el2, host_hypctx.mdcr_el2); - isb(); +static void +vmm_hyp_reg_restore(struct hypctx *hypctx, struct hyp *hyp, bool guest) +{ + vmm_hyp_reg_restore_special(hypctx, hyp, guest); + vmm_hyp_reg_restore_pmu_debug(hypctx); + vmm_hyp_reg_restore_timer(hypctx, hyp, guest); + vmm_hyp_reg_restore_vgic(hypctx, guest); +} - /* Store the exit info */ - hypctx->exit_info.far_el2 = READ_SPECIALREG(far_el2); - vmm_hyp_reg_store(hypctx, hyp, true, ecv_poff); +static void +vmm_hyp_handle_guest_exit(struct hypctx *hypctx, uint64_t *ret) +{ + bool hpfar_valid; + uint64_t s1e1r, hpfar_el2; hpfar_valid = true; - if (ret == EXCP_TYPE_EL1_SYNC) { + if (*ret == EXCP_TYPE_EL1_SYNC) { switch (ESR_ELx_EXCEPTION(hypctx->tf.tf_esr)) { case EXCP_INSN_ABORT_L: case EXCP_DATA_ABORT_L: @@ -699,24 +726,47 @@ vmm_hyp_call_guest(struct hyp *hyp, struct hypctx *hypctx) hpfar_el2 <<= HPFAR_EL2_FIPA_SHIFT; hypctx->exit_info.hpfar_el2 = hpfar_el2; } else { - ret = EXCP_TYPE_REENTER; + *ret = EXCP_TYPE_REENTER; } } +} - vmm_hyp_reg_restore(&host_hypctx, NULL, false, ecv_poff); +/* Minimum guest entry logic that should not be reordered */ +static uint64_t +__vmm_hyp_call_guest(struct hypctx *hypctx, struct hypctx *host_hypctx) +{ + uint64_t ret; + WRITE_SPECIALREG(vttbr_el2, hypctx->hyp->vttbr_el2); + WRITE_SPECIALREG(mdcr_el2, hypctx->mdcr_el2); + /* Call into the guest */ + ret = VMM_HYP_FUNC(do_call_guest)(hypctx); + WRITE_SPECIALREG(mdcr_el2, host_hypctx->mdcr_el2); -#ifndef VMM_VHE - if ((hyp->feats & HYP_FEAT_HCX) != 0) - WRITE_SPECIALREG(MRS_REG_ALT_NAME(HCRX_EL2), hcrx_el2); -#endif + isb(); + + return ret; +} + +static uint64_t +vmm_hyp_call_guest(struct hyp *hyp, struct hypctx *hypctx) +{ + struct hypctx host_hypctx; + uint64_t ret; + + /* Allows uniform implementation of guest and host register reloads */ + host_hypctx.vncr_regs = hypctx->host_vncr_regs; + #ifndef VMM_VHE + host_hypctx.el2_vncr_addr = hypctx->el2_host_vncr_addr; + #endif + + vmm_hyp_reg_store(&host_hypctx, hyp, false); + vmm_hyp_reg_restore(hypctx, hyp, true); - /* Restore the host special registers */ - WRITE_SPECIALREG(ich_hcr_el2, ich_hcr_el2); - WRITE_SPECIALREG(ich_vmcr_el2, ich_vmcr_el2); + ret = __vmm_hyp_call_guest(hypctx, &host_hypctx); - WRITE_SPECIALREG(cnthctl_el2, cnthctl_el2); - WRITE_SPECIALREG(cntkctl_el1, cntkctl_el1); - WRITE_SPECIALREG(cntvoff_el2, cntvoff_el2); + vmm_hyp_reg_store(hypctx, hyp, true); + vmm_hyp_handle_guest_exit(hypctx, &ret); + vmm_hyp_reg_restore(&host_hypctx, hyp, false); return (ret); }