Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 67a3b5cb authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull Paolo Bonzini:
 "Bugfixes for x86, PPC and s390"

* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
  KVM: PPC: Book3S: Fix race and leak in kvm_vm_ioctl_create_spapr_tce()
  KVM, pkeys: do not use PKRU value in vcpu->arch.guest_fpu.state
  KVM: x86: simplify handling of PKRU
  KVM: x86: block guest protection keys unless the host has them enabled
  KVM: PPC: Book3S HV: Add missing barriers to XIVE code and document them
  KVM: PPC: Book3S HV: Workaround POWER9 DD1.0 bug causing IPB bit loss
  KVM: PPC: Book3S HV: Use msgsync with hypervisor doorbells on POWER9
  KVM: s390: sthyi: fix specification exception detection
  KVM: s390: sthyi: fix sthyi inline assembly
parents 17e34c4f 47c5310a
Loading
Loading
Loading
Loading
+34 −22
Original line number Diff line number Diff line
@@ -294,32 +294,26 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
				   struct kvm_create_spapr_tce_64 *args)
{
	struct kvmppc_spapr_tce_table *stt = NULL;
	struct kvmppc_spapr_tce_table *siter;
	unsigned long npages, size;
	int ret = -ENOMEM;
	int i;
	int fd = -1;

	if (!args->size)
		return -EINVAL;

	/* Check this LIOBN hasn't been previously allocated */
	list_for_each_entry(stt, &kvm->arch.spapr_tce_tables, list) {
		if (stt->liobn == args->liobn)
			return -EBUSY;
	}

	size = _ALIGN_UP(args->size, PAGE_SIZE >> 3);
	npages = kvmppc_tce_pages(size);
	ret = kvmppc_account_memlimit(kvmppc_stt_pages(npages), true);
	if (ret) {
		stt = NULL;
		goto fail;
	}
	if (ret)
		return ret;

	ret = -ENOMEM;
	stt = kzalloc(sizeof(*stt) + npages * sizeof(struct page *),
		      GFP_KERNEL);
	if (!stt)
		goto fail;
		goto fail_acct;

	stt->liobn = args->liobn;
	stt->page_shift = args->page_shift;
@@ -334,24 +328,42 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
			goto fail;
	}

	kvm_get_kvm(kvm);
	ret = fd = anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops,
				    stt, O_RDWR | O_CLOEXEC);
	if (ret < 0)
		goto fail;

	mutex_lock(&kvm->lock);

	/* Check this LIOBN hasn't been previously allocated */
	ret = 0;
	list_for_each_entry(siter, &kvm->arch.spapr_tce_tables, list) {
		if (siter->liobn == args->liobn) {
			ret = -EBUSY;
			break;
		}
	}

	if (!ret) {
		list_add_rcu(&stt->list, &kvm->arch.spapr_tce_tables);
		kvm_get_kvm(kvm);
	}

	mutex_unlock(&kvm->lock);

	return anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops,
				stt, O_RDWR | O_CLOEXEC);
	if (!ret)
		return fd;

	put_unused_fd(fd);

 fail:
	if (stt) {
	for (i = 0; i < npages; i++)
		if (stt->pages[i])
			__free_page(stt->pages[i]);

	kfree(stt);
	}
 fail_acct:
	kvmppc_account_memlimit(kvmppc_stt_pages(npages), false);
	return ret;
}

+3 −0
Original line number Diff line number Diff line
@@ -1291,6 +1291,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
	/* Hypervisor doorbell - exit only if host IPI flag set */
	cmpwi	r12, BOOK3S_INTERRUPT_H_DOORBELL
	bne	3f
BEGIN_FTR_SECTION
	PPC_MSGSYNC
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
	lbz	r0, HSTATE_HOST_IPI(r13)
	cmpwi	r0, 0
	beq	4f
+65 −3
Original line number Diff line number Diff line
@@ -16,7 +16,22 @@ static void GLUE(X_PFX,ack_pending)(struct kvmppc_xive_vcpu *xc)
	u8 cppr;
	u16 ack;

	/* XXX DD1 bug workaround: Check PIPR vs. CPPR first ! */
	/*
	 * Ensure any previous store to CPPR is ordered vs.
	 * the subsequent loads from PIPR or ACK.
	 */
	eieio();

	/*
	 * DD1 bug workaround: If PIPR is less favored than CPPR
	 * ignore the interrupt or we might incorrectly lose an IPB
	 * bit.
	 */
	if (cpu_has_feature(CPU_FTR_POWER9_DD1)) {
		u8 pipr = __x_readb(__x_tima + TM_QW1_OS + TM_PIPR);
		if (pipr >= xc->hw_cppr)
			return;
	}

	/* Perform the acknowledge OS to register cycle. */
	ack = be16_to_cpu(__x_readw(__x_tima + TM_SPC_ACK_OS_REG));
@@ -235,6 +250,11 @@ static u32 GLUE(X_PFX,scan_interrupts)(struct kvmppc_xive_vcpu *xc,
	/*
	 * If we found an interrupt, adjust what the guest CPPR should
	 * be as if we had just fetched that interrupt from HW.
	 *
	 * Note: This can only make xc->cppr smaller as the previous
	 * loop will only exit with hirq != 0 if prio is lower than
	 * the current xc->cppr. Thus we don't need to re-check xc->mfrr
	 * for pending IPIs.
	 */
	if (hirq)
		xc->cppr = prio;
@@ -380,6 +400,12 @@ X_STATIC int GLUE(X_PFX,h_cppr)(struct kvm_vcpu *vcpu, unsigned long cppr)
	old_cppr = xc->cppr;
	xc->cppr = cppr;

	/*
	 * Order the above update of xc->cppr with the subsequent
	 * read of xc->mfrr inside push_pending_to_hw()
	 */
	smp_mb();

	/*
	 * We are masking less, we need to look for pending things
	 * to deliver and set VP pending bits accordingly to trigger
@@ -420,21 +446,37 @@ X_STATIC int GLUE(X_PFX,h_eoi)(struct kvm_vcpu *vcpu, unsigned long xirr)
	 * used to signal MFRR changes is EOId when fetched from
	 * the queue.
	 */
	if (irq == XICS_IPI || irq == 0)
	if (irq == XICS_IPI || irq == 0) {
		/*
		 * This barrier orders the setting of xc->cppr vs.
		 * subsquent test of xc->mfrr done inside
		 * scan_interrupts and push_pending_to_hw
		 */
		smp_mb();
		goto bail;
	}

	/* Find interrupt source */
	sb = kvmppc_xive_find_source(xive, irq, &src);
	if (!sb) {
		pr_devel(" source not found !\n");
		rc = H_PARAMETER;
		/* Same as above */
		smp_mb();
		goto bail;
	}
	state = &sb->irq_state[src];
	kvmppc_xive_select_irq(state, &hw_num, &xd);

	state->in_eoi = true;
	mb();

	/*
	 * This barrier orders both setting of in_eoi above vs,
	 * subsequent test of guest_priority, and the setting
	 * of xc->cppr vs. subsquent test of xc->mfrr done inside
	 * scan_interrupts and push_pending_to_hw
	 */
	smp_mb();

again:
	if (state->guest_priority == MASKED) {
@@ -461,6 +503,14 @@ X_STATIC int GLUE(X_PFX,h_eoi)(struct kvm_vcpu *vcpu, unsigned long xirr)

	}

	/*
	 * This barrier orders the above guest_priority check
	 * and spin_lock/unlock with clearing in_eoi below.
	 *
	 * It also has to be a full mb() as it must ensure
	 * the MMIOs done in source_eoi() are completed before
	 * state->in_eoi is visible.
	 */
	mb();
	state->in_eoi = false;
bail:
@@ -495,6 +545,18 @@ X_STATIC int GLUE(X_PFX,h_ipi)(struct kvm_vcpu *vcpu, unsigned long server,
	/* Locklessly write over MFRR */
	xc->mfrr = mfrr;

	/*
	 * The load of xc->cppr below and the subsequent MMIO store
	 * to the IPI must happen after the above mfrr update is
	 * globally visible so that:
	 *
	 * - Synchronize with another CPU doing an H_EOI or a H_CPPR
	 *   updating xc->cppr then reading xc->mfrr.
	 *
	 * - The target of the IPI sees the xc->mfrr update
	 */
	mb();

	/* Shoot the IPI if most favored than target cppr */
	if (mfrr < xc->cppr)
		__x_writeq(0, __x_trig_page(&xc->vp_ipi_data));
+5 −2
Original line number Diff line number Diff line
@@ -394,7 +394,7 @@ static int sthyi(u64 vaddr)
		"srl     %[cc],28\n"
		: [cc] "=d" (cc)
		: [code] "d" (code), [addr] "a" (addr)
		: "memory", "cc");
		: "3", "memory", "cc");
	return cc;
}

@@ -425,7 +425,7 @@ int handle_sthyi(struct kvm_vcpu *vcpu)
	VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr);
	trace_kvm_s390_handle_sthyi(vcpu, code, addr);

	if (reg1 == reg2 || reg1 & 1 || reg2 & 1 || addr & ~PAGE_MASK)
	if (reg1 == reg2 || reg1 & 1 || reg2 & 1)
		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);

	if (code & 0xffff) {
@@ -433,6 +433,9 @@ int handle_sthyi(struct kvm_vcpu *vcpu)
		goto out;
	}

	if (addr & ~PAGE_MASK)
		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);

	/*
	 * If the page has not yet been faulted in, we want to do that
	 * now and not after all the expensive calculations.
+3 −3
Original line number Diff line number Diff line
@@ -450,10 +450,10 @@ static inline int copy_fpregs_to_fpstate(struct fpu *fpu)
	return 0;
}

static inline void __copy_kernel_to_fpregs(union fpregs_state *fpstate)
static inline void __copy_kernel_to_fpregs(union fpregs_state *fpstate, u64 mask)
{
	if (use_xsave()) {
		copy_kernel_to_xregs(&fpstate->xsave, -1);
		copy_kernel_to_xregs(&fpstate->xsave, mask);
	} else {
		if (use_fxsr())
			copy_kernel_to_fxregs(&fpstate->fxsave);
@@ -477,7 +477,7 @@ static inline void copy_kernel_to_fpregs(union fpregs_state *fpstate)
			: : [addr] "m" (fpstate));
	}

	__copy_kernel_to_fpregs(fpstate);
	__copy_kernel_to_fpregs(fpstate, -1);
}

extern int copy_fpstate_to_sigframe(void __user *buf, void __user *fp, int size);
Loading