trona_win32 Overview
|
The Rust files under This page documents both the existing Rust source (so future contributors know what is there) and the actual built artifacts (so today’s contributors do not get confused about what runs at runtime). |
What is actually built
The single Win32-related artifact in the SaltyOS build is kernel32.dll:
| Source | Output |
|---|---|
|
|
kernel32_pe.c is freestanding C: it has no libc, makes its SaltyOS syscalls through inline assembly, and uses the same IpcContext / TronaMsg layout that libtrona.so uses (the structs are defined inline at the top of the file because the C file cannot include Rust headers).
kernel32.dll PE Stub documents the C code in detail.
The Rust source — design intent
The 914 lines of Rust under lib/trona/win32/ declare a trona_win32 crate that would be built and linked alongside libtrona.so (or as a separate libtrona_win32.so) if any meson target referenced it.
None do.
The crate is currently dead source — it compiles cleanly when copied into a sandbox build, but no automated build invokes it.
This is documented here for two reasons:
-
The doc-comments in the Rust files are the most thorough description of the intended Win32 architecture in the tree. Anyone planning to extend the Win32 personality should read them before writing new code.
-
The same
kernel32_pe.ccode that gets built has accreted over time and partially duplicates what the Rust crate would provide. A future contributor consolidating the two needs to know which file owns which feature.
Below is the structure of the Rust crate as it exists today.
lib/trona/win32/lib.rs
//! trona_win32 -- Win32 API compatibility layer for SaltyOS
//!
//! Provides minimal Win32 console API for PE binaries running on SaltyOS.
//! Functions are exported with `#[unsafe(no_mangle)]` so PE import tables
//! can reference them directly.
#![no_std]
#![no_main]
#![feature(linkage)]
extern crate trona;
pub mod console;
pub mod crt;
pub mod error;
pub mod handle;
pub mod protocol;
pub mod paths;
pub mod process;
pub use handle::HANDLE;
pub use protocol::*;
It declares the crate as extern crate trona, which would link it against libtrona.so if it were built.
The protocol module is mostly empty (3 lines) and exists as a placeholder for re-exporting the Win32 protocol labels from uapi/protocol/win32.rs.
handle.rs — the handle table
pub type HANDLE = isize;
#[repr(u32)]
pub enum HandleKind {
Free = 0,
VfsFd = 1,
CapSlot = 2,
ServerObject = 3,
}
pub struct HandleEntry {
pub kind: HandleKind,
pub vfs_fd: i32,
pub cap_slot: u64,
}
The handle table is a fixed-size array of 64 slots.
HANDLE values are encoded as (slot * 4) + 4, which is consistent with Windows pseudo-handles like STD_INPUT_HANDLE = -10 being distinct from any real slot index.
init_handle_table() would map slot 0 to VFS fd 0 (stdin), slot 1 to fd 1 (stdout), and slot 2 to fd 2 (stderr) — so GetStdHandle(STD_INPUT_HANDLE) resolves to slot 0 and ultimately to VFS fd 0.
alloc_vfs_fd(fd) would scan from slot 3 onwards for a free slot, allocate it, and return the encoded HANDLE.
None of this code runs today — kernel32_pe.c has its own minimal handle handling that is not derived from this Rust file.
error.rs — error mapping
pub fn trona_to_win32_error(trona_err: u64) -> u32 {
match trona_err {
TRONA_OK => ERROR_SUCCESS,
TRONA_INVALID_CAPABILITY => ERROR_INVALID_HANDLE,
TRONA_INVALID_OPERATION => ERROR_INVALID_FUNCTION,
TRONA_INSUFFICIENT_RIGHTS => ERROR_ACCESS_DENIED,
TRONA_INVALID_ARGUMENT => ERROR_INVALID_PARAMETER,
TRONA_OUT_OF_MEMORY => ERROR_NOT_ENOUGH_MEMORY,
TRONA_NOT_FOUND => ERROR_FILE_NOT_FOUND,
TRONA_BUSY => ERROR_BUSY,
TRONA_ALREADY_EXISTS => ERROR_ALREADY_EXISTS,
_ => ERROR_INVALID_FUNCTION,
}
}
The mapping table from TRONA_* error codes to Win32 ERROR_* codes.
GetLastError() and SetLastError(err) would read and write a thread-local last-error value.
kernel32_pe.c reimplements both — its GetLastError reads a __thread DWORD last_error (via the file’s local TLS), and the conversion table is duplicated inline at the function call sites.
console.rs — VFS-direct console I/O
//! Console I/O (WriteConsoleA/W, ReadConsoleA) delegates to the win32_csrss
//! server via IPC, which in turn forwards to the console server.
Despite the doc comment, the actual console.rs Rust source bypasses csrss and writes directly to VFS file descriptors.
The doc comment was written for an earlier intended architecture in which csrss owned the console data path; the implementation has since moved console data to the same VFS code path that POSIX uses.
The functions defined are:
-
WriteConsoleA(handle, buf, len, written_out, reserved)— chunksbufinto 144-byte pieces and sendsVFS_WRITE(3) to the VFS endpoint. -
WriteConsoleW(handle, buf, len, written_out, reserved)— Unicode variant; converts from UTF-16 LE to UTF-8 inline as it writes to VFS. -
ReadConsoleA(handle, buf, len, read_out, control_chars)— sendsVFS_READ(2) to the VFS endpoint. -
GetConsoleMode(handle, mode_out)— returns the constantDEFAULT_INPUT_MODE = 0x0007for input handles andDEFAULT_OUTPUT_MODE = 0x0003for output handles. Does not consult any external state. -
SetConsoleMode(handle, mode)— accepts the call and returns success without storing the mode anywhere.
|
The |
process.rs — process operations
Three functions:
-
ExitProcess(exit_code)— sends a best-effortW32_CLIENT_EXIT(0x106, non-blocking) to win32_csrss to notify it the client is exiting, then sendsPM_EXIT(blocking) to procmgr. Never returns. -
GetCurrentProcess()— returns the pseudo-handle-1, matching Windows. -
GetCurrentProcessId()— sendsPM_GETPIDto procmgr and returns the result.
crt.rs — CRT-style initialization
crt.rs defines a static __win32srv_ep slot that would cache the win32_csrss endpoint capability after a one-time W32_CLIENT_REGISTER (0x105) round-trip.
The setup function would also wire up the basic Win32 environment block (current directory, environment strings, command line) before calling the user’s main.
This is the only place in the trona_win32 Rust source that actually uses one of the W32_* protocol labels (W32_CLIENT_REGISTER).
Plus the use in process.rs of W32_CLIENT_EXIT, those two are the only W32_* labels currently exercised by any code in the tree.
paths.rs
paths.rs is 7 lines — basically a placeholder for path canonicalization (Windows backslash → forward slash, drive letter handling, \\?\ prefix stripping).
None of the code is wired in.
Why is this code unbuilt?
The most likely explanation is iterative development: the Rust crate was scaffolded as a planned design but the immediate goal — getting a single C-language kernel32.dll running so a basic PE binary could spawn — was easier to satisfy by writing a self-contained kernel32_pe.c from scratch.
Once that worked, no one went back to wire up the Rust crate.
A future cleanup pass would either:
-
Build the Rust crate. Add a
trona_win32custom_target tolib/trona/meson.build, link it into a separatelibtrona_win32.so, and rewritekernel32_pe.cso its functions delegate to the Rust crate via function calls. This would makekernel32.dlla thin C shim over Rust, matching howlibc.sois a thin C shim over Rust inbasaltc. -
Delete the Rust crate. Remove
lib/trona/win32/*.rsentirely and accept that all Win32 functionality lives inkernel32_pe.c.
Either decision would resolve the current "two parallel implementations, one of which is dead code" situation. Until that happens, the Rust files are reference material for design intent, not active code.
What does run today
For the actual runtime behavior — WriteConsoleA actually writing to the serial console, CreateFileA opening files, ExitProcess actually killing a PE binary — the answer is always kernel32_pe.c.
Every Windows API a PE binary on SaltyOS calls is implemented in that single C file, and the implementation talks directly to substrate endpoints via inline syscalls.
kernel32.dll PE Stub is the page that documents what kernel32_pe.c actually exports and how each function works.
Related pages
-
kernel32.dll PE Stub — the actual built artifact and its API surface.
-
Win32 Protocol Labels — the seven
W32*labels defined inuapi/protocol/win32.rs. -
PE Dynamic Linker — the rtld that loads PE binaries and resolves their
kernel32.dllimports.