Switch QEMU from NETDUINOPLUS2 to B-L475E-IOT01A#185
Conversation
There was a problem hiding this comment.
28 issues found across 83 files
Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="kernel/init.c">
<violation number="1" location="kernel/init.c:65">
P1: Do not dereference `fault_pc` in the HardFault handler; reading `inst[0]` can cause a nested fault and lock up fault handling.</violation>
</file>
<file name="include/platform/stm32l4/systick.h">
<violation number="1" location="include/platform/stm32l4/systick.h:6">
P1: `CORE_CLOCK` is set to 168MHz in the STM32L4 header, but L4 clock init configures 80MHz, so SysTick timing calculations will be wrong.</violation>
</file>
<file name="kernel/memory.c">
<violation number="1" location="kernel/memory.c:381">
P2: The loop limit was reduced from `i < 8` to `i < 7`, permanently wasting MPU region 7. Since the Cortex-M MPU only has 8 regions and region 7 is not reserved for any other purpose (the cleanup loop still clears it to NULL), this appears to be an unintended off-by-one. The stack fpage loop above still uses `i < 8` as its limit, creating an inconsistency.</violation>
</file>
<file name="board/Kconfig">
<violation number="1" location="board/Kconfig:41">
P2: The documented QEMU command for B-L475E-IOT01A omits `-semihosting`, which conflicts with the new QEMU mode behavior and can lead to missing console output when users run the command directly.</violation>
</file>
<file name="include/platform/stm32l4/registers.h">
<violation number="1" location="include/platform/stm32l4/registers.h:69">
P0: SYSCFG base address overlaps USART1 base, so SYSCFG register accesses target the wrong peripheral.</violation>
<violation number="2" location="include/platform/stm32l4/registers.h:791">
P1: SYSCFG reset bit mask is set to USART1's bit, causing reset operations to hit the wrong peripheral.</violation>
<violation number="3" location="include/platform/stm32l4/registers.h:873">
P1: SYSCFG clock-enable mask uses USART1's bit, so SYSCFG clock control is incorrect.</violation>
</file>
<file name="kernel/thread.c">
<violation number="1" location="kernel/thread.c:275">
P1: When the cycle guard fires, the thread is returned but not linked into the parent's child chain. A later `thread_destroy` on this thread will NULL-dereference while walking the sibling list. Either undo `thread_init` (remove from thread_map) and return `NULL`, or still link the thread despite the warning.</violation>
</file>
<file name="platform/stm32-common/gpio-l4.c">
<violation number="1" location="platform/stm32-common/gpio-l4.c:145">
P2: Use atomic BSRR set writes instead of ODR read-modify-write in `gpio_out_high` to avoid losing concurrent GPIO updates.</violation>
<violation number="2" location="platform/stm32-common/gpio-l4.c:150">
P2: Use atomic BSRR reset writes instead of ODR read-modify-write in `gpio_out_low` to prevent race-prone GPIO clears.</violation>
</file>
<file name="include/platform/stm32l4/hwtimer.h">
<violation number="1" location="include/platform/stm32l4/hwtimer.h:6">
P2: The header guard macro uses `STM32F4` in an STM32L4 header. Rename it to `STM32L4` to avoid incorrect guard identity and possible include conflicts.</violation>
</file>
<file name="scripts/qemu-kdb-auto.py">
<violation number="1" location="scripts/qemu-kdb-auto.py:67">
P1: QEMU stdin is captured by a pipe but terminal input is never forwarded, so manual KDB input (and further interactive commands) cannot work.</violation>
</file>
<file name="include/platform/stm32l4/gpio.h">
<violation number="1" location="include/platform/stm32l4/gpio.h:62">
P2: `af_usart6` is exposed for STM32L4 even though this target defines USART6 as unavailable; remove this alias to avoid advertising an invalid peripheral mapping.</violation>
</file>
<file name="include/platform/stm32l4/usart.h">
<violation number="1" location="include/platform/stm32l4/usart.h:6">
P1: This stm32l4 header reuses the stm32f4 include guard macro, creating a real guard collision with `include/platform/stm32f4/usart.h`. Use an L4-specific guard name to avoid include-order-dependent header omission.</violation>
</file>
<file name="include/platform/stm32l4/syscfg.h">
<violation number="1" location="include/platform/stm32l4/syscfg.h:6">
P2: Use an STM32L4-specific include guard; reusing the STM32F4 guard can cause this header to be silently excluded when both platform headers are seen.</violation>
</file>
<file name="platform/stm32l4/Kconfig">
<violation number="1" location="platform/stm32l4/Kconfig:1">
P2: This new Kconfig file is an exact duplicate of `platform/stm32f4/Kconfig`, creating high-maintenance duplicated platform config that can drift over time.</violation>
</file>
<file name="platform/stm32l4/f9_sram.ld">
<violation number="1" location="platform/stm32l4/f9_sram.ld:117">
P3: This comment is stale and references the removed `netduinoplus2` target, which makes the linker rationale misleading for STM32L4 maintenance.</violation>
</file>
<file name="include/platform/stm32l4/nvic_private.h">
<violation number="1" location="include/platform/stm32l4/nvic_private.h:2">
P3: This file duplicates the STM32F429 NVIC private table verbatim, creating high-maintenance copy-paste logic likely to drift.</violation>
</file>
<file name="scripts/qemu-test.py">
<violation number="1" location="scripts/qemu-test.py:160">
P2: Board auto-detection uses raw substring matching on the whole path, which can select the wrong machine for custom paths.</violation>
<violation number="2" location="scripts/qemu-test.py:194">
P1: The `script` wrapper is invoked with invalid arguments, so QEMU fails to launch on hosts that have `script` installed.</violation>
</file>
<file name="include/platform/stm32l4/exti.h">
<violation number="1" location="include/platform/stm32l4/exti.h:1">
P1: The stm32l4 EXTI header reuses the stm32f4 include guard macro, so including both headers can silently drop one header due to guard collision.</violation>
<violation number="2" location="include/platform/stm32l4/exti.h:4">
P1: This L4 header includes the F4 GPIO header, which drags in F4 register definitions instead of L4 ones.</violation>
</file>
<file name="include/platform/stm32l4/rcc.h">
<violation number="1" location="include/platform/stm32l4/rcc.h:13">
P2: `RCC_FLAG_MSIRDY` is encoded for the wrong register, so `RCC_GetFlagStatus` checks `RCC_CSR` instead of `RCC_CR`.</violation>
</file>
<file name="user/lib/l4/platform/syscalls.c">
<violation number="1" location="user/lib/l4/platform/syscalls.c:153">
P2: Hard-coded `#48` offset for `utcb->mr_low[0]` is fragile and inconsistent with the `__builtin_offsetof` approach used in `irq_restore` (per the PR description). Pass the offset as an `"i"` operand to keep the asm in sync with the struct layout.
This offset appears three times in this function and would silently break if any field is added before `mr_low` in `utcb_t`.</violation>
</file>
<file name="platform/stm32l4/usart.c">
<violation number="1" location="platform/stm32l4/usart.c:100">
P1: USART init sets the wrong CR1 UE bit for STM32L4, so the peripheral may never be enabled.</violation>
</file>
<file name="scripts/qemu-kdb.sh">
<violation number="1" location="scripts/qemu-kdb.sh:42">
P1: QEMU stdin is wired to a FIFO without a persistent writer, which can block startup or feed EOF between key events.</violation>
<violation number="2" location="scripts/qemu-kdb.sh:48">
P3: Use `printf` instead of `echo` so only `?` is sent to KDB (no trailing newline).</violation>
</file>
<file name="platform/stm32-common/rcc.c">
<violation number="1" location="platform/stm32-common/rcc.c:171">
P2: The PLL-to-SYSCLK switch timeout has no fallback, unlike the PLL lock timeout which properly does `goto fallback_clock`. If the switch fails, Flash wait states remain configured for 80MHz while the system actually runs on HSI/MSI, risking bus faults or incorrect peripheral timing.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
19 issues found across 85 files
Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="scripts/qemu-test.py">
<violation number="1" location="scripts/qemu-test.py:196">
P1: The `script(1)` wrapper is built with invalid arguments, so QEMU launch can fail whenever `script` is present.</violation>
</file>
<file name="kernel/thread.c">
<violation number="1" location="kernel/thread.c:275">
P1: Returning `thr` after detecting a child-chain cycle leaves the thread in `thread_map` with `t_parent = caller` but not linked into the caller's child/sibling chain. If `thread_destroy` is later called on this thread, it will NULL-dereference while walking the parent's child list trying to unlink it.
Either destroy the thread and return `NULL`, or link it into the chain before returning.</violation>
</file>
<file name="include/platform/stm32l4/exti.h">
<violation number="1" location="include/platform/stm32l4/exti.h:1">
P1: Header guard collides with `stm32f4/exti.h`; one platform header can suppress the other based on include order.</violation>
<violation number="2" location="include/platform/stm32l4/exti.h:4">
P1: Including `stm32f4/gpio.h` in the STM32L4 EXTI header mixes incompatible register definitions and can produce wrong hardware addresses.</violation>
</file>
<file name="include/platform/stm32l4/systick.h">
<violation number="1" location="include/platform/stm32l4/systick.h:1">
P2: The include guard was renamed to an F4 macro in the STM32L4 header, which collides with the existing STM32F4 systick header and can cause the wrong header to be skipped.</violation>
<violation number="2" location="include/platform/stm32l4/systick.h:6">
P1: `CORE_CLOCK` is set to 168MHz in the STM32L4 systick header, but the L4 clock configuration is 80MHz. This will skew systick-based timing and timeout calculations.</violation>
</file>
<file name="platform/stm32l4/f9.ld">
<violation number="1" location="platform/stm32l4/f9.ld:159">
P1: mem1_start is now placed in RamLoc, but MEM1 is defined as the 0x10000000 AHB/CCM pool. This makes the MEM1 range inverted (start > end), corrupting the memory map and allowing bogus memory descriptors.</violation>
</file>
<file name="include/platform/stm32l4/registers.h">
<violation number="1" location="include/platform/stm32l4/registers.h:69">
P1: `SYSCFG_BASE` is mapped to the same APB2 offset as `USART1_BASE`, so SYSCFG register writes alias USART1 space and hit the wrong peripheral.</violation>
</file>
<file name="user/lib/l4/pager.c">
<violation number="1" location="user/lib/l4/pager.c:580">
P2: Handle the NULL return from init_thread_pool before using pool to avoid a NULL dereference when RES_FPAGE is too small.</violation>
</file>
<file name="include/platform/stm32l4/syscfg.h">
<violation number="1" location="include/platform/stm32l4/syscfg.h:6">
P2: Header guard macro uses STM32F4 name in an STM32L4 header, which risks include collisions and incorrect guard behavior. Rename it to an STM32L4-specific guard.</violation>
</file>
<file name="kernel/memory.c">
<violation number="1" location="kernel/memory.c:385">
P2: Loop limit reduced from `i < 8` to `i < 7`, permanently wasting one MPU region. With only 8 hardware MPU regions available and the code explicitly noting their scarcity, this means region 7 is always cleared, never assigned an fpage. If this is intentional (e.g., reserving region 7 for a specific purpose on the new board), it should be documented. Otherwise, this is an off-by-one that increases unnecessary memory faults for address spaces that need all 8 regions.</violation>
</file>
<file name="include/platform/stm32l4/hwtimer.h">
<violation number="1" location="include/platform/stm32l4/hwtimer.h:6">
P3: Header guard name doesn’t match the STM32L4 header; use an STM32L4-specific guard to avoid collisions or mismatched expectations.</violation>
</file>
<file name="scripts/qemu-kdb-auto.py">
<violation number="1" location="scripts/qemu-kdb-auto.py:84">
P1: The wrapper disconnects user keyboard input from QEMU, so `--no-trigger` manual mode and interactive KDB input do not work.</violation>
<violation number="2" location="scripts/qemu-kdb-auto.py:117">
P2: `line_buffer` grows without bound even though it is only needed for one-time boot marker detection.</violation>
</file>
<file name="platform/stm32l4/Kconfig">
<violation number="1" location="platform/stm32l4/Kconfig:1">
P2: This file is an exact duplicate of `platform/stm32f4/Kconfig`, introducing high-maintenance copy/paste configuration that is likely to drift.</violation>
<violation number="2" location="platform/stm32l4/Kconfig:32">
P3: The interrupt prompt label is misspelled (`EXIT1` instead of `EXTI1`), which makes the Kconfig menu misleading.</violation>
</file>
<file name="scripts/qemu-kdb.sh">
<violation number="1" location="scripts/qemu-kdb.sh:37">
P1: QEMU stdin is attached to a FIFO before any writer is opened, which can block startup and prevent the VM from booting until input is written.</violation>
</file>
<file name="platform/stm32l4/f9_sram.ld">
<violation number="1" location="platform/stm32l4/f9_sram.ld:158">
P1: Setting `mem1_start` from the RamLoc location creates an inverted MEM1 range (`start > 0x10010000`), which underflows available-memory size calculations.</violation>
</file>
<file name="platform/stm32-common/gpio-l4.c">
<violation number="1" location="platform/stm32-common/gpio-l4.c:145">
P2: Use BSRR for single-pin set operations instead of ODR read-modify-write to avoid lost concurrent GPIO updates.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| dbg_printf(DL_KDB, | ||
| "THREAD_CREATE: child chain cycle caller=%t child=%p\n", | ||
| caller->t_globalid, caller->t_child); | ||
| return thr; |
There was a problem hiding this comment.
P1: Returning thr after detecting a child-chain cycle leaves the thread in thread_map with t_parent = caller but not linked into the caller's child/sibling chain. If thread_destroy is later called on this thread, it will NULL-dereference while walking the parent's child list trying to unlink it.
Either destroy the thread and return NULL, or link it into the chain before returning.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At kernel/thread.c, line 275:
<comment>Returning `thr` after detecting a child-chain cycle leaves the thread in `thread_map` with `t_parent = caller` but not linked into the caller's child/sibling chain. If `thread_destroy` is later called on this thread, it will NULL-dereference while walking the parent's child list trying to unlink it.
Either destroy the thread and return `NULL`, or link it into the chain before returning.</comment>
<file context>
@@ -233,9 +264,16 @@ tcb_t *thread_create(l4_thread_t globalid, utcb_t *utcb)
+ dbg_printf(DL_KDB,
+ "THREAD_CREATE: child chain cycle caller=%t child=%p\n",
+ caller->t_globalid, caller->t_child);
+ return thr;
+ }
t->t_sibling = thr;
</file context>
| return thr; | |
| thread_deinit(thr); | |
| return NULL; |
| sys.stdout.write(chunk) | ||
| sys.stdout.flush() | ||
|
|
||
| line_buffer += chunk |
There was a problem hiding this comment.
P2: line_buffer grows without bound even though it is only needed for one-time boot marker detection.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/qemu-kdb-auto.py, line 117:
<comment>`line_buffer` grows without bound even though it is only needed for one-time boot marker detection.</comment>
<file context>
@@ -0,0 +1,158 @@
+ sys.stdout.write(chunk)
+ sys.stdout.flush()
+
+ line_buffer += chunk
+
+ # Detect boot completion
</file context>
786ea60 to
80e1bd8
Compare
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
This replaces Netduino Plus 2 QEMU target with B-L475E-IOT01A Discovery (STM32L475VG) to gain proper FPU and MPU emulation. This eliminates the mock infrastructure (mpu_mock, scb_mock, safe_mmio) that was papering over the old target's incomplete peripheral emulation.
Platform changes:
FPU support:
IPC fix:
KDB:
Build/test:
Summary by cubic
Switches QEMU to the B-L475E-IOT01A (STM32L475VG) for accurate FPU/MPU emulation, adds full STM32L4 support with a semihosting console, and removes the Netduino Plus 2 target and mock peripherals. This improves kernel correctness and makes CI and local testing faster and simpler.
New Features
platform/stm32l4/usart.c.-M b-l475e-iot01awith semihosting I/O; Kconfig addsSTDIO_SEMIHOSTINGandDEBUG_DEV_SEMIHOSTINGand defaults to semihosting under QEMU; optional USART1 RX for KDB input; new helpersscripts/qemu-kdb.shandscripts/qemu-kdb-auto.py.irq_restorewith a single asm block, adds lazy d8–d15 save/restore, and builds kernel with-mgeneral-regs-only; early CCR setup enables STKALIGN and clears UNALIGN_TRP.L4_Ipcnaked path that reloads the UTCB MR pointer; movest_pagerinto TCB with UTCB sync for unprivileged callers.qemu-build.ymlto build and release a minimal QEMU; build/test jobs download prebuilt QEMU v10.2.2;scripts/qemu-test.pyauto-detects the board and enables semihosting; POSIX job trims options to fit 96KB SRAM; docs and workflows updated tob-l475e-iot01a.mpu_mock,scb_mock,safe_mmio.Migration
b-l475e-iot01a. QEMU:qemu-system-arm -M b-l475e-iot01a -nographic -semihosting -serial mon:stdio -kernel build/b-l475e-iot01a/f9.elf.CONFIG_KDB_UART_INPUTor usescripts/qemu-kdb.sh/scripts/qemu-kdb-auto.pyto trigger?.Written for commit 9e4b78c. Summary will update on new commits.