Skip to content

Commit 046835b

Browse files
murzinvRussell King
authored andcommitted
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: Vladimir Murzin <vladimir.murzin@arm.com> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
1 parent 3c24121 commit 046835b

File tree

9 files changed

+547
-4
lines changed

9 files changed

+547
-4
lines changed

arch/arm/include/asm/mpu.h

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
/* ID_MMFR0 data relevant to MPU */
1313
#define MMFR0_PMSA (0xF << 4)
1414
#define MMFR0_PMSAv7 (3 << 4)
15+
#define MMFR0_PMSAv8 (4 << 4)
1516

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

51+
#define PMSAv8_BAR_XN 1
52+
53+
#define PMSAv8_LAR_EN 1
54+
#define PMSAv8_LAR_IDX(n) (((n) & 0x7) << 1)
55+
56+
57+
#define PMSAv8_AP_PL1RW_PL0NA (0 << 1)
58+
#define PMSAv8_AP_PL1RW_PL0RW (1 << 1)
59+
#define PMSAv8_AP_PL1RO_PL0RO (3 << 1)
60+
61+
#ifdef CONFIG_SMP
62+
#define PMSAv8_RGN_SHARED (3 << 3) // inner sharable
63+
#else
64+
#define PMSAv8_RGN_SHARED (0 << 3)
65+
#endif
66+
67+
#define PMSAv8_RGN_DEVICE_nGnRnE 0
68+
#define PMSAv8_RGN_NORMAL 1
69+
70+
#define PMSAv8_MAIR(attr, mt) ((attr) << ((mt) * 8))
71+
72+
#ifdef CONFIG_CPU_V7M
73+
#define PMSAv8_MINALIGN 32
74+
#else
75+
#define PMSAv8_MINALIGN 64
76+
#endif
77+
5078
/* For minimal static MPU region configurations */
5179
#define PMSAv7_PROBE_REGION 0
5280
#define PMSAv7_BG_REGION 1
5381
#define PMSAv7_RAM_REGION 2
5482
#define PMSAv7_ROM_REGION 3
5583

84+
/* Fixed for PMSAv8 only */
85+
#define PMSAv8_XIP_REGION 0
86+
#define PMSAv8_KERNEL_REGION 1
87+
5688
/* Maximum number of regions Linux is interested in */
5789
#define MPU_MAX_REGIONS 16
5890

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

6496
struct mpu_rgn {
6597
/* Assume same attributes for d/i-side */
66-
u32 drbar;
67-
u32 drsr;
68-
u32 dracr;
98+
union {
99+
u32 drbar; /* PMSAv7 */
100+
u32 prbar; /* PMSAv8 */
101+
};
102+
union {
103+
u32 drsr; /* PMSAv7 */
104+
u32 prlar; /* PMSAv8 */
105+
};
106+
union {
107+
u32 dracr; /* PMSAv7 */
108+
u32 unused; /* not used in PMSAv8 */
109+
};
69110
};
70111

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

77118
#ifdef CONFIG_ARM_MPU
78119
extern void __init pmsav7_adjust_lowmem_bounds(void);
120+
extern void __init pmsav8_adjust_lowmem_bounds(void);
121+
79122
extern void __init pmsav7_setup(void);
123+
extern void __init pmsav8_setup(void);
80124
#else
81125
static inline void pmsav7_adjust_lowmem_bounds(void) {};
126+
static inline void pmsav8_adjust_lowmem_bounds(void) {};
82127
static inline void pmsav7_setup(void) {};
128+
static inline void pmsav8_setup(void) {};
83129
#endif
84130

85131
#endif /* __ASSEMBLY__ */

arch/arm/include/asm/v7m.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@
6868
#define PMSAv7_RBAR 0x9c
6969
#define PMSAv7_RASR 0xa0
7070

71+
#define PMSAv8_RNR 0x98
72+
#define PMSAv8_RBAR 0x9c
73+
#define PMSAv8_RLAR 0xa0
74+
#define PMSAv8_RBAR_A(n) (PMSAv8_RBAR + 8*(n))
75+
#define PMSAv8_RLAR_A(n) (PMSAv8_RLAR + 8*(n))
76+
#define PMSAv8_MAIR0 0xc0
77+
#define PMSAv8_MAIR1 0xc4
78+
7179
/* Cache opeartions */
7280
#define V7M_SCB_ICIALLU 0x250 /* I-cache invalidate all to PoU */
7381
#define V7M_SCB_ICIMVAU 0x258 /* I-cache invalidate by MVA to PoU */

arch/arm/kernel/asm-offsets.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ int main(void)
197197
DEFINE(MPU_RGN_DRBAR, offsetof(struct mpu_rgn, drbar));
198198
DEFINE(MPU_RGN_DRSR, offsetof(struct mpu_rgn, drsr));
199199
DEFINE(MPU_RGN_DRACR, offsetof(struct mpu_rgn, dracr));
200+
DEFINE(MPU_RGN_PRBAR, offsetof(struct mpu_rgn, prbar));
201+
DEFINE(MPU_RGN_PRLAR, offsetof(struct mpu_rgn, prlar));
200202
#endif
201203
return 0;
202204
}

arch/arm/kernel/head-nommu.S

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,25 @@ M_CLASS(ldr r3, [r12, 0x50])
132132
AR_CLASS(mrc p15, 0, r3, c0, c1, 4) @ Read ID_MMFR0
133133
and r3, r3, #(MMFR0_PMSA) @ PMSA field
134134
teq r3, #(MMFR0_PMSAv7) @ PMSA v7
135+
beq 1f
136+
teq r3, #(MMFR0_PMSAv8) @ PMSA v8
137+
/*
138+
* Memory region attributes for PMSAv8:
139+
*
140+
* n = AttrIndx[2:0]
141+
* n MAIR
142+
* DEVICE_nGnRnE 000 00000000
143+
* NORMAL 001 11111111
144+
*/
145+
ldreq r3, =PMSAv8_MAIR(0x00, PMSAv8_RGN_DEVICE_nGnRnE) | \
146+
PMSAv8_MAIR(0xff, PMSAv8_RGN_NORMAL)
147+
AR_CLASS(mcreq p15, 0, r3, c10, c2, 0) @ MAIR 0
148+
M_CLASS(streq r3, [r12, #PMSAv8_MAIR0])
149+
moveq r3, #0
150+
AR_CLASS(mcreq p15, 0, r3, c10, c2, 1) @ MAIR 1
151+
M_CLASS(streq r3, [r12, #PMSAv8_MAIR1])
152+
153+
1:
135154
#endif
136155
#ifdef CONFIG_CPU_CP15
137156
/*
@@ -235,6 +254,8 @@ M_CLASS(ldr r0, [r12, 0x50])
235254
and r0, r0, #(MMFR0_PMSA) @ PMSA field
236255
teq r0, #(MMFR0_PMSAv7) @ PMSA v7
237256
beq __setup_pmsa_v7
257+
teq r0, #(MMFR0_PMSAv8) @ PMSA v8
258+
beq __setup_pmsa_v8
238259

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

328+
ENTRY(__setup_pmsa_v8)
329+
mov r0, #0
330+
AR_CLASS(mcr p15, 0, r0, c6, c2, 1) @ PRSEL
331+
M_CLASS(str r0, [r12, #PMSAv8_RNR])
332+
isb
333+
334+
#ifdef CONFIG_XIP_KERNEL
335+
ldr r5, =CONFIG_XIP_PHYS_ADDR @ ROM start
336+
ldr r6, =(_exiprom) @ ROM end
337+
sub r6, r6, #1
338+
bic r6, r6, #(PMSAv8_MINALIGN - 1)
339+
340+
orr r5, r5, #(PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED)
341+
orr r6, r6, #(PMSAv8_LAR_IDX(PMSAv8_RGN_NORMAL) | PMSAv8_LAR_EN)
342+
343+
AR_CLASS(mcr p15, 0, r5, c6, c8, 0) @ PRBAR0
344+
AR_CLASS(mcr p15, 0, r6, c6, c8, 1) @ PRLAR0
345+
M_CLASS(str r5, [r12, #PMSAv8_RBAR_A(0)])
346+
M_CLASS(str r6, [r12, #PMSAv8_RLAR_A(0)])
347+
#endif
348+
349+
ldr r5, =KERNEL_START
350+
ldr r6, =KERNEL_END
351+
sub r6, r6, #1
352+
bic r6, r6, #(PMSAv8_MINALIGN - 1)
353+
354+
orr r5, r5, #(PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED)
355+
orr r6, r6, #(PMSAv8_LAR_IDX(PMSAv8_RGN_NORMAL) | PMSAv8_LAR_EN)
356+
357+
AR_CLASS(mcr p15, 0, r5, c6, c8, 4) @ PRBAR1
358+
AR_CLASS(mcr p15, 0, r6, c6, c8, 5) @ PRLAR1
359+
M_CLASS(str r5, [r12, #PMSAv8_RBAR_A(1)])
360+
M_CLASS(str r6, [r12, #PMSAv8_RLAR_A(1)])
361+
362+
/* Setup Background: 0x0 - min(KERNEL_START, XIP_PHYS_ADDR) */
363+
#ifdef CONFIG_XIP_KERNEL
364+
ldr r6, =KERNEL_START
365+
ldr r5, =CONFIG_XIP_PHYS_ADDR
366+
cmp r6, r5
367+
movcs r6, r5
368+
#else
369+
ldr r6, =KERNEL_START
370+
#endif
371+
cmp r6, #0
372+
beq 1f
373+
374+
mov r5, #0
375+
sub r6, r6, #1
376+
bic r6, r6, #(PMSAv8_MINALIGN - 1)
377+
378+
orr r5, r5, #(PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED | PMSAv8_BAR_XN)
379+
orr r6, r6, #(PMSAv8_LAR_IDX(PMSAv8_RGN_DEVICE_nGnRnE) | PMSAv8_LAR_EN)
380+
381+
AR_CLASS(mcr p15, 0, r5, c6, c9, 0) @ PRBAR2
382+
AR_CLASS(mcr p15, 0, r6, c6, c9, 1) @ PRLAR2
383+
M_CLASS(str r5, [r12, #PMSAv8_RBAR_A(2)])
384+
M_CLASS(str r6, [r12, #PMSAv8_RLAR_A(2)])
385+
386+
1:
387+
/* Setup Background: max(KERNEL_END, _exiprom) - 0xffffffff */
388+
#ifdef CONFIG_XIP_KERNEL
389+
ldr r5, =KERNEL_END
390+
ldr r6, =(_exiprom)
391+
cmp r5, r6
392+
movcc r5, r6
393+
#else
394+
ldr r5, =KERNEL_END
395+
#endif
396+
mov r6, #0xffffffff
397+
bic r6, r6, #(PMSAv8_MINALIGN - 1)
398+
399+
orr r5, r5, #(PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED | PMSAv8_BAR_XN)
400+
orr r6, r6, #(PMSAv8_LAR_IDX(PMSAv8_RGN_DEVICE_nGnRnE) | PMSAv8_LAR_EN)
401+
402+
AR_CLASS(mcr p15, 0, r5, c6, c9, 4) @ PRBAR3
403+
AR_CLASS(mcr p15, 0, r6, c6, c9, 5) @ PRLAR3
404+
M_CLASS(str r5, [r12, #PMSAv8_RBAR_A(3)])
405+
M_CLASS(str r6, [r12, #PMSAv8_RLAR_A(3)])
406+
407+
#ifdef CONFIG_XIP_KERNEL
408+
/* Setup Background: min(_exiprom, KERNEL_END) - max(KERNEL_START, XIP_PHYS_ADDR) */
409+
ldr r5, =(_exiprom)
410+
ldr r6, =KERNEL_END
411+
cmp r5, r6
412+
movcs r5, r6
413+
414+
ldr r6, =KERNEL_START
415+
ldr r0, =CONFIG_XIP_PHYS_ADDR
416+
cmp r6, r0
417+
movcc r6, r0
418+
419+
sub r6, r6, #1
420+
bic r6, r6, #(PMSAv8_MINALIGN - 1)
421+
422+
orr r5, r5, #(PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED | PMSAv8_BAR_XN)
423+
orr r6, r6, #(PMSAv8_LAR_IDX(PMSAv8_RGN_DEVICE_nGnRnE) | PMSAv8_LAR_EN)
424+
425+
#ifdef CONFIG_CPU_V7M
426+
/* There is no alias for n == 4 */
427+
mov r0, #4
428+
str r0, [r12, #PMSAv8_RNR] @ PRSEL
429+
isb
430+
431+
str r5, [r12, #PMSAv8_RBAR_A(0)]
432+
str r6, [r12, #PMSAv8_RLAR_A(0)]
433+
#else
434+
mcr p15, 0, r5, c6, c10, 1 @ PRBAR4
435+
mcr p15, 0, r6, c6, c10, 2 @ PRLAR4
436+
#endif
437+
#endif
438+
ret lr
439+
ENDPROC(__setup_pmsa_v8)
440+
307441
#ifdef CONFIG_SMP
308442
/*
309443
* r6: pointer at mpu_rgn_info
@@ -319,6 +453,8 @@ ENTRY(__secondary_setup_mpu)
319453
and r0, r0, #(MMFR0_PMSA) @ PMSA field
320454
teq r0, #(MMFR0_PMSAv7) @ PMSA v7
321455
beq __secondary_setup_pmsa_v7
456+
teq r0, #(MMFR0_PMSAv8) @ PMSA v8
457+
beq __secondary_setup_pmsa_v8
322458
b __error_p
323459
ENDPROC(__secondary_setup_mpu)
324460

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

500+
ENTRY(__secondary_setup_pmsa_v8)
501+
ldr r4, [r6, #MPU_RNG_INFO_USED]
502+
#ifndef CONFIG_XIP_KERNEL
503+
add r4, r4, #1
504+
#endif
505+
mov r5, #MPU_RNG_SIZE
506+
add r3, r6, #MPU_RNG_INFO_RNGS
507+
mla r3, r4, r5, r3
508+
509+
1:
510+
sub r3, r3, #MPU_RNG_SIZE
511+
sub r4, r4, #1
512+
513+
mcr p15, 0, r4, c6, c2, 1 @ PRSEL
514+
isb
515+
516+
ldr r5, [r3, #MPU_RGN_PRBAR]
517+
ldr r6, [r3, #MPU_RGN_PRLAR]
518+
519+
mcr p15, 0, r5, c6, c3, 0 @ PRBAR
520+
mcr p15, 0, r6, c6, c3, 1 @ PRLAR
521+
522+
cmp r4, #0
523+
bgt 1b
524+
525+
ret lr
526+
ENDPROC(__secondary_setup_pmsa_v8)
364527
#endif /* CONFIG_SMP */
365528
#endif /* CONFIG_ARM_MPU */
366529
#include "head-common.S"

arch/arm/kernel/vmlinux-xip.lds.S

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <asm/cache.h>
1414
#include <asm/thread_info.h>
1515
#include <asm/memory.h>
16+
#include <asm/mpu.h>
1617
#include <asm/page.h>
1718

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

150151
BSS_SECTION(0, 0, 8)
152+
#ifdef CONFIG_ARM_MPU
153+
. = ALIGN(PMSAv8_MINALIGN);
154+
#endif
151155
_end = .;
152156

153157
STABS_DEBUG

arch/arm/kernel/vmlinux.lds.S

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <asm/cache.h>
1313
#include <asm/thread_info.h>
1414
#include <asm/memory.h>
15+
#include <asm/mpu.h>
1516
#include <asm/page.h>
1617
#include <asm/pgtable.h>
1718

@@ -54,6 +55,9 @@ SECTIONS
5455
. = ALIGN(1<<SECTION_SHIFT);
5556
#endif
5657

58+
#ifdef CONFIG_ARM_MPU
59+
. = ALIGN(PMSAv8_MINALIGN);
60+
#endif
5761
.text : { /* Real text segment */
5862
_stext = .; /* Text and read-only data */
5963
ARM_TEXT
@@ -143,6 +147,9 @@ SECTIONS
143147
_edata = .;
144148

145149
BSS_SECTION(0, 0, 0)
150+
#ifdef CONFIG_ARM_MPU
151+
. = ALIGN(PMSAv8_MINALIGN);
152+
#endif
146153
_end = .;
147154

148155
STABS_DEBUG

arch/arm/mm/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ obj-$(CONFIG_MMU) += fault-armv.o flush.o idmap.o ioremap.o \
1010

1111
ifneq ($(CONFIG_MMU),y)
1212
obj-y += nommu.o
13-
obj-$(CONFIG_ARM_MPU) += pmsa-v7.o
13+
obj-$(CONFIG_ARM_MPU) += pmsa-v7.o pmsa-v8.o
1414
endif
1515

1616
obj-$(CONFIG_ARM_PTDUMP_CORE) += dump.o

arch/arm/mm/nommu.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ static void __init adjust_lowmem_bounds_mpu(void)
107107
case MMFR0_PMSAv7:
108108
pmsav7_adjust_lowmem_bounds();
109109
break;
110+
case MMFR0_PMSAv8:
111+
pmsav8_adjust_lowmem_bounds();
112+
break;
110113
default:
111114
break;
112115
}
@@ -120,6 +123,9 @@ static void __init mpu_setup(void)
120123
case MMFR0_PMSAv7:
121124
pmsav7_setup();
122125
break;
126+
case MMFR0_PMSAv8:
127+
pmsav8_setup();
128+
break;
123129
default:
124130
break;
125131
}

0 commit comments

Comments
 (0)