[PATCH v1] arm: Support for the PXN CPU feature on ARMv7
Catalin Marinas
catalin.marinas at arm.com
Mon Nov 24 07:06:53 PST 2014
On Sat, Nov 22, 2014 at 10:42:36AM +0000, Jungseung Lee wrote:
> diff --git a/arch/arm/include/asm/pgalloc.h b/arch/arm/include/asm/pgalloc.h
> index 78a7793..e63c633 100644
> --- a/arch/arm/include/asm/pgalloc.h
> +++ b/arch/arm/include/asm/pgalloc.h
> @@ -17,6 +17,7 @@
> #include <asm/processor.h>
> #include <asm/cacheflush.h>
> #include <asm/tlbflush.h>
> +#include <asm/cputype.h>
>
> #define check_pgt_cache() do { } while (0)
>
> @@ -25,6 +26,19 @@
> #define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_USER))
> #define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_KERNEL))
>
> +static inline bool cpu_has_classic_pxn(void)
> +{
> +#ifdef CONFIG_CPU_V7
I don't think shouldn't trigger this when LPAE is enabled.
> + unsigned int vmsa;
> +
> + /* LPAE implies atomic ldrd/strd instructions */
How is this comment relevant? Copy/paste?
> + vmsa = (read_cpuid_ext(CPUID_EXT_MMFR0) & 0xf) >> 0;
> + if (vmsa == 4)
> + return 1;
> +#endif
> + return 0;
> +}
In general we put the #ifdef outside the function:
#if __LINUX_ARM_ARCH__ >= 7 && !defined(CONFIG_ARM_LPAE)
static inline bool cpu_has_classic_pxn(void)
{
unsigned int vmsa = (read_cpuid_ext(CPUID_EXT_MMFR0) & 0xf) >> 0;
return vmsa == 4;
}
#else
static inline bool cpu_has_classic_pxn(void)
{
return false;
}
#endif
I used __LINUX_ARM_ARCH__ instead of CONFIG_CPU_V7 to cope with kernel
images built for both v6 and v7. You could also check for
cpu_architecture() >= 7, though with a bit of performance impact.
> static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
> @@ -157,7 +171,11 @@ pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
> static inline void
> pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep)
> {
> - __pmd_populate(pmdp, page_to_phys(ptep), _PAGE_USER_TABLE);
> + if (cpu_has_classic_pxn())
> + __pmd_populate(pmdp, page_to_phys(ptep),
> + _PAGE_USER_TABLE | PMD_PXNTABLE);
> + else
> + __pmd_populate(pmdp, page_to_phys(ptep), _PAGE_USER_TABLE);
> }
Nitpick (personal preference):
pmdval_t pmdval = _PAGE_USER_TABLE;
if (cpu_has_classic_pxn())
pmdval |= PMD_PXNTABLE;
__pmd_populate(pmdp, page_to_phys(ptep), pmdval);
> #define pmd_pgtable(pmd) pmd_page(pmd)
>
> diff --git a/arch/arm/include/asm/pgtable-2level-hwdef.h b/arch/arm/include/asm/pgtable-2level-hwdef.h
> index 5cfba15..5e68278 100644
> --- a/arch/arm/include/asm/pgtable-2level-hwdef.h
> +++ b/arch/arm/include/asm/pgtable-2level-hwdef.h
> @@ -20,12 +20,14 @@
> #define PMD_TYPE_FAULT (_AT(pmdval_t, 0) << 0)
> #define PMD_TYPE_TABLE (_AT(pmdval_t, 1) << 0)
> #define PMD_TYPE_SECT (_AT(pmdval_t, 2) << 0)
> +#define PMD_PXNTABLE (_AT(pmdval_t, 1) << 2) /* v7 */
> #define PMD_BIT4 (_AT(pmdval_t, 1) << 4)
> #define PMD_DOMAIN(x) (_AT(pmdval_t, (x)) << 5)
> #define PMD_PROTECTION (_AT(pmdval_t, 1) << 9) /* v5 */
> /*
> * - section
> */
> +#define PMD_SECT_PXN (_AT(pmdval_t, 1) << 0) /* v7 */
> #define PMD_SECT_BUFFERABLE (_AT(pmdval_t, 1) << 2)
> #define PMD_SECT_CACHEABLE (_AT(pmdval_t, 1) << 3)
> #define PMD_SECT_XN (_AT(pmdval_t, 1) << 4) /* v6 */
> diff --git a/arch/arm/include/asm/pgtable-3level-hwdef.h b/arch/arm/include/asm/pgtable-3level-hwdef.h
> index 9fd61c7..f8f1cff 100644
> --- a/arch/arm/include/asm/pgtable-3level-hwdef.h
> +++ b/arch/arm/include/asm/pgtable-3level-hwdef.h
> @@ -76,6 +76,7 @@
> #define PTE_EXT_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */
> #define PTE_EXT_AF (_AT(pteval_t, 1) << 10) /* Access Flag */
> #define PTE_EXT_NG (_AT(pteval_t, 1) << 11) /* nG */
> +#define PTE_EXT_PXN (_AT(pteval_t, 1) << 53) /* PXN */
> #define PTE_EXT_XN (_AT(pteval_t, 1) << 54) /* XN */
>
> /*
> diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
> index 3b30062..04db03c 100644
> --- a/arch/arm/include/asm/pgtable.h
> +++ b/arch/arm/include/asm/pgtable.h
> @@ -247,6 +247,9 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
> if (!pte_special(pteval))
> __sync_icache_dcache(pteval);
> ext |= PTE_EXT_NG;
> +#ifdef CONFIG_ARM_LPAE
> + ext |= PTE_EXT_PXN;
> +#endif
I think you can avoid touching set_pte_at() and instead:
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 9f98cec7fe1e..5b0a0472e689 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -605,6 +605,11 @@ static void __init build_mem_type_table(void)
}
kern_pgprot |= PTE_EXT_AF;
vecs_pgprot |= PTE_EXT_AF;
+
+ /*
+ * Set PXN for user mappings
+ */
+ user_pgprot |= PTE_EXT_PXN;
#endif
for (i = 0; i < 16; i++) {
--
Catalin
More information about the linux-arm-kernel
mailing list