KVM: arm64: nv: timers: Add a per-timer, per-vcpu offset
authorMarc Zyngier <maz@kernel.org>
Thu, 30 Mar 2023 17:47:56 +0000 (18:47 +0100)
committerMarc Zyngier <maz@kernel.org>
Thu, 30 Mar 2023 18:01:10 +0000 (19:01 +0100)
Being able to set a global offset isn't enough.

With NV, we also need to a per-vcpu, per-timer offset (for example,
CNTVCT_EL0 being offset by CNTVOFF_EL2).

Use a similar method as the VM-wide offset to have a timer point
to the shadow register that contains the offset value.

Reviewed-by: Colton Lewis <coltonlewis@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20230330174800.2677007-17-maz@kernel.org
arch/arm64/kvm/arch_timer.c
arch/arm64/kvm/hyp/include/hyp/switch.h
include/kvm/arm_arch_timer.h

index d3a7902269c19c3aff6ce022deabd4741bd8fb01..b87bf182af33c91d8623e539b04bac42a6c52660 100644 (file)
@@ -89,10 +89,17 @@ u64 timer_get_cval(struct arch_timer_context *ctxt)
 
 static u64 timer_get_offset(struct arch_timer_context *ctxt)
 {
-       if (ctxt && ctxt->offset.vm_offset)
-               return *ctxt->offset.vm_offset;
+       u64 offset = 0;
 
-       return 0;
+       if (!ctxt)
+               return 0;
+
+       if (ctxt->offset.vm_offset)
+               offset += *ctxt->offset.vm_offset;
+       if (ctxt->offset.vcpu_offset)
+               offset += *ctxt->offset.vcpu_offset;
+
+       return offset;
 }
 
 static void timer_set_ctl(struct arch_timer_context *ctxt, u32 ctl)
index 9954368f639d063b8be65d32d9c0f6e6e743d7ce..d07cbc313889a7f3048007185d8eae62e9e03176 100644 (file)
@@ -353,6 +353,8 @@ static bool kvm_hyp_handle_cntpct(struct kvm_vcpu *vcpu)
 
        if (ctxt->offset.vm_offset)
                val -= *kern_hyp_va(ctxt->offset.vm_offset);
+       if (ctxt->offset.vcpu_offset)
+               val -= *kern_hyp_va(ctxt->offset.vcpu_offset);
 
        vcpu_set_reg(vcpu, kvm_vcpu_sys_get_rt(vcpu), val);
        __kvm_skip_instr(vcpu);
index f093ea9f540d43a7cf36215b8487643a10c298fb..209da0c2ac9f725abdce1e42f0c128e8d338ee6c 100644 (file)
@@ -29,6 +29,11 @@ struct arch_timer_offset {
         * structure. If NULL, assume a zero offset.
         */
        u64     *vm_offset;
+       /*
+        * If set, pointer to one of the offsets in the vcpu's sysreg
+        * array. If NULL, assume a zero offset.
+        */
+       u64     *vcpu_offset;
 };
 
 struct arch_timer_vm_data {