diff --git a/xen/arch/arm/arm64/asm-offsets.c b/xen/arch/arm/arm64/asm-offsets.c index 602ffa5b54..320289b281 100644 --- a/xen/arch/arm/arm64/asm-offsets.c +++ b/xen/arch/arm/arm64/asm-offsets.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -68,6 +69,12 @@ void __dummy__(void) OFFSET(ARM_SMCCC_1_2_REGS_X14_OFFS, struct arm_smccc_1_2_regs, a14); OFFSET(ARM_SMCCC_1_2_REGS_X16_OFFS, struct arm_smccc_1_2_regs, a16); BLANK(); + +#ifdef CONFIG_MPU + DEFINE(XEN_MPUMAP_MASK_sizeof, sizeof(xen_mpumap_mask)); + DEFINE(XEN_MPUMAP_sizeof, sizeof(xen_mpumap)); + BLANK(); +#endif } /* diff --git a/xen/arch/arm/arm64/cache.S b/xen/arch/arm/arm64/cache.S index c0a8ca163a..d3c13d98cc 100644 --- a/xen/arch/arm/arm64/cache.S +++ b/xen/arch/arm/arm64/cache.S @@ -50,3 +50,24 @@ FUNC(__flush_dcache_area) dsb sy ret END(__flush_dcache_area) + +/* + * __invalidate_dcache_area(addr, size) + * + * Ensure that the data held in the cache for the buffer is invalidated. + * + * - addr - start address of the buffer + * - size - size of the buffer + */ +FUNC(__invalidate_dcache_area) + dcache_line_size x2, x3 + add x1, x0, x1 + sub x3, x2, #1 + bic x0, x0, x3 +1: dc ivac, x0 /* invalidate D line / unified line */ + add x0, x0, x2 + cmp x0, x1 + b.lo 1b + dsb sy + ret +END(__invalidate_dcache_area) diff --git a/xen/arch/arm/arm64/mpu/head.S b/xen/arch/arm/arm64/mpu/head.S index 6d336cafbb..5df0af571e 100644 --- a/xen/arch/arm/arm64/mpu/head.S +++ b/xen/arch/arm/arm64/mpu/head.S @@ -40,6 +40,10 @@ FUNC(enable_boot_cpu_mm) mrs x5, MPUIR_EL2 and x5, x5, #NUM_MPU_REGIONS_MASK + ldr x0, =max_mpu_regions + strb w5, [x0] + dc ivac, x0 /* Invalidate cache for max_mpu_regions addr */ + /* x0: region sel */ mov x0, xzr /* Xen text section. */ @@ -74,6 +78,27 @@ FUNC(enable_boot_cpu_mm) prepare_xen_region x0, x1, x2, x3, x4, x5, attr_prbar=REGION_DEVICE_PRBAR, attr_prlar=REGION_DEVICE_PRLAR #endif +zero_mpu: + /* Reset remaining MPU regions */ + cmp x0, x5 + beq out_zero_mpu + mov x1, #0 + mov x2, #1 + prepare_xen_region x0, x1, x2, x3, x4, x5, attr_prlar=REGION_DISABLED_PRLAR + b zero_mpu + +out_zero_mpu: + /* Invalidate data cache for MPU data structures */ + mov x4, lr + ldr x0, =xen_mpumap_mask + mov x1, #XEN_MPUMAP_MASK_sizeof + bl __invalidate_dcache_area + + ldr x0, =xen_mpumap + mov x1, #XEN_MPUMAP_sizeof + bl __invalidate_dcache_area + mov lr, x4 + b enable_mpu ret END(enable_boot_cpu_mm) diff --git a/xen/arch/arm/include/asm/arm32/mpu.h b/xen/arch/arm/include/asm/arm32/mpu.h new file mode 100644 index 0000000000..f0d4d4055c --- /dev/null +++ b/xen/arch/arm/include/asm/arm32/mpu.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef ARM_ARM32_MPU_H +#define ARM_ARM32_MPU_H + +#ifndef __ASSEMBLY__ + +/* MPU Protection Region */ +typedef struct { + uint32_t prbar; + uint32_t prlar; +} pr_t; + +#endif /* __ASSEMBLY__ */ + +#endif /* ARM_ARM32_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/bitmap-op.inc b/xen/arch/arm/include/asm/bitmap-op.inc new file mode 100644 index 0000000000..dd8563e02a --- /dev/null +++ b/xen/arch/arm/include/asm/bitmap-op.inc @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * Sets a bit in a bitmap declared by DECLARE_BITMAP, symbol name passed through + * bitmap_symbol. + * + * bitmap_set_bit: symbol of the bitmap declared by DECLARE_BITMAP + * bit: bit number to be set in the bitmap + * tmp1-tmp4: temporary registers used for the computation + * + * Preserves: bit. + * Clobbers: tmp1, tmp2, tmp3, tmp4. + */ +.macro bitmap_set_bit bitmap_symbol, bit, tmp1, tmp2, tmp3, tmp4 + adr_l \tmp1, \bitmap_symbol + mov \tmp2, #(BYTES_PER_LONG - 1) + mvn \tmp2, \tmp2 /* mask for the alignment ~(BYTES_PER_LONG - 1) */ + lsr \tmp3, \bit, #3 /* retrieve byte offset (bit/8) */ + and \tmp2, \tmp3, \tmp2 /* word offset = (bit/8) & ~(BYTES_PER_LONG - 1) */ + add \tmp1, \tmp1, \tmp2 /* bitmap_symbol + word offset */ + and \tmp2, \bit, #(BITS_PER_LONG - 1) /* bit offset inside word */ + + ldr \tmp3, [\tmp1] + mov \tmp4, #1 + lsl \tmp4, \tmp4, \tmp2 /* (1 << offset) */ + orr \tmp3, \tmp3, \tmp4 /* set the bit */ + str \tmp3, [\tmp1] +.endm + +/* + * Clears a bit in a bitmap declared by DECLARE_BITMAP, symbol name passed + * through bitmap_symbol. + * + * bitmap_set_bit: symbol of the bitmap declared by DECLARE_BITMAP + * bit: bit number to be set in the bitmap + * tmp1-tmp4: temporary registers used for the computation + * + * Preserves: bit. + * Clobbers: tmp1, tmp2, tmp3, tmp4. + */ +.macro bitmap_clear_bit bitmap_symbol, bit, tmp1, tmp2, tmp3, tmp4 + adr_l \tmp1, \bitmap_symbol + mov \tmp2, #(BYTES_PER_LONG - 1) + mvn \tmp2, \tmp2 /* mask for the alignment ~(BYTES_PER_LONG - 1) */ + lsr \tmp3, \bit, #3 /* retrieve byte offset (bit/8) */ + and \tmp2, \tmp3, \tmp2 /* word offset = (bit/8) & ~(BYTES_PER_LONG - 1) */ + add \tmp1, \tmp1, \tmp2 /* bitmap_symbol + word offset */ + and \tmp2, \bit, #(BITS_PER_LONG - 1) /* bit offset inside word */ + + ldr \tmp3, [\tmp1] + mov \tmp4, #1 + lsl \tmp4, \tmp4, \tmp2 /* (1 << offset) */ + mvn \tmp4, \tmp4 /* ~(1 << offset) */ + and \tmp3, \tmp3, \tmp4 /* clear the bit */ + str \tmp3, [\tmp1] +.endm + +/* + * Local variables: + * mode: ASM + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/include/asm/mpu.h b/xen/arch/arm/include/asm/mpu.h index bb83f5a5f5..fb93b8b19d 100644 --- a/xen/arch/arm/include/asm/mpu.h +++ b/xen/arch/arm/include/asm/mpu.h @@ -8,6 +8,10 @@ #if defined(CONFIG_ARM_64) # include +#elif defined(CONFIG_ARM_32) +# include +#else +# error "unknown ARM variant" #endif #define MPU_REGION_SHIFT 6 @@ -17,6 +21,7 @@ #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) +#define MAX_MPU_REGION_NR NUM_MPU_REGIONS_MASK #endif /* __ARM_MPU_H__ */ diff --git a/xen/arch/arm/include/asm/mpu/mm.h b/xen/arch/arm/include/asm/mpu/mm.h index bfd840fa5d..409b4dd53d 100644 --- a/xen/arch/arm/include/asm/mpu/mm.h +++ b/xen/arch/arm/include/asm/mpu/mm.h @@ -8,9 +8,16 @@ #include #include #include +#include extern struct page_info *frame_table; +extern uint8_t max_mpu_regions; + +extern DECLARE_BITMAP(xen_mpumap_mask, MAX_MPU_REGION_NR); + +extern pr_t xen_mpumap[MAX_MPU_REGION_NR]; + #define virt_to_maddr(va) ((paddr_t)((vaddr_t)(va) & PADDR_MASK)) #ifdef CONFIG_ARM_32 diff --git a/xen/arch/arm/include/asm/mpu/regions.inc b/xen/arch/arm/include/asm/mpu/regions.inc index 47868a1526..6b8c233e6c 100644 --- a/xen/arch/arm/include/asm/mpu/regions.inc +++ b/xen/arch/arm/include/asm/mpu/regions.inc @@ -1,14 +1,34 @@ /* SPDX-License-Identifier: GPL-2.0-only */ +#include #include #include /* Backgroud region enable/disable */ #define SCTLR_ELx_BR BIT(17, UL) +#define REGION_DISABLED_PRLAR 0x00 /* NS=0 ATTR=000 EN=0 */ #define REGION_NORMAL_PRLAR 0x0f /* NS=0 ATTR=111 EN=1 */ #define REGION_DEVICE_PRLAR 0x09 /* NS=0 ATTR=100 EN=1 */ +#define PRLAR_ELx_EN 0x1 + +#ifdef CONFIG_ARM_64 +#define XEN_MPUMAP_ENTRY_SHIFT 0x4 /* 16 byte structure */ + +.macro store_pair reg1, reg2, dst + stp \reg1, \reg2, [\dst] +.endm + +#else +#define XEN_MPUMAP_ENTRY_SHIFT 0x3 /* 8 byte structure */ + +.macro store_pair reg1, reg2, dst + .word 0xe7f000f0 /* unimplemented */ +.endm + +#endif + /* * Macro to prepare and set a EL2 MPU memory region. * We will also create an according MPU memory region entry, which @@ -59,6 +79,24 @@ dsb sy isb + /* Load pair into xen_mpumap */ + adr_l \base, xen_mpumap + add \base, \base, \sel, LSL #XEN_MPUMAP_ENTRY_SHIFT + store_pair \prbar, \prlar, \base + + /* Set/clear xen_mpumap_mask bitmap */ + tst \prlar, #PRLAR_ELx_EN + bne 2f + /* Region is disabled, clear the bit in the bitmap */ + bitmap_clear_bit xen_mpumap_mask, \sel, \base, \limit, \prbar, \prlar + b 3f + +2: + /* Region is enabled, set the bit in the bitmap */ + bitmap_set_bit xen_mpumap_mask, \sel, \base, \limit, \prbar, \prlar + +3: + add \sel, \sel, #1 1: diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c index 07c8959f4e..2f31b7b787 100644 --- a/xen/arch/arm/mpu/mm.c +++ b/xen/arch/arm/mpu/mm.c @@ -7,9 +7,25 @@ #include #include #include +#include struct page_info *frame_table; +/* Maximum number of supported MPU memory regions by the EL2 MPU. */ +uint8_t __ro_after_init max_mpu_regions; + +/* + * Bitmap xen_mpumap_mask is to record the usage of EL2 MPU memory regions. + * Bit 0 represents MPU memory region 0, bit 1 represents MPU memory + * region 1, ..., and so on. + * If a MPU memory region gets enabled, set the according bit to 1. + */ +DECLARE_BITMAP(xen_mpumap_mask, MAX_MPU_REGION_NR) \ + __cacheline_aligned __section(".data"); + +/* EL2 Xen MPU memory region mapping table. */ +pr_t __cacheline_aligned __section(".data") xen_mpumap[MAX_MPU_REGION_NR]; + static void __init __maybe_unused build_assertions(void) { /*