arch/risc-v: Implement up_addrenv_fork() and provide POSIX fork() - #19774
Draft
casaroli wants to merge 2 commits into
Draft
arch/risc-v: Implement up_addrenv_fork() and provide POSIX fork()#19774casaroli wants to merge 2 commits into
casaroli wants to merge 2 commits into
Conversation
Duplicate an address environment into freshly allocated pages mapped at the same virtual addresses, which is what POSIX fork() is built on. The walk mirrors up_addrenv_destroy(): every final level page table the source has under its static tables is visited, and every page it maps is duplicated, so the cost is the size of the process rather than the size of its address space. Shared memory stays shared -- the very same page is mapped, and up_addrenv_destroy() already knows not to free SHM pages. riscv_fork() then lets the child run at the parent's stack addresses. A pointer to a stack local taken before fork() must name the same object in the child that it named in the parent, so the child adopts the parent's stack geometry rather than being given a relocated copy; the parent's stack is already in the duplicate, at the parent's address, with its contents. RISC-V already builds the child's register context from the caller's saved syscall frame, so nothing else is needed and ARCH_HAVE_FORK follows. It is the first architecture with real fork(). Verified on rv-virt:knsh64 under qemu-system-riscv64: ostest's fork_test reports "Parent and child had independent memory", and vfork_test passes. rv-virt:nsh64 is unchanged, with vfork() passing and fork() correctly absent. Assisted-by: Claude Code:claude-opus-5 Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
|
Review of apache#19772 asked for this shape, and it applies to every architecture in the series. ARCH_HAVE_FORK described when it was available from inside its own definition, which put the per-architecture condition somewhere nobody looks. The architecture now says so itself. The condition repeats both dependencies rather than relying on them, because a select bypasses depends on. RISC-V also excludes dynamic stacks, so that is named here too. Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
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
fork()was withdrawn from every architecture by #19562, and each architecture restores it with the correct behaviour. This pull request restores it for RISC-V.up_addrenv_fork()duplicates an address environment into freshly allocated pages mapped at the same virtual addresses. The text, data and heap regions of the source are walked one page at a time and copied into fresh pages hung off the page tables of the child.The other half was already in the tree before #19562.
riscv_swint.cstores the exception frame of the caller inxcp.sregs, andriscv_fork.cbuilds the child from it. RISC-V was the architecture the other ports copied for that.riscv_fork.calso loses a duplicate branch. The review round of #19562 added the same-virtual-address shortcut to that file, and this commit added its own copy of it. One remains.Impact
The change is specific to RISC-V. It adds capability and removes none.
ARCH_HAVE_FORKtakesdefault y if ARCH_RISCV. That is broader than the condition the other architectures use, so the guard matters:depends on ARCH_ADDRENV && !ARCH_STACK_DYNAMIC. A configuration without address environments is unaffected, and a protected build is excluded, MPU and MMU alike. A protected build has one address space, protected by a fixed set of regions, and a second copy of a process at the same virtual addresses has no meaning there.vfork()does not change. No board configuration changes.Nine RISC-V chips select
ARCH_HAVE_ADDRENVtoday: MPFS, QEMU_RV, JH7110, BL808, K230, SG2000, EIC7700X and two LiteX cores.fork()becomes available on those, in a kernel build.Testing
Emulation only. QEMU 11.0.3 on macOS 15 with Apple Silicon, xPack
riscv-none-elf-gcc14.2.0-3.rv-virt:knsh_romfsvfork()andfork()pass, status 0rv-virt:knsh64vfork()andfork()pass, status 0Do not add
-bios noneto the 32-bit command. Without OpenSBI the guest prints nothing at all, which reads as a boot failure and is not one. The 64-bit configuration loads its applications over hostfs and needs-semihosting.tools/checkpatch.sh -c -u -m -ggives no errors.What is not tested
No RISC-V hardware. This is the reason for the draft status.
rv-virt:knshdoes not boot here, and it does not boot at the merge base either, so I usedrv-virt:knsh_romfsfor the 32-bit row.A report from a RISC-V board is welcome. Take this branch with apache/nuttx-apps#3685, build a kernel configuration and run
ostest. The fork tests are the first output.