Skip to content

add basic support of the system calls 'fork' and 'spawn_process' - #970

Draft
stlankes wants to merge 17 commits into
hermit-os:mainfrom
stlankes:fork
Draft

stlankes wants to merge 17 commits into
hermit-os:mainfrom
stlankes:fork

Conversation

@stlankes

@stlankes stlankes commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

In the long term, Hermit will also be usable as a monolithic OS. To prepare for this, an example of calling the system calls fork and spawn_process are being integrated. In the case of a unikernel, the fork call will return an error (ENOSYS).

@stlankes
stlankes force-pushed the fork branch 2 times, most recently from 3fcf25e to 10fc90a Compare April 8, 2026 09:29
@stlankes stlankes changed the title add basic support of the system call 'fork' add basic support of the system calls 'fork' and 'spawn_process' Apr 10, 2026
@stlankes
stlankes force-pushed the fork branch 4 times, most recently from 0377355 to e152509 Compare May 3, 2026 10:08
@stlankes
stlankes marked this pull request as draft July 12, 2026 20:31
stlankes added 10 commits July 12, 2026 22:33
In the long term, Hermit will also be usable as a monolithic OS.
To prepare for this, an example of calling the fork system call
is being integrated. In the case of a unikernel, the fork call
will return an error (ENOSYS).
Add the system call `spawn_process`, which creates a new process
from the executable file.
In the long term, Hermit will also be usable as a monolithic OS.
To prepare for this, an example of calling the fork system call
is being integrated. In the case of a unikernel, the fork call
will return an error (ENOSYS).
Replace all `-22` placeholders in the user-side syscall layer
with real `syscall!` invocations and extend `SyscallNo` with the
matching numbers (18–53) for spawn/join, file metadata, condvars,
task blocking and the socket API.
- extend the fork example to test the system call `exec`
Mirrors hermit/src/syscall/x86_64.rs for the aarch64 target so that
common-os user-space binaries can issue syscalls into the kernel.

Convention follows the Linux-like AArch64 SVC ABI:
  - svc #0           triggers the exception
  - syscall number   in x8 (input only)
  - arguments        in x0..x5 (up to six, like the existing macro)
  - return value     in x0 (`inlateout` for syscall1+, plain `lateout`
                            for syscall0)
  - PSTATE.NZCV is preserved across the SVC, so options(preserves_flags)
    is sound

The macro and the syscall0..syscall6 helper signatures match the x86_64
side verbatim, so the rest of the crate (sys_open, sys_read, sys_write,
sys_fork, sys_waitpid, …) compiles unchanged on aarch64.
+ revert obsolete changes
- add a small benchmark to measure the overhead
Wires up the sys_mmap user-space stub (hermit_abi PROT_* flags,
plumbing in syscall/mod.rs and Cargo.toml) and switches the Talck-
based user heap from a 64 KiB static buffer to an mmap-backed heap
that can grow on demand:
- the first sys_malloc reserves an initial MIN_SIZE region via
  sys_mmap (anonymous, demand-paged), and HEAP_END tracks its
  current upper bound;
- a later allocation that exceeds the existing heap extends the
  same VMA via sys_mmap(extend_size, …, &mut heap_end) and tells
  the allocator about the new region with ALLOC.extend(…).
stlankes added 4 commits July 15, 2026 07:18
Wires up the sys_mmap user-space stub (hermit_abi PROT_* flags,
plumbing in syscall/mod.rs and Cargo.toml) and switches the Talck-
based user heap from a 64 KiB static buffer to an mmap-backed heap
that can grow on demand:
- the first sys_malloc reserves an initial MIN_SIZE region via
  sys_mmap (anonymous, demand-paged), and HEAP_END tracks its
  current upper bound;
- a later allocation that exceeds the existing heap extends the
  same VMA via sys_mmap(extend_size, …, &mut heap_end) and tells
  the allocator about the new region with ALLOC.extend(…).
the latest kernel version doesn't longer touch the user stack
Both wrappers pass optional NULL-terminated argv/envp arrays to the
kernel. _start now forwards the real argc/argv/envp provided by the
kernel to runtime_entry instead of a dummy argument vector, so
std::env::args() and std::env::vars() work in user processes.

The fork and spawn examples pass a demo argument vector and
environment; hello_world prints its arguments and environment.
Add the ecall-based syscall shim for riscv64 (number in a7, arguments
in a0..a5, return value in a0), matching the kernel's user-mode
dispatcher. With the riscv64gc-unknown-hermit target the examples now
build and run on riscv64 under the common-os kernel.
stlankes added 2 commits July 25, 2026 22:57
Expose the kernel's sys_pipe (syscall number 58) to user space:
declare `pipe(pipefd: *mut i32)` in hermit-abi and implement the
sys_pipe stub that issues the syscall in the common-os runtime.

Lets applications create a pipe whose two descriptors are inherited
across fork, enabling parent/child communication.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants