TrustZone Example for Versatile Express Cortex-A9x4 and VE-A9x4 FVP model - ARM®DS-5™

This example demonstrates the support for TrustZone in DS-5 Debugger, targeted at Versatile Express Cortex-A9x4 and VE-A9x4 FVP model.

Purpose and scope

This example demonstrates the support for TrustZone in DS-5 Debugger. It uses two images combined into a single executable - one image runs in the Secure world, and the other image runs in the Normal (or Non-Secure) world, linked via a Secure Monitor. These make use of the TrustZone Security Extensions in Cortex-A9MPCore on a Versatile Express board and on a Cortex-A9x4-FVP model. This is a simple example to show basic features - it is not intended as a reference for developing a trusted execution environment, in particular: the Secure Monitor only provides a partial context switch (only the SVC mode registers are saved/restored), and the TrustZone Protection Controller (TZPC) is configured to allow non-secure access to all memory and peripherals.

Hardware and software requirements

  • Versatile Express Cortex-A9x4 and a suitable power supply for it or the VE-A9x4 FVP model.
  • If using Versatile Express Cortex-A9x4 a DSTREAM debug hardware and a suitable power supply for it, and a JTAG cable to connect it to the target
This example is intended to be built with the ARM Compiler 5. If you wish to modify and rebuild the example, you must use the ARM Compiler 5 to rebuild it.
The executable builds with a base address 0x80000000, and is intended for running on Versatile Express Cortex-A9x4 or VE-A9x4 FVP model.
Ready-made debug launch configurations TrustZone-versatile-A9x4-example.launch and TrustZone-Cortex-A9x4-FVP-example.launch are provided.

Building the example

This example can be built with the ARM Compiler 5 using the supplied Eclipse project, or directly on the command-line with the supplied Makefile.
The Eclipse project is a makefile builder project, rather than a managed builder project, because two link steps are needed to build the project.
This executable has an application base address 0x80000000, and is intended for running on Versatile Express Cortex-A9x4 or VE-A9x4 FVP model.
This example depends on semihosting support being provided by the debug system. DS-5 Debugger enables semihosting automatically if either symbols __auto_semihosting or__semihosting_library_function are present in an image. The ARM Compiler 5.0 adds __semihosting_library_function automatically to an image at link time if that image uses any semihosting-using functions. If compiling with gcc or an earlier release of armcc, use an alias symbol definition such as void __auto_semihosting(void) __attribute__ ((alias("main")));

Building on the command-line

To build the example on the command-line with the supplied make utility:
  • On Windows, open a DS-5 Command Prompt
  • On Linux, execute ~/DS-5/bin/suite_exec sh to start an sh shell configured for the suite environment
Then navigate to the ...\TrustZone directory, and type:
make
The usual make rules: cleanall and rebuild are provided in the makefile.

Building from Eclipse

To build the supplied Eclipse projects:
  1. In the Project Explorer view, select the project you want to build.
  2. Select Project → Build Project.

Running the example

  1. If using Versatile Express Cortex-A9x4, power-up the board and let its Loader initialize. To prevent Linux from booting, ensure both switches SW0 and SW1 are up/off.
  2. Select Debug Configurations from the Run menu.
  3. Select the TrustZone-versatile-A9x4-example or TrustZone-Cortex-A9x4-FVP-example from the list of DS-5 Debugger configurations.
  4. If using TrustZone-versatile-A9x4-example, in the Connections panel, enter the USB: or TCP: IP address or name of your DSTREAM unit in the Debug Hardware Address field, or click on Browseto select one from a list, otherwise an error will be reported: Launch configuration has errors: Configuration for connection type 'Bare Metal Debug' is not valid - Connection cannot be empty .
  5. If using TrustZone-Cortex-A9x4-FVP-example, make sure that the Model Parameters field is empty.
  6. Click on Debug to start debugging. Debugging requires the DS-5 Debug perspective. If the Confirm Perspective Switch dialog box opens, click on Yes to switch perspective.
  7. The example image will be downloaded to the target and will run to secureStart. All open views will be refreshed.
  8. Run the executable (press F8). Text output appears in the App Console view (if the example runs on real hardware) or in the Target Console view (if the example runs on a model), similar to this:
Hello from Normal world
Hello from Secure world
Hello from Normal world
Hello from Secure world
Hello from Normal world
Hello from Secure world
Hello from Normal world
Hello from Secure world
Hello from Normal world
Hello from Secure world
Hello from Normal world
Hello from Secure world
Hello from Normal world
Hello from Secure world
Hello from Normal world
Hello from Secure world
Hello from Normal world
Hello from Secure world
Hello from Normal world
Hello from Secure world
To run the example again, you must first disconnect DS-5 Debugger from the target, if using Versatile Express Cortex-A9x4 power-cycle the target, then reconnect DS-5 Debugger and reload the executable in the same way as before.

Program execution flow

The flow of program execution is shown below:
  secureStart     startup_secure.s: Initialization of Secure world
       |
    __main        ARM library initialization
       |
     main         main_secure.c: Enable caches and configure TZPC
       |
  monitorInit     monitor.s: initialize Monitor
       |
     main         main_secure.c: Print message and execute SMC
       |
     S -> NS
       |
  normalStart     startup_normal.s: Initialization of Normal world
       |
    __main        ARM library initialization
       |
     main         main_normal.c: Enable caches, print message and execute SMC
       |
    NS -> S
       |
  SMC_Handler     monitor.s: Perform context switch from NS to S
       |
     main         main_secure.c: Print message and execute SMC
       |
  SMC_Handler     monitor.s: Perform context switch from S to NS
       |
     S -> NS
       |
     main         main_normal.c: Print message and execute SMC
       |
    NS -> S
       |
  SMC_Handler     monitor.s: Perform context switch from NS to S
       |
     main         main_secure.c: Print message and execute SMC

Exploring the example

First disconnect any existing debug session, then power-cycle the target if using Versatile Express Cortex-A9x4, then reconnect and reload the executable in the same way as before, selecting "Debug from entry point" in the Debugger tab. The executable TrustZone-versatile.axf loaded contains the Secure world image and its debug symbols, and the Normal world image (but not its debug symbols). Notice that the debug launcher not only loads the executable TrustZone-versatile.axf but also seperately loads debug symbols for the Normal world image with add-symbol-file normal.axf N:0.
  1. Program execution starts from secureStart in startup_secure.s. This routine initializes the Secure world, including setting up the SVC stack, invalidating the caches and TLBs, setting up the page tables, enabling the MMU, then branching to the C library run-time initialization in __main. Check the processor is in SVC mode in Secure state by looking at the M bit in the CPSR and NS bit in CP15_SCR in the Registers view, or type output $CPSR.M and output $CP15_SCR.NS in the CLI.
  2. Set a breakpoint on Secure world's main() with b main_secure.c::main and run to it (press F8). The source file qualifier is needed in this breakpoint command because there are two main() functions in the image - a Secure world main and a Normal world main. Secure world's main() will then enable the caches and configure the TZPC before calling monitorInit in monitor.s to initialize the Monitor and call NS world.
  3. Set a breakpoint in the Monitor initialization code in monitor.s with b monitorInit and run to it (press F8). The Monitor initialization will install the Monitor's vector table, initialize the Monitor mode stack pointer, create and save a dummy Normal world state (this will be used for the first entry to the Normal world) before returning to the Secure world caller.
  4. Single-step (press F5) to CPS #Mode_MON then single-step this instruction. Notice the mode change from SVC to MON reflected in the CPSR, then back again to SVC a couple of instructions later. Single-step through to the final BX lr in monitor.s, then single-step again to return to the Secure world in main_secure.c.
  5. Secure world's main will print the first "Hello from Secure world", then execute an SMC instruction via yield() to switch back to the Monitor.
  6. Set a breakpoint on yield(), run to it, then single-step the SMC instruction. This triggers an SMC exception, landing at the SMC entry in the Monitor's vector table. Notice the mode change from SVC to MON reflected in the CPSR.
  7. Single-step through to the end of SMC_Handler. Notice the NS bit being toggled before stepping the exception return instruction MOVS pc, lr that jumps to Normal world's normalStart routine.
  8. normalStart initializes the Normal world, including identifying the current CPU and sleeping all except CPU 0, setting up stacks, invalidating the caches and TLBs, setting up the page tables, enabling the MMU, setting the Vector Base Address Register (needed here because NS VBAR has no defined reset value), then branching to the C library run-time initialization in __main.
  9. Set a breakpoint on Normal world's main() with b main_normal.c::main and run to it (press F8). Normal world's main will enable the caches, print the first "Hello from Normal world", then execute an SMC instruction via yield() to switch into the Monitor.
  10. Set a breakpoint on yield(), run to it, then single-step the SMC instruction. This again triggers an SMC exception, landing at the SMC entry in the Monitor's vector table. Notice the mode change from SVC to MON reflected in the CPSR.
  11. Step or run to the exception return instruction MOVS pc, lr and step it. Notice the mode change from MON to SVC reflected in the CPSR, and a jump to Secure world's main().
  12. Secure world's main will print the second "Hello from Secure world", then execute an SMC instruction via yield() to switch back to the Monitor again.
  13. Continue running (press F8) a few more times to repeat the switching between Normal and Secure world via the Monitor.
  14. In the Breakpoints view, delete all the breakpoints, then from View Menu, select Manage Signals, then tick Stop and Print for the SMC exception.
  15. Continue running (press F8) a few more times to see the SMC exception being trapped by the debugger.
  16. In a real system, the TrustZone Protection Controller (TZPC) can be is configured to allow/forbid secure/non-secure access to memory and peripherals. In this simple example, the TZPC is configured to allow non-secure access to all memory and peripherals. However, the TZPC itself is only accessible in secure world. To demonstrate this, open Memory view at address S:0x100E6800 (the S:meaning Secure access). The TZPC is based at 0x100E6000 but its status/control registers start at offset 0x800. Notice the registers contain 0xFF, as programmed earlier in main_secure.c() with calls to setDecodeRegionNS(). Then open a Memory view at address N:0x100E6800 (the N: meaning Non-Secure access). This address region will abort because the TZPC is not accessible from Non-Secure state.
  17. Continue running (press F8) until the application exits normally, then disconnect.
  18. To run the example again, you must first power-cycle the target, then reconnect and reload the executable in the same way as before.

Known issues and troubleshooting

  • Eclipse reports Unresolved inclusion for system headers such as stdio.h if it cannot locate the header files for a project. You can resolve this by right-clicking on the project in the Project Explorer view and then selecting Properties... from the context menu. In the dialog box, select: C/C++ General → Paths and Symbols → Add... and then add the path to the ARM Compiler 5 headers on your host workstation. For example, C:\Program Files\DS-5\include. Select both Add to all configurations and Add to all languages, click on Apply so that Eclipse can rebuild the index.
  • On Windows 7 and later, launching a debug configuration to connect to a Fixed Virtual Platform (FVP) model may give the following error: Windows cannot find "C:\Windows\System32\telnet.exe". ARM FVPs make use of "telnet" as a serial terminal, to enable UART data to be transferred between application code running on an ARM FVP and your computer. This error occurs when the telnet client is disabled or otherwise unavailable on your computer. The telnet client is not enabled by default on Windows 7 and later. To enable the telnet client on your computer:
    1. From the Windows Start menu, select Control Panel > Programs and Features
    2. Click on "Turn Windows features on or off"
    3. From the list that appears, select the "Telnet Client" checkbox
    4. Click "OK" to close the dialog.

See also:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章