feat: Rust std target + ruststd tests; SYS_EXIT_GROUP; fix mkdir/create under missing parent
This commit is contained in:
1 parent
9e66c3b249
commit
e87bd358a6
20 files changed
+657
-97
No files matched your search
+74
-39
@@ -1,18 +1,31 @@
|
||||
# Rust on MontaukOS
|
||||
|
||||
Phase 1: `no_std` + `alloc` programs, cross-compiled from Linux with a
|
||||
stock nightly toolchain and a custom target spec. No compiler fork.
|
||||
Rust programs are built for `x86_64-unknown-montauk`, a built-in target of a
|
||||
forked rustc with a native `std` (`target_os = "montauk"`, not a Unix). Both
|
||||
`std` programs and `no_std` programs (on `montauk-rt`) are supported.
|
||||
|
||||
## Setup (once)
|
||||
|
||||
```bash
|
||||
# rustup, plus a nightly whose cargo the linked toolchain borrows
|
||||
curl --proto '=https' -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain none
|
||||
~/.cargo/bin/rustup toolchain install nightly --component rust-src
|
||||
~/.cargo/bin/rustup toolchain install nightly
|
||||
|
||||
# The fork: rust-lang/rust, branch `montauk` (bootstrap.toml is set up)
|
||||
cd ~/dev/mtk/rust
|
||||
./x build library --stage 1 --target x86_64-unknown-linux-gnu,x86_64-unknown-montauk
|
||||
rustup toolchain link montauk ~/dev/mtk/rust/build/host/stage1
|
||||
```
|
||||
|
||||
`rust-toolchain.toml` selects nightly + `rust-src` for this directory.
|
||||
`make programs` builds the Rust programs when that toolchain is present
|
||||
and prints a notice and skips them otherwise. It never downloads a toolchain
|
||||
The stage1 build takes about five minutes (it downloads CI LLVM). After
|
||||
changing only `library/`, rebuild with
|
||||
`./x build library --stage 1 --target x86_64-unknown-montauk` (seconds); the
|
||||
link stays valid.
|
||||
|
||||
`rust-toolchain.toml` selects the `montauk` toolchain for this directory. It
|
||||
has no cargo of its own; rustup falls back to the nightly's cargo.
|
||||
`make programs` builds the Rust programs when that toolchain is linked, and
|
||||
prints a notice and skips them otherwise. It never downloads a toolchain
|
||||
(`RUSTUP_AUTO_INSTALL=0`).
|
||||
|
||||
## Building
|
||||
@@ -26,45 +39,67 @@ Output: `target/x86_64-unknown-montauk/release/<name>`, installed as
|
||||
`programs/bin/os/<name>.elf`. Add new binaries to `RUST_PROGRAMS` in
|
||||
`programs/GNUmakefile` and to the workspace `members`.
|
||||
|
||||
The GCC driver links crt1/crti/crtbegin, the libc and libgcc from
|
||||
`toolchain/sysroot`, the same as ports. After changing `programs/lib/libc`,
|
||||
re-run `toolchain/build-montauk-toolchain.sh` so Rust programs pick it up.
|
||||
`make rust` relinks the programs when the sysroot libc or the toolchain's std
|
||||
is newer than the last build (cargo tracks neither).
|
||||
|
||||
## Layout
|
||||
|
||||
| Path | Purpose |
|
||||
|------|---------|
|
||||
| `x86_64-unknown-montauk.json` | Target spec: static non-PIE ET_EXEC, no red zone, local-exec TLS, panic=abort |
|
||||
| `.cargo/config.toml` | `-Zbuild-std=core,alloc`, linker = `x86_64-montauk-gcc` |
|
||||
| `montauk-rt/` | Runtime: syscalls, allocator, `print!`, argv, threads, futex `Mutex`, panic handler |
|
||||
| `rusthello/` | Smoke test (`rusthello`, `rusthello panic`, `rusthello panic-thread`) |
|
||||
| `.cargo/config.toml` | target = `x86_64-unknown-montauk`, linker = `x86_64-montauk-gcc` |
|
||||
| `rust-toolchain.toml` | the linked `montauk` toolchain |
|
||||
| `ruststd/` | `std` smoke test (`ruststd`, `ruststd net <host> [port]`) |
|
||||
| `montauk-rt/` | `no_std` runtime: syscalls, allocator, `print!`, argv, threads, futex `Mutex`, panic handler |
|
||||
| `rusthello/` | `no_std` smoke test (`rusthello`, `rusthello panic`, `rusthello panic-thread`, `rusthello fault-thread`) |
|
||||
|
||||
The GCC driver links crt1/crti/crtbegin, the libc and libgcc from
|
||||
`toolchain/sysroot`, the same as ports. After changing `programs/lib/libc`,
|
||||
re-run `toolchain/build-montauk-toolchain.sh` so Rust programs pick it up.
|
||||
## The std port (in the fork)
|
||||
|
||||
Syscall numbers and status codes are generated at build time by
|
||||
`montauk-rt/build.rs` from `programs/include/Api/Syscall.hpp` and
|
||||
`kernel/src/Common/StatusCodes.hpp`, so there is nothing to keep in sync by hand.
|
||||
| Fork path | What |
|
||||
|-----------|------|
|
||||
| `compiler/rustc_target/src/spec/base/montauk.rs`, `targets/x86_64_unknown_montauk.rs` | Target: static non-PIE ET_EXEC, no red zone, local-exec TLS, panic=abort, linker `x86_64-montauk-gcc` |
|
||||
| `library/std/src/sys/pal/montauk/` | Platform layer: `abi.rs` (syscall numbers, status codes, `SYSCALL` wrappers) |
|
||||
| `library/std/src/sys/*/montauk.rs` | alloc, env, fs, io errors, net, paths, process, random, stdio, futex, thread, time |
|
||||
| `library/std/src/os/montauk/` | `std::os::montauk::ffi::{OsStrExt, OsStringExt}` |
|
||||
|
||||
## Writing a program
|
||||
std calls the kernel directly. The libc is used only where C code in the same
|
||||
process must agree: the heap (`malloc`), the environment table (`setenv`),
|
||||
`exit` (atexit handlers) and line-buffered terminal input (`read(0)`). The
|
||||
syscall numbers in `abi.rs` are a hand-kept subset of `Api/Syscall.hpp`.
|
||||
|
||||
```rust
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
extern crate alloc;
|
||||
## Platform behaviour
|
||||
|
||||
montauk_rt::entry!(main);
|
||||
|
||||
fn main() -> i32 {
|
||||
montauk_rt::println!("hello from Rust");
|
||||
0
|
||||
}
|
||||
```
|
||||
|
||||
## Limits (Phase 1)
|
||||
|
||||
- No `std`. No `std::fs`, `std::net`, `std::process` or `std::thread`; use
|
||||
`montauk_rt` equivalents where they exist.
|
||||
- `panic = "abort"`. A panic on any thread prints the message and kills the
|
||||
whole process.
|
||||
- Thread stacks are owned by the `JoinHandle`. An unjoined thread leaks its stack.
|
||||
|
||||
Phase 2 (a forked rustc at `~/dev/mtk/rust` with a native `target_os =
|
||||
"montauk"` std) replaces the JSON spec with a built-in target.
|
||||
- Errors: the raw OS error of an `io::Error` is the kernel status code
|
||||
(positive, `montauk/statuscodes.h`); `ErrorKind` is mapped from it.
|
||||
- Paths: `0:/os/x.elf` is absolute; joining onto it replaces the base. Search
|
||||
paths (`PATH`, `env::split_paths`) are separated by `;`, not `:`.
|
||||
- Files: kernel handles have no position, so `File` keeps its own cursor.
|
||||
`OpenOptions::truncate` deletes and recreates the file; `set_len` can only
|
||||
grow a file. No links, permissions are read-only, `fsync` is a no-op.
|
||||
- Threads: stacks are mapped with `SYS_MMAP_ANON` (no guard page). A detached
|
||||
thread is reaped (joined, stack freed) by the next spawn or join, so its
|
||||
kernel slot does not leak. `available_parallelism()` is an error (the kernel
|
||||
does not report a CPU count). `std::process::exit` from any thread ends the
|
||||
process (libc `exit` -> `SYS_EXIT_GROUP`).
|
||||
- Sync: `Mutex`, `RwLock`, `Condvar`, `Once` and thread parking use the
|
||||
generic futex implementations over `SYS_FUTEX_WAIT`/`SYS_FUTEX_WAKE`.
|
||||
- `thread_local!` uses native `#[thread_local]` (PT_TLS); destructors run when
|
||||
a spawned thread exits (not on the main thread).
|
||||
- Time: `Instant` has 1 ms resolution; `SystemTime` comes from the wall clock
|
||||
(local time minus the timezone offset) with 1 s resolution.
|
||||
- Processes: `Command` supports arguments, environment, `current_dir` (entered
|
||||
in the parent for the duration of the spawn), `wait`, `try_wait` and `kill`.
|
||||
Only inherited stdio is supported; piped/null stdio and `output()` return
|
||||
`Unsupported`, because a redirected child's output stream disappears with
|
||||
the child. A bare program name is searched in `PATH`, else `0:/os` and
|
||||
`0:/games`; `.elf` may be omitted. `ExitStatus` shows abnormal ends as
|
||||
"terminated by signal N".
|
||||
- Net: IPv4 only. TCP connect/accept/read/write with read timeouts and
|
||||
non-blocking mode, UDP send_to/recv_from/connect, DNS via `SYS_RESOLVE`.
|
||||
No socket options, no `peek`, no `shutdown(Write)`, and accepted
|
||||
connections do not know the peer's address.
|
||||
- `panic = "abort"`: a panic on any thread prints the message and kills the
|
||||
whole process (exit status "signal 6").
|
||||
- `HashMap`'s random keys come from `SYS_GETRANDOM`, which is not a CSPRNG.
|
||||
Reference in new issue
Block a user