boards/risc-v/qemu-rv: switch rv-virt flat nsh defconfigs to nxinit entrypoint - #20119
Merged
xiaoxiang781216 merged 2 commits intoSep 13, 2026
Merged
Conversation
…ntrypoint 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>
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>
JianyuWang0623
force-pushed
the
br_wjy_rvvirt_nxinit_switch
branch
3 times, most recently
from
September 11, 2026 15:34
edbe7ea to
926ac3a
Compare
JianyuWang0623
marked this pull request as ready for review
September 11, 2026 15:40
JianyuWang0623
requested review from
acassis,
anchao,
jerpelea,
lupyuen,
masayuki2009,
pussuw,
tmedicci,
xiaoxiang781216,
yamt and
yf13
as code owners
September 11, 2026 15:40
acassis
approved these changes
Sep 11, 2026
xiaoxiang781216
approved these changes
Sep 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Switch every
rv-virt(qemu-rv) flat-build defconfig whose init entry point wasnsh_mainto 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,
plus pnsh/pnsh64 (
CONFIG_BUILD_PROTECTED=y) — 25 configs total.nshnow runsas a "console sh" service started by
init.rcinstead of being the top-levelinit task, matching the pattern already used by
boards/arm/qemu-armv7a,boards/arm64/qemu-armv8aandboards/sim.elf(entrypointelf_main) and the 11 kernel-build configs(
CONFIG_INIT_FILEPATH="/system/bin/init") are out of scope and untouched.Each switched defconfig only gains the nxinit-essential keys (minimal delta,
regenerated with
make savedefconfig):CONFIG_INIT_ENTRYPOINT="init_main",CONFIG_SYSTEM_NXINIT=y(+ its depsEXPERIMENTAL,LIBC_EXECFUNCS,SCHED_CHILD_STATUS),CONFIG_ETC_ROMFS=y/CONFIG_FS_ROMFS=yto shipinit.rc. Board changes: newsrc/etc/init.d/init.rc,Makefile/CMakeLists.txtto ship it via ROMFS, and a
CONFIG_FS_BINFS-gatedmount(NULL, CONFIG_PATH_INITIAL, "binfs", ...)inqemu_rv_boardinit.csoposix_spawnp("sh")can resolve the builtin.CONFIG_PATH_INITIALis left at its pre-existing"/system/bin"and binfs ismounted at that same
CONFIG_PATH_INITIALpath, so no defconfig needs aPATH_INITIALchange.smp/smp64 additionally re-enable binfmt (they had
CONFIG_DEFAULT_SMALL=ypullingin
CONFIG_BINFMT_DISABLE=y, which would blockLIBC_EXECFUNCS→SYSTEM_NXINIT).pnsh/pnsh64 rely on the boardctl(BOARDIOC_BUILTINS) hand-off; see the second commit.
Impact
service child of
init_mainrather than the init task itself.boardctl(BOARDIOC_BUILTINS)registration(nuttx-apps
system/nxinit) to populate the kernel builtin table underPROTECTED build.
Known dependency for one runtime symptom
During full-runtime testing, the switched
rv-virt:smp/smp64show anintermittent zero-output boot hang on QEMU 8.2.2. This was root-caused to a
pre-existing use-after-scope of the
_inode_search()path buffer underCONFIG_LIBC_TEMPBUFFER=n(DEFAULT_SMALLdefault): the buffer escapes itsallocaframe and occasionally corrupts a freshly-registered inode name such as/dev/console, which then breaks console setup. It is not caused by thisdefconfig switch — it reproduces on the pre-switch
nsh_mainconfigs and iscore-count-independent — but nxinit's extra task spawn raises its hit rate.
That underlying bug is fixed separately by #20118
(
fs: fix use-after-scope of alloca path buffers (CONFIG_LIBC_TEMPBUFFER=n)).With #20118 applied, the switched rv-virt:smp boots reliably
(smp8 60/60, smp4 20/20, smp1 20/20) vs. ~27.5%/10% zero-byte hangs without it.
This PR is kept as a draft pending #20118 so the two land in a sensible order.
Testing
Toolchain: xPack
riscv-none-elf-gcc14.2.0. Emulator: QEMU 8.2.2.All configs were actually booted (not just compiled);
psshowsinit_mainasthe parent and
shas its running child. Runtime logs below.nsh (rv-virt, riscv32 flat)
nsh64 (rv-virt, riscv64 flat)
pnsh (rv-virt, riscv32 PROTECTED build)
Two blobs (
nuttx+nuttx_user). Besides theinit_main/shrelationship,this confirms the apps-side
boardctl(BOARDIOC_BUILTINS)hand-off populated thekernel builtin table:
/system/binlists the builtins andhelloruns.smp (rv-virt, riscv32 SMP) — with #20118 applied
The smp/smp64 intermittent boot hang described above is gone once #20118 is
applied. Booted with all 8 CPUs up;
init_mainspawnsshas expected:Stability with #20118 applied (
-serial file:capture, prompt-reached count):-smp 840/40, versus ~27.5% zero-output hangs on the same config without #20118.