1313#include <asm/tlb.h>
1414#include <asm/kvm_mmu.h>
1515
16+ static inline bool kvm_hugepage_capable (struct kvm_memory_slot * slot )
17+ {
18+ return slot -> arch .flags & KVM_MEM_HUGEPAGE_CAPABLE ;
19+ }
20+
21+ static inline bool kvm_hugepage_incapable (struct kvm_memory_slot * slot )
22+ {
23+ return slot -> arch .flags & KVM_MEM_HUGEPAGE_INCAPABLE ;
24+ }
25+
1626static inline void kvm_ptw_prepare (struct kvm * kvm , kvm_ptw_ctx * ctx )
1727{
1828 ctx -> level = kvm -> arch .root_level ;
@@ -365,6 +375,69 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
365375 kvm_ptw_top (kvm -> arch .pgd , start << PAGE_SHIFT , end << PAGE_SHIFT , & ctx );
366376}
367377
378+ int kvm_arch_prepare_memory_region (struct kvm * kvm , const struct kvm_memory_slot * old ,
379+ struct kvm_memory_slot * new , enum kvm_mr_change change )
380+ {
381+ gpa_t gpa_start ;
382+ hva_t hva_start ;
383+ size_t size , gpa_offset , hva_offset ;
384+
385+ if ((change != KVM_MR_MOVE ) && (change != KVM_MR_CREATE ))
386+ return 0 ;
387+ /*
388+ * Prevent userspace from creating a memory region outside of the
389+ * VM GPA address space
390+ */
391+ if ((new -> base_gfn + new -> npages ) > (kvm -> arch .gpa_size >> PAGE_SHIFT ))
392+ return - ENOMEM ;
393+
394+ new -> arch .flags = 0 ;
395+ size = new -> npages * PAGE_SIZE ;
396+ gpa_start = new -> base_gfn << PAGE_SHIFT ;
397+ hva_start = new -> userspace_addr ;
398+ if (IS_ALIGNED (size , PMD_SIZE ) && IS_ALIGNED (gpa_start , PMD_SIZE )
399+ && IS_ALIGNED (hva_start , PMD_SIZE ))
400+ new -> arch .flags |= KVM_MEM_HUGEPAGE_CAPABLE ;
401+ else {
402+ /*
403+ * Pages belonging to memslots that don't have the same
404+ * alignment within a PMD for userspace and GPA cannot be
405+ * mapped with PMD entries, because we'll end up mapping
406+ * the wrong pages.
407+ *
408+ * Consider a layout like the following:
409+ *
410+ * memslot->userspace_addr:
411+ * +-----+--------------------+--------------------+---+
412+ * |abcde|fgh Stage-1 block | Stage-1 block tv|xyz|
413+ * +-----+--------------------+--------------------+---+
414+ *
415+ * memslot->base_gfn << PAGE_SIZE:
416+ * +---+--------------------+--------------------+-----+
417+ * |abc|def Stage-2 block | Stage-2 block |tvxyz|
418+ * +---+--------------------+--------------------+-----+
419+ *
420+ * If we create those stage-2 blocks, we'll end up with this
421+ * incorrect mapping:
422+ * d -> f
423+ * e -> g
424+ * f -> h
425+ */
426+ gpa_offset = gpa_start & (PMD_SIZE - 1 );
427+ hva_offset = hva_start & (PMD_SIZE - 1 );
428+ if (gpa_offset != hva_offset ) {
429+ new -> arch .flags |= KVM_MEM_HUGEPAGE_INCAPABLE ;
430+ } else {
431+ if (gpa_offset == 0 )
432+ gpa_offset = PMD_SIZE ;
433+ if ((size + gpa_offset ) < (PMD_SIZE * 2 ))
434+ new -> arch .flags |= KVM_MEM_HUGEPAGE_INCAPABLE ;
435+ }
436+ }
437+
438+ return 0 ;
439+ }
440+
368441void kvm_arch_commit_memory_region (struct kvm * kvm ,
369442 struct kvm_memory_slot * old ,
370443 const struct kvm_memory_slot * new ,
@@ -562,47 +635,23 @@ static int kvm_map_page_fast(struct kvm_vcpu *vcpu, unsigned long gpa, bool writ
562635}
563636
564637static bool fault_supports_huge_mapping (struct kvm_memory_slot * memslot ,
565- unsigned long hva , unsigned long map_size , bool write )
638+ unsigned long hva , bool write )
566639{
567- size_t size ;
568- gpa_t gpa_start ;
569- hva_t uaddr_start , uaddr_end ;
640+ hva_t start , end ;
570641
571642 /* Disable dirty logging on HugePages */
572643 if (kvm_slot_dirty_track_enabled (memslot ) && write )
573644 return false;
574645
575- size = memslot -> npages * PAGE_SIZE ;
576- gpa_start = memslot -> base_gfn << PAGE_SHIFT ;
577- uaddr_start = memslot -> userspace_addr ;
578- uaddr_end = uaddr_start + size ;
646+ if (kvm_hugepage_capable (memslot ))
647+ return true;
579648
580- /*
581- * Pages belonging to memslots that don't have the same alignment
582- * within a PMD for userspace and GPA cannot be mapped with stage-2
583- * PMD entries, because we'll end up mapping the wrong pages.
584- *
585- * Consider a layout like the following:
586- *
587- * memslot->userspace_addr:
588- * +-----+--------------------+--------------------+---+
589- * |abcde|fgh Stage-1 block | Stage-1 block tv|xyz|
590- * +-----+--------------------+--------------------+---+
591- *
592- * memslot->base_gfn << PAGE_SIZE:
593- * +---+--------------------+--------------------+-----+
594- * |abc|def Stage-2 block | Stage-2 block |tvxyz|
595- * +---+--------------------+--------------------+-----+
596- *
597- * If we create those stage-2 blocks, we'll end up with this incorrect
598- * mapping:
599- * d -> f
600- * e -> g
601- * f -> h
602- */
603- if ((gpa_start & (map_size - 1 )) != (uaddr_start & (map_size - 1 )))
649+ if (kvm_hugepage_incapable (memslot ))
604650 return false;
605651
652+ start = memslot -> userspace_addr ;
653+ end = start + memslot -> npages * PAGE_SIZE ;
654+
606655 /*
607656 * Next, let's make sure we're not trying to map anything not covered
608657 * by the memslot. This means we have to prohibit block size mappings
@@ -615,8 +664,7 @@ static bool fault_supports_huge_mapping(struct kvm_memory_slot *memslot,
615664 * userspace_addr or the base_gfn, as both are equally aligned (per
616665 * the check above) and equally sized.
617666 */
618- return (hva & ~(map_size - 1 )) >= uaddr_start &&
619- (hva & ~(map_size - 1 )) + map_size <= uaddr_end ;
667+ return (hva >= ALIGN (start , PMD_SIZE )) && (hva < ALIGN_DOWN (end , PMD_SIZE ));
620668}
621669
622670/*
@@ -842,7 +890,7 @@ static int kvm_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, bool write)
842890
843891 /* Disable dirty logging on HugePages */
844892 level = 0 ;
845- if (!fault_supports_huge_mapping (memslot , hva , PMD_SIZE , write )) {
893+ if (!fault_supports_huge_mapping (memslot , hva , write )) {
846894 level = 0 ;
847895 } else {
848896 level = host_pfn_mapping_level (kvm , gfn , memslot );
@@ -901,12 +949,6 @@ void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
901949{
902950}
903951
904- int kvm_arch_prepare_memory_region (struct kvm * kvm , const struct kvm_memory_slot * old ,
905- struct kvm_memory_slot * new , enum kvm_mr_change change )
906- {
907- return 0 ;
908- }
909-
910952void kvm_arch_flush_remote_tlbs_memslot (struct kvm * kvm ,
911953 const struct kvm_memory_slot * memslot )
912954{
0 commit comments