Skip to content

Commit

Permalink
riscv: Fix set_huge_pte_at() for NAPOT mapping
Browse files Browse the repository at this point in the history
[ Upstream commit 1458eb2 ]

As stated by the privileged specification, we must clear a NAPOT
mapping and emit a sfence.vma before setting a new translation.

Fixes: 82a1a1f ("riscv: mm: support Svnapot in hugetlb page")
Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
Link: https://lore.kernel.org/r/20240117195741.1926459-2-alexghiti@rivosinc.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Alexandre Ghiti authored and gregkh committed Feb 16, 2024
1 parent 4a67cb9 commit ee0948b
Showing 1 changed file with 40 additions and 2 deletions.
42 changes: 40 additions & 2 deletions arch/riscv/mm/hugetlbpage.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,36 @@ pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags)
return entry;
}

static void clear_flush(struct mm_struct *mm,
unsigned long addr,
pte_t *ptep,
unsigned long pgsize,
unsigned long ncontig)
{
struct vm_area_struct vma = TLB_FLUSH_VMA(mm, 0);
unsigned long i, saddr = addr;

for (i = 0; i < ncontig; i++, addr += pgsize, ptep++)
ptep_get_and_clear(mm, addr, ptep);

flush_tlb_range(&vma, saddr, addr);
}

/*
* When dealing with NAPOT mappings, the privileged specification indicates that
* "if an update needs to be made, the OS generally should first mark all of the
* PTEs invalid, then issue SFENCE.VMA instruction(s) covering all 4 KiB regions
* within the range, [...] then update the PTE(s), as described in Section
* 4.2.1.". That's the equivalent of the Break-Before-Make approach used by
* arm64.
*/
void set_huge_pte_at(struct mm_struct *mm,
unsigned long addr,
pte_t *ptep,
pte_t pte,
unsigned long sz)
{
unsigned long hugepage_shift;
unsigned long hugepage_shift, pgsize;
int i, pte_num;

if (sz >= PGDIR_SIZE)
Expand All @@ -198,7 +221,22 @@ void set_huge_pte_at(struct mm_struct *mm,
hugepage_shift = PAGE_SHIFT;

pte_num = sz >> hugepage_shift;
for (i = 0; i < pte_num; i++, ptep++, addr += (1 << hugepage_shift))
pgsize = 1 << hugepage_shift;

if (!pte_present(pte)) {
for (i = 0; i < pte_num; i++, ptep++, addr += pgsize)
set_ptes(mm, addr, ptep, pte, 1);
return;
}

if (!pte_napot(pte)) {
set_ptes(mm, addr, ptep, pte, 1);
return;
}

clear_flush(mm, addr, ptep, pgsize, pte_num);

for (i = 0; i < pte_num; i++, ptep++, addr += pgsize)
set_pte_at(mm, addr, ptep, pte);
}

Expand Down

0 comments on commit ee0948b

Please sign in to comment.