Commit graph zephyr/arch/riscv
Author SHA1 Message Date
Joel Holdsworth
e3802d3e1f arch: riscv: support building without generated SW ISR table
Make GEN_SW_ISR_TABLE depend on GEN_ISR_TABLES, and guard the import of
_sw_isr_table in isr.S so that applications can build without generated
ISR tables when interrupts are unused.

Assisted-by: Gemini:gemini-3.8-flash
Signed-off-by: Joel Holdsworth <jholdsworth@nvidia.com>
2026-09-26 08:40:33 +02:00
Sefa Celik
e560c91b1f arch: riscv: andes: handle NMI arriving at the reset vector
On AndeStar V5 cores such as the N25/N25F, the NMI vector base address
register (mnvec, CSR 0x7C3) is read-only and reads back the reset_vector
input signal. An NMI therefore enters the system at __reset, and the
boot path re-initialises the core, destroying the machine state the NMI
was raised to let software examine.

Add CONFIG_RISCV_CUSTOM_CSR_ANDES_NMI, gated on a CPU_HAS_ANDES_NMI
capability that the SoC selects, so the option is only offered on cores
implementing the Andes NMI extension rather than the RISC-V RNMI
extension. It tells the two cases apart at the top of __reset and
branches to _andes_nmi_entry instead of booting. Coming out of reset
mcause and mepc both read 0, whereas an NMI sets mcause to 1 and leaves
the interrupted PC in mepc. The option defaults to n, so behaviour is
unchanged unless a SoC enables it.

Note that Andes reports the NMI with the mcause interrupt bit clear,
rather than set as the privileged specification recommends, so the check
compares mcause against 1 exactly. That value is also the instruction
access fault code. Such exceptions are taken through mtvec, which is set
up early in boot, so in practice they do not reach the reset vector;
mtvec.BASE does reset to 0 however, so a fault raised before that setup
cannot be told apart from an NMI.

_andes_nmi_entry is weak and only parks the core, so that the option
links on its own. A SoC enabling NMIs is expected to provide a real
handler overriding it, and to set up whatever that handler needs, such
as an NMI stack in mscratch, before enabling any NMI source.

Signed-off-by: Sefa Celik <sefa.celik@analog.com>
2026-09-26 01:14:25 +02:00
Fin Maaß
80c6a6f2ba arch: riscv: grant S-mode access to the Zkr seed CSR
The seed CSR of the Zkr extension is only accessible from M-mode after
reset. When the kernel runs in S-mode on top of the in-tree M-mode
runtime, set mseccfg.SSEED before dropping to S-mode, so that the
kernel can use the entropy source. U-mode access stays disabled.

With an external SBI implementation this is up to the firmware, OpenSBI
sets SSEED on harts that implement Zkr.

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Fin Maaß <f.maass@vogl-electronic.com>
2026-09-24 17:12:58 +02:00
Fin Maaß
d4120a7b0d arch: riscv: add Zkr ISA extension support
Add RISCV_ISA_EXT_ZKR for the Zkr entropy source extension. As for the
other ISA extensions, it is enabled from the riscv,isa-extensions
devicetree property. It is also enabled by Zk, which includes Zkr.

Add the addresses of the seed and mseccfg CSRs and the mseccfg.SSEED
bit, which grants S-mode access to the seed CSR.

Zkr is not added to -march: it adds no instructions and the CSRs are
addressed by number, while the LLVM toolchain of the Zephyr SDK selects
its multilib from the exact -march string and has none matching zkr.

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Fin Maaß <f.maass@vogl-electronic.com>
2026-09-24 17:12:58 +02:00
Ayush Singh
c847bfbc8f arch: riscv: Add initial smp support with external sbi
This patch only allows enabling SMP in 1 core setups.

Signed-off-by: Ayush Singh <ayush@beagleboard.org>
2026-09-24 03:49:59 +02:00
Ayush Singh
27619328e7 arch: riscv: core: Add ipi_sbi support
RISC-V Supervisor Binary Interface Specification supports
inter-processor interrupts using the IPI extension.

Signed-off-by: Ayush Singh <ayush@beagleboard.org>
2026-09-24 03:49:59 +02:00
Adrian Śliwa
78087d0662 arch: riscv: enable U-mode access to the Zicntr counters
Reads of cycle, time and instret below M-mode are gated by mcounteren
and scounteren, both zero out of reset. Zephyr sets neither in a build
with user threads, so user mode cannot read these counters.

Set them during per-CPU init, since the registers are per-hart. An
M-mode kernel writes mcounteren, and scounteren when misa reports
S-mode, as it does not exist otherwise. An S-mode kernel writes
scounteren alone, because mcounteren is out of reach and is expected
to be set by the SBI, as reset.S does for the built-in one.

Signed-off-by: Adrian Śliwa <asliwa@internships.antmicro.com>
2026-09-16 05:58:39 +02:00
Adrian Śliwa
56164d22a4 arch: riscv: share the counter-enable bit definitions
The counter enable bits are identical in mcounteren, scounteren and
hcounteren, so move them out of reset.S into csr.h. This lets the arch
code that opens the counters to user mode reuse them instead of adding
a second copy.

Signed-off-by: Adrian Śliwa <asliwa@internships.antmicro.com>
2026-09-16 05:58:39 +02:00
Dhruv Menon
908a2e5f0d arch: riscv: switch to main stack before unmasking interrupts
If an interrupt was already pending when z_cstart() completed (such as an
early timer compare event or peripheral interrupt), the ISR fired
immediately while sp still pointed to the interrupt stack. Because
_current_cpu->nested is 0, _isr_wrapper assumed the interruption came
from thread mode and reset sp to the top of _kernel.cpus[0].irq_stack,
causing subsequent ISR C call frames to write directly over the hardware-
saved ESF. This corrupted the saved mepc, leading to an Illegal Instruction
exception (mcause: 2) upon mret.

this commit fixes this by moving interrupt enablement
(csrs RV_STATUS_CSR, %2)  inside the inline assembly block after the stack
pointer has been  switched to main_stack (mv sp, %0)

Signed-off-by: Dhruv Menon <dhruvmenon1104@gmail.com>
2026-09-16 05:55:37 +02:00
Sylvio Alves
886d9899db arch: riscv: add soc hook to close the syscall ecall
Some RISC-V SoCs cannot deliver a fault raised by the syscall
body itself while the ECALL exception of a user-mode syscall is
still being handled. The stack guard below the privileged stack
catches a syscall whose call chain runs too deep, but on such a
SoC that access fault is reported asynchronously inside the open
ECALL and locks the core up, resetting the chip with nothing
delivered to software. A user-mode application can therefore
reset the board through the depth of a granted service call.

Masking interrupts does not help here. The existing
RISCV_SOC_HAS_SYSCALL_INTMASK holds off the interrupt
controller, while this fault comes from the body itself.

Add the hidden RISCV_SOC_SYSCALL_CLOSE_ECALL option. When a SoC
selects it, the IRQ wrapper leaves the exception before running
the syscall body: it returns to the following instruction with
the previous privilege set to machine mode, so the body runs on
the same privileged stack with the same privileges but outside
the exception. A fault taken there is an ordinary top-level trap
the SoC delivers normally, and a syscall that overflows the
privileged stack is reported as a stack overflow that kills only
the offending thread.

The exception exit path reloads the exception program counter
and status register from the saved frame, so borrowing both here
does not disturb the return to user mode.

Assisted-by: Claude:opus-5
Signed-off-by: Sylvio Alves <sylvio.alves@espressif.com>
2026-09-14 15:41:06 -04:00
Sylvio Alves
32381dcbfb arch: riscv: add soc hook to mask syscall interrupts
Some RISC-V SoCs cannot take an interrupt in the syscall body: an
interrupt, or another asynchronously reported event such as an
imprecise access fault, taken while the ECALL exception is still
being handled locks the CPU up, with no fault delivered to
software. Precise synchronous traps, such as the ECALL used to
switch out of the body, nest normally. The syscall path sets
mstatus.MIE before running the body, so such a SoC must hold
interrupts off another way.

This is not the Smdbltrp double trap. On the affected cores
reading mstatush traps, so there is no mstatus.MDT to clear, and
the vendor status CSR exposes the in-exception state as a
read-only bit that stays set until mret. Software cannot end the
exception window early, so the only option is to keep interrupts
from being taken while it is open.

Add the hidden RISCV_SOC_HAS_SYSCALL_INTMASK option following
the existing RISCV_SOC_HAS_* hook pattern. When a SoC selects it,
the IRQ wrapper invokes a SoC-provided SOC_SYSCALL_INTMASK macro
on syscall entry, typically raising a hardware interrupt level
threshold, while the generic code carries no SoC register
knowledge. This is a SoC hook rather than part of the generic
CLIC interrupt level support because the SoCs that need it drive
their interrupt controller from SoC code and do not select
RISCV_HAS_CLIC.

The mask is per exception frame. The SoC context hooks save the
state on entry and restore it on the exception exit path, and
with RISCV_ALWAYS_SWITCH_THROUGH_ECALL every context switch goes
through that path: a thread that blocks in the body hands the
CPU to a thread that restores its own saved state, and a new
thread starts from SOC_ESF_INIT. The option therefore depends on
both. While the mask is raised the body is not preemptible and
pending interrupts, the tick included, wait for the syscall to
return or block; the help text says so.

Assisted-by: Claude:opus-5
Signed-off-by: Sylvio Alves <sylvio.alves@espressif.com>
2026-09-14 15:41:06 -04:00
Sylvio Alves
37d3022714 arch: riscv: pre-validate user strings on imprecise-fault socs
arch_user_string_nlen() dereferences a user pointer and recovers
from a bad address through a fault fixup that matches the
faulting mepc against the load instruction's range. On some
RISC-V SoCs the load access fault is imprecise: the reported mepc
lands past the faulting load, so the fixup misses it and the
fault escalates to a fatal reset.

Rename the asm routine to z_riscv_user_string_nlen() and alias
arch_user_string_nlen() to it by default. Under the new
RISCV_USER_STRING_NLEN_VALIDATE option a C implementation takes
over instead: it checks the whole range with
arch_buffer_validate() first and, when that fails, walks the
string in PMP-granularity chunks, validating each chunk before
reading it, so no load that could fault is ever issued. The
faulting load may sit at any offset (a string that starts in an
accessible region and runs unterminated into an inaccessible
one), which is why one check of the first byte is not enough.
The generic syscall handler is untouched.

Add a syscalls test scenario that enables the option on RISC-V.

Assisted-by: Claude:opus-5
Signed-off-by: Sylvio Alves <sylvio.alves@espressif.com>
2026-09-14 15:41:06 -04:00
Liu Qian
18b49e8379 arch: riscv: pmp: add NAPOT multi-slot mode for non-aligned regions
When TOR is unsupported (PMP_NO_TOR), the Kconfig forced
PMP_POWER_OF_TWO_ALIGNMENT=y, wasting memory: 33 KB of code+rodata
aligns to 64 KB, 257 KB aligns to 512 KB.

Add PMP_NAPOT_USE_MULTI_SLOTS: splits a non-naturally-aligned region
into multiple NAPOT entries, each covering the largest naturally-
aligned block at the current address. [0x1800, 0x3800) becomes
0x800 + 0x1000 + 0x800 (3 slots instead of padding to 8192).

Depends on !USERSPACE: arch_mem_domain_max_partitions_get() assumes
1-2 slots per partition and resync_pmp_domain() can only log on
failure, so a partition needing more slots would run unmapped (silent
loss of protection). Help text documents that disabling
PMP_POWER_OF_TWO_ALIGNMENT also splits stack guards and u-mode stacks,
and that PMP_GRANULARITY=64 cuts both ways for that case.

try_multi_entries_set() uses clz/ctz builtins, clears already-written
config bytes on failure before restoring *index_p (otherwise the
trailing write_pmp_entries(0, PMP_SLOTS) in z_riscv_pmp_init() would
program locked partial entries), and folds start/size into the inner
failure logs.

Signed-off-by: Liu Qian <liuqian.andy@picoheart.com>
2026-09-11 17:34:41 +02:00
Liu Qian
96c7e335e4 arch/riscv: add release barrier before publishing switch_handle
Under RVWMO the context stores (callee-saved registers, stack
pointer) may be reordered before the switch_handle store, so a hart
spinning in z_sched_switch_spin() could observe the handle before
the saved context is visible and restore stale registers.

Add fence rw, w before publishing switch_handle, pairing with the
acquire barrier in z_sched_switch_spin(), same as ARM64.

Signed-off-by: Liu Qian <liuqian.andy@picoheart.com>
2026-09-11 17:32:12 +02:00
Hongquan Li
999f33ee60 arch: riscv: smp: panic on secondary hartid lookup failure
If the loop searching for a matching hartid in
arch_secondary_cpu_init() exited without a match, cpu_num would
stay 0 and the secondary hart would initialize itself using
CPU 0's per-CPU state, TLS, PMP and startup callback.

This state is currently unreachable: reset.S gates each secondary
hart until riscv_cpu_wake_flag equals its own mhartid, and the
flag is only ever written from _kernel.cpus[].arch.hartid in
arch_cpu_start(), so a hart whose hartid is absent from the CPU
table never reaches this function. Add the check as defensive
hardening: break on the first match and call k_panic() if the
loop completes without one.

The check sits after the mscratch write because arch_curr_cpu()
reads mscratch, so the fatal path needs per-CPU state set first.

Signed-off-by: Hongquan Li <hongquan.li@processmission.com>
2026-08-31 06:58:37 -04:00
Hongquan Li
181907202d arch: riscv: pass NULL thread to custom stack guard without multithreading
In !CONFIG_MULTITHREADING mode the inline assembly in
z_riscv_switch_to_main_no_multithreading() calls
z_riscv_custom_stack_guard_enable() without setting a0 to the
k_thread * the callee's contract requires. The Andes implementation
only survives because it ignores the argument; any implementation
that dereferences thread faults.

Change the contract to accept a NULL thread in no-multithreading mode
(no thread object exists there) and pass NULL from the caller; the
Andes HSP implementation now checks for NULL and guards the main
stack. Also pin main_entry to callee-saved s1 so the jalr target
survives the call.

Fixes #113190

Signed-off-by: Hongquan Li <hongquan.li@processmission.com>
2026-08-28 15:28:18 -04:00
Lior David
58a459a991 arch/riscv: align TLS storage to ARCH_STACK_PTR_ALIGN
The TLS storage is stored in a reserved stack area, so it
needs to be aligned with ARCH_STACK_PTR_ALIGN (16 bytes),
otherwise the stack pointer gets out of alignment which
violates the RISCV psABI specification.
In addition, the Zcmp instructions such as cm.push and cm.pop
will have undefined behavior if called with unaligned stack
pointer. This can cause unexpected runtime failures.

Signed-off-by: Lior David <liord@qti.qualcomm.com>
2026-08-27 22:11:25 -04:00
Benjamin Cabé
2782b62e07 arch: riscv: skip the reschedule call on the IRQ exit fast path
On every non-nested interrupt exit, the ISR wrapper called
z_get_next_switch_handle() to ask the scheduler whether a context
switch is needed, including the stack juggling needed around the call
and a second stack sentinel check inside the callee (isr.S already
performs one on this path). For the vast majority of interrupts no
reschedule is needed and all of that work amounts to nothing.

On uniprocessor builds the scheduler's decision is fully captured by
_kernel.ready_q.cache: when it still designates the current thread,
z_get_next_switch_handle() reduces to no-op bookkeeping. Add a short
inline comparison (four instructions) to the interrupt exit path and
skip the call entirely in that case, the same way the Arm Cortex-M
exception exit decides whether to pend PendSV. The fast path is
disabled on SMP (where the decision requires the scheduler lock) and
when thread usage accounting needs to run on every switch decision.

Measured on ESP32-C6 @ 160 MHz (m5stack_nanoc6/esp32c6/hpcore):

* latency_measure: return from ISR to interrupted thread
  464 -> 401 ns (-14%); return from ISR to a different thread
  1099 -> 1124 ns (+2.3%, the added instructions, taken only when
  an actual reschedule follows); all other metrics unchanged. The
  regression is a constant cost paid only when a context switch
  follows anyway, and is amortized: the change nets out positive
  whenever more than ~28% of interrupt exits (~10% on QEMU) return
  to the interrupted thread, which tick and device interrupts
  overwhelmingly do.
* thread_metric: interrupt processing +3.3% (10303330 -> 10645986);
  interrupt preemption -0.5% (5027551 -> 5001353), every interrupt
  there reschedules so it only pays the added check; preemptive and
  cooperative scheduling unchanged (<0.01%).

Measured on qemu_riscv32 (QEMU icount, deterministic):

* latency_measure: return from ISR to interrupted thread
  50 -> 31 cycles (-38%); return from ISR to a different thread
  63 -> 65 cycles (+3.2%).
* thread_metric: interrupt processing +9.6% (1420879 -> 1557774);
  interrupt preemption -0.45% (713682 -> 710438).

Code size: +12 B text (+0.03% at -Os, +0.02% at -O2) on
qemu_riscv32; +16 B (+0.02%, -Os) on ESP32-C6.

Assisted-by: Claude:fable-5
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
2026-08-27 12:12:48 +01:00
Kaveesha Yalegama
b06c28cf3d riscv: fpu: improve FPU instruction filtering in trap handler
Updates the fast-path assembly in isr.S to explicitly filter out
vector instructions that share opcodes with FP loads/stores,
preventing them from corrupting the FPU context state.

Additionally, introduces CONFIG_RISCV_FPU_INSN_VALIDATE (default
'y' with CONFIG_ASSERT) to provide a C-level runtime validator in
z_riscv_fpu_trap(). This intercepts misrouted non-FPU instructions,
prints the faulting opcode, and throws a kernel oops.

Fixes #96551

Signed-off-by: Kaveesha Yalegama <kaveesha.yalegama@gmail.com>
2026-08-27 12:04:26 +01:00
Benjamin Cabé
5389672ba0 arch: riscv: remove deprecated EXTRA_EXCEPTION_INFO Kconfig option
The RISC-V specific shadow definition of EXTRA_EXCEPTION_INFO was
deprecated in Zephyr 4.3 and is now removed as part of the 4.5
deprecation removal cycle.

The RISC-V exception handling code (isr.S, fatal.c, coredump.c and the
offsets definitions) has been keyed off CONFIG_EXCEPTION_DEBUG since the
deprecation, so removing the symbol requires no code conversion. RISC-V
applications that still set CONFIG_EXTRA_EXCEPTION_INFO must use
CONFIG_EXCEPTION_DEBUG instead.

Note this only drops the deprecated RISC-V local definition. The generic
EXTRA_EXCEPTION_INFO option in arch/Kconfig, guarded by
ARCH_HAS_EXTRA_EXCEPTION_INFO and used by Arm and SPARC, is unaffected.

Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Assisted-by: Claude:opus-5
2026-08-25 07:59:26 -07:00
Jinming Zhao
5b69ef3e99 arch: riscv: stacktrace: fix exception frame unwinding
The ra register is caller-saved. For a non-leaf function interrupted
after a call, esf->ra points back into that function instead of to its
caller. Emitting it unconditionally adds a bogus frame.

A leaf frame may have no saved return address, so its direct caller must
come from esf->ra. Detect the compact leaf layout using a validated,
monotonically increasing caller frame pointer, then continue through the
normal walk loop. This preserves callback and maximum-depth semantics.

Request leaf frame pointers when CONFIG_FRAME_POINTER is enabled so
supporting compilers cannot omit the frame entirely. Older compact leaf
frames remain supported.

Add exact RV32E, RV32, and RV64 traces for leaf and non-leaf exception
frames. Trigger the fault with an illegal instruction so M-mode and
S-mode exercise the same exception path without relying on ebreak
behavior.

Signed-off-by: Jinming Zhao <jinmzhao@qti.qualcomm.com>
2026-08-25 07:56:42 -07:00
Ayush Singh
5a95bb9cff arch: riscv: Add S-mode only support
- When launching Zephyr from a bootloader (eg: u-boot), the image binary
  launches in S-mode. Thus we cannot call M-mode only functions, or
  perform M to S mode transition.
- SMP is currently broken in this setup. MPU, FPU not tested yet either
  since PolarFire soc does not enable it by default.
- Tested on beaglev_fire with PolarFire soc.

Signed-off-by: Ayush Singh <ayush@beagleboard.org>
2026-08-25 11:24:09 +02:00
Hongquan Li
c8f461d8a3 arch: riscv: pmp: panic when memory-attr regions exceed PMP slots
set_pmp_mem_attr() ignored the result of set_pmp_entry(), so when the
zephyr,memory-attr regions needed more PMP slots than available, the
trailing regions were silently dropped and their permissions never
enforced (default-allowed per the RISC-V privileged spec).

Log the region that could not be installed and call k_panic() so a
configuration that cannot be honored fails the boot loudly instead of
silently degrading security.

Fixes #113777

Signed-off-by: Hongquan Li <hongquan.li@processmission.com>
2026-08-21 16:16:52 +02:00
Fin Maaß
67ad3e2902 include: sys: add common header for reversing bits
Add common function for reversing bits.

Signed-off-by: Fin Maaß <f.maass@vogl-electronic.com>
2026-08-19 18:39:40 -04:00
Fin Maaß
a8649affcc riscv: select RISCV_ISA_EXT_ZBKB
select RISCV_ISA_EXT_ZBKB on extensions that
include it.

Signed-off-by: Fin Maaß <info@finmaass.de>
2026-08-17 16:27:42 -04:00
Hongquan Li
1740527e67 arch: riscv: fix arch_user_string_nlen() reading past maxsize
The loop loaded s[counter] before checking counter == maxsize, so it
read s[maxsize] when the first maxsize bytes were all non-NUL and
dereferenced s[0] when maxsize == 0, violating the strnlen()
semantics required by arch_user_string_nlen(). The over-read byte
cannot change the returned length, but if it is not accessible the
exception fixup reports a spurious error and callers reject valid
input with EFAULT.

Check the limit before the load instead.

Fixes zephyrproject-rtos/zephyr#113722

Signed-off-by: Hongquan Li <hongquan.li@processmission.com>
2026-08-07 06:47:54 -04:00
Hongquan Li
fad5e2d7a7 arch: riscv: clear fpu_recently_used in arch_float_disable()
Clear the fpu_recently_used flag when disabling FPU access for a
thread. This flag is used by the context switch path to decide whether
to re-enable FPU access; leaving it set caused k_float_disable() to be
silently reverted on the next context switch back to the thread.

Fixes #113645

Signed-off-by: Hongquan Li <hongquan.li@processmission.com>
2026-08-03 08:45:03 -04:00
Hongquan Li
3d2284ca98 arch: riscv: track K_FP_REGS coherently across FPU ownership changes
Set K_FP_REGS in z_riscv_fpu_load() when a thread becomes the FPU
owner, and clear it in arch_float_disable(). This keeps user_options
consistent across lazy-FPU architectures rather than only clearing
the flag.

Fixes #113645

Signed-off-by: Hongquan Li <hongquan.li@processmission.com>
2026-08-03 08:45:03 -04:00
Hongquan Li
4e3cebb97e arch: riscv: refactor arch_float_disable() and add flush helper
Introduce z_riscv_fpu_flush_thread() to perform the
architecture-specific FPU context flush without touching thread
options or fpu_recently_used, and make arch_float_disable() use it.

Reject NULL thread pointers with -EINVAL in arch_float_disable().
Unlike Cortex-M, RISC-V does not restrict the call to the current
thread or exclude ISR context.

Switch arch_spin_relax() to the new helper: it only needs to flush
the current CPU FPU context in response to a pending IPI, so it must
not go through arch_float_disable(), which now rejects NULL pointers
while _current_cpu->arch.fpu_owner may legitimately be NULL.

Fixes #113645

Signed-off-by: Hongquan Li <hongquan.li@processmission.com>
2026-08-03 08:45:03 -04:00
Hongquan Li
2374c3a0d3 arch: riscv: fix SBI SRST unsupported return
Store SBI_ERR_NOT_SUPPORTED in the saved a0 slot for unsupported
SRST functions. The previous store used the saved t2 offset.

S-mode callers kept the old a0 value, and t2 was restored as -1.

Fixes #113149.

Signed-off-by: Hongquan Li <hongquan.li@processmission.com>
2026-07-22 19:07:46 +01:00
Hongquan Li
12edc1d062 arch: riscv: coredump: skip priv stack dump for unstarted user threads
The RISC-V coredump hook arch_coredump_priv_stack_dump() derives the
privilege stack region from thread->arch.priv_stack_start. That field
is only initialized when a thread enters user mode via
arch_user_mode_enter(). For a K_USER thread that has been created but
has never run, priv_stack_start is still 0, causing the hook to dump a
low-address region near 0 and potentially trigger a nested memory
fault.

Add an early return when priv_stack_start is 0 so that unstarted user
threads are skipped.

Fixes #113875

Signed-off-by: Hongquan Li <hongquan.li@processmission.com>
2026-07-22 19:06:50 +01:00
Sylvio Alves
9dae2a0c21 arch: riscv: deny gracefully when a thread runs out of pmp slots
arch_mem_domain_max_partitions_get() returns an optimistic slot
estimate and its comment says resync_pmp_domain() should deny
availability when the estimate is too high, but that path asserted
instead. On a SoC whose global regions leave few slots, a domain can
hold more partitions than fit a thread's remaining PMP entries, so the
assert fired during a context switch and reset the whole system. Stop
programming and log instead: the thread runs with the partitions that
fit and faults, only itself, on an access to an unmapped one, which is
recoverable.

Signed-off-by: Sylvio Alves <sylvio.alves@espressif.com>
2026-07-20 16:44:28 -05:00
Sylvio Alves
659faff954 arch: riscv: accept flash rodata in buffer validation
On SoCs whose flash-mapped read-only data sits in an address window
separate from the executable text, the __rom_region symbol only spans
the text. A user-mode thread passing a const string or other rodata
pointer to a syscall then failed the buffer validation, because the
rodata fell outside the only read-only range that was checked.

Accept the rodata region as well so reads of flash-mapped constants
from user mode validate correctly. SoCs with contiguous text and
rodata are unaffected since __rom_region already covers both.

Signed-off-by: Sylvio Alves <sylvio.alves@espressif.com>
2026-07-20 16:44:28 -05:00
Sylvio Alves
28a743a54a arch: riscv: let llext modules call syscalls under userspace
On RISC-V with CONFIG_USERSPACE, arch_is_user_context() read the
thread-local is_user_mode symbol directly inline. Every syscall stub
inlines this check, so any extension (llext) that called a syscall
pulled in a thread-local relocation the loader cannot resolve, failing
to link with an undefined is_user_mode symbol.

Move the thread-local read into an exported, non-inline accessor
z_riscv_thread_is_user_mode(), declared in arch/riscv/thread.h and
called from arch_is_user_context(), mirroring the Arm
z_arm_thread_is_in_user_mode() approach. Extensions now resolve the
exported symbol instead of a thread-local one, so a loaded module can
call syscalls. The tp-not-initialized fast path stays inline.

Signed-off-by: Sylvio Alves <sylvio.alves@espressif.com>
2026-07-20 16:44:28 -05:00
Omar Naffaa
3f020fe3c4 arch: riscv: Use new CPU macro to iterate through CPUs
Replace DT_FOREACH_CHILD_STATUS_OKAY_SEP usage with new
DT_FOREACH_CPU_STATUS_OKAY_SEP macro.

Signed-off-by: Omar Naffaa <onaffaa@qti.qualcomm.com>
2026-07-20 08:30:45 -05:00
Adrian Śliwa
5bf87816ff arch: riscv: bump idle stack size
Test

```
west twister -p mpfs_icicle/polarfire/u54/smp -s
kernel.threads.thread_stack
```

fails with `idle thread stack size 512 too low`.

Signed-off-by: Adrian Śliwa <asliwa@internships.antmicro.com>
2026-07-17 11:56:19 -04:00
Anas Nashif
25d08114e9 arch: gate idle notification hooks on SYS_IDLE_HOOKS
The architecture idle paths call sys_trace_idle() and
sys_trace_idle_exit() to notify subscribers when the CPU enters and
leaves the idle state. These calls were guarded by CONFIG_TRACING,
which tied idle-time accounting to the tracing subsystem even though
no tracing backend is required to service the hooks.

Introduce a hidden Kconfig symbol, SYS_IDLE_HOOKS, that any subsystem
needing these notifications can select, and have TRACING select it.
Switch the idle-path guards in every architecture and SoC that emits
the hooks from CONFIG_TRACING to CONFIG_SYS_IDLE_HOOKS. Because
TRACING selects the new symbol, existing tracing behaviour is
unchanged; the change only lets non-tracing consumers receive the
hooks.

This is a prerequisite for building the CPU load module without the
tracing subsystem.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-07-17 11:55:28 -04:00
Adrian Śliwa
cda79d7ac6 arch: riscv: Bump privileged stack size
Since 5528dee556 (`device: Add asserts to DEVICE_API_GET`), the
following tests fail with a privileged-stack overflow during the
`log_panic()` syscall:

```
west twister -p hifive_unmatched/fu740/u74 -s logging.log_user
west twister -p hifive_unleashed/fu540/u54 -s logging.log_user
```

`qemu_riscv64` passes only because its defconfig sets
`CONFIG_PRIVILEGED_STACK_SIZE=2048`, lowering it to `1024` reproduces
the failure in a similar way.

The bad commit makes stack frames bigger along the `log_panic()` flush
chain. Peak privileged-stack usage goes from just-under to just-over
1024 bytes.

Signed-off-by: Adrian Śliwa <asliwa@internships.antmicro.com>
2026-07-07 17:25:03 +01:00
Omar Naffaa
b284cdb15c drivers: interrupt_controller: APLIC IRQ affinity support
Implement and enable IRQ affinity in APLIC direct mode driver

Signed-off-by: Omar Naffaa <onaffaa@qti.qualcomm.com>
2026-07-07 17:24:52 +01:00
Anas Nashif
d67bb4516a arch: riscv: fatal: do not mark z_riscv_fatal_error as unreachable
z_riscv_fatal_error() may return: when a fatal error is handled (for
example an expected fault in ztest aborting the current thread), the
generic z_fatal_error() returns and the exception exit path in isr.S
takes care of rescheduling. isr.S explicitly sets the return address
to no_reschedule before tail-calling z_riscv_fault for this reason.

The CODE_UNREACHABLE hint made LLVM place a trapping instruction
(unimp) right after the call. When the handler returned, the CPU
executed the unimp and re-entered the fault path, so tests raising
expected faults hung in an endless fatal error loop when built with
clang. GCC builds only worked by chance, falling through into
whatever code the compiler laid out after the call.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-07-05 15:31:30 -04:00
Filip Kokosinski
ddec762ad2 arch/riscv: support RV32I in the internal SBI
Right now, the SBI hard-codes the usage of ld/sd instructions, which are
not available on 32-bit platforms. This commit changes this to sr/lr from
`asm_macros.inc`, which automatically resolves them to proper load/store
instructions on 32-bit and 64-bit configurations. It also ensures proper
timer handling through 32-bit registers.

Signed-off-by: Filip Kokosinski <fkokosinski@antmicro.com>
Co-authored-by: Jakub Klimczak <jklimczak@internships.antmicro.com>
Signed-off-by: Jakub Klimczak <jklimczak@internships.antmicro.com>
2026-07-03 19:25:39 -04:00
Etienne Carriere
b2fdf98b3c arch: use <> to include Zephyr headers instead of ""
Use <> operator to include a Zephyr header file instead of "" that
is intended to local header files, not header files relative to
specifically defined search paths.

This change was made running the sed shell command below:
$ sed -i -E 's/#include "zephyr\/([^"]+)\.h"/#include <zephyr\/\1.h>/g' \
    `grep -rsl "#include \"zephyr/" arch/`

Signed-off-by: Etienne Carriere <etienne.carriere@st.com>
2026-06-30 06:49:18 -04:00
Liu Qian
ab0c08a6ce arch: riscv: add Zk and Zks ISA extension support
Add RISCV_ISA_EXT_ZK (Scalar Cryptography) and RISCV_ISA_EXT_ZKS
(ShangMi Suite) Kconfig options, and append them to the GCC march
flag when enabled.

Signed-off-by: Liu Qian <liuqian.andy@picoheart.com>
2026-06-29 13:56:59 -05:00
Omar Naffaa
0bbd981df0 arch: riscv: Add support for Smaia and Ssaia extensions
As a part of the AIA specification two new extensions were introduced:
Smaia (Supervisor Machine AIA) and Ssaia (Supervisor Software AIA).
Support is added for these 2 extensions

Signed-off-by: Omar Naffaa <onaffaa@qti.qualcomm.com>
2026-06-22 15:48:32 +02:00
Christoph Busold
6c766d0250 arch: riscv: Refactor PMP writing for DEP
Add macros to read and write CSRs with immediates and use them for
setting userspace blocker in PMP instead of the existing helpers.
This makes the code simpler than with the large switch statement
and should be a bit more efficient.

Signed-off-by: Christoph Busold <cbusold@qti.qualcomm.com>
2026-06-19 22:37:17 +02:00
Christoph Busold
9828037e91 arch: riscv: Detach DEP config from EXECUTE_XOR_WRITE
Move EXECUTE_XOR_WRITE back into userspace and update the comment
to reflect that it only applies to memory partitions.

PMP_DATA_EXECUTION_PREVENTION is now independent from it and no
longer a requirement.

For full protection both options should be enabled. Otherwise,
some data areas my be left executable and writable at the same
time.

Signed-off-by: Christoph Busold <cbusold@qti.qualcomm.com>
2026-06-19 22:37:17 +02:00
Christoph Busold
259d1250f2 arch: riscv: Optimize PMP_DATA_EXECUTION_PREVENTION path
When set_userspace_blocker is called on context switches between
user and kernel, read only the required pmpcfg register instead
of all.

Signed-off-by: Christoph Busold <cbusold@qti.qualcomm.com>
2026-06-19 22:37:17 +02:00
Christoph Busold
fe26d3747e arch: riscv: Add new config PMP_DATA_EXECUTION_PREVENTION
CONFIG_EXECUTE_XOR_WRITE now depends on
PMP_DATA_EXECUTION_PREVENTION, which in turn selects
PMP_KERNEL_MODE_DYNAMIC if user space is enabled. Another new
config PMP_KERNEL_MODE_DYNAMIC_CATCHALL indicates whether dynamic
catch-all programming is required.

This simplifies the code structure.

Signed-off-by: Christoph Busold <cbusold@qti.qualcomm.com>
2026-06-19 22:37:17 +02:00
Christoph Busold
f7e2998288 arch: riscv: Enable CONFIG_EXECUTE_XOR_WRITE during syscalls
Remove userspace blocker in z_riscv_pmp_kernelmode_enable. This way
data execution will not only be blocked in kernel threads but also
during kernel execution in syscalls on behalf of user threads.

Signed-off-by: Christoph Busold <cbusold@qti.qualcomm.com>
2026-06-19 22:37:17 +02:00
Christoph Busold
70df4ac429 arch: riscv: Add CONFIG_EXECUTE_XOR_WRITE support using PMP
CONFIG_EXECUTE_XOR_WRITE is a basic countermeasure to prevent code
injection attacks by making data non-executable. This can be done
on RISC-V with PMP by removing the executable permission.

Since PMP slots are statically prioritized, we can add a region
covering the whole address space into the last register giving
only read-write access. This will be overridden by any other
configured register with lower index so that the code region
remains executable.

In order to make this register apply to kernel threads in M mode,
it needs to be locked, but this means we cannot remove it anymore.
For CONFIG_USERSPACE we therefore need to reserve another register
so that we can add another address space-wide region with higher
priority without any permission to override the last one and limit
user threads to their assigned regions. This needs to be removed
when switching from user to kernel threads, which is done in the
new function z_riscv_pmp_usermode_disable.

This feature simplifies CONFIG_PMP_KERNEL_MODE_DYNAMIC because we
already have a catch-all register for kernel threads.

Does not work with CONFIG_CODE_DATA_RELOCATION for now and requires
PMP region locking.

Signed-off-by: Christoph Busold <cbusold@qti.qualcomm.com>
2026-06-19 22:37:17 +02:00