Keep Realm timer state separate from the normal guest timer registers. The RMM reports timer snapshots on REC exit.
Signed-off-by: Koichiro Den <[email protected]> --- xen/arch/arm/cca/Makefile | 1 + xen/arch/arm/cca/build.c | 10 +++- xen/arch/arm/cca/rec.c | 90 ++++++++++++++++++++++++++++++++++ xen/arch/arm/cca/state.c | 3 ++ xen/arch/arm/domain.c | 6 ++- xen/arch/arm/include/asm/cca.h | 5 ++ 6 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 xen/arch/arm/cca/rec.c diff --git a/xen/arch/arm/cca/Makefile b/xen/arch/arm/cca/Makefile index 0e66280012b7..b473132c1a67 100644 --- a/xen/arch/arm/cca/Makefile +++ b/xen/arch/arm/cca/Makefile @@ -4,3 +4,4 @@ obj-y += rmi.o obj-y += sro.o obj-y += state.o obj-y += build.o +obj-y += rec.o diff --git a/xen/arch/arm/cca/build.c b/xen/arch/arm/cca/build.c index 29eb0c6057b0..18e825eec83a 100644 --- a/xen/arch/arm/cca/build.c +++ b/xen/arch/arm/cca/build.c @@ -851,7 +851,7 @@ static int arm_cca_create_rec(struct domain *d, struct vcpu *v, bool runnable, struct arm_cca_rmi_rec_params *params; struct page_info *rec_pg = NULL; struct page_info *params_pg = NULL; - bool rec_delegated = false, run_created = false; + bool rec_delegated = false, run_created = false, timers_created = false; void *va; int rc = -ENOMEM; @@ -872,6 +872,11 @@ static int arm_cca_create_rec(struct domain *d, struct vcpu *v, bool runnable, run_created = true; } + rc = arm_cca_vcpu_timer_init(v); + if ( rc != 0 ) + goto out; + timers_created = true; + rc = arm_cca_delegate_granule(page_to_maddr(rec_pg)); if ( rc != 0 ) goto out; @@ -913,6 +918,9 @@ out: if ( rc != 0 && rec_pg ) arm_cca_free_or_abandon_build_page(d, rec_pg, rec_delegated); + if ( rc != 0 && timers_created ) + arm_cca_vcpu_timer_destroy(v); + if ( rc != 0 && run_created ) { arm_cca_free_rec_run(v->arch.cca.run); diff --git a/xen/arch/arm/cca/rec.c b/xen/arch/arm/cca/rec.c new file mode 100644 index 000000000000..8314a7a45d95 --- /dev/null +++ b/xen/arch/arm/cca/rec.c @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <xen/lib.h> +#include <xen/sched.h> +#include <xen/timer.h> +#include <xen/xmalloc.h> + +#include <asm/cca.h> +#include <asm/time.h> +#include <asm/vgic.h> + +struct arm_cca_timer { + struct vcpu *v; + unsigned int irq; + struct timer timer; + register_t ctl; + uint64_t cval; +}; + +struct arm_cca_vcpu_timers { + struct arm_cca_timer phys; + struct arm_cca_timer virt; + struct timer wfx; +}; + +static void arm_cca_timer_update_irq(struct arm_cca_timer *timer) +{ + register_t ctl = timer->ctl; + bool level; + + ctl &= (CNTx_CTL_ENABLE | CNTx_CTL_PENDING | CNTx_CTL_MASK); + level = (ctl == (CNTx_CTL_ENABLE | CNTx_CTL_PENDING)); + + vgic_inject_irq(timer->v->domain, timer->v, timer->irq, level); +} + +static void arm_cca_timer_expired(void *data) +{ + struct arm_cca_timer *timer = data; + + timer->ctl |= CNTx_CTL_PENDING; + arm_cca_timer_update_irq(timer); +} + +static void arm_cca_wfx_timer_expired(void *data) +{ + vcpu_unblock(data); +} + +static void arm_cca_timer_init(struct vcpu *v, struct arm_cca_timer *timer, + unsigned int irq) +{ + init_timer(&timer->timer, arm_cca_timer_expired, timer, v->processor); + timer->v = v; + timer->irq = irq; + timer->ctl = 0; + timer->cval = 0; +} + +int arm_cca_vcpu_timer_init(struct vcpu *v) +{ + struct arm_cca_vcpu_timers *timers; + + ASSERT(!v->arch.cca.timers); + + timers = xzalloc(struct arm_cca_vcpu_timers); + if ( !timers ) + return -ENOMEM; + + v->arch.cca.timers = timers; + + arm_cca_timer_init(v, &timers->phys, GUEST_TIMER_PHYS_NS_PPI); + arm_cca_timer_init(v, &timers->virt, GUEST_TIMER_VIRT_PPI); + init_timer(&timers->wfx, arm_cca_wfx_timer_expired, v, v->processor); + + return 0; +} + +void arm_cca_vcpu_timer_destroy(struct vcpu *v) +{ + struct arm_cca_vcpu_timers *timers = v->arch.cca.timers; + + if ( !timers ) + return; + + kill_timer(&timers->phys.timer); + kill_timer(&timers->virt.timer); + kill_timer(&timers->wfx); + XFREE(v->arch.cca.timers); +} diff --git a/xen/arch/arm/cca/state.c b/xen/arch/arm/cca/state.c index d85a20a9e7d2..03e0d1d2382b 100644 --- a/xen/arch/arm/cca/state.c +++ b/xen/arch/arm/cca/state.c @@ -51,6 +51,7 @@ static void arm_cca_reset_vcpu_state(struct vcpu *v) v->arch.cca.rec = INVALID_PADDR; v->arch.cca.run = NULL; v->arch.cca.run_pa = INVALID_PADDR; + v->arch.cca.timers = NULL; v->arch.cca.rec_page = NULL; v->arch.cca.nr_aux = 0; @@ -439,6 +440,8 @@ void arm_cca_vcpu_init(struct vcpu *v) void arm_cca_vcpu_destroy(struct vcpu *v) { + arm_cca_vcpu_timer_destroy(v); + if ( v->arch.cca.run ) arm_cca_free_rec_run(v->arch.cca.run); diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 2d9469f388c6..d2ee90248a44 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -113,7 +113,8 @@ static void ctxt_switch_from(struct vcpu *p) /* Arch timer */ p->arch.cntkctl = READ_SYSREG(CNTKCTL_EL1); - virt_timer_save(p); + if ( !is_vcpu_realm(p) ) + virt_timer_save(p); #ifdef CONFIG_ARM_32 p->arch.joscr = READ_CP32(JOSCR); @@ -265,7 +266,8 @@ static void ctxt_switch_to(struct vcpu *n) /* This is could trigger an hardware interrupt from the virtual * timer. The interrupt needs to be injected into the guest. */ WRITE_SYSREG(n->arch.cntkctl, CNTKCTL_EL1); - virt_timer_restore(n); + if ( !is_vcpu_realm(n) ) + virt_timer_restore(n); WRITE_SYSREG(n->arch.mdcr_el2, MDCR_EL2); } diff --git a/xen/arch/arm/include/asm/cca.h b/xen/arch/arm/include/asm/cca.h index 5e6b11a3693d..323988b379ba 100644 --- a/xen/arch/arm/include/asm/cca.h +++ b/xen/arch/arm/include/asm/cca.h @@ -29,6 +29,7 @@ struct vcpu; struct arm_cca_rmi_realm_params; struct arm_cca_rmi_rec_params; struct arm_cca_rmi_rec_run; +struct arm_cca_vcpu_timers; struct page_info; struct arm_cca_rtt_record { @@ -99,6 +100,8 @@ struct arm_cca_vcpu_state { void *run; paddr_t run_pa; + struct arm_cca_vcpu_timers *timers; + struct page_info *rec_page; struct page_info *aux_pages[ARM_CCA_MAX_REC_AUX]; unsigned int nr_aux; @@ -114,6 +117,8 @@ int arm_cca_domain_finalize(struct domain *d, gfn_t base_gfn, void arm_cca_vcpu_init(struct vcpu *v); void noreturn arm_cca_vcpu_run(struct vcpu *v); void arm_cca_vcpu_destroy(struct vcpu *v); +int arm_cca_vcpu_timer_init(struct vcpu *v); +void arm_cca_vcpu_timer_destroy(struct vcpu *v); void *arm_cca_alloc_rec_run(void); void arm_cca_free_rec_run(void *run); -- 2.51.0
