Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 046835b4 authored by Vladimir Murzin's avatar Vladimir Murzin Committed by Russell King
Browse files

ARM: 8757/1: NOMMU: Support PMSAv8 MPU



ARMv8R/M architecture defines new memory protection scheme - PMSAv8
which is not compatible with PMSAv7.

Key differences to PMSAv7 are:
 - Region geometry is defined by base and limit addresses
 - Addresses need to be either 32 or 64 byte aligned
 - No region priority due to overlapping regions are not allowed
 - It is unified, i.e. no distinction between data/instruction regions
 - Memory attributes are controlled via MAIR

This patch implements support for PMSAv8 MPU defined by ARMv8R/M
architecture.

Signed-off-by: default avatarVladimir Murzin <vladimir.murzin@arm.com>
Signed-off-by: default avatarRussell King <rmk+kernel@armlinux.org.uk>
parent 3c241210
Loading
Loading
Loading
Loading
+49 −3
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
/* ID_MMFR0 data relevant to MPU */
#define MMFR0_PMSA		(0xF << 4)
#define MMFR0_PMSAv7		(3 << 4)
#define MMFR0_PMSAv8		(4 << 4)

/* MPU D/I Size Register fields */
#define PMSAv7_RSR_SZ		1
@@ -47,12 +48,43 @@
#define PMSAv7_AP_PL1RW_PL0R0	(0x2 << 8)
#define PMSAv7_AP_PL1RW_PL0NA	(0x1 << 8)

#define PMSAv8_BAR_XN		1

#define PMSAv8_LAR_EN		1
#define PMSAv8_LAR_IDX(n)	(((n) & 0x7) << 1)


#define PMSAv8_AP_PL1RW_PL0NA	(0 << 1)
#define PMSAv8_AP_PL1RW_PL0RW	(1 << 1)
#define PMSAv8_AP_PL1RO_PL0RO	(3 << 1)

#ifdef CONFIG_SMP
#define PMSAv8_RGN_SHARED	(3 << 3) // inner sharable
#else
#define PMSAv8_RGN_SHARED	(0 << 3)
#endif

#define PMSAv8_RGN_DEVICE_nGnRnE	0
#define PMSAv8_RGN_NORMAL		1

#define PMSAv8_MAIR(attr, mt)	((attr) << ((mt) * 8))

#ifdef CONFIG_CPU_V7M
#define PMSAv8_MINALIGN		32
#else
#define PMSAv8_MINALIGN		64
#endif

/* For minimal static MPU region configurations */
#define PMSAv7_PROBE_REGION	0
#define PMSAv7_BG_REGION	1
#define PMSAv7_RAM_REGION	2
#define PMSAv7_ROM_REGION	3

/* Fixed for PMSAv8 only */
#define PMSAv8_XIP_REGION	0
#define PMSAv8_KERNEL_REGION	1

/* Maximum number of regions Linux is interested in */
#define MPU_MAX_REGIONS	16

@@ -63,9 +95,18 @@

struct mpu_rgn {
	/* Assume same attributes for d/i-side  */
	u32 drbar;
	u32 drsr;
	u32 dracr;
	union {
		u32 drbar;   /* PMSAv7 */
		u32 prbar;   /* PMSAv8 */
	};
	union {
		u32 drsr;   /* PMSAv7 */
		u32 prlar;  /* PMSAv8 */
	};
	union {
		u32 dracr;  /* PMSAv7 */
		u32 unused; /* not used in PMSAv8 */
	};
};

struct mpu_rgn_info {
@@ -76,10 +117,15 @@ extern struct mpu_rgn_info mpu_rgn_info;

#ifdef CONFIG_ARM_MPU
extern void __init pmsav7_adjust_lowmem_bounds(void);
extern void __init pmsav8_adjust_lowmem_bounds(void);

extern void __init pmsav7_setup(void);
extern void __init pmsav8_setup(void);
#else
static inline void pmsav7_adjust_lowmem_bounds(void) {};
static inline void pmsav8_adjust_lowmem_bounds(void) {};
static inline void pmsav7_setup(void) {};
static inline void pmsav8_setup(void) {};
#endif

#endif /* __ASSEMBLY__ */
+8 −0
Original line number Diff line number Diff line
@@ -68,6 +68,14 @@
#define PMSAv7_RBAR		0x9c
#define PMSAv7_RASR		0xa0

#define PMSAv8_RNR		0x98
#define PMSAv8_RBAR		0x9c
#define PMSAv8_RLAR		0xa0
#define PMSAv8_RBAR_A(n)	(PMSAv8_RBAR + 8*(n))
#define PMSAv8_RLAR_A(n)	(PMSAv8_RLAR + 8*(n))
#define PMSAv8_MAIR0		0xc0
#define PMSAv8_MAIR1		0xc4

/* Cache opeartions */
#define	V7M_SCB_ICIALLU		0x250	/* I-cache invalidate all to PoU */
#define	V7M_SCB_ICIMVAU		0x258	/* I-cache invalidate by MVA to PoU */
+2 −0
Original line number Diff line number Diff line
@@ -197,6 +197,8 @@ int main(void)
  DEFINE(MPU_RGN_DRBAR,	offsetof(struct mpu_rgn, drbar));
  DEFINE(MPU_RGN_DRSR,	offsetof(struct mpu_rgn, drsr));
  DEFINE(MPU_RGN_DRACR,	offsetof(struct mpu_rgn, dracr));
  DEFINE(MPU_RGN_PRBAR,	offsetof(struct mpu_rgn, prbar));
  DEFINE(MPU_RGN_PRLAR,	offsetof(struct mpu_rgn, prlar));
#endif
  return 0; 
}
+163 −0
Original line number Diff line number Diff line
@@ -132,6 +132,25 @@ M_CLASS(ldr r3, [r12, 0x50])
AR_CLASS(mrc	p15, 0, r3, c0, c1, 4)          @ Read ID_MMFR0
	and	r3, r3, #(MMFR0_PMSA)           @ PMSA field
	teq	r3, #(MMFR0_PMSAv7)             @ PMSA v7
	beq	1f
	teq	r3, #(MMFR0_PMSAv8)		@ PMSA v8
	/*
	 * Memory region attributes for PMSAv8:
	 *
	 *   n = AttrIndx[2:0]
	 *                      n       MAIR
	 *   DEVICE_nGnRnE      000     00000000
	 *   NORMAL             001     11111111
	 */
	ldreq	r3, =PMSAv8_MAIR(0x00, PMSAv8_RGN_DEVICE_nGnRnE) | \
		     PMSAv8_MAIR(0xff, PMSAv8_RGN_NORMAL)
AR_CLASS(mcreq	p15, 0, r3, c10, c2, 0)		@ MAIR 0
M_CLASS(streq	r3, [r12, #PMSAv8_MAIR0])
	moveq	r3, #0
AR_CLASS(mcreq	p15, 0, r3, c10, c2, 1)		@ MAIR 1
M_CLASS(streq	r3, [r12, #PMSAv8_MAIR1])

1:
#endif
#ifdef CONFIG_CPU_CP15
	/*
@@ -235,6 +254,8 @@ M_CLASS(ldr r0, [r12, 0x50])
	and	r0, r0, #(MMFR0_PMSA)		@ PMSA field
	teq	r0, #(MMFR0_PMSAv7)		@ PMSA v7
	beq	__setup_pmsa_v7
	teq	r0, #(MMFR0_PMSAv8)		@ PMSA v8
	beq	__setup_pmsa_v8

	ret	lr
ENDPROC(__setup_mpu)
@@ -304,6 +325,119 @@ M_CLASS(ldr r0, [r12, #MPU_TYPE])
	ret	lr
ENDPROC(__setup_pmsa_v7)

ENTRY(__setup_pmsa_v8)
	mov	r0, #0
AR_CLASS(mcr	p15, 0, r0, c6, c2, 1)		@ PRSEL
M_CLASS(str	r0, [r12, #PMSAv8_RNR])
	isb

#ifdef CONFIG_XIP_KERNEL
	ldr	r5, =CONFIG_XIP_PHYS_ADDR		@ ROM start
	ldr     r6, =(_exiprom)				@ ROM end
	sub	r6, r6, #1
	bic	r6, r6, #(PMSAv8_MINALIGN - 1)

	orr	r5, r5, #(PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED)
	orr	r6, r6, #(PMSAv8_LAR_IDX(PMSAv8_RGN_NORMAL) | PMSAv8_LAR_EN)

AR_CLASS(mcr	p15, 0, r5, c6, c8, 0)			@ PRBAR0
AR_CLASS(mcr	p15, 0, r6, c6, c8, 1)			@ PRLAR0
M_CLASS(str	r5, [r12, #PMSAv8_RBAR_A(0)])
M_CLASS(str	r6, [r12, #PMSAv8_RLAR_A(0)])
#endif

	ldr	r5, =KERNEL_START
	ldr	r6, =KERNEL_END
	sub	r6, r6, #1
	bic	r6, r6, #(PMSAv8_MINALIGN - 1)

	orr	r5, r5, #(PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED)
	orr	r6, r6, #(PMSAv8_LAR_IDX(PMSAv8_RGN_NORMAL) | PMSAv8_LAR_EN)

AR_CLASS(mcr	p15, 0, r5, c6, c8, 4)			@ PRBAR1
AR_CLASS(mcr	p15, 0, r6, c6, c8, 5)			@ PRLAR1
M_CLASS(str	r5, [r12, #PMSAv8_RBAR_A(1)])
M_CLASS(str	r6, [r12, #PMSAv8_RLAR_A(1)])

	/* Setup Background: 0x0 - min(KERNEL_START, XIP_PHYS_ADDR) */
#ifdef CONFIG_XIP_KERNEL
	ldr	r6, =KERNEL_START
	ldr	r5, =CONFIG_XIP_PHYS_ADDR
	cmp	r6, r5
	movcs	r6, r5
#else
	ldr	r6, =KERNEL_START
#endif
	cmp	r6, #0
	beq	1f

	mov	r5, #0
	sub	r6, r6, #1
	bic	r6, r6, #(PMSAv8_MINALIGN - 1)

	orr	r5, r5, #(PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED | PMSAv8_BAR_XN)
	orr	r6, r6, #(PMSAv8_LAR_IDX(PMSAv8_RGN_DEVICE_nGnRnE) | PMSAv8_LAR_EN)

AR_CLASS(mcr	p15, 0, r5, c6, c9, 0)			@ PRBAR2
AR_CLASS(mcr	p15, 0, r6, c6, c9, 1)			@ PRLAR2
M_CLASS(str	r5, [r12, #PMSAv8_RBAR_A(2)])
M_CLASS(str	r6, [r12, #PMSAv8_RLAR_A(2)])

1:
	/* Setup Background: max(KERNEL_END, _exiprom) - 0xffffffff */
#ifdef CONFIG_XIP_KERNEL
	ldr	r5, =KERNEL_END
	ldr	r6, =(_exiprom)
	cmp	r5, r6
	movcc	r5, r6
#else
	ldr	r5, =KERNEL_END
#endif
	mov	r6, #0xffffffff
	bic	r6, r6, #(PMSAv8_MINALIGN - 1)

	orr	r5, r5, #(PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED | PMSAv8_BAR_XN)
	orr	r6, r6, #(PMSAv8_LAR_IDX(PMSAv8_RGN_DEVICE_nGnRnE) | PMSAv8_LAR_EN)

AR_CLASS(mcr	p15, 0, r5, c6, c9, 4)			@ PRBAR3
AR_CLASS(mcr	p15, 0, r6, c6, c9, 5)			@ PRLAR3
M_CLASS(str	r5, [r12, #PMSAv8_RBAR_A(3)])
M_CLASS(str	r6, [r12, #PMSAv8_RLAR_A(3)])

#ifdef CONFIG_XIP_KERNEL
	/* Setup Background: min(_exiprom, KERNEL_END) - max(KERNEL_START, XIP_PHYS_ADDR) */
	ldr	r5, =(_exiprom)
	ldr	r6, =KERNEL_END
	cmp	r5, r6
	movcs	r5, r6

	ldr	r6, =KERNEL_START
	ldr	r0, =CONFIG_XIP_PHYS_ADDR
	cmp	r6, r0
	movcc	r6, r0

	sub	r6, r6, #1
	bic	r6, r6, #(PMSAv8_MINALIGN - 1)

	orr	r5, r5, #(PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED | PMSAv8_BAR_XN)
	orr	r6, r6, #(PMSAv8_LAR_IDX(PMSAv8_RGN_DEVICE_nGnRnE) | PMSAv8_LAR_EN)

#ifdef CONFIG_CPU_V7M
	/* There is no alias for n == 4 */
	mov	r0, #4
	str	r0, [r12, #PMSAv8_RNR]			@ PRSEL
	isb

	str	r5, [r12, #PMSAv8_RBAR_A(0)]
	str	r6, [r12, #PMSAv8_RLAR_A(0)]
#else
	mcr	p15, 0, r5, c6, c10, 1			@ PRBAR4
	mcr	p15, 0, r6, c6, c10, 2			@ PRLAR4
#endif
#endif
	ret	lr
ENDPROC(__setup_pmsa_v8)

#ifdef CONFIG_SMP
/*
 * r6: pointer at mpu_rgn_info
@@ -319,6 +453,8 @@ ENTRY(__secondary_setup_mpu)
	and	r0, r0, #(MMFR0_PMSA)		@ PMSA field
	teq	r0, #(MMFR0_PMSAv7)		@ PMSA v7
	beq	__secondary_setup_pmsa_v7
	teq	r0, #(MMFR0_PMSAv8)		@ PMSA v8
	beq	__secondary_setup_pmsa_v8
	b	__error_p
ENDPROC(__secondary_setup_mpu)

@@ -361,6 +497,33 @@ ENTRY(__secondary_setup_pmsa_v7)
	ret	lr
ENDPROC(__secondary_setup_pmsa_v7)

ENTRY(__secondary_setup_pmsa_v8)
	ldr	r4, [r6, #MPU_RNG_INFO_USED]
#ifndef CONFIG_XIP_KERNEL
	add	r4, r4, #1
#endif
	mov	r5, #MPU_RNG_SIZE
	add	r3, r6, #MPU_RNG_INFO_RNGS
	mla	r3, r4, r5, r3

1:
	sub	r3, r3, #MPU_RNG_SIZE
	sub	r4, r4, #1

	mcr	p15, 0, r4, c6, c2, 1		@ PRSEL
	isb

	ldr	r5, [r3, #MPU_RGN_PRBAR]
	ldr	r6, [r3, #MPU_RGN_PRLAR]

	mcr	p15, 0, r5, c6, c3, 0		@ PRBAR
	mcr	p15, 0, r6, c6, c3, 1           @ PRLAR

	cmp	r4, #0
	bgt	1b

	ret	lr
ENDPROC(__secondary_setup_pmsa_v8)
#endif /* CONFIG_SMP */
#endif /* CONFIG_ARM_MPU */
#include "head-common.S"
+4 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <asm/cache.h>
#include <asm/thread_info.h>
#include <asm/memory.h>
#include <asm/mpu.h>
#include <asm/page.h>

#include "vmlinux.lds.h"
@@ -148,6 +149,9 @@ SECTIONS
	__init_end = .;

	BSS_SECTION(0, 0, 8)
#ifdef CONFIG_ARM_MPU
	. = ALIGN(PMSAv8_MINALIGN);
#endif
	_end = .;

	STABS_DEBUG
Loading