Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e353eb9

Browse files
袁浩Sword-Destiny
袁浩
authored andcommittedDec 7, 2023
add teeos std impl
Signed-off-by: 袁浩 <[email protected]>
1 parent 2896841 commit e353eb9

File tree

18 files changed

+1190
-10
lines changed

18 files changed

+1190
-10
lines changed
 

‎compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ pub fn target() -> Target {
44
let mut base = base::teeos::opts();
55
base.features = "+strict-align,+neon,+fp-armv8".into();
66
base.max_atomic_width = Some(128);
7-
base.linker = Some("aarch64-linux-gnu-ld".into());
87

98
Target {
109
llvm_target: "aarch64-unknown-none".into(),

‎library/panic_abort/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,16 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 {
8181
}
8282
core::intrinsics::unreachable();
8383
}
84+
} else if #[cfg(target_os = "teeos")] {
85+
mod teeos {
86+
extern "C" {
87+
pub fn TEE_Panic(code: u32) -> !;
88+
}
89+
}
90+
91+
unsafe fn abort() -> ! {
92+
teeos::TEE_Panic(1);
93+
}
8494
} else {
8595
unsafe fn abort() -> ! {
8696
core::intrinsics::abort();

‎library/std/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ fn main() {
3434
|| target.contains("xous")
3535
|| target.contains("hurd")
3636
|| target.contains("uefi")
37+
|| target.contains("teeos")
3738
// See src/bootstrap/synthetic_targets.rs
3839
|| env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
3940
{

‎library/std/src/sys/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ cfg_if::cfg_if! {
5353
} else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
5454
mod sgx;
5555
pub use self::sgx::*;
56+
} else if #[cfg(target_os = "teeos")] {
57+
mod teeos;
58+
pub use self::teeos::*;
5659
} else {
5760
mod unsupported;
5861
pub use self::unsupported::*;

‎library/std/src/sys/teeos/alloc.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use crate::alloc::{GlobalAlloc, Layout, System};
2+
use crate::ptr;
3+
use crate::sys::common::alloc::{realloc_fallback, MIN_ALIGN};
4+
5+
#[stable(feature = "alloc_system_type", since = "1.28.0")]
6+
unsafe impl GlobalAlloc for System {
7+
#[inline]
8+
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
9+
// jemalloc provides alignment less than MIN_ALIGN for small allocations.
10+
// So only rely on MIN_ALIGN if size >= align.
11+
// Also see <https://github.com/rust-lang/rust/issues/45955> and
12+
// <https://github.com/rust-lang/rust/issues/62251#issuecomment-507580914>.
13+
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
14+
libc::malloc(layout.size()) as *mut u8
15+
} else {
16+
aligned_malloc(&layout)
17+
}
18+
}
19+
20+
#[inline]
21+
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
22+
// See the comment above in `alloc` for why this check looks the way it does.
23+
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
24+
libc::calloc(layout.size(), 1) as *mut u8
25+
} else {
26+
let ptr = self.alloc(layout);
27+
if !ptr.is_null() {
28+
ptr::write_bytes(ptr, 0, layout.size());
29+
}
30+
ptr
31+
}
32+
}
33+
34+
#[inline]
35+
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
36+
libc::free(ptr as *mut libc::c_void)
37+
}
38+
39+
#[inline]
40+
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
41+
if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
42+
libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
43+
} else {
44+
realloc_fallback(self, ptr, layout, new_size)
45+
}
46+
}
47+
}
48+
49+
#[inline]
50+
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
51+
let mut out = ptr::null_mut();
52+
// posix_memalign requires that the alignment be a multiple of `sizeof(void*)`.
53+
// Since these are all powers of 2, we can just use max.
54+
let align = layout.align().max(crate::mem::size_of::<usize>());
55+
let ret = libc::posix_memalign(&mut out, align, layout.size());
56+
if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
57+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
use crate::cell::UnsafeCell;
2+
use crate::ptr;
3+
use crate::sync::atomic::{AtomicPtr, Ordering::Relaxed};
4+
use crate::sys::locks::mutex::{self, Mutex};
5+
use crate::sys::time::TIMESPEC_MAX;
6+
use crate::sys_common::lazy_box::{LazyBox, LazyInit};
7+
use crate::time::Duration;
8+
9+
extern "C" {
10+
pub fn pthread_cond_timedwait(
11+
cond: *mut libc::pthread_cond_t,
12+
lock: *mut libc::pthread_mutex_t,
13+
adstime: *const libc::timespec,
14+
) -> libc::c_int;
15+
}
16+
17+
struct AllocatedCondvar(UnsafeCell<libc::pthread_cond_t>);
18+
19+
pub struct Condvar {
20+
inner: LazyBox<AllocatedCondvar>,
21+
mutex: AtomicPtr<libc::pthread_mutex_t>,
22+
}
23+
24+
#[inline]
25+
fn raw(c: &Condvar) -> *mut libc::pthread_cond_t {
26+
c.inner.0.get()
27+
}
28+
29+
unsafe impl Send for AllocatedCondvar {}
30+
unsafe impl Sync for AllocatedCondvar {}
31+
32+
impl LazyInit for AllocatedCondvar {
33+
fn init() -> Box<Self> {
34+
let condvar = Box::new(AllocatedCondvar(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)));
35+
36+
let r = unsafe { libc::pthread_cond_init(condvar.0.get(), crate::ptr::null()) };
37+
assert_eq!(r, 0);
38+
39+
condvar
40+
}
41+
}
42+
43+
impl Drop for AllocatedCondvar {
44+
#[inline]
45+
fn drop(&mut self) {
46+
let r = unsafe { libc::pthread_cond_destroy(self.0.get()) };
47+
debug_assert_eq!(r, 0);
48+
}
49+
}
50+
51+
impl Condvar {
52+
pub const fn new() -> Condvar {
53+
Condvar { inner: LazyBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) }
54+
}
55+
56+
#[inline]
57+
fn verify(&self, mutex: *mut libc::pthread_mutex_t) {
58+
match self.mutex.compare_exchange(ptr::null_mut(), mutex, Relaxed, Relaxed) {
59+
Ok(_) => {} // Stored the address
60+
Err(n) if n == mutex => {} // Lost a race to store the same address
61+
_ => panic!("attempted to use a condition variable with two mutexes"),
62+
}
63+
}
64+
65+
#[inline]
66+
pub fn notify_one(&self) {
67+
let r = unsafe { libc::pthread_cond_signal(raw(self)) };
68+
debug_assert_eq!(r, 0);
69+
}
70+
71+
#[inline]
72+
pub fn notify_all(&self) {
73+
let r = unsafe { libc::pthread_cond_broadcast(raw(self)) };
74+
debug_assert_eq!(r, 0);
75+
}
76+
77+
#[inline]
78+
pub unsafe fn wait(&self, mutex: &Mutex) {
79+
let mutex = mutex::raw(mutex);
80+
self.verify(mutex);
81+
let r = libc::pthread_cond_wait(raw(self), mutex);
82+
debug_assert_eq!(r, 0);
83+
}
84+
85+
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
86+
use crate::sys::time::Timespec;
87+
88+
let mutex = mutex::raw(mutex);
89+
self.verify(mutex);
90+
91+
let timeout = Timespec::now(libc::CLOCK_MONOTONIC)
92+
.checked_add_duration(&dur)
93+
.and_then(|t| t.to_timespec())
94+
.unwrap_or(TIMESPEC_MAX);
95+
96+
let r = pthread_cond_timedwait(raw(self), mutex, &timeout);
97+
assert!(r == libc::ETIMEDOUT || r == 0);
98+
r == 0
99+
}
100+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
pub mod condvar;
2+
#[path = "../../unix/locks/pthread_mutex.rs"]
3+
pub mod mutex;
4+
pub mod rwlock;
5+
6+
pub(crate) use condvar::Condvar;
7+
pub(crate) use mutex::Mutex;
8+
pub(crate) use rwlock::RwLock;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use crate::sys::locks::mutex::Mutex;
2+
3+
/// we do not supported rwlock, so use mutex to simulate rwlock.
4+
/// it's useful because so many code in std will use rwlock.
5+
pub struct RwLock {
6+
inner: Mutex,
7+
}
8+
9+
impl RwLock {
10+
#[inline]
11+
pub const fn new() -> RwLock {
12+
RwLock { inner: Mutex::new() }
13+
}
14+
15+
#[inline]
16+
pub fn read(&self) {
17+
unsafe { self.inner.lock() };
18+
}
19+
20+
#[inline]
21+
pub fn try_read(&self) -> bool {
22+
unsafe { self.inner.try_lock() }
23+
}
24+
25+
#[inline]
26+
pub fn write(&self) {
27+
unsafe { self.inner.lock() };
28+
}
29+
30+
#[inline]
31+
pub unsafe fn try_write(&self) -> bool {
32+
unsafe { self.inner.try_lock() }
33+
}
34+
35+
#[inline]
36+
pub unsafe fn read_unlock(&self) {
37+
unsafe { self.inner.unlock() };
38+
}
39+
40+
#[inline]
41+
pub unsafe fn write_unlock(&self) {
42+
unsafe { self.inner.unlock() };
43+
}
44+
}

‎library/std/src/sys/teeos/mod.rs

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
//! System bindings for the Teeos platform
2+
//!
3+
//! This module contains the facade (aka platform-specific) implementations of
4+
//! OS level functionality for Teeos.
5+
#![allow(unsafe_op_in_unsafe_fn)]
6+
#![allow(unused_variables)]
7+
#![allow(dead_code)]
8+
9+
pub use self::rand::hashmap_random_keys;
10+
11+
pub mod alloc;
12+
#[path = "../unsupported/args.rs"]
13+
pub mod args;
14+
#[path = "../unix/cmath.rs"]
15+
pub mod cmath;
16+
#[path = "../unsupported/env.rs"]
17+
pub mod env;
18+
pub mod locks;
19+
//pub mod fd;
20+
#[path = "../unsupported/fs.rs"]
21+
pub mod fs;
22+
#[path = "../unsupported/io.rs"]
23+
pub mod io;
24+
#[path = "../unix/memchr.rs"]
25+
pub mod memchr;
26+
pub mod net;
27+
#[path = "../unsupported/once.rs"]
28+
pub mod once;
29+
pub mod os;
30+
#[path = "../unix/os_str.rs"]
31+
pub mod os_str;
32+
#[path = "../unix/path.rs"]
33+
pub mod path;
34+
#[path = "../unsupported/pipe.rs"]
35+
pub mod pipe;
36+
#[path = "../unsupported/process.rs"]
37+
pub mod process;
38+
mod rand;
39+
pub mod stdio;
40+
pub mod thread;
41+
pub mod thread_local_dtor;
42+
#[path = "../unix/thread_local_key.rs"]
43+
pub mod thread_local_key;
44+
#[path = "../unsupported/thread_parking.rs"]
45+
pub mod thread_parking;
46+
#[allow(non_upper_case_globals)]
47+
#[path = "../unix/time.rs"]
48+
pub mod time;
49+
50+
use crate::io::ErrorKind;
51+
52+
pub fn abort_internal() -> ! {
53+
unsafe { libc::abort() }
54+
}
55+
56+
// Trusted Applications are loaded as dynamic libraries on Teeos,
57+
// so this should never be called.
58+
pub fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {}
59+
60+
// SAFETY: must be called only once during runtime cleanup.
61+
// this is not guaranteed to run, for example when the program aborts.
62+
pub unsafe fn cleanup() {
63+
unimplemented!()
64+
// We do NOT have stack overflow handler, because TEE OS will kill TA when it happens.
65+
// So cleanup is commented
66+
// stack_overflow::cleanup();
67+
}
68+
69+
#[inline]
70+
pub(crate) fn is_interrupted(errno: i32) -> bool {
71+
errno == libc::EINTR
72+
}
73+
74+
// Note: code below is 1:1 copied from unix/mod.rs
75+
pub fn decode_error_kind(errno: i32) -> ErrorKind {
76+
use ErrorKind::*;
77+
match errno as libc::c_int {
78+
libc::E2BIG => ArgumentListTooLong,
79+
libc::EADDRINUSE => AddrInUse,
80+
libc::EADDRNOTAVAIL => AddrNotAvailable,
81+
libc::EBUSY => ResourceBusy,
82+
libc::ECONNABORTED => ConnectionAborted,
83+
libc::ECONNREFUSED => ConnectionRefused,
84+
libc::ECONNRESET => ConnectionReset,
85+
libc::EDEADLK => Deadlock,
86+
libc::EDQUOT => FilesystemQuotaExceeded,
87+
libc::EEXIST => AlreadyExists,
88+
libc::EFBIG => FileTooLarge,
89+
libc::EHOSTUNREACH => HostUnreachable,
90+
libc::EINTR => Interrupted,
91+
libc::EINVAL => InvalidInput,
92+
libc::EISDIR => IsADirectory,
93+
libc::ELOOP => FilesystemLoop,
94+
libc::ENOENT => NotFound,
95+
libc::ENOMEM => OutOfMemory,
96+
libc::ENOSPC => StorageFull,
97+
libc::ENOSYS => Unsupported,
98+
libc::EMLINK => TooManyLinks,
99+
libc::ENAMETOOLONG => InvalidFilename,
100+
libc::ENETDOWN => NetworkDown,
101+
libc::ENETUNREACH => NetworkUnreachable,
102+
libc::ENOTCONN => NotConnected,
103+
libc::ENOTDIR => NotADirectory,
104+
libc::ENOTEMPTY => DirectoryNotEmpty,
105+
libc::EPIPE => BrokenPipe,
106+
libc::EROFS => ReadOnlyFilesystem,
107+
libc::ESPIPE => NotSeekable,
108+
libc::ESTALE => StaleNetworkFileHandle,
109+
libc::ETIMEDOUT => TimedOut,
110+
libc::ETXTBSY => ExecutableFileBusy,
111+
libc::EXDEV => CrossesDevices,
112+
113+
libc::EACCES | libc::EPERM => PermissionDenied,
114+
115+
// These two constants can have the same value on some systems,
116+
// but different values on others, so we can't use a match
117+
// clause
118+
x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock,
119+
120+
_ => Uncategorized,
121+
}
122+
}
123+
124+
#[doc(hidden)]
125+
pub trait IsMinusOne {
126+
fn is_minus_one(&self) -> bool;
127+
}
128+
129+
macro_rules! impl_is_minus_one {
130+
($($t:ident)*) => ($(impl IsMinusOne for $t {
131+
fn is_minus_one(&self) -> bool {
132+
*self == -1
133+
}
134+
})*)
135+
}
136+
137+
impl_is_minus_one! { i8 i16 i32 i64 isize }
138+
139+
pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
140+
if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) }
141+
}
142+
143+
pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
144+
where
145+
T: IsMinusOne,
146+
F: FnMut() -> T,
147+
{
148+
loop {
149+
match cvt(f()) {
150+
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
151+
other => return other,
152+
}
153+
}
154+
}
155+
156+
pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> {
157+
if error == 0 { Ok(()) } else { Err(crate::io::Error::from_raw_os_error(error)) }
158+
}
159+
160+
use crate::io as std_io;
161+
pub fn unsupported<T>() -> std_io::Result<T> {
162+
Err(unsupported_err())
163+
}
164+
165+
pub fn unsupported_err() -> std_io::Error {
166+
std_io::Error::new(std_io::ErrorKind::Unsupported, "operation not supported on this platform")
167+
}

‎library/std/src/sys/teeos/net.rs

Lines changed: 372 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,372 @@
1+
use crate::fmt;
2+
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
3+
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
4+
use crate::sys::unsupported;
5+
use crate::time::Duration;
6+
7+
pub struct TcpStream(!);
8+
9+
impl TcpStream {
10+
pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
11+
unsupported()
12+
}
13+
14+
pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
15+
unsupported()
16+
}
17+
18+
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
19+
self.0
20+
}
21+
22+
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
23+
self.0
24+
}
25+
26+
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
27+
self.0
28+
}
29+
30+
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
31+
self.0
32+
}
33+
34+
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
35+
self.0
36+
}
37+
38+
pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
39+
self.0
40+
}
41+
42+
pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> {
43+
self.0
44+
}
45+
46+
pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
47+
self.0
48+
}
49+
50+
pub fn is_read_vectored(&self) -> bool {
51+
self.0
52+
}
53+
54+
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
55+
self.0
56+
}
57+
58+
pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
59+
self.0
60+
}
61+
62+
pub fn is_write_vectored(&self) -> bool {
63+
self.0
64+
}
65+
66+
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
67+
self.0
68+
}
69+
70+
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
71+
self.0
72+
}
73+
74+
pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
75+
self.0
76+
}
77+
78+
pub fn duplicate(&self) -> io::Result<TcpStream> {
79+
self.0
80+
}
81+
82+
pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
83+
self.0
84+
}
85+
86+
pub fn linger(&self) -> io::Result<Option<Duration>> {
87+
self.0
88+
}
89+
90+
pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
91+
self.0
92+
}
93+
94+
pub fn nodelay(&self) -> io::Result<bool> {
95+
self.0
96+
}
97+
98+
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
99+
self.0
100+
}
101+
102+
pub fn ttl(&self) -> io::Result<u32> {
103+
self.0
104+
}
105+
106+
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
107+
self.0
108+
}
109+
110+
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
111+
self.0
112+
}
113+
}
114+
115+
impl fmt::Debug for TcpStream {
116+
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
117+
self.0
118+
}
119+
}
120+
121+
pub struct TcpListener(!);
122+
123+
impl TcpListener {
124+
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
125+
unsupported()
126+
}
127+
128+
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
129+
self.0
130+
}
131+
132+
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
133+
self.0
134+
}
135+
136+
pub fn duplicate(&self) -> io::Result<TcpListener> {
137+
self.0
138+
}
139+
140+
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
141+
self.0
142+
}
143+
144+
pub fn ttl(&self) -> io::Result<u32> {
145+
self.0
146+
}
147+
148+
pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
149+
self.0
150+
}
151+
152+
pub fn only_v6(&self) -> io::Result<bool> {
153+
self.0
154+
}
155+
156+
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
157+
self.0
158+
}
159+
160+
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
161+
self.0
162+
}
163+
}
164+
165+
impl fmt::Debug for TcpListener {
166+
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
167+
self.0
168+
}
169+
}
170+
171+
pub struct UdpSocket(!);
172+
173+
impl UdpSocket {
174+
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
175+
unsupported()
176+
}
177+
178+
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
179+
self.0
180+
}
181+
182+
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
183+
self.0
184+
}
185+
186+
pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
187+
self.0
188+
}
189+
190+
pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
191+
self.0
192+
}
193+
194+
pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
195+
self.0
196+
}
197+
198+
pub fn duplicate(&self) -> io::Result<UdpSocket> {
199+
self.0
200+
}
201+
202+
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
203+
self.0
204+
}
205+
206+
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
207+
self.0
208+
}
209+
210+
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
211+
self.0
212+
}
213+
214+
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
215+
self.0
216+
}
217+
218+
pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
219+
self.0
220+
}
221+
222+
pub fn broadcast(&self) -> io::Result<bool> {
223+
self.0
224+
}
225+
226+
pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
227+
self.0
228+
}
229+
230+
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
231+
self.0
232+
}
233+
234+
pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
235+
self.0
236+
}
237+
238+
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
239+
self.0
240+
}
241+
242+
pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
243+
self.0
244+
}
245+
246+
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
247+
self.0
248+
}
249+
250+
pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
251+
self.0
252+
}
253+
254+
pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
255+
self.0
256+
}
257+
258+
pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
259+
self.0
260+
}
261+
262+
pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
263+
self.0
264+
}
265+
266+
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
267+
self.0
268+
}
269+
270+
pub fn ttl(&self) -> io::Result<u32> {
271+
self.0
272+
}
273+
274+
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
275+
self.0
276+
}
277+
278+
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
279+
self.0
280+
}
281+
282+
pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
283+
self.0
284+
}
285+
286+
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
287+
self.0
288+
}
289+
290+
pub fn send(&self, _: &[u8]) -> io::Result<usize> {
291+
self.0
292+
}
293+
294+
pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
295+
self.0
296+
}
297+
}
298+
299+
impl fmt::Debug for UdpSocket {
300+
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
301+
self.0
302+
}
303+
}
304+
305+
pub struct LookupHost(!);
306+
307+
impl LookupHost {
308+
pub fn port(&self) -> u16 {
309+
self.0
310+
}
311+
}
312+
313+
impl Iterator for LookupHost {
314+
type Item = SocketAddr;
315+
fn next(&mut self) -> Option<SocketAddr> {
316+
self.0
317+
}
318+
}
319+
320+
impl TryFrom<&str> for LookupHost {
321+
type Error = io::Error;
322+
323+
fn try_from(_v: &str) -> io::Result<LookupHost> {
324+
unsupported()
325+
}
326+
}
327+
328+
impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
329+
type Error = io::Error;
330+
331+
fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
332+
unsupported()
333+
}
334+
}
335+
336+
#[allow(nonstandard_style)]
337+
pub mod netc {
338+
pub const AF_INET: u8 = 0;
339+
pub const AF_INET6: u8 = 1;
340+
pub type sa_family_t = u8;
341+
342+
#[derive(Copy, Clone)]
343+
pub struct in_addr {
344+
pub s_addr: u32,
345+
}
346+
347+
#[derive(Copy, Clone)]
348+
pub struct sockaddr_in {
349+
pub sin_family: sa_family_t,
350+
pub sin_port: u16,
351+
pub sin_addr: in_addr,
352+
}
353+
354+
#[derive(Copy, Clone)]
355+
pub struct in6_addr {
356+
pub s6_addr: [u8; 16],
357+
}
358+
359+
#[derive(Copy, Clone)]
360+
pub struct sockaddr_in6 {
361+
pub sin6_family: sa_family_t,
362+
pub sin6_port: u16,
363+
pub sin6_addr: in6_addr,
364+
pub sin6_flowinfo: u32,
365+
pub sin6_scope_id: u32,
366+
}
367+
368+
#[derive(Copy, Clone)]
369+
pub struct sockaddr {}
370+
}
371+
372+
pub type Socket = UdpSocket;

‎library/std/src/sys/teeos/os.rs

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
//! Implementation of `std::os` functionality for teeos
2+
3+
use core::marker::PhantomData;
4+
5+
use crate::error::Error as StdError;
6+
use crate::ffi::{OsStr, OsString};
7+
use crate::fmt;
8+
use crate::io;
9+
use crate::path;
10+
use crate::path::PathBuf;
11+
12+
use super::unsupported;
13+
14+
pub fn errno() -> i32 {
15+
unsafe { (*libc::__errno_location()) as i32 }
16+
}
17+
18+
// Hardcoded to return 4096, since `sysconf` is only implemented as a stub.
19+
pub fn page_size() -> usize {
20+
// unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize };
21+
4096
22+
}
23+
24+
// Everything below are stubs and copied from unsupported.rs
25+
26+
pub fn error_string(_errno: i32) -> String {
27+
"error string unimplemented".to_string()
28+
}
29+
30+
pub fn getcwd() -> io::Result<PathBuf> {
31+
unsupported()
32+
}
33+
34+
pub fn chdir(_: &path::Path) -> io::Result<()> {
35+
unsupported()
36+
}
37+
38+
pub struct SplitPaths<'a>(!, PhantomData<&'a ()>);
39+
40+
pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
41+
panic!("unsupported")
42+
}
43+
44+
impl<'a> Iterator for SplitPaths<'a> {
45+
type Item = PathBuf;
46+
fn next(&mut self) -> Option<PathBuf> {
47+
self.0
48+
}
49+
}
50+
51+
#[derive(Debug)]
52+
pub struct JoinPathsError;
53+
54+
pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
55+
where
56+
I: Iterator<Item = T>,
57+
T: AsRef<OsStr>,
58+
{
59+
Err(JoinPathsError)
60+
}
61+
62+
impl fmt::Display for JoinPathsError {
63+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64+
"not supported on this platform yet".fmt(f)
65+
}
66+
}
67+
68+
impl StdError for JoinPathsError {
69+
#[allow(deprecated)]
70+
fn description(&self) -> &str {
71+
"not supported on this platform yet"
72+
}
73+
}
74+
75+
pub fn current_exe() -> io::Result<PathBuf> {
76+
unsupported()
77+
}
78+
79+
pub struct Env(!);
80+
81+
impl Env {
82+
// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
83+
pub fn str_debug(&self) -> impl fmt::Debug + '_ {
84+
let Self(inner) = self;
85+
match *inner {}
86+
}
87+
}
88+
89+
impl fmt::Debug for Env {
90+
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
91+
let Self(inner) = self;
92+
match *inner {}
93+
}
94+
}
95+
96+
impl Iterator for Env {
97+
type Item = (OsString, OsString);
98+
fn next(&mut self) -> Option<(OsString, OsString)> {
99+
let Self(inner) = self;
100+
match *inner {}
101+
}
102+
}
103+
104+
pub fn env() -> Env {
105+
panic!("not supported on this platform")
106+
}
107+
108+
pub fn getenv(_: &OsStr) -> Option<OsString> {
109+
None
110+
}
111+
112+
pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
113+
Err(io::Error::new(io::ErrorKind::Unsupported, "cannot set env vars on this platform"))
114+
}
115+
116+
pub fn unsetenv(_: &OsStr) -> io::Result<()> {
117+
Err(io::Error::new(io::ErrorKind::Unsupported, "cannot unset env vars on this platform"))
118+
}
119+
120+
pub fn temp_dir() -> PathBuf {
121+
panic!("no filesystem on this platform")
122+
}
123+
124+
pub fn home_dir() -> Option<PathBuf> {
125+
None
126+
}
127+
128+
pub fn exit(_code: i32) -> ! {
129+
panic!("TA should not call `exit`")
130+
}
131+
132+
pub fn getpid() -> u32 {
133+
panic!("no pids on this platform")
134+
}

‎library/std/src/sys/teeos/rand.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
pub fn hashmap_random_keys() -> (u64, u64) {
2+
const KEY_LEN: usize = core::mem::size_of::<u64>();
3+
4+
let mut v = [0u8; KEY_LEN * 2];
5+
imp::fill_bytes(&mut v);
6+
7+
let key1 = v[0..KEY_LEN].try_into().unwrap();
8+
let key2 = v[KEY_LEN..].try_into().unwrap();
9+
10+
(u64::from_ne_bytes(key1), u64::from_ne_bytes(key2))
11+
}
12+
13+
mod imp {
14+
extern "C" {
15+
fn TEE_GenerateRandom(randomBuffer: *mut core::ffi::c_void, randomBufferLen: libc::size_t);
16+
}
17+
18+
pub fn fill_bytes(v: &mut [u8]) {
19+
unsafe { TEE_GenerateRandom(v.as_mut_ptr() as _, v.len() * crate::mem::size_of::<u8>()) }
20+
}
21+
}

‎library/std/src/sys/teeos/stdio.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#![deny(unsafe_op_in_unsafe_fn)]
2+
3+
use crate::io;
4+
use core::arch::asm;
5+
6+
pub struct Stdin;
7+
pub struct Stdout;
8+
pub struct Stderr;
9+
10+
const KCALL_DEBUG_CMD_PUT_BYTES: i64 = 2;
11+
12+
unsafe fn debug_call(cap_ref: u64, call_no: i64, arg1: u64, arg2: u64) -> i32 {
13+
let ret: u64;
14+
unsafe {
15+
asm!(
16+
"svc #99",
17+
inout("x0") cap_ref => ret,
18+
in("x1") call_no,
19+
in("x2") arg1,
20+
in("x3") arg2,
21+
);
22+
}
23+
24+
ret as i32
25+
}
26+
27+
fn print_buf(s: &[u8]) -> io::Result<usize> {
28+
// Corresponds to `HM_DEBUG_PUT_BYTES_LIMIT`.
29+
const MAX_LEN: usize = 512;
30+
let len = if s.len() > MAX_LEN { MAX_LEN } else { s.len() };
31+
let result = unsafe { debug_call(0, KCALL_DEBUG_CMD_PUT_BYTES, s.as_ptr() as u64, len as u64) };
32+
33+
if result == 0 { Ok(len) } else { Err(io::Error::from(io::ErrorKind::InvalidInput)) }
34+
}
35+
36+
impl Stdin {
37+
pub const fn new() -> Stdin {
38+
Stdin
39+
}
40+
}
41+
42+
impl io::Read for Stdin {
43+
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
44+
Ok(0)
45+
}
46+
}
47+
48+
impl Stdout {
49+
pub const fn new() -> Stdout {
50+
Stdout
51+
}
52+
}
53+
54+
impl io::Write for Stdout {
55+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
56+
print_buf(buf)
57+
}
58+
59+
fn flush(&mut self) -> io::Result<()> {
60+
Ok(())
61+
}
62+
}
63+
64+
impl Stderr {
65+
pub const fn new() -> Stderr {
66+
Stderr
67+
}
68+
}
69+
70+
impl io::Write for Stderr {
71+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
72+
print_buf(buf)
73+
}
74+
75+
fn flush(&mut self) -> io::Result<()> {
76+
Ok(())
77+
}
78+
}
79+
80+
pub const STDIN_BUF_SIZE: usize = 0;
81+
82+
pub fn is_ebadf(err: &io::Error) -> bool {
83+
err.raw_os_error() == Some(libc::EBADF as i32)
84+
}
85+
86+
pub fn panic_output() -> Option<impl io::Write> {
87+
Some(Stderr::new())
88+
}

‎library/std/src/sys/teeos/thread.rs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
use core::convert::TryInto;
2+
3+
use crate::cmp;
4+
use crate::ffi::CStr;
5+
use crate::io;
6+
use crate::mem;
7+
use crate::num::NonZeroUsize;
8+
use crate::ptr;
9+
use crate::sys::os;
10+
use crate::time::Duration;
11+
12+
pub const DEFAULT_MIN_STACK_SIZE: usize = 8 * 1024;
13+
14+
pub struct Thread {
15+
id: libc::pthread_t,
16+
}
17+
18+
// Some platforms may have pthread_t as a pointer in which case we still want
19+
// a thread to be Send/Sync
20+
unsafe impl Send for Thread {}
21+
unsafe impl Sync for Thread {}
22+
23+
extern "C" {
24+
pub fn TEE_Wait(timeout: u32) -> u32;
25+
}
26+
27+
impl Thread {
28+
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
29+
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
30+
let p = Box::into_raw(Box::new(p));
31+
let mut native: libc::pthread_t = mem::zeroed();
32+
let mut attr: libc::pthread_attr_t = mem::zeroed();
33+
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
34+
assert_eq!(
35+
libc::pthread_attr_settee(
36+
&mut attr,
37+
libc::TEESMP_THREAD_ATTR_CA_INHERIT,
38+
libc::TEESMP_THREAD_ATTR_TASK_ID_INHERIT,
39+
libc::TEESMP_THREAD_ATTR_HAS_SHADOW,
40+
),
41+
0,
42+
);
43+
44+
let stack_size = cmp::max(stack, min_stack_size(&attr));
45+
46+
match libc::pthread_attr_setstacksize(&mut attr, stack_size) {
47+
0 => {}
48+
n => {
49+
assert_eq!(n, libc::EINVAL);
50+
// EINVAL means |stack_size| is either too small or not a
51+
// multiple of the system page size. Because it's definitely
52+
// >= PTHREAD_STACK_MIN, it must be an alignment issue.
53+
// Round up to the nearest page and try again.
54+
let page_size = os::page_size();
55+
let stack_size =
56+
(stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1);
57+
assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0);
58+
}
59+
};
60+
61+
let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _);
62+
// Note: if the thread creation fails and this assert fails, then p will
63+
// be leaked. However, an alternative design could cause double-free
64+
// which is clearly worse.
65+
assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
66+
67+
return if ret != 0 {
68+
// The thread failed to start and as a result p was not consumed. Therefore, it is
69+
// safe to reconstruct the box so that it gets deallocated.
70+
drop(Box::from_raw(p));
71+
Err(io::Error::from_raw_os_error(ret))
72+
} else {
73+
// The new thread will start running earliest after the next yield.
74+
// We add a yield here, so that the user does not have to.
75+
Thread::yield_now();
76+
Ok(Thread { id: native })
77+
};
78+
79+
extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
80+
unsafe {
81+
// Next, set up our stack overflow handler which may get triggered if we run
82+
// out of stack.
83+
// this is not necessary in TEE.
84+
//let _handler = stack_overflow::Handler::new();
85+
// Finally, let's run some code.
86+
Box::from_raw(main as *mut Box<dyn FnOnce()>)();
87+
}
88+
ptr::null_mut()
89+
}
90+
}
91+
92+
pub fn yield_now() {
93+
let ret = unsafe { libc::sched_yield() };
94+
debug_assert_eq!(ret, 0);
95+
}
96+
97+
/// This does not do anything on teeos
98+
pub fn set_name(_name: &CStr) {
99+
// Both pthread_setname_np and prctl are not available to the TA,
100+
// so we can't implement this currently. If the need arises please
101+
// contact the teeos rustzone team.
102+
}
103+
104+
/// only main thread could wait for sometime in teeos
105+
pub fn sleep(dur: Duration) {
106+
let sleep_millis = dur.as_millis();
107+
let final_sleep: u32 =
108+
if sleep_millis >= u32::MAX as u128 { u32::MAX } else { sleep_millis as u32 };
109+
unsafe {
110+
let _ = TEE_Wait(final_sleep);
111+
}
112+
}
113+
114+
/// must join, because no pthread_detach supported
115+
pub fn join(self) {
116+
unsafe {
117+
let ret = libc::pthread_join(self.id, ptr::null_mut());
118+
mem::forget(self);
119+
assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
120+
}
121+
}
122+
123+
pub fn id(&self) -> libc::pthread_t {
124+
self.id
125+
}
126+
127+
pub fn into_id(self) -> libc::pthread_t {
128+
let id = self.id;
129+
mem::forget(self);
130+
id
131+
}
132+
}
133+
134+
impl Drop for Thread {
135+
fn drop(&mut self) {
136+
// we can not call detach, so just panic if thread spawn without join
137+
panic!("thread must join, detach is not supported!");
138+
}
139+
}
140+
141+
// Note: Both `sched_getaffinity` and `sysconf` are available but not functional on
142+
// teeos, so this function always returns an Error!
143+
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
144+
Err(io::Error::new(
145+
io::ErrorKind::NotFound,
146+
"The number of hardware threads is not known for the target platform",
147+
))
148+
}
149+
150+
// stub
151+
pub mod guard {
152+
use crate::ops::Range;
153+
pub type Guard = Range<usize>;
154+
pub unsafe fn current() -> Option<Guard> {
155+
None
156+
}
157+
pub unsafe fn init() -> Option<Guard> {
158+
None
159+
}
160+
}
161+
162+
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
163+
libc::PTHREAD_STACK_MIN.try_into().expect("Infallible")
164+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
2+
use crate::sys_common::thread_local_dtor::register_dtor_fallback;
3+
register_dtor_fallback(t, dtor);
4+
}

‎library/std/src/sys/unix/time.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ struct Nanoseconds(u32);
2323

2424
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2525
pub struct SystemTime {
26-
pub(in crate::sys::unix) t: Timespec,
26+
pub(crate) t: Timespec,
2727
}
2828

2929
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
30-
pub(in crate::sys::unix) struct Timespec {
30+
pub(crate) struct Timespec {
3131
tv_sec: i64,
3232
tv_nsec: Nanoseconds,
3333
}
@@ -239,11 +239,11 @@ impl From<libc::timespec> for Timespec {
239239
not(target_arch = "riscv32")
240240
))]
241241
#[repr(C)]
242-
pub(in crate::sys::unix) struct __timespec64 {
243-
pub(in crate::sys::unix) tv_sec: i64,
242+
pub(crate) struct __timespec64 {
243+
pub(crate) tv_sec: i64,
244244
#[cfg(target_endian = "big")]
245245
_padding: i32,
246-
pub(in crate::sys::unix) tv_nsec: i32,
246+
pub(crate) tv_nsec: i32,
247247
#[cfg(target_endian = "little")]
248248
_padding: i32,
249249
}
@@ -255,7 +255,7 @@ pub(in crate::sys::unix) struct __timespec64 {
255255
not(target_arch = "riscv32")
256256
))]
257257
impl __timespec64 {
258-
pub(in crate::sys::unix) fn new(tv_sec: i64, tv_nsec: i32) -> Self {
258+
pub(crate) fn new(tv_sec: i64, tv_nsec: i32) -> Self {
259259
Self { tv_sec, tv_nsec, _padding: 0 }
260260
}
261261
}

‎library/std/src/thread/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1581,6 +1581,7 @@ impl<'scope, T> JoinInner<'scope, T> {
15811581
/// [`thread::Builder::spawn`]: Builder::spawn
15821582
/// [`thread::spawn`]: spawn
15831583
#[stable(feature = "rust1", since = "1.0.0")]
1584+
#[cfg_attr(target_os = "teeos", must_use)]
15841585
pub struct JoinHandle<T>(JoinInner<'static, T>);
15851586

15861587
#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")]

‎src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Create the following shell scripts that wrap Clang from the OpenHarmony SDK:
3939
```sh
4040
#!/bin/sh
4141
exec /path/to/ohos-sdk/linux/native/llvm/bin/clang \
42-
--target aarch64-linux-gnu \
42+
-target aarch64-linux-gnu \
4343
"$@"
4444
```
4545

@@ -48,7 +48,7 @@ exec /path/to/ohos-sdk/linux/native/llvm/bin/clang \
4848
```sh
4949
#!/bin/sh
5050
exec /path/to/ohos-sdk/linux/native/llvm/bin/clang++ \
51-
--target aarch64-linux-gnu \
51+
-target aarch64-linux-gnu \
5252
"$@"
5353
```
5454

@@ -81,6 +81,13 @@ ranlib = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ranlib"
8181
llvm-config = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-config"
8282
```
8383

84+
```text
85+
note: You need to insert "/usr/include/x86_64-linux-gnu/" into environment variable: $C_INCLUDE_PATH
86+
if some header files like bits/xxx.h not found.
87+
note: You can install gcc-aarch64-linux-gnu,g++-aarch64-linux-gnu if some files like crti.o not found.
88+
note: You may need to install libc6-dev-i386 libc6-dev if "gnu/stubs-32.h" not found.
89+
```
90+
8491
## Building Rust programs
8592

8693
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
9198
You will need to configure the linker to use in `~/.cargo/config`:
9299
```toml
93100
[target.aarch64-unknown-teeos]
94-
linker = "/path/to/aarch64-unknown-teeos-clang.sh"
101+
linker = "/path/to/aarch64-unknown-teeos-clang.sh" # or aarch64-linux-gnu-ld
95102
```
96103

97104
## Testing

0 commit comments

Comments
 (0)
Please sign in to comment.