Message ID | 20250407184443.1790995-3-ayan.kumar.halder@amd.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | Enable early bootup of Armv8-R AArch32 systems | expand |
Hi Ayan, > On 7 Apr 2025, at 19:44, Ayan Kumar Halder <ayan.kumar.halder@amd.com> wrote: > > We have created the same boot-time MPU protection regions as Armv8-R AArch64. > Also, we have defined *_PRBAR macros for arm32. The only difference from > arm64 is that XN is 1-bit for arm32. > The macros have been defined in mpu/cpregs.h. > > Also defined WRITE_SYSREG_ASM() to write to system registers in assembly. > > Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com> > --- > […] > diff --git a/xen/arch/arm/include/asm/arm32/sysregs.h b/xen/arch/arm/include/asm/arm32/sysregs.h > index 22871999af..a90d1610a1 100644 > --- a/xen/arch/arm/include/asm/arm32/sysregs.h > +++ b/xen/arch/arm/include/asm/arm32/sysregs.h > @@ -20,6 +20,13 @@ > * uses r0 as a placeholder register. */ > #define CMD_CP32(name...) "mcr " __stringify(CP32(r0, name)) ";" > > +#define REGION_TEXT_PRBAR 0x18 /* SH=11 AP=10 XN=0 */ > +#define REGION_RO_PRBAR 0x1D /* SH=11 AP=10 XN=1 */ > +#define REGION_DATA_PRBAR 0x19 /* SH=11 AP=00 XN=1 */ > +#define REGION_DEVICE_PRBAR 0x11 /* SH=10 AP=00 XN=1 */ > + > +#define WRITE_SYSREG_ASM(v, name) mcr CP32(v, name) probably the same applies to this patch, this one needs to stay where __ASSEMBLY__ is defined? The rest looks good to me! Reviewed-by: Luca Fancellu <luca.fancellu@arm.com> Cheers, Luca
On 07/04/2025 20:44, Ayan Kumar Halder wrote: > We have created the same boot-time MPU protection regions as Armv8-R AArch64. > Also, we have defined *_PRBAR macros for arm32. The only difference from > arm64 is that XN is 1-bit for arm32. > The macros have been defined in mpu/cpregs.h. NIT: Describe your changes in imperative mood > > Also defined WRITE_SYSREG_ASM() to write to system registers in assembly. > > Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com> > --- > Changes from > > v1 - > > 1. enable_mpu() now sets HMAIR{0,1} registers. This is similar to what is > being done in enable_mmu(). All the mm related configurations happen in this > function. > > 2. Fixed some typos. > > v2 - > 1. Include the common prepare_xen_region.inc in head.S. > > 2. Define LOAD_SYSREG()/STORE_SYSREG() for arm32. > > v3 - > 1. Rename STORE_SYSREG() as WRITE_SYSREG_ASM() > > 2. enable_boot_cpu_mm() is defined in head.S > > v4 - > 1. *_PRBAR is moved to arm32/sysregs.h. > > 2. MPU specific CP15 system registers are defined in mpu/cpregs.h. > > xen/arch/arm/arm32/Makefile | 1 + > xen/arch/arm/arm32/mpu/Makefile | 1 + > xen/arch/arm/arm32/mpu/head.S | 101 +++++++++++++++++++++++ > xen/arch/arm/include/asm/arm32/sysregs.h | 7 ++ > xen/arch/arm/include/asm/cpregs.h | 4 + > xen/arch/arm/include/asm/mpu/cpregs.h | 24 ++++++ > 6 files changed, 138 insertions(+) > create mode 100644 xen/arch/arm/arm32/mpu/Makefile > create mode 100644 xen/arch/arm/arm32/mpu/head.S > create mode 100644 xen/arch/arm/include/asm/mpu/cpregs.h > > diff --git a/xen/arch/arm/arm32/Makefile b/xen/arch/arm/arm32/Makefile > index 40a2b4803f..537969d753 100644 > --- a/xen/arch/arm/arm32/Makefile > +++ b/xen/arch/arm/arm32/Makefile > @@ -1,5 +1,6 @@ > obj-y += lib/ > obj-$(CONFIG_MMU) += mmu/ > +obj-$(CONFIG_MPU) += mpu/ > > obj-$(CONFIG_EARLY_PRINTK) += debug.o > obj-y += domctl.o > diff --git a/xen/arch/arm/arm32/mpu/Makefile b/xen/arch/arm/arm32/mpu/Makefile > new file mode 100644 > index 0000000000..3340058c08 > --- /dev/null > +++ b/xen/arch/arm/arm32/mpu/Makefile > @@ -0,0 +1 @@ > +obj-y += head.o > diff --git a/xen/arch/arm/arm32/mpu/head.S b/xen/arch/arm/arm32/mpu/head.S > new file mode 100644 > index 0000000000..84e9f1f8ec > --- /dev/null > +++ b/xen/arch/arm/arm32/mpu/head.S > @@ -0,0 +1,101 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Start-of-day code for an Armv8-R MPU system. That's exactly the same text as for Aarch64. At least write Armv8A-R-AArch32. > + */ > + > +#include <asm/arm32/macros.h> > +#include <asm/mpu/common.inc> > +#include <asm/page.h> > + > +/* > + * Set up the memory attribute type tables and enable EL2 MPU and data cache. > + * If the Background region is enabled, then the MPU uses the default memory > + * map as the Background region for generating the memory > + * attributes when MPU is disabled. > + * Since the default memory map of the Armv8-R AArch32 architecture is > + * IMPLEMENTATION DEFINED, we intend to turn off the Background region here. > + * > + * Clobbers r0 - r1 > + */ > +FUNC_LOCAL(enable_mpu) > + /* Set up memory attribute type tables */ > + mov_w r0, MAIR0VAL > + mov_w r1, MAIR1VAL > + mcr CP32(r0, HMAIR0) > + mcr CP32(r1, HMAIR1) Is there really a need to do these 2 writes one after another? Why can't we use only r0 and save one clobbered reg? mov_w r0, MAIR0VAL mcr CP32(r0, HMAIR0) mov_w r0, MAIR1VAL mcr CP32(r0, HMAIR1) > + > + mrc CP32(r0, HSCTLR) > + bic r0, r0, #SCTLR_ELx_BR /* Disable Background region */ > + orr r0, r0, #SCTLR_Axx_ELx_M /* Enable MPU */ > + orr r0, r0, #SCTLR_Axx_ELx_C /* Enable D-cache */ > + mcr CP32(r0, HSCTLR) > + isb > + > + ret > +END(enable_mpu) > + > +/* > + * Maps the various sections of Xen (described in xen.lds.S) as different MPU > + * regions. > + * > + * Clobbers r0 - r5 > + * > + */ > +FUNC(enable_boot_cpu_mm) > + /* Get the number of regions specified in MPUIR_EL2 */ > + mrc CP32(r5, MPUIR_EL2) > + and r5, r5, #NUM_MPU_REGIONS_MASK > + > + /* x0: region sel */ > + mov r0, #0 > + /* Xen text section. */ > + mov_w r1, _stext > + mov_w r2, _etext > + prepare_xen_region r0, r1, r2, r3, r4, r5, attr_prbar=REGION_TEXT_PRBAR > + > + /* Xen read-only data section. */ > + mov_w r1, _srodata > + mov_w r2, _erodata > + prepare_xen_region r0, r1, r2, r3, r4, r5, attr_prbar=REGION_RO_PRBAR > + > + /* Xen read-only after init and data section. (RW data) */ > + mov_w r1, __ro_after_init_start > + mov_w r2, __init_begin > + prepare_xen_region r0, r1, r2, r3, r4, r5 > + > + /* Xen code section. */ > + mov_w r1, __init_begin > + mov_w r2, __init_data_begin > + prepare_xen_region r0, r1, r2, r3, r4, r5, attr_prbar=REGION_TEXT_PRBAR > + > + /* Xen data and BSS section. */ > + mov_w r1, __init_data_begin > + mov_w r2, __bss_end > + prepare_xen_region r0, r1, r2, r3, r4, r5 > + > +#ifdef CONFIG_EARLY_PRINTK > + /* Xen early UART section. */ > + mov_w r1, CONFIG_EARLY_UART_BASE_ADDRESS > + mov_w r2, (CONFIG_EARLY_UART_BASE_ADDRESS + CONFIG_EARLY_UART_SIZE) > + prepare_xen_region r0, r1, r2, r3, r4, r5, attr_prbar=REGION_DEVICE_PRBAR, attr_prlar=REGION_DEVICE_PRLAR > +#endif > + > + b enable_mpu > +END(enable_boot_cpu_mm) > + > +/* > + * We don't yet support secondary CPUs bring-up. Implement a dummy helper to > + * please the common code. > + */ > +FUNC(enable_secondary_cpu_mm) > + PRINT("- SMP not enabled yet -\r\n") > +1: wfe > + b 1b > +END(enable_secondary_cpu_mm) > + > +/* > + * Local variables: > + * mode: ASM > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/xen/arch/arm/include/asm/arm32/sysregs.h b/xen/arch/arm/include/asm/arm32/sysregs.h > index 22871999af..a90d1610a1 100644 > --- a/xen/arch/arm/include/asm/arm32/sysregs.h > +++ b/xen/arch/arm/include/asm/arm32/sysregs.h > @@ -20,6 +20,13 @@ > * uses r0 as a placeholder register. */ > #define CMD_CP32(name...) "mcr " __stringify(CP32(r0, name)) ";" > > +#define REGION_TEXT_PRBAR 0x18 /* SH=11 AP=10 XN=0 */ > +#define REGION_RO_PRBAR 0x1D /* SH=11 AP=10 XN=1 */ > +#define REGION_DATA_PRBAR 0x19 /* SH=11 AP=00 XN=1 */ > +#define REGION_DEVICE_PRBAR 0x11 /* SH=10 AP=00 XN=1 */ > + > +#define WRITE_SYSREG_ASM(v, name) mcr CP32(v, name) Same comment as for previous patch. > + > #ifndef __ASSEMBLY__ > > /* C wrappers */ > diff --git a/xen/arch/arm/include/asm/cpregs.h b/xen/arch/arm/include/asm/cpregs.h > index aec9e8f329..6019a2cbdd 100644 > --- a/xen/arch/arm/include/asm/cpregs.h > +++ b/xen/arch/arm/include/asm/cpregs.h > @@ -1,6 +1,10 @@ > #ifndef __ASM_ARM_CPREGS_H > #define __ASM_ARM_CPREGS_H > > +#ifdef CONFIG_MPU NIT: Do we really need to protect this include? I thought we do the ifdefery if we need to include either mmu or mpu. Here we don't have a choice and afaict there's nothing problematic in mpu/cpregs.h > +#include <asm/mpu/cpregs.h> > +#endif > + > /* > * AArch32 Co-processor registers. > * > diff --git a/xen/arch/arm/include/asm/mpu/cpregs.h b/xen/arch/arm/include/asm/mpu/cpregs.h > new file mode 100644 > index 0000000000..6b20c7ceae > --- /dev/null > +++ b/xen/arch/arm/include/asm/mpu/cpregs.h > @@ -0,0 +1,24 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > + > +#ifndef __ASM_ARM_MPU_CPREGS_H > +#define __ASM_ARM_MPU_CPREGS_H > + > +/* CP15 CR0: MPU Type Register */ > +#define HMPUIR p15,4,c0,c0,4 > + > +/* CP15 CR6: MPU Protection Region Base/Limit/Select Address Register */ > +#define HPRSELR p15,4,c6,c2,1 > +#define PRBAR_EL2 p15,4,c6,c3,0 > +#define PRLAR_EL2 p15,4,c6,c8,1 > + > +#define MPUIR_EL2 HMPUIR > +#define PRSELR_EL2 HPRSELR AFAIK, these macros are there to use AArch64 sysreg names in common code when compiling Arm32. This would mean they should be protected with #ifdef CONFIG_ARM_32. ~Michal
Hi, On 08/04/2025 10:13, Orzel, Michal wrote: > > On 07/04/2025 20:44, Ayan Kumar Halder wrote: >> We have created the same boot-time MPU protection regions as Armv8-R AArch64. >> Also, we have defined *_PRBAR macros for arm32. The only difference from >> arm64 is that XN is 1-bit for arm32. >> The macros have been defined in mpu/cpregs.h. > NIT: Describe your changes in imperative mood > >> Also defined WRITE_SYSREG_ASM() to write to system registers in assembly. >> >> Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com> >> --- >> Changes from >> >> v1 - >> >> 1. enable_mpu() now sets HMAIR{0,1} registers. This is similar to what is >> being done in enable_mmu(). All the mm related configurations happen in this >> function. >> >> 2. Fixed some typos. >> >> v2 - >> 1. Include the common prepare_xen_region.inc in head.S. >> >> 2. Define LOAD_SYSREG()/STORE_SYSREG() for arm32. >> >> v3 - >> 1. Rename STORE_SYSREG() as WRITE_SYSREG_ASM() >> >> 2. enable_boot_cpu_mm() is defined in head.S >> >> v4 - >> 1. *_PRBAR is moved to arm32/sysregs.h. >> >> 2. MPU specific CP15 system registers are defined in mpu/cpregs.h. >> >> xen/arch/arm/arm32/Makefile | 1 + >> xen/arch/arm/arm32/mpu/Makefile | 1 + >> xen/arch/arm/arm32/mpu/head.S | 101 +++++++++++++++++++++++ >> xen/arch/arm/include/asm/arm32/sysregs.h | 7 ++ >> xen/arch/arm/include/asm/cpregs.h | 4 + >> xen/arch/arm/include/asm/mpu/cpregs.h | 24 ++++++ >> 6 files changed, 138 insertions(+) >> create mode 100644 xen/arch/arm/arm32/mpu/Makefile >> create mode 100644 xen/arch/arm/arm32/mpu/head.S >> create mode 100644 xen/arch/arm/include/asm/mpu/cpregs.h >> >> diff --git a/xen/arch/arm/arm32/Makefile b/xen/arch/arm/arm32/Makefile >> index 40a2b4803f..537969d753 100644 >> --- a/xen/arch/arm/arm32/Makefile >> +++ b/xen/arch/arm/arm32/Makefile >> @@ -1,5 +1,6 @@ >> obj-y += lib/ >> obj-$(CONFIG_MMU) += mmu/ >> +obj-$(CONFIG_MPU) += mpu/ >> >> obj-$(CONFIG_EARLY_PRINTK) += debug.o >> obj-y += domctl.o >> diff --git a/xen/arch/arm/arm32/mpu/Makefile b/xen/arch/arm/arm32/mpu/Makefile >> new file mode 100644 >> index 0000000000..3340058c08 >> --- /dev/null >> +++ b/xen/arch/arm/arm32/mpu/Makefile >> @@ -0,0 +1 @@ >> +obj-y += head.o >> diff --git a/xen/arch/arm/arm32/mpu/head.S b/xen/arch/arm/arm32/mpu/head.S >> new file mode 100644 >> index 0000000000..84e9f1f8ec >> --- /dev/null >> +++ b/xen/arch/arm/arm32/mpu/head.S >> @@ -0,0 +1,101 @@ >> +/* SPDX-License-Identifier: GPL-2.0-only */ >> +/* >> + * Start-of-day code for an Armv8-R MPU system. > That's exactly the same text as for Aarch64. At least write Armv8A-R-AArch32. Ack > >> + */ >> + >> +#include <asm/arm32/macros.h> >> +#include <asm/mpu/common.inc> >> +#include <asm/page.h> >> + >> +/* >> + * Set up the memory attribute type tables and enable EL2 MPU and data cache. >> + * If the Background region is enabled, then the MPU uses the default memory >> + * map as the Background region for generating the memory >> + * attributes when MPU is disabled. >> + * Since the default memory map of the Armv8-R AArch32 architecture is >> + * IMPLEMENTATION DEFINED, we intend to turn off the Background region here. >> + * >> + * Clobbers r0 - r1 >> + */ >> +FUNC_LOCAL(enable_mpu) >> + /* Set up memory attribute type tables */ >> + mov_w r0, MAIR0VAL >> + mov_w r1, MAIR1VAL >> + mcr CP32(r0, HMAIR0) >> + mcr CP32(r1, HMAIR1) > Is there really a need to do these 2 writes one after another? > Why can't we use only r0 and save one clobbered reg? > mov_w r0, MAIR0VAL > mcr CP32(r0, HMAIR0) > mov_w r0, MAIR1VAL > mcr CP32(r0, HMAIR1) I just copied it as it is from head.S. :) I will change it in v6. > >> + >> + mrc CP32(r0, HSCTLR) >> + bic r0, r0, #SCTLR_ELx_BR /* Disable Background region */ >> + orr r0, r0, #SCTLR_Axx_ELx_M /* Enable MPU */ >> + orr r0, r0, #SCTLR_Axx_ELx_C /* Enable D-cache */ >> + mcr CP32(r0, HSCTLR) >> + isb >> + >> + ret >> +END(enable_mpu) >> + >> +/* >> + * Maps the various sections of Xen (described in xen.lds.S) as different MPU >> + * regions. >> + * >> + * Clobbers r0 - r5 >> + * >> + */ >> +FUNC(enable_boot_cpu_mm) >> + /* Get the number of regions specified in MPUIR_EL2 */ >> + mrc CP32(r5, MPUIR_EL2) >> + and r5, r5, #NUM_MPU_REGIONS_MASK >> + >> + /* x0: region sel */ >> + mov r0, #0 >> + /* Xen text section. */ >> + mov_w r1, _stext >> + mov_w r2, _etext >> + prepare_xen_region r0, r1, r2, r3, r4, r5, attr_prbar=REGION_TEXT_PRBAR >> + >> + /* Xen read-only data section. */ >> + mov_w r1, _srodata >> + mov_w r2, _erodata >> + prepare_xen_region r0, r1, r2, r3, r4, r5, attr_prbar=REGION_RO_PRBAR >> + >> + /* Xen read-only after init and data section. (RW data) */ >> + mov_w r1, __ro_after_init_start >> + mov_w r2, __init_begin >> + prepare_xen_region r0, r1, r2, r3, r4, r5 >> + >> + /* Xen code section. */ >> + mov_w r1, __init_begin >> + mov_w r2, __init_data_begin >> + prepare_xen_region r0, r1, r2, r3, r4, r5, attr_prbar=REGION_TEXT_PRBAR >> + >> + /* Xen data and BSS section. */ >> + mov_w r1, __init_data_begin >> + mov_w r2, __bss_end >> + prepare_xen_region r0, r1, r2, r3, r4, r5 >> + >> +#ifdef CONFIG_EARLY_PRINTK >> + /* Xen early UART section. */ >> + mov_w r1, CONFIG_EARLY_UART_BASE_ADDRESS >> + mov_w r2, (CONFIG_EARLY_UART_BASE_ADDRESS + CONFIG_EARLY_UART_SIZE) >> + prepare_xen_region r0, r1, r2, r3, r4, r5, attr_prbar=REGION_DEVICE_PRBAR, attr_prlar=REGION_DEVICE_PRLAR >> +#endif >> + >> + b enable_mpu >> +END(enable_boot_cpu_mm) >> + >> +/* >> + * We don't yet support secondary CPUs bring-up. Implement a dummy helper to >> + * please the common code. >> + */ >> +FUNC(enable_secondary_cpu_mm) >> + PRINT("- SMP not enabled yet -\r\n") >> +1: wfe >> + b 1b >> +END(enable_secondary_cpu_mm) >> + >> +/* >> + * Local variables: >> + * mode: ASM >> + * indent-tabs-mode: nil >> + * End: >> + */ >> diff --git a/xen/arch/arm/include/asm/arm32/sysregs.h b/xen/arch/arm/include/asm/arm32/sysregs.h >> index 22871999af..a90d1610a1 100644 >> --- a/xen/arch/arm/include/asm/arm32/sysregs.h >> +++ b/xen/arch/arm/include/asm/arm32/sysregs.h >> @@ -20,6 +20,13 @@ >> * uses r0 as a placeholder register. */ >> #define CMD_CP32(name...) "mcr " __stringify(CP32(r0, name)) ";" >> >> +#define REGION_TEXT_PRBAR 0x18 /* SH=11 AP=10 XN=0 */ >> +#define REGION_RO_PRBAR 0x1D /* SH=11 AP=10 XN=1 */ >> +#define REGION_DATA_PRBAR 0x19 /* SH=11 AP=00 XN=1 */ >> +#define REGION_DEVICE_PRBAR 0x11 /* SH=10 AP=00 XN=1 */ >> + >> +#define WRITE_SYSREG_ASM(v, name) mcr CP32(v, name) > Same comment as for previous patch. Ack. > >> + >> #ifndef __ASSEMBLY__ >> >> /* C wrappers */ >> diff --git a/xen/arch/arm/include/asm/cpregs.h b/xen/arch/arm/include/asm/cpregs.h >> index aec9e8f329..6019a2cbdd 100644 >> --- a/xen/arch/arm/include/asm/cpregs.h >> +++ b/xen/arch/arm/include/asm/cpregs.h >> @@ -1,6 +1,10 @@ >> #ifndef __ASM_ARM_CPREGS_H >> #define __ASM_ARM_CPREGS_H >> >> +#ifdef CONFIG_MPU > NIT: Do we really need to protect this include? I thought we do the ifdefery if > we need to include either mmu or mpu. Here we don't have a choice and afaict > there's nothing problematic in mpu/cpregs.h Ack. > >> +#include <asm/mpu/cpregs.h> >> +#endif >> + >> /* >> * AArch32 Co-processor registers. >> * >> diff --git a/xen/arch/arm/include/asm/mpu/cpregs.h b/xen/arch/arm/include/asm/mpu/cpregs.h >> new file mode 100644 >> index 0000000000..6b20c7ceae >> --- /dev/null >> +++ b/xen/arch/arm/include/asm/mpu/cpregs.h >> @@ -0,0 +1,24 @@ >> +/* SPDX-License-Identifier: GPL-2.0-only */ >> + >> +#ifndef __ASM_ARM_MPU_CPREGS_H >> +#define __ASM_ARM_MPU_CPREGS_H >> + >> +/* CP15 CR0: MPU Type Register */ >> +#define HMPUIR p15,4,c0,c0,4 >> + >> +/* CP15 CR6: MPU Protection Region Base/Limit/Select Address Register */ >> +#define HPRSELR p15,4,c6,c2,1 >> +#define PRBAR_EL2 p15,4,c6,c3,0 >> +#define PRLAR_EL2 p15,4,c6,c8,1 >> + >> +#define MPUIR_EL2 HMPUIR >> +#define PRSELR_EL2 HPRSELR > AFAIK, these macros are there to use AArch64 sysreg names in common code when > compiling Arm32. This would mean they should be protected with #ifdef CONFIG_ARM_32. In the case of Arm64, the MPU system registers are defined by the compiler. So, these definitions are overridden. I will enclose this within CONFIG_ARM_32 for better readability. @Luca - I will keep your R-b unless you object. The changes are mostly style related. :) - Ayan > > ~Michal >
diff --git a/xen/arch/arm/arm32/Makefile b/xen/arch/arm/arm32/Makefile index 40a2b4803f..537969d753 100644 --- a/xen/arch/arm/arm32/Makefile +++ b/xen/arch/arm/arm32/Makefile @@ -1,5 +1,6 @@ obj-y += lib/ obj-$(CONFIG_MMU) += mmu/ +obj-$(CONFIG_MPU) += mpu/ obj-$(CONFIG_EARLY_PRINTK) += debug.o obj-y += domctl.o diff --git a/xen/arch/arm/arm32/mpu/Makefile b/xen/arch/arm/arm32/mpu/Makefile new file mode 100644 index 0000000000..3340058c08 --- /dev/null +++ b/xen/arch/arm/arm32/mpu/Makefile @@ -0,0 +1 @@ +obj-y += head.o diff --git a/xen/arch/arm/arm32/mpu/head.S b/xen/arch/arm/arm32/mpu/head.S new file mode 100644 index 0000000000..84e9f1f8ec --- /dev/null +++ b/xen/arch/arm/arm32/mpu/head.S @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Start-of-day code for an Armv8-R MPU system. + */ + +#include <asm/arm32/macros.h> +#include <asm/mpu/common.inc> +#include <asm/page.h> + +/* + * Set up the memory attribute type tables and enable EL2 MPU and data cache. + * If the Background region is enabled, then the MPU uses the default memory + * map as the Background region for generating the memory + * attributes when MPU is disabled. + * Since the default memory map of the Armv8-R AArch32 architecture is + * IMPLEMENTATION DEFINED, we intend to turn off the Background region here. + * + * Clobbers r0 - r1 + */ +FUNC_LOCAL(enable_mpu) + /* Set up memory attribute type tables */ + mov_w r0, MAIR0VAL + mov_w r1, MAIR1VAL + mcr CP32(r0, HMAIR0) + mcr CP32(r1, HMAIR1) + + mrc CP32(r0, HSCTLR) + bic r0, r0, #SCTLR_ELx_BR /* Disable Background region */ + orr r0, r0, #SCTLR_Axx_ELx_M /* Enable MPU */ + orr r0, r0, #SCTLR_Axx_ELx_C /* Enable D-cache */ + mcr CP32(r0, HSCTLR) + isb + + ret +END(enable_mpu) + +/* + * Maps the various sections of Xen (described in xen.lds.S) as different MPU + * regions. + * + * Clobbers r0 - r5 + * + */ +FUNC(enable_boot_cpu_mm) + /* Get the number of regions specified in MPUIR_EL2 */ + mrc CP32(r5, MPUIR_EL2) + and r5, r5, #NUM_MPU_REGIONS_MASK + + /* x0: region sel */ + mov r0, #0 + /* Xen text section. */ + mov_w r1, _stext + mov_w r2, _etext + prepare_xen_region r0, r1, r2, r3, r4, r5, attr_prbar=REGION_TEXT_PRBAR + + /* Xen read-only data section. */ + mov_w r1, _srodata + mov_w r2, _erodata + prepare_xen_region r0, r1, r2, r3, r4, r5, attr_prbar=REGION_RO_PRBAR + + /* Xen read-only after init and data section. (RW data) */ + mov_w r1, __ro_after_init_start + mov_w r2, __init_begin + prepare_xen_region r0, r1, r2, r3, r4, r5 + + /* Xen code section. */ + mov_w r1, __init_begin + mov_w r2, __init_data_begin + prepare_xen_region r0, r1, r2, r3, r4, r5, attr_prbar=REGION_TEXT_PRBAR + + /* Xen data and BSS section. */ + mov_w r1, __init_data_begin + mov_w r2, __bss_end + prepare_xen_region r0, r1, r2, r3, r4, r5 + +#ifdef CONFIG_EARLY_PRINTK + /* Xen early UART section. */ + mov_w r1, CONFIG_EARLY_UART_BASE_ADDRESS + mov_w r2, (CONFIG_EARLY_UART_BASE_ADDRESS + CONFIG_EARLY_UART_SIZE) + prepare_xen_region r0, r1, r2, r3, r4, r5, attr_prbar=REGION_DEVICE_PRBAR, attr_prlar=REGION_DEVICE_PRLAR +#endif + + b enable_mpu +END(enable_boot_cpu_mm) + +/* + * We don't yet support secondary CPUs bring-up. Implement a dummy helper to + * please the common code. + */ +FUNC(enable_secondary_cpu_mm) + PRINT("- SMP not enabled yet -\r\n") +1: wfe + b 1b +END(enable_secondary_cpu_mm) + +/* + * Local variables: + * mode: ASM + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/include/asm/arm32/sysregs.h b/xen/arch/arm/include/asm/arm32/sysregs.h index 22871999af..a90d1610a1 100644 --- a/xen/arch/arm/include/asm/arm32/sysregs.h +++ b/xen/arch/arm/include/asm/arm32/sysregs.h @@ -20,6 +20,13 @@ * uses r0 as a placeholder register. */ #define CMD_CP32(name...) "mcr " __stringify(CP32(r0, name)) ";" +#define REGION_TEXT_PRBAR 0x18 /* SH=11 AP=10 XN=0 */ +#define REGION_RO_PRBAR 0x1D /* SH=11 AP=10 XN=1 */ +#define REGION_DATA_PRBAR 0x19 /* SH=11 AP=00 XN=1 */ +#define REGION_DEVICE_PRBAR 0x11 /* SH=10 AP=00 XN=1 */ + +#define WRITE_SYSREG_ASM(v, name) mcr CP32(v, name) + #ifndef __ASSEMBLY__ /* C wrappers */ diff --git a/xen/arch/arm/include/asm/cpregs.h b/xen/arch/arm/include/asm/cpregs.h index aec9e8f329..6019a2cbdd 100644 --- a/xen/arch/arm/include/asm/cpregs.h +++ b/xen/arch/arm/include/asm/cpregs.h @@ -1,6 +1,10 @@ #ifndef __ASM_ARM_CPREGS_H #define __ASM_ARM_CPREGS_H +#ifdef CONFIG_MPU +#include <asm/mpu/cpregs.h> +#endif + /* * AArch32 Co-processor registers. * diff --git a/xen/arch/arm/include/asm/mpu/cpregs.h b/xen/arch/arm/include/asm/mpu/cpregs.h new file mode 100644 index 0000000000..6b20c7ceae --- /dev/null +++ b/xen/arch/arm/include/asm/mpu/cpregs.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ASM_ARM_MPU_CPREGS_H +#define __ASM_ARM_MPU_CPREGS_H + +/* CP15 CR0: MPU Type Register */ +#define HMPUIR p15,4,c0,c0,4 + +/* CP15 CR6: MPU Protection Region Base/Limit/Select Address Register */ +#define HPRSELR p15,4,c6,c2,1 +#define PRBAR_EL2 p15,4,c6,c3,0 +#define PRLAR_EL2 p15,4,c6,c8,1 + +#define MPUIR_EL2 HMPUIR +#define PRSELR_EL2 HPRSELR + +#endif /* __ASM_ARM_MPU_CPREGS_H */ + +/* + * Local variables: + * mode: ASM + * indent-tabs-mode: nil + * End: + */
We have created the same boot-time MPU protection regions as Armv8-R AArch64. Also, we have defined *_PRBAR macros for arm32. The only difference from arm64 is that XN is 1-bit for arm32. The macros have been defined in mpu/cpregs.h. Also defined WRITE_SYSREG_ASM() to write to system registers in assembly. Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com> --- Changes from v1 - 1. enable_mpu() now sets HMAIR{0,1} registers. This is similar to what is being done in enable_mmu(). All the mm related configurations happen in this function. 2. Fixed some typos. v2 - 1. Include the common prepare_xen_region.inc in head.S. 2. Define LOAD_SYSREG()/STORE_SYSREG() for arm32. v3 - 1. Rename STORE_SYSREG() as WRITE_SYSREG_ASM() 2. enable_boot_cpu_mm() is defined in head.S v4 - 1. *_PRBAR is moved to arm32/sysregs.h. 2. MPU specific CP15 system registers are defined in mpu/cpregs.h. xen/arch/arm/arm32/Makefile | 1 + xen/arch/arm/arm32/mpu/Makefile | 1 + xen/arch/arm/arm32/mpu/head.S | 101 +++++++++++++++++++++++ xen/arch/arm/include/asm/arm32/sysregs.h | 7 ++ xen/arch/arm/include/asm/cpregs.h | 4 + xen/arch/arm/include/asm/mpu/cpregs.h | 24 ++++++ 6 files changed, 138 insertions(+) create mode 100644 xen/arch/arm/arm32/mpu/Makefile create mode 100644 xen/arch/arm/arm32/mpu/head.S create mode 100644 xen/arch/arm/include/asm/mpu/cpregs.h