Skip to content

Commit 786ea60

Browse files
committed
Switch QEMU from NETDUINOPLUS2 to B-L475E-IOT01A
This replaces Netduino Plus 2 (STM32F4) QEMU target with B-L475E-IOT01A Discovery (STM32L475VG) for proper FPU/MPU emulation, eliminating the mock infrastructure (mpu_mock, scb_mock, safe_mmio) that was papering over the old target's incomplete peripheral emulation. Platform changes: - Add STM32L4 platform support (registers, GPIO, RCC, USART, NVIC, linker scripts with correct L4 memory map and no CCM RAM) - Fix L4 register addresses: USART1 at 0x40013800, RCC enable registers at correct L4 offsets, GPIO clocks on AHB2 (not AHB1), PLL source set to MSI (not HSE), USART_IT_CR offsets for L4 - Add full L4 USART register ops (ISR/RDR/TDR layout) - Add ARM semihosting for console I/O under QEMU FPU support: - Fix irq_restore: single asm block with __builtin_offsetof prevents compiler from reusing clobbered registers after ldm {r4-r11} - Add -mgeneral-regs-only to kernel CFLAGS to prevent GCC from emitting VFP instructions for non-FP operations in handler mode - Add FPU lazy context save/restore (d8-d15) in PendSV handler IPC fix: - Fix L4_Ipc naked function: reload UTCB MR pointer from current_utcb after SVC return instead of reusing LR (which the exception frame restores to the caller's return address) KDB: - Add USART1 RX interrupt path for KDB input under QEMU semihosting (CONFIG_KDB_UART_INPUT, gated on CONFIG_QEMU) - Improve hard fault handler to read correct stack (MSP vs PSP) Build/test: - Update qemu-test.py: auto-detect board, add -semihosting for L4, fail on unsupported boards instead of silent fallback - Bootstrap Kconfig tools in CI test job before direct Python usage - Update CI workflow: replace netduinoplus2 with b-l475e-iot01a - Remove Netduino Plus 2 board, STM32F1 platform, mock infrastructure
1 parent 035a501 commit 786ea60

86 files changed

Lines changed: 4709 additions & 2530 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build.yml

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
runs-on: ubuntu-24.04
1515
strategy:
1616
matrix:
17-
board: [discoveryf4, discoveryf429, netduinoplus2]
17+
board: [discoveryf4, discoveryf429, b-l475e-iot01a]
1818

1919
steps:
2020
- uses: actions/checkout@v6
@@ -66,14 +66,28 @@ jobs:
6666
release: '15.2.Rel1'
6767

6868
- name: Install QEMU
69-
run: sudo apt-get update && sudo apt-get install -y qemu-system-arm
70-
71-
- name: Configure for netduinoplus2 with ${{ matrix.name }}
69+
env:
70+
GH_TOKEN: ${{ github.token }}
71+
QEMU_VERSION: '10.2.2'
72+
run: |
73+
# Download prebuilt QEMU from GitHub release (built by qemu-build.yml)
74+
asset="qemu-${QEMU_VERSION}-arm-softmmu-linux-x86_64.tar.gz"
75+
gh release download "qemu-v${QEMU_VERSION}" \
76+
--pattern "$asset" \
77+
--dir /tmp
78+
sudo tar -xzf "/tmp/${asset}" -C /opt
79+
echo "/opt/qemu/bin" >> "$GITHUB_PATH"
80+
/opt/qemu/bin/qemu-system-arm --version
81+
/opt/qemu/bin/qemu-system-arm -M help | awk '{print $1}' | grep -Fx b-l475e-iot01a
82+
83+
- name: Configure for b-l475e-iot01a with ${{ matrix.name }}
7284
run: |
73-
make netduinoplus2_defconfig
74-
# Enable QEMU mode and selected test suite
85+
# Bootstrap Kconfig tools (cloned on demand by make, but we
86+
# need them before the first make invocation here)
87+
make tools/kconfig/kconfiglib.py
88+
cp board/b-l475e-iot01a/defconfig .config
89+
# Enable selected test suite on top of board defaults
7590
python3 tools/kconfig/setconfig.py \
76-
QEMU=y \
7791
${{ matrix.config }}=y
7892
python3 tools/kconfig/genconfig.py --header-path include/autoconf.h Kconfig
7993
@@ -91,7 +105,7 @@ jobs:
91105
- name: Run MPU fault test
92106
if: matrix.app == 'tests'
93107
run: make run-tests FAULT=mpu
94-
continue-on-error: true # MPU not fully emulated in QEMU
108+
continue-on-error: true # MPU fault test may behave differently under QEMU
95109

96110
- name: Run stack canary fault test
97111
if: matrix.app == 'tests'

.github/workflows/qemu-build.yml

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
name: Build QEMU
2+
3+
# Build a minimal QEMU (arm-softmmu only) and upload as a GitHub release.
4+
# The test jobs in build.yml download this prebuilt binary instead of
5+
# compiling QEMU from source on every run.
6+
#
7+
# Trigger manually or bump QEMU_VERSION to rebuild.
8+
9+
on:
10+
workflow_dispatch:
11+
inputs:
12+
qemu_version:
13+
description: 'QEMU version to build (e.g. 10.2.2)'
14+
required: true
15+
default: '10.2.2'
16+
17+
env:
18+
QEMU_VERSION: ${{ inputs.qemu_version || '10.2.2' }}
19+
20+
permissions:
21+
contents: write # create releases
22+
23+
jobs:
24+
build:
25+
runs-on: ubuntu-24.04
26+
steps:
27+
- uses: actions/checkout@v6
28+
29+
- name: Validate version format
30+
run: |
31+
if ! echo "${QEMU_VERSION}" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
32+
echo "ERROR: Invalid QEMU_VERSION '${QEMU_VERSION}' (expected N.N.N)"
33+
exit 1
34+
fi
35+
36+
- name: Install build dependencies
37+
run: |
38+
sudo apt-get update
39+
sudo apt-get install -y ninja-build pkg-config libglib2.0-dev libpixman-1-dev
40+
41+
- name: Build QEMU ${{ env.QEMU_VERSION }} (arm-softmmu)
42+
run: |
43+
curl -sL "https://download.qemu.org/qemu-${QEMU_VERSION}.tar.xz" | tar xJ
44+
cd "qemu-${QEMU_VERSION}"
45+
./configure \
46+
--target-list=arm-softmmu \
47+
--prefix=/opt/qemu \
48+
--disable-docs
49+
make -j$(nproc)
50+
sudo make install
51+
52+
- name: Verify
53+
run: |
54+
/opt/qemu/bin/qemu-system-arm --version
55+
/opt/qemu/bin/qemu-system-arm -M help | awk '{print $1}' | grep -Fx b-l475e-iot01a
56+
57+
- name: Package
58+
run: |
59+
tar -czf "qemu-${QEMU_VERSION}-arm-softmmu-linux-x86_64.tar.gz" -C /opt qemu
60+
61+
- name: Create release
62+
env:
63+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
64+
run: |
65+
tag="qemu-v${QEMU_VERSION}"
66+
asset="qemu-${QEMU_VERSION}-arm-softmmu-linux-x86_64.tar.gz"
67+
68+
# Upload to existing release, or create a new one.
69+
# Upload first so the old asset stays available until replaced.
70+
if gh release view "$tag" >/dev/null 2>&1; then
71+
gh release upload "$tag" "$asset" --clobber
72+
else
73+
gh release create "$tag" "$asset" \
74+
--title "QEMU ${QEMU_VERSION} (arm-softmmu, linux-x86_64)" \
75+
--notes "Prebuilt QEMU ${QEMU_VERSION} (arm-softmmu only) for CI test jobs."
76+
fi

Documentation/quick-start.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ F9 Microkernel supports the following boards:
77
* [STM32F429I-DISC1](https://www.st.com/en/evaluation-tools/32f429idiscovery.html)
88
* [NUCLEO-F429ZI](https://www.st.com/en/evaluation-tools/nucleo-f429zi.html)
99
- All supported boards are based on the ARM Cortex-M4F core. F9 should work on any STM32F40x/STM32F429/STM32F439 microcontroller.
10-
* Netduino Plus 2 (STM32F405RGT6)
11-
- Supported by upstream [QEMU for emulation](https://www.qemu.org/docs/master/system/arm/stm32.html), making it ideal for development and testing without hardware.
10+
* [B-L475E-IOT01A](https://www.st.com/en/evaluation-tools/b-l475e-iot01a.html)
11+
- Supported by upstream QEMU and used as the default emulation target.
1212

1313
## Toolchain Requirements
1414

@@ -89,16 +89,18 @@ KDB communicates via USART. The port can be selected during `make config`.
8989
9090
## QEMU Emulation
9191

92-
For Netduino Plus 2 under QEMU, the default configuration uses USART1, which
93-
QEMU routes to the console. Run with:
92+
For B-L475E-IOT01A under QEMU, semihosting carries normal console output and
93+
USART1 is reserved for KDB input. Run with:
9494

9595
```shell
96-
qemu-system-arm -M netduinoplus2 -nographic -serial mon:stdio \
97-
-kernel build/netduinoplus2/f9.elf
96+
qemu-system-arm -M b-l475e-iot01a -nographic \
97+
-semihosting -serial mon:stdio \
98+
-kernel build/b-l475e-iot01a/f9.elf
9899
```
99100

100-
Note: `-serial mon:stdio` is required for interactive KDB shell.
101-
The `mon:` prefix enables QEMU monitor access via `Ctrl+a` and `c`. Exit with `Ctrl+a` and `x`.
101+
Note: `-serial mon:stdio` is still required for interactive KDB shell.
102+
The `mon:` prefix enables QEMU monitor access via `Ctrl+A` then `c`. Exit with
103+
`Ctrl+A` then `x`.
102104

103105
## Serial Terminal Setup
104106

Makefile

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ endif
1616

1717
ifeq "$(CONFIG_BOARD_STM32F429DISCOVERY)" "y"
1818
BOARD ?= discoveryf429
19-
else ifeq "$(CONFIG_BOARD_NETDUINOPLUS2)" "y"
20-
BOARD ?= netduinoplus2
2119
else ifeq "$(CONFIG_BOARD_STM32F429NUCLEO)" "y"
2220
BOARD ?= nucleof429
21+
else ifeq "$(CONFIG_BOARD_B_L475E_IOT01A)" "y"
22+
BOARD ?= b-l475e-iot01a
2323
else
2424
BOARD ?= discoveryf4
2525
endif
@@ -32,8 +32,9 @@ out ?= build/$(BOARD)
3232
# output directory for host build targets
3333
out_host ?= build/host
3434

35-
# QEMU command for netduinoplus2 emulation
36-
# Usage: qemu-system-arm -M netduinoplus2 -nographic -kernel build/netduinoplus2/f9.elf
35+
# QEMU emulation support (auto-detects board from build path)
36+
# Usage: make run-tests
37+
# Direct: qemu-system-arm -M b-l475e-iot01a -nographic -kernel build/b-l475e-iot01a/f9.elf
3738
QEMU ?= qemu-system-arm
3839

3940
includes-user = user/include
@@ -114,8 +115,12 @@ include mk/generic.mk
114115

115116
# Run tests with clean output (filtered debug messages)
116117
.PHONY: qemu-clean
117-
qemu-clean:
118+
qemu-clean: $(out)/f9.elf
118119
@echo "Running F9 tests (clean output)..."
119-
@python3 scripts/qemu-test.py $(out)/f9.elf -t 75 2>&1 | \
120+
@$(PYTHON) scripts/qemu-test.py $(out)/f9.elf -t 75 2>&1 | \
120121
grep -vE "^(IPC: |pager_|THREAD_CREATE:)" | \
121122
grep -vE "^\[TEST:(RUN|PASS|FAIL|SKIP|START)\]" || true
123+
124+
# Note: 'make run-tests' target defined in mk/generic.mk
125+
# Supports fault testing: make run-tests FAULT=mpu
126+
# Auto-detects board and QEMU machine from build path

README.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ while adding advanced features from industrial RTOSes.
3333
- UTCBs: Always-mapped user-level thread control blocks for fast syscall argument access
3434

3535
### Hardware Support
36-
- ARM Cortex-M3/M4/M4F: Optimized for Cortex-M architecture
36+
- ARM Cortex-M4/M4F: Optimized for Cortex-M architecture
3737
- NVIC: Nested Vectored Interrupt Controller integration
3838
- Bit Banding: Hardware bit manipulation support (where available)
39-
- FPU: Lazy context switching for Cortex-M4F floating-point unit
39+
- FPU: Lazy context switching for Cortex-M4F floating-point unit (VFPv4-D16)
4040

4141
### Development Tools
4242
- KDB: In-kernel debugger with thread, memory, and timer inspection
@@ -124,13 +124,16 @@ make flash # Flash to STM32F4 board (requires stlink)
124124
make qemu
125125
```
126126

127-
Press `Ctrl+A` and then `X` to exit QEMU. Press `?` in KDB for debug menu (requires `CONFIG_KDB`).
127+
Press `Ctrl+A` then `X` to exit QEMU. Press `?` for KDB debug menu (requires `CONFIG_KDB`).
128+
129+
QEMU uses the B-L475E-IOT01A machine with ARM semihosting for output and USART1
130+
for KDB input. Both `-semihosting` and `-serial mon:stdio` are added automatically.
128131

129132
### Supported Hardware
130133
- STM32F4DISCOVERY (STM32F407VG)
131134
- STM32F429I-DISC1 (STM32F429ZI)
132135
- NUCLEO-F429ZI (STM32F429ZI)
133-
- Netduino Plus 2 (STM32F405RG) - QEMU only, used for automated testing
136+
- B-L475E-IOT01A (STM32L475VG) - QEMU target with FPU and MPU emulation
134137

135138
For detailed instructions including toolchain setup, serial configuration, and debugging,
136139
see [Documentation/quick-start.md](Documentation/quick-start.md).
@@ -149,8 +152,9 @@ Run `make config` to configure options via menu. Key options:
149152
| `CONFIG_KTIMER_TICKLESS` | Tickless scheduling (power efficiency) |
150153
| `CONFIG_MAX_THREADS` | Maximum number of threads |
151154
| `CONFIG_MAX_KT_EVENTS` | Maximum kernel timer events |
155+
| `CONFIG_FPU` | FPU support with lazy context switching (Cortex-M4F) |
152156
| `CONFIG_PANIC_DUMP_STACK` | Dump stack on kernel panic |
153-
| `CONFIG_QEMU` | QEMU emulation workarounds |
157+
| `CONFIG_QEMU` | QEMU emulation mode (auto-enabled for B-L475E-IOT01A) |
154158

155159
For build system details, see [Documentation/build-system.md](Documentation/build-system.md).
156160

board/Kconfig

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -22,32 +22,38 @@ config BOARD_STM32F429DISCOVERY
2222
help
2323
STM32F429 Discovery board with STM32F429ZIT6 MCU and LCD.
2424

25-
config BOARD_NETDUINOPLUS2
26-
bool "Netduino Plus 2"
27-
select PLATFORM_STM32F4
28-
help
29-
Netduino Plus 2 board with STM32F405RGT6 MCU.
30-
This board is supported by upstream QEMU for emulation.
31-
3225
config BOARD_STM32F429NUCLEO
3326
bool "STM32F429 Nucleo"
3427
select PLATFORM_STM32F429
3528
help
3629
STM32F429 Nucleo board with STM32F429ZIT6 MCU.
3730

31+
config BOARD_B_L475E_IOT01A
32+
bool "B-L475E-IOT01A Discovery"
33+
select PLATFORM_STM32L4
34+
select QEMU
35+
help
36+
STMicroelectronics B-L475E-IOT01A Discovery board with STM32L475VG MCU.
37+
Includes Cortex-M4F with FPU, MPU, and full QEMU support with FPU emulation.
38+
QEMU mode is automatically enabled for this board.
39+
40+
QEMU command:
41+
qemu-system-arm -M b-l475e-iot01a -nographic -kernel build/b-l475e-iot01a/f9.elf
42+
3843
endchoice
3944

4045
config QEMU
41-
bool "QEMU emulation mode"
42-
default y if BOARD_NETDUINOPLUS2
46+
bool "QEMU emulation mode" if !BOARD_B_L475E_IOT01A
4347
help
4448
Enable workarounds for QEMU emulation limitations:
45-
- Use synchronous UART output (QEMU TXE interrupt unreliable)
46-
- Place bitmaps in regular SRAM (QEMU lacks CCM RAM emulation)
49+
- Use semihosting for console I/O (reliable in QEMU)
50+
- Use synchronous UART output if UART is selected
4751

4852
Enable this when running under QEMU. Disable for real hardware
4953
to get better performance.
5054

55+
Note: Automatically enabled and mandatory for B-L475E-IOT01A board.
56+
5157
# Hardware feature availability flags
5258
# These control which ARM architecture tests can run based on
5359
# platform capabilities and emulation limitations.
@@ -65,29 +71,6 @@ config HAS_PRECISE_TIMING
6571

6672
Disabled in QEMU because timing is not cycle-accurate.
6773

68-
config MPU_MOCK
69-
bool "Software MPU mock for testing"
70-
depends on QEMU
71-
default y if QEMU
72-
help
73-
Enable minimal MPU register mock for test_arm_mpu_config in QEMU.
74-
75-
Returns MPU_TYPE = 0x800 (8 regions, unified) to validate that
76-
MPU_TYPE register is readable without QEMU hanging.
77-
78-
For full MPU validation, test on real hardware with actual MPU.
79-
80-
config SCB_MOCK
81-
bool "Software SCB mock for testing"
82-
depends on QEMU
83-
default y if QEMU
84-
help
85-
Enable minimal SCB register mock for test_arm_unaligned in QEMU.
86-
87-
Returns SCB_CCR = 0x200 (STKALIGN enabled, UNALIGN_TRP disabled)
88-
to validate SCB_CCR register readability without QEMU hanging.
89-
90-
For full SCB validation, test on real hardware with actual SCB.
9174

9275
endmenu
9376

@@ -97,3 +80,6 @@ config PLATFORM_STM32F4
9780

9881
config PLATFORM_STM32F429
9982
bool
83+
84+
config PLATFORM_STM32L4
85+
bool
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
*/
55

66
#include "board.h"
7-
#include <platform/stm32f4/gpio.h>
8-
#include <platform/stm32f4/usart.h>
7+
#include <platform/stm32l4/gpio.h>
8+
#include <platform/stm32l4/usart.h>
99

1010
struct usart_dev console_uart = {
11-
.u_num = 2,
11+
.u_num = 1,
1212
.baud = 115200,
1313
BOARD_USART_CONFIGS.tx =
1414
{

board/b-l475e-iot01a/board.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* Copyright (c) 2013-2014 The F9 Microkernel Project. All rights reserved.
2+
* Use of this source code is governed by a BSD-style license that can be
3+
* found in the LICENSE file.
4+
*/
5+
6+
#ifndef B_L475E_IOT01A_BOARD_H_
7+
#define B_L475E_IOT01A_BOARD_H_
8+
9+
#include <platform/stm32l4/gpio.h>
10+
#include <platform/stm32l4/nvic.h>
11+
#include <platform/stm32l4/registers.h>
12+
#include <platform/stm32l4/systick.h>
13+
#include <platform/stm32l4/usart.h>
14+
15+
extern struct usart_dev console_uart;
16+
17+
/* ST-Link VCP uses USART1: PB6 (TX), PB7 (RX) */
18+
#define BOARD_UART_DEVICE USART1_IRQn
19+
#define BOARD_UART_HANDLER USART1_HANDLER
20+
#define BOARD_USART_FUNC af_usart1
21+
#define BOARD_USART_CONFIGS \
22+
.base = USART1_BASE, .rcc_apbenr = RCC_USART1_APBENR, \
23+
.rcc_reset = RCC_APB2RSTR_USART1RST,
24+
#define BOARD_USART_TX_IO_PORT GPIOB
25+
#define BOARD_USART_TX_IO_PIN 6
26+
#define BOARD_USART_RX_IO_PORT GPIOB
27+
#define BOARD_USART_RX_IO_PIN 7
28+
29+
#endif /* B_L475E_IOT01A_BOARD_H_ */
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
# Use of this source code is governed by a BSD-style license that can be
33
# found in the LICENSE file.
44

5-
CHIP := stm32f4
5+
CHIP := stm32l4
66
PLATFORM := stm32
7-
STM32_VARIANT := f4
7+
STM32_VARIANT := l4
88

99
board-y = board.o
1010
loader-board-y = board.loader.o

board/b-l475e-iot01a/defconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
CONFIG_BOARD_B_L475E_IOT01A=y
2+
CONFIG_FPU=y

0 commit comments

Comments
 (0)