diff --git a/xen/arch/arm/arch.mk b/xen/arch/arm/arch.mk index 022dcda192..9c4bedfb3b 100644 --- a/xen/arch/arm/arch.mk +++ b/xen/arch/arm/arch.mk @@ -9,7 +9,11 @@ CFLAGS-$(CONFIG_ARM_32) += -msoft-float CFLAGS-$(CONFIG_ARM_32) += -mcpu=cortex-a15 CFLAGS-$(CONFIG_ARM_32) += -mno-unaligned-access +ifeq ($(CONFIG_MPU),y) +CFLAGS-$(CONFIG_ARM_64) += -march=armv8-r +else CFLAGS-$(CONFIG_ARM_64) += -mcpu=generic +endif CFLAGS-$(CONFIG_ARM_64) += -mgeneral-regs-only # No fp registers etc $(call cc-option-add,CFLAGS-$(CONFIG_ARM_64),CC,-mno-outline-atomics) diff --git a/xen/arch/arm/arm64/mpu/Makefile b/xen/arch/arm/arm64/mpu/Makefile index b18cec4836..a8a750a3d0 100644 --- a/xen/arch/arm/arm64/mpu/Makefile +++ b/xen/arch/arm/arm64/mpu/Makefile @@ -1 +1,2 @@ +obj-y += head.o obj-y += mm.o diff --git a/xen/arch/arm/arm64/mpu/head.S b/xen/arch/arm/arm64/mpu/head.S new file mode 100644 index 0000000000..a06589566f --- /dev/null +++ b/xen/arch/arm/arm64/mpu/head.S @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Start-of-day code for an Armv8-R MPU system. + */ + +#include + +#define REGION_TEXT_PRBAR 0x38 /* SH=11 AP=10 XN=00 */ +#define REGION_RO_PRBAR 0x3A /* SH=11 AP=10 XN=10 */ +#define REGION_DATA_PRBAR 0x32 /* SH=11 AP=00 XN=10 */ + +#define REGION_NORMAL_PRLAR 0x0f /* NS=0 ATTR=111 EN=1 */ + +/* + * Macro to prepare and set a EL2 MPU memory region. + * We will also create an according MPU memory region entry, which + * is a structure of pr_t, in table \prmap. + * + * sel: region selector + * base: reg storing base address + * limit: reg storing limit address + * prbar: store computed PRBAR_EL2 value + * prlar: store computed PRLAR_EL2 value + * maxcount: maximum number of EL2 regions supported + * attr_prbar: PRBAR_EL2-related memory attributes. If not specified it will be + * REGION_DATA_PRBAR + * attr_prlar: PRLAR_EL2-related memory attributes. If not specified it will be + * REGION_NORMAL_PRLAR + * + * Preserves \maxcount + * Output: + * \sel: Next available region selector index. + * Clobbers \base, \limit, \prbar, \prlar + * + * Note that all parameters using registers should be distinct. + */ +.macro prepare_xen_region, sel, base, limit, prbar, prlar, maxcount, attr_prbar=REGION_DATA_PRBAR, attr_prlar=REGION_NORMAL_PRLAR + /* Check if the region is empty */ + cmp \base, \limit + beq 1f + + /* Check if the number of regions exceeded the count specified in MPUIR_EL2 */ + cmp \sel, \maxcount + bge fail_insufficient_regions + + /* Prepare value for PRBAR_EL2 reg and preserve it in \prbar.*/ + and \base, \base, #MPU_REGION_MASK + mov \prbar, #\attr_prbar + orr \prbar, \prbar, \base + + /* Limit address should be inclusive */ + sub \limit, \limit, #1 + and \limit, \limit, #MPU_REGION_MASK + mov \prlar, #\attr_prlar + orr \prlar, \prlar, \limit + + msr PRSELR_EL2, \sel + isb + msr PRBAR_EL2, \prbar + msr PRLAR_EL2, \prlar + dsb sy + isb + + add \sel, \sel, #1 + +1: +.endm + +/* + * Failure caused due to insufficient MPU regions. + */ +FUNC_LOCAL(fail_insufficient_regions) + PRINT("- Selected MPU region is above the implemented number in MPUIR_EL2 -\r\n") +1: wfe + b 1b +END(fail_insufficient_regions) + +/* + * Maps the various sections of Xen (described in xen.lds.S) as different MPU + * regions. + * + * Clobbers x0 - x5 + * + */ +FUNC(enable_boot_cpu_mm) + /* Get the number of regions specified in MPUIR_EL2 */ + mrs x5, MPUIR_EL2 + and x5, x5, #NUM_MPU_REGIONS_MASK + + /* x0: region sel */ + mov x0, xzr + /* Xen text section. */ + ldr x1, =_stext + ldr x2, =_etext + prepare_xen_region x0, x1, x2, x3, x4, x5, attr_prbar=REGION_TEXT_PRBAR + + /* Xen read-only data section. */ + ldr x1, =_srodata + ldr x2, =_erodata + prepare_xen_region x0, x1, x2, x3, x4, x5, attr_prbar=REGION_RO_PRBAR + + /* Xen read-only after init and data section. (RW data) */ + ldr x1, =__ro_after_init_start + ldr x2, =__init_begin + prepare_xen_region x0, x1, x2, x3, x4, x5 + + /* Xen code section. */ + ldr x1, =__init_begin + ldr x2, =__init_data_begin + prepare_xen_region x0, x1, x2, x3, x4, x5, attr_prbar=REGION_TEXT_PRBAR + + /* Xen data and BSS section. */ + ldr x1, =__init_data_begin + ldr x2, =__bss_end + prepare_xen_region x0, x1, x2, x3, x4, x5 + + ret +END(enable_boot_cpu_mm) + +/* + * Local variables: + * mode: ASM + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/include/asm/arm64/mpu.h b/xen/arch/arm/include/asm/arm64/mpu.h new file mode 100644 index 0000000000..f8a029f1a1 --- /dev/null +++ b/xen/arch/arm/include/asm/arm64/mpu.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * mpu.h: Arm Memory Protection Unit definitions. + */ + +#ifndef __ARM64_MPU_H__ +#define __ARM64_MPU_H__ + +#define MPU_REGION_SHIFT 6 +#define MPU_REGION_ALIGN (_AC(1, UL) << MPU_REGION_SHIFT) +#define MPU_REGION_MASK (~(MPU_REGION_ALIGN - 1)) + +#define NUM_MPU_REGIONS_SHIFT 8 +#define NUM_MPU_REGIONS (_AC(1, UL) << NUM_MPU_REGIONS_SHIFT) +#define NUM_MPU_REGIONS_MASK (NUM_MPU_REGIONS - 1) +#endif /* __ARM64_MPU_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/include/asm/mm.h b/xen/arch/arm/include/asm/mm.h index 5abd4b0d1c..59b774b7b8 100644 --- a/xen/arch/arm/include/asm/mm.h +++ b/xen/arch/arm/include/asm/mm.h @@ -16,7 +16,7 @@ #if defined(CONFIG_MMU) # include -#else +#elif !defined(CONFIG_MPU) # error "Unknown memory management layout" #endif diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S index d1e579e8a8..bbccff1a03 100644 --- a/xen/arch/arm/xen.lds.S +++ b/xen/arch/arm/xen.lds.S @@ -147,6 +147,7 @@ SECTIONS *(.altinstr_replacement) } :text . = ALIGN(PAGE_SIZE); + __init_data_begin = .; .init.data : { *(.init.rodata) *(.init.rodata.*)