Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Rust backed camkes components #17

Closed
wants to merge 12 commits into from
21 changes: 20 additions & 1 deletion camkes/templates/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,19 @@ endif

/*- endfor -*/

# Rust rules for camkes components that use rust.
/*- for i in instances if not i.type.hardware -*/
.PHONY: /*? i.type.name ?*/_rust
/*? i.type.name ?*/_rust:
@echo " [RS] /*? i.type.name ?*/_rust"
# cd $(SOURCE_DIR)/components//*? i.type.name ?*/ && RUST_TARGET_PATH=${STAGE_DIR}/common/ RUST_BACKTRACE=1 \
cd $(/*? i.type.name ?*/_RUST) && RUST_TARGET_PATH=${STAGE_DIR}/common/ RUST_BACKTRACE=1 \
CARGO_HOME="${PWD}" RUSTFLAGS="--sysroot=${PWD}/sysroot" cargo build --lib $(RUST_CARGO_FLAGS) --manifest-path $(/*? i.type.name ?*/_RUST)/Cargo.toml --target=$(RUST_CUSTOM_TARGET)
echo cp $(/*? i.type.name ?*/_RUST)/target/${RUST_CUSTOM_TARGET}/${RUST_RELEASE_MODE}/$(/*? i.type.name ?*/_RUST:%=lib%.a) $(/*? i.type.name ?*/_RUST:%=%.a)
$(Q) cp $(/*? i.type.name ?*/_RUST)/target/${RUST_CUSTOM_TARGET}/${RUST_RELEASE_MODE}/lib*.a $(/*? i.type.name ?*/_RUST:%=%.a)

/*- endfor -*/

# Library dependencies required by glue code.
/*- for i in instances -*/
/*? i.name ?*/_instance_LIBS += ${/*? i.type.name ?*/_LIBS} ${CAMKES_CORE_LIBS}
Expand Down Expand Up @@ -402,16 +415,22 @@ define /*? i.name ?*/_buildrump
endef
/*- endif -*/

ifdef /*? i.type.name ?*/_RUST
/*? i.type.name ?*/_CARGO_TARGET=/*? i.type.name ?*/_rust
endif

/*? i.name ?*/.instance.bin: $(/*? i.name ?*/_CFILES:%.c=%.o) \
$(/*? i.name ?*/_CXXFILES:%.cxx=%.o) \
$(/*? i.name ?*/_ASMFILES:%.S=%.o) \
$(/*? i.type.name ?*/_CARGO_TARGET) \
$(/*? i.name ?*/_OFILES) \
/*- if rump_config -*/ $(/*? i.name ?*/_rumpbin) /*- endif -*/ \
/*- if rump_config -*/ $(INTERMEDIATE_BASEFILE) /*- endif -*/ \
$(/*? i.name ?*/_instance_LIBS:%=lib%.a) \
$(abspath ${BUILD_DIR})/ld//*? i.name ?*//generated/linker.lds
@echo " [LD] $(notdir $@)"
${Q}${/*? i.name ?*/_CC} $(CRTOBJFILES) $(filter %.o,$^) $(FINOBJFILES) ${/*? i.name ?*/_instance_LDFLAGS} -o $@
@echo " [RUST_MAIN_OBJECT] $(/*? i.type.name ?*/_RUST:%=%.a)"
${Q}${/*? i.name ?*/_CC} $(CRTOBJFILES) $(filter %.o,$^) $(filter %.a,$^) $(/*? i.type.name ?*/_RUST:%=%.a) $(FINOBJFILES) ${/*? i.name ?*/_instance_LDFLAGS} -o $@
$(/*? i.name ?*/_buildrump)

/*- set p = Perspective(group=i.address_space) -*/
Expand Down
22 changes: 22 additions & 0 deletions camkesrust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#
# Copyright 2018, Data61
# Commonwealth Scientific and Industrial Research Organisation (CSIRO)
# ABN 41 687 119 230.
#
# This software may be distributed and modified according to the terms of
# the BSD 2-Clause license. Note that NO WARRANTY is provided.
# See "LICENSE_BSD2.txt" for details.
#
# @TAG(DATA61_BSD)
#

[package]
name = "camkesrust"
version = "0.1.0"
authors = ["Kent McLeod <[email protected]>"]

[dependencies]

[replace]
"libc:0.2.40" = { git = 'https://github.com/GaloisInc/rs_liblibc.git' }

23 changes: 23 additions & 0 deletions camkesrust/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// Copyright 2018, Data61
// Commonwealth Scientific and Industrial Research Organisation (CSIRO)
// ABN 41 687 119 230.
//
// This software may be distributed and modified according to the terms of
// the BSD 2-Clause license. Note that NO WARRANTY is provided.
// See "LICENSE_BSD2.txt" for details.
//
// @TAG(DATA61_BSD)
//
#![no_std]
#![feature(libc)]
#![feature(alloc)]
#![feature(const_fn)]

extern crate libc;
extern crate alloc;

pub use mutex::*;

mod mutex;

187 changes: 187 additions & 0 deletions camkesrust/src/mutex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
//
// Copyright 2018, Data61
// Commonwealth Scientific and Industrial Research Organisation (CSIRO)
// ABN 41 687 119 230.
//
// This software may be distributed and modified according to the terms of
// the BSD 2-Clause license. Note that NO WARRANTY is provided.
// See "LICENSE_BSD2.txt" for details.
//
// @TAG(DATA61_BSD)
//
use core::ops::{Drop, Deref, DerefMut};
use core::cell::UnsafeCell;

use libc::c_void;

extern "C"
{
/// These functions are provided by libsel4camkes: <camkes/sync.h>
/// They provide an allocation and locking interface for mutexes backed by seL4 Notification objects.
/// These functions are not thread safe and must be handled as such.

/// Allocate a new mutex. Returns 0 on success, -1 on failure
fn camkes_mutex_new(allocator: *mut c_void, mutex: *mut*mut c_void) -> isize;

/// Acquire lock to mutex. Cannot be called if lock is held by current thread.
fn camkes_mutex_lock(mutex: *mut c_void) -> isize;

/// Release lock to mutex. Can only be called if current thread holds lock.
fn camkes_mutex_unlock(mutex: *mut c_void) -> isize;

/// Releases mutex back to allocator.
fn camkes_mutex_free(allocator: *mut c_void, mutex: *mut c_void) -> isize;

/// Initialises allocator.
fn init_default_allocator_heap(allocator: *mut*mut c_void) -> isize;
}

// Reference to allocator returned by initial call to `init_default_allocator_heap`.
// We bootstrap a Mutex to store the allocator in so that subsequent calls to it are
// synchronised. It cannot be used until `init_allocator` has been called.
static mut ALLOCATOR: Mutex<*mut c_void> = Mutex::uninitialized(0 as *mut c_void);



/// Mutual Exclusion provided by mutex_pool in libsel4camkes c library.
pub struct Mutex<T: ?Sized>
{
lock: *mut c_void,
data: UnsafeCell<T>,
}


pub struct MutexGuard<'a, T: ?Sized + 'a>
{
lock: *mut c_void,
data: &'a mut T,
}

// Same unsafe impls as `std::sync::Mutex`
unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}

impl<T> Mutex<T>
{

/// This function needs to be called in a single threaded environment such as the
/// Camkes `pre_init` function. If you are using lazy_static! then this needs to
/// be called before any of the lazy initialisation occurs.
///
/// TODO: This could potentially be moved to a `lazy_static!` macro that initialises ALLOCATOR
pub unsafe fn init_allocator() -> Result<(),()>
{

// Initialise allocator in underlying c library
let mut alloc = 0 as *mut c_void;
match init_default_allocator_heap(&mut alloc) {
0 => (),
_ => panic!{"Could not allocate default allocator"},
}

// Use allocator to create initial mutex for future accesses to the allocator
// by calls to `Mutex::new(T)`.
let mut mtx = 0 as *mut c_void;
match camkes_mutex_new(alloc, &mut mtx) {
0 => (),
_ => panic!{"Could not allocate inital mutex for allocator."},
}

// Save reference to allocator in static mut. The mutex should ensure accesses
// are thread safe.
ALLOCATOR = Mutex{
lock:mtx,
data:UnsafeCell::new(alloc)
};
Ok(())
}

/// const initialiser for bootstrapping ALLOCATOR.
const fn uninitialized(user_data: T) -> Mutex<T> {
Mutex { lock: 0 as *mut c_void, data: UnsafeCell::new(user_data) }
}

/// Create a new Mutex around data T. Returns an error code passed from the underlying
/// library if error.
pub fn new(user_data: T) -> Result<Mutex<T>, isize>
{

let mut mtx = 0 as *mut c_void;
unsafe {
let alloc = ALLOCATOR.lock();
match camkes_mutex_new(*alloc, &mut mtx) {
0 => (),
i => return Err(i),
}
};
Ok(Mutex
{
lock: mtx,
data: UnsafeCell::new(user_data),
})
}


/// Consumes this mutex, returning the underlying data.
pub fn into_inner(self) -> T
{
// We know statically that there are no outstanding references to
// `self` so there's no need to lock.
let Mutex { data, lock } = self;
unsafe {
let alloc = ALLOCATOR.lock();
match camkes_mutex_free(*alloc, lock) {
0 => (),
_ => panic!{"Failed to free mutex"}
}
};
data.into_inner()
}
}

impl<T: ?Sized> Mutex<T>
{

/// Acquire lock. camkes_mutex_lock is blocking until the lock is acquired.
/// There is no way to timeout on a lock request.
pub fn lock(&self) -> MutexGuard<T>
{
unsafe {
match camkes_mutex_lock(self.lock) {
0 => (),
_ => panic!{"lock returned error"},
}
};
MutexGuard
{
lock: self.lock,
data: unsafe { &mut *self.data.get() },
}
}
}

// Implement some standard Deref coercions
impl<'a, T: ?Sized> Deref for MutexGuard<'a, T>
{
type Target = T;
fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T>
{
fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

impl<'a, T: ?Sized> Drop for MutexGuard<'a, T>
{
/// The dropping of the MutexGuard will release the lock it was created from.
fn drop(&mut self)
{
unsafe{
match camkes_mutex_unlock(self.lock) {
0 => (),
_ => panic!{"Failed to release lock"},
}
};
}
}
2 changes: 1 addition & 1 deletion libsel4camkes/Kbuild
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@
#

libs-y += libsel4camkes
libsel4camkes: libsel4 $(libc) common libutils libplatsupport libsel4utils libsel4muslcsys
libsel4camkes: libsel4 $(libc) common libutils libplatsupport libsel4utils libsel4muslcsys libsel4sync
53 changes: 53 additions & 0 deletions libsel4camkes/include/camkes/sync.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2018, Data61
* Commonwealth Scientific and Industrial Research Organisation (CSIRO)
* ABN 41 687 119 230.
*
* This software may be distributed and modified according to the terms of
* the BSD 2-Clause license. Note that NO WARRANTY is provided.
* See "LICENSE_BSD2.txt" for details.
*
* @TAG(DATA61_BSD)
*/

#pragma once

/* This file defines a simple mutex interface that is intended
* to be backed by a notification_pool implemented by the Camkes runtime.
* It doesn't use static inline functions like other libsel4* interfaces
* in order to allow this interface to be used over a FFI.
*/

/* Allocates a mutex. Returns -1 on failure, 0 on success */
typedef int (*alloc_mutex_fn)(void * cookie, void **mutex);
/* Frees a mutex. Returns -1 on failure, 0 on success */
typedef int (*free_mutex_fn)(void * cookie, void *mutex);

/* Interface struct for allocating mutexs */
typedef struct {
void * cookie;
alloc_mutex_fn alloc;
free_mutex_fn free;
} camkes_mutex_allocator;

/* Creates a new mutex from the allocator */
int camkes_mutex_new(camkes_mutex_allocator *allocator, void **mutex);

/* Acquire mutex. Undefined behavior if caller already holds mutex. */
int camkes_mutex_lock(void *mutex);

/* Release mutex. Undefined behavior if caller tries to release mutex they do not hold. */
int camkes_mutex_unlock(void *mutex);

/* Frees a mutex */
int camkes_mutex_free(camkes_mutex_allocator *allocator, void *mutex);

/* Initialises a default allocator that uses camkes/alloc.h to allocate mutexes from a
* camkes seL4Notification pool. The maximum number of mutexes must be defined at build time.
* If a mutex is freed, it can be allocated again.
*/
int init_default_allocator(camkes_mutex_allocator *allocator);

/* Initialises the default allocator but will call malloc internally to do this. */
int init_default_allocator_heap(camkes_mutex_allocator **allocator);

Loading