alnyan/yggdrasil: migrate sources to 1.94.0

This commit is contained in:
2026-03-27 16:37:57 +02:00
parent 4a4ef493e3
commit 1cd2fb99b4
86 changed files with 4573 additions and 19 deletions
@@ -42,3 +42,4 @@ pub(crate) mod windows_msvc;
pub(crate) mod windows_uwp_gnu;
pub(crate) mod windows_uwp_msvc;
pub(crate) mod xtensa;
pub(crate) mod yggdrasil;
@@ -0,0 +1,36 @@
use crate::spec::{
Cc, LinkOutputKind, LinkerFlavor, Lld, Os, RelocModel, StackProbeType, TargetOptions,
crt_objects,
};
pub(crate) fn opts() -> TargetOptions {
let pre_link_args = TargetOptions::link_args(
LinkerFlavor::Gnu(Cc::No, Lld::No),
&["-zmax-page-size=4096", "--dynamic-linker=/libexec/dyn-loader"],
);
TargetOptions {
os: Os::Yggdrasil,
linker: Some("rust-lld".into()),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
pre_link_objects: crt_objects::new(&[
(LinkOutputKind::DynamicNoPicExe, &["rust_entry0.o"]),
(LinkOutputKind::DynamicPicExe, &["rust_entry0.o"]),
(LinkOutputKind::StaticNoPicExe, &["rust_entry0.o"]),
(LinkOutputKind::StaticPicExe, &["rust_entry0.o"]),
]),
executables: true,
dynamic_linking: true,
position_independent_executables: true,
relocation_model: RelocModel::Pic,
pre_link_args,
stack_probes: StackProbeType::Inline,
max_atomic_width: Some(128),
eh_frame_header: false,
has_thread_local: true,
..Default::default()
}
}
+5
View File
@@ -1801,6 +1801,10 @@ supported_targets! {
("x86_64-lynx-lynxos178", x86_64_lynx_lynxos178),
("x86_64-pc-cygwin", x86_64_pc_cygwin),
("aarch64-unknown-yggdrasil", aarch64_unknown_yggdrasil),
("riscv64-unknown-yggdrasil", riscv64_unknown_yggdrasil),
("x86_64-unknown-yggdrasil", x86_64_unknown_yggdrasil),
}
/// Cow-Vec-Str: Cow<'static, [Cow<'static, str>]>
@@ -1994,6 +1998,7 @@ crate::target_spec_enum! {
Windows = "windows",
Xous = "xous",
Zkvm = "zkvm",
Yggdrasil = "yggdrasil",
Unknown = "unknown",
}
other_variant = Other;
@@ -0,0 +1,24 @@
use crate::spec::{Arch, PanicStrategy, Target, TargetMetadata};
pub(crate) fn target() -> Target {
let mut base = crate::spec::base::yggdrasil::opts();
base.disable_redzone = true;
base.panic_strategy = PanicStrategy::Abort;
base.features = "+fp-armv8,+neon,+strict-align,+v8a".into();
base.plt_by_default = true;
Target {
llvm_target: "aarch64-unknown-none".into(),
pointer_width: 64,
arch: Arch::AArch64,
data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
metadata: TargetMetadata {
description: Some("AArch64 yggdrasil".into()),
tier: Some(1),
host_tools: Some(true),
std: Some(true),
},
options: base,
}
}
@@ -0,0 +1,32 @@
use crate::spec::{Arch, CodeModel, PanicStrategy, Target, TargetMetadata, TargetOptions};
pub(crate) fn target() -> Target {
let base = crate::spec::base::yggdrasil::opts();
Target {
llvm_target: "riscv64".into(),
pointer_width: 64,
arch: Arch::RiscV64,
data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
metadata: TargetMetadata {
description: Some("RISC-V 64-bit yggdrasil".into()),
tier: Some(1),
host_tools: Some(false),
std: Some(true),
},
options: TargetOptions {
code_model: Some(CodeModel::Medium),
disable_redzone: true,
max_atomic_width: Some(64),
features: "+m,+a,+c,+zicsr,+zifencei".into(),
panic_strategy: PanicStrategy::Abort,
llvm_abiname: "lp64".into(),
plt_by_default: true,
..base // From android
// features: "+m,+a,+f,+d,+c,+b,+v,+zicsr,+zifencei".into(),
// supported_sanitizers: SanitizerSet::ADDRESS,
// supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
},
}
}
@@ -0,0 +1,25 @@
use crate::spec::{Arch, PanicStrategy, Target, TargetMetadata};
pub(crate) fn target() -> Target {
let mut base = crate::spec::base::yggdrasil::opts();
base.disable_redzone = true;
base.panic_strategy = PanicStrategy::Abort;
base.plt_by_default = true;
base.features = "+sse,+cx16".into();
Target {
llvm_target: "x86_64-unknown-linux-gnu".into(),
pointer_width: 64,
arch: Arch::X86_64,
data_layout:
"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(),
metadata: TargetMetadata {
description: Some("x86_64 yggdrasil".into()),
tier: Some(1),
host_tools: Some(true),
std: Some(true),
},
options: base,
}
}
+135
View File
@@ -2,6 +2,31 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "abi-generator"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
"thiserror",
]
[[package]]
name = "abi-lib"
version = "0.1.0"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "abi-serde"
version = "0.1.0"
dependencies = [
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "addr2line"
version = "0.25.1"
@@ -153,6 +178,22 @@ dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "libm"
version = "0.2.8"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "libyalloc"
version = "0.1.0"
dependencies = [
"libc",
"rustc-std-workspace-core",
"yggdrasil-rt",
]
[[package]]
name = "memchr"
version = "2.7.6"
@@ -213,6 +254,25 @@ dependencies = [
"unwind",
]
[[package]]
name = "prettyplease"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "proc_macro"
version = "0.0.0"
@@ -229,6 +289,15 @@ dependencies = [
"cc",
]
[[package]]
name = "quote"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
[[package]]
name = "r-efi"
version = "5.3.0"
@@ -331,6 +400,7 @@ dependencies = [
"hashbrown",
"hermit-abi",
"libc",
"libyalloc",
"miniz_oxide",
"moto-rt",
"object",
@@ -347,6 +417,7 @@ dependencies = [
"wasi 0.11.1+wasi-snapshot-preview1",
"wasi 0.14.4+wasi-0.2.4",
"windows-targets 0.0.0",
"yggdrasil-rt",
]
[[package]]
@@ -358,6 +429,17 @@ dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "syn"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "sysroot"
version = "0.0.0"
@@ -378,6 +460,32 @@ dependencies = [
"std",
]
[[package]]
name = "thiserror"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unwind"
version = "0.0.0"
@@ -520,3 +628,30 @@ dependencies = [
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "yggdrasil-abi"
version = "0.1.0"
dependencies = [
"abi-generator",
"abi-lib",
"abi-serde",
"prettyplease",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "yggdrasil-rt"
version = "0.1.0"
dependencies = [
"abi-generator",
"abi-lib",
"abi-serde",
"cc",
"libm",
"prettyplease",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
"yggdrasil-abi",
]
+38
View File
@@ -0,0 +1,38 @@
#![feature(no_core, lang_items, auto_traits)]
#![allow(internal_features)]
#![crate_type = "rlib"]
#![no_core]
#![no_main]
#[lang = "pointee_sized"]
pub trait PointeeSized {}
#[lang = "meta_sized"]
pub trait MetaSized: PointeeSized {}
#[lang = "sized"]
pub trait Sized: MetaSized {}
#[lang = "sync"]
auto trait Sync {}
#[lang = "copy"]
trait Copy {}
#[lang = "freeze"]
auto trait Freeze {}
impl ::Copy for usize {}
// #[lang = "drop_in_place"]
// #[inline]
// #[allow(unconditional_recursion)]
// pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
// drop_in_place(to_drop);
// }
#[unsafe(no_mangle)]
unsafe extern "C" fn _start(arg: usize) -> ! {
extern "C" {
fn __rust_start(arg: usize, main: usize) -> !;
fn main(argc: isize, argv: *const *const u8) -> i32;
}
__rust_start(arg, main as *const () as usize)
}
+4
View File
@@ -102,6 +102,10 @@ vex-sdk = { version = "0.27.0", features = [
'rustc-dep-of-std',
], default-features = false }
[target.'cfg(target_os = "yggdrasil")'.dependencies]
yggdrasil-rt = { path = "../../../lib/runtime", features = ['rustc-dep-of-std'] }
libyalloc = { path = "../../../lib/libyalloc", features = ['rustc-dep-of-std'] }
[features]
backtrace = [
'addr2line/rustc-dep-of-std',
+1
View File
@@ -57,6 +57,7 @@ fn main() {
|| target_os == "nuttx"
|| target_os == "cygwin"
|| target_os == "vexos"
|| target_os == "yggdrasil"
// See src/bootstrap/src/core/build_steps/synthetic_targets.rs
|| env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
+6
View File
@@ -183,6 +183,8 @@ pub mod vita;
pub mod vxworks;
#[cfg(target_os = "xous")]
pub mod xous;
#[cfg(target_os = "yggdrasil")]
pub mod yggdrasil;
#[cfg(any(
unix,
@@ -194,5 +196,9 @@ pub mod xous;
))]
pub mod fd;
#[stable(feature = "os_fd", since = "1.66.0")]
#[cfg(target_os = "yggdrasil")]
pub use yggdrasil::io::fd;
#[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin", doc))]
mod net;
+74
View File
@@ -0,0 +1,74 @@
#![unstable(feature = "yggdrasil_os", issue = "none")]
use yggdrasil_rt::io::FileMode;
use yggdrasil_rt::sys as syscall;
use crate::fs::{FileType, Metadata, OpenOptions};
use crate::io;
use crate::path::Path;
use crate::sys::{AsInner, AsInnerMut};
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub trait MetadataExt {
fn mode_ext(&self) -> FileMode;
fn inode(&self) -> Option<u32>;
fn block_count(&self) -> u64;
fn block_size(&self) -> u64;
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub trait FileTypeExt {
fn is_block_device(&self) -> bool;
fn is_char_device(&self) -> bool;
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub trait OpenOptionsExt {
fn mode_ext(&mut self, mode: FileMode) -> &mut Self;
}
impl MetadataExt for Metadata {
fn mode_ext(&self) -> FileMode {
self.as_inner().mode_ext()
}
fn inode(&self) -> Option<u32> {
self.as_inner().inode()
}
fn block_count(&self) -> u64 {
self.as_inner().block_count()
}
fn block_size(&self) -> u64 {
self.as_inner().block_size()
}
}
impl OpenOptionsExt for OpenOptions {
fn mode_ext(&mut self, mode: FileMode) -> &mut Self {
self.as_inner_mut().mode = mode;
self
}
}
impl FileTypeExt for FileType {
#[inline]
fn is_block_device(&self) -> bool {
self.as_inner().is_block_device()
}
#[inline]
fn is_char_device(&self) -> bool {
self.as_inner().is_char_device()
}
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(target: P, path: Q) -> Result<(), io::Error> {
let target = target.as_ref().to_str().unwrap();
let path = path.as_ref().to_str().unwrap();
unsafe { syscall::create_symlink(None, target, path) }?;
Ok(())
}
+18
View File
@@ -0,0 +1,18 @@
#![unstable(feature = "yggdrasil_os", issue = "none")]
use yggdrasil_rt::io::device as rt;
use yggdrasil_rt::sys as syscall;
use crate::io;
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub type MountOptions<'a> = rt::MountOptions<'a>;
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub type UnmountOptions = rt::UnmountOptions;
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub unsafe fn mount_raw(options: &MountOptions<'_>) -> io::Result<()> {
syscall::mount(options)?;
Ok(())
}
+12
View File
@@ -0,0 +1,12 @@
mod owned;
mod raw;
pub use owned::*;
pub use raw::*;
use crate::io;
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn clone_fd(src: RawFd) -> io::Result<RawFd> {
Ok(unsafe { yggdrasil_rt::sys::clone_fd(src, None) }?)
}
+150
View File
@@ -0,0 +1,150 @@
#![stable(feature = "io_safety", since = "1.63.0")]
use super::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::marker::PhantomData;
use crate::mem::forget;
use crate::sys::IntoInner;
macro_rules! stdio_impl_as_fd {
($($ty:ty => $n:expr),*) => {$(
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsFd for $ty {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
BorrowedFd {
fd: $n,
_pd: PhantomData
}
}
}
// #[stable(feature = "io_safety", since = "1.21.0")]
// impl AsFd for &$ty {
// #[inline]
// fn as_raw_fd(&self) -> RawFd {
// $n
// }
// }
)*};
}
#[stable(feature = "io_safety", since = "1.63.0")]
#[repr(transparent)]
#[derive(Debug)]
pub struct OwnedFd {
fd: RawFd,
}
#[stable(feature = "io_safety", since = "1.63.0")]
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
pub struct BorrowedFd<'fd> {
fd: RawFd,
_pd: PhantomData<&'fd OwnedFd>,
}
#[stable(feature = "io_safety", since = "1.63.0")]
pub trait AsFd {
#[stable(feature = "io_safety", since = "1.63.0")]
fn as_fd(&self) -> BorrowedFd<'_>;
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl<T: AsFd> AsFd for &T {
fn as_fd(&self) -> BorrowedFd<'_> {
T::as_fd(self)
}
}
// Borrowed
impl BorrowedFd<'_> {
#[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
#[stable(feature = "io_safety", since = "1.63.0")]
pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
// assert_ne!(fd, u32::MAX as RawFd);
Self { fd, _pd: PhantomData }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsFd for BorrowedFd<'_> {
fn as_fd(&self) -> BorrowedFd<'_> {
*self
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsRawFd for BorrowedFd<'_> {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
// Owned
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsFd for OwnedFd {
fn as_fd(&self) -> BorrowedFd<'_> {
unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl IntoRawFd for OwnedFd {
fn into_raw_fd(self) -> RawFd {
let fd = self.fd;
forget(self);
fd
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl FromRawFd for OwnedFd {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self { fd }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsRawFd for OwnedFd {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl Drop for OwnedFd {
fn drop(&mut self) {
unsafe {
yggdrasil_rt::sys::close(self.fd).ok();
}
}
}
// TODO: AsFd for File, From<File> for OwnedFd, From<OwnedFd> for File,
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::fs::File> for OwnedFd {
fn from(value: crate::fs::File) -> OwnedFd {
let inner = value.into_inner();
Self { fd: inner.into_raw_fd() }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsFd for crate::fs::File {
fn as_fd(&self) -> BorrowedFd<'_> {
BorrowedFd { fd: self.as_raw_fd(), _pd: PhantomData }
}
}
stdio_impl_as_fd!(
crate::io::Stdin => RawFd::STDIN,
crate::io::Stdout => RawFd::STDOUT,
crate::io::Stderr => RawFd::STDERR
);
stdio_impl_as_fd!(
crate::io::StdinLock<'_> => RawFd::STDIN,
crate::io::StdoutLock<'_> => RawFd::STDOUT,
crate::io::StderrLock<'_> => RawFd::STDERR
);
+98
View File
@@ -0,0 +1,98 @@
#![stable(feature = "os_fd", since = "1.66.0")]
#[stable(feature = "rust1", since = "1.0.0")]
pub type RawFd = yggdrasil_rt::io::RawFd;
use crate::sys::{AsInner, FromInner, IntoInner};
macro_rules! stdio_impl_as_raw_fd {
($($ty:ty => $n:expr),*) => {$(
#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawFd for $ty {
#[inline]
fn as_raw_fd(&self) -> RawFd {
$n
}
}
#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawFd for &$ty {
#[inline]
fn as_raw_fd(&self) -> RawFd {
$n
}
}
)*};
}
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawFd {
#[stable(feature = "rust1", since = "1.0.0")]
fn as_raw_fd(&self) -> RawFd;
}
#[stable(feature = "rust1", since = "1.0.0")]
pub trait FromRawFd {
#[stable(feature = "rust1", since = "1.0.0")]
unsafe fn from_raw_fd(fd: RawFd) -> Self;
}
#[stable(feature = "rust1", since = "1.0.0")]
pub trait IntoRawFd {
#[stable(feature = "rust1", since = "1.0.0")]
fn into_raw_fd(self) -> RawFd;
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for RawFd {
fn as_raw_fd(&self) -> RawFd {
*self
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl FromRawFd for RawFd {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
fd
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl IntoRawFd for RawFd {
fn into_raw_fd(self) -> RawFd {
self
}
}
stdio_impl_as_raw_fd!(
crate::io::Stdin => RawFd::STDIN,
crate::io::Stdout => RawFd::STDOUT,
crate::io::Stderr => RawFd::STDERR
);
stdio_impl_as_raw_fd!(
crate::io::StdinLock<'_> => RawFd::STDIN,
crate::io::StdoutLock<'_> => RawFd::STDOUT,
crate::io::StderrLock<'_> => RawFd::STDERR
);
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for crate::fs::File {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().as_raw_fd()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl FromRawFd for crate::fs::File {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
let inner = crate::sys::fs::File::from_raw_fd(fd);
crate::fs::File::from_inner(inner)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl IntoRawFd for crate::fs::File {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_raw_fd()
}
}
@@ -0,0 +1,67 @@
#![unstable(feature = "yggdrasil_os", issue = "none")]
use super::fd::RawFd;
use crate::os::fd::{AsRawFd, OwnedFd};
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub struct FileMapping<'a> {
data: &'a mut [u8],
fd: OwnedFd,
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl<'a> FileMapping<'a> {
pub fn new<F: Into<OwnedFd>>(f: F, offset: u64, len: usize) -> crate::io::Result<Self> {
use yggdrasil_rt::mem::{MappingFlags, MappingSource};
let owned_fd = f.into();
let raw_fd = owned_fd.as_raw_fd();
let base = unsafe {
yggdrasil_rt::sys::map_memory(
None,
len,
MappingFlags::WRITE,
&MappingSource::File(raw_fd, offset),
)
}?;
#[allow(fuzzy_provenance_casts)]
let data = unsafe { crate::slice::from_raw_parts_mut(base as *mut u8, len) };
Ok(Self { data, fd: owned_fd })
}
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl crate::ops::Deref for FileMapping<'_> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.data
}
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl crate::ops::DerefMut for FileMapping<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.data
}
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl Drop for FileMapping<'_> {
fn drop(&mut self) {
// Unmap the memory
let base = self.data.as_ptr() as usize;
let len = self.data.len();
unsafe {
yggdrasil_rt::sys::unmap_memory(base, len).expect("Memory unmap failed");
}
}
}
impl AsRawFd for FileMapping<'_> {
fn as_raw_fd(&self) -> RawFd {
self.fd.as_raw_fd()
}
}
+25
View File
@@ -0,0 +1,25 @@
#![allow(dead_code)]
pub mod fd;
pub mod device;
pub mod mapping;
// pub mod message_channel;
pub mod net;
//pub mod pid;
pub mod pipe;
pub mod poll;
pub mod shared_memory;
pub mod terminal;
pub mod timer;
pub use yggdrasil_rt::io::{FileMetadataUpdate, FileMetadataUpdateMode, FileMode as RawFileMode};
pub fn update_metadata<P: AsRef<crate::path::Path>>(
path: P,
update: &FileMetadataUpdate,
) -> crate::io::Result<()> {
let path = path.as_ref().to_str().unwrap();
unsafe { yggdrasil_rt::sys::update_metadata(None, path, &update) }?;
Ok(())
}
@@ -0,0 +1 @@
pub mod raw_socket;
@@ -0,0 +1,41 @@
#![unstable(feature = "yggdrasil_os", issue = "none")]
use yggdrasil_rt::net::{self as rt, SocketInterfaceQuery};
use crate::io;
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
use crate::sys::fd::FileDesc;
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub struct RawSocket(FileDesc);
impl RawSocket {
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn bind<'a, Q: Into<SocketInterfaceQuery<'a>>>(interface: Q) -> io::Result<Self> {
let query = interface.into();
let raw = rt::bind_raw(query)?;
let inner = unsafe { FileDesc::from_raw_fd(raw) };
Ok(Self(inner))
}
pub fn send(&self, data: &[u8]) -> io::Result<usize> {
Ok(rt::socket::send(self.as_raw_fd(), data)?)
}
pub fn recv(&self, data: &mut [u8]) -> io::Result<usize> {
Ok(rt::socket::receive(self.as_raw_fd(), data)?)
}
pub fn hardware_address(&self) -> io::Result<[u8; 6]> {
rt::get_socket_option!(self.as_raw_fd(), rt::options::BoundHardwareAddress)
.map(Into::into)
.map_err(io::Error::from)
}
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl AsRawFd for RawSocket {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
+17
View File
@@ -0,0 +1,17 @@
#![unstable(feature = "yggdrasil_os", issue = "none")]
use yggdrasil_rt::io as rt;
use crate::os::fd::{FromRawFd, OwnedFd};
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn create_pipe_pair(
read_nonblocking: bool,
write_nonblocking: bool,
) -> crate::io::Result<(OwnedFd, OwnedFd)> {
let (read, write) = rt::create_pipe_pair(read_nonblocking, write_nonblocking)?;
let read = unsafe { OwnedFd::from_raw_fd(read) };
let write = unsafe { OwnedFd::from_raw_fd(write) };
Ok((read, write))
}
+58
View File
@@ -0,0 +1,58 @@
#![unstable(feature = "yggdrasil_os", issue = "none")]
use yggdrasil_rt::io::poll as rt;
use crate::io;
use crate::os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd};
use crate::time::Duration;
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub type PollControl = rt::PollControl;
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub struct PollChannel(OwnedFd);
impl PollChannel {
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn new() -> io::Result<Self> {
let raw_fd = unsafe { yggdrasil_rt::sys::create_poll_channel() }?;
let fd = unsafe { OwnedFd::from_raw_fd(raw_fd) };
Ok(Self(fd))
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn add(&mut self, fd: RawFd) -> io::Result<()> {
unsafe {
yggdrasil_rt::sys::poll_channel_control(self.0.as_raw_fd(), PollControl::AddFd, fd)
}?;
Ok(())
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn remove(&mut self, fd: RawFd) -> io::Result<()> {
unsafe {
yggdrasil_rt::sys::poll_channel_control(self.0.as_raw_fd(), PollControl::RemoveFd, fd)
}?;
Ok(())
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn wait(
&mut self,
timeout: Option<Duration>,
retain: bool,
) -> io::Result<Option<(RawFd, io::Result<()>)>> {
let mut output = None;
unsafe {
yggdrasil_rt::sys::poll_channel_wait(self.0.as_raw_fd(), &timeout, retain, &mut output)
}?;
Ok(output.map(|(l, r)| (l, r.map_err(io::Error::from))))
}
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl AsRawFd for PollChannel {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
@@ -0,0 +1,43 @@
#![unstable(feature = "yggdrasil_os", issue = "none")]
use yggdrasil_rt::sys as syscall;
use crate::io;
use crate::os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd};
use crate::os::yggdrasil::io::mapping::FileMapping;
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub struct SharedMemory(OwnedFd, usize);
impl SharedMemory {
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn new(size: usize) -> io::Result<Self> {
let raw_fd = unsafe { syscall::create_shared_memory(size) }?;
let fd = unsafe { OwnedFd::from_raw_fd(raw_fd) };
Ok(Self(fd, size))
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn size(&self) -> usize {
self.1
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn into_mapping<'a>(self) -> io::Result<FileMapping<'a>> {
FileMapping::new(self.0, 0, self.1)
}
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl Into<OwnedFd> for SharedMemory {
fn into(self) -> OwnedFd {
self.0
}
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl AsRawFd for SharedMemory {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
@@ -0,0 +1,84 @@
#![unstable(feature = "yggdrasil_os", issue = "none")]
use yggdrasil_rt::io::{FileMode, OpenOptions, terminal as rt};
use yggdrasil_rt::process::ProcessGroupId;
use yggdrasil_rt::sys as syscall;
use crate::fs::File;
use crate::io;
use crate::mem::MaybeUninit;
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
use crate::path::Path;
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub type TerminalOptions = rt::TerminalOptions;
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub type TerminalSize = rt::TerminalSize;
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub unsafe fn set_terminal_options<F: AsRawFd>(fd: &F, opt: &TerminalOptions) -> io::Result<()> {
rt::set_terminal_options(fd.as_raw_fd(), opt)?;
Ok(())
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub unsafe fn get_terminal_options<F: AsRawFd>(fd: &F) -> io::Result<TerminalOptions> {
Ok(rt::get_terminal_options(fd.as_raw_fd())?)
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub unsafe fn set_terminal_group<F: AsRawFd>(fd: &F, group: ProcessGroupId) -> io::Result<()> {
Ok(rt::set_terminal_group(fd.as_raw_fd(), group)?)
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn get_terminal_size<F: AsRawFd>(fd: &F) -> io::Result<TerminalSize> {
Ok(rt::get_terminal_size(fd.as_raw_fd())?)
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub unsafe fn update_terminal_options<F: AsRawFd, M: FnOnce(TerminalOptions) -> TerminalOptions>(
fd: &F,
mutator: M,
) -> io::Result<TerminalOptions> {
let old = get_terminal_options(fd)?;
let new = mutator(old);
set_terminal_options(fd, &new)?;
Ok(old)
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub unsafe fn start_terminal_session<P: AsRef<Path>>(terminal: P) -> io::Result<()> {
let terminal = terminal.as_ref().to_str().unwrap();
syscall::start_session()?;
let stdin_fd = syscall::open(None, terminal, OpenOptions::READ, FileMode::empty())?;
let stdout_stderr_fd = syscall::open(None, terminal, OpenOptions::WRITE, FileMode::empty())?;
syscall::clone_fd(stdin_fd, Some(RawFd::STDIN))?;
syscall::clone_fd(stdout_stderr_fd, Some(RawFd::STDOUT))?;
syscall::clone_fd(stdout_stderr_fd, Some(RawFd::STDERR))?;
syscall::close(stdin_fd)?;
syscall::close(stdout_stderr_fd)?;
Ok(())
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn create_pty(
options: Option<TerminalOptions>,
size: TerminalSize,
) -> io::Result<(File, File)> {
let options = options.unwrap_or_default();
let mut fds = [MaybeUninit::uninit(), MaybeUninit::uninit()];
unsafe { syscall::create_pty(&options, &size, &mut fds) }?;
let master = unsafe { File::from_raw_fd(fds[0].assume_init()) };
let slave = unsafe { File::from_raw_fd(fds[1].assume_init()) };
Ok((master, slave))
}
+50
View File
@@ -0,0 +1,50 @@
#![unstable(feature = "yggdrasil_os", issue = "none")]
use yggdrasil_rt::io::TimerOptions;
use yggdrasil_rt::sys as syscall;
use crate::io;
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
use crate::sys::fd::FileDesc;
use crate::time::Duration;
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub struct TimerFd(FileDesc);
impl TimerFd {
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn new(repeat: bool, nonblocking: bool) -> io::Result<Self> {
let mut options = TimerOptions::empty();
if repeat {
options |= TimerOptions::REPEAT;
}
let raw = unsafe { syscall::create_timer(options) }?;
let fd = unsafe { FileDesc::from_raw_fd(raw) };
if nonblocking {
fd.set_nonblocking(true)?;
}
Ok(Self(fd))
}
pub fn start(&mut self, timeout: Duration) -> io::Result<()> {
let tval = timeout.as_micros();
unsafe { syscall::write(self.0.as_raw_fd(), &tval.to_ne_bytes()) }?;
Ok(())
}
pub fn is_expired(&mut self) -> io::Result<bool> {
let mut buf = [0; 1];
match unsafe { syscall::read(self.0.as_raw_fd(), &mut buf) }.map_err(io::Error::from) {
Ok(_) => Ok(true),
Err(e) if e.kind() == io::ErrorKind::WouldBlock => Ok(false),
Err(e) => Err(e),
}
}
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl AsRawFd for TimerFd {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
+34
View File
@@ -0,0 +1,34 @@
#![unstable(feature = "yggdrasil_os", issue = "none")]
#![allow(exported_private_dependencies)]
pub use yggdrasil_rt as rt;
pub mod fs;
pub mod io;
pub mod process;
pub mod signal;
use yggdrasil_rt::process::ProgramArgumentInner;
use yggdrasil_rt::sys as syscall;
use crate::path::{Path, PathBuf};
pub(crate) static mut REAL_BINARY_PATH: Option<PathBuf> = None;
pub(crate) unsafe fn set_real_program(program_arg: &ProgramArgumentInner) {
if let Some(real_program) = program_arg.real_program() {
let real_program_str = real_program.to_str().expect("Invalid real_program from kernel");
REAL_BINARY_PATH = Some(PathBuf::from(real_program_str));
}
}
pub fn real_binary_path() -> &'static Path {
#[allow(static_mut_refs)]
unsafe {
REAL_BINARY_PATH.as_deref().unwrap_or_else(|| Path::new(""))
}
}
pub fn get_random(buffer: &mut [crate::mem::MaybeUninit<u8>]) {
unsafe { syscall::get_random(buffer.assume_init_mut()) }
}
+100
View File
@@ -0,0 +1,100 @@
#![stable(feature = "os", since = "1.0.0")]
use yggdrasil_rt::io::RawFd;
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub use yggdrasil_rt::process::ProcessGroupId;
use yggdrasil_rt::process::{ProcessId, Signal, SpawnFlags};
use yggdrasil_rt::sys as syscall;
use crate::io;
use crate::path::Path;
use crate::process::{Child, Command, ExitStatus};
use crate::sealed::Sealed;
use crate::sys::{AsInner, AsInnerMut};
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub trait ChildExt: Sealed {
#[unstable(feature = "yggdrasil_os", issue = "none")]
fn main_thread_id(&self) -> io::Result<u32>;
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub trait CommandExt: Sealed {
#[unstable(feature = "yggdrasil_os", issue = "none")]
fn process_group(&mut self, pgroup: ProcessGroupId) -> &mut Command;
#[unstable(feature = "yggdrasil_os", issue = "none")]
unsafe fn gain_terminal<F: Into<RawFd>>(&mut self, fd: F) -> &mut Command;
#[unstable(feature = "yggdrasil_os", issue = "none")]
unsafe fn attach_tracing(&mut self) -> &mut Command;
#[unstable(feature = "yggdrasil_os", issue = "none")]
fn disable_aslr(&mut self) -> &mut Command;
#[unstable(feature = "yggdrasil_os", issue = "none")]
fn change_root<P: AsRef<Path>>(&mut self, new: P) -> &mut Command;
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub trait ExitStatusExt: Sealed {
#[unstable(feature = "yggdrasil_os", issue = "none")]
fn signal(&self) -> Option<Result<Signal, u32>>;
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl CommandExt for Command {
fn process_group(&mut self, pgroup: ProcessGroupId) -> &mut Command {
self.as_inner_mut().pgroup = Some(pgroup);
self
}
unsafe fn gain_terminal<F: Into<RawFd>>(&mut self, fd: F) -> &mut Command {
self.as_inner_mut().gain_terminal = Some(fd.into());
self
}
unsafe fn attach_tracing(&mut self) -> &mut Command {
self.as_inner_mut().attach_trace = true;
self
}
fn disable_aslr(&mut self) -> &mut Command {
self.as_inner_mut().flags |= SpawnFlags::DISABLE_ASLR;
self
}
fn change_root<P: AsRef<Path>>(&mut self, new: P) -> &mut Command {
self.as_inner_mut().change_root(new);
self
}
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl ExitStatusExt for ExitStatus {
fn signal(&self) -> Option<Result<Signal, u32>> {
self.as_inner().signal()
}
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl ChildExt for Child {
fn main_thread_id(&self) -> io::Result<u32> {
self.as_inner().main_thread_id()
}
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn id_ext() -> ProcessId {
unsafe { syscall::get_pid() }
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn group_id() -> ProcessGroupId {
unsafe { syscall::get_process_group_id() }
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub fn create_process_group() -> ProcessGroupId {
unsafe { syscall::create_process_group() }
}
+27
View File
@@ -0,0 +1,27 @@
pub use yggdrasil_rt::process::{ProcessId, Signal};
pub use yggdrasil_rt::sys as syscall;
use crate::io;
#[must_use = "It is adviced to store the original handler in case it needs to be restored later"]
#[derive(Clone, Copy)]
pub enum SignalHandler {
Ignore,
Terminate,
Function(fn(Signal)),
}
pub fn set_signal_handler(signal: Signal, handler: SignalHandler) -> SignalHandler {
crate::sys::signal::set_signal_handler(signal, handler)
}
pub fn send(destination: u32, signal: Signal) -> io::Result<()> {
let destination = unsafe { ProcessId::from_raw(destination) };
unsafe { syscall::send_signal(destination, signal) }?;
Ok(())
}
pub fn abort() -> ! {
unsafe { syscall::send_signal(syscall::get_pid(), Signal::Aborted) }.expect("Could not abort");
unreachable!();
}
+3
View File
@@ -107,4 +107,7 @@ cfg_select! {
target_os = "zkvm" => {
mod zkvm;
}
target_os = "yggdrasil" => {
mod yggdrasil;
}
}
+49
View File
@@ -0,0 +1,49 @@
use libyalloc::allocator::BucketAllocator;
use libyalloc::sys::OsPageProvider;
use crate::alloc::{GlobalAlloc, Layout, System};
use crate::cell::UnsafeCell;
use crate::ptr::NonNull;
use crate::sys::sync::Mutex;
struct Global {
lock: Mutex,
inner: UnsafeCell<BucketAllocator<OsPageProvider>>,
}
#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let ptr = unsafe {
ALLOC.lock.lock();
let ptr = (*ALLOC.inner.get()).allocate(layout);
ALLOC.lock.unlock();
ptr
};
if let Some(ptr) = ptr { ptr.as_ptr() } else { crate::ptr::null_mut() }
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
let ptr = NonNull::new(ptr).expect("Invalid pointer");
unsafe {
ALLOC.lock.lock();
(*ALLOC.inner.get()).free(ptr, layout);
ALLOC.lock.unlock();
}
}
}
impl Global {
#[rustc_const_unstable(feature = "yggdrasil_os", issue = "none")]
const fn new() -> Self {
Self { lock: Mutex::new(), inner: UnsafeCell::new(BucketAllocator::new()) }
}
}
unsafe impl Sync for Global {}
static ALLOC: Global = Global::new();
+4
View File
@@ -53,6 +53,10 @@ cfg_select! {
mod zkvm;
pub use zkvm::*;
}
target_os = "yggdrasil" => {
mod yggdrasil;
pub use yggdrasil::*;
}
_ => {
mod unsupported;
pub use unsupported::*;
+74
View File
@@ -0,0 +1,74 @@
use crate::ffi::OsString;
use crate::{fmt, vec};
#[allow(dead_code)]
#[derive(Clone)]
pub struct Args {
iter: vec::IntoIter<OsString>,
}
pub fn args() -> Args {
Args { iter: imp::clone() }
}
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.iter, f)
}
}
impl Iterator for Args {
type Item = OsString;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl ExactSizeIterator for Args {
fn len(&self) -> usize {
self.iter.len()
}
}
impl DoubleEndedIterator for Args {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
pub(crate) mod imp {
use yggdrasil_rt::process::ProgramArgumentInner;
use crate::ffi::{OsStr, OsString};
use crate::sync::atomic::{AtomicPtr, Ordering};
use crate::{ptr, vec};
static ARGS: AtomicPtr<Vec<OsString>> = AtomicPtr::new(ptr::null_mut());
pub(crate) fn init(arg: &ProgramArgumentInner) {
let mut args = Box::new(Vec::new());
for arg in arg.args() {
let arg = unsafe { OsStr::from_encoded_bytes_unchecked(arg.to_bytes()) };
args.push(arg.to_owned());
}
let args = Box::into_raw(args);
ARGS.store(args, Ordering::Release);
}
pub(super) fn clone() -> vec::IntoIter<OsString> {
unsafe {
ARGS.load(Ordering::Acquire)
.as_ref()
.expect("Program arguments not yet initialized")
.clone()
.into_iter()
}
}
}
+4
View File
@@ -55,6 +55,10 @@ cfg_select! {
mod zkvm;
pub use zkvm::*;
}
target_os = "yggdrasil" => {
mod yggdrasil;
pub use yggdrasil::*;
}
_ => {
mod unsupported;
pub use unsupported::*;
+107
View File
@@ -0,0 +1,107 @@
use crate::collections::hash_map;
use crate::ffi::{OsStr, OsString};
use crate::sys::AsInner;
use crate::{fmt, io};
pub struct Env {
iter: hash_map::IntoIter<OsString, OsString>,
}
impl !Send for Env {}
impl !Sync for Env {}
impl Iterator for Env {
type Item = (OsString, OsString);
fn next(&mut self) -> Option<(OsString, OsString)> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl fmt::Debug for Env {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.iter, f)
}
}
pub fn env() -> Env {
let iter = imp::read().clone().into_iter();
Env { iter }
}
pub fn getenv(name: &OsStr) -> Option<OsString> {
if name.as_inner().as_encoded_bytes().contains(&b'=') {
return None;
}
let env = imp::read();
env.get(name).cloned()
}
pub unsafe fn setenv(name: &OsStr, value: &OsStr) -> io::Result<()> {
if name.as_inner().as_encoded_bytes().contains(&b'=') {
return Err(io::Error::new(io::ErrorKind::Uncategorized, "Invalid env var name"));
}
let mut env = imp::write();
env.insert(name.to_owned(), value.to_owned());
Ok(())
}
pub unsafe fn unsetenv(name: &OsStr) -> io::Result<()> {
if name.as_inner().as_encoded_bytes().contains(&b'=') {
return Err(io::Error::new(io::ErrorKind::Uncategorized, "Invalid env var name"));
}
let mut env = imp::write();
env.remove(name);
Ok(())
}
pub(crate) mod imp {
use yggdrasil_rt::process::ProgramArgumentInner;
use crate::collections::HashMap;
use crate::ffi::{OsStr, OsString};
use crate::ptr;
use crate::sync::atomic::{AtomicPtr, Ordering};
use crate::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
static ENV: AtomicPtr<RwLock<HashMap<OsString, OsString>>> = AtomicPtr::new(ptr::null_mut());
pub(super) fn read() -> RwLockReadGuard<'static, HashMap<OsString, OsString>> {
unsafe {
ENV.load(Ordering::Acquire)
.as_ref()
.expect("Environment variables not initialized")
.read()
.expect("Could not obtain env read lock")
}
}
pub(super) fn write() -> RwLockWriteGuard<'static, HashMap<OsString, OsString>> {
unsafe {
ENV.load(Ordering::Acquire)
.as_ref()
.expect("Environment variables not initialized")
.write()
.expect("Could not obtain env write lock")
}
}
pub(crate) fn init(arg: &ProgramArgumentInner) {
let mut envs = HashMap::new();
for pair in arg.envs() {
let pair = pair.to_bytes();
let Some((key, value)) = pair.split_once(|c| *c == b'=') else { continue };
let key = unsafe { OsStr::from_encoded_bytes_unchecked(key).to_owned() };
let value = unsafe { OsStr::from_encoded_bytes_unchecked(value).to_owned() };
envs.insert(key, value);
}
let envs = Box::into_raw(Box::new(RwLock::new(envs)));
ENV.store(envs, Ordering::Release);
}
}
+4
View File
@@ -15,6 +15,10 @@ cfg_select! {
mod motor;
pub use motor::*;
}
target_os = "yggdrasil" => {
mod yggdrasil;
pub use yggdrasil::*;
}
all(target_vendor = "fortanix", target_env = "sgx") => {
mod sgx;
pub use sgx::*;
+128
View File
@@ -0,0 +1,128 @@
use yggdrasil_rt::io::{self as rt, FileSync, options};
use yggdrasil_rt::sys as syscall;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use crate::sys::fs::{self, FileAttr};
use crate::sys::{AsInner, FromInner, IntoInner};
#[derive(Debug)]
pub struct FileDesc {
fd: OwnedFd,
}
impl FileDesc {
pub(crate) fn set_nonblocking(&self, non_blocking: bool) -> io::Result<()> {
rt::set_file_option::<options::NonBlocking>(self.as_raw_fd(), &non_blocking)?;
Ok(())
}
pub(crate) fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
Ok(unsafe { syscall::read(self.fd.as_raw_fd(), buffer) }?)
}
pub(crate) fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
io::default_read_buf(|buf| self.read(buf), cursor)
}
pub(crate) fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
todo!("FileDesc::read_vectored()")
}
pub(crate) fn write(&self, buffer: &[u8]) -> io::Result<usize> {
Ok(unsafe { syscall::write(self.fd.as_raw_fd(), buffer) }?)
}
pub(crate) fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
todo!("FileDesc::write_vectored()")
}
pub(crate) fn read_to_end(&self, buffer: &mut Vec<u8>) -> io::Result<usize> {
let mut buf = [0; 512];
let mut bytes_read = 0;
loop {
let amount = self.read(&mut buf)?;
if amount == 0 {
break;
}
buffer.extend_from_slice(&buf[..amount]);
bytes_read += amount;
}
Ok(bytes_read)
}
pub(crate) fn try_clone(&self) -> io::Result<Self> {
let raw = unsafe { syscall::clone_fd(self.as_raw_fd(), None) }?;
Ok(unsafe { Self::from_raw_fd(raw) })
}
pub(crate) fn metadata(&self) -> io::Result<FileAttr> {
fs::get_metadata_inner(Some(self.as_raw_fd()), "", true)
}
pub(crate) fn truncate(&self, size: u64) -> io::Result<()> {
unsafe { syscall::truncate(self.as_raw_fd(), size) }?;
Ok(())
}
pub(crate) fn datasync(&self) -> io::Result<()> {
unsafe { syscall::fsync(self.as_raw_fd(), FileSync::DATA) }?;
Ok(())
}
pub(crate) fn fsync(&self) -> io::Result<()> {
unsafe { syscall::fsync(self.as_raw_fd(), FileSync::METADATA | FileSync::DATA) }?;
Ok(())
}
pub(crate) fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
let mut output = 0;
unsafe { syscall::seek(self.as_raw_fd(), pos.into(), &mut output) }?;
Ok(output)
}
}
impl IntoInner<OwnedFd> for FileDesc {
fn into_inner(self) -> OwnedFd {
self.fd
}
}
impl FromInner<OwnedFd> for FileDesc {
fn from_inner(fd: OwnedFd) -> Self {
Self { fd }
}
}
impl FromRawFd for FileDesc {
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } }
}
}
impl AsInner<OwnedFd> for FileDesc {
fn as_inner(&self) -> &OwnedFd {
&self.fd
}
}
impl AsFd for FileDesc {
fn as_fd(&self) -> BorrowedFd<'_> {
self.fd.as_fd()
}
}
impl AsRawFd for FileDesc {
fn as_raw_fd(&self) -> RawFd {
self.fd.as_raw_fd()
}
}
impl IntoRawFd for FileDesc {
fn into_raw_fd(self) -> RawFd {
self.fd.into_raw_fd()
}
}
+22
View File
@@ -0,0 +1,22 @@
#![allow(exported_private_dependencies)]
use yggdrasil_rt::io::SeekFrom as OsSeekFrom;
use crate::io::SeekFrom;
mod file;
mod socket;
pub use file::FileDesc;
pub(crate) use socket::SocketFileDesc;
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl From<SeekFrom> for OsSeekFrom {
fn from(value: SeekFrom) -> OsSeekFrom {
match value {
SeekFrom::Start(v) => OsSeekFrom::Start(v),
SeekFrom::End(v) => OsSeekFrom::End(v),
SeekFrom::Current(v) => OsSeekFrom::Current(v),
}
}
}
+245
View File
@@ -0,0 +1,245 @@
use yggdrasil_rt::{io as rt_io, net as rt, sys as syscall};
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use crate::sys::{AsInner, FromInner, IntoInner};
use crate::time::Duration;
#[derive(Debug)]
pub(crate) struct SocketFileDesc {
fd: OwnedFd,
}
impl SocketFileDesc {
pub(crate) fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
rt::set_socket_option::<rt::options::RecvTimeout>(self.as_raw_fd(), &timeout)?;
Ok(())
}
pub(crate) fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
rt::set_socket_option::<rt::options::SendTimeout>(self.as_raw_fd(), &timeout)?;
Ok(())
}
pub(crate) fn set_linger(&self, _linger: Option<Duration>) -> io::Result<()> {
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::set_linger()")
}
pub(crate) fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
rt::set_socket_option::<rt::options::NoDelay>(self.as_raw_fd(), &nodelay)?;
Ok(())
}
pub(crate) fn set_ttl(&self, ttl: u32) -> io::Result<()> {
rt::set_socket_option::<rt::options::Ttl>(self.as_raw_fd(), &ttl)?;
Ok(())
}
pub(crate) fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
rt_io::set_file_option::<rt_io::options::NonBlocking>(self.as_raw_fd(), &nonblocking)?;
Ok(())
}
pub(crate) fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
rt::set_socket_option::<rt::options::Ipv6Only>(self.as_raw_fd(), &only_v6)?;
Ok(())
}
pub(crate) fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
rt::set_socket_option::<rt::options::Broadcast>(self.as_raw_fd(), &broadcast)?;
Ok(())
}
pub fn set_multicast_loop_v4(&self, loop_v4: bool) -> io::Result<()> {
rt::set_socket_option::<rt::options::MulticastLoopV4>(self.as_raw_fd(), &loop_v4)?;
Ok(())
}
pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
rt::set_socket_option::<rt::options::MulticastTtlV4>(self.as_raw_fd(), &ttl)?;
Ok(())
}
pub fn set_multicast_loop_v6(&self, loop_v6: bool) -> io::Result<()> {
rt::set_socket_option::<rt::options::MulticastLoopV6>(self.as_raw_fd(), &loop_v6)?;
Ok(())
}
pub(crate) fn read_timeout(&self) -> io::Result<Option<Duration>> {
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::RecvTimeout)?)
}
pub(crate) fn write_timeout(&self) -> io::Result<Option<Duration>> {
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::SendTimeout)?)
}
pub(crate) fn linger(&self) -> io::Result<Option<Duration>> {
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::linger()")
}
pub(crate) fn nodelay(&self) -> io::Result<bool> {
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::NoDelay)?)
}
pub(crate) fn ttl(&self) -> io::Result<u32> {
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::Ttl)?)
}
pub(crate) fn only_v6(&self) -> io::Result<bool> {
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::Ipv6Only)?)
}
pub(crate) fn broadcast(&self) -> io::Result<bool> {
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::Broadcast)?)
}
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::MulticastLoopV4)?)
}
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::MulticastTtlV4)?)
}
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::MulticastLoopV6)?)
}
pub(crate) fn local_addr(&self) -> io::Result<SocketAddr> {
Ok(rt::local_address(self.as_raw_fd())?)
}
pub(crate) fn peer_addr(&self) -> io::Result<SocketAddr> {
Ok(rt::peer_address(self.as_raw_fd())?)
}
pub(crate) fn join_multicast_v4(
&self,
_multiaddr: &Ipv4Addr,
_interface: &Ipv4Addr,
) -> io::Result<()> {
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::join_multicast_v4()")
}
pub(crate) fn join_multicast_v6(
&self,
_multiaddr: &Ipv6Addr,
_interface: u32,
) -> io::Result<()> {
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::join_multicast_v6()")
}
pub(crate) fn leave_multicast_v4(
&self,
_multiaddr: &Ipv4Addr,
_interface: &Ipv4Addr,
) -> io::Result<()> {
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::leave_multicast_v4()")
}
pub(crate) fn leave_multicast_v6(
&self,
_multiaddr: &Ipv6Addr,
_interface: u32,
) -> io::Result<()> {
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::leave_multicast_v6()")
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::take_error()")
}
pub(crate) fn accept(&self) -> io::Result<(SocketFileDesc, SocketAddr)> {
let (raw, remote) = rt::socket::accept_ip(self.as_raw_fd())?;
let fd = unsafe { Self::from_raw_fd(raw) };
Ok((fd, remote))
}
pub(crate) fn recv_from(&self, buffer: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
Ok(rt::socket::receive_from_ip(self.as_raw_fd(), buffer)?)
}
pub(crate) fn recv(&self, buffer: &mut [u8]) -> io::Result<usize> {
Ok(rt::socket::receive(self.as_raw_fd(), buffer)?)
}
pub(crate) fn recv_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> {
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::recv_buf()")
}
pub(crate) fn recv_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::recv_vectored()")
}
pub(crate) fn peek(&self, _buffer: &mut [u8]) -> io::Result<usize> {
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::peek()")
}
pub(crate) fn peek_from(&self, _buffer: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::peek_from()")
}
pub(crate) fn send(&self, data: &[u8]) -> io::Result<usize> {
Ok(rt::socket::send(self.as_raw_fd(), data)?)
}
pub(crate) fn send_to(&self, data: &[u8], dst: &SocketAddr) -> io::Result<usize> {
Ok(rt::socket::send_to_ip(self.as_raw_fd(), data, dst)?)
}
pub(crate) fn send_vectored(&self, _data: &[IoSlice<'_>]) -> io::Result<usize> {
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::send_vectored()")
}
pub(crate) fn shutdown(&self, _how: Shutdown) -> io::Result<()> {
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::shutdown()")
}
pub(crate) fn try_clone(&self) -> io::Result<Self> {
let fd = unsafe { syscall::clone_fd(self.as_raw_fd(), None) }?;
Ok(unsafe { Self::from_raw_fd(fd) })
}
}
impl AsFd for SocketFileDesc {
fn as_fd(&self) -> BorrowedFd<'_> {
self.fd.as_fd()
}
}
impl IntoRawFd for SocketFileDesc {
fn into_raw_fd(self) -> RawFd {
self.fd.into_raw_fd()
}
}
impl AsRawFd for SocketFileDesc {
fn as_raw_fd(&self) -> RawFd {
self.fd.as_raw_fd()
}
}
impl FromRawFd for SocketFileDesc {
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } }
}
}
impl IntoInner<OwnedFd> for SocketFileDesc {
fn into_inner(self) -> OwnedFd {
self.fd
}
}
impl AsInner<OwnedFd> for SocketFileDesc {
fn as_inner(&self) -> &OwnedFd {
&self.fd
}
}
impl FromInner<OwnedFd> for SocketFileDesc {
fn from_inner(fd: OwnedFd) -> Self {
Self { fd }
}
}
+5
View File
@@ -45,6 +45,11 @@ cfg_select! {
mod vexos;
use vexos as imp;
}
target_os = "yggdrasil" => {
mod yggdrasil;
use yggdrasil as imp;
pub(crate) use imp::get_metadata_inner;
}
_ => {
mod unsupported;
use unsupported as imp;
+171
View File
@@ -0,0 +1,171 @@
use yggdrasil_rt::io::{
FileAttr as OsFileAttr, FileMetadataUpdate, FileMetadataUpdateMode, FileMode as OsFileMode,
FileType as OsFileType,
};
use yggdrasil_rt::time::SystemTime as RtSystemTime;
use crate::hash::Hash;
use crate::os::fd::RawFd;
use crate::path::Path;
use crate::sys::run_with_path_str;
use crate::sys::time::SystemTime;
use crate::{fmt, io};
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct FileAttr(pub(super) OsFileAttr);
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct FilePermissions(pub(super) OsFileMode);
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct FileType(pub(super) OsFileType);
#[derive(Copy, Clone, Debug, Default)]
pub struct FileTimes {
pub(crate) atime: Option<RtSystemTime>,
pub(crate) mtime: Option<RtSystemTime>,
}
impl FileAttr {
pub fn size(&self) -> u64 {
self.0.size
}
pub fn perm(&self) -> FilePermissions {
FilePermissions(self.0.mode)
}
pub fn file_type(&self) -> FileType {
FileType(self.0.ty)
}
pub fn mode_ext(&self) -> OsFileMode {
self.0.mode
}
pub fn inode(&self) -> Option<u32> {
self.0.inode
}
pub fn block_count(&self) -> u64 {
self.0.block_count
}
pub fn block_size(&self) -> u64 {
self.0.block_size
}
pub fn modified(&self) -> io::Result<SystemTime> {
let time = SystemTime(self.0.mtime);
Ok(time)
}
pub fn accessed(&self) -> io::Result<SystemTime> {
let time = SystemTime(self.0.atime);
Ok(time)
}
pub fn created(&self) -> io::Result<SystemTime> {
let time = SystemTime(self.0.ctime);
Ok(time)
}
}
impl FilePermissions {
pub fn readonly(&self) -> bool {
!self.0.contains_any(
OsFileMode::USER_WRITE | OsFileMode::GROUP_WRITE | OsFileMode::OTHER_WRITE,
)
}
pub fn set_readonly(&mut self, readonly: bool) {
if readonly {
self.0 &= !(OsFileMode::USER_WRITE | OsFileMode::GROUP_WRITE | OsFileMode::OTHER_WRITE);
} else {
self.0 |= OsFileMode::USER_WRITE | OsFileMode::GROUP_WRITE | OsFileMode::OTHER_WRITE;
}
}
}
impl fmt::Debug for FilePermissions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0.bits(), f)
}
}
impl FileType {
pub fn is_dir(&self) -> bool {
self.0 == OsFileType::Directory
}
pub fn is_file(&self) -> bool {
self.0 == OsFileType::File
}
pub fn is_symlink(&self) -> bool {
self.0 == OsFileType::Symlink
}
pub fn is_char_device(&self) -> bool {
self.0 == OsFileType::Char
}
pub fn is_block_device(&self) -> bool {
self.0 == OsFileType::Block
}
}
impl fmt::Debug for FileType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl FileTimes {
pub fn set_accessed(&mut self, t: SystemTime) {
self.atime = Some(t.0);
}
pub fn set_modified(&mut self, t: SystemTime) {
self.mtime = Some(t.0);
}
}
pub(crate) fn get_metadata_inner(
at: Option<RawFd>,
path: &str,
follow: bool,
) -> io::Result<FileAttr> {
let mut metadata = crate::mem::MaybeUninit::uninit();
unsafe { yggdrasil_rt::sys::get_metadata(at, path, &mut metadata, follow) }?;
Ok(unsafe { FileAttr(metadata.assume_init()) })
}
pub fn stat(path: &Path) -> io::Result<FileAttr> {
run_with_path_str(path, |path_str| get_metadata_inner(None, path_str, true))
}
pub fn lstat(path: &Path) -> io::Result<FileAttr> {
run_with_path_str(path, |path_str| get_metadata_inner(None, path_str, false))
}
pub fn set_perm(path: &Path, perm: FilePermissions) -> io::Result<()> {
run_with_path_str(path, |path_str| {
unsafe {
yggdrasil_rt::sys::update_metadata(
None,
path_str,
&FileMetadataUpdate::Permissions(FileMetadataUpdateMode::Set(perm.0)),
)
}
.map_err(io::Error::from)
})
}
pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> {
todo!("sys::fs::yggdrasil::set_times()")
}
pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> {
todo!("sys::fs::yggdrasil::set_times_nofollow()")
}
+162
View File
@@ -0,0 +1,162 @@
use yggdrasil_rt::io::{DirectoryEntry as OsDirectoryEntry, FileMode as OsFileMode};
use super::{FileAttr, FileType, get_metadata_inner};
use crate::ffi::OsString;
use crate::mem::MaybeUninit;
use crate::os::fd::{AsRawFd, FromRawFd};
use crate::path::{Path, PathBuf};
use crate::str::FromStr;
use crate::sys::fd::FileDesc;
use crate::sys::run_with_path_str;
use crate::{fmt, io};
const BUFFER_SIZE: usize = 8;
pub struct DirEntry {
filename: OsString,
path: PathBuf,
ty: FileType,
}
pub struct ReadDir {
fd: FileDesc,
path: PathBuf,
// TODO fetch more entries at a time
buffer: [MaybeUninit<OsDirectoryEntry>; BUFFER_SIZE],
buffer_position: usize,
buffer_len: usize,
eof: bool,
}
#[derive(Debug)]
pub struct DirBuilder {
mode: OsFileMode,
}
impl ReadDir {
fn open(path: &Path) -> io::Result<Self> {
let path_buf = PathBuf::from(path);
let path_str = path.to_str().unwrap();
let fd = unsafe { yggdrasil_rt::sys::open_directory(None, path_str) }?;
Ok(ReadDir {
fd: unsafe { FileDesc::from_raw_fd(fd) },
buffer: [MaybeUninit::uninit(); BUFFER_SIZE],
buffer_position: 0,
buffer_len: 0,
path: path_buf,
eof: false,
})
}
fn fill_buffer(&mut self) -> io::Result<()> {
// If eof, don't attempt to load anything
// If pos != len, still have some entries
if self.eof || self.buffer_position != self.buffer_len {
return Ok(());
}
self.buffer_position = 0;
self.buffer_len = unsafe {
yggdrasil_rt::sys::read_directory_entries(self.fd.as_raw_fd(), &mut self.buffer)
}?;
if self.buffer_len == 0 {
self.eof = true;
}
Ok(())
}
}
impl Iterator for ReadDir {
type Item = io::Result<DirEntry>;
fn next(&mut self) -> Option<io::Result<DirEntry>> {
loop {
if let Err(e) = self.fill_buffer() {
break Some(Err(e));
}
if self.eof {
return None;
}
assert_ne!(self.buffer_position, self.buffer_len);
let entry = unsafe { self.buffer[self.buffer_position].assume_init_ref() };
self.buffer_position += 1;
break Some(DirEntry::from_raw(self.path.clone(), entry));
}
}
}
impl fmt::Debug for ReadDir {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&*self.path, f)
}
}
impl DirEntry {
fn from_raw(parent: PathBuf, raw: &OsDirectoryEntry) -> io::Result<Self> {
let filename = OsString::from_str(raw.name.as_ref()).unwrap();
let path = parent.join(filename.clone());
let ty = match raw.ty {
Some(ty) => FileType(ty),
None => {
let metadata = run_with_path_str(path.as_ref(), |path_str| {
get_metadata_inner(None, path_str, false)
})?;
metadata.file_type()
}
};
Ok(Self { path, filename, ty })
}
pub fn path(&self) -> PathBuf {
self.path.clone()
}
pub fn file_name(&self) -> OsString {
self.filename.clone()
}
pub fn metadata(&self) -> io::Result<FileAttr> {
run_with_path_str(self.path.as_ref(), |path_str| get_metadata_inner(None, path_str, false))
}
pub fn file_type(&self) -> io::Result<FileType> {
Ok(self.ty)
}
}
impl DirBuilder {
pub fn new() -> Self {
Self { mode: OsFileMode::default_dir() }
}
pub fn mkdir(&self, path: &Path) -> io::Result<()> {
run_with_path_str(path, |path_str| {
unsafe { yggdrasil_rt::sys::create_directory(None, path_str, self.mode) }
.map_err(io::Error::from)
})
}
}
pub fn readdir(path: &Path) -> io::Result<ReadDir> {
ReadDir::open(path)
}
pub fn rmdir(path: &Path) -> io::Result<()> {
run_with_path_str(path, |path_str| {
yggdrasil_rt::io::remove_directory(None, path_str).map_err(io::Error::from)
})
}
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
run_with_path_str(path, |path_str| {
yggdrasil_rt::io::remove_directory_recursive(None, path_str).map_err(io::Error::from)
})
}
+252
View File
@@ -0,0 +1,252 @@
use yggdrasil_rt::io::{
FileMetadataUpdate, FileMetadataUpdateMode, FileMode as OsFileMode, FileTimesUpdate,
OpenOptions as OsOpenOptions,
};
use super::{FileAttr, FilePermissions, FileTimes};
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
use crate::path::Path;
use crate::sys::fd::FileDesc;
use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner};
#[derive(Debug)]
pub struct File(FileDesc);
#[derive(Clone, Copy, Debug)]
pub struct OpenOptions {
pub(crate) options: OsOpenOptions,
pub(crate) mode: OsFileMode,
}
impl OpenOptions {
pub fn new() -> Self {
Self::default()
}
pub fn read(&mut self, read: bool) {
if read {
self.options |= OsOpenOptions::READ;
} else {
self.options &= !OsOpenOptions::READ;
}
}
pub fn write(&mut self, write: bool) {
if write {
self.options |= OsOpenOptions::WRITE;
} else {
self.options &= !OsOpenOptions::WRITE;
}
}
pub fn append(&mut self, append: bool) {
if append {
self.options |= OsOpenOptions::APPEND;
} else {
self.options &= !OsOpenOptions::APPEND;
}
}
pub fn truncate(&mut self, truncate: bool) {
if truncate {
self.options |= OsOpenOptions::TRUNCATE;
} else {
self.options &= !OsOpenOptions::TRUNCATE;
}
}
pub fn create(&mut self, create: bool) {
if create {
self.options |= OsOpenOptions::CREATE;
} else {
self.options &= !OsOpenOptions::CREATE;
}
}
pub fn create_new(&mut self, create_new: bool) {
if create_new {
self.options |= OsOpenOptions::CREATE_EXCL | OsOpenOptions::CREATE;
} else {
self.options &= !OsOpenOptions::CREATE_EXCL | OsOpenOptions::CREATE;
}
}
}
impl Default for OpenOptions {
fn default() -> Self {
Self { mode: OsFileMode::default_file(), options: OsOpenOptions::default() }
}
}
impl File {
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
let path = path.as_os_str();
unsafe {
yggdrasil_rt::sys::open(None, path.to_str().unwrap(), opts.options, opts.mode)
.map(|fd| File::from_raw_fd(fd))
.map_err(io::Error::from)
}
}
pub fn file_attr(&self) -> io::Result<FileAttr> {
self.0.metadata()
}
pub fn fsync(&self) -> io::Result<()> {
self.0.fsync()
}
pub fn datasync(&self) -> io::Result<()> {
self.0.datasync()
}
pub fn truncate(&self, size: u64) -> io::Result<()> {
self.0.truncate(size)
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs)
}
#[inline]
pub fn is_read_vectored(&self) -> bool {
true
}
pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
self.0.read_buf(cursor)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs)
}
#[inline]
pub fn is_write_vectored(&self) -> bool {
true
}
pub fn lock(&self) -> io::Result<()> {
todo!("File::lock()")
}
pub fn lock_shared(&self) -> io::Result<()> {
todo!("File::lock_shared()")
}
pub fn try_lock(&self) -> Result<(), crate::fs::TryLockError> {
todo!("File::try_lock()")
}
pub fn try_lock_shared(&self) -> Result<(), crate::fs::TryLockError> {
todo!("File::try_lock_shared()")
}
pub fn unlock(&self) -> io::Result<()> {
todo!("File::unlock()")
}
pub fn flush(&self) -> io::Result<()> {
Ok(())
}
pub fn size(&self) -> Option<io::Result<u64>> {
// TODO
None
}
pub fn tell(&self) -> io::Result<u64> {
self.0.seek(SeekFrom::Current(0))
}
pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
self.0.seek(pos)
}
pub fn duplicate(&self) -> io::Result<File> {
self.0.try_clone().map(Self)
}
pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
unsafe {
yggdrasil_rt::sys::update_metadata(
Some(self.as_raw_fd()),
"",
&FileMetadataUpdate::Permissions(FileMetadataUpdateMode::Set(perm.0)),
)
}
.map_err(io::Error::from)
}
pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
unsafe {
yggdrasil_rt::sys::update_metadata(
Some(self.as_raw_fd()),
"",
&FileMetadataUpdate::Times(FileTimesUpdate {
atime: times.atime,
mtime: times.mtime,
ctime: None,
}),
)
}
.map_err(io::Error::from)
}
}
impl AsInner<FileDesc> for File {
fn as_inner(&self) -> &FileDesc {
&self.0
}
}
impl IntoInner<FileDesc> for File {
fn into_inner(self) -> FileDesc {
self.0
}
}
impl AsInnerMut<FileDesc> for File {
fn as_inner_mut(&mut self) -> &mut FileDesc {
&mut self.0
}
}
impl FromInner<FileDesc> for File {
fn from_inner(file_desc: FileDesc) -> Self {
Self(file_desc)
}
}
impl AsFd for File {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
impl AsRawFd for File {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
impl IntoRawFd for File {
fn into_raw_fd(self) -> RawFd {
self.0.into_raw_fd()
}
}
impl FromRawFd for File {
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) }
}
}
+89
View File
@@ -0,0 +1,89 @@
#![allow(exported_private_dependencies)]
use yggdrasil_rt::io::{AccessMode as OsAccessMode, Rename};
use crate::os::yggdrasil::fs::{MetadataExt, OpenOptionsExt};
use crate::path::{Path, PathBuf};
use crate::sys::run_with_path_str;
use crate::{io, os};
mod attr;
mod dir;
mod file;
pub(crate) use attr::get_metadata_inner;
pub use attr::{
FileAttr, FilePermissions, FileTimes, FileType, lstat, set_perm, set_times, set_times_nofollow,
stat,
};
pub use dir::{DirBuilder, DirEntry, ReadDir, readdir, remove_dir_all, rmdir};
pub use file::{File, OpenOptions};
pub use crate::sys::fs::common::Dir;
pub fn unlink(path: &Path) -> io::Result<()> {
run_with_path_str(path, |path_str| {
yggdrasil_rt::io::remove_file(None, path_str).map_err(io::Error::from)
})
}
pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
let old = old.to_str().unwrap();
let new = new.to_str().unwrap();
unsafe {
yggdrasil_rt::sys::rename(&Rename {
source_at: None,
destination_at: None,
source: old,
destination: new,
})
}?;
Ok(())
}
pub fn exists(path: &Path) -> io::Result<bool> {
run_with_path_str(path, |path| {
unsafe { yggdrasil_rt::sys::check_access(None, path, OsAccessMode::empty()) }
.map_err(io::Error::from)
})
.map(|_| true)
}
pub fn readlink(path: &Path) -> io::Result<PathBuf> {
// TODO PATH_MAX
let mut buf = [0; 4096];
let len = run_with_path_str(path, |path_str| {
unsafe { yggdrasil_rt::sys::read_link(None, path_str, &mut buf) }.map_err(io::Error::from)
})?;
// TODO error handling
let path = core::str::from_utf8(&buf[..len]).unwrap();
Ok(PathBuf::from(path))
}
pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
os::yggdrasil::fs::symlink(original, link)
}
pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
Err(io::Error::new(io::ErrorKind::Uncategorized, "Hard links are not implemented"))
}
pub fn canonicalize(path: &Path) -> io::Result<PathBuf> {
run_with_path_str(path, |path_str| {
yggdrasil_rt::io::canonicalize(path_str, |s| s.into()).map_err(io::Error::from)
})
}
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
let src_stat = from.metadata()?;
let raw_mode = src_stat.mode_ext();
let mut src = crate::fs::File::open(from)?;
let mut dst = crate::fs::OpenOptions::new()
.write(true)
.truncate(true)
.create(true)
.mode_ext(raw_mode)
.open(to)?;
crate::io::copy(&mut src, &mut dst)
}
+4
View File
@@ -39,6 +39,10 @@ cfg_select! {
mod xous;
pub use xous::*;
}
target_os = "yggdrasil" => {
mod yggdrasil;
pub use yggdrasil::*;
}
any(
target_os = "vexos",
target_family = "wasm",
+67
View File
@@ -0,0 +1,67 @@
use yggdrasil_rt::Error as OsError;
use crate::io::{self, RawOsError};
pub fn errno() -> i32 {
// Errors are not reported via errno
0
}
pub fn is_interrupted(code: i32) -> bool {
decode_error_kind(code) == io::ErrorKind::Interrupted
}
pub fn decode_error_kind(errno: i32) -> io::ErrorKind {
let errno = errno as u32;
match OsError::try_from(errno) {
// I/O kinds
Ok(OsError::DoesNotExist) | Ok(OsError::ProcessNotFound) => io::ErrorKind::NotFound,
Ok(OsError::AlreadyExists) => io::ErrorKind::AlreadyExists,
Ok(OsError::TimedOut) => io::ErrorKind::TimedOut,
Ok(OsError::IsADirectory) => io::ErrorKind::IsADirectory,
Ok(OsError::NotADirectory) => io::ErrorKind::NotADirectory,
Ok(OsError::DirectoryNotEmpty) => io::ErrorKind::DirectoryNotEmpty,
Ok(OsError::Interrupted) => io::ErrorKind::Interrupted,
Ok(OsError::WouldBlock) => io::ErrorKind::WouldBlock,
Ok(OsError::ReadOnly) => io::ErrorKind::ReadOnlyFilesystem,
Ok(OsError::PermissionDenied) => io::ErrorKind::PermissionDenied,
Ok(OsError::CrossDeviceLink) => io::ErrorKind::CrossesDevices,
Ok(OsError::UnrecognizedExecutable)
| Ok(OsError::MissingData)
| Ok(OsError::BufferTooSmall)
| Ok(OsError::QueueFull) => io::ErrorKind::InvalidData,
// Memory and general
Ok(OsError::OutOfMemory) => io::ErrorKind::OutOfMemory,
Ok(OsError::InvalidArgument)
| Ok(OsError::InvalidMemoryOperation)
| Ok(OsError::InvalidOperation)
| Ok(OsError::UndefinedSyscall) => io::ErrorKind::InvalidInput,
Ok(OsError::NotImplemented) => io::ErrorKind::Unsupported,
// Network
Ok(OsError::HostUnreachable) => io::ErrorKind::HostUnreachable,
Ok(OsError::NetworkUnreachable) => io::ErrorKind::NetworkUnreachable,
Ok(OsError::ConnectionReset) => io::ErrorKind::ConnectionReset,
Ok(OsError::ConnectionRefused) => io::ErrorKind::ConnectionRefused,
Ok(OsError::NotConnected) => io::ErrorKind::NotConnected,
Ok(OsError::AddrInUse) => io::ErrorKind::AddrInUse,
// Uncategorized
Ok(OsError::InvalidFile) => io::ErrorKind::Uncategorized,
Err(_) => io::ErrorKind::Uncategorized,
}
}
pub fn error_string(errno: i32) -> String {
crate::format!("{}", decode_error_kind(errno))
}
#[allow(exported_private_dependencies)]
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl From<yggdrasil_rt::Error> for crate::io::Error {
fn from(e: yggdrasil_rt::Error) -> Self {
let raw_os_error = u32::from(e) as RawOsError;
io::Error::from_raw_os_error(raw_os_error)
}
}
@@ -0,0 +1,6 @@
use crate::os::fd::{AsFd, AsRawFd};
pub fn is_terminal(fd: &impl AsFd) -> bool {
let fd = fd.as_fd();
yggdrasil_rt::io::terminal::is_terminal(fd.as_raw_fd())
}
+4
View File
@@ -41,6 +41,10 @@ mod is_terminal {
mod motor;
pub use motor::*;
}
target_os = "yggdrasil" => {
mod yggdrasil;
pub use yggdrasil::*;
}
_ => {
mod unsupported;
pub use unsupported::*;
@@ -29,6 +29,10 @@ cfg_select! {
mod uefi;
pub use uefi::*;
}
target_os = "yggdrasil" => {
mod yggdrasil;
pub use yggdrasil::*;
}
_ => {
mod unsupported;
pub use unsupported::*;
@@ -0,0 +1,189 @@
use yggdrasil_rt::net::dns::{
self, DnsClass, DnsMessage, DnsRecordData, DnsReplyCode, DnsType, UdpRequester,
};
use crate::fs::File;
use crate::io::{self, BufRead, BufReader};
use crate::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
use crate::os::fd::AsRawFd;
use crate::os::yggdrasil::io::poll::PollChannel;
use crate::os::yggdrasil::io::timer::TimerFd;
use crate::str::FromStr;
use crate::sys::pal::util::random;
use crate::time::Duration;
const TIMEOUT: u64 = 500;
const NAMESERVER: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 53);
const HOSTS_PATH: &str = "/etc/hosts";
pub struct LookupHost {
addresses: Vec<IpAddr>,
port: u16,
}
struct DnsRequester {
nameserver: SocketAddr,
poll: PollChannel,
timer: TimerFd,
socket: UdpSocket,
}
impl DnsRequester {
pub fn new(nameserver: SocketAddr) -> io::Result<Self> {
let mut poll = PollChannel::new()?;
let timer = TimerFd::new(false, false)?;
let socket = UdpSocket::bind("0.0.0.0:0")?;
poll.add(timer.as_raw_fd())?;
poll.add(socket.as_raw_fd())?;
Ok(Self { nameserver, poll, timer, socket })
}
}
impl UdpRequester for DnsRequester {
type Error = io::Error;
fn send_message(&mut self, message: &[u8]) -> io::Result<()> {
self.socket.send_to(message, &self.nameserver)?;
Ok(())
}
fn receive_message<F: Fn(&[u8]) -> Option<DnsMessage>>(
&mut self,
map: F,
) -> io::Result<DnsMessage> {
let mut buffer = [0; 2048];
self.timer.start(Duration::from_millis(TIMEOUT))?;
loop {
let (poll_fd, result) = self.poll.wait(None, true)?.unwrap();
result?;
match poll_fd {
fd if fd == self.socket.as_raw_fd() => {
let (len, _) = self.socket.recv_from(&mut buffer)?;
if let Some(message) = map(&buffer[..len]) {
return Ok(message);
}
}
fd if fd == self.timer.as_raw_fd() => {
return Err(io::Error::new(io::ErrorKind::TimedOut, "DNS query timed out"));
}
_ => unreachable!(),
}
}
}
}
// impl LookupHost {
// pub fn port(&self) -> u16 {
// self.port
// }
// }
impl Iterator for LookupHost {
type Item = SocketAddr;
fn next(&mut self) -> Option<SocketAddr> {
let ip = self.addresses.pop()?;
Some(SocketAddr::new(ip, self.port))
}
}
impl TryFrom<&str> for LookupHost {
type Error = io::Error;
fn try_from(s: &str) -> io::Result<Self> {
use crate::str::FromStr;
let (hostname, port) = s
.rsplit_once(':')
.ok_or(io::Error::new(io::ErrorKind::InvalidData, "Invalid host:port combination"))?;
let port =
u16::from_str(port).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
Self::try_from((hostname, port))
}
}
impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
type Error = io::Error;
fn try_from((hostname, port): (&'a str, u16)) -> io::Result<Self> {
if let Ok(addresses) = get_addresses_from_hosts(hostname) {
if !addresses.is_empty() {
return Ok(Self { addresses, port });
}
}
let addresses = get_addresses_from_dns(hostname)?;
Ok(Self { addresses, port })
}
}
pub fn lookup_host(query: &str, port: u16) -> io::Result<LookupHost> {
LookupHost::try_from((query, port))
}
fn get_addresses_from_hosts(hostname: &str) -> io::Result<Vec<IpAddr>> {
let reader = BufReader::new(File::open(HOSTS_PATH)?);
let mut addresses = vec![];
for line in reader.lines() {
let line = line?;
let line = line.trim();
if line.starts_with('#') {
continue;
}
let Some((address, host)) = line.split_once(' ') else {
continue;
};
let address = address.trim();
let host = host.trim();
let Ok(address) = IpAddr::from_str(address) else {
continue;
};
if host == hostname {
addresses.push(address);
}
}
Ok(addresses)
}
fn get_addresses_from_dns(hostname: &str) -> io::Result<Vec<IpAddr>> {
let xid = random();
let cookie = random();
let mut addresses = vec![];
let mut requester = DnsRequester::new(NAMESERVER)?;
let message = dns::perform_query(&mut requester, hostname, DnsType::A, xid, cookie)?;
if message.reply_code != DnsReplyCode::NO_ERROR {
return Err(io::Error::new(io::ErrorKind::Other, "DNS server returned error"));
}
for answer in message.answers {
let Some(name) = answer.name.0.as_ref() else {
continue;
};
let name = name.trim_end_matches('.');
if name != hostname {
continue;
}
match (answer.ty, answer.class, &answer.rdata) {
(DnsType::A, DnsClass::IN, DnsRecordData::A(address)) => {
addresses.push(IpAddr::V4(u32::from(*address).into()));
}
_ => (),
}
}
Ok(addresses)
}
@@ -0,0 +1,11 @@
#![allow(exported_private_dependencies)]
mod lookup_host;
mod tcp_listener;
mod tcp_stream;
mod udp_socket;
pub use lookup_host::lookup_host;
pub use tcp_listener::TcpListener;
pub use tcp_stream::TcpStream;
pub use udp_socket::UdpSocket;
@@ -0,0 +1,100 @@
use yggdrasil_rt::net as rt;
use super::TcpStream;
use crate::io;
use crate::net::{SocketAddr, ToSocketAddrs};
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
use crate::sys::fd::SocketFileDesc;
use crate::sys::net::connection::each_addr;
use crate::sys::{AsInner, FromInner, IntoInner};
#[derive(Debug)]
pub struct TcpListener(SocketFileDesc);
impl TcpListener {
fn try_bind(addr: &SocketAddr) -> io::Result<TcpListener> {
let raw = rt::bind_tcp(addr)?;
let fd = unsafe { SocketFileDesc::from_raw_fd(raw) };
Ok(Self(fd))
}
// pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
each_addr(addr, Self::try_bind)
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
self.0.local_addr()
}
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
let (fd, remote) = self.0.accept()?;
let stream = TcpStream::from_inner(fd);
Ok((stream, remote))
}
pub fn duplicate(&self) -> io::Result<TcpListener> {
self.0.try_clone().map(Self)
}
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
self.0.set_ttl(ttl)
}
pub fn ttl(&self) -> io::Result<u32> {
self.0.ttl()
}
pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
self.0.set_only_v6(only_v6)
}
pub fn only_v6(&self) -> io::Result<bool> {
self.0.only_v6()
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.0.take_error()
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
self.0.set_nonblocking(nonblocking)
}
}
impl FromInner<SocketFileDesc> for TcpListener {
fn from_inner(fd: SocketFileDesc) -> Self {
Self(fd)
}
}
impl IntoInner<SocketFileDesc> for TcpListener {
fn into_inner(self) -> SocketFileDesc {
self.0
}
}
impl AsInner<SocketFileDesc> for TcpListener {
fn as_inner(&self) -> &SocketFileDesc {
&self.0
}
}
impl FromRawFd for TcpListener {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self(SocketFileDesc::from_raw_fd(fd))
}
}
impl AsRawFd for TcpListener {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for crate::net::TcpListener {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().as_raw_fd()
}
}
@@ -0,0 +1,164 @@
use yggdrasil_rt::net as rt;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::net::{Shutdown, SocketAddr, ToSocketAddrs};
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
use crate::sys::fd::SocketFileDesc;
use crate::sys::net::connection::each_addr;
use crate::sys::{AsInner, FromInner, IntoInner};
use crate::time::Duration;
#[derive(Debug)]
pub struct TcpStream(SocketFileDesc);
impl TcpStream {
fn connect_inner(remote: &SocketAddr, timeout: Option<Duration>) -> io::Result<TcpStream> {
let fd = rt::connect_tcp(remote, timeout)?;
let fd = unsafe { SocketFileDesc::from_raw_fd(fd) };
Ok(Self(fd))
}
// pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
each_addr(addr, |addr| Self::connect_inner(addr, None))
}
pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
Self::connect_inner(addr, Some(timeout))
}
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
self.0.set_read_timeout(dur)
}
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
self.0.set_write_timeout(dur)
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
self.0.read_timeout()
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
self.0.write_timeout()
}
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.0.peek(buf)
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.0.recv(buf)
}
pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
self.0.recv_buf(buf)
}
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.0.recv_vectored(bufs)
}
#[inline]
pub fn is_read_vectored(&self) -> bool {
false
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.0.send(buf)
}
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.0.send_vectored(bufs)
}
#[inline]
pub fn is_write_vectored(&self) -> bool {
false
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.0.peer_addr()
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
self.0.local_addr()
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
self.0.shutdown(how)
}
pub fn duplicate(&self) -> io::Result<TcpStream> {
self.0.try_clone().map(Self)
}
pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
self.0.set_linger(linger)
}
pub fn linger(&self) -> io::Result<Option<Duration>> {
self.0.linger()
}
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
self.0.set_nodelay(nodelay)
}
pub fn nodelay(&self) -> io::Result<bool> {
self.0.nodelay()
}
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
self.0.set_ttl(ttl)
}
pub fn ttl(&self) -> io::Result<u32> {
self.0.ttl()
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.0.take_error()
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
self.0.set_nonblocking(nonblocking)
}
}
impl FromInner<SocketFileDesc> for TcpStream {
fn from_inner(fd: SocketFileDesc) -> Self {
Self(fd)
}
}
impl IntoInner<SocketFileDesc> for TcpStream {
fn into_inner(self) -> SocketFileDesc {
self.0
}
}
impl AsInner<SocketFileDesc> for TcpStream {
fn as_inner(&self) -> &SocketFileDesc {
&self.0
}
}
impl FromRawFd for TcpStream {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self(SocketFileDesc::from_raw_fd(fd))
}
}
impl AsRawFd for TcpStream {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for crate::net::TcpStream {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().as_raw_fd()
}
}
@@ -0,0 +1,187 @@
use yggdrasil_rt::net as rt;
use crate::io;
use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
use crate::sys::fd::SocketFileDesc;
use crate::sys::net::connection::each_addr;
use crate::sys::{AsInner, FromInner, IntoInner};
use crate::time::Duration;
#[derive(Debug)]
pub struct UdpSocket(SocketFileDesc);
impl UdpSocket {
fn try_bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
let raw = rt::bind_udp(addr)?;
let inner = unsafe { SocketFileDesc::from_raw_fd(raw) };
Ok(Self(inner))
}
// Should succeed on first call
fn try_connect(&self, addr: &SocketAddr) -> io::Result<()> {
rt::connect_udp(self.as_raw_fd(), addr)?;
Ok(())
}
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
each_addr(addr, Self::try_bind)
}
pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
each_addr(addr, |addr| self.try_connect(addr))
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.0.peer_addr()
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
self.0.local_addr()
}
pub fn recv(&self, buffer: &mut [u8]) -> io::Result<usize> {
self.0.recv(buffer)
}
pub fn recv_from(&self, buffer: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.0.recv_from(buffer)
}
pub fn send(&self, buffer: &[u8]) -> io::Result<usize> {
self.0.send(buffer)
}
pub fn send_to(&self, buffer: &[u8], dst: &SocketAddr) -> io::Result<usize> {
self.0.send_to(buffer, dst)
}
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.0.peek(buf)
}
pub fn peek_from(&self, buffer: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.0.peek_from(buffer)
}
pub fn duplicate(&self) -> io::Result<UdpSocket> {
self.0.try_clone().map(Self)
}
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
self.0.set_read_timeout(dur)
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
self.0.read_timeout()
}
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
self.0.set_write_timeout(dur)
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
self.0.write_timeout()
}
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
self.0.set_ttl(ttl)
}
pub fn ttl(&self) -> io::Result<u32> {
self.0.ttl()
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
self.0.set_nonblocking(nonblocking)
}
pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
self.0.set_broadcast(broadcast)
}
pub fn broadcast(&self) -> io::Result<bool> {
self.0.broadcast()
}
pub fn set_multicast_loop_v4(&self, loop_v4: bool) -> io::Result<()> {
self.0.set_multicast_loop_v4(loop_v4)
}
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
self.0.multicast_loop_v4()
}
pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
self.0.set_multicast_ttl_v4(ttl)
}
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
self.0.multicast_ttl_v4()
}
pub fn set_multicast_loop_v6(&self, loop_v6: bool) -> io::Result<()> {
self.0.set_multicast_loop_v6(loop_v6)
}
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
self.0.multicast_loop_v6()
}
pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
self.0.join_multicast_v6(multiaddr, interface)
}
pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
self.0.join_multicast_v4(multiaddr, interface)
}
pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
self.0.leave_multicast_v6(multiaddr, interface)
}
pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
self.0.leave_multicast_v4(multiaddr, interface)
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.0.take_error()
}
}
impl FromInner<SocketFileDesc> for UdpSocket {
fn from_inner(fd: SocketFileDesc) -> Self {
Self(fd)
}
}
impl IntoInner<SocketFileDesc> for UdpSocket {
fn into_inner(self) -> SocketFileDesc {
self.0
}
}
impl AsInner<SocketFileDesc> for UdpSocket {
fn as_inner(&self) -> &SocketFileDesc {
&self.0
}
}
impl FromRawFd for UdpSocket {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self(SocketFileDesc::from_raw_fd(fd))
}
}
impl AsRawFd for UdpSocket {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for crate::net::UdpSocket {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().as_raw_fd()
}
}
+4
View File
@@ -7,6 +7,10 @@ cfg_select! {
mod windows;
pub use windows::hostname;
}
target_os = "yggdrasil" => {
mod yggdrasil;
pub use yggdrasil::hostname;
}
_ => {
mod unsupported;
pub use unsupported::hostname;
@@ -0,0 +1,6 @@
use crate::ffi::OsString;
use crate::io::{Error, Result};
pub fn hostname() -> Result<OsString> {
Err(Error::UNSUPPORTED_PLATFORM)
}
+4
View File
@@ -60,6 +60,10 @@ cfg_select! {
mod zkvm;
pub use self::zkvm::*;
}
target_os = "yggdrasil" => {
mod yggdrasil;
pub use self::yggdrasil::*;
}
_ => {
mod unsupported;
pub use self::unsupported::*;
@@ -0,0 +1,11 @@
// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
// SAFETY: must be called only once during runtime cleanup.
// NOTE: this is not guaranteed to run, for example when the program aborts.
pub unsafe fn cleanup() {}
pub fn abort_internal() -> ! {
core::intrinsics::abort();
}
@@ -0,0 +1,43 @@
use yggdrasil_rt::process::{ExitCode as OsExitCode, ProgramArgumentInner};
use crate::sys::{args, env, signal, thread};
unsafe fn init_kernel_arg(program_arg: usize) {
unsafe {
let program_arg = crate::ptr::with_exposed_provenance::<ProgramArgumentInner>(program_arg);
let Some(program_arg) = program_arg.as_ref() else {
yggdrasil_rt::debug_trace!(Error, "Kernel provided NULL argument");
yggdrasil_rt::sys::exit_process(OsExitCode::Exited(1));
};
// Setup TLS as soon as possible
thread::init(program_arg.auxv());
// Setup real binary from auxv
crate::os::yggdrasil::set_real_program(program_arg);
args::imp::init(program_arg);
env::imp::init(program_arg);
}
}
#[cfg(not(test))]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn __rust_start(program_arg: usize, main_ptr: usize) -> ! {
unsafe { init_kernel_arg(program_arg) };
// Initialize signals
signal::init(true);
if main_ptr != 0 {
let main: unsafe extern "C" fn(isize, *const *const u8) -> i32 =
unsafe { core::mem::transmute(main_ptr) };
let result = unsafe { main(0, core::ptr::null()) };
unsafe { yggdrasil_rt::sys::exit_process(OsExitCode::Exited(result)) };
}
loop {}
// let main_ptr = (main as *const ()).addr();
// if main_ptr != 0 {
// let result = unsafe { main(0, null()) };
// }
}
@@ -0,0 +1,23 @@
use yggdrasil_rt::process::MutexOperation;
use yggdrasil_rt::sys;
use crate::sync::atomic::Atomic;
use crate::time::Duration;
pub type Primitive = u32;
pub type Futex = Atomic<Primitive>;
pub type SmallPrimitive = u32;
pub type SmallFutex = Atomic<SmallPrimitive>;
pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>) -> bool {
unsafe { sys::mutex(futex, &MutexOperation::WaitWhileEqual(expected, timeout)).is_ok() }
}
pub fn futex_wake(futex: &Atomic<u32>) -> bool {
unsafe { sys::mutex(futex, &MutexOperation::Wake(1)).ok() };
true
}
pub fn futex_wake_all(futex: &Atomic<u32>) {
unsafe { sys::mutex(futex, &MutexOperation::Wake(u32::MAX)).ok() };
}
+14
View File
@@ -0,0 +1,14 @@
#![deny(unsafe_op_in_unsafe_fn)]
pub mod futex;
pub mod os;
pub mod signal;
pub mod time;
pub mod util;
mod common;
mod entry;
mod path;
pub use common::*;
pub use path::*;
+108
View File
@@ -0,0 +1,108 @@
use yggdrasil_rt::process::ExitCode as OsExitCode;
use yggdrasil_rt::sys as syscall;
use crate::error::Error as StdError;
use crate::ffi::{OsStr, OsString};
use crate::path::{Path, PathBuf};
use crate::sys::{AsInner, FromInner, os_str, run_with_path_str};
use crate::{fmt, io, iter, mem, slice};
pub struct SplitPaths<'a> {
iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>, fn(&'a [u8]) -> PathBuf>,
}
#[derive(Debug)]
pub struct JoinPathsError;
impl<'a> Iterator for SplitPaths<'a> {
type Item = PathBuf;
fn next(&mut self) -> Option<PathBuf> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl fmt::Display for JoinPathsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "path segment contains separator `/`")
}
}
impl StdError for JoinPathsError {
#[allow(deprecated)]
fn description(&self) -> &str {
"failed to join paths"
}
}
pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
fn bytes_to_path(b: &[u8]) -> PathBuf {
PathBuf::from(unsafe { mem::transmute::<_, &OsStr>(b) })
}
fn is_separator(b: &u8) -> bool {
*b == b'/'
}
let unparsed = &unparsed.as_inner().inner;
SplitPaths {
iter: unparsed
.split(is_separator as fn(&u8) -> bool)
.map(bytes_to_path as fn(&[u8]) -> PathBuf),
}
}
pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
where
I: Iterator<Item = T>,
T: AsRef<OsStr>,
{
let mut joined = Vec::new();
for (i, path) in paths.enumerate() {
let path = &path.as_ref().as_inner().inner;
if i > 0 {
joined.push(b'/')
}
if path.contains(&b'/') {
return Err(JoinPathsError);
}
joined.extend_from_slice(path);
}
Ok(FromInner::from_inner(os_str::Buf { inner: joined }))
}
pub fn current_exe() -> io::Result<PathBuf> {
Ok(yggdrasil_rt::io::current_exe(|s| s.into())?)
}
pub fn home_dir() -> Option<PathBuf> {
yggdrasil_rt::io::home_directory(|s| s.into()).ok()
}
pub fn temp_dir() -> PathBuf {
// TODO prefix by pid
let mut template = *b"/tmp/dXXXXXXXXX";
yggdrasil_rt::io::make_temp_directory(&mut template)
.expect("Could not set up a temporary directory");
PathBuf::from(core::str::from_utf8(&template).unwrap())
}
pub fn getcwd() -> io::Result<PathBuf> {
Ok(yggdrasil_rt::io::current_directory(|s| s.into())?)
}
pub fn chdir(path: &Path) -> io::Result<()> {
run_with_path_str(path, |p| yggdrasil_rt::io::set_current_directory(p).map_err(io::Error::from))
}
pub fn exit(code: i32) -> ! {
let code = OsExitCode::Exited(code);
unsafe { syscall::exit_process(code) }
}
pub fn getpid() -> u32 {
unsafe { syscall::get_pid() }.into_raw()
}
@@ -0,0 +1,7 @@
use crate::path::Path;
#[inline]
pub fn run_with_path_str<T, F: FnOnce(&str) -> T>(path: &Path, f: F) -> T {
let path_str = path.to_str().unwrap();
f(path_str)
}
@@ -0,0 +1,44 @@
#![allow(exported_private_dependencies)]
use yggdrasil_rt::process::Signal;
use yggdrasil_rt::process::signal::{self as imp, SignalHandler as RtHandler};
use crate::os::yggdrasil::signal::SignalHandler as StdHandler;
const SIGNAL_STACK_SIZE: usize = 4096 * 8;
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl From<StdHandler> for RtHandler {
fn from(std: StdHandler) -> RtHandler {
match std {
StdHandler::Ignore => RtHandler::Ignore,
StdHandler::Terminate => RtHandler::Terminate,
StdHandler::Function(function) => RtHandler::Rust(function),
}
}
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl From<RtHandler> for StdHandler {
fn from(rt: RtHandler) -> StdHandler {
match rt {
RtHandler::Ignore => StdHandler::Ignore,
RtHandler::Terminate => StdHandler::Terminate,
RtHandler::Rust(function) => StdHandler::Function(function),
RtHandler::C(_) => unreachable!("std will never set a C signal handler"),
}
}
}
pub fn set_signal_handler(signal: Signal, handler: StdHandler) -> StdHandler {
imp::set_handler(signal, handler.into()).into()
}
pub fn init(main: bool) {
if main {
imp::setup_signal_full(SIGNAL_STACK_SIZE)
.expect("Couldn't setup signal handler for the main thread");
} else {
imp::setup_signal_stack(SIGNAL_STACK_SIZE).expect("Couldn't setup thread signal stack");
}
}
+51
View File
@@ -0,0 +1,51 @@
use yggdrasil_rt::time::{self as rt, SystemTime as SysTimespec};
use crate::time::Duration;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Instant(pub(crate) SysTimespec);
impl Instant {
pub fn now() -> Self {
Self(rt::get_monotonic_time().expect("Could not retrieve monotonic time value"))
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
self.0.checked_add_duration(other).map(Self)
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
self.0.checked_sub_duration(other).map(Self)
}
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
self.0.checked_sub_time(&other.0)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct SystemTime(pub(crate) SysTimespec);
pub const UNIX_EPOCH: SystemTime = SystemTime(SysTimespec::ZERO);
impl SystemTime {
pub const MAX: SystemTime = SystemTime(SysTimespec::MAX);
pub const MIN: SystemTime = SystemTime(SysTimespec::MIN);
pub fn now() -> Self {
Self(rt::get_real_time().expect("Could not retrieve real time value"))
}
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.0.sub_time(&other.0)
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<Self> {
self.0.checked_add_duration(other).map(Self)
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Self> {
self.0.checked_sub_duration(other).map(Self)
}
}
+48
View File
@@ -0,0 +1,48 @@
use crate::env;
use crate::path::PathBuf;
pub fn resolve_binary(name: &str) -> Option<String> {
// Already an absolute path
if name.starts_with('/') {
return None;
}
let Ok(path) = env::var("PATH") else {
return None;
};
for entry in path.split(':') {
let full_path = PathBuf::from(entry).join(name);
if full_path.exists() {
return Some(full_path.to_str().unwrap().to_owned());
}
}
None
}
macro_rules! impl_random_safe {
($($ty:ty),+) => {
$(impl RandomSafe for $ty {
unsafe fn __randomize(&mut self) {
let bytes: &mut [u8; size_of::<Self>()] = unsafe { $crate::mem::transmute(self) };
crate::sys::random::fill_bytes(bytes);
}
})+
};
}
pub trait RandomSafe: Default {
unsafe fn __randomize(&mut self);
}
impl_random_safe!(u8, u16, u32, u64);
pub fn random<T: RandomSafe>() -> T {
let mut v = T::default();
unsafe {
v.__randomize();
}
v
}
+4
View File
@@ -13,6 +13,10 @@ cfg_select! {
mod motor;
pub use motor::{Pipe, pipe};
}
target_os = "yggdrasil" => {
mod yggdrasil;
pub use yggdrasil::{Pipe, pipe};
}
_ => {
mod unsupported;
pub use unsupported::{Pipe, pipe};
+124
View File
@@ -0,0 +1,124 @@
#![allow(exported_private_dependencies)]
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, PipeReader, PipeWriter};
use crate::os::fd::{AsRawFd, IntoRawFd, OwnedFd, RawFd};
use crate::os::yggdrasil::io::pipe as os_pipe;
use crate::sys::fd::FileDesc;
use crate::sys::{FromInner, IntoInner};
#[derive(Debug)]
pub struct Pipe(FileDesc);
impl Pipe {
pub fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
self.0.read(buffer)
}
pub fn read_buf(&self, buffer: BorrowedCursor<'_>) -> io::Result<()> {
self.0.read_buf(buffer)
}
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs)
}
pub fn is_read_vectored(&self) -> bool {
true
}
pub fn read_to_end(&self, buffer: &mut Vec<u8>) -> io::Result<usize> {
self.0.read_to_end(buffer)
}
pub fn write(&self, buffer: &[u8]) -> io::Result<usize> {
self.0.write(buffer)
}
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs)
}
pub fn is_write_vectored(&self) -> bool {
true
}
pub fn try_clone(&self) -> io::Result<Self> {
self.0.try_clone().map(Self)
}
}
impl AsRawFd for Pipe {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
impl IntoRawFd for Pipe {
fn into_raw_fd(self) -> RawFd {
self.0.into_raw_fd()
}
}
impl FromInner<FileDesc> for Pipe {
fn from_inner(fd: FileDesc) -> Self {
Self(fd)
}
}
impl FromInner<OwnedFd> for Pipe {
fn from_inner(fd: OwnedFd) -> Self {
Self(FileDesc::from_inner(fd))
}
}
impl IntoInner<FileDesc> for Pipe {
fn into_inner(self) -> FileDesc {
self.0
}
}
#[inline]
pub fn pipe() -> io::Result<(Pipe, Pipe)> {
let (p0, p1) = os_pipe::create_pipe_pair(false, false)?;
Ok((Pipe::from_inner(p0), Pipe::from_inner(p1)))
}
// pub fn read2(p1: Pipe, v1: &mut Vec<u8>, p2: Pipe, v2: &mut Vec<u8>) -> io::Result<()> {
// let p1 = p1.into_inner();
// let p2 = p2.into_inner();
//
// let mut poll = PollChannel::new()?;
// poll.add(p1.as_raw_fd())?;
// poll.add(p2.as_raw_fd())?;
//
// loop {
// match poll.wait(None, true)? {
// Some((fd, _)) if fd == p1.as_raw_fd() => {
// p1.read_to_end(v1)?;
// p2.read_to_end(v2)?;
// break;
// }
// Some((fd, _)) if fd == p2.as_raw_fd() => {
// p2.read_to_end(v2)?;
// p1.read_to_end(v1)?;
// }
// _ => continue,
// }
// }
//
// Ok(())
// }
#[stable(feature = "rust1", since = "1.0.0")]
impl IntoRawFd for PipeReader {
fn into_raw_fd(self) -> RawFd {
self.0.into_raw_fd()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl IntoRawFd for PipeWriter {
fn into_raw_fd(self) -> RawFd {
self.0.into_raw_fd()
}
}
+8 -2
View File
@@ -15,6 +15,10 @@ cfg_select! {
mod motor;
use motor as imp;
}
target_os = "yggdrasil" => {
mod yggdrasil;
use yggdrasil as imp;
}
_ => {
mod unsupported;
use unsupported as imp;
@@ -43,7 +47,8 @@ pub use imp::{
))
),
target_os = "windows",
target_os = "motor"
target_os = "motor",
target_os = "yggdrasil"
))]
pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
let (mut process, mut pipes) = cmd.spawn(Stdio::MakePipe, false)?;
@@ -81,6 +86,7 @@ pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec<u8>, Vec<
))
),
target_os = "windows",
target_os = "motor"
target_os = "motor",
target_os = "yggdrasil"
)))]
pub use imp::output;
@@ -0,0 +1,208 @@
use yggdrasil_rt::process::{
ProcessGroupId as OsProcessGroupId, SpawnFlags, SpawnOption, SpawnOptions,
};
use yggdrasil_rt::sys as syscall;
use super::{ChildPipes, Process, Stdio};
use crate::ffi::OsStr;
use crate::os::fd::RawFd;
use crate::path::{Path, PathBuf};
use crate::process::StdioPipes;
use crate::sys::process::env::{CommandEnv, CommandEnvs};
use crate::sys::util;
use crate::{fmt, io};
#[derive(Debug)]
pub struct Command {
program: String,
args: Vec<String>,
env: CommandEnv,
cwd: Option<PathBuf>,
pub(crate) root: Option<PathBuf>,
pub(crate) pgroup: Option<OsProcessGroupId>,
pub(crate) gain_terminal: Option<RawFd>,
pub(crate) attach_trace: bool,
pub(crate) flags: SpawnFlags,
stdin: Stdio,
stdout: Stdio,
stderr: Stdio,
}
pub struct CommandArgs<'a>(crate::slice::Iter<'a, String>);
impl Command {
pub fn new(program: &OsStr) -> Self {
let program = program.to_str().unwrap().to_owned();
Self {
program,
args: vec![],
env: Default::default(),
cwd: None,
root: None,
pgroup: None,
gain_terminal: None,
attach_trace: false,
flags: SpawnFlags::const_default(),
stdin: Stdio::Inherit,
stdout: Stdio::Inherit,
stderr: Stdio::Inherit,
}
}
pub fn arg(&mut self, arg: &OsStr) {
if arg.len() == 0 {
self.args.push(String::new());
} else {
let arg = arg.to_str().unwrap().to_owned();
self.args.push(arg);
}
}
pub fn env_mut(&mut self) -> &mut CommandEnv {
&mut self.env
}
pub fn cwd(&mut self, dir: &OsStr) {
self.cwd = Some(dir.into());
}
pub fn stdin(&mut self, stdin: Stdio) {
self.stdin = stdin;
}
pub fn stdout(&mut self, stdout: Stdio) {
self.stdout = stdout;
}
pub fn stderr(&mut self, stderr: Stdio) {
self.stderr = stderr;
}
pub fn get_program(&self) -> &OsStr {
self.program.as_str().as_ref()
}
pub fn get_args(&self) -> CommandArgs<'_> {
CommandArgs(self.args.iter())
}
pub fn get_envs(&self) -> CommandEnvs<'_> {
self.env.iter()
}
pub fn get_env_clear(&self) -> bool {
self.env.does_clear()
}
pub fn get_current_dir(&self) -> Option<&Path> {
self.cwd.as_deref()
}
pub fn spawn(
&mut self,
_default: Stdio,
_needs_stdin: bool,
) -> io::Result<(Process, StdioPipes)> {
// let default_stdin = if needs_stdin { &default } else { &self.stdin };
let stdin = &self.stdin;
let stdout = &self.stdout;
let stderr = &self.stderr;
let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
let ours = StdioPipes { stdin: our_stdin, stdout: our_stdout, stderr: our_stderr };
let theirs = ChildPipes { stdin: their_stdin, stdout: their_stdout, stderr: their_stderr };
let process = self.do_spawn(&theirs)?;
Ok((process, ours))
}
fn do_spawn(&mut self, pipes: &ChildPipes) -> io::Result<Process> {
let mut optional = Vec::new();
if let Some(stdin) = pipes.stdin.as_inherit_option(RawFd::STDIN) {
optional.push(stdin);
}
if let Some(stdout) = pipes.stdout.as_inherit_option(RawFd::STDOUT) {
optional.push(stdout);
}
if let Some(stderr) = pipes.stderr.as_inherit_option(RawFd::STDERR) {
optional.push(stderr);
}
if let Some(pgroup) = self.pgroup {
optional.push(SpawnOption::SetProcessGroup(pgroup));
}
if let Some(fd) = self.gain_terminal {
optional.push(SpawnOption::GainTerminal(fd));
}
if self.attach_trace {
optional.push(SpawnOption::AttachTrace);
}
let program = self.program.as_str();
let arguments = &Vec::from_iter(
crate::iter::once(self.program.as_str())
.chain(self.args.iter().map(|arg| arg.as_str())),
);
let program = &util::resolve_binary(program).unwrap_or_else(|| program.to_owned());
let envs = Vec::from_iter(self.env.capture().iter().filter_map(|(key, value)| {
let key = key.to_str()?;
let value = value.to_str()?;
Some(format!("{}={}", key, value))
}));
let directory = self.cwd.as_ref().map(|cwd| cwd.to_str().unwrap());
let root = self.root.as_ref().map(|root| root.to_str().unwrap());
let environment = &Vec::from_iter(envs.iter().map(|x| x.as_str()));
let options = SpawnOptions {
program,
arguments,
environment,
directory,
root,
optional: &optional,
flags: self.flags,
};
let pid = unsafe { syscall::spawn_process(&options) }?;
Ok(Process { pid })
}
pub(crate) fn change_root<P: AsRef<Path>>(&mut self, root: P) {
self.root = Some(root.as_ref().into());
}
}
impl<'a> Iterator for CommandArgs<'a> {
type Item = &'a OsStr;
fn next(&mut self) -> Option<&'a OsStr> {
self.0.next().map(|s| s.as_ref())
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<'a> ExactSizeIterator for CommandArgs<'a> {}
impl<'a> fmt::Debug for CommandArgs<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
@@ -0,0 +1,92 @@
#![allow(exported_private_dependencies)]
use yggdrasil_rt::process::{
self as rt, ExitCode as OsExitCode, ProcessId as OsProcessId, ProcessWait, Signal as OsSignal,
WaitFlags,
};
use yggdrasil_rt::sys as syscall;
use crate::io;
use crate::os::fd::AsRawFd;
use crate::os::yggdrasil::io::poll::PollChannel;
mod command;
mod status;
mod stdio;
pub use command::{Command, CommandArgs};
pub use status::{ExitCode, ExitStatus, ExitStatusError};
pub use stdio::{ChildPipes, Stdio};
pub use crate::ffi::OsString as EnvKey;
// Process
pub struct Process {
pid: OsProcessId,
}
impl Process {
pub fn id(&self) -> u32 {
self.pid.into_raw()
}
pub fn main_thread_id(&self) -> io::Result<u32> {
Ok(rt::get_process_option!(Some(self.pid), rt::options::MainThread)?.into_raw())
}
pub fn kill(&mut self) -> io::Result<()> {
unsafe { syscall::send_signal(self.pid, OsSignal::Killed) }?;
Ok(())
}
fn wait_impl(&mut self, flags: WaitFlags) -> io::Result<ExitStatus> {
let mut status = OsExitCode::Exited(0);
unsafe { syscall::wait_process(&ProcessWait::Process(self.pid), &mut status, flags) }?;
Ok(ExitStatus(status))
}
pub fn wait(&mut self) -> io::Result<ExitStatus> {
self.wait_impl(WaitFlags::empty())
}
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
match self.wait_impl(WaitFlags::NON_BLOCKING) {
Ok(s) => Ok(Some(s)),
Err(e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
Err(e) => Err(e),
}
}
}
// ChildPipe
pub type ChildPipe = crate::sys::pipe::Pipe;
pub fn read_output(
out: ChildPipe,
stdout: &mut Vec<u8>,
err: ChildPipe,
stderr: &mut Vec<u8>,
) -> io::Result<()> {
let mut poll = PollChannel::new()?;
poll.add(out.as_raw_fd())?;
poll.add(err.as_raw_fd())?;
loop {
match poll.wait(None, true)? {
Some((fd, _)) if fd == out.as_raw_fd() => {
out.read_to_end(stdout)?;
err.read_to_end(stderr)?;
break;
}
Some((fd, _)) if fd == err.as_raw_fd() => {
err.read_to_end(stderr)?;
out.read_to_end(stdout)?;
}
_ => continue,
}
}
Ok(())
}
@@ -0,0 +1,75 @@
use yggdrasil_rt::process::{ExitCode as OsExitCode, Signal as OsSignal};
use crate::fmt;
use crate::num::NonZeroI32;
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct ExitStatus(pub(super) OsExitCode);
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct ExitStatusError(pub(super) NonZeroI32);
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct ExitCode(pub(super) bool);
impl ExitStatus {
pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
if let Some(error) = self.0.as_failure() { Err(ExitStatusError(error)) } else { Ok(()) }
}
pub fn code(&self) -> Option<i32> {
match self.0 {
OsExitCode::Exited(code) => Some(code),
_ => None,
}
}
pub fn signal(&self) -> Option<Result<OsSignal, u32>> {
self.0.signal()
}
}
impl Default for ExitStatus {
fn default() -> Self {
Self(OsExitCode::SUCCESS)
}
}
impl ExitStatusError {
pub fn code(self) -> Option<NonZeroI32> {
Some(self.0)
}
}
impl From<ExitStatusError> for ExitStatus {
fn from(value: ExitStatusError) -> Self {
Self(OsExitCode::from(i32::from(value.0)))
}
}
impl ExitCode {
pub const SUCCESS: Self = Self(false);
pub const FAILURE: Self = Self(true);
pub fn as_i32(&self) -> i32 {
self.0 as i32
}
}
impl From<u8> for ExitCode {
fn from(value: u8) -> Self {
Self(value != 0)
}
}
impl fmt::Debug for ExitStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl fmt::Display for ExitStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
@@ -0,0 +1,105 @@
use yggdrasil_rt::process::SpawnOption;
use crate::io::{self, Stderr, Stdin, Stdout};
use crate::os::fd::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::os::yggdrasil::io::pipe as os_pipe;
use crate::sys::FromInner;
use crate::sys::fs::File;
use crate::sys::pipe::Pipe;
#[derive(Debug)]
pub struct ChildPipes {
pub stdin: ChildStdio,
pub stdout: ChildStdio,
pub stderr: ChildStdio,
}
#[derive(Debug)]
pub enum ChildStdio {
Inherit,
Null,
CopyFd(RawFd),
MoveFd(RawFd),
}
#[derive(Debug)]
pub enum Stdio {
Inherit,
Null,
MakePipe,
MoveFd(RawFd),
CopyFd(RawFd),
}
impl Stdio {
pub fn to_child_stdio(&self, readable: bool) -> io::Result<(ChildStdio, Option<Pipe>)> {
match self {
Stdio::Inherit => Ok((ChildStdio::Inherit, None)),
Stdio::Null => Ok((ChildStdio::Null, None)),
Stdio::MakePipe => {
let (read, write) = os_pipe::create_pipe_pair(false, false)?;
if readable {
let write = Pipe::from_inner(write);
Ok((ChildStdio::MoveFd(read.into_raw_fd()), Some(write)))
} else {
let read = Pipe::from_inner(read);
Ok((ChildStdio::MoveFd(write.into_raw_fd()), Some(read)))
}
}
Stdio::MoveFd(fd) => Ok((ChildStdio::MoveFd(*fd), None)),
Stdio::CopyFd(fd) => Ok((ChildStdio::CopyFd(*fd), None)),
}
}
}
#[allow(ineffective_unstable_trait_impl)]
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl FromRawFd for crate::process::Stdio {
#[inline]
unsafe fn from_raw_fd(fd: RawFd) -> crate::process::Stdio {
let io = Stdio::MoveFd(fd);
crate::process::Stdio::from_inner(io)
}
}
impl From<Pipe> for Stdio {
fn from(pipe: Pipe) -> Stdio {
Self::MoveFd(pipe.into_raw_fd())
}
}
impl From<File> for Stdio {
fn from(file: File) -> Stdio {
Self::MoveFd(file.into_raw_fd())
}
}
impl From<Stdin> for Stdio {
fn from(s: Stdin) -> Stdio {
Self::CopyFd(s.as_raw_fd())
}
}
impl From<Stdout> for Stdio {
fn from(s: Stdout) -> Stdio {
Self::CopyFd(s.as_raw_fd())
}
}
impl From<Stderr> for Stdio {
fn from(s: Stderr) -> Stdio {
Self::CopyFd(s.as_raw_fd())
}
}
impl ChildStdio {
pub(super) fn as_inherit_option(&self, child: RawFd) -> Option<SpawnOption> {
match self {
Self::Inherit => Some(SpawnOption::CopyFile { source: child, child }),
&Self::MoveFd(fd) => Some(SpawnOption::MoveFile { source: fd, child }),
&Self::CopyFd(fd) => Some(SpawnOption::CopyFile { source: fd, child }),
Self::Null => None,
}
}
}
+4
View File
@@ -102,6 +102,10 @@ cfg_select! {
mod zkvm;
pub use zkvm::fill_bytes;
}
target_os = "yggdrasil" => {
mod yggdrasil;
pub use yggdrasil::fill_bytes;
}
any(
all(target_family = "wasm", target_os = "unknown"),
target_os = "xous",
+16
View File
@@ -0,0 +1,16 @@
#[inline(always)]
pub fn fill_bytes(buffer: &mut [u8]) {
unsafe { yggdrasil_rt::sys::get_random(buffer) }
}
// pub fn hashmap_random_keys() -> (u64, u64) {
// const KEY_LEN: usize = crate::mem::size_of::<u64>();
//
// let mut v = [0u8; KEY_LEN * 2];
// fill_bytes(&mut v);
//
// let key1 = v[0..KEY_LEN].try_into().unwrap();
// let key2 = v[KEY_LEN..].try_into().unwrap();
//
// (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2))
// }
+4
View File
@@ -45,6 +45,10 @@ cfg_select! {
mod zkvm;
pub use zkvm::*;
}
target_os = "yggdrasil" => {
mod yggdrasil;
pub use yggdrasil::*;
}
_ => {
mod unsupported;
pub use unsupported::*;
+125
View File
@@ -0,0 +1,125 @@
use yggdrasil_rt::Error as OsError;
use yggdrasil_rt::io::RawFd;
use crate::io;
use crate::io::{IoSlice, IoSliceMut};
use crate::sealed::Sealed;
pub struct Stdin;
pub struct Stdout;
pub struct Stderr;
impl Sealed for Stdin {}
impl Stdin {
pub const fn new() -> Self {
Self
}
}
impl Sealed for Stdout {}
impl Stdout {
pub const fn new() -> Self {
Self
}
}
impl Sealed for Stderr {}
impl Stderr {
pub const fn new() -> Self {
Self
}
}
impl io::Read for Stdin {
fn read(&mut self, data: &mut [u8]) -> io::Result<usize> {
Ok(unsafe { yggdrasil_rt::sys::read(RawFd::STDIN, data) }?)
}
fn read_vectored(&mut self, _data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
unimplemented!()
}
#[inline]
fn is_read_vectored(&self) -> bool {
false
}
}
impl io::Write for Stdout {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
Ok(unsafe { yggdrasil_rt::sys::write(RawFd::STDOUT, data) }?)
}
fn write_vectored(&mut self, _data: &[IoSlice<'_>]) -> io::Result<usize> {
unimplemented!()
}
#[inline]
fn is_write_vectored(&self) -> bool {
false
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl io::Write for Stderr {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
Ok(unsafe { yggdrasil_rt::sys::write(RawFd::STDERR, data) }?)
}
fn write_vectored(&mut self, _data: &[IoSlice<'_>]) -> io::Result<usize> {
unimplemented!()
}
#[inline]
fn is_write_vectored(&self) -> bool {
false
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
pub const STDIN_BUF_SIZE: usize = 64;
impl crate::io::IsTerminal for Stdin {
fn is_terminal(&self) -> bool {
yggdrasil_rt::io::terminal::is_terminal(RawFd::STDIN)
}
}
pub fn is_ebadf(err: &io::Error) -> bool {
err.raw_os_error() == Some(u32::from(OsError::InvalidFile) as i32)
}
pub struct PanicOutput {
stderr: Stderr,
}
impl PanicOutput {
pub fn new() -> Self {
Self { stderr: Stderr::new() }
}
}
impl io::Write for PanicOutput {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
yggdrasil_rt::debug::trace_raw(yggdrasil_rt::debug::TraceLevel::Error, buf);
self.stderr.write(buf).ok();
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
pub fn panic_output() -> Option<impl io::Write> {
Some(PanicOutput::new())
}
+1
View File
@@ -10,6 +10,7 @@ cfg_select! {
target_os = "fuchsia",
all(target_family = "wasm", target_feature = "atomics"),
target_os = "hermit",
target_os = "yggdrasil",
) => {
mod futex;
pub use futex::Condvar;
+1
View File
@@ -9,6 +9,7 @@ cfg_select! {
target_os = "dragonfly",
all(target_family = "wasm", target_feature = "atomics"),
target_os = "hermit",
target_os = "yggdrasil",
) => {
mod futex;
pub use futex::Mutex;
+2 -1
View File
@@ -9,7 +9,8 @@ cfg_select! {
target_os = "fuchsia",
all(target_family = "wasm", target_feature = "atomics"),
target_os = "hermit",
target_os = "motor",
target_os = "motor",
target_os = "yggdrasil",
) => {
mod futex;
pub use futex::RwLock;
+5
View File
@@ -48,6 +48,11 @@ cfg_select! {
mod unsupported;
pub use unsupported::{Thread, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
}
target_os = "yggdrasil" => {
mod yggdrasil;
pub use yggdrasil::{available_parallelism, sleep, Thread, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
pub(crate) use yggdrasil::init;
}
any(target_family = "unix", target_os = "wasi") => {
mod unix;
pub use unix::{Thread, available_parallelism, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+80
View File
@@ -0,0 +1,80 @@
use yggdrasil_rt::process::{self, AuxValue, ExitCode as OsExitCode, thread as rt, thread_local};
use crate::boxed::Box;
use crate::ffi::CStr;
use crate::io;
use crate::num::NonZeroUsize;
use crate::thread::ThreadInit;
use crate::time::Duration;
#[repr(C)]
pub struct Thread {
inner: rt::ThreadHandle<()>,
}
pub const DEFAULT_MIN_STACK_SIZE: usize = 8192;
// TODO put it into OnceLock
pub(super) static mut TLS_IMAGE: Option<thread_local::TlsImage> = None;
impl Thread {
pub unsafe fn new(stack_size: usize, init: Box<ThreadInit>) -> io::Result<Thread> {
// Unused now
let _ = set_name;
let info = rt::ThreadCreateInfo {
signal_stack: rt::ThreadSignalStack::Allocate(4096 * 8),
stack: rt::ThreadStack::Allocate(stack_size),
entry: rt::ThreadFunction::Pointer(Self::entry),
#[allow(static_mut_refs)]
tls_image: TLS_IMAGE.as_ref(),
};
let inner = rt::Thread::spawn(info, init, false)?;
Ok(Thread { inner })
}
pub fn join(self) {
self.inner.join_uninterruptible();
}
fn entry(init: Box<ThreadInit>) {
let start = init.init();
(start)();
}
}
pub fn set_name(name: &CStr) {
rt::Thread::<()>::set_name(
name.to_str().expect("Thread::set_name() expects a valid UTF-8 string"),
);
}
pub fn current_os_id() -> Option<u64> {
Some(unsafe { yggdrasil_rt::sys::get_tid() as u64 })
}
pub fn yield_now() {
yggdrasil_rt::debug_trace!(Error, "thread::yield_now()");
loop {}
}
pub fn sleep(duration: Duration) {
process::uninterruptible_sleep(duration)
}
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
yggdrasil_rt::debug_trace!(Error, "thread::available_parallelism()");
loop {}
}
pub(crate) unsafe fn init<'a, I: Iterator<Item = &'a AuxValue>>(auxv: I) {
// Rust doesn't have a pthread_self, so just reserve two slots in the TCB:
// * self-pointer
// * DTV pointer
let image = thread_local::TlsImage::from_auxv(auxv);
if let Err(error) = thread_local::init_tls(image.as_ref(), false) {
yggdrasil_rt::debug_trace!(Debug, "Could not setup main thread TLS: {error:?}");
// TODO kill self with ABORTED signal instead
yggdrasil_rt::sys::exit_process(OsExitCode::Exited(1));
}
TLS_IMAGE = image;
}
@@ -0,0 +1,21 @@
use yggdrasil_rt::process::thread_local as imp;
pub type Key = usize;
#[inline]
pub unsafe fn set(key: Key, value: *mut u8) {
let dtv = imp::get_dtv();
dtv.set_specific(key, value.cast(), true);
}
#[inline]
pub fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
// TODO dtors
let dtv = imp::get_dtv();
dtv.new_specific()
}
#[inline]
pub unsafe fn destroy(_key: Key) {
// TODO dtors
}
+9
View File
@@ -195,6 +195,15 @@ pub(crate) mod key {
pub(super) use moto_rt::tls::{Key, get, set};
use moto_rt::tls::{create, destroy};
}
target_os = "yggdrasil" => {
mod racy;
#[cfg(test)]
mod tests;
mod yggdrasil;
pub(super) use racy::LazyKey;
pub(super) use yggdrasil::{Key, set};
use yggdrasil::{create, destroy};
}
_ => {}
}
}
+61 -16
View File
@@ -930,29 +930,41 @@ impl Step for StartupObjects {
let target = self.target;
// Even though no longer necessary on x86_64, they are kept for now to
// avoid potential issues in downstream crates.
if !target.is_windows_gnu() {
if !target.is_windows_gnu() && !target.ends_with("-yggdrasil") {
return vec![];
}
let mut target_deps = vec![];
if target.ends_with("-yggdrasil") {
let dst_dir = &builder.native_dir(target).join("rtstartup");
let sysroot_dir = &builder.sysroot_target_libdir(for_compiler, target);
t!(fs::create_dir_all(dst_dir));
let src_dir = &builder.src.join("library").join("rtstartup");
let dst_dir = &builder.native_dir(target).join("rtstartup");
let sysroot_dir = &builder.sysroot_target_libdir(for_compiler, target);
t!(fs::create_dir_all(dst_dir));
let src_file = &builder.src.join("library/rtstartup/yggdrasil_rust_entry.rs");
let dst_file = &dst_dir.join("rust_entry0.o");
let target_file = sysroot_dir.join("rust_entry0.o");
for file in &["rsbegin", "rsend"] {
let src_file = &src_dir.join(file.to_string() + ".rs");
let dst_file = &dst_dir.join(file.to_string() + ".o");
if !up_to_date(src_file, dst_file) {
let mut cmd = command(&builder.initial_rustc);
// FIXME(alnyan) do this properly
let fake_target = if target.starts_with("aarch64-") {
"aarch64-unknown-none"
} else if target.starts_with("x86_64-") {
"x86_64-unknown-none"
} else if target.starts_with("i686-") {
"i686-unknown-linux-gnu"
} else if target.starts_with("riscv64-") {
"riscv64imac-unknown-none-elf"
} else {
unimplemented!("This code shouldn't be reachable");
};
cmd.env("RUSTC_BOOTSTRAP", "1");
if !builder.local_rebuild {
// a local_rebuild compiler already has stage1 features
cmd.arg("--cfg").arg("bootstrap");
}
cmd.arg("--target")
.arg(target.rustc_target_arg())
.arg(fake_target)
.arg("--emit=obj")
.arg("-o")
.arg(dst_file)
@@ -960,12 +972,45 @@ impl Step for StartupObjects {
.run(builder);
}
let obj = sysroot_dir.join((*file).to_string() + ".o");
builder.copy_link(dst_file, &obj, FileType::NativeLibrary);
target_deps.push((obj, DependencyType::Target));
}
builder.copy_link(dst_file, &target_file, FileType::NativeLibrary);
// builder.copy_link(dst_file, &target);
// target_deps.push((target, DependencyType::Target));
target_deps
vec![(target_file, DependencyType::Target)]
} else {
let mut target_deps = vec![];
let src_dir = &builder.src.join("library").join("rtstartup");
let dst_dir = &builder.native_dir(target).join("rtstartup");
let sysroot_dir = &builder.sysroot_target_libdir(for_compiler, target);
t!(fs::create_dir_all(dst_dir));
for file in &["rsbegin", "rsend"] {
let src_file = &src_dir.join(file.to_string() + ".rs");
let dst_file = &dst_dir.join(file.to_string() + ".o");
if !up_to_date(src_file, dst_file) {
let mut cmd = command(&builder.initial_rustc);
cmd.env("RUSTC_BOOTSTRAP", "1");
if !builder.local_rebuild {
// a local_rebuild compiler already has stage1 features
cmd.arg("--cfg").arg("bootstrap");
}
cmd.arg("--target")
.arg(target.rustc_target_arg())
.arg("--emit=obj")
.arg("-o")
.arg(dst_file)
.arg(src_file)
.run(builder);
}
let obj = sysroot_dir.join((*file).to_string() + ".o");
builder.copy_link(dst_file, &obj, FileType::NativeLibrary);
target_deps.push((obj, DependencyType::Target));
}
target_deps
}
}
}
+3
View File
@@ -38,6 +38,9 @@ pub struct Finder {
const STAGE0_MISSING_TARGETS: &[&str] = &[
// just a dummy comment so the list doesn't get onelined
"riscv64im-unknown-none-elf",
"x86_64-unknown-yggdrasil",
"aarch64-unknown-yggdrasil",
"riscv64-unknown-yggdrasil",
];
/// Minimum version threshold for libstdc++ required when using prebuilt LLVM
+1
View File
@@ -444,6 +444,7 @@ impl fmt::Display for Display<'_> {
"watchos" => "watchOS",
"windows" => "Windows",
"visionos" => "visionOS",
"yggdrasil" => "Yggdrasil",
_ => "",
},
(sym::target_arch, Some(arch)) => match arch.as_str() {