Skip to content

Commit 2162183

Browse files
murzinvRussell King
authored andcommitted
ARM: 8713/1: NOMMU: Support MPU in XIP configuration
Currently, there is assumption in early MPU setup code that kernel image is located in RAM, which is obviously not true for XIP. To run code from ROM we need to make sure that it is covered by MPU. However, due to we allocate regions (semi-)dynamically we can run into issue of trimming region we are running from in case ROM spawns several MPU regions. To help deal with that we enforce minimum alignments for start end end of XIP address space as 1MB and 128Kb correspondingly. Tested-by: Alexandre TORGUE <[email protected]> Tested-by: Benjamin Gaignard <[email protected]> Signed-off-by: Vladimir Murzin <[email protected]> Signed-off-by: Russell King <[email protected]>
1 parent 5c9d9a1 commit 2162183

File tree

5 files changed

+90
-7
lines changed

5 files changed

+90
-7
lines changed

arch/arm/Kconfig-nommu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ config REMAP_VECTORS_TO_RAM
5252

5353
config ARM_MPU
5454
bool 'Use the ARM v7 PMSA Compliant MPU'
55-
depends on !XIP_KERNEL && (CPU_V7 || CPU_V7M)
55+
depends on CPU_V7 || CPU_V7M
5656
default y if CPU_V7
5757
help
5858
Some ARM systems without an MMU have instead a Memory Protection

arch/arm/include/asm/mpu.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#endif
4242

4343
/* Access permission bits of ACR (only define those that we use)*/
44+
#define MPU_AP_PL1RO_PL0NA (0x5 << 8)
4445
#define MPU_AP_PL1RW_PL0RW (0x3 << 8)
4546
#define MPU_AP_PL1RW_PL0R0 (0x2 << 8)
4647
#define MPU_AP_PL1RW_PL0NA (0x1 << 8)
@@ -49,7 +50,7 @@
4950
#define MPU_PROBE_REGION 0
5051
#define MPU_BG_REGION 1
5152
#define MPU_RAM_REGION 2
52-
#define MPU_VECTORS_REGION 3
53+
#define MPU_ROM_REGION 3
5354

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

arch/arm/kernel/head-nommu.S

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,26 @@ M_CLASS(ldr r0, [r12, #MPU_TYPE])
258258
setup_region r0, r5, r6, MPU_INSTR_SIDE r12 @ 0x0, BG region, enabled
259259
2: isb
260260

261+
#ifdef CONFIG_XIP_KERNEL
262+
set_region_nr r0, #MPU_ROM_REGION, r12
263+
isb
264+
265+
ldr r5,=(MPU_AP_PL1RO_PL0NA | MPU_RGN_NORMAL)
266+
267+
ldr r0, =CONFIG_XIP_PHYS_ADDR @ ROM start
268+
ldr r6, =(_exiprom) @ ROM end
269+
sub r6, r6, r0 @ Minimum size of region to map
270+
clz r6, r6 @ Region size must be 2^N...
271+
rsb r6, r6, #31 @ ...so round up region size
272+
lsl r6, r6, #MPU_RSR_SZ @ Put size in right field
273+
orr r6, r6, #(1 << MPU_RSR_EN) @ Set region enabled bit
274+
275+
setup_region r0, r5, r6, MPU_DATA_SIDE, r12 @ XIP_PHYS_ADDR, shared, enabled
276+
beq 3f @ Memory-map not unified
277+
setup_region r0, r5, r6, MPU_INSTR_SIDE, r12 @ XIP_PHYS_ADDR, shared, enabled
278+
3: isb
279+
#endif
280+
261281
/* Enable the MPU */
262282
AR_CLASS(mrc p15, 0, r0, c1, c0, 0) @ Read SCTLR
263283
AR_CLASS(bic r0, r0, #CR_BR) @ Disable the 'default mem-map'

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
/* No __ro_after_init data in the .rodata section - which will always be ro */
77
#define RO_AFTER_INIT_DATA
88

9+
#include <linux/sizes.h>
10+
911
#include <asm-generic/vmlinux.lds.h>
1012
#include <asm/cache.h>
1113
#include <asm/thread_info.h>
@@ -187,6 +189,9 @@ SECTIONS
187189
INIT_RAM_FS
188190
}
189191

192+
#ifdef CONFIG_ARM_MPU
193+
. = ALIGN(SZ_128K);
194+
#endif
190195
_exiprom = .; /* End of XIP ROM area */
191196

192197
/*
@@ -314,3 +319,21 @@ ASSERT(__hyp_idmap_text_end - (__hyp_idmap_text_start & PAGE_MASK) <= PAGE_SIZE,
314319
*/
315320
ASSERT((_end - __bss_start) >= 12288, ".bss too small for CONFIG_XIP_DEFLATED_DATA")
316321
#endif
322+
323+
#ifdef CONFIG_ARM_MPU
324+
/*
325+
* Due to PMSAv7 restriction on base address and size we have to
326+
* enforce minimal alignment restrictions. It was seen that weaker
327+
* alignment restriction on _xiprom will likely force XIP address
328+
* space spawns multiple MPU regions thus it is likely we run in
329+
* situation when we are reprogramming MPU region we run on with
330+
* something which doesn't cover reprogramming code itself, so as soon
331+
* as we update MPU settings we'd immediately try to execute straight
332+
* from background region which is XN.
333+
* It seem that alignment in 1M should suit most users.
334+
* _exiprom is aligned as 1/8 of 1M so can be covered by subregion
335+
* disable
336+
*/
337+
ASSERT(!(_xiprom & (SZ_1M - 1)), "XIP start address may cause MPU programming issues")
338+
ASSERT(!(_exiprom & (SZ_128K - 1)), "XIP end address may cause MPU programming issues")
339+
#endif

arch/arm/mm/pmsa-v7.c

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
#include <linux/bitops.h>
88
#include <linux/memblock.h>
99

10+
#include <asm/cacheflush.h>
1011
#include <asm/cp15.h>
1112
#include <asm/cputype.h>
1213
#include <asm/mpu.h>
14+
#include <asm/sections.h>
1315

1416
#include "mm.h"
1517

@@ -20,6 +22,9 @@ struct region {
2022
};
2123

2224
static struct region __initdata mem[MPU_MAX_REGIONS];
25+
#ifdef CONFIG_XIP_KERNEL
26+
static struct region __initdata xip[MPU_MAX_REGIONS];
27+
#endif
2328

2429
static unsigned int __initdata mpu_min_region_order;
2530
static unsigned int __initdata mpu_max_regions;
@@ -229,7 +234,6 @@ static int __init allocate_region(phys_addr_t base, phys_addr_t size,
229234
/* MPU initialisation functions */
230235
void __init adjust_lowmem_bounds_mpu(void)
231236
{
232-
phys_addr_t phys_offset = PHYS_OFFSET;
233237
phys_addr_t specified_mem_size, total_mem_size = 0;
234238
struct memblock_region *reg;
235239
bool first = true;
@@ -256,8 +260,19 @@ void __init adjust_lowmem_bounds_mpu(void)
256260
/* ... and one for vectors */
257261
mem_max_regions--;
258262
#endif
263+
264+
#ifdef CONFIG_XIP_KERNEL
265+
/* plus some regions to cover XIP ROM */
266+
num = allocate_region(CONFIG_XIP_PHYS_ADDR, __pa(_exiprom) - CONFIG_XIP_PHYS_ADDR,
267+
mem_max_regions, xip);
268+
269+
mem_max_regions -= num;
270+
#endif
271+
259272
for_each_memblock(memory, reg) {
260273
if (first) {
274+
phys_addr_t phys_offset = PHYS_OFFSET;
275+
261276
/*
262277
* Initially only use memory continuous from
263278
* PHYS_OFFSET */
@@ -355,7 +370,7 @@ static int __init __mpu_min_region_order(void)
355370

356371
static int __init mpu_setup_region(unsigned int number, phys_addr_t start,
357372
unsigned int size_order, unsigned int properties,
358-
unsigned int subregions)
373+
unsigned int subregions, bool need_flush)
359374
{
360375
u32 size_data;
361376

@@ -374,6 +389,9 @@ static int __init mpu_setup_region(unsigned int number, phys_addr_t start,
374389
size_data = ((size_order - 1) << MPU_RSR_SZ) | 1 << MPU_RSR_EN;
375390
size_data |= subregions << MPU_RSR_SD;
376391

392+
if (need_flush)
393+
flush_cache_all();
394+
377395
dsb(); /* Ensure all previous data accesses occur with old mappings */
378396
rgnr_write(number);
379397
isb();
@@ -416,7 +434,28 @@ void __init mpu_setup(void)
416434
/* Background */
417435
err |= mpu_setup_region(region++, 0, 32,
418436
MPU_ACR_XN | MPU_RGN_STRONGLY_ORDERED | MPU_AP_PL1RW_PL0NA,
419-
0);
437+
0, false);
438+
439+
#ifdef CONFIG_XIP_KERNEL
440+
/* ROM */
441+
for (i = 0; i < ARRAY_SIZE(xip); i++) {
442+
/*
443+
* In case we overwrite RAM region we set earlier in
444+
* head-nommu.S (which is cachable) all subsequent
445+
* data access till we setup RAM bellow would be done
446+
* with BG region (which is uncachable), thus we need
447+
* to clean and invalidate cache.
448+
*/
449+
bool need_flush = region == MPU_RAM_REGION;
450+
451+
if (!xip[i].size)
452+
continue;
453+
454+
err |= mpu_setup_region(region++, xip[i].base, ilog2(xip[i].size),
455+
MPU_AP_PL1RO_PL0NA | MPU_RGN_NORMAL,
456+
xip[i].subreg, need_flush);
457+
}
458+
#endif
420459

421460
/* RAM */
422461
for (i = 0; i < ARRAY_SIZE(mem); i++) {
@@ -425,14 +464,14 @@ void __init mpu_setup(void)
425464

426465
err |= mpu_setup_region(region++, mem[i].base, ilog2(mem[i].size),
427466
MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL,
428-
mem[i].subreg);
467+
mem[i].subreg, false);
429468
}
430469

431470
/* Vectors */
432471
#ifndef CONFIG_CPU_V7M
433472
err |= mpu_setup_region(region++, vectors_base, ilog2(2 * PAGE_SIZE),
434473
MPU_AP_PL1RW_PL0NA | MPU_RGN_NORMAL,
435-
0);
474+
0, false);
436475
#endif
437476
if (err) {
438477
panic("MPU region initialization failure! %d", err);

0 commit comments

Comments
 (0)