Includes library modifications to allow access to AIN_4 (AIN_0 / 5)

Committer:
bryantaylor
Date:
Tue Sep 20 21:26:12 2016 +0000
Revision:
0:eafc3fd41f75
hackathon

Who changed what in which revision?

UserRevisionLine numberNew contents of line
bryantaylor 0:eafc3fd41f75 1 # Quick-Start Guide for uVisor on mbed OS
bryantaylor 0:eafc3fd41f75 2
bryantaylor 0:eafc3fd41f75 3 This guide will help you get started with uVisor on mbed OS by walking you through creating a sample application for the NXP FRDM-K64F board.
bryantaylor 0:eafc3fd41f75 4
bryantaylor 0:eafc3fd41f75 5 The uVisor provides sandboxed environments and resources protection for applications built for ARM Cortex-M3 and Cortex-M4 devices. Here we will show you how to enable the uVisor and configure a secure box to get hold of some exclusive resources (memory, peripherals, interrupts). For more information on the uVisor design philosophy, please check out our the uVisor [introductory document](../../README.md).
bryantaylor 0:eafc3fd41f75 6
bryantaylor 0:eafc3fd41f75 7 ## Overview
bryantaylor 0:eafc3fd41f75 8
bryantaylor 0:eafc3fd41f75 9 To get a basic `blinky` application running on mbed OS with uVisor enabled, you will need the following:
bryantaylor 0:eafc3fd41f75 10
bryantaylor 0:eafc3fd41f75 11 * A platform and a toolchain supported by uVisor on mbed OS. You can verify this on [the official list](../../README.md#supported-platforms). Please note that uVisor might support some platform internally, but not on mbed OS. Generally this means that the porting process has only been partially completed. If you want to port your platform to uVisor and enable it on mbed OS, please follow the [uVisor Porting Guide for mbed OS](../core/PORTING.md).
bryantaylor 0:eafc3fd41f75 12 * git. It will be used to download the mbed codebase.
bryantaylor 0:eafc3fd41f75 13 * The mbed command-line tools, mbed-cli. You can run `pip install mbed-cli` to install them.
bryantaylor 0:eafc3fd41f75 14
bryantaylor 0:eafc3fd41f75 15 For the remainder of this guide we will assume the following:
bryantaylor 0:eafc3fd41f75 16
bryantaylor 0:eafc3fd41f75 17 * You are developing on a \*nix machine, in the `~/code` folder.
bryantaylor 0:eafc3fd41f75 18 * You are building the app for the [NXP FRDM-K64F](http://developer.mbed.org/platforms/FRDM-K64F/) target, with the [GCC ARM Embedded](https://launchpad.net/gcc-arm-embedded) toolchain.
bryantaylor 0:eafc3fd41f75 19
bryantaylor 0:eafc3fd41f75 20 The instructions provided can be easily generalized to the case of other targets on other host OSs.
bryantaylor 0:eafc3fd41f75 21
bryantaylor 0:eafc3fd41f75 22 ## Start with the `blinky` app
bryantaylor 0:eafc3fd41f75 23 [Go to top](#overview)
bryantaylor 0:eafc3fd41f75 24
bryantaylor 0:eafc3fd41f75 25 To create a new mbed application called `uvisor-example` just run the following commands:
bryantaylor 0:eafc3fd41f75 26
bryantaylor 0:eafc3fd41f75 27 ```bash
bryantaylor 0:eafc3fd41f75 28 $ cd ~/code
bryantaylor 0:eafc3fd41f75 29 $ mbed new uvisor-example
bryantaylor 0:eafc3fd41f75 30 ```
bryantaylor 0:eafc3fd41f75 31
bryantaylor 0:eafc3fd41f75 32 The mbed-cli tools will automatically fetch the mbed codebase for you. By default, git will be used to track your code changes, so your application will be ready to be pushed to a git server, if you want to.
bryantaylor 0:eafc3fd41f75 33
bryantaylor 0:eafc3fd41f75 34 Once the import process is finished, create a `source` folder:
bryantaylor 0:eafc3fd41f75 35 ```bash
bryantaylor 0:eafc3fd41f75 36 $ mkdir ~/code/uvisor-example/source
bryantaylor 0:eafc3fd41f75 37 ```
bryantaylor 0:eafc3fd41f75 38 and place a new file `main.cpp` in it:
bryantaylor 0:eafc3fd41f75 39
bryantaylor 0:eafc3fd41f75 40 ```C
bryantaylor 0:eafc3fd41f75 41 /* ~/code/uvisor-example/source/main.cpp */
bryantaylor 0:eafc3fd41f75 42
bryantaylor 0:eafc3fd41f75 43 #include "mbed.h"
bryantaylor 0:eafc3fd41f75 44 #include "rtos.h"
bryantaylor 0:eafc3fd41f75 45
bryantaylor 0:eafc3fd41f75 46 DigitalOut led(LED1);
bryantaylor 0:eafc3fd41f75 47
bryantaylor 0:eafc3fd41f75 48 int main(void)
bryantaylor 0:eafc3fd41f75 49 {
bryantaylor 0:eafc3fd41f75 50 while (true) {
bryantaylor 0:eafc3fd41f75 51 led = !led;
bryantaylor 0:eafc3fd41f75 52 Thread::wait(500);
bryantaylor 0:eafc3fd41f75 53 }
bryantaylor 0:eafc3fd41f75 54 }
bryantaylor 0:eafc3fd41f75 55 ```
bryantaylor 0:eafc3fd41f75 56
bryantaylor 0:eafc3fd41f75 57 This simple application just blinks an LED from the main thread, which is created by default by the OS.
bryantaylor 0:eafc3fd41f75 58
bryantaylor 0:eafc3fd41f75 59 ---
bryantaylor 0:eafc3fd41f75 60
bryantaylor 0:eafc3fd41f75 61 **Checkpoint**
bryantaylor 0:eafc3fd41f75 62
bryantaylor 0:eafc3fd41f75 63 Compile the application:
bryantaylor 0:eafc3fd41f75 64
bryantaylor 0:eafc3fd41f75 65 ```bash
bryantaylor 0:eafc3fd41f75 66 $ mbed compile -m K64F -t GCC_ARM
bryantaylor 0:eafc3fd41f75 67 ```
bryantaylor 0:eafc3fd41f75 68
bryantaylor 0:eafc3fd41f75 69 The resulting binary will be located at:
bryantaylor 0:eafc3fd41f75 70
bryantaylor 0:eafc3fd41f75 71 ```bash
bryantaylor 0:eafc3fd41f75 72 ~/code/uvisor-example/.build/K64F/GCC_ARM/uvisor-example.bin
bryantaylor 0:eafc3fd41f75 73 ```
bryantaylor 0:eafc3fd41f75 74
bryantaylor 0:eafc3fd41f75 75 Drag-and-drop it onto the USB device mounted on your computer in order to flash the device. When the flashing process is completed, press the reset button on the device. You should see the device LED blinking.
bryantaylor 0:eafc3fd41f75 76
bryantaylor 0:eafc3fd41f75 77 ---
bryantaylor 0:eafc3fd41f75 78
bryantaylor 0:eafc3fd41f75 79 In the next sections you will see:
bryantaylor 0:eafc3fd41f75 80
bryantaylor 0:eafc3fd41f75 81 * How to [enable uVisor](#enable-uvisor) on the `uvisor-example` app.
bryantaylor 0:eafc3fd41f75 82 * How to [add a secure box](#add-a-secure-box) to the `uvisor-example` app with exclusive access to a timer, to a push-button interrupt, and to static and dynamic memories.
bryantaylor 0:eafc3fd41f75 83
bryantaylor 0:eafc3fd41f75 84 ## Enable uVisor
bryantaylor 0:eafc3fd41f75 85 [Go to top](#overview)
bryantaylor 0:eafc3fd41f75 86
bryantaylor 0:eafc3fd41f75 87 To enable the uVisor on the app, just add the following lines at the beginning of the `main.cpp` file:
bryantaylor 0:eafc3fd41f75 88
bryantaylor 0:eafc3fd41f75 89 ```C
bryantaylor 0:eafc3fd41f75 90 /* ~/code/uvisor-example/source/main.cpp */
bryantaylor 0:eafc3fd41f75 91
bryantaylor 0:eafc3fd41f75 92 #include "mbed.h"
bryantaylor 0:eafc3fd41f75 93 #include "rtos.h"
bryantaylor 0:eafc3fd41f75 94 #include "uvisor-lib/uvisor-lib.h"
bryantaylor 0:eafc3fd41f75 95
bryantaylor 0:eafc3fd41f75 96 /* Register privleged system IRQ hooks.
bryantaylor 0:eafc3fd41f75 97 * This is a system-wide configuration and it is independent from the app, but
bryantaylor 0:eafc3fd41f75 98 * for the moment it needs to be specified in the app. This will change in a
bryantaylor 0:eafc3fd41f75 99 * later version: The configuration will be provided by the OS. */
bryantaylor 0:eafc3fd41f75 100 extern "C" void SVC_Handler(void);
bryantaylor 0:eafc3fd41f75 101 extern "C" void PendSV_Handler(void);
bryantaylor 0:eafc3fd41f75 102 extern "C" void SysTick_Handler(void);
bryantaylor 0:eafc3fd41f75 103 UVISOR_SET_PRIV_SYS_IRQ_HOOKS(SVC_Handler, PendSV_Handler, SysTick_Handler);
bryantaylor 0:eafc3fd41f75 104
bryantaylor 0:eafc3fd41f75 105 /* Main box Access Control Lists (ACLs). */
bryantaylor 0:eafc3fd41f75 106 /* Note: These are specific to the NXP FRDM-K64F board. See the section below
bryantaylor 0:eafc3fd41f75 107 * for more information. */
bryantaylor 0:eafc3fd41f75 108 static const UvisorBoxAclItem g_main_box_acls[] = {
bryantaylor 0:eafc3fd41f75 109 /* For the LED */
bryantaylor 0:eafc3fd41f75 110 {SIM, sizeof(*SIM), UVISOR_TACLDEF_PERIPH},
bryantaylor 0:eafc3fd41f75 111 {PORTB, sizeof(*PORTB), UVISOR_TACLDEF_PERIPH},
bryantaylor 0:eafc3fd41f75 112
bryantaylor 0:eafc3fd41f75 113 /* For messages printed on the serial port. */
bryantaylor 0:eafc3fd41f75 114 {OSC, sizeof(*OSC), UVISOR_TACLDEF_PERIPH},
bryantaylor 0:eafc3fd41f75 115 {MCG, sizeof(*MCG), UVISOR_TACLDEF_PERIPH},
bryantaylor 0:eafc3fd41f75 116 {UART0, sizeof(*UART0), UVISOR_TACLDEF_PERIPH},
bryantaylor 0:eafc3fd41f75 117 };
bryantaylor 0:eafc3fd41f75 118
bryantaylor 0:eafc3fd41f75 119 /* Enable uVisor, using the ACLs we just created. */
bryantaylor 0:eafc3fd41f75 120 UVISOR_SET_MODE_ACL(UVISOR_ENABLED, g_main_box_acls);
bryantaylor 0:eafc3fd41f75 121
bryantaylor 0:eafc3fd41f75 122 /* Rest of the existing app code */
bryantaylor 0:eafc3fd41f75 123 ...
bryantaylor 0:eafc3fd41f75 124 ```
bryantaylor 0:eafc3fd41f75 125
bryantaylor 0:eafc3fd41f75 126 In the code above we specified 3 elements:
bryantaylor 0:eafc3fd41f75 127
bryantaylor 0:eafc3fd41f75 128 1. System-wide uVisor configurations: `UVISOR_SET_PRIV_SYS_IRQ_HOOKS`. Application authors currently need to specify the privileged system IRQ hooks at the application level with this macro, but in the future the operating system will register the privileged system IRQ hooks on its own.
bryantaylor 0:eafc3fd41f75 129 1. Main box Access Control Lists (ACLs). Since with uVisor enabled everything runs in unprivileged mode, we need to make sure that peripherals that are accessed by the OS and the main box are allowed. These peripherals are specified using a list like the one in the snippet above. For the purpose of this example we provide you the list of all the ACLs that we know you will need. For other platforms or other applications you need to determine those ACLs following a process that is described in a [section](#the-main-box-acls) below.
bryantaylor 0:eafc3fd41f75 130 1. App-specific uVisor configurations: `UVISOR_SET_MODE_ACL`. This macro sets the uVisor mode (enabled) and associates the list of ACLs we just created with the main box.
bryantaylor 0:eafc3fd41f75 131
bryantaylor 0:eafc3fd41f75 132 Before compiling, we 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:
bryantaylor 0:eafc3fd41f75 133
bryantaylor 0:eafc3fd41f75 134 ```JSON
bryantaylor 0:eafc3fd41f75 135 {
bryantaylor 0:eafc3fd41f75 136 "target_overrides": {
bryantaylor 0:eafc3fd41f75 137 "K64F": {
bryantaylor 0:eafc3fd41f75 138 "target.features_add": ["UVISOR"],
bryantaylor 0:eafc3fd41f75 139 "target.extra_labels_add": ["UVISOR_SUPPORTED"]
bryantaylor 0:eafc3fd41f75 140 }
bryantaylor 0:eafc3fd41f75 141 },
bryantaylor 0:eafc3fd41f75 142 "macros": [
bryantaylor 0:eafc3fd41f75 143 "FEATURE_UVISOR",
bryantaylor 0:eafc3fd41f75 144 "TARGET_UVISOR_SUPPORTED"
bryantaylor 0:eafc3fd41f75 145 ]
bryantaylor 0:eafc3fd41f75 146 }
bryantaylor 0:eafc3fd41f75 147 ```
bryantaylor 0:eafc3fd41f75 148
bryantaylor 0:eafc3fd41f75 149 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. Since the uVisor relies on those symbols in some assembly code, we need to define them manually.
bryantaylor 0:eafc3fd41f75 150
bryantaylor 0:eafc3fd41f75 151 ---
bryantaylor 0:eafc3fd41f75 152
bryantaylor 0:eafc3fd41f75 153 **Checkpoint**
bryantaylor 0:eafc3fd41f75 154
bryantaylor 0:eafc3fd41f75 155 Compile the application again. This time the `K64F` target will include the new features and labels we provided in `mbed_app.json`;
bryantaylor 0:eafc3fd41f75 156
bryantaylor 0:eafc3fd41f75 157 ```bash
bryantaylor 0:eafc3fd41f75 158 $ mbed compile -m K64F -t GCC_ARM
bryantaylor 0:eafc3fd41f75 159 ```
bryantaylor 0:eafc3fd41f75 160
bryantaylor 0:eafc3fd41f75 161 The binary will be located at:
bryantaylor 0:eafc3fd41f75 162
bryantaylor 0:eafc3fd41f75 163 ```bash
bryantaylor 0:eafc3fd41f75 164 ~/code/uvisor-example/.build/K64F/GCC_ARM/uvisor-example.bin
bryantaylor 0:eafc3fd41f75 165 ```
bryantaylor 0:eafc3fd41f75 166
bryantaylor 0:eafc3fd41f75 167 Re-flash the device and press the reset button. The device LED should be blinking as in the previous case.
bryantaylor 0:eafc3fd41f75 168
bryantaylor 0:eafc3fd41f75 169 ---
bryantaylor 0:eafc3fd41f75 170
bryantaylor 0:eafc3fd41f75 171 If you enable uVisor in the `blinky` app as it was written above, you will not get any particular security feature. All code and resources share the same security context, which we call the *main box*.
bryantaylor 0:eafc3fd41f75 172
bryantaylor 0:eafc3fd41f75 173 A lot happens under the hood, though. All the user code now runs in unprivileged mode, and the systems services like the `NVIC` APIs or the OS SVCalls are routed through the uVisor.
bryantaylor 0:eafc3fd41f75 174
bryantaylor 0:eafc3fd41f75 175 ## Add a secure box
bryantaylor 0:eafc3fd41f75 176 [Go to top](#overview)
bryantaylor 0:eafc3fd41f75 177
bryantaylor 0:eafc3fd41f75 178 Now that uVisor is enabled, we can finally add a *secure box*.
bryantaylor 0:eafc3fd41f75 179
bryantaylor 0:eafc3fd41f75 180 A secure box is a special compartment that is granted 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.
bryantaylor 0:eafc3fd41f75 181
bryantaylor 0:eafc3fd41f75 182 Code that belongs to a box is not obfuscated by uVisor, 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.
bryantaylor 0:eafc3fd41f75 183
bryantaylor 0:eafc3fd41f75 184 Instead, we provide specific APIs to instruct the uVisor to protect a private resource. Here we will show how to use these APIs in the `uvisor-example` app.
bryantaylor 0:eafc3fd41f75 185
bryantaylor 0:eafc3fd41f75 186 ### Configure the secure box
bryantaylor 0:eafc3fd41f75 187
bryantaylor 0:eafc3fd41f75 188 For this example, we want to create a secure box called `private_timer`. The `private_timer` box will be configured to have exclusive access to the PIT timer and to the GPIO PORT C on the NXP FRDM-K64F board, which means that other boxes will be prevented from accessing these peripherals.
bryantaylor 0:eafc3fd41f75 189
bryantaylor 0:eafc3fd41f75 190 Each secure box must have at least one thread, which we call the box's main thread. In our `private_timer` box we will only use this thread throughout the whole program. The thread will constantly save the current timer value in a private buffer. In addition, we want to print the content of the buffered timer values whenever we press the `SW2` button on the board.
bryantaylor 0:eafc3fd41f75 191
bryantaylor 0:eafc3fd41f75 192 We want the box to have exclusive access to the following resources:
bryantaylor 0:eafc3fd41f75 193
bryantaylor 0:eafc3fd41f75 194 * The timer and push-button peripherals (as specified by a peripheral ACL). Nobody else should be able to read the timer values.
bryantaylor 0:eafc3fd41f75 195 * The push-button interrupt (as specified by an IRQ ACL). We want the button IRQ to be re-routed to our box-specific ISR.
bryantaylor 0:eafc3fd41f75 196 * The buffer that holds the timer samples (as specified by a dynamic memory ACL).
bryantaylor 0:eafc3fd41f75 197 * The static memory that holds information about the timer buffer (as specified by a static memory ACL).
bryantaylor 0:eafc3fd41f75 198
bryantaylor 0:eafc3fd41f75 199 Create a new source file, `~/code/uvisor-example/source/secure_box.cpp`. We will configure the secure box inside this file. The secure box name for this example is `private_timer`.
bryantaylor 0:eafc3fd41f75 200
bryantaylor 0:eafc3fd41f75 201 ```C
bryantaylor 0:eafc3fd41f75 202 /* ~/code/uvisor-example/source/secure_box.cpp */
bryantaylor 0:eafc3fd41f75 203
bryantaylor 0:eafc3fd41f75 204 #include "mbed.h"
bryantaylor 0:eafc3fd41f75 205 #include "rtos.h"
bryantaylor 0:eafc3fd41f75 206 #include "uvisor-lib/uvisor-lib.h"
bryantaylor 0:eafc3fd41f75 207
bryantaylor 0:eafc3fd41f75 208 /* Private static memory for the secure box */
bryantaylor 0:eafc3fd41f75 209 typedef struct {
bryantaylor 0:eafc3fd41f75 210 uint32_t * buffer;
bryantaylor 0:eafc3fd41f75 211 int index;
bryantaylor 0:eafc3fd41f75 212 } PrivateTimerStaticMemory;
bryantaylor 0:eafc3fd41f75 213
bryantaylor 0:eafc3fd41f75 214 /* ACLs list for the secure box: Timer (PIT). */
bryantaylor 0:eafc3fd41f75 215 static const UvisorBoxAclItem g_private_timer_acls[] = {
bryantaylor 0:eafc3fd41f75 216 {PIT, sizeof(*PIT), UVISOR_TACLDEF_PERIPH}
bryantaylor 0:eafc3fd41f75 217 {PORTC, sizeof(*PORTC), UVISOR_TACLDEF_PERIPH},
bryantaylor 0:eafc3fd41f75 218 };
bryantaylor 0:eafc3fd41f75 219
bryantaylor 0:eafc3fd41f75 220 static void private_timer_main_thread(const void *);
bryantaylor 0:eafc3fd41f75 221
bryantaylor 0:eafc3fd41f75 222 /* Secure box configuration */
bryantaylor 0:eafc3fd41f75 223 UVISOR_BOX_NAMESPACE(NULL); /* We won't specify a box namespace for this example. */
bryantaylor 0:eafc3fd41f75 224 UVISOR_BOX_HEAPSIZE(4096); /* Heap size for the secure box */
bryantaylor 0:eafc3fd41f75 225 UVISOR_BOX_MAIN(private_timer_main_thread, /* Main thread for the secure box */
bryantaylor 0:eafc3fd41f75 226 osPriorityNormal, /* Priority of the secure box's main thread */
bryantaylor 0:eafc3fd41f75 227 1024); /* Stack size for the secure box's main thread */
bryantaylor 0:eafc3fd41f75 228 UVISOR_BOX_CONFIG(private_timer, /* Name of the secure box */
bryantaylor 0:eafc3fd41f75 229 g_private_timer_acls, /* ACLs list for the secure box */
bryantaylor 0:eafc3fd41f75 230 1024, /* Stack size for the secure box */
bryantaylor 0:eafc3fd41f75 231 PrivateTimerStaticMemory); /* Private static memory for the secure box. */
bryantaylor 0:eafc3fd41f75 232 ```
bryantaylor 0:eafc3fd41f75 233
bryantaylor 0:eafc3fd41f75 234 ### Create the secure box's main thread function
bryantaylor 0:eafc3fd41f75 235
bryantaylor 0:eafc3fd41f75 236 In general, you can decide what to do in your box's main thread. You can run it once and then kill it, use it to configure memories, peripherals, or to create other threads. In this app, the box's main thread is the only thread for the `private_timer` box, and it will run throughout the whole program.
bryantaylor 0:eafc3fd41f75 237
bryantaylor 0:eafc3fd41f75 238 The `private_timer_main_thread` function configures the PIT timer, allocates the dynamic buffer to hold the timer values and initializes its private static memory, `PrivateTimerStaticMemory`. A spinning loop is used to update the values in the buffer every time the thread is reactivated.
bryantaylor 0:eafc3fd41f75 239
bryantaylor 0:eafc3fd41f75 240 ```C
bryantaylor 0:eafc3fd41f75 241 /* Number of timer samples we will use */
bryantaylor 0:eafc3fd41f75 242 #define PRIVATE_TIMER_BUFFER_COUNT 256
bryantaylor 0:eafc3fd41f75 243
bryantaylor 0:eafc3fd41f75 244 /* For debug purposes: print the buffer values when the SW2 button is pressed. */
bryantaylor 0:eafc3fd41f75 245 static void private_timer_button_on_press(void)
bryantaylor 0:eafc3fd41f75 246 {
bryantaylor 0:eafc3fd41f75 247 for (int i = 0; i < PRIVATE_TIMER_BUFFER_COUNT; i++) {
bryantaylor 0:eafc3fd41f75 248 printf("buffer[%03d] = %lu\r\n", i, uvisor_ctx->buffer[i]);
bryantaylor 0:eafc3fd41f75 249 }
bryantaylor 0:eafc3fd41f75 250 }
bryantaylor 0:eafc3fd41f75 251
bryantaylor 0:eafc3fd41f75 252 /* Main thread for the secure box */
bryantaylor 0:eafc3fd41f75 253 static void private_timer_main_thread(const void *)
bryantaylor 0:eafc3fd41f75 254 {
bryantaylor 0:eafc3fd41f75 255 /* Create the buffer and cache its pointer to the private static memory. */
bryantaylor 0:eafc3fd41f75 256 uvisor_ctx->buffer = (uint32_t *) malloc(PRIVATE_TIMER_BUFFER_COUNT * sizeof(uint32_t));
bryantaylor 0:eafc3fd41f75 257 if (uvisor_ctx->buffer == NULL) {
bryantaylor 0:eafc3fd41f75 258 mbed_die();
bryantaylor 0:eafc3fd41f75 259 }
bryantaylor 0:eafc3fd41f75 260 uvisor_ctx->index = 0;
bryantaylor 0:eafc3fd41f75 261
bryantaylor 0:eafc3fd41f75 262 /* Setup the push-button callback. */
bryantaylor 0:eafc3fd41f75 263 InterruptIn button(SW2);
bryantaylor 0:eafc3fd41f75 264 button.mode(PullUp);
bryantaylor 0:eafc3fd41f75 265 button.fall(&private_timer_button_on_press);
bryantaylor 0:eafc3fd41f75 266
bryantaylor 0:eafc3fd41f75 267 /* Setup and start the timer. */
bryantaylor 0:eafc3fd41f75 268 Timer timer;
bryantaylor 0:eafc3fd41f75 269 timer.start();
bryantaylor 0:eafc3fd41f75 270
bryantaylor 0:eafc3fd41f75 271 while (1) {
bryantaylor 0:eafc3fd41f75 272 /* Store the timer value. */
bryantaylor 0:eafc3fd41f75 273 uvisor_ctx->buffer[uvisor_ctx->index] = timer.read_us();
bryantaylor 0:eafc3fd41f75 274
bryantaylor 0:eafc3fd41f75 275 /* Update the index. Behave as a circular buffer. */
bryantaylor 0:eafc3fd41f75 276 if (uvisor_ctx->index < PRIVATE_TIMER_BUFFER_COUNT - 1) {
bryantaylor 0:eafc3fd41f75 277 uvisor_ctx->index++;
bryantaylor 0:eafc3fd41f75 278 } else {
bryantaylor 0:eafc3fd41f75 279 uvisor_ctx->index = 0;
bryantaylor 0:eafc3fd41f75 280 }
bryantaylor 0:eafc3fd41f75 281 }
bryantaylor 0:eafc3fd41f75 282 }
bryantaylor 0:eafc3fd41f75 283 ```
bryantaylor 0:eafc3fd41f75 284
bryantaylor 0:eafc3fd41f75 285 A few things to note in the code above:
bryantaylor 0:eafc3fd41f75 286
bryantaylor 0:eafc3fd41f75 287 * If code is running in the context of `private_timer`, then any object instantiated inside that code will belong to the `private_timer` heap and stack. This means that in the example above the `InterruptIn` and `Timer` objects are private to the `private_timer` box. The same applies to the dynamically allocated buffer `uvisor_ctx->buffer`.
bryantaylor 0:eafc3fd41f75 288 * The content of the private memory `PrivateTimerStaticMemory` can be accessed using the `PrivateTimerStaticMemory * uvisor_ctx` pointer, which is maintained by uVisor.
bryantaylor 0:eafc3fd41f75 289 * The `InterruptIn` object triggers the registration of an interrupt slot. Since that code is run in the context of the `private_timer` box, then the push-button IRQ belongs to that box. If you want to use the IRQ APIs directly, read the [section](#the-nvic-apis) below.
bryantaylor 0:eafc3fd41f75 290 * Even if the `private_timer_button_on_press` function runs in the context of `private_timer`, we can still use the `printf` function, which accesses the `UART0` peripheral, owned by the main box. This is because all ACLs declared in the main 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.
bryantaylor 0:eafc3fd41f75 291
bryantaylor 0:eafc3fd41f75 292 > **Warning**: Instantiating an object in the `secure_box.cpp` global scope will automatically map it to the main box context, not the `private_timer` one. If you want an object to be private to a box, you need to instantiate it inside the code that will run in the context of that box (like the `InterruptIn` and `Timer` objects), or alternatively statically initialize it in the box private static memory (like the `buffer` and `index` variables in `PrivateTimerStaticMemory`).
bryantaylor 0:eafc3fd41f75 293
bryantaylor 0:eafc3fd41f75 294 ---
bryantaylor 0:eafc3fd41f75 295
bryantaylor 0:eafc3fd41f75 296 **Checkpoint**
bryantaylor 0:eafc3fd41f75 297
bryantaylor 0:eafc3fd41f75 298 Compile the application again:
bryantaylor 0:eafc3fd41f75 299
bryantaylor 0:eafc3fd41f75 300 ```bash
bryantaylor 0:eafc3fd41f75 301 $ mbed compile -m K64F -t GCC_ARM
bryantaylor 0:eafc3fd41f75 302 ```
bryantaylor 0:eafc3fd41f75 303
bryantaylor 0:eafc3fd41f75 304 Re-flash the device, and press the reset button. The device LED should be blinking as in the previous case.
bryantaylor 0:eafc3fd41f75 305
bryantaylor 0:eafc3fd41f75 306 If you don't see the LED blinking, it means that the application halted somewhere, probably because uVisor captured a fault. You can setup the uVisor debug messages to see if there is any problem. Follow the [Debugging uVisor on mbed OS](DEBUGGING.md) document for a step-by-step guide.
bryantaylor 0:eafc3fd41f75 307
bryantaylor 0:eafc3fd41f75 308 If the LED is blinking, it means that the app is running fine. If you now press the `SW2` button on the NXP FRDM-K64F board, the `private_timer_button_on_press` function will be executed, printing the values in the timer buffer. You can observe these values by opening a serial port connection to the device, with a baud rate of 9600. When the print is completed, you should see the LED blinking again.
bryantaylor 0:eafc3fd41f75 309
bryantaylor 0:eafc3fd41f75 310 ### Expose public secure entry points to the secure box
bryantaylor 0:eafc3fd41f75 311
bryantaylor 0:eafc3fd41f75 312 Coming soon.
bryantaylor 0:eafc3fd41f75 313
bryantaylor 0:eafc3fd41f75 314 ## Wrap-up
bryantaylor 0:eafc3fd41f75 315 [Go to top](#overview)
bryantaylor 0:eafc3fd41f75 316
bryantaylor 0:eafc3fd41f75 317 In this guide we showed you how to:
bryantaylor 0:eafc3fd41f75 318
bryantaylor 0:eafc3fd41f75 319 * Enable uVisor on an existing application.
bryantaylor 0:eafc3fd41f75 320 * Add a secure box to your application.
bryantaylor 0:eafc3fd41f75 321 * Protect static and dynamic memories in a secure box.
bryantaylor 0:eafc3fd41f75 322 * Gain exclusive access to a peripheral and an IRQ in a secure box.
bryantaylor 0:eafc3fd41f75 323 * (Coming soon) Expose public secure entry points to a secure box.
bryantaylor 0:eafc3fd41f75 324
bryantaylor 0:eafc3fd41f75 325 You can now modify the example or create a new one to protect your resources into a secure box. You might find the following resources useful:
bryantaylor 0:eafc3fd41f75 326
bryantaylor 0:eafc3fd41f75 327 * [uVisor API documentation](API.md)
bryantaylor 0:eafc3fd41f75 328 * [Debugging uVisor on mbed OS](DEBUGGING.md)
bryantaylor 0:eafc3fd41f75 329
bryantaylor 0:eafc3fd41f75 330 If you found any bug or inconsistency in this guide, please [raise an issue](https://github.com/ARMmbed/uvisor/issues/new).
bryantaylor 0:eafc3fd41f75 331
bryantaylor 0:eafc3fd41f75 332 ## Appendix
bryantaylor 0:eafc3fd41f75 333 [Go to top](#overview)
bryantaylor 0:eafc3fd41f75 334
bryantaylor 0:eafc3fd41f75 335 This section contains additional information that you might find useful when setting up a secure box.
bryantaylor 0:eafc3fd41f75 336
bryantaylor 0:eafc3fd41f75 337 ### The NVIC APIs
bryantaylor 0:eafc3fd41f75 338
bryantaylor 0:eafc3fd41f75 339 The ARM CMSIS header files provide APIs to configure, enable and disable IRQs in the NVIC module. These APIs are all prefixed with `NVIC_` and can be found in the `core_cm*.h` files in your CMSIS module.
bryantaylor 0:eafc3fd41f75 340
bryantaylor 0:eafc3fd41f75 341 In addition, the CMSIS header also provide APIs to set and get an interrupt vector at runtime. This requires the interrupt vector table, which is usually located in flash, to be relocated to SRAM.
bryantaylor 0:eafc3fd41f75 342
bryantaylor 0:eafc3fd41f75 343 When the uVisor is enabled, all NVIC APIs are re-routed to the corresponding uVisor vIRQ APIs, which virtualize the interrupt module. The uVisor interrupt model has the following features:
bryantaylor 0:eafc3fd41f75 344
bryantaylor 0:eafc3fd41f75 345 * The uVisor owns the interrupt vector table.
bryantaylor 0:eafc3fd41f75 346 * All ISRs are relocated to SRAM.
bryantaylor 0:eafc3fd41f75 347 * Code in a box can only change the state of an IRQ (enable it, change its priority, etc.) if the box registered that IRQ with uVisor at runtime, using the `NVIC_SetVector` API.
bryantaylor 0:eafc3fd41f75 348 * An IRQ that belongs to a box can only be modified when that box context is active.
bryantaylor 0:eafc3fd41f75 349
bryantaylor 0:eafc3fd41f75 350 Although this behaviour is different from the original NVIC one, it is backwards compatible. This means that legacy code (like a device HAL) will still work after uVisor is enabled. The general use case is the following:
bryantaylor 0:eafc3fd41f75 351
bryantaylor 0:eafc3fd41f75 352 ```C
bryantaylor 0:eafc3fd41f75 353 #define MY_IRQ 42
bryantaylor 0:eafc3fd41f75 354
bryantaylor 0:eafc3fd41f75 355 /* Set the ISR for MY_IRQ at runtime.
bryantaylor 0:eafc3fd41f75 356 * Without uVisor: Relocate the interrupt vector table to SRAM and set my_isr as
bryantaylor 0:eafc3fd41f75 357 the ISR for MY_IRQ.
bryantaylor 0:eafc3fd41f75 358 * With uVisor: Register MY_IRQ for the current box with my_isr as ISR. */
bryantaylor 0:eafc3fd41f75 359 NVIC_SetVector(MY_IRQ, &my_isr);
bryantaylor 0:eafc3fd41f75 360
bryantaylor 0:eafc3fd41f75 361 /* Change the IRQ state. */
bryantaylor 0:eafc3fd41f75 362 NVIC_SetPriority(MY_IRQ, 3);
bryantaylor 0:eafc3fd41f75 363 NVIC_EnableIRQ(MY_IRQ);
bryantaylor 0:eafc3fd41f75 364 ```
bryantaylor 0:eafc3fd41f75 365
bryantaylor 0:eafc3fd41f75 366 > **Note**: In this model a call to `NVIC_SetVector` must always happen before an IRQ state is changed. In platforms that don't relocate the interrupt vector table such a call might be originally absent and must be added to work with uVisor.
bryantaylor 0:eafc3fd41f75 367
bryantaylor 0:eafc3fd41f75 368 For more information on the uVisor APIs, checkout the [uVisor API documentation](API.md) document.
bryantaylor 0:eafc3fd41f75 369
bryantaylor 0:eafc3fd41f75 370 ### The *main box* ACLs
bryantaylor 0:eafc3fd41f75 371
bryantaylor 0:eafc3fd41f75 372 The code samples that we provide in this guide give you a ready-made list of ACLs for the main box. The list includes peripherals that we already know will be necessary to make the example app work, and it is specific to the NXP FRDM-K64F target.
bryantaylor 0:eafc3fd41f75 373
bryantaylor 0:eafc3fd41f75 374 This section shows how to discover the needed ACLs for the main box. You might need to follow these instructions in case you want to generate the ACLs list for a different target or a different app.
bryantaylor 0:eafc3fd41f75 375
bryantaylor 0:eafc3fd41f75 376 At the moment the uVisor does not provide a way to detect and list all the faulting ACLs for a given platform automatically. This is a planned feature that will be released in the future.
bryantaylor 0:eafc3fd41f75 377
bryantaylor 0:eafc3fd41f75 378 In order to generate the list of ACLs, use the code provided in the [Enable uVisor](#enable-uvisor) section. In this case, though, start with an empty ACLs list:
bryantaylor 0:eafc3fd41f75 379
bryantaylor 0:eafc3fd41f75 380 ```C
bryantaylor 0:eafc3fd41f75 381 static const UvisorBoxAclItem g_main_box_acls[] = {
bryantaylor 0:eafc3fd41f75 382 }
bryantaylor 0:eafc3fd41f75 383 ```
bryantaylor 0:eafc3fd41f75 384
bryantaylor 0:eafc3fd41f75 385 You now need to compile your application using uVisor in debug mode. This operation requires some more advanced steps, which are described in detail in the [Debugging uVisor on mbed OS](DEBUGGING.md) document. The main idea is that you compile the application in debug mode:
bryantaylor 0:eafc3fd41f75 386
bryantaylor 0:eafc3fd41f75 387 ```bash
bryantaylor 0:eafc3fd41f75 388 $ mbed compile -m K64F -t GCC_ARM -o "debug-info"
bryantaylor 0:eafc3fd41f75 389 ```
bryantaylor 0:eafc3fd41f75 390
bryantaylor 0:eafc3fd41f75 391 and then use a GDB-compatible interface to flash the device, enable semihosting, and access the uVisor debug messages. Please read the [Debugging uVisor on mbed OS](DEBUGGING.md) document for the detailed instructions.
bryantaylor 0:eafc3fd41f75 392
bryantaylor 0:eafc3fd41f75 393 Once the uVisor debug messages are enabled, you will see you application fail. The failure is due to the first missing ACL being hit by the main box code. The message will look like:
bryantaylor 0:eafc3fd41f75 394
bryantaylor 0:eafc3fd41f75 395 ```
bryantaylor 0:eafc3fd41f75 396 ***********************************************************
bryantaylor 0:eafc3fd41f75 397 BUS FAULT
bryantaylor 0:eafc3fd41f75 398 ***********************************************************
bryantaylor 0:eafc3fd41f75 399
bryantaylor 0:eafc3fd41f75 400 ...
bryantaylor 0:eafc3fd41f75 401
bryantaylor 0:eafc3fd41f75 402 * MEMORY MAP
bryantaylor 0:eafc3fd41f75 403 Address: 0x4004800C
bryantaylor 0:eafc3fd41f75 404 Region/Peripheral: SIM
bryantaylor 0:eafc3fd41f75 405 Base address: 0x40047000
bryantaylor 0:eafc3fd41f75 406 End address: 0x40048060
bryantaylor 0:eafc3fd41f75 407
bryantaylor 0:eafc3fd41f75 408 ...
bryantaylor 0:eafc3fd41f75 409 ```
bryantaylor 0:eafc3fd41f75 410
bryantaylor 0:eafc3fd41f75 411 Now that you know which peripheral is causing the fault (the `SIM` peripheral, in this example), you can add its entry to the ACLs list:
bryantaylor 0:eafc3fd41f75 412
bryantaylor 0:eafc3fd41f75 413
bryantaylor 0:eafc3fd41f75 414 ```C
bryantaylor 0:eafc3fd41f75 415 static const UvisorBoxAclItem g_main_box_acls[] = {
bryantaylor 0:eafc3fd41f75 416 {SIM, sizeof(*SIM), UVISOR_TACLDEF_PERIPH},
bryantaylor 0:eafc3fd41f75 417 };
bryantaylor 0:eafc3fd41f75 418 ```
bryantaylor 0:eafc3fd41f75 419
bryantaylor 0:eafc3fd41f75 420 > **Note**: If the fault debug screen does not show the name of the peripheral, you need to look it up in the target device reference manual.
bryantaylor 0:eafc3fd41f75 421
bryantaylor 0:eafc3fd41f75 422 For readability, do not use the hard-coded addresses of your peripherals, but rather use the symbols provided by the target CMSIS module.
bryantaylor 0:eafc3fd41f75 423
bryantaylor 0:eafc3fd41f75 424 Repeat the process multiple times until all ACLs have been added to the list. When no other ACL is needed any more, the system will run without hitting a uVisor fault.