Merge pull request #3817 from AlessandroA/update_uvisor

Update uVisor to v0.27.0
pull/3840/head
Sam Grove 2017-02-24 14:04:26 -06:00 committed by GitHub
commit 262234db27
25 changed files with 346 additions and 218 deletions

View File

@ -53,7 +53,7 @@
* @param value[in] Value to write at the address location.
*/
#define SECURE_WRITE(address, value) \
uvisor_write(main, UVISOR_RGW_SHARED, address, value, UVISOR_RGW_OP_WRITE, 0xFFFFFFFFUL)
uvisor_write(public_box, UVISOR_RGW_SHARED, address, value, UVISOR_RGW_OP_WRITE, 0xFFFFFFFFUL)
/** Get the value at the target address.
*
@ -61,7 +61,7 @@
* @returns The value `*address`.
*/
#define SECURE_READ(address) \
uvisor_read(main, UVISOR_RGW_SHARED, address, UVISOR_RGW_OP_READ, 0xFFFFFFFFUL)
uvisor_read(public_box, UVISOR_RGW_SHARED, address, UVISOR_RGW_OP_READ, 0xFFFFFFFFUL)
/** Get the selected bits at the target address.
*
@ -70,7 +70,7 @@
* @returns The value `*address & mask`.
*/
#define SECURE_BITS_GET(address, mask) \
UVISOR_BITS_GET(main, UVISOR_RGW_SHARED, address, mask)
UVISOR_BITS_GET(public_box, UVISOR_RGW_SHARED, address, mask)
/** Check the selected bits at the target address.
*
@ -79,7 +79,7 @@
* @returns The value `((*address & mask) == mask)`.
*/
#define SECURE_BITS_CHECK(address, mask) \
UVISOR_BITS_CHECK(main, UVISOR_RGW_SHARED, address, mask)
UVISOR_BITS_CHECK(public_box, UVISOR_RGW_SHARED, address, mask)
/** Set the selected bits to 1 at the target address.
*
@ -88,7 +88,7 @@
* @param mask[in] Bits to select out of the target address
*/
#define SECURE_BITS_SET(address, mask) \
UVISOR_BITS_SET(main, UVISOR_RGW_SHARED, address, mask)
UVISOR_BITS_SET(public_box, UVISOR_RGW_SHARED, address, mask)
/** Clear the selected bits at the target address.
*
@ -97,7 +97,7 @@
* @param mask[in] Bits to select out of the target address
*/
#define SECURE_BITS_CLEAR(address, mask) \
UVISOR_BITS_CLEAR(main, UVISOR_RGW_SHARED, address, mask)
UVISOR_BITS_CLEAR(public_box, UVISOR_RGW_SHARED, address, mask)
/** Set the selected bits at the target address to the given value.
*
@ -108,7 +108,7 @@
* must be already shifted to the correct bit position
*/
#define SECURE_BITS_SET_VALUE(address, mask, value) \
UVISOR_BITS_SET_VALUE(main, UVISOR_RGW_SHARED, address, mask, value)
UVISOR_BITS_SET_VALUE(public_box, UVISOR_RGW_SHARED, address, mask, value)
/** Toggle the selected bits at the target address.
*
@ -117,7 +117,7 @@
* @param mask[in] Bits to select out of the target address
*/
#define SECURE_BITS_TOGGLE(address, mask) \
UVISOR_BITS_TOGGLE(main, UVISOR_RGW_SHARED, address, mask)
UVISOR_BITS_TOGGLE(public_box, UVISOR_RGW_SHARED, address, mask)
#else

View File

@ -1,13 +1,15 @@
588 Milosch Meriac
506 Alessandro Angelino
95 Jaeden Amero
61 Niklas Hauser
592 Milosch Meriac
544 Alessandro Angelino
98 Jaeden Amero
64 Niklas Hauser
4 Irit Arkin
3 Hugo Vincent
3 JaredCJR
3 Jim Huang
2 Jan Jongboom
2 Nathan Chong
2 Vincenzo Frascino
2 tonyyanxuan
1 Aksel Skauge Mellbye
1 Nathan Chong
1 Amanda Butler
1 ccli8

View File

@ -1,32 +1,33 @@
# Quick-Start Guide for uVisor on mbed OS
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.
This guide will help you get started with uVisor on mbed OS by showing you how to create a sample application for the NXP FRDM-K64F board.
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).
The uVisor provides sandboxed environments and resources protection for applications built for ARM Cortex-M3 and Cortex-M4 devices. 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).
## Overview
To get a basic `blinky` application running on mbed OS with uVisor enabled, you will need the following:
* 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).
* 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 is only partly complete. 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).
* git. It will be used to download the mbed codebase.
* The mbed command-line tools, mbed-cli. You can run `pip install mbed-cli` to install them.
* mbed-cli. You can run `pip install mbed-cli` to install it.
For the remainder of this guide we will assume the following:
* You are developing on a \*nix machine, in the `~/code` folder.
* 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.
* 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) toolchain.
The instructions provided can be easily generalized to the case of other targets on other host OSs.
You can use these instructions as guidelines in the case of other targets on other host OSs.
## Start with the `blinky` app
[Go to top](#overview)
To create a new mbed application called `uvisor-example` just run the following commands:
To create a new mbed application called `uvisor-example`, just run the following commands:
```bash
$ cd ~/code
$ mbed new uvisor-example
$ cd uvisor-example
```
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.
@ -41,7 +42,6 @@ and place a new file `main.cpp` in it:
/* ~/code/uvisor-example/source/main.cpp */
#include "mbed.h"
#include "rtos.h"
DigitalOut led(LED1);
@ -49,12 +49,12 @@ int main(void)
{
while (true) {
led = !led;
Thread::wait(500);
wait(0.5);
}
}
```
This simple application just blinks an LED from the main thread, which is created by default by the OS.
This application blinks an LED from the main thread, which the OS creates by default.
---
@ -69,10 +69,10 @@ $ mbed compile -m K64F -t GCC_ARM
The resulting binary will be located at:
```bash
~/code/uvisor-example/.build/K64F/GCC_ARM/uvisor-example.bin
~/code/uvisor-example/BUILD/K64F/GCC_ARM/uvisor-example.bin
```
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.
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.
---
@ -84,70 +84,59 @@ In the next sections you will see:
## Enable uVisor
[Go to top](#overview)
To enable the uVisor on the app, just add the following lines at the beginning of the `main.cpp` file:
To enable the uVisor on the app, add the following lines at the beginning of the `main.cpp` file:
```C
/* ~/code/uvisor-example/source/main.cpp */
#include "mbed.h"
#include "rtos.h"
#include "uvisor-lib/uvisor-lib.h"
/* Register privleged system hooks.
* This is a system-wide configuration and it is independent from the app, but
* for the moment it needs to be specified in the app. This will change in a
* later version: The configuration will be provided by the OS. */
extern "C" void SVC_Handler(void);
extern "C" void PendSV_Handler(void);
extern "C" void SysTick_Handler(void);
extern "C" uint32_t rt_suspend(void);
UVISOR_SET_PRIV_SYS_HOOKS(SVC_Handler, PendSV_Handler, SysTick_Handler, rt_suspend);
/* Main box Access Control Lists (ACLs). */
/* Public box Access Control Lists (ACLs). */
/* Note: These are specific to the NXP FRDM-K64F board. See the section below
* for more information. */
static const UvisorBoxAclItem g_main_box_acls[] = {
static const UvisorBoxAclItem g_public_box_acls[] = {
/* For the LED */
{SIM, sizeof(*SIM), UVISOR_TACLDEF_PERIPH},
{PORTB, sizeof(*PORTB), UVISOR_TACLDEF_PERIPH},
/* For messages printed on the serial port. */
/* For messages printed on the serial port */
{OSC, sizeof(*OSC), UVISOR_TACLDEF_PERIPH},
{MCG, sizeof(*MCG), UVISOR_TACLDEF_PERIPH},
{UART0, sizeof(*UART0), UVISOR_TACLDEF_PERIPH},
{PIT, sizeof(*PIT), UVISOR_TACLDEF_PERIPH},
};
/* Enable uVisor, using the ACLs we just created. */
UVISOR_SET_MODE_ACL(UVISOR_ENABLED, g_main_box_acls);
UVISOR_SET_MODE_ACL(UVISOR_ENABLED, g_public_box_acls);
/* Rest of the existing app code */
/* Rest of the existing code */
...
```
In the code above we specified 3 elements:
In the code above we specified 2 elements:
1. System-wide uVisor configurations: `UVISOR_SET_PRIV_SYS_HOOKS`. Application authors currently need to specify the privileged system hooks at the application level with this macro, but in the future the operating system will register the privileged system hooks on its own.
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.
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.
1. Public 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 public 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.
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 public box.
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:
```JSON
{
"target_overrides": {
"K64F": {
"*": {
"target.features_add": ["UVISOR"],
"target.extra_labels_add": ["UVISOR_SUPPORTED"]
}
},
"macros": [
"FEATURE_UVISOR",
"TARGET_UVISOR_SUPPORTED"
"FEATURE_UVISOR=1",
"TARGET_UVISOR_SUPPORTED=1"
]
}
```
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.
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, we need to define them manually.
---
@ -162,16 +151,16 @@ $ mbed compile -m K64F -t GCC_ARM
The binary will be located at:
```bash
~/code/uvisor-example/.build/K64F/GCC_ARM/uvisor-example.bin
~/code/uvisor-example/BUILD/K64F/GCC_ARM/uvisor-example.bin
```
Re-flash the device and press the reset button. The device LED should be blinking as in the previous case.
Reflash the device and press the reset button. The device LED should be blinking as in the previous case.
---
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*.
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 *public box*.
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.
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.
## Add a secure box
[Go to top](#overview)
@ -180,117 +169,134 @@ Now that uVisor is enabled, we can finally add a *secure box*.
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.
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.
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.
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.
Instead, we provide specific APIs to instruct the uVisor to protect a private resource. We will show how to use these APIs in the `uvisor-example` app.
### Configure the secure box
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.
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.
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.
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 2 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 is restarted. For debug purposes, the program prints the content of the buffer every time it is filled up.
We want the box to have exclusive access to the following resources:
* The timer and push-button peripherals (as specified by a peripheral ACL). Nobody else should be able to read the timer values.
* The push-button interrupt (as specified by an IRQ ACL). We want the button IRQ to be re-routed to our box-specific ISR.
* The buffer that holds the timer samples (as specified by a dynamic memory ACL).
* The static memory that holds information about the timer buffer (as specified by a static memory ACL).
* The push-button peripheral (as specified by a peripheral ACL). Nobody else should be able to access the push-button port.
* The push-button interrupt (as specified by an IRQ ACL). We want the button IRQ to be rerouted to our box-specific ISR.
* The private dynamically allocated buffer (as specified by a dynamic memory ACL).
* The private variables (as specified by a static memory ACL).
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`.
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_button`.
```C
/* ~/code/uvisor-example/source/secure_box.cpp */
#include "mbed.h"
#include "rtos.h"
#include "uvisor-lib/uvisor-lib.h"
/* Private static memory for the secure box */
typedef struct {
uint32_t * buffer;
int index;
} PrivateTimerStaticMemory;
uint32_t * buffer; /* Static private memory, pointing to dynamically allocated private memory */
uint32_t counter; /* Static private memory */
int index; /* Static private memory */
RawSerial * pc; /* Static private memory, pointing to dynamically allocated private memory */
} PrivateButtonStaticMemory;
/* ACLs list for the secure box: Timer (PIT). */
static const UvisorBoxAclItem g_private_timer_acls[] = {
{PIT, sizeof(*PIT), UVISOR_TACLDEF_PERIPH}
{PORTC, sizeof(*PORTC), UVISOR_TACLDEF_PERIPH},
static const UvisorBoxAclItem g_private_button_acls[] = {
{PORTC, sizeof(*PORTC), UVISOR_TACLDEF_PERIPH}, /* Private peripheral */
};
static void private_timer_main_thread(const void *);
static void private_button_main_thread(const void *);
/* Secure box configuration */
UVISOR_BOX_NAMESPACE(NULL); /* We won't specify a box namespace for this example. */
UVISOR_BOX_HEAPSIZE(4096); /* Heap size for the secure box */
UVISOR_BOX_MAIN(private_timer_main_thread, /* Main thread for the secure box */
UVISOR_BOX_MAIN(private_button_main_thread, /* Main thread for the secure box */
osPriorityNormal, /* Priority of the secure box's main thread */
1024); /* Stack size for the secure box's main thread */
UVISOR_BOX_CONFIG(private_timer, /* Name of the secure box */
g_private_timer_acls, /* ACLs list for the secure box */
UVISOR_BOX_CONFIG(private_button, /* Name of the secure box */
g_private_button_acls, /* ACLs list for the secure box */
1024, /* Stack size for the secure box */
PrivateTimerStaticMemory); /* Private static memory for the secure box. */
PrivateButtonStaticMemory); /* Private static memory for the secure box. */
```
### Create the secure box's main thread function
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.
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 whole program.
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.
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 is used to update the counter value every second.
```C
/* Number of timer samples we will use */
#define PRIVATE_TIMER_BUFFER_COUNT 256
/* ~/code/uvisor-example/source/secure_box.cpp */
/* For debug purposes: print the buffer values when the SW2 button is pressed. */
static void private_timer_button_on_press(void)
/* The previous code goes here. */
...
#define uvisor_ctx ((PrivateButtonStaticMemory *) __uvisor_ctx)
#define PRIVATE_BUTTON_BUFFER_COUNT 8
static void private_button_on_press(void)
{
for (int i = 0; i < PRIVATE_TIMER_BUFFER_COUNT; i++) {
printf("buffer[%03d] = %lu\r\n", i, uvisor_ctx->buffer[i]);
/* Store the thread count into the buffer and reset it. */
uvisor_ctx->buffer[uvisor_ctx->index] = uvisor_ctx->counter;
uvisor_ctx->counter = 0;
/* Update the index. Behave as a circular buffer. */
if (uvisor_ctx->index < PRIVATE_BUTTON_BUFFER_COUNT - 1) {
uvisor_ctx->index++;
} else {
uvisor_ctx->index = 0;
/* For debug purposes: Print the content of the buffer. */
uvisor_ctx->pc->printf("Thread count between button presses: ");
for (int i = 0; i < PRIVATE_BUTTON_BUFFER_COUNT; ++i) {
uvisor_ctx->pc->printf("%lu ", uvisor_ctx->buffer[i]);
}
uvisor_ctx->pc->printf("\r\n");
}
}
/* Main thread for the secure box */
static void private_timer_main_thread(const void *)
static void private_button_main_thread(const void *)
{
/* Allocate serial port to ensure that code in this secure box
* won't touch handle in the default security context when printing */
if (!(uvisor_ctx->pc = new RawSerial(USBTX, USBRX)))
return;
/* Create the buffer and cache its pointer to the private static memory. */
uvisor_ctx->buffer = (uint32_t *) malloc(PRIVATE_TIMER_BUFFER_COUNT * sizeof(uint32_t));
uvisor_ctx->buffer = (uint32_t *) malloc(PRIVATE_BUTTON_BUFFER_COUNT * sizeof(uint32_t));
if (uvisor_ctx->buffer == NULL) {
uvisor_ctx->pc->printf("ERROR: Failed to allocate memory for the button buffer\r\n");
mbed_die();
}
uvisor_ctx->index = 0;
uvisor_ctx->counter = 0;
/* Setup the push-button callback. */
InterruptIn button(SW2);
InterruptIn button(SW2); /* Private IRQ */
button.mode(PullUp);
button.fall(&private_timer_button_on_press);
/* Setup and start the timer. */
Timer timer;
timer.start();
button.fall(&private_button_on_press);
/* Increment the private counter every second. */
while (1) {
/* Store the timer value. */
uvisor_ctx->buffer[uvisor_ctx->index] = timer.read_us();
/* Update the index. Behave as a circular buffer. */
if (uvisor_ctx->index < PRIVATE_TIMER_BUFFER_COUNT - 1) {
uvisor_ctx->index++;
} else {
uvisor_ctx->index = 0;
}
uvisor_ctx->counter++;
wait(1.0);
}
}
```
A few things to note in the code above:
* 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`.
* The content of the private memory `PrivateTimerStaticMemory` can be accessed using the `PrivateTimerStaticMemory * uvisor_ctx` pointer, which is maintained by uVisor.
* 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.
* 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.
* If code is running in the context of `private_button`, then any object instantiated inside that code will belong 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`.
* 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.
* The `InterruptIn` object triggers the registration of an interrupt slot. Because that code is run in the context of the `private_button` 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.
* Even if the `private_button_on_press` function runs in the context of `private_button`, we 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.
> **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`).
> **Warning**: Instantiating an object in the `secure_box.cpp` global scope will automatically map 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`).
---
@ -302,15 +308,117 @@ Compile the application again:
$ mbed compile -m K64F -t GCC_ARM
```
Re-flash the device, and press the reset button. The device LED should be blinking as in the previous case.
Reflash the device, and press the reset button. The device LED should be blinking as in the previous case.
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.
If you don't see the LED blinking, it means that the application halted somewhere, probably because uVisor captured a fault. You can set up 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.
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.
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_button_on_press` function will be executed, 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.
### Expose public secure entry points to the secure box
## Expose public secure entry points to the secure box
Coming soon.
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 the arguments and return values are automatically serialized using an RPC protocol to ensure no private memory can be leaked to external boxes.
You can define a public secure entry point to retrieve the index value from the secure box. This index value is increased every time the `SW2` button is pressed.
### Defining a secure entry point
Create a new source file, `~/code/uvisor-example/source/secure_box.h`. In here we will define the functions that can be called through RPC.
```cpp
/* ~/code/uvisor-example/source/secure_box.h */
#ifndef SECURE_BOX_H_
#define SECURE_BOX_H_
#include "uvisor-lib/uvisor-lib.h"
UVISOR_EXTERN int (*secure_get_index)(void);
#endif
```
### Implementing a secure entry point
Now that you have defined the secure entry point, you can map the entry point to a function running in the secure box. This is done 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:
```cpp
/* ~/code/uvisor-example/source/secure_box.cpp */
/* Function called through RPC */
static int get_index() {
/* Access to private memory here */
return uvisor_ctx->index;
}
UVISOR_BOX_RPC_GATEWAY_SYNC (private_button, secure_get_index, get_index, int, void);
#define PRIVATE_BUTTON_BUFFER_COUNT 8
```
### Listening for RPC messages
To receive RPC messages you will 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:
```cpp
/* ~/code/uvisor-example/source/secure_box.cpp */
static void listen_for_rpc() {
/* List of functions to wait for */
static const TFN_Ptr my_fn_array[] = {
(TFN_Ptr) get_index
};
while (1) {
int caller_id;
int status = rpc_fncall_waitfor(my_fn_array, 1, &caller_id, UVISOR_WAIT_FOREVER);
if (status) {
uvisor_error(USER_NOT_ALLOWED);
}
}
}
/* Main thread for the secure box */
static void private_button_main_thread(const void *)
{
/* allocate serial port to ensure that code in this secure box
* won't touch handle in the default security context when printing */
if (!(uvisor_ctx->pc = new RawSerial(USBTX, USBRX)))
return;
/* Start listening for RPC messages in a separate thread */
Thread rpc_thread(osPriorityNormal, 1024);
rpc_thread.start(&listen_for_rpc);
/* ... Rest of the private_button_main_thread function ... */
```
### Calling the public secure entry point
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 main box. In `~/code/uvisor-example/source/main.cpp`, first include the header file for the secure box:
```cpp
/* ~/code/uvisor-example/source/main.cpp */
#include "secure-box.h"
```
And then replace the `main` function with:
```cpp
/* ~/code/uvisor-example/source/main.cpp */
int main(void)
{
while (true) {
led = !led;
printf("Secure index is %d\r\n", secure_get_index());
Thread::wait(500);
}
}
```
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 be increased.
## Wrap-up
[Go to top](#overview)
@ -321,34 +429,35 @@ In this guide we showed you how to:
* Add a secure box to your application.
* Protect static and dynamic memories in a secure box.
* Gain exclusive access to a peripheral and an IRQ in a secure box.
* (Coming soon) Expose public secure entry points to a secure box.
* Expose public secure entry points to a secure box.
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:
You can now modify the example or create a new one to protect your resources into a secure box. You may find the following resources useful:
* [uVisor API documentation](API.md)
* [Debugging uVisor on mbed OS](DEBUGGING.md)
* [uVisor API documentation](API.md).
* [Debugging uVisor on mbed OS](DEBUGGING.md).
If you found any bug or inconsistency in this guide, please [raise an issue](https://github.com/ARMmbed/uvisor/issues/new).
## Appendix
[Go to top](#overview)
This section contains additional information that you might find useful when setting up a secure box.
This section contains additional information that you may find useful when setting up a secure box.
### The NVIC APIs
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.
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.
In addition, the CMSIS header files 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.
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:
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:
* The uVisor owns the interrupt vector table.
* All ISRs are relocated to SRAM.
* 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.
* The first call to any NVIC API will register the IRQ for exclusive use with the active box. IRQs cannot be unregistered.
* 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 first.
* An IRQ that belongs to a box can only be modified when that box context is active.
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:
Although this behaviour is different from the original NVIC one, it is backward compatible. This means that legacy code (like a device HAL) will still work after uVisor is enabled. The general use case is the following:
```C
#define MY_IRQ 42
@ -364,34 +473,34 @@ NVIC_SetPriority(MY_IRQ, 3);
NVIC_EnableIRQ(MY_IRQ);
```
> **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.
> **Note**: When enabling the IRQ before setting the vector, uVisor uses the handler specified in the original vector table. This mirrors the NVIC hardware behavior.
For more information on the uVisor APIs, checkout the [uVisor API documentation](API.md) document.
For more information on the uVisor APIs, see the [uVisor API documentation](API.md) document.
### The *main box* ACLs
### The *public box* ACLs
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.
The code samples that we provide in this guide give you a ready-made list of ACLs for the public 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.
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.
This section shows how to discover the needed ACLs for the public 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.
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.
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:
```C
static const UvisorBoxAclItem g_main_box_acls[] = {
static const UvisorBoxAclItem g_public_box_acls[] = {
}
```
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:
```bash
$ mbed compile -m K64F -t GCC_ARM -o "debug-info"
$ mbed compile -m K64F -t GCC_ARM --profile mbed-os/tools/profiles/debug.json
```
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.
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.
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:
Once the uVisor debug messages are enabled, you will see your application fail. The failure is due to the first missing ACL being hit by the public box code. The message will look like:
```
***********************************************************
@ -413,13 +522,13 @@ Now that you know which peripheral is causing the fault (the `SIM` peripheral, i
```C
static const UvisorBoxAclItem g_main_box_acls[] = {
static const UvisorBoxAclItem g_public_box_acls[] = {
{SIM, sizeof(*SIM), UVISOR_TACLDEF_PERIPH},
};
```
> **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.
For readability, do not use the hard-coded addresses of your peripherals, but rather use the symbols provided by the target CMSIS module.
For readability, do not use the hard-coded addresses of your peripherals, but rather use the symbols that the target CMSIS module provides.
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.

View File

@ -1 +1 @@
v0.26.2
v0.27.0

View File

@ -45,6 +45,10 @@ TARGET_LIST_DIR_DST:=$(addprefix $(TARGET_SUPPORTED)/,$(TARGET_LIST))
TARGET_LIST_RELEASE:=$(addsuffix /release,$(TARGET_LIST_DIR_DST))
TARGET_LIST_DEBUG:=$(addsuffix /debug,$(TARGET_LIST_DIR_DST))
# mbed OS paths
MBED_OS_ROOT:=../../..
MBED_OS_CMSIS:=$(MBED_OS_ROOT)/cmsis
.PHONY: all deploy rsync publish uvisor uvisor-compile clean cache update
all: uvisor
@ -75,6 +79,10 @@ rsync:
cp $(UVISOR_DIR)/core/system/inc/page_allocator_config.h $(TARGET_LIB_SRC)/page_allocator_config.h
rsync -a --delete $(UVISOR_API)/rtx/src/ $(TARGET_LIB_SRC)/rtx
#
# Copying the secure API header file...
# Note: This will not be needed when we upstream the file to CMSIS.
cp $(UVISOR_DIR)/core/cmsis/inc/core_cmSecureAccess.h $(MBED_OS_CMSIS)/
#
# Copying the documentation...
cp $(UVISOR_DIR)/docs/api/QUICKSTART.md $(TARGET_PREFIX)/README.md
#

View File

@ -18,7 +18,6 @@
#define __RTX_BOX_INDEX_H__
#include "cmsis_os.h"
#include "api/inc/vmpu_exports.h"
#ifdef __cplusplus
extern "C" {

View File

@ -24,7 +24,7 @@
#include <stdint.h>
UVISOR_EXTERN const uint32_t __uvisor_mode;
UVISOR_EXTERN void const * const main_cfg_ptr;
UVISOR_EXTERN void const * const public_box_cfg_ptr;
#define UVISOR_DISABLED 0
#define UVISOR_PERMISSIVE 1
@ -41,32 +41,30 @@ UVISOR_EXTERN void const * const main_cfg_ptr;
\
UVISOR_EXTERN const uint32_t __uvisor_mode = (mode); \
\
static const __attribute__((section(".keep.uvisor.cfgtbl"), aligned(4))) UvisorBoxConfig main_cfg = { \
static const __attribute__((section(".keep.uvisor.cfgtbl"), aligned(4))) UvisorBoxConfig public_box_cfg = { \
UVISOR_BOX_MAGIC, \
UVISOR_BOX_VERSION, \
0, \
0, \
sizeof(RtxBoxIndex), \
{ \
sizeof(RtxBoxIndex), \
0, \
sizeof(uvisor_rpc_t), \
0, \
sizeof(uvisor_rpc_outgoing_message_queue_t), \
sizeof(uvisor_rpc_incoming_message_queue_t), \
sizeof(uvisor_rpc_fn_group_queue_t), \
}, \
0, \
NULL, \
NULL, \
acl_list, \
acl_list_count \
}; \
\
UVISOR_EXTERN const __attribute__((section(".keep.uvisor.cfgtbl_ptr_first"), aligned(4))) void * const main_cfg_ptr = &main_cfg;
UVISOR_EXTERN const __attribute__((section(".keep.uvisor.cfgtbl_ptr_first"), aligned(4))) void * const public_box_cfg_ptr = &public_box_cfg;
/* Creates a global page heap with at least `minimum_number_of_pages` each of size `page_size` in bytes.
* The total page heap size is at least `minimum_number_of_pages * page_size`. */
#define UVISOR_SET_PAGE_HEAP(page_size, minimum_number_of_pages) \
const uint32_t __uvisor_page_size = (page_size); \
uint8_t __attribute__((section(".keep.uvisor.page_heap"))) \
main_page_heap_reserved[ (page_size) * (minimum_number_of_pages) ]
public_page_heap_reserved[ (page_size) * (minimum_number_of_pages) ]
/* this macro selects an overloaded macro (variable number of arguments) */
@ -92,15 +90,13 @@ UVISOR_EXTERN void const * const main_cfg_ptr;
static const __attribute__((section(".keep.uvisor.cfgtbl"), aligned(4))) UvisorBoxConfig box_name ## _cfg = { \
UVISOR_BOX_MAGIC, \
UVISOR_BOX_VERSION, \
UVISOR_MIN_STACK(stack_size), \
__uvisor_box_heapsize, \
sizeof(RtxBoxIndex), \
{ \
sizeof(RtxBoxIndex), \
context_size, \
sizeof(uvisor_rpc_outgoing_message_queue_t), \
sizeof(uvisor_rpc_incoming_message_queue_t), \
sizeof(uvisor_rpc_fn_group_queue_t), \
sizeof(uvisor_rpc_t), \
__uvisor_box_heapsize, \
}, \
UVISOR_MIN_STACK(stack_size), \
__uvisor_box_lib_config, \
__uvisor_box_namespace, \
acl_list, \
@ -155,6 +151,6 @@ UVISOR_EXTERN void const * const main_cfg_ptr;
#define UVISOR_BOX_HEAPSIZE(heap_size) \
static const uint32_t __uvisor_box_heapsize = heap_size;
#define uvisor_ctx (*__uvisor_ps)
#define __uvisor_ctx (((UvisorBoxIndex *) __uvisor_ps)->bss.address_of.context)
#endif /* __UVISOR_API_BOX_CONFIG_H__ */

View File

@ -20,6 +20,7 @@
#include "api/inc/pool_queue_exports.h"
#include "api/inc/uvisor_semaphore_exports.h"
#include "api/inc/rpc_gateway_exports.h"
#include "api/inc/vmpu_exports.h"
typedef uint32_t (*TFN_Ptr)(uint32_t, uint32_t, uint32_t, uint32_t);
@ -137,4 +138,23 @@ typedef UVISOR_RPC_OUTGOING_MESSAGE_TYPE(UVISOR_RPC_OUTGOING_MESSAGE_SLOTS) uvis
typedef UVISOR_RPC_INCOMING_MESSAGE_TYPE(UVISOR_RPC_INCOMING_MESSAGE_SLOTS) uvisor_rpc_incoming_message_queue_t;
typedef UVISOR_RPC_FN_GROUP_TYPE(UVISOR_RPC_FN_GROUP_SLOTS) uvisor_rpc_fn_group_queue_t;
typedef struct uvisor_rpc_t {
/* Outgoing message queue */
uvisor_rpc_outgoing_message_queue_t outgoing_message_queue;
/* Incoming message queue */
uvisor_rpc_incoming_message_queue_t incoming_message_queue;
/* Function group queue */
uvisor_rpc_fn_group_queue_t fn_group_queue;
/* Counter to avoid waiting on the same RPC result twice by accident. */
uint32_t result_counter;
} uvisor_rpc_t;
static inline uvisor_rpc_t * uvisor_rpc(UvisorBoxIndex * const index)
{
return (uvisor_rpc_t *) index->bss.address_of.rpc;
}
#endif

View File

@ -42,8 +42,8 @@ UVISOR_EXTERN const uint32_t __uvisor_mode;
#define UVISOR_SET_MODE_ACL_COUNT(mode, acl_list, acl_list_count) \
UVISOR_EXTERN const uint32_t __uvisor_mode = UVISOR_DISABLED; \
static const void *main_acl = acl_list; \
extern const __attribute__((section(".keep.uvisor.cfgtbl_ptr_first"), aligned(4))) void * const main_cfg_ptr = &main_acl;
static const void *public_box_acl = acl_list; \
extern const __attribute__((section(".keep.uvisor.cfgtbl_ptr_first"), aligned(4))) void * const public_box_cfg_ptr = &public_box_acl;
#define __UVISOR_BOX_CONFIG_NOCONTEXT(box_name, acl_list, stack_size) \
static const void *box_acl_ ## box_name = acl_list; \

View File

@ -19,7 +19,6 @@
#include "api/inc/uvisor_exports.h"
#include "api/inc/pool_queue_exports.h"
#include "api/inc/rpc_exports.h"
#include <stdint.h>
/* The maximum box namespace length is 37 so that it is exactly big enough for
@ -27,6 +26,9 @@
* terminating NULL. */
#define UVISOR_MAX_BOX_NAMESPACE_LENGTH 37
/** Invalid box id for use in marking objects with invalid ownership. */
#define UVISOR_BOX_ID_INVALID ((uint8_t) -1)
/* supervisor user access modes */
#define UVISOR_TACL_UEXECUTE 0x0001UL
#define UVISOR_TACL_UWRITE 0x0002UL
@ -150,61 +152,63 @@ typedef struct {
UvisorBoxAcl acl;
} UVISOR_PACKED UvisorBoxAclItem;
/* This struct contains all the BSS sections that uVisor allocates for a secure
* box. It can be used to keep the sizes of the sections or their pointers. */
typedef struct uvisor_bss_sections_t {
uint32_t index;
uint32_t context;
uint32_t rpc;
uint32_t heap;
} UVISOR_PACKED UvisorBssSections;
/* The number of per-box BSS sections. */
#define UVISOR_BSS_SECTIONS_COUNT (sizeof(UvisorBssSections) / sizeof(uint32_t))
/* Compile-time per-box configuration table
* Each box has one of this table in flash. Every other data structure that this
* table might point to must be in flash as well. The uVisor core must check the
* sanity of the table before trusting its fields. */
typedef struct {
/* Contains user provided size of box context without guards of buffers. */
uint32_t context_size;
/* Contains total memory used by the RPC queues (incl. management and pool). */
uint32_t rpc_outgoing_message_size;
uint32_t rpc_incoming_message_size;
uint32_t rpc_fn_group_size;
} UVISOR_PACKED uvisor_sizes_t;
/* The number of additional bss sections per box bss.
* The size of each section is stored in the box config, and uVisor core will
* iterate over the box bss, split it into sections as defined by the size table
* and assign a pointer to beginning of that section into the box index pointer table.
*/
#define UVISOR_BOX_INDEX_SIZE_COUNT (sizeof(uvisor_sizes_t) / sizeof(uint32_t))
typedef struct {
uint32_t magic;
uint32_t version;
/* Box stack size includes stack guards and rounding buffer. */
uint32_t stack_size;
/* Contains user provided size of box heap without guards of buffers. */
uint32_t heap_size;
/* Contains the size of the index (must be at least sizeof(UvisorBoxIndex)). */
uint32_t index_size;
const uint32_t magic;
const uint32_t version;
/* The UvisorBssSections struct is union-ed with a size_t array to allow for
* loops to scan the sizes of all the BSS sections and allocate the
* necessary space for each of them. */
union {
uint32_t bss_size[UVISOR_BOX_INDEX_SIZE_COUNT];
uvisor_sizes_t sizes;
};
size_t sizes[UVISOR_BSS_SECTIONS_COUNT];
UvisorBssSections size_of;
} const bss;
/* Contains the size of the secure box static stack. */
/* Note: This does not include guards. */
/* Note: It is kept separately from the BSS sections as it's implementation
* specific where the stack sits with respect to the BSS. */
const uint32_t stack_size;
/* Opaque-to-uVisor data that potentially contains uvisor-lib-specific or
* OS-specific per-box configuration */
const void * const lib_config;
const char * box_namespace;
const char * const box_namespace;
const UvisorBoxAclItem * const acl_list;
uint32_t acl_count;
const uint32_t acl_count;
} UVISOR_PACKED UvisorBoxConfig;
/* Enumeration-time per-box index table
* Each box has one of this table in SRAM. The index tables are initialized at
* box enumeration time and are then managed by the secure boxes themselves. */
/* Note: Each box is able to read and write its own version of this table. Do
* not trust these pointers in the uVisor core. */
typedef struct {
/* The UvisorSramPointers struct is union-ed with a void * array to allow
* for loops to scan the pointers to all the SRAM sections and access them
* individually. */
union {
void * bss_ptr[UVISOR_BOX_INDEX_SIZE_COUNT];
struct {
/* Pointer to the user context */
void * ctx;
/* Pointer to the RPC queues */
uvisor_rpc_outgoing_message_queue_t * rpc_outgoing_message_queue;
uvisor_rpc_incoming_message_queue_t * rpc_incoming_message_queue;
uvisor_rpc_fn_group_queue_t * rpc_fn_group_queue;
};
};
/* Pointer to the box heap */
void * box_heap;
void * pointers[UVISOR_BSS_SECTIONS_COUNT];
UvisorBssSections address_of;
} bss;
/* Size of the box heap */
uint32_t box_heap_size;
/* Pointer to the currently active heap.
@ -212,10 +216,6 @@ typedef struct {
* box heap needs to be initialized before use! */
void * active_heap;
/* Counter that helps to avoid waiting on the same RPC message result twice
* by accident. */
uint32_t rpc_result_counter;
/* Box ID */
int box_id_self;

View File

@ -36,6 +36,7 @@
* SVC call, which automagically serializes access to it. */
#define UVISOR_PAGE_ALLOCATOR_MUTEX_AQUIRE {}
#define UVISOR_PAGE_ALLOCATOR_MUTEX_RELEASE {}
#define UVISOR_PAGE_UNUSED UVISOR_BOX_ID_INVALID
#endif /* defined(UVISOR_PRESENT) && (UVISOR_PRESENT == 1) */
@ -73,12 +74,6 @@ uint8_t page_allocator_get_page_from_address(uint32_t address)
void page_allocator_init(void * const heap_start, void * const heap_end, const uint32_t * const page_size)
{
/* Make sure the UVISOR_PAGE_UNUSED is definitely NOT a valid box id. */
if (vmpu_is_box_id_valid(UVISOR_PAGE_UNUSED)) {
HALT_ERROR(SANITY_CHECK_FAILED,
"UVISOR_PAGE_UNUSED (%u) must not be a valid box id!\n",
UVISOR_PAGE_UNUSED);
}
if (!page_size || !vmpu_public_flash_addr((uint32_t) page_size)) {
HALT_ERROR(SANITY_CHECK_FAILED,
"Page size pointer (0x%08x) is not in flash memory.\n",

View File

@ -44,8 +44,6 @@
/* The page box_id is the box id which is 8-bit large. */
typedef uint8_t page_owner_t;
/* Define a unused value for the page table. */
#define UVISOR_PAGE_UNUSED ((page_owner_t) (-1))
/* Contains the total number of available pages. */
extern uint8_t g_page_count_total;
/* Contains the shift of the page owner mask. */

View File

@ -39,9 +39,9 @@ void __uvisor_initialize_rpc_queues(void)
uvisor_pool_slot_t i;
uvisor_rpc_outgoing_message_queue_t * rpc_outgoing_msg_queue = index->rpc_outgoing_message_queue;
uvisor_rpc_incoming_message_queue_t * rpc_incoming_msg_queue = index->rpc_incoming_message_queue;
uvisor_rpc_fn_group_queue_t * rpc_fn_group_queue = index->rpc_fn_group_queue;
uvisor_rpc_outgoing_message_queue_t * rpc_outgoing_msg_queue = &(uvisor_rpc(index)->outgoing_message_queue);
uvisor_rpc_incoming_message_queue_t * rpc_incoming_msg_queue = &(uvisor_rpc(index)->incoming_message_queue);
uvisor_rpc_fn_group_queue_t * rpc_fn_group_queue = &(uvisor_rpc(index)->fn_group_queue);
/* Initialize the outgoing RPC message queue. */
if (uvisor_pool_queue_init(&rpc_outgoing_msg_queue->queue,

View File

@ -76,7 +76,7 @@ static int init_allocator()
if (__uvisor_ps->index.active_heap == NULL) {
/* We need to initialize the process heap. */
if (__uvisor_ps->index.box_heap != NULL) {
if ((void *) __uvisor_ps->index.bss.address_of.heap != NULL) {
/* Lock the mutex during initialization. */
int kernel_initialized = is_kernel_initialized();
if (kernel_initialized) {
@ -84,7 +84,7 @@ static int init_allocator()
}
/* Initialize the process heap. */
SecureAllocator allocator = secure_allocator_create_with_pool(
__uvisor_ps->index.box_heap,
(void *) __uvisor_ps->index.bss.address_of.heap,
__uvisor_ps->index.box_heap_size);
/* Set the allocator. */
ret = allocator ? 0 : -1;
@ -112,9 +112,10 @@ static void * memory(void * ptr, size_t size, int heap, int operation)
}
/* Check if we need to aquire the mutex. */
int mutexed = is_kernel_initialized() &&
((heap == HEAP_PROCESS) || __uvisor_ps->index.box_heap == __uvisor_ps->index.active_heap);
((heap == HEAP_PROCESS) ||
(void *) __uvisor_ps->index.bss.address_of.heap == __uvisor_ps->index.active_heap);
void * allocator = (heap == HEAP_PROCESS) ?
(__uvisor_ps->index.box_heap) :
((void *) __uvisor_ps->index.bss.address_of.heap) :
(__uvisor_ps->index.active_heap);
/* Aquire the mutex if required.

View File

@ -59,18 +59,18 @@ static void box_index_init(void *box_bss, uint32_t heap_size)
void secure_malloc_init(void)
{
/* get the main heap size from the linker script */
/* get the public heap size from the linker script */
uint32_t heap_size = ((uint32_t) __HeapLimit -
(uint32_t) __end__);
/* Main heap size is aligned to page boundaries n*UVISOR_PAGE_SIZE */
/* Public heap size is aligned to page boundaries n*UVISOR_PAGE_SIZE */
uint32_t heap_start = (uint32_t) __StackLimit - heap_size;
/* align the start address of the main heap to a page boundary */
/* align the start address of the public heap to a page boundary */
heap_start &= ~(UVISOR_PAGE_SIZE - 1);
/* adjust the heap size to the new heap start address */
heap_size = (uint32_t) __StackLimit - heap_start;
/* page heap now extends from the previous main heap start address
* to the new main heap start address */
/* page heap now extends from the previous public heap start address
* to the new public heap start address */
extern uint32_t __uvisor_page_size;
page_allocator_init(__end__, (void *) heap_start, &__uvisor_page_size);
box_index_init((void *) heap_start, heap_size);