summaryrefslogtreecommitdiffstats
path: root/library/std/src/os
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /library/std/src/os
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/std/src/os')
-rw-r--r--library/std/src/os/fd/owned.rs12
-rw-r--r--library/std/src/os/fd/raw.rs5
-rw-r--r--library/std/src/os/fortanix_sgx/io.rs23
-rw-r--r--library/std/src/os/hurd/fs.rs348
-rw-r--r--library/std/src/os/hurd/mod.rs6
-rw-r--r--library/std/src/os/hurd/raw.rs33
-rw-r--r--library/std/src/os/mod.rs6
-rw-r--r--library/std/src/os/solid/io.rs22
-rw-r--r--library/std/src/os/uefi/env.rs92
-rw-r--r--library/std/src/os/uefi/mod.rs8
-rw-r--r--library/std/src/os/unix/fs.rs6
-rw-r--r--library/std/src/os/unix/io/mod.rs16
-rw-r--r--library/std/src/os/unix/mod.rs2
-rw-r--r--library/std/src/os/unix/net/tests.rs2
-rw-r--r--library/std/src/os/unix/process.rs42
-rw-r--r--library/std/src/os/wasi/fs.rs4
-rw-r--r--library/std/src/os/windows/io/mod.rs10
-rw-r--r--library/std/src/os/windows/io/raw.rs6
-rw-r--r--library/std/src/os/windows/io/socket.rs8
-rw-r--r--library/std/src/os/windows/process.rs108
-rw-r--r--library/std/src/os/xous/ffi.rs647
-rw-r--r--library/std/src/os/xous/ffi/definitions.rs283
-rw-r--r--library/std/src/os/xous/ffi/definitions/memoryflags.rs176
-rw-r--r--library/std/src/os/xous/mod.rs17
-rw-r--r--library/std/src/os/xous/services.rs132
-rw-r--r--library/std/src/os/xous/services/log.rs63
-rw-r--r--library/std/src/os/xous/services/systime.rs28
-rw-r--r--library/std/src/os/xous/services/ticktimer.rs42
28 files changed, 2105 insertions, 42 deletions
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 2180d2974..81106d6c6 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -15,8 +15,9 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
/// A borrowed file descriptor.
///
-/// This has a lifetime parameter to tie it to the lifetime of something that
-/// owns the file descriptor.
+/// This has a lifetime parameter to tie it to the lifetime of something that owns the file
+/// descriptor. For the duration of that lifetime, it is guaranteed that nobody will close the file
+/// descriptor.
///
/// This uses `repr(transparent)` and has the representation of a host file
/// descriptor, so it can be used in FFI in places where a file descriptor is
@@ -42,7 +43,8 @@ pub struct BorrowedFd<'fd> {
/// An owned file descriptor.
///
-/// This closes the file descriptor on drop.
+/// This closes the file descriptor on drop. It is guaranteed that nobody else will close the file
+/// descriptor.
///
/// This uses `repr(transparent)` and has the representation of a host file
/// descriptor, so it can be used in FFI in places where a file descriptor is
@@ -155,7 +157,9 @@ impl FromRawFd for OwnedFd {
/// # Safety
///
/// The resource pointed to by `fd` must be open and suitable for assuming
- /// ownership. The resource must not require any cleanup other than `close`.
+ /// [ownership][io-safety]. The resource must not require any cleanup other than `close`.
+ ///
+ /// [io-safety]: io#io-safety
#[inline]
unsafe fn from_raw_fd(fd: RawFd) -> Self {
assert_ne!(fd, u32::MAX as RawFd);
diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs
index 592e072ad..ef896ea95 100644
--- a/library/std/src/os/fd/raw.rs
+++ b/library/std/src/os/fd/raw.rs
@@ -84,7 +84,10 @@ pub trait FromRawFd {
///
/// # Safety
///
- /// The `fd` passed in must be a valid and open file descriptor.
+ /// The `fd` passed in must be an [owned file descriptor][io-safety];
+ /// in particular, it must be open.
+ ///
+ /// [io-safety]: io#io-safety
///
/// # Example
///
diff --git a/library/std/src/os/fortanix_sgx/io.rs b/library/std/src/os/fortanix_sgx/io.rs
index 7223ade68..7e57435b6 100644
--- a/library/std/src/os/fortanix_sgx/io.rs
+++ b/library/std/src/os/fortanix_sgx/io.rs
@@ -31,15 +31,22 @@ pub trait FromRawFd {
/// Constructs a new instance of `Self` from the given raw file
/// descriptor and metadata.
///
- /// This function **consumes ownership** of the specified file
- /// descriptor. The returned object will take responsibility for closing
- /// it when the object goes out of scope.
+ /// This function is typically used to **consume ownership** of the
+ /// specified file descriptor. When used in this way, the returned object
+ /// will take responsibility for closing it when the object goes out of
+ /// scope.
///
- /// This function is also unsafe as the primitives currently returned
- /// have the contract that they are the sole owner of the file
- /// descriptor they are wrapping. Usage of this function could
- /// accidentally allow violating this contract which can cause memory
- /// unsafety in code that relies on it being true.
+ /// However, consuming ownership is not strictly required. Use a
+ /// [`From<OwnedFd>::from`] implementation for an API which strictly
+ /// consumes ownership.
+ ///
+ /// # Safety
+ ///
+ /// The `fd` passed in must be an [owned file descriptor][io-safety];
+ /// in particular, it must be open.
+ // FIXME: say something about `metadata`.
+ ///
+ /// [io-safety]: io#io-safety
#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> Self;
}
diff --git a/library/std/src/os/hurd/fs.rs b/library/std/src/os/hurd/fs.rs
new file mode 100644
index 000000000..00ff1560f
--- /dev/null
+++ b/library/std/src/os/hurd/fs.rs
@@ -0,0 +1,348 @@
+//! Hurd-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
+
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Returns the device ID on which this file resides.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_dev());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ /// Returns the inode number.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ino());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ /// Returns the file type and mode.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mode());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ /// Returns the number of hard links to file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_nlink());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ /// Returns the user ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_uid());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ /// Returns the group ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_gid());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ /// Returns the device ID that this file represents. Only relevant for special file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_rdev());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
+ ///
+ /// The size of a symbolic link is the length of the pathname it contains,
+ /// without a terminating null byte.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_size());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ /// Returns the last access time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ /// Returns the last access time of the file, in nanoseconds since [`st_atime`].
+ ///
+ /// [`st_atime`]: Self::st_atime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ /// Returns the last modification time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`].
+ ///
+ /// [`st_mtime`]: Self::st_mtime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ /// Returns the last status change time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`].
+ ///
+ /// [`st_ctime`]: Self::st_ctime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ /// Returns the "preferred" block size for efficient filesystem I/O.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blksize());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ /// Returns the number of blocks allocated to the file, 512-byte units.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blocks());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_fsid as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atim.tv_sec as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atim.tv_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtim.tv_sec as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtim.tv_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctim.tv_sec as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctim.tv_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/library/std/src/os/hurd/mod.rs b/library/std/src/os/hurd/mod.rs
new file mode 100644
index 000000000..aee86c7f6
--- /dev/null
+++ b/library/std/src/os/hurd/mod.rs
@@ -0,0 +1,6 @@
+//! Hurd-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/hurd/raw.rs b/library/std/src/os/hurd/raw.rs
new file mode 100644
index 000000000..fa2666635
--- /dev/null
+++ b/library/std/src/os/hurd/raw.rs
@@ -0,0 +1,33 @@
+//! Hurd-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::{c_long, c_uint, c_ulong};
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = c_long;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = c_ulong;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = c_uint;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = c_ulong;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = c_long;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_long;
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index 634c3cc4a..11ad21515 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -117,6 +117,8 @@ pub mod haiku;
pub mod hermit;
#[cfg(target_os = "horizon")]
pub mod horizon;
+#[cfg(target_os = "hurd")]
+pub mod hurd;
#[cfg(target_os = "illumos")]
pub mod illumos;
#[cfg(target_os = "ios")]
@@ -140,12 +142,16 @@ pub mod solid;
#[cfg(target_os = "tvos")]
#[path = "ios/mod.rs"]
pub(crate) mod tvos;
+#[cfg(target_os = "uefi")]
+pub mod uefi;
#[cfg(target_os = "vita")]
pub mod vita;
#[cfg(target_os = "vxworks")]
pub mod vxworks;
#[cfg(target_os = "watchos")]
pub(crate) mod watchos;
+#[cfg(target_os = "xous")]
+pub mod xous;
#[cfg(any(unix, target_os = "wasi", doc))]
pub mod fd;
diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs
index 33cc5a015..f82034663 100644
--- a/library/std/src/os/solid/io.rs
+++ b/library/std/src/os/solid/io.rs
@@ -27,15 +27,21 @@ pub trait FromRawFd {
/// Constructs a new instance of `Self` from the given raw file
/// descriptor.
///
- /// This function **consumes ownership** of the specified file
- /// descriptor. The returned object will take responsibility for closing
- /// it when the object goes out of scope.
+ /// This function is typically used to **consume ownership** of the
+ /// specified file descriptor. When used in this way, the returned object
+ /// will take responsibility for closing it when the object goes out of
+ /// scope.
///
- /// This function is also unsafe as the primitives currently returned
- /// have the contract that they are the sole owner of the file
- /// descriptor they are wrapping. Usage of this function could
- /// accidentally allow violating this contract which can cause memory
- /// unsafety in code that relies on it being true.
+ /// However, consuming ownership is not strictly required. Use a
+ /// [`From<OwnedFd>::from`] implementation for an API which strictly
+ /// consumes ownership.
+ ///
+ /// # Safety
+ ///
+ /// The `fd` passed in must be an [owned file descriptor][io-safety];
+ /// in particular, it must be open.
+ ///
+ /// [io-safety]: io#io-safety
unsafe fn from_raw_fd(fd: RawFd) -> Self;
}
diff --git a/library/std/src/os/uefi/env.rs b/library/std/src/os/uefi/env.rs
new file mode 100644
index 000000000..5d082e7c1
--- /dev/null
+++ b/library/std/src/os/uefi/env.rs
@@ -0,0 +1,92 @@
+//! UEFI-specific extensions to the primitives in `std::env` module
+
+#![unstable(feature = "uefi_std", issue = "100499")]
+
+use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
+use crate::{ffi::c_void, ptr::NonNull};
+
+static SYSTEM_TABLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
+static IMAGE_HANDLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
+// Flag to check if BootServices are still valid.
+// Start with assuming that they are not available
+static BOOT_SERVICES_FLAG: AtomicBool = AtomicBool::new(false);
+
+/// Initializes the global System Table and Image Handle pointers.
+///
+/// The standard library requires access to the UEFI System Table and the Application Image Handle
+/// to operate. Those are provided to UEFI Applications via their application entry point. By
+/// calling `init_globals()`, those pointers are retained by the standard library for future use.
+/// Thus this function must be called before any of the standard library services are used.
+///
+/// The pointers are never exposed to any entity outside of this application and it is guaranteed
+/// that, once the application exited, these pointers are never dereferenced again.
+///
+/// Callers are required to ensure the pointers are valid for the entire lifetime of this
+/// application. In particular, UEFI Boot Services must not be exited while an application with the
+/// standard library is loaded.
+///
+/// # SAFETY
+/// Calling this function more than once will panic
+pub(crate) unsafe fn init_globals(handle: NonNull<c_void>, system_table: NonNull<c_void>) {
+ IMAGE_HANDLE
+ .compare_exchange(
+ crate::ptr::null_mut(),
+ handle.as_ptr(),
+ Ordering::Release,
+ Ordering::Acquire,
+ )
+ .unwrap();
+ SYSTEM_TABLE
+ .compare_exchange(
+ crate::ptr::null_mut(),
+ system_table.as_ptr(),
+ Ordering::Release,
+ Ordering::Acquire,
+ )
+ .unwrap();
+ BOOT_SERVICES_FLAG.store(true, Ordering::Release)
+}
+
+/// Get the SystemTable Pointer.
+/// If you want to use `BootServices` then please use [`boot_services`] as it performs some
+/// additional checks.
+///
+/// Note: This function panics if the System Table or Image Handle is not initialized
+pub fn system_table() -> NonNull<c_void> {
+ try_system_table().unwrap()
+}
+
+/// Get the ImageHandle Pointer.
+///
+/// Note: This function panics if the System Table or Image Handle is not initialized
+pub fn image_handle() -> NonNull<c_void> {
+ try_image_handle().unwrap()
+}
+
+/// Get the BootServices Pointer.
+/// This function also checks if `ExitBootServices` has already been called.
+pub fn boot_services() -> Option<NonNull<c_void>> {
+ if BOOT_SERVICES_FLAG.load(Ordering::Acquire) {
+ let system_table: NonNull<r_efi::efi::SystemTable> = try_system_table()?.cast();
+ let boot_services = unsafe { (*system_table.as_ptr()).boot_services };
+ NonNull::new(boot_services).map(|x| x.cast())
+ } else {
+ None
+ }
+}
+
+/// Get the SystemTable Pointer.
+/// This function is mostly intended for places where panic is not an option
+pub(crate) fn try_system_table() -> Option<NonNull<c_void>> {
+ NonNull::new(SYSTEM_TABLE.load(Ordering::Acquire))
+}
+
+/// Get the SystemHandle Pointer.
+/// This function is mostly intended for places where panicking is not an option
+pub(crate) fn try_image_handle() -> Option<NonNull<c_void>> {
+ NonNull::new(IMAGE_HANDLE.load(Ordering::Acquire))
+}
+
+pub(crate) fn disable_boot_services() {
+ BOOT_SERVICES_FLAG.store(false, Ordering::Release)
+}
diff --git a/library/std/src/os/uefi/mod.rs b/library/std/src/os/uefi/mod.rs
new file mode 100644
index 000000000..8ef05eee1
--- /dev/null
+++ b/library/std/src/os/uefi/mod.rs
@@ -0,0 +1,8 @@
+//! Platform-specific extensions to `std` for UEFI.
+
+#![unstable(feature = "uefi_std", issue = "100499")]
+#![doc(cfg(target_os = "uefi"))]
+
+pub mod env;
+#[path = "../windows/ffi.rs"]
+pub mod ffi;
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index 029de8fbf..0eb4e88cf 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -123,7 +123,7 @@ pub trait FileExt {
buf = &mut tmp[n..];
offset += n as u64;
}
- Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(ref e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
}
@@ -155,7 +155,7 @@ pub trait FileExt {
/// flag fail to respect the offset parameter, always appending to the end
/// of the file instead.
///
- /// It is possible to inadvertantly set this flag, like in the example below.
+ /// It is possible to inadvertently set this flag, like in the example below.
/// Therefore, it is important to be vigilant while changing options to mitigate
/// unexpected behaviour.
///
@@ -258,7 +258,7 @@ pub trait FileExt {
buf = &buf[n..];
offset += n as u64
}
- Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(ref e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
}
diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs
index 25b5dbff1..827278f8b 100644
--- a/library/std/src/os/unix/io/mod.rs
+++ b/library/std/src/os/unix/io/mod.rs
@@ -6,7 +6,8 @@
//!
//! This module provides three types for representing file descriptors,
//! with different ownership properties: raw, borrowed, and owned, which are
-//! analogous to types used for representing pointers:
+//! analogous to types used for representing pointers. These types reflect concepts of [I/O
+//! safety][io-safety] on Unix.
//!
//! | Type | Analogous to |
//! | ------------------ | ------------ |
@@ -17,8 +18,8 @@
//! Like raw pointers, `RawFd` values are primitive values. And in new code,
//! they should be considered unsafe to do I/O on (analogous to dereferencing
//! them). Rust did not always provide this guidance, so existing code in the
-//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe. Once the
-//! `io_safety` feature is stable, libraries will be encouraged to migrate,
+//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe.
+//! Libraries are encouraged to migrate,
//! either by adding `unsafe` to APIs that dereference `RawFd` values, or by
//! using to `BorrowedFd` or `OwnedFd` instead.
//!
@@ -54,6 +55,8 @@
//! Like boxes, `OwnedFd` values conceptually own the resource they point to,
//! and free (close) it when they are dropped.
//!
+//! See the [`io` module docs][io-safety] for a general explanation of I/O safety.
+//!
//! ## `/proc/self/mem` and similar OS features
//!
//! Some platforms have special files, such as `/proc/self/mem`, which
@@ -65,15 +68,16 @@
//! to be opened and read from or written must be `unsafe`. Rust's safety guarantees
//! only cover what the program itself can do, and not what entities outside
//! the program can do to it. `/proc/self/mem` is considered to be such an
-//! external entity, along with debugging interfaces, and people with physical access to
-//! the hardware. This is true even in cases where the program is controlling
-//! the external entity.
+//! external entity, along with `/proc/self/fd/*`, debugging interfaces, and people with physical
+//! access to the hardware. This is true even in cases where the program is controlling the external
+//! entity.
//!
//! If you desire to comprehensively prevent programs from reaching out and
//! causing external entities to reach back in and violate memory safety, it's
//! necessary to use *sandboxing*, which is outside the scope of `std`.
//!
//! [`BorrowedFd<'a>`]: crate::os::unix::io::BorrowedFd
+//! [io-safety]: crate::io#io-safety
#![stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
index 401ec1e7a..3724e90af 100644
--- a/library/std/src/os/unix/mod.rs
+++ b/library/std/src/os/unix/mod.rs
@@ -53,6 +53,8 @@ mod platform {
pub use crate::os::haiku::*;
#[cfg(target_os = "horizon")]
pub use crate::os::horizon::*;
+ #[cfg(target_os = "hurd")]
+ pub use crate::os::hurd::*;
#[cfg(target_os = "illumos")]
pub use crate::os::illumos::*;
#[cfg(target_os = "ios")]
diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs
index 3d4302e66..6a6af9efd 100644
--- a/library/std/src/os/unix/net/tests.rs
+++ b/library/std/src/os/unix/net/tests.rs
@@ -662,7 +662,7 @@ fn test_send_vectored_fds_unix_stream() {
}
}
-#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
+#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
#[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets
fn test_send_vectored_with_ancillary_to_unix_datagram() {
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index 2b40b672d..ac5510304 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -434,6 +434,20 @@ impl From<crate::process::ChildStdin> for OwnedFd {
}
}
+/// Create a `ChildStdin` from the provided `OwnedFd`.
+///
+/// The provided file descriptor must point to a pipe
+/// with the `CLOEXEC` flag set.
+#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
+impl From<OwnedFd> for process::ChildStdin {
+ #[inline]
+ fn from(fd: OwnedFd) -> process::ChildStdin {
+ let fd = sys::fd::FileDesc::from_inner(fd);
+ let pipe = sys::pipe::AnonPipe::from_inner(fd);
+ process::ChildStdin::from_inner(pipe)
+ }
+}
+
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsFd for crate::process::ChildStdout {
#[inline]
@@ -450,6 +464,20 @@ impl From<crate::process::ChildStdout> for OwnedFd {
}
}
+/// Create a `ChildStdout` from the provided `OwnedFd`.
+///
+/// The provided file descriptor must point to a pipe
+/// with the `CLOEXEC` flag set.
+#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
+impl From<OwnedFd> for process::ChildStdout {
+ #[inline]
+ fn from(fd: OwnedFd) -> process::ChildStdout {
+ let fd = sys::fd::FileDesc::from_inner(fd);
+ let pipe = sys::pipe::AnonPipe::from_inner(fd);
+ process::ChildStdout::from_inner(pipe)
+ }
+}
+
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsFd for crate::process::ChildStderr {
#[inline]
@@ -466,6 +494,20 @@ impl From<crate::process::ChildStderr> for OwnedFd {
}
}
+/// Create a `ChildStderr` from the provided `OwnedFd`.
+///
+/// The provided file descriptor must point to a pipe
+/// with the `CLOEXEC` flag set.
+#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
+impl From<OwnedFd> for process::ChildStderr {
+ #[inline]
+ fn from(fd: OwnedFd) -> process::ChildStderr {
+ let fd = sys::fd::FileDesc::from_inner(fd);
+ let pipe = sys::pipe::AnonPipe::from_inner(fd);
+ process::ChildStderr::from_inner(pipe)
+ }
+}
+
/// Returns the OS-assigned process identifier associated with this process's parent.
#[must_use]
#[stable(feature = "unix_ppid", since = "1.27.0")]
diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs
index 160c8f1ec..3da8c8355 100644
--- a/library/std/src/os/wasi/fs.rs
+++ b/library/std/src/os/wasi/fs.rs
@@ -82,7 +82,7 @@ pub trait FileExt {
buf = &mut tmp[n..];
offset += n as u64;
}
- Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(ref e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
}
@@ -162,7 +162,7 @@ pub trait FileExt {
buf = &buf[n..];
offset += n as u64
}
- Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(ref e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
}
diff --git a/library/std/src/os/windows/io/mod.rs b/library/std/src/os/windows/io/mod.rs
index e2a401fb6..3d3ae3878 100644
--- a/library/std/src/os/windows/io/mod.rs
+++ b/library/std/src/os/windows/io/mod.rs
@@ -6,7 +6,8 @@
//!
//! This module provides three types for representing raw handles and sockets
//! with different ownership properties: raw, borrowed, and owned, which are
-//! analogous to types used for representing pointers:
+//! analogous to types used for representing pointers. These types reflect concepts of [I/O
+//! safety][io-safety] on Windows.
//!
//! | Type | Analogous to |
//! | ---------------------- | ------------ |
@@ -23,8 +24,8 @@
//! And in new code, they should be considered unsafe to do I/O on (analogous
//! to dereferencing them). Rust did not always provide this guidance, so
//! existing code in the Rust ecosystem often doesn't mark `RawHandle` and
-//! `RawSocket` usage as unsafe. Once the `io_safety` feature is stable,
-//! libraries will be encouraged to migrate, either by adding `unsafe` to APIs
+//! `RawSocket` usage as unsafe.
+//! Libraries are encouraged to migrate, either by adding `unsafe` to APIs
//! that dereference `RawHandle` and `RawSocket` values, or by using to
//! `BorrowedHandle`, `BorrowedSocket`, `OwnedHandle`, or `OwnedSocket`.
//!
@@ -45,8 +46,11 @@
//! Like boxes, `OwnedHandle` and `OwnedSocket` values conceptually own the
//! resource they point to, and free (close) it when they are dropped.
//!
+//! See the [`io` module docs][io-safety] for a general explanation of I/O safety.
+//!
//! [`BorrowedHandle<'a>`]: crate::os::windows::io::BorrowedHandle
//! [`BorrowedSocket<'a>`]: crate::os::windows::io::BorrowedSocket
+//! [io-safety]: crate::io#io-safety
#![stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs
index 1759e2e7f..770583a9c 100644
--- a/library/std/src/os/windows/io/raw.rs
+++ b/library/std/src/os/windows/io/raw.rs
@@ -62,7 +62,7 @@ pub trait FromRawHandle {
/// # Safety
///
/// The `handle` passed in must:
- /// - be a valid an open handle,
+ /// - be an [owned handle][io-safety]; in particular, it must be open.
/// - be a handle for a resource that may be freed via [`CloseHandle`]
/// (as opposed to `RegCloseKey` or other close functions).
///
@@ -71,6 +71,7 @@ pub trait FromRawHandle {
///
/// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+ /// [io-safety]: io#io-safety
#[stable(feature = "from_raw_os", since = "1.1.0")]
unsafe fn from_raw_handle(handle: RawHandle) -> Self;
}
@@ -207,10 +208,11 @@ pub trait FromRawSocket {
/// # Safety
///
/// The `socket` passed in must:
- /// - be a valid an open socket,
+ /// - be an [owned socket][io-safety]; in particular, it must be open.
/// - be a socket that may be freed via [`closesocket`].
///
/// [`closesocket`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-closesocket
+ /// [io-safety]: io#io-safety
#[stable(feature = "from_raw_os", since = "1.1.0")]
unsafe fn from_raw_socket(sock: RawSocket) -> Self;
}
diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs
index 6359835ca..c80b9e284 100644
--- a/library/std/src/os/windows/io/socket.rs
+++ b/library/std/src/os/windows/io/socket.rs
@@ -116,7 +116,7 @@ impl BorrowedSocket<'_> {
let mut info = unsafe { mem::zeroed::<sys::c::WSAPROTOCOL_INFOW>() };
let result = unsafe {
sys::c::WSADuplicateSocketW(
- self.as_raw_socket(),
+ self.as_raw_socket() as sys::c::SOCKET,
sys::c::GetCurrentProcessId(),
&mut info,
)
@@ -134,7 +134,7 @@ impl BorrowedSocket<'_> {
};
if socket != sys::c::INVALID_SOCKET {
- unsafe { Ok(OwnedSocket::from_raw_socket(socket)) }
+ unsafe { Ok(OwnedSocket::from_raw_socket(socket as RawSocket)) }
} else {
let error = unsafe { sys::c::WSAGetLastError() };
@@ -158,7 +158,7 @@ impl BorrowedSocket<'_> {
}
unsafe {
- let socket = OwnedSocket::from_raw_socket(socket);
+ let socket = OwnedSocket::from_raw_socket(socket as RawSocket);
socket.set_no_inherit()?;
Ok(socket)
}
@@ -211,7 +211,7 @@ impl Drop for OwnedSocket {
#[inline]
fn drop(&mut self) {
unsafe {
- let _ = sys::c::closesocket(self.socket);
+ let _ = sys::c::closesocket(self.socket as sys::c::SOCKET);
}
}
}
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
index 073168cf2..d00e79476 100644
--- a/library/std/src/os/windows/process.rs
+++ b/library/std/src/os/windows/process.rs
@@ -106,6 +106,45 @@ impl IntoRawHandle for process::ChildStderr {
}
}
+/// Create a `ChildStdin` from the provided `OwnedHandle`.
+///
+/// The provided handle must be asynchronous, as reading and
+/// writing from and to it is implemented using asynchronous APIs.
+#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
+impl From<OwnedHandle> for process::ChildStdin {
+ fn from(handle: OwnedHandle) -> process::ChildStdin {
+ let handle = sys::handle::Handle::from_inner(handle);
+ let pipe = sys::pipe::AnonPipe::from_inner(handle);
+ process::ChildStdin::from_inner(pipe)
+ }
+}
+
+/// Create a `ChildStdout` from the provided `OwnedHandle`.
+///
+/// The provided handle must be asynchronous, as reading and
+/// writing from and to it is implemented using asynchronous APIs.
+#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
+impl From<OwnedHandle> for process::ChildStdout {
+ fn from(handle: OwnedHandle) -> process::ChildStdout {
+ let handle = sys::handle::Handle::from_inner(handle);
+ let pipe = sys::pipe::AnonPipe::from_inner(handle);
+ process::ChildStdout::from_inner(pipe)
+ }
+}
+
+/// Create a `ChildStderr` from the provided `OwnedHandle`.
+///
+/// The provided handle must be asynchronous, as reading and
+/// writing from and to it is implemented using asynchronous APIs.
+#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
+impl From<OwnedHandle> for process::ChildStderr {
+ fn from(handle: OwnedHandle) -> process::ChildStderr {
+ let handle = sys::handle::Handle::from_inner(handle);
+ let pipe = sys::pipe::AnonPipe::from_inner(handle);
+ process::ChildStderr::from_inner(pipe)
+ }
+}
+
/// Windows-specific extensions to [`process::ExitStatus`].
///
/// This trait is sealed: it cannot be implemented outside the standard library.
@@ -192,6 +231,66 @@ pub trait CommandExt: Sealed {
/// ```
#[unstable(feature = "windows_process_extensions_async_pipes", issue = "98289")]
fn async_pipes(&mut self, always_async: bool) -> &mut process::Command;
+
+ /// Sets a raw attribute on the command, providing extended configuration options for Windows processes.
+ ///
+ /// This method allows you to specify custom attributes for a child process on Windows systems using raw attribute values.
+ /// Raw attributes provide extended configurability for process creation, but their usage can be complex and potentially unsafe.
+ ///
+ /// The `attribute` parameter specifies the raw attribute to be set, while the `value` parameter holds the value associated with that attribute.
+ /// Please refer to the [`windows-rs`](https://microsoft.github.io/windows-docs-rs/doc/windows/) documentation or the [`Win32 API documentation`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute) for detailed information about available attributes and their meanings.
+ ///
+ /// # Note
+ ///
+ /// The maximum number of raw attributes is the value of [`u32::MAX`].
+ /// If this limit is exceeded, the call to [`process::Command::spawn`] will return an `Error` indicating that the maximum number of attributes has been exceeded.
+ /// # Safety
+ ///
+ /// The usage of raw attributes is potentially unsafe and should be done with caution. Incorrect attribute values or improper configuration can lead to unexpected behavior or errors.
+ ///
+ /// # Example
+ ///
+ /// The following example demonstrates how to create a child process with a specific parent process ID using a raw attribute.
+ ///
+ /// ```rust
+ /// #![feature(windows_process_extensions_raw_attribute)]
+ /// use std::os::windows::{process::CommandExt, io::AsRawHandle};
+ /// use std::process::Command;
+ ///
+ /// # struct ProcessDropGuard(std::process::Child);
+ /// # impl Drop for ProcessDropGuard {
+ /// # fn drop(&mut self) {
+ /// # let _ = self.0.kill();
+ /// # }
+ /// # }
+ ///
+ /// let parent = Command::new("cmd").spawn()?;
+ ///
+ /// let mut child_cmd = Command::new("cmd");
+ ///
+ /// const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000;
+ ///
+ /// unsafe {
+ /// child_cmd.raw_attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, parent.as_raw_handle() as isize);
+ /// }
+ /// #
+ /// # let parent = ProcessDropGuard(parent);
+ ///
+ /// let mut child = child_cmd.spawn()?;
+ ///
+ /// # child.kill()?;
+ /// # Ok::<(), std::io::Error>(())
+ /// ```
+ ///
+ /// # Safety Note
+ ///
+ /// Remember that improper use of raw attributes can lead to undefined behavior or security vulnerabilities. Always consult the documentation and ensure proper attribute values are used.
+ #[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
+ unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
+ &mut self,
+ attribute: usize,
+ value: T,
+ ) -> &mut process::Command;
}
#[stable(feature = "windows_process_extensions", since = "1.16.0")]
@@ -219,6 +318,15 @@ impl CommandExt for process::Command {
let _ = always_async;
self
}
+
+ unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
+ &mut self,
+ attribute: usize,
+ value: T,
+ ) -> &mut process::Command {
+ self.as_inner_mut().raw_attribute(attribute, value);
+ self
+ }
}
#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
diff --git a/library/std/src/os/xous/ffi.rs b/library/std/src/os/xous/ffi.rs
new file mode 100644
index 000000000..8be7fbb10
--- /dev/null
+++ b/library/std/src/os/xous/ffi.rs
@@ -0,0 +1,647 @@
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[path = "../unix/ffi/os_str.rs"]
+mod os_str;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::os_str::{OsStrExt, OsStringExt};
+
+mod definitions;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use definitions::*;
+
+fn lend_mut_impl(
+ connection: Connection,
+ opcode: usize,
+ data: &mut [u8],
+ arg1: usize,
+ arg2: usize,
+ blocking: bool,
+) -> Result<(usize, usize), Error> {
+ let mut a0 = if blocking { Syscall::SendMessage } else { Syscall::TrySendMessage } as usize;
+ let mut a1: usize = connection.try_into().unwrap();
+ let mut a2 = InvokeType::LendMut as usize;
+ let a3 = opcode;
+ let a4 = data.as_mut_ptr() as usize;
+ let a5 = data.len();
+ let a6 = arg1;
+ let a7 = arg2;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::MemoryReturned as usize {
+ Ok((a1, a2))
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+pub(crate) fn lend_mut(
+ connection: Connection,
+ opcode: usize,
+ data: &mut [u8],
+ arg1: usize,
+ arg2: usize,
+) -> Result<(usize, usize), Error> {
+ lend_mut_impl(connection, opcode, data, arg1, arg2, true)
+}
+
+pub(crate) fn try_lend_mut(
+ connection: Connection,
+ opcode: usize,
+ data: &mut [u8],
+ arg1: usize,
+ arg2: usize,
+) -> Result<(usize, usize), Error> {
+ lend_mut_impl(connection, opcode, data, arg1, arg2, false)
+}
+
+fn lend_impl(
+ connection: Connection,
+ opcode: usize,
+ data: &[u8],
+ arg1: usize,
+ arg2: usize,
+ blocking: bool,
+) -> Result<(usize, usize), Error> {
+ let mut a0 = if blocking { Syscall::SendMessage } else { Syscall::TrySendMessage } as usize;
+ let a1: usize = connection.try_into().unwrap();
+ let a2 = InvokeType::Lend as usize;
+ let a3 = opcode;
+ let a4 = data.as_ptr() as usize;
+ let a5 = data.len();
+ let mut a6 = arg1;
+ let mut a7 = arg2;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1 => _,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6,
+ inlateout("a7") a7,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::MemoryReturned as usize {
+ Ok((a6, a7))
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+pub(crate) fn lend(
+ connection: Connection,
+ opcode: usize,
+ data: &[u8],
+ arg1: usize,
+ arg2: usize,
+) -> Result<(usize, usize), Error> {
+ lend_impl(connection, opcode, data, arg1, arg2, true)
+}
+
+pub(crate) fn try_lend(
+ connection: Connection,
+ opcode: usize,
+ data: &[u8],
+ arg1: usize,
+ arg2: usize,
+) -> Result<(usize, usize), Error> {
+ lend_impl(connection, opcode, data, arg1, arg2, false)
+}
+
+fn scalar_impl(connection: Connection, args: [usize; 5], blocking: bool) -> Result<(), Error> {
+ let mut a0 = if blocking { Syscall::SendMessage } else { Syscall::TrySendMessage } as usize;
+ let mut a1: usize = connection.try_into().unwrap();
+ let a2 = InvokeType::Scalar as usize;
+ let a3 = args[0];
+ let a4 = args[1];
+ let a5 = args[2];
+ let a6 = args[3];
+ let a7 = args[4];
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::Ok as usize {
+ Ok(())
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+pub(crate) fn scalar(connection: Connection, args: [usize; 5]) -> Result<(), Error> {
+ scalar_impl(connection, args, true)
+}
+
+pub(crate) fn try_scalar(connection: Connection, args: [usize; 5]) -> Result<(), Error> {
+ scalar_impl(connection, args, false)
+}
+
+fn blocking_scalar_impl(
+ connection: Connection,
+ args: [usize; 5],
+ blocking: bool,
+) -> Result<[usize; 5], Error> {
+ let mut a0 = if blocking { Syscall::SendMessage } else { Syscall::TrySendMessage } as usize;
+ let mut a1: usize = connection.try_into().unwrap();
+ let mut a2 = InvokeType::BlockingScalar as usize;
+ let mut a3 = args[0];
+ let mut a4 = args[1];
+ let mut a5 = args[2];
+ let a6 = args[3];
+ let a7 = args[4];
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2,
+ inlateout("a3") a3,
+ inlateout("a4") a4,
+ inlateout("a5") a5,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::Scalar1 as usize {
+ Ok([a1, 0, 0, 0, 0])
+ } else if result == SyscallResult::Scalar2 as usize {
+ Ok([a1, a2, 0, 0, 0])
+ } else if result == SyscallResult::Scalar5 as usize {
+ Ok([a1, a2, a3, a4, a5])
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+pub(crate) fn blocking_scalar(
+ connection: Connection,
+ args: [usize; 5],
+) -> Result<[usize; 5], Error> {
+ blocking_scalar_impl(connection, args, true)
+}
+
+pub(crate) fn try_blocking_scalar(
+ connection: Connection,
+ args: [usize; 5],
+) -> Result<[usize; 5], Error> {
+ blocking_scalar_impl(connection, args, false)
+}
+
+fn connect_impl(address: ServerAddress, blocking: bool) -> Result<Connection, Error> {
+ let a0 = if blocking { Syscall::Connect } else { Syscall::TryConnect } as usize;
+ let address: [u32; 4] = address.into();
+ let a1: usize = address[0].try_into().unwrap();
+ let a2: usize = address[1].try_into().unwrap();
+ let a3: usize = address[2].try_into().unwrap();
+ let a4: usize = address[3].try_into().unwrap();
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ let mut result: usize;
+ let mut value: usize;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0 => result,
+ inlateout("a1") a1 => value,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+ if result == SyscallResult::ConnectionId as usize {
+ Ok(value.try_into().unwrap())
+ } else if result == SyscallResult::Error as usize {
+ Err(value.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+/// Connect to a Xous server represented by the specified `address`.
+///
+/// The current thread will block until the server is available. Returns
+/// an error if the server cannot accept any more connections.
+pub(crate) fn connect(address: ServerAddress) -> Result<Connection, Error> {
+ connect_impl(address, true)
+}
+
+/// Attempt to connect to a Xous server represented by the specified `address`.
+///
+/// If the server does not exist then None is returned.
+pub(crate) fn try_connect(address: ServerAddress) -> Result<Option<Connection>, Error> {
+ match connect_impl(address, false) {
+ Ok(conn) => Ok(Some(conn)),
+ Err(Error::ServerNotFound) => Ok(None),
+ Err(e) => Err(e),
+ }
+}
+
+/// Terminate the current process and return the specified code to the parent process.
+pub(crate) fn exit(return_code: u32) -> ! {
+ let a0 = Syscall::TerminateProcess as usize;
+ let a1 = return_code as usize;
+ let a2 = 0;
+ let a3 = 0;
+ let a4 = 0;
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ in("a0") a0,
+ in("a1") a1,
+ in("a2") a2,
+ in("a3") a3,
+ in("a4") a4,
+ in("a5") a5,
+ in("a6") a6,
+ in("a7") a7,
+ )
+ };
+ unreachable!();
+}
+
+/// Suspend the current thread and allow another thread to run. This thread may
+/// continue executing again immediately if there are no other threads available
+/// to run on the system.
+pub(crate) fn do_yield() {
+ let a0 = Syscall::Yield as usize;
+ let a1 = 0;
+ let a2 = 0;
+ let a3 = 0;
+ let a4 = 0;
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0 => _,
+ inlateout("a1") a1 => _,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+}
+
+/// Allocate memory from the system. An optional physical and/or virtual address
+/// may be specified in order to ensure memory is allocated at specific offsets,
+/// otherwise the kernel will select an address.
+///
+/// # Safety
+///
+/// This function is safe unless a virtual address is specified. In that case,
+/// the kernel will return an alias to the existing range. This violates Rust's
+/// pointer uniqueness guarantee.
+pub(crate) unsafe fn map_memory<T>(
+ phys: Option<core::ptr::NonNull<T>>,
+ virt: Option<core::ptr::NonNull<T>>,
+ count: usize,
+ flags: MemoryFlags,
+) -> Result<&'static mut [T], Error> {
+ let mut a0 = Syscall::MapMemory as usize;
+ let mut a1 = phys.map(|p| p.as_ptr() as usize).unwrap_or_default();
+ let mut a2 = virt.map(|p| p.as_ptr() as usize).unwrap_or_default();
+ let a3 = count * core::mem::size_of::<T>();
+ let a4 = flags.bits();
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::MemoryRange as usize {
+ let start = core::ptr::from_exposed_addr_mut::<T>(a1);
+ let len = a2 / core::mem::size_of::<T>();
+ let end = unsafe { start.add(len) };
+ Ok(unsafe { core::slice::from_raw_parts_mut(start, len) })
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+/// Destroy the given memory, returning it to the compiler.
+///
+/// Safety: The memory pointed to by `range` should not be used after this
+/// function returns, even if this function returns Err().
+pub(crate) unsafe fn unmap_memory<T>(range: *mut [T]) -> Result<(), Error> {
+ let mut a0 = Syscall::UnmapMemory as usize;
+ let mut a1 = range.as_mut_ptr() as usize;
+ let a2 = range.len();
+ let a3 = 0;
+ let a4 = 0;
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::Ok as usize {
+ Ok(())
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+/// Adjust the memory flags for the given range. This can be used to remove flags
+/// from a given region in order to harden memory access. Note that flags may
+/// only be removed and may never be added.
+///
+/// Safety: The memory pointed to by `range` may become inaccessible or have its
+/// mutability removed. It is up to the caller to ensure that the flags specified
+/// by `new_flags` are upheld, otherwise the program will crash.
+pub(crate) unsafe fn update_memory_flags<T>(
+ range: *mut [T],
+ new_flags: MemoryFlags,
+) -> Result<(), Error> {
+ let mut a0 = Syscall::UpdateMemoryFlags as usize;
+ let mut a1 = range.as_mut_ptr() as usize;
+ let a2 = range.len();
+ let a3 = new_flags.bits();
+ let a4 = 0; // Process ID is currently None
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::Ok as usize {
+ Ok(())
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+/// Create a thread with a given stack and up to four arguments
+pub(crate) fn create_thread(
+ start: *mut usize,
+ stack: *mut [u8],
+ arg0: usize,
+ arg1: usize,
+ arg2: usize,
+ arg3: usize,
+) -> Result<ThreadId, Error> {
+ let mut a0 = Syscall::CreateThread as usize;
+ let mut a1 = start as usize;
+ let a2 = stack.as_mut_ptr() as usize;
+ let a3 = stack.len();
+ let a4 = arg0;
+ let a5 = arg1;
+ let a6 = arg2;
+ let a7 = arg3;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::ThreadId as usize {
+ Ok(a1.into())
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+/// Wait for the given thread to terminate and return the exit code from that thread.
+pub(crate) fn join_thread(thread_id: ThreadId) -> Result<usize, Error> {
+ let mut a0 = Syscall::JoinThread as usize;
+ let mut a1 = thread_id.into();
+ let a2 = 0;
+ let a3 = 0;
+ let a4 = 0;
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::Scalar1 as usize {
+ Ok(a1)
+ } else if result == SyscallResult::Scalar2 as usize {
+ Ok(a1)
+ } else if result == SyscallResult::Scalar5 as usize {
+ Ok(a1)
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+/// Get the current thread's ID
+pub(crate) fn thread_id() -> Result<ThreadId, Error> {
+ let mut a0 = Syscall::GetThreadId as usize;
+ let mut a1 = 0;
+ let a2 = 0;
+ let a3 = 0;
+ let a4 = 0;
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::ThreadId as usize {
+ Ok(a1.into())
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+/// Adjust the given `knob` limit to match the new value `new`. The current value must
+/// match the `current` in order for this to take effect.
+///
+/// The new value is returned as a result of this call. If the call fails, then the old
+/// value is returned. In either case, this function returns successfully.
+///
+/// An error is generated if the `knob` is not a valid limit, or if the call
+/// would not succeed.
+pub(crate) fn adjust_limit(knob: Limits, current: usize, new: usize) -> Result<usize, Error> {
+ let mut a0 = Syscall::JoinThread as usize;
+ let mut a1 = knob as usize;
+ let a2 = current;
+ let a3 = new;
+ let a4 = 0;
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::Scalar2 as usize && a1 == knob as usize {
+ Ok(a2)
+ } else if result == SyscallResult::Scalar5 as usize && a1 == knob as usize {
+ Ok(a1)
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
diff --git a/library/std/src/os/xous/ffi/definitions.rs b/library/std/src/os/xous/ffi/definitions.rs
new file mode 100644
index 000000000..345005bcc
--- /dev/null
+++ b/library/std/src/os/xous/ffi/definitions.rs
@@ -0,0 +1,283 @@
+mod memoryflags;
+pub(crate) use memoryflags::*;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+/// Indicates a particular syscall number as used by the Xous kernel.
+#[derive(Copy, Clone)]
+#[repr(usize)]
+pub enum Syscall {
+ MapMemory = 2,
+ Yield = 3,
+ UpdateMemoryFlags = 12,
+ ReceiveMessage = 15,
+ SendMessage = 16,
+ Connect = 17,
+ CreateThread = 18,
+ UnmapMemory = 19,
+ ReturnMemory = 20,
+ TerminateProcess = 22,
+ TrySendMessage = 24,
+ TryConnect = 25,
+ GetThreadId = 32,
+ JoinThread = 36,
+ AdjustProcessLimit = 38,
+ ReturnScalar = 40,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+/// Copies of these invocation types here for when we're running
+/// in environments without libxous.
+#[derive(Copy, Clone)]
+#[repr(usize)]
+pub enum SyscallResult {
+ Ok = 0,
+ Error = 1,
+ MemoryRange = 3,
+ ConnectionId = 7,
+ Message = 9,
+ ThreadId = 10,
+ Scalar1 = 14,
+ Scalar2 = 15,
+ MemoryReturned = 18,
+ Scalar5 = 20,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Copy, Clone)]
+/// A list of all known errors that may be returned by the Xous kernel.
+#[repr(usize)]
+pub enum Error {
+ NoError = 0,
+ BadAlignment = 1,
+ BadAddress = 2,
+ OutOfMemory = 3,
+ MemoryInUse = 4,
+ InterruptNotFound = 5,
+ InterruptInUse = 6,
+ InvalidString = 7,
+ ServerExists = 8,
+ ServerNotFound = 9,
+ ProcessNotFound = 10,
+ ProcessNotChild = 11,
+ ProcessTerminated = 12,
+ Timeout = 13,
+ InternalError = 14,
+ ServerQueueFull = 15,
+ ThreadNotAvailable = 16,
+ UnhandledSyscall = 17,
+ InvalidSyscall = 18,
+ ShareViolation = 19,
+ InvalidThread = 20,
+ InvalidPid = 21,
+ UnknownError = 22,
+ AccessDenied = 23,
+ UseBeforeInit = 24,
+ DoubleFree = 25,
+ DebugInProgress = 26,
+ InvalidLimit = 27,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<usize> for Error {
+ fn from(src: usize) -> Self {
+ match src {
+ 0 => Self::NoError,
+ 1 => Self::BadAlignment,
+ 2 => Self::BadAddress,
+ 3 => Self::OutOfMemory,
+ 4 => Self::MemoryInUse,
+ 5 => Self::InterruptNotFound,
+ 6 => Self::InterruptInUse,
+ 7 => Self::InvalidString,
+ 8 => Self::ServerExists,
+ 9 => Self::ServerNotFound,
+ 10 => Self::ProcessNotFound,
+ 11 => Self::ProcessNotChild,
+ 12 => Self::ProcessTerminated,
+ 13 => Self::Timeout,
+ 14 => Self::InternalError,
+ 15 => Self::ServerQueueFull,
+ 16 => Self::ThreadNotAvailable,
+ 17 => Self::UnhandledSyscall,
+ 18 => Self::InvalidSyscall,
+ 19 => Self::ShareViolation,
+ 20 => Self::InvalidThread,
+ 21 => Self::InvalidPid,
+ 23 => Self::AccessDenied,
+ 24 => Self::UseBeforeInit,
+ 25 => Self::DoubleFree,
+ 26 => Self::DebugInProgress,
+ 27 => Self::InvalidLimit,
+ 22 | _ => Self::UnknownError,
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<i32> for Error {
+ fn from(src: i32) -> Self {
+ let Ok(src) = core::convert::TryInto::<usize>::try_into(src) else {
+ return Self::UnknownError;
+ };
+ src.into()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::fmt::Display for Error {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(
+ f,
+ "{}",
+ match self {
+ Error::NoError => "no error occurred",
+ Error::BadAlignment => "memory was not properly aligned",
+ Error::BadAddress => "an invalid address was supplied",
+ Error::OutOfMemory => "the process or service has run out of memory",
+ Error::MemoryInUse => "the requested address is in use",
+ Error::InterruptNotFound =>
+ "the requested interrupt does not exist on this platform",
+ Error::InterruptInUse => "the requested interrupt is currently in use",
+ Error::InvalidString => "the specified string was not formatted correctly",
+ Error::ServerExists => "a server with that address already exists",
+ Error::ServerNotFound => "the requetsed server could not be found",
+ Error::ProcessNotFound => "the target process does not exist",
+ Error::ProcessNotChild =>
+ "the requested operation can only be done on child processes",
+ Error::ProcessTerminated => "the target process has crashed",
+ Error::Timeout => "the requested operation timed out",
+ Error::InternalError => "an internal error occurred",
+ Error::ServerQueueFull => "the server has too many pending messages",
+ Error::ThreadNotAvailable => "the specified thread does not exist",
+ Error::UnhandledSyscall => "the kernel did not recognize that syscall",
+ Error::InvalidSyscall => "the syscall had incorrect parameters",
+ Error::ShareViolation => "an attempt was made to share memory twice",
+ Error::InvalidThread => "tried to resume a thread that was not ready",
+ Error::InvalidPid => "kernel attempted to use a pid that was not valid",
+ Error::AccessDenied => "no permission to perform the requested operation",
+ Error::UseBeforeInit => "attempt to use a service before initialization finished",
+ Error::DoubleFree => "the requested resource was freed twice",
+ Error::DebugInProgress => "kernel attempted to activate a thread being debugged",
+ Error::InvalidLimit => "process attempted to adjust an invalid limit",
+ Error::UnknownError => "an unknown error occurred",
+ }
+ )
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::fmt::Debug for Error {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "{}", self)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl crate::error::Error for Error {}
+
+/// Indicates the type of Message that is sent when making a `SendMessage` syscall.
+#[derive(Copy, Clone)]
+#[repr(usize)]
+pub(crate) enum InvokeType {
+ LendMut = 1,
+ Lend = 2,
+ Move = 3,
+ Scalar = 4,
+ BlockingScalar = 5,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug, Copy, Clone)]
+/// A representation of a connection to a Xous service.
+pub struct Connection(u32);
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<u32> for Connection {
+ fn from(src: u32) -> Connection {
+ Connection(src)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl TryFrom<usize> for Connection {
+ type Error = core::num::TryFromIntError;
+ fn try_from(src: usize) -> Result<Self, Self::Error> {
+ Ok(Connection(src.try_into()?))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Into<u32> for Connection {
+ fn into(self) -> u32 {
+ self.0
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl TryInto<usize> for Connection {
+ type Error = core::num::TryFromIntError;
+ fn try_into(self) -> Result<usize, Self::Error> {
+ self.0.try_into()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
+pub enum ServerAddressError {
+ InvalidLength,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct ServerAddress([u32; 4]);
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl TryFrom<&str> for ServerAddress {
+ type Error = ServerAddressError;
+ fn try_from(value: &str) -> Result<Self, Self::Error> {
+ let b = value.as_bytes();
+ if b.len() == 0 || b.len() > 16 {
+ return Err(Self::Error::InvalidLength);
+ }
+
+ let mut this_temp = [0u8; 16];
+ for (dest, src) in this_temp.iter_mut().zip(b.iter()) {
+ *dest = *src;
+ }
+
+ let mut this = [0u32; 4];
+ for (dest, src) in this.iter_mut().zip(this_temp.chunks_exact(4)) {
+ *dest = u32::from_le_bytes(src.try_into().unwrap());
+ }
+ Ok(ServerAddress(this))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Into<[u32; 4]> for ServerAddress {
+ fn into(self) -> [u32; 4] {
+ self.0
+ }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub(crate) struct ThreadId(usize);
+
+impl From<usize> for ThreadId {
+ fn from(src: usize) -> ThreadId {
+ ThreadId(src)
+ }
+}
+
+impl Into<usize> for ThreadId {
+ fn into(self) -> usize {
+ self.0
+ }
+}
+
+#[derive(Copy, Clone)]
+#[repr(usize)]
+/// Limits that can be passed to `AdjustLimit`
+pub(crate) enum Limits {
+ HeapMaximum = 1,
+ HeapSize = 2,
+}
diff --git a/library/std/src/os/xous/ffi/definitions/memoryflags.rs b/library/std/src/os/xous/ffi/definitions/memoryflags.rs
new file mode 100644
index 000000000..af9de3cbf
--- /dev/null
+++ b/library/std/src/os/xous/ffi/definitions/memoryflags.rs
@@ -0,0 +1,176 @@
+/// Flags to be passed to the MapMemory struct.
+/// Note that it is an error to have memory be
+/// writable and not readable.
+#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct MemoryFlags {
+ bits: usize,
+}
+
+impl MemoryFlags {
+ /// Free this memory
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub const FREE: Self = Self { bits: 0b0000_0000 };
+
+ /// Immediately allocate this memory. Otherwise it will
+ /// be demand-paged. This is implicitly set when `phys`
+ /// is not 0.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub const RESERVE: Self = Self { bits: 0b0000_0001 };
+
+ /// Allow the CPU to read from this page.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub const R: Self = Self { bits: 0b0000_0010 };
+
+ /// Allow the CPU to write to this page.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub const W: Self = Self { bits: 0b0000_0100 };
+
+ /// Allow the CPU to execute from this page.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub const X: Self = Self { bits: 0b0000_1000 };
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn bits(&self) -> usize {
+ self.bits
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn from_bits(raw: usize) -> Option<MemoryFlags> {
+ if raw > 16 { None } else { Some(MemoryFlags { bits: raw }) }
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_empty(&self) -> bool {
+ self.bits == 0
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn empty() -> MemoryFlags {
+ MemoryFlags { bits: 0 }
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn all() -> MemoryFlags {
+ MemoryFlags { bits: 15 }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::fmt::Binary for MemoryFlags {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ core::fmt::Binary::fmt(&self.bits, f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::fmt::Octal for MemoryFlags {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ core::fmt::Octal::fmt(&self.bits, f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::fmt::LowerHex for MemoryFlags {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ core::fmt::LowerHex::fmt(&self.bits, f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::fmt::UpperHex for MemoryFlags {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ core::fmt::UpperHex::fmt(&self.bits, f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::BitOr for MemoryFlags {
+ type Output = Self;
+
+ /// Returns the union of the two sets of flags.
+ #[inline]
+ fn bitor(self, other: MemoryFlags) -> Self {
+ Self { bits: self.bits | other.bits }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::BitOrAssign for MemoryFlags {
+ /// Adds the set of flags.
+ #[inline]
+ fn bitor_assign(&mut self, other: Self) {
+ self.bits |= other.bits;
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::BitXor for MemoryFlags {
+ type Output = Self;
+
+ /// Returns the left flags, but with all the right flags toggled.
+ #[inline]
+ fn bitxor(self, other: Self) -> Self {
+ Self { bits: self.bits ^ other.bits }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::BitXorAssign for MemoryFlags {
+ /// Toggles the set of flags.
+ #[inline]
+ fn bitxor_assign(&mut self, other: Self) {
+ self.bits ^= other.bits;
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::BitAnd for MemoryFlags {
+ type Output = Self;
+
+ /// Returns the intersection between the two sets of flags.
+ #[inline]
+ fn bitand(self, other: Self) -> Self {
+ Self { bits: self.bits & other.bits }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::BitAndAssign for MemoryFlags {
+ /// Disables all flags disabled in the set.
+ #[inline]
+ fn bitand_assign(&mut self, other: Self) {
+ self.bits &= other.bits;
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::Sub for MemoryFlags {
+ type Output = Self;
+
+ /// Returns the set difference of the two sets of flags.
+ #[inline]
+ fn sub(self, other: Self) -> Self {
+ Self { bits: self.bits & !other.bits }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::SubAssign for MemoryFlags {
+ /// Disables all flags enabled in the set.
+ #[inline]
+ fn sub_assign(&mut self, other: Self) {
+ self.bits &= !other.bits;
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::Not for MemoryFlags {
+ type Output = Self;
+
+ /// Returns the complement of this set of flags.
+ #[inline]
+ fn not(self) -> Self {
+ Self { bits: !self.bits } & MemoryFlags { bits: 15 }
+ }
+}
diff --git a/library/std/src/os/xous/mod.rs b/library/std/src/os/xous/mod.rs
new file mode 100644
index 000000000..153694a89
--- /dev/null
+++ b/library/std/src/os/xous/mod.rs
@@ -0,0 +1,17 @@
+#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(cfg(target_os = "xous"))]
+
+pub mod ffi;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod services;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::ffi::{OsStrExt, OsStringExt};
+}
diff --git a/library/std/src/os/xous/services.rs b/library/std/src/os/xous/services.rs
new file mode 100644
index 000000000..5c219f1fb
--- /dev/null
+++ b/library/std/src/os/xous/services.rs
@@ -0,0 +1,132 @@
+use crate::os::xous::ffi::Connection;
+use core::sync::atomic::{AtomicU32, Ordering};
+
+mod log;
+pub(crate) use log::*;
+
+mod systime;
+pub(crate) use systime::*;
+
+mod ticktimer;
+pub(crate) use ticktimer::*;
+
+mod ns {
+ const NAME_MAX_LENGTH: usize = 64;
+ use crate::os::xous::ffi::{lend_mut, Connection};
+ // By making this repr(C), the layout of this struct becomes well-defined
+ // and no longer shifts around.
+ // By marking it as `align(4096)` we define that it will be page-aligned,
+ // meaning it can be sent between processes. We make sure to pad out the
+ // entire struct so that memory isn't leaked to the name server.
+ #[repr(C, align(4096))]
+ struct ConnectRequest {
+ data: [u8; 4096],
+ }
+
+ impl ConnectRequest {
+ pub fn new(name: &str) -> Self {
+ let mut cr = ConnectRequest { data: [0u8; 4096] };
+ let name_bytes = name.as_bytes();
+
+ // Copy the string into our backing store.
+ for (&src_byte, dest_byte) in name_bytes.iter().zip(&mut cr.data[0..NAME_MAX_LENGTH]) {
+ *dest_byte = src_byte;
+ }
+
+ // Set the string length to the length of the passed-in String,
+ // or the maximum possible length. Which ever is smaller.
+ for (&src_byte, dest_byte) in (name.len().min(NAME_MAX_LENGTH) as u32)
+ .to_le_bytes()
+ .iter()
+ .zip(&mut cr.data[NAME_MAX_LENGTH..])
+ {
+ *dest_byte = src_byte;
+ }
+ cr
+ }
+ }
+
+ pub fn connect_with_name_impl(name: &str, blocking: bool) -> Option<Connection> {
+ let mut request = ConnectRequest::new(name);
+ let opcode = if blocking {
+ 6 /* BlockingConnect */
+ } else {
+ 7 /* TryConnect */
+ };
+ let cid = if blocking { super::name_server() } else { super::try_name_server()? };
+
+ lend_mut(cid, opcode, &mut request.data, 0, name.len().min(NAME_MAX_LENGTH))
+ .expect("unable to perform lookup");
+
+ // Read the result code back from the nameserver
+ let result = u32::from_le_bytes(request.data[0..4].try_into().unwrap());
+ if result == 0 {
+ // If the result was successful, then the CID is stored in the next 4 bytes
+ Some(u32::from_le_bytes(request.data[4..8].try_into().unwrap()).into())
+ } else {
+ None
+ }
+ }
+
+ pub fn connect_with_name(name: &str) -> Option<Connection> {
+ connect_with_name_impl(name, true)
+ }
+
+ pub fn try_connect_with_name(name: &str) -> Option<Connection> {
+ connect_with_name_impl(name, false)
+ }
+}
+
+/// Attempt to connect to a server by name. If the server does not exist, this will
+/// block until the server is created.
+///
+/// Note that this is different from connecting to a server by address. Server
+/// addresses are always 16 bytes long, whereas server names are arbitrary-length
+/// strings up to 64 bytes in length.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn connect(name: &str) -> Option<Connection> {
+ ns::connect_with_name(name)
+}
+
+/// Attempt to connect to a server by name. If the server does not exist, this will
+/// immediately return `None`.
+///
+/// Note that this is different from connecting to a server by address. Server
+/// addresses are always 16 bytes long, whereas server names are arbitrary-length
+/// strings.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn try_connect(name: &str) -> Option<Connection> {
+ ns::try_connect_with_name(name)
+}
+
+static NAME_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0);
+
+/// Return a `Connection` to the name server. If the name server has not been started,
+/// then this call will block until the name server has been started. The `Connection`
+/// will be shared among all connections in a process, so it is safe to call this
+/// multiple times.
+pub(crate) fn name_server() -> Connection {
+ let cid = NAME_SERVER_CONNECTION.load(Ordering::Relaxed);
+ if cid != 0 {
+ return cid.into();
+ }
+
+ let cid = crate::os::xous::ffi::connect("xous-name-server".try_into().unwrap()).unwrap();
+ NAME_SERVER_CONNECTION.store(cid.into(), Ordering::Relaxed);
+ cid
+}
+
+fn try_name_server() -> Option<Connection> {
+ let cid = NAME_SERVER_CONNECTION.load(Ordering::Relaxed);
+ if cid != 0 {
+ return Some(cid.into());
+ }
+
+ if let Ok(Some(cid)) = crate::os::xous::ffi::try_connect("xous-name-server".try_into().unwrap())
+ {
+ NAME_SERVER_CONNECTION.store(cid.into(), Ordering::Relaxed);
+ Some(cid)
+ } else {
+ None
+ }
+}
diff --git a/library/std/src/os/xous/services/log.rs b/library/std/src/os/xous/services/log.rs
new file mode 100644
index 000000000..e6bae929e
--- /dev/null
+++ b/library/std/src/os/xous/services/log.rs
@@ -0,0 +1,63 @@
+use crate::os::xous::ffi::Connection;
+use core::sync::atomic::{AtomicU32, Ordering};
+
+/// Group `usize` bytes into a `usize` and return it, beginning
+/// from `offset` * sizeof(usize) bytes from the start. For example,
+/// `group_or_null([1,2,3,4,5,6,7,8], 1)` on a 32-bit system will
+/// return a usize with 5678 packed into it.
+fn group_or_null(data: &[u8], offset: usize) -> usize {
+ let start = offset * core::mem::size_of::<usize>();
+ let mut out_array = [0u8; core::mem::size_of::<usize>()];
+ if start < data.len() {
+ for (dest, src) in out_array.iter_mut().zip(&data[start..]) {
+ *dest = *src;
+ }
+ }
+ usize::from_le_bytes(out_array)
+}
+
+pub(crate) enum LogScalar<'a> {
+ /// A panic occurred, and a panic log is forthcoming
+ BeginPanic,
+
+ /// Some number of bytes will be appended to the log message
+ AppendPanicMessage(&'a [u8]),
+}
+
+impl<'a> Into<[usize; 5]> for LogScalar<'a> {
+ fn into(self) -> [usize; 5] {
+ match self {
+ LogScalar::BeginPanic => [1000, 0, 0, 0, 0],
+ LogScalar::AppendPanicMessage(c) =>
+ // Text is grouped into 4x `usize` words. The id is 1100 plus
+ // the number of characters in this message.
+ // Ignore errors since we're already panicking.
+ {
+ [
+ 1100 + c.len(),
+ group_or_null(&c, 0),
+ group_or_null(&c, 1),
+ group_or_null(&c, 2),
+ group_or_null(&c, 3),
+ ]
+ }
+ }
+ }
+}
+
+/// Return a `Connection` to the log server, which is used for printing messages to
+/// the console and reporting panics. If the log server has not yet started, this
+/// will block until the server is running. It is safe to call this multiple times,
+/// because the address is shared among all threads in a process.
+pub(crate) fn log_server() -> Connection {
+ static LOG_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0);
+
+ let cid = LOG_SERVER_CONNECTION.load(Ordering::Relaxed);
+ if cid != 0 {
+ return cid.into();
+ }
+
+ let cid = crate::os::xous::ffi::connect("xous-log-server ".try_into().unwrap()).unwrap();
+ LOG_SERVER_CONNECTION.store(cid.into(), Ordering::Relaxed);
+ cid
+}
diff --git a/library/std/src/os/xous/services/systime.rs b/library/std/src/os/xous/services/systime.rs
new file mode 100644
index 000000000..bbb875c69
--- /dev/null
+++ b/library/std/src/os/xous/services/systime.rs
@@ -0,0 +1,28 @@
+use crate::os::xous::ffi::{connect, Connection};
+use core::sync::atomic::{AtomicU32, Ordering};
+
+pub(crate) enum SystimeScalar {
+ GetUtcTimeMs,
+}
+
+impl Into<[usize; 5]> for SystimeScalar {
+ fn into(self) -> [usize; 5] {
+ match self {
+ SystimeScalar::GetUtcTimeMs => [3, 0, 0, 0, 0],
+ }
+ }
+}
+
+/// Return a `Connection` to the systime server. This server is used for reporting the
+/// realtime clock.
+pub(crate) fn systime_server() -> Connection {
+ static SYSTIME_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0);
+ let cid = SYSTIME_SERVER_CONNECTION.load(Ordering::Relaxed);
+ if cid != 0 {
+ return cid.into();
+ }
+
+ let cid = connect("timeserverpublic".try_into().unwrap()).unwrap();
+ SYSTIME_SERVER_CONNECTION.store(cid.into(), Ordering::Relaxed);
+ cid
+}
diff --git a/library/std/src/os/xous/services/ticktimer.rs b/library/std/src/os/xous/services/ticktimer.rs
new file mode 100644
index 000000000..7759303fd
--- /dev/null
+++ b/library/std/src/os/xous/services/ticktimer.rs
@@ -0,0 +1,42 @@
+use crate::os::xous::ffi::Connection;
+use core::sync::atomic::{AtomicU32, Ordering};
+
+pub(crate) enum TicktimerScalar {
+ ElapsedMs,
+ SleepMs(usize),
+ LockMutex(usize /* cookie */),
+ UnlockMutex(usize /* cookie */),
+ WaitForCondition(usize /* cookie */, usize /* timeout (ms) */),
+ NotifyCondition(usize /* cookie */, usize /* count */),
+ FreeMutex(usize /* cookie */),
+ FreeCondition(usize /* cookie */),
+}
+
+impl Into<[usize; 5]> for TicktimerScalar {
+ fn into(self) -> [usize; 5] {
+ match self {
+ TicktimerScalar::ElapsedMs => [0, 0, 0, 0, 0],
+ TicktimerScalar::SleepMs(msecs) => [1, msecs, 0, 0, 0],
+ TicktimerScalar::LockMutex(cookie) => [6, cookie, 0, 0, 0],
+ TicktimerScalar::UnlockMutex(cookie) => [7, cookie, 0, 0, 0],
+ TicktimerScalar::WaitForCondition(cookie, timeout_ms) => [8, cookie, timeout_ms, 0, 0],
+ TicktimerScalar::NotifyCondition(cookie, count) => [9, cookie, count, 0, 0],
+ TicktimerScalar::FreeMutex(cookie) => [10, cookie, 0, 0, 0],
+ TicktimerScalar::FreeCondition(cookie) => [11, cookie, 0, 0, 0],
+ }
+ }
+}
+
+/// Return a `Connection` to the ticktimer server. This server is used for synchronization
+/// primitives such as sleep, Mutex, and Condvar.
+pub(crate) fn ticktimer_server() -> Connection {
+ static TICKTIMER_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0);
+ let cid = TICKTIMER_SERVER_CONNECTION.load(Ordering::Relaxed);
+ if cid != 0 {
+ return cid.into();
+ }
+
+ let cid = crate::os::xous::ffi::connect("ticktimer-server".try_into().unwrap()).unwrap();
+ TICKTIMER_SERVER_CONNECTION.store(cid.into(), Ordering::Relaxed);
+ cid
+}