The Armv6-M Unprivileged/Privileged Extension is optional. Cortex-M0 does not implement it, while Cortex-M0+ may implement it. The RP2040 Cortex-M0+ configuration provides the extension.
Add an ARM feature bit and a cortex-m0plus CPU type that enables it. Permit privileged writes to CONTROL.nPRIV when either the Main Extension or the optional privilege extension is present. Update the microbit Cortex-M0 test to verify that writes to nPRIV are ignored. Signed-off-by: Gilles Grimaud <[email protected]> --- target/arm/cpu.h | 1 + target/arm/tcg/cpu-v7m.c | 11 ++++ target/arm/tcg/m_helper.c | 4 +- tests/tcg/arm/system/meson.build | 6 ++ tests/tcg/arm/system/test-armv6m-control.S | 66 ++++++++++++++++++++++ 5 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 tests/tcg/arm/system/test-armv6m-control.S diff --git a/target/arm/cpu.h b/target/arm/cpu.h index e3f931dba2..66606b3444 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2168,6 +2168,7 @@ enum arm_features { ARM_FEATURE_VBAR, /* has cp15 VBAR */ ARM_FEATURE_M_SECURITY, /* M profile Security Extension */ ARM_FEATURE_M_MAIN, /* M profile Main Extension */ + ARM_FEATURE_M_UNPRIV, /* M profile Unprivileged/Privileged Extension */ ARM_FEATURE_V8_1M, /* M profile extras only in v8.1M and later */ /* * ARM_FEATURE_BACKCOMPAT_CNTFRQ makes the CPU default cntfrq be 62.5MHz diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c index 48b31d5eac..ac99c93ec3 100644 --- a/target/arm/tcg/cpu-v7m.c +++ b/target/arm/tcg/cpu-v7m.c @@ -76,6 +76,15 @@ static void cortex_m0_initfn(Object *obj) SET_IDREG(isar, ID_ISAR6, 0x00000000); } +static void cortex_m0plus_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cortex_m0_initfn(obj); + set_feature(&cpu->env, ARM_FEATURE_M_UNPRIV); + cpu->midr = 0x410cc601; +} + static void cortex_m3_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -325,6 +334,8 @@ static void arm_v7m_class_init(ObjectClass *oc, const void *data) static const ARMCPUInfo arm_v7m_cpus[] = { { .name = "cortex-m0", .initfn = cortex_m0_initfn, .class_init = arm_v7m_class_init }, + { .name = "cortex-m0plus", .initfn = cortex_m0plus_initfn, + .class_init = arm_v7m_class_init }, { .name = "cortex-m3", .initfn = cortex_m3_initfn, .class_init = arm_v7m_class_init }, { .name = "cortex-m4", .initfn = cortex_m4_initfn, diff --git a/target/arm/tcg/m_helper.c b/target/arm/tcg/m_helper.c index 33c9e7c55b..f8461a4d66 100644 --- a/target/arm/tcg/m_helper.c +++ b/target/arm/tcg/m_helper.c @@ -2775,7 +2775,9 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) !arm_v7m_is_handler_mode(env))) { write_v7m_control_spsel(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0); } - if (cur_el > 0 && arm_feature(env, ARM_FEATURE_M_MAIN)) { + if (cur_el > 0 && + (arm_feature(env, ARM_FEATURE_M_MAIN) || + arm_feature(env, ARM_FEATURE_M_UNPRIV))) { env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK; env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK; } diff --git a/tests/tcg/arm/system/meson.build b/tests/tcg/arm/system/meson.build index 5286997670..e92a83a8d5 100644 --- a/tests/tcg/arm/system/meson.build +++ b/tests/tcg/arm/system/meson.build @@ -45,6 +45,12 @@ tests += { '-T', files('test-armv6m-undef.ld')], 'qemu_args': ['-M', 'microbit', qemu_base_args], }, + 'test-armv6m-control.S': { + 'cflags': ['-mcpu=cortex-m0', '-mfloat-abi=soft', '-nostdlib', + '-Wl,--build-id=none', + '-T', files('test-armv6m-undef.ld')], + 'qemu_args': ['-M', 'microbit', qemu_base_args], + }, 'semiconsole.c': { 'cflags': cflags, 'qemu_args': ['-serial', 'none', '-chardev', 'stdio,mux=on,id=stdio0', diff --git a/tests/tcg/arm/system/test-armv6m-control.S b/tests/tcg/arm/system/test-armv6m-control.S new file mode 100644 index 0000000000..42ce42db2b --- /dev/null +++ b/tests/tcg/arm/system/test-armv6m-control.S @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Test that Cortex-M0 does not implement CONTROL.nPRIV. */ + +.syntax unified +.cpu cortex-m0 +.thumb + +#define SRAM_BASE 0x20000000 +#define SRAM_SIZE (16 * 1024) + +#define semihosting_call bkpt 0xab +#define SYS_EXIT 0x18 + +vector_table: + .word SRAM_BASE + SRAM_SIZE + .word reset + 1 + .word 0 + .word failure + 1 + .rept 7 + .word 0 + .endr + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .rept 32 + .word 0 + .endr + +.equ exc_reset_thumb, reset + 1 +.global exc_reset_thumb +reset: + /* Thread mode starts privileged. */ + mrs r0, control + movs r1, 1 + tst r0, r1 + bne failure + + /* Cortex-M0 does not implement the optional privilege extension. */ + movs r0, 1 + msr control, r0 + isb + mrs r0, control + tst r0, r1 + bne failure + +success: + movs r0, 1 + b exit + +failure: + movs r0, 0 + +exit: + movs r1, 0 + cmp r0, 1 + bne 1f + ldr r1, ADP_Stopped_ApplicationExit +1: + movs r0, SYS_EXIT + semihosting_call + +.align 2 +ADP_Stopped_ApplicationExit: + .word 0x20026 -- 2.55.0
