Skip to content

Commit

Permalink
LoongArch: Use accessors to page table entries instead of direct dere…
Browse files Browse the repository at this point in the history
…ference

commit 4574815 upstream.

As very well explained in commit 20a004e ("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 edf9556 ("riscv: Use accessors to page table
entries instead of direct dereference").

Signed-off-by: Huacai Chen <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
chenhuacai authored and gregkh committed Sep 12, 2024
1 parent 12bc88c commit 60e01e9
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 42 deletions.
4 changes: 2 additions & 2 deletions arch/loongarch/include/asm/hugetlb.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions arch/loongarch/include/asm/kfence.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
48 changes: 29 additions & 19 deletions arch/loongarch/include/asm/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
#define KFENCE_AREA_START (VMEMMAP_END + 1)
#define KFENCE_AREA_END (KFENCE_AREA_START + KFENCE_AREA_SIZE - 1)

#define ptep_get(ptep) READ_ONCE(*(ptep))
#define pmdp_get(pmdp) READ_ONCE(*(pmdp))

#define pte_ERROR(e) \
pr_err("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
#ifndef __PAGETABLE_PMD_FOLDED
Expand Down Expand Up @@ -147,19 +150,19 @@ static inline int p4d_present(p4d_t p4d)
return p4d_val(p4d) != (unsigned long)invalid_pud_table;
}

static inline void p4d_clear(p4d_t *p4dp)
{
p4d_val(*p4dp) = (unsigned long)invalid_pud_table;
}

static inline pud_t *p4d_pgtable(p4d_t p4d)
{
return (pud_t *)p4d_val(p4d);
}

static inline void set_p4d(p4d_t *p4d, p4d_t p4dval)
{
*p4d = p4dval;
WRITE_ONCE(*p4d, p4dval);
}

static inline void p4d_clear(p4d_t *p4dp)
{
set_p4d(p4dp, __p4d((unsigned long)invalid_pud_table));
}

#define p4d_phys(p4d) PHYSADDR(p4d_val(p4d))
Expand Down Expand Up @@ -193,17 +196,20 @@ static inline int pud_present(pud_t pud)
return pud_val(pud) != (unsigned long)invalid_pmd_table;
}

static inline void pud_clear(pud_t *pudp)
static inline pmd_t *pud_pgtable(pud_t pud)
{
pud_val(*pudp) = ((unsigned long)invalid_pmd_table);
return (pmd_t *)pud_val(pud);
}

static inline pmd_t *pud_pgtable(pud_t pud)
static inline void set_pud(pud_t *pud, pud_t pudval)
{
return (pmd_t *)pud_val(pud);
WRITE_ONCE(*pud, pudval);
}

#define set_pud(pudptr, pudval) do { *(pudptr) = (pudval); } while (0)
static inline void pud_clear(pud_t *pudp)
{
set_pud(pudp, __pud((unsigned long)invalid_pmd_table));
}

#define pud_phys(pud) PHYSADDR(pud_val(pud))
#define pud_page(pud) (pfn_to_page(pud_phys(pud) >> PAGE_SHIFT))
Expand Down Expand Up @@ -231,12 +237,15 @@ static inline int pmd_present(pmd_t pmd)
return pmd_val(pmd) != (unsigned long)invalid_pte_table;
}

static inline void pmd_clear(pmd_t *pmdp)
static inline void set_pmd(pmd_t *pmd, pmd_t pmdval)
{
pmd_val(*pmdp) = ((unsigned long)invalid_pte_table);
WRITE_ONCE(*pmd, pmdval);
}

#define set_pmd(pmdptr, pmdval) do { *(pmdptr) = (pmdval); } while (0)
static inline void pmd_clear(pmd_t *pmdp)
{
set_pmd(pmdp, __pmd((unsigned long)invalid_pte_table));
}

#define pmd_phys(pmd) PHYSADDR(pmd_val(pmd))

Expand Down Expand Up @@ -314,7 +323,8 @@ extern void paging_init(void);

static inline void set_pte(pte_t *ptep, pte_t pteval)
{
*ptep = pteval;
WRITE_ONCE(*ptep, pteval);

if (pte_val(pteval) & _PAGE_GLOBAL) {
pte_t *buddy = ptep_buddy(ptep);
/*
Expand All @@ -341,16 +351,16 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
: [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp)
: [global] "r" (page_global));
#else /* !CONFIG_SMP */
if (pte_none(*buddy))
pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL;
if (pte_none(ptep_get(buddy)))
WRITE_ONCE(*buddy, __pte(pte_val(ptep_get(buddy)) | _PAGE_GLOBAL));
#endif /* CONFIG_SMP */
}
}

static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
/* Preserve global status for the pair */
if (pte_val(*ptep_buddy(ptep)) & _PAGE_GLOBAL)
if (pte_val(ptep_get(ptep_buddy(ptep))) & _PAGE_GLOBAL)
set_pte(ptep, __pte(_PAGE_GLOBAL));
else
set_pte(ptep, __pte(0));
Expand Down Expand Up @@ -589,7 +599,7 @@ static inline pmd_t pmd_mkinvalid(pmd_t pmd)
static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
unsigned long address, pmd_t *pmdp)
{
pmd_t old = *pmdp;
pmd_t old = pmdp_get(pmdp);

pmd_clear(pmdp);

Expand Down
8 changes: 4 additions & 4 deletions arch/loongarch/kvm/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -695,19 +695,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;

Expand Down
6 changes: 3 additions & 3 deletions arch/loongarch/mm/hugetlbpage.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
10 changes: 5 additions & 5 deletions arch/loongarch/mm/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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__);
Expand All @@ -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__);
Expand All @@ -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);
Expand All @@ -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;
}
Expand Down
10 changes: 5 additions & 5 deletions arch/loongarch/mm/kasan_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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,
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion arch/loongarch/mm/pgtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down

0 comments on commit 60e01e9

Please sign in to comment.