Skip to content

Commit 5b32510

Browse files
Ryan Robertswilldeacon
authored andcommitted
arm64/mm: Add uffd write-protect support
Let's use the newly-free PTE SW bit (58) to add support for uffd-wp. The standard handlers are implemented for set/test/clear for both pte and pmd. Additionally we must also track the uffd-wp state as a pte swp bit, so use a free swap pte bit (3). Acked-by: Peter Xu <[email protected]> Reviewed-by: Catalin Marinas <[email protected]> Reviewed-by: David Hildenbrand <[email protected]> Signed-off-by: Ryan Roberts <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 5556481 commit 5b32510

File tree

3 files changed

+53
-0
lines changed

3 files changed

+53
-0
lines changed

arch/arm64/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ config ARM64
255255
select SYSCTL_EXCEPTION_TRACE
256256
select THREAD_INFO_IN_TASK
257257
select HAVE_ARCH_USERFAULTFD_MINOR if USERFAULTFD
258+
select HAVE_ARCH_USERFAULTFD_WP if USERFAULTFD
258259
select TRACE_IRQFLAGS_SUPPORT
259260
select TRACE_IRQFLAGS_NMI_SUPPORT
260261
select HAVE_SOFTIRQ_ON_OWN_STACK

arch/arm64/include/asm/pgtable-prot.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@
2626
*/
2727
#define PTE_PRESENT_INVALID (PTE_NG) /* only when !PTE_VALID */
2828

29+
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
30+
#define PTE_UFFD_WP (_AT(pteval_t, 1) << 58) /* uffd-wp tracking */
31+
#define PTE_SWP_UFFD_WP (_AT(pteval_t, 1) << 3) /* only for swp ptes */
32+
#else
33+
#define PTE_UFFD_WP (_AT(pteval_t, 0))
34+
#define PTE_SWP_UFFD_WP (_AT(pteval_t, 0))
35+
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
36+
2937
#define _PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
3038
#define _PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
3139

arch/arm64/include/asm/pgtable.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,23 @@ static inline pte_t pte_mkdevmap(pte_t pte)
280280
return set_pte_bit(pte, __pgprot(PTE_DEVMAP | PTE_SPECIAL));
281281
}
282282

283+
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
284+
static inline int pte_uffd_wp(pte_t pte)
285+
{
286+
return !!(pte_val(pte) & PTE_UFFD_WP);
287+
}
288+
289+
static inline pte_t pte_mkuffd_wp(pte_t pte)
290+
{
291+
return pte_wrprotect(set_pte_bit(pte, __pgprot(PTE_UFFD_WP)));
292+
}
293+
294+
static inline pte_t pte_clear_uffd_wp(pte_t pte)
295+
{
296+
return clear_pte_bit(pte, __pgprot(PTE_UFFD_WP));
297+
}
298+
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
299+
283300
static inline void __set_pte_nosync(pte_t *ptep, pte_t pte)
284301
{
285302
WRITE_ONCE(*ptep, pte);
@@ -477,6 +494,23 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte)
477494
return clear_pte_bit(pte, __pgprot(PTE_SWP_EXCLUSIVE));
478495
}
479496

497+
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
498+
static inline pte_t pte_swp_mkuffd_wp(pte_t pte)
499+
{
500+
return set_pte_bit(pte, __pgprot(PTE_SWP_UFFD_WP));
501+
}
502+
503+
static inline int pte_swp_uffd_wp(pte_t pte)
504+
{
505+
return !!(pte_val(pte) & PTE_SWP_UFFD_WP);
506+
}
507+
508+
static inline pte_t pte_swp_clear_uffd_wp(pte_t pte)
509+
{
510+
return clear_pte_bit(pte, __pgprot(PTE_SWP_UFFD_WP));
511+
}
512+
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
513+
480514
#ifdef CONFIG_NUMA_BALANCING
481515
/*
482516
* See the comment in include/linux/pgtable.h
@@ -527,6 +561,15 @@ static inline int pmd_trans_huge(pmd_t pmd)
527561
#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))
528562
#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))
529563
#define pmd_mkinvalid(pmd) pte_pmd(pte_mkinvalid(pmd_pte(pmd)))
564+
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
565+
#define pmd_uffd_wp(pmd) pte_uffd_wp(pmd_pte(pmd))
566+
#define pmd_mkuffd_wp(pmd) pte_pmd(pte_mkuffd_wp(pmd_pte(pmd)))
567+
#define pmd_clear_uffd_wp(pmd) pte_pmd(pte_clear_uffd_wp(pmd_pte(pmd)))
568+
#define pmd_swp_uffd_wp(pmd) pte_swp_uffd_wp(pmd_pte(pmd))
569+
#define pmd_swp_mkuffd_wp(pmd) pte_pmd(pte_swp_mkuffd_wp(pmd_pte(pmd)))
570+
#define pmd_swp_clear_uffd_wp(pmd) \
571+
pte_pmd(pte_swp_clear_uffd_wp(pmd_pte(pmd)))
572+
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
530573

531574
#define pmd_thp_or_huge(pmd) (pmd_huge(pmd) || pmd_trans_huge(pmd))
532575

@@ -1261,6 +1304,7 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
12611304
* Encode and decode a swap entry:
12621305
* bits 0-1: present (must be zero)
12631306
* bits 2: remember PG_anon_exclusive
1307+
* bit 3: remember uffd-wp state
12641308
* bits 6-10: swap type
12651309
* bit 11: PTE_PRESENT_INVALID (must be zero)
12661310
* bits 12-61: swap offset

0 commit comments

Comments
 (0)