From 54fe0693c06ed8671217eca9c9aa8107572f4614 Mon Sep 17 00:00:00 2001 From: Alessandro Angelino Date: Mon, 7 Mar 2016 15:45:33 +0000 Subject: [PATCH] Add documentation about the debug box --- docs/DEBUGGING.md | 82 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 10 deletions(-) diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md index 42ad298c..5215cecc 100644 --- a/docs/DEBUGGING.md +++ b/docs/DEBUGGING.md @@ -4,15 +4,23 @@ The uVisor is distributed as a pre-linked binary blob. Blobs for different mbed If you only want to use the uVisor debug features on an already supported platform, you do not need to clone it and build it locally. If you instead want to make modifications to uVisor (or port it to your platform) and test the modifications locally with your app, please follow the [Developing with uVisor locally](DEVELOPING_LOCALLY.md) guide first. -In this quick guide we will show you how to enable debug on uVisor. You will need the following: +In this quick guide we will show you how to enable the default debug features on uVisor, and how to instrument it to get even more debug information. You will need the following: * A GDB-enabled board (and the related tools). * yotta. -## Debug your application +## Debug capabilities -Debug messages are delivered through [semihosting](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471l/pge1358787045051.html), which requires a debugger to be connected to the device. +The uVisor provides two main sources of debug information: -We will assume from now on that you have a debugger connected to your board. We will use our Hello World application for this example, but of course any other can be used, provided that it is correctly setup to use uVisor. See [Developing with uVisor locally](DEVELOPING_LOCALLY.md) for more details. +1. Runtime messages. These are delivered through [semihosting](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471l/pge1358787045051.html), which requires a debugger to be connected to the device. Currently debug messages are used to instrument some of the security-critical features of uVisor, like boot and start-up configuration, interrupts management, and context switching. A post-mortem screen is also output when the system is halted due to a fault. + +2. Debug box drivers. We call a *debug box* a secure box that registers with uVisor to handle debug events and messages. The uVisor provides a predefined function table that describes the driver and its capabilities. Different debug boxes can implement these handlers differently, independently from uVisor. All handlers are executed in unprivileged mode. + +Runtime messages and debug box handlers are independent from each other. Even if an application does not include a debug box, the uVisor is still able to deliver basic runtime messages. Conversely, an application that includes a debug box will handle debug events even if the release build of uVisor is used and possibly even without a debugger connected. + +## Enabling runtime messages + +If you want to observe the uVisor runtime messages you need to have a debugger connected to your board. We will use our Hello World application for this guide, built for the NXP FRDM-K64F target: ```bash $ cd ~/code @@ -21,13 +29,14 @@ $ yotta install uvisor-helloworld $ cd uvisor-helloworld ``` -Build your application: +Of course any other application can be used, provided that it is correctly set up to use uVisor. See [Developing with uVisor locally](DEVELOPING_LOCALLY.md) for more details. +Runtime messages are silenced by default. In order to enable them, you need to build your application linking to the debug version of uVisor. Starting with v2.0.0, `uvisor-lib` comes with both the release and debug builds of uVisor, so you only need to run the following command: ```bash $ yotta build -d ``` -The `-d` option ensures that yotta enables debug symbols and disables optimizations. In addition, it ensures that the `uvisor-lib` modules selects the debug build of uVisor, which enables the uVisor debug features. +The `-d` option ensures that yotta enables debug symbols and disables optimizations. In addition, it ensures that the `uvisor-lib` modules selects the debug build of uVisor, which enables the uVisor runtime messages. Now start the GDB server. This step changes depending on which debugger you are using. In case you are using a J-Link debugger, run: @@ -35,7 +44,7 @@ Now start the GDB server. This step changes depending on which debugger you are $ JLinkGDBServer -device ${device_name} -if ${interface} ``` -where `${device_name}` and `${interface}` are J-Link-specific. Please check out the [J-Link documentation](https://www.segger.com/admin/uploads/productDocs/UM08001_JLink.pdf) and the list of [supported devices](https://www.segger.com/jlink_supported_devices.html). +In the command above `${device_name}` and `${interface}` are J-Link-specific. Please check out the [J-Link documentation](https://www.segger.com/admin/uploads/productDocs/UM08001_JLink.pdf) and the list of [supported devices](https://www.segger.com/jlink_supported_devices.html). Time to flash the device! We will use GDB for that, even if your device allows drag & drop flashing. This allows us to potentially group several commands together into a start-up GDB script. @@ -64,8 +73,6 @@ The following is the minimum set of commands you need to send to the device to f From here on if you send the `c` command the program will run indefinitely. Of course you can configure other addresses/ports for the target. Please refer to the [GDB documentation](http://www.gnu.org/software/gdb/documentation/) for details on the GDB commands. -## Debugging messages - You can observe the debug messages using `netcat` or any other equivalent program: ```bash @@ -93,9 +100,64 @@ Currently the following messages are printed: * Debug messages might interfere with timing constraints, as they are shown while running in the highest priority level. Applications that have very strict timing requirements might show some unexpected behaviour. +## The debug box + +> Warning: The debug box feature is an early prototype. The APIs and procedures described here might change several times in non-backwards-compatible ways. + +The uVisor code is instrumented to output debug information when it is relevant. In order to keep the uVisor as simple and hardware-independent as possible, some of this information is not handled and interpreted directly by uVisor. + +Instead, debug events and messages are forwarded to a special unprivileged box, called a *debug box*. A debug box is configured just like any other secure box, but it registers with uVisor to handle debug callbacks. These callbacks must adhere to a format that is provided by uVisor, in the form of a debug box driver. + +The debug box driver is encoded in a standard table (a C `struct`) that must be populated by a debug box at initialization time. A debug box can decide to implement only some of the available handlers, although they must all exist at least as empty functions, otherwise the program behaviour might be unpredictable. + +Currently, only one debug handler is provided. A debug box driver will always expect a `get_version()` handler in position 0 of the function table: + +```C +typedef struct TUvisorDebugDriver { + uint32_t (*get_version)(void); /* 0. Return the implemented driver version. */ + void (*halt_error)(int); /* 1. Halt on error. Reboot upon return. */ +} +``` + +The following is an example of how to implement and configure a debug box. + +```C +#include "mbed-drivers/mbed.h" +#include "uvisor-lib/uvisor-lib.h" + +/* Configure the debug box. */ +UVISOR_BOX_NAMESPACE(NULL); +UVISOR_BOX_CONFIG(box_debug, UVISOR_BOX_STACK_SIZE); + +static uint32_t get_version(void) { + return 0; +} + +static void halt_error(int reason) { + printf("We halted with reason %i\r\n", reason); + /* We will now reboot. */ +} + +UVISOR_EXTERN void __box_debug_init(void) { + /* Debug box driver -- Version 0 */ + static const TUvisorDebugDriver driver = { + get_version, + halt_error + }; + + /* Register the debug box with uVisor. */ + uvisor_debug_init(&driver); +} + +void box_debug::init(void) { + /* The debug box is initialized from the context of box_debug. */ + secure_gateway(box_debug, __box_debug_init); +} +``` + ## Platform-specific details -Currently the following platforms are supported by uVisor: +Currently the following platforms are officially supported by uVisor: * [NXP FRDM-K64F](http://developer.mbed.org/platforms/FRDM-K64F/). * [STMicorelectronics STM32F429I-DISCO](http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF259090).