Skip to content

arch/arm64: Implement up_addrenv_fork() and provide POSIX fork() - #19773

Draft
casaroli wants to merge 3 commits into
apache:masterfrom
casaroli:arm64-fork
Draft

arch/arm64: Implement up_addrenv_fork() and provide POSIX fork()#19773
casaroli wants to merge 3 commits into
apache:masterfrom
casaroli:arm64-fork

Conversation

@casaroli

Copy link
Copy Markdown
Contributor

Draft. The evidence is emulation only. I keep this as a draft until fork() runs on ARM64 hardware. A Raspberry Pi test is planned.

Summary

fork() was withdrawn from every architecture by #19562, and each architecture restores it with the correct behaviour. This pull request restores it for ARM64.

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 is already in master. #19562 added the saved-syscall-frame path, where dispatch_syscall() stores the exception frame of the caller in xcp.sregs and arm64_fork() builds the child from it. arm64_fork.c also already takes both paths: a child that keeps the stack addresses of the parent needs no relocation, which is what a duplicated address environment gives it. Only the hook and the Kconfig default were missing.

Impact

The change is specific to ARM64. It adds capability and removes none.

fork() becomes available on ARM64 in a kernel build over an MMU. ARCH_HAVE_FORK keeps depends on ARCH_ADDRENV, so a configuration without address environments is not affected. A protected build is excluded.

vfork() does not change. No board configuration changes.

Testing

Emulation only. qemu-armv8a:knsh, a kernel build, under QEMU 11.0.3 on macOS 15 with Apple Silicon, aarch64-none-elf-gcc 14.2.rel1.

qemu-system-aarch64 -cpu cortex-a53 -nographic \
  -machine virt,virtualization=on,gic-version=3 \
  -net none -semihosting -kernel nuttx

-semihosting is necessary. A kernel build loads its applications over hostfs, and without the flag the guest traps in smh_call and panics in AppBringUp, which looks like a kernel defect and is not one.

ostest runs to the end:

user_main: vfork() test
vfork_test: Child 7 ran and exited before the parent resumed
user_main: fork() test
fork_test: Child running independently (child)
fork_test: Parent and child had independent memory
ostest_main: Exiting with status 0

tools/checkpatch.sh -c -u -m -g gives no errors.

What is not tested

No ARM64 hardware. This is the reason for the draft status.

The protected build is not tested at run time either. The only ARM64 protected configurations in the tree are the ARMv8-R FVPs, and QEMU has no Cortex-R82. fork() is excluded from a protected build in any case.

A report from an ARM64 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.

Duplicate an address environment into freshly allocated pages mapped at the
same virtual addresses, which is what POSIX fork() is built on.  It lives in
arm64_addrenv_mmu.c:  an MPU address environment is a set of protection
regions over one physical address space, not a mapping that can be duplicated
at the same virtual addresses, so ARCH_HAVE_FORK is conditioned on
ARCH_USE_MMU and excludes the protected configurations.

arm64_fork_stack() 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.  With a
zero offset arm64_fork_reloc() is then the identity, so the register context
needs no further special casing.

Verified on qemu-armv8a:knsh under qemu-system-aarch64:  ostest's fork_test
reports "Parent and child had independent memory", and vfork_test passes.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
@github-actions github-actions Bot added Area: Documentation Improvements or additions to documentation Arch: arm64 Issues related to ARM64 (64-bit) architecture Size: M The size of the change in this PR is medium labels Aug 10, 2026
The kernel mode section shows the QEMU command but does not say why
-semihosting is there.  Without it the guest traps in smh_call and stops in
AppBringUp, which reads as a kernel defect and is not one.  It cost me a
session once.

Also state that a kernel build is the only mode on this board with POSIX
fork(), and that vfork() is available in every mode.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

qemu-armv8a

  • Code: .text.romfs_cachenode +4 B (+0.0%, 316,720 B)

s698pm-dkit

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 the ARCH_ADDRENV dependency rather than relying on it,
because a select bypasses depends on:  without that repetition an architecture
could offer fork() where there is no address environment to duplicate.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: arm64 Issues related to ARM64 (64-bit) architecture Area: Documentation Improvements or additions to documentation Size: M The size of the change in this PR is medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant