about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/std/src/os/mod.rs2
-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.rs14
5 files changed, 1122 insertions, 0 deletions
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index 634c3cc4a15..de6d784c65b 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -146,6 +146,8 @@ pub mod vita;
 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/xous/ffi.rs b/library/std/src/os/xous/ffi.rs
new file mode 100644
index 00000000000..8be7fbb102f
--- /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 00000000000..345005bcc78
--- /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 00000000000..af9de3cbff2
--- /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 00000000000..3d69bc2e04e
--- /dev/null
+++ b/library/std/src/os/xous/mod.rs
@@ -0,0 +1,14 @@
+#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(cfg(target_os = "xous"))]
+
+pub mod ffi;
+
+/// 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};
+}