mirror of https://github.com/ARMmbed/mbed-os.git
uVisor: Import RTX5-capable uVisor
Imported from 20170407_v7-M tag, commit e33f2739e961 "Make function in transition macro match target".pull/4294/head
parent
b793a3fb89
commit
6be9e47a07
|
|
@ -1,15 +1,16 @@
|
|||
592 Milosch Meriac
|
||||
544 Alessandro Angelino
|
||||
98 Jaeden Amero
|
||||
64 Niklas Hauser
|
||||
4 Irit Arkin
|
||||
547 Alessandro Angelino
|
||||
105 Jaeden Amero
|
||||
65 Niklas Hauser
|
||||
5 Irit Arkin
|
||||
3 Hugo Vincent
|
||||
3 JaredCJR
|
||||
3 Jim Huang
|
||||
3 JaredCJR
|
||||
2 tonyyanxuan
|
||||
2 Jan Jongboom
|
||||
2 Nathan Chong
|
||||
2 Vincenzo Frascino
|
||||
2 tonyyanxuan
|
||||
1 Aksel Skauge Mellbye
|
||||
1 Amanda Butler
|
||||
1 Aksel Skauge Mellbye
|
||||
1 AnotherButler
|
||||
1 ccli8
|
||||
|
|
|
|||
|
|
@ -1,28 +1,28 @@
|
|||
# Quick-Start Guide for uVisor on mbed OS
|
||||
# Getting started guide for uVisor on mbed OS
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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).
|
||||
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).
|
||||
|
||||
## Overview
|
||||
## Requirements
|
||||
|
||||
To get a basic `blinky` application running on mbed OS with uVisor enabled, you will need the following:
|
||||
To run the `blinky` application on mbed OS with uVisor enabled, you need:
|
||||
|
||||
* 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.
|
||||
* mbed-cli. You can run `pip install mbed-cli` to install it.
|
||||
- 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).
|
||||
- Git.
|
||||
- mbed CLI. Run `pip install mbed-cli` to install it.
|
||||
|
||||
For the remainder of this guide we will assume the following:
|
||||
The remainder of this guide assumes:
|
||||
|
||||
* 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 [GNU ARM Embedded Toolchain](https://launchpad.net/gcc-arm-embedded) toolchain.
|
||||
- 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 [GNU ARM Embedded Toolchain](https://launchpad.net/gcc-arm-embedded).
|
||||
|
||||
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:
|
||||
Create a new mbed application called `uvisor-example` by running the following commands:
|
||||
|
||||
```bash
|
||||
$ cd ~/code
|
||||
|
|
@ -30,13 +30,13 @@ $ 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.
|
||||
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.
|
||||
|
||||
Once the import process is finished, create a `source` folder:
|
||||
Once the import process finishes, create a `source` folder:
|
||||
```bash
|
||||
$ mkdir ~/code/uvisor-example/source
|
||||
```
|
||||
and place a new file `main.cpp` in it:
|
||||
Place a new file `main.cpp` in it:
|
||||
|
||||
```C
|
||||
/* ~/code/uvisor-example/source/main.cpp */
|
||||
|
|
@ -66,25 +66,18 @@ Compile the application:
|
|||
$ mbed compile -m K64F -t GCC_ARM
|
||||
```
|
||||
|
||||
The resulting binary will be located at:
|
||||
The resulting binary is located at:
|
||||
|
||||
```bash
|
||||
~/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.
|
||||
|
||||
---
|
||||
|
||||
In the next sections you will see:
|
||||
|
||||
* How to [enable uVisor](#enable-uvisor) on the `uvisor-example` app.
|
||||
* 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.
|
||||
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.
|
||||
|
||||
## Enable uVisor
|
||||
[Go to top](#overview)
|
||||
|
||||
To enable the uVisor on the app, add the following lines at the beginning of the `main.cpp` file:
|
||||
To enable the uVisor on the app, add these lines to the beginning of the `main.cpp` file:
|
||||
|
||||
```C
|
||||
/* ~/code/uvisor-example/source/main.cpp */
|
||||
|
|
@ -114,12 +107,12 @@ UVISOR_SET_MODE_ACL(UVISOR_ENABLED, g_public_box_acls);
|
|||
...
|
||||
```
|
||||
|
||||
In the code above we specified 2 elements:
|
||||
In the code above, we specified two elements:
|
||||
|
||||
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.
|
||||
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).
|
||||
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.
|
||||
|
||||
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:
|
||||
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:
|
||||
|
||||
```JSON
|
||||
{
|
||||
|
|
@ -136,57 +129,57 @@ Before compiling, we need to override the original `K64F` target to enable the u
|
|||
}
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
**Checkpoint**
|
||||
|
||||
Compile the application again. This time the `K64F` target will include the new features and labels we provided in `mbed_app.json`;
|
||||
Compile the application again. This time, the `K64F` target includes the new features and labels you provided in `mbed_app.json`;
|
||||
|
||||
```bash
|
||||
$ mbed compile -m K64F -t GCC_ARM
|
||||
```
|
||||
|
||||
The binary will be located at:
|
||||
The binary is located at:
|
||||
|
||||
```bash
|
||||
~/code/uvisor-example/BUILD/K64F/GCC_ARM/uvisor-example.bin
|
||||
```
|
||||
|
||||
Reflash 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 blinks 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 *public box*.
|
||||
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*.
|
||||
|
||||
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.
|
||||
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)
|
||||
|
||||
Now that uVisor is enabled, we can finally add a *secure box*.
|
||||
Now that uVisor is enabled, you 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.
|
||||
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.
|
||||
|
||||
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. 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. The `uvisor-example` app will show how to use these APIs.
|
||||
|
||||
### Configure the secure box
|
||||
|
||||
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_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.
|
||||
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.
|
||||
|
||||
We want the box to have exclusive access to the following resources:
|
||||
You want the box to have exclusive access to the following resources:
|
||||
|
||||
* 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).
|
||||
- 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). You want the button IRQ to reroute 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_button`.
|
||||
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`.
|
||||
|
||||
```C
|
||||
/* ~/code/uvisor-example/source/secure_box.cpp */
|
||||
|
|
@ -223,9 +216,9 @@ UVISOR_BOX_CONFIG(private_button, /* Name of 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 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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
```C
|
||||
/* ~/code/uvisor-example/source/secure_box.cpp */
|
||||
|
|
@ -291,12 +284,12 @@ static void private_button_main_thread(const void *)
|
|||
|
||||
A few things to note in the code above:
|
||||
|
||||
* 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.
|
||||
- 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`.
|
||||
- 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 runs in the context of the `private_button` box, the push-button IRQ belongs to that box. If you want to use the IRQ APIs directly, read the [NVIC APIs section](#the-nvic-apis) below.
|
||||
- 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.
|
||||
|
||||
> **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`).
|
||||
> **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`).
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -308,13 +301,14 @@ Compile the application again:
|
|||
$ mbed compile -m K64F -t GCC_ARM
|
||||
```
|
||||
|
||||
Reflash 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 blinks.
|
||||
|
||||
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 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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Expose public secure entry points to the secure box
|
||||
[Go to top](#overview)
|
||||
|
||||
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.
|
||||
|
||||
|
|
@ -352,7 +346,7 @@ static int get_index() {
|
|||
|
||||
UVISOR_BOX_RPC_GATEWAY_SYNC (private_button, secure_get_index, get_index, int, void);
|
||||
|
||||
#define PRIVATE_BUTTON_BUFFER_COUNT 8
|
||||
#define PRIVATE_BUTTON_BUFFER_COUNT 8
|
||||
```
|
||||
|
||||
### Listening for RPC messages
|
||||
|
|
@ -395,7 +389,7 @@ static void private_button_main_thread(const void *)
|
|||
|
||||
### 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:
|
||||
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:
|
||||
|
||||
```cpp
|
||||
/* ~/code/uvisor-example/source/main.cpp */
|
||||
|
|
@ -420,44 +414,18 @@ int main(void)
|
|||
|
||||
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)
|
||||
## The NVIC APIs
|
||||
|
||||
In this guide we showed you how to:
|
||||
|
||||
* Enable uVisor on an existing application.
|
||||
* 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.
|
||||
* 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 may find the following resources useful:
|
||||
|
||||
* [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 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 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.
|
||||
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.
|
||||
|
||||
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.
|
||||
* 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.
|
||||
- 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.
|
||||
- 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 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:
|
||||
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. The general use case is the following:
|
||||
|
||||
```C
|
||||
#define MY_IRQ 42
|
||||
|
|
@ -473,34 +441,22 @@ NVIC_SetPriority(MY_IRQ, 3);
|
|||
NVIC_EnableIRQ(MY_IRQ);
|
||||
```
|
||||
|
||||
> **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.
|
||||
> **Note**: In this model, a call to `NVIC_SetVector` must happen before an IRQ state changes. In platforms that don't relocate the interrupt vector table, such a call might be absent and must be added to work with uVisor.
|
||||
|
||||
For more information on the uVisor APIs, see the [uVisor API documentation](API.md) document.
|
||||
## The *public box* ACLs
|
||||
|
||||
### The *public box* ACLs
|
||||
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.
|
||||
|
||||
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 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:
|
||||
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:
|
||||
|
||||
```C
|
||||
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:
|
||||
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.
|
||||
|
||||
```bash
|
||||
$ 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.
|
||||
|
||||
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:
|
||||
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:
|
||||
|
||||
```
|
||||
***********************************************************
|
||||
|
|
@ -509,7 +465,7 @@ Once the uVisor debug messages are enabled, you will see your application fail.
|
|||
|
||||
...
|
||||
|
||||
* MEMORY MAP
|
||||
/* MEMORY MAP
|
||||
Address: 0x4004800C
|
||||
Region/Peripheral: SIM
|
||||
Base address: 0x40047000
|
||||
|
|
@ -518,8 +474,7 @@ Once the uVisor debug messages are enabled, you will see your application fail.
|
|||
...
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
Once you know which peripheral is causing the fault (the `SIM` peripheral, in this example), add its entry to the ACLs list:
|
||||
|
||||
```C
|
||||
static const UvisorBoxAclItem g_public_box_acls[] = {
|
||||
|
|
@ -527,8 +482,16 @@ static const UvisorBoxAclItem g_public_box_acls[] = {
|
|||
};
|
||||
```
|
||||
|
||||
> **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.
|
||||
> **Note**: If the fault debug screen does not show the name of the peripheral, 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 that the target CMSIS module provides.
|
||||
For readability, do not use the hard-coded addresses of your peripherals. Instead, 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.
|
||||
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.
|
||||
|
||||
## Additional resources
|
||||
[Go to top](#overview)
|
||||
|
||||
- [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).
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
v0.27.0
|
||||
20170407_v7-M
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@
|
|||
#ifndef __RTX_BOX_INDEX_H__
|
||||
#define __RTX_BOX_INDEX_H__
|
||||
|
||||
#include "cmsis_os.h"
|
||||
#include "cmsis_os2.h"
|
||||
#include "rtx_os.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -28,12 +29,14 @@ typedef struct
|
|||
/* The uvisor box index must be placed at the beginning */
|
||||
UvisorBoxIndex index;
|
||||
|
||||
/* Id of the mutex */
|
||||
osMutexId mutex_id;
|
||||
/* Pointer to the data of the mutex */
|
||||
osMutexDef_t mutex;
|
||||
/* ID of the mutex */
|
||||
osMutexId_t mutex_id;
|
||||
|
||||
/* Attribute of the mutex */
|
||||
osMutexAttr_t mutex_attr;
|
||||
|
||||
/* Internal data of the mutex */
|
||||
int32_t mutex_data[4];
|
||||
osRtxMutex_t mutex_data;
|
||||
} RtxBoxIndex;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -26,6 +26,12 @@
|
|||
UVISOR_EXTERN const uint32_t __uvisor_mode;
|
||||
UVISOR_EXTERN void const * const public_box_cfg_ptr;
|
||||
|
||||
typedef struct {
|
||||
void (*function)(void *);
|
||||
size_t priority;
|
||||
size_t stack_size;
|
||||
} uvisor_box_main_t;
|
||||
|
||||
#define UVISOR_DISABLED 0
|
||||
#define UVISOR_PERMISSIVE 1
|
||||
#define UVISOR_ENABLED 2
|
||||
|
|
@ -145,8 +151,12 @@ UVISOR_EXTERN void const * const public_box_cfg_ptr;
|
|||
* thread of your box will use for its body. If you don't want a main thread,
|
||||
* too bad: you have to have one. */
|
||||
#define UVISOR_BOX_MAIN(function, priority, stack_size) \
|
||||
static osThreadDef(function, priority, stack_size); \
|
||||
static const void * const __uvisor_box_lib_config = osThread(function);
|
||||
static const uvisor_box_main_t __uvisor_box_main = { \
|
||||
function, \
|
||||
priority, \
|
||||
stack_size, \
|
||||
}; \
|
||||
static const void * const __uvisor_box_lib_config = &__uvisor_box_main;
|
||||
|
||||
#define UVISOR_BOX_HEAPSIZE(heap_size) \
|
||||
static const uint32_t __uvisor_box_heapsize = heap_size;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ typedef struct uvisor_semaphore UvisorSemaphore;
|
|||
* These functions will be run by unprivileged code only. */
|
||||
typedef struct {
|
||||
void (*box_init)(void * lib_config);
|
||||
int (*semaphore_init)(UvisorSemaphore * semaphore, int32_t count);
|
||||
int (*semaphore_init)(UvisorSemaphore * semaphore, uint32_t initial_count, uint32_t max_count);
|
||||
int (*semaphore_pend)(UvisorSemaphore * semaphore, uint32_t timeout_ms);
|
||||
} UvisorLibHooks;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@
|
|||
|
||||
#include "api/inc/uvisor_semaphore_exports.h"
|
||||
|
||||
UVISOR_EXTERN int __uvisor_semaphore_init(UvisorSemaphore * semaphore, int32_t count);
|
||||
/* Initialize a semaphore with the specified initial count. This function is
|
||||
* not safe to call from interrupt context. */
|
||||
UVISOR_EXTERN int __uvisor_semaphore_init(UvisorSemaphore * semaphore, uint32_t initial_count, uint32_t max_count);
|
||||
|
||||
/* This function is not safe to call from interrupt context, even if the
|
||||
* timeout is zero. */
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#include "api/inc/uvisor_exports.h"
|
||||
|
||||
/* This must be big enough for all operating systems uVisor runs on. */
|
||||
#define UVISOR_SEMAPHORE_INTERNAL_SIZE (16)
|
||||
#define UVISOR_SEMAPHORE_INTERNAL_SIZE (36)
|
||||
|
||||
/* An opaque structure, that one knows the size of so that they can allocate
|
||||
* memory. */
|
||||
|
|
|
|||
|
|
@ -18,8 +18,9 @@
|
|||
#include "api/inc/pool_queue_exports.h"
|
||||
#include "api/inc/rpc_exports.h"
|
||||
#include "api/inc/uvisor_semaphore.h"
|
||||
#include "api/inc/box_config.h"
|
||||
#include "mbed_interface.h"
|
||||
#include "cmsis_os.h"
|
||||
#include "cmsis_os2.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
|
@ -27,9 +28,9 @@
|
|||
extern void SVC_Handler(void);
|
||||
extern void PendSV_Handler(void);
|
||||
extern void SysTick_Handler(void);
|
||||
extern uint32_t rt_suspend(void);
|
||||
extern uint32_t svcRtxKernelLock(void);
|
||||
|
||||
UVISOR_SET_PRIV_SYS_HOOKS(SVC_Handler, PendSV_Handler, SysTick_Handler, rt_suspend, __uvisor_semaphore_post);
|
||||
UVISOR_SET_PRIV_SYS_HOOKS(SVC_Handler, PendSV_Handler, SysTick_Handler, svcRtxKernelLock, __uvisor_semaphore_post);
|
||||
|
||||
extern RtxBoxIndex * const __uvisor_ps;
|
||||
|
||||
|
|
@ -56,15 +57,7 @@ void __uvisor_initialize_rpc_queues(void)
|
|||
/* Initialize all the result semaphores. */
|
||||
for (i = 0; i < UVISOR_RPC_OUTGOING_MESSAGE_SLOTS; i++) {
|
||||
UvisorSemaphore * semaphore = &rpc_outgoing_msg_queue->messages[i].semaphore;
|
||||
if (__uvisor_semaphore_init(semaphore, 1)) {
|
||||
uvisor_error(USER_NOT_ALLOWED);
|
||||
}
|
||||
|
||||
/* Semaphores are created with their value initialized to count. We
|
||||
* want the semaphore to start at zero. Decrement the semaphore, so it
|
||||
* starts with a value of zero. This will allow the first pend to
|
||||
* block. */
|
||||
if (__uvisor_semaphore_pend(semaphore, 0)) {
|
||||
if (__uvisor_semaphore_init(semaphore, 1, 0)) {
|
||||
uvisor_error(USER_NOT_ALLOWED);
|
||||
}
|
||||
}
|
||||
|
|
@ -102,15 +95,7 @@ void __uvisor_initialize_rpc_queues(void)
|
|||
/* Initialize all the function group semaphores. */
|
||||
for (i = 0; i < UVISOR_RPC_FN_GROUP_SLOTS; i++) {
|
||||
UvisorSemaphore * semaphore = &rpc_fn_group_queue->fn_groups[i].semaphore;
|
||||
if (__uvisor_semaphore_init(semaphore, 1)) {
|
||||
uvisor_error(USER_NOT_ALLOWED);
|
||||
}
|
||||
|
||||
/* Semaphores are created with their value initialized to count. We
|
||||
* want the semaphore to start at zero. Decrement the semaphore, so it
|
||||
* starts with a value of zero. This will allow the first pend to
|
||||
* block. */
|
||||
if (__uvisor_semaphore_pend(semaphore, 0)) {
|
||||
if (__uvisor_semaphore_init(semaphore, 1, 0)) {
|
||||
uvisor_error(USER_NOT_ALLOWED);
|
||||
}
|
||||
}
|
||||
|
|
@ -120,16 +105,14 @@ void __uvisor_initialize_rpc_queues(void)
|
|||
* create box main threads for the box. */
|
||||
void __uvisor_lib_box_init(void * lib_config)
|
||||
{
|
||||
osThreadId thread_id;
|
||||
osThreadDef_t * flash_thread_def = lib_config;
|
||||
osThreadDef_t thread_def;
|
||||
osThreadId_t thread_id;
|
||||
uvisor_box_main_t * box_main = lib_config;
|
||||
osThreadAttr_t thread_attr = { 0 };
|
||||
|
||||
__uvisor_initialize_rpc_queues();
|
||||
|
||||
/* Copy thread definition from flash to RAM. The thread definition is most
|
||||
* likely in flash, so we need to copy it to box-local RAM before we can
|
||||
* modify it. */
|
||||
memcpy(&thread_def, flash_thread_def, sizeof(thread_def));
|
||||
thread_attr.priority = box_main->priority;
|
||||
thread_attr.stack_size = box_main->stack_size;
|
||||
|
||||
/* Note that the box main thread stack is separate from the box stack. This
|
||||
* is because the thread must be created to use a different stack than the
|
||||
|
|
@ -138,17 +121,26 @@ void __uvisor_lib_box_init(void * lib_config)
|
|||
/* Allocate memory for the main thread from the process heap (which is
|
||||
* private to the process). This memory is never freed, even if the box's
|
||||
* main thread exits. */
|
||||
thread_def.stack_pointer = malloc_p(thread_def.stacksize);
|
||||
|
||||
if (thread_def.stack_pointer == NULL) {
|
||||
/* No process heap memory available */
|
||||
mbed_die();
|
||||
thread_attr.stack_mem = malloc_p(thread_attr.stack_size);
|
||||
if (thread_attr.stack_mem == NULL) {
|
||||
/* No process heap memory available for thread stack */
|
||||
uvisor_error(USER_NOT_ALLOWED);
|
||||
}
|
||||
|
||||
thread_id = osThreadCreate(&thread_def, NULL);
|
||||
/* Allocate memory for the main thread control block from the process heap
|
||||
* (which is private to the process). This memory is never freed, even if
|
||||
* the box's main thread exits. */
|
||||
thread_attr.cb_size = sizeof(osRtxThread_t);
|
||||
thread_attr.cb_mem = malloc_p(thread_attr.cb_size);
|
||||
if (thread_attr.cb_mem == NULL) {
|
||||
/* No process heap memory available for thread control block. */
|
||||
uvisor_error(USER_NOT_ALLOWED);
|
||||
}
|
||||
|
||||
thread_id = osThreadNew(box_main->function, NULL, &thread_attr);
|
||||
|
||||
if (thread_id == NULL) {
|
||||
/* Failed to create thread */
|
||||
mbed_die();
|
||||
uvisor_error(USER_NOT_ALLOWED);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "cmsis_os.h"
|
||||
#include "cmsis_os2.h"
|
||||
#include "uvisor-lib/uvisor-lib.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
|
@ -44,7 +44,7 @@ static int is_kernel_initialized()
|
|||
if (kernel_running) {
|
||||
return 1;
|
||||
}
|
||||
if (osKernelRunning()) {
|
||||
if (osKernelGetState() == osKernelRunning) {
|
||||
kernel_running = 1;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -64,10 +64,13 @@ static int init_allocator()
|
|||
}
|
||||
|
||||
if ((__uvisor_ps->mutex_id == NULL) && is_kernel_initialized()) {
|
||||
/* Point the mutex pointer to the data. */
|
||||
__uvisor_ps->mutex.mutex = &(__uvisor_ps->mutex_data);
|
||||
/* Point the mutex attr to the data. */
|
||||
__uvisor_ps->mutex_attr.attr_bits = 0; /* Non-recursive */
|
||||
__uvisor_ps->mutex_attr.cb_mem = &__uvisor_ps->mutex_data;
|
||||
__uvisor_ps->mutex_attr.cb_size = sizeof(__uvisor_ps->mutex_data);
|
||||
|
||||
/* Create mutex if not already done. */
|
||||
__uvisor_ps->mutex_id = osMutexCreate(&(__uvisor_ps->mutex));
|
||||
__uvisor_ps->mutex_id = osMutexNew(&__uvisor_ps->mutex_attr);
|
||||
/* Mutex failed to be created. */
|
||||
if (__uvisor_ps->mutex_id == NULL) {
|
||||
return -1;
|
||||
|
|
@ -80,7 +83,7 @@ static int init_allocator()
|
|||
/* Lock the mutex during initialization. */
|
||||
int kernel_initialized = is_kernel_initialized();
|
||||
if (kernel_initialized) {
|
||||
osMutexWait(__uvisor_ps->mutex_id, osWaitForever);
|
||||
osMutexAcquire(__uvisor_ps->mutex_id, osWaitForever);
|
||||
}
|
||||
/* Initialize the process heap. */
|
||||
SecureAllocator allocator = secure_allocator_create_with_pool(
|
||||
|
|
@ -123,7 +126,7 @@ static void * memory(void * ptr, size_t size, int heap, int operation)
|
|||
* the `rt_alloc_mem` and `rt_free_mem` functions in `uvisor_allocator.c`.
|
||||
* However, it is simpler to do it here for now. */
|
||||
if (mutexed) {
|
||||
osMutexWait(__uvisor_ps->mutex_id, osWaitForever);
|
||||
osMutexAcquire(__uvisor_ps->mutex_id, osWaitForever);
|
||||
}
|
||||
/* Perform the required operation. */
|
||||
switch(operation)
|
||||
|
|
|
|||
|
|
@ -15,8 +15,28 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "rt_TypeDef.h"
|
||||
#include "rt_Memory.h"
|
||||
#include "rtx_lib.h"
|
||||
|
||||
/* uVisor uses rtx_memory instead of implementing its own dynamic,
|
||||
* non-fixed-size memory allocator. To do this, uVisor creates multiple
|
||||
* non-fixed-size allocator pools (one per page) and allocates memory from
|
||||
* these pools. uVisor must manage the memory for these pools' control blocks,
|
||||
* so it must know the size of these control blocks. */
|
||||
|
||||
/* The following memory pool control block structs are copied from
|
||||
* rtx_memory.c, so that uVisor can manage the memory for these control blocks
|
||||
* within pages. */
|
||||
typedef struct mem_head_s {
|
||||
uint32_t size; // Memory Pool size
|
||||
uint32_t used; // Used Memory
|
||||
} mem_head_t;
|
||||
|
||||
// Memory Block Header structure
|
||||
typedef struct mem_block_s {
|
||||
struct mem_block_s *next; // Next Memory Block in list
|
||||
uint32_t info; // Info: length = <31:2>:'00', type = <1:0>
|
||||
} mem_block_t;
|
||||
/* End copy */
|
||||
|
||||
#include "secure_allocator.h"
|
||||
#include "uvisor-lib/uvisor-lib.h"
|
||||
|
|
@ -49,17 +69,29 @@ SecureAllocator secure_allocator_create_with_pool(
|
|||
/* Signal that this is non-page allocated memory. */
|
||||
allocator->table.page_size = bytes;
|
||||
allocator->table.page_count = 0;
|
||||
/* The internal rt_Memory MEMP structure must be placed AFTER table.page_origins[0] !!! */
|
||||
/* The internal rtx_Memory memory pool structure must be placed AFTER
|
||||
* table.page_origins[0] !!! */
|
||||
size_t offset = OFFSETOF(SecureAllocatorInternal, table.page_origins) + sizeof(((UvisorPageTable) {0}).page_origins);
|
||||
/* Create MEMP structure inside the memory. */
|
||||
if (rt_init_mem(mem + offset, bytes - offset)) {
|
||||
uintptr_t page_origin = (uintptr_t) mem + offset;
|
||||
|
||||
/* Align page_origin to a multiple of 8 (because RTX requries 8-byte
|
||||
* alignment of the origin). */
|
||||
page_origin = (page_origin + (0x8 - 1)) & -0x8;
|
||||
offset = page_origin - (uintptr_t) mem;
|
||||
size_t size = bytes - offset;
|
||||
/* Align size to a multiple of 8 (because RTX requires 8-byte alignment of
|
||||
* the size) */
|
||||
size &= -0x8;
|
||||
|
||||
/* Create pool allocator structure inside the memory. */
|
||||
if (!osRtxMemoryInit((void *) page_origin, size)) {
|
||||
/* Abort if failed. */
|
||||
DPRINTF("secure_allocator_create_with_pool: MEMP allocator creation failed\n\n");
|
||||
DPRINTF("secure_allocator_create_with_pool: pool allocator %p with offset %d creation failed (size %u bytes)\n\n", page_origin, offset, bytes - offset);
|
||||
return NULL;
|
||||
}
|
||||
/* Remember the MEMP pointer though. */
|
||||
allocator->table.page_origins[0] = mem + offset;
|
||||
DPRINTF("secure_allocator_create_with_pool: Created MEMP allocator %p with offset %d\n\n", mem + offset, offset);
|
||||
/* Remember the pool allocator pointer though. */
|
||||
allocator->table.page_origins[0] = (void *) page_origin;
|
||||
DPRINTF("secure_allocator_create_with_pool: Created pool allocator %p with offset %d\n\n", page_origin, offset);
|
||||
return allocator;
|
||||
}
|
||||
|
||||
|
|
@ -68,9 +100,9 @@ SecureAllocator secure_allocator_create_with_pages(
|
|||
size_t maximum_malloc_size)
|
||||
{
|
||||
const uint32_t page_size = uvisor_get_page_size();
|
||||
/* The rt_Memory allocator puts one MEMP structure at both the
|
||||
/* The rtx_Memory allocator puts one pool allocator structure at both the
|
||||
* beginning and end of the memory pool. */
|
||||
const size_t block_overhead = 2 * sizeof(MEMP);
|
||||
const size_t block_overhead = 2 * sizeof(mem_block_t);
|
||||
const size_t page_size_with_overhead = page_size + block_overhead;
|
||||
/* Calculate the integer part of required the page count. */
|
||||
size_t page_count = size / page_size_with_overhead;
|
||||
|
|
@ -110,11 +142,15 @@ SecureAllocator secure_allocator_create_with_pages(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize a MEMP structure in all pages. */
|
||||
/* Initialize a memory pool structure in all pages. */
|
||||
for(size_t ii = 0; ii < page_count; ii++) {
|
||||
/* Add each page as a pool. */
|
||||
rt_init_mem(allocator->table.page_origins[ii], page_size);
|
||||
DPRINTF("secure_allocator_create_with_pages: Created MEMP allocator %p with offset %d\n", allocator->table.page_origins[ii], 0);
|
||||
osStatus_t status = osRtxMemoryInit(allocator->table.page_origins[ii], page_size);
|
||||
if (status == osOK) {
|
||||
DPRINTF("secure_allocator_create_with_pages: Created memory pool allocator %p with offset %d page %u\n", allocator->table.page_origins[ii], 0, ii);
|
||||
} else {
|
||||
DPRINTF("secure_allocator_create_with_pages: Failed creating memory pool allocator %p with offset %d page %u\n", allocator->table.page_origins[ii], 0, ii);
|
||||
}
|
||||
}
|
||||
DPRINTF("\n");
|
||||
/* Aaaand across the line. */
|
||||
|
|
@ -124,7 +160,7 @@ SecureAllocator secure_allocator_create_with_pages(
|
|||
int secure_allocator_destroy(
|
||||
SecureAllocator allocator)
|
||||
{
|
||||
DPRINTF("secure_allocator_destroy: Destroying MEMP allocator at %p\n", table(allocator)->page_origins[0]);
|
||||
DPRINTF("secure_allocator_destroy: Destroying memory pool allocator at %p\n", table(allocator)->page_origins[0]);
|
||||
|
||||
/* Check if we are working on statically allocated memory. */
|
||||
SecureAllocatorInternal * alloc = (SecureAllocatorInternal * const) allocator;
|
||||
|
|
@ -153,7 +189,7 @@ void * secure_malloc(
|
|||
size_t index = 0;
|
||||
do {
|
||||
/* Search in this page. */
|
||||
void * mem = rt_alloc_mem(table(allocator)->page_origins[index], size);
|
||||
void * mem = osRtxMemoryAlloc(table(allocator)->page_origins[index], size, 0);
|
||||
/* Return if we found something. */
|
||||
if (mem) {
|
||||
DPRINTF("secure_malloc: Found %4uB in page %u at %p\n", size, index, mem);
|
||||
|
|
@ -187,7 +223,7 @@ void * secure_realloc(
|
|||
/* Passing NULL as ptr is legal, realloc acts as malloc then. */
|
||||
if (ptr) {
|
||||
/* Get the size of the ptr memory. */
|
||||
size_t size = ((MEMP *) ((uint32_t) ptr - sizeof(MEMP)))->len;
|
||||
size_t size = ((mem_block_t *) ((uint32_t) ptr - sizeof(mem_block_t)))->info & ~0x3;
|
||||
/* Copy the memory to the new location, min(new_size, size). */
|
||||
memcpy(new_ptr, ptr, new_size < size ? new_size : size);
|
||||
/* Free the previous memory. */
|
||||
|
|
@ -203,9 +239,9 @@ void secure_free(
|
|||
size_t index = 0;
|
||||
do {
|
||||
/* Search in this page. */
|
||||
int ret = rt_free_mem(table(allocator)->page_origins[index], ptr);
|
||||
int ret = osRtxMemoryFree(table(allocator)->page_origins[index], ptr);
|
||||
/* Return if free was successful. */
|
||||
if (ret == 0) {
|
||||
if (ret == 1) {
|
||||
DPRINTF("secure_free: Freed %p in page %u.\n", ptr, index);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,22 +51,27 @@ int uvisor_page_free(const UvisorPageTable *const table)
|
|||
}
|
||||
|
||||
/* Implement mutex for page allocator. */
|
||||
static osMutexId g_page_allocator_mutex_id = NULL;
|
||||
static int32_t g_page_allocator_mutex_data[4];
|
||||
static const osMutexDef_t g_page_allocator_mutex = { g_page_allocator_mutex_data };
|
||||
static osMutexId_t g_page_allocator_mutex_id = NULL;
|
||||
static osRtxMutex_t g_page_allocator_mutex_data;
|
||||
static osMutexDef_t g_page_allocator_mutex_attr = {
|
||||
.name = "",
|
||||
.attr_bits = 0, /* Non-recursive */
|
||||
.cb_mem = &g_page_allocator_mutex_data,
|
||||
.cb_size = sizeof(g_page_allocator_mutex_data)
|
||||
};
|
||||
|
||||
static void page_allocator_mutex_aquire()
|
||||
{
|
||||
if (g_page_allocator_mutex_id == NULL) {
|
||||
/* Create mutex if not already done. */
|
||||
g_page_allocator_mutex_id = osMutexCreate(&g_page_allocator_mutex);
|
||||
g_page_allocator_mutex_id = osMutexNew(&g_page_allocator_mutex_attr);
|
||||
if (g_page_allocator_mutex_id == NULL) {
|
||||
/* Mutex failed to be created. */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
osMutexWait(g_page_allocator_mutex_id, osWaitForever);
|
||||
osMutexAcquire(g_page_allocator_mutex_id, osWaitForever);
|
||||
}
|
||||
|
||||
/* Alignment of MPU regions is not required anymore, however we still require
|
||||
|
|
|
|||
|
|
@ -1,24 +1,27 @@
|
|||
#include "api/inc/uvisor_semaphore_exports.h"
|
||||
#include "api/inc/uvisor_exports.h"
|
||||
#include "api/inc/halt_exports.h"
|
||||
#include "cmsis_os.h"
|
||||
#include "cmsis_os2.h"
|
||||
#include "rtx_lib.h"
|
||||
#include <string.h>
|
||||
|
||||
typedef struct uvisor_semaphore_internal {
|
||||
osSemaphoreId id;
|
||||
osSemaphoreDef_t def;
|
||||
uint32_t data[2]; /* RTX expects this is 4-byte aligned */
|
||||
osSemaphoreId_t id;
|
||||
osSemaphoreAttr_t attr;
|
||||
osRtxSemaphore_t data;
|
||||
} UVISOR_ALIGN(4) uvisor_semaphore_internal_t;
|
||||
|
||||
UVISOR_STATIC_ASSERT(UVISOR_SEMAPHORE_INTERNAL_SIZE >= sizeof(UvisorSemaphore), semaphore_size_too_small);
|
||||
|
||||
int __uvisor_semaphore_init(UvisorSemaphore * s, int32_t count)
|
||||
int __uvisor_semaphore_init(UvisorSemaphore * s, uint32_t max_count, uint32_t initial_count)
|
||||
{
|
||||
uvisor_semaphore_internal_t * semaphore = (uvisor_semaphore_internal_t *) s;
|
||||
|
||||
memset(semaphore->data, 0, sizeof(semaphore->data));
|
||||
semaphore->def.semaphore = semaphore->data;
|
||||
semaphore->id = osSemaphoreCreate(&semaphore->def, count);
|
||||
memset(&semaphore->data, 0, sizeof(semaphore->data));
|
||||
memset(&semaphore->attr, 0, sizeof(semaphore->attr));
|
||||
semaphore->attr.cb_size = sizeof(semaphore->data);
|
||||
semaphore->attr.cb_mem = &semaphore->data;
|
||||
semaphore->id = osSemaphoreNew(max_count, initial_count, &semaphore->attr);
|
||||
|
||||
/* Error when semaphore->id is NULL */
|
||||
return semaphore->id == NULL ? UVISOR_ERROR_OUT_OF_STRUCTURES : 0;
|
||||
|
|
@ -28,14 +31,14 @@ int __uvisor_semaphore_pend(UvisorSemaphore * s, uint32_t timeout_ms)
|
|||
{
|
||||
uvisor_semaphore_internal_t * semaphore = (uvisor_semaphore_internal_t *) s;
|
||||
|
||||
int32_t num_available_tokens = osSemaphoreWait(semaphore->id, timeout_ms);
|
||||
osStatus_t status = osSemaphoreAcquire(semaphore->id, timeout_ms);
|
||||
|
||||
if (num_available_tokens == -1) {
|
||||
return UVISOR_ERROR_INVALID_PARAMETERS;
|
||||
}
|
||||
|
||||
if (num_available_tokens == 0) {
|
||||
if (status == osErrorTimeout) {
|
||||
return UVISOR_ERROR_TIMEOUT;
|
||||
} else if (status == osErrorParameter) {
|
||||
return UVISOR_ERROR_INVALID_PARAMETERS;
|
||||
} else if (status != osOK) {
|
||||
return -1; /* Other error */
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue