Commit graph

63275 commits

Author SHA1 Message Date
Felipe Moura
88c8623ced xtensa/espressif: enable openeth RX interrupt, fix ifdown()'s TX/RX disable
esp_openeth_initialize() (arch/xtensa/src/common/espressif/esp_openeth.c)
attaches the MAC interrupt with esp_setup_irq() but never calls
up_enable_irq(OPENETH_IRQ_MAC), unlike every other Espressif driver in
this tree. Left masked, openeth_isr_handler() never runs and received
frames are only picked up when the netdev work thread happens to run
for some other reason (a transmit). A guest can therefore send but
effectively not receive: ping still works because each request is
itself a transmit, while a socket blocked in recvfrom() waits on a
wake-up that never comes.

Confirmed with a GDB breakpoint counter on openeth_isr_handler():
zero hits before the fix, dozens after, under QEMU's esp32s3 machine
(the open_eth NIC it emulates). With the interrupt enabled, TCP
retransmits over a fixed test window dropped from 86 to 4.

Separately, openeth_ifdown() calls openeth_enable() right under a
comment that says "Disable TX and RX" -- it should call
openeth_disable(), which is what actually disables the two DMA
descriptor rings. Fixed alongside since it's the same function and
the same class of mistake.

Board-independent (arch/xtensa/src/common/espressif), not specific
to any one esp32s3 board; open_eth itself only exists as a QEMU
peripheral, so there's no real-hardware regression risk from either
change.

Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
Assisted-by: Claude:claude-sonnet-5
2026-09-15 18:16:44 -03:00
yushuailong
b5f7b88bae sched/clock: Normalize CLOCK_FD getres errors.
Convert failures from CLOCK_FD lookup and PTP_CLOCK_GETRES into the public
clock_getres() convention of returning ERROR and setting errno. This keeps
dynamic PTP clocks consistent with the other clock_getres() error paths.

Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
2026-09-16 00:04:02 +08:00
yushuailong
144ab6f1b8 sched/cpuload: Validate PID before critmon update.
Move the critical-monitor update after PID hash entry validation and keep
the scheduler critical section held so the TCB remains stable. Invalid or
stale PIDs now return -ESRCH instead of passing a NULL TCB to
nxsched_update_critmon().

Also add the declaration spacing required by nxstyle in the modified file.

Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
2026-09-16 00:04:02 +08:00
yushuailong
c02024b45d sched/clock: Keep RTC synchronized with timekeeping.
Move RTC synchronization outside the non-timekeeping branch so setting
CLOCK_REALTIME also updates the RTC when CONFIG_CLOCK_TIMEKEEPING is
enabled. This prevents corrected wall time from reverting to an older RTC
value after restart.

Preserve the existing low-priority work queue path for RTC drivers that may
block while updating hardware.

Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
2026-09-16 00:04:02 +08:00
yushuailong
36c0dce6d1 sched/irq: Cancel queued work before detaching worked IRQs.
Remove pending IRQ work before clearing its callback state, and guard the
worker callback against a concurrent detach.  This prevents detached worked
IRQs from invoking a NULL function pointer.

Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
2026-09-16 00:02:45 +08:00
yushuailong
6f98c6d38c sched/irq: Make threaded IRQ detach safe without a task.
Only call kthread_delete for a valid positive PID and always clear the IRQ
thread slot afterward.  This makes detach on an unused IRQ, including a
repeated detach, a safe no-op instead of deleting the calling task.

Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
2026-09-16 00:02:45 +08:00
yushuailong
4621d75e2d sched/irq: Reject worked IRQs without a work queue.
Return ENOMEM and leave the IRQ detached when no custom work queue can be
created or all queue slots are occupied.  Also release the queue mutex on
the full-table path and avoid caching a failed queue creation.

Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
2026-09-16 00:02:45 +08:00
yushuailong
6d2443924f sched/irq: Keep threaded IRQ slots free after create failure.
Store the thread PID only after kthread_create succeeds.  This prevents a
negative error value from making subsequent attachment attempts fail with
EINVAL after a transient thread creation failure.

Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
2026-09-16 00:02:45 +08:00
raiden00pl
dcca9a4735 arch/intel64: don't touch the outgoing stack after releasing the csection
up_switch_context() and up_exit() released the critical section and then
kept using the outgoing task's stack: a call/ret through
nxsched_switch_context() and the call into x86_64_fullcontextrestore().
Once the lock is released the outgoing task can be woken and run by
another CPU on that same stack, so those accesses race with it.

Release the critical section as the last step and enter
x86_64_fullcontextrestore() with a jmp so nothing is read from or
written to the outgoing stack after the release.

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
2026-09-15 11:39:05 -03:00
raiden00pl
a5bf9ad9c9 arch/intel64: iretq directly from the register save area
x86_64_fullcontextrestore() built the iretq frame by pushing onto the
current stack.  When called from up_switch_context()/up_exit() that is
the outgoing task's stack, and the outgoing task may already be running
on another CPU, whose pushes clobber the frame before iretq consumes it,
causing a #GP/#PF panic under SMP load.

REG_RIP..REG_SS are contiguous and match the iretq frame layout, so
point RSP at the register save area and iretq from there without
touching the stack at all.

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
2026-09-15 11:39:05 -03:00
raiden00pl
93803cf175 arch/intel64: start IDLE stacks below the register save area
The initial IDLE RSP was placed inside the IDLE register save area that
up_initial_state() later carves out of the stack top, so the idle thread
ran on its own saved context and corrupted it, causing a #GP/#PF panic
under interrupt load.  Compute the save area position exactly and start
RSP below it.

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
2026-09-15 11:39:05 -03:00
raiden00pl
b4ea7848c6 arch/x86_64: don't place the idle stack base below _ebss
The -16 in g_idle_topstack put the derived CPU0 idle stack base at
_ebss - 16, and tls_init_info() writes the TLS info there, corrupting
the last 16 bytes of .bss. Start the stack at _ebss like other
architectures.

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
2026-09-15 11:39:05 -03:00
raiden00pl
d855b5662d boards/qemu-armv8a: add S2OPC server configuration
add S2OPC server configuration for qemu-armv8a

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
2026-09-15 14:55:24 +02:00
raiden00pl
87abfcf36f boards/sim: add S2OPC server configuration
add S2OPC server configuration for sim

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
2026-09-15 14:55:24 +02:00
Xiang Xiao
144d9dff02 libc: add paths.h, sys/ttydefaults.h and termios IUTF8
Add commonly required POSIX/BSD interfaces that portable command-line
utilities expect but that were missing from the C library:

- include/paths.h: _PATH_DEFPATH and the other standard default paths.
- include/sys/ttydefaults.h: BSD default control-character and terminal
  flag definitions.
- include/termios.h: define the IUTF8 input flag.

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2026-09-15 14:51:15 +02:00
zhangning21
44cdacf607 ci: apply Depends-On dependencies to the memory report
The memory report builds this pull request merged into master, together
with the nuttx-apps default branch, and nothing else, so a companion or
predecessor pull request it declares is absent. For a breaking change the
target then fails to build and no report is produced at all, even though
the Build workflow already tests the declared sources through Depends-On.

Apply the declared dependencies before building, reusing the parser and
the fetch/cherry-pick sequence that build.yml uses, and mapping each
repository to its checkout exactly as build.yml does. A stacked nuttx
dependency is no more optional than an apps one: a pull request that uses
an API its predecessor introduces does not build without it.

As build.yml does, read the description through the API rather than
trusting the event payload, so that a manual re-run after editing a
Depends-On line applies the current declaration instead of the one the run
was created with. Unlike build.yml, a failed read stops the job rather
than falling back to the payload: build.yml resolves this once and hands
every target the same tree, while this job runs per target, so a fallback
could leave targets on different declarations while their results are
filed under one SHA.

A declared dependency that cannot be applied fails the job, and so does a
missing parser, a parser crash, or a status this step does not recognise:
each of those means the declaration was never evaluated, and continuing
would measure a combination nobody asked for. build.yml fails Fetch-Source
on the same conditions, and no other step in this job carries
continue-on-error, so falling back silently would be inconsistent with
both. A declaration that parses to nothing valid only warns, again
matching build.yml.

Forward the parser's warnings too. --print-state prints only the state, so
an entry the parser drops -- an unsupported repository, say -- would
otherwise leave no trace here at all, although build.yml annotates it, and
the source set named below would be silently incomplete.

The report is filed under the pull request head SHA rather than the SHA of
the tree that was built, so the measurement cannot be reproduced from that
SHA alone and cannot be split per dependency. That limits provenance, not
the measurement: a combined result is what the declaration asks for, and a
regression that only appears in combination is still a regression. Name
the whole source set in the step summary so the reader knows which heads
went into the number.

Note in the parser that the --print-state output is a parsed contract; the
edit gate that used to be its only caller is gone.

Update the CI documentation to match. Its Pull Request Dependencies
section attributes dependency application to build.yml's Fetch-Source
job alone, so after this change it would read as if the memory report
measured the normal source selection. Cross-reference the two sections
rather than restating the rules, which stay shared.

Signed-off-by: zhangning21 <zhangning21@xiaomi.com>
2026-09-15 08:47:25 -03:00
Jukka Laitinen
d8deca6c52 arch/arm/imx9, arch/arm64/imx9: Release eDMA lock before callbacks
Fix a potential deadlock in the DMA driver. DMA completion callbacks
may immediately submit another transfer, for example:

imx9_dmaterminate()
  -> imx9_dma_txcallback()
    -> imx9_dma_txavailable()
      -> uart_xmitchars_dma()
        -> imx9_dma_send()
          -> imx9_dmach_stop()
	    -> imx9_dmaterminate()

Resulting dmaterminate to take the same spinlock again. Fix this by moving
the spin_unlock_irqrestore_nopreempt before calling the callback. It is not
necessary to keep dma channel locked during the callback; the channel is
already free at this point.

This doesn't directly affect arch/arm/imx9 (the cortex-m version) because
it is not SMP (the spinlock is reduced to blocking irqs), but it is worth
fixing at the same to keep drivers in sync.

Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
2026-09-15 08:41:58 -03:00
Jukka Laitinen
d5d93f6207 arch/arm/src/imx9/imx9_edma.c: Fix nxstyle issues
Fix alignment issues

Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
2026-09-15 08:41:58 -03:00
raiden00pl
44e35044ea boards/qemu-intel64: add citest configuration
CI/NTFC testing config for intel64

Signed-off-by: raiden00pl <raiden00@railab.me>
2026-09-15 18:33:47 +08:00
donghaokun
0276c6aae1 arch/risc-v/include/irq.h: fix vector context allocated size
VPU_XCPTC_SIZE, which is expressed in bytes, but vregs is an array of
uintreg_t.

Signed-off-by: luke kun <donghaokun@lixiang.com>
2026-09-15 16:10:23 +08:00
arnavsharma990
0ccd15d166 drivers/sensors/sensor: cancel fetch watchdog on close to fix UAF
Some checks failed
Build Documentation / build-html (push) Has been cancelled
MemBrowse Memory Report / changes-filter (push) Has been cancelled
MemBrowse Memory Report / load-targets (push) Has been cancelled
MemBrowse Memory Report / identical (push) Has been cancelled
MemBrowse Memory Report / analyze (push) Has been cancelled
sensor_poll() arms a per-subscriber watchdog for fetch()-only sensors
with a requested interval. The watchdog handler sensor_fetch_expired()
dereferences the subscriber and re-arms itself unless user->fds is NULL.

sensor_poll() teardown clears user->fds and cancels the watchdog, but
sensor_close() removed the subscriber from the user list and freed it
without doing either. A close() racing an armed timer therefore lets
the handler run after the subscriber is freed, causing a timer-context
use-after-free and re-arm of a freed watchdog.

Mirror the poll teardown in sensor_close(): clear user->fds and cancel
user->wdog under upper->lock before notifying other users and freeing
the subscriber.

Fixes #20145.

Signed-off-by: arnavsharma990 <2006arnavsharma@gmail.com>
2026-09-15 09:41:11 +08:00
Taha Zarif
384e5e4df4 docs: document Python linting requirements
Document the Python format and lint tools enforced by checkpatch.sh and CI,
and show how to run the existing Python auto-format path.

Assisted-by: ChatGPT:gpt-5.6-sol
Signed-off-by: Taha Zarif <tahazarif380@gmail.com>
2026-09-15 09:40:09 +08:00
Junbo Zheng
7797b12244 libc/atexit: honor registrations made during exit processing
Some checks are pending
Build Documentation / build-html (push) Waiting to run
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
atexit_call_exitfuncs() cached its loop bound on entry
(for (idx = aehead->nfuncs - 1; idx >= 0; idx--)), while
atexit_register() appends new entries at funcs[nfuncs] and bumps nfuncs.
Any function registered by an exit handler via atexit() / on_exit() /
__cxa_atexit() lands above the cached bound and is never invoked, even
though the registration returns OK.

This contradicts the exit(3) documentation that NuttX mirrors verbatim
in its own exit() docstring (libs/libc/stdlib/lib_exit.c):

  It is possible for one of these functions to use atexit(3) or
  on_exit(3) to register an additional function to be executed
  during exit processing; the new registration is added to the
  front of the list of functions that remain to be called.

The same restructure closes a second defect: atexit_call_exitfuncs()
read and cleared the task-group-shared ta_exit list without holding
ta_lock, while atexit_register() takes it ("The following must be
atomic").  Entries are now claimed under the lock and the handler is
invoked with the lock released, so a handler re-entering
atexit_register() cannot deadlock (also safe with the non-recursive
nxmutex used here).

Evidence: exit(3) man page, DESCRIPTION -
https://man7.org/linux/man-pages/man3/exit.3.html
NuttX mirrors this passage verbatim in its own exit() docstring --
5a209a853e/libs/libc/stdlib/lib_exit.c (L65-L70)

Before:
```
A handler that registers another function during exit processing
gets a success return from atexit(), but the new function is never
invoked - it lands above the loop bound cached on entry.
```

After:
```
A registration made during exit processing runs before the older
remaining handlers (order A -> B -> C below), matching the exit(3)
guarantee, and the list is consumed under ta_lock.
```

Testing:

Simulated (sim:nsh, CONFIG_LIBC_MAX_EXITFUNS=8).

Build and run:
```
cmake -B build -DBOARD_CONFIG=sim:nsh -GNinja
cmake -S . -B build   # after setting CONFIG_LIBC_MAX_EXITFUNS=8
                       # in build/.config (sim:nsh default is 1)
cmake --build build -j$(nproc)
(echo hello; echo poweroff) | ./build/nuttx
```
"hello" runs the test at the NSH prompt; poweroff terminates the sim.

The test was carried by apps/examples/hello/hello_main.c (scratch only,
not part of this commit); its diff:

```
--- a/examples/hello/hello_main.c
+++ b/examples/hello/hello_main.c
@@ -24,6 +24,7 @@

 #include <nuttx/config.h>
 #include <stdio.h>
+#include <stdlib.h>

 /****************************************************************************
  * Public Functions
@@ -33,8 +34,29 @@
  * hello_main
  ****************************************************************************/

+static void handler_b(void)
+{
+  printf("ATEXIT-TEST: handler B called (registered during exit)\n");
+}
+
+static void handler_a(void)
+{
+  int ret;
+
+  printf("ATEXIT-TEST: handler A called\n");
+  ret = atexit(handler_b);
+  printf("ATEXIT-TEST: atexit(handler_b) inside A returned %d\n", ret);
+}
+
+static void handler_c(void)
+{
+  printf("ATEXIT-TEST: handler C called\n");
+}
+
 int main(int argc, FAR char *argv[])
 {
   printf("Hello, World!!\n");
+  atexit(handler_c);   /* older entry, must run LAST */
+  atexit(handler_a);   /* registers handler_b during exit */
   return 0;
 }
```

Before the fix:
```
Hello, World!!
ATEXIT-TEST: handler A called
ATEXIT-TEST: atexit(handler_b) inside A returned 0
ATEXIT-TEST: handler C called
```
(handler B is never invoked although its registration returned 0)

After the fix:
```
Hello, World!!
ATEXIT-TEST: handler A called
ATEXIT-TEST: atexit(handler_b) inside A returned 0
ATEXIT-TEST: handler B called (registered during exit)
ATEXIT-TEST: handler C called
```

Assisted-by: Claude Code (GLM-5.3) <claude@anthropic.com>
Signed-off-by: Junbo Zheng <zhengjunbo1@xiaomi.com>
2026-09-14 18:52:46 -03:00
Junbo Zheng
ef37425f71 sched: fix 1-byte overflow in prctl(PR_GET_NAME)
strlcpy() was given sizeof(tcb->name), i.e. CONFIG_TASK_NAME_SIZE + 1,
but the documented caller contract is a buffer of CONFIG_TASK_NAME_SIZE
bytes (include/sys/prctl.h). When a task name is exactly
CONFIG_TASK_NAME_SIZE chars (the normal result of nxtask_setup_name()
truncation), the terminating NUL lands one byte past the caller buffer.
Pass CONFIG_TASK_NAME_SIZE to strlcpy() so the copy is truncated
in-bounds, and drop the stale forced-NUL line left over from the strncpy
era (it ran after the overflow had already happened).

Before:
```
guard byte placed right after a CONFIG_TASK_NAME_SIZE caller buffer
reads 0x00 (expected 0xAA) after the call: strlcpy writes its
terminating NUL one byte past the buffer when the task name is exactly
CONFIG_TASK_NAME_SIZE chars.
```

After:
```
strlcpy(name, tcb->name, CONFIG_TASK_NAME_SIZE) writes at most
CONFIG_TASK_NAME_SIZE bytes; the caller buffer stays intact.
```

Testing:

Simulated (sim:nsh, CONFIG_TASK_NAME_SIZE=31).

Build and run:
```
cmake -B build -DBOARD_CONFIG=sim:nsh -GNinja
cmake --build build -j$(nproc)
echo hello | ./build/nuttx
```
then run "hello" at the NSH prompt.

The test was carried by apps/examples/hello/hello_main.c (scratch only,
not part of this commit); its diff:

```
--- a/examples/hello/hello_main.c
+++ b/examples/hello/hello_main.c
@@ -24,6 +24,8 @@

 #include <nuttx/config.h>
 #include <stdio.h>
+#include <string.h>
+#include <sys/prctl.h>

 /****************************************************************************
  * Public Functions
@@ -35,6 +37,55 @@

 int main(int argc, FAR char *argv[])
 {
+  /* Longest-legal task name: exactly CONFIG_TASK_NAME_SIZE chars, the
+   * normal result of nxtask_setup_name() truncation.
+   */
+
+  static const char longname[] =
+    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+  /* Caller buffer per the documented prctl(PR_GET_NAME) contract, with a
+   * guard byte immediately after it to detect the 1-byte overflow.
+   */
+
+  struct
+    {
+      char buf[CONFIG_TASK_NAME_SIZE];
+      volatile unsigned char guard;
+    } s;
+
+  _Static_assert(sizeof(longname) - 1 > CONFIG_TASK_NAME_SIZE,
+                 "test name must exceed CONFIG_TASK_NAME_SIZE");
+
   printf("Hello, World!!\n");
+  printf("prctl test: CONFIG_TASK_NAME_SIZE=%d\n", CONFIG_TASK_NAME_SIZE);
+
+  s.guard = 0xaa;
+  s.buf[0] = '\0';
+
+  if (prctl(PR_SET_NAME, (unsigned long)longname) != 0)
+    {
+      printf("prctl test: PR_SET_NAME failed\n");
+      return 1;
+    }
+
+  if (prctl(PR_GET_NAME, (unsigned long)s.buf) != 0)
+    {
+      printf("prctl test: PR_GET_NAME failed\n");
+      return 1;
+    }
+
+  printf("prctl test: guard=0x%02x (expected 0xaa), name len=%zu, "
+         "last char=0x%02x\n",
         s.guard, strlen(s.buf), (unsigned char)s.buf[strlen(s.buf)]);
+
+  if (s.guard != 0xaa)
+    {
+      printf("prctl test: FAIL - terminating NUL written 1 byte past "
+             "the caller buffer\n");
+      return 1;
+    }
+
+  printf("prctl test: PASS - caller buffer intact\n");
   return 0;
 }
```

Before the fix:
```
prctl test: guard=0x00 (expected 0xaa), name len=30, last char=0x00
prctl test: FAIL - terminating NUL written 1 byte past the caller buffer
```

After the fix:
```
prctl test: guard=0xaa (expected 0xaa), name len=30, last char=0x00
prctl test: PASS - caller buffer intact
```

Assisted-by: Claude Code (GLM-5.3) <claude@anthropic.com>
Signed-off-by: Junbo Zheng <zhengjunbo1@xiaomi.com>
2026-09-14 18:51:55 -03:00
Darryl Ring
8da98f255f arch/arm/stm32: Remove unneccessary ifdef
The compilation of stm32_mpuinit.c is guarded by CMakeLists.txt and
Make.defs, so this is unneccessary.

Signed-off-by: Darryl Ring <darryl@bluerobotics.com>
2026-09-14 18:49:00 -03:00
Darryl Ring
72e468de8f boards/arm/stm32h5/nucleo-h563zi: Configure MPU
If CONFIG_ARM_MPU and CONFIG_STM32_ICACHE are set, this will configure an
MPU region marking the OTP flash as non-cacheable. This prevents hard faults
when accessing the 4K OTP region from software.

Signed-off-by: Darryl Ring <darryl@bluerobotics.ca>
2026-09-14 18:49:00 -03:00
Darryl Ring
86635d82d6 arch/arm/stm32h5: Enable MPU support
This adds MPU initialization code based on the STM32U5. Unlike the
STM32U5 code, though, this allows the MPU to be used outside of
PROTECTED build mode.

PROTECTED build mode is still not yet supported.

Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Darryl Ring <darryl@bluerobotics.com>
2026-09-14 18:49:00 -03:00
Ulaş Sertan Kemeç
762d2b7958 Documentation/am67: Document GPIO and SPI support on t3-gem-o1.
Add a Peripheral Support section to the board page listing the GPIO and
MCU_MCSPI0 drivers, and replace the "UART console only" warning on both
the chip and board pages -- it no longer describes the port.  The
replacement states what actually constrains the port: NuttX runs on the
R5F under RemoteProc and depends on the bootloader or Linux Device
Manager having powered and clocked the peripherals, because there is no
TISCI client yet.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Ulaş Sertan Kemeç <sertan.usk@gmail.com>
2026-09-14 18:45:44 -03:00
halak0013
4f3b818c3f arch/arm/am67: Add GPIO and MCU_MCSPI0 master driver.
Adds the AM67 GPIO lower half and a polled MCU_MCSPI0 master driver, with the
pad configuration both need.  The K3 instance is not the OMAP2 layout: an HL
header block precedes the functional registers.

Chip select is released only after CHSTAT.EOT, since a high SCLK otherwise
drops it mid-word and truncates the write, and CHCTRL.EN stays asserted between
transfers.

t3-gem-o1 registers /dev/spi0 for its ICM-20948 (CS3) and LPS22DF (CS1), and
raises NSH_MAXARGUMENTS to 16 so the spi tool can address a device.

Verified on t3-gem-o1: WHO_AM_I reads 0xEA on CS3 and 0xB4 on CS1, and the
ICM-20948 streams continuous accelerometer samples over the bus.

Co-authored-by: Ulaş Sertan Kemeç <sertan.usk@gmail.com>
Assisted-by: Cursor
Assisted-by: Claude Code:claude-opus-4-8
Signed-off-by: Ulaş Sertan Kemeç <sertan.usk@gmail.com>
2026-09-14 18:45:44 -03:00
Zhaoqi Xu
f7c65c6205 cmake: reconfigure when .config changes
config.h and CONFIG_* are produced at configure time. kconfig-tweak
edits .config without going through the menuconfig target, so Ninja
left a stale header. Watch .config with CMAKE_CONFIGURE_DEPENDS.

Fixes apache/nuttx#12322

Signed-off-by: Zhaoqi Xu <lzy00419@outlook.com>
2026-09-14 18:40:45 -03:00
raiden00pl
9f5b02fb5a arch/arm/stm32: Fix nxstyle issues in stm32_usbdev_m0_v1.c
Fix nxstyle issues in stm32_usbdev_m0_v1.c

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
2026-09-14 18:32:23 -03:00
raiden00pl
9cf62ee2f3 boards/stm32c0/nucleo-c071rb: Add usb-cdc config
add usb-cdc config for nucleo-c071rb

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
2026-09-14 18:32:23 -03:00
raiden00pl
93db0083df arch/arm/stm32c0: Add USB device support
add USB device support for STM32C0

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
2026-09-14 18:32:23 -03:00
raiden00pl
11128e5543 arch/arm/stm32: Add STM32C0 to HSI48 M0 driver
add STM32C0 to HSI48 M0 driver

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
2026-09-14 18:32:23 -03:00
raiden00pl
47042a6014 arch/arm/stm32c0: Fix RCC CRS and HSIUSB48 bits
APB1 bit 16 is CRS, not CRC (CRC is on AHB). RCC_CRRCR only holds the
HSIUSB48 calibration; the HSIUSB48 enable lives in RCC_CR.

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
2026-09-14 18:32:23 -03:00
raiden00pl
63ca8d1cbc arch/arm/stm32: Add USBDEV_M0_V2 IP flag
Gate the 32-bit USB DRD FS path of the common M0 usbdev driver on
STM32_HAVE_IP_USBDEV_M0_V2 instead of the STM32G0 family symbol.

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
2026-09-14 18:32:23 -03:00
raiden00pl
2a34f57dce Documentation: add S2OPC documentation
add S2OPC documentation

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
2026-09-14 18:30:38 -03:00
Xiang Xiao
d5d134bc79 fs/aio: raise the default AIO_LISTIO_MAX so LTP keeps passing
The new CONFIG_FS_AIO_LISTIO_MAX option defaults to 10 and lio_listio()
now rejects nent > {AIO_LISTIO_MAX} with EINVAL.  The LTP release pinned
by apps/testing/ltp (20230516) submits 256 requests in a single batch from
conformance/interfaces/lio_listio/2-1.c, so ltp_interfaces_lio_listio_2_1
now fails on every configuration that enables CONFIG_TESTING_LTP
(sim:citest, rv-virt:citest, sim:posix_test):

  lio_listio/2-1.c Error at lio_listio() 22: Invalid argument

The EINVAL check itself is required by POSIX, so keep it and raise the
default instead; the limit no longer costs memory because the requests are
linked through the aiocb's own lio_link.

While here, keep _POSIX_AIO_LISTIO_MAX at its POSIX-mandated value of 2
and let AIO_LISTIO_MAX carry the configurable implementation limit.

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2026-09-14 17:12:49 -03:00
Xiang Xiao
74d2c2d119 fs/aio: use list_clear_node() to mark non-batch requests
aio_fsync()/aio_read()/aio_write()/lio_listio() initialized
aiocbp->lio_link with list_initialize(), which makes the node
self-referential (prev = next = &node).  aio_signal() tests
list_in_list(&lio_link) to detect lio_listio batches, so it wrongly
entered the lio_listio completion path for every standalone AIO
operation and notified through the uninitialized
lio_sigevent/lio_sigwork.

With CONFIG_SIG_EVTHREAD=y, garbage lio_sigevent.sigev_notify ==
SIGEV_THREAD caused nxsig_notification() to queue &lio_sigwork.work
onto the low-priority work queue with garbage func/value.  After the
aiocb was freed, the dangling work_s was dispatched with worker=NULL,
crashing in work_dispatch().

Fix: initialize lio_link with list_clear_node() (prev = next = NULL)
so list_in_list() returns false for non-lio_listio operations and
aio_signal() skips the lio_listio path.

While there, reject a NULL aiocbp in aio_fsync(): POSIX Issue 6 no
longer defines a NULL special case, and the old DEBUGASSERT() panicked
debug builds.

Co-developed-by: dengwenqi <dengwenqi@xiaomi.com>
Co-developed-by: fangxinyong <fangxinyong@xiaomi.com>
Signed-off-by: fangxinyong <fangxinyong@xiaomi.com>
Signed-off-by: dengwenqi <dengwenqi@xiaomi.com>
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2026-09-14 17:12:49 -03:00
Xiang Xiao
3b3e97e4a8 fs/aio: add internal aio_read/aio_write to avoid lio_link overwrite
lio_listio() links each aiocbp->lio_link into its batch list before
submitting the I/O, but submitted the operations through the public
aio_read()/aio_write(), which re-initialized lio_link and destroyed
the list membership.  With an aiocb pre-filled with garbage (as in
ostest), the completion path then walked an invalid list.

Extract aio_read_internal()/aio_write_internal() that skip the
lio_link setup; aio_read()/aio_write() initialize lio_link (and
reject a NULL aiocbp) before calling the internal functions, while
lio_listio() calls the internal functions directly to preserve its
own lio_link setup.  For entries that are not part of a batch,
lio_listio() self-initializes lio_link instead.

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2026-09-14 17:12:49 -03:00
Xiang Xiao
7142c0a19e fs/aio: initialize lio_link in aio_fsync()
aio_fsync() never initialized aiocbp->lio_link, but the reworked
aio_signal() tests list_in_list(&lio_link) on every completion.  With
an uninitialized (or zero-filled) lio_link the behavior was
unpredictable; initialize the node so standalone fsync operations are
self-consistent.

Signed-off-by: tengshuangshuang <tengshuangshuang@xiaomi.com>
2026-09-14 17:12:49 -03:00
Xiang Xiao
41f29b32e9 libc/aio: loop in aio_suspend() until a listed request completes
aio_suspend() checked the completion status once and then performed a
single sigtimedwait().  Any SIGPOLL delivered by an unrelated AIO
operation (one not referenced by 'list') woke the caller even though
none of the awaited requests had completed, and with a timeout the
remaining wait time was not preserved either.

Re-check the completion status after every wakeup and continue
waiting, recomputing the remaining time from the absolute deadline so
that the full timeout is honored.

Signed-off-by: wushenhui <wushenhui@xiaomi.com>
2026-09-14 17:12:49 -03:00
Xiang Xiao
4cec501584 fs/aio: fix aio_read/aio_write return values per POSIX
Per POSIX, aio_read() and aio_write() must return -1 and set errno to
EINVAL when the request cannot be queued (aio_reqprio < 0,
aio_offset < 0), and the error must also be retrievable via
aio_error().  Conversely, when queuing fails with a bad file
descriptor, the error belongs to the asynchronous operation: the
functions must return 0 and report EBADF through aio_error().

- Merge the offset/reqprio checks and return ERROR with errno set,
  after storing the result in aio_result for aio_error().
- Drop the aio_fildes < 0 early return: a closed descriptor is now
  caught by fcntl()/aio_queue() and reported through aio_result with
  the function returning OK.
- aio_error(): report -EINVAL (failed validation) through errno
  instead of returning it as an error value.

Signed-off-by: tengshuangshuang <tengshuangshuang@xiaomi.com>
2026-09-14 17:12:49 -03:00
Xiang Xiao
b7d6c8ff41 fs/aio: fix aioc use-after-free and aio_cancel() issues
aioc_decant() frees the AIO container and detaches the aiocbp.  The
I/O workers (aio_read_worker, aio_write_worker, aio_fsync_worker)
called it before signaling completion, so aio_signal() and any code
touching the container afterwards ran on freed memory.  Additionally,
if the caller closed the file early the detached container could be
reused with a stale file reference.  Move aioc_decant() to after
aio_signal() and use aioc->aioc_aiocbp directly in the workers.

aio_cancel() also had two problems: with no aiocbp it looped over
g_aio_pending with a do/while that skipped the list re-entry check, so
a failed work_cancel() on an already running I/O caused an endless
loop; and an invalid fildes only checked 'fildes < 0' instead of
validating the descriptor, so a closed fd was not reported as EBADF.
Use a for-loop that always advances and validate the descriptor with
file_get()/file_put().

Co-developed-by: wushenhui <wushenhui@xiaomi.com>
Signed-off-by: wushenhui <wushenhui@xiaomi.com>
Signed-off-by: tengshuangshuang <tengshuangshuang@xiaomi.com>
2026-09-14 17:12:49 -03:00
Xiang Xiao
2f4d017bb6 fs/aio: add configurable AIO_LISTIO_MAX limit
lio_listio() never validated 'nent' against {AIO_LISTIO_MAX}, so a
batch larger than the documented limit was silently accepted, and the
hard-coded _POSIX_AIO_LISTIO_MAX value of 2 was too small for real
workloads (LTP uses 10 entries per call).

Add the FS_AIO_LISTIO_MAX Kconfig option (default 10), use it for
_POSIX_AIO_LISTIO_MAX in include/limits.h, validate 'nent' in
lio_listio(), and report the limit through sysconf(_SC_AIO_LISTIO_MAX).

Signed-off-by: tengshuangshuang <tengshuangshuang@xiaomi.com>
2026-09-14 17:12:49 -03:00
Xiang Xiao
1ea86e65fd aio: make the lio_listio() prototype match POSIX
POSIX declares lio_listio() as:

  int lio_listio(int, struct aiocb *restrict const [restrict], int,
                 struct sigevent *restrict);

Update the prototype in include/aio.h (and the implementation and
libc.csv entry) accordingly, and drop the parameter names from the
other aio_* prototypes for consistency.

Signed-off-by: guoshichao <guoshichao@xiaomi.com>
2026-09-14 17:12:49 -03:00
Xiang Xiao
d2489101ac fs/aio: skip lio_link teardown for failed submissions in LIO_WAIT mode
When a queued operation fails immediately (bad fd, EINVAL, or a failed
aio_read/aio_write submission), lio_listio() unconditionally deleted
the aiocbp from the request list.  In LIO_WAIT mode (or when no sig was
requested) the lio_link nodes were never linked into the list, so
list_delete() corrupted memory and crashed.

Only unlink the node when it was actually linked, i.e. when
mode == LIO_NOWAIT and a sigevent was provided.

Signed-off-by: tengshuangshuang <tengshuangshuang@xiaomi.com>
2026-09-14 17:12:49 -03:00
Xiang Xiao
2466219100 fs/aio: guard against all-NULL aiocb lists in lio_listio()
When lio_listio() is called with LIO_NOWAIT and a non-NULL sig, and no
I/O could be queued (or all entries are LIO_NOP/NULL), the completion
notification dereferences a NULL aiocbp picked from an empty iteration,
crashing nxsig_notification().

Scan the list for any non-NULL entry before delivering the
notification, and skip it entirely when the list contains only NULL
entries.

Signed-off-by: zhengyu16 <zhengyu16@xiaomi.com>
2026-09-14 17:12:49 -03:00
Xiang Xiao
ad364be818 fs/aio: rework lio_listio() with a lock-protected request list
Previously, lio_listio() called aio_read()/aio_write() to submit the
I/O and only then initialized the per-request notification state
(aio_priv based), so a worker thread could complete an operation before
that state was set up (thread-unsafe), and the completion notification
hijacked the per-request sigevent machinery.

Rework the implementation: lio_listio() now links every aiocb of the
batch into a list (lio_link) before any I/O is submitted.  When an
operation completes, aio_signal() removes its node from the list under
aio_lock() and delivers the lio_listio completion notification only
when the list becomes empty.  The unused aio_priv field is replaced by
the lio_link/lio_sigevent/lio_sigwork fields in struct aiocb.

Co-developed-by: wushenhui <wushenhui@xiaomi.com>
Signed-off-by: wushenhui <wushenhui@xiaomi.com>
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2026-09-14 17:12:49 -03:00
Xiang Xiao
f35993c638 fs/aio: move lio_listio() to fs/aio
lio_listio() submits I/O through the internal aio_read/aio_write
helpers and is only built when CONFIG_FS_AIO is enabled.  Keeping it in
libs/libc splits one subsystem across two directories and forces fs/aio
to export internal interfaces to the libc build.

Move the file (and its two build system entries) from libs/libc/aio to
fs/aio so that the whole AIO implementation lives in one place.

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2026-09-14 17:12:49 -03:00