Skip to content

Commit

Permalink
add teeos std impl
Browse files Browse the repository at this point in the history
Signed-off-by: 袁浩 <yuanhao34@huawei.com>
  • Loading branch information
袁浩 authored and Sword-Destiny committed Dec 6, 2023
1 parent 2896841 commit 7566d14
Show file tree
Hide file tree
Showing 18 changed files with 1,257 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
10 changes: 10 additions & 0 deletions library/panic_abort/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 {
}
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();
Expand Down
1 change: 1 addition & 0 deletions library/std/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down
3 changes: 3 additions & 0 deletions library/std/src/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ cfg_if::cfg_if! {
} 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::*;
Expand Down
57 changes: 57 additions & 0 deletions library/std/src/sys/teeos/alloc.rs
Original file line number Diff line number Diff line change
@@ -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 }
}
100 changes: 100 additions & 0 deletions library/std/src/sys/teeos/locks/condvar.rs
Original file line number Diff line number Diff line change
@@ -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
}
}
8 changes: 8 additions & 0 deletions library/std/src/sys/teeos/locks/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
111 changes: 111 additions & 0 deletions library/std/src/sys/teeos/locks/rwlock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
use crate::cell::UnsafeCell;
use crate::mem::{forget, MaybeUninit};
use crate::sys::cvt_nz;
use crate::sys::locks::mutex::PthreadMutexAttr;
use crate::sys_common::lazy_box::{LazyBox, LazyInit};

/// we do not supported rwlock, so use mutex to simulate rwlock.
/// it's useful because so many code in std will use rwlock.
struct AllocatedRwlock(UnsafeCell<libc::pthread_mutex_t>);

/// also implemented by mutex
pub struct RwLock {
inner: LazyBox<AllocatedRwlock>,
}

#[inline]
pub unsafe fn raw(m: &RwLock) -> *mut libc::pthread_mutex_t {
m.inner.0.get()
}

unsafe impl Send for AllocatedRwlock {}
unsafe impl Sync for AllocatedRwlock {}

impl LazyInit for AllocatedRwlock {
fn init() -> Box<Self> {
let mutex = Box::new(AllocatedRwlock(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)));

unsafe {
let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit();
cvt_nz(libc::pthread_mutexattr_init(attr.as_mut_ptr())).unwrap();
let attr = PthreadMutexAttr(&mut attr);
cvt_nz(libc::pthread_mutexattr_settype(
attr.0.as_mut_ptr(),
libc::PTHREAD_MUTEX_NORMAL,
))
.unwrap();
cvt_nz(libc::pthread_mutex_init(mutex.0.get(), attr.0.as_ptr())).unwrap();
}

mutex
}

fn destroy(mutex: Box<Self>) {
// We're not allowed to pthread_mutex_destroy a locked mutex,
// so check first if it's unlocked.
if unsafe { libc::pthread_mutex_trylock(mutex.0.get()) == 0 } {
unsafe { libc::pthread_mutex_unlock(mutex.0.get()) };
drop(mutex);
} else {
// The mutex is locked. This happens if a MutexGuard is leaked.
// In this case, we just leak the Mutex too.
forget(mutex);
}
}

fn cancel_init(_: Box<Self>) {
// In this case, we can just drop it without any checks,
// since it cannot have been locked yet.
}
}

impl Drop for AllocatedRwlock {
#[inline]
fn drop(&mut self) {
let r = unsafe { libc::pthread_mutex_destroy(self.0.get()) };
debug_assert_eq!(r, 0);
}
}

impl RwLock {
#[inline]
pub const fn new() -> RwLock {
RwLock { inner: LazyBox::new() }
}

#[inline]
pub fn read(&self) {
let r = unsafe { libc::pthread_mutex_lock(raw(self)) };
debug_assert_eq!(r, 0);
}

#[inline]
pub fn try_read(&self) -> bool {
let r = unsafe { libc::pthread_mutex_trylock(raw(self)) };
r == 0
}

#[inline]
pub fn write(&self) {
let r = unsafe { libc::pthread_mutex_lock(raw(self)) };
debug_assert_eq!(r, 0);
}

#[inline]
pub unsafe fn try_write(&self) -> bool {
let r = unsafe { libc::pthread_mutex_trylock(raw(self)) };
r == 0
}

#[inline]
pub unsafe fn read_unlock(&self) {
let r = unsafe { libc::pthread_mutex_unlock(raw(self)) };
debug_assert_eq!(r, 0);
}

#[inline]
pub unsafe fn write_unlock(&self) {
let r = unsafe { libc::pthread_mutex_unlock(raw(self)) };
debug_assert_eq!(r, 0);
}
}

0 comments on commit 7566d14

Please sign in to comment.