Skip to content

Commit df7d7f3

Browse files
committed
added initial tasks
1 parent 0c10c58 commit df7d7f3

1 file changed

Lines changed: 139 additions & 1 deletion

File tree

docs/embedded/index.md

Lines changed: 139 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,141 @@
1-
# Intorduction
1+
# Introduction
22

3+
## Prerequisites
34

5+
If you did not attend the **Tock Workshop**, please follow the [Setup Tutorial](../tock_workshop/index.md).
6+
7+
## Getting Started
8+
9+
For this track we will be using the **Nucleo-F429ZI** boards. The board's main can be found in the `boards/nucleo_f429zi` subfolder. Try to flash the kernel to the board, using the board's `Makefile`. After you are done flashing, connect to the board using `tockloader listen`
10+
11+
```shell
12+
[INFO ] No device name specified. Using default name "tock".
13+
[INFO ] No serial port with device name "tock" found.
14+
[INFO ] Found 2 serial ports.
15+
Multiple serial port options found. Which would you like to use?
16+
[0] /dev/cu.debug-console - n/a
17+
[1] /dev/cu.usbmodem1303 - STM32 STLink
18+
19+
Which option? [0] 1
20+
[INFO ] Using "/dev/cu.usbmodem1303 - STM32 STLink".
21+
[INFO ] Listening for serial output.
22+
23+
tock$
24+
```
25+
26+
## Customize your kernel
27+
28+
After connecting to Tock's terminal, you can run `help` to see the supported commands. One of them is `reset` and by running it, you can see the default *"welcome"* message.
29+
30+
```shell
31+
tock$ reset
32+
Initialization complete. Entering main loop
33+
tock$
34+
```
35+
36+
Personalize your kernel, by changing the hostname and the banner.
37+
38+
## Print Counter Capsule
39+
40+
For this task, you will need to build a capsule that prints a custom message each time it receives a print command from an application, along with a message counter representing the number of commands received. Remember that you will need to implement the `SyscallDriver` trait.
41+
42+
### The simple way
43+
44+
Simplest method to do this is to add a `counter` field in the capsule's structure. One issue you will most likely encounter is that the `command` method required by the `SyscallDriver` trait has a immutable reference to `&self`, so you may need to wrap the counter in a wrapper that allows for inner mutability, such as `Cell`.
45+
46+
### The Tock way
47+
48+
One issue with the previous approach is that the counter would be shared between the applications. This could be an issue for mutually distrustful application. Fortunately, Tock has a mechanism in place for such situations, called `Grant`s, which are per-process memory regions allocated in the kernel for a capsule to store that process’s state.
49+
50+
To access this region, you can simply add a new `grant` field in the capsule structure.
51+
52+
```rust title="capsules/extra/src/print_counter.rs"
53+
use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
54+
55+
// TODO: Define `App` structure. Make sure to satisfy trait constraints.
56+
struct App;
57+
58+
struct PrintCounter {
59+
grant: Grant<
60+
App,
61+
UpcallCount<0>,
62+
AllowRoCount<0>,
63+
AllowRwCount<0>
64+
>,
65+
}
66+
```
67+
68+
As before, we will need to define a component for this capsule, to initialize it.
69+
70+
```rust title="boards/components/src/print_counter.rs"
71+
#[macro_export]
72+
macro_rules! print_counter_component_static {
73+
($(,)?) => {{
74+
kernel::static_buf!(capsules_extra::print_counter::PrintCounter)
75+
};};
76+
}
77+
78+
pub struct PrintCounterComponent;
79+
80+
impl Component for PrintCounterComponent {
81+
type StaticInput = &'static mut MaybeUninit<capsules_extra::print_counter::PrintCounter>;
82+
83+
type Output = &'static capsules_extra::print_counter::PrintCounter;
84+
85+
fn finalize(self, static_memory: Self::StaticInput) -> Self::Output {
86+
todo!()
87+
}
88+
}
89+
```
90+
91+
Grants are a sensitive component of the operating system, so the creation and management operations are considered unsafe, and require
92+
privileges to perform. Tock restricts these privileged operations through the use of capabilities, which are tokens implementing `unsafe` traits. Because capsules are forbidden from using unsafe code, these tokens cannot be forged.
93+
94+
Creating a grant is requires a reference to the board's kernel, and a driver number, so we will need to add these parts in the components.
95+
96+
```rust title="boards/components/src/print_counter.rs"
97+
pub struct PrintCounterComponent {
98+
driver_num: usize,
99+
board_kernel: &'static kernel::Kernel,
100+
}
101+
102+
impl PrintCounterComponent {
103+
pub fn new(driver_num: usize, board_kernel: &'static kernel::Kernel) -> Self {
104+
Self {
105+
driver_num,
106+
board_kernel,
107+
}
108+
}
109+
}
110+
```
111+
112+
The capability needed for grant creating is called `MemoryAllocationCapability`, and it can be found in the `kernel::capabilities` module. The `kernel` also exposes the `crate_capability!` macro for ease of use.
113+
114+
```rust title="boards/components/src/print_counter.rs"
115+
impl Component for PrintCounterComponent {
116+
// ...
117+
118+
fn finalize(self, static_memory: Self::StaticInput) -> Self::Output {
119+
let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
120+
let grant = self.board_kernel.create_grant(self.driver_num, &grant_cap);
121+
122+
static_memory.write(capsules_extra::print_counter::PrintCounter::new(grant))
123+
}
124+
}
125+
```
126+
127+
:::note `new` constructor
128+
You will also need to implement the `new` constructor for the `PrintCounter` capsule.
129+
:::
130+
131+
Next, you must implement the `SyscallDriver` trait, where the command logic will be. For the `allocate_grant` method implementation, it is enough to use the `enter` method of the Grant which takes a closure with two parameters.
132+
133+
```rust
134+
fn allocate_grant(&self, process_id: kernel::ProcessId) -> Result<(), kernel::process::Error> {
135+
self.grant.enter(process_id, |_, _| {})
136+
}
137+
```
138+
139+
For the command logic, you must also use the `enter` API. The first parameter of the closure will be a mutable reference to a `GrantData` wrapper over the previously defined `App`. The wrapper is transparent, meaning it permits accessing fields of the generic type.
140+
141+
The next step is configuring the capsule in the board's main file. Remember you need to add the capsule in the `NucleoF429ZI` structure, the `SyscallDriverLookup` and initialize the printer counter capsule.

0 commit comments

Comments
 (0)