Commit bceeedb2 authored by Paolo Bonzini's avatar Paolo Bonzini

Merge tag 'kvmarm-fixes-6.3-1' of...

Merge tag 'kvmarm-fixes-6.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD

KVM/arm64 fixes for 6.3, part #1

A single patch to address a rather annoying bug w.r.t. guest timer
offsetting. Effectively the synchronization of timer offsets between
vCPUs was broken, leading to inconsistent timer reads within the VM.
parents eeac8ede 47053904
...@@ -193,6 +193,9 @@ struct kvm_arch { ...@@ -193,6 +193,9 @@ struct kvm_arch {
/* Interrupt controller */ /* Interrupt controller */
struct vgic_dist vgic; struct vgic_dist vgic;
/* Timers */
struct arch_timer_vm_data timer_data;
/* Mandated version of PSCI */ /* Mandated version of PSCI */
u32 psci_version; u32 psci_version;
......
...@@ -84,14 +84,10 @@ u64 timer_get_cval(struct arch_timer_context *ctxt) ...@@ -84,14 +84,10 @@ u64 timer_get_cval(struct arch_timer_context *ctxt)
static u64 timer_get_offset(struct arch_timer_context *ctxt) static u64 timer_get_offset(struct arch_timer_context *ctxt)
{ {
struct kvm_vcpu *vcpu = ctxt->vcpu; if (ctxt->offset.vm_offset)
return *ctxt->offset.vm_offset;
switch(arch_timer_ctx_index(ctxt)) {
case TIMER_VTIMER:
return __vcpu_sys_reg(vcpu, CNTVOFF_EL2);
default:
return 0; return 0;
}
} }
static void timer_set_ctl(struct arch_timer_context *ctxt, u32 ctl) static void timer_set_ctl(struct arch_timer_context *ctxt, u32 ctl)
...@@ -128,15 +124,12 @@ static void timer_set_cval(struct arch_timer_context *ctxt, u64 cval) ...@@ -128,15 +124,12 @@ static void timer_set_cval(struct arch_timer_context *ctxt, u64 cval)
static void timer_set_offset(struct arch_timer_context *ctxt, u64 offset) static void timer_set_offset(struct arch_timer_context *ctxt, u64 offset)
{ {
struct kvm_vcpu *vcpu = ctxt->vcpu; if (!ctxt->offset.vm_offset) {
switch(arch_timer_ctx_index(ctxt)) {
case TIMER_VTIMER:
__vcpu_sys_reg(vcpu, CNTVOFF_EL2) = offset;
break;
default:
WARN(offset, "timer %ld\n", arch_timer_ctx_index(ctxt)); WARN(offset, "timer %ld\n", arch_timer_ctx_index(ctxt));
return;
} }
WRITE_ONCE(*ctxt->offset.vm_offset, offset);
} }
u64 kvm_phys_timer_read(void) u64 kvm_phys_timer_read(void)
...@@ -765,25 +758,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu) ...@@ -765,25 +758,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)
return 0; return 0;
} }
/* Make the updates of cntvoff for all vtimer contexts atomic */
static void update_vtimer_cntvoff(struct kvm_vcpu *vcpu, u64 cntvoff)
{
unsigned long i;
struct kvm *kvm = vcpu->kvm;
struct kvm_vcpu *tmp;
mutex_lock(&kvm->lock);
kvm_for_each_vcpu(i, tmp, kvm)
timer_set_offset(vcpu_vtimer(tmp), cntvoff);
/*
* When called from the vcpu create path, the CPU being created is not
* included in the loop above, so we just set it here as well.
*/
timer_set_offset(vcpu_vtimer(vcpu), cntvoff);
mutex_unlock(&kvm->lock);
}
void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu) void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
{ {
struct arch_timer_cpu *timer = vcpu_timer(vcpu); struct arch_timer_cpu *timer = vcpu_timer(vcpu);
...@@ -791,10 +765,11 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu) ...@@ -791,10 +765,11 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
struct arch_timer_context *ptimer = vcpu_ptimer(vcpu); struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
vtimer->vcpu = vcpu; vtimer->vcpu = vcpu;
vtimer->offset.vm_offset = &vcpu->kvm->arch.timer_data.voffset;
ptimer->vcpu = vcpu; ptimer->vcpu = vcpu;
/* Synchronize cntvoff across all vtimers of a VM. */ /* Synchronize cntvoff across all vtimers of a VM. */
update_vtimer_cntvoff(vcpu, kvm_phys_timer_read()); timer_set_offset(vtimer, kvm_phys_timer_read());
timer_set_offset(ptimer, 0); timer_set_offset(ptimer, 0);
hrtimer_init(&timer->bg_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD); hrtimer_init(&timer->bg_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD);
...@@ -840,7 +815,7 @@ int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value) ...@@ -840,7 +815,7 @@ int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
break; break;
case KVM_REG_ARM_TIMER_CNT: case KVM_REG_ARM_TIMER_CNT:
timer = vcpu_vtimer(vcpu); timer = vcpu_vtimer(vcpu);
update_vtimer_cntvoff(vcpu, kvm_phys_timer_read() - value); timer_set_offset(timer, kvm_phys_timer_read() - value);
break; break;
case KVM_REG_ARM_TIMER_CVAL: case KVM_REG_ARM_TIMER_CVAL:
timer = vcpu_vtimer(vcpu); timer = vcpu_vtimer(vcpu);
......
...@@ -44,7 +44,7 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) ...@@ -44,7 +44,7 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
feature = smccc_get_arg1(vcpu); feature = smccc_get_arg1(vcpu);
switch (feature) { switch (feature) {
case KVM_PTP_VIRT_COUNTER: case KVM_PTP_VIRT_COUNTER:
cycles = systime_snapshot.cycles - vcpu_read_sys_reg(vcpu, CNTVOFF_EL2); cycles = systime_snapshot.cycles - vcpu->kvm->arch.timer_data.voffset;
break; break;
case KVM_PTP_PHYS_COUNTER: case KVM_PTP_PHYS_COUNTER:
cycles = systime_snapshot.cycles; cycles = systime_snapshot.cycles;
......
...@@ -23,6 +23,19 @@ enum kvm_arch_timer_regs { ...@@ -23,6 +23,19 @@ enum kvm_arch_timer_regs {
TIMER_REG_CTL, TIMER_REG_CTL,
}; };
struct arch_timer_offset {
/*
* If set, pointer to one of the offsets in the kvm's offset
* structure. If NULL, assume a zero offset.
*/
u64 *vm_offset;
};
struct arch_timer_vm_data {
/* Offset applied to the virtual timer/counter */
u64 voffset;
};
struct arch_timer_context { struct arch_timer_context {
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu;
...@@ -32,6 +45,8 @@ struct arch_timer_context { ...@@ -32,6 +45,8 @@ struct arch_timer_context {
/* Emulated Timer (may be unused) */ /* Emulated Timer (may be unused) */
struct hrtimer hrtimer; struct hrtimer hrtimer;
/* Offset for this counter/timer */
struct arch_timer_offset offset;
/* /*
* We have multiple paths which can save/restore the timer state onto * We have multiple paths which can save/restore the timer state onto
* the hardware, so we need some way of keeping track of where the * the hardware, so we need some way of keeping track of where the
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment