FAILED: patch "[PATCH] LoongArch: Use accessors to page table entries instead of" failed to apply to 6.6-stable tree
Subsystems (5)
[email protected]
maintainerThe patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x 4574815abf43e2bf05643e1b3f7a2e5d6df894f0
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2024091028-stinking-mourner-56f5@gregkh' --subject-prefix 'PATCH 6.6.y' HEAD^..
Possible dependencies:
4574815abf43 ("LoongArch: Use accessors to page table entries instead of direct dereference") 752e2cd7b4fb ("LoongArch: KVM: Implement kvm mmu operations")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 4574815abf43e2bf05643e1b3f7a2e5d6df894f0 Mon Sep 17 00:00:00 2001
From: Huacai Chen <[email protected]>
Date: Wed, 7 Aug 2024 17:37:11 +0800
Subject: [PATCH] LoongArch: Use accessors to page table entries instead of
direct dereference
As very well explained in commit 20a004e7b017cce282 ("arm64: mm: Use READ_ONCE/WRITE_ONCE when accessing page tables"), an architecture whose page table walker can modify the PTE in parallel must use READ_ONCE()/ WRITE_ONCE() macro to avoid any compiler transformation.
So apply that to LoongArch which is such an architecture, in order to avoid potential problems.
Similar to commit edf955647269422e ("riscv: Use accessors to page table entries instead of direct dereference").
arch/loongarch/include/asm/hugetlb.h +2 -2
@@ -34,7 +34,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { pte_t clear; -pte_t pte = *ptep; +pte_t pte =ptep_get (ptep);pte_val (clear) = (unsigned long )invalid_pte_table;set_pte_at (mm, addr, ptep, clear);
@@ -65,7 +65,7 @@ static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma, pte_t *ptep, pte_t pte, int dirty) { - int changed = !pte_same(*ptep, pte); + int changed = !pte_same(ptep_get(ptep), pte);if (changed) {set_pte_at (vma->vm_mm, addr, ptep, pte);
arch/loongarch/include/asm/kfence.h +3 -3
@@ -53,13 +53,13 @@ static inline bool kfence_protect_page(unsigned long addr, bool protect) {pte_t *pte =virt_to_kpte (addr); -if (WARN_ON (!pte) ||pte_none (*pte)) +if (WARN_ON (!pte) ||pte_none (ptep_get (pte)))return false;if (protect) -set_pte (pte,__pte (pte_val (*pte) & ~(_PAGE_VALID | _PAGE_PRESENT))); +set_pte (pte,__pte (pte_val (ptep_get (pte)) & ~(_PAGE_VALID | _PAGE_PRESENT)));else -set_pte (pte,__pte (pte_val (*pte) | (_PAGE_VALID | _PAGE_PRESENT))); +set_pte (pte,__pte (pte_val (ptep_get (pte)) | (_PAGE_VALID | _PAGE_PRESENT)));preempt_disable ();local_flush_tlb_one (addr);
arch/loongarch/include/asm/pgtable.h +30 -20
112 lines not on this page · raw message
arch/loongarch/kvm/mmu.c +4 -4
@@ -714,19 +714,19 @@ static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn,* value) and then p*d_offset() walks into the target huge page instead * of the old page table (sees the new value). */ - pgd =READ_ONCE (*pgd_offset (kvm->mm, hva)); + pgd =pgdp_get (pgd_offset (kvm->mm, hva));if (pgd_none (pgd)) goto out; - p4d =READ_ONCE (*p4d_offset (&pgd, hva)); + p4d =p4dp_get (p4d_offset (&pgd, hva));if (p4d_none (p4d) || !p4d_present (p4d)) goto out; - pud =READ_ONCE (*pud_offset (&p4d, hva)); + pud =pudp_get (pud_offset (&p4d, hva));if (pud_none (pud) || !pud_present (pud)) goto out; - pmd =READ_ONCE (*pmd_offset (&pud, hva)); + pmd =pmdp_get (pmd_offset (&pud, hva));if (pmd_none (pmd) || !pmd_present (pmd)) goto out;
arch/loongarch/mm/hugetlbpage.c +3 -3
@@ -39,11 +39,11 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr,pmd_t *pmd =NULL ; pgd =pgd_offset (mm, addr); -if (pgd_present (*pgd)) { +if (pgd_present (pgdp_get (pgd))) { p4d =p4d_offset (pgd, addr); -if (p4d_present (*p4d)) { +if (p4d_present (p4dp_get (p4d))) { pud =pud_offset (p4d, addr); -if (pud_present (*pud)) +if (pud_present (pudp_get (pud))) pmd =pmd_offset (pud, addr); } }
arch/loongarch/mm/init.c +5 -5
@@ -141,7 +141,7 @@ void __meminit vmemmap_set_pmd(pmd_t *pmd, void *p, int node,int __meminit vmemmap_check_pmd (pmd_t *pmd,int node,unsigned long addr,unsigned long next) { -int huge =pmd_val (*pmd) & _PAGE_HUGE; +int huge =pmd_val (pmdp_get (pmd)) & _PAGE_HUGE;if (huge)vmemmap_verify ((pte_t *)pmd, node, addr, next);
@@ -173,7 +173,7 @@ pte_t * __init populate_kernel_pte(unsigned long addr)pud_t *pud;pmd_t *pmd; -if (p4d_none (*p4d)) { +if (p4d_none (p4dp_get (p4d))) { pud =memblock_alloc (PAGE_SIZE ,PAGE_SIZE );if (!pud)panic ("%s: Failed to allocate memory\n" , __func__);
@@ -184,7 +184,7 @@ pte_t * __init populate_kernel_pte(unsigned long addr) } pud =pud_offset (p4d, addr); -if (pud_none (*pud)) { +if (pud_none (pudp_get (pud))) { pmd =memblock_alloc (PAGE_SIZE ,PAGE_SIZE );if (!pmd)panic ("%s: Failed to allocate memory\n" , __func__);
@@ -195,7 +195,7 @@ pte_t * __init populate_kernel_pte(unsigned long addr) } pmd =pmd_offset (pud, addr); -if (!pmd_present (*pmd)) { +if (!pmd_present (pmdp_get (pmd))) {pte_t *pte; pte =memblock_alloc (PAGE_SIZE ,PAGE_SIZE );
@@ -216,7 +216,7 @@ void __init __set_fixmap(enum fixed_addresses idx,BUG_ON (idx <=FIX_HOLE || idx >= __end_of_fixed_addresses); ptep =populate_kernel_pte (addr); -if (!pte_none (*ptep)) { +if (!pte_none (ptep_get (ptep))) {pte_ERROR (*ptep);return ; }
arch/loongarch/mm/kasan_init.c +5 -5
@@ -105,7 +105,7 @@ static phys_addr_t __init kasan_alloc_zeroed_page(int node)static pte_t *__init kasan_pte_offset (pmd_t *pmdp,unsigned long addr,int node,bool early) { -if (__pmd_none (early,READ_ONCE (*pmdp))) { +if (__pmd_none (early,pmdp_get (pmdp))) {phys_addr_t pte_phys = early ?__pa_symbol (kasan_early_shadow_pte) :kasan_alloc_zeroed_page (node);if (!early)
@@ -118,7 +118,7 @@ static pte_t *__init kasan_pte_offset(pmd_t *pmdp, unsigned long addr, int node,static pmd_t *__init kasan_pmd_offset (pud_t *pudp,unsigned long addr,int node,bool early) { -if (__pud_none (early,READ_ONCE (*pudp))) { +if (__pud_none (early,pudp_get (pudp))) {phys_addr_t pmd_phys = early ?__pa_symbol (kasan_early_shadow_pmd) :kasan_alloc_zeroed_page (node);if (!early)
@@ -131,7 +131,7 @@ static pmd_t *__init kasan_pmd_offset(pud_t *pudp, unsigned long addr, int node,static pud_t *__init kasan_pud_offset (p4d_t *p4dp,unsigned long addr,int node,bool early) { -if (__p4d_none (early,READ_ONCE (*p4dp))) { +if (__p4d_none (early,p4dp_get (p4dp))) {phys_addr_t pud_phys = early ?__pa_symbol (kasan_early_shadow_pud) :kasan_alloc_zeroed_page (node);if (!early)
@@ -154,7 +154,7 @@ static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr, : kasan_alloc_zeroed_page(node); next = addr +PAGE_SIZE ;set_pte (ptep,pfn_pte (__phys_to_pfn (page_phys),PAGE_KERNEL )); - }while (ptep++, addr = next, addr != end &&__pte_none (early,READ_ONCE (*ptep))); + }while (ptep++, addr = next, addr != end &&__pte_none (early,ptep_get (ptep))); } static void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr,
@@ -166,7 +166,7 @@ static void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr,do { next =pmd_addr_end (addr, end);kasan_pte_populate (pmdp, addr, next, node, early); - }while (pmdp++, addr = next, addr != end &&__pmd_none (early,READ_ONCE (*pmdp))); + }while (pmdp++, addr = next, addr != end &&__pmd_none (early,pmdp_get (pmdp))); } static void __init kasan_pud_populate(p4d_t *p4dp, unsigned long addr,
arch/loongarch/mm/pgtable.c +1 -1
@@ -128,7 +128,7 @@ pmd_t mk_pmd(struct page *page, pgprot_t prot)void set_pmd_at (struct mm_struct *mm,unsigned long addr,pmd_t *pmdp,pmd_t pmd) { - *pmdp = pmd; +WRITE_ONCE (*pmdp, pmd);flush_tlb_all (); }
PATCH 1/2 LoongArch: KVM: Implement kvm mmu operations
From: Tianrui Zhao <[email protected]>
From: Tianrui Zhao <[email protected]>
commit 752e2cd7b4fb412f3e008493e0195e357bab9773 upstream
Implement LoongArch kvm mmu, it is used to switch gpa to hpa when guest exit because of address translation exception.
This patch implement: allocating gpa page table, searching gpa from it, and flushing guest gpa in the table.
--- arch/loongarch/include/asm/kvm_mmu.h | 139 ++++ arch/loongarch/kvm/mmu.c | 914 +++++++++++++++++++++++++++ 2 files changed, 1053 insertions(+) create mode 100644 arch/loongarch/include/asm/kvm_mmu.h create mode 100644 arch/loongarch/kvm/mmu.c
arch/loongarch/include/asm/kvm_mmu.h new file +139 -0
@@ -0,0 +1,139 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2020-2023 Loongson Technology Corporation Limited +*/ + +#ifndef __ASM_LOONGARCH_KVM_MMU_H__ +#define __ASM_LOONGARCH_KVM_MMU_H__ + +#include <linux/kvm_host.h> +#include <asm/pgalloc.h> +#include <asm/tlb.h> + +/* +* KVM_MMU_CACHE_MIN_PAGES is the number of GPA page table translation levels +* for which pages need to be cached. +*/ +#define KVM_MMU_CACHE_MIN_PAGES (CONFIG_PGTABLE_LEVELS - 1) + +#define _KVM_FLUSH_PGTABLE 0x1 +#define _KVM_HAS_PGMASK 0x2 +#define kvm_pfn_pte (pfn, prot) (((pfn) << PFN_PTE_SHIFT) | pgprot_val(prot)) +#define kvm_pte_pfn (x) ((phys_addr_t)((x & _PFN_MASK) >> PFN_PTE_SHIFT)) + +typedef unsigned long kvm_pte_t ; +typedef struct kvm_ptw_ctx kvm_ptw_ctx ; +typedef int (*kvm_pte_ops )(kvm_pte_t *pte,phys_addr_t addr,kvm_ptw_ctx *ctx); + +struct kvm_ptw_ctx { +kvm_pte_ops ops; +unsigned long flag; + +/* for kvm_arch_mmu_enable_log_dirty_pt_masked use */ +unsigned long mask; +unsigned long gfn; + +/* page walk mmu info */ +unsigned int level; +unsigned long pgtable_shift; +unsigned long invalid_entry; +unsigned long *invalid_ptes; +unsigned int *pte_shifts; +void *opaque; + +/* free pte table page list */ +struct list_head list; +}; + +kvm_pte_t *kvm_pgd_alloc (void ); + +static inline void kvm_set_pte (kvm_pte_t *ptep,kvm_pte_t val) +{ +WRITE_ONCE (*ptep, val); +} + +static inline int kvm_pte_write (kvm_pte_t pte) {return pte & _PAGE_WRITE; } +static inline int kvm_pte_dirty (kvm_pte_t pte) {return pte & _PAGE_DIRTY; } +static inline int kvm_pte_young (kvm_pte_t pte) {return pte & _PAGE_ACCESSED; } +static inline int kvm_pte_huge (kvm_pte_t pte) {return pte & _PAGE_HUGE; } + +static inline kvm_pte_t kvm_pte_mkyoung (kvm_pte_t pte) +{ +return pte | _PAGE_ACCESSED; +} + +static inline kvm_pte_t kvm_pte_mkold (kvm_pte_t pte) +{ +return pte & ~_PAGE_ACCESSED; +} + +static inline kvm_pte_t kvm_pte_mkdirty (kvm_pte_t pte) +{ +return pte | _PAGE_DIRTY; +} + +static inline kvm_pte_t kvm_pte_mkclean (kvm_pte_t pte) +{ +return pte & ~_PAGE_DIRTY; +} + +static inline kvm_pte_t kvm_pte_mkhuge (kvm_pte_t pte) +{ +return pte | _PAGE_HUGE; +} + +static inline kvm_pte_t kvm_pte_mksmall (kvm_pte_t pte) +{ +return pte & ~_PAGE_HUGE; +} + +static inline int kvm_need_flush (kvm_ptw_ctx *ctx) +{ +return ctx->flag & _KVM_FLUSH_PGTABLE; +} + +static inline kvm_pte_t *kvm_pgtable_offset (kvm_ptw_ctx *ctx,kvm_pte_t *table, +phys_addr_t addr) +{ + +return table + ((addr >> ctx->pgtable_shift) & (PTRS_PER_PTE -1 )); +} + +static inline phys_addr_t kvm_pgtable_addr_end (kvm_ptw_ctx *ctx, +phys_addr_t addr,phys_addr_t end) +{ +phys_addr_t boundary, size; + + size =0x1UL << ctx->pgtable_shift; + boundary = (addr + size) & ~(size -1 ); +return (boundary -1 < end -1 ) ? boundary : end; +} + +static inline int kvm_pte_present (kvm_ptw_ctx *ctx,kvm_pte_t *entry) +{ +if (!ctx || ctx->level ==0 ) +return !!(*entry & _PAGE_PRESENT); + +return *entry != ctx->invalid_entry; +} + +static inline int kvm_pte_none (kvm_ptw_ctx *ctx,kvm_pte_t *entry) +{ +return *entry == ctx->invalid_entry; +} + +static inline void kvm_ptw_enter (kvm_ptw_ctx *ctx) +{ + ctx->level--; + ctx->pgtable_shift = ctx->pte_shifts[ctx->level]; + ctx->invalid_entry = ctx->invalid_ptes[ctx->level]; +} + +static inline void kvm_ptw_exit (kvm_ptw_ctx *ctx) +{ + ctx->level++; + ctx->pgtable_shift = ctx->pte_shifts[ctx->level]; + ctx->invalid_entry = ctx->invalid_ptes[ctx->level]; +} + +#endif /* __ASM_LOONGARCH_KVM_MMU_H__ */
arch/loongarch/kvm/mmu.c new file +914 -0
914 lines not on this page · raw message
Signature · 1 line
2.45.2
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH 2/2 LoongArch: Use accessors to page table entries instead of direct dereference
From: Huacai Chen <[email protected]>
From: Huacai Chen <[email protected]>
commit 4574815abf43e2bf05643e1b3f7a2e5d6df894f0 upstream
As very well explained in commit 20a004e7b017cce282 ("arm64: mm: Use READ_ONCE/WRITE_ONCE when accessing page tables"), an architecture whose page table walker can modify the PTE in parallel must use READ_ONCE()/ WRITE_ONCE() macro to avoid any compiler transformation.
So apply that to LoongArch which is such an architecture, in order to avoid potential problems.
Similar to commit edf955647269422e ("riscv: Use accessors to page table entries instead of direct dereference").
--- arch/loongarch/include/asm/hugetlb.h | 4 +-- arch/loongarch/include/asm/kfence.h | 6 ++-- arch/loongarch/include/asm/pgtable.h | 48 +++++++++++++++++----------- arch/loongarch/kvm/mmu.c | 8 ++--- arch/loongarch/mm/hugetlbpage.c | 6 ++-- arch/loongarch/mm/init.c | 10 +++--- arch/loongarch/mm/kasan_init.c | 10 +++--- arch/loongarch/mm/pgtable.c | 2 +- 8 files changed, 52 insertions(+), 42 deletions(-)
arch/loongarch/include/asm/hugetlb.h +2 -2
@@ -34,7 +34,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { pte_t clear; -pte_t pte = *ptep; +pte_t pte =ptep_get (ptep);pte_val (clear) = (unsigned long )invalid_pte_table;set_pte_at (mm, addr, ptep, clear);
@@ -65,7 +65,7 @@ static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma, pte_t *ptep, pte_t pte, int dirty) { - int changed = !pte_same(*ptep, pte); + int changed = !pte_same(ptep_get(ptep), pte);if (changed) {set_pte_at (vma->vm_mm, addr, ptep, pte);
arch/loongarch/include/asm/kfence.h +3 -3
@@ -43,13 +43,13 @@ static inline bool kfence_protect_page(unsigned long addr, bool protect) {pte_t *pte =virt_to_kpte (addr); -if (WARN_ON (!pte) ||pte_none (*pte)) +if (WARN_ON (!pte) ||pte_none (ptep_get (pte)))return false;if (protect) -set_pte (pte,__pte (pte_val (*pte) & ~(_PAGE_VALID | _PAGE_PRESENT))); +set_pte (pte,__pte (pte_val (ptep_get (pte)) & ~(_PAGE_VALID | _PAGE_PRESENT)));else -set_pte (pte,__pte (pte_val (*pte) | (_PAGE_VALID | _PAGE_PRESENT))); +set_pte (pte,__pte (pte_val (ptep_get (pte)) | (_PAGE_VALID | _PAGE_PRESENT)));preempt_disable ();local_flush_tlb_one (addr);
arch/loongarch/include/asm/pgtable.h +29 -19
111 lines not on this page · raw message
arch/loongarch/kvm/mmu.c +4 -4
@@ -679,19 +679,19 @@ static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn,* value) and then p*d_offset() walks into the target huge page instead * of the old page table (sees the new value). */ - pgd =READ_ONCE (*pgd_offset (kvm->mm, hva)); + pgd =pgdp_get (pgd_offset (kvm->mm, hva));if (pgd_none (pgd)) goto out; - p4d =READ_ONCE (*p4d_offset (&pgd, hva)); + p4d =p4dp_get (p4d_offset (&pgd, hva));if (p4d_none (p4d) || !p4d_present (p4d)) goto out; - pud =READ_ONCE (*pud_offset (&p4d, hva)); + pud =pudp_get (pud_offset (&p4d, hva));if (pud_none (pud) || !pud_present (pud)) goto out; - pmd =READ_ONCE (*pmd_offset (&pud, hva)); + pmd =pmdp_get (pmd_offset (&pud, hva));if (pmd_none (pmd) || !pmd_present (pmd)) goto out;
arch/loongarch/mm/hugetlbpage.c +3 -3
@@ -39,11 +39,11 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr,pmd_t *pmd =NULL ; pgd =pgd_offset (mm, addr); -if (pgd_present (*pgd)) { +if (pgd_present (pgdp_get (pgd))) { p4d =p4d_offset (pgd, addr); -if (p4d_present (*p4d)) { +if (p4d_present (p4dp_get (p4d))) { pud =pud_offset (p4d, addr); -if (pud_present (*pud)) +if (pud_present (pudp_get (pud))) pmd =pmd_offset (pud, addr); } }
arch/loongarch/mm/init.c +5 -5
@@ -140,7 +140,7 @@ void __meminit vmemmap_set_pmd(pmd_t *pmd, void *p, int node,int __meminit vmemmap_check_pmd (pmd_t *pmd,int node,unsigned long addr,unsigned long next) { -int huge =pmd_val (*pmd) & _PAGE_HUGE; +int huge =pmd_val (pmdp_get (pmd)) & _PAGE_HUGE;if (huge)vmemmap_verify ((pte_t *)pmd, node, addr, next);
@@ -172,7 +172,7 @@ pte_t * __init populate_kernel_pte(unsigned long addr)pud_t *pud;pmd_t *pmd; -if (p4d_none (*p4d)) { +if (p4d_none (p4dp_get (p4d))) { pud =memblock_alloc (PAGE_SIZE ,PAGE_SIZE );if (!pud)panic ("%s: Failed to allocate memory\n" , __func__);
@@ -183,7 +183,7 @@ pte_t * __init populate_kernel_pte(unsigned long addr) } pud =pud_offset (p4d, addr); -if (pud_none (*pud)) { +if (pud_none (pudp_get (pud))) { pmd =memblock_alloc (PAGE_SIZE ,PAGE_SIZE );if (!pmd)panic ("%s: Failed to allocate memory\n" , __func__);
@@ -194,7 +194,7 @@ pte_t * __init populate_kernel_pte(unsigned long addr) } pmd =pmd_offset (pud, addr); -if (!pmd_present (*pmd)) { +if (!pmd_present (pmdp_get (pmd))) {pte_t *pte; pte =memblock_alloc (PAGE_SIZE ,PAGE_SIZE );
@@ -215,7 +215,7 @@ void __init __set_fixmap(enum fixed_addresses idx,BUG_ON (idx <=FIX_HOLE || idx >= __end_of_fixed_addresses); ptep =populate_kernel_pte (addr); -if (!pte_none (*ptep)) { +if (!pte_none (ptep_get (ptep))) {pte_ERROR (*ptep);return ; }
arch/loongarch/mm/kasan_init.c +5 -5
@@ -105,7 +105,7 @@ static phys_addr_t __init kasan_alloc_zeroed_page(int node)static pte_t *__init kasan_pte_offset (pmd_t *pmdp,unsigned long addr,int node,bool early) { -if (__pmd_none (early,READ_ONCE (*pmdp))) { +if (__pmd_none (early,pmdp_get (pmdp))) {phys_addr_t pte_phys = early ?__pa_symbol (kasan_early_shadow_pte) :kasan_alloc_zeroed_page (node);if (!early)
@@ -118,7 +118,7 @@ static pte_t *__init kasan_pte_offset(pmd_t *pmdp, unsigned long addr, int node,static pmd_t *__init kasan_pmd_offset (pud_t *pudp,unsigned long addr,int node,bool early) { -if (__pud_none (early,READ_ONCE (*pudp))) { +if (__pud_none (early,pudp_get (pudp))) {phys_addr_t pmd_phys = early ?__pa_symbol (kasan_early_shadow_pmd) :kasan_alloc_zeroed_page (node);if (!early)
@@ -131,7 +131,7 @@ static pmd_t *__init kasan_pmd_offset(pud_t *pudp, unsigned long addr, int node,static pud_t *__init kasan_pud_offset (p4d_t *p4dp,unsigned long addr,int node,bool early) { -if (__p4d_none (early,READ_ONCE (*p4dp))) { +if (__p4d_none (early,p4dp_get (p4dp))) {phys_addr_t pud_phys = early ?__pa_symbol (kasan_early_shadow_pud) :kasan_alloc_zeroed_page (node);if (!early)
@@ -154,7 +154,7 @@ static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr, : kasan_alloc_zeroed_page(node); next = addr +PAGE_SIZE ;set_pte (ptep,pfn_pte (__phys_to_pfn (page_phys),PAGE_KERNEL )); - }while (ptep++, addr = next, addr != end &&__pte_none (early,READ_ONCE (*ptep))); + }while (ptep++, addr = next, addr != end &&__pte_none (early,ptep_get (ptep))); } static void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr,
@@ -166,7 +166,7 @@ static void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr,do { next =pmd_addr_end (addr, end);kasan_pte_populate (pmdp, addr, next, node, early); - }while (pmdp++, addr = next, addr != end &&__pmd_none (early,READ_ONCE (*pmdp))); + }while (pmdp++, addr = next, addr != end &&__pmd_none (early,pmdp_get (pmdp))); } static void __init kasan_pud_populate(p4d_t *p4dp, unsigned long addr,
arch/loongarch/mm/pgtable.c +1 -1
@@ -128,7 +128,7 @@ pmd_t mk_pmd(struct page *page, pgprot_t prot)void set_pmd_at (struct mm_struct *mm,unsigned long addr,pmd_t *pmdp,pmd_t pmd) { - *pmdp = pmd; +WRITE_ONCE (*pmdp, pmd);flush_tlb_all (); }
Signature · 1 line
2.45.2
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH RESEND 2/2 LoongArch: Use accessors to page table entries instead of direct dereference
From: Huacai Chen <[email protected]>
commit 4574815abf43e2bf05643e1b3f7a2e5d6df894f0 upstream
As very well explained in commit 20a004e7b017cce282 ("arm64: mm: Use READ_ONCE/WRITE_ONCE when accessing page tables"), an architecture whose page table walker can modify the PTE in parallel must use READ_ONCE()/ WRITE_ONCE() macro to avoid any compiler transformation.
So apply that to LoongArch which is such an architecture, in order to avoid potential problems.
Similar to commit edf955647269422e ("riscv: Use accessors to page table entries instead of direct dereference").
--- arch/loongarch/include/asm/hugetlb.h | 4 +-- arch/loongarch/include/asm/kfence.h | 6 ++-- arch/loongarch/include/asm/pgtable.h | 48 +++++++++++++++++----------- arch/loongarch/kvm/mmu.c | 8 ++--- arch/loongarch/mm/hugetlbpage.c | 6 ++-- arch/loongarch/mm/init.c | 10 +++--- arch/loongarch/mm/kasan_init.c | 10 +++--- arch/loongarch/mm/pgtable.c | 2 +- 8 files changed, 52 insertions(+), 42 deletions(-)
arch/loongarch/include/asm/hugetlb.h +2 -2
@@ -34,7 +34,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { pte_t clear; -pte_t pte = *ptep; +pte_t pte =ptep_get (ptep);pte_val (clear) = (unsigned long )invalid_pte_table;set_pte_at (mm, addr, ptep, clear);
@@ -65,7 +65,7 @@ static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma, pte_t *ptep, pte_t pte, int dirty) { - int changed = !pte_same(*ptep, pte); + int changed = !pte_same(ptep_get(ptep), pte);if (changed) {set_pte_at (vma->vm_mm, addr, ptep, pte);
arch/loongarch/include/asm/kfence.h +3 -3
@@ -43,13 +43,13 @@ static inline bool kfence_protect_page(unsigned long addr, bool protect) {pte_t *pte =virt_to_kpte (addr); -if (WARN_ON (!pte) ||pte_none (*pte)) +if (WARN_ON (!pte) ||pte_none (ptep_get (pte)))return false;if (protect) -set_pte (pte,__pte (pte_val (*pte) & ~(_PAGE_VALID | _PAGE_PRESENT))); +set_pte (pte,__pte (pte_val (ptep_get (pte)) & ~(_PAGE_VALID | _PAGE_PRESENT)));else -set_pte (pte,__pte (pte_val (*pte) | (_PAGE_VALID | _PAGE_PRESENT))); +set_pte (pte,__pte (pte_val (ptep_get (pte)) | (_PAGE_VALID | _PAGE_PRESENT)));preempt_disable ();local_flush_tlb_one (addr);
arch/loongarch/include/asm/pgtable.h +29 -19
111 lines not on this page · raw message
arch/loongarch/kvm/mmu.c +4 -4
@@ -679,19 +679,19 @@ static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn,* value) and then p*d_offset() walks into the target huge page instead * of the old page table (sees the new value). */ - pgd =READ_ONCE (*pgd_offset (kvm->mm, hva)); + pgd =pgdp_get (pgd_offset (kvm->mm, hva));if (pgd_none (pgd)) goto out; - p4d =READ_ONCE (*p4d_offset (&pgd, hva)); + p4d =p4dp_get (p4d_offset (&pgd, hva));if (p4d_none (p4d) || !p4d_present (p4d)) goto out; - pud =READ_ONCE (*pud_offset (&p4d, hva)); + pud =pudp_get (pud_offset (&p4d, hva));if (pud_none (pud) || !pud_present (pud)) goto out; - pmd =READ_ONCE (*pmd_offset (&pud, hva)); + pmd =pmdp_get (pmd_offset (&pud, hva));if (pmd_none (pmd) || !pmd_present (pmd)) goto out;
arch/loongarch/mm/hugetlbpage.c +3 -3
@@ -39,11 +39,11 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr,pmd_t *pmd =NULL ; pgd =pgd_offset (mm, addr); -if (pgd_present (*pgd)) { +if (pgd_present (pgdp_get (pgd))) { p4d =p4d_offset (pgd, addr); -if (p4d_present (*p4d)) { +if (p4d_present (p4dp_get (p4d))) { pud =pud_offset (p4d, addr); -if (pud_present (*pud)) +if (pud_present (pudp_get (pud))) pmd =pmd_offset (pud, addr); } }
arch/loongarch/mm/init.c +5 -5
@@ -140,7 +140,7 @@ void __meminit vmemmap_set_pmd(pmd_t *pmd, void *p, int node,int __meminit vmemmap_check_pmd (pmd_t *pmd,int node,unsigned long addr,unsigned long next) { -int huge =pmd_val (*pmd) & _PAGE_HUGE; +int huge =pmd_val (pmdp_get (pmd)) & _PAGE_HUGE;if (huge)vmemmap_verify ((pte_t *)pmd, node, addr, next);
@@ -172,7 +172,7 @@ pte_t * __init populate_kernel_pte(unsigned long addr)pud_t *pud;pmd_t *pmd; -if (p4d_none (*p4d)) { +if (p4d_none (p4dp_get (p4d))) { pud =memblock_alloc (PAGE_SIZE ,PAGE_SIZE );if (!pud)panic ("%s: Failed to allocate memory\n" , __func__);
@@ -183,7 +183,7 @@ pte_t * __init populate_kernel_pte(unsigned long addr) } pud =pud_offset (p4d, addr); -if (pud_none (*pud)) { +if (pud_none (pudp_get (pud))) { pmd =memblock_alloc (PAGE_SIZE ,PAGE_SIZE );if (!pmd)panic ("%s: Failed to allocate memory\n" , __func__);
@@ -194,7 +194,7 @@ pte_t * __init populate_kernel_pte(unsigned long addr) } pmd =pmd_offset (pud, addr); -if (!pmd_present (*pmd)) { +if (!pmd_present (pmdp_get (pmd))) {pte_t *pte; pte =memblock_alloc (PAGE_SIZE ,PAGE_SIZE );
@@ -215,7 +215,7 @@ void __init __set_fixmap(enum fixed_addresses idx,BUG_ON (idx <=FIX_HOLE || idx >= __end_of_fixed_addresses); ptep =populate_kernel_pte (addr); -if (!pte_none (*ptep)) { +if (!pte_none (ptep_get (ptep))) {pte_ERROR (*ptep);return ; }
arch/loongarch/mm/kasan_init.c +5 -5
@@ -105,7 +105,7 @@ static phys_addr_t __init kasan_alloc_zeroed_page(int node)static pte_t *__init kasan_pte_offset (pmd_t *pmdp,unsigned long addr,int node,bool early) { -if (__pmd_none (early,READ_ONCE (*pmdp))) { +if (__pmd_none (early,pmdp_get (pmdp))) {phys_addr_t pte_phys = early ?__pa_symbol (kasan_early_shadow_pte) :kasan_alloc_zeroed_page (node);if (!early)
@@ -118,7 +118,7 @@ static pte_t *__init kasan_pte_offset(pmd_t *pmdp, unsigned long addr, int node,static pmd_t *__init kasan_pmd_offset (pud_t *pudp,unsigned long addr,int node,bool early) { -if (__pud_none (early,READ_ONCE (*pudp))) { +if (__pud_none (early,pudp_get (pudp))) {phys_addr_t pmd_phys = early ?__pa_symbol (kasan_early_shadow_pmd) :kasan_alloc_zeroed_page (node);if (!early)
@@ -131,7 +131,7 @@ static pmd_t *__init kasan_pmd_offset(pud_t *pudp, unsigned long addr, int node,static pud_t *__init kasan_pud_offset (p4d_t *p4dp,unsigned long addr,int node,bool early) { -if (__p4d_none (early,READ_ONCE (*p4dp))) { +if (__p4d_none (early,p4dp_get (p4dp))) {phys_addr_t pud_phys = early ?__pa_symbol (kasan_early_shadow_pud) :kasan_alloc_zeroed_page (node);if (!early)
@@ -154,7 +154,7 @@ static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr, : kasan_alloc_zeroed_page(node); next = addr +PAGE_SIZE ;set_pte (ptep,pfn_pte (__phys_to_pfn (page_phys),PAGE_KERNEL )); - }while (ptep++, addr = next, addr != end &&__pte_none (early,READ_ONCE (*ptep))); + }while (ptep++, addr = next, addr != end &&__pte_none (early,ptep_get (ptep))); } static void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr,
@@ -166,7 +166,7 @@ static void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr,do { next =pmd_addr_end (addr, end);kasan_pte_populate (pmdp, addr, next, node, early); - }while (pmdp++, addr = next, addr != end &&__pmd_none (early,READ_ONCE (*pmdp))); + }while (pmdp++, addr = next, addr != end &&__pmd_none (early,pmdp_get (pmdp))); } static void __init kasan_pud_populate(p4d_t *p4dp, unsigned long addr,
arch/loongarch/mm/pgtable.c +1 -1
@@ -128,7 +128,7 @@ pmd_t mk_pmd(struct page *page, pgprot_t prot)void set_pmd_at (struct mm_struct *mm,unsigned long addr,pmd_t *pmdp,pmd_t pmd) { - *pmdp = pmd; +WRITE_ONCE (*pmdp, pmd);flush_tlb_all (); }
Signature · 1 line
2.45.2
Greg KH
maintainerRe: [PATCH 6.6.y RESEND 2/2] LoongArch: Use accessors to page table entries instead of direct dereference
Quoted 9 lines · He Lugang
From: Huacai Chen <[email protected]>
commit
4574815abf43e2bf05643e1b3f7a2e5d6df894f0upstreamAs very well explained in commit
20a004e7b017cce282("arm64: mm: Use READ_ONCE/WRITE_ONCE when accessing page tables"), an architecture whose page table walker can modify the PTE in parallel must use READ_ONCE()/WRITE_ONCE()macro to avoid any compiler transformation.
Quoted 7 lines
So apply that to LoongArch which is such an architecture, in order to avoid potential problems.
Similar to commit
edf955647269422e("riscv: Use accessors to page table entries instead of direct dereference").Signed-off-by Huacai Chen <[email protected]>
You did not sign off on this, so I'm dropping it :(
PATCH RESEND 1/2 LoongArch: KVM: Implement kvm mmu operations
In reply to [email protected]From: Tianrui Zhao <[email protected]>
commit 752e2cd7b4fb412f3e008493e0195e357bab9773 upstream
Implement LoongArch kvm mmu, it is used to switch gpa to hpa when guest exit because of address translation exception.
This patch implement: allocating gpa page table, searching gpa from it, and flushing guest gpa in the table.
--- arch/loongarch/include/asm/kvm_mmu.h | 139 ++++ arch/loongarch/kvm/mmu.c | 914 +++++++++++++++++++++++++++ 2 files changed, 1053 insertions(+) create mode 100644 arch/loongarch/include/asm/kvm_mmu.h create mode 100644 arch/loongarch/kvm/mmu.c
arch/loongarch/include/asm/kvm_mmu.h new file +139 -0
@@ -0,0 +1,139 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2020-2023 Loongson Technology Corporation Limited +*/ + +#ifndef __ASM_LOONGARCH_KVM_MMU_H__ +#define __ASM_LOONGARCH_KVM_MMU_H__ + +#include <linux/kvm_host.h> +#include <asm/pgalloc.h> +#include <asm/tlb.h> + +/* +* KVM_MMU_CACHE_MIN_PAGES is the number of GPA page table translation levels +* for which pages need to be cached. +*/ +#define KVM_MMU_CACHE_MIN_PAGES (CONFIG_PGTABLE_LEVELS - 1) + +#define _KVM_FLUSH_PGTABLE 0x1 +#define _KVM_HAS_PGMASK 0x2 +#define kvm_pfn_pte (pfn, prot) (((pfn) << PFN_PTE_SHIFT) | pgprot_val(prot)) +#define kvm_pte_pfn (x) ((phys_addr_t)((x & _PFN_MASK) >> PFN_PTE_SHIFT)) + +typedef unsigned long kvm_pte_t ; +typedef struct kvm_ptw_ctx kvm_ptw_ctx ; +typedef int (*kvm_pte_ops )(kvm_pte_t *pte,phys_addr_t addr,kvm_ptw_ctx *ctx); + +struct kvm_ptw_ctx { +kvm_pte_ops ops; +unsigned long flag; + +/* for kvm_arch_mmu_enable_log_dirty_pt_masked use */ +unsigned long mask; +unsigned long gfn; + +/* page walk mmu info */ +unsigned int level; +unsigned long pgtable_shift; +unsigned long invalid_entry; +unsigned long *invalid_ptes; +unsigned int *pte_shifts; +void *opaque; + +/* free pte table page list */ +struct list_head list; +}; + +kvm_pte_t *kvm_pgd_alloc (void ); + +static inline void kvm_set_pte (kvm_pte_t *ptep,kvm_pte_t val) +{ +WRITE_ONCE (*ptep, val); +} + +static inline int kvm_pte_write (kvm_pte_t pte) {return pte & _PAGE_WRITE; } +static inline int kvm_pte_dirty (kvm_pte_t pte) {return pte & _PAGE_DIRTY; } +static inline int kvm_pte_young (kvm_pte_t pte) {return pte & _PAGE_ACCESSED; } +static inline int kvm_pte_huge (kvm_pte_t pte) {return pte & _PAGE_HUGE; } + +static inline kvm_pte_t kvm_pte_mkyoung (kvm_pte_t pte) +{ +return pte | _PAGE_ACCESSED; +} + +static inline kvm_pte_t kvm_pte_mkold (kvm_pte_t pte) +{ +return pte & ~_PAGE_ACCESSED; +} + +static inline kvm_pte_t kvm_pte_mkdirty (kvm_pte_t pte) +{ +return pte | _PAGE_DIRTY; +} + +static inline kvm_pte_t kvm_pte_mkclean (kvm_pte_t pte) +{ +return pte & ~_PAGE_DIRTY; +} + +static inline kvm_pte_t kvm_pte_mkhuge (kvm_pte_t pte) +{ +return pte | _PAGE_HUGE; +} + +static inline kvm_pte_t kvm_pte_mksmall (kvm_pte_t pte) +{ +return pte & ~_PAGE_HUGE; +} + +static inline int kvm_need_flush (kvm_ptw_ctx *ctx) +{ +return ctx->flag & _KVM_FLUSH_PGTABLE; +} + +static inline kvm_pte_t *kvm_pgtable_offset (kvm_ptw_ctx *ctx,kvm_pte_t *table, +phys_addr_t addr) +{ + +return table + ((addr >> ctx->pgtable_shift) & (PTRS_PER_PTE -1 )); +} + +static inline phys_addr_t kvm_pgtable_addr_end (kvm_ptw_ctx *ctx, +phys_addr_t addr,phys_addr_t end) +{ +phys_addr_t boundary, size; + + size =0x1UL << ctx->pgtable_shift; + boundary = (addr + size) & ~(size -1 ); +return (boundary -1 < end -1 ) ? boundary : end; +} + +static inline int kvm_pte_present (kvm_ptw_ctx *ctx,kvm_pte_t *entry) +{ +if (!ctx || ctx->level ==0 ) +return !!(*entry & _PAGE_PRESENT); + +return *entry != ctx->invalid_entry; +} + +static inline int kvm_pte_none (kvm_ptw_ctx *ctx,kvm_pte_t *entry) +{ +return *entry == ctx->invalid_entry; +} + +static inline void kvm_ptw_enter (kvm_ptw_ctx *ctx) +{ + ctx->level--; + ctx->pgtable_shift = ctx->pte_shifts[ctx->level]; + ctx->invalid_entry = ctx->invalid_ptes[ctx->level]; +} + +static inline void kvm_ptw_exit (kvm_ptw_ctx *ctx) +{ + ctx->level++; + ctx->pgtable_shift = ctx->pte_shifts[ctx->level]; + ctx->invalid_entry = ctx->invalid_ptes[ctx->level]; +} + +#endif /* __ASM_LOONGARCH_KVM_MMU_H__ */
arch/loongarch/kvm/mmu.c new file +914 -0
914 lines not on this page · raw message
Signature · 1 line
2.45.2