Commit graph

62720 commits

Author SHA1 Message Date
alexcekay
a450392da5 fs/cromfs: Fix stale cache read in read() fast path.
cromfs_read()'s fast path decompresses a block directly into the
caller's buffer whenever a read reaches a block at its start and the
caller has room for the whole decompressed block, bypassing the
per-file decompression cache (ff_buffer). It nonetheless marked that
block as cached by setting ff_offset, without ever writing ff_buffer
itself.

A later read of the same block that fell onto the slow path trusted
that false cache tag, skipped decompression, and copied from
ff_buffer without it ever having been populated for that block. A
repeated identical fast-path read of the same block hit the same
false tag and skipped decompression entirely, leaving the caller's
buffer untouched and returning whatever was already there.

Fixed by having the fast path only read the cache, never populate it:
reuse ff_buffer when a prior slow-path read already cached the same
block, otherwise decompress straight into the caller's buffer without
touching ff_offset/ff_buffer.

Co-authored-by: Pavlo
Assisted-by: Claude Code:claude-sonnet-5
Signed-off-by: alexcekay <alexander@auterion.com>
2026-08-12 12:12:46 -03:00
Alin Jerpelea
4977c28a3f Documentation: add NuttX 13.0.1 release notes
add release notes for NuttX 13.0.1 release

Signed-off-by: Alin Jerpelea <alin.jerpelea@sony.com>
2026-08-12 21:53:28 +08:00
zhanghongyu
8422531f93 net/udp: fix d_len corruption for 2nd+ SO_REUSEADDR listener
In udp_input()'s broadcast/multicast fan-out loop, each iteration
calls netdev_iob_replace(dev, iob) to swap in a freshly cloned iob
before handing the packet to the next matching connection. That
function unconditionally sets dev->d_len = iob->io_pktlen, which is
the full frame length (IP + UDP headers + payload), undoing the
'dev->d_len -= udpiplen' done once before the loop to strip the
headers off for udp_input_conn().

As a result, every connection after the first sees a d_len that is
udpiplen (IP+UDP header length, eg 28 bytes for IPv4) too large.
This value flows into udp_datahandler() as buflen (it reads
dev->d_len directly) and is stored as the queued packet's declared
length in the connection's read-ahead iob chain. Once more than one
such oversized entry has queued up in the same chain, the consumer
(udp_readahead() in udp_recvfrom.c) parses the following entry's
metadata starting at the wrong offset, so whatever byte happens to
land on src_addr_size is trusted as-is. That single byte (0-255) is
then used as the length in iob_copyout(srcaddr, iob, src_addr_size,
...), which fills a fixed-size stack buffer with no bounds check
outside a DEBUGASSERT - compiled out in release builds - so an
oversized value overflows that stack buffer.

Re-apply the same '-= udpiplen' header-stripping after each
netdev_iob_replace() call in the loop, matching what's already done
once before the loop for the first connection.

Inside udp_input_conn, d_appdata is always set first, and since neither
the ICMP nor ICMPv6 process accesses d_appdata, the redundant d_appdata
settings have been removed.

Signed-off-by: yi chen <94xhn1@gmail.com>
2026-08-12 09:41:52 -03:00
dechao_gong
0be19937ba Documentation/rtl8721dx,rtl8721f: document the I2C driver
The I2C master driver support for the RTL8721Dx (pke8721daf) and RTL8721F
(rtl8721f_evb) boards was merged without the matching board documentation.
Add the missing I2C entry to each board's Features list and an "i2c"
configuration section describing the /dev/i2cN devices, the board pin
table, and the i2ctool usage, mirroring the existing gpio/uart sections.

Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
Assisted-by: Claude <noreply@anthropic.com>
2026-08-12 08:46:16 -03:00
dechao_gong
af49db4483 arch/arm/rtl8720f: add I2C master driver support
Wire the RTL8720F to the shared Ameba I2C master driver
(arch/arm/src/common/ameba/ameba_i2c.c), reusing it unchanged.

Add the per-chip header arch/arm/src/rtl8720f/ameba_i2c_chip.h supplying
the chip's I2C wiring: two controllers (I2C0/I2C1) on their non-secure
register aliases (0x401c8000 / 0x401c9000), the APBPeriph function/clock
masks, the crossbar SCL/SDA pad-mux codes (59/60 and 61/62), and
AMEBA_I2C_HAS_DMA_FIELDS=1 (the chip's I2C_InitTypeDef carries the DMA
request-level fields).

Add the board glue: rtl8720f_i2c.c registers I2C0 at /dev/i2c0
(PA22/PA23) and I2C1 at /dev/i2c1 (PA24/PA25), plus the build wiring
(Make.defs / CMakeLists.txt / ameba_board.mk pull in the common driver
and the fwlib ram_common/ameba_i2c.c data-table source), the bringup
registration hook and the board header declaration.

Add the i2c defconfig (minimal NSH with the i2ctool) and document the
config in the board index.

Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
Assisted-by: Claude <noreply@anthropic.com>
2026-08-12 08:46:16 -03:00
dechao_gong
18d2ae253c arch/arm/rtl8720f: add UART master driver support
Wire the shared common UART driver
(arch/arm/src/common/ameba/ameba_uart.c) into RTL8720F.  Add an
ameba_uart_chip.h supplying the per-chip UART parameters: two
general-purpose controllers (UART0/UART1), their non-secure register
bases (0x401C3000 / 0x401C4000 -- the fwlib UART_DEV_TABLE points at
the non-secure alias), NVIC vectors, APBPeriph function/clock masks
and the crossbar TX/RX pad-mux function codes.

The fwlib ROM UART routines index data tables (UART_DEV_TABLE,
APBPeriph_UARTx) that live in fwlib ram_common/ameba_uart.c, so that
source is compiled in when CONFIG_AMEBA_UART is set.  Wire
CONFIG_AMEBA_UART into Make.defs/CMakeLists/ameba_board.mk, add the
board port table (UART0 at /dev/ttyS1, PA22 TX / PA23 RX, 115200 8N1)
with bringup registration, a uart config and board documentation.

Hardware-verified on rtl8720f_evb: serialrx/serialblaster over a
PA22-to-PA23 TX/RX loopback transferred all 2600 bytes intact.

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
2026-08-12 08:46:16 -03:00
dechao_gong
3197472ad4 arch/arm/rtl8720f: add single-port GPIO support
RTL8720F drives all GPIO through a single 32-pin port A controller
served by one NVIC vector, unlike RTL8721Dx (ports A/B) or RTL8721F
(ports A/B/C).  Add an ameba_gpio_chip.h that configures the shared
common GPIO driver (arch/arm/src/common/ameba/ameba_gpio.c) for a
single port: AMEBA_GPIO_NPORTS=1, AMEBA_GPIO_PORT_IRQS={GPIOA} and
the APBPeriph_GPIO gate bits.

GPIO_INTStatusGet/ClearEdge live in the RTL8720F ROM symbol table, so
no fwlib ram_common object needs compiling in.  Wire CONFIG_AMEBA_GPIO
into Make.defs/CMakeLists/Kconfig, add the board pin table (PA22 out,
PA23 in, PA24 interrupt) with bringup registration and a gpio config.

Hardware-verified on rtl8720f_evb: output, input and (falling-edge)
interrupt all confirmed via a PA22-to-PA24 loopback.

Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
Assisted-by: Claude <noreply@anthropic.com>
2026-08-12 08:46:16 -03:00
Luka Filipović
62b41ad9b4 arch/arm/src/common/stm32: Bound SDIO command response wait by time.
Some checks are pending
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions
stm32_waitresponse() polls SDIO_STA bounded only by an iteration
counter, set to 0x7fffffff for all R1/R1B/R2/R4/R5/R6 commands.  The
hardware CTIMEOUT flag is the intended exit for a missing response,
but it is only generated while the card clock is running and the CPSM
has reached its Wait state.  If the card clock stops or the peripheral
fails, SDIO_STA never updates and the loop spins for INT32_MAX
iterations while holding the FAT filesystem lock, at the caller's
priority-inheritance boosted priority if higher priority tasks block
on the filesystem.  Since the mmcsd layer retries failed commands,
the driver's recovery paths are never reached and the system never
recovers.

Bound the wait by time instead: 250 ms for response-bearing commands
(the largest timeout the SD specification allows for any operation)
and 10 ms for the no-response/R3/R7 cases.  CTIMEOUT remains the
normal error exit within microseconds; the software bound only fires
when the peripheral itself is dead, converting an unbounded spin into
-ETIMEDOUT so the existing mmcsd retry logic can run.

Signed-off-by: Luka Filipović <filipovicluka3@gmail.com>
Assisted-by: Claude Code:claude-fable-5
2026-08-12 15:41:32 +08:00
raiden00pl
9b0d46c222 cmake: normalize .config on reconfigure
olddefconfig only ran when .config was generated from the defconfig,
so changes applied to an existing .config (e.g. with kconfig-tweak)
never got their dependent defaults. Run olddefconfig on reconfigure as
well, as the Make flow does on every build.

Signed-off-by: raiden00pl <raiden00@railab.me>
Assisted-by: Claude Code
2026-08-12 14:38:44 +08:00
dechao_gong
30cbb23e6b arch/arm/rtl8721f: add I2C master driver support
Wire the shared Ameba I2C master lower-half (arch/arm/src/common/
ameba/ameba_i2c.c) into the RTL8721F (amebagreen2) build through a
per-chip header (ameba_i2c_chip.h), and register the RTL8721F EVB
buses at /dev/i2cN.

Per-chip differences from the other Ameba SoCs (non-secure register
bases, crossbar pinmux codes, APB clock masks and the fwlib
I2C_InitTypeDef layout) are isolated in ameba_i2c_chip.h; no change to
the shared driver is needed.

Verified end-to-end on hardware against a second Ameba board acting
as an I2C slave: address ACK, register write and read-back over
repeated-START, and bus scan all pass on I2C0 (PA22/PA23).

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
2026-08-12 14:22:00 +08:00
dechao_gong
dfc55c9bbe arch/arm/rtl8721dx: add shared Ameba I2C driver
Add a shared NuttX I2C master lower-half for the Realtek Ameba I2C
controllers (I2C0/I2C1) in arch/arm/src/common/ameba, driven through
the SDK fwlib in polling mode.  Per-chip wiring (controller count,
register bases, clock masks, crossbar pad-mux codes and the fwlib
I2C_InitTypeDef layout) lives in arch/arm/src/rtl8721dx/ameba_i2c_chip.h
so a port to the other Ameba chips only supplies a same-named header.

Each controller registers as /dev/i2cN from pke8721daf bring-up through
the stock I2C character driver; a dedicated `i2c` defconfig drives the
i2ctool for validation.

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
2026-08-12 14:22:00 +08:00
Ricard Rosson
9b02dead5d boards/esp32s3-ws-lcd128: use esp_hr_timer_init(), fix Wi-Fi build
esp32s3_bringup.c still guards on CONFIG_ESP32S3_RT_TIMER, includes
"esp32s3_rt_timer.h" and calls esp32s3_rt_timer_init().  None of those
exist any more: c17e16eaed ("xtensa/espressif: Update common-source
integration for Xtensa devices") deleted the chip-specific RT timer and
replaced it with the common-source HR Timer, and updated every other
esp32s3 board's bringup to CONFIG_ESPRESSIF_HR_TIMER /
"espressif/esp_hr_timer.h" / esp_hr_timer_init().  This board was missed.

The stale guard is not dead code: ESPRESSIF_WIRELESS selects
ESP32S3_RT_TIMER (which survives only as a deprecated alias that selects
ESPRESSIF_HR_TIMER), so enabling Wi-Fi on this board turns the guard on and
the build fails outright:

  board/esp32s3_bringup.c:61:12: fatal error: esp32s3_rt_timer.h:
  No such file or directory

No esp32s3-ws-lcd128 defconfig enables Wi-Fi, which is why CI has not
caught it.

Switch to the same guard, include and initializer the other esp32s3 boards
use.  No functional change for the existing defconfigs: they leave both
ESP32S3_RT_TIMER and ESPRESSIF_HR_TIMER unset, so the block stays compiled
out.

Verified with esp32s3-ws-lcd128:nsh plus CONFIG_ESPRESSIF_WIFI=y (and the
Wi-Fi prerequisites the in-tree wifi defconfigs set: SCHED_LPWORK,
DRIVERS_WIRELESS/DRIVERS_IEEE80211, NETDEV_WIRELESS_IOCTL, IOB_NCHAINS,
TLS_TASK_NELEM, TIMER): the fatal error above before the change, a clean
build and image after it, with no other change to the configuration.

Signed-off-by: Ricard Rosson <ricard@groundbits.com>
Assisted-by: Claude Opus 5 (Claude Code)
2026-08-12 08:16:52 +02:00
ganjing
a0fcbb7957 libs/libc/risc-v: Refresh memcpy and memset with XLEN-adaptive loops.
Rewrite arch_memcpy.S and arch_memset.S to be register-width aware on
both RV32 and RV64 using REG_L/REG_S/SZREG macros from asm.h.

memcpy gains:
 - 16xSZREG unrolled main loop (128B/iter on RV64, 64B on RV32).
 - Shift-merge path for misaligned src: reads two aligned words
   straddling each output word and shifts them together, so no load
   or store is ever misaligned.
 - Single SZREG and byte loops for remainder and small copies.

memset gains:
 - 32xSZREG unrolled main loop (256B/iter on RV64, 128B on RV32)
   using Duff's device for non-power-of-two remainders.
 - .option norvc ensures fixed 4-byte instruction width for correct
   jump offset calculation in the Duff's device entry.
 - Zero-length input handled correctly (branch to guarded tail).

The old memcpy always used lw/sw even on RV64, wasting half the
memory bandwidth. The old memset unrolled only 16 bytes per iteration.

Signed-off-by: ganjing <ganjing@xiaomi.com>
2026-08-12 10:24:01 +08:00
ganjing
931d5f50d4 libs/libc/risc-v: Add optimized strlcpy.
Add word-at-a-time strlcpy using DETECTNULL for both the copy phase
and the strlen tail when truncated.  The copy loop aligns src and
processes a register at a time, falling to bytewise for the last word
containing the terminator.  When truncated, the remaining src length
is measured with a second word-at-a-time loop.

strlcpy has 46 call sites in a typical kernel image (more than strcpy)
and is not covered by newlib OPTSPEED, making it a high-value target.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: ganjing <ganjing@xiaomi.com>
2026-08-12 10:23:47 +08:00
ganjing
ad9c9d41b0 libs/libc/risc-v: Unroll memcmp with 4-word XOR|OR folding.
Reduce branch overhead in the memcmp main loop by comparing four
words per iteration: XOR each pair, OR the four differences together,
and branch once.  On a mismatch the single-word loop locates the
exact differing word within four words of the fault.

Add a beqz guard at .Lbyte_cmp entry to handle the case where the
4-word loop consumes all remaining bytes exactly.

Measured on QEMU RV32: memcmp(128) 313 -> 271 cycles (13% faster).

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: ganjing <ganjing@xiaomi.com>
2026-08-12 10:23:47 +08:00
ganjing
9b20c629fe libs/libc/risc-v: Add optimized string and memory functions.
Add assembly-optimized implementations for 14 string/memory functions
using word-at-a-time techniques (DETECTNULL, broadcast+XOR) and
XLEN-adaptive macros for both RV32 and RV64:

 - memmove: direction check + forward tail to memcpy, reverse path
   with 16xSZREG unroll and shift-merge for misaligned src.
 - memcmp: word-granularity compare when both pointers share alignment,
   bytewise fallback for mismatched pointers.
 - memchr: broadcast target byte, XOR with each word, DETECTNULL to
   find matches. Counter-based bounds (no pointer overflow).
 - strlen: DETECTNULL word loop, constants loaded from .srodata.
 - strnlen: strlen with counter-based length limit.
 - strcpy/strncpy: word loop with DETECTNULL, zero-fill remainder
   for strncpy. strncpy reuses strcpy via #define USE_AS_STRNCPY.
 - stpcpy/stpncpy: reuse strcpy/strncpy via #define USE_AS_STPCPY.
 - strchr/strchrnul: broadcast+XOR detecting both target char and
   null simultaneously. strchrnul reuses strchr via #define.
 - strrchr: forward scan recording last match position.
 - strncmp: word-at-a-time compare with null detection and counter.
 - strcat: strlen(dst) then strcpy(dst_end, src) word-at-a-time.

Each function is independently selectable via CONFIG_RISCV_<FUNC>,
or all enabled together with CONFIG_RISCV_STRING_FUNCTION=y.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: ganjing <ganjing@xiaomi.com>
2026-08-12 10:23:47 +08:00
Marco Casaroli
5dafb683e4 xtensa/esp32: Let a protected build boot from simple boot.
Some checks are pending
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions
A protected build on the ESP32 could only use the legacy IDF image format.
Kconfig allowed simple boot to be selected with BUILD_PROTECTED, because the
legacy format is only a default and not a select, but the result did not link
and then did not boot.

Simple boot has no second-stage bootloader.  __start() maps the flash itself,
so everything it reaches must already be in RAM.  kernel-space.ld pinned none
of it, and it did not place esp32_start at all, so the entry point went to the
flash the code was about to map.  The chip loaded the RAM segments, jumped to
0x400d0ba4 and took an IllegalInstruction on the first instruction.

So this pins the bootloader, flash, ROM, clock and log objects that
bootloader_init() and map_rom_segments() reach, along with esp32_start itself,
and defines the six _image_* symbols that __start() needs.  All of it is
behind CONFIG_ESPRESSIF_SIMPLE_BOOT, so a legacy build gets the same IRAM it
had before.

kernel-space.ld also had no `#include <nuttx/config.h>'.  It held no
conditionals until now, so nothing showed the omission:  the new blocks
compiled away silently and the link failed as if the file had not been
changed.

The default is unchanged.  A protected build still selects the legacy format
unless the user clears CONFIG_ESP32_APP_FORMAT_LEGACY.

Verified on an ESP32-DevKitC V4, ESP32-D0WD-V3 revision 3.1, with
esp32-devkitc:knsh and the legacy format turned off.  The kernel flashes at
0x1000 and the user image at 0x90000, with no bootloader and no partition
table.  It maps seven segments, reaches NSH, and runs ostest to the same point
as the legacy build.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-08-12 00:37:18 +08:00
Marco Casaroli
46528ea5ee xtensa/esp32s3: Let a protected build boot from simple boot.
BUILD_PROTECTED defaults ESP32S3_APP_FORMAT_LEGACY to y, so a protected build
has always needed the ESP-IDF second-stage bootloader.  Nothing about the
protected layout requires it:  the kernel and user images are described
entirely by ESP32S3_KERNEL_OFFSET, ESP32S3_KERNEL_IMAGE_SIZE and
ESP32S3_KERNEL_RAM_SIZE, and esp32s3_userspace() maps the user image itself.
Three obstacles stood in the way.

Those three symbols were gated on ESP32S3_APP_FORMAT_LEGACY, but
protected_memory.ld needs all of them for KIROM, KDROM, UIROM, UDROM, KDRAM
and UDRAM.  Without them the region lengths underflow to 2**64-1 and the
kernel/user RAM split lands nowhere, which the hardware reports as a DRAM0
PMS monitor violation once the first user process runs.  The offset becomes
0x0 for simple boot, where the image is flashed at the start of the device.

protected_memory.ld had no case for a 32 MB part, so FLASH_SIZE was
undefined there and ROM, UIROM and UDROM underflowed the same way.
flat_memory.ld has had the case all along.

kernel-space.ld defined none of the symbols simple boot needs
(_image_irom_*, _image_drom_*, _bss_*), and kept none of the early code
resident.  __start() runs bootloader_init() and map_rom_segments() before any
flash mapping exists, so everything they reach has to be in RAM -- including
map_rom_segments() itself, which unmaps the MMU it is running from, and
nuttx_enter_critical(), reached from rtc_clk_init() by way of regi2c.  These
mirror what esp32s3_sections.ld already does for the flat build.

Verified on an ESP32-S3-WROOM-2 (32 MB octal flash), esp32s3-devkit:knsh with
FLASH_MODE_OCT:  boots to NSH and runs ostest, where it reaches the same
timedmutex abort as every other target.  The legacy path is untouched.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-08-11 23:49:21 +08:00
guanyi
83e4b6065a drivers/devfreq: add missing governor_data field and ondemand declaration
The ondemand governor (devfreq_ondemand.c) references dev->governor_data
to store its private state, and defines devfreq_ondemand(), but neither
the field in struct devfreq_s nor the function declaration were present
in include/nuttx/devfreq.h.  As a result, building with
CONFIG_DEVFREQ_GOV_ONDEMAND=y failed to compile.

These two definitions were originally introduced by a downstream commit
that was not part of the devfreq upstreaming series, so the gap only
surfaced when the ondemand governor is enabled (which additionally
requires !CONFIG_SCHED_CPULOAD_NONE and is off by default).

Add the governor_data field to struct devfreq_s and declare
devfreq_ondemand() alongside the other governors.

Signed-off-by: guanyi <guanyi@xiaomi.com>
2026-08-11 12:40:27 -03:00
raiden00pl
481d1697a8 arch/x86_64: align the user signal frame and skip the ABI red zone
Some checks are pending
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions
The signal frame was built inside the 128 byte red zone of the
interrupted user code and inherited its stack alignment, so a leaf
function could lose live data to the siginfo copy and the handler
could fault on an SSE access. Build the frame below the red zone,
16 byte aligned; the naked trampoline calls the handler itself and
its call provides the return address slot.

Signed-off-by: raiden00pl <raiden00@railab.me>
Assisted-by: Claude Code
2026-08-11 22:06:32 +08:00
raiden00pl
2c79c9951b arch/x86_64: run the signal trampoline on the thread kernel stack
For a thread interrupted in user mode the trampoline ran on the user
stack, where the signal handler then grows over its frame. Run it on
the thread kernel stack, unused while the thread is in user mode. The
stack cannot be selected from the saved CS: up_initial_state() records
the caller CS, a kernel selector even for user threads.

Signed-off-by: raiden00pl <raiden00@railab.me>
Assisted-by: Claude Code
2026-08-11 22:06:32 +08:00
raiden00pl
4405b12155 arch/x86_64: restore the kernel stack when a signal handler returns
SYS_signal_handler_return restored RSP from saved_rsp, which is not
written when a task signals itself: synchronous dispatch skips
up_schedule_sigaction(), so the kernel stack pointer was set to zero
and the next push faulted. Save the kernel stack pointer at dispatch
in xcp.kstkptr, as risc-v does, and restore that.

Signed-off-by: raiden00pl <raiden00@railab.me>
Assisted-by: Claude Code
2026-08-11 22:06:32 +08:00
Ricard Rosson
3d30272ce7 arch/xtensa/espressif: initialize the HR Timer from the Wi-Fi init path
The Espressif Wi-Fi stack cannot work unless the esp_timer subsystem has
been initialized, but nothing in the Wi-Fi code does that: it is left to
each board's bringup to call esp_hr_timer_init() first.  Any board that
does not happen to make that call dies on the first RF enable.

The dependency is not visible from the Wi-Fi sources.  The path is:

  board_wlan_init() -> esp_wlan_sta_initialize() -> esp_wlan_initialize()
    -> esp_wifi_initialize() -> esp_wifi_api_adapter_init()

and later, when the radio is first powered up:

  esp_phy_enable_wrapper() -> esp_phy_enable() (esp-hal-3rdparty,
  components/esp_phy/src/phy_init.c) -> phy_track_pll_init()
  (components/esp_phy/src/phy_common.c)

phy_track_pll_init() calls esp_timer_create() and
esp_timer_start_periodic() wrapped in ESP_ERROR_CHECK().  Both return
ESP_ERR_INVALID_STATE while esp_timer is uninitialized, because the HAL's
own esp_timer_init_os() startup hook is compiled out on NuttX
(#ifndef __NuttX__ in components/esp_timer/src/esp_timer.c), so the timer
task and the timer ISR only ever get created from NuttX's
esp_hr_timer_init() -> esp_timer_init().

Initialize the HR Timer at the top of esp_wifi_api_adapter_init(), where
the requirement actually originates.  esp_hr_timer_init() is idempotent
(it early-returns once the subsystem is up), so boards that already call
it during bringup are unaffected.  Also make ESPRESSIF_WIRELESS select
ESPRESSIF_HR_TIMER explicitly instead of inheriting it through the
deprecated ESP32{,S2,S3}_RT_TIMER symbols, so the timer adapter is
guaranteed to be built whenever the radio is.

This is deliberately limited to Xtensa.  The RISC-V common-espressif tree
has the same unenforced dependency, but nothing is broken there today: its
ESPRESSIF_WIRELESS already selects both ESPRESSIF_HR_TIMER and RTC_DRIVER,
and esp_rtc.c initializes the timer.  The mirror change can follow from
someone able to test it on RISC-V hardware.

This was diagnosed on an out-of-tree ESP32-S3 board whose bringup lacked
the call.  The failure gives no panic output at all and looks exactly like
a CPU lockup: the system tick stops, the console dies mid-line and USB
stays enumerated but unresponsive.  It was tracked down with ROM-level
ets_printf() breadcrumbs along the init path plus a high-priority thread
that busy-waits on ets_delay_us(): the breadcrumb trail ends inside
phy_track_pll_init() and never reaches the print after it, and the
busy-wait thread keeps printing while every sleep()-based thread stops
waking, showing the tick is gone.  Initializing the timer ahead of Wi-Fi
init makes the same image associate to an AP, obtain a DHCP lease and
serve telnet.  Validated on ESP32-S3 silicon (240 MHz, no PSRAM, 16 MiB
flash).

esp32s3-devkit:wifi builds clean with the change.

Signed-off-by: Ricard Rosson <ricard@groundbits.com>
Assisted-by: Claude Opus 5 (Claude Code)
2026-08-11 10:43:39 -03:00
22078360
23ea1503a1 mips/Makefile: Add nuttx build with CONFIG_ALLSYMS enabled.
Change the arch/mips/src/Makefile to build nuttx with CONFIG_ALLSYMS
enabled in MIPS architecture. This enables symbol name showing in
system, such as 'dumpstack 3' shows both functions name and addresses.

This change is referred to arch/tricore/src/Makefile and updated to
work well with MIPS. And it works with and without CONFIG_ALLSYMS enabled.

Fixes apache#19728

Signed-off-by: wangtao <twangpicasso@gmail.com>
2026-08-11 09:53:38 -03:00
Marco Casaroli
8f69f27b4d boards/esp32-devkitc: Let ostest finish on the knsh configuration.
A full ostest run never reached the end on esp32-devkitc:knsh.  It stopped in
the barrier test:

  barrier_test: ERROR thread 6 create, status=12
  ostest_main: Exiting with status 256

The cause is the interaction of two settings that are each reasonable on their
own.  CONFIG_TLS_ALIGNED is set and CONFIG_TLS_LOG2_MAXSTACK is 13, so every
pthread stack must start on an 8 KiB boundary.  The barrier threads take the
2 KiB default stack, so each one occupies an 8 KiB aligned slot.  Eight of them
do not fit the 96 KiB user heap of a protected build once the tests before them
have fragmented it, and up_create_stack() fails:

  up_create_stack: ERROR: Failed to allocate stack, size 2048

The flat build has the same two settings and passes, because its heap is
320 KiB against 96 KiB here.

So this lowers the barrier thread count for this configuration only.  Four
threads still test a barrier, and they leave margin:  six was the most that
ever started, so six would pass with none.

The user heap cannot grow far.  User data has to sit in the MMU governed window
of SRAM2, which is 128 KiB in total, and the kernel holds the first 32 KiB of
it.

Verified on an ESP32-DevKitC V4, ESP32-D0WD-V3 revision 3.1.  All four threads
reach the barrier and ostest reports "Exiting with status 0".

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-08-11 09:52:16 -03:00
Lwazi Dube
30a3769057 arch/mips: Add support for loadable ELF modules
Implement architecture-specific ELF header definitions and relocation handling
for the MIPS architecture to enable loadable modules.

Fixes #19178.

Changes include:
- Add `arch/mips/include/elf.h` with MIPS ELF relocation types and
  architecture-specific ELF data structures (`arch_elfdata_s`).
- Implement `libs/libc/machine/mips/arch_elf.c` containing `up_checkarch`,
  `up_relocate`, and `up_relocateadd` functions handling `R_MIPS_NONE`,
  `R_MIPS_32`, `R_MIPS_26`, `R_MIPS_HI16`, and `R_MIPS_LO16` relocations.
- Integrate MIPS machine-specific C library support in
  `libs/libc/machine/mips/Make.defs`.
- Update `LDMODULEFLAGS` in `arch/mips/src/mips32/Toolchain.defs` to include the
  little-endian (`-EL`) flag.
- Update `up_coherent_dcache` for proper cache synchronization on JZ4780.

Signed-off-by: Lwazi Dube <lwazeh@gmail.com>
2026-08-11 09:46:46 -03:00
Filipe Cavalcanti
2567b729cf arch/risc-v/espressif: fix SPI IOMUX false positive without SPI2
Some checks are pending
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions
SPI_VIA_IOMUX used SPI2 IOMUX pin macros that are undefined when SPI2
is disabled or on chips without IOMUX SPI pins (e.g. ESP32-P4), so the
driver took the IOMUX path and never routed SPI3 via the GPIO matrix.

Signed-off-by: Filipe Cavalcanti <filipe.cavalcanti@espressif.com>
2026-08-11 13:56:50 +08:00
raiden00pl
45c75f3bda fs/romfs: fix node cache overflow in directories with >256 entries
romfs_cachenode() tracked the allocated size of rn_child in a uint8_t
while rn_count is a uint16_t. Past 256 entries the size wraps to zero,
the grow condition rn_count == num - 1 can never be true again and the
array is not reallocated: entries are written beyond the allocation,
corrupting the heap.

Track the allocated size in a size_t.

Signed-off-by: raiden00pl <raiden00@railab.me>
Assisted-by: Claude Code
2026-08-11 10:53:19 +08:00
Darryl Ring
894a08e35f arch/arm/stm32h5: Fix handling of GPIO port I
Correct the number of GPIO ports (STM32_NPORTS) from 8 to 9 and include
GPIOI in the g_gpiobase array. Also fix the comparison that would
prevent the GPIOI clock from being enabled (this is really a no-op,
though).

Signed-off-by: Darryl Ring <darryl@bluerobotics.com>
2026-08-11 10:51:46 +08:00
zhangyu117
e9e93c3b2c arch/tricore: idle donot depend on illd
Some checks are pending
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions
Replace the iLLD Ifx_Ssw_infiniteLoop() helper in the idle path with
a self-contained 'loopu' instruction wrapper (tricore_idle_loop()).
The 'loopu' (loop unconditional) instruction branches back to itself
until an interrupt is taken, which is the standard TriCore low-power
idle sequence; the GNU and Tasking assemblers spell the backward
label differently, so the macro dispatches on the toolchain.

This removes the arch/tricore idle path's dependency on the Infineon
iLLD/Ssw layer.  No behavior change: the loop is still interrupted by
any IRQ that causes a context switch away from the idle task.

Signed-off-by: zhangyu117 <zhangyu117@xiaomi.com>
2026-08-11 03:41:03 +08:00
Marco Casaroli
7f6a0a30da boards/arm/stm32l4/b-l475e-iot01a: Add a QEMU nsh configuration.
Some checks failed
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions
Build Documentation / build-html (push) Has been cancelled
QEMU's b-l475e-iot01a machine models the STM32L4x5 core peripherals, but
not the QUADSPI controller or the on-board MX25R6435F flash.  The nsh
configuration therefore panics during board bring-up, inside
stm32_qspi_initialize() -> mx25rxx_initialize() -> qspi_command(), before
the console has produced any output.

Add a qemu configuration that is nsh without CONFIG_B_L475E_IOT01A_MTD_FLASH
and the QSPI/MTD/SMARTFS chain that symbol selects.  It boots to an NSH
prompt on USART1 under:

  qemu-system-arm -M b-l475e-iot01a -nographic -kernel nuttx

Document the new configuration, including the fact that QEMU's STM32L4x5
USART model never calls qemu_chr_fe_accept_input() after the guest reads
RDR.  Console input consequently stalls after the first byte or two when a
line is pasted or piped in, although typing at human speed works.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-08-10 22:46:31 +08:00
dechao_gong
9e33dc077a Documentation/rtl8721f: add rtl8721f_evb board photo
Add the board photo and replace the placeholder todo in the RTL8721F EVB
documentation index with a figure directive so the board page renders the
hardware image, matching the other Realtek board pages.

Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
Assisted-by: Claude <noreply@anthropic.com>
2026-08-10 09:51:02 -03:00
dechao_gong
b5ec07b19b arch/arm/rtl8721f: add UART character driver support
Expose the RTL8721F general-purpose UARTs through the shared Ameba serial
driver in arch/arm/src/common/ameba.  Only the chip-specific glue is added:
a new ameba_uart_chip.h supplying the green2 register bases, IRQs, clock
masks and UART TX/RX pin-mux function codes, plus the build wiring and a
board port table registering UART0 at /dev/ttyS1.  The common serial layer
is reused unchanged.

A new "uart" board config enables the driver with the serialrx and
serialblaster examples and runtime TERMIOS support.

Verified on RTL8721F EVB hardware with a PA24/PA25 loopback: single-message
echo, 2600-byte serialrx/serialblaster throughput with no loss, and TERMIOS
reconfiguration (CS7 data-bit truncation, parity and stop-bit ioctl
round-trip, and 9600 baud reprogramming) all pass.

Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
Assisted-by: Claude <noreply@anthropic.com>
2026-08-10 09:51:02 -03:00
Marco Casaroli
067e30e14f arch/x86_64: Build fork() children from the caller's syscall frame.
In a kernel build vfork() is reached through a system call, so the return
address and stack pointer the architecture's entry point can see for itself
are the kernel's, not the caller's.  A child built from those resumes at a
kernel address, which is why x86_64 selected the fork family only for the
flat build.

x86_64_syscall() now publishes the caller's frame in xcp.sregs for the
duration of the stub call, and x86_64_fork() builds the child from it:

  x86_64_fork_syscall()  when xcp.sregs is non-NULL, so that the child
                         returns from the very same `syscall' instruction as
                         the parent, in user mode, on its own stack;
  x86_64_fork_direct()   otherwise, which is the flat build and any kernel
                         thread that calls the entry point as a plain
                         function.

The discriminator is xcp.sregs rather than TCB_FLAG_SYSCALL, which arm64 and
RISC-V use:  that flag also defers signal actions, x86_64 has never raised it,
and its kernel-build signal path does not survive being made to -- a
pre-existing problem that does not belong to this work.

Two properties of SYSCALL/SYSRET shape the child's frame.  The instruction
leaves the caller's RIP and RFLAGS in RCX and R11 rather than on a stack, so
they are moved into the RIP and RFLAGS slots of the interrupt frame the child
is resumed from; and the hardware never records the caller's CS and SS at all,
SYSRETQ reconstructing them from IA32_STAR, so the child's are filled in with
the user code and data selectors at RPL 3.  The frame is therefore not copied
wholesale:  the extended state and the general registers are inherited, while
the segment registers and the thread pointer stay as up_initial_state() left
them, the child's stack being a fresh allocation the parent's FS base does not
describe.

x86_64_fork_relocfp() is new and is not optional here.  A function returns
with `leave', which feeds the frame pointer into the stack pointer, so
relocating only the RBP the child resumes with gets it exactly one frame:
the next return loads a saved RBP still pointing into the parent's stack.

With that in place ARCH_X86_64 can select ARCH_HAVE_VFORK unconditionally.

Build-verified on qemu-intel64:knsh_romfs and qemu-intel64:ostest.  NuttX on
qemu-intel64 requires tsc-deadline and pcid, which TCG does not implement, so
it cannot be run on this host.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-08-10 08:57:30 -03:00
Marco Casaroli
3557791ae2 arch/arm64: Build fork() children from the caller's syscall frame.
In a kernel or protected build vfork() is reached through a system call, so
the return address and stack pointer that the entry point in
arm64_fork_func.S can snapshot for itself belong to the kernel-side stub, not
to the caller.  A child built from that snapshot resumes at a kernel address
on a kernel stack.  This is why arm64 selected the fork family only for the
flat build.

Record what the caller was actually doing instead.  arm64_sync_exc passes the
exception frame to dispatch_syscall() in x7 -- x0-x6 carry the call number and
its six parameters, so x7 is free -- and dispatch_syscall() stores it in
xcp.sregs, mirroring what riscv_swint.c does.

arm64_fork() then chooses where the caller's registers live:

  arm64_fork_syscall()  when TCB_FLAG_SYSCALL is set, rebuilding the child
                        from xcp.sregs so that it returns from the very same
                        SVC as the parent;
  arm64_fork_direct()   otherwise, which is the flat build and any kernel
                        thread that calls the entry point as a plain function.

The stack copy and the relocation of pointers into it are shared by both
paths in arm64_fork_stack() and arm64_fork_reloc().

With that in place ARCH_ARM64 can select ARCH_HAVE_VFORK unconditionally.

Verified on qemu-armv8a:knsh (BUILD_KERNEL), qemu-armv8a:nsh (BUILD_FLAT) and
qemu-armv8a:citest_smp under qemu-system-aarch64:  ostest's vfork_test passes
on all three, and it was absent from knsh before the change.  The protected
configurations are build-verified only (fvp-armv8r:pnsh), there being no
emulator for them here.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-08-10 08:57:30 -03:00
Marco Casaroli
0aaa04d055 arch/arm: Restore vfork() on 32-bit ARM kernel builds.
ARCH_ARM has selected ARCH_HAVE_VFORK only "if !BUILD_KERNEL" since the
fork()/vfork() split.  That condition was deliberate but temporary:  it was
added because the fork family had never worked on a 32-bit ARM kernel build --
the entry point in fork.S snapshots the kernel-side stub rather than the
caller, so a child resumes at a kernel address -- and said in as many words
that "arch/arm takes the condition off again in the patch that adds its
saved-syscall-frame path".

That patch is the one before this.  arm_syscall() records the caller's
exception frame in xcp.sregs and arm_fork() builds the child from it, so the
condition has nothing left to protect against.

Cortex-M is unaffected either way -- BUILD_KERNEL depends on ARCH_USE_MMU,
which it does not have -- so the only configurations this changes are the
MMU-capable ARM ports, which are exactly the ones the previous commit fixed.

Verified on qemu-armv7a:knsh under qemu-system-arm:  ostest's vfork_test
passes, where before the change vfork() was absent.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-08-10 08:57:30 -03:00
Marco Casaroli
608d1e269a arch/arm: Build fork() children from the caller's syscall frame on armv7-a.
In a kernel build the cloning primitives are reached through a system call,
and armv7-a dispatches one by re-pointing the caller's own exception frame at
dispatch_syscall() and switching to the task's kernel stack.  The snapshot the
entry point in fork.S takes for itself therefore describes the kernel-side
stub, and the frames below it are on a stack the child gets no copy of:  a
child built from that snapshot resumes at a kernel address with a stack
pointer into its own user stack.  It faulted with a prefetch abort at PC 0 on
qemu-armv7a:knsh, which is why the fork family had never been run there.

Record what the caller was actually doing instead.  arm_syscall() stores the
exception frame of the outermost system call in xcp.sregs, mirroring
riscv_swint.c, and arm_fork() chooses where the caller's registers live:

  arm_fork_syscall()  when a user stack pointer is saved, rebuilding the child
                      from xcp.sregs so that it returns from the very same SVC
                      as the parent, in the same mode, on its own stack and
                      with no inherited system call nesting;
  arm_fork_direct()   otherwise -- the flat build, a kernel thread in any
                      build, and a build without a kernel stack, where the
                      call is dispatched on the caller's own stack so the
                      caller's frames are copied along with the kernel-side
                      ones.

Note that the discriminator is xcp.ustkptr rather than TCB_FLAG_SYSCALL.  On
armv7-a the caller is the task that runs the kernel side of its own system
call, so being in a system call is not by itself a reason to distrust the
snapshot; the switch to the kernel stack is.  Because arm_syscall() has
already re-pointed the frame by the time arm_fork() runs, the caller's PC,
CPSR and SP come from where arm_syscall() put them -- syscall[0].sysreturn,
syscall[0].cpsr and ustkptr -- and the rest from the frame itself.

Nothing selects the primitives on an ARM kernel build yet, so this commit
changes no configuration; it is what the next one needs to be correct.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-08-10 08:57:30 -03:00
Marco Casaroli
aae62ceaae !Documentation: Describe the fork()/vfork() split.
Documentation/guides/fork_vfork_migration.rst is new.  It says what changed
and why, gives the two primitives as a table, states plainly what breaks, and
answers "which replacement do I want?" from the reader's own reason for having
called fork() -- posix_spawn() or vfork() to run a program, pthread_create()
for a second flow of control that shares memory, fork() itself for an
independent copy.  It also documents the two configuration symbols, what an
architecture has to implement to gain real fork(), and the one visible
consequence of moving the vfork() suspension into the kernel: a waitpid()
after a child that _exit()s can only report status where
CONFIG_SCHED_CHILD_STATUS is enabled.

reference/user/01_task_control.rst gains an entry for fork() and rewrites the
one for vfork(), which described NuttX's limitations rather than the
interface's contract.  standards/posix.rst moves fork() from "No" to "Cond."
and vfork() from "Yes" to "Cond.", both being conditional on the configuration
now.  implementation/memory_configurations.rst no longer lists fork() as
unimplementable in the presence of address environments, which was the whole
point of that section's wish list.  Three long-standing typos in that file are
corrected while touching it, since codespell checks the whole of any file a
patch modifies.

BREAKING CHANGE: this commit carries no code; it is the migration guide for
the fork() withdrawal in the commit before it, and is marked so that every
commit in the series carries the marker CONTRIBUTING.md 1.13 requires.  The
quick fixes are in Documentation/guides/fork_vfork_migration.rst.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-08-10 08:57:30 -03:00
Marco Casaroli
70c2ef5911 !sched/arch/libc: Give fork() and vfork() their real, separate semantics.
NuttX implemented fork() and vfork() as the same function.  Both were libc
wrappers around a single up_fork() syscall; vfork() differed only by a
trailing waitpid().  Underneath, the child joined the parent's address
environment -- the same addrenv_join() that pthread_create() uses -- and got
a private copy of the stack.  So the child shared .data, .bss and the heap
with its parent and ran concurrently with it.

That is not fork().  It is vfork()-with-a-private-stack under fork()'s name,
and the history says so: today's fork() is NuttX's old vfork(), renamed in
c33d1c9c97 (2023) without any change of behaviour.  The failure was silent --
a program written against POSIX fork() compiled, ran, and had its child's
writes land in the parent's variables.

Separate them into two primitives, chosen by which function the caller
called rather than by what the hardware happens to be:

  fork()   child gets its own copy of the parent's memory at the same
           virtual addresses; runs concurrently.  Only where an address
           environment can be duplicated -- elsewhere it is not declared at
           all, so calling it is a build error naming the function.
  vfork()  child shares the parent's memory; parent suspended until the
           child _exit()s or exec()s.  Implementable everywhere.

Below libc there is still one syscall.  up_fork() gains a bool saying which
primitive the caller used, since the per-architecture register snapshot is
the same for both, and passes it to nxtask_setup_fork(), which is the single
place the memory semantics are decided.  The argument arrives in the first
argument register and is never touched:  each architecture's snapshot takes
some other call-clobbered register for its scratch, so the flag is simply
still there when the C worker is called.

The vfork() parent suspension moves out of libc into nxtask_start_fork(),
released from nxsched_release_tcb() by nxtask_resume_vfork().  Two things
follow: the parent is resumed at exec(), since exec_swap() has already handed
the child's pid to the loaded program by the time the vfork stub exits, and
vfork() no longer depends on CONFIG_SCHED_WAITPID.

Releasing there requires one fix in nxtask_exit().  It raises rtcb->lockcount
directly rather than through sched_lock() while it tears the TCB down, so the
nxsem_post() that wakes the vfork() parent leaves it queued where a blocked
task collects while pre-emption is off -- g_pendingtasks, or g_readytorun on
SMP -- and the matching raw lockcount-- does not publish it the way
sched_unlock() would, leaving the parent stranded with nothing to move it on.
The fix mirrors sched_unlock() for each case:  nxsched_merge_pending(), or
nxsched_deliver_task() under CONFIG_SMP.  Both are no-ops while pre-emption is
still disabled, and up_exit() re-reads this_task() afterwards, so a change of
the ready-to-run head is honoured.  Without it vfork() deadlocks wherever no
other task happens to call sched_unlock() afterwards -- rv-virt:nsh64 and
rv-virt:pnsh64, where NSH is blocked in waitpid() holding the lock, and
qemu-armv8a:citest_smp, which hangs the moment the vfork() test runs.

fork() is built on a new addrenv_fork(), backed by an up_addrenv_fork() hook
that duplicates an address environment into freshly allocated pages mapped at
the same virtual addresses -- unlike up_addrenv_clone(), which copies only
the representation and leaves both pointing at the same page tables.  The
child then adopts the parent's stack geometry rather than being given a
relocated copy: a pointer to a stack local taken before fork() must name the
same object in the child that it named in the parent, and the parent's stack
is already in the duplicate, with its contents, at the parent's address.

No architecture implements up_addrenv_fork() yet, so this commit leaves
fork() unavailable everywhere.  That is the intended state.  It withdraws
fork() from ARCH_ARM, flat ARCH_ARM64, ARCH_RISCV, ARCH_SIM and ARCH_X86_64,
where until now it named the sharing primitive; per-architecture patches
restore it, with POSIX semantics, as up_addrenv_fork() lands.  In the
meantime the sharing primitive is still there under the name that describes
it: vfork() for a child that runs a program, pthread_create() for a second
flow of control that shares memory, posix_spawn() for both at once.

Kconfig: ARCH_HAVE_VFORK inherits ARCH_HAVE_FORK's select lines, conditions
included, so no configuration gains machinery; ARCH_HAVE_FORK is redefined to
mean "can provide POSIX fork() semantics" and now depends on ARCH_ADDRENV.

There is one deliberate departure from "verbatim".  ARCH_ARM selected the
fork family unconditionally, BUILD_KERNEL included, and that has never
worked:  on a kernel build the architecture's fork entry point sees the
kernel's return address and stack pointer rather than the caller's, so the
child resumes at a kernel address.  On qemu-armv7a:knsh master faults in
ostest's fork case with "Child did not run" and then a data abort; without
the condition this change faults the same way through vfork().  ARCH_ARM64
and ARCH_X86_64 already carried "if !BUILD_KERNEL" for exactly this reason --
ARM was the outlier.  Conditioning it turns a runtime fault into an honest
absence, which is the whole point of the change; arch/arm takes the condition
off again in the patch that adds its saved-syscall-frame path.  Only the
MMU-capable ARM ports are affected, since Cortex-M cannot build BUILD_KERNEL
at all.

Also fixes two latent syntax errors found on the way: a missing comma in
riscv_fork.c and mips_fork.c, both in *_FRAMEPOINTER && !SAVE_GP branches
that are never compiled today.

BREAKING CHANGE: fork() is withdrawn from every architecture.  It is no
longer declared in unistd.h, so code that calls it fails to build with an error
naming the function, and the sharing behaviour it used to have is gone rather
than renamed.  CONFIG_ARCH_HAVE_FORK no longer means "fork() exists"; it means
"this configuration can provide POSIX fork() semantics", and no architecture
selects it yet.

Quick fix, chosen by why the call was made:

  to run a program                vfork() + exec*(), or better posix_spawn()
  a second flow of control that   pthread_create()
  shares the caller's memory
  a genuinely independent copy    keep fork(), and wait for the per-arch patch
  of the process                  that implements up_addrenv_fork() and selects
                                  CONFIG_ARCH_HAVE_FORK

Out-of-tree code that tests CONFIG_ARCH_HAVE_FORK to decide whether a
fork-then-exec path is available wants CONFIG_ARCH_HAVE_VFORK instead, which is
selected in exactly the places CONFIG_ARCH_HAVE_FORK used to be.  The full
migration guide is Documentation/guides/fork_vfork_migration.rst.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-08-10 08:57:30 -03:00
Alan Carvalho de Assis
87260499e1 cmake: Use NUTTX(_DIR/_BIN_DIR) instead CMAKE(_SRC_DIR/_BIN_DIR)
Some checks are pending
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions
This change fixes NuttX’s CMake support when NuttX is embedded
in another project via add_subdirectory(). CMake’s CMAKE_SOURCE_DIR
and CMAKE_BINARY_DIR refer to the outermost project, causing NuttX
to access its .config, generated files, host tools, and build artifacts
in the parent project’s directories. The fix introduces NUTTX_DIR and
NUTTX_BINARY_DIR, based on CMAKE_CURRENT_SOURCE_DIR and
CMAKE_CURRENT_BINARY_DIR, and consistently uses them for NuttX
self-references while preserving existing standalone builds. It fixes
the Kconfig initialization failure reported in #19697 and allows an
embedded sim:nsh build to configure, build, and boot successfully.
The change affects only the CMake build system (not Make or Kconfig
defaults), requires the corresponding nuttx-apps change, and does not
extend add_subdirectory() support to cross-compiled non-sim boards due
to CMake’s toolchain-file limitation.

Fixes #19697.

Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Alan Carvalho de Assis <acassis@gmail.com>
2026-08-09 11:13:08 -03:00
Justin Hammond
b8e26b127e drivers/usbhost: Let the HID keyboard pick its interrupt pipe.
HIDKBD_NOGETREPORT reads keyboard reports with DRVR_ASYNCH(), and that
macro is only defined when USBHOST_ASYNCH is set.  The option selected
neither, so turning it on by itself fails at the call site with no hint
that a second option was meant to come with it.

Select it.  Every in-tree configuration that sets NOGETREPORT already
resolves USBHOST_ASYNCH: ci20:jumbo and sama5d3-xplained:bluetooth
through USBHOST_HUB, and the two linum-stm32h753bi configurations by
setting it directly.  No existing build changes.

The two that set it directly no longer can, since a selected symbol is
no longer settable, so savedefconfig drops the line.  Their defconfigs
are normalized here to keep them canonical.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
2026-08-09 20:57:41 +08:00
Justin Hammond
a023f61a38 drivers/usbhost: Do not unregister a HID keyboard that never registered.
usbhost_destroy() unregisters the keyboard unconditionally, and it runs
for a device that never got as far as being registered as well: an
enumeration that failed part way through, or a device unplugged while it
was still being set up.

The upper half does not tolerate that call.  It asserts that the lower
half carries the state keyboard_register() puts there, so a keyboard that
fails to come up takes the system down with an assertion rather than
being cleaned up and forgotten.  Seen on a low speed keyboard that
attaches and then does not finish enumerating.

The state the registration leaves behind is what says whether there is
anything to undo, so look at it first.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
2026-08-09 20:57:41 +08:00
Justin Hammond
31fbb99218 sched/semaphore: Keep a negative task id out of the mutex holder.
Some checks are pending
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions
A mutex records its holder as a task id in the low 31 bits of a word
whose top bit means "someone is blocked on this".  The id was stored
without masking, so an id with its top bit set became a holder with the
blocking bit raised.

Task ids are normally small and positive, but not always.
nxsched_gettid() reports -ESRCH for a context that no longer maps to a
running task, and there is a window where that is exactly what the
running context is: nxtask_exit() marks the next task ready to run
while the dying task is still executing on its own stack, and only then
releases the TCB.  Freeing the group inside that release takes and
drops the group's mutexes, so the lock stores 0xfffffffd and the unlock
compares 0x7ffffffd, which are not equal.

With assertions enabled the unlock trips its holder check, and every
exit of a process that frees memory panics.  In a kernel build that is
every exit, so no program could be run twice, and running one at all
took the shell down with it.  Without assertions the failure is silent:
the accidental blocking bit sends the unlock looking for a waiter that
never existed.

Encode the id the same way everywhere it is stored or compared, so that
a lock and an unlock from one context agree whatever the id's sign.
The masked forms of -1 and -2 would alias the "no holder" and "reset"
values, but nxsched_gettid() yields only valid ids and -ESRCH.

mm_lock() already sidesteps this window with a note that gettid() may
return -ESRCH during a context switch; this gives the generic mutex the
same footing rather than a second special case.

Test case, on the EIC7700 EVB, which is a kernel build with assertions:

  nsh> hello
  Hello, World!!

Before, that printed and then panicked in sem_post, taking the shell
with it, every time.  After, five runs in a row complete and the shell
survives.  ps over telnet still completes.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
2026-08-09 10:05:30 +08:00
raiden00pl
753d2a3466 drivers/serial: fetch uart_writev data from the iovec segment
Some checks failed
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions
Build Documentation / build-html (push) Has been cancelled
Since 00010089b8 uart_writev() takes the data one byte at a time with
uio_copyto() plus uio_advance().  Both of them walk the iovec list and
redo the byte counters for every single byte, so most of the work is
bookkeeping rather than copying.  On slow cores this is what limits how
fast the TX buffer can be filled.

Take a pointer to the current iovec segment and read the bytes straight
from it, and move the uio forward once per segment instead of once per
byte.  nseg counts only the bytes that really went into the buffer: it
is increased at the end of a loop pass, and that step is skipped when
uart_putxmitchar() fails.

Measured on nRF52840 (Cortex-M4, 64 MHz), 8 MiB write() to a CDC/ACM
port: 223 KB/s to 481 KB/s.

Signed-off-by: raiden00pl <raiden00@railab.me>
Assisted-by: Claude Code
2026-08-09 03:23:28 +08:00
guanyi3
e7ef45d39a Documentation: add devfreq framework documentation
Document the device frequency scaling framework: the QoS/governor arbitration model, the lower-half driver interface, built-in governors, in-kernel QoS requests, change notifications, procfs, and suspend/resume.

Signed-off-by: guanyi3 <guanyi3@xiaomi.com>
2026-08-08 15:23:54 -03:00
guanyi3
3839a11f2b drivers/devfreq: add ondemand governor build support
Add Kconfig, Make.defs, and CMakeLists.txt entries for the ondemand governor so it can be enabled via CONFIG_DEVFREQ_GOV_ONDEMAND.

Signed-off-by: guanyi3 <guanyi3@xiaomi.com>
2026-08-08 15:23:54 -03:00
guanyi3
2d66436185 drivers/devfreq: guard backtrace code with CONFIG_LIBC_BACKTRACE_DEPTH
When CONFIG_LIBC_BACKTRACE_DEPTH is not set or <= 0, backtrace_get()
is a macro that always sets depth to 0, making the for-loop body
unreachable (Coverity CID 8405332 DEADCODE).

Wrap backtrace_get() call, the loop, and related variable declarations
with #if CONFIG_LIBC_BACKTRACE_DEPTH > 0 to eliminate the dead code
and avoid unused variable warnings.

Signed-off-by: guanyi3 <guanyi3@xiaomi.com>
2026-08-08 15:23:54 -03:00
guanyi3
31041f84ea drivers/devfreq: fix qos_get_value returning wrong min/max aggregation
QOS_REQ_MIN should return the highest value among all min requests
(most restrictive lower bound), but plist_first returns the lowest.
QOS_REQ_MAX should return the lowest value among all max requests
(most restrictive upper bound), but plist_last returns the highest.

This caused qos constraints to be ineffective. For example, two
requests (32, 208000) and (104000, 104000) would merge to (32, 208000)
instead of the correct (104000, 104000).

Fix by using plist_last for QOS_REQ_MIN and plist_first for QOS_REQ_MAX.

Signed-off-by: guanyi3 <guanyi3@xiaomi.com>
2026-08-08 15:23:54 -03:00
guanyi3
674e5ef4d8 drivers/devfreq: use hardware frequency instead of cached value in driver_target
The cached devfreq->cur may become stale when the hardware frequency is
changed externally (e.g. by another core or governor). This causes
driver_target to incorrectly skip frequency transitions when the target
matches the cached value but differs from the actual hardware frequency.

Use driver->get_frequency() to read the real hardware frequency for the
unchanged check, and sync devfreq->cur on match to keep the cache correct.

Signed-off-by: guanyi3 <guanyi3@xiaomi.com>
2026-08-08 15:23:54 -03:00
guanyi3
414694b780 devfreq/ondemand: fix use-after-free in ondemand worker
When devfreq_gov_ondemand_stop() is called from idle task context,
work_cancel() is used instead of work_cancel_sync(), which does not
wait for the currently running worker to complete. If
devfreq_gov_ondemand_exit() then frees governor_data, the worker
may still be accessing it, causing a use-after-free crash.

Fix this by:
- Nullifying dev->governor_data under dev->lock in exit before freeing.
- Moving the governor_data read inside dev->lock in the worker and
  adding a NULL check to bail out early if data has been freed.

Signed-off-by: guanyi3 <guanyi3@xiaomi.com>
2026-08-08 15:23:54 -03:00