Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 45 additions & 9 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-24.04
strategy:
matrix:
board: [discoveryf4, discoveryf429, netduinoplus2]
board: [discoveryf4, discoveryf429, b-l475e-iot01a]

steps:
- uses: actions/checkout@v6
Expand Down Expand Up @@ -52,9 +52,13 @@ jobs:
- app: tests
name: "Kernel Test Suite"
config: USER_APP_TESTS
config_extra: ""
- app: posix
name: "POSIX Compliance (PSE51+PSE52)"
config: USER_APP_POSIX
# POSIX test suite is larger; disable symbol map and kprobes
# to fit kernel + user code in 96KB SRAM1.
config_extra: "SYMMAP=n KPROBES=n"

name: test (${{ matrix.app }})
steps:
Expand All @@ -66,15 +70,47 @@ jobs:
release: '15.2.Rel1'

- name: Install QEMU
run: sudo apt-get update && sudo apt-get install -y qemu-system-arm

- name: Configure for netduinoplus2 with ${{ matrix.name }}
env:
GH_TOKEN: ${{ github.token }}
QEMU_VERSION: '10.2.2'
run: |
asset="qemu-${QEMU_VERSION}-arm-softmmu-linux-x86_64.tar.gz"

# Try prebuilt binary from GitHub release first, fall back to
# building from source (needed until qemu-build.yml has run once).
dl_err=$(gh release download "qemu-v${QEMU_VERSION}" \
--pattern "$asset" --dir /tmp 2>&1) && dl_ok=1 || dl_ok=0
if [ "$dl_ok" = 1 ]; then
echo "[QEMU] Using prebuilt binary from release"
sudo tar -xzf "/tmp/${asset}" -C /opt
elif echo "$dl_err" | grep -qi "release not found"; then
echo "[QEMU] Release not found, building from source..."
sudo apt-get update
sudo apt-get install -y ninja-build pkg-config libglib2.0-dev libpixman-1-dev
curl -fsSL "https://download.qemu.org/qemu-${QEMU_VERSION}.tar.xz" | tar xJ
cd "qemu-${QEMU_VERSION}"
./configure --target-list=arm-softmmu --prefix=/opt/qemu --disable-docs
make -j$(nproc)
sudo make install
cd ..
else
echo "[QEMU] gh release download failed: $dl_err"
exit 1
fi

echo "/opt/qemu/bin" >> "$GITHUB_PATH"
/opt/qemu/bin/qemu-system-arm --version
/opt/qemu/bin/qemu-system-arm -M help | awk '{print $1}' | grep -Fx b-l475e-iot01a

- name: Configure for b-l475e-iot01a with ${{ matrix.name }}
run: |
make netduinoplus2_defconfig
# Enable QEMU mode and selected test suite
# Bootstrap Kconfig tools (cloned on demand by make, but we
# need them before the first make invocation here)
make tools/kconfig/kconfiglib.py
cp board/b-l475e-iot01a/defconfig .config
# Enable selected test suite on top of board defaults
python3 tools/kconfig/setconfig.py \
QEMU=y \
${{ matrix.config }}=y
${{ matrix.config }}=y ${{ matrix.config_extra }}
python3 tools/kconfig/genconfig.py --header-path include/autoconf.h Kconfig

- name: Verify configuration
Expand All @@ -91,7 +127,7 @@ jobs:
- name: Run MPU fault test
if: matrix.app == 'tests'
run: make run-tests FAULT=mpu
continue-on-error: true # MPU not fully emulated in QEMU
continue-on-error: true # MPU fault test may behave differently under QEMU

- name: Run stack canary fault test
if: matrix.app == 'tests'
Expand Down
76 changes: 76 additions & 0 deletions .github/workflows/qemu-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: Build QEMU

# Build a minimal QEMU (arm-softmmu only) and upload as a GitHub release.
# The test jobs in build.yml download this prebuilt binary instead of
# compiling QEMU from source on every run.
#
# Trigger manually or bump QEMU_VERSION to rebuild.

on:
workflow_dispatch:
inputs:
qemu_version:
description: 'QEMU version to build (e.g. 10.2.2)'
required: true
default: '10.2.2'

env:
QEMU_VERSION: ${{ inputs.qemu_version || '10.2.2' }}

permissions:
contents: write # create releases

jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6

- name: Validate version format
run: |
if ! echo "${QEMU_VERSION}" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "ERROR: Invalid QEMU_VERSION '${QEMU_VERSION}' (expected N.N.N)"
exit 1
fi

- name: Install build dependencies
run: |
sudo apt-get update
sudo apt-get install -y ninja-build pkg-config libglib2.0-dev libpixman-1-dev

- name: Build QEMU ${{ env.QEMU_VERSION }} (arm-softmmu)
run: |
curl -fsSL "https://download.qemu.org/qemu-${QEMU_VERSION}.tar.xz" | tar xJ
cd "qemu-${QEMU_VERSION}"
./configure \
--target-list=arm-softmmu \
--prefix=/opt/qemu \
--disable-docs
make -j$(nproc)
sudo make install

- name: Verify
run: |
/opt/qemu/bin/qemu-system-arm --version
/opt/qemu/bin/qemu-system-arm -M help | awk '{print $1}' | grep -Fx b-l475e-iot01a

- name: Package
run: |
tar -czf "qemu-${QEMU_VERSION}-arm-softmmu-linux-x86_64.tar.gz" -C /opt qemu

- name: Create release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
tag="qemu-v${QEMU_VERSION}"
asset="qemu-${QEMU_VERSION}-arm-softmmu-linux-x86_64.tar.gz"

# Upload to existing release, or create a new one.
# Upload first so the old asset stays available until replaced.
if gh release view "$tag" >/dev/null 2>&1; then
gh release upload "$tag" "$asset" --clobber
else
gh release create "$tag" "$asset" \
--title "QEMU ${QEMU_VERSION} (arm-softmmu, linux-x86_64)" \
--notes "Prebuilt QEMU ${QEMU_VERSION} (arm-softmmu only) for CI test jobs."
fi
18 changes: 10 additions & 8 deletions Documentation/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ F9 Microkernel supports the following boards:
* [STM32F429I-DISC1](https://www.st.com/en/evaluation-tools/32f429idiscovery.html)
* [NUCLEO-F429ZI](https://www.st.com/en/evaluation-tools/nucleo-f429zi.html)
- All supported boards are based on the ARM Cortex-M4F core. F9 should work on any STM32F40x/STM32F429/STM32F439 microcontroller.
* Netduino Plus 2 (STM32F405RGT6)
- 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.
* [B-L475E-IOT01A](https://www.st.com/en/evaluation-tools/b-l475e-iot01a.html)
- Supported by upstream QEMU and used as the default emulation target.

## Toolchain Requirements

Expand Down Expand Up @@ -89,16 +89,18 @@ KDB communicates via USART. The port can be selected during `make config`.

## QEMU Emulation

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

```shell
qemu-system-arm -M netduinoplus2 -nographic -serial mon:stdio \
-kernel build/netduinoplus2/f9.elf
qemu-system-arm -M b-l475e-iot01a -nographic \
-semihosting -serial mon:stdio \
-kernel build/b-l475e-iot01a/f9.elf
```

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

## Serial Terminal Setup

Expand Down
17 changes: 11 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ endif

ifeq "$(CONFIG_BOARD_STM32F429DISCOVERY)" "y"
BOARD ?= discoveryf429
else ifeq "$(CONFIG_BOARD_NETDUINOPLUS2)" "y"
BOARD ?= netduinoplus2
else ifeq "$(CONFIG_BOARD_STM32F429NUCLEO)" "y"
BOARD ?= nucleof429
else ifeq "$(CONFIG_BOARD_B_L475E_IOT01A)" "y"
BOARD ?= b-l475e-iot01a
else
BOARD ?= discoveryf4
endif
Expand All @@ -32,8 +32,9 @@ out ?= build/$(BOARD)
# output directory for host build targets
out_host ?= build/host

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

includes-user = user/include
Expand Down Expand Up @@ -114,8 +115,12 @@ include mk/generic.mk

# Run tests with clean output (filtered debug messages)
.PHONY: qemu-clean
qemu-clean:
qemu-clean: $(out)/f9.elf
@echo "Running F9 tests (clean output)..."
@python3 scripts/qemu-test.py $(out)/f9.elf -t 75 2>&1 | \
@$(PYTHON) scripts/qemu-test.py $(out)/f9.elf -t 75 2>&1 | \
grep -vE "^(IPC: |pager_|THREAD_CREATE:)" | \
grep -vE "^\[TEST:(RUN|PASS|FAIL|SKIP|START)\]" || true

# Note: 'make run-tests' target defined in mk/generic.mk
# Supports fault testing: make run-tests FAULT=mpu
# Auto-detects board and QEMU machine from build path
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ while adding advanced features from industrial RTOSes.
- UTCBs: Always-mapped user-level thread control blocks for fast syscall argument access

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

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

Press `Ctrl+A` and then `X` to exit QEMU. Press `?` in KDB for debug menu (requires `CONFIG_KDB`).
Press `Ctrl+A` then `X` to exit QEMU. Press `?` for KDB debug menu (requires `CONFIG_KDB`).

QEMU uses the B-L475E-IOT01A machine with ARM semihosting for output and USART1
for KDB input. Both `-semihosting` and `-serial mon:stdio` are added automatically.

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

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

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

Expand Down
54 changes: 20 additions & 34 deletions board/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,38 @@ config BOARD_STM32F429DISCOVERY
help
STM32F429 Discovery board with STM32F429ZIT6 MCU and LCD.

config BOARD_NETDUINOPLUS2
bool "Netduino Plus 2"
select PLATFORM_STM32F4
help
Netduino Plus 2 board with STM32F405RGT6 MCU.
This board is supported by upstream QEMU for emulation.

config BOARD_STM32F429NUCLEO
bool "STM32F429 Nucleo"
select PLATFORM_STM32F429
help
STM32F429 Nucleo board with STM32F429ZIT6 MCU.

config BOARD_B_L475E_IOT01A
bool "B-L475E-IOT01A Discovery"
select PLATFORM_STM32L4
select QEMU
help
STMicroelectronics B-L475E-IOT01A Discovery board with STM32L475VG MCU.
Includes Cortex-M4F with FPU, MPU, and full QEMU support with FPU emulation.
QEMU mode is automatically enabled for this board.

QEMU command:
qemu-system-arm -M b-l475e-iot01a -nographic -kernel build/b-l475e-iot01a/f9.elf
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.

endchoice

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

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

Note: Automatically enabled and mandatory for B-L475E-IOT01A board.

# Hardware feature availability flags
# These control which ARM architecture tests can run based on
# platform capabilities and emulation limitations.
Expand All @@ -65,29 +71,6 @@ config HAS_PRECISE_TIMING

Disabled in QEMU because timing is not cycle-accurate.

config MPU_MOCK
bool "Software MPU mock for testing"
depends on QEMU
default y if QEMU
help
Enable minimal MPU register mock for test_arm_mpu_config in QEMU.

Returns MPU_TYPE = 0x800 (8 regions, unified) to validate that
MPU_TYPE register is readable without QEMU hanging.

For full MPU validation, test on real hardware with actual MPU.

config SCB_MOCK
bool "Software SCB mock for testing"
depends on QEMU
default y if QEMU
help
Enable minimal SCB register mock for test_arm_unaligned in QEMU.

Returns SCB_CCR = 0x200 (STKALIGN enabled, UNALIGN_TRP disabled)
to validate SCB_CCR register readability without QEMU hanging.

For full SCB validation, test on real hardware with actual SCB.

endmenu

Expand All @@ -97,3 +80,6 @@ config PLATFORM_STM32F4

config PLATFORM_STM32F429
bool

config PLATFORM_STM32L4
bool
6 changes: 3 additions & 3 deletions board/netduinoplus2/board.c → board/b-l475e-iot01a/board.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
*/

#include "board.h"
#include <platform/stm32f4/gpio.h>
#include <platform/stm32f4/usart.h>
#include <platform/stm32l4/gpio.h>
#include <platform/stm32l4/usart.h>

struct usart_dev console_uart = {
.u_num = 2,
.u_num = 1,
.baud = 115200,
BOARD_USART_CONFIGS.tx =
{
Expand Down
Loading
Loading