Rewrite arch_memcpy.S and arch_memset.S to be register-width aware on
both RV32 and RV64 using REG_L/REG_S/SZREG macros from asm.h.
memcpy gains:
- 16xSZREG unrolled main loop (128B/iter on RV64, 64B on RV32).
- Shift-merge path for misaligned src: reads two aligned words
straddling each output word and shifts them together, so no load
or store is ever misaligned.
- Single SZREG and byte loops for remainder and small copies.
memset gains:
- 32xSZREG unrolled main loop (256B/iter on RV64, 128B on RV32)
using Duff's device for non-power-of-two remainders.
- .option norvc ensures fixed 4-byte instruction width for correct
jump offset calculation in the Duff's device entry.
- Zero-length input handled correctly (branch to guarded tail).
The old memcpy always used lw/sw even on RV64, wasting half the
memory bandwidth. The old memset unrolled only 16 bytes per iteration.
Signed-off-by: ganjing <ganjing@xiaomi.com>
Add word-at-a-time strlcpy using DETECTNULL for both the copy phase
and the strlen tail when truncated. The copy loop aligns src and
processes a register at a time, falling to bytewise for the last word
containing the terminator. When truncated, the remaining src length
is measured with a second word-at-a-time loop.
strlcpy has 46 call sites in a typical kernel image (more than strcpy)
and is not covered by newlib OPTSPEED, making it a high-value target.
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: ganjing <ganjing@xiaomi.com>
Reduce branch overhead in the memcmp main loop by comparing four
words per iteration: XOR each pair, OR the four differences together,
and branch once. On a mismatch the single-word loop locates the
exact differing word within four words of the fault.
Add a beqz guard at .Lbyte_cmp entry to handle the case where the
4-word loop consumes all remaining bytes exactly.
Measured on QEMU RV32: memcmp(128) 313 -> 271 cycles (13% faster).
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: ganjing <ganjing@xiaomi.com>
Add assembly-optimized implementations for 14 string/memory functions
using word-at-a-time techniques (DETECTNULL, broadcast+XOR) and
XLEN-adaptive macros for both RV32 and RV64:
- memmove: direction check + forward tail to memcpy, reverse path
with 16xSZREG unroll and shift-merge for misaligned src.
- memcmp: word-granularity compare when both pointers share alignment,
bytewise fallback for mismatched pointers.
- memchr: broadcast target byte, XOR with each word, DETECTNULL to
find matches. Counter-based bounds (no pointer overflow).
- strlen: DETECTNULL word loop, constants loaded from .srodata.
- strnlen: strlen with counter-based length limit.
- strcpy/strncpy: word loop with DETECTNULL, zero-fill remainder
for strncpy. strncpy reuses strcpy via #define USE_AS_STRNCPY.
- stpcpy/stpncpy: reuse strcpy/strncpy via #define USE_AS_STPCPY.
- strchr/strchrnul: broadcast+XOR detecting both target char and
null simultaneously. strchrnul reuses strchr via #define.
- strrchr: forward scan recording last match position.
- strncmp: word-at-a-time compare with null detection and counter.
- strcat: strlen(dst) then strcpy(dst_end, src) word-at-a-time.
Each function is independently selectable via CONFIG_RISCV_<FUNC>,
or all enabled together with CONFIG_RISCV_STRING_FUNCTION=y.
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: ganjing <ganjing@xiaomi.com>
Implement architecture-specific ELF header definitions and relocation handling
for the MIPS architecture to enable loadable modules.
Fixes#19178.
Changes include:
- Add `arch/mips/include/elf.h` with MIPS ELF relocation types and
architecture-specific ELF data structures (`arch_elfdata_s`).
- Implement `libs/libc/machine/mips/arch_elf.c` containing `up_checkarch`,
`up_relocate`, and `up_relocateadd` functions handling `R_MIPS_NONE`,
`R_MIPS_32`, `R_MIPS_26`, `R_MIPS_HI16`, and `R_MIPS_LO16` relocations.
- Integrate MIPS machine-specific C library support in
`libs/libc/machine/mips/Make.defs`.
- Update `LDMODULEFLAGS` in `arch/mips/src/mips32/Toolchain.defs` to include the
little-endian (`-EL`) flag.
- Update `up_coherent_dcache` for proper cache synchronization on JZ4780.
Signed-off-by: Lwazi Dube <lwazeh@gmail.com>
NuttX implemented fork() and vfork() as the same function. Both were libc
wrappers around a single up_fork() syscall; vfork() differed only by a
trailing waitpid(). Underneath, the child joined the parent's address
environment -- the same addrenv_join() that pthread_create() uses -- and got
a private copy of the stack. So the child shared .data, .bss and the heap
with its parent and ran concurrently with it.
That is not fork(). It is vfork()-with-a-private-stack under fork()'s name,
and the history says so: today's fork() is NuttX's old vfork(), renamed in
c33d1c9c97 (2023) without any change of behaviour. The failure was silent --
a program written against POSIX fork() compiled, ran, and had its child's
writes land in the parent's variables.
Separate them into two primitives, chosen by which function the caller
called rather than by what the hardware happens to be:
fork() child gets its own copy of the parent's memory at the same
virtual addresses; runs concurrently. Only where an address
environment can be duplicated -- elsewhere it is not declared at
all, so calling it is a build error naming the function.
vfork() child shares the parent's memory; parent suspended until the
child _exit()s or exec()s. Implementable everywhere.
Below libc there is still one syscall. up_fork() gains a bool saying which
primitive the caller used, since the per-architecture register snapshot is
the same for both, and passes it to nxtask_setup_fork(), which is the single
place the memory semantics are decided. The argument arrives in the first
argument register and is never touched: each architecture's snapshot takes
some other call-clobbered register for its scratch, so the flag is simply
still there when the C worker is called.
The vfork() parent suspension moves out of libc into nxtask_start_fork(),
released from nxsched_release_tcb() by nxtask_resume_vfork(). Two things
follow: the parent is resumed at exec(), since exec_swap() has already handed
the child's pid to the loaded program by the time the vfork stub exits, and
vfork() no longer depends on CONFIG_SCHED_WAITPID.
Releasing there requires one fix in nxtask_exit(). It raises rtcb->lockcount
directly rather than through sched_lock() while it tears the TCB down, so the
nxsem_post() that wakes the vfork() parent leaves it queued where a blocked
task collects while pre-emption is off -- g_pendingtasks, or g_readytorun on
SMP -- and the matching raw lockcount-- does not publish it the way
sched_unlock() would, leaving the parent stranded with nothing to move it on.
The fix mirrors sched_unlock() for each case: nxsched_merge_pending(), or
nxsched_deliver_task() under CONFIG_SMP. Both are no-ops while pre-emption is
still disabled, and up_exit() re-reads this_task() afterwards, so a change of
the ready-to-run head is honoured. Without it vfork() deadlocks wherever no
other task happens to call sched_unlock() afterwards -- rv-virt:nsh64 and
rv-virt:pnsh64, where NSH is blocked in waitpid() holding the lock, and
qemu-armv8a:citest_smp, which hangs the moment the vfork() test runs.
fork() is built on a new addrenv_fork(), backed by an up_addrenv_fork() hook
that duplicates an address environment into freshly allocated pages mapped at
the same virtual addresses -- unlike up_addrenv_clone(), which copies only
the representation and leaves both pointing at the same page tables. The
child then adopts the parent's stack geometry rather than being given a
relocated copy: a pointer to a stack local taken before fork() must name the
same object in the child that it named in the parent, and the parent's stack
is already in the duplicate, with its contents, at the parent's address.
No architecture implements up_addrenv_fork() yet, so this commit leaves
fork() unavailable everywhere. That is the intended state. It withdraws
fork() from ARCH_ARM, flat ARCH_ARM64, ARCH_RISCV, ARCH_SIM and ARCH_X86_64,
where until now it named the sharing primitive; per-architecture patches
restore it, with POSIX semantics, as up_addrenv_fork() lands. In the
meantime the sharing primitive is still there under the name that describes
it: vfork() for a child that runs a program, pthread_create() for a second
flow of control that shares memory, posix_spawn() for both at once.
Kconfig: ARCH_HAVE_VFORK inherits ARCH_HAVE_FORK's select lines, conditions
included, so no configuration gains machinery; ARCH_HAVE_FORK is redefined to
mean "can provide POSIX fork() semantics" and now depends on ARCH_ADDRENV.
There is one deliberate departure from "verbatim". ARCH_ARM selected the
fork family unconditionally, BUILD_KERNEL included, and that has never
worked: on a kernel build the architecture's fork entry point sees the
kernel's return address and stack pointer rather than the caller's, so the
child resumes at a kernel address. On qemu-armv7a:knsh master faults in
ostest's fork case with "Child did not run" and then a data abort; without
the condition this change faults the same way through vfork(). ARCH_ARM64
and ARCH_X86_64 already carried "if !BUILD_KERNEL" for exactly this reason --
ARM was the outlier. Conditioning it turns a runtime fault into an honest
absence, which is the whole point of the change; arch/arm takes the condition
off again in the patch that adds its saved-syscall-frame path. Only the
MMU-capable ARM ports are affected, since Cortex-M cannot build BUILD_KERNEL
at all.
Also fixes two latent syntax errors found on the way: a missing comma in
riscv_fork.c and mips_fork.c, both in *_FRAMEPOINTER && !SAVE_GP branches
that are never compiled today.
BREAKING CHANGE: fork() is withdrawn from every architecture. It is no
longer declared in unistd.h, so code that calls it fails to build with an error
naming the function, and the sharing behaviour it used to have is gone rather
than renamed. CONFIG_ARCH_HAVE_FORK no longer means "fork() exists"; it means
"this configuration can provide POSIX fork() semantics", and no architecture
selects it yet.
Quick fix, chosen by why the call was made:
to run a program vfork() + exec*(), or better posix_spawn()
a second flow of control that pthread_create()
shares the caller's memory
a genuinely independent copy keep fork(), and wait for the per-arch patch
of the process that implements up_addrenv_fork() and selects
CONFIG_ARCH_HAVE_FORK
Out-of-tree code that tests CONFIG_ARCH_HAVE_FORK to decide whether a
fork-then-exec path is available wants CONFIG_ARCH_HAVE_VFORK instead, which is
selected in exactly the places CONFIG_ARCH_HAVE_FORK used to be. The full
migration guide is Documentation/guides/fork_vfork_migration.rst.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
This change fixes NuttX’s CMake support when NuttX is embedded
in another project via add_subdirectory(). CMake’s CMAKE_SOURCE_DIR
and CMAKE_BINARY_DIR refer to the outermost project, causing NuttX
to access its .config, generated files, host tools, and build artifacts
in the parent project’s directories. The fix introduces NUTTX_DIR and
NUTTX_BINARY_DIR, based on CMAKE_CURRENT_SOURCE_DIR and
CMAKE_CURRENT_BINARY_DIR, and consistently uses them for NuttX
self-references while preserving existing standalone builds. It fixes
the Kconfig initialization failure reported in #19697 and allows an
embedded sim:nsh build to configure, build, and boot successfully.
The change affects only the CMake build system (not Make or Kconfig
defaults), requires the corresponding nuttx-apps change, and does not
extend add_subdirectory() support to cross-compiled non-sim boards due
to CMake’s toolchain-file limitation.
Fixes#19697.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Alan Carvalho de Assis <acassis@gmail.com>
A mutex records its holder as a task id in the low 31 bits of a word
whose top bit means "someone is blocked on this". The id was stored
without masking, so an id with its top bit set became a holder with the
blocking bit raised.
Task ids are normally small and positive, but not always.
nxsched_gettid() reports -ESRCH for a context that no longer maps to a
running task, and there is a window where that is exactly what the
running context is: nxtask_exit() marks the next task ready to run
while the dying task is still executing on its own stack, and only then
releases the TCB. Freeing the group inside that release takes and
drops the group's mutexes, so the lock stores 0xfffffffd and the unlock
compares 0x7ffffffd, which are not equal.
With assertions enabled the unlock trips its holder check, and every
exit of a process that frees memory panics. In a kernel build that is
every exit, so no program could be run twice, and running one at all
took the shell down with it. Without assertions the failure is silent:
the accidental blocking bit sends the unlock looking for a waiter that
never existed.
Encode the id the same way everywhere it is stored or compared, so that
a lock and an unlock from one context agree whatever the id's sign.
The masked forms of -1 and -2 would alias the "no holder" and "reset"
values, but nxsched_gettid() yields only valid ids and -ESRCH.
mm_lock() already sidesteps this window with a note that gettid() may
return -ESRCH during a context switch; this gives the generic mutex the
same footing rather than a second special case.
Test case, on the EIC7700 EVB, which is a kernel build with assertions:
nsh> hello
Hello, World!!
Before, that printed and then panicked in sem_post, taking the shell
with it, every time. After, five runs in a row complete and the shell
survives. ps over telnet still completes.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
dns_recv_response() checked for room using sizeof(struct dns_answer_s),
but that structure is the 10-byte header plus a union holding the largest
address it can carry. With IPv6 built the union is 16 bytes, so the check
demanded 26 bytes where 10 were needed, and any answer sitting at the end
of a response was rejected as truncated.
An A record answer supplies 14 bytes, so whether a lookup worked depended
on how much padding the server happened to send after it:
$ dig +noedns @10.1.1.2 github.com A # ANSWER 1, AUTHORITY 0, ADDITIONAL 0
-> answer is last in the packet, 14 bytes remain, rejected
$ dig +noedns @10.11.5.254 github.com A # ANSWER 1, AUTHORITY 13, ADDITIONAL 7
-> 26+ bytes remain, accepted
On the board, before and after, against the first of those servers:
nsh> nslookup apache.org
[CPU1] dns_recv_response: DNS answer header truncated
Host: apache.org Addr: 2a04:4e42::644 <- A record lost
nsh> nslookup apache.org
Host: apache.org Addr: 2a04:4e42::644
Host: apache.org Addr: 151.101.2.132 <- both returned
The address that follows the header is already bounds checked separately,
where its real length is known, so only the header check was wrong. The
size is now a named constant next to the structure, since the rest of this
function already used the literal 10 for the same quantity.
Only IPv4-only builds escaped it, where sizeof happens to equal 14 and an
A record fits exactly.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
allsyms_lookup() derived a symbol's size from the physically next table
entry, assuming address order. Under CONFIG_SYMTAB_ORDEREDBYNAME the
table is sorted by name instead, producing a huge bogus size in
%pS/backtrace output.
Scan for the closest larger address instead of relying on table order.
Signed-off-by: liang.huang <liang.huang@houmo.ai>
Assisted-by: Claude Code:claude-sonnet-5
allsyms_findbyvalue()/%pS printed a bogus name/offset for addresses
outside the real symbol table's coverage, due to the boundary sentinels
being matchable as real symbols.
Compute the high sentinel from the actual symbol range and treat a
sentinel match as "not found".
Signed-off-by: liang.huang <liang.huang@houmo.ai>
Assisted-by: Claude Code:claude-sonnet-5
g_allsyms/g_nallsyms only exist in the kernel image, but symtab_allsyms.c
is unconditionally built into libc.a, so user-mode code under
CONFIG_BUILD_PROTECTED/CONFIG_BUILD_KERNEL fails to link.
Guard the affected code so user-mode libc.a no longer references these
kernel-only symbols.
Signed-off-by: liang.huang <liang.huang@houmo.ai>
Assisted-by: Claude Code:claude-sonnet-5
dlopen() of a library that is already loaded fails. libelf_insert()
rejects a name that is already in the module registry with EEXIST, and
dlinsert() passes that straight out, so the second caller gets NULL.
POSIX says dlopen() shall return a handle to the object, and there is no
way today for two modules to hold the same library at once -- which is
what a shared library is for.
So dlopen() now takes another reference on a library that is already
there, and dlclose() only tears it down when the last handle goes. The
count lives in the dlfcn layer rather than in libelf_insert() so that
insmod keeps its own behaviour: a second insmod of the same name still
fails with EEXIST, which is right for a kernel module.
The module name is what makes any of this possible, and a PROTECTED build
did not have one. Names were defined for CONFIG_BUILD_FLAT or the kernel
side of a split build, on the reasoning that only the kernel needed them,
which predates dlopen() being usable from user space. Without a name the
user-space copy of libelf cannot recognise a second open of a library,
cannot count opens, and cannot make dlclose() mean anything -- two
dlopen()s there produce two independent copies of the library and lose
track of the first. Names are therefore defined wherever CONFIG_LIBC_DLFCN
is, which costs NAME_MAX per loaded module in that configuration.
The path no longer has to be copied either. The module name is the
basename of the file and libelf_insert() takes it as a const string, so
dlinsert() finds it with strrchr() instead of handing a writable
duplicate of the whole path to basename().
BUILD_KERNEL is deliberately untouched. dlopen() returns NULL there
unconditionally: dlinsert() is a stub, because sharing a library between
processes with separate address spaces needs the text in a shared region
and the data per process at a matching virtual address, which is a
different problem from this one.
Built for mps3-an547:picostest with and without CONFIG_LIBC_DLFCN, and
for stm32f4discovery:kostest, a PROTECTED configuration, with it enabled.
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Perform pseudo-filesystem permission checks inside inode_reserve() and
inode_remove() while the inode tree lock is held, and hold that lock across
pseudorename mutations so symlink swaps cannot bypass directory checks.
Hold a read lock around pseudo-fs open permission checks.
On setuid/setgid exec, update saved set-IDs, mark the task group secure,
sanitize dangerous environment variables, clear debug/dumpable flags, and
add issetugid(), secure_getenv(), and PR_SET/GET_DUMPABLE support.
Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
The strto* interfaces document explicit bases in the range 2 through 36, and lib_isbasedigit() already supports alphabetic digits through base 36. However, lib_checkbase() rejects every explicit base above 26 with EINVAL.
Raise the validation limit to 36 so the conversion interfaces accept the full documented range while continuing to reject base 37 and above.
Signed-off-by: hanzhijian <hanzhijian@zepp.com>
When CONFIG_TESTING_OSTEST_MULTIUSER is enabled, default
CONFIG_LIBC_PASSWD_FILEPATH to a writable tmpfs path used by the
ostest multiuser passwd sub-test.
Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
Accept user#️⃣uid:gid:home lines produced by mkpasswd in addition
to the six-field gecos form, and raise the default line buffer to 256.
Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
Implement POSIX real/effective/saved credential getters and paired
setters in the task group layer, with libc stubs and syscalls.
Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
During the Toybox port to NuttX, Claude noticed that changes in the
menuconfig weren't taking affect. This issue exists for a long time on
NuttX, in fact BayLibre's presentation from 2017 make jokes about our
building system not been reliable:
https://www.youtube.com/watch?v=XUJK2htXxKw&t=320s
Stale archive members from $(AR)'s additive-only behavior can linger
after Kconfig toggles change which files provide a symbol, causing dead
weight or "multiple definition" link errors on incremental builds.
Fixed by splitting ARCHIVE into two macros: ARCHIVE keeps the original
additive behavior for apps/libapps.a, which many independent
subdirectories contribute to across a build, while the new
ARCHIVE_REBUILD deletes then archives for the far more common case
of a single Makefile building its own self-contained $(OBJS)
- all 39 such call sites now use it.
Assisted-By: Claude Sonnet 5
Signed-off-by: Alan C. Assis <acassis@gmail.com>
When loading a zoneinfo file fails, parse a non-colon-prefixed TZ value
as a POSIX timezone string. Treat a successful tzparse() result as
success while preserving the leading-colon file-only behavior.
Assisted-by: Codex:gpt-5.6 Sol
Signed-off-by: hanzhijian <hanzhijian@zepp.com>
getaddrinfo() and getservbyname() use the built-in service table when
resolving service names. The table only contained ntp, so common
service names such as http and https could not be resolved without a
numeric port.
Add http and https entries for both TCP and UDP to match the existing
service table style.
Testing:
- Host: Ubuntu 22.04 x86_64.
- Board/config: sim:nsh with CONFIG_LIBC_NETDB=y and
CONFIG_EXAMPLES_HELLO=y.
- make clean && make -j16.
- Ran a temporary hello example that called getservbyname("http",
"tcp") and getservbyname("https", "tcp"). The app verified ports
80 and 443 and printed "getservbyname http/https test passed".
Assisted-by: Claude:Claude-Fable-5
Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
posix_spawnattr_init() no longer pre-fills attr->stacksize and
attr->priority (it leaves them zero, as memset already does). When a
caller does not set them, the binary loader supplies them from the
loaded ELF (binp->stacksize / binp->priority, parsed from the nx_*
symbols), and nxtask_spawn_exec() falls back to the parent priority and
CONFIG_POSIX_SPAWN_DEFAULT_STACKSIZE for the posix_spawn() function-task
path.
This lets an application's stack size and priority embedded as ELF
symbols actually drive the spawned task, instead of being overridden by
the spawnattr defaults.
Signed-off-by: anjiahao <anjiahao@xiaomi.com>
Add libelf_findsymbol() to locate a symbol in the ELF symbol table by
name, reusing the existing libelf_findsymtab/libelf_readsym/libelf_symname
helpers, and expose its prototype in include/nuttx/lib/elf.h.
Signed-off-by: anjiahao <anjiahao@xiaomi.com>
nsh_fileapp() could not apply an application's Kconfig-configured
priority/stacksize via posix_spawn() under CONFIG_BUILD_KERNEL, because
the registry table (struct builtin_s / g_builtins[]) was gated on
CONFIG_BUILTIN, which depends on !BUILD_KERNEL. Those settings were
silently ignored in KERNEL builds.
CONFIG_BUILTIN conflates the table with main_t-based dispatch, which is
meaningless under CONFIG_BUILD_KERNEL. Add a hidden derived symbol,
APP_REGISTRY, that tracks table availability independently of dispatch:
config APP_REGISTRY
bool
default y if BUILTIN || BUILD_KERNEL
Switch the guards on the table itself (Make.defs, builtin.h) from
CONFIG_BUILTIN to CONFIG_APP_REGISTRY. Call sites that dereference
builtin->main stay gated on CONFIG_BUILTIN and remain unreachable
under CONFIG_BUILD_KERNEL.
Signed-off-by: liang.huang <liang.huang@houmo.ai>
Update the DNS stream send and receive helpers to advance their buffers
by the number of bytes actually transferred. Advancing by the original
remaining length skips data when send() or recv() completes partially.
Signed-off-by: Old-Ding <ai.neo.ae86@gmail.com>
Check the provided length before reading the current lowoutstream byte. This avoids reading past zero-length or fully consumed buffers before the loop condition stops.
Generated-by: OpenAI Codex
Signed-off-by: Old-Ding <35417409+Old-Ding@users.noreply.github.com>
The existing first-order LCG (seed = 470001 * seed % 999563) has several
quality problems:
- Output range limited to [1, 999562] (~20 bits) instead of full 32-bit
- Lower bits have very short periods (8-bit period = 1, 16-bit = 105)
- Overall period only ~1M, far too short for many applications
- Causes mbedtls_rsa_gen_key to loop forever when rand() consumption
aligns with the cycle length (issue #16760)
Replace the entire order-based LCG implementation (CONFIG_LIBC_RAND_ORDER
0-3) with Marsaglia's xorshift32:
- Full 32-bit output range
- Period 2^32 - 1 (~4.29 billion)
- Fast: just three XOR/shift operations
- No floating-point math needed
- No CONFIG_LIBC_RAND_ORDER configuration required
Remove the CONFIG_LIBC_RAND_ORDER Kconfig option and clean up all
defconfig references (12 boards) and related comments.
Signed-off-by: hanzhijian <hanzhijian@zepp.com>
Add crc32_ieee() and crc32_ieeepart() that produce CRC32 values
compatible with Linux/zlib. The difference from the existing crc32():
crc32(): init=0, no final XOR (NuttX native)
crc32_ieee(): init=0xFFFFFFFF, final XOR 0xFFFFFFFF (Linux/zlib)
The existing crc32() and crc32part() are unchanged to avoid breaking
existing callers (bbsram, sbram, etc.).
New functions:
crc32_ieee(src, len) - full CRC, Linux-compatible
crc32_ieeepart(src, len, crcval) - incremental CRC, Linux-compatible
Verified on sim:nsh against known Linux zlib test vectors:
crc32_ieee("hello") = 0x3610a686 (Linux: 0x3610a686) PASS
crc32_ieee("123456789") = 0xcbf43926 (Linux: 0xcbf43926) PASS
crc32_ieee("") = 0x00000000 (Linux: 0x00000000) PASS
crc32_ieeepart incremental = 0xcbf43926 PASS
crc32("hello") = 0xf032519b (unchanged) PASS
Signed-off-by: hanzhijian <hanzhijian@zepp.com>
NuttX defines constants for the sizes of types just as constants
directly in the code. The real values depend on compiler and target
platform. It is possible that value declared by NuttX header is wrong
compared to the compiler configuration. This is more likely in case of
floating points.
Not all compilers supported by NuttX provide required info through
defines and thus it is more generic to specify limits as constants, but
in case compiler provides them then it is a good idea to compare. This
commit adds such set of comparisons for limits.h and float.h constants.
The comparisons were tested with GCC and Clang. They will be ignored in
case compiler doesn't provide them.
Signed-off-by: Karel Kočí <kkoci@elektroline.cz>
Align the NuttX open(2) flag constants with the Linux asm-generic
values so that the FUSE wire protocol and other cross-platform
interfaces work without conversion.
All code that used '(flags & O_RDONLY)' as a bitmask check (always 0
now that O_RDONLY=0) has been updated to use '(flags & O_ACCMODE)'
comparisons.
The NUTTX_O_* constants in include/nuttx/fs/hostfs.h are updated to
match, and the sim hostfs open flag mapping is fixed.
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
O_RDOK and O_WROK are non-standard aliases for O_RDONLY and O_WRONLY
respectively. Having two names for the same flag creates confusion,
especially when aligning the flag values with Linux. Remove the
aliases and replace all uses with the standard O_RDONLY/O_WRONLY.
No functional change — O_RDOK was defined as O_RDONLY and O_WROK as
O_WRONLY, so the replacement is a pure text substitution.
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
Add getgroups() to the C library. NuttX has no supplementary group
IDs, so it reports a single group, the effective group ID, and follows
POSIX for the gidsetsize == 0 and short-buffer (EINVAL) cases.
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
NuttX has no real session/process-group abstraction, so the TTY layer
collapses the foreground process group onto the single dev->pid field
(pgrp == pid, one member per group). Extend the controlling-terminal
support so portable software (e.g. dropbear, socat) that relies on
job-control primitives works without losing the existing NuttX-specific
behaviour.
Driver (serial.c, pty.c):
- TIOCSCTTY now accepts a flag: arg > 0 keeps the historical "target
PID in arg" semantics (NSH registers the foreground command it just
spawned), while arg == 0 selects the calling task via
nxsched_getpid(), matching the POSIX flag convention used by
dropbear/socat/apue. This preserves all existing callers and makes
the previously-dead arg==0 path deliver SIGINT correctly.
- Add TIOCGPGRP/TIOCGSID (return dev->pid) and TIOCSPGRP (set it).
- pty.c gains the same handlers against pd_pid and includes
nuttx/sched.h for nxsched_getpid().
ioctl numbers (tioctl.h): TIOCGPGRP/TIOCSPGRP/TIOCGSID at 0x37-0x39.
libc wrappers:
- termios: tcgetpgrp(), tcsetpgrp(), tcgetsid() over the new ioctls.
- unistd: setsid()/getsid()/setpgid() stubs consistent with the
existing getpgrp()/getpgid() single-session model (sid == pgid ==
pid; setpgid only succeeds for pgid == pid).
Declare the new prototypes in unistd.h (tcgetsid was already in
termios.h) and register all sources in the Make.defs/CMakeLists.
Group-broadcast signalling (kill(-pgrp)) remains unsupported, so
tty signals still target the single dev->pid; a real session/process
group model is left as a follow-up.
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
Add getgrouplist() to the C library. It scans the group database for
a user's supplementary groups and always reports the primary group
first. Without CONFIG_LIBC_GROUP_FILE only the primary group is
returned, since no membership information is available.
The group file is read through lib_get_tempbuffer()/lib_put_tempbuffer()
to avoid a heap allocation on every lookup.
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
The current implementation exits syslog_write_foreach function
if write to one channel fails, causing other channels not being written
and returning negated errno. libc syslog functions then stay in
an infinite loop, because error is returned and the same bytes
are still passed to syslograwstream_flush and syslog_write_foreach.
The channel write may fail for many reasons - disconnected USB if
CDC ACM syslog is enabled, lost networking if telnet syslog is enabled,
error on NOR flash etc. This shouldn't lead to an ininite loop in the
code though.
The solution ensures all channels in syslog_write_foreach are tried,
therefore the user get the output to the working channels even if
the first one is broken. It also updates syslograwstream_addchar and
syslograwstream_addstring to skip the bytes if all channels fails. This
ensures syslog call won't result in an infinite loop, but the user may
lost the debugging output.
Co-authored-by: Martin Krasula <mkrasula@elektroline.cz>
Signed-off-by: Michal Lenc <michallenc@seznam.cz>
Correct build errors when CONFIG_ENABLE_ALL_SIGNALS is not defined
- sched makefiles: Move pending-signal helpers from the ENABLE_ALL_SIGNALS-only
list to the !DISABLE_ALL_SIGNALS list so signal dispatch is available in
PARTIAL builds sched: make SIG_PREALLOC_ACTIONS, SIG_ALLOC_ACTIONS and
SIG_DEFAULT depend on ENABLE_ALL_SIGNALS
- sched: fix ifdefs around pending-signal queue access and signal-mask for
PARTIAL/DISABLE modes
- arch: gate SYS_signal_handler / _return calls and SYSCALL_LOOKUP(signal)
with ENABLE_ALL_SIGNALS
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
This fixes an issue where ostest robust mutex test gets stuck.
In CONFIG_PTHREAD_MUTEX_ROBUST mode, every NORMAL mutex is robust by
definition, so the robust flag must be set to allow the mutex to be tracked
in the holder's mutex list.
Otherwise, pthread_mutex_add() will not record the mutex and
pthread_mutex_inconsistent() will not be able to mark it as inconsistent or
wake waiters when the holder thread terminates.
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
This adds 3 configuration options for the lib_strftime, which can be
used to save flash memory when all the formatters are not needed by an
embedded application.
There is always a minimal set of formatters supported:
"%a, %b/%h, %d, %H, %m, %M, %S, %Y, %%". To add on top of that one can
specify:
- LIBC_STRFTIME_C_STANDARD_FORMATS : All ISO-C conversion specifiers
- LIBC_STRFTIME_POSIX_FORMATS : Additional posix formats
- LIBC_STRFTIME_NONSTANDARD_FORMATS : Additional GNU nonstandard formats
All of these are enabled by default unless building for CONFIG_DEFAULT_SMALL.
Disabling these options can save over 3KB of flash on an 32-bit
ARM system, when all the format specifiers are not needed.
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
readdir() returned NULL at end-of-directory without ensuring errno was
clean. POSIX requires errno to be unchanged at EOF, but the underlying
read() path may leave a stale errno value. Callers that follow the
POSIX idiom (set errno to 0 before the call, test it after a NULL
return), such as readdir_r() and scandir(), then misread this as a
readdir() failure.
Save errno on entry and restore it on the end-of-directory return so
that EOF no longer reports a spurious error, while genuine errors
(read() returning a negative value) still propagate.
Signed-off-by: yushuailong <yyyusl@qq.com>
1. The original method of restoring the register context relies on
the ret instruction, which does not conform to the semantics of
longjmp not returning.
2. There are csa leak during longjmp and need recycle.
Signed-off-by: zhangyu117 <zhangyu117@xiaomi.com>
Add setjmp/longjmp support for TriCore architecture using iLLD
intrinsics to save and restore the CSA (Context Save Area) chain.
This implementation saves upper/lower context registers and walks
the CSA linked list to restore the full call context on longjmp.
Signed-off-by: zhangyuan29 <zhangyuan29@xiaomi.com>
The sim architecture needs to defer C++ global constructors until after
NuttX kernel initialization completes. On macOS this was previously done
via a runtime hack (sim_macho_init.c): a __attribute__((constructor))
function intercepted constructors, saved them, and replayed them later.
That approach was fragile because it depended on constructor ordering
and required mprotect() to patch the read-only __mod_init_func section
at runtime.
This commit replaces the runtime hack with a post-link patching scheme:
1. Link with -Wl,-ld_classic,-no_fixup_chains to keep the classic
__mod_init_func pointer format (prevents ld64 from converting it
to __init_offsets).
2. Post-link, run patch_macho_initsection.py (python3 + lief) to
patch Mach-O section type flags from
MOD_INIT_FUNC_POINTERS/INIT_FUNC_OFFSETS to REGULAR, so dyld
skips them entirely.
3. Use the Mach-O auto-generated boundary symbols
section$start$__DATA_CONST$__mod_init_func /
section$end$__DATA_CONST$__mod_init_func, mapped via __asm()
labels in arch/sim/include/arch.h to the common _sinit[]/_einit[]
names used by lib_cxx_initialize().
Linux behavior is unchanged.
Changes:
- arch/sim/include/arch.h: add macOS __asm() declarations for
_sinit/_einit
- arch/sim/src/Makefile: drop sim_macho_init.c HEADSRC handling,
always pass -ld_classic,-no_fixup_chains on macOS, run
patch_macho_initsection.py after link when CONFIG_HAVE_CXXINITIALIZE
- arch/sim/src/sim/CMakeLists.txt: same for the CMake build
- arch/sim/src/patch_macho_initsection.py: new lief-based patcher
- arch/sim/src/sim/posix/sim_macho_init.c: deleted (135-line hack)
- libs/libc/misc/lib_cxx_initialize.c: remove
macho_call_saved_init_funcs special case; single unified loop
Testing:
- macOS (Ventura VM): verified lief patching with standalone test
(test_sinit7) confirming the constructor is deferred past main()
and only invoked when explicitly called via the _sinit/_einit loop.
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
Now that time_t is unconditionally 64-bit (signed int64_t) and the
struct timespec fields tv_sec / tv_nsec are wide enough on their own,
the explicit (uint64_t)/(int64_t)/(int) casts that used to guard the
multiplications and subtractions in *_us / *_ms / *_ns helpers are no
longer needed. Drop them to keep the timekeeping math readable and
consistent with the previous sclock_t/time_t cleanup.
In the same spirit, this commit also:
* Normalises the printf-style format specifiers and casts used to
print tv_sec / tv_nsec / tv_usec values across arch/, drivers/,
fs/, sched/ and libs/. The prior code was a mix of
"%d"/"%u"/"%ld"/"%lu"/"%lld"/PRIu32/PRIu64 with matching
(int)/(unsigned long)/(long long)/PRIu* casts; some formats
truncated time_t on 32-bit hosts, others mismatched signedness or
width. Replace all such cases with the portable POSIX-recommended
forms:
- tv_sec (time_t, signed, impl-defined width) -> %jd + (intmax_t)
- tv_nsec (long, signed) -> %ld (no cast)
- tv_usec (suseconds_t / long) -> %ld (no cast)
Add #include <stdint.h> where required.
* Drops a few stale `(FAR const time_t *)&ts.tv_sec` casts and
related `(FAR struct tm *)` / `(const time_t *)` casts in
gmtime_r() / localtime_r() / gmtime() callers; ts.tv_sec is plain
time_t now and the casts only obscured the type.
* Fixes one overflow in fs/procfs/fs_procfscritmon.c where
all_time.tv_sec * 1000000 could overflow on 32-bit time_t before
being multiplied again; cast to uint64_t at the start.
No behavioural change.
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
POSIX leaves the signedness of time_t and clock_t unspecified, but
mainstream implementations (Linux glibc/musl, the BSDs, macOS, RTEMS,
Zephyr's POSIX layer, Windows _time64) expose time_t as signed 64-bit.
NuttX has historically used uint64_t only because it was tied to the
CONFIG_SYSTEM_TIME64 knob; with that gone, switch:
time_t : uint64_t -> int64_t
clock_t : uint64_t -> int64_t
CLOCK_MAX: UINT64_MAX -> INT64_MAX
This lets (time_t)-1 sentinels, negative tick deltas, and host-side
headers behave as on every other POSIX system without source churn.
Headers updated:
- include/sys/types.h, include/limits.h, include/nuttx/clock.h
- include/nuttx/fs/hostfs.h (nuttx_time_t alias)
- include/nuttx/{mqueue.h,wdog.h,wqueue.h,timers/clkcnt.h}
Because clock_t is now signed 64-bit, the NuttX-internal sclock_t
alias becomes redundant: every sclock_t/SCLOCK_MAX use is folded
back to clock_t/CLOCK_MAX (notably in sched/wdog, sched/mqueue,
sched/sched, sched/clock, sched/timer, libs/libc/time, fs/vfs and
the drivers/arch consumers below).
Tick/period constants (NSEC_PER_SEC, USEC_PER_SEC, MSEC_PER_SEC,
SEC_PER_MIN, ...) in include/nuttx/clock.h are retyped from "long"
literals to INT64_C(...) so that 64-bit arithmetic no longer
depends on the host's long width.
Strip now-redundant (time_t)/(clock_t)/(unsigned long) casts and
unsigned-only branches across the tree:
- arch RTC / oneshot / tickless lowerhalfs:
arm: cxd56xx, efm32, imxrt, lc823450, max326xx, sam34, sama5,
samd5e5, samv7, stm32, stm32f7, stm32h7, stm32l4, stm32wb,
xmc4
mips: pic32mz sparc: bm3803 x86_64: intel64
risc-v/xtensa: espressif (esp_i2c[_slave], esp_rtc,
esp32c3{_i2c,_rtc,_wifi_adapter}, esp32{,s2,s3}_*),
mpfs_perf
- drivers: audio/tone, input/aw86225, power/pm/{activity,
stability}_governor, rpmsg/rpmsg_ping,
timers/{ds3231,mcp794xx,pcf85263,rx8010},
wireless/ieee80211/bcm43xxx, wireless/spirit/spirit_spi
- core: fs/vfs/{fs_poll,fs_timerfd}, mm/iob/iob_alloc,
libs/libc/{netdb/lib_dnscache,time/{lib_calendar2utc,
lib_time}}, net/icmp/icmp_pmtu, net/icmpv6/icmpv6_pmtu,
net/ipfrag, net/tcp/{tcp.h,tcp_timer},
net/utils/net_snoop, net/mld/mld_query (drop the now-dead
mld_mrc2mrd helper since signed math handles it directly),
sched/clock/{clock,clock_initialize},
sched/sched/{sched_profil,sched_setparam,sched_setscheduler},
sched/pthread/pthread_create,
sched/wdog/{wd_gettime,wd_start,wdog.h},
sched/timer/timer_gettime, sched/mqueue/*
Flip the few in-tree printf format strings that assumed an
unsigned 64-bit tv_sec:
* drivers/rpmsg/rpmsg_ping.c PRIu64 -> PRId64
* arch/xtensa/src/esp32{,s2,s3}/esp32*_oneshot_lowerhalf.c
PRIu32 (already wrong) -> PRId64
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
The 32-bit system clock has a limited range (~497 days) and the
configuration knob is no longer worth the complexity given that
practically every modern target already enables it. Make 64-bit
time_t/clock_t/sclock_t/nuttx_time_t the only supported flavor.
Specifically:
- Drop the SYSTEM_TIME64 Kconfig option and its dependent
PERF_OVERFLOW_CORRECTION/HRTIMER guards in sched/Kconfig.
- Remove every #ifdef CONFIG_SYSTEM_TIME64 branch in headers
(include/{sys/types.h,limits.h,inttypes.h,nuttx/clock.h,
nuttx/fs/hostfs.h}) and core code paths
(sched/clock/clock.h, drivers/power/pm/pm_procfs.c,
drivers/rpmsg/rpmsg_ping.c, fs/procfs/fs_procfsuptime.c,
libs/libc/wqueue/work_usrthread.c,
arch/avr/src/avrdx/avrdx_timerisr_tickless_alarm.c).
- Strip CONFIG_SYSTEM_TIME64=y from every board defconfig.
- Update Documentation/guides/rust.rst accordingly.
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
Long long support is now unconditional in printf/scanf and related
helpers. Remove the Kconfig option, the conditional compilation in
libvsprintf/libvscanf/ultoa_invert, the build-time #error in the
rn2xx3 driver, and clean up CONFIG_LIBC_LONG_LONG entries from all
board defconfigs.
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
Every compiler supported by NuttX provides the "long long" types,
so the CONFIG_HAVE_LONG_LONG indirection is no longer useful.
Remove the option from include/nuttx/compiler.h and treat
"long long" as unconditionally available across the OS.
In addition to deleting the guard itself, this commit unconditionally
enables the long-long flavored helpers that used to be gated behind
it:
- libs/libc/fixedmath: drop the soft-emulated b32/ub32 routines
in lib_fixedmath.c (-261 lines) and trim the matching
prototypes, Make.defs and CMakeLists.txt entries; keep only
the long-long backed implementations.
- include/sys/endian.h, include/strings.h, libs/libc/string
/lib_ffsll.c, lib_flsll.c: always expose the 64-bit byte-swap
and ffsll/flsll variants.
- libs/libm/libm/lib_llround{,f,l}.c: drop the empty stubs.
- libs/libc/stdlib (atoll, llabs, lldiv, strtoll/ull, rand48,
strtold), libs/libc/stream (libvsprintf, libvscanf,
libbsprintf, ultoa_invert), libs/libc/misc (crc64, crc64emac),
libs/libc/inttypes/strtoimax, libs/libc/lzf, libs/libc/libc.csv,
libs/libc/string (memset, vikmemcpy): remove the
#ifdef CONFIG_HAVE_LONG_LONG branches.
- include/{stddef.h,stdlib.h,fixedmath.h,sys/epoll.h,cxx/cstdlib,
nuttx/audio/audio.h,nuttx/crc64.h,nuttx/lib/math.h,
nuttx/lib/math32.h,nuttx/lib/stdbit.h}: same guard cleanup.
- drivers/note/note_driver.c, fs/spiffs/src/spiffs.h,
sched/irq/irq_procfs.c: drop their local guards as well.
- Documentation/applications/netutils/ntpclient/index.rst:
refresh the documentation snippet.
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
The goal is to only execute recipes when there is an actual change in
the prerequisites.
There are several issues which cause the nuttx binary target to be
re-made every time the top level make is run.
1. Previously the target nuttx$(EXEEXT), was used, but make resolved
this in the relative directory make -C $(ARCH_SRC), and couldn’t find
it (need an absolute path: `$(TOPDIR)/..).
2. The .tmp prerequisite for nuttx was always deleted
3. libboard's recipe had a sub-make which may or may not update that
target. This was a phony target, and was therefore always considered out
of date.
These issues were causing the nuttx recipe to be run every make, which
was hiding some missing prerequisites:
1. the .config is a prerequisite for the .tmp target
2. libapps.a (and other linklibs) are pre-requisites for nuttx
Changes:
The changes are only in the build system, and only for arm.
Track nuttx$(EXEEXT) via vpath so Make knows when it's already up to
date without an explicit path. Add $(TOPDIR)/.config as a dependency
to the linker script preprocessing so config changes trigger
re-preprocessing.
Keep the .tmp linker script on disk (clean already removes it) so
timestamp-based dependency checking works across builds. These .tmp
files need to be added to the gitignore or the CI will complain.
Use FORCE pattern for board/libboard to ensure it's always checked
but use the actual library file as the link dependency so nuttx is
only re-linked when library content changes. Add staging libs as
dependency to nuttx link rule so changed app libs trigger re-link.
Signed-off-by: Liam Hickey <williamhickey@geotab.com>
Add dedicated NEON implementations for mutually aligned medium and long memcpy copies when building with __ARM_NEON__. These paths use NEON multi-register loads and stores while preserving the existing VFP implementation for non-NEON VFP configurations.
NEON builds also define USE_VFP, so select the NEON implementation explicitly before falling back to VFP. Apply the same aligned-copy optimization to the armv7-a, armv7-r, and armv8-r implementations.
Signed-off-by: yaojiaqi <yaojiaqi@lixiang.com>
This commit avoid that dns_recv_response() accepts fewer tha 10 bytes
that could end up with an OOB read.
Signed-off-by: Alan C. Assis <acassis@gmail.com>