Allow sim HCI socket users to select the host-side HCI target at runtime
with --bt-dev. Passing --bt-dev=hciN overrides CONFIG_SIM_HCISOCKET_DEVID
for the BlueZ HCI user channel, while omitting the option keeps the existing
configured default behavior.
Also allow --bt-dev=/path/to/socket to connect to an H:4 stream exposed
through a Unix-domain socket. This lets sim applications use a controller
provided by another host process or by a UART-to-Unix-socket bridge without
requiring BlueZ raw HCI privileges for the NuttX process.
Use host-side output for early --bt-dev parse errors, since NuttX stdio is
not initialized before nx_start().
Document the BlueZ and Unix socket modes, including the capability
requirements for BlueZ and the socat bridge example for Unix socket mode.
Testing:
Host: Ubuntu 22.04 x86_64
Board/config: sim:bthcisock
Style checks:
git diff --check HEAD~2..HEAD
PATH=/home/mi/bsim-auto-test/.venv/bin:$PATH \
./tools/checkpatch.sh -c -u -m -g HEAD~2..HEAD
Clean build:
make distclean
./tools/configure.sh -l -a ../../nuttx-apps sim:bthcisock
kconfig-tweak --file .config --set-val STACK_USAGE_WARNING 0
make olddefconfig
make -j16
Invalid runtime argument smoke test:
./nuttx --bt-dev=invalid
Verified the command exits with status 1 and reports the invalid target
without crashing before nx_start().
Unix socket HCI smoke test:
socat -d -d UNIX-LISTEN:/tmp/hci.sock,fork,reuseaddr \
/dev/ttyACM2,b1000000,raw,echo=0,crtscts=1
printf 'ifconfig\nbt bnep0 info\npoweroff\n' | \
timeout 20s ./nuttx --bt-dev=/tmp/hci.sock
Verified the sim registers the Bluetooth network device as bnep0 and
bt bnep0 info reads the controller state through the Unix-socket HCI
path, including BDAddr aa:bb:cc:dd:ee:ff from the attached controller.
Assisted-by: OpenAI Codex
Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
Start the simulated HCI socket receive watchdog only after the host HCI
socket has been opened successfully. The previous code armed the watchdog
immediately after driver registration, before the Bluetooth stack opened the
driver and before the device had a valid host fd.
Cancel the watchdog on close/free and close any opened host fd during
allocation-failure cleanup. This keeps the polling path tied to the actual
socket lifetime and prevents the watchdog from polling an invalid host fd.
Testing:
Host: Ubuntu 22.04 x86_64
Board/config: sim:bthcisock
Style checks:
git diff --check HEAD~2..HEAD
PATH=/home/mi/bsim-auto-test/.venv/bin:$PATH \
./tools/checkpatch.sh -c -u -m -g HEAD~2..HEAD
Clean build:
make distclean
./tools/configure.sh -l -a ../../nuttx-apps sim:bthcisock
kconfig-tweak --file .config --set-val STACK_USAGE_WARNING 0
make olddefconfig
make -j16
Default startup smoke test:
printf 'poweroff\n' | timeout 10s ./nuttx
Verified the sim still reaches NSH and powers off cleanly. When no
host HCI controller is available through the default BlueZ target, the
board reports sim_bthcisock_register() failure and continues booting;
no invalid-fd watchdog crash occurs.
Assisted-by: OpenAI Codex
Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
Add support for using a BabbleSim PHY as the monotonic time source for
the Linux sim target. When CONFIG_SIM_BSIM_TIME is enabled, the sim
host build links a small host-side time helper against the BabbleSim
PhyCom and Util libraries. The helper joins the BabbleSim PHY wait
protocol and advances NuttX monotonic time through PB_MSG_WAIT requests
instead of Linux wall-time sleeps.
A SIM binary built with CONFIG_SIM_BSIM_TIME enabled joins BabbleSim time
at startup. Runtime options allow the test runner to select the
BabbleSim simulation id, PHY id, and device number:
--sim-bsim-sid=<simulation-id>
--sim-bsim-pid=<phy-id>
--sim-bsim-dev=<device-number>
Keep the integration inside the sim host time path rather than exposing
a new application API. RTC/realtime reads still use the host realtime
clock; the BabbleSim source is used only for monotonic time after the sim
has joined the PHY. The Kconfig option depends on the sleep based
walltime mode and is disabled for SMP and non-Linux hosts.
The build requires BSIM_COMPONENTS_PATH for headers and either
BSIM_OUT_PATH or BSIM_LIBS_DIR for shared libraries. The path checks are
skipped for clean, distclean, clean_context, and context targets so a
tree with CONFIG_SIM_BSIM_TIME enabled can still be cleaned without
exporting the BabbleSim environment first.
Document the configuration, build environment, runtime options, and the
requirement that the BabbleSim PHY process is started separately by the
test runner.
Testing:
Host: Ubuntu 22.04 x86_64
Board/config: sim:nsh
Style check:
git diff --check
Default sim build and smoke test:
./tools/configure.sh -l -a ../nuttx-apps sim:nsh
make -j16
printf 'help\npoweroff\n' | timeout 20s ./nuttx
BabbleSim-enabled build:
kconfig-tweak --file .config \
-e SIM_WALLTIME_SLEEP \
-d SIM_WALLTIME_SIGNAL \
-e SIM_BSIM_TIME
make olddefconfig
BSIM_OUT_PATH=/tmp/bsworld/build/babblesim/bsim \
BSIM_COMPONENTS_PATH=/tmp/bsworld/build/babblesim/bsim/components \
make -j16
Verified actual BabbleSim PHY time integration without a controller by
starting bs_2G4_phy_v1 and running NSH usleep through the PHY wait
barrier:
bs_2G4_phy_v1 -s=<sid> -D=1 -defmodem=BLE_simple -nodump
printf 'usleep 1000000\npoweroff\n' | \
./nuttx --sim-bsim-sid=<sid> \
--sim-bsim-pid=2G4 \
--sim-bsim-dev=0
The same 1 second simulated sleep completed in 19 ms wall time when no
handbrake device was present. With handbrake registered as device 1:
bs_2G4_phy_v1 -s=<sid> -D=2 -defmodem=BLE_simple -nodump
bs_device_handbrake -s=<sid> -p=2G4 -d=1 -pp=50000 -r=1
the same NuttX usleep test completed in 985 ms wall time. A shorter
200 ms check showed the same behavior: 27 ms without handbrake and
172 ms with handbrake. This verifies that NuttX sim time advances
through the BabbleSim PHY and that the handbrake affects the NuttX sim
device.
Also verified make distclean succeeds after CONFIG_SIM_BSIM_TIME was
enabled and without exporting BSIM_COMPONENTS_PATH.
BSWorld out-of-tree native BLE examples:
./tools/configure.sh -l /path/to/bsim-auto-test/tests/nuttx/native_ble/source/advertiser/config
make -j16
exodus --tarball -o /path/to/bsim-auto-test/tests/nuttx/native_ble/source/advertiser/prebuilt/nuttx.tgz nuttx
./tools/configure.sh -l /path/to/bsim-auto-test/tests/nuttx/native_ble/source/scanner/config
make -j16
exodus --tarball -o /path/to/bsim-auto-test/tests/nuttx/native_ble/source/scanner/prebuilt/nuttx.tgz nuttx
pytest tests/nuttx/native_ble -q --no-ellisys
Assisted-by: OpenAI Codex
Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
bitbucket.org/nuttx/buildroot returns 404, as does every other repository
under that Bitbucket organisation. The buildroot that still carries the
NuttX toolchain, ldnxflat included, is github.com/patacongo/buildroot.
Thirty three files carried the dead address, most of them as a "Bitbucket
download site" for a board's toolchain. There are no downloads to offer, so
those now name the repository, and the surrounding prose says so.
The other dead Bitbucket addresses are left alone: nuttx/nuttx, nuttx/tools,
nuttx/uclibc and nuttx/nxwidgets need a decision each about what replaces
them, which is not this patch. patacongo/obsoleted is still there.
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
The download link is dead: bitbucket.org/nuttx/buildroot is gone, and the
buildroot that still carries ldnxflat is github.com/patacongo/buildroot.
The instructions were also more than is needed. mknxflat came in tree with
PR #19600, so only ldnxflat has to be built, and an ordinary arm-none-eabi
GCC compiles and links NXFLAT modules: a board does not have to select
CONFIG_ARM_TOOLCHAIN_BUILDROOT to use them. What ldnxflat does need is a
binutils source and build tree, because it reads its input through libbfd.
The CI test list said mknxflat is what the container lacks. It is in tree
now; ldnxflat is the one that is missing.
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
A function pointer under FDPIC is not a code address. Because each
PT_LOAD segment is placed independently, a pointer has to carry the data
base its callee will need, so it is a two-word descriptor: the entry
point, and the base to install in the PIC register before branching.
R_ARM_FUNCDESC_VALUE says "the thing you are patching is such a
descriptor", and R_ARM_FUNCDESC says "manufacture one and give me its
address".
Both need state a relocation cannot carry. A descriptor's second word is
the *object's* data base, from DT_PLTGOT, and R_ARM_FUNCDESC carves
descriptors from a pool whose cursor has to survive from one relocation
to the next. up_relocate() is handed only a relocation, a resolved
symbol and an address to patch.
arch_data is the existing channel for exactly this -- RISC-V already uses
it to remember a HI20 relocation while its LO12 partner is processed --
but nothing has ever put loader state into it: it is declared zeroed and
written only by up_relocate() itself. So ARCH_ELFDATA_INIT and
ARCH_ELFDATA_FINI are added, seeding the block from the loadinfo before
the relocation loop and reading the cursor back after. Both default to
nothing, so an architecture that does not define them is unaffected, and
RISC-V's use of arch_data is untouched. libelf_relocatedyn() walks both
dynamic tables under one arch_data, so the cursor spans the whole object.
The addend handling is the part that is easy to get wrong. REL format
keeps the addend in place, in the word about to become the entry point,
and a pointer to a static function is referenced through its *section*
symbol -- the value is the section base and the offset, including the
Thumb bit, is entirely in the addend. Dropping it yields an even address
and the core faults trying to execute it as ARM code.
The GOT written into a descriptor is the loading object's own, even for
an imported function, which is what makes a callback work: when the base
firmware's qsort() calls back into a module's comparison function, the
module needs its own data base in the PIC register.
libelf_relocatedyn()'s imported-symbol path needed a change to suit. It
stores the resolved address directly and never calls up_relocate(), which
cannot produce a two-word descriptor, so under FDPIC the resolved value
now goes through up_relocate() and the relocation type decides what to
write.
Implemented for armv7-m and armv8-m, the profiles FDPIC targets; the
other ARM variants gain the arch_data block but no new relocations.
Built and booted mps3-an547:picostest and lm3s6965-ek:qemu-nxflat, the
ELF PIC and NXFLAT users of this code, both unchanged.
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
work_cancel() used to return -ENOENT when the work structure was not
in the queue, and callers depend on that: aio_cancel() tears down the
AIO container (file_put() + aioc_free()) only when work_cancel()
reports success, because a work item that is not queued may already be
executing on a worker thread (see the comment in fs/aio/aio_cancel.c).
Since commit 6f72f5481d ("sched/wqueue: Refactor delayed and periodical
workqueue") work_cancel() returns OK unconditionally, and commit
d2e01b9055 ("sched/wqueue: harden custom queue lifecycle") kept that
behaviour and dropped -ENOENT from the function documentation. Under
SMP the LTP aio_cancel tests then free the aio container and its file
while the lpwork thread is still executing aio_write_worker() on it,
which ends in a page fault in file_write() (f_inode == NULL) and a
panic.
Return -ENOENT again when the work is not queued, and document it.
For the synchronous variant "not queued" alone does not tell whether
the callback is running: the worker scan does, so report OK when a
running callback was found and waited for, and -ENOENT only when the
work was neither queued nor running.
Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
Follow-up to the previous commit, which switched every flat-build
rv-virt nsh defconfig from nsh_main to nxinit (init_main) but left
pnsh and pnsh64 (CONFIG_BUILD_PROTECTED=y) on nsh_main. Under protected
build nxinit's "console sh" service failed to start:
posix_spawnp("sh") resolves through the kernel-space binfmt "builtin"
loader / BINFS, but the kernel-space g_builtins/g_builtin_count table
those rely on was never populated -- CONFIG_BUILD_PROTECTED links
apps/builtin/builtin_list.c only into the user blob (nuttx_user), and
nothing called the boardctl(BOARDIOC_BUILTINS) hand-off NuttX has
provided for this since release 8.1.
With that hand-off now issued by apps/system/nxinit early in init_main()
(nuttx-apps, "system/nxinit: register g_builtins with the kernel under
PROTECTED build"), pnsh/pnsh64 can use nxinit like every other
flat-build rv-virt nsh defconfig. Apply the same minimal
nxinit-essential delta used for the 23 configs switched previously.
Verified on rv-virt:pnsh: `ps` shows init_main as the parent with sh
as its Running child, `ls /bin` lists the builtins, and `hello` runs
(see the PR description for logs).
Assisted-by: opencode-agent/claude-sonnet-5
Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
Switch every rv-virt (qemu-rv) flat-build defconfig whose init entry
point was nsh_main to nxinit (init_main): citest, citest64, fb, fb64,
flats, flats64, leds, leds64, leds64_rust, leds64_zig, libcxx,
libcxx64, lvgl64_vector, netnsh, netnsh64, netnsh64_smp, netnsh_smp,
nsh, nsh64, python, smp, smp64, virt_nsh (23 configs; pnsh/pnsh64 are
switched in the following commit). nsh now runs as a "console sh"
service started by init.rc instead of being the top-level init task,
matching boards/arm/qemu-armv7a, boards/arm64/qemu-armv8a and
boards/sim. elf (elf_main) and the 11 kernel-build configs (which use
CONFIG_INIT_FILEPATH) are out of scope and untouched.
Each switched defconfig gains only the nxinit-essential keys
(regenerated with make savedefconfig): CONFIG_INIT_ENTRYPOINT="init_main",
CONFIG_SYSTEM_NXINIT=y and its deps (CONFIG_EXPERIMENTAL,
CONFIG_LIBC_EXECFUNCS, CONFIG_SCHED_CHILD_STATUS), and
CONFIG_ETC_ROMFS=y/CONFIG_FS_ROMFS=y to ship init.rc via ROMFS.
Add boards/risc-v/qemu-rv/rv-virt/src/etc/init.d/init.rc registering a
"console sh" service (guarded by CONFIG_SYSTEM_NSH), shipped via ROMFS
in both the Make (RCSRCS, only when CONFIG_ETC_ROMFS && CONFIG_SYSTEM_NXINIT)
and CMake (nuttx_add_romfs()) builds, matching qemu-armv7a/qemu-armv8a.
rc.sysinit and rcS are left in place: on rv-virt both are empty
license-only shells still referenced unconditionally by boards/Board.mk
for the kernel-build and pnsh/pnsh64 configs.
CONFIG_FS_BINFS=y is added with a binfs mount at CONFIG_PATH_INITIAL
(pre-existing "/system/bin") in
qemu_rv_boardinit.c:board_late_initialize() (gated on CONFIG_FS_BINFS,
so the block and the CONFIG_PATH_INITIAL reference compile out when
binfs is not selected).
Rationale: nxinit resolves the "sh" service via posix_spawnp() ->
exec_spawn() -> load_module(); with CONFIG_LIBC_ENVPATH that walks $PATH
via envpath_next() and stat()s each "$dir/sh" candidate, so it never
reaches the builtin binfmt loader unless a real directory entry exists.
CONFIG_PATH_INITIAL is left at its pre-existing "/system/bin"; mounting
binfs there (rather than repointing PATH) makes "sh" resolvable while
keeping the defconfig delta minimal. This never surfaced under nsh_main,
which runs nsh_consolemain() inline without spawning by relative path.
Equivalent to the binfs mount already present in boards/sim's
sim_bringup.c (which mounts at /bin, its own PATH_INITIAL).
smp and smp64 additionally re-enable binfmt: their CONFIG_DEFAULT_SMALL=y
default pulls in CONFIG_BINFMT_DISABLE=y, which blocks
CONFIG_LIBC_EXECFUNCS (thus CONFIG_SYSTEM_NXINIT) and would otherwise
fail to link with "undefined reference to init_main". Same fix
boards/sim used for its affected configs.
citest/citest64 also carry their pre-existing explicit
CONFIG_INIT_STACKSIZE value (3072/4096) over to
CONFIG_SYSTEM_NSH_STACKSIZE: under nxinit "sh" is a separate spawned
child sized by SYSTEM_NSH_STACKSIZE, which otherwise dropped to the
2048 default and overflowed (citest64 crashed running `ps`). Every
other switched config that had an INIT_STACKSIZE override already had a
matching SYSTEM_NSH_STACKSIZE one.
All 23 switched configs were booted (not just compiled) and show
init_main as the parent with sh as its Running child in `ps` (see the
PR description for logs).
Assisted-by: opencode-agent/claude-sonnet-5
Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
Clamp each wall-clock adjustment in both positive and negative directions, then subtract the applied amount from the remaining adjustment. This makes adjtime converge to zero and prevents large negative adjustments from slewing the clock in the wrong direction.
Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
CLOCK_TIMEKEEPING already provides a software-based adjtime implementation. Exclude the generic adjtime state and entry point when timekeeping is enabled, while retaining clock_adjtime support for PTP clocks.
Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
spawn_execattrs() discards the return value from nxsched_set_scheduler(). As a result, an invalid scheduling policy or parameter is silently ignored and the spawn operation continues with the original scheduling configuration.
Store and return the result from nxsched_set_scheduler() so that the caller can tear down the child task when applying the requested scheduler attributes fails. Update the function comments to describe the existing error return behavior.
Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
Sporadic scheduling parameters are processed independently by sched_setparam(), sched_setscheduler(), and pthread_create(). The three paths currently validate different subsets of the parameters.
In particular, pthread_create() does not validate sched_ss_max_repl and only requires the replenishment period to be greater than the budget, while the scheduler interfaces enforce the implementation's 50 percent duty-cycle limit.
Add nxsched_validate_sporadic() to validate the common parameters and convert the replenishment period and budget to ticks. Use it from all paths that directly initialize or update sporadic scheduler state.
Express the duty-cycle check using division to avoid overflow when doubling a clock_t value.
Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
nxsched_set_param() applied the sporadic parameters and restarted the
replenishment timer in set_sporadic_param() before nxsched_reprioritize()
rejected an out-of-range priority with EINVAL, leaving stale sporadic
state (e.g. a truncated hi_priority) behind on failure.
Validate sched_priority up front so the error path is atomic.
Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
Commit 2ec7d90eba refactored sched_setparam() into set_sporadic_param()
but moved the apply logic into the former reject branch without
inverting the condition. As a result sched_setparam() rejects valid
sporadic parameters (repl >= 2 * budget) with EINVAL and accepts
invalid ones, tripping the DEBUGASSERT in sched_sporadic.c or wrapping
the replenishment calculation.
Invert the condition to match process_sporadic() in sched_setscheduler.c.
Fixes: 2ec7d90eba ("sched_setparam.c: coverity HIS_metric_violation: RETURN")
Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
Running `./tools/checkpatch.sh -g` on this file reported seven pre-existing
style errors. Fix them so that the file passes nxstyle cleanly:
- Add the missing blank line after the declarations in sensor_lock(),
sensor_unlock(), sensor_update_interval() and sensor_generate_timing().
- Indent the SNIOC_GET_EVENTS and SNIOC_FLUSH case labels with six spaces
like the other twelve case labels of the same switch.
- Drop the two extra spaces in front of the poll_notify() call in
sensor_poll().
Whitespace only, no functional change: the file is byte identical once all
whitespace is stripped.
Signed-off-by: likun17 <likun17@xiaomi.com>
Cover the remaining electrical quantities so that they do not have to fork
into driver private namespaces later. Add SENSOR_TYPE_RESISTANCE (Ohm),
SENSOR_TYPE_CONDUCTIVITY (S/m), SENSOR_TYPE_ENERGY (J) and
SENSOR_TYPE_CHARGE (C), the last two matching the native unit of the
accumulator registers in power and energy monitors.
Signed-off-by: likun17 <likun17@xiaomi.com>
uORB has no type for electrical quantities, so power monitors can only use
the legacy character drivers, which are deprecated and report their values
in three incompatible unit systems. Add SENSOR_TYPE_VOLTAGE,
SENSOR_TYPE_CURRENT and SENSOR_TYPE_POWER with their message structs in SI
units (V, A, W).
Signed-off-by: likun17 <likun17@xiaomi.com>
When executing in place from flash, the XIP FlexSPI clock must not be
reconfigured during the initial clock setup. The boot ROM configures the
clock for its flash read sequence, and changing it before the board installs
a suitable high-speed read sequence can break instruction fetch. The board's
flash setup may reconfigure the clock afterward.
Signed-off-by: Peter van der Perk <peter.vanderperk@nxp.com>
The mcuboot-loader image overflows its flash region once the FAT deferred-delete change is applied. Long filename support is not needed by the bootloader, which boots from flash areas and never opens FAT files by long name, so disable CONFIG_FAT_LFN to reclaim the space while keeping short filename support intact.
Signed-off-by: Arnav Sharma <2006arnavsharma@gmail.com>
Fix blank-line-after-declarations and switch-case alignment issues in fs/fat files touched by the unlink-while-open change, including pre-existing violations in the same regions. No functional change.
Signed-off-by: Arnav Sharma <2006arnavsharma@gmail.com>
Add a FAT local canonical open-file object to maintain shared state between multiple open handles of the same file. When an open file is unlinked, remove its directory entry but defer freeing the FAT cluster chain until the last open reference is closed. The shared object maintains the file size, starting cluster, directory-entry location, reference count, and pending-delete state. This avoids identifying open deleted files solely by their cluster number and correctly handles empty files, multiple opens, dup(), rename, and directory or cluster reuse. Pending deleted files no longer write metadata back to a removed or reused directory entry, while fstat(), truncate(), sync(), and subsequent writes continue to operate on the shared in-memory state. The implementation is kept within fs/fat and does not introduce a generic VFS inode mechanism. Fixes: #20037
Signed-off-by: Arnav Sharma <2006arnavsharma@gmail.com>
nuttx_parse_function_args declares FUNC as its one-value keyword, so
the parsed variable is IN_FUNC, but both FATAL_ERROR messages
referenced a never-defined IN_NAME, printing an empty function name
for every argument-misuse diagnostic of every wrapper that uses this
parser. Reference IN_FUNC instead.
Before:
```
CMake Error ...: : unparsed WRONG;x
```
After:
```
CMake Error ...: myfunc: unparsed WRONG;x
```
Assisted-by: Claude Code (glm-5.3) <claude@anthropic.com>
Signed-off-by: Junbo Zheng <zhengjunbo1@xiaomi.com>
The arch-line filter in savedefconfig.cmake encodes semicolons in
NameAndValue before appending it, but decoded a never-assigned Value
variable instead, so any CONFIG_ARCH* value containing a semicolon
was written to the defconfig with literal __SEMICOLON__ placeholders.
Decode NameAndValue itself.
Before:
```
CONFIG_ARCH_BOARD_CUSTOM_NAME="a;b;c" -> "a__SEMICOLON__b__SEMICOLON__c"
```
After:
```
semicolons are restored and the line is written verbatim
```
Assisted-by: Claude Code (glm-5.3) <claude@anthropic.com>
Signed-off-by: Junbo Zheng <zhengjunbo1@xiaomi.com>
This restores the entrypoint switch from commit
7cc6707a76 ("boards/esp32s3-xiao: switch
defconfigs to nxinit entrypoint"), reverted in 76b90e02cbe4967193
b620abcb1efb9f6b3f8f5b after a real-hardware regression report on
Seeed XIAO ESP32-S3 (board hangs, no USB console), and fixes the
actual root cause this time instead of just reverting it.
Root cause: the shared boards/xtensa/esp32s3 init.rc starts the
interactive console as a plain "sh", which, unlike nsh_main's
nsh_consolemain(), never registers/connects the CDC-ACM gadget this
board uses as its console (CONFIG_CDCACM_CONSOLE=y, no
CONFIG_DEV_CONSOLE). Restoring the previous commit's entrypoint switch
on its own is therefore not sufficient - it would just reintroduce the
same regression, so that commit is folded into this one rather than
kept as a separate, individually broken step.
Fix, using the "console" service option added to nxinit by a companion
apps change:
- init.rc: bring up the console gadget once, unconditionally, before
any service starts, via "exec -- sercon" (apps/system/cdcacm already
implements exactly this and depends on neither nxinit nor nsh); flag
the "console" service with the new "console" option so its stdio is
connected to the (now registered) gadget device.
- esp32s3-xiao's usbnsh/combo defconfigs: add CONFIG_SYSTEM_CDCACM=y so
sercon is actually built in. Verified with "make savedefconfig"
against both defconfigs (byte-identical, no manual edits beyond the
generated diff).
Verified end to end on real Seeed XIAO ESP32-S3 Sense hardware
(usbnsh): after this change the board enumerates its NuttX CDC-ACM
gadget on a normal reset and boots to an interactive nsh session
spawned by nxinit ("ps" shows init_main as PID 2, parent of "sh").
Assisted-by: Kiro:claude-sonnet-5
Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
Nothing copies .data on a RAM/remoteproc image (CONFIG_BOOT_RUNFROMISRAM=y),
so an LMA distinct from the VMA loads initialised data where the code never
reads it. _sidata was taken before .init_section, putting the load address
sizeof(.init_section) below the run address.
That section is empty in the in-tree configurations, so the fault is latent
today and this change is a no-op for them; it appears as soon as anything lands
in .init_array.
Assisted-by: Claude Code:claude-opus-4-8
Signed-off-by: Ulaş Sertan Kemeç <sertan.usk@gmail.com>
waitid() documents WNOWAIT support but exited_child() unconditionally
removed and freed the child status entry, so a second wait on the same
child failed with ECHILD. Debug builds were also inconsistent: the
options mask rejected WNOWAIT entirely with ENOSYS.
Pass options down to exited_child() and skip the discard when WNOWAIT
is set, matching waitpid(), and add WNOWAIT to the debug options mask.
Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
Replace a literal 100000 with the USEC_PER_SEC macro in the oneshot
timer restart calculation. This bug causes incorrect timeout values
when CONFIG_SCHED_CPULOAD_TICKSPERSEC=1, though defaults are not
affected. Present since 2016 (commit 300361539a).
Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
Add a NULL check for the param argument before dereferencing
param->sched_priority. The sibling functions sched_setparam and
sched_getparam already have this check; sched_setscheduler was
the only one missing it, allowing a NULL pointer dereference
via sched_setscheduler(0, SCHED_FIFO, NULL).
Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
Compare ctcb->group->tg_ppid against rtcb->group->tg_pid (the group
leader PID) instead of rtcb->pid in waitid() and in the
!CONFIG_SCHED_CHILD_STATUS path of waitpid(). Commit ece224a7e3
("handle waitpid waitting tcb->group is NULL") rewrote the
comparisons this way when adding the ctcb->group NULL guard,
regressing what 90be95bb89 had correct: a non-group-leader thread
calling waitid(P_PID) or waitpid() on a child always gets ECHILD.
Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
LDREX/STREX to Shareable memory needs an external exclusive monitor, and this
Cortex-R5F has none on the path to DDR; Non-shareable uses the core-local
monitor instead. Every atomic compiles to inline LDREX here, since the chip
selects no LIBC_ATOMIC_* backend and falls back to LIBC_ATOMIC_TOOLCHAIN.
Verified on t3-gem-o1: without this the core runs but the console never
appears; with it the same image boots and ostest exits with status 0.
Assisted-by: Claude Code:claude-opus-4-8
Signed-off-by: Ulaş Sertan Kemeç <sertan.usk@gmail.com>
Add what a kernel build needs on Xtensa: a crt0 for a user process, the
kernel stack allocation that a system call switches to, the syscall entry and
return path for an unprivileged caller, and the initial register state that
starts a user task at EL0 with its save area on the kernel stack.
On the ESP32-S3 the arch code that runs while the flash mapping is in flux
moves to IRAM, and the kernel heap is placed above the user .bss so that
up_allocate_kheap() and the user address environment do not overlap.
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Add CONFIG_MM_PGSIZE == 32768 and 65536 to the page-size switch (and the
Kconfig help text). The 64 KB size matches the ESP32-S3 cache-MMU page
granularity, so an address-environment port there can use one mm_pgalloc()
page per cache-MMU page (naturally 64 KB-aligned by the granule allocator)
instead of coalescing several smaller pages. Inert for existing configs:
MM_PGSIZE is only used when CONFIG_MM_PGALLOC is enabled (BUILD_KERNEL).
Assisted-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Same issue as the previous commit, on the receive side: uart_read()
advances recv.tail from thread context without holding the critical
section, but the recvbuf batch path of uart_recvchars() reads recv.tail
several times (the full check, the watermark count and the free-space
computation). If uart_read() moves and wraps the index in between, the
computed free space goes negative and is passed to recvbuf() as a huge
size_t, which lets the driver store past the end of the ring buffer.
Read recv.tail once per loop iteration and derive everything from that
snapshot. The consumer only ever moves the index forward, so a stale
snapshot merely stores less now.
Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
uart_putxmitchar() advances xmit.head from thread context without
holding the critical section, so on SMP the head index can move, and
wrap around, while uart_xmitchars() runs in the TX interrupt on another
CPU. Since commit b319c27f03 ("serial: Added APIs for receiving and
sending multiple chars") the sendbuf path of uart_xmitchars() reads
xmit.head twice: once to decide whether the pending data is contiguous
and again to compute its length. If the producer wraps the index in
between, the computed length goes negative, is passed to sendbuf() as a
huge size_t and the driver transmits memory far beyond the ring buffer.
The per-byte path reads the index only once and is not affected, which
is why this went unnoticed: the batch path is only used by drivers that
implement sendbuf, and the 16550 driver gained it in commit 45c38d8592
("drivers/serial/16550: add polling mode support for serial drivers").
qemu-intel64 with SMP is the first configuration combining a sendbuf
driver with a producer running on another CPU.
On qemu-intel64 SMP this shows up as an endless stream of NUL bytes on
the console (captured with gdb: head = 1, tail = 8, size = 16, and
u16550_sendbuf() called with size = (size_t)-7), which makes the ntfc
test harness fail every test that runs while the flood lasts.
Read the head index once per loop iteration and use that snapshot for
both the contiguity test and the length. The producer only ever moves
the index forward, so a stale snapshot merely sends less now.
Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
Document the per-service "console [<device>]" option added to nxinit
by the companion apache/nuttx-apps PR: what it does (open the given
device, or CONFIG_SYSTEM_NXINIT_CONSOLE_DEV if omitted, and dup it onto
the service's stdin/stdout/stderr before spawning), why a plain shell
service needs it (unlike nsh, it never opens a console device on its
own), and why a USB gadget console additionally needs the gadget
brought up first (e.g. via "exec -- sercon"), since the device does not
exist until then.
Assisted-by: Kiro:claude-sonnet-5
Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
intel64_oneshot_handler() cleared oneshot->handler and oneshot->arg
after picking them up, without holding g_oneshot_spin, while
intel64_oneshot_start() re-arms the timer under that lock from another
CPU. Now that the HPET ISR stays attached across a re-arm, a stale
interrupt can interleave with start(): it reads the freshly installed
handler, clears it, and start() then sets running = true again, so the
genuine expiry that follows finds running == true with a NULL handler
and jumps to address zero from interrupt context (page fault at RIP 0
in the CPU0 IDLE task while the LTP lio_listio tests were running), or
the alarm is simply lost and the tickless system stops.
The handler and its argument are owned by start() and cancel(); the ISR
only needs to read them. Leave them alone in the ISR and skip the call
if none is installed. The remaining effect of a stale interrupt is an
early invocation of the alarm callback, which is harmless: the tickless
scheduler re-evaluates its expirations and re-arms the timer.
Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
intel64_hpet_setisr() with a NULL handler detached the ISR with
irq_attach(irq, NULL), which installs irq_unexpected_isr(). The oneshot
driver does this every time the timer expires or is re-armed, so an HPET
interrupt already in flight to another CPU lands on the unexpected ISR
and panics the system:
irq_unexpected_isr: ERROR irq: 34
seen under SMP with the LTP test suite. Just mask the interrupt and keep
the ISR attached; intel64_oneshot_handler() already treats an interrupt
that arrives while the timer is not running as spurious.
Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
intel64_oneshot_start() takes g_oneshot_spin and then, if the timer is
already running, calls intel64_oneshot_cancel(), which takes the same
spinlock again. Spinlocks are not recursive, so the CPU spins forever
on its own lock while holding the critical section; the HPET timer ISR
on another CPU then blocks on g_cpu_irqlock and the system hangs.
This is hit as soon as the tickless scheduler re-arms a running HPET
oneshot timer under SMP (ostest task_restart, LTP aio tests).
Stop the running timer inline instead of calling cancel: disable the
interrupt, detach the ISR so up_enable_irq() does not assert on a busy
IRQ, and clear the running flag. The ISR, comparator and interrupt
enable are reprogrammed by the rest of the function anyway.
Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
The in-tree esp32s3-xiao board bringup never wires up Wi-Fi at all --
unlike esp32s3-devkit/esp32s3-eye, it has no
`#ifdef CONFIG_ESPRESSIF_WIFI` include of esp32s3_board_wlan.h and no
call to board_wlan_init(). Add both, mirroring those boards' pattern
and placement exactly.
On its own this is not enough for a board that also uses CONFIG_PM:
Wi-Fi's PHY/RF calibration inside board_wlan_init() cannot tolerate
the clock gating of PM_STANDBY (light sleep). If the idle task enters
light sleep while phy_init's calibration is still running -- which the
greedy governor is free to do the moment the CPU goes idle during
driver init -- the calibration hangs forever waiting on a clock that
just stopped. Confirmed on real XIAO ESP32-S3 hardware: with
CONFIG_PM + CONFIG_ESPRESSIF_WIFI both enabled and no guard, boot got
stuck 100% of the time right after the "net80211 rom version" line,
before phy_init ever printed, and never reached NSH -- reproducible
across repeated flashes, 50s+ waits, not even responding to a UART
wakeup keypress (a genuine hang, not quiet sleep).
Fixed by holding a stronger PM lock than PM_STANDBY for the duration
of board_wlan_init(): pm_stay(PM_IDLE_DOMAIN, PM_IDLE) blocks
PM_STANDBY/PM_SLEEP while still allowing normal CPU idle, and
pm_relax() releases it immediately after, restoring whatever floor the
board's own PM policy holds otherwise. Confirmed fixed on the same
hardware: boots clean to NSH with Wi-Fi + PM enabled together, `ps`
shows the wifi/netdev-wlan0 kernel threads running, and `wapi scan`/
`ifup wlan0` work normally.
esp32c3-devkit and esp32c6-devkit also combine CONFIG_PM with Wi-Fi,
but don't need this guard today: both call board_wlan_init() well
before esp_pmconfigure() (which is what actually arms the PM governor)
runs near the end of bringup, so PM isn't active yet during their
Wi-Fi init. This board's PM handling begins earlier in bringup, so the
two can race here.
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
Assisted-by: Claude:claude-sonnet-5