Armv6-M supports no more than 32 external interrupts. Its ICTR and Active Bit Register locations are reserved, and Cortex-M0 implements two priority bits.
Reject Armv6-M NVIC configurations with more than 32 external interrupts. Add a check-tcg test that verifies the reserved register behavior and priority masking on the microbit machine. Signed-off-by: Gilles Grimaud <[email protected]> --- hw/intc/armv7m_nvic.c | 7 +++ tests/tcg/arm/system/meson.build | 6 +++ tests/tcg/arm/system/test-armv6m-nvic.S | 70 +++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 tests/tcg/arm/system/test-armv6m-nvic.S diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index a7651f831e..c1ceb7450f 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -2728,6 +2728,13 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) return; } + if (!arm_feature(&s->cpu->env, ARM_FEATURE_V7) && + !arm_feature(&s->cpu->env, ARM_FEATURE_V8) && + s->num_irq > 32) { + error_setg(errp, "Armv6-M NVIC cannot exceed 32 external IRQs"); + return; + } + qdev_init_gpio_in(dev, set_irq_level, s->num_irq); /* include space for internal exception vectors */ diff --git a/tests/tcg/arm/system/meson.build b/tests/tcg/arm/system/meson.build index 4c77b9c3d6..5286997670 100644 --- a/tests/tcg/arm/system/meson.build +++ b/tests/tcg/arm/system/meson.build @@ -39,6 +39,12 @@ tests += { '-T', files('test-armv6m-undef.ld')], 'qemu_args': ['-M', 'microbit', qemu_base_args], }, + 'test-armv6m-nvic.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-nvic.S b/tests/tcg/arm/system/test-armv6m-nvic.S new file mode 100644 index 0000000000..ecb29eaa3d --- /dev/null +++ b/tests/tcg/arm/system/test-armv6m-nvic.S @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Test Armv6-M NVIC register behavior. */ + +.syntax unified +.cpu cortex-m0 +.thumb + +#define SRAM_BASE 0x20000000 +#define SRAM_SIZE (16 * 1024) + +#define NVIC_ICTR 0xe000e004 +#define NVIC_IABR0 0xe000e300 +#define NVIC_IPR0 0xe000e400 + +#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 44 + .word 0 + .endr + +.equ exc_reset_thumb, reset + 1 +.global exc_reset_thumb +reset: + /* ICTR is reserved and reads as zero on Armv6-M. */ + ldr r0, =NVIC_ICTR + ldr r1, [r0] + cmp r1, 0 + bne failure + + /* The Active Bit Register is reserved and behaves as RAZ/WI. */ + ldr r0, =NVIC_IABR0 + movs r1, 1 + str r1, [r0] + ldr r1, [r0] + cmp r1, 0 + bne failure + + /* Cortex-M0 implements the two most significant priority bits. */ + ldr r0, =NVIC_IPR0 + movs r1, 0xff + strb r1, [r0] + ldrb r1, [r0] + cmp r1, 0xc0 + 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
