[1/3] arch/xtensa: Provide vfork() - #19795
Draft
casaroli wants to merge 1 commit into
Draft
Conversation
casaroli
marked this pull request as draft
August 11, 2026 14:23
|
simbit18
requested review from
eren-terzioglu,
fdcavalcanti,
tmedicci and
xiaoxiang781216
August 11, 2026 14:40
casaroli
force-pushed
the
xtensa-split-1-vfork
branch
from
August 11, 2026 14:58
87d1d68 to
af62cf0
Compare
casaroli
marked this pull request as ready for review
August 11, 2026 15:00
This was referenced Aug 11, 2026
Xtensa selected neither fork primitive, so vfork() was simply absent. This wires it onto the two-primitive semantics. There is no assembly entry point and none is needed. Every exception entry already runs SPILL_ALL_WINDOWS, so the whole context of the calling thread is in its exception frame and copying its stack copies a complete frame chain. A flat build reaches that frame through SYS_save_context, issued inline so that the recorded stack pointer belongs to a frame that stays alive for the whole operation; a build with syscalls reaches it through xcp.sregs, recorded by xtensa_swint() for the duration of the call. The stack copy needs more than a relocated stack pointer here. A windowed ABI stores each frame's caller stack pointer absolutely, in the base save area below the frame, so a copy taken at a different address still names the parent throughout and the child's first retw would underflow onto the parent's stack. xtensa_fork_rebase() walks that chain and adds the relocation offset to each link. The copy also starts one base save area below the stack pointer rather than at it, because the frame the child resumes into keeps its caller's spilled a0-a3 there. Ported from the per-architecture work, reduced to the two primitives. Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
casaroli
force-pushed
the
xtensa-split-1-vfork
branch
from
August 11, 2026 20:05
af62cf0 to
27547e0
Compare
casaroli
marked this pull request as draft
August 11, 2026 20:21
Contributor
Author
🔗 Cross-repo PR dependenciesThe read-only Build run reported the following dependent PR(s) and fetched head SHA(s): CI run: https://github.com/apache/nuttx/actions/runs/31531206452 |
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
Split from #19772, part 1 of 3, as asked in review.
It gives Xtensa
vfork()and nothing else. No MMU, no address environment, no chip code.up_fork(bool vfork)is the architecture half of the primitive introduced by #19562. The child gets its own stack holding a relocated copy of the part of the parent's that is in use, and resumes where the caller would have returned.Two paths reach it. A flat build calls in directly, so the caller's registers are taken at the call. A build with system calls arrives through
xtensa_swint(), which has already recorded the caller's frame inxcp.sregs; that frame is used instead, because the caller is on the far side of the boundary.The windowed ABI needs care in one place. A stack pointer has a base save area 16 bytes below it holding the caller's spilled
a0–a3, and the frame chain runs through it.SPILL_ALL_WINDOWSputs the register file into memory first, and the chain is then walked and rebased onto the child's copy, because a frame pointer that still points into the parent's stack would send the child back into memory it does not own.Impact
Xtensa gains
vfork(). Nothing else changes, and no board configuration changes.fork()is not provided here. That needs an address environment and arrives in part three.Testing
Host: macOS 15 on Apple Silicon,
xtensa-esp32s3-elf-gccandxtensa-esp32-elf-gcc, both 12.2.0.Three boards ran
ostestto the end.esp32-devkitc:ostestvfork()passes, status 0esp32s3-devkit:ostestvfork()passes, status 0esp32s3-devkit:ostestvfork()passes, status 0The 32 MB octal part also needs
ESP32S3_FLASH_MODE_OCTandESP32S3_SPI_FLASH_USE_32BIT_ADDRESS.Both Xtensa cores that NuttX supports are covered, and the LX6 has no MMU at all — which is the case this part is meant to serve.
tools/checkpatch.sh -c -u -m -greports no errors.depends-on: apache/nuttx-apps/pull/3685