mirror of
https://github.com/torvalds/linux.git
synced 2024-11-29 07:31:29 +00:00
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 <peterx@redhat.com> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Reviewed-by: David Hildenbrand <david@redhat.com> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com> Link: https://lore.kernel.org/r/20240503144604.151095-5-ryan.roberts@arm.com Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
55564814a8
commit
5b32510af7
@ -255,6 +255,7 @@ config ARM64
|
||||
select SYSCTL_EXCEPTION_TRACE
|
||||
select THREAD_INFO_IN_TASK
|
||||
select HAVE_ARCH_USERFAULTFD_MINOR if USERFAULTFD
|
||||
select HAVE_ARCH_USERFAULTFD_WP if USERFAULTFD
|
||||
select TRACE_IRQFLAGS_SUPPORT
|
||||
select TRACE_IRQFLAGS_NMI_SUPPORT
|
||||
select HAVE_SOFTIRQ_ON_OWN_STACK
|
||||
|
@ -26,6 +26,14 @@
|
||||
*/
|
||||
#define PTE_PRESENT_INVALID (PTE_NG) /* only when !PTE_VALID */
|
||||
|
||||
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
|
||||
#define PTE_UFFD_WP (_AT(pteval_t, 1) << 58) /* uffd-wp tracking */
|
||||
#define PTE_SWP_UFFD_WP (_AT(pteval_t, 1) << 3) /* only for swp ptes */
|
||||
#else
|
||||
#define PTE_UFFD_WP (_AT(pteval_t, 0))
|
||||
#define PTE_SWP_UFFD_WP (_AT(pteval_t, 0))
|
||||
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
|
||||
|
||||
#define _PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
|
||||
#define _PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
|
||||
|
||||
|
@ -280,6 +280,23 @@ static inline pte_t pte_mkdevmap(pte_t pte)
|
||||
return set_pte_bit(pte, __pgprot(PTE_DEVMAP | PTE_SPECIAL));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
|
||||
static inline int pte_uffd_wp(pte_t pte)
|
||||
{
|
||||
return !!(pte_val(pte) & PTE_UFFD_WP);
|
||||
}
|
||||
|
||||
static inline pte_t pte_mkuffd_wp(pte_t pte)
|
||||
{
|
||||
return pte_wrprotect(set_pte_bit(pte, __pgprot(PTE_UFFD_WP)));
|
||||
}
|
||||
|
||||
static inline pte_t pte_clear_uffd_wp(pte_t pte)
|
||||
{
|
||||
return clear_pte_bit(pte, __pgprot(PTE_UFFD_WP));
|
||||
}
|
||||
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
|
||||
|
||||
static inline void __set_pte_nosync(pte_t *ptep, pte_t pte)
|
||||
{
|
||||
WRITE_ONCE(*ptep, pte);
|
||||
@ -477,6 +494,23 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte)
|
||||
return clear_pte_bit(pte, __pgprot(PTE_SWP_EXCLUSIVE));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
|
||||
static inline pte_t pte_swp_mkuffd_wp(pte_t pte)
|
||||
{
|
||||
return set_pte_bit(pte, __pgprot(PTE_SWP_UFFD_WP));
|
||||
}
|
||||
|
||||
static inline int pte_swp_uffd_wp(pte_t pte)
|
||||
{
|
||||
return !!(pte_val(pte) & PTE_SWP_UFFD_WP);
|
||||
}
|
||||
|
||||
static inline pte_t pte_swp_clear_uffd_wp(pte_t pte)
|
||||
{
|
||||
return clear_pte_bit(pte, __pgprot(PTE_SWP_UFFD_WP));
|
||||
}
|
||||
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
|
||||
|
||||
#ifdef CONFIG_NUMA_BALANCING
|
||||
/*
|
||||
* See the comment in include/linux/pgtable.h
|
||||
@ -527,6 +561,15 @@ static inline int pmd_trans_huge(pmd_t pmd)
|
||||
#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))
|
||||
#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))
|
||||
#define pmd_mkinvalid(pmd) pte_pmd(pte_mkinvalid(pmd_pte(pmd)))
|
||||
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
|
||||
#define pmd_uffd_wp(pmd) pte_uffd_wp(pmd_pte(pmd))
|
||||
#define pmd_mkuffd_wp(pmd) pte_pmd(pte_mkuffd_wp(pmd_pte(pmd)))
|
||||
#define pmd_clear_uffd_wp(pmd) pte_pmd(pte_clear_uffd_wp(pmd_pte(pmd)))
|
||||
#define pmd_swp_uffd_wp(pmd) pte_swp_uffd_wp(pmd_pte(pmd))
|
||||
#define pmd_swp_mkuffd_wp(pmd) pte_pmd(pte_swp_mkuffd_wp(pmd_pte(pmd)))
|
||||
#define pmd_swp_clear_uffd_wp(pmd) \
|
||||
pte_pmd(pte_swp_clear_uffd_wp(pmd_pte(pmd)))
|
||||
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
|
||||
|
||||
#define pmd_thp_or_huge(pmd) (pmd_huge(pmd) || pmd_trans_huge(pmd))
|
||||
|
||||
@ -1261,6 +1304,7 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
|
||||
* Encode and decode a swap entry:
|
||||
* bits 0-1: present (must be zero)
|
||||
* bits 2: remember PG_anon_exclusive
|
||||
* bit 3: remember uffd-wp state
|
||||
* bits 6-10: swap type
|
||||
* bit 11: PTE_PRESENT_INVALID (must be zero)
|
||||
* bits 12-61: swap offset
|
||||
|
Loading…
Reference in New Issue
Block a user