-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
435 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[package] | ||
authors = ["Tock Project Developers <[email protected]>"] | ||
categories = ["embedded", "no-std", "os"] | ||
edition = "2018" | ||
license = "Apache-2.0 OR MIT" | ||
name = "libtock_console" | ||
repository = "https://www.github.com/tock/libtock-rs" | ||
version = "0.1.0" | ||
|
||
[dependencies] | ||
libtock_platform = { path = "../platform" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#[derive(Clone,Copy)] | ||
pub struct Console; | ||
|
||
impl Console { | ||
pub fn check_exists<'a, P: libtock_platform::Platform<'a>>() -> libtock_platform::ReturnCode { | ||
unimplemented!() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/// `AllowedSlice` is a slice-based analogue of `Allowed`. It represents a slice | ||
/// that has been shared with the kernel using the `allow` system call. | ||
/// Unlike `Allowed`, `AllowSlice`'s methods accept an index into the shared | ||
/// slice, and operate on the element at that index. | ||
// Like Allowed, AllowedSlice does not directly use the 'b lifetime. Platform | ||
// uses 'b to prevent the AllowedSlice from accessing the buffer after the | ||
// buffer becomes invalid. | ||
// AllowedSlice requires T to be Copy for the same reasons as Allowed. See | ||
// Allowed's comments for more information. | ||
pub struct AllowedSlice<'b, T: Copy + 'b> { | ||
// `data` points to the start of the shared slice, and `len` is the length | ||
// of that slice. | ||
// Safety properties: | ||
// 1. The slice remains valid and usable for the lifetime of this | ||
// AllowedSlice instance. | ||
// 2. Read and write accesses into the slice must be performed as a | ||
// volatile operation, as the kernel may mutate the slice at any time. | ||
// 3. The shared slice may have an arbitrary bit pattern in it, so reading | ||
// from the slice is only safe if the type contained within is | ||
// AllowReadable. | ||
data: core::ptr::NonNull<T>, | ||
len: usize, | ||
|
||
// Use the 'b parameter, and make AllowedSlice invariant w.r.t. T. See | ||
// Allowed's comment for a more detailed description. | ||
_phantom: core::marker::PhantomData<&'b mut [T]>, | ||
} | ||
|
||
// AllowedSlice's API mirrors that of Allowed, but with indexing on most | ||
// methods. Se Allowed's comments for more details. | ||
impl<'b, T: Copy + 'b> AllowedSlice<'b, T> { | ||
// The caller (Platform) must make sure the following are true: | ||
// 1. `data` points to a valid [T] slice of length `len`. | ||
// 2. There are no other references to the slice. | ||
// 3. The slice remains usable until the AllowedSlice's lifetime has ended. | ||
#[allow(unused)] // TODO: Remove when Platform is implemented. | ||
pub(crate) unsafe fn new(data: core::ptr::NonNull<T>, len: usize) -> AllowedSlice<'b, T> { | ||
AllowedSlice { | ||
data, | ||
len, | ||
_phantom: core::marker::PhantomData, | ||
} | ||
} | ||
|
||
/// Sets the value at `index`, or does nothing if `index` is out of range. | ||
pub fn set(&self, index: usize, value: T) -> Result<(), OutOfBounds> { | ||
if index >= self.len { | ||
return Err(OutOfBounds); | ||
} | ||
unsafe { | ||
core::ptr::write_volatile(self.data.as_ptr().add(index), value); | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl<'b, T: crate::AllowReadable + Copy + 'b> AllowedSlice<'b, T> { | ||
/// Returns the value at `index` without changing it. | ||
pub fn get(&self, index: usize) -> Result<T, OutOfBounds> { | ||
if index >= self.len { | ||
return Err(OutOfBounds); | ||
} | ||
Ok(unsafe { core::ptr::read_volatile(self.data.as_ptr().add(index)) }) | ||
} | ||
|
||
/// Returns the value at `index` without changing it. If `index` is out of | ||
/// bounds, returns the provided default value. | ||
pub fn get_or_default(&self, index: usize, default: T) -> T { | ||
if index >= self.len { | ||
return default; | ||
} | ||
unsafe { core::ptr::read_volatile(self.data.as_ptr().add(index)) } | ||
} | ||
} | ||
|
||
/// An error type indicating an out-of-bounds access. | ||
#[derive(PartialEq)] | ||
pub struct OutOfBounds; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
use crate::{AllowedSlice, OutOfBounds}; | ||
use core::marker::PhantomData; | ||
use core::ptr::NonNull; | ||
|
||
// KernelSlice simulates a kernel's access to a slice that has been shared with | ||
// the kernel. It is the slice-based equivalent to KernelPtr, defined in | ||
// allowed_tests.rs. See KernelPtr's documentation for a description of | ||
// KernelSlice's purpose. | ||
struct KernelSlice<'b, T: Copy + 'b> { | ||
data: NonNull<T>, | ||
len: usize, | ||
|
||
// Consume the 'b lifetime. | ||
_phantom: PhantomData<&'b mut [T]>, | ||
} | ||
|
||
impl<'b, T: Copy + 'b> KernelSlice<'b, T> { | ||
pub fn allow_slice(buffer: &'b mut [T]) -> (AllowedSlice<'b, T>, KernelSlice<'b, T>) { | ||
let data = NonNull::new(buffer.as_mut_ptr()).unwrap(); | ||
let len = buffer.len(); | ||
let _ = buffer; | ||
let allowed_slice = unsafe { AllowedSlice::new(data, len) }; | ||
let kernel_slice = KernelSlice { | ||
data, | ||
len, | ||
_phantom: PhantomData, | ||
}; | ||
(allowed_slice, kernel_slice) | ||
} | ||
|
||
// Copies the value out of the given entry in the buffer and returns it. | ||
pub fn get(&self, index: usize) -> T { | ||
assert!(index < self.len); | ||
unsafe { core::ptr::read(self.data.as_ptr().add(index)) } | ||
} | ||
} | ||
|
||
#[test] | ||
fn set() { | ||
let mut buffer = [0, 1, 2]; | ||
let (allowed_slice, kernel_slice) = KernelSlice::allow_slice(&mut buffer); | ||
assert_eq!(kernel_slice.get(0), 0); | ||
assert_eq!(kernel_slice.get(1), 1); | ||
assert_eq!(kernel_slice.get(2), 2); | ||
|
||
assert!(allowed_slice.set(4, 4) == Err(OutOfBounds)); | ||
assert_eq!(kernel_slice.get(0), 0); | ||
assert_eq!(kernel_slice.get(1), 1); | ||
assert_eq!(kernel_slice.get(2), 2); | ||
|
||
assert!(allowed_slice.set(1, 4) == Ok(())); | ||
assert_eq!(kernel_slice.get(0), 0); | ||
assert_eq!(kernel_slice.get(1), 4); | ||
assert_eq!(kernel_slice.get(2), 2); | ||
} | ||
|
||
#[test] | ||
fn get() { | ||
let mut buffer = [0, 1, 2]; | ||
let (allowed_slice, kernel_slice) = KernelSlice::allow_slice(&mut buffer); | ||
assert_eq!(kernel_slice.get(0), 0); | ||
assert_eq!(kernel_slice.get(1), 1); | ||
assert_eq!(kernel_slice.get(2), 2); | ||
|
||
assert!(allowed_slice.get(4).is_err()); | ||
assert_eq!(kernel_slice.get(0), 0); | ||
assert_eq!(kernel_slice.get(1), 1); | ||
assert_eq!(kernel_slice.get(2), 2); | ||
|
||
assert!(allowed_slice.get(1) == Ok(1)); | ||
assert_eq!(kernel_slice.get(0), 0); | ||
assert_eq!(kernel_slice.get(1), 1); | ||
assert_eq!(kernel_slice.get(2), 2); | ||
} | ||
|
||
#[test] | ||
fn get_or_default() { | ||
let mut buffer = [0, 1, 2]; | ||
let (allowed_slice, kernel_slice) = KernelSlice::allow_slice(&mut buffer); | ||
assert_eq!(kernel_slice.get(0), 0); | ||
assert_eq!(kernel_slice.get(1), 1); | ||
assert_eq!(kernel_slice.get(2), 2); | ||
|
||
assert_eq!(allowed_slice.get_or_default(4, 3), 3); | ||
assert_eq!(kernel_slice.get(0), 0); | ||
assert_eq!(kernel_slice.get(1), 1); | ||
assert_eq!(kernel_slice.get(2), 2); | ||
|
||
assert_eq!(allowed_slice.get_or_default(1, 4), 1); | ||
assert_eq!(kernel_slice.get(0), 0); | ||
assert_eq!(kernel_slice.get(1), 1); | ||
assert_eq!(kernel_slice.get(2), 2); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,12 @@ | ||
mod allow_readable; | ||
mod allowed; | ||
mod allowed_slice; | ||
|
||
pub use allow_readable::AllowReadable; | ||
pub use allowed::Allowed; | ||
pub use allowed_slice::{AllowedSlice, OutOfBounds}; | ||
|
||
#[cfg(test)] | ||
mod allowed_slice_tests; | ||
#[cfg(test)] | ||
mod allowed_tests; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
//! `async_traits` provides the `AsyncCall`, `Callback`, and `StaticCallback` | ||
//! traits. These traits form the basis for `libtock_core`'s asynchronous API | ||
//! structure. | ||
//! | ||
//! In general, an `AsyncCall` is used to initiate an asynchronous operation. | ||
//! When the operation is complete, a `Callback` or `StaticCall` is used to | ||
//! inform the client of the operation's completion. Clients may then issue | ||
//! additional `AsyncCall` invocations from within the response callback. | ||
//! | ||
//! Note that callbacks should not be issued from within the `AsyncCall` call; | ||
//! doing so causes reentrancy and stack utilization issues. This is enforced | ||
//! through use of the CallbackContext type parameter. | ||
//! | ||
//! These traits are designed to be implemented on zero sized types (ZSTs) that | ||
//! refer indirectly to the objects that implement the corresponding | ||
//! functionality. As a result, they require `Copy` and take `self` by value. In | ||
//! many cases, these traits will be implemented on references to objects rather | ||
//! than on the objects themselves. For example, a `Console` driver would | ||
//! implement `AsyncCall` on `&Console`, not on `Console` itself, as `Console` | ||
//! would not be a `Copy` type. | ||
/// Represents a call that starts an asynchronous operation. The `start` request | ||
/// can return a payload synchronously; this may be used to return a "failed to | ||
/// start"-style error message. | ||
pub trait AsyncCall<Request, SyncResponse>: Copy { | ||
fn start(self, request: Request) -> SyncResponse; | ||
} | ||
|
||
/// A callback reporting the results of an asynchronous operation. Like | ||
/// AsyncCall, this callback may carry data, and as such `Callback` may be | ||
/// implemented on reference types. | ||
pub trait Callback<AsyncResponse>: Copy { | ||
fn callback(self, context: CallbackContext, response: AsyncResponse); | ||
} | ||
|
||
/// A marker type indicating this method executes as a callback. In this case, | ||
/// callbacks refer either to kernel callbacks (those resulting from a | ||
/// `subscribe` sysem call) or to deferred callbacks. In both cases, the | ||
/// `Platform` implementation provides the `CallbackContext`. | ||
/// | ||
/// `CallbackContext` is `Copy` so it is easy to pass into function invocations. | ||
// The lifetime parameter 'c exists to prevent a CallbackContext from being | ||
// moved into a location that outlives the callback's execution. | ||
#[derive(Clone, Copy)] | ||
pub struct CallbackContext<'c> { | ||
// This serves two purposes. First, it is `pub(crate)`, so user code cannot | ||
// construct the CallbackContext. Second, it uses the lifetime parameter to | ||
// avoid an "unused lifetime parameter" error. | ||
pub(crate) _private: core::marker::PhantomData<&'c ()>, | ||
} | ||
|
||
/// A variation of callback that is not allowed to carry data. This conveys the | ||
/// callback entirely via the type system. This is used in places that cannot | ||
/// carry runtime data, such as the system call API, but generally requires the | ||
/// client to store the data it needs in a `static` location. As such, APIs | ||
/// should prefer to support `Callback` wherever possible. | ||
pub trait StaticCallback<AsyncResponse> { | ||
fn callback(context: CallbackContext, response: AsyncResponse); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
//! PlatformApi is a trait presenting a safe interface to Tock's system API as | ||
//! well as a deferred call mechanism. It is implemented by the Platform type in | ||
//! this crate. | ||
//! | ||
//! PlatformApi exists so that code that uses Platform's API only needs one type | ||
//! parameter, rather than the two required by Platform. | ||
// A lifetime (for buffers) is omitted because it is extremely annoying to use | ||
// as a generic constraint: you need drivers to have a 'k generic argument to | ||
// pass into the PlatformApi<'k> constraint, but then you get errors about 'k | ||
// being unused. | ||
// TODO: Remove the lifetime parameter on Allowed and AllowedSlice. | ||
pub trait PlatformApi: Copy { | ||
// Shares a value with the kernel. The value becomes a read-write shared | ||
// buffer between userspace and the kernel. | ||
fn allow<T: Copy>( | ||
self, | ||
driver: usize, | ||
minor: usize, | ||
buffer: &'static mut T, | ||
) -> Result<crate::Allowed<'static, T>, crate::ErrorCode>; | ||
|
||
// Shares a slice with the kernel. The shared slice becomes a read-write | ||
// shared buffer between userspace and the kernel. | ||
fn allow_slice<T: Copy>( | ||
self, | ||
driver: usize, | ||
minor: usize, | ||
buffer: &'static mut [T], | ||
) -> Result<crate::AllowedSlice<'static, T>, crate::ErrorCode>; | ||
|
||
// TODO: Finish PlatformApi | ||
|
||
// Executes a single callback. Will run a deferred callback if one is | ||
// available, or wait for one kernel callback if no deferred callback is | ||
// queued. | ||
fn run_callback(self); | ||
} |
Oops, something went wrong.