mirror of
https://github.com/AsahiLinux/u-boot
synced 2025-03-13 21:36:57 +00:00
armv8: Add ARMv8 MPU configuration logic
Armv8r64 is the first Armv8 platform that only has a PMSA at the current exception level. The architecture supplement for Armv8r64 describes new fields in ID_AA64MMFR0_EL1 which can be used to detect whether a VMSA or PMSA is present. These fields are RES0 on Armv8a. Add logic to read these fields and, for the protection of the memory used by U-Boot, initialize the MPU instead of the MMU during init, then clear the MPU regions before transition to the next stage. Provide a default (blank) MPU memory map, which can be overridden by board configurations. Signed-off-by: Peter Hoyes <Peter.Hoyes@arm.com>
This commit is contained in:
parent
37a757e227
commit
2f5b7b7490
2 changed files with 154 additions and 3 deletions
|
@ -15,6 +15,7 @@
|
|||
#include <asm/global_data.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/armv8/mmu.h>
|
||||
#include <asm/armv8/mpu.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
|
@ -365,6 +366,86 @@ __weak u64 get_page_table_size(void)
|
|||
return size;
|
||||
}
|
||||
|
||||
static void mpu_clear_regions(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; mpu_mem_map[i].end || mpu_mem_map[i].attrs; i++) {
|
||||
setup_el2_mpu_region(i, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static struct mpu_region default_mpu_mem_map[] = {{0,}};
|
||||
__weak struct mpu_region *mpu_mem_map = default_mpu_mem_map;
|
||||
|
||||
static void mpu_setup(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (current_el() != 2) {
|
||||
panic("MPU configuration is only supported at EL2");
|
||||
}
|
||||
|
||||
set_sctlr(get_sctlr() & ~(CR_M | CR_WXN));
|
||||
|
||||
asm volatile("msr MAIR_EL2, %0" : : "r" MEMORY_ATTRIBUTES);
|
||||
|
||||
for (i = 0; mpu_mem_map[i].end || mpu_mem_map[i].attrs; i++) {
|
||||
setup_el2_mpu_region(i,
|
||||
PRBAR_ADDRESS(mpu_mem_map[i].start)
|
||||
| PRBAR_OUTER_SH | PRBAR_AP_RW_ANY,
|
||||
PRLAR_ADDRESS(mpu_mem_map[i].end)
|
||||
| mpu_mem_map[i].attrs | PRLAR_EN_BIT
|
||||
);
|
||||
}
|
||||
|
||||
set_sctlr(get_sctlr() | CR_M);
|
||||
}
|
||||
|
||||
static bool el_has_mmu(void)
|
||||
{
|
||||
uint64_t id_aa64mmfr0;
|
||||
asm volatile("mrs %0, id_aa64mmfr0_el1"
|
||||
: "=r" (id_aa64mmfr0) : : "cc");
|
||||
uint64_t msa = id_aa64mmfr0 & ID_AA64MMFR0_EL1_MSA_MASK;
|
||||
uint64_t msa_frac = id_aa64mmfr0 & ID_AA64MMFR0_EL1_MSA_FRAC_MASK;
|
||||
|
||||
switch (msa) {
|
||||
case ID_AA64MMFR0_EL1_MSA_VMSA:
|
||||
/*
|
||||
* VMSA supported in all translation regimes.
|
||||
* No support for PMSA.
|
||||
*/
|
||||
return true;
|
||||
case ID_AA64MMFR0_EL1_MSA_USE_FRAC:
|
||||
/* See MSA_frac for the supported MSAs. */
|
||||
switch (msa_frac) {
|
||||
case ID_AA64MMFR0_EL1_MSA_FRAC_NO_PMSA:
|
||||
/*
|
||||
* PMSA not supported in any translation
|
||||
* regime.
|
||||
*/
|
||||
return true;
|
||||
case ID_AA64MMFR0_EL1_MSA_FRAC_VMSA:
|
||||
/*
|
||||
* PMSA supported in all translation
|
||||
* regimes. No support for VMSA.
|
||||
*/
|
||||
case ID_AA64MMFR0_EL1_MSA_FRAC_PMSA:
|
||||
/*
|
||||
* PMSA supported in all translation
|
||||
* regimes.
|
||||
*/
|
||||
return false;
|
||||
default:
|
||||
panic("Unsupported id_aa64mmfr0_el1 " \
|
||||
"MSA_frac value");
|
||||
}
|
||||
default:
|
||||
panic("Unsupported id_aa64mmfr0_el1 MSA value");
|
||||
}
|
||||
}
|
||||
|
||||
void setup_pgtables(void)
|
||||
{
|
||||
int i;
|
||||
|
@ -479,8 +560,13 @@ void dcache_enable(void)
|
|||
/* The data cache is not active unless the mmu is enabled */
|
||||
if (!(get_sctlr() & CR_M)) {
|
||||
invalidate_dcache_all();
|
||||
__asm_invalidate_tlb_all();
|
||||
mmu_setup();
|
||||
|
||||
if (el_has_mmu()) {
|
||||
__asm_invalidate_tlb_all();
|
||||
mmu_setup();
|
||||
} else {
|
||||
mpu_setup();
|
||||
}
|
||||
}
|
||||
|
||||
set_sctlr(get_sctlr() | CR_C);
|
||||
|
@ -499,7 +585,11 @@ void dcache_disable(void)
|
|||
set_sctlr(sctlr & ~(CR_C|CR_M));
|
||||
|
||||
flush_dcache_all();
|
||||
__asm_invalidate_tlb_all();
|
||||
|
||||
if (el_has_mmu())
|
||||
__asm_invalidate_tlb_all();
|
||||
else
|
||||
mpu_clear_regions();
|
||||
}
|
||||
|
||||
int dcache_status(void)
|
||||
|
|
61
arch/arm/include/asm/armv8/mpu.h
Normal file
61
arch/arm/include/asm/armv8/mpu.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* (C) Copyright 2021 Arm Limited
|
||||
*/
|
||||
|
||||
#ifndef _ASM_ARMV8_MPU_H_
|
||||
#define _ASM_ARMV8_MPU_H_
|
||||
|
||||
#include <asm/armv8/mmu.h>
|
||||
#include <asm/barriers.h>
|
||||
#include <linux/stringify.h>
|
||||
|
||||
#define PRSELR_EL2 S3_4_c6_c2_1
|
||||
#define PRBAR_EL2 S3_4_c6_c8_0
|
||||
#define PRLAR_EL2 S3_4_c6_c8_1
|
||||
#define MPUIR_EL2 S3_4_c0_c0_4
|
||||
|
||||
#define PRBAR_ADDRESS(addr) ((addr) & ~(0x3fULL))
|
||||
|
||||
/* Access permissions */
|
||||
#define PRBAR_AP(val) (((val) & 0x3) << 2)
|
||||
#define PRBAR_AP_RW_HYP PRBAR_AP(0x0)
|
||||
#define PRBAR_AP_RW_ANY PRBAR_AP(0x1)
|
||||
#define PRBAR_AP_RO_HYP PRBAR_AP(0x2)
|
||||
#define PRBAR_AP_RO_ANY PRBAR_AP(0x3)
|
||||
|
||||
/* Shareability */
|
||||
#define PRBAR_SH(val) (((val) & 0x3) << 4)
|
||||
#define PRBAR_NON_SH PRBAR_SH(0x0)
|
||||
#define PRBAR_OUTER_SH PRBAR_SH(0x2)
|
||||
#define PRBAR_INNER_SH PRBAR_SH(0x3)
|
||||
|
||||
/* Memory attribute (MAIR idx) */
|
||||
#define PRLAR_ATTRIDX(val) (((val) & 0x7) << 1)
|
||||
#define PRLAR_EN_BIT (0x1)
|
||||
#define PRLAR_ADDRESS(addr) ((addr) & ~(0x3fULL))
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
static inline void setup_el2_mpu_region(uint8_t region, uint64_t base, uint64_t limit)
|
||||
{
|
||||
asm volatile("msr " __stringify(PRSELR_EL2) ", %0" : : "r" (region));
|
||||
isb();
|
||||
asm volatile("msr " __stringify(PRBAR_EL2) ", %0" : : "r" (base));
|
||||
asm volatile("msr " __stringify(PRLAR_EL2) ", %0" : : "r" (limit));
|
||||
dsb();
|
||||
isb();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct mpu_region {
|
||||
u64 start;
|
||||
u64 end;
|
||||
u64 attrs;
|
||||
};
|
||||
|
||||
extern struct mpu_region *mpu_mem_map;
|
||||
|
||||
#endif /* _ASM_ARMV8_MPU_H_ */
|
Loading…
Add table
Reference in a new issue