Commit bceeedb2 authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

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
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -193,6 +193,9 @@ struct kvm_arch {
	/* Interrupt controller */
	struct vgic_dist	vgic;

	/* Timers */
	struct arch_timer_vm_data timer_data;

	/* Mandated version of PSCI */
	u32 psci_version;

+10 −35
Original line number Diff line number Diff line
@@ -84,15 +84,11 @@ u64 timer_get_cval(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;
}
}

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)

static void timer_set_offset(struct arch_timer_context *ctxt, u64 offset)
{
	struct kvm_vcpu *vcpu = ctxt->vcpu;

	switch(arch_timer_ctx_index(ctxt)) {
	case TIMER_VTIMER:
		__vcpu_sys_reg(vcpu, CNTVOFF_EL2) = offset;
		break;
	default:
	if (!ctxt->offset.vm_offset) {
		WARN(offset, "timer %ld\n", arch_timer_ctx_index(ctxt));
		return;
	}

	WRITE_ONCE(*ctxt->offset.vm_offset, offset);
}

u64 kvm_phys_timer_read(void)
@@ -765,25 +758,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)
	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)
{
	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
@@ -791,10 +765,11 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);

	vtimer->vcpu = vcpu;
	vtimer->offset.vm_offset = &vcpu->kvm->arch.timer_data.voffset;
	ptimer->vcpu = vcpu;

	/* 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);

	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)
		break;
	case KVM_REG_ARM_TIMER_CNT:
		timer = vcpu_vtimer(vcpu);
		update_vtimer_cntvoff(vcpu, kvm_phys_timer_read() - value);
		timer_set_offset(timer, kvm_phys_timer_read() - value);
		break;
	case KVM_REG_ARM_TIMER_CVAL:
		timer = vcpu_vtimer(vcpu);
+1 −1
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
	feature = smccc_get_arg1(vcpu);
	switch (feature) {
	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;
	case KVM_PTP_PHYS_COUNTER:
		cycles = systime_snapshot.cycles;
+15 −0
Original line number Diff line number Diff line
@@ -23,6 +23,19 @@ enum kvm_arch_timer_regs {
	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 kvm_vcpu			*vcpu;

@@ -32,6 +45,8 @@ struct arch_timer_context {
	/* Emulated Timer (may be unused) */
	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
	 * the hardware, so we need some way of keeping track of where the