Merge #262
262: Remove `libtock_platform::allows`. r=hudson-ayers a=jrvanwhy
Tock 2.0 system calls do not need the types in `allows`. Now that I'm reworking `libtock_platform` to use Tock 2.0 system calls, we can get rid of the module.
Co-authored-by: Johnathan Van Why <jrvanwhy@google.com>
diff --git a/core/platform/src/allows/allow_readable.rs b/core/platform/src/allows/allow_readable.rs
deleted file mode 100644
index c35701b..0000000
--- a/core/platform/src/allows/allow_readable.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-/// Because the kernel may modify shared memory and place any bit pattern into
-/// that memory, we can only read types out of shared memory if every bit
-/// pattern is a valid value of that type. `AllowReadable` types are safe to
-/// read out of a shared buffer.
-pub unsafe trait AllowReadable {}
-
-unsafe impl AllowReadable for i8 {}
-unsafe impl AllowReadable for i16 {}
-unsafe impl AllowReadable for i32 {}
-unsafe impl AllowReadable for i64 {}
-unsafe impl AllowReadable for i128 {}
-unsafe impl AllowReadable for isize {}
-unsafe impl AllowReadable for u8 {}
-unsafe impl AllowReadable for u16 {}
-unsafe impl AllowReadable for u32 {}
-unsafe impl AllowReadable for u64 {}
-unsafe impl AllowReadable for u128 {}
-unsafe impl AllowReadable for usize {}
diff --git a/core/platform/src/allows/allowed.rs b/core/platform/src/allows/allowed.rs
deleted file mode 100644
index 386562f..0000000
--- a/core/platform/src/allows/allowed.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-/// An individual value that has been shared with the kernel using the `allow`
-/// system call.
-// Allowed's implementation does not directly use the 'b lifetime. Platform uses
-// 'b to prevent the Allowed from accessing the buffer after the buffer becomes
-// invalid.
-// Allowed requires T to be Copy due to concerns about the semantics of
-// non-copyable types in shared memory as well as concerns about unexpected
-// behavior with Drop types. See the following PR discussion for more
-// information: https://github.com/tock/libtock-rs/pull/222
-pub struct Allowed<'b, T: Copy + 'b> {
- // Safety properties:
- // 1. `buffer` remains valid and usable for the lifetime of this Allowed
- // instance.
- // 2. Read and write accesses of `buffer`'s pointee must be performed as a
- // volatile operation, as the kernel may mutate buffer's pointee at any
- // time.
- // 3. The value `buffer` points to may have an arbitrary bit pattern in
- // it, so reading from `buffer` is only safe if the type contained
- // within is AllowReadable.
- buffer: core::ptr::NonNull<T>,
-
- // We need to use the 'b lifetime in Allowed to prevent an "unused lifetime"
- // compiler error. We use it here. Note that the phantom data must be an
- // &mut rather than a shared reference in order to make Allowed invariant
- // with respect to T. Invariance is required because Allowed allows us to
- // mutate the value in buffer, and invariance is the required property to do
- // so without allowing callers to produce dangling references. This is
- // documented at https://doc.rust-lang.org/nomicon/subtyping.html.
- _phantom: core::marker::PhantomData<&'b mut T>,
-}
-
-// Allowed's API is based on that of core::cell::Cell, but removes some methods
-// that are not safe for use with shared memory.
-//
-// Internally, Allowed performs accesses to the shared memory using volatile
-// reads and writes through raw pointers. We avoid constructing references to
-// shared memory because that leads to undefined behavior (there is some
-// background on this in the following discussion:
-// https://github.com/rust-lang/unsafe-code-guidelines/issues/33). Tock runs on
-// single-threaded platforms, some of which lack atomic instructions, so we only
-// need to be able to deconflict races between the kernel (which will never
-// interrupt an instruction's execution) and this process. Therefore volatile
-// accesses are sufficient to deconflict races.
-impl<'b, T: Copy + 'b> Allowed<'b, T> {
- // Allowed can only be constructed by the Platform. It is constructed after
- // the `allow` system call, and as such must accept a raw pointer rather
- // than a reference. The caller must make sure the following are true:
- // 1. buffer points to a valid instance of type T
- // 2. There are no references to buffer's pointee
- // 3. buffer remains usable until the Allowed's lifetime has ended.
- #[allow(dead_code)] // TODO: Remove when Platform is implemented
- pub(crate) unsafe fn new(buffer: core::ptr::NonNull<T>) -> Allowed<'b, T> {
- Allowed {
- buffer,
- _phantom: core::marker::PhantomData,
- }
- }
-
- // Sets the value in the buffer.
- pub fn set(&self, value: T) {
- unsafe {
- core::ptr::write_volatile(self.buffer.as_ptr(), value);
- }
- }
-}
-
-impl<'b, T: crate::AllowReadable + Copy + 'b> Allowed<'b, T> {
- pub fn get(&self) -> T {
- unsafe { core::ptr::read_volatile(self.buffer.as_ptr()) }
- }
-}
diff --git a/core/platform/src/allows/allowed_tests.rs b/core/platform/src/allows/allowed_tests.rs
deleted file mode 100644
index 1859dd1..0000000
--- a/core/platform/src/allows/allowed_tests.rs
+++ /dev/null
@@ -1,98 +0,0 @@
-use crate::Allowed;
-use core::marker::PhantomData;
-use core::ptr::NonNull;
-
-// How do we simulate accesses to the shared buffer by the kernel?
-//
-// Well, a naive way would be to mutate the `buffer` variable directly. Because
-// Allowed accesses the memory through a *mut pointer, such a test would compile
-// and run fine with the current Rust compiler. As far as I can tell, it would
-// not hit any behavior documented as undefined at
-// https://doc.rust-lang.org/stable/reference/behavior-considered-undefined.html,
-// nor would it cause rustc to generate LLVM bitcode that encounters undefined
-// behavior.
-//
-// However, the naive approach will throw an "undefined behavior" error when run
-// under Miri (e.g. with `cargo miri test`), which uses the stacked borrows
-// model [1]. In particular, accessing the `buffer` variable directly pops the
-// SharedRW off buffer's borrow stack, which prevents Allowed from using its
-// *mut pointer to access `buffer` afterwards. It is likely that Rust will adopt
-// the stacked borrows model as its formal model for borrow validity, and in
-// that case accessing `buffer` in that manner will become undefined behavior.
-// In addition, running these tests under Miri is highly valuable, as this is
-// tricky code to get correct and an unsound API may be hard to fix.
-//
-// Instead, we explicitly refer to buffer through use of a KernelPtr that
-// simulates the pointer that `allow()` would hand to the Tock kernel. As far as
-// the stacked borrows model is concerned, accesses through the KernelPtr
-// variable behave identically to mutations performed by the kernel. This
-// pattern allows us to use `cargo miri test` to not only execute the unit
-// tests, but to test whether Allowed would encounter undefined behavior when
-// interacting with a real Tock kernel.
-//
-// [1] https://plv.mpi-sws.org/rustbelt/stacked-borrows/paper.pdf
-struct KernelPtr<'b, T: Copy + 'b> {
- ptr: NonNull<T>,
-
- // We need to consume the 'b lifetime. This is very similar to Allowed's
- // implementation.
- _phantom: PhantomData<&'b mut T>,
-}
-
-impl<'b, T: Copy + 'b> KernelPtr<'b, T> {
- // The constructor for KernelPtr; simulates allow(). Returns both the
- // Allowed instance the Platform would return and a KernelPtr the test can
- // use to simulate a kernel.
- pub fn allow(buffer: &'b mut T) -> (Allowed<'b, T>, KernelPtr<'b, T>) {
- let ptr = NonNull::new(buffer).unwrap();
- // Discard buffer *without* creating a reference to it, as would be done
- // if we called drop().
- let _ = buffer;
- // All 3 preconditions of Allowed::new are satisfied by the fact that
- // `buffer` is directly derived from a &'b mut T.
- let allowed = unsafe { Allowed::new(ptr) };
- let kernel_ptr = KernelPtr {
- ptr,
- _phantom: PhantomData,
- };
- (allowed, kernel_ptr)
- }
-
- // Replaces the value in the buffer with a new one.
- pub fn set(&self, value: T) {
- unsafe {
- core::ptr::write(self.ptr.as_ptr(), value);
- }
- }
-
- // Copies the contained value out of the buffer.
- pub fn get(&self) -> T {
- unsafe { core::ptr::read(self.ptr.as_ptr()) }
- }
-}
-
-#[test]
-fn set() {
- let mut buffer = 1;
- let (allowed, kernel_ptr) = KernelPtr::allow(&mut buffer);
- assert_eq!(kernel_ptr.get(), 1);
-
- // Simulate the kernel replacing the value in buffer.
- kernel_ptr.set(2);
- allowed.set(3);
- assert_eq!(kernel_ptr.get(), 3);
-}
-
-#[test]
-fn get() {
- let mut buffer = 1;
- let (allowed, kernel_ptr) = KernelPtr::allow(&mut buffer);
- assert_eq!(kernel_ptr.get(), 1);
-
- assert_eq!(allowed.get(), 1);
- assert_eq!(kernel_ptr.get(), 1);
-
- kernel_ptr.set(2);
- assert_eq!(allowed.get(), 2);
- assert_eq!(kernel_ptr.get(), 2);
-}
diff --git a/core/platform/src/allows/mod.rs b/core/platform/src/allows/mod.rs
deleted file mode 100644
index 8cb2158..0000000
--- a/core/platform/src/allows/mod.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-mod allow_readable;
-mod allowed;
-
-pub use allow_readable::AllowReadable;
-pub use allowed::Allowed;
-
-#[cfg(test)]
-mod allowed_tests;
diff --git a/core/platform/src/lib.rs b/core/platform/src/lib.rs
index 0588d14..0a9f936 100644
--- a/core/platform/src/lib.rs
+++ b/core/platform/src/lib.rs
@@ -1,21 +1,11 @@
#![no_std]
-// TODO: Implement this crate, which will be done piece-by-piece. Platform will
-// include:
-// 1. The Allowed and AllowedSlice abstractions for sharing memory with the
-// kernel
-// 2. The PlatformApi trait and Platform implementation.
-// 3. A system call trait so that Platform works in both real Tock apps and
-// unit test environments. [DONE]
-
-mod allows;
mod async_traits;
mod error_code;
mod raw_syscalls;
mod syscalls;
mod syscalls_impl;
-pub use allows::{AllowReadable, Allowed};
pub use async_traits::{CallbackContext, FreeCallback, Locator, MethodCallback};
pub use error_code::ErrorCode;
pub use raw_syscalls::{OneArgMemop, RawSyscalls, YieldType, ZeroArgMemop};