PES4 / Mbed OS Queue_02
Committer:
demayer
Date:
Sat Mar 28 15:28:19 2020 +0000
Revision:
0:6bf0743ece18
IMU Thread with an event-queue running parallel to handle tasks like a 5 times blinking LED. Button with interrupt detected.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
demayer 0:6bf0743ece18 1 # Getting started guide for uVisor on mbed OS
demayer 0:6bf0743ece18 2
demayer 0:6bf0743ece18 3 This guide will help you start uVisor on mbed OS by showing you how to create a sample application for the NXP FRDM-K64F board.
demayer 0:6bf0743ece18 4
demayer 0:6bf0743ece18 5 The uVisor provides sandboxed environments and resources protection for applications built for ARM Cortex-M3 and Cortex-M4 devices. This guide will show you how to enable the uVisor and configure a secure box to access some exclusive resources (memory, peripherals, interrupts). For more information about the uVisor design philosophy, please see the uVisor [introductory document](../../README.md).
demayer 0:6bf0743ece18 6
demayer 0:6bf0743ece18 7 ## Requirements
demayer 0:6bf0743ece18 8
demayer 0:6bf0743ece18 9 To run the `blinky` application on mbed OS with uVisor enabled, you need:
demayer 0:6bf0743ece18 10
demayer 0:6bf0743ece18 11 - A platform and a toolchain that uVisor on mbed OS supports. You can verify this on [the official list](../README.md#supported-platforms). If uVisor supports your platform internally but not on mbed OS, the porting process is incomplete. To port your platform to uVisor and enable it on mbed OS, please follow the [uVisor porting guide for mbed OS](../core/PORTING.md).
demayer 0:6bf0743ece18 12 - Git.
demayer 0:6bf0743ece18 13 - mbed CLI. Run `pip install mbed-cli` to install it.
demayer 0:6bf0743ece18 14
demayer 0:6bf0743ece18 15 The remainder of this guide assumes:
demayer 0:6bf0743ece18 16
demayer 0:6bf0743ece18 17 - You are developing on a \*nix machine in the `~/code` folder.
demayer 0:6bf0743ece18 18 - You are building the app for the [NXP FRDM-K64F](http://developer.mbed.org/platforms/FRDM-K64F/) target with the [GNU ARM Embedded Toolchain](https://launchpad.net/gcc-arm-embedded).
demayer 0:6bf0743ece18 19
demayer 0:6bf0743ece18 20 You can use these instructions as guidelines in the case of other targets on other host OSs.
demayer 0:6bf0743ece18 21
demayer 0:6bf0743ece18 22 ## Start with the `blinky` app
demayer 0:6bf0743ece18 23 [Go to top](#overview)
demayer 0:6bf0743ece18 24
demayer 0:6bf0743ece18 25 Create a new mbed application called `uvisor-example` by running the following commands:
demayer 0:6bf0743ece18 26
demayer 0:6bf0743ece18 27 ```bash
demayer 0:6bf0743ece18 28 $ cd ~/code
demayer 0:6bf0743ece18 29 $ mbed new uvisor-example
demayer 0:6bf0743ece18 30 $ cd uvisor-example
demayer 0:6bf0743ece18 31 ```
demayer 0:6bf0743ece18 32
demayer 0:6bf0743ece18 33 The mbed CLI tools automatically fetch the mbed codebase. By default, Git tracks your code changes, so you can push your application to a Git server if you want to.
demayer 0:6bf0743ece18 34
demayer 0:6bf0743ece18 35 Once the import process finishes, create a `source` folder:
demayer 0:6bf0743ece18 36 ```bash
demayer 0:6bf0743ece18 37 $ mkdir ~/code/uvisor-example/source
demayer 0:6bf0743ece18 38 ```
demayer 0:6bf0743ece18 39 Place a new file `main.cpp` in it:
demayer 0:6bf0743ece18 40
demayer 0:6bf0743ece18 41 ```C
demayer 0:6bf0743ece18 42 /* ~/code/uvisor-example/source/main.cpp */
demayer 0:6bf0743ece18 43
demayer 0:6bf0743ece18 44 #include "mbed.h"
demayer 0:6bf0743ece18 45
demayer 0:6bf0743ece18 46 DigitalOut led(LED1);
demayer 0:6bf0743ece18 47
demayer 0:6bf0743ece18 48 int main(void)
demayer 0:6bf0743ece18 49 {
demayer 0:6bf0743ece18 50 while (true) {
demayer 0:6bf0743ece18 51 led = !led;
demayer 0:6bf0743ece18 52 wait(0.5);
demayer 0:6bf0743ece18 53 }
demayer 0:6bf0743ece18 54 }
demayer 0:6bf0743ece18 55 ```
demayer 0:6bf0743ece18 56
demayer 0:6bf0743ece18 57 This application blinks an LED from the main thread, which the OS creates by default.
demayer 0:6bf0743ece18 58
demayer 0:6bf0743ece18 59 ---
demayer 0:6bf0743ece18 60
demayer 0:6bf0743ece18 61 **Checkpoint**
demayer 0:6bf0743ece18 62
demayer 0:6bf0743ece18 63 Compile the application:
demayer 0:6bf0743ece18 64
demayer 0:6bf0743ece18 65 ```bash
demayer 0:6bf0743ece18 66 $ mbed compile -m K64F -t GCC_ARM
demayer 0:6bf0743ece18 67 ```
demayer 0:6bf0743ece18 68
demayer 0:6bf0743ece18 69 The resulting binary is located at:
demayer 0:6bf0743ece18 70
demayer 0:6bf0743ece18 71 ```bash
demayer 0:6bf0743ece18 72 ~/code/uvisor-example/BUILD/K64F/GCC_ARM/uvisor-example.bin
demayer 0:6bf0743ece18 73 ```
demayer 0:6bf0743ece18 74
demayer 0:6bf0743ece18 75 Drag and drop it onto the USB device mounted on your computer to flash the device. When the flashing process is complete, press the reset button on the device. The device's LED blinks.
demayer 0:6bf0743ece18 76
demayer 0:6bf0743ece18 77 ## Enable uVisor
demayer 0:6bf0743ece18 78 [Go to top](#overview)
demayer 0:6bf0743ece18 79
demayer 0:6bf0743ece18 80 To enable the uVisor on the app, add these lines to the beginning of the `main.cpp` file:
demayer 0:6bf0743ece18 81
demayer 0:6bf0743ece18 82 ```C
demayer 0:6bf0743ece18 83 /* ~/code/uvisor-example/source/main.cpp */
demayer 0:6bf0743ece18 84
demayer 0:6bf0743ece18 85 #include "mbed.h"
demayer 0:6bf0743ece18 86 #include "uvisor-lib/uvisor-lib.h"
demayer 0:6bf0743ece18 87
demayer 0:6bf0743ece18 88 /* Public box Access Control Lists (ACLs). */
demayer 0:6bf0743ece18 89 /* Note: These are specific to the NXP FRDM-K64F board. See the section below
demayer 0:6bf0743ece18 90 * for more information. */
demayer 0:6bf0743ece18 91 static const UvisorBoxAclItem g_public_box_acls[] = {
demayer 0:6bf0743ece18 92 /* For the LED */
demayer 0:6bf0743ece18 93 {SIM, sizeof(*SIM), UVISOR_TACLDEF_PERIPH},
demayer 0:6bf0743ece18 94 {PORTB, sizeof(*PORTB), UVISOR_TACLDEF_PERIPH},
demayer 0:6bf0743ece18 95
demayer 0:6bf0743ece18 96 /* For messages printed on the serial port */
demayer 0:6bf0743ece18 97 {OSC, sizeof(*OSC), UVISOR_TACLDEF_PERIPH},
demayer 0:6bf0743ece18 98 {MCG, sizeof(*MCG), UVISOR_TACLDEF_PERIPH},
demayer 0:6bf0743ece18 99 {UART0, sizeof(*UART0), UVISOR_TACLDEF_PERIPH},
demayer 0:6bf0743ece18 100 {PIT, sizeof(*PIT), UVISOR_TACLDEF_PERIPH},
demayer 0:6bf0743ece18 101 };
demayer 0:6bf0743ece18 102
demayer 0:6bf0743ece18 103 /* Enable uVisor, using the ACLs we just created. */
demayer 0:6bf0743ece18 104 UVISOR_SET_MODE_ACL(UVISOR_ENABLED, g_public_box_acls);
demayer 0:6bf0743ece18 105
demayer 0:6bf0743ece18 106 /* Rest of the existing code */
demayer 0:6bf0743ece18 107 ...
demayer 0:6bf0743ece18 108 ```
demayer 0:6bf0743ece18 109
demayer 0:6bf0743ece18 110 In the code above, we specified two elements:
demayer 0:6bf0743ece18 111
demayer 0:6bf0743ece18 112 1. Public box Access Control Lists (ACLs). With uVisor enabled, everything runs in unprivileged mode, so make sure the public box and peripherals the OS accesses are allowed. These peripherals are specified using a list like the one in the snippet above. This example provides the list of all the ACLs you need. For other platforms or other applications, you need to determine those ACLs following the process in [The main box ACLs](#the-main-box-acls).
demayer 0:6bf0743ece18 113 1. App-specific uVisor configurations: `UVISOR_SET_MODE_ACL`. This macro sets the uVisor mode (enabled) and associates the list of ACLs you just created with the public box.
demayer 0:6bf0743ece18 114
demayer 0:6bf0743ece18 115 Before compiling, you need to override the original `K64F` target to enable the uVisor feature. To do so, add the file `~/code/uvisor-example/mbed_app.json` with the following content:
demayer 0:6bf0743ece18 116
demayer 0:6bf0743ece18 117 ```JSON
demayer 0:6bf0743ece18 118 {
demayer 0:6bf0743ece18 119 "target_overrides": {
demayer 0:6bf0743ece18 120 "*": {
demayer 0:6bf0743ece18 121 "target.features_add": ["UVISOR"],
demayer 0:6bf0743ece18 122 "target.extra_labels_add": ["UVISOR_SUPPORTED"]
demayer 0:6bf0743ece18 123 }
demayer 0:6bf0743ece18 124 },
demayer 0:6bf0743ece18 125 "macros": [
demayer 0:6bf0743ece18 126 "FEATURE_UVISOR=1",
demayer 0:6bf0743ece18 127 "TARGET_UVISOR_SUPPORTED=1"
demayer 0:6bf0743ece18 128 ]
demayer 0:6bf0743ece18 129 }
demayer 0:6bf0743ece18 130 ```
demayer 0:6bf0743ece18 131
demayer 0:6bf0743ece18 132 The macros `FEATURE_UVISOR` and `TARGET_UVISOR_SUPPORTED` in the configuration file above are automatically defined for C and C++ files but not for assembly files. Because the uVisor relies on those symbols in some assembly code, you need to define them manually.
demayer 0:6bf0743ece18 133
demayer 0:6bf0743ece18 134 ---
demayer 0:6bf0743ece18 135
demayer 0:6bf0743ece18 136 **Checkpoint**
demayer 0:6bf0743ece18 137
demayer 0:6bf0743ece18 138 Compile the application again. This time, the `K64F` target includes the new features and labels you provided in `mbed_app.json`;
demayer 0:6bf0743ece18 139
demayer 0:6bf0743ece18 140 ```bash
demayer 0:6bf0743ece18 141 $ mbed compile -m K64F -t GCC_ARM
demayer 0:6bf0743ece18 142 ```
demayer 0:6bf0743ece18 143
demayer 0:6bf0743ece18 144 The binary is located at:
demayer 0:6bf0743ece18 145
demayer 0:6bf0743ece18 146 ```bash
demayer 0:6bf0743ece18 147 ~/code/uvisor-example/BUILD/K64F/GCC_ARM/uvisor-example.bin
demayer 0:6bf0743ece18 148 ```
demayer 0:6bf0743ece18 149
demayer 0:6bf0743ece18 150 Reflash the device, and press the reset button. The device LED blinks as in the previous case.
demayer 0:6bf0743ece18 151
demayer 0:6bf0743ece18 152 ---
demayer 0:6bf0743ece18 153
demayer 0:6bf0743ece18 154 If you enable uVisor in the `blinky` app as it was written above, you do not get any particular security feature. All code and resources share the same security context, which we call the *public box*.
demayer 0:6bf0743ece18 155
demayer 0:6bf0743ece18 156 A lot happens unseen, though. All the user code now runs in unprivileged mode, and the systems services, such as the `NVIC` APIs and the OS SVCalls, are routed through the uVisor.
demayer 0:6bf0743ece18 157
demayer 0:6bf0743ece18 158 ## Add a secure box
demayer 0:6bf0743ece18 159 [Go to top](#overview)
demayer 0:6bf0743ece18 160
demayer 0:6bf0743ece18 161 Now that uVisor is enabled, you can finally add a *secure box*.
demayer 0:6bf0743ece18 162
demayer 0:6bf0743ece18 163 A secure box is a special compartment with exclusive access to peripherals, memories and interrupts. Private resources are only accessible when the *context* of the secure box is active. The uVisor is the only one that can enable a secure box context, for example upon thread switching or interrupt handling.
demayer 0:6bf0743ece18 164
demayer 0:6bf0743ece18 165 uVisor does not obfuscate code that belongs to a box, so it is still readable and executable from outside of the box. In addition, declaring an object in the same file that configures a secure box does not protect that object automatically.
demayer 0:6bf0743ece18 166
demayer 0:6bf0743ece18 167 Instead, we provide specific APIs to instruct the uVisor to protect a private resource. The `uvisor-example` app will show how to use these APIs.
demayer 0:6bf0743ece18 168
demayer 0:6bf0743ece18 169 ### Configure the secure box
demayer 0:6bf0743ece18 170
demayer 0:6bf0743ece18 171 For this example, we want to create a secure box called `private_button`. The `private_button` box has exclusive access to the push-button on the NXP FRDM-K64F board, which means that other boxes cannot access its corresponding peripheral.
demayer 0:6bf0743ece18 172
demayer 0:6bf0743ece18 173 Each secure box must have at least one thread, which we call the box's main thread. In our `private_button` box, we only use this thread throughout the whole program. The thread runs every second and counts the number of times it has been called between two button presses. The thread count is saved in a variable private to the box. Whenever we press the `SW2` button on the board, the current thread count is stored into a private buffer and restarts. For debug purposes, the program prints the content of the buffer every time it fills up.
demayer 0:6bf0743ece18 174
demayer 0:6bf0743ece18 175 You want the box to have exclusive access to the following resources:
demayer 0:6bf0743ece18 176
demayer 0:6bf0743ece18 177 - The push-button peripheral (as specified by a peripheral ACL). Nobody else should be able to access the push-button port.
demayer 0:6bf0743ece18 178 - The push-button interrupt (as specified by an IRQ ACL). You want the button IRQ to reroute to our box-specific ISR.
demayer 0:6bf0743ece18 179 - The private dynamically allocated buffer (as specified by a dynamic memory ACL).
demayer 0:6bf0743ece18 180 - The private variables (as specified by a static memory ACL).
demayer 0:6bf0743ece18 181
demayer 0:6bf0743ece18 182 Create a new source file, `~/code/uvisor-example/source/secure_box.cpp`. You will configure the secure box inside this file. The secure box name for this example is `private_button`.
demayer 0:6bf0743ece18 183
demayer 0:6bf0743ece18 184 ```C
demayer 0:6bf0743ece18 185 /* ~/code/uvisor-example/source/secure_box.cpp */
demayer 0:6bf0743ece18 186
demayer 0:6bf0743ece18 187 #include "mbed.h"
demayer 0:6bf0743ece18 188 #include "uvisor-lib/uvisor-lib.h"
demayer 0:6bf0743ece18 189
demayer 0:6bf0743ece18 190 /* Private static memory for the secure box */
demayer 0:6bf0743ece18 191 typedef struct {
demayer 0:6bf0743ece18 192 uint32_t * buffer; /* Static private memory, pointing to dynamically allocated private memory */
demayer 0:6bf0743ece18 193 uint32_t counter; /* Static private memory */
demayer 0:6bf0743ece18 194 int index; /* Static private memory */
demayer 0:6bf0743ece18 195 RawSerial * pc; /* Static private memory, pointing to dynamically allocated private memory */
demayer 0:6bf0743ece18 196 } PrivateButtonStaticMemory;
demayer 0:6bf0743ece18 197
demayer 0:6bf0743ece18 198 /* ACLs list for the secure box: Timer (PIT). */
demayer 0:6bf0743ece18 199 static const UvisorBoxAclItem g_private_button_acls[] = {
demayer 0:6bf0743ece18 200 {PORTC, sizeof(*PORTC), UVISOR_TACLDEF_PERIPH}, /* Private peripheral */
demayer 0:6bf0743ece18 201 {(void *) PORTC_IRQn, 0, UVISOR_TACL_IRQ}, /* Private IRQ */
demayer 0:6bf0743ece18 202 };
demayer 0:6bf0743ece18 203
demayer 0:6bf0743ece18 204 static void private_button_main_thread(const void *);
demayer 0:6bf0743ece18 205
demayer 0:6bf0743ece18 206 /* Secure box configuration */
demayer 0:6bf0743ece18 207 UVISOR_BOX_NAMESPACE(NULL); /* We won't specify a box namespace for this example. */
demayer 0:6bf0743ece18 208 UVISOR_BOX_HEAPSIZE(4096); /* Heap size for the secure box */
demayer 0:6bf0743ece18 209 UVISOR_BOX_MAIN(private_button_main_thread, /* Main thread for the secure box */
demayer 0:6bf0743ece18 210 osPriorityNormal, /* Priority of the secure box's main thread */
demayer 0:6bf0743ece18 211 1024); /* Stack size for the secure box's main thread */
demayer 0:6bf0743ece18 212 UVISOR_BOX_CONFIG(private_button, /* Name of the secure box */
demayer 0:6bf0743ece18 213 g_private_button_acls, /* ACLs list for the secure box */
demayer 0:6bf0743ece18 214 1024, /* Stack size for the secure box */
demayer 0:6bf0743ece18 215 PrivateButtonStaticMemory); /* Private static memory for the secure box. */
demayer 0:6bf0743ece18 216 ```
demayer 0:6bf0743ece18 217
demayer 0:6bf0743ece18 218 ### Create the secure box's main thread function
demayer 0:6bf0743ece18 219
demayer 0:6bf0743ece18 220 In general, you can decide what to do in your box's main thread. You can run it once and then stop it or use it to configure memories or peripherals or to create other threads. In this app, the box's main thread is the only thread for the `private_button` box, and it runs throughout the program.
demayer 0:6bf0743ece18 221
demayer 0:6bf0743ece18 222 The `private_button_main_thread` function configures the push-button to trigger an interrupt when pressed, allocates the dynamic buffer to hold the thread count values and initializes its private static memory, `PrivateButtonStaticMemory`. A spinning loop updates the counter value every second.
demayer 0:6bf0743ece18 223
demayer 0:6bf0743ece18 224 ```C
demayer 0:6bf0743ece18 225 /* ~/code/uvisor-example/source/secure_box.cpp */
demayer 0:6bf0743ece18 226
demayer 0:6bf0743ece18 227 /* The previous code goes here. */
demayer 0:6bf0743ece18 228 ...
demayer 0:6bf0743ece18 229
demayer 0:6bf0743ece18 230 #define uvisor_ctx ((PrivateButtonStaticMemory *) __uvisor_ctx)
demayer 0:6bf0743ece18 231
demayer 0:6bf0743ece18 232 #define PRIVATE_BUTTON_BUFFER_COUNT 8
demayer 0:6bf0743ece18 233
demayer 0:6bf0743ece18 234 static void private_button_on_press(void)
demayer 0:6bf0743ece18 235 {
demayer 0:6bf0743ece18 236 /* Store the thread count into the buffer and reset it. */
demayer 0:6bf0743ece18 237 uvisor_ctx->buffer[uvisor_ctx->index] = uvisor_ctx->counter;
demayer 0:6bf0743ece18 238 uvisor_ctx->counter = 0;
demayer 0:6bf0743ece18 239
demayer 0:6bf0743ece18 240 /* Update the index. Behave as a circular buffer. */
demayer 0:6bf0743ece18 241 if (uvisor_ctx->index < PRIVATE_BUTTON_BUFFER_COUNT - 1) {
demayer 0:6bf0743ece18 242 uvisor_ctx->index++;
demayer 0:6bf0743ece18 243 } else {
demayer 0:6bf0743ece18 244 uvisor_ctx->index = 0;
demayer 0:6bf0743ece18 245
demayer 0:6bf0743ece18 246 /* For debug purposes: Print the content of the buffer. */
demayer 0:6bf0743ece18 247 uvisor_ctx->pc->printf("Thread count between button presses: ");
demayer 0:6bf0743ece18 248 for (int i = 0; i < PRIVATE_BUTTON_BUFFER_COUNT; ++i) {
demayer 0:6bf0743ece18 249 uvisor_ctx->pc->printf("%lu ", uvisor_ctx->buffer[i]);
demayer 0:6bf0743ece18 250 }
demayer 0:6bf0743ece18 251 uvisor_ctx->pc->printf("\n");
demayer 0:6bf0743ece18 252 }
demayer 0:6bf0743ece18 253
demayer 0:6bf0743ece18 254 }
demayer 0:6bf0743ece18 255
demayer 0:6bf0743ece18 256 /* Main thread for the secure box */
demayer 0:6bf0743ece18 257 static void private_button_main_thread(const void *)
demayer 0:6bf0743ece18 258 {
demayer 0:6bf0743ece18 259 /* Allocate serial port to ensure that code in this secure box
demayer 0:6bf0743ece18 260 * won't touch handle in the default security context when printing */
demayer 0:6bf0743ece18 261 if (!(uvisor_ctx->pc = new RawSerial(USBTX, USBRX))) {
demayer 0:6bf0743ece18 262 return;
demayer 0:6bf0743ece18 263 }
demayer 0:6bf0743ece18 264
demayer 0:6bf0743ece18 265 /* Create the buffer and cache its pointer to the private static memory. */
demayer 0:6bf0743ece18 266 uvisor_ctx->buffer = (uint32_t *) malloc(PRIVATE_BUTTON_BUFFER_COUNT * sizeof(uint32_t));
demayer 0:6bf0743ece18 267 if (uvisor_ctx->buffer == NULL) {
demayer 0:6bf0743ece18 268 uvisor_ctx->pc->printf("ERROR: Failed to allocate memory for the button buffer\n");
demayer 0:6bf0743ece18 269 mbed_die();
demayer 0:6bf0743ece18 270 }
demayer 0:6bf0743ece18 271 uvisor_ctx->index = 0;
demayer 0:6bf0743ece18 272 uvisor_ctx->counter = 0;
demayer 0:6bf0743ece18 273
demayer 0:6bf0743ece18 274 /* Setup the push-button callback. */
demayer 0:6bf0743ece18 275 InterruptIn button(SW2); /* Private IRQ */
demayer 0:6bf0743ece18 276 button.mode(PullUp);
demayer 0:6bf0743ece18 277 button.fall(&private_button_on_press);
demayer 0:6bf0743ece18 278
demayer 0:6bf0743ece18 279 /* Increment the private counter every second. */
demayer 0:6bf0743ece18 280 while (1) {
demayer 0:6bf0743ece18 281 uvisor_ctx->counter++;
demayer 0:6bf0743ece18 282 wait(1.0);
demayer 0:6bf0743ece18 283 }
demayer 0:6bf0743ece18 284 }
demayer 0:6bf0743ece18 285 ```
demayer 0:6bf0743ece18 286
demayer 0:6bf0743ece18 287 A few things to note in the code above:
demayer 0:6bf0743ece18 288
demayer 0:6bf0743ece18 289 - If code runs in the context of `private_button`, then any object instantiated inside that code belongs to the `private_button` heap and stack. This means that in the example above, the `InterruptIn` object is private to the `private_button` box. The same applies to the dynamically allocated buffer `uvisor_ctx->buffer`.
demayer 0:6bf0743ece18 290 - You can access the content of the private memory `PrivateButtonStaticMemory` using the `void * const __uvisor_ctx` pointer, which uVisor maintains. You need to cast this pointer to your own context type. In this example we used a pre-processor symbol to improve readability.
demayer 0:6bf0743ece18 291 - The `InterruptIn` object triggers the registration of an interrupt slot using the NVIC APIs. If you want to use the IRQ APIs directly, read the [NVIC APIs section](#the-nvic-apis) below. We registered the push-button IRQ to the `private_button` box through an IRQ ACL, and hence only code from this box can access it. Changing the push-button IRQ state from the public box causes a uVisor fault.
demayer 0:6bf0743ece18 292 - Even if the `private_button_on_press` function runs in the context of `private_button`, you can still use the `printf` function, which accesses the `UART0` peripheral, owned by the public box. This is because all ACLs declared in the public box are by default shared with all the other secure boxes. This also means that the messages we are printing on the serial port are not secure because other boxes have access to that peripheral.
demayer 0:6bf0743ece18 293
demayer 0:6bf0743ece18 294 > **Warning**: Instantiating an object in the `secure_box.cpp` global scope automatically maps it to the public box context, not the `private_button` one. If you want an object to be private to a box, you need to instantiate it inside the code that runs in the context of that box (such as the `InterruptIn` object), or alternatively statically initialize it in the box private static memory (such as the `buffer`, `index` and `counter` variables in `PrivateButtonStaticMemory`).
demayer 0:6bf0743ece18 295
demayer 0:6bf0743ece18 296 ---
demayer 0:6bf0743ece18 297
demayer 0:6bf0743ece18 298 **Checkpoint**
demayer 0:6bf0743ece18 299
demayer 0:6bf0743ece18 300 Compile the application again:
demayer 0:6bf0743ece18 301
demayer 0:6bf0743ece18 302 ```bash
demayer 0:6bf0743ece18 303 $ mbed compile -m K64F -t GCC_ARM
demayer 0:6bf0743ece18 304 ```
demayer 0:6bf0743ece18 305
demayer 0:6bf0743ece18 306 Reflash the device, and press the reset button. The device LED blinks.
demayer 0:6bf0743ece18 307
demayer 0:6bf0743ece18 308 If the LED doens't blink, it means the application halted somewhere, probably because uVisor captured a fault. You can set up the uVisor debug messages to see if there is a problem. See [Debugging uVisor on mbed OS](DEBUGGING.md) for a step-by-step guide.
demayer 0:6bf0743ece18 309
demayer 0:6bf0743ece18 310 If the LED is blinking, the app is running correctly. If you press the `SW2` button on the NXP FRDM-K64F board, the `private_button_on_press` function executes, printing the values in the timer buffer after `PRIVATE_BUTTON_BUFFER_COUNT` presses. You can observe these values by opening a serial port connection to the device, with a baud rate of 9600.
demayer 0:6bf0743ece18 311
demayer 0:6bf0743ece18 312 ## Expose public secure entry points to the secure box
demayer 0:6bf0743ece18 313 [Go to top](#overview)
demayer 0:6bf0743ece18 314
demayer 0:6bf0743ece18 315 So far, the code in the secure box cannot communicate to other boxes. To let other boxes call functions in our secure box, you can define public secure entry points. These entry points can map to private functions within the context of a secure box, and an RPC protocol automatically serializes the arguments and return values to ensure no private memory can leak to external boxes.
demayer 0:6bf0743ece18 316
demayer 0:6bf0743ece18 317 You can define a public secure entry point to retrieve the index value from the secure box. This index value increases every time you press the `SW2` button.
demayer 0:6bf0743ece18 318
demayer 0:6bf0743ece18 319 ### Defining a secure entry point
demayer 0:6bf0743ece18 320
demayer 0:6bf0743ece18 321 Create a new source file, `~/code/uvisor-example/source/secure_box.h`, where you will define the functions that you can call through RPC.
demayer 0:6bf0743ece18 322
demayer 0:6bf0743ece18 323 ```cpp
demayer 0:6bf0743ece18 324 /* ~/code/uvisor-example/source/secure_box.h */
demayer 0:6bf0743ece18 325
demayer 0:6bf0743ece18 326 #ifndef SECURE_BOX_H_
demayer 0:6bf0743ece18 327 #define SECURE_BOX_H_
demayer 0:6bf0743ece18 328
demayer 0:6bf0743ece18 329 #include "uvisor-lib/uvisor-lib.h"
demayer 0:6bf0743ece18 330
demayer 0:6bf0743ece18 331 UVISOR_EXTERN int (*secure_get_index)(void);
demayer 0:6bf0743ece18 332
demayer 0:6bf0743ece18 333 #endif
demayer 0:6bf0743ece18 334 ```
demayer 0:6bf0743ece18 335
demayer 0:6bf0743ece18 336 ### Implementing a secure entry point
demayer 0:6bf0743ece18 337
demayer 0:6bf0743ece18 338 Now that you have defined the secure entry point, you can map the entry point to a function running in the secure box. You can do this through the `UVISOR_BOX_RPC_GATEWAY_SYNC` macro. Open `~/code/uvisor-example/source/secure_box.cpp`, and replace the line with `#define PRIVATE_BUTTON_BUFFER_COUNT 8` by:
demayer 0:6bf0743ece18 339
demayer 0:6bf0743ece18 340 ```cpp
demayer 0:6bf0743ece18 341 /* ~/code/uvisor-example/source/secure_box.cpp */
demayer 0:6bf0743ece18 342
demayer 0:6bf0743ece18 343 /* Function called through RPC */
demayer 0:6bf0743ece18 344 static int get_index() {
demayer 0:6bf0743ece18 345 /* Access to private memory here */
demayer 0:6bf0743ece18 346 return uvisor_ctx->index;
demayer 0:6bf0743ece18 347 }
demayer 0:6bf0743ece18 348
demayer 0:6bf0743ece18 349 UVISOR_BOX_RPC_GATEWAY_SYNC (private_button, secure_get_index, get_index, int, void);
demayer 0:6bf0743ece18 350
demayer 0:6bf0743ece18 351 #define PRIVATE_BUTTON_BUFFER_COUNT 8
demayer 0:6bf0743ece18 352 ```
demayer 0:6bf0743ece18 353
demayer 0:6bf0743ece18 354 ### Listening for RPC messages
demayer 0:6bf0743ece18 355
demayer 0:6bf0743ece18 356 To receive RPC messages, you need to spin up a new thread, running in the secure box context. You can do this in the main thread of the secure box. In `~/code/uvisor-example/source/secure_box.cpp`, replace the first five lines of `private_button_main_thread` with:
demayer 0:6bf0743ece18 357
demayer 0:6bf0743ece18 358 ```cpp
demayer 0:6bf0743ece18 359 /* ~/code/uvisor-example/source/secure_box.cpp */
demayer 0:6bf0743ece18 360
demayer 0:6bf0743ece18 361 static void listen_for_rpc() {
demayer 0:6bf0743ece18 362 /* List of functions to wait for */
demayer 0:6bf0743ece18 363 static const TFN_Ptr my_fn_array[] = {
demayer 0:6bf0743ece18 364 (TFN_Ptr) get_index
demayer 0:6bf0743ece18 365 };
demayer 0:6bf0743ece18 366
demayer 0:6bf0743ece18 367 while (1) {
demayer 0:6bf0743ece18 368 int caller_id;
demayer 0:6bf0743ece18 369 int status = rpc_fncall_waitfor(my_fn_array, 1, &caller_id, UVISOR_WAIT_FOREVER);
demayer 0:6bf0743ece18 370
demayer 0:6bf0743ece18 371 if (status) {
demayer 0:6bf0743ece18 372 uvisor_error(USER_NOT_ALLOWED);
demayer 0:6bf0743ece18 373 }
demayer 0:6bf0743ece18 374 }
demayer 0:6bf0743ece18 375 }
demayer 0:6bf0743ece18 376
demayer 0:6bf0743ece18 377 /* Main thread for the secure box */
demayer 0:6bf0743ece18 378 static void private_button_main_thread(const void *)
demayer 0:6bf0743ece18 379 {
demayer 0:6bf0743ece18 380 /* allocate serial port to ensure that code in this secure box
demayer 0:6bf0743ece18 381 * won't touch handle in the default security context when printing */
demayer 0:6bf0743ece18 382 if (!(uvisor_ctx->pc = new RawSerial(USBTX, USBRX)))
demayer 0:6bf0743ece18 383 return;
demayer 0:6bf0743ece18 384
demayer 0:6bf0743ece18 385 /* Start listening for RPC messages in a separate thread */
demayer 0:6bf0743ece18 386 Thread rpc_thread(osPriorityNormal, 1024);
demayer 0:6bf0743ece18 387 rpc_thread.start(&listen_for_rpc);
demayer 0:6bf0743ece18 388
demayer 0:6bf0743ece18 389 /* ... Rest of the private_button_main_thread function ... */
demayer 0:6bf0743ece18 390 ```
demayer 0:6bf0743ece18 391
demayer 0:6bf0743ece18 392 ### Calling the public secure entry point
demayer 0:6bf0743ece18 393
demayer 0:6bf0743ece18 394 To call the public secure entry point from any other box, you can use the `secure_get_index` function. It will automatically do an RPC call into the secure box and serialize the return value. You can try this out from the public box. In `~/code/uvisor-example/source/main.cpp`, first include the header file for the secure box:
demayer 0:6bf0743ece18 395
demayer 0:6bf0743ece18 396 ```cpp
demayer 0:6bf0743ece18 397 /* ~/code/uvisor-example/source/main.cpp */
demayer 0:6bf0743ece18 398
demayer 0:6bf0743ece18 399 #include "secure_box.h"
demayer 0:6bf0743ece18 400 ```
demayer 0:6bf0743ece18 401
demayer 0:6bf0743ece18 402 Then replace the `main` function with:
demayer 0:6bf0743ece18 403
demayer 0:6bf0743ece18 404 ```cpp
demayer 0:6bf0743ece18 405 /* ~/code/uvisor-example/source/main.cpp */
demayer 0:6bf0743ece18 406
demayer 0:6bf0743ece18 407 int main(void)
demayer 0:6bf0743ece18 408 {
demayer 0:6bf0743ece18 409 while (true) {
demayer 0:6bf0743ece18 410 led = !led;
demayer 0:6bf0743ece18 411 printf("Secure index is %d\n", secure_get_index());
demayer 0:6bf0743ece18 412 Thread::wait(500);
demayer 0:6bf0743ece18 413 }
demayer 0:6bf0743ece18 414 }
demayer 0:6bf0743ece18 415 ```
demayer 0:6bf0743ece18 416
demayer 0:6bf0743ece18 417 You can observe the secure index by opening a serial port connection to the device with a baud rate of 9600. When you press the `SW2` button, the index will increase.
demayer 0:6bf0743ece18 418
demayer 0:6bf0743ece18 419 ## The NVIC APIs
demayer 0:6bf0743ece18 420
demayer 0:6bf0743ece18 421 The ARM CMSIS header files provide APIs to configure, enable and disable IRQs in the NVIC module. These APIs all begin with `NVIC_`, and you can find them in the `core_cm*.h` files in your CMSIS module. The CMSIS header files also provide APIs to set and get an interrupt vector at runtime. This requires the relocation of the interrupt vector table, which is usually located in flash, to SRAM.
demayer 0:6bf0743ece18 422
demayer 0:6bf0743ece18 423 When the uVisor is enabled, all NVIC APIs are rerouted to the corresponding uVisor vIRQ APIs, which virtualize the interrupt module. The uVisor interrupt model has the following features:
demayer 0:6bf0743ece18 424
demayer 0:6bf0743ece18 425 - The uVisor owns the interrupt vector table.
demayer 0:6bf0743ece18 426 - All ISRs are relocated to SRAM.
demayer 0:6bf0743ece18 427 - Code in a box can only change the state of an IRQ (enable it, change its priority and so on) if the box registered that IRQ with uVisor through an IRQ ACL.
demayer 0:6bf0743ece18 428 - An IRQ that belongs to a box can only be modified when that box context is active.
demayer 0:6bf0743ece18 429
demayer 0:6bf0743ece18 430 Although this behavior is different from that of the original NVIC, it is backward compatible. Legacy code (such as a device HAL) still works after uVisor is enabled.
demayer 0:6bf0743ece18 431
demayer 0:6bf0743ece18 432 All IRQ slots that are not listed in any box ACL list are considered unclaimed. Boxes can gain exclusive ownership of unclaimed IRQs on a first-come first-served basis through the use of the NVIC APIs.
demayer 0:6bf0743ece18 433
demayer 0:6bf0743ece18 434 ## The *public box* ACLs
demayer 0:6bf0743ece18 435
demayer 0:6bf0743ece18 436 The code samples in this guide provide a list of ACLs for the public box. The list includes peripherals necessary to make the example app work, and they are specific to the NXP FRDM-K64F target.
demayer 0:6bf0743ece18 437
demayer 0:6bf0743ece18 438 To generate the ACLs list for a different target or a different app, use the code provided in the [Enable uVisor](#enable-uvisor) section, but start with an empty ACLs list:
demayer 0:6bf0743ece18 439
demayer 0:6bf0743ece18 440 ```C
demayer 0:6bf0743ece18 441 static const UvisorBoxAclItem g_public_box_acls[] = {
demayer 0:6bf0743ece18 442 }
demayer 0:6bf0743ece18 443 ```
demayer 0:6bf0743ece18 444
demayer 0:6bf0743ece18 445 Compile your application using uVisor in debug mode. This operation requires some more advanced steps. Please read [Debugging uVisor on mbed OS](DEBUGGING.md) for the detailed instructions.
demayer 0:6bf0743ece18 446
demayer 0:6bf0743ece18 447 Once the uVisor debug messages are enabled, your application fails. The failure is due to the first missing ACL being hit by the public box code. The message will look like:
demayer 0:6bf0743ece18 448
demayer 0:6bf0743ece18 449 ```
demayer 0:6bf0743ece18 450 ***********************************************************
demayer 0:6bf0743ece18 451 BUS FAULT
demayer 0:6bf0743ece18 452 ***********************************************************
demayer 0:6bf0743ece18 453
demayer 0:6bf0743ece18 454 * Active Box ID: 0
demayer 0:6bf0743ece18 455 * FAULT SYNDROME REGISTERS
demayer 0:6bf0743ece18 456
demayer 0:6bf0743ece18 457 CFSR: 0x00008200
demayer 0:6bf0743ece18 458 BFAR: 0x40048044
demayer 0:6bf0743ece18 459 --> PRECISERR: precise data access.
demayer 0:6bf0743ece18 460
demayer 0:6bf0743ece18 461 ...
demayer 0:6bf0743ece18 462 ```
demayer 0:6bf0743ece18 463
demayer 0:6bf0743ece18 464 Look up the faulty address (the value of BFAR) in the target device reference manual.
demayer 0:6bf0743ece18 465
demayer 0:6bf0743ece18 466 Once you know which peripheral is causing the fault (the `SIM` peripheral, in this example), add its entry to the ACLs list:
demayer 0:6bf0743ece18 467
demayer 0:6bf0743ece18 468 ```C
demayer 0:6bf0743ece18 469 static const UvisorBoxAclItem g_public_box_acls[] = {
demayer 0:6bf0743ece18 470 {SIM, sizeof(*SIM), UVISOR_TACLDEF_PERIPH},
demayer 0:6bf0743ece18 471 };
demayer 0:6bf0743ece18 472 ```
demayer 0:6bf0743ece18 473
demayer 0:6bf0743ece18 474 > **Note**: If the fault debug screen does not show the name of the peripheral, look it up in the target device reference manual.
demayer 0:6bf0743ece18 475
demayer 0:6bf0743ece18 476 For readability, do not use the hard-coded addresses of your peripherals. Instead, use the symbols that the target CMSIS module provides.
demayer 0:6bf0743ece18 477
demayer 0:6bf0743ece18 478 Repeat the process multiple times until all ACLs have been added to the list. When no other ACL is needed, the system runs without hitting a uVisor fault.
demayer 0:6bf0743ece18 479
demayer 0:6bf0743ece18 480 ## Additional resources
demayer 0:6bf0743ece18 481 [Go to top](#overview)
demayer 0:6bf0743ece18 482
demayer 0:6bf0743ece18 483 - [uVisor API documentation](API.md).
demayer 0:6bf0743ece18 484 - [Debugging uVisor on mbed OS](DEBUGGING.md).
demayer 0:6bf0743ece18 485 - [Using nonvolatile storage from uVisor on mbed OS](manual/Flash.md).
demayer 0:6bf0743ece18 486
demayer 0:6bf0743ece18 487 If you found any bug or inconsistency in this guide, please [raise an issue](https://github.com/ARMmbed/uvisor/issues/new).