Auto merge of #116565 - Sword-Destiny:master, r=Amanieu

add teeos std impl

add teeos std library implement.

this MR is draft untill the libc update to 0.2.150

this MR is the final step for suppot rust in teeos.
first step(add target): https://github.com/rust-lang/rust/pull/113480
second step(add teeos libc): https://github.com/rust-lang/libc/pull/3333
This commit is contained in:
bors 2023-12-07 05:22:21 +00:00
commit 568f6a8641
18 changed files with 1190 additions and 10 deletions

View File

@ -4,7 +4,6 @@ pub fn target() -> Target {
let mut base = base::teeos::opts();
base.features = "+strict-align,+neon,+fp-armv8".into();
base.max_atomic_width = Some(128);
base.linker = Some("aarch64-linux-gnu-ld".into());
Target {
llvm_target: "aarch64-unknown-none".into(),

View File

@ -81,6 +81,16 @@ unsafe fn abort() -> ! {
}
core::intrinsics::unreachable();
}
} else if #[cfg(target_os = "teeos")] {
mod teeos {
extern "C" {
pub fn TEE_Panic(code: u32) -> !;
}
}
unsafe fn abort() -> ! {
teeos::TEE_Panic(1);
}
} else {
unsafe fn abort() -> ! {
core::intrinsics::abort();

View File

@ -34,6 +34,7 @@ fn main() {
|| target.contains("xous")
|| target.contains("hurd")
|| target.contains("uefi")
|| target.contains("teeos")
// See src/bootstrap/synthetic_targets.rs
|| env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
{

View File

@ -53,6 +53,9 @@
} else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
mod sgx;
pub use self::sgx::*;
} else if #[cfg(target_os = "teeos")] {
mod teeos;
pub use self::teeos::*;
} else {
mod unsupported;
pub use self::unsupported::*;

View File

@ -0,0 +1,57 @@
use crate::alloc::{GlobalAlloc, Layout, System};
use crate::ptr;
use crate::sys::common::alloc::{realloc_fallback, MIN_ALIGN};
#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
// jemalloc provides alignment less than MIN_ALIGN for small allocations.
// So only rely on MIN_ALIGN if size >= align.
// Also see <https://github.com/rust-lang/rust/issues/45955> and
// <https://github.com/rust-lang/rust/issues/62251#issuecomment-507580914>.
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
libc::malloc(layout.size()) as *mut u8
} else {
aligned_malloc(&layout)
}
}
#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
// See the comment above in `alloc` for why this check looks the way it does.
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
libc::calloc(layout.size(), 1) as *mut u8
} else {
let ptr = self.alloc(layout);
if !ptr.is_null() {
ptr::write_bytes(ptr, 0, layout.size());
}
ptr
}
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
libc::free(ptr as *mut libc::c_void)
}
#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
} else {
realloc_fallback(self, ptr, layout, new_size)
}
}
}
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
let mut out = ptr::null_mut();
// posix_memalign requires that the alignment be a multiple of `sizeof(void*)`.
// Since these are all powers of 2, we can just use max.
let align = layout.align().max(crate::mem::size_of::<usize>());
let ret = libc::posix_memalign(&mut out, align, layout.size());
if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
}

View File

@ -0,0 +1,100 @@
use crate::cell::UnsafeCell;
use crate::ptr;
use crate::sync::atomic::{AtomicPtr, Ordering::Relaxed};
use crate::sys::locks::mutex::{self, Mutex};
use crate::sys::time::TIMESPEC_MAX;
use crate::sys_common::lazy_box::{LazyBox, LazyInit};
use crate::time::Duration;
extern "C" {
pub fn pthread_cond_timedwait(
cond: *mut libc::pthread_cond_t,
lock: *mut libc::pthread_mutex_t,
adstime: *const libc::timespec,
) -> libc::c_int;
}
struct AllocatedCondvar(UnsafeCell<libc::pthread_cond_t>);
pub struct Condvar {
inner: LazyBox<AllocatedCondvar>,
mutex: AtomicPtr<libc::pthread_mutex_t>,
}
#[inline]
fn raw(c: &Condvar) -> *mut libc::pthread_cond_t {
c.inner.0.get()
}
unsafe impl Send for AllocatedCondvar {}
unsafe impl Sync for AllocatedCondvar {}
impl LazyInit for AllocatedCondvar {
fn init() -> Box<Self> {
let condvar = Box::new(AllocatedCondvar(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)));
let r = unsafe { libc::pthread_cond_init(condvar.0.get(), crate::ptr::null()) };
assert_eq!(r, 0);
condvar
}
}
impl Drop for AllocatedCondvar {
#[inline]
fn drop(&mut self) {
let r = unsafe { libc::pthread_cond_destroy(self.0.get()) };
debug_assert_eq!(r, 0);
}
}
impl Condvar {
pub const fn new() -> Condvar {
Condvar { inner: LazyBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) }
}
#[inline]
fn verify(&self, mutex: *mut libc::pthread_mutex_t) {
match self.mutex.compare_exchange(ptr::null_mut(), mutex, Relaxed, Relaxed) {
Ok(_) => {} // Stored the address
Err(n) if n == mutex => {} // Lost a race to store the same address
_ => panic!("attempted to use a condition variable with two mutexes"),
}
}
#[inline]
pub fn notify_one(&self) {
let r = unsafe { libc::pthread_cond_signal(raw(self)) };
debug_assert_eq!(r, 0);
}
#[inline]
pub fn notify_all(&self) {
let r = unsafe { libc::pthread_cond_broadcast(raw(self)) };
debug_assert_eq!(r, 0);
}
#[inline]
pub unsafe fn wait(&self, mutex: &Mutex) {
let mutex = mutex::raw(mutex);
self.verify(mutex);
let r = libc::pthread_cond_wait(raw(self), mutex);
debug_assert_eq!(r, 0);
}
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
use crate::sys::time::Timespec;
let mutex = mutex::raw(mutex);
self.verify(mutex);
let timeout = Timespec::now(libc::CLOCK_MONOTONIC)
.checked_add_duration(&dur)
.and_then(|t| t.to_timespec())
.unwrap_or(TIMESPEC_MAX);
let r = pthread_cond_timedwait(raw(self), mutex, &timeout);
assert!(r == libc::ETIMEDOUT || r == 0);
r == 0
}
}

View File

@ -0,0 +1,8 @@
pub mod condvar;
#[path = "../../unix/locks/pthread_mutex.rs"]
pub mod mutex;
pub mod rwlock;
pub(crate) use condvar::Condvar;
pub(crate) use mutex::Mutex;
pub(crate) use rwlock::RwLock;

View File

@ -0,0 +1,44 @@
use crate::sys::locks::mutex::Mutex;
/// we do not supported rwlock, so use mutex to simulate rwlock.
/// it's useful because so many code in std will use rwlock.
pub struct RwLock {
inner: Mutex,
}
impl RwLock {
#[inline]
pub const fn new() -> RwLock {
RwLock { inner: Mutex::new() }
}
#[inline]
pub fn read(&self) {
unsafe { self.inner.lock() };
}
#[inline]
pub fn try_read(&self) -> bool {
unsafe { self.inner.try_lock() }
}
#[inline]
pub fn write(&self) {
unsafe { self.inner.lock() };
}
#[inline]
pub unsafe fn try_write(&self) -> bool {
unsafe { self.inner.try_lock() }
}
#[inline]
pub unsafe fn read_unlock(&self) {
unsafe { self.inner.unlock() };
}
#[inline]
pub unsafe fn write_unlock(&self) {
unsafe { self.inner.unlock() };
}
}

View File

@ -0,0 +1,167 @@
//! System bindings for the Teeos platform
//!
//! This module contains the facade (aka platform-specific) implementations of
//! OS level functionality for Teeos.
#![allow(unsafe_op_in_unsafe_fn)]
#![allow(unused_variables)]
#![allow(dead_code)]
pub use self::rand::hashmap_random_keys;
pub mod alloc;
#[path = "../unsupported/args.rs"]
pub mod args;
#[path = "../unix/cmath.rs"]
pub mod cmath;
#[path = "../unsupported/env.rs"]
pub mod env;
pub mod locks;
//pub mod fd;
#[path = "../unsupported/fs.rs"]
pub mod fs;
#[path = "../unsupported/io.rs"]
pub mod io;
#[path = "../unix/memchr.rs"]
pub mod memchr;
pub mod net;
#[path = "../unsupported/once.rs"]
pub mod once;
pub mod os;
#[path = "../unix/os_str.rs"]
pub mod os_str;
#[path = "../unix/path.rs"]
pub mod path;
#[path = "../unsupported/pipe.rs"]
pub mod pipe;
#[path = "../unsupported/process.rs"]
pub mod process;
mod rand;
pub mod stdio;
pub mod thread;
pub mod thread_local_dtor;
#[path = "../unix/thread_local_key.rs"]
pub mod thread_local_key;
#[path = "../unsupported/thread_parking.rs"]
pub mod thread_parking;
#[allow(non_upper_case_globals)]
#[path = "../unix/time.rs"]
pub mod time;
use crate::io::ErrorKind;
pub fn abort_internal() -> ! {
unsafe { libc::abort() }
}
// Trusted Applications are loaded as dynamic libraries on Teeos,
// so this should never be called.
pub fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {}
// SAFETY: must be called only once during runtime cleanup.
// this is not guaranteed to run, for example when the program aborts.
pub unsafe fn cleanup() {
unimplemented!()
// We do NOT have stack overflow handler, because TEE OS will kill TA when it happens.
// So cleanup is commented
// stack_overflow::cleanup();
}
#[inline]
pub(crate) fn is_interrupted(errno: i32) -> bool {
errno == libc::EINTR
}
// Note: code below is 1:1 copied from unix/mod.rs
pub fn decode_error_kind(errno: i32) -> ErrorKind {
use ErrorKind::*;
match errno as libc::c_int {
libc::E2BIG => ArgumentListTooLong,
libc::EADDRINUSE => AddrInUse,
libc::EADDRNOTAVAIL => AddrNotAvailable,
libc::EBUSY => ResourceBusy,
libc::ECONNABORTED => ConnectionAborted,
libc::ECONNREFUSED => ConnectionRefused,
libc::ECONNRESET => ConnectionReset,
libc::EDEADLK => Deadlock,
libc::EDQUOT => FilesystemQuotaExceeded,
libc::EEXIST => AlreadyExists,
libc::EFBIG => FileTooLarge,
libc::EHOSTUNREACH => HostUnreachable,
libc::EINTR => Interrupted,
libc::EINVAL => InvalidInput,
libc::EISDIR => IsADirectory,
libc::ELOOP => FilesystemLoop,
libc::ENOENT => NotFound,
libc::ENOMEM => OutOfMemory,
libc::ENOSPC => StorageFull,
libc::ENOSYS => Unsupported,
libc::EMLINK => TooManyLinks,
libc::ENAMETOOLONG => InvalidFilename,
libc::ENETDOWN => NetworkDown,
libc::ENETUNREACH => NetworkUnreachable,
libc::ENOTCONN => NotConnected,
libc::ENOTDIR => NotADirectory,
libc::ENOTEMPTY => DirectoryNotEmpty,
libc::EPIPE => BrokenPipe,
libc::EROFS => ReadOnlyFilesystem,
libc::ESPIPE => NotSeekable,
libc::ESTALE => StaleNetworkFileHandle,
libc::ETIMEDOUT => TimedOut,
libc::ETXTBSY => ExecutableFileBusy,
libc::EXDEV => CrossesDevices,
libc::EACCES | libc::EPERM => PermissionDenied,
// These two constants can have the same value on some systems,
// but different values on others, so we can't use a match
// clause
x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock,
_ => Uncategorized,
}
}
#[doc(hidden)]
pub trait IsMinusOne {
fn is_minus_one(&self) -> bool;
}
macro_rules! impl_is_minus_one {
($($t:ident)*) => ($(impl IsMinusOne for $t {
fn is_minus_one(&self) -> bool {
*self == -1
}
})*)
}
impl_is_minus_one! { i8 i16 i32 i64 isize }
pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) }
}
pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
where
T: IsMinusOne,
F: FnMut() -> T,
{
loop {
match cvt(f()) {
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
other => return other,
}
}
}
pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> {
if error == 0 { Ok(()) } else { Err(crate::io::Error::from_raw_os_error(error)) }
}
use crate::io as std_io;
pub fn unsupported<T>() -> std_io::Result<T> {
Err(unsupported_err())
}
pub fn unsupported_err() -> std_io::Error {
std_io::Error::new(std_io::ErrorKind::Unsupported, "operation not supported on this platform")
}

View File

@ -0,0 +1,372 @@
use crate::fmt;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
use crate::sys::unsupported;
use crate::time::Duration;
pub struct TcpStream(!);
impl TcpStream {
pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
unsupported()
}
pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
unsupported()
}
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
self.0
}
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
self.0
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
self.0
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
self.0
}
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
self.0
}
pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
self.0
}
pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> {
self.0
}
pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.0
}
pub fn is_read_vectored(&self) -> bool {
self.0
}
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
self.0
}
pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
self.0
}
pub fn is_write_vectored(&self) -> bool {
self.0
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.0
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
self.0
}
pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
self.0
}
pub fn duplicate(&self) -> io::Result<TcpStream> {
self.0
}
pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
self.0
}
pub fn linger(&self) -> io::Result<Option<Duration>> {
self.0
}
pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
self.0
}
pub fn nodelay(&self) -> io::Result<bool> {
self.0
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
self.0
}
pub fn ttl(&self) -> io::Result<u32> {
self.0
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.0
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
self.0
}
}
impl fmt::Debug for TcpStream {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0
}
}
pub struct TcpListener(!);
impl TcpListener {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
unsupported()
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
self.0
}
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
self.0
}
pub fn duplicate(&self) -> io::Result<TcpListener> {
self.0
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
self.0
}
pub fn ttl(&self) -> io::Result<u32> {
self.0
}
pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
self.0
}
pub fn only_v6(&self) -> io::Result<bool> {
self.0
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.0
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
self.0
}
}
impl fmt::Debug for TcpListener {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0
}
}
pub struct UdpSocket(!);
impl UdpSocket {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
unsupported()
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.0
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
self.0
}
pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.0
}
pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.0
}
pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
self.0
}
pub fn duplicate(&self) -> io::Result<UdpSocket> {
self.0
}
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
self.0
}
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
self.0
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
self.0
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
self.0
}
pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
self.0
}
pub fn broadcast(&self) -> io::Result<bool> {
self.0
}
pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
self.0
}
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
self.0
}
pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
self.0
}
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
self.0
}
pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
self.0
}
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
self.0
}
pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
self.0
}
pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
self.0
}
pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
self.0
}
pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
self.0
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
self.0
}
pub fn ttl(&self) -> io::Result<u32> {
self.0
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.0
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
self.0
}
pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
self.0
}
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
self.0
}
pub fn send(&self, _: &[u8]) -> io::Result<usize> {
self.0
}
pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
self.0
}
}
impl fmt::Debug for UdpSocket {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0
}
}
pub struct LookupHost(!);
impl LookupHost {
pub fn port(&self) -> u16 {
self.0
}
}
impl Iterator for LookupHost {
type Item = SocketAddr;
fn next(&mut self) -> Option<SocketAddr> {
self.0
}
}
impl TryFrom<&str> for LookupHost {
type Error = io::Error;
fn try_from(_v: &str) -> io::Result<LookupHost> {
unsupported()
}
}
impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
type Error = io::Error;
fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
unsupported()
}
}
#[allow(nonstandard_style)]
pub mod netc {
pub const AF_INET: u8 = 0;
pub const AF_INET6: u8 = 1;
pub type sa_family_t = u8;
#[derive(Copy, Clone)]
pub struct in_addr {
pub s_addr: u32,
}
#[derive(Copy, Clone)]
pub struct sockaddr_in {
pub sin_family: sa_family_t,
pub sin_port: u16,
pub sin_addr: in_addr,
}
#[derive(Copy, Clone)]
pub struct in6_addr {
pub s6_addr: [u8; 16],
}
#[derive(Copy, Clone)]
pub struct sockaddr_in6 {
pub sin6_family: sa_family_t,
pub sin6_port: u16,
pub sin6_addr: in6_addr,
pub sin6_flowinfo: u32,
pub sin6_scope_id: u32,
}
#[derive(Copy, Clone)]
pub struct sockaddr {}
}
pub type Socket = UdpSocket;

View File

@ -0,0 +1,134 @@
//! Implementation of `std::os` functionality for teeos
use core::marker::PhantomData;
use crate::error::Error as StdError;
use crate::ffi::{OsStr, OsString};
use crate::fmt;
use crate::io;
use crate::path;
use crate::path::PathBuf;
use super::unsupported;
pub fn errno() -> i32 {
unsafe { (*libc::__errno_location()) as i32 }
}
// Hardcoded to return 4096, since `sysconf` is only implemented as a stub.
pub fn page_size() -> usize {
// unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize };
4096
}
// Everything below are stubs and copied from unsupported.rs
pub fn error_string(_errno: i32) -> String {
"error string unimplemented".to_string()
}
pub fn getcwd() -> io::Result<PathBuf> {
unsupported()
}
pub fn chdir(_: &path::Path) -> io::Result<()> {
unsupported()
}
pub struct SplitPaths<'a>(!, PhantomData<&'a ()>);
pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
panic!("unsupported")
}
impl<'a> Iterator for SplitPaths<'a> {
type Item = PathBuf;
fn next(&mut self) -> Option<PathBuf> {
self.0
}
}
#[derive(Debug)]
pub struct JoinPathsError;
pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
where
I: Iterator<Item = T>,
T: AsRef<OsStr>,
{
Err(JoinPathsError)
}
impl fmt::Display for JoinPathsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
"not supported on this platform yet".fmt(f)
}
}
impl StdError for JoinPathsError {
#[allow(deprecated)]
fn description(&self) -> &str {
"not supported on this platform yet"
}
}
pub fn current_exe() -> io::Result<PathBuf> {
unsupported()
}
pub struct Env(!);
impl Env {
// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
pub fn str_debug(&self) -> impl fmt::Debug + '_ {
let Self(inner) = self;
match *inner {}
}
}
impl fmt::Debug for Env {
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self(inner) = self;
match *inner {}
}
}
impl Iterator for Env {
type Item = (OsString, OsString);
fn next(&mut self) -> Option<(OsString, OsString)> {
let Self(inner) = self;
match *inner {}
}
}
pub fn env() -> Env {
panic!("not supported on this platform")
}
pub fn getenv(_: &OsStr) -> Option<OsString> {
None
}
pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
Err(io::Error::new(io::ErrorKind::Unsupported, "cannot set env vars on this platform"))
}
pub fn unsetenv(_: &OsStr) -> io::Result<()> {
Err(io::Error::new(io::ErrorKind::Unsupported, "cannot unset env vars on this platform"))
}
pub fn temp_dir() -> PathBuf {
panic!("no filesystem on this platform")
}
pub fn home_dir() -> Option<PathBuf> {
None
}
pub fn exit(_code: i32) -> ! {
panic!("TA should not call `exit`")
}
pub fn getpid() -> u32 {
panic!("no pids on this platform")
}

View File

@ -0,0 +1,21 @@
pub fn hashmap_random_keys() -> (u64, u64) {
const KEY_LEN: usize = core::mem::size_of::<u64>();
let mut v = [0u8; KEY_LEN * 2];
imp::fill_bytes(&mut v);
let key1 = v[0..KEY_LEN].try_into().unwrap();
let key2 = v[KEY_LEN..].try_into().unwrap();
(u64::from_ne_bytes(key1), u64::from_ne_bytes(key2))
}
mod imp {
extern "C" {
fn TEE_GenerateRandom(randomBuffer: *mut core::ffi::c_void, randomBufferLen: libc::size_t);
}
pub fn fill_bytes(v: &mut [u8]) {
unsafe { TEE_GenerateRandom(v.as_mut_ptr() as _, v.len() * crate::mem::size_of::<u8>()) }
}
}

View File

@ -0,0 +1,88 @@
#![deny(unsafe_op_in_unsafe_fn)]
use crate::io;
use core::arch::asm;
pub struct Stdin;
pub struct Stdout;
pub struct Stderr;
const KCALL_DEBUG_CMD_PUT_BYTES: i64 = 2;
unsafe fn debug_call(cap_ref: u64, call_no: i64, arg1: u64, arg2: u64) -> i32 {
let ret: u64;
unsafe {
asm!(
"svc #99",
inout("x0") cap_ref => ret,
in("x1") call_no,
in("x2") arg1,
in("x3") arg2,
);
}
ret as i32
}
fn print_buf(s: &[u8]) -> io::Result<usize> {
// Corresponds to `HM_DEBUG_PUT_BYTES_LIMIT`.
const MAX_LEN: usize = 512;
let len = if s.len() > MAX_LEN { MAX_LEN } else { s.len() };
let result = unsafe { debug_call(0, KCALL_DEBUG_CMD_PUT_BYTES, s.as_ptr() as u64, len as u64) };
if result == 0 { Ok(len) } else { Err(io::Error::from(io::ErrorKind::InvalidInput)) }
}
impl Stdin {
pub const fn new() -> Stdin {
Stdin
}
}
impl io::Read for Stdin {
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
Ok(0)
}
}
impl Stdout {
pub const fn new() -> Stdout {
Stdout
}
}
impl io::Write for Stdout {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
print_buf(buf)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl Stderr {
pub const fn new() -> Stderr {
Stderr
}
}
impl io::Write for Stderr {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
print_buf(buf)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
pub const STDIN_BUF_SIZE: usize = 0;
pub fn is_ebadf(err: &io::Error) -> bool {
err.raw_os_error() == Some(libc::EBADF as i32)
}
pub fn panic_output() -> Option<impl io::Write> {
Some(Stderr::new())
}

View File

@ -0,0 +1,164 @@
use core::convert::TryInto;
use crate::cmp;
use crate::ffi::CStr;
use crate::io;
use crate::mem;
use crate::num::NonZeroUsize;
use crate::ptr;
use crate::sys::os;
use crate::time::Duration;
pub const DEFAULT_MIN_STACK_SIZE: usize = 8 * 1024;
pub struct Thread {
id: libc::pthread_t,
}
// Some platforms may have pthread_t as a pointer in which case we still want
// a thread to be Send/Sync
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}
extern "C" {
pub fn TEE_Wait(timeout: u32) -> u32;
}
impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
let p = Box::into_raw(Box::new(p));
let mut native: libc::pthread_t = mem::zeroed();
let mut attr: libc::pthread_attr_t = mem::zeroed();
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
assert_eq!(
libc::pthread_attr_settee(
&mut attr,
libc::TEESMP_THREAD_ATTR_CA_INHERIT,
libc::TEESMP_THREAD_ATTR_TASK_ID_INHERIT,
libc::TEESMP_THREAD_ATTR_HAS_SHADOW,
),
0,
);
let stack_size = cmp::max(stack, min_stack_size(&attr));
match libc::pthread_attr_setstacksize(&mut attr, stack_size) {
0 => {}
n => {
assert_eq!(n, libc::EINVAL);
// EINVAL means |stack_size| is either too small or not a
// multiple of the system page size. Because it's definitely
// >= PTHREAD_STACK_MIN, it must be an alignment issue.
// Round up to the nearest page and try again.
let page_size = os::page_size();
let stack_size =
(stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1);
assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0);
}
};
let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _);
// Note: if the thread creation fails and this assert fails, then p will
// be leaked. However, an alternative design could cause double-free
// which is clearly worse.
assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
return if ret != 0 {
// The thread failed to start and as a result p was not consumed. Therefore, it is
// safe to reconstruct the box so that it gets deallocated.
drop(Box::from_raw(p));
Err(io::Error::from_raw_os_error(ret))
} else {
// The new thread will start running earliest after the next yield.
// We add a yield here, so that the user does not have to.
Thread::yield_now();
Ok(Thread { id: native })
};
extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
unsafe {
// Next, set up our stack overflow handler which may get triggered if we run
// out of stack.
// this is not necessary in TEE.
//let _handler = stack_overflow::Handler::new();
// Finally, let's run some code.
Box::from_raw(main as *mut Box<dyn FnOnce()>)();
}
ptr::null_mut()
}
}
pub fn yield_now() {
let ret = unsafe { libc::sched_yield() };
debug_assert_eq!(ret, 0);
}
/// This does not do anything on teeos
pub fn set_name(_name: &CStr) {
// Both pthread_setname_np and prctl are not available to the TA,
// so we can't implement this currently. If the need arises please
// contact the teeos rustzone team.
}
/// only main thread could wait for sometime in teeos
pub fn sleep(dur: Duration) {
let sleep_millis = dur.as_millis();
let final_sleep: u32 =
if sleep_millis >= u32::MAX as u128 { u32::MAX } else { sleep_millis as u32 };
unsafe {
let _ = TEE_Wait(final_sleep);
}
}
/// must join, because no pthread_detach supported
pub fn join(self) {
unsafe {
let ret = libc::pthread_join(self.id, ptr::null_mut());
mem::forget(self);
assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
}
}
pub fn id(&self) -> libc::pthread_t {
self.id
}
pub fn into_id(self) -> libc::pthread_t {
let id = self.id;
mem::forget(self);
id
}
}
impl Drop for Thread {
fn drop(&mut self) {
// we can not call detach, so just panic if thread spawn without join
panic!("thread must join, detach is not supported!");
}
}
// Note: Both `sched_getaffinity` and `sysconf` are available but not functional on
// teeos, so this function always returns an Error!
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
Err(io::Error::new(
io::ErrorKind::NotFound,
"The number of hardware threads is not known for the target platform",
))
}
// stub
pub mod guard {
use crate::ops::Range;
pub type Guard = Range<usize>;
pub unsafe fn current() -> Option<Guard> {
None
}
pub unsafe fn init() -> Option<Guard> {
None
}
}
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
libc::PTHREAD_STACK_MIN.try_into().expect("Infallible")
}

View File

@ -0,0 +1,4 @@
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
use crate::sys_common::thread_local_dtor::register_dtor_fallback;
register_dtor_fallback(t, dtor);
}

View File

@ -23,11 +23,11 @@
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SystemTime {
pub(in crate::sys::unix) t: Timespec,
pub(crate) t: Timespec,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(in crate::sys::unix) struct Timespec {
pub(crate) struct Timespec {
tv_sec: i64,
tv_nsec: Nanoseconds,
}
@ -239,11 +239,11 @@ fn from(t: libc::timespec) -> Timespec {
not(target_arch = "riscv32")
))]
#[repr(C)]
pub(in crate::sys::unix) struct __timespec64 {
pub(in crate::sys::unix) tv_sec: i64,
pub(crate) struct __timespec64 {
pub(crate) tv_sec: i64,
#[cfg(target_endian = "big")]
_padding: i32,
pub(in crate::sys::unix) tv_nsec: i32,
pub(crate) tv_nsec: i32,
#[cfg(target_endian = "little")]
_padding: i32,
}
@ -255,7 +255,7 @@ pub(in crate::sys::unix) struct __timespec64 {
not(target_arch = "riscv32")
))]
impl __timespec64 {
pub(in crate::sys::unix) fn new(tv_sec: i64, tv_nsec: i32) -> Self {
pub(crate) fn new(tv_sec: i64, tv_nsec: i32) -> Self {
Self { tv_sec, tv_nsec, _padding: 0 }
}
}

View File

@ -1581,6 +1581,7 @@ fn join(mut self) -> Result<T> {
/// [`thread::Builder::spawn`]: Builder::spawn
/// [`thread::spawn`]: spawn
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(target_os = "teeos", must_use)]
pub struct JoinHandle<T>(JoinInner<'static, T>);
#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")]

View File

@ -39,7 +39,7 @@ Create the following shell scripts that wrap Clang from the OpenHarmony SDK:
```sh
#!/bin/sh
exec /path/to/ohos-sdk/linux/native/llvm/bin/clang \
--target aarch64-linux-gnu \
-target aarch64-linux-gnu \
"$@"
```
@ -48,7 +48,7 @@ exec /path/to/ohos-sdk/linux/native/llvm/bin/clang \
```sh
#!/bin/sh
exec /path/to/ohos-sdk/linux/native/llvm/bin/clang++ \
--target aarch64-linux-gnu \
-target aarch64-linux-gnu \
"$@"
```
@ -81,6 +81,13 @@ ranlib = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ranlib"
llvm-config = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-config"
```
```text
note: You need to insert "/usr/include/x86_64-linux-gnu/" into environment variable: $C_INCLUDE_PATH
if some header files like bits/xxx.h not found.
note: You can install gcc-aarch64-linux-gnu,g++-aarch64-linux-gnu if some files like crti.o not found.
note: You may need to install libc6-dev-i386 libc6-dev if "gnu/stubs-32.h" not found.
```
## Building Rust programs
Rust does not yet ship pre-compiled artifacts for this target. To compile for
@ -91,7 +98,7 @@ this target, you will either need to build Rust with the target enabled (see
You will need to configure the linker to use in `~/.cargo/config`:
```toml
[target.aarch64-unknown-teeos]
linker = "/path/to/aarch64-unknown-teeos-clang.sh"
linker = "/path/to/aarch64-unknown-teeos-clang.sh" # or aarch64-linux-gnu-ld
```
## Testing