Skip to content

Commit f04de6d

Browse files
committed
LoongArch: Add ARCH_HAS_SET_DIRECT_MAP support
Add set_direct_map_*() functions for setting the direct map alias for the page to its default permissions and to an invalid state that cannot be cached in a TLB. (See d253ca0 ("x86/mm/cpa: Add set_direct_map_*() functions")) Add a similar implementation for LoongArch. This fixes the KFENCE warnings during hibernation: ================================================================== BUG: KFENCE: invalid read in swsusp_save+0x368/0x4d8 Invalid read at 0x00000000f7b89a3c: swsusp_save+0x368/0x4d8 hibernation_snapshot+0x3f0/0x4e0 hibernate+0x20c/0x440 state_store+0x128/0x140 kernfs_fop_write_iter+0x160/0x260 vfs_write+0x2c0/0x520 ksys_write+0x74/0x160 do_syscall+0xb0/0x160 CPU: 0 UID: 0 PID: 812 Comm: bash Tainted: G B 6.11.0-rc1+ #1566 Tainted: [B]=BAD_PAGE Hardware name: Loongson-LS3A5000-7A1000-1w-CRB, BIOS vUDK2018-LoongArch-V2.0.0 10/21/2022 ================================================================== Note: We can only set permissions for KVRANGE/XKVRANGE kernel addresses. Signed-off-by: Huacai Chen <[email protected]>
1 parent e86935f commit f04de6d

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

arch/loongarch/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ config LOONGARCH
2626
select ARCH_HAS_PTE_DEVMAP
2727
select ARCH_HAS_PTE_SPECIAL
2828
select ARCH_HAS_SET_MEMORY
29+
select ARCH_HAS_SET_DIRECT_MAP
2930
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
3031
select ARCH_INLINE_READ_LOCK if !PREEMPTION
3132
select ARCH_INLINE_READ_LOCK_BH if !PREEMPTION

arch/loongarch/include/asm/set_memory.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,8 @@ int set_memory_nx(unsigned long addr, int numpages);
1414
int set_memory_ro(unsigned long addr, int numpages);
1515
int set_memory_rw(unsigned long addr, int numpages);
1616

17+
bool kernel_page_present(struct page *page);
18+
int set_direct_map_default_noflush(struct page *page);
19+
int set_direct_map_invalid_noflush(struct page *page);
20+
1721
#endif /* _ASM_LOONGARCH_SET_MEMORY_H */

arch/loongarch/mm/pageattr.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,63 @@ int set_memory_rw(unsigned long addr, int numpages)
156156

157157
return __set_memory(addr, numpages, __pgprot(_PAGE_WRITE | _PAGE_DIRTY), __pgprot(0));
158158
}
159+
160+
bool kernel_page_present(struct page *page)
161+
{
162+
pgd_t *pgd;
163+
p4d_t *p4d;
164+
pud_t *pud;
165+
pmd_t *pmd;
166+
pte_t *pte;
167+
unsigned long addr = (unsigned long)page_address(page);
168+
169+
if (addr < vm_map_base)
170+
return true;
171+
172+
pgd = pgd_offset_k(addr);
173+
if (pgd_none(pgdp_get(pgd)))
174+
return false;
175+
if (pgd_leaf(pgdp_get(pgd)))
176+
return true;
177+
178+
p4d = p4d_offset(pgd, addr);
179+
if (p4d_none(p4dp_get(p4d)))
180+
return false;
181+
if (p4d_leaf(p4dp_get(p4d)))
182+
return true;
183+
184+
pud = pud_offset(p4d, addr);
185+
if (pud_none(pudp_get(pud)))
186+
return false;
187+
if (pud_leaf(pudp_get(pud)))
188+
return true;
189+
190+
pmd = pmd_offset(pud, addr);
191+
if (pmd_none(pmdp_get(pmd)))
192+
return false;
193+
if (pmd_leaf(pmdp_get(pmd)))
194+
return true;
195+
196+
pte = pte_offset_kernel(pmd, addr);
197+
return pte_present(ptep_get(pte));
198+
}
199+
200+
int set_direct_map_default_noflush(struct page *page)
201+
{
202+
unsigned long addr = (unsigned long)page_address(page);
203+
204+
if (addr < vm_map_base)
205+
return 0;
206+
207+
return __set_memory(addr, 1, PAGE_KERNEL, __pgprot(0));
208+
}
209+
210+
int set_direct_map_invalid_noflush(struct page *page)
211+
{
212+
unsigned long addr = (unsigned long)page_address(page);
213+
214+
if (addr < vm_map_base)
215+
return 0;
216+
217+
return __set_memory(addr, 1, __pgprot(0), __pgprot(_PAGE_PRESENT | _PAGE_VALID));
218+
}

0 commit comments

Comments
 (0)