KVM: Support PUD hugepages at stage 2
Subsystems (4)
v7 cover KVM: Support PUD hugepages at stage 2
This series is an update to the PUD hugepage support previously posted at [0]. This patchset adds support for PUD hugepages at stage 2 a feature that is useful on cores that have support for large sized TLB mappings (e.g., 1GB for 4K granule).
This version fixes two bugs -
* Corrects stage 2 fault handling for unsupported hugepage sizes (new patch 1/9). This is a long standing bug and needs backporting to earlier kernels
* Ensures that multiple vcpus faulting on the same hugepage doesn't hamper forward progress (patch 9)
The patches are based on dynamic IPA support which could lead to a situation where the guest doesn't have PUD level. In this case, the patches have been updated to fallback to the PTE level mappings at stage 2.
The patches have been tested on AMD Seattle system with the following hugepage sizes - 64K, 32M, 1G.
Thanks,
Punit
v6 -> v7
* Restrict thp check to exclude hugetlbfs pages - Patch 1
* Don't update PUD entry if there's no change - Patch 9
* Add check for PUD level in stage 2 - Patch 9
v5 -> v6
* Split Patch 1 to move out the refactoring of exec permissions on page table entries.
* Patch 4 - Initialise p*dpp pointers in stage2_get_leaf_entry()
* Patch 5 - Trigger a BUG() in kvm_pud_pfn() on arm
v4 -> v5:
* Patch 1 - Drop helper stage2_should_exec() and refactor the condition to decide if a page table entry should be marked executable
* Patch 4-6 - Introduce stage2_get_leaf_entry() and use it in this and latter patches
* Patch 7 - Use stage 2 accessors instead of using the page table helpers directly
* Patch 7 - Add a note to update the PUD hugepage support when number of levels of stage 2 tables differs from stage 1
v3 -> v4:
* Patch 1 and 7 - Don't put down hugepages pte if logging is enabled
* Patch 4-5 - Add PUD hugepage support for exec and access faults
* Patch 6 - PUD hugepage support for aging page table entries
v2 -> v3:
* Update vma_pagesize directly if THP [1/4]. Previsouly this was done indirectly via hugetlb
* Added review tag [4/4]
v1 -> v2:
* Create helper to check if the page should have exec permission [1/4]
* Fix broken condition to detect THP hugepage [1/4]
* Fix in-correct hunk resulting from a rebase [4/4]
[0] https://www.spinics.net/lists/kvm-arm/msg32241.html
[1] https://www.spinics.net/lists/kvm-arm/msg32641.html
Punit Agrawal (9):
KVM: arm/arm64: Ensure only THP is candidate for adjustment
KVM: arm/arm64: Share common code in user_mem_abort()
KVM: arm/arm64: Re-factor setting the Stage 2 entry to exec on fault
KVM: arm/arm64: Introduce helpers to manipulate page table entries
KVM: arm64: Support dirty page tracking for PUD hugepages
KVM: arm64: Support PUD hugepage in stage2_is_exec()
KVM: arm64: Support handling access faults for PUD hugepages
KVM: arm64: Update age handlers to support PUD hugepages
KVM: arm64: Add support for creating PUD hugepages at stage 2
arch/arm/include/asm/kvm_mmu.h | 61 +++++ arch/arm64/include/asm/kvm_mmu.h | 48 ++++ arch/arm64/include/asm/pgtable-hwdef.h | 4 + arch/arm64/include/asm/pgtable.h | 9 + virt/kvm/arm/mmu.c | 324 +++++++++++++++++++------ 5 files changed, 368 insertions(+), 78 deletions(-)
Signature · 1 line
2.18.0
PATCH v7 1/9 KVM: arm/arm64: Ensure only THP is candidate for adjustment
PageTransCompoundMap() returns true for hugetlbfs and THP hugepages. This behaviour incorrectly leads to stage 2 faults for unsupported hugepage sizes (e.g., 64K hugepage with 4K pages) to be treated as THP faults.
Tighten the check to filter out hugetlbfs pages. This also leads to consistently mapping all unsupported hugepage sizes as PTE level entries at stage 2.
--- virt/kvm/arm/mmu.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
virt/kvm/arm/mmu.c +7 -1
@@ -1231,8 +1231,14 @@ static bool transparent_hugepage_adjust(kvm_pfn_t *pfnp, phys_addr_t *ipap) {kvm_pfn_t pfn = *pfnp;gfn_t gfn = *ipap >>PAGE_SHIFT ; +struct page *page =pfn_to_page (pfn); -if (PageTransCompoundMap (pfn_to_page (pfn))) { +/* +* PageTransCompoungMap() returns true for THP and +* hugetlbfs. Make sure the adjustment is done only for THP +* pages. +*/ +if (!PageHuge (page) &&PageTransCompoundMap (page)) {unsigned long mask;/* * The address we faulted on is backed by a transparent huge
Signature · 1 line
2.18.0
Re: [PATCH v7 1/9] KVM: arm/arm64: Ensure only THP is candidate for adjustment
Hi Punit,
Quoted 25 lines · Punit Agrawal
PageTransCompoundMap()returns true for hugetlbfs and THP hugepages. This behaviour incorrectly leads to stage 2 faults for unsupported hugepage sizes (e.g., 64K hugepage with 4K pages) to be treated as THP faults.Tighten the check to filter out hugetlbfs pages. This also leads to consistently mapping all unsupported hugepage sizes as PTE level entries at stage 2.
Signed-off-by Punit Agrawal <[email protected]>Cc Christoffer Dall <[email protected]>Cc Marc Zyngier <[email protected]>Cc Suzuki Poulose <[email protected]>Cc [email protected] # v4.13+--- virt/kvm/arm/mmu.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)virt/kvm/arm/mmu.c +0
-0@@ -1231,8 +1231,14 @@ static bool transparent_hugepage_adjust(kvm_pfn_t *pfnp, phys_addr_t *ipap) {kvm_pfn_t pfn = *pfnp;
virt/kvm/arm/mmu.c static bool transparent_hugepage_adjust(kvm_pfn_t *pfnp, phys_addr_t *ipap) · line 1241
Quoted 10 lines
virt/kvm/arm/mmu.c +7
-1gfn_t gfn = *ipap >>PAGE_SHIFT ; +struct page *page =pfn_to_page (pfn); -if (PageTransCompoundMap (pfn_to_page (pfn))) { +/* +* PageTransCompoungMap() returns true for THP and +* hugetlbfs. Make sure the adjustment is done only for THP +* pages. +*/ +if (!PageHuge (page) &&PageTransCompoundMap (page)) {
PATCH v7 2/9 KVM: arm/arm64: Share common code in user_mem_abort()
In reply to Punit AgrawalThe code for operations such as marking the pfn as dirty, and dcache/icache maintenance during stage 2 fault handling is duplicated between normal pages and PMD hugepages.
Instead of creating another copy of the operations when we introduce PUD hugepages, let's share them across the different pagesizes.
--- virt/kvm/arm/mmu.c | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-)
virt/kvm/arm/mmu.c +29 -16
@@ -1490,7 +1490,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,kvm_pfn_t pfn;pgprot_t mem_type =PAGE_S2 ;bool logging_active =memslot_is_logging (memslot); -unsigned long flags =0 ; +unsigned long vma_pagesize, flags =0 ; write_fault =kvm_is_write_fault (vcpu); exec_fault =kvm_vcpu_trap_is_iabt (vcpu);
@@ -1510,10 +1510,17 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,return -EFAULT ; } -if (vma_kernel_pagesize (vma) ==PMD_SIZE && !logging_active) { + vma_pagesize =vma_kernel_pagesize (vma); +if (vma_pagesize ==PMD_SIZE && !logging_active) { hugetlb = true; gfn = (fault_ipa &PMD_MASK ) >>PAGE_SHIFT ; }else { +/* +* Fallback to PTE if it's not one of the Stage 2 +* supported hugepage sizes +*/ + vma_pagesize =PAGE_SIZE ; +/* * Pages belonging to memslots that don't have the same * alignment for userspace and IPA cannot be mapped using
@@ -1579,23 +1586,34 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,if (mmu_notifier_retry (kvm, mmu_seq)) goto out_unlock; -if (!hugetlb && !force_pte) +if (!hugetlb && !force_pte) { +/* +* Only PMD_SIZE transparent hugepages(THP) are +* currently supported. This code will need to be +* updated to support other THP sizes. +*/ hugetlb =transparent_hugepage_adjust (&pfn, &fault_ipa); +if (hugetlb) + vma_pagesize =PMD_SIZE ; + } + +if (writable) +kvm_set_pfn_dirty (pfn); -if (hugetlb) { +if (fault_status !=FSC_PERM ) +clean_dcache_guest_page (pfn, vma_pagesize); + +if (exec_fault) +invalidate_icache_guest_page (pfn, vma_pagesize); + +if (hugetlb && vma_pagesize ==PMD_SIZE ) {pmd_t new_pmd =pfn_pmd (pfn, mem_type); new_pmd =pmd_mkhuge (new_pmd); -if (writable) { +if (writable) new_pmd =kvm_s2pmd_mkwrite (new_pmd); -kvm_set_pfn_dirty (pfn); - } - -if (fault_status !=FSC_PERM ) -clean_dcache_guest_page (pfn,PMD_SIZE );if (exec_fault) { new_pmd =kvm_s2pmd_mkexec (new_pmd); -invalidate_icache_guest_page (pfn,PMD_SIZE ); }else if (fault_status ==FSC_PERM ) {/* Preserve execute if XN was already cleared */ if (stage2_is_exec (kvm, fault_ipa))
@@ -1608,16 +1626,11 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,if (writable) { new_pte =kvm_s2pte_mkwrite (new_pte); -kvm_set_pfn_dirty (pfn);mark_page_dirty (kvm, gfn); } -if (fault_status !=FSC_PERM ) -clean_dcache_guest_page (pfn,PAGE_SIZE ); -if (exec_fault) { new_pte =kvm_s2pte_mkexec (new_pte); -invalidate_icache_guest_page (pfn,PAGE_SIZE ); }else if (fault_status ==FSC_PERM ) {/* Preserve execute if XN was already cleared */ if (stage2_is_exec (kvm, fault_ipa))
Signature · 1 line
2.18.0
PATCH v7 3/9 KVM: arm/arm64: Re-factor setting the Stage 2 entry to exec on fault
In reply to Punit AgrawalStage 2 fault handler marks a page as executable if it is handling an execution fault or if it was a permission fault in which case the executable bit needs to be preserved.
The logic to decide if the page should be marked executable is duplicated for PMD and PTE entries. To avoid creating another copy when support for PUD hugepages is introduced refactor the code to share the checks needed to mark a page table entry as executable.
--- virt/kvm/arm/mmu.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-)
virt/kvm/arm/mmu.c +15 -13
@@ -1481,7 +1481,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, unsigned long fault_status) {int ret; -bool write_fault, exec_fault, writable, hugetlb = false, force_pte = false; +bool write_fault, writable, hugetlb = false, force_pte = false; +bool exec_fault, needs_exec;unsigned long mmu_seq;gfn_t gfn = fault_ipa >>PAGE_SHIFT ;struct kvm *kvm = vcpu->kvm;
@@ -1606,19 +1607,25 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,if (exec_fault)invalidate_icache_guest_page (pfn, vma_pagesize); +/* +* If we took an execution fault we have made the +* icache/dcache coherent above and should now let the s2 +* mapping be executable. +* +* Write faults (!exec_fault && FSC_PERM) are orthogonal to +* execute permissions, and we preserve whatever we have. +*/ + needs_exec = exec_fault || + (fault_status ==FSC_PERM &&stage2_is_exec (kvm, fault_ipa)); +if (hugetlb && vma_pagesize ==PMD_SIZE ) {pmd_t new_pmd =pfn_pmd (pfn, mem_type); new_pmd =pmd_mkhuge (new_pmd);if (writable) new_pmd =kvm_s2pmd_mkwrite (new_pmd); -if (exec_fault) { +if (needs_exec) new_pmd =kvm_s2pmd_mkexec (new_pmd); - }else if (fault_status ==FSC_PERM ) { -/* Preserve execute if XN was already cleared */ -if (stage2_is_exec (kvm, fault_ipa)) - new_pmd =kvm_s2pmd_mkexec (new_pmd); - } ret =stage2_set_pmd_huge (kvm, memcache, fault_ipa, &new_pmd); }else {
@@ -1629,13 +1636,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,mark_page_dirty (kvm, gfn); } -if (exec_fault) { +if (needs_exec) new_pte =kvm_s2pte_mkexec (new_pte); - }else if (fault_status ==FSC_PERM ) { -/* Preserve execute if XN was already cleared */ -if (stage2_is_exec (kvm, fault_ipa)) - new_pte =kvm_s2pte_mkexec (new_pte); - } ret =stage2_set_pte (kvm, memcache, fault_ipa, &new_pte, flags); }
Signature · 1 line
2.18.0
PATCH v7 4/9 KVM: arm/arm64: Introduce helpers to manipulate page table entries
In reply to Punit AgrawalIntroduce helpers to abstract architectural handling of the conversion of pfn to page table entries and marking a PMD page table entry as a block entry.
The helpers are introduced in preparation for supporting PUD hugepages at stage 2 - which are supported on arm64 but do not exist on arm.
--- arch/arm/include/asm/kvm_mmu.h | 5 +++++ arch/arm64/include/asm/kvm_mmu.h | 5 +++++ virt/kvm/arm/mmu.c | 14 ++++++++------ 3 files changed, 18 insertions(+), 6 deletions(-)
arch/arm/include/asm/kvm_mmu.h +5 -0
@@ -82,6 +82,11 @@ void kvm_clear_hyp_idmap(void);#define kvm_mk_pud (pmdp) __pud(__pa(pmdp) | PMD_TYPE_TABLE)#define kvm_mk_pgd (pudp) ({ BUILD_BUG(); 0; }) +#define kvm_pfn_pte (pfn, prot) pfn_pte(pfn, prot) +#define kvm_pfn_pmd (pfn, prot) pfn_pmd(pfn, prot) + +#define kvm_pmd_mkhuge (pmd) pmd_mkhuge(pmd) +static inline pte_t kvm_s2pte_mkwrite (pte_t pte) {pte_val (pte) |=L_PTE_S2_RDWR ;
arch/arm64/include/asm/kvm_mmu.h +5 -0
@@ -184,6 +184,11 @@ void kvm_clear_hyp_idmap(void);#define kvm_mk_pgd (pudp) \ __pgd(__phys_to_pgd_val(__pa(pudp)) | PUD_TYPE_TABLE) +#define kvm_pfn_pte (pfn, prot) pfn_pte(pfn, prot) +#define kvm_pfn_pmd (pfn, prot) pfn_pmd(pfn, prot) + +#define kvm_pmd_mkhuge (pmd) pmd_mkhuge(pmd) +static inline pte_t kvm_s2pte_mkwrite (pte_t pte) {pte_val (pte) |=PTE_S2_RDWR ;
virt/kvm/arm/mmu.c +8 -6
@@ -607,7 +607,7 @@ static void create_hyp_pte_mappings(pmd_t *pmd, unsigned long start, addr = start;do { pte =pte_offset_kernel (pmd, addr); -kvm_set_pte (pte,pfn_pte (pfn, prot)); +kvm_set_pte (pte,kvm_pfn_pte (pfn, prot));get_page (virt_to_page (pte)); pfn++; }while (addr +=PAGE_SIZE , addr != end);
@@ -1202,7 +1202,7 @@ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa, pfn =__phys_to_pfn (pa);for (addr = guest_ipa; addr < end; addr +=PAGE_SIZE ) { -pte_t pte =pfn_pte (pfn,PAGE_S2_DEVICE ); +pte_t pte =kvm_pfn_pte (pfn,PAGE_S2_DEVICE );if (writable) pte =kvm_s2pte_mkwrite (pte);
@@ -1619,8 +1619,10 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, (fault_status ==FSC_PERM &&stage2_is_exec (kvm, fault_ipa));if (hugetlb && vma_pagesize ==PMD_SIZE ) { -pmd_t new_pmd =pfn_pmd (pfn, mem_type); - new_pmd =pmd_mkhuge (new_pmd); +pmd_t new_pmd =kvm_pfn_pmd (pfn, mem_type); + + new_pmd =kvm_pmd_mkhuge (new_pmd); +if (writable) new_pmd =kvm_s2pmd_mkwrite (new_pmd);
@@ -1629,7 +1631,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, ret =stage2_set_pmd_huge (kvm, memcache, fault_ipa, &new_pmd); }else { -pte_t new_pte =pfn_pte (pfn, mem_type); +pte_t new_pte =kvm_pfn_pte (pfn, mem_type);if (writable) { new_pte =kvm_s2pte_mkwrite (new_pte);
@@ -1886,7 +1888,7 @@ void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)* just like a translation fault and clean the cache to the PoC. */ clean_dcache_guest_page (pfn,PAGE_SIZE ); - stage2_pte =pfn_pte (pfn,PAGE_S2 ); + stage2_pte =kvm_pfn_pte (pfn,PAGE_S2 );handle_hva_to_gpa (kvm, hva, end, &kvm_set_spte_handler, &stage2_pte); }
Signature · 1 line
2.18.0
PATCH v7 5/9 KVM: arm64: Support dirty page tracking for PUD hugepages
In reply to Punit AgrawalIn preparation for creating PUD hugepages at stage 2, add support for write protecting PUD hugepages when they are encountered. Write protecting guest tables is used to track dirty pages when migrating VMs.
Also, provide trivial implementations of required kvm_s2pud_* helpers to allow sharing of code with arm32.
--- arch/arm/include/asm/kvm_mmu.h | 15 +++++++++++++++ arch/arm64/include/asm/kvm_mmu.h | 10 ++++++++++ virt/kvm/arm/mmu.c | 11 +++++++---- 3 files changed, 32 insertions(+), 4 deletions(-)
arch/arm/include/asm/kvm_mmu.h +15 -0
@@ -87,6 +87,21 @@ void kvm_clear_hyp_idmap(void);#define kvm_pmd_mkhuge (pmd) pmd_mkhuge(pmd) +/* +* The following kvm_*pud*() functions are provided strictly to allow +* sharing code with arm64. They should never be called in practice. +*/ +static inline void kvm_set_s2pud_readonly (pud_t *pud) +{ +BUG (); +} + +static inline bool kvm_s2pud_readonly (pud_t *pud) +{ +BUG (); +return false; +} +static inline pte_t kvm_s2pte_mkwrite (pte_t pte) {pte_val (pte) |=L_PTE_S2_RDWR ;
arch/arm64/include/asm/kvm_mmu.h +10 -0
@@ -251,6 +251,16 @@ static inline bool kvm_s2pmd_exec(pmd_t *pmdp)return !(READ_ONCE (pmd_val (*pmdp)) &PMD_S2_XN ); } +static inline void kvm_set_s2pud_readonly (pud_t *pudp) +{ +kvm_set_s2pte_readonly ((pte_t *)pudp); +} + +static inline bool kvm_s2pud_readonly (pud_t *pudp) +{ +return kvm_s2pte_readonly ((pte_t *)pudp); +} +#define hyp_pte_table_empty (ptep) kvm_page_empty(ptep)#ifdef __PAGETABLE_PMD_FOLDED
virt/kvm/arm/mmu.c +7 -4
@@ -1347,9 +1347,12 @@ static void stage2_wp_puds(struct kvm *kvm, pgd_t *pgd,do { next =stage2_pud_addr_end (kvm, addr, end);if (!stage2_pud_none (kvm, *pud)) { -/* TODO:PUD not supported, revisit later if supported */ -BUG_ON (stage2_pud_huge (kvm, *pud)); -stage2_wp_pmds (kvm, pud, addr, next); +if (stage2_pud_huge (kvm, *pud)) { +if (!kvm_s2pud_readonly (pud)) +kvm_set_s2pud_readonly (pud); + }else { +stage2_wp_pmds (kvm, pud, addr, next); + } } }while (pud++, addr = next, addr != end); }
@@ -1392,7 +1395,7 @@ static void stage2_wp_range(struct kvm *kvm, phys_addr_t addr, phys_addr_t end)* * Called to start logging dirty pages after memory region * KVM_MEM_LOG_DIRTY_PAGES operation is called. After this function returns -* all present PMD and PTEs are write protected in the memory region. +* all present PUD, PMD and PTEs are write protected in the memory region. * Afterwards read of dirty page log can be called. * * Acquires kvm_mmu_lock. Called with kvm->slots_lock mutex acquired,
Signature · 1 line
2.18.0
PATCH v7 6/9 KVM: arm64: Support PUD hugepage in stage2_is_exec()
In reply to Punit AgrawalIn preparation for creating PUD hugepages at stage 2, add support for detecting execute permissions on PUD page table entries. Faults due to lack of execute permissions on page table entries is used to perform i-cache invalidation on first execute.
Provide trivial implementations of arm32 helpers to allow sharing of code.
--- arch/arm/include/asm/kvm_mmu.h | 6 +++ arch/arm64/include/asm/kvm_mmu.h | 5 +++ arch/arm64/include/asm/pgtable-hwdef.h | 2 + virt/kvm/arm/mmu.c | 53 +++++++++++++++++++++++--- 4 files changed, 61 insertions(+), 5 deletions(-)
arch/arm/include/asm/kvm_mmu.h +6 -0
@@ -102,6 +102,12 @@ static inline bool kvm_s2pud_readonly(pud_t *pud)return false; } +static inline bool kvm_s2pud_exec (pud_t *pud) +{ +BUG (); +return false; +} +static inline pte_t kvm_s2pte_mkwrite (pte_t pte) {pte_val (pte) |=L_PTE_S2_RDWR ;
arch/arm64/include/asm/kvm_mmu.h +5 -0
@@ -261,6 +261,11 @@ static inline bool kvm_s2pud_readonly(pud_t *pudp)return kvm_s2pte_readonly ((pte_t *)pudp); } +static inline bool kvm_s2pud_exec (pud_t *pudp) +{ +return !(READ_ONCE (pud_val (*pudp)) &PUD_S2_XN ); +} +#define hyp_pte_table_empty (ptep) kvm_page_empty(ptep)#ifdef __PAGETABLE_PMD_FOLDED
arch/arm64/include/asm/pgtable-hwdef.h +2 -0
@@ -193,6 +193,8 @@#define PMD_S2_RDWR (_AT(pmdval_t, 3) << 6)/* HAP[2:1] */ #define PMD_S2_XN (_AT(pmdval_t, 2) << 53)/* XN[1:0] */ +#define PUD_S2_XN (_AT(pudval_t, 2) << 53)/* XN[1:0] */ +/* * Memory Attribute override for Stage-2 (MemAttr[3:0]) */
virt/kvm/arm/mmu.c +48 -5
71 lines not on this page · raw message
Signature · 1 line
2.18.0
PATCH v7 7/9 KVM: arm64: Support handling access faults for PUD hugepages
In reply to Punit AgrawalIn preparation for creating larger hugepages at Stage 2, extend the access fault handling at Stage 2 to support PUD hugepages when encountered.
Provide trivial helpers for arm32 to allow sharing of code.
--- arch/arm/include/asm/kvm_mmu.h | 9 +++++++++ arch/arm64/include/asm/kvm_mmu.h | 7 +++++++ arch/arm64/include/asm/pgtable.h | 6 ++++++ virt/kvm/arm/mmu.c | 22 +++++++++++----------- 4 files changed, 33 insertions(+), 11 deletions(-)
arch/arm/include/asm/kvm_mmu.h +9 -0
@@ -85,6 +85,9 @@ void kvm_clear_hyp_idmap(void);#define kvm_pfn_pte (pfn, prot) pfn_pte(pfn, prot)#define kvm_pfn_pmd (pfn, prot) pfn_pmd(pfn, prot) +#define kvm_pud_pfn (pud) ({ BUG(); 0; }) + +#define kvm_pmd_mkhuge (pmd) pmd_mkhuge(pmd)/*
@@ -108,6 +111,12 @@ static inline bool kvm_s2pud_exec(pud_t *pud)return false; } +static inline pud_t kvm_s2pud_mkyoung (pud_t pud) +{ +BUG (); +return pud; +} +static inline pte_t kvm_s2pte_mkwrite (pte_t pte) {pte_val (pte) |=L_PTE_S2_RDWR ;
arch/arm64/include/asm/kvm_mmu.h +7 -0
@@ -187,6 +187,8 @@ void kvm_clear_hyp_idmap(void);#define kvm_pfn_pte (pfn, prot) pfn_pte(pfn, prot)#define kvm_pfn_pmd (pfn, prot) pfn_pmd(pfn, prot) +#define kvm_pud_pfn (pud) pud_pfn(pud) +#define kvm_pmd_mkhuge (pmd) pmd_mkhuge(pmd)static inline pte_t kvm_s2pte_mkwrite (pte_t pte)
@@ -266,6 +268,11 @@ static inline bool kvm_s2pud_exec(pud_t *pudp)return !(READ_ONCE (pud_val (*pudp)) &PUD_S2_XN ); } +static inline pud_t kvm_s2pud_mkyoung (pud_t pud) +{ +return pud_mkyoung (pud); +} +#define hyp_pte_table_empty (ptep) kvm_page_empty(ptep)#ifdef __PAGETABLE_PMD_FOLDED
arch/arm64/include/asm/pgtable.h +6 -0
@@ -314,6 +314,11 @@ static inline pte_t pud_pte(pud_t pud)return __pte (pud_val (pud)); } +static inline pud_t pte_pud (pte_t pte) +{ +return __pud (pte_val (pte)); +} +static inline pmd_t pud_pmd (pud_t pud) {return __pmd (pud_val (pud));
@@ -380,6 +385,7 @@ static inline int pmd_protnone(pmd_t pmd)#define pfn_pmd (pfn,prot) __pmd(__phys_to_pmd_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))#define mk_pmd (page,prot) pfn_pmd(page_to_pfn(page),prot) +#define pud_mkyoung (pud) pte_pud(pte_mkyoung(pud_pte(pud)))#define pud_write (pud) pte_write(pud_pte(pud))#define __pud_to_phys (pud) __pte_to_phys(pud_pte(pud))
virt/kvm/arm/mmu.c +11 -11
@@ -1706,6 +1706,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,*/ static void handle_access_fault (struct kvm_vcpu *vcpu,phys_addr_t fault_ipa) { +pud_t *pud;pmd_t *pmd;pte_t *pte;kvm_pfn_t pfn;
@@ -1715,24 +1716,23 @@ static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)spin_lock (&vcpu->kvm->mmu_lock); - pmd =stage2_get_pmd (vcpu->kvm,NULL , fault_ipa); -if (!pmd ||pmd_none (*pmd))/* Nothing there */ +if (!stage2_get_leaf_entry (vcpu->kvm, fault_ipa, &pud, &pmd, &pte)) goto out; -if (pmd_thp_or_huge (*pmd)) {/* THP, HugeTLB */ +if (pud) {/* HugeTLB */ + *pud =kvm_s2pud_mkyoung (*pud); + pfn =kvm_pud_pfn (*pud); + pfn_valid = true; + }else if (pmd) {/* THP, HugeTLB */ *pmd =pmd_mkyoung (*pmd); pfn =pmd_pfn (*pmd); pfn_valid = true; - goto out; + }else { + *pte =pte_mkyoung (*pte);/* Just a page... */ + pfn =pte_pfn (*pte); + pfn_valid = true; } - pte =pte_offset_kernel (pmd, fault_ipa); -if (pte_none (*pte))/* Nothing there either */ - goto out; - - *pte =pte_mkyoung (*pte);/* Just a page... */ - pfn =pte_pfn (*pte); - pfn_valid = true; out:spin_unlock (&vcpu->kvm->mmu_lock);if (pfn_valid)
Signature · 1 line
2.18.0
PATCH v7 8/9 KVM: arm64: Update age handlers to support PUD hugepages
In reply to Punit AgrawalIn preparation for creating larger hugepages at Stage 2, add support to the age handling notifiers for PUD hugepages when encountered.
Provide trivial helpers for arm32 to allow sharing code.
--- arch/arm/include/asm/kvm_mmu.h | 6 +++++ arch/arm64/include/asm/kvm_mmu.h | 5 ++++ arch/arm64/include/asm/pgtable.h | 1 + virt/kvm/arm/mmu.c | 39 ++++++++++++++++---------------- 4 files changed, 32 insertions(+), 19 deletions(-)
arch/arm/include/asm/kvm_mmu.h +6 -0
@@ -117,6 +117,12 @@ static inline pud_t kvm_s2pud_mkyoung(pud_t pud)return pud; } +static inline bool kvm_s2pud_young (pud_t pud) +{ +BUG (); +return false; +} +static inline pte_t kvm_s2pte_mkwrite (pte_t pte) {pte_val (pte) |=L_PTE_S2_RDWR ;
arch/arm64/include/asm/kvm_mmu.h +5 -0
@@ -273,6 +273,11 @@ static inline pud_t kvm_s2pud_mkyoung(pud_t pud)return pud_mkyoung (pud); } +static inline bool kvm_s2pud_young (pud_t pud) +{ +return pud_young (pud); +} +#define hyp_pte_table_empty (ptep) kvm_page_empty(ptep)#ifdef __PAGETABLE_PMD_FOLDED
arch/arm64/include/asm/pgtable.h +1 -0
@@ -385,6 +385,7 @@ static inline int pmd_protnone(pmd_t pmd)#define pfn_pmd (pfn,prot) __pmd(__phys_to_pmd_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))#define mk_pmd (page,prot) pfn_pmd(page_to_pfn(page),prot) +#define pud_young (pud) pte_young(pud_pte(pud))#define pud_mkyoung (pud) pte_pud(pte_mkyoung(pud_pte(pud)))#define pud_write (pud) pte_write(pud_pte(pud))
virt/kvm/arm/mmu.c +20 -19
@@ -1225,6 +1225,11 @@ static int stage2_pmdp_test_and_clear_young(pmd_t *pmd)return stage2_ptep_test_and_clear_young ((pte_t *)pmd); } +static int stage2_pudp_test_and_clear_young (pud_t *pud) +{ +return stage2_ptep_test_and_clear_young ((pte_t *)pud); +} +/** * kvm_phys_addr_ioremap - map a device range to guest IPA *
@@ -1940,42 +1945,38 @@ void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)static int kvm_age_hva_handler (struct kvm *kvm,gpa_t gpa,u64 size,void *data) { +pud_t *pud;pmd_t *pmd;pte_t *pte; -WARN_ON (size !=PAGE_SIZE && size !=PMD_SIZE ); - pmd =stage2_get_pmd (kvm,NULL , gpa); -if (!pmd ||pmd_none (*pmd))/* Nothing there */ +WARN_ON (size !=PAGE_SIZE && size !=PMD_SIZE && size !=PUD_SIZE ); +if (!stage2_get_leaf_entry (kvm, gpa, &pud, &pmd, &pte))return 0 ; -if (pmd_thp_or_huge (*pmd))/* THP, HugeTLB */ +if (pud) +return stage2_pudp_test_and_clear_young (pud); +else if (pmd)return stage2_pmdp_test_and_clear_young (pmd); - - pte =pte_offset_kernel (pmd, gpa); -if (pte_none (*pte)) -return 0 ; - -return stage2_ptep_test_and_clear_young (pte); +else +return stage2_ptep_test_and_clear_young (pte); }static int kvm_test_age_hva_handler (struct kvm *kvm,gpa_t gpa,u64 size,void *data) { +pud_t *pud;pmd_t *pmd;pte_t *pte; -WARN_ON (size !=PAGE_SIZE && size !=PMD_SIZE ); - pmd =stage2_get_pmd (kvm,NULL , gpa); -if (!pmd ||pmd_none (*pmd))/* Nothing there */ +WARN_ON (size !=PAGE_SIZE && size !=PMD_SIZE && size !=PUD_SIZE ); +if (!stage2_get_leaf_entry (kvm, gpa, &pud, &pmd, &pte))return 0 ; -if (pmd_thp_or_huge (*pmd))/* THP, HugeTLB */ +if (pud) +return kvm_s2pud_young (*pud); +else if (pmd)return pmd_young (*pmd); - - pte =pte_offset_kernel (pmd, gpa); -if (!pte_none (*pte))/* Just a page... */ +else return pte_young (*pte); - -return 0 ; }int kvm_age_hva (struct kvm *kvm,unsigned long start,unsigned long end)
Signature · 1 line
2.18.0
PATCH v7 9/9 KVM: arm64: Add support for creating PUD hugepages at stage 2
In reply to Punit AgrawalKVM only supports PMD hugepages at stage 2. Now that the various page handling routines are updated, extend the stage 2 fault handling to map in PUD hugepages.
Addition of PUD hugepage support enables additional page sizes (e.g., 1G with 4K granule) which can be useful on cores that support mapping larger block sizes in the TLB entries.
--- arch/arm/include/asm/kvm_mmu.h | 20 +++++ arch/arm64/include/asm/kvm_mmu.h | 16 ++++ arch/arm64/include/asm/pgtable-hwdef.h | 2 + arch/arm64/include/asm/pgtable.h | 2 + virt/kvm/arm/mmu.c | 108 +++++++++++++++++++++++-- 5 files changed, 143 insertions(+), 5 deletions(-)
arch/arm/include/asm/kvm_mmu.h +20 -0
@@ -84,11 +84,14 @@ void kvm_clear_hyp_idmap(void);#define kvm_pfn_pte (pfn, prot) pfn_pte(pfn, prot)#define kvm_pfn_pmd (pfn, prot) pfn_pmd(pfn, prot) +#define kvm_pfn_pud (pfn, prot) (__pud(0))#define kvm_pud_pfn (pud) ({ BUG(); 0; })#define kvm_pmd_mkhuge (pmd) pmd_mkhuge(pmd) +/* No support for pud hugepages */ +#define kvm_pud_mkhuge (pud) (pud)/* * The following kvm_*pud*() functions are provided strictly to allow
@@ -105,6 +108,23 @@ static inline bool kvm_s2pud_readonly(pud_t *pud)return false; } +static inline void kvm_set_pud (pud_t *pud,pud_t new_pud) +{ +BUG (); +} + +static inline pud_t kvm_s2pud_mkwrite (pud_t pud) +{ +BUG (); +return pud; +} + +static inline pud_t kvm_s2pud_mkexec (pud_t pud) +{ +BUG (); +return pud; +} +static inline bool kvm_s2pud_exec (pud_t *pud) {BUG ();
arch/arm64/include/asm/kvm_mmu.h +16 -0
@@ -184,12 +184,16 @@ void kvm_clear_hyp_idmap(void);#define kvm_mk_pgd (pudp) \ __pgd(__phys_to_pgd_val(__pa(pudp)) | PUD_TYPE_TABLE) +#define kvm_set_pud (pudp, pud) set_pud(pudp, pud) +#define kvm_pfn_pte (pfn, prot) pfn_pte(pfn, prot)#define kvm_pfn_pmd (pfn, prot) pfn_pmd(pfn, prot) +#define kvm_pfn_pud (pfn, prot) pfn_pud(pfn, prot)#define kvm_pud_pfn (pud) pud_pfn(pud)#define kvm_pmd_mkhuge (pmd) pmd_mkhuge(pmd) +#define kvm_pud_mkhuge (pud) pud_mkhuge(pud)static inline pte_t kvm_s2pte_mkwrite (pte_t pte) {
@@ -203,6 +207,12 @@ static inline pmd_t kvm_s2pmd_mkwrite(pmd_t pmd)return pmd; } +static inline pud_t kvm_s2pud_mkwrite (pud_t pud) +{ +pud_val (pud) |=PUD_S2_RDWR ; +return pud; +} +static inline pte_t kvm_s2pte_mkexec (pte_t pte) {pte_val (pte) &= ~PTE_S2_XN ;
@@ -215,6 +225,12 @@ static inline pmd_t kvm_s2pmd_mkexec(pmd_t pmd)return pmd; } +static inline pud_t kvm_s2pud_mkexec (pud_t pud) +{ +pud_val (pud) &= ~PUD_S2_XN ; +return pud; +} +static inline void kvm_set_s2pte_readonly (pte_t *ptep) {pteval_t old_pteval, pteval;
arch/arm64/include/asm/pgtable-hwdef.h +2 -0
@@ -193,6 +193,8 @@#define PMD_S2_RDWR (_AT(pmdval_t, 3) << 6)/* HAP[2:1] */ #define PMD_S2_XN (_AT(pmdval_t, 2) << 53)/* XN[1:0] */ +#define PUD_S2_RDONLY (_AT(pudval_t, 1) << 6)/* HAP[2:1] */ +#define PUD_S2_RDWR (_AT(pudval_t, 3) << 6)/* HAP[2:1] */ #define PUD_S2_XN (_AT(pudval_t, 2) << 53)/* XN[1:0] */ /*
arch/arm64/include/asm/pgtable.h +2 -0
@@ -389,6 +389,8 @@ static inline int pmd_protnone(pmd_t pmd)#define pud_mkyoung (pud) pte_pud(pte_mkyoung(pud_pte(pud)))#define pud_write (pud) pte_write(pud_pte(pud)) +#define pud_mkhuge (pud) (__pud(pud_val(pud) & ~PUD_TABLE_BIT)) +#define __pud_to_phys (pud) __pte_to_phys(pud_pte(pud))#define __phys_to_pud_val (phys) __phys_to_pte_val(phys)#define pud_pfn (pud) ((__pud_to_phys(pud) & PUD_MASK) >> PAGE_SHIFT)
virt/kvm/arm/mmu.c +103 -5
151 lines not on this page · raw message
Signature · 1 line
2.18.0
Suzuki K Poulose
reviewerRe: [PATCH v7 9/9] KVM: arm64: Add support for creating PUD hugepages at stage 2
Hi Punit,
Quoted 24 lines · Punit Agrawal
KVM only supports PMD hugepages at stage 2. Now that the various page handling routines are updated, extend the stage 2 fault handling to map in PUD hugepages.
Addition of PUD hugepage support enables additional page sizes (e.g., 1G with 4K granule) which can be useful on cores that support mapping larger block sizes in the TLB entries.
Signed-off-by Punit Agrawal <[email protected]>Cc Christoffer Dall <[email protected]>Cc Marc Zyngier <[email protected]>Cc Russell King <[email protected]>Cc Catalin Marinas <[email protected]>Cc Will Deacon <[email protected]>arch/arm/include/asm/kvm_mmu.h +0
-0@@ -84,11 +84,14 @@ void kvm_clear_hyp_idmap(void);#define kvm_pfn_pte (pfn, prot) pfn_pte(pfn, prot)
arch/arm/include/asm/kvm_mmu.h void kvm_clear_hyp_idmap(void); · line 95
Quoted 10 lines
arch/arm/include/asm/kvm_mmu.h +3
-0#define kvm_pfn_pmd (pfn, prot) pfn_pmd(pfn, prot) +#define kvm_pfn_pud (pfn, prot) (__pud(0))#define kvm_pud_pfn (pud) ({ BUG(); 0; })#define kvm_pmd_mkhuge (pmd) pmd_mkhuge(pmd) +/* No support for pud hugepages */ +#define kvm_pud_mkhuge (pud) (pud)
shouldn't this be BUG() like other PUD huge helpers for arm32 ?
Quoted 29 lines
arch/arm/include/asm/kvm_mmu.h +17
-0/* * The following kvm_*pud*() functions are provided strictly to allow @@ -105,6 +108,23 @@ static inline bool kvm_s2pud_readonly(pud_t *pud)return false; } +static inline void kvm_set_pud (pud_t *pud,pud_t new_pud) +{ +BUG (); +} + +static inline pud_t kvm_s2pud_mkwrite (pud_t pud) +{ +BUG (); +return pud; +} + +static inline pud_t kvm_s2pud_mkexec (pud_t pud) +{ +BUG (); +return pud; +} +virt/kvm/arm/mmu.c +0
-0
...
Quoted 7 lines
virt/kvm/arm/mmu.c +2
-1@@ -1669,7 +1746,28 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, needs_exec = exec_fault || (fault_status ==FSC_PERM &&stage2_is_exec (kvm, fault_ipa)); -if (hugetlb && vma_pagesize ==PMD_SIZE ) { +if (hugetlb && vma_pagesize ==PUD_SIZE ) { +/*
virt/kvm/arm/mmu.c static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, · line 1760
Quoted 10 lines
virt/kvm/arm/mmu.c +10
-0+* Assuming that PUD level always exists at Stage 2 - +* this is true for 4k pages with 40 bits IPA +* currently supported. +* +* When using 64k pages, 40bits of IPA results in +* using only 2-levels at Stage 2. Overlooking this +* problem for now as a PUD hugepage with 64k pages is +* too big (4TB) to be practical. +*/ +pud_t new_pud =kvm_pfn_pud (pfn, mem_type);
Is this based on the Dynamic IPA series ? The cover letter seems to suggest that it is. But I don't see the check to make sure we have stage2 PUD level here before we go ahead and try PUD huge page at stage2. Also the comment above seems outdated in that case.
Quoted 4 lines
virt/kvm/arm/mmu.c +3
-0+ + new_pud =kvm_pud_mkhuge (new_pud); +if (writable)
virt/kvm/arm/mmu.c static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, · line 1773
Quoted 10 lines
virt/kvm/arm/mmu.c +7
-0+ new_pud =kvm_s2pud_mkwrite (new_pud); + +if (needs_exec) + new_pud =kvm_s2pud_mkexec (new_pud); + + ret =stage2_set_pud_huge (kvm, memcache, fault_ipa, &new_pud); + }else if (hugetlb && vma_pagesize ==PMD_SIZE ) {pmd_t new_pmd =kvm_pfn_pmd (pfn, mem_type); new_pmd =kvm_pmd_mkhuge (new_pmd);
Suzuki
Re: [PATCH v7 9/9] KVM: arm64: Add support for creating PUD hugepages at stage 2
Quoted 82 lines · Suzuki K Poulose
Hi Punit,
Quoted 22 lines · Punit Agrawal
KVM only supports PMD hugepages at stage 2. Now that the various page handling routines are updated, extend the stage 2 fault handling to map in PUD hugepages.
Addition of PUD hugepage support enables additional page sizes (e.g., 1G with 4K granule) which can be useful on cores that support mapping larger block sizes in the TLB entries.
Signed-off-by Punit Agrawal <[email protected]>Cc Christoffer Dall <[email protected]>Cc Marc Zyngier <[email protected]>Cc Russell King <[email protected]>Cc Catalin Marinas <[email protected]>Cc Will Deacon <[email protected]>arch/arm/include/asm/kvm_mmu.h +0
-0arch/arm/include/asm/kvm_mmu.h void kvm_clear_hyp_idmap(void); · line 91
Quoted 8 lines
arch/arm/include/asm/kvm_mmu.h +3
-0@@ -84,11 +84,14 @@ void kvm_clear_hyp_idmap(void);#define kvm_pfn_pte (pfn, prot) pfn_pte(pfn, prot)#define kvm_pfn_pmd (pfn, prot) pfn_pmd(pfn, prot) +#define kvm_pfn_pud (pfn, prot) (__pud(0))#define kvm_pud_pfn (pud) ({ BUG(); 0; })#define kvm_pmd_mkhuge (pmd) pmd_mkhuge(pmd) +/* No support for pud hugepages */ +#define kvm_pud_mkhuge (pud) (pud)shouldn't this be
BUG()like other PUD huge helpers for arm32 ?Quoted 28 lines
arch/arm/include/asm/kvm_mmu.h +16
-0/* * The following kvm_*pud*() functions are provided strictly to allow @@ -105,6 +108,23 @@ static inline bool kvm_s2pud_readonly(pud_t *pud)return false; } +static inline void kvm_set_pud(pud_t *pud, pud_t new_pud) +{ +BUG (); +} + +static inline pud_t kvm_s2pud_mkwrite (pud_t pud) +{ +BUG (); +return pud; +} + +static inline pud_t kvm_s2pud_mkexec (pud_t pud) +{ +BUG (); +return pud; +} +virt/kvm/arm/mmu.c +0
-0...
Quoted 13 lines
virt/kvm/arm/mmu.c +9
-0@@ -1669,7 +1746,28 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, needs_exec = exec_fault || (fault_status ==FSC_PERM &&stage2_is_exec (kvm, fault_ipa)); - if (hugetlb && vma_pagesize == PMD_SIZE) { +if (hugetlb && vma_pagesize ==PUD_SIZE ) { +/* +* Assuming that PUD level always exists at Stage 2 - +* this is true for 4k pages with 40 bits IPA +* currently supported. +* +* When using 64k pages, 40bits of IPA results in +* using only 2-levels at Stage 2. Overlooking this +* problem for now as a PUD hugepage with 64k pages is
Quoted 8 lines
virt/kvm/arm/mmu.c static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, · line 1760
Quoted 3 lines
virt/kvm/arm/mmu.c +3
-0+* too big (4TB) to be practical. +*/ +pud_t new_pud =kvm_pfn_pud (pfn, mem_type);Is this based on the Dynamic IPA series ? The cover letter seems to suggest that it is. But I don't see the check to make sure we have stage2 PUD level here before we go ahead and try PUD huge page at stage2. Also the comment above seems outdated in that case.
It is indeed based on the Dynamic IPA series but I seem to have lost the actual changes introducing the checks for PUD level. Let me fix that up and post an update.
Sorry for the noise.
Punit
Quoted 17 lines
Quoted 4 lines
virt/kvm/arm/mmu.c +3
-0+ + new_pud =kvm_pud_mkhuge (new_pud); +if (writable)virt/kvm/arm/mmu.c static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
Quoted 10 lines
virt/kvm/arm/mmu.c +7
-0+ new_pud =kvm_s2pud_mkwrite (new_pud); + +if (needs_exec) + new_pud =kvm_s2pud_mkexec (new_pud); + + ret =stage2_set_pud_huge (kvm, memcache, fault_ipa, &new_pud); + }else if (hugetlb && vma_pagesize ==PMD_SIZE ) {pmd_t new_pmd =kvm_pfn_pmd (pfn, mem_type); new_pmd =kvm_pmd_mkhuge (new_pmd);Suzuki
PATCH v7 9/9 KVM: arm64: Add support for creating PUD hugepages at stage 2
In reply to Punit AgrawalKVM only supports PMD hugepages at stage 2. Now that the various page handling routines are updated, extend the stage 2 fault handling to map in PUD hugepages.
Addition of PUD hugepage support enables additional page sizes (e.g., 1G with 4K granule) which can be useful on cores that support mapping larger block sizes in the TLB entries.
---
v7 -> v7.1
* Added arm helper kvm_stage2_has_pud()
* Added check for PUD level present at stage 2
* Dropped redundant comment
* Fixed up kvm_pud_mkhuge() to complain on arm
arch/arm/include/asm/kvm_mmu.h | 20 +++++ arch/arm/include/asm/stage2_pgtable.h | 5 ++ arch/arm64/include/asm/kvm_mmu.h | 16 ++++ arch/arm64/include/asm/pgtable-hwdef.h | 2 + arch/arm64/include/asm/pgtable.h | 2 + virt/kvm/arm/mmu.c | 106 +++++++++++++++++++++++-- 6 files changed, 145 insertions(+), 6 deletions(-)
arch/arm/include/asm/kvm_mmu.h +20 -0
@@ -84,11 +84,14 @@ void kvm_clear_hyp_idmap(void);#define kvm_pfn_pte (pfn, prot) pfn_pte(pfn, prot)#define kvm_pfn_pmd (pfn, prot) pfn_pmd(pfn, prot) +#define kvm_pfn_pud (pfn, prot) (__pud(0))#define kvm_pud_pfn (pud) ({ BUG(); 0; })#define kvm_pmd_mkhuge (pmd) pmd_mkhuge(pmd) +/* No support for pud hugepages */ +#define kvm_pud_mkhuge (pud) ( {BUG(); pud; })/* * The following kvm_*pud*() functions are provided strictly to allow
@@ -105,6 +108,23 @@ static inline bool kvm_s2pud_readonly(pud_t *pud)return false; } +static inline void kvm_set_pud (pud_t *pud,pud_t new_pud) +{ +BUG (); +} + +static inline pud_t kvm_s2pud_mkwrite (pud_t pud) +{ +BUG (); +return pud; +} + +static inline pud_t kvm_s2pud_mkexec (pud_t pud) +{ +BUG (); +return pud; +} +static inline bool kvm_s2pud_exec (pud_t *pud) {BUG ();
arch/arm/include/asm/stage2_pgtable.h +5 -0
@@ -68,4 +68,9 @@ stage2_pmd_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end)#define stage2_pmd_table_empty (kvm, pmdp) kvm_page_empty(pmdp)#define stage2_pud_table_empty (kvm, pudp) false +static inline bool kvm_stage2_has_pud (struct kvm *kvm) +{ +return KVM_VTCR_SL0 ==VTCR_SL_L1 ; +} +#endif /* __ARM_S2_PGTABLE_H_ */
arch/arm64/include/asm/kvm_mmu.h +16 -0
@@ -184,12 +184,16 @@ void kvm_clear_hyp_idmap(void);#define kvm_mk_pgd (pudp) \ __pgd(__phys_to_pgd_val(__pa(pudp)) | PUD_TYPE_TABLE) +#define kvm_set_pud (pudp, pud) set_pud(pudp, pud) +#define kvm_pfn_pte (pfn, prot) pfn_pte(pfn, prot)#define kvm_pfn_pmd (pfn, prot) pfn_pmd(pfn, prot) +#define kvm_pfn_pud (pfn, prot) pfn_pud(pfn, prot)#define kvm_pud_pfn (pud) pud_pfn(pud)#define kvm_pmd_mkhuge (pmd) pmd_mkhuge(pmd) +#define kvm_pud_mkhuge (pud) pud_mkhuge(pud)static inline pte_t kvm_s2pte_mkwrite (pte_t pte) {
@@ -203,6 +207,12 @@ static inline pmd_t kvm_s2pmd_mkwrite(pmd_t pmd)return pmd; } +static inline pud_t kvm_s2pud_mkwrite (pud_t pud) +{ +pud_val (pud) |=PUD_S2_RDWR ; +return pud; +} +static inline pte_t kvm_s2pte_mkexec (pte_t pte) {pte_val (pte) &= ~PTE_S2_XN ;
@@ -215,6 +225,12 @@ static inline pmd_t kvm_s2pmd_mkexec(pmd_t pmd)return pmd; } +static inline pud_t kvm_s2pud_mkexec (pud_t pud) +{ +pud_val (pud) &= ~PUD_S2_XN ; +return pud; +} +static inline void kvm_set_s2pte_readonly (pte_t *ptep) {pteval_t old_pteval, pteval;
arch/arm64/include/asm/pgtable-hwdef.h +2 -0
@@ -193,6 +193,8 @@#define PMD_S2_RDWR (_AT(pmdval_t, 3) << 6)/* HAP[2:1] */ #define PMD_S2_XN (_AT(pmdval_t, 2) << 53)/* XN[1:0] */ +#define PUD_S2_RDONLY (_AT(pudval_t, 1) << 6)/* HAP[2:1] */ +#define PUD_S2_RDWR (_AT(pudval_t, 3) << 6)/* HAP[2:1] */ #define PUD_S2_XN (_AT(pudval_t, 2) << 53)/* XN[1:0] */ /*
arch/arm64/include/asm/pgtable.h +2 -0
@@ -389,6 +389,8 @@ static inline int pmd_protnone(pmd_t pmd)#define pud_mkyoung (pud) pte_pud(pte_mkyoung(pud_pte(pud)))#define pud_write (pud) pte_write(pud_pte(pud)) +#define pud_mkhuge (pud) (__pud(pud_val(pud) & ~PUD_TABLE_BIT)) +#define __pud_to_phys (pud) __pte_to_phys(pud_pte(pud))#define __phys_to_pud_val (phys) __phys_to_pte_val(phys)#define pud_pfn (pud) ((__pud_to_phys(pud) & PUD_MASK) >> PAGE_SHIFT)
virt/kvm/arm/mmu.c +100 -6
152 lines not on this page · raw message
Signature · 1 line
2.18.0
Re: [PATCH v7.1 9/9] KVM: arm64: Add support for creating PUD hugepages at stage 2
Quoted 31 lines · Punit Agrawal
KVM only supports PMD hugepages at stage 2. Now that the various page handling routines are updated, extend the stage 2 fault handling to map in PUD hugepages.
Addition of PUD hugepage support enables additional page sizes (e.g., 1G with 4K granule) which can be useful on cores that support mapping larger block sizes in the TLB entries.
Signed-off-by Punit Agrawal <[email protected]>Cc Christoffer Dall <[email protected]>Cc Marc Zyngier <[email protected]>Cc Russell King <[email protected]>Cc Catalin Marinas <[email protected]>Cc Will Deacon <[email protected]>---
v7 -> v7.1
* Added arm helper
kvm_stage2_has_pud()
* Added check for PUD level present at stage 2
* Dropped redundant comment
* Fixed upkvm_pud_mkhuge()to complain on armarch/arm/include/asm/kvm_mmu.h | 20 +++++ arch/arm/include/asm/stage2_pgtable.h | 5 ++ arch/arm64/include/asm/kvm_mmu.h | 16 ++++ arch/arm64/include/asm/pgtable-hwdef.h | 2 + arch/arm64/include/asm/pgtable.h | 2 + virt/kvm/arm/mmu.c | 106 +++++++++++++++++++++++-- 6 files changed, 145 insertions(+), 6 deletions(-)
[...]
arch/arm/include/asm/stage2_pgtable.h stage2_pmd_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) · line 75
Quoted 13 lines
arch/arm/include/asm/stage2_pgtable.h +5
-0@@ -68,4 +68,9 @@ stage2_pmd_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end)#define stage2_pmd_table_empty (kvm, pmdp) kvm_page_empty(pmdp)#define stage2_pud_table_empty (kvm, pudp) false +static inline bool kvm_stage2_has_pud (struct kvm *kvm) +{ +return KVM_VTCR_SL0 ==VTCR_SL_L1 ; +} +
Turns out this isn't quite the right check. On arm32, the maximum number of supported levels is 3 with LPAE - effectively the helper should always return false.
I've updated the check locally to key off of CONFIG_PGTABLE_LEVELS. I'll post these patches later today.
Thanks,
Punit