Skip to content

Define the userspace syscall ABI and errno values once #962

Description

@forkwright

Finding

Thumos's syscall ABI is declared in the kernel and then hand-repeated in every direct-rustc userspace program. The same pattern exists inside the kernel for errno numbers: fd, futex, socket, syscall, IPC, pipe, time, and other modules independently restate Linux-compatible negative values.

The direct-rustc build choice is deliberate and can remain. It does not require every program to own its own inline-assembly wrapper or numeric constants; a generated/included ABI module can preserve the one-file program model while deriving from one manifest.

Verified against origin/main b2c706b0dd6d63c895b4adc6aa4ecccaf9d9dfab.

Evidence

Syscall numbers and veneers

  • crates/thumos/src/syscall.rs:79-106 begins the canonical #[repr(u32)] Syscall enum: Exit = 0, Write = 1, Yield = 2, Getpid = 3, through the rest of the grouped ABI.
  • crates/thumos/init/init.rs:19-75 separately embeds the same numbers in inline assembly (r7 = 1 for Write, r7 = 70 for clock_gettime, r7 = 7 for Sleep).
  • crates/thumos/init/shell.rs:16-47 repeats the Write veneer and hardcodes r7 = 0 for Exit.
  • Exact-ref source inventory finds the same sys_write veneer copied into five programs: init.rs, shell.rs, crasher.rs, metaxu_probe.rs, and init2.rs. Four independently define sys_exit; init/probe paths repeat other syscall wrappers.
  • crates/thumos/build.rs:144-165 explains that these programs are compiled directly with rustc rather than as a nested Cargo crate. They are still compiled from multiple source files and can all include or receive one generated ABI source.

Errno values

  • crates/thumos/src/fd.rs:39-56 defines a broad local Linux-ARM errno table including EBADF, ENOENT, EMFILE, ENFILE, EINVAL, and EFAULT.
  • crates/thumos/src/futex.rs:28-43 restates EAGAIN, ENOMEM, EINVAL, and EFAULT.
  • crates/thumos/src/socket.rs:66-77 restates EAGAIN and ENOMEM beside its socket-specific values.
  • crates/thumos/src/syscall.rs:53-74 restates EFAULT, EPERM, ESRCH, and EAGAIN at the dispatch layer.
  • Exact source enumeration on this revision finds EAGAIN declared in four kernel modules, EFAULT in four, EINVAL in five, and ENOMEM in three. Additional local EPERM/ESRCH declarations use the same convention, with IPC also carrying a signed representation.

No current issue owns ABI/errno single-sourcing. #474 established the minimal userspace runtime and thin syscall shim as a goal, but it does not enforce one source across the programs now present. Recent uaccess work (#890/#952) changes syscall mechanics, not numeric ownership.

Why this matters

A syscall number or errno value is an ABI fact. A new syscall, renumbering, compatibility alias, signedness decision, or return-convention fix must currently be copied into whichever userspace programs use it, and nothing proves the program's r7 literal still names the kernel variant its comment claims.

The risk grows with every QEMU witness binary: they are intended to prove kernel behavior, but a stale veneer can invoke a different syscall and produce a misleading witness. Kernel-local errno copies create the same failure one layer down—two subsystems can report different values for the same named POSIX condition while each looks individually conventional.

Desired correction

Define a small typed ABI source once. Viable shapes include a checked TOML/Rust manifest that generates both the kernel enum and a userspace include, or one no_std source module that direct-rustc programs include! without becoming workspace crates. Generate/centralize syscall numbers, argument/return convention documentation, and reusable veneers from that source.

Likewise, create one kernel errno module with a deliberate signed/unsigned representation and explicit conversion helpers. Subsystems import or re-export those constants; domain-specific errors remain local.

Done when:

  • Syscall discriminants and userspace r7 values derive from one source;
  • each direct-rustc program uses one shared syscall veneer module rather than copying sys_write/sys_exit;
  • kernel errno names have one numeric declaration each;
  • any required u32/i32 conversion is explicit and tested;
  • the build compiles every userspace program and asserts its ABI fingerprint matches the kernel's;
  • adding or changing a syscall in only one surface fails the build/check; and
  • the direct-rustc, no-nested-Cargo property described in build.rs remains intact unless independently reconsidered.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions