Commit graph

63161 commits

Author SHA1 Message Date
Marco Casaroli
4cdd3cdbda arch/arm, libs/libc/elf: Build FDPIC modules in the normal ELF build.
With CONFIG_FDPIC selected, a module built by apps/Application.mk is now an
FDPIC shared object.  Nothing about how a module is written or built
changes: the same MODULE = m in the same Makefile, the same crt0 and the
same linker script.

Two things differ from the position independent build beside it.  The
compiler is told -mfdpic -fPIC, and the link is done by an
arm-uclinuxfdpiceabi linker.  The stock arm-none-eabi compiler emits correct
FDPIC objects for both C and C++, so only the link needs it: the stock
linker carries the armelf emulation alone and would turn every import into
an R_ARM_JUMP_SLOT, one word, where the ABI wants an R_ARM_FUNCDESC_VALUE,
which is two, a code address and the data base that goes with it.  Such a
module links cleanly and then calls out of itself with the caller's data
base still in r9.  That linker is in the CI image.

gnu-elf.ld.in gains the two segments an FDPIC module needs, under
CONFIG_FDPIC, because the loader places its read-only and writable segments
independently, and names .dynamic, because a shared object is bound through
it.  The sections themselves are untouched and so are the symbols crt0.c
walks, so one script serves both and both build systems get it.

.bss moves to the end of the script, for every configuration and not only
FDPIC.  It held no file content but sat ahead of .got and .dynamic, which
do, so the writable segment's p_filesz had to span it and the module file
carried the whole of .bss.  A module with 16 KiB of .bss went from 26724 to
10340 bytes, and its writable segment from p_filesz 0x40ac to 0xac against
an unchanged p_memsz.  The loader reads p_filesz off the media, so it read
those bytes too.

Built for mps3-an547:picostest with apps/examples/elf, CONFIG_FDPIC both
ways.  With it on, every module in apps/bin is ARM FDPIC with two PT_LOAD
segments and enters at _start; hello++3, which has a static C++ object,
carries DT_INIT_ARRAY and DT_FINI_ARRAY.  With it off the generated script
has no PHDRS and the modules are what they were.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-09-09 10:21:21 +08:00
Huskya
a60ee84197 arch/arm/src/common/stm32: accept interface-recipient GET/SET_DESCRIPTOR
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
HID class devices fetch the HID Report Descriptor with a
GET_DESCRIPTOR setup packet whose recipient is an interface
(bmRequestType 0x81, wValue 0x2200).  stm32_ep0out_stdrequest() only
dispatches device-recipient descriptor requests and stalls the rest,
so HID class devices cannot enumerate.  Dispatch interface-recipient
requests to the class driver as well.

Signed-off-by: Huskya <itshusky01@gmail.com>
2026-09-09 10:16:12 +08:00
Michal Lenc
48c75c5752 arch/risc-v/src/eic7700x/Kconfig: fix broken kconfig-frontends parsing
kconfig-frontends package needs newline at the end of Kconfig file,
otherwise the parsing fails.

Signed-off-by: Michal Lenc <michallenc@seznam.cz>
2026-09-09 10:15:05 +08:00
Marco Casaroli
0518ccb9ca libs/libc/elf, binfmt: Describe the GOT by base and size, not by index.
gotindex named the .got section header, and every user then reached through
shdr[] for what it actually wanted.  Only one of the five wanted the index.

gotbase and gotsize say it directly.  gotsize is the extent of .got and is
also what says the object has one, and gotbase is where the GOT ended up:
the placed address of .got for an ordinary object, or DT_PLTGOT for an FDPIC
one, which libelf_bind() already reads.  Both are set in libelf_loadfile(),
after the sections are placed, so gotbase is the address the object will be
read at rather than the one it was linked for.

The GOT walk in libelf_loadfile() now runs only when there is a base, which
also keeps it off an FDPIC object.  An FDPIC object's sections are never
placed, so .got carried a link time sh_addr there, and the walk read and
wrote through it.  Its GOT is relocated through its own relocations.

The check that gates libelf_xipacquire() runs before the load, when neither
field is set, so it looks the section up by name.  It hands the index it
found to libelf_loadfile(), which is the only reason that function takes
one: the object is searched once, not twice.

One behaviour changes: a .got that exists but is empty now reads as no GOT.
There is nothing for any of the five users to do with an empty one.

Built for pimoroni-pico-2-plus with CONFIG_PIC, CONFIG_ELF and
CONFIG_LIBC_ELF, and for mps3-an547:bl, which is the board that read the
index.  Run on QEMU with mps3-an547:picostest, which loads PIC ELF modules
from a romfs: hello prints, and ostest reaches the timed mutex test, the
same as before the change.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-09-08 16:31:16 -03:00
Marco Casaroli
1c72098fd5 libs/libc/elf: Fix the nxstyle errors around the FDPIC changes.
The FDPIC work touches these files, and nxstyle reports errors on the lines
around every hunk, which fails the check job.  The errors are older than
this series: a switch body indented two columns too deep in elf_symbols.c,
and declarations with no blank line after them.

Whitespace and one reworded comment, no change in behaviour.

Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-09-08 16:31:16 -03:00
Marco Casaroli
e666653b80 libs/libc/elf: Publish FDPIC functions as descriptors for dlsym.
A module that dlopen()s a library gets back function addresses from
dlsym() and calls them.  Under FDPIC a bare code address is not enough:
the callee needs its own data base as well, so what dlsym() returns has
to be a function descriptor.

The exported symbol table carries no type information -- symtab_s is a
name and a value, and its own comment says typing would have to be added
to support anything but function pointers -- so by the time dlsym() is
asked there is no way to tell a function from an object.
libelf_insertsymtab() is the last point that can: st_info is still in
hand there.  So an FDPIC object's exported functions are published as the
address of a descriptor carved from the module's pool, and dlopen(),
dlsym() and the module registry need no knowledge of FDPIC at all.  The
pool is sized for the dynamic symbol table as well as the relocations,
since both can draw from it.

That leaves the symbol values themselves, which were wrong for any
ET_DYN object.  libelf_loadsymtab() adds the symbol's section address to
its value, which is right for ET_REL, where the section address is where
the section was actually placed and the value is relative to it.  In a
shared object both are already full link-time addresses, so adding them
counts the section twice.  It needs translating onto wherever the object
was placed instead.

Library data is shared between everything that dlopen()s it, because the
registry holds one instance per name.  Giving each user its own copy
would mean teaching the registry about instances, which is a much larger
change to shared code; an executable loaded through exec() already gets
its own data, since that path loads a fresh copy each time.

Built and run on lm3s6965-ek with the examples/elf ROMFS; the FDPIC
module continues to load, relocate and call through its own descriptors.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-09-08 16:31:16 -03:00
Marco Casaroli
04dc50e71a libs/libc/elf: Fix two ways an FDPIC module failed to relocate.
Running one for the first time turned up two holes in the ET_DYN path.
Neither shows up in a build.

An undefined symbol is resolved with libelf_findglobal(), which searches
only the table of globally registered symbols.  The export table that
exec() hands its caller went no further than the ET_REL path, so an
ET_DYN module could not import anything the caller supplied.  Invisible
while such modules resolved everything internally; an FDPIC module
imports its libc, and every import failed with "Unable to resolve addr of
ext ref printf" although the caller had passed a table containing printf.
The export table is now threaded into libelf_relocatedyn() and consulted
when the global table has no answer, leaving the existing lookup order
intact.

A relocation naming a symbol defined inside the object was dropped
silently.  The code handles a relocation with no symbol, and one against
an undefined symbol, but a defined symbol fell through both.  That was
harmless while every dynamic relocation arriving here had symbol index
zero, which is the case for R_ARM_RELATIVE.  FDPIC brings the first ones
that do not: a pointer to a static function is emitted against the
*section* symbol, so the value is the section base and the offset within
it -- including the Thumb bit -- is carried as the addend.  Deriving a
value from the word being patched, as the no-symbol case does, would
translate that addend as though it were an address.  Confirmed against a
real module: .text at 0x23c plus an addend of 0x95 gives 0x2d1, which is
the function with its Thumb bit.

Also stop libelf_symname() reporting a nameless symbol as an error.  A
section symbol has no name, and libelf_findsymbol() walks the whole table
looking for optional entries such as nx_stacksize, so it meets these
routinely and checks for -ESRCH itself.  At error level it printed ten or
more lines per module load and buried the diagnostics that matter.

Built and run on lm3s6965-ek with the examples/elf ROMFS.  The ET_REL
test modules load as before, and an FDPIC module now loads, relocates,
resolves printf and puts from the table exec() supplied, and calls
through a function descriptor of its own.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-09-08 16:31:16 -03:00
Marco Casaroli
450cfad383 libs/libc/elf: Read the dynamic tags an FDPIC object needs.
libelf_relocatedyn() reads the handful of DT_* tags it needs to walk the
relocation tables and ignores the rest.  Three more matter now.

DT_PLTGOT is where the object's data base lives.  An FDPIC module runs
with that in the PIC base register, and every function descriptor built
for it names the same base as the one its callee should run with, so
without it there is nothing to put in a descriptor's second word.

The DT_*_ARRAY tags are the constructor and destructor tables.  These are
already found through the section headers a few lines further down, and
that path is kept, but the dynamic tags are the authoritative copy and an
object is not obliged to carry section headers at all.  Both paths now
translate through libelf_addr(), so they agree on the answer rather than
depending on which ran last.  The tag values themselves were missing from
include/elf.h and are added.

Sizing the descriptor pool has to happen here rather than later.
R_ARM_FUNCDESC asks the loader to manufacture a descriptor and hand back
its address, which means the space must exist by the time the relocation
is applied, and by then the segment has been placed.  So libelf_elfsize()
reserves it behind the writable data, bounded by the relocation count --
one relocation cannot ask for more than one descriptor.  That bound has
slack in it, but a descriptor is two words and modules are small, which
is cheaper than walking every relocation twice to get an exact count.

Nothing here runs for a non-FDPIC object.  Built and booted
mps3-an547:picostest with no change in behaviour.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-09-08 16:31:16 -03:00
Marco Casaroli
1aa32bbc07 libs/libc/elf: Place an FDPIC object's segments independently.
An ET_DYN object is loaded into one allocation with its data behind its
text, because its data references sit at a fixed distance from the code
that makes them.  An FDPIC object does not work that way: it reaches its
data through a base register, so the two segments can be placed wherever
suits, and the point of the format is that the read-only one is left on
the media and executed there while only the writable one is copied.  One
copy of the text then serves every instance.

So libelf_load() grows a second case.  The object announces itself in the
OS/ABI byte, which is noted once in libelf_loadhdrs() rather than
re-derived; e_flags cannot be used for this, as an FDPIC object's are an
unremarkable EABI version and testing them would reject every valid
module.  Text is taken from the media address plus the segment's own file
offset -- the same arithmetic the ET_REL path already does with
sh_offset -- and libelf_loadfile() does not read it.  If the filesystem
cannot show its media, the loader copies the text to RAM instead.  The
module then loses the shared text and the flash saving, but it runs.

Obtaining that address needs two mechanisms, and they are not
interchangeable.  A compacting filesystem can move a file's blocks, so it
hands out an address only with a pin that holds them still and expects
the pin back; xipfs is the one in tree.  A filesystem whose layout never
changes has nothing to hold and answers FIOC_XIPBASE with a bare address;
romfs and tmpfs are those.  libelf_xipacquire() asks for the pin first,
because a filesystem that needs one is not safe without it, and
libelf_unload() gives it back.  The loader asks for a pin only if it can
hold one, or the pin would stay for ever.

The pin is thus not specific to FDPIC.  Any module that executes in place
from a compacting filesystem takes one, and gives it back at unload.

mmap() is not used, though both filesystems implement it.  The mapping
would be recorded against whichever task called the loader, while the
release happens when the module's own task exits, which is a different
group -- so the pin would outlive the module and the extent would never
become movable again.

Unloading has to change with placement: the existing path frees only
textalloc because ET_DYN had a single allocation, which would leak an
FDPIC object's data and free media the filesystem only lent us.

Nothing here runs for a non-FDPIC object; every branch is behind the flag
and the single-allocation path is untouched.  Built and booted
mps3-an547:picostest, which is CONFIG_ELF with CONFIG_PIC, with no change
in behaviour.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-09-08 16:31:16 -03:00
Marco Casaroli
9f1107862b binfmt, arch/arm: Add the CONFIG_FDPIC option and the ABI header.
The commits that follow teach the ELF loader to load an FDPIC object.  This
puts the option they hang off and the definitions they share in one place
first, so each of them builds on its own.

CONFIG_FDPIC depends on ARCH_HAVE_ELF_FDPIC, which an architecture selects
when it has a PIC base register and the FDPIC relocations.  Only armv7-m
and armv8-m select it today, and it defaults off, so nothing changes for
anyone who does not ask for it.

include/nuttx/fdpic.h holds what both sides of the loader need: the two
word function descriptor an FDPIC module passes instead of a code address,
the test for whether the caller is such a module, and the call sequence
that enters one with its own data base.  All of it is behind CONFIG_FDPIC,
thus the header is empty without it and a file may include it
unconditionally.

The call sequence itself is architecture specific, so arch/arm/include/arch.h
supplies it as up_fdpic_invoke(), beside the other PIC base register macros.
up_setpicbase() cannot serve here: the register has to hold the module's
base for exactly one call and then go back, and nothing in C tells the
compiler the register is live across that call, so the save, the install,
the branch and the restore have to be one sequence.

Built for mps3-an547:bl and mps3-an547:picostest, with CONFIG_FDPIC off,
which is every configuration in the tree.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-09-08 16:31:16 -03:00
wangjianyu3
f17c655284 Documentation/rp2040: document fastboot_usb config for waveshare boards
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
Add a "fastboot_usb" section to the waveshare-rp2040-zero and
waveshare-rp2040-lcd-1.28 board doc pages, describing the USB fastboot
composite configuration added by the previous commits: fastbootd runs
on boot instead of NSH, composed together with CDC/ACM for the
console, and reachable on the host via fastboot devices/getvar/reboot.

Assisted-by: OpenCode:claude-sonnet-5
Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
2026-09-08 08:22:37 -03:00
wangjianyu3
7e53ba18f8 arch/arm/rp2040: fix IN endpoint DPSRAM index for bare-eplog callers
rp2040_allocep() indexes the endpoint's DPSRAM buffer/control
registers via RP2040_DPINDEX(eplog) and RP2040_EPINDEX(eplog), both
of which take the transfer direction from the direction bit of
'eplog' itself instead of trusting the explicit 'in' argument that
is also passed to this function.

This is harmless for callers that always encode the direction bit
into 'eplog' (e.g. CDC/ACM's CDCACM_MKEPBULKIN()/MKEPINTIN(), which
OR in USB_DIR_IN), since 'in' then always agrees with that bit.  But
drivers/usbdev/usbdev_fs.c (the generic ADB/fastboot class driver)
calls DEV_ALLOCEP() with a bare endpoint number in 'eplog' (no
direction bit) and passes the direction only via the separate 'in'
parameter - matching this function's own "direction bit ignored"
contract for 'eplog' (see its Input Parameters doc, and the
pre-existing "Ignore any direction bits in the logical address"
comment, both dating back to the original driver in b860e3c4ad).
For such a bare-number IN endpoint, USB_ISEPOUT(eplog) always
evaluates true (the IN bit is never set on a plain number), so
RP2040_DPINDEX(eplog) silently pointed the endpoint's buffer/control
registers at its OUT slot instead of its IN slot.  The real IN slot
was left unconfigured, so the SIE responded to every IN token on
that endpoint with a STALL - confirmed on real hardware via usbmon:
'C Bi:1:050:6 -32 0' (EPIPE) on every attempt, while the paired OUT
endpoint (which "accidentally" resolved to the correct slot for the
same reason) worked fine.

Fix: normalize 'eplog' to agree with the explicit 'in' argument
before it is used by RP2040_EPINDEX()/RP2040_DPINDEX(), so both
macros keep their original, single-argument form and every use of
eplog's direction bit below this point is consistent with 'in'.
Existing 0x80-encoded callers (EP0, CDC/ACM) already agree with 'in'
and are unaffected by the normalization.

Also fix two pre-existing nxstyle violations in this same file
(a misaligned comment block under USB_REQ_SYNCHFRAME, and a bare
';' body instead of empty braces on a while loop), both dating back
to the original driver in b860e3c4ad as well; CI runs nxstyle on
the whole file whenever it is touched.

Assisted-by: OpenCode:claude-sonnet-5
Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
2026-09-08 08:22:37 -03:00
wangjianyu3
cab92d310d boards/rp2040: add USB fastboot composite support for waveshare boards
Add a CDC/ACM (console) + USB fastboot (ADB "fastboot" personality)
composite device to the shared rp2040_composite.c board glue, and a
new "fastboot_usb" defconfig for waveshare-rp2040-zero and
waveshare-rp2040-lcd-1.28.

- boards/arm/rp2040/common/src/rp2040_composite.c: add a third
  composite slot for CONFIG_USBADB (covers both plain ADB and, with
  CONFIG_USBFASTBOOT, the "fastboot" personality of the same driver)
  alongside the existing MSC/CDC-ACM slots.  While adding this,
  fixed a latent bug: the CDC/ACM block never advanced ifnobase/
  strbase after filling in its own slot, because CDC/ACM used to
  always be the *last* device in the composite (nothing downstream
  ever needed the incremented values).  Now that a device can follow
  CDC/ACM, the missing increment caused the fastboot interface to be
  assigned the same USB interface number as CDC/ACM's control
  interface (both 0), which the Linux kernel rejects with "Duplicate
  descriptor for config 1 interface 0 altsetting 0, skipping" and
  drops the fastboot interface entirely (confirmed via lsusb -v and
  disassembly of the generated board_composite_connect() code).

- boards/arm/rp2040/waveshare-rp2040-zero/configs/fastboot_usb and
  boards/arm/rp2040/waveshare-rp2040-lcd-1.28/configs/fastboot_usb:
  new defconfig booting directly into fastbootd
  (CONFIG_INIT_ENTRYPOINT="fastbootd_main", no nsh) which brings up
  the CDC/ACM + fastboot composite via
  CONFIG_SYSTEM_FASTBOOTD_USB_BOARDCTL as soon as fastbootd starts,
  so the CDC/ACM sub-interface still provides a console for boot/
  fastbootd log visibility without requiring a wired UART, while the
  fastboot vendor interface is what `fastboot devices`/`getvar` talk
  to.

Assisted-by: OpenCode:claude-sonnet-5
Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
2026-09-08 08:22:37 -03:00
yushuailong
35e8eebff3 Documentation/critmon: Document context-switch accounting.
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
Remove the misspelled crimon placeholder so the application appears
only under its correct name.

Document how nxsched_switch_critmon() updates timing across context
switches, correct the RUN and TIME column descriptions, and link the
application page to the implementation guide.

This follows up on PR #20066

Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
2026-09-08 08:30:45 +02:00
zhekunren
078782846e net/tcp: add configurable delayed ACK threshold
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
The delayed ACK logic previously sent an ACK for at least every second
received segment (hard-coded threshold of 2 per RFC 1122).  Add the
NET_TCP_ACK_FREQUENCY Kconfig option (range 1-255, default 2) to make
this threshold configurable at build time.

The delayed ACK timer still forces an ACK after at most 0.5 seconds, so
RFC 1122 timing compliance is preserved regardless of the configured
threshold.  The default value of 2 keeps the exact current behavior:
the new condition rx_unackseg >= FREQ - 1 is equivalent to the previous
rx_unackseg > 0, and the counter increment degenerates to the previous
rx_unackseg = 1 assignment.

Signed-off-by: zhekunren <zhekunren@qq.com>
Assisted-by: GLM-5.2 <noreply@z.ai>
2026-09-08 09:00:19 +08:00
Michal Lenc
af2a8c6412 drivers/mtd/gd25.c: ensure the device is not in power down mode
Commit 2a7cf05 added support for QSPI control but removed functions
gd25_purdid (leave power down state) and gd25_pd (enter power down).
It's likely ok to avoid putting the device in power down state after
every operation, but we need to wake it up from the power down state
before first accessing it.

Without the fix the flashes used with NuttX prior to 2a7cf05 commit
don't work anymore as they are in power down state. The fix ensures
we wake from this state during the initialization.

Also fixes various coding style errors.

Signed-off-by: Michal Lenc <michallenc@seznam.cz>
2026-09-08 08:59:33 +08:00
zhangyu117
9b9d87b69c arch/atomic: remove up_testset in spinlock
Remove the per-arch testset implementation from the spinlock layer.

The testset abstraction predates the unified spinlock.h API and is no
longer used now that all arches provide spin_lock_irqsave()/
spin_unlock_irqrestore() directly.  Drop the per-arch *_testset.{c,S}
implementations and spinlock.h files for arm, sim, sparc, tricore,
x86_64, and xtensa, along with the CXD56_TESTSET,
CXD56_TESTSET_WITH_HWSEM, and CXD56_ATOMIC_WITH_HWSEM Kconfig options
in arch/arm/src/cxd56xx, and simplify the CXD56 semaphore pool loop
in cxd56_sph.c to a single unconditional range.

Signed-off-by: zhangyu117 <zhangyu117@xiaomi.com>
2026-09-08 08:58:54 +08:00
ouyangxiangzhen
f1837981fa style: add missing blank line after declarations
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
Fix checkpatch "Missing blank line after declarations" errors in
drivers/timers/arch_timer.c and sched/sched/sched_processtickless.c.
These are pre-existing issues, not introduced by the recent tickless
RR series.

Assisted-by: Zhipu GLM-5.3
Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
2026-09-07 10:17:46 -03:00
ouyangxiangzhen
75bc159896 sched/tickless: Fix SCHED_RR timeslice accounting on preemption
In tickless mode, the scheduler timer is stopped whenever the currently
running task requires no time slicing (CLOCK_MAX).  When a SCHED_RR task
was later switched in, nothing re-armed the timer, so the task could run
indefinitely without round-robin rotation.

Also, when a SCHED_RR task was preempted, its timeslice counter was not
decremented for the time already consumed, effectively giving the task
"bonus" CPU time when resumed.

Solve both by performing RR accounting on context switches:

- nxsched_suspend_roundrobin() charges the elapsed execution time
  against the timeslice of the RR task being switched out
- nxsched_resume_roundrobin() restarts the scheduler timer for the
  remaining timeslice of the RR task being switched in, so the timer
  is always armed while an RR task is running

This also removes the previous workaround in nxsched_process_timer
that triggered the scheduler on every timer tick.

Assisted-by: Zhipu GLM-5.3
Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
2026-09-07 10:17:46 -03:00
ouyangxiangzhen
be9200f95a sched/sched: Fix roundrobin scheduler timer if SCHED_TICKLESS enabled
In tickless mode, the scheduler timer is stopped whenever the currently
running task requires no time slicing (CLOCK_MAX).  When a SCHED_RR task
was later switched in, nothing re-armed the timer, so the task could run
indefinitely without round-robin rotation.

Reassess the scheduler timer in nxsched_switch_context() before the
context switch when the task being switched in uses round-robin
scheduling, so that the timer is always armed while an RR task is
running.  Hooking into nxsched_switch_context() covers all context
switch paths (task context switch, interrupt exit, syscall and task
exit) since every architecture calls it on every switch.

Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
2026-09-07 10:17:46 -03:00
ouyangxiangzhen
f134a5678d sched/hrtimer: Fix reprogram with wrong expiration when reinserting hrtimer
In hrtimer_start_absolute, when a pending hrtimer is removed (was the
head) and reinserted with a later expiration time, the reprogram flag
remains true but the hrtimer is no longer the earliest timer in the
queue. The old code passed hrtimer->expired to hrtimer_reprogram, which
was incorrect. Use hrtimer_get_first()->expired to ensure the hardware
timer is reprogrammed with the actual earliest timer's expiration time.

Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
2026-09-07 10:17:46 -03:00
ouyangxiangzhen
b438b7a083 timers/clkcnt: Round-up when converting nsec to cnt
Use round-up logic in clkcnt_delta_time2cnt() to prevent
timer sleep duration being too short due to truncation.

Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
2026-09-07 10:17:46 -03:00
ouyangxiangzhen
9ab05ec3f5 drivers/timers: fix UB and mask width in up_timer_getmask
The mask computation introduced by "fix infinite loop in
up_timer_getmask when maxticks == CLOCK_MAX" has two problems:

1. If maxticks == 0, flsx(0) expands to __builtin_clz(0), which is
   undefined behavior, and the shift count becomes 8 * sizeof(clock_t)
   = 64 for a 64-bit clock_t, which is undefined behavior as well.
   The loop-based code that was replaced kept *mask = 0 in this case.

2. CLOCK_MAX is INT64_MAX, i.e. 63 one bits, not a full-width bit
   pattern. The resulting mask is always one bit narrower than the
   one produced by the original loop; e.g. a 32-bit timer got
   0x7fffffff instead of 0xffffffff, so counter deltas >= 2^31 were
   truncated in the clock timekeeping code.

Fix this by keeping *mask = 0 when maxticks == 0 and by deriving the
mask from the full-width unsigned constant (uint64_t)-1, which
restores the all-ones semantics of the original loop and still covers
the maxticks == CLOCK_MAX case.

Also initialize maxticks in arch_timer.c: if the lower half does not
implement the maxtimeout ops, the value is left untouched and would
otherwise be read uninitialized.

Assisted-by: Zhipu GLM-5.3
Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
2026-09-07 10:17:46 -03:00
ouyangxiangzhen
72db205050 drivers/timers: fix infinite loop in up_timer_getmask when maxticks == CLOCK_MAX
When maxticks equals CLOCK_MAX (all bits set), the loop that builds
the mask by (*mask << 1) | 1 never terminates because the shifted
value wraps around to the same mask value, making next > maxticks
always false.
Replace the loop with a single flsx-based expression that computes
the mask directly, which naturally covers the CLOCK_MAX case.

Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
2026-09-07 10:17:46 -03:00
yushuailong
170d02da21 sched/critmonitor: Restore the target run start time.
The context-switch merge assigned the current timestamp to run_time instead of run_start. This overwrote the accumulated runtime and left the next elapsed-time calculation with a stale start value when critical-monitor CPU load accounting was disabled.

Store the timestamp in run_start under the thread runtime monitor configuration, matching the former resume path.

Fixes: b2a69ba781 ("sched: merge nxsched_suspend/resume_critmon")
Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
2026-09-07 21:06:53 +08:00
yushuailong
23d2eb96f3 tools/pynuttx: Update the preemption field annotations.
The struct tcb_s premp_* members were renamed to preemp_*, but the GDB TCB protocol retained the old annotations.

Update the annotations to match the current structure field names.

Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
2026-09-07 21:06:53 +08:00
yushuailong
ba77d2b708 sched/critmonitor: Fix the preemption start field name.
The premp_start member was renamed to preemp_start, but the old name was reintroduced when the critical monitor switch paths were merged.

Use the current struct tcb_s field name so configurations with preemption monitoring enabled build successfully.

Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
2026-09-07 21:06:53 +08:00
yushuailong
4d14db131c sched/critmonitor: Fix declaration spacing.
Add the blank lines required between local declarations and statements so sched_critmonitor.c passes nxstyle.

Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
2026-09-07 21:06:53 +08:00
raiden00pl
eb2226dccc tools/nxstyle: whitelist S2OPC identifiers
Whitelist the S2OPC and OPC UA prefixes plus the mixed-case
structure fields used by the NuttX port and server example.

Signed-off-by: raiden00pl <raiden00@railab.me>
2026-09-07 21:05:55 +08:00
Justin Hammond
c47d7151d7 arch/risc-v/eic7700x: Maintain the data cache through the L3 controller.
The EIC7700X is not cache coherent.  No device that moves data on its
own snoops the harts' caches or is snooped by them, so a buffer handed
to a device needs the cache maintained around the transfer.  The harts
are coherent with each other; it is DMA that is not.

The RISC-V standard offers no way to do that here: the Zicbom extension
this core does not implement is the portable answer, and there is no
other.  Maintenance is instead a store to the L3 controller carrying the
physical address of a cache block.  That store is the only operation the
hardware offers: it writes back and invalidates together, so a block
cannot be dropped without being written out first.  Everything built on
top is shaped by that, which is why a range being invalidated has to own
whole blocks.

The L3 is inclusive of the L1 data cache and back invalidates it, so one
store per block maintains the whole hierarchy, with nothing to do per
hart.  The block size is 64 bytes, which is what makes the descriptor
rules in the storage and network drivers what they are.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
2026-09-07 10:03:52 -03:00
Justin Hammond
1686bb6c9e arch/risc-v/eic7700x: Add CPU core clock control.
Drives the speed of the four application cores.  The rate is set to any
of the operating points the vendor validates, all of which share a core
voltage, so this touches no regulator.

The cores run from the PLL being reprogrammed, so they park on a slower
clock first, through a selector the vendor names as glitch free.  While
parked the PLL is stopped, given new dividers, restarted and watched
until it locks; if it never locks the cores stay parked, since returning
them to an unlocked PLL does not fail safely.

Above a gigahertz the bus ratio must be two to one before the cores
return: the bus fabric does not reach beyond about eight hundred
megahertz.  That is the one step in the sequence software cannot recover
from, so the mux is moved before the ratio.

The rate is measured rather than derived.  The cores are counted against
the crystal derived time counter and the result reported beside what the
clock tree computes, because the manual and the vendor's code number the
CPU PLL's outputs differently.  The core selector's parent is
cpupll_fout1, and the three CPU PLL outputs are marked
CLK_GET_RATE_NOCACHE since this driver reprograms that PLL at run time.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
2026-09-07 10:03:33 -03:00
Jacob Dahl
304cbb1372 arch/arm/stm32h7: poll MDIO completion in microseconds, not 5 ms steps
stm32_c22_read() and stm32_c22_write() waited for the MACMDIOAR busy bit
with up_mdelay(5) between checks. A Clause 22 frame takes about 30 us,
so the first check always sees the bus busy and every PHY register
access costs a 5 ms busy-wait, roughly 150 times the transfer.

stm32_phyinit() waits for link-up with PHY_RETRY_TIMEOUT (6552) MSR
reads. With no cable attached that is 33 s of CPU spent in
up_mdelay() inside ifup, with the network lock held: on an STM32H753
the netinit thread pinned the core at 44% for the first 65 s after
boot and every socket operation on other threads blocked until it gave
up. Before the MDIO bus refactor, stm32_phyread() polled the busy bit
in a tight loop.

Poll every 10 us instead, with the timeout expressed in microseconds so
the total bound stays at 10 ms, and report the timeout from the result
rather than the loop counter so a transfer that completes on the last
iteration is not logged as timed out.

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
2026-09-07 09:57:52 -03:00
Hritik Naik
2a6a86cb68 fs/procfs: fix buffer overflow in mount_sprintf
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
vsnprintf() returns the total formatted string length even when truncated to info->line. Passing this untruncated length to procfs_memcpy causes a read beyond the 64-byte line staging buffer.

Fixes #20011

Signed-off-by: Hritik Naik <hritiknaik16@gmail.com>
2026-09-06 12:16:02 -03:00
Abhishek Mishra
e6d8fe32ea Documentation/applications: document how to test tflite-micro.
Add a Testing section for sim:tflm and document Makefile tflm_hello,
AllocateTensors, and generic ops so the in-tree docs match the apps
TFLM changes.

Assisted-by: Cursor:Grok-4.6
Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
2026-09-06 21:12:43 +08:00
Megha Rajput
05cc04e306 net: preserve checksum state for empty fragments
Some checks failed
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
checksum() accesses data[0] and calculates an invalid last_byte
pointer when processing an empty fragment with odd state set.

Return early when len is zero to preserve the checksum state and
avoid accessing data from an empty fragment.

Assisted by: GitHub Copilot
Signed-off-by: Megha Rajput <i.meghar.2408@gmail.com>
2026-09-05 10:36:43 +08:00
wangjianyu3
71499bd66e boards/rp2040: support reboot bootloader via reset_usb_boot()
Add reset_usb_boot ROM function typedef and wire it into
board_reset() so that 'nsh> reboot bootloader'
(BOARDIOC_SOFTRESETCAUSE_ENTER_BOOTLOADER) on RP2040 boards enters
BOOTSEL USB mass-storage mode directly, matching the behavior
already available on rp23xx boards.  All other status values keep
the existing up_systemreset() behavior.

This affects all boards under boards/arm/rp2040/common (pico,
pico-w, feather-rp2040, xiao-rp2040, w5500-evb-pico, etc.) since
the change is in the shared board_reset() implementation.

Assisted-by: GitHubCopilot:claude-4.6-opus
Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
2026-09-05 10:36:07 +08:00
jsanchez-2g
6b5673a433 stm32g0: Add flash bank swap support
Add APIs to toggle the dual-bank flash mapping and reload the option bytes. Reject bank swapping when BOOT_LOCK is enabled and leave the swap operation as a no-op on single-bank devices.

Assisted-by: OpenAI Codex <codex@openai.com>
Signed-off-by: jsanchez-2g <jsanchez@2g-eng.com>
2026-09-05 10:34:48 +08:00
Justin Hammond
4a5852f02c boards/risc-v/eic7700x: Correct the UART reference clock.
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 console divisor was computed from 198144000, a figure with no source
in the manual, the vendor tree or Linux, all of which give the low speed
peripheral clock as 200 MHz.  The clock tree now reports lsp_uart0_pclk
at 200 MHz, and section 12.4.3.2 makes that clock the UART's baud
reference.

Also enable the fractional divisor.  These are DesignWare UARTs with DLF
implemented, four bits wide at offset 0xc0, which is where
UART_DLF_OFFSET lands once scaled by this board's register increment.
Section 12.4.3.2 works the same example at the same 200 MHz.

At 115200 the error goes from 1.41% to 0.006%.  The old figure with the
old divisor was tolerable; the margin only gets worse at higher rates.

DEBUG_CLK and DEBUG_CLK_ERROR are enabled so a clock that fails to
register is reported.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
2026-09-04 15:56:37 -03:00
Justin Hammond
2114981067 boards/risc-v/eic7700x: Report the clock tree at startup.
The architecture registers the clock tree before the board runs, and every
driver the board brings up afterwards depends on it.  Report what
registered, so a tree that came up short is visible without a debug build.

eic7700x_clk_count() supplies the numbers; /proc/clk has the tree itself.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
2026-09-04 15:56:37 -03:00
Justin Hammond
0a85476f7c arch/risc-v/eic7700x: Describe the clock tree the boot loader leaves.
Nothing in this port knew what any clock ran at, so a driver needing a
rate had to carry a hard coded one, which is wrong the moment the boot
loader changes.

Register the Clock and Reset Generator with the NuttX clock framework:
the PLLs, muxes, dividers and gates covering the low speed peripherals,
the U84 cluster, the RTC and timers, the NOC, boot SPI, SCPU, LPCPU, DDR
and TCU, the high speed peripherals, the always on DMA and secure blocks,
the GPU, DSP, die to die link and NPU, and the video input, output and
codec paths.  The tree is visible through /proc/clk.

Registration writes nothing: the tree comes up describing what the boot
loader left behind.  A clock moves only when a driver asks, by enabling a
gate, setting a divider or reparenting a mux.  A mux carrying a clock the
system is running on will speed up on request and refuses to slow down,
because that changes the timing every driver downstream was configured
for while they are using it.

The PLL post divider fields do not sit where the TRM's register diagram
puts them; they are ordered here to match the rates the tree reports.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
2026-09-04 15:56:37 -03:00
Justin Hammond
01106b4784 arch/risc-v/eic7700x: Add the blank lines nxstyle asks for.
Two declarations in eic7700x_start.c are followed immediately by a
statement, which nxstyle reports as "Missing blank line after
declarations".  Both predate this series and are already in master, but
CI runs checkpatch over the whole range rather than per commit, so any
change touching this file is reported against them.

Whitespace only, no functional change.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
2026-09-04 15:56:37 -03:00
Marco Casaroli
0d31418ba8 arch, boards, cmake: Build C++ ELF modules without __cxa_atexit.
A C++ module with a static object does not link.  GCC registers each such
object's destructor with __cxa_atexit(dtor, obj, &__dso_handle), and
__dso_handle comes from crtbegin, which a module does not link:

  hello++3.cxx:119: undefined reference to `__dso_handle'

It is reachable today with CONFIG_PIC, where a module is linked as an
executable and the symbol has to resolve.  Without it the link is
relocatable, the symbol stays undefined and nothing complains until
something makes it resolve.

-fno-use-cxa-atexit registers the destructors with atexit() instead, which
puts them in .fini_array.  That is also where libelf_uninit() looks for them
when the module is unloaded, so the flag that makes the link work is also
the flag that makes the destructors run.

The option goes wherever CXXELFFLAGS is defined, which is the architecture
Toolchain.defs and the boards that reassign it.  The toolchains that are not
GCC or Clang are left alone: ceva, tricore, z16 and the z80 family.

The CMake build sets it once, next to where the architecture elf.cmake is
included.  A generator expression keeps it off the C compiles, because the
option is valid for C++ alone and GCC warns about it otherwise, and the
compiler id gates it so that a toolchain which is neither GCC nor Clang does
not see it.  It cannot go in the toolchain file itself: CMake reads that file
again inside try_compile, in a project that has not included the NuttX
extensions, so the call is an unknown command there.

Reproduced with apps/examples/elf on mps3-an547:picostest with CONFIG_PIC
enabled: hello++3 fails to link before and links after.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-09-04 15:44:24 -03:00
Megha Rajput
c5619cb3fe fs/inode: propagate inode search errors
inode_reserve() previously continued processing all negative return
values from inode_search(). Only -ENOENT indicates that the target
inode is absent and creation may continue.

Propagate other search errors through the existing cleanup path to
avoid continuing inode creation with invalid insertion metadata.
Assisted-by: GitHub Copilot
Signed-off-by: Megha Rajput <i.meghar.2408@gmail.com>
2026-09-04 13:50:54 -03:00
AlmAck
784c6519de arch/arm/nrf53: enable the application core flash cache
The nRF5340 application core comes out of reset with its flash cache
disabled and nothing in the tree turns it on.  nrf53_start() does call
nrf53_enable_icache(), but that drives NVMC ICACHECNF and is gated on
NRF53_FLASH_PREFETCH, which depends on NRF53_NETCORE -- so it is not
even compiled for an application core build.

The nRF5340 places the application core cache in a separate CACHE
peripheral at 0x50001000.  NRF53_CACHE_BASE is already defined in
hardware/nrf53_memorymap_cpuapp.h, but there was no register header and
no enable.  Add both, behind a new NRF53_CACHE option.

The option defaults to n, matching ARMV7M_ICACHE and
ARMV8M_ICACHE/DCACHE, so that upgrading does not silently change the
behaviour of an existing configuration.

Measured on nrf5340-dk at 64 MHz with apps/benchmarks/scbench:

  protected-build syscall round trip   64.1 us -> 29.6 us
  userspace sem wait + post pair       4.75 us -> 1.95 us

Flat builds benefit equally; the gain is on any flash-resident code
path.

Per the nRF5340 Product Specification, 'CACHE - Instruction and data
cache', 'both instruction and data accesses towards flash memory or XIP
code regions are cached'.  The cache does not observe NVMC programming,
so nrf53_flash.c has to account for it: both up_progmem_eraseblock() and
up_progmem_write() read back what they just programmed to verify it, and
up_progmem_ispageerased() reads a whole page, so lines covering the
region being programmed are commonly resident.  Bypass the cache for the
duration of an erase or a write and invalidate it before re-enabling, so
the verify reads the array and later readers do too.  That file is built
only when NRF53_PROGMEM is selected, which is not the default.

Signed-off-by: AlmAck <gluca86@gmail.com>
2026-09-04 13:50:15 -03:00
jsanchez-2g
b75b93fd32 stm32g0: Fix erase bank selection after bank swap
The flash page number follows the logical memory mapping, but BKER selects a physical flash bank. Account for the nSWAP_BANK option when selecting BKER so erasing a logical address targets the corresponding physical bank after a swap.

Assisted-by: OpenAI Codex <codex@openai.com>
Signed-off-by: jsanchez-2g <jsanchez@2g-eng.com>
2026-09-04 13:44:51 -03:00
Felipe Moura
c8f1e093f5 xtensa/esp32s3: drop redundant CONFIG_UORB_STACKSIZE from defconfig
nuttx-apps PR #3763 adds "default 4096 if LIBC_PRINT_EXTENSION" to
CONFIG_UORB_STACKSIZE. Both lckfb-szpi-esp32s3/qmi8658 and
esp32s3-ws-lcd128/imu-qmi8658 already set CONFIG_UORB_STACKSIZE=4096
explicitly, which now matches the new default and makes the line
redundant, so savedefconfig drops it -- causing the CI defconfig-sync
check (testbuild.sh -R) to flag these files as stale and fail the
xtensa-03 job.

Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
Assisted-by: Claude:claude-sonnet-5
2026-09-04 13:27:32 -03:00
DuoYuWang
30503f8fdf boards/imx93-evk: disable work queues in bootloader
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
The bootloader image has no linked HPWORK or LPWORK consumers, but
enabling both queues pulls unused scheduler code into its constrained
OCRAM region.

Disable the predefined work queues and let deferred memory reclamation
fall back to the idle thread.

Assisted-by: Codex:GPT-5
Signed-off-by: DuoYuWang <thirteenking.wang@gmail.com>
2026-09-04 23:02:48 +08:00
DuoYuWang
a1e2813c25 Documentation/wqueue: document custom user queues
Describe the handle-based custom queue APIs, worker-pool creation and
teardown, periodic requeue, cancellation semantics, and return values.

Clarify that libc user work queue APIs use blocking synchronization and
must only be called from task context, while kernel and Flat queue and
asynchronous cancellation operations remain ISR-safe.

Assisted-by: Codex:GPT-5
Signed-off-by: DuoYuWang <thirteenking.wang@gmail.com>
2026-09-04 23:02:48 +08:00
DuoYuWang
315d9f7e64 libc/wqueue: use the uninterruptible wait helper
Replace the local EINTR retry loop with nxsem_wait_uninterruptible().
This keeps the master implementation aligned with the libc semaphore API
without changing cancellation behavior.

Keep the cleanup separate so release branches where the helper is not
available to Protected user space can use the functional commit without a
downstream compatibility patch.

Assisted-by: Codex:GPT-5
Signed-off-by: DuoYuWang <thirteenking.wang@gmail.com>
2026-09-04 23:02:48 +08:00
DuoYuWang
ae5997eef7 libc/wqueue: support custom user work queues
Implement the handle-based create, queue, priority, cancellation, and
teardown APIs for CONFIG_LIBC_USRWORK.  Custom queues use configurable
pthread worker pools while the predefined USRWORK queue remains available.

Match scheduler-backend delay, replacement, cancellation, and lifecycle
semantics.  Restrict the libc backend to task context because it uses
blocking synchronization.

Tested on an STM32H7 PX4 FMUv6C with ostest wqueue in Protected user space.

Assisted-by: Codex:GPT-5
Signed-off-by: DuoYuWang <thirteenking.wang@gmail.com>
2026-09-04 23:02:48 +08:00