Skip to content

STM32CubeIDE

HannesH edited this page Mar 17, 2021 · 27 revisions

STM32CubeIDE

About the IDE

As with any other IDE, the STM32CubeIDE faciciltates the developement of Programs. It features tools for debugging, a menu in which you can import example projects, an ioc-file for code generation and many other things. We will present you some features that you need to work on your own project. Please note that there are already some features described in the getting started guide. Here you can find some advanced descriptions as well as some pictures showing important locations.

Pictures

overview

Import a project

Once you launch the STM32CubeIDE you can import new projects. First locate the column on the lefthand above which "Project Explorer" is written. Rightclick on any free space and choose import. The most used options for us were "General > Exisitng Projects into Workspace" or "General > Import STM32Cube Example"

  • If you import an existing project navigate to the folder which includes the .project file. If there are nested projects choose the folder with the top-level .project-file.
  • If you import an example choose the board you are using (in our case the NUCLEO-L552ZE-Q). Please note that there is a rider named "Example" which contains some porjects that can be reused. We used FreeRTOS_SecureIOToggle_TustZone, which might be easier to start with than with our project. Afterwards you can choose whether TrustZone should be enabled and if you would like to configure the PINs with their default configuration.

Build and Launch a project

To build your project, choose the project click on the arrow next to the hammer, choose your build configuration and then click the hammer. Once the project is build, you may run or debug the project, according to the build configuration. If you run a project which contains other projects (such as the FreeRTOS_SecureIOToggle_TrustZone), you must consider the dependencies. If you import examples there is a readme specifiying the details on how to build and launch. Otherwise the following instructions should build and flash every project correctly:

  1. Select the Project containing the Secure.elf
  2. At the top of the CubeIDE, click the arrow next to the Debug- or Run-Icon > Configurations, click on the Startup Rider > add xxxx/NonSecure.elf
  3. Click Apply, close the window
  4. Build the secure project
  5. Build the NonSecure project
  6. Select the Secure-Project and hit Debug/Run

Configure the .ioc file

The STM32CubeIDE offers automatic code generation, which can be used by configuring the .ioc-File. What needs to be considered when generating code depends - of course - on the application that is developed, so we can't tell you what you exactly have to do, but we will explain you how we configured the .ioc-file to use FreeRTOS on the one hand and to enable interrupts on the other hand. After changes have been made to the .ioc-file save it and the code generation should start.

Enable FreeRTOS

Once you open the .ioc-File, navigate to the point Middleware on the left hand side of the provided GUI. There you choose FreeRTOS and select the interface you want to use. Once you have chosen a CMSIS version you have the option to configure other parameters. Mainly interresting for our application is the configuration of the "Tasks and Queues" rider. Here you can add new or configure already exisitng tasks. A more extensive description and other things you should consider can be found in the page about FreeRTOS

Enable Interrupts

Before you can enable Interrupts you have to configure the coresponding pin to generate Interrupts. To do so, choose the pin in the picture on the right hand side and in the dropdown menu choose GPIO_EXTIXX. In our case we wanted the user Button to generate interrupts. We searched in the documentation for the coressponding pin (PC13) and choose in the menu GPIO_EXTI13. Now, open the System Core dropdown menu on the lefthand side of the GUI, there select GPIO, search for the pin you have configured beforehand, select it and assign the pin a context (secure or nonsecure). We didn't need to change anything about the GPIO mode, but you might do so. In a last step choose the rider NVIC in the GPIO-view and enable Interrupts. Once you auto-generate code there should be a designated code segment in the stm32l5xx_it.c file in which you may write your interrupt handling.

Add custom files

If you need to add files manually to the project, you should use already used directories in which source-code already exists. That way you avoid the most problems arising with the IDE not finding your file. If, on the other hand, you want to use an external library that you want to add manually, you need to add the paths to the to the project. You do so by right clicking on the blue project file in the IDE > Properties > C/C++ General > Paths and Symbols, there you can add header files that are needed. To link files within your project you may right-click on the folder that you want your link to be placed > new > File > Advanced, there check the box "Link to file in the file systems" and search for the file or folder you want to create the link for.
Please note that the option to link files can be applied for header-files as well as for source-code. The option to name the IDE new paths are only working for header files.

Usage of NonSecure Callable functions

Introduction

The main goal of the project was to demonstrate how TrustZone protects a LED which we have successfully demonstrated. In this chapter we will look into the most important functionality that makes TrustZone work correctly: NonSecure Callable functions.

Usage of NSC-Functions

If you are writing an application in the NonSecure area, you might need to invocate a service of the secure area. To gain that privilege, one calls a function marked as NonSecure Callable (NSC). For that purpose any project generated with TrustZone features a file called "secure_nsc.c". In there are some functions defined with the macro "secureportNON_SECURE_CALLABLE", this is the prefix every function needs, if one wants to add NSC-Functions. New NSC-Functions should be added there.
After that the header file with the defined function must be included. It doesn't matter that the file is in the secure project meaning that you can use the funtions in the NonSecure project without any further steps.

Further technical explanation and possible attack

TrustZone distinguishes semantically between three kinds of memory region: Secure, NonSecure and NonSecure Callable, where NonSecure is only allowed to use NonSecure memory and Secure may call any NonSecure function. As mentioned before, NSC functions allow NonSecure functions to also call secure functions. But how does this transition work?
We will explain this technology with an example from our project: SECURE_LEDS_setBlue() (you may accompany this description by setting a breakpoint at a call of this function). Upon calling this function, we see in the debugger (disassembly) that actually "__SECURE_LEDS_setBlue_veneer" is called. If we follow that branch we get to a function that doesn't seem to be doing much in regard of what we would expect (there is nothing about toggling a LED), but a branch to another function which is, as for now, unnamed.
If we step into that branch we reach a function actually called SECURE_LEDS_setBlue. This function however contains only two instructions: "sg" and the branch to yet another function called SECURE_LEDS_setBlue. Once we have branched to this function we finally arrived in the actual function that is concerned with the LED-Toggle.
After showing what happens in the code we might want to consider what these calls actually mean: The first call branches to __SECURE_LEDS_setBlue_veneer. If we look at the address, we see that this function resides in an address of about 0x08044b28 (this may depend on how you configured your board, look at the site about STM32CubeProgrammer for more). This means here we are still in the NonSecure region.
After the next branch however, we are in the SECURE_LEDS_setBlue function at address 0x0c03e048; this is in the secure region or rather the NonSecure Callable Region. This section is exclusively used to execute the "sg" (Secure Gateway) instruction and branch then to the actually secure function. The execution of the "sg" instruction in the NSC region is actually responsible for switching from the Secure to the NonSecure state, after that the execution in the secure area (0x0c000e18) begins. The only special thing to mention here is the sequence of execution before the branch to the NonSecure region and after the last instruction of the code. We assume here is everthing prepared to return to NonSecure mode (i.e. no information is allowed to leak).
We thought that, with some dedication, one could write such a functions as described and put them as "injected code" that passed the download verification in the corresponding areas. Our project could be used as a basis to go off on.

Clone this wiki locally