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

Commit 1795f81f authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

Merge tag 'kvm-ppc-fixes-4.19-2' of...

Merge tag 'kvm-ppc-fixes-4.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc into HEAD

Second set of PPC KVM fixes for 4.19

Two fixes for KVM on POWER machines.  Both of these relate to memory
corruption and host crashes seen when transparent huge pages are
enabled.  The first fixes a host crash that can occur when a DMA
mapping is removed by the guest and the page mapped was part of a
transparent huge page; the second fixes corruption that could occur
when a hypervisor page fault for a radix guest is being serviced at
the same time that the backing page is being collapsed or split.
parents cb5fb87a 71d29f43
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -1051,7 +1051,6 @@ static inline void vmemmap_remove_mapping(unsigned long start,
	return hash__vmemmap_remove_mapping(start, page_size);
}
#endif
struct page *realmode_pfn_to_page(unsigned long pfn);

static inline pte_t pmd_pte(pmd_t pmd)
{
+0 −2
Original line number Diff line number Diff line
@@ -220,8 +220,6 @@ extern void iommu_del_device(struct device *dev);
extern int __init tce_iommu_bus_notifier_init(void);
extern long iommu_tce_xchg(struct iommu_table *tbl, unsigned long entry,
		unsigned long *hpa, enum dma_data_direction *direction);
extern long iommu_tce_xchg_rm(struct iommu_table *tbl, unsigned long entry,
		unsigned long *hpa, enum dma_data_direction *direction);
#else
static inline void iommu_register_group(struct iommu_table_group *table_group,
					int pci_domain_number,
+1 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ extern long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem,
		unsigned long ua, unsigned int pageshift, unsigned long *hpa);
extern long mm_iommu_ua_to_hpa_rm(struct mm_iommu_table_group_mem_t *mem,
		unsigned long ua, unsigned int pageshift, unsigned long *hpa);
extern void mm_iommu_ua_mark_dirty_rm(struct mm_struct *mm, unsigned long ua);
extern long mm_iommu_mapped_inc(struct mm_iommu_table_group_mem_t *mem);
extern void mm_iommu_mapped_dec(struct mm_iommu_table_group_mem_t *mem);
#endif
+0 −25
Original line number Diff line number Diff line
@@ -1013,31 +1013,6 @@ long iommu_tce_xchg(struct iommu_table *tbl, unsigned long entry,
}
EXPORT_SYMBOL_GPL(iommu_tce_xchg);

#ifdef CONFIG_PPC_BOOK3S_64
long iommu_tce_xchg_rm(struct iommu_table *tbl, unsigned long entry,
		unsigned long *hpa, enum dma_data_direction *direction)
{
	long ret;

	ret = tbl->it_ops->exchange_rm(tbl, entry, hpa, direction);

	if (!ret && ((*direction == DMA_FROM_DEVICE) ||
			(*direction == DMA_BIDIRECTIONAL))) {
		struct page *pg = realmode_pfn_to_page(*hpa >> PAGE_SHIFT);

		if (likely(pg)) {
			SetPageDirty(pg);
		} else {
			tbl->it_ops->exchange_rm(tbl, entry, hpa, direction);
			ret = -EFAULT;
		}
	}

	return ret;
}
EXPORT_SYMBOL_GPL(iommu_tce_xchg_rm);
#endif

int iommu_take_ownership(struct iommu_table *tbl)
{
	unsigned long flags, i, sz = (tbl->it_size + 7) >> 3;
+37 −54
Original line number Diff line number Diff line
@@ -525,8 +525,8 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
				   unsigned long ea, unsigned long dsisr)
{
	struct kvm *kvm = vcpu->kvm;
	unsigned long mmu_seq, pte_size;
	unsigned long gpa, gfn, hva, pfn;
	unsigned long mmu_seq;
	unsigned long gpa, gfn, hva;
	struct kvm_memory_slot *memslot;
	struct page *page = NULL;
	long ret;
@@ -623,9 +623,10 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
	 */
	hva = gfn_to_hva_memslot(memslot, gfn);
	if (upgrade_p && __get_user_pages_fast(hva, 1, 1, &page) == 1) {
		pfn = page_to_pfn(page);
		upgrade_write = true;
	} else {
		unsigned long pfn;

		/* Call KVM generic code to do the slow-path check */
		pfn = __gfn_to_pfn_memslot(memslot, gfn, false, NULL,
					   writing, upgrade_p);
@@ -639,41 +640,16 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
		}
	}

	/* See if we can insert a 1GB or 2MB large PTE here */
	level = 0;
	if (page && PageCompound(page)) {
		pte_size = PAGE_SIZE << compound_order(compound_head(page));
		if (pte_size >= PUD_SIZE &&
		    (gpa & (PUD_SIZE - PAGE_SIZE)) ==
		    (hva & (PUD_SIZE - PAGE_SIZE))) {
			level = 2;
			pfn &= ~((PUD_SIZE >> PAGE_SHIFT) - 1);
		} else if (pte_size >= PMD_SIZE &&
			   (gpa & (PMD_SIZE - PAGE_SIZE)) ==
			   (hva & (PMD_SIZE - PAGE_SIZE))) {
			level = 1;
			pfn &= ~((PMD_SIZE >> PAGE_SHIFT) - 1);
		}
	}

	/*
	 * Compute the PTE value that we need to insert.
	 */
	if (page) {
		pgflags = _PAGE_READ | _PAGE_EXEC | _PAGE_PRESENT | _PAGE_PTE |
			_PAGE_ACCESSED;
		if (writing || upgrade_write)
			pgflags |= _PAGE_WRITE | _PAGE_DIRTY;
		pte = pfn_pte(pfn, __pgprot(pgflags));
	} else {
	/*
	 * Read the PTE from the process' radix tree and use that
		 * so we get the attribute bits.
	 * so we get the shift and attribute bits.
	 */
	local_irq_disable();
	ptep = __find_linux_pte(vcpu->arch.pgdir, hva, NULL, &shift);
	pte = *ptep;
	local_irq_enable();

	/* Get pte level from shift/size */
	if (shift == PUD_SHIFT &&
	    (gpa & (PUD_SIZE - PAGE_SIZE)) ==
	    (hva & (PUD_SIZE - PAGE_SIZE))) {
@@ -682,11 +658,19 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
		   (gpa & (PMD_SIZE - PAGE_SIZE)) ==
		   (hva & (PMD_SIZE - PAGE_SIZE))) {
		level = 1;
		} else if (shift && shift != PAGE_SHIFT) {
			/* Adjust PFN */
			unsigned long mask = (1ul << shift) - PAGE_SIZE;
			pte = __pte(pte_val(pte) | (hva & mask));
	} else {
		level = 0;
		if (shift > PAGE_SHIFT) {
			/*
			 * If the pte maps more than one page, bring over
			 * bits from the virtual address to get the real
			 * address of the specific single page we want.
			 */
			unsigned long rpnmask = (1ul << shift) - PAGE_SIZE;
			pte = __pte(pte_val(pte) | (hva & rpnmask));
		}
	}

	pte = __pte(pte_val(pte) | _PAGE_EXEC | _PAGE_ACCESSED);
	if (writing || upgrade_write) {
		if (pte_val(pte) & _PAGE_WRITE)
@@ -694,7 +678,6 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
	} else {
		pte = __pte(pte_val(pte) & ~(_PAGE_WRITE | _PAGE_DIRTY));
	}
	}

	/* Allocate space in the tree and write the PTE */
	ret = kvmppc_create_pte(kvm, pte, gpa, level, mmu_seq);
Loading