Skip to content

Commit 1458eb2

Browse files
Alexandre Ghitipalmer-dabbelt
authored andcommitted
riscv: Fix set_huge_pte_at() for NAPOT mapping
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>
1 parent 6613476 commit 1458eb2

File tree

1 file changed

+40
-2
lines changed

1 file changed

+40
-2
lines changed

arch/riscv/mm/hugetlbpage.c

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,13 +177,36 @@ pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags)
177177
return entry;
178178
}
179179

180+
static void clear_flush(struct mm_struct *mm,
181+
unsigned long addr,
182+
pte_t *ptep,
183+
unsigned long pgsize,
184+
unsigned long ncontig)
185+
{
186+
struct vm_area_struct vma = TLB_FLUSH_VMA(mm, 0);
187+
unsigned long i, saddr = addr;
188+
189+
for (i = 0; i < ncontig; i++, addr += pgsize, ptep++)
190+
ptep_get_and_clear(mm, addr, ptep);
191+
192+
flush_tlb_range(&vma, saddr, addr);
193+
}
194+
195+
/*
196+
* When dealing with NAPOT mappings, the privileged specification indicates that
197+
* "if an update needs to be made, the OS generally should first mark all of the
198+
* PTEs invalid, then issue SFENCE.VMA instruction(s) covering all 4 KiB regions
199+
* within the range, [...] then update the PTE(s), as described in Section
200+
* 4.2.1.". That's the equivalent of the Break-Before-Make approach used by
201+
* arm64.
202+
*/
180203
void set_huge_pte_at(struct mm_struct *mm,
181204
unsigned long addr,
182205
pte_t *ptep,
183206
pte_t pte,
184207
unsigned long sz)
185208
{
186-
unsigned long hugepage_shift;
209+
unsigned long hugepage_shift, pgsize;
187210
int i, pte_num;
188211

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

200223
pte_num = sz >> hugepage_shift;
201-
for (i = 0; i < pte_num; i++, ptep++, addr += (1 << hugepage_shift))
224+
pgsize = 1 << hugepage_shift;
225+
226+
if (!pte_present(pte)) {
227+
for (i = 0; i < pte_num; i++, ptep++, addr += pgsize)
228+
set_ptes(mm, addr, ptep, pte, 1);
229+
return;
230+
}
231+
232+
if (!pte_napot(pte)) {
233+
set_ptes(mm, addr, ptep, pte, 1);
234+
return;
235+
}
236+
237+
clear_flush(mm, addr, ptep, pgsize, pte_num);
238+
239+
for (i = 0; i < pte_num; i++, ptep++, addr += pgsize)
202240
set_pte_at(mm, addr, ptep, pte);
203241
}
204242

0 commit comments

Comments
 (0)