cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pmsa-v8.c (6837B)


      1/*
      2 * Based on linux/arch/arm/pmsa-v7.c
      3 *
      4 * ARM PMSAv8 supporting functions.
      5 */
      6
      7#include <linux/memblock.h>
      8#include <linux/range.h>
      9
     10#include <asm/cp15.h>
     11#include <asm/cputype.h>
     12#include <asm/mpu.h>
     13
     14#include <asm/memory.h>
     15#include <asm/sections.h>
     16
     17#include "mm.h"
     18
     19#ifndef CONFIG_CPU_V7M
     20
     21#define PRSEL	__ACCESS_CP15(c6, 0, c2, 1)
     22#define PRBAR	__ACCESS_CP15(c6, 0, c3, 0)
     23#define PRLAR	__ACCESS_CP15(c6, 0, c3, 1)
     24
     25static inline u32 prlar_read(void)
     26{
     27	return read_sysreg(PRLAR);
     28}
     29
     30static inline u32 prbar_read(void)
     31{
     32	return read_sysreg(PRBAR);
     33}
     34
     35static inline void prsel_write(u32 v)
     36{
     37	write_sysreg(v, PRSEL);
     38}
     39
     40static inline void prbar_write(u32 v)
     41{
     42	write_sysreg(v, PRBAR);
     43}
     44
     45static inline void prlar_write(u32 v)
     46{
     47	write_sysreg(v, PRLAR);
     48}
     49#else
     50
     51static inline u32 prlar_read(void)
     52{
     53	return readl_relaxed(BASEADDR_V7M_SCB + PMSAv8_RLAR);
     54}
     55
     56static inline u32 prbar_read(void)
     57{
     58	return readl_relaxed(BASEADDR_V7M_SCB + PMSAv8_RBAR);
     59}
     60
     61static inline void prsel_write(u32 v)
     62{
     63	writel_relaxed(v, BASEADDR_V7M_SCB + PMSAv8_RNR);
     64}
     65
     66static inline void prbar_write(u32 v)
     67{
     68	writel_relaxed(v, BASEADDR_V7M_SCB + PMSAv8_RBAR);
     69}
     70
     71static inline void prlar_write(u32 v)
     72{
     73	writel_relaxed(v, BASEADDR_V7M_SCB + PMSAv8_RLAR);
     74}
     75
     76#endif
     77
     78static struct range __initdata io[MPU_MAX_REGIONS];
     79static struct range __initdata mem[MPU_MAX_REGIONS];
     80
     81static unsigned int __initdata mpu_max_regions;
     82
     83static __init bool is_region_fixed(int number)
     84{
     85	switch (number) {
     86	case PMSAv8_XIP_REGION:
     87	case PMSAv8_KERNEL_REGION:
     88		return true;
     89	default:
     90		return false;
     91	}
     92}
     93
     94void __init pmsav8_adjust_lowmem_bounds(void)
     95{
     96	phys_addr_t mem_end;
     97	phys_addr_t reg_start, reg_end;
     98	bool first = true;
     99	u64 i;
    100
    101	for_each_mem_range(i, &reg_start, &reg_end) {
    102		if (first) {
    103			phys_addr_t phys_offset = PHYS_OFFSET;
    104
    105			/*
    106			 * Initially only use memory continuous from
    107			 * PHYS_OFFSET */
    108			if (reg_start != phys_offset)
    109				panic("First memory bank must be contiguous from PHYS_OFFSET");
    110			mem_end = reg_end;
    111			first = false;
    112		} else {
    113			/*
    114			 * memblock auto merges contiguous blocks, remove
    115			 * all blocks afterwards in one go (we can't remove
    116			 * blocks separately while iterating)
    117			 */
    118			pr_notice("Ignoring RAM after %pa, memory at %pa ignored\n",
    119				  &mem_end, &reg_start);
    120			memblock_remove(reg_start, 0 - reg_start);
    121			break;
    122		}
    123	}
    124}
    125
    126static int __init __mpu_max_regions(void)
    127{
    128	static int max_regions;
    129	u32 mpuir;
    130
    131	if (max_regions)
    132		return max_regions;
    133
    134	mpuir = read_cpuid_mputype();
    135
    136	max_regions  = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION;
    137
    138	return max_regions;
    139}
    140
    141static int __init __pmsav8_setup_region(unsigned int number, u32 bar, u32 lar)
    142{
    143	if (number > mpu_max_regions
    144	    || number >= MPU_MAX_REGIONS)
    145		return -ENOENT;
    146
    147	dsb();
    148	prsel_write(number);
    149	isb();
    150	prbar_write(bar);
    151	prlar_write(lar);
    152
    153	mpu_rgn_info.rgns[number].prbar = bar;
    154	mpu_rgn_info.rgns[number].prlar = lar;
    155
    156	mpu_rgn_info.used++;
    157
    158	return 0;
    159}
    160
    161static int __init pmsav8_setup_ram(unsigned int number, phys_addr_t start,phys_addr_t end)
    162{
    163	u32 bar, lar;
    164
    165	if (is_region_fixed(number))
    166		return -EINVAL;
    167
    168	bar = start;
    169	lar = (end - 1) & ~(PMSAv8_MINALIGN - 1);
    170
    171	bar |= PMSAv8_AP_PL1RW_PL0RW | PMSAv8_RGN_SHARED;
    172	lar |= PMSAv8_LAR_IDX(PMSAv8_RGN_NORMAL) | PMSAv8_LAR_EN;
    173
    174	return __pmsav8_setup_region(number, bar, lar);
    175}
    176
    177static int __init pmsav8_setup_io(unsigned int number, phys_addr_t start,phys_addr_t end)
    178{
    179	u32 bar, lar;
    180
    181	if (is_region_fixed(number))
    182		return -EINVAL;
    183
    184	bar = start;
    185	lar = (end - 1) & ~(PMSAv8_MINALIGN - 1);
    186
    187	bar |= PMSAv8_AP_PL1RW_PL0RW | PMSAv8_RGN_SHARED | PMSAv8_BAR_XN;
    188	lar |= PMSAv8_LAR_IDX(PMSAv8_RGN_DEVICE_nGnRnE) | PMSAv8_LAR_EN;
    189
    190	return __pmsav8_setup_region(number, bar, lar);
    191}
    192
    193static int __init pmsav8_setup_fixed(unsigned int number, phys_addr_t start,phys_addr_t end)
    194{
    195	u32 bar, lar;
    196
    197	if (!is_region_fixed(number))
    198		return -EINVAL;
    199
    200	bar = start;
    201	lar = (end - 1) & ~(PMSAv8_MINALIGN - 1);
    202
    203	bar |= PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED;
    204	lar |= PMSAv8_LAR_IDX(PMSAv8_RGN_NORMAL) | PMSAv8_LAR_EN;
    205
    206	prsel_write(number);
    207	isb();
    208
    209	if (prbar_read() != bar || prlar_read() != lar)
    210		return -EINVAL;
    211
    212	/* Reserved region was set up early, we just need a record for secondaries */
    213	mpu_rgn_info.rgns[number].prbar = bar;
    214	mpu_rgn_info.rgns[number].prlar = lar;
    215
    216	mpu_rgn_info.used++;
    217
    218	return 0;
    219}
    220
    221#ifndef CONFIG_CPU_V7M
    222static int __init pmsav8_setup_vector(unsigned int number, phys_addr_t start,phys_addr_t end)
    223{
    224	u32 bar, lar;
    225
    226	if (number == PMSAv8_KERNEL_REGION)
    227		return -EINVAL;
    228
    229	bar = start;
    230	lar = (end - 1) & ~(PMSAv8_MINALIGN - 1);
    231
    232	bar |= PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED;
    233	lar |= PMSAv8_LAR_IDX(PMSAv8_RGN_NORMAL) | PMSAv8_LAR_EN;
    234
    235	return __pmsav8_setup_region(number, bar, lar);
    236}
    237#endif
    238
    239void __init pmsav8_setup(void)
    240{
    241	int i, err = 0;
    242	int region = PMSAv8_KERNEL_REGION;
    243
    244	/* How many regions are supported ? */
    245	mpu_max_regions = __mpu_max_regions();
    246
    247	/* RAM: single chunk of memory */
    248	add_range(mem,  ARRAY_SIZE(mem), 0,  memblock.memory.regions[0].base,
    249		  memblock.memory.regions[0].base + memblock.memory.regions[0].size);
    250
    251	/* IO: cover full 4G range */
    252	add_range(io, ARRAY_SIZE(io), 0, 0, 0xffffffff);
    253
    254	/* RAM and IO: exclude kernel */
    255	subtract_range(mem, ARRAY_SIZE(mem), __pa(KERNEL_START), __pa(KERNEL_END));
    256	subtract_range(io, ARRAY_SIZE(io),  __pa(KERNEL_START), __pa(KERNEL_END));
    257
    258#ifdef CONFIG_XIP_KERNEL
    259	/* RAM and IO: exclude xip */
    260	subtract_range(mem, ARRAY_SIZE(mem), CONFIG_XIP_PHYS_ADDR, __pa(_exiprom));
    261	subtract_range(io, ARRAY_SIZE(io), CONFIG_XIP_PHYS_ADDR, __pa(_exiprom));
    262#endif
    263
    264#ifndef CONFIG_CPU_V7M
    265	/* RAM and IO: exclude vectors */
    266	subtract_range(mem, ARRAY_SIZE(mem),  vectors_base, vectors_base + 2 * PAGE_SIZE);
    267	subtract_range(io, ARRAY_SIZE(io),  vectors_base, vectors_base + 2 * PAGE_SIZE);
    268#endif
    269	/* IO: exclude RAM */
    270	for (i = 0; i < ARRAY_SIZE(mem); i++)
    271		subtract_range(io, ARRAY_SIZE(io), mem[i].start, mem[i].end);
    272
    273	/* Now program MPU */
    274
    275#ifdef CONFIG_XIP_KERNEL
    276	/* ROM */
    277	err |= pmsav8_setup_fixed(PMSAv8_XIP_REGION, CONFIG_XIP_PHYS_ADDR, __pa(_exiprom));
    278#endif
    279	/* Kernel */
    280	err |= pmsav8_setup_fixed(region++, __pa(KERNEL_START), __pa(KERNEL_END));
    281
    282
    283	/* IO */
    284	for (i = 0; i < ARRAY_SIZE(io); i++) {
    285		if (!io[i].end)
    286			continue;
    287
    288		err |= pmsav8_setup_io(region++, io[i].start, io[i].end);
    289	}
    290
    291	/* RAM */
    292	for (i = 0; i < ARRAY_SIZE(mem); i++) {
    293		if (!mem[i].end)
    294			continue;
    295
    296		err |= pmsav8_setup_ram(region++, mem[i].start, mem[i].end);
    297	}
    298
    299	/* Vectors */
    300#ifndef CONFIG_CPU_V7M
    301	err |= pmsav8_setup_vector(region++, vectors_base, vectors_base + 2 * PAGE_SIZE);
    302#endif
    303	if (err)
    304		pr_warn("MPU region initialization failure! %d", err);
    305	else
    306		pr_info("Using ARM PMSAv8 Compliant MPU. Used %d of %d regions\n",
    307			mpu_rgn_info.used, mpu_max_regions);
    308}