The RB fork's KernelScheme trait has an extra 'arg: u64' parameter in
kfdwrite (not in upstream). Also RB's FileDescriptor has a 'cloexec' field.
Both are now handled correctly.
This merge uses -X ours to preserve ALL upstream functions while keeping
all RB-specific features (cpuinfo, iostat, msr, facs, fadt, s3_resume,
+rb0.3.1 version). The kfdwrite function that was lost during a bad
merge (7aa2a165) has been surgically restored from upstream/master.
Missing upstream functions still pending restoration:
- bulk_insert_files, resize in context.rs
- insert_hole, remove_hole, resize_hole in memory.rs
- eq, hash, get_event_stat, read_with_timeout in event.rs
- kcall in debug.rs
- __syscall_instruction_end in syscall.rs
The AddrSpaceSwitchReadGuard was acquired in select_next_context() and stored
in percpu.new_addrsp_guard, but NEVER consumed/released. This held a read lock
on the address space forever, causing usermode_bootstrap's acquire_write() to
deadlock — the bootstrap process could never start.
The guard is redundant: CONTEXT_SWITCH_LOCK + context write guards in
SwitchResultInner already protect the address space during the switch.
Matching upstream commit ca67b1da which has no AddrSpaceSwitchReadGuard.
AddrSpace handles from dup(b'empty') and dup(b'exclusive') use the write
syscall for mmap commands, not seekable I/O. The kwriteoff handler returns
the mapped address (not bytes written), which sys_write would incorrectly
add to the file offset when POSITIONED is set. This corrupted the offset,
causing the next write to fail with EINVAL (offset_word skip exhausted
the buffer). Only mmap-min-addr needs POSITIONED for actual read/write.
The previous default only accepted u64::MAX as 'stream write' offset, but
sys_write/sys_read pass offset=0 for non-positioned I/O. This caused
ESPIPE on all writes to non-positioned FDs (Debug/stdout). Now both
u64::MAX and 0 are accepted as 'no offset' for the default implementation.
Schemes that override kwriteoff (AddrSpace) still handle offset=0 correctly.
The default kreadoff/kwriteoff implementations in scheme/mod.rs require
offset=u64::MAX for stream (non-positioned) I/O. Passing offset=0 causes
ESPIPE (Illegal seek), which breaks ALL writes to non-positioned FDs
including Debug/stdout. This was the root cause of the procmgr child
appearing to 'panic' — its log output silently failed with ESPIPE.
The addr_space_lock.mmap() result must be used or explicitly ignored.
Use let _ = ... to discard it — if mmap fails here, the process
crash will be more informative than a Result warning.
- syscall/futex.rs: scope the context write guard so futexes.swap_remove
can borrow mutably after the guard drops
- syscall/process.rs: add missing 'shared' arg to Grant::zeroed
The bump allocator previously had no way to track which frames are
free for reuse. Add a FreeNode struct that records (next, count,
phys) for freed regions, enabling frame recycling after initial
identity-mapping setup is complete.
The .map_err().?() pattern doesn't work in a function returning (),
because ? requires the enclosing function to return Result. Replace
with plain .expect() (these are bootstrap initialization failures —
if mmap fails here, the kernel cannot continue).
The initial bootstrap init (started directly by the kernel via
usermode_bootstrap) had RSP = 0 from InterruptStack::init(), which
does NOT set RSP. This caused any push/call in the binary to fault
on address 0.
The Rust panic handler caught the resulting page fault and generated
ud2 — visible as 'Invalid opcode fault' at a low RIP before main()
ever runs. This was the root cause of the init crash.
Fix:
- Map 8 pages (32 KiB) of user stack just above the initfs image
- Set RSP to the top of the stack
- Add debug log showing the mapped region
The stack is intentionally small (32 KiB) — enough for Rust _start
to run but small enough to detect stack overflow immediately. Once
init calls fexec_impl to spawn the real init, the real init gets its
own full 8 MB stack via the redox-rt exec path.
- rmm/src/arch/emulate.rs: replace unimplemented!() with actual TLB
invalidation (remove the address from the map). Without this the
emulate arch silently fails to invalidate TLB entries during
context switches, which can cause stale mappings.
- src/syscall/futex.rs: remove completed TODO marker for FUTEX_REQUEUE
(work done in a prior commit).
The sys_mkns and sys_setns functions added in 48fc2f1c reference
UserSliceRo and FileHandle but the imports were not updated, causing
the build to fail with 'cannot find type' errors. This commit adds
the missing imports.
Adds proper kernel-level namespace syscall handling:
- SYS_MKNS: dups the current namespace fd with the caller-supplied
buffer (NsDup::ForkNs + scheme names). The dup is handled by the
bootstrap's userspace namespace manager (initnsmgr) which creates
the new namespace and returns the fd.
- SYS_SETNS: switches the calling context's ns_fd to the given fd.
This makes the new namespace the default for all subsequent scheme
lookups by this context.
- Context gains an ns_fd: Option<usize> field, initialized to None,
meaning "use the global namespace" (default).
- Both syscalls are wired into the dispatch table in syscall/mod.rs.
Per local/docs/LOCAL-FORK-SUPREMACY-POLICY.md: the kernel fork must
be complete. Previously SYS_SETNS was undefined and SYS_MKNS returned
ENOSYS; init's setrens() panicked on bare metal.
sys_read and sys_write passed u64::MAX as the offset for non-positioned
file descriptors. Many scheme handlers (AddrSpace, proc:Start, etc.)
check offset != 0 or offset % word_size != 0, causing EINVAL when
receiving u64::MAX. Passing 0 instead fixes all non-positioned read/write
operations across all scheme handlers uniformly.
This replaces the per-handler u64::MAX workarounds with a root-cause fix.
sys_write passes u64::MAX as offset for non-positioned file descriptors.
ContextHandle::Start used an inline 'offset != 0' check which rejected
u64::MAX, causing EINVAL when bootstrap called start_fd.write(&[0]) during
fork_inner(). Replaced with require_zero_offset() which accepts both 0 and
u64::MAX (fixed in the previous commit for the same class of bug).
sys_write passes u64::MAX as the offset sentinel for non-positioned file
descriptors. The proc scheme's require_zero_offset rejected this value,
causing bootstrap's tcb_activate to crash with EINVAL when writing
EnvRegisters (fsbase) back to the regs/env handle.
This was the root cause of the 'Invalid opcode fault' during bootstrap
(PID 0) that prevented redbear-mini from reaching a login prompt.
Previously: PfError::Oom during page fault recovery caused the
entire kernel to panic via todo!("oom"). This means a single
OOM allocation in a user process would crash the whole OS.
Now: OOM is logged as a warning, the faulting process receives
SIGSEGV (same path as other non-fatal page faults), and the
kernel continues. The process may be killed, but the system
stays up. This is consistent with how Linux handles OOM during
page fault handling: send SIGSEGV/SIGKILL, don't panic.