@@ -538,8 +538,8 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
538538 unsigned long ea , unsigned long dsisr )
539539{
540540 struct kvm * kvm = vcpu -> kvm ;
541- unsigned long mmu_seq , pte_size ;
542- unsigned long gpa , gfn , hva , pfn ;
541+ unsigned long mmu_seq ;
542+ unsigned long gpa , gfn , hva ;
543543 struct kvm_memory_slot * memslot ;
544544 struct page * page = NULL ;
545545 long ret ;
@@ -636,9 +636,10 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
636636 */
637637 hva = gfn_to_hva_memslot (memslot , gfn );
638638 if (upgrade_p && __get_user_pages_fast (hva , 1 , 1 , & page ) == 1 ) {
639- pfn = page_to_pfn (page );
640639 upgrade_write = true;
641640 } else {
641+ unsigned long pfn ;
642+
642643 /* Call KVM generic code to do the slow-path check */
643644 pfn = __gfn_to_pfn_memslot (memslot , gfn , false, NULL ,
644645 writing , upgrade_p );
@@ -652,63 +653,55 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
652653 }
653654 }
654655
655- /* See if we can insert a 1GB or 2MB large PTE here */
656- level = 0 ;
657- if (page && PageCompound (page )) {
658- pte_size = PAGE_SIZE << compound_order (compound_head (page ));
659- if (pte_size >= PUD_SIZE &&
660- (gpa & (PUD_SIZE - PAGE_SIZE )) ==
661- (hva & (PUD_SIZE - PAGE_SIZE ))) {
662- level = 2 ;
663- pfn &= ~((PUD_SIZE >> PAGE_SHIFT ) - 1 );
664- } else if (pte_size >= PMD_SIZE &&
665- (gpa & (PMD_SIZE - PAGE_SIZE )) ==
666- (hva & (PMD_SIZE - PAGE_SIZE ))) {
667- level = 1 ;
668- pfn &= ~((PMD_SIZE >> PAGE_SHIFT ) - 1 );
669- }
670- }
671-
672656 /*
673- * Compute the PTE value that we need to insert.
657+ * Read the PTE from the process' radix tree and use that
658+ * so we get the shift and attribute bits.
674659 */
675- if (page ) {
676- pgflags = _PAGE_READ | _PAGE_EXEC | _PAGE_PRESENT | _PAGE_PTE |
677- _PAGE_ACCESSED ;
678- if (writing || upgrade_write )
679- pgflags |= _PAGE_WRITE | _PAGE_DIRTY ;
680- pte = pfn_pte (pfn , __pgprot (pgflags ));
681- } else {
682- /*
683- * Read the PTE from the process' radix tree and use that
684- * so we get the attribute bits.
685- */
686- local_irq_disable ();
687- ptep = __find_linux_pte (vcpu -> arch .pgdir , hva , NULL , & shift );
688- pte = * ptep ;
660+ local_irq_disable ();
661+ ptep = __find_linux_pte (vcpu -> arch .pgdir , hva , NULL , & shift );
662+ /*
663+ * If the PTE disappeared temporarily due to a THP
664+ * collapse, just return and let the guest try again.
665+ */
666+ if (!ptep ) {
689667 local_irq_enable ();
690- if (shift == PUD_SHIFT &&
691- (gpa & (PUD_SIZE - PAGE_SIZE )) ==
692- (hva & (PUD_SIZE - PAGE_SIZE ))) {
693- level = 2 ;
694- } else if (shift == PMD_SHIFT &&
695- (gpa & (PMD_SIZE - PAGE_SIZE )) ==
696- (hva & (PMD_SIZE - PAGE_SIZE ))) {
697- level = 1 ;
698- } else if (shift && shift != PAGE_SHIFT ) {
699- /* Adjust PFN */
700- unsigned long mask = (1ul << shift ) - PAGE_SIZE ;
701- pte = __pte (pte_val (pte ) | (hva & mask ));
702- }
703- pte = __pte (pte_val (pte ) | _PAGE_EXEC | _PAGE_ACCESSED );
704- if (writing || upgrade_write ) {
705- if (pte_val (pte ) & _PAGE_WRITE )
706- pte = __pte (pte_val (pte ) | _PAGE_DIRTY );
707- } else {
708- pte = __pte (pte_val (pte ) & ~(_PAGE_WRITE | _PAGE_DIRTY ));
668+ if (page )
669+ put_page (page );
670+ return RESUME_GUEST ;
671+ }
672+ pte = * ptep ;
673+ local_irq_enable ();
674+
675+ /* Get pte level from shift/size */
676+ if (shift == PUD_SHIFT &&
677+ (gpa & (PUD_SIZE - PAGE_SIZE )) ==
678+ (hva & (PUD_SIZE - PAGE_SIZE ))) {
679+ level = 2 ;
680+ } else if (shift == PMD_SHIFT &&
681+ (gpa & (PMD_SIZE - PAGE_SIZE )) ==
682+ (hva & (PMD_SIZE - PAGE_SIZE ))) {
683+ level = 1 ;
684+ } else {
685+ level = 0 ;
686+ if (shift > PAGE_SHIFT ) {
687+ /*
688+ * If the pte maps more than one page, bring over
689+ * bits from the virtual address to get the real
690+ * address of the specific single page we want.
691+ */
692+ unsigned long rpnmask = (1ul << shift ) - PAGE_SIZE ;
693+ pte = __pte (pte_val (pte ) | (hva & rpnmask ));
709694 }
710695 }
711696
697+ pte = __pte (pte_val (pte ) | _PAGE_EXEC | _PAGE_ACCESSED );
698+ if (writing || upgrade_write ) {
699+ if (pte_val (pte ) & _PAGE_WRITE )
700+ pte = __pte (pte_val (pte ) | _PAGE_DIRTY );
701+ } else {
702+ pte = __pte (pte_val (pte ) & ~(_PAGE_WRITE | _PAGE_DIRTY ));
703+ }
704+
712705 /* Allocate space in the tree and write the PTE */
713706 ret = kvmppc_create_pte (kvm , pte , gpa , level , mmu_seq );
714707
0 commit comments