From 0368d914fa9df7e6ee7a6bbf4bb272d0c9860ab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Wed, 9 Sep 2026 10:12:34 -0400 Subject: [PATCH] Fixed the RISC-V64 trap frame size mismatch in the regression test BSP The RISC-V64 port moved its interrupt frame to 528 bytes (65 slots plus 8 bytes of padding, so sp stays 16-byte aligned at a call) and published the size as TX_RISCV_TRAP_FRAME_SIZE. The port sources were converted to use it, but the shared regression test BSP was not: its trap_entry still allocated a hardcoded 65 * REGBYTES, or 520 bytes. Every interrupt therefore unwound 8 bytes more than it allocated: trap_entry: addi sp,sp,-520 _tx_thread_context_restore: addi sp,sp,528 On the RISC-V64 regression suite that left 24 of 95 tests failing in the default configuration, typically as an illegal instruction once execution reached a corrupted frame. The example BSP under the port directory was converted with the port and was unaffected, which is why the functional QEMU test kept passing. The test BSP now takes both frame sizes from the port it is linked against, so the two cannot drift apart again. A port that publishes no contract keeps the historical layout, so the RISC-V32 side is unchanged until its own port publishes one. TX_RISCV_TRAP_CALL_FRAME_SIZE is restored to the RISC-V64 tx_port.h. It was removed as unused when the frame sizes were introduced, but it is part of the same contract: it is the space a trap entry reserves around a call into C, and the psABI requires 16 bytes there rather than one register slot. Verified on QEMU with every linkable test built, comparing against the commit before the port change: before the port change 2 failures out of 95 (both unlinkable) current dev 24 failures out of 95 with this change 2 failures out of 95 (both unlinkable) The two remaining failures predate all of this: newlib pulls _impure_ptr out of R_RISCV_HI20 range for time(), so those two binaries do not link. RISC-V32 is unchanged at 2 failures across all five configurations. Assisted-by: Claude Code (Opus 5) --- ports/risc-v64/gnu/inc/tx_port.h | 5 +++ .../cmake/riscv/bsp/tx_initialize_low_level.S | 33 +++++++++++++++---- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/ports/risc-v64/gnu/inc/tx_port.h b/ports/risc-v64/gnu/inc/tx_port.h index 0e31cc426..ad71694be 100644 --- a/ports/risc-v64/gnu/inc/tx_port.h +++ b/ports/risc-v64/gnu/inc/tx_port.h @@ -84,6 +84,11 @@ #define TX_RISCV_TRAP_FRAME_SIZE 256 #endif +/* Bytes a trap entry reserves around a call into C. The RISC-V psABI + requires sp to stay 16-byte aligned at a call boundary, so this is 16 + rather than one register slot. */ +#define TX_RISCV_TRAP_CALL_FRAME_SIZE 16 + #if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double) #define TX_RISCV_SOL_FRAME_SIZE 240 diff --git a/test/tx/cmake/riscv/bsp/tx_initialize_low_level.S b/test/tx/cmake/riscv/bsp/tx_initialize_low_level.S index 8d474d66b..327946bb0 100644 --- a/test/tx/cmake/riscv/bsp/tx_initialize_low_level.S +++ b/test/tx/cmake/riscv/bsp/tx_initialize_low_level.S @@ -1,5 +1,6 @@ /*************************************************************************** * Copyright (c) 2026 10xEngineers + * Copyright (c) 2026 Eclipse ThreadX contributors * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at @@ -8,10 +9,13 @@ * SPDX-License-Identifier: MIT **************************************************************************/ +// Some portions generated by Claude Code (Opus 5). + /* Trap entry and low-level init for RISC-V QEMU virt regression tests. Supports both RV32 and RV64 via __riscv_xlen conditionals. */ #include "csr.h" +#include "tx_port.h" #if __riscv_xlen == 64 #define STORE sd @@ -33,13 +37,28 @@ .extern trap_handler .extern _tx_thread_context_restore -trap_entry: +/* Take the interrupt frame size from the port that this BSP is linked + against, so the two can never disagree. A port that publishes no + contract keeps the historical layout. */ +#ifndef TX_RISCV_TRAP_FRAME_SIZE #if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double) - addi sp, sp, -(65 * REGBYTES) +#define TX_RISCV_TRAP_FRAME_SIZE (65 * REGBYTES) #else - addi sp, sp, -(32 * REGBYTES) +#define TX_RISCV_TRAP_FRAME_SIZE (32 * REGBYTES) +#endif +#endif + +/* The RISC-V psABI requires sp to be 16-byte aligned at a call. */ +#ifndef TX_RISCV_TRAP_CALL_FRAME_SIZE +#define TX_RISCV_TRAP_CALL_FRAME_SIZE 16 #endif + .equ TX_TRAP_FRAME_SIZE, TX_RISCV_TRAP_FRAME_SIZE + .equ TX_TRAP_CALL_FRAME_SIZE, TX_RISCV_TRAP_CALL_FRAME_SIZE + +trap_entry: + addi sp, sp, -TX_TRAP_FRAME_SIZE + STORE x1, (28 * REGBYTES)(sp) call _tx_thread_context_save @@ -47,11 +66,11 @@ trap_entry: csrr a0, mcause csrr a1, mepc csrr a2, mtval - addi sp, sp, -REGBYTES + addi sp, sp, -TX_TRAP_CALL_FRAME_SIZE STORE ra, 0(sp) call trap_handler LOAD ra, 0(sp) - addi sp, sp, REGBYTES + addi sp, sp, TX_TRAP_CALL_FRAME_SIZE call _tx_thread_context_restore @@ -89,11 +108,11 @@ _tx_initialize_low_level: fscsr x0 #endif - addi sp, sp, -REGBYTES + addi sp, sp, -TX_TRAP_CALL_FRAME_SIZE STORE ra, 0(sp) call board_init LOAD ra, 0(sp) - addi sp, sp, REGBYTES + addi sp, sp, TX_TRAP_CALL_FRAME_SIZE la t0, trap_entry csrw mtvec, t0