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

Merge tag 'kvmarm-fixes-for-5.3-2' of...

Merge tag 'kvmarm-fixes-for-5.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD

KVM/arm fixes for 5.3, take #2

- Fix our system register reset so that we stop writing
  non-sensical values to them, and track which registers
  get reset instead.
- Sync VMCR back from the GIC on WFI so that KVM has an
  exact vue of PMR.
- Reevaluate state of HW-mapped, level triggered interrupts
  on enable.
parents 0e1c438c 16e604a4
Loading
Loading
Loading
Loading
+15 −8
Original line number Diff line number Diff line
@@ -651,13 +651,22 @@ int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
}

static void reset_coproc_regs(struct kvm_vcpu *vcpu,
			      const struct coproc_reg *table, size_t num)
			      const struct coproc_reg *table, size_t num,
			      unsigned long *bmap)
{
	unsigned long i;

	for (i = 0; i < num; i++)
		if (table[i].reset)
		if (table[i].reset) {
			int reg = table[i].reg;

			table[i].reset(vcpu, &table[i]);
			if (reg > 0 && reg < NR_CP15_REGS) {
				set_bit(reg, bmap);
				if (table[i].is_64bit)
					set_bit(reg + 1, bmap);
			}
		}
}

static struct coproc_params decode_32bit_hsr(struct kvm_vcpu *vcpu)
@@ -1432,17 +1441,15 @@ void kvm_reset_coprocs(struct kvm_vcpu *vcpu)
{
	size_t num;
	const struct coproc_reg *table;

	/* Catch someone adding a register without putting in reset entry. */
	memset(vcpu->arch.ctxt.cp15, 0x42, sizeof(vcpu->arch.ctxt.cp15));
	DECLARE_BITMAP(bmap, NR_CP15_REGS) = { 0, };

	/* Generic chip reset first (so target could override). */
	reset_coproc_regs(vcpu, cp15_regs, ARRAY_SIZE(cp15_regs));
	reset_coproc_regs(vcpu, cp15_regs, ARRAY_SIZE(cp15_regs), bmap);

	table = get_target_table(vcpu->arch.target, &num);
	reset_coproc_regs(vcpu, table, num);
	reset_coproc_regs(vcpu, table, num, bmap);

	for (num = 1; num < NR_CP15_REGS; num++)
		WARN(vcpu_cp15(vcpu, num) == 0x42424242,
		WARN(!test_bit(num, bmap),
		     "Didn't reset vcpu_cp15(vcpu, %zi)", num);
}
+18 −14
Original line number Diff line number Diff line
@@ -632,7 +632,7 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
	 */
	val = ((pmcr & ~ARMV8_PMU_PMCR_MASK)
	       | (ARMV8_PMU_PMCR_MASK & 0xdecafbad)) & (~ARMV8_PMU_PMCR_E);
	__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
	__vcpu_sys_reg(vcpu, r->reg) = val;
}

static bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags)
@@ -981,13 +981,13 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
/* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
#define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
	{ SYS_DESC(SYS_DBGBVRn_EL1(n)),					\
	  trap_bvr, reset_bvr, n, 0, get_bvr, set_bvr },		\
	  trap_bvr, reset_bvr, 0, 0, get_bvr, set_bvr },		\
	{ SYS_DESC(SYS_DBGBCRn_EL1(n)),					\
	  trap_bcr, reset_bcr, n, 0, get_bcr, set_bcr },		\
	  trap_bcr, reset_bcr, 0, 0, get_bcr, set_bcr },		\
	{ SYS_DESC(SYS_DBGWVRn_EL1(n)),					\
	  trap_wvr, reset_wvr, n, 0,  get_wvr, set_wvr },		\
	  trap_wvr, reset_wvr, 0, 0,  get_wvr, set_wvr },		\
	{ SYS_DESC(SYS_DBGWCRn_EL1(n)),					\
	  trap_wcr, reset_wcr, n, 0,  get_wcr, set_wcr }
	  trap_wcr, reset_wcr, 0, 0,  get_wcr, set_wcr }

/* Macro to expand the PMEVCNTRn_EL0 register */
#define PMU_PMEVCNTR_EL0(n)						\
@@ -1540,7 +1540,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
	{ SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 },
	{ SYS_DESC(SYS_CTR_EL0), access_ctr },

	{ SYS_DESC(SYS_PMCR_EL0), access_pmcr, reset_pmcr, },
	{ SYS_DESC(SYS_PMCR_EL0), access_pmcr, reset_pmcr, PMCR_EL0 },
	{ SYS_DESC(SYS_PMCNTENSET_EL0), access_pmcnten, reset_unknown, PMCNTENSET_EL0 },
	{ SYS_DESC(SYS_PMCNTENCLR_EL0), access_pmcnten, NULL, PMCNTENSET_EL0 },
	{ SYS_DESC(SYS_PMOVSCLR_EL0), access_pmovs, NULL, PMOVSSET_EL0 },
@@ -2254,13 +2254,19 @@ static int emulate_sys_reg(struct kvm_vcpu *vcpu,
}

static void reset_sys_reg_descs(struct kvm_vcpu *vcpu,
			      const struct sys_reg_desc *table, size_t num)
				const struct sys_reg_desc *table, size_t num,
				unsigned long *bmap)
{
	unsigned long i;

	for (i = 0; i < num; i++)
		if (table[i].reset)
		if (table[i].reset) {
			int reg = table[i].reg;

			table[i].reset(vcpu, &table[i]);
			if (reg > 0 && reg < NR_SYS_REGS)
				set_bit(reg, bmap);
		}
}

/**
@@ -2774,18 +2780,16 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
{
	size_t num;
	const struct sys_reg_desc *table;

	/* Catch someone adding a register without putting in reset entry. */
	memset(&vcpu->arch.ctxt.sys_regs, 0x42, sizeof(vcpu->arch.ctxt.sys_regs));
	DECLARE_BITMAP(bmap, NR_SYS_REGS) = { 0, };

	/* Generic chip reset first (so target could override). */
	reset_sys_reg_descs(vcpu, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
	reset_sys_reg_descs(vcpu, sys_reg_descs, ARRAY_SIZE(sys_reg_descs), bmap);

	table = get_target_table(vcpu->arch.target, true, &num);
	reset_sys_reg_descs(vcpu, table, num);
	reset_sys_reg_descs(vcpu, table, num, bmap);

	for (num = 1; num < NR_SYS_REGS; num++) {
		if (WARN(__vcpu_sys_reg(vcpu, num) == 0x4242424242424242,
		if (WARN(!test_bit(num, bmap),
			 "Didn't reset __vcpu_sys_reg(%zi)\n", num))
			break;
	}
+1 −0
Original line number Diff line number Diff line
@@ -350,6 +350,7 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);

void kvm_vgic_load(struct kvm_vcpu *vcpu);
void kvm_vgic_put(struct kvm_vcpu *vcpu);
void kvm_vgic_vmcr_sync(struct kvm_vcpu *vcpu);

#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
#define vgic_initialized(k)	((k)->arch.vgic.initialized)
+11 −0
Original line number Diff line number Diff line
@@ -318,6 +318,17 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)

void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
{
	/*
	 * If we're about to block (most likely because we've just hit a
	 * WFI), we need to sync back the state of the GIC CPU interface
	 * so that we have the lastest PMR and group enables. This ensures
	 * that kvm_arch_vcpu_runnable has up-to-date data to decide
	 * whether we have pending interrupts.
	 */
	preempt_disable();
	kvm_vgic_vmcr_sync(vcpu);
	preempt_enable();

	kvm_vgic_v4_enable_doorbell(vcpu);
}

+16 −0
Original line number Diff line number Diff line
@@ -113,6 +113,22 @@ void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);

		raw_spin_lock_irqsave(&irq->irq_lock, flags);
		if (vgic_irq_is_mapped_level(irq)) {
			bool was_high = irq->line_level;

			/*
			 * We need to update the state of the interrupt because
			 * the guest might have changed the state of the device
			 * while the interrupt was disabled at the VGIC level.
			 */
			irq->line_level = vgic_get_phys_line_level(irq);
			/*
			 * Deactivate the physical interrupt so the GIC will let
			 * us know when it is asserted again.
			 */
			if (!irq->active && was_high && !irq->line_level)
				vgic_irq_set_phys_active(irq, false);
		}
		irq->enabled = true;
		vgic_queue_irq_unlock(vcpu->kvm, irq, flags);

Loading