Skip to content

Commit ba9b77f

Browse files
committed
feat(lcrust-stdlib): Lilium support in rust stdlib
1 parent ca6f1ad commit ba9b77f

File tree

13 files changed

+352
-33
lines changed

13 files changed

+352
-33
lines changed

lccc/targets/rust/x86_64-lilium.md

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
# TCR: x86_64-*-lilium-std
2+
3+
## Basic Properties
4+
5+
This target is for the Lilium OS using the System V ABI on x86_64. Pointers are 8 bytes in size, the target supports `std`, and unwinding is supported.
6+
7+
The target supports any value for the vendor field. The standard vendor is `pc`, and all other vendors are aliases that differ only in the `target_vendor` cfg which is set to the value of this field.
8+
9+
The standard cfg values are
10+
```rust
11+
target_abi=""
12+
target_arch="x86_64"
13+
target_endian="little"
14+
target_env="std"
15+
target_family="lilium"
16+
target_has_atomic
17+
target_has_atomic="16"
18+
target_has_atomic="32"
19+
target_has_atomic="64"
20+
target_has_atomic="8"
21+
target_has_atomic="ptr"
22+
target_has_atomic_equal_alignment="16"
23+
target_has_atomic_equal_alignment="32"
24+
target_has_atomic_equal_alignment="64"
25+
target_has_atomic_equal_alignment="8"
26+
target_has_atomic_equal_alignment="ptr"
27+
target_has_atomic_load_store
28+
target_has_atomic_load_store="16"
29+
target_has_atomic_load_store="32"
30+
target_has_atomic_load_store="64"
31+
target_has_atomic_load_store="8"
32+
target_has_atomic_load_store="ptr"
33+
target_os="lilium"
34+
target_pointer_width="64"
35+
target_thread_local
36+
```
37+
38+
The type aliases used for `core::ffi` types are:
39+
```rust
40+
pub type c_char = u8;
41+
pub type c_double = f64;
42+
pub type c_float = f32;
43+
pub type c_int = i32;
44+
pub type c_long = i64;
45+
pub type c_longlong = i64;
46+
pub type c_schar = i8;
47+
pub type c_short = i16;
48+
pub type c_uchar = u8;
49+
pub type c_uint = u32;
50+
pub type c_ulong = u64;
51+
pub type c_ulonglong = u64;
52+
pub type c_ushort = u16;
53+
pub type c_ptrdiff_t = isize;
54+
pub type c_size_t = usize;
55+
pub type c_ssize_t = isize;
56+
```
57+
58+
## Language Feature Interactions
59+
60+
The following special `extern` ABIs are supported. Each ABI supports a `-unwind` variant:
61+
* `extern "win64"`
62+
* `extern "sysv64"`
63+
* `extern "vectorcall"`
64+
* `extern "efiabi"`
65+
66+
The `extern "C"` and `extern "system"` ABIs match `extern "sysv64"`.
67+
68+
All x86_64 standard target features are supported. The default target features are:
69+
* `sse`
70+
* `sse2`
71+
* `fxsr`
72+
73+
## Target-specific Modules
74+
75+
The standard `core::arch::x86_64` module is defined.
76+
77+
The `std::ffi::OsStr` type is guaranteed to store valid UTF-8. Invalid UTF-8 in strings is rejected by kernel interfaces, and is not produced by any kernel interface that returns succesfully.
78+
79+
A new `std::os::lilium` module is defined, to support OS-Specific Facilities on Lilium. The initial API Surface is:
80+
```rust
81+
// std::os::lilium
82+
83+
pub trait OsStrExt : Sealed{
84+
/// Infallibly converts from an [`OsStr`] to a [`str`]
85+
fn as_str(&self) -> &str;
86+
/// Infallibly converts from a mutable [`OsStr`] to a [`str`]
87+
fn as_str_mut(&mut self) -> &mut str;
88+
/// Infallibly converts from a [`str`] to an [`OsStr`]
89+
fn from_str(st: &str) -> &Self;
90+
/// Infallibly converts from a mutable [`str`] to an [`OsStr`]
91+
fn from_str_mut(st: &mut str) -> &mut Self;
92+
}
93+
94+
impl OsStrExt for std::ffi::OsStr;
95+
96+
pub trait OsStringExt : Sealed{
97+
/// Infallibly converts from an [`OsString`] to a [`String`]
98+
fn into_string(self) -> String;
99+
}
100+
101+
impl OsStringExt for std::ffi::OsString;
102+
103+
#[repr(C,align(16))]
104+
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
105+
pub struct OsUuid{
106+
pub lo: u64,
107+
pub hi: u64,
108+
}
109+
110+
pub mod except{
111+
#[repr(C)]
112+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
113+
pub struct ExceptionStatusInfo {
114+
pub except_code: OsUuid,
115+
pub except_info: u64,
116+
pub except_reason: u64,
117+
}
118+
}
119+
120+
pub mod handle{
121+
/// Type representing a pointer to a handle, for doing raw operations on OS Primitives.
122+
#[repr(transparent)]
123+
pub struct RawHandlePtr<T>(*mut T);
124+
125+
pub trait HandleType: Sealed{}
126+
127+
pub struct AsRawHandle<T: HandleType>{
128+
fn as_raw_handle(&self) -> RawHandlePtr<T>;
129+
}
130+
131+
pub struct FromRawHandle<T: HandleType> {
132+
unsafe fn from_raw_handle(hdl: RawHandlePtr<T>) -> Self;
133+
}
134+
}
135+
136+
pub mod io{
137+
pub struct IOHandle(/*private fields*/);
138+
139+
impl HandleType for IOHandle{}
140+
141+
impl AsRawHandle<IOHandle> for std::fs::File;
142+
impl AsRawHandle<IOHandle> for std::net::TcpStream;
143+
impl AsRawHandle<IOHandle> for std::net::UdpSocket;
144+
impl AsRawHandle<IOHandle> for std::io::Stdin;
145+
impl AsRawHandle<IOHandle> for std::io::StdinLock;
146+
impl AsRawHandle<IOHandle> for std::io::Stderr;
147+
impl AsRawHandle<IOHandle> for std::io::StderrLock;
148+
impl AsRawHandle<IOHandle> for std::io::Stdout;
149+
impl AsRawHandle<IOHandle> for std::io::StdoutLock;
150+
impl AsRawHandle<IOHandle> for std::process::ChildStdin;
151+
impl AsRawHandle<IOHandle> for std::process::ChildStdout;
152+
impl AsRawHandle<IOHandle> for std::process::ChildStderr;
153+
154+
impl FromRawHandle<IOHandle> for std::process::Stdio;
155+
156+
}
157+
158+
pub mod fs{
159+
pub struct FileHandle(/*private fields*/);
160+
161+
impl HandleType for FileHandle;
162+
163+
impl AsRawHandle<FileHandle> for std::fs::File;
164+
impl FromRawHandle<FileHandle> for std::fs::File;
165+
impl AsRawHandle<FileHandle> for std::fs::ReadDir;
166+
impl FromRawHandle<FileHandle> for std::fs::ReadDir{
167+
/// Constructs a new [`ReadDir`] from the specified handle.
168+
///
169+
/// ## Note
170+
/// If the `hdl` originally came from a [`ReadDir`], this method will return a fresh iterator that will iterate from the beginning
171+
unsafe fn from_raw_handle(hdl: RawHandlePtr<FileHandle>) -> Self;
172+
}
173+
174+
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> Result<()>;
175+
176+
/// Creates a new weak link
177+
///
178+
/// Weak Links are features of the Lilium Filesystem, allowing a weak reference to a filesystem object.
179+
/// They act similiarily to hard links (cannot cross filesystems), but does not keep a hold on the object data (or most metadata).
180+
///
181+
/// Weak links are generally not needed for most use cases.
182+
pub fn weak_link<P: AsRef<Path>, Q: AsRef<Path>>(original:P, link: Q) -> Result<()>;
183+
}
184+
185+
pub mod thread{
186+
pub struct ThreadHandle(/*private fields*/);
187+
188+
impl HandleType for ThreadHandle;
189+
impl AsRawHandle<ThreadHandle> for std::thread::Thread;
190+
impl<T> AsRawHandle<ThreadHandle> for std::thread::JoinHandle<T>;
191+
impl<'scope, T> AsRawHandle<ThreadHandle> for std::thread::ScopedJoinHandle<'scope, T>;
192+
}
193+
194+
pub mod process{
195+
pub struct ProcessHandle(/*private fields*/);
196+
impl HandleType for ProcessHandle{}
197+
198+
impl AsRawHandle<ProcessHandle> for std::process::Child;
199+
200+
impl FromRawHandle<ProcessHandle> for std::process::Child;
201+
202+
pub trait ExitStatusExt: Sealed{
203+
fn exception(&self) -> Option<ExceptionStatusInfo>;
204+
}
205+
206+
pub trait CommandExt : Sealed{
207+
fn arg0<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self;
208+
}
209+
}
210+
```
211+
212+
The `*Handle` types are opaque in the OS design, but are provided to allow third party crates that provide more comprehensive access to the Lilium SCI and USI to use or access standard types.
213+
214+
### Platform Specific Behaviour
215+
216+
The following documents the initial implementation correspondance of certain standard library functions to Lilium. None of these are guarantees
217+
218+
#### `std::io::copy`
219+
220+
This corresponds to calling the SCI function `IOCopyFull` if possible. Support is available based on implementation of the `AsRawHandle<IOHandle>` trait.
221+
If the stream being read is larger than `u64::MAX` bytes, and the stream being written to accepts the full size copy, returns `u64::MAX`
222+
223+
#### `std::fs::copy`
224+
225+
This corresponds to calling the SCI function `CopyObject` and specifying all streams are to gbe copied.
226+
The return value is the total size of all streams copied. Like `std::io::copy` if that value exceeds `u64::MAX` bytes, it returns `u64::MAX`.
227+
Note that if the stream copied carries out of band data (such as a device file) only the size of the actual stream (not the out-of-band data) is counted.
228+
For example, copying
229+
230+
#### `std::env::var`
231+
232+
This corresponds to calling the SCI function `GetEnvironmentVariable` with a null map (the default map for the process).
233+
234+
Due to the fact that the kernel will only yield (and permit) UTF-8 values for environment variables, this function will never return `std::env::VarError::NotUnicode`.
235+
236+
#### `std::io::IsTerminal`
237+
238+
The `is_terminal` method corresponds to querying the `Interactive` device feature on the device corresponding with the object's `IOHandle` (with flags set to 0). The device is obtained from the raw `IOHandle` as follows:
239+
* If the Handle is a `DeviceHandle`, uses it directly in `TestDeviceFeature`
240+
* If the Handle is a `FileHandle`, the `DeviceHandle` is obtained using `OpenDeviceFromFile`. If this succeeds, the result is used in `TestDeviceFeature`
241+
* If it's neither a `FileHandle` nor a `DeviceHandle` or it is a `FileHandle` and `OpenDeviceFromFile` fails, the function returns `false`.
242+
243+
The function returns `true` iff the call to `TestDeviceFeature` succeeds.
244+
245+
## Deviations
246+
247+
The Lilium OS is a non-Unix-like non-Windows OS - it does not support POSIX-like interfaces, or win32 api.
248+
It is thus incompatible with any platform-dependant code in existance today.
249+
The OS was specificially designed to not be constrained by POSIX, allowing more interesting design space to be explored in its design. The Rust design, and the implementation of the platform in lccc reflects this unique design, rather than trying to incompletely weld an interface compatible with most Rust programs (those using `std::os::unix`) onto an incompatible OS Interface.
250+
251+
A new value for `target_family`, `"lilium"` is used by the target. This reflects the uniqueness of its interface, and the possibility of other kernels matching the published standard kernel interface.
252+
253+
Like most targets supported by lccc, the `target_vendor` cfg is determined by the target name, rather than using a fixed value for all of the covered targets.

lcrust/libraries/lcrust_panic/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![cfg_attr(define_lang_items, lcrust_lang_items)]
44
#![lcrust::mangle_as = "std"]
55

6+
67
extern crate alloc;
78

89
pub(crate) mod rt;
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use crate:rt::panic::ForeignExceptionType;
1+
use crate::rt::panic::ForeignExceptionType;
22

33
pub struct ForeignPanic(pub(crate) *mut ForeignExceptionType);
44

5-
impl Drop for ForeignPanic{
6-
fn drop(&mut self){
7-
unsafe{crate::panicking::lcrust::dispose_foreign_exception(self.0)}
5+
impl Drop for ForeignPanic {
6+
fn drop(&mut self) {
7+
unsafe { crate::panicking::lcrust::dispose_foreign_exception(self.0) }
88
}
9-
}
9+
}

lcrust/libraries/lcrust_panic/src/panicking/lcrust.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ extern "lcrust-v0" {
99

1010
#[lcrust::mangled_import]
1111
#[lcrust::weak_import]
12-
pub static PANIC_ABORT_OVERRIDE: usize;
12+
pub static __abort_on_unwind: ();
1313
}
1414

1515
struct PrintOrDefault<'a, T>(Option<T>, &'a str);

lcrust/libraries/lcrust_panic/src/panicking/unwind.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,16 @@ pub fn begin_panic(info: &core::panic::PanicInfo) -> !{
134134
}else{
135135
panic_call_hook(info);
136136

137-
if count > 0 || ALWAYS_ABORT.get(Ordering::Relaxed) != 0{
137+
138+
139+
if count > 0 {
138140
unsafe{abort(info.location(), Some("Double-panic: Aborting process"))}
139141
}
140142

143+
if (&raw const crate::panicking::lcrust::__abort_on_unwind).is_null() || ALWAYS_ABORT.get(Ordering::Relaxed) != 0 {
144+
145+
}
146+
141147
// Per lcrust abi v0: `PanicInfo` constructed by the implementation shall have a location valid for the duration of the program
142148
let location = unsafe{core::mem::transmute(core::ptr::read(info.location().unwrap()))};
143149

@@ -157,7 +163,7 @@ pub fn begin_panic(info: &core::panic::PanicInfo) -> !{
157163

158164
unsafe{unwind_info.write(info)};
159165
let except = unsafe{unwind_info.offset(1).align_to(layout.align()).cast::<u8>};
160-
// The payload may not be `Copy`, but `begin`
166+
// The payload may not be `Copy`, but `begin_unwind` doesn't return anyways.
161167
unsafe{core::ptr::copy_nonoverlapping(info.payload() as *const dyn Any as *const u8, except, info.size())};
162168

163169
begin_unwind(unwind_info)

lcrust/libraries/libstd/src/hash.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub use core::hash::*;
2+
3+
mod rand;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use core::cell::RefCell;
2+
use core::hash::siphash::{SipHashState, SipHasher};
3+
4+
thread_local! {
5+
static RAND_GEN: RefCell<Option<(u64,SipHashState)>> = const {RefCell::new(None)};
6+
}
7+
8+
#[track_caller]
9+
pub(crate) fn gen_keys() -> (u64, u64) {
10+
RAND_GEN.with_borrow_mut(|x| {
11+
let (step, state) = x.get_or_insert_with(|| {
12+
let mut buf = [[0u8; 8], [0u8; 8], [0u8; 8]];
13+
14+
match crate::os::rand::seed_rand_buffer(buf.flatten_mut()) {
15+
Ok(()) => {
16+
let [a, b, k] = buf.map(u64::from_ne_bytes);
17+
18+
(k, SipHashState::new_with_keys(a, b))
19+
}
20+
Err(e) if e.kind() == crate::io::ErrorKind::Unsupported => (
21+
0xa5a5a5a5a5a5a5a5,
22+
SipHashState::new_with_keys(0x0123456789abcdef, 0xfecba9876543210),
23+
),
24+
Err(e) => panic!("{e}"),
25+
}
26+
});
27+
state.update_and_round::<2>(*step);
28+
let k0 = state.update_and_final::<2>();
29+
let k1 = state.update_and_final::<2>();
30+
state.update_and_round::<2>(*step);
31+
32+
(k0, k1)
33+
})
34+
}
35+
36+
pub struct RandomState(SipHasher<2, 4>);

lcrust/libraries/libstd/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ pub mod prelude;
3131
#[prelude_import]
3232
pub use std::prelude::v1::*;
3333

34+
pub mod hash;
35+
3436
pub mod os;
3537

3638
pub mod process;

lcrust/libraries/libstd/src/os.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1-
21
pub(crate) mod rand;
2+
3+
#[cfg(feature = "lilium")]
4+
pub mod lilium;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![unstable(feature = "lccc_os_lilium")]
2+
3+
#[repr(C, align(16))]
4+
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
5+
pub struct OsUuid {
6+
pub lo: u64,
7+
pub hi: u64,
8+
}

0 commit comments

Comments
 (0)