Add O_NONBLOCK handling to UserInner::call_inner for Opcode::OpenAt.
When the caller passes O_NONBLOCK in the open flags and the
provider has not yet responded after one scheduling quantum,
return EAGAIN immediately instead of blocking the caller.
This implements Design B from local/docs/INITNSMGR-CONCURRENCY-DESIGN.md,
enabling the initnsmgr to use O_NONBLOCK on openat to avoid
head-of-line blocking on slow provider daemons.
The mechanism:
1. Detect O_NONBLOCK + OpenAt from sqe.args[3] (flags).
2. For nonblock open, skip the block() call - stay Runnable.
3. Send the SQE and trigger the provider event (same as blocking).
4. Do one context::switch() to give the provider a chance to run
and respond. If the provider responds within that quantum,
return Ok(result).
5. If the provider has not responded, cancel the request via
the existing cancellation path (Cancel SQE + cleanup of
callee_responsible PageSpan and fds), and return EAGAIN.
The caller treats EAGAIN as 'try again later' and parks the
request; initnsmgr (in local/sources/base) implements the
event-driven deferred retry pattern that uses this signal.
Preserves all existing behavior for non-open opcodes and for
open without O_NONBLOCK. Round-robin scheduler means the provider
gets a fair chance to run after the caller yields.
Per local/AGENTS.md:
- No new branches (work on submodule/kernel)
- No stubs, no todo!/unimplemented!
- Cross-module change: kernel + base (committed separately)
Closes v5.3 Design B (kernel side). Base side is the companion
commit on submodule/base.
- acpi.rs: LPI_MWAIT_HINT/LPI_MWAIT_HINT_SET atomics + set/get
accessors; AcpiVerb::SetLpiHint handler reads the 4-byte LE
payload and stores the firmware-recommended MWAIT hint.
- interrupt/mod.rs idle_loop(): prefer the LPIT entry_trigger hint
(set by acpid) for mwait_loop(); fall back to CPUID leaf-5 max
substate when no LPIT hint is available (no LPIT table, or
pre-acpid boot).
This is the full Modern Standby integration: the CPU now enters the
firmware-optimal deepest LPI state during s2idle, not merely the
CPUID-reported deepest state.
Two fixes required for the merged tree to compile (repo cook kernel
--force-rebuild passes with them):
- event.rs: drop EAGAIN/EINTR from the top-level syscall import — the
crate::syscall::error import further down already brings both names
into scope (E0252 duplicate-definition).
- scheme/proc.rs: drop UnmapVec from the context::memory import — the
fork deleted that machinery from context/memory.rs (E0432
unresolved import); the type's only use site is the import itself.
The previous backport rewrote the whole dup2 (duplicate-first, remove/insert)
which perturbed ordinary dup2 used by process-spawn stdio setup and could
break exec (ENOENT). Restrict the new behavior to the self-dup-with-buffer
case (dup2(ft, ft, 'refresh')); the normal fd!=new_fd path is byte-for-byte
the original.
Backport of upstream kernel 37ffa2e2. The proc scheme's filetable dup2
only accepted 'copy'; a 'refresh' buffer now re-materializes the
filetable's descriptor list in place. dup2() no longer short-circuits a
self-dup (fd==new_fd) when a buffer is supplied, and duplicates before
replacing the target descriptor. Together with relibc's
FdTbl::from_binary_fd issuing dup2(ft, ft, 'refresh'), an exec'd process
(e.g. a login shell) rebuilds its fd table from the CURRENT parent state
instead of a stale snapshot -- fixing interactive shells whose pty-slave
stdin returned nothing while writes to fd 1/2 worked. fs.rs dup2 adapted
to the local duplicate_file(cloexec) signature.
Device memory registration currently stops when /soc or its ranges
property is absent and only considers direct /soc children. Some
devicetrees place the interrupt controller at the root and the
selected UART below nested buses.
Register the exact translated range of the diagnostic UART and the
register ranges of root interrupt controllers. Use the hierarchical
translator when initializing GICv2 and GICv3 registers.
This keeps the translation change limited to the selected console
and interrupt controllers while preserving the existing behavior for
other devices.
Signed-off-by: Luiz Fernando Becher de Araujo <luiz.becher.araujo@gmail.com>
The existing MMIO helper only translates addresses through the /soc
ranges property. This does not handle devices below nested buses,
such as the UART in the devicetree used by the Meson boards.
Add an address translator that walks each ancestor bus and applies
its ranges property until reaching the CPU address space. Treat
empty ranges as an identity mapping and reject regions that cross a
range boundary.
Keep the existing helper’s behavior unchanged for other devices to
limit the scope of the behavioral change.
Add tests for nested buses, empty ranges, exact range boundaries,
and regions crossing a boundary.
Signed-off-by: Luiz Fernando Becher de Araujo <luiz.becher.araujo@gmail.com>
The debug scheme's fevent always returned empty, relying solely on the
edge-triggered debug_notify(). A reader that registers with an event queue after
input has already arrived (fbcond's serial console) would miss it. Report
readable when the input queue is non-empty.
The event scheme (scheme:event, Redox's epoll backend) implemented
open/read/write/fpath/fevent but NOT dup, so dup() of an event-queue fd
fell through to the default kdup and returned EINVAL. tokio/mio's I/O
reactor construction does exactly this: Poll::new() opens the queue, then
registry.try_clone() dups it (registrations go through the clone, polling
through the original). The EINVAL made every tokio Runtime::build() with an
I/O driver fail — killing all zbus daemons (sessiond/polkit/udisks/upower)
and the brush login shell ("failed to create tokio runtime: Invalid
argument"), which is why text login never worked.
Implement kdup: duping an event-queue fd returns a second handle to the
SAME queue (shared registrations + delivered events, as epoll requires),
reference-counted on EventQueue so the queue survives until the last fd
closes. eventfd counters are not dup-able (unused: mio's Redox waker uses a
pipe). Verified: cargo check --target x86_64-unknown-kernel passes.
The MSR R/W scheme lets root request an arbitrary wrmsr/rdmsr on any CPU
(used by cpufreqd/thermald). A bad MSR number or reserved-bit value raises
#GP; on the raw wrmsr/rdmsr that is a kernel-mode fault that panics the
whole machine at exit_this_context (unreachable!) — i.e. root userspace can
crash the kernel. Observed on KVM: cpufreqd writing a legacy P-state MSR
(#GP in the msr IPI handler) halted the boot right before the console/login.
Add wrmsr_safe/rdmsr_safe (arch/x86_64): the faulting instruction sits in a
__wrmsr_safe_start/end (resp. rdmsr) region, and the #GP handler recognises a
fault inside those bounds and returns an error via recover_and_efault — the
same fault-recovery mechanism already used for usercopy page faults. The MSR
scheme (local path) and the cross-CPU msr IPI handler now use these and
surface EIO to the caller (IPI failures propagated via a new MsrMailbox
faulted flag) instead of panicking. 32-bit x86 keeps the raw path (untested).
Two fixes on the clean base (all boot-investigation diagnostics removed):
1. ProcScheme::kcall now accepts FileTableVerb::Resize on filetable
handles as a no-op instead of returning EBADF. After the upstream
'move fd allocation into userspace' relibc refactor, FILETABLE
pre-syncs its size via a Resize call before growing; the kernel
already grows posix_fdtbl on insert. Returning EBADF broke add_posix
once a process's fd table grew (notably the bootstrap process manager
proxying child thread ops), making the child's regs/env dup fail and
its ld.so panic, crashing initfs daemons (randd) at boot.
2. ProcUptime uses integer arithmetic instead of f64 (the kernel is
built with +soft-float; f64 in format!() breaks the build).
* Remove lots of unsafe code by initialising in the closure passed to
`call_once`
* Remove `NUMBER_OF_DOMAINS` as size can always be inferred from the
hashmap's len