aboutsummaryrefslogtreecommitdiff
path: root/book/en/src/internals/access.md
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-05-09 19:33:42 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-05-09 19:33:42 +0000
commit2596ea0e46bec73d090d9e51d41e6c2f481b8e15 (patch)
tree9d148e9ef2d922c710a41b991f21d14cb2fe7bc4 /book/en/src/internals/access.md
parentbc024f197929be1ce7dac9e6cbf6672c3980437e (diff)
parentea02405ef0cea368707b723054b699fa423d4823 (diff)
Merge #175
175: document internals r=japaric a=japaric note that this assumes that RFC #155 has been implemented [Rendered text](https://japaric.github.io/rtfm5/book/en/internals.html) Do not merge this before PR #176 Co-authored-by: Jorge Aparicio <jorge@japaric.io>
Diffstat (limited to 'book/en/src/internals/access.md')
-rw-r--r--book/en/src/internals/access.md158
1 files changed, 158 insertions, 0 deletions
diff --git a/book/en/src/internals/access.md b/book/en/src/internals/access.md
new file mode 100644
index 0000000..513cef1
--- /dev/null
+++ b/book/en/src/internals/access.md
@@ -0,0 +1,158 @@
+# Access control
+
+One of the core foundations of RTFM is access control. Controlling which parts
+of the program can access which static variables is instrumental to enforcing
+memory safety.
+
+Static variables are used to share state between interrupt handlers, or between
+interrupts handlers and the bottom execution context, `main`. In normal Rust
+code it's hard to have fine grained control over which functions can access a
+static variable because static variables can be accessed from any function that
+resides in the same scope in which they are declared. Modules give some control
+over how a static variable can be accessed by they are not flexible enough.
+
+To achieve the fine-grained access control where tasks can only access the
+static variables (resources) that they have specified in their RTFM attribute
+the RTFM framework performs a source code level transformation. This
+transformation consists of placing the resources (static variables) specified by
+the user *inside* a `const` item and the user code *outside* the `const` item.
+This makes it impossible for the user code to refer to these static variables.
+
+Access to the resources is then given to each task using a `Resources` struct
+whose fields correspond to the resources the task has access to. There's one
+such struct per task and the `Resources` struct is initialized with either a
+mutable reference (`&mut`) to the static variables or with a resource proxy (see
+section on [critical sections](critical-sections.html)).
+
+The code below is an example of the kind of source level transformation that
+happens behind the scenes:
+
+``` rust
+#[rtfm::app(device = ..)]
+const APP: () = {
+ static mut X: u64: 0;
+ static mut Y: bool: 0;
+
+ #[init(resources = [Y])]
+ fn init(c: init::Context) {
+ // .. user code ..
+ }
+
+ #[interrupt(binds = UART0, resources = [X])]
+ fn foo(c: foo::Context) {
+ // .. user code ..
+ }
+
+ #[interrupt(binds = UART1, resources = [X, Y])]
+ fn bar(c: bar::Context) {
+ // .. user code ..
+ }
+
+ // ..
+};
+```
+
+The framework produces codes like this:
+
+``` rust
+fn init(c: init::Context) {
+ // .. user code ..
+}
+
+fn foo(c: foo::Context) {
+ // .. user code ..
+}
+
+fn bar(c: bar::Context) {
+ // .. user code ..
+}
+
+// Public API
+pub mod init {
+ pub struct Context<'a> {
+ pub resources: Resources<'a>,
+ // ..
+ }
+
+ pub struct Resources<'a> {
+ pub Y: &'a mut bool,
+ }
+}
+
+pub mod foo {
+ pub struct Context<'a> {
+ pub resources: Resources<'a>,
+ // ..
+ }
+
+ pub struct Resources<'a> {
+ pub X: &'a mut u64,
+ }
+}
+
+pub mod bar {
+ pub struct Context<'a> {
+ pub resources: Resources<'a>,
+ // ..
+ }
+
+ pub struct Resources<'a> {
+ pub X: &'a mut u64,
+ pub Y: &'a mut bool,
+ }
+}
+
+/// Implementation details
+const APP: () = {
+ // everything inside this `const` item is hidden from user code
+
+ static mut X: u64 = 0;
+ static mut Y: bool = 0;
+
+ // the real entry point of the program
+ unsafe fn main() -> ! {
+ interrupt::disable();
+
+ // ..
+
+ // call into user code; pass references to the static variables
+ init(init::Context {
+ resources: init::Resources {
+ X: &mut X,
+ },
+ // ..
+ });
+
+ // ..
+
+ interrupt::enable();
+
+ // ..
+ }
+
+ // interrupt handler that `foo` binds to
+ #[no_mangle]
+ unsafe fn UART0() {
+ // call into user code; pass references to the static variables
+ foo(foo::Context {
+ resources: foo::Resources {
+ X: &mut X,
+ },
+ // ..
+ });
+ }
+
+ // interrupt handler that `bar` binds to
+ #[no_mangle]
+ unsafe fn UART1() {
+ // call into user code; pass references to the static variables
+ bar(bar::Context {
+ resources: bar::Resources {
+ X: &mut X,
+ Y: &mut Y,
+ },
+ // ..
+ });
+ }
+};
+```