Skip to content

Commit 55f4db7

Browse files
committed
KVM: e500: perform hugepage check after looking up the PFN
e500 KVM tries to bypass __kvm_faultin_pfn() in order to map VM_PFNMAP VMAs as huge pages. This is a Bad Idea because VM_PFNMAP VMAs could become noncontiguous as a result of callsto remap_pfn_range(). Instead, use the already existing host PTE lookup to retrieve a valid host-side mapping level after __kvm_faultin_pfn() has returned. Then find the largest size that will satisfy the guest's request while staying within a single host PTE. Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 03b755b commit 55f4db7

File tree

1 file changed

+69
-109
lines changed

1 file changed

+69
-109
lines changed

arch/powerpc/kvm/e500_mmu_host.c

Lines changed: 69 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -326,15 +326,14 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
326326
struct tlbe_ref *ref)
327327
{
328328
struct kvm_memory_slot *slot;
329-
unsigned long pfn = 0; /* silence GCC warning */
329+
unsigned int psize;
330+
unsigned long pfn;
330331
struct page *page = NULL;
331332
unsigned long hva;
332-
int pfnmap = 0;
333333
int tsize = BOOK3E_PAGESZ_4K;
334334
int ret = 0;
335335
unsigned long mmu_seq;
336336
struct kvm *kvm = vcpu_e500->vcpu.kvm;
337-
unsigned long tsize_pages = 0;
338337
pte_t *ptep;
339338
unsigned int wimg = 0;
340339
pgd_t *pgdir;
@@ -356,111 +355,12 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
356355
slot = gfn_to_memslot(vcpu_e500->vcpu.kvm, gfn);
357356
hva = gfn_to_hva_memslot(slot, gfn);
358357

359-
if (tlbsel == 1) {
360-
struct vm_area_struct *vma;
361-
mmap_read_lock(kvm->mm);
362-
363-
vma = find_vma(kvm->mm, hva);
364-
if (vma && hva >= vma->vm_start &&
365-
(vma->vm_flags & VM_PFNMAP)) {
366-
/*
367-
* This VMA is a physically contiguous region (e.g.
368-
* /dev/mem) that bypasses normal Linux page
369-
* management. Find the overlap between the
370-
* vma and the memslot.
371-
*/
372-
373-
unsigned long start, end;
374-
unsigned long slot_start, slot_end;
375-
376-
pfnmap = 1;
377-
writable = vma->vm_flags & VM_WRITE;
378-
379-
start = vma->vm_pgoff;
380-
end = start +
381-
vma_pages(vma);
382-
383-
pfn = start + ((hva - vma->vm_start) >> PAGE_SHIFT);
384-
385-
slot_start = pfn - (gfn - slot->base_gfn);
386-
slot_end = slot_start + slot->npages;
387-
388-
if (start < slot_start)
389-
start = slot_start;
390-
if (end > slot_end)
391-
end = slot_end;
392-
393-
tsize = (gtlbe->mas1 & MAS1_TSIZE_MASK) >>
394-
MAS1_TSIZE_SHIFT;
395-
396-
/*
397-
* e500 doesn't implement the lowest tsize bit,
398-
* or 1K pages.
399-
*/
400-
tsize = max(BOOK3E_PAGESZ_4K, tsize & ~1);
401-
402-
/*
403-
* Now find the largest tsize (up to what the guest
404-
* requested) that will cover gfn, stay within the
405-
* range, and for which gfn and pfn are mutually
406-
* aligned.
407-
*/
408-
409-
for (; tsize > BOOK3E_PAGESZ_4K; tsize -= 2) {
410-
unsigned long gfn_start, gfn_end;
411-
tsize_pages = 1UL << (tsize - 2);
412-
413-
gfn_start = gfn & ~(tsize_pages - 1);
414-
gfn_end = gfn_start + tsize_pages;
415-
416-
if (gfn_start + pfn - gfn < start)
417-
continue;
418-
if (gfn_end + pfn - gfn > end)
419-
continue;
420-
if ((gfn & (tsize_pages - 1)) !=
421-
(pfn & (tsize_pages - 1)))
422-
continue;
423-
424-
gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1);
425-
pfn &= ~(tsize_pages - 1);
426-
break;
427-
}
428-
} else if (vma && hva >= vma->vm_start &&
429-
is_vm_hugetlb_page(vma)) {
430-
unsigned long psize = vma_kernel_pagesize(vma);
431-
432-
tsize = (gtlbe->mas1 & MAS1_TSIZE_MASK) >>
433-
MAS1_TSIZE_SHIFT;
434-
435-
/*
436-
* Take the largest page size that satisfies both host
437-
* and guest mapping
438-
*/
439-
tsize = min(__ilog2(psize) - 10, tsize);
440-
441-
/*
442-
* e500 doesn't implement the lowest tsize bit,
443-
* or 1K pages.
444-
*/
445-
tsize = max(BOOK3E_PAGESZ_4K, tsize & ~1);
446-
}
447-
448-
mmap_read_unlock(kvm->mm);
449-
}
450-
451-
if (likely(!pfnmap)) {
452-
tsize_pages = 1UL << (tsize + 10 - PAGE_SHIFT);
453-
pfn = __kvm_faultin_pfn(slot, gfn, FOLL_WRITE, &writable, &page);
454-
if (is_error_noslot_pfn(pfn)) {
455-
if (printk_ratelimit())
456-
pr_err("%s: real page not found for gfn %lx\n",
457-
__func__, (long)gfn);
458-
return -EINVAL;
459-
}
460-
461-
/* Align guest and physical address to page map boundaries */
462-
pfn &= ~(tsize_pages - 1);
463-
gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1);
358+
pfn = __kvm_faultin_pfn(slot, gfn, FOLL_WRITE, &writable, &page);
359+
if (is_error_noslot_pfn(pfn)) {
360+
if (printk_ratelimit())
361+
pr_err("%s: real page not found for gfn %lx\n",
362+
__func__, (long)gfn);
363+
return -EINVAL;
464364
}
465365

466366
spin_lock(&kvm->mmu_lock);
@@ -478,7 +378,7 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
478378
* can't run hence pfn won't change.
479379
*/
480380
local_irq_save(flags);
481-
ptep = find_linux_pte(pgdir, hva, NULL, NULL);
381+
ptep = find_linux_pte(pgdir, hva, NULL, &psize);
482382
if (ptep) {
483383
pte_t pte = READ_ONCE(*ptep);
484384

@@ -495,6 +395,66 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
495395
}
496396
local_irq_restore(flags);
497397

398+
if (psize && tlbsel == 1) {
399+
unsigned long psize_pages, tsize_pages;
400+
unsigned long start, end;
401+
unsigned long slot_start, slot_end;
402+
403+
psize_pages = 1UL << (psize - PAGE_SHIFT);
404+
start = pfn & ~(psize_pages - 1);
405+
end = start + psize_pages;
406+
407+
slot_start = pfn - (gfn - slot->base_gfn);
408+
slot_end = slot_start + slot->npages;
409+
410+
if (start < slot_start)
411+
start = slot_start;
412+
if (end > slot_end)
413+
end = slot_end;
414+
415+
tsize = (gtlbe->mas1 & MAS1_TSIZE_MASK) >>
416+
MAS1_TSIZE_SHIFT;
417+
418+
/*
419+
* Any page size that doesn't satisfy the host mapping
420+
* will fail the start and end tests.
421+
*/
422+
tsize = min(psize - PAGE_SHIFT + BOOK3E_PAGESZ_4K, tsize);
423+
424+
/*
425+
* e500 doesn't implement the lowest tsize bit,
426+
* or 1K pages.
427+
*/
428+
tsize = max(BOOK3E_PAGESZ_4K, tsize & ~1);
429+
430+
/*
431+
* Now find the largest tsize (up to what the guest
432+
* requested) that will cover gfn, stay within the
433+
* range, and for which gfn and pfn are mutually
434+
* aligned.
435+
*/
436+
437+
for (; tsize > BOOK3E_PAGESZ_4K; tsize -= 2) {
438+
unsigned long gfn_start, gfn_end;
439+
tsize_pages = 1UL << (tsize - 2);
440+
441+
gfn_start = gfn & ~(tsize_pages - 1);
442+
gfn_end = gfn_start + tsize_pages;
443+
444+
if (gfn_start + pfn - gfn < start)
445+
continue;
446+
if (gfn_end + pfn - gfn > end)
447+
continue;
448+
if ((gfn & (tsize_pages - 1)) !=
449+
(pfn & (tsize_pages - 1)))
450+
continue;
451+
452+
gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1);
453+
pfn &= ~(tsize_pages - 1);
454+
break;
455+
}
456+
}
457+
498458
kvmppc_e500_ref_setup(ref, gtlbe, pfn, wimg, writable);
499459
kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize,
500460
ref, gvaddr, stlbe);

0 commit comments

Comments
 (0)