Skip to content

Commit cfc67b5

Browse files
committed
application: document RVV vector interrupt stack behavior and increase SMODE_STACK_SIZE
When compiled with RVV (e.g. -march=rv64imafdcv), __INTERRUPT or __SUPERVISOR_INTERRUPT decorated vector interrupt handlers save context on the current stack, NOT on the separated interrupt stack. For non-leaf handlers (calling other functions), all 32 vector registers (v0-v31, each vlenb bytes) are saved, consuming significant stack space (e.g. 512B for VLEN=128, 16KB for VLEN=4096). For leaf handlers, only actually-used V registers are saved, or none if no V instructions are used. The compiler also saves all caller-saved GPR + FP registers + FCSR, plus any callee-saved registers actually used by the handler (e.g. s0 as frame base for non-leaf handlers using SAVE_IRQ_CSR_CONTEXT_S()). Changes: - Add comments in demo_eclic_stress, demo_sstc, and demo_smode_eclic explaining vector interrupt stack behavior, leaf vs non-leaf handler differences, and the risk of stack overflow with large vlen - Increase SMODE_STACK_SIZE from 10240 to 20480 in demo_eclic_stress - Increase SMODE_STACK_SIZE from 2048 to 20480 in demo_sstc - Increase SMODE_STACK_SIZE from 2048 to 20480 in demo_smode_eclic - Add corresponding notes in doc/source/design/app.rst for all three demos - Update changelog.rst with the above changes Signed-off-by: Huaqi Fang <578567190@qq.com>
1 parent 9cc217e commit cfc67b5

5 files changed

Lines changed: 89 additions & 4 deletions

File tree

application/baremetal/demo_eclic_stress/main.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,39 @@ uintptr_t mmode_int_sp = (uintptr_t)(mmode_int_stack + sizeof(mmode_int_stack));
204204
uint8_t smode_int_stack[INTERRUPT_STACK_SIZE] __attribute__((aligned(16)));
205205
uintptr_t smode_int_sp = (uintptr_t)(smode_int_stack + sizeof(smode_int_stack));
206206

207+
/*
208+
* NOTE: Vector interrupts decorated with __INTERRUPT or __SUPERVISOR_INTERRUPT
209+
* are handled by compiler-generated prologue/epilogue code. Context saving
210+
* (including the extra
211+
* RVV vector registers when compiled with e.g. -march=rv64imafdcv) happens on
212+
* the current stack, NOT on the separated interrupt stack (mmode_int_stack /
213+
* smode_int_stack above). The separated interrupt stack only applies to
214+
* non-vector interrupts.
215+
*
216+
* In M-Mode or S-Mode, vector interrupts therefore run on the background
217+
* task's stack (main's stack or RTOS task stack for M-Mode; smode_stack for
218+
* S-Mode), which must be large enough to accommodate the full context frame.
219+
* See the disassembly of eclic_int37_handler (S-mode vector interrupt) for
220+
* reference:
221+
* - All caller-saved GPR + FP registers + FCSR + callee-saved
222+
* registers used by the handler (e.g. s0 as frame base): ~304 bytes
223+
* (ra, t0-t6, a0-a7, ft0-ft11, fa0-fa7, fcsr; may include s0 if used)
224+
* - Vector registers (RVV only):
225+
* - Non-leaf interrupt handlers (e.g. eclic_int37_handler which calls
226+
* printf): ALL v0-v31 saved, 32 * vlenb bytes (e.g. 512B for VLEN=128,
227+
* 2048B for VLEN=512)
228+
* - Leaf interrupt handlers: only registers actually used by the handler
229+
* body, or none if no V instructions are used
230+
* Note: scause/sepc/sstatus are NOT part of the compiler-generated context
231+
* frame. They are saved manually in the handler body via
232+
* SAVE_IRQ_CSR_CONTEXT_S() or equivalent code, and use additional local
233+
* stack space.
234+
*
235+
* WARNING: For non-leaf interrupt handlers compiled with RVV, the vector
236+
* context alone can consume up to 32 * vlenb bytes (e.g. 16KB for VLEN=4096).
237+
* Ensure the stack size is sufficient to avoid stack overflow, especially in
238+
* RTOS tasks where stack sizes are typically limited.
239+
*/
207240
/* Create a stack for supervisor mode execution */
208241
#define SMODE_STACK_SIZE 20480
209242
uint8_t smode_stack[SMODE_STACK_SIZE] __attribute__((aligned(16)));

application/baremetal/demo_smode_eclic/demo_smode_eclic.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,29 @@
2626
// 100ms
2727
#define TIMER_TICKS (SOC_TIMER_FREQ / 10)
2828

29-
// 2048 is enough
30-
#define SMODE_STACK_SIZE 2048
29+
/*
30+
* NOTE: Vector interrupts decorated with __INTERRUPT or __SUPERVISOR_INTERRUPT
31+
* are handled by compiler-generated prologue/epilogue code. When compiled with
32+
* RVV (e.g. -march=rv64imafdcv), the compiler may additionally save vector
33+
* registers (v0-v31, each taking vlenb bytes) on the current stack.
34+
* Vector interrupts do NOT use the separated interrupt stack; they run on the
35+
* background task's stack (here smode_stack for S-Mode, or the main/task
36+
* stack for M-Mode vector interrupts).
37+
*
38+
* For non-leaf interrupt handlers (e.g. eclic_ssip_handler which calls
39+
* printf), the compiler saves all caller-saved GPR + FP registers + FCSR
40+
* (e.g. ra, t0-t6, a0-a7, ft0-ft11, fa0-fa7, fcsr) plus any callee-saved
41+
* registers actually used by the handler (e.g. s0 as frame base). For non-
42+
* leaf handlers, ALL v0-v31 are also saved (32 * vlenb bytes). For leaf
43+
* handlers, only actually-used registers are saved, or none at all if no V
44+
* instructions are used in the handler body.
45+
*
46+
* WARNING: For non-leaf interrupt handlers compiled with RVV, the vector
47+
* context alone can consume up to 32 * vlenb bytes (e.g. 16KB for VLEN=4096).
48+
* Ensure the stack size is sufficient to avoid stack overflow, especially in
49+
* RTOS tasks where stack sizes are typically limited.
50+
*/
51+
#define SMODE_STACK_SIZE 20480
3152

3253
// Execute Hart ID
3354
#define EXECUTE_HARTID 0

application/baremetal/demo_sstc/main.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,33 @@
2929
// 100ms
3030
#define TIMER_TICKS (SOC_TIMER_FREQ / 10)
3131

32-
// 4096 is enough
33-
#define SMODE_STACK_SIZE 4096
32+
/*
33+
* NOTE: Vector interrupts decorated with __INTERRUPT or __SUPERVISOR_INTERRUPT
34+
* are handled by compiler-generated prologue/epilogue code
35+
* (e.g. eclic_ssip_handler here).
36+
* When compiled with RVV (e.g. -march=rv64imafdcv), the compiler may
37+
* additionally save vector registers (v0-v31, each taking vlenb bytes) on
38+
* the current stack.
39+
* Vector interrupts do NOT use the separated interrupt stack; they run on the
40+
* background task's stack (here smode_stack for S-Mode, or the main/task
41+
* stack for M-Mode vector interrupts).
42+
* Non-vector interrupts (e.g. eclic_stip_handler registered as
43+
* ECLIC_NON_VECTOR_INTERRUPT) use the separated interrupt stack instead.
44+
*
45+
* For non-leaf interrupt handlers (e.g. eclic_ssip_handler which calls
46+
* printf), the compiler saves all caller-saved GPR + FP registers + FCSR
47+
* (e.g. ra, t0-t6, a0-a7, ft0-ft11, fa0-fa7, fcsr) plus any callee-saved
48+
* registers actually used by the handler (e.g. s0 as frame base). For non-
49+
* leaf handlers, ALL v0-v31 are also saved (32 * vlenb bytes). For leaf
50+
* handlers, only actually-used registers are saved, or none at all if no V
51+
* instructions are used in the handler body.
52+
*
53+
* WARNING: For non-leaf interrupt handlers compiled with RVV, the vector
54+
* context alone can consume up to 32 * vlenb bytes (e.g. 16KB for VLEN=4096).
55+
* Ensure the stack size is sufficient to avoid stack overflow, especially in
56+
* RTOS tasks where stack sizes are typically limited.
57+
*/
58+
#define SMODE_STACK_SIZE 20480
3459

3560
/* Create a stack for supervisor mode execution */
3661
uint8_t smode_stack[SMODE_STACK_SIZE] __attribute__((aligned(16)));

doc/source/changelog.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ This is release version of ``0.9.0`` of Nuclei SDK.
9696
- Update ``demo_eclic_stress`` application to use ``__SMODE_PRESENT`` instead of ``__TEE_PRESENT`` and update npk.yml to remove TEE requirement
9797
- Update ``demo_smode_eclic`` application to use ``__SMODE_PRESENT`` instead of ``__TEE_PRESENT`` and add ``XLCFG_SMODE`` configuration variable
9898
- Update ``demo_sstc`` application to use ``__SMODE_PRESENT`` instead of ``__TEE_PRESENT`` and remove TEE requirement
99+
- Add comments in ``demo_eclic_stress`` to document that ``__INTERRUPT`` vector interrupts save RVV context on the background stack, not on the separated interrupt stack, and increase ``SMODE_STACK_SIZE`` from 10240 to 20480 to accommodate RVV vector register saving overhead
100+
- Add comments in ``demo_sstc`` to document RVV vector interrupt stack behavior and increase ``SMODE_STACK_SIZE`` from 2048 to 20480 to accommodate RVV vector register saving overhead
101+
- Add comments in ``demo_smode_eclic`` to document RVV vector interrupt stack behavior and increase ``SMODE_STACK_SIZE`` from 2048 to 20480 to accommodate RVV vector register saving overhead
99102
- Update ``demo_smode_plic`` application to add ``XLCFG_PLIC`` configuration variable
100103
- Update ``demo_plic`` application to add ``XLCFG_PLIC`` configuration variable
101104
- Update ``demo_cidu`` application to add ``XLCFG_CIDU`` configuration variable

doc/source/design/app.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,7 @@ This `demo_eclic_stress application`_ is used to validate the functionality of t
581581

582582
- This demo requires ECLIC, System Timer, and optional TEE (Trusted Execution Environment) and SSTC extension to be present. When TEE and SSTC is present, both M-Mode and S-Mode interrupts are tested. When TEE is not present, only M-Mode interrupts are tested.
583583
- It can also work with ECLICv2, see :ref:`design_soc_evalsoc_eclicv2`
584+
- **Vector interrupt stack behavior**: When compiled with RVV (e.g. ``-march=rv64imafdcv``), `__INTERRUPT` decorated vector interrupt handlers save context on the current stack, NOT on the separated interrupt stack. For non-leaf handlers (which call other functions), the compiler saves all caller-saved GPR + FP registers + FCSR plus any callee-saved registers actually used, and ALL 32 vector registers (v0-v31, each `vlenb` bytes) are also saved (e.g. 512B for VLEN=128, 16KB for VLEN=4096). For leaf handlers, only actually-used registers are saved. In M-Mode or S-Mode, vector interrupts run on the background task stack (main stack for M-Mode, `SMODE_STACK_SIZE` for S-Mode), which must be large enough to accommodate the context.
584585

585586
**How to run this application:**
586587

@@ -1701,6 +1702,7 @@ the ECLIC API and Interrupt in supervisor mode with TEE.
17011702
* In this application's Makefile, we provided comments in Makefile about optimization
17021703
for code size, please refer to chapter :ref:`design_app_demo_eclic` for details.
17031704
* Need to enable TEE in <Device.h> if TEE present in CPU.
1705+
* **Vector interrupt stack behavior**: When compiled with RVV, `__INTERRUPT` or `__SUPERVISOR_INTERRUPT` decorated vector interrupt handlers save context on the current stack, NOT on the separated interrupt stack. For non-leaf handlers, the compiler saves all caller-saved GPR + FP registers + FCSR plus any callee-saved registers actually used, and ALL 32 vector registers are also saved (32 * `vlenb` bytes). For leaf handlers, only actually-used registers are saved. Ensure the background stack (`SMODE_STACK_SIZE`) is large enough to accommodate vector context.
17041706

17051707
* The timer interrupt and timer software interrupt are used
17061708
* The timer interrupt is registered as non-vector interrupt
@@ -1913,6 +1915,7 @@ This demo is similar with :ref:`design_app_demo_smode_eclic`
19131915

19141916
* It doesn't work with gd32vf103 processor.
19151917
* It needs Nuclei CPU configured with TEE feature and S-Mode ECLIC and SSTC feature
1918+
* **Vector interrupt stack behavior**: When compiled with RVV, `__INTERRUPT` decorated vector interrupt handlers (e.g. `eclic_ssip_handler`) save context on the current stack, NOT on the separated interrupt stack. For non-leaf handlers, the compiler saves all caller-saved GPR + FP registers + FCSR plus any callee-saved registers actually used, and ALL 32 vector registers are also saved (32 * `vlenb` bytes). For leaf handlers, only actually-used registers are saved. Non-vector interrupts (e.g. `eclic_stip_handler`) use the separated interrupt stack. In S-Mode, vector interrupts run on `smode_stack`; in M-Mode, they run on the main/task stack. Ensure the background stack is large enough to accommodate vector context.
19161919

19171920
**How to run this application:**
19181921

0 commit comments

Comments
 (0)