Skip to content

This is a minimal starter dual-CPU security application template for PSoC™ 62/63 MCU devices. This code example is meant to be a companion to the AN221111 – PSoC™ 6 MCU: Designing a secured system application note. It demonstrates the following features to create a secured system as explained in the application note.

License

Notifications You must be signed in to change notification settings

Infineon/mtb-example-psoc6-security

Repository files navigation

PSoC™ 6 MCU: Security application template

This is a minimal starter dual-CPU security application template for PSoC™ 62/63 MCU devices. This code example is meant to be a companion to the AN221111 – PSoC™ 6 MCU: Designing a secured system application note. It demonstrates the following features to create a secured system as explained in the application note.

  • Bootloader-based on industry-standard MCUboot (CM0+)
  • Cryptographically signed bootloader
  • Dual-CPU operation; user applications for both CM0+ and CM4
  • Supports Device Firmware Update (DFU) with standard UART interface
  • FreeRTOS running on CM4
  • Signed CM0+ and CM4 application bundle
  • Full Chain of Trust (CoT)
  • Isolated CPUs using Shared Memory Protection Unit (SMPU)

The application template bundles three projects:

  • proj_btldr_cm0p – Implements an MCUboot-based basic bootloader project run by CM0+. The bootloader handles image authentication and upgrades. When the image is valid, the bootloader lets the user project bundle (CM0+/CM4 user image) and run the image by passing the starting address of the image to it. It also programs the protection units and other system security related features.

  • proj_cm0p – Implements a blinky LED project run by CM0+ that toggles the user LED at different rates depending on whether it was built in BOOT mode or UPGRADE mode.

  • proj_cm4 – This project has two implementations

    1. Implements a DFU task to receive firmware updates over UART using FreeRTOS. It also demonstrates the usage of IPCs to request data from the CM0+ project. This application is merged with the proj_cm0p image to generate the dual-CPU image to be programmed.

      You can build the CM0+ and CM4 user project in one of the following ways:

      • BOOT mode: The user image is built to be programmed into the primary slot. The bootloader will simply boot the user image on the next reset.

      • UPGRADE mode: The user image is built to be programmed into the secondary slot. Based on the user input, the bootloader will copy the image into the primary slot and boot it on the next reset.

    2. Impelments an RMA functionality to transition the device to RMA lifecycle mode. TRANSITION_TO_RMA flag should be set to enable the RMA mode trasition. The DFU task is disabled when this flag is set.

The application template also has files and directories that are of importance such as the following:

  • shared directory that contains the linker scripts for different BSPs
  • common.mk is a configuration Makefile that defines the target, toolchain, optimization etc., and defines macros that can be used in the linker scripts.

View this README on GitHub.

Provide feedback on this Code Example.

Requirements

  • ModusToolbox™ v3.1 or later (tested with v3.2)
  • Programming language: C
  • openssl 1.0.2 or higher
  • PSoC™ 6 board support package (BSP) minimum required version: 4.0.0
  • Cypress™ programmer
  • Other tools: Python 3.8.10 or later
  • Associated parts: All PSoC™ 6 Dual-CPU MCU parts (except PSoC™ 64)

Supported toolchains (make variable 'TOOLCHAIN')

  • GNU Arm® Embedded Compiler v11.3.1 (GCC_ARM) – Default value of TOOLCHAIN

Supported kits (make variable 'TARGET')

Hardware setup

This example uses the board's default configuration. See the kit user guide to ensure that the board is configured correctly.

Note: ModusToolbox™ software requires KitProg3. Before using this code example, make sure that the board is upgraded to KitProg3. The tool and instructions are available in the Firmware Loader GitHub repository.

If you do not upgrade, you will see an error like "unable to find CMSIS-DAP device" or "KitProg firmware is out of date".

Software setup

  1. Install a terminal emulator if you don't have one. Instructions in this document use Tera Term.

  2. Install the Python interpreter and add it to the top of the system path in environmental variables. This code example is tested with Python v3.8.10 .

  3. This example also requires some Python packages to be installed. Run the following command in your terminal from the application root folder to install all the pre-requisite packages:

    pip install -r ./proj_btldr_cm0p/scripts/requirements.txt
    

    Note: For MacOS users, latest version of openssl must be installed from homebrew/ports, and "/usr/local/bin" must be in PATH before "/usr/bin".

    brew install openssl
    

    Since MacOs comes with LibraSSL, users need to execute the following command to make sure openssl will be used while building the project.

    export PATH="/usr/local/opt/openssl@3/bin:$PATH"
    

Note: This example currently does not work with custom BSP names. If you want to change the BSP name to a non-default value, ensure to update the modified BSP name in common.mk file under relevant sections. Otherwise project creation fails.

Using the code example

Create the project

The ModusToolbox™ tools package provides the Project Creator as both a GUI tool and a command line tool.

Use Project Creator GUI
  1. Open the Project Creator GUI tool.

    There are several ways to do this, including launching it from the dashboard or from inside the Eclipse IDE. For more details, see the Project Creator user guide (locally available at {ModusToolbox™ install directory}/tools_{version}/project-creator/docs/project-creator.pdf).

  2. On the Choose Board Support Package (BSP) page, select a kit supported by this code example. See Supported kits.

    Note: To use this code example for a kit not listed here, you may need to update the source files. If the kit does not have the required resources, the application may not work.

  3. On the Select Application page:

    a. Select the Applications(s) Root Path and the Target IDE.

    Note: Depending on how you open the Project Creator tool, these fields may be pre-selected for you.

    b. Select this code example from the list by enabling the checkbox.

Note: Type in the filter box to narrow the list of displayed examples.

c. (Optional) Change the suggested New Application Name and New BSP Name.

d. Click Create to complete the application creation process.

Use Project Creator CLI

The 'project-creator-cli' tool can be used to create applications from a CLI terminal or from within batch files or shell scripts. This tool is available in the {ModusToolbox™ install directory}/tools_{version}/project-creator/ directory.

Use a CLI terminal to invoke the 'project-creator-cli' tool. On Windows, use the command-line 'modus-shell' program provided in the ModusToolbox™ installation instead of a standard Windows command-line application. This shell provides access to all ModusToolbox™ tools. You can access it by typing "modus-shell" in the search box in the Windows menu. In Linux and macOS, you can use any terminal application.

The following example clones the "Security application template" application with the desired name "MySecurityApp" configured for the CY8CKIT-062-WIFI-BT BSP into the specified working directory, C:/mtb_projects:

project-creator-cli --board-id CY8CKIT-062-WIFI-BT --app-id mtb-example-psoc6-security --user-app-name MySecurityApp --target-dir "C:/mtb_projects"

The 'project-creator-cli' tool has the following arguments:

Argument Description Required/optional
--board-id Defined in the field of the BSP manifest Required
--app-id Defined in the field of the CE manifest Required
--target-dir Specify the directory in which the application is to be created if you prefer not to use the default current working directory Optional
--user-app-name Specify the name of the application if you prefer to have a name other than the example's default name Optional

Note: The project-creator-cli tool uses the git clone and make getlibs commands to fetch the repository and import the required libraries. For details, see the "Project creator tools" section of the ModusToolbox™ tools package user guide (locally available at {ModusToolbox™ install directory}/docs_{version}/mtb_user_guide.pdf).

Open the project

After the project has been created, you can open it in your preferred development environment.

Eclipse IDE

If you opened the Project Creator tool from the included Eclipse IDE, the project will open in Eclipse automatically.

For more details, see the Eclipse IDE for ModusToolbox™ user guide (locally available at {ModusToolbox™ install directory}/docs_{version}/mt_ide_user_guide.pdf).

Visual Studio (VS) Code

Launch VS Code manually, and then open the generated {project-name}.code-workspace file located in the project directory.

For more details, see the Visual Studio Code for ModusToolbox™ user guide (locally available at {ModusToolbox™ install directory}/docs_{version}/mt_vscode_user_guide.pdf).

Operation

This application bundles three projects: the bootloader project run by the CM0+ CPU (proj_btldr_cm0p), the blinky project run by the CM0+ CPU (proj_cm0p), and the FreeRTOS project run by the CM4 CPU (proj_cm4).

The example can be built in two different ways:

  • For development (default) – Used for developing the application and testing it

  • For production – Used when firmware testing is complete and the device is ready to be deployed in the field

The steps remain similar for both methods except that during a production build, an additional post-build step is executed to merge the HEX files of all the applications to create a single binary. See CM0+/CM4 dual-CPU user projects: Post-build steps (for production).

You need to build and program the projects in the following order. Do not start building the application yet: follow the Step-by-step instructions as follows

  1. Build and program the bootloader project – On next reset, CM0+ runs the bootloader and prints a message that no valid image has been found.

  2. Build the blinky project in BOOT (default) mode – A CM0+ binary will be generated on successful build.

  3. Build and program the FreeRTOS project in BOOT (default) mode – The CM4 binary gets generated that integrates the CM0+ binary on a successful build. Once programmed, the bootloader will find that the user application exists and then transfer control to it if the validation is successful. The blinky and FreeRTOS projects will be running on the CM0+ and CM4 CPUs respectively with debug messages printed on the serial terminal.

  4. Build the blinky project in UPGRADE mode – A CM0+ binary will be generated on a successful build.

  5. Build and program the FreeRTOS project in UPGRADE mode – The CM4 binary is generated that integrates the CM0+ binary on a successful build. The DFU UART connections must be done as explained in Table 7: DFU status LED and UART connections. The DFU Host tool is used to transfer the image over UART. Once the transfer is complete, the bootloader will find that the upgrade image exists and then either overwrite the primary slot or swap the primary slot with the new image based on the value of SWAP_UPGRADE. The blinky and FreeRTOS projects will be running on the CM0+ and CM4 CPUs respectively with debug messages printed on the serial terminal.

Step-by-step instructions

For development

The proj_btldr_cm0p project design is based on MCUboot, which uses the imgtool Python module for image signing and key management.

  1. Connect the board to your PC using the provided USB cable through the KitProg3 USB connector. Open a terminal program and select the KitProg3 COM port. Set the serial port parameters to 8N1 and 115200 baud.

  2. Build and program the bootloader project. If the build fails, check if you have installed the pre-requisite python libraries described in Software Setup. When programming consecutively, make sure to erase the device first before re-programming.

    Using Eclipse IDE for ModusToolbox™ software
    1. Select the proj_btldr_cm0p project in the Project Explorer.

    2. Follow the instructions as mentioned in KBA236748 to create the <Project Name> Program (KitProg3_MiniProg4) OpenOCD configuration correctly.

    3. In the Quick Panel, scroll down, and click <Project Name> Program (KitProg3_MiniProg4).

    Using CLI

    From the terminal, go to the proj_btldr_cm0p directory and execute the make program command to build and program the project using the default toolchain to the default target.

    You can specify a target and toolchain manually using the following command:

    make program TARGET=<BSP> TOOLCHAIN=<toolchain>
    

    Example:

    make program TARGET=CY8CPROTO-062-4343W TOOLCHAIN=GCC_ARM
    
    Using Cypress™ Programmer (for programming only)

    Use the following settings when programming the kit using Cypress™ Programmer.

    1. Select Reset chip.
    2. Deselect Program Security Data. (Note: When programming eFuse, this should be selected).
    3. Set Voltage to 3.3 V (Note: When programming eFuse, set this to 2.5 V).
    4. Set Reset Type as soft.
    5. Set SFlash Restrictions to "Erase/Program USER/TOC/KEY allowed".
    6. Specify the HEX file to be programmed and then click Connect and Program.

    Figure 1. Cypress™ Programmer settings

    CYPRESS Programmer settings


    After programming, the bootloader starts automatically. Confirm that the UART terminal displays the current lifecycle state, access restrictions, status of protection units configuration, and status of the bootloader operation as highlighted in the Figure 2.

    Note that the primary slot does not contain any valid image at this stage.

    Figure 2. Bootloader starting with no bootable image

    Note: If you do not see any message printed on the UART terminal (assuming that you have the right settings as mentioned in Step 1), it is most likely because of any of the following reasons:

    • SFlash wasn't updated – Perform an Erase using CYPRESS™ Programmer to erase the SFlash contents (USER/TOC/KEY). Now Program the HEX file to see if it works as expected.
    • The validation of the bootloader has failed – The bootloader image is signed with the RSA private key as part of the post-build steps. Ensure that the correct public key information that pairs with the private key is being used in the cy_ps_keystorage.c file. See Generating a key-pair for more details.

  3. Build the proj_cm4 project (use one of the options as shown in Step 2). All the projects are built during a build. This builds proj_cm0p along with proj_cm4 every time to create the dual-CPU user image (primary_app.hex).

  4. (Skip to Step 5 if not using IDE) Create the OpenOCD configuration for programming the hex file by following the steps in KBA236748. Change the executable from app_combined.hex to primary_app.hex in the configuration options.

  5. Program the proj_cm4 project (use one of the options as shown in Step 2).

    After programming, the proj_btldr_cm0p project starts automatically. At this stage, valid user image exists in the primary slot and control is transferred to it if the validation is successful. The UART terminal will display the following message based on the validation status:

    • If validation is successful:

      Figure 3. Bootloader starting with a valid user image

      Bootloader starting with a valid user image

    • If validation fails:

      Figure 4. Bootloader starting with an invalid user image

      Bootloader starting with an invalid user image

    Note that the secondary slot does not contain any valid image at this stage.

  6. If the user image is running successfully, the LED toggles on the kit to indicate a successful CM0+ startup. The UART terminal displays the successful startup of the CM4 project.

    Note: On kits with two LEDs, you should see the second LED glow indicating a successful CM4 startup. See Table 7: DFU status LED and UART connections for LED pin assignment.

  7. Edit the common.mk file in the application root directory to create the UPGRADE image. Change the IMG_TYPE variable to UPGRADE.

    IMG_TYPE ?= UPGRADE
    
  8. Build the proj_cm4 project. The projects have been developed to incorporate minor changes based on whether IMG_TYPE is set to BOOT or UPGRADE. This combines proj_cm0p along with proj_cm4 to create the dual-CPU user image. As part of the post-build steps, it merges the proj_cm0p HEX file with the proj_cm4 HEX and signs the image using imgtool to create the user application bundle (primary_app_UPGRADE.hex) and then converts it to a .cyacd2 file required by the DFU Host tool.

  9. Connect an external MiniProg3/4 or KitProg3 programmer/debugger and make the connections required for the DFU UART as explained in Table 7: DFU status LED and UART connections.

  10. Open the DFU Host tool (dfuh-tool) from ModusToolbox install directory}/tools_<version>/dfuh-tool. Verify that you see the debugger probe. Choose the one that has UART on it as follows:

DFU Host tool UART

  1. Select the .cyacd2 file from the build output and click Program. The operation should take a few minutes to complete.

  2. Once complete, the image validation status is displayed. If validation is successful, a software reset is initiated to boot it into the new image as follows. Else, the upgrade is aborted.

    DFU upgrade

    Observe that the blinky LED is now blinking faster (every 250 ms) and the debug logs indicate the upgrade image being run.

  3. Once the working of the bootloader and user projects has been tested, you can blow the eFuses to transition from NORMAL to SECURE lifecycle mode for further testing. See eFuse programming for debug access restrictions and lifecycle.

  4. Once the device is working as expected in SECURE lifecycle mode, proceed to Step-by-step instructions for production build to program multiple devices at production level.

For production

The proj_btldr_cm0p project design is based on MCUboot, which uses the imgtool Python module for image signing and key management.

  1. Connect the board to your PC using the provided USB cable through the KitProg3 USB connector. Open a terminal program and select the KitProg3 COM port. Set the serial port parameters to 8N1 and 115200 baud.

  2. This step assumes that you have tested the working of your bootloader and your user projects in SECURE lifecycle stage during development. Edit the proj_btldr_cm0p/source/cy_ps_efuse.h file and set the CY_EFUSE_AVAILABLE macro to '1'.

    #define CY_EFUSE_AVAILABLE 1
    
  3. Verify the eFuse configuration defined in the cy_efuse_data variable.

  4. Build the bootloader project. This generates the proj_btldr_cm0p.hex file in the output build directory.

    Using Eclipse IDE for ModusToolbox™ software
    1. Select the proj_btldr_cm0p project in the Project Explorer.

    2. In the Quick Panel, scroll down, and click Build <Application Name>.

    Using CLI

    From the terminal, go to the proj_btldr_cm0p directory and execute the make build command to build the project using the default toolchain to the default target.

    You can specify a target and toolchain manually using the following command:

    make build TARGET=<BSP> TOOLCHAIN=<toolchain>
    

    Example:

    make build TARGET=CY8CPROTO-062-4343W TOOLCHAIN=GCC_ARM
    

  1. Navigate to the proj_cm4 directory and edit the Makefile to enable production build. Change the PRODUCTION Makefile variable to '1'.

    PRODUCTION=1
    
  2. Build the proj_cm4 project. All the projects are built during a build. This builds proj_cm0p along with proj_cm4 every time to create the dual-CPU user image (primary_app.hex). Because production build is enabled, a merged HEX file (production.hex) of all the three applications is also generated as part of the post-build steps. See CM0+/CM4 dual-CPU user projects: Post-build steps (for production).

  3. Program the merged HEX file using Cypress™ Programmer. When programming consecutively, make sure to erase the device first before re-programming:

    1. Select the correct kit in the Probe/Kit option. Specify the production.hex file to be programmed and use the following settings:

      1. Select Reset chip.
      2. Select Program Security Data. (Note: When not programming eFuse, leave this deselected.)
      3. Set Voltage to 2.5 V. (Note: When not programming eFuse, set this to 3.3 V.)
      4. Set Reset Type to Soft.
      5. Set Sflash Restrictions to "Erase/Program USER/TOC/KEY allowed".

      Note: Cypress™ Programmer will indicate the current operating voltage at the bottom right as highlighted in the figure. If you do not see 2.5 V even after setting the Voltage option to 2.5 V, check if the kit has a VDD select switch / jumper and change it to 2.5 V or 1.8 V - 3.3 V variable voltage.


      Figure 5. Cpress™ Programmer settings

      Programmer settings

    2. Click Connect and then click Program.

  4. After programming, the proj_btldr_cm0p project starts automatically. At this stage, valid user image exists in the primary slot and control is transferred to it, if the validation is successful. The UART terminal displays the following message based on the validation status:

    • If validation is successful:

      Figure 6. Bootloader starting with valid user image

      Bootloader starting with valid user image

    • If validation fails:

      Figure 7. Bootloader starting with invalid user image

      Bootloader starting with invalid user image

    Note that the secondary slot does not contain any valid image at this stage. This represents the state of the device in the field.

  5. If the user projects are running successfully, the LED should be toggling on the kit to indicate successful CM0+ startup. The UART terminal will display the successful startup of the CM4 project.

    Note: On kits with two LEDs, you should see the second LED glow indicating a successful CM4 startup. See Table 7: DFU status LED and UART connections for LED pin assignment.

  6. Build the proj_cm4 project for UPGRADE by changing IMG_TYPE to UPGRADE in common.mk. This represents the new firmware to be sent to the device in the field. The projects have been developed to incorporate minor changes based on whether IMG_TYPE is set to BOOT or UPGRADE. As part of the post-build steps, it merges the CM0p and CM4 user projects and signs the image using imgtool to create the user application bundle (primary_app_UPGRADE.hex) and then converts it to a .cyacd2 file required by the DFU Host tool.

  7. Connect an external MiniProg3/4 or KitProg3 and make the connections needed for the DFU UART as explained in Table 7: DFU status LED and UART connections.

  8. Open the DFU Host tool (dfuh-tool) and verify that you are seeing the debugger probe. Choose the one that has UART on it as follows:

Figure 8. Message from DFU host tool

DFU Host tool UART

  1. Select the .cyacd2 file from the build output and click Program. The operation should take a few minutes to complete.

  2. Once complete, the image validation status will be displayed. If validation is successful, a software reset is initiated to boot it into the new image as highlighted below. Else, the upgrade is aborted.

    Figure 9. DFU upgrade

    DFU upgrade

    Observe that the blinky LED is now blinking faster (every 250 ms) and the debug logs indicate the upgrade image being run.

Debugging

You can debug the example to step through the code.

In Eclipse IDE

Use the <Application Name> Debug (KitProg3_MiniProg4) configuration in the Quick Panel. For more details, see the "Program and debug" section in the Eclipse IDE for ModusToolbox™ user guide.

Note: (Only while debugging) On the CM4 CPU, some code in main() may execute before the debugger halts at the beginning of main(). This means that some code executes twice – once before the debugger stops execution, and again after the debugger resets the program counter to the beginning of main(). See KBA231071 to learn about this and for the workaround.

In other IDEs

Follow the instructions in your preferred IDE.

Design and implementation

This code example is meant to be a companion to the AN221111 – PSoC™ 6 MCU: Designing a secured system application note. The code example demonstrates several concepts such as the following:

  • Secure Boot and Chain of trust
  • Shared memory protection units (SMPU) for memory protection
  • Peripheral protection units (PPU) for peripheral / memory protection
  • eFuses for lifecycle transitions and lifecyle access restrictions
  • Protection contexts (PC) for bus master roles and enforcing access restrictions
  • Inter-processor communication (IPC) for communication between the CPUs
  • MCUboot bootloader functionality for validating and running images
  • Device firmware updates (DFU) for updating the user image
  • Crypto block usage for image validation
  • RMA Transition for putting the device in RMA mode

These concepts are covered in detail in the application note.

Project structure

This application template has three projects - proj_btldr_cm0p, proj_cm0p and proj_cm4. It also contains a shared directory that contains the linker scripts.

Figure 10. Project structure

Project structure

Project configuration

The three projects rely on the configurations defined in the common.mk file. This file defines the start addresses and sizes for different memory regions and specifies certain common build configurations. The linker script symbols are also supplied by this file.

The partitions in the memory are created using the three linker scripts present in the shared/linker_script/<BSP>/TOOLCHAIN_GCC_ARM directory.

Table 1. Linker scripts

File Description
COMPONENT_CM0P/<device>_cm0p_btldr.ld Specifies the memory layout for the proj_btldr_cm0p project
COMPONENT_CM0P/<device>_cm0p.ld Specifies the memory layout for the proj_cm0p project
COMPONENT_CM4/<device>_cm4.ld Specifies the memory layout for the proj_cm4 project

The linker scripts contain symbols that specify the starting address and length of each of the memory regions. The values for these symbols are supplied using the common.mk file as explained below.

Flash memory layout

The flash has been divided into the following sections:

  • Bootloader – For running the MCUboot Bootloader project
  • Protected memory – For storing confidential data or keys. See Protected storage for more information.
  • Primary slot – For running the CM0+ and CM4 user projects
  • Secondary slot – For storing the new dual-CPU firmware image
  • Scratch (Supported only on PSoC™6 2M) – For supporting MCUboot swap-based upgrade operation. See Swap-based upgrade for PSoC™ 6 MCU for more information.

The flash memory layout is illustrated as follows for different memory variants of PSoC™ 62/63:

Figure 11. Flash memory layout

Flash memory layout

SRAM memory layout

The SRAM has been divided into the following sections:

  • CM0+ bootloader/app – Scratch-pad memory for CM0+ bootloader or CM0+ user project. Note that this is shared because the SRAM region can be reused between the bootloader and the CM0+ user projects.
  • Shared SRAM – Used by both the CM0+ and CM4 for sharing any data.
  • CM4 app – Scratchpad memory for CM4 project.

The SRAM memory map is illustrated below for different memory variants of PSoC™ 62/63:

Figure 12. SRAM memory layout

SRAM memory layout

Configuring the common make variables

This section explains the important make variables common to all three applications that affect their functionality. You can either update these variables directly in the Makefile or pass them along with the make build command.

Build control variables

Table 2. Build control variables

Variable Default value Description
IMG_TYPE BOOT Valid values: BOOT, UPGRADE
BOOT: Use when the image is built for the primary slot. The --pad argument is not passed to the imgtool.
UPGRADE: Use when the image is built for the secondary slot. The --pad argument is passed to the imgtool.
Also, the CM0+ blinky project defines the LED toggle delay differently depending on whether the image is BOOT type or UPGRADE type.
SWAP_UPGRADE 0 Set this to '0' when the upgrade image needs to be overwritten into the primary slot. Swap-based upgrade is not supported in this code example. It is left to the user to implement it using PSoC™6 MCU: MCUboot-based basic bootloader code example as reference.
USE_EXT_FLASH 0 Set this to '0' when the image needs to be built for the external flash. This affects the value used for padding by the imgtool. The padding value is '0' for the internal flash and 0xff for the external flash. This code example does not support using an external flash. Setting this to '1' will require changes that are left to the user.
USE_CRYPTO_HW 1 When set to '1', Mbed TLS uses the crypto block in PSoC™ 6 MCU for providing hardware acceleration of crypto functions using the cy-mbedtls-acceleration library
KEY_FILE_PATH ../proj_btldr_cm0p/keys Path to the private key file. Used with the imgtool for signing the image
APP_VERSION_MAJOR
APP_VERSION_MINOR
APP_VERSION_BUILD
1.0.0 if IMG_TYPE=BOOT
2.0.0 if IMG_TYPE=UPGRADE
Passed to the imgtool with the-v option in MAJOR.MINOR.BUILD format, while signing the image. Also available as macros to the application with the same names.
SIGN_KEY_FILE_ECC cypress-test-ec-p256 Name of the ECC private and public key files (the same name is used for both keys)
SIGN_KEY_FILE_RSA cypress-test-rsa-2048 Name of the RSA private and public key files (the same name is used for both keys)

Memory layout variables

Based on the values set for the variables listed below, the common.mk file calculates the start addresses and offsets, and defines the symbols to be used by the linker scripts.

Table 3. Memory layout variables

Variable Default value
(512K)
Default value
(1M)
Default value
(2M)
Description
CM0P_BTLDR_FLASH_SIZE 0x1C000 0x1C000 0x1C000 Flash size of the bootloader project run by CM0+.
In the linker script for the bootloader project (CM0+), the LENGTH of the flash region is set to this value.
PROTECTED_MEM_SIZE 0x4000 0x4000 0x4000 Flash size of the protected memory section
CM0P_APP_FLASH_SIZE 0x10000 0x20000 0x20000 Flash size of the blinky user project run by CM0+.
In the linker script for the user project (CM0+), the LENGTH of the flash region is set to this value.
CM4_APP_FLASH_SIZE 0x20000 0x50000 0xC0000 Flash size of the user project run by CM4.
In the linker script for the user project (CM4), the LENGTH of the flash region is set to this value.
CM0P_BTLDR_SRAM_SIZE 0x10000 0x10000 0x30000 RAM size of the bootloader project run by CM0+.
In the linker script for the bootloader project (CM0+), LENGTH of the ram region is set to this value.
CM0P_APP_SRAM_SIZE 0x10000 0x10000 0x30000 RAM size of the blinky user project run by CM0+.
In the linker script for the blinky user project (CM0+), LENGTH of the ram region is set to this value.
SHARED_SRAM_SIZE 0x8000 0x8000 0x10000 RAM size for shared scratchpad region for user projects run by CM0+/CM4.
CM4_APP_SRAM_SIZE 0x27800 0x27800 0xBF800 RAM size of the user project run by CM4.
In the linker script for the user project (CM4), LENGTH of the ram region is set to this value.
In the linker script for the user project (CM4), the ORIGIN of the ram region is offset to this value, and the LENGTH of the ram region is calculated based on this value.
MCUBOOT_SCRATCH_SIZE NA NA 0x20000 Size of the scratch area used by MCUboot while swapping the image between the primary slot and secondary slot. Scratch area is required for swap-based upgrade. Note that this is not used in the code example but exists to support swap-based upgrade when implemented.
MCUBOOT_HEADER_SIZE 0x400 0x400 0x400 Size of the MCUboot header. Must be a multiple of 1024 (see the note below).
Used in the following:
1. In the linker script for the user project (CM0+), the starting address of the.text section is offset by the MCUboot header size from the ORIGIN of the flash region. This is to leave space for the header that will be later inserted by the imgtool during post-build steps.
2. Passed to the imgtool while signing the image. imgtool fills the space of this size with zeroes (or 0xFF depending on internal or external flash) and then adds the actual header from the beginning of the image.
MCUBOOT_SECTOR_SIZE 512 512 512 Flash row size; used only when swap upgrade is enabled.
MCUBOOT_MAX_IMG_SECTORS 128 128 128 Maximum number of flash sectors (or rows) per image slot for which swap status is tracked in the image trailer. This value can be simply set to MCUBOOT_SLOT_SIZE/MCUBOOT_SECTOR_SIZE. For PSoC™ 6 MCUs, MCUBOOT_SECTOR_SIZE=512 bytes. When MCUBOOT_SLOT_SIZE=0x10000, MCUBOOT_MAX_IMG_SECTORS would be 128 (0x10000/512). The minimum number of sectors accepted by the MCUboot library is 32, so MCUBOOT_MAX_IMG_SECTORS is set to 32 if MCUBOOT_SLOT_SIZE/MCUBOOT_SECTOR_SIZE is less than 32.

Used in the following:
1. In the common.mk file, this value is used in DEFINE+= to override the macro with the same name in mcuboot/boot/cypress/MCUBootApp
/config/mcuboot_config/mcuboot_config.h
.
2. In the CM4 user project Makefile, this value is passed with the -M option to the imgtool while signing the image. imgtool adds padding in the trailer area depending on this value.
MCUBOOT_IMAGE_NUMBER 1 1 1 The number of images supported in the case of multi-image bootloading. This code example supports only one image.

Bootloader implementation

The bootloader is designed based on the PSoC™ 6 MCU: MCUboot-based basic bootloader repo in GitHub. It is customized in this example to configure system security.

MCUboot effectively divides the memory into primary and secondary slots for the user application. This code example uses a custom memory map. To achieve this, CY_FLASH_MAP_EXT_DESC is defined in the common.mk file to override the default memory map. The custom memory partitions are then defined in the proj_btldr_cm0p/source/cy_flash_map.h file.

The user image running in the primary slot is a combination of CM0+ and CM4 projects and is directly programmed into the internal flash to quickly evaluate the MCUboot operation.

Note: This example does not support programming the user image into the external flash. The example should be modified to support this if required. See mtb-example-psoc6-mcuboot-basic to understand how this can be done.

The upgrade application that can download the upgrade image over a wired or wireless communication interface will write the image into the secondary slot. This code example uses UART wired transfer for downloading the upgrade image. For wireless transfers, see mtb-example-anycloud-ota-mqtt which is implemented using the anycloud-ota middleware.

This code example uses ModusToolbox™ software resources such as BSPs and PSoC™ 6 MCU to provide a rich development experience that aligns well with other code examples based on ModusToolbox™ software. Figure 13 shows the execution flow of the code example.

Figure 13. Boot flow

Boot flow

The MCUboot bootloader project is considered the "secure" project and is responsible for setting up the protection units, the TOC2 and eFuse values for lifecycle mode transitions and access restrictions.

MCUboot basics

MCUboot is a library that helps to implement secured bootloader applications for 32-bit MCUs.

MCUboot works by dividing the flash into two slots per image – primary and secondary. The first version of the application is programmed into the primary slot during production. A firmware update application running in the device receives the upgrade image over a wired or wireless (over-the-air or OTA) communication interface and places it in the secondary slot. This slot-based partition helps in read-/write-protecting the primary slot from a less privileged application.

Typically, a bootloader application executes in secured mode and is privileged to access the primary slot while a less-privileged application such as an OTA application cannot access the primary slot, but it can access the secondary slot.

MCUboot always boots from the primary slot and copies the image from the secondary slot into the primary slot when an upgrade is requested. The upgrade can be either overwrite-based or swap-based. In an overwrite-based upgrade, the image in the primary slot is lost and there is no way to roll back if the new image has an issue. In a swap-based upgrade, the images are swapped between the two slots and a rollback is possible. In this case, MCUboot makes use of an additional area in the flash called scratch area for reliable swapping. MCUboot for PSoC™ 6 MCU supports both swap-based and overwrite-based upgrades.

Each image slot contains the metadata which is used by MCUboot to determine the current state and what actions should be taken during the current boot operation. In the case of an upgrade image, the img_ok field is updated by the application to make the current image permanent in the primary slot. See image trailer for more details.

MCUboot implements reset recovery and can resume the copy operation if a reset or power failure occurs in the middle. MCUboot also supports multi-image bootloading where several pairs of primary and secondary slots can exist. In this case, MCUboot can update each image independently; that is, update the image in any primary slot using the image from the corresponding secondary slot. However, MCUboot always boots from the primary slot of image 0. The image 0 application, once booted, can boot other images as required.

Swap-based upgrade for PSoC™ 6 MCU

There are three types of swap modes supported in MCUboot – scratch, move, and using a status partition. Only swap mode using status partition can be used with PSoC™ 6 MCU devices because of the hardware restriction of the large minimum flash write/erase size.

The MCUboot library is designed with the minimum flash to write/erase size to be 8 bytes or less. This is to ensure that data is not lost when writing to the flash sector status so that it is a single-cycle operation ensuring the robustness of the application.

Because PSoC™ 6 MCU devices have large minimum flash write/erase size, swap using status partition has been implemented. Using this algorithm, a separate area in the internal flash is used to store swap status values and the image trailer data such as the swap size and info, boot image magic value, and the 'image ok' field.

In overwrite mode, the image trailer is added to the end of the application image. The Cy_DFU_ValidateApp function in the proj_cm4/source/dfu_user.c file, part of the CM4 user project, is responsible for validating the image received. The function iterates through the image header and image trailer to find the hash and signature to be verified.

A +---------------------+
  | Header              | <- struct image_header
  +---------------------+
  | Payload             |
  +---------------------+
  | TLV area            |
  | +-----------------+ |    struct image_tlv_info with
  | | TLV area header | | <- IMAGE_TLV_PROT_INFO_MAGIC (optional)
  | +-----------------+ |
  | | Protected TLVs  | | <- Protected TLVs (not used)
B | +-----------------+ |
  | | TLV area header | | <- struct image_tlv_info with IMAGE_TLV_INFO_MAGIC
C | +-----------------+ |
  | | SHA256 hash     | | <- Hash from A - B
D | +-----------------+ |
  | | Keyhash         | | <- Indicates which pub. key for sig
  | +-----------------+ |
  | | Signature       | | <- Signature from C - D, only hash
  | +-----------------+ |
  +---------------------+

However, in swap-based upgrade, the image header and trailer are not added to the end of flash but instead assigned a separate area in the internal flash. It is left to the user to modify the Cy_DFU_ValidateApp function to support swap-based upgrade. The code example does not support swap-based upgrade by default.

See the "Swap status partition description" section of the MCUboot app documentation.

See MCUboot design documentation for details.

Flash map/partition

Figure 14 shows the default flash map or partition used with MCUboot. The partitions need not be contiguous in the memory because it is possible to configure the offset and size of each partition. However, the offset and the size must be aligned to the boundary of a flash row or sector. For PSoC™ 6 MCUs, the size of a flash row is 512 bytes. Also, the partition can be in either the internal flash or external flash.

The memory partition is described or defined through a flash map (a data structure). It is important that the bootloader project and the dual-CPU user projects agree on the flash map. This example uses a shared file (common.mk) between the three apps so that they can use the same set of flash map parameters. See Customizing the flash map for more details.

Figure 14. Typical flash map

Typical flash map

Customizing the flash map

A default flash map is defined through the boot_area_descs variable in the libs/mcuboot/boot/cypress/cy_flash_pal/cy_flash_map.c file; this variable is constructed using the macros defined in the libs/mcuboot/boot/cypress/MCUBootApp/sysflash/sysflash.h file.

You can either configure the parameters such as the bootloader size and slot size that constitute the default flash map or completely override the default flash map.

Because this code example required a custom flash map, the following modifications were done:

  • Added DEFINES+=CY_FLASH_MAP_EXT_DESC in the common.mk file.
  • Defined and initialized the struct flash_area *boot_area_descs[] variable using the proj_btldr_cm0p/source/cy_flash_map.h file to create the custom flash map.

See Table 3. Memory layout variables for details on configuring these parameters.

Configuring bootloader make variables

This section explains the important make variables in the Makefile that affect the MCUboot functionality. You can either update these variables directly in the Makefile or pass them along with the make build command.

The make variables depend on the values set in the common.mk file. The variables mostly define the MCUboot files to include for the build. Additionally, it contains make targets for key generation as explained in the Generating a key-pair section.

The post-build steps generate the SHA-256 digest and then sign it with the RSA-2048 private key to generate the signed HEX file. The original HEX file is overwritten with the signed HEX file so that programming of the HEX can be done directly without any modifications to OpenOCD configurations.

CM0+ blinky user project implementation

The CM0+ blinky user project toggles an LED at an interval decided by the value of IMG_TYPE.

Table 4. LED intervals for different image types

IMG_TYPE LED interval
BOOT 1000 ms
UPGRADE 250 ms

The LED pin mapping for different BSPs is as shown below.

Table 5. Blinky LED pin assignment

BSP LED pin
CY8CKIT-062-BLE P1_5
CY8CKIT-062-WIFI-BT P1_5
CY8CPROTO-062-4343W P13_7
CY8CKIT-062S2-43012 P1_5
CY8CPROTO-063-BLE P6_3
CY8CPROTO-062S3-4343W P11_1

Additionally, it also demonstrates how protected storage and IPC can be implemented.

Protected storage

Protected storage is an area in the flash that can be used to store any critical data or keys that should be accessed only by the secure CM0+ processor. This area has been protected using SMPUs to allow access only to CM0+. This data can be exchanged with CM4 if needed via IPC.

In this code example, dedicated IPC channels 8 and 9 are assigned to CM0+ and CM4 respectively. Interrupts are set up on both cores to receive the notify and release interrupts.

IPC System Pipes must be placed in the shared SRAM so that both the cores can access them. IPC system pipes are placed in the .cy_sharedmem section of the memory by default if the section is defined in the linker script. This section has been defined in the linker script to be part of the last 8 KB of the shared SRAM.

Additionally, user IPC semaphores used for message passing need to be placed in the shared SRAM so that both the cores can access them. For this reason, another section (.shared_ram) is defined in the shared SRAM.

Shared SRAM distribution is as follows:

Figure 15. Shared SRAM distribution

Shared SRAM distribution

The linker scripts define the placement of both these sections and their respective sizes.

IPC_SYSTEM_PIPES_SIZE = 0x2000;

MEMORY
{
   ...
   shared_ram        (rwx)   : ORIGIN = SHARED_SRAM_START, LENGTH = SHARED_SRAM_SIZE
   ...
}

SECTIONS
{
   ...
   ...

    .shared_ram (NOLOAD):
    {
        . = ALIGN(4);
        __shared_ram_start__ = .;
        KEEP(*(.shared_ram))
        . = ALIGN(4);
        __shared_ram_end__ = .;
    } > shared_ram

    .cy_sharedmem ORIGIN(shared_ram) + LENGTH(shared_ram) - IPC_SYSTEM_PIPES_SIZE (NOLOAD):
    {
        . = ALIGN(4);
        __public_ram_start__ = .;
        KEEP(*(.cy_sharedmem))
        . = ALIGN(4);
        __public_ram_end__ = .;
    } > shared_ram

    ...
    ...
}

CM0+ sets up its IPC channels and interrupts, and then proceeds to toggle the LED. When a message is received on channel 8 from CM4, the interrupt callback is triggered and the device ID data stored in the protected storage is sent to CM4 on channel 9. This is a simple demonstration of how IPCs can be used. This can be expanded based on user application.

Configuring CM0+ project make variables

This section explains the important make variables in the Makefile that affect the CM0+ user project functionality. You can either update these variables directly in the Makefile or pass them along with the make build command.

In the proj_cm0p Makefile, the following line was added to specify the application CPU:

CORE=CM0P

If you intend to use the design.modus-generated code in CM0+, add BSP_DESIGN_MODUS to COMPONENTS= in the CM0+ Makefile.

The following defines were added for use in the project:

Table 6. Variables defined in the application

Variable Default value Description
KIT_NAME APPNAME with '-' replaced with '_' Used to specify the kit used in the project
CY_CORTEX_M4_APPL_ADDR CM4_APP_FLASH_START Specifies the start address of the CM4 project. The CM4_APP_FLASH_START value is supplied by the common.mk file.
CY_IPC_DEFAULT_CFG_DISABLE 1 Disables the default IPC configuration that comes with the BSP

CM4 FreeRTOS user project implementation

The example uses FreeRTOS to set up a dfu_task and call the scheduler. The dfu_task execution flow is as follows:

  1. Initialize the DFU
  2. Set up IPC pipes on CM4 to request the unique device ID from CM0+
  3. Initialize the DFU status LED
  4. Initialize retarget-io for UART debug logs
  5. Start DFU transport
  6. Request unique device ID from CM0+ using IPC pipes
  7. Enter a while loop and wait for IPC callback or DFU host commands

The DFU status LED and UART pin mapping for different BSPs are as follows:

Table 7. DFU status LED and UART connections

BSP LED pin UART pin TX UART pin RX
CY8CKIT-062-BLE P13_7 P13_1 P13_0
CY8CKIT-062-WIFI-BT P13_7 P13_1 P13_0
CY8CPROTO-062-4343W N/A P13_1 P13_0
CY8CKIT-062S2-43012 P11_1 P12_1 P12_0
CY8CPROTO-063-BLE P7_1 P9_1 P9_0
CY8CPROTO-062S3-4343W N/A P3_1 / B_RX P3_0 / B_TX

The DFU UART requires an external USB-to-UART bridge to be connected to communicate with your PC. You can either use a snapped-out KitProg3 board or MiniProg4 or any FTDI USB-UART converters for this purpose. The connections are as follows:

MiniProg4 connections

The MiniProg 3/4 UART connections are found on the 6x2 connector. See the MiniProg4 user guide for more information.

Table 8. MiniProg4 UART connections

6x2 connector pin index 6x2 connector pin name PSoC™6 BSP
1 VTARG P6_VDD
12 GND GND
8 RX UART pin TX
6 TX UART pin RX

KitProg3 connections

Table 9. KitProg3 UART connections

KitProg3 pins PSoC™6 BSP
VTARG P6_VDD
GND GND
RX UART pin TX
TX UART pin RX

FTDI USB-UART converters

Table 10. FTDI USB-UART connections

Converter Pins PSoC™6 BSP
RX UART pin TX
TX UART pin RX

Protected storage

CM4 can access critical data stored in the protected storage area by requesting it from CM0+ via IPC.

In this code example, dedicated IPC channels 8 and 9 are assigned to CM0+ and CM4 respectively. Interrupts are set up on both cores to receive the notify and release interrupts.

CM4 sets up its IPC channels and interrupts, and then sends a message to CM0+ on channel 8 requesting for the device ID. The device ID sent on channel 9 by CM0+ is received by CM4 which is then printed on the serial terminal. This is a simple demonstration of how IPCs can be used. This can be expanded based on the user application.

Device Firmware Update (DFU)

The dfu_task continuously monitors the UART channel for host commands to initiate the DFU transfer. When the DFU transfer is initiated by the host, the data is received via UART and written into the secondary slot.

Because this application uses MCUboot, the trailer of the upgrade image has the following format:

A +---------------------+
  | Header              | <- struct image_header
  +---------------------+
  | Payload             |
  +---------------------+
  | TLV area            |
  | +-----------------+ |    struct image_tlv_info with
  | | TLV area header | | <- IMAGE_TLV_PROT_INFO_MAGIC (optional)
  | +-----------------+ |
  | | Protected TLVs  | | <- Protected TLVs (not used)
B | +-----------------+ |
  | | TLV area header | | <- struct image_tlv_info with IMAGE_TLV_INFO_MAGIC
C | +-----------------+ |
  | | SHA256 hash     | | <- Hash from A - B
D | +-----------------+ |
  | | Keyhash         | | <- Indicates which pub. key for signature.
  | +-----------------+ |
  | | Signature       | | <- Signature from C - D; only hash.
  | +-----------------+ |
  +---------------------+

Once the upgrade image is received, the execution iterates through the trailer to get the image size, hash, and signature to do the validation. The public key located in the ecc-public-key-p256.h file is used for the verification. The Cy_DFU_ValidateApp function in the dfu_user.c file implements this logic. See the following for detailed series of steps used to validate the image:

Figure 16. DFU upgrade image validation flow

DFU upgrade image validation

Note: The public key generated using imgtool is in DER format. Crypto APIs require the keys to be in ASN.1 format. Therefore, the public key is converted from DER to ASN.1 format before passing it to crypto APIs. See the extract_pub_key function in the dfu_user.c file to learn more.

Configuring CM4 project make variables

This section explains the important make variables in the Makefile that affect the CM4 user project functionality. You can either update these variables directly in the Makefile or pass them along with the make build command.

The following defines were added for use in the project:

Table 11. CM4 make variables

Variable Default value Description
HEADER_OFFSET 0 Starting address of the CM0+/CM4 user projects or the offset at which the header of an image begins. Image = Header + CM0+ project + CM4 project + TLV + trailer.
New relocated address = ORIGIN + HEADER_OFFSET
ORIGIN is defined in the CM0+ linker script and is usually the address next to the end of the bootloader image.
KEY_FILE_PATH proj_btldr_cm0p/keys Path to the keys folder
APP_VERSION_MAJOR
APP_VERSION_MINOR
APP_VERSION_BUILD
1.0.0 if IMG_TYPE=BOOT
2.0.0 if IMG_TYPE=UPGRADE
Passed to the imgtool with the-v option in MAJOR.MINOR.BUILD format, while signing the image. Also available as macros to the application with the same names.
COMPONENTS FREERTOS
CUSTOM_DESIGN_MODUS
Includes the FreeRTOS library and uses a custom design.modus file
DISABLE_COMPONENTS CM0P_SLEEP
BSP_DESIGN_MODUS
Disables using pre-built CM0+ image and default BSP design.modus file
CY_IPC_DEFAULT_CFG_DISABLE 1 Disables the default IPC configuration that comes with the BSP

Each project should have its own deps folder. If the same library is used by both projects, it should be in the deps folder of both projects. If the library location is specified as the shared asset repo in the mtb file (which is by default), they will both automatically access it from the shared location.

When the CM4 project is built, it builds both the CM0+ and CM4 projects; the resulting build artifacts contain code for both projects. When the user image starts, the CM0+ project starts first. It is responsible for starting CM4.

Security overview

In this code example, the bootloader is responsible for setting up the security for the entire system. See AN221111 – PSoC™ 6 MCU: Designing a secured system for detailed information.

Secured boot

The boot parameters are specified using the TOC2 structure variable cy_toc2 in the proj_btldr_cm0p/source/main.c file.

Table 12. TOC2 contents

Parameter Description
Object size Size of the application image in bytes
Magic number TOC2 ID (magic number = 0x1211220)
User key address Address of the user key
SMIF configuration address SMIF configuration structure (optional)
Application 1 address First user application address
Application 1 format First user application format (only CYSAF supported)
Application 2 address Second user application address
Application 2 format Second user application format (only CYSAF supported)
Secure hash objects Number of hash objects to be included for verification
Signature key address Address of the signature key (public key used to sign the bootloader image)
Additional objects Additional objects to be included in secure hash
TOC2 flags Flags in TOC to control the flash boot options
CRC CRC16-CCITT checksum of the TOC2 structure

In this code example, the TOC2 structure is set to the following:

/* TOC2 in SFlash */
CY_SECTION(".cy_toc_part2") __USED static const cy_stc_ps_toc_t cy_toc2 =
{
		.objSize     = sizeof(cy_stc_ps_toc_t) - sizeof(uint32_t),  /* Object Size (Bytes) excluding CRC */
		.magicNum    = CY_PS_TOC2_MAGICNUMBER,                      /* TOC2 ID (magic number) */
		.userKeyAddr = (uint32_t)&CySecureKeyStorage,               /* User key storage address */
		.smifCfgAddr = 0UL,                                         /* SMIF config list pointer */
		.appAddr1    = CY_START_OF_FLASH,                           /* App1 (MCUBoot) start address */
		.appFormat1  = CY_PS_APP_FORMAT_CYPRESS,                    /* App1 Format */
		.appAddr2    = 0,                                           /* App2 (User App) start address */
		.appFormat2  = 0,                                           /* App2 Format */
		.shashObj    = 1UL,                                         /* Include public key in the SECURE HASH */
		.sigKeyAddr  = (uint32_t)&SFLASH->PUBLIC_KEY,               /* Address of signature verification key */
		.tocFlags    = CY_PS_FLASHBOOT_FLAGS,                       /* Flashboot flags stored in TOC2 */
		.crc         = 0UL                                          /* CRC populated by cymcuelftool */
};

Note: Application 1 here is the MCUboot bootloader and Application 2 is the user application. Passing the start address tells flash boot to validate the images before passing control to them. In this code example, because MCUboot is responsible for validating and launching the user application images, the Application 2 start address is not passed and therefore set to '0'.

Protection units

The flash and SRAM are divided into different sections as follows:

Figure 17. Protection unit memory map (device with 1-MB flash)

Protection unit memory map

Each section is protected using the shared memory protection unit (SMPU) with a pre-defined protection context (PC). The following table shows the protection units configured in this example for a PSoC™ 6 MCU device with 1 MB of flash.

Table 13. Protection units configuration for 1M devices

Section Bus master Memory SMPU Start address Size Access attributes Secure Protection context
CM0+ bootloader CM0+ Flash 13 0x1000_0000 112 KB R/X Yes PC = 1,2
Protected memory CM0+ Flash 7 0x1001_C000 16 KB R/W/X Yes PC = 2
CM0+ Project CM0+ Flash 11 0x1002_0000 128 KB R/W/X Yes PC = 1,2
CM4 Project + Secondary slot CM4 Flash 9 0x1004_0000 320 KB + 448K R/W/X No PC = 1,4
CM0+ bootloader / User Project CM0+ SRAM 12 0x0800_0000 64 KB R/W/X Yes PC = 1,2
Shared SRAM CM0+ / CM4 SRAM 10 0x0801_0000 32 KB R/W No PC = 1,2,4
CM4 SRAM CM4 SRAM 5 0x0801_8000 160 KB R/W/X No PC = 4

Applications using other PSoC™ 6 MCU devices have a similar SMPU protection unit configuration with changes in start addresses and regions sizes.

Figure 18. Protection unit memory map (device with 2-MB flash)

Protection unit memory map (device with 2-MB flash)


Figure 19. Protection unit memory map (device with 512-KB flash)

Protection unit memory map (device with 512-KB  flash


Note: If the device has 288 KB of SRAM, use SRAM_SIZE = 256 KB instead.

The CM0+ CPU configures all the SMPU and PC. It also configures the bus master to be assigned to a PC. To learn how to configure the SMPU, see this blog post. Once all the protection units are configured, CM0+ transitions the following bus masters to their respective PC values:

Table 14. Protection contexts assignment

Bus master PC
CM0+ 1
CM4 4
Test controller 5

Once the CM0+ bus master's PC is set to '1', it locks all the protections in place.


eFuse programming for debug access restrictions and lifecycle

eFuses are responsible for lifecycle transitions and access restrictions for each lifecyle. See the AN221111 – PSoC™ 6 MCU: Designing a secured system for information on eFuse settings and offsets.

Programming the eFuses is irreversible and care should be taken to verify the settings before blowing them. Incorrect settings may brick the device permanently.

To program the eFuse, the following steps should be followed.

  1. Open Cypress™ Programmer. Connect to the kit and click Erase. This erases any prior configuration residing on the flash and SFlash.

  2. Build and program the CM0+/CM4 dual-CPU user projects by selecting either the primary_app.hex or primary_app_boot.hex file in Cypress™ Programmer.

    Note: It is important to have the user image programmed before the bootloader is programmed. This is because the bootloader programs the eFuses. If programmed first, the bootloader will lock down the debug ports and the user image can no longer be programmed.

  3. Edit the proj_btldr_cm0p/source/cy_ps_efuse.h file and set the CY_EFUSE_AVAILABLE macro to '1'. This step causes the eFuse data to be included in the HEX file.

    #define CY_EFUSE_AVAILABLE 1
    
  4. Verify the eFuse configuration defined in cy_efuse_data.

  5. Clean and build the proj_btldr_cm0p project.

  6. Open Cypress™ Programmer and select the proj_btldr_cm0p.hex file along with the following settings:

    1. Select Program Security Data.
    2. Set the voltage to 2.5 V (Note: This option isn't visible for all BSPs. In such cases, set the VTARG jumpers to 2.5 V on the kit.)
    3. Set SFlash restrictions to "Erase/Program USER/TOC/KEY allowed".

    Note: Cypress™ Programmer will indicate the current operating voltage at the bottom right as highlighted in the figure. If you do not see 2.5 V even after setting the Voltage option to 2.5 V, check if the kit has a VDD select switch / jumper and change it to 2.5 V or 1.8 V - 3.3 V variable voltage.


    Figure 20. Programming eFuse using Cypress™ Programmer

    Programming eFuse using CYPRESS™ Programmer

  7. Program the kit.

    Once programming is complete, a reset will be executed. If the eFuses are configured to disable the debug ports, Cypress™ Programmer will not be able to connect to the kit indicating successful locking of the debug ports. The current lifecycle stage will be indicated in the serial terminal.

Note: In SECURE lifecycle mode, if secure access restrictions are set to enable debug access ports, you must configure the GPIOs for the debugger to get access to the debug ports. This is demonstrated in the configure_swj function in proj_btldr_cm0p/source/main.c. By default, this function is disabled, but can be enabled by setting the CONFIGURE_SWJ_PINS macro to '1'.

#define CONFIGURE_SWJ_PINS    (1u)

MCUboot security

MCUboot checks the image integrity with SHA-256, and image authenticity with digital signature verification. Multiple signature algorithms are supported; this example enables ECDSA SECP256R1 (EC256) by default. MCUboot uses the Mbed TLS library for cryptography.

PSoC™ 6 MCU supports hardware-accelerated cryptography based on the Mbed TLS library via a shim layer. The cy-mbedtls-acceleration library implements this layer.

Hardware-accelerated cryptography shortens the boot time by more than four times compared to the software implementation (observation results). To enable it in the bootloader project, set USE_CRYPTO_HW=1 in the common.mk file. This is enabled by default.

MCUboot verifies the signature of the image in the primary slot every time before booting if MCUBOOT_VALIDATE_PRIMARY_SLOT is defined. In addition, it verifies the signature of the image in the secondary slot before copying it to the primary slot.

This example enables image authentication by uncommenting the following lines in the proj_btldr_cm0p/libs/mcuboot/boot/cypress/MCUBootApp/config/mcuboot_config/mcuboot_config.h file:

#define MCUBOOT_SIGN_EC256
#define NUM_ECC_BYTES (256 / 8)
.
.
.
#define MCUBOOT_VALIDATE_PRIMARY_SLOT

When these options are enabled, the public key is embedded within the bootloader project. The dual-CPU user project is signed using the private key during the post-build steps. The imgtool Python module included in the MCUboot repository is used for signing the image.

This example includes a sample key-pair under the proj_btldr_cm0p/keys directory. You must not use this key-pair in your end-product. See Generating a key-pair for generating a new key-pair.

Generating a key-pair

Key generation is supported directly by make commands defined in proj_btldr_cm0p/Makefile.

To execute the make commands, open "modus-shell" in Windows or any terminal application in macOS/Linux. In Eclipse IDE, modus-shell can be accessed directly in the terminal window.

Navigate to the proj_btldr_cm0p project folder.

cd <workspace_path>/mtb-example-psoc6-security/proj_btldr_cm0p/

The make commands support ECC and RSA key generation as listed below.

Generating an RSA key-pair

  1. In the terminal, run the following command:

    make rsa_keygen
    

    The RSA private key rsa_private_generated.txt is generated in the proj_btldr_cm0p/keys folder. The RSA public key is generated in a file named rsa_to_c_generated.txt. The contents of the rsa_private_generated.txt file are automatically copied over to the cypress-test-rsa-2048.pem file.

  2. Copy the .moduleData[], .expData[], .barrettData[], .inverseModuleData[], and .rBarData[] arrays from rsa_to_c_generated.txt and replace the ones in proj_btldr_cm0p/source/cy_ps_keystorage.c.

    The names of the files used for signing user application images can be modified by changing the SIGN_KEY_FILE_RSA variable in common.mk file.

    Note: If you run only the make rsa_keygen script but do not copy the updated C code to the cy_ps_keystorage.c file, your secured boot will fail because the image is signed with a newer private key that is not compatible with the older public key.

    Figure 21. Generating the RSA key

    Generating the RSA key

Generating the ECC key-pair

  1. In the terminal, run the following command:

    make ecc_keygen
    

    This creates the following files in the proj_btldr_cm0p/keys folder:

    • cypress-test-ec-p256.pem (private key)
    • cypress-test-ec-p256.pub (public key in a C-like array)
    • ecc-public-key-p256.h (public header file in a C-like array)
  2. Copy the contents of cypress-test-ec-p256.pem to ecc-private-key-p256.h in a string-based format.

This header file can be used for establishing the identity during transactions with any host. Note that the code example does not use it; it is left to the users for implementing it based on their use case.

The Cy_DFU_ValidateApp function in proj_cm4/source/dfu_user.c part of the CM4 user project makes use of the public key generated in ecc-public-key-p256.h for validating the image received.

The names of the files generated can be modified by changing the SIGN_KEY_FILE_ECC variable in common.mk except the public key header file name (ecc-public-key-p256.h) which is kept constant and cannot be changed because it is included as a header file in the application.

Figure 22. Generating the ECC key

Generating the ECC key

Return Merchandise Authorization (RMA) mode

This feature demonstrates how to transition the PSoC™ 61/62 MCU from "SECURED"/”SECURED_WITH_DEBUG” to the "RMA" lifecycle stage. The RMA lifecycle stage can be used by customers to return the parts to Infineon for failure analysis.

CAUTION: After transitioning the PSoC™ 62 MCU into RMA stage, it cannot be converted back into other lifecycle stages.

To transition a device to the RMA stage, you must have access to the following:

  • The device unique ID (12 bytes)
  • Private key that is paired with a public key stored and authenticated in SFlash.

Follow the steps below to put the device in RMA mode

  1. Read the device unique ID by running the Security Template code example. When the CM4 code executes, it displays a 12-byte device unique ID stored in the device SFlash on the termimal as shown in Figure 23.

Figure 23. Device unique ID

Device Unique ID

  1. Generate RMA certificate using the device unique ID mentioned in Step-1 and the your private key paired with the public key stored internally in SFlash. Refer the below steps to generate RMA certificate

    Pre-requisites: Openssl 1.0.2 or higher and gcc 11.3.0 (any version is fine)

  • Open the rma_certificate_generation folder present in .\proj_cm4 directory.
  • Replace the Public/Private key pair in the rma_certificate_generation folder with your public/private key pair present in ./proj_btldr_cm0p/keys. Please use the same existing file names for the keys so that the script works properly. Also, this key pair should be the same that is stored in SFlash public key area used to sign/verify the application
  • Run Ubuntu shell (any shell that has gcc) from "rma_certificate_generation" folder.
  • Now, Run sudo ./generate_cert_script.sh "0x018ba21d" "0x012f2a13" "0x007a030d"in the shell. 0x018ba21d 012f2a13 007a030d is the 12-byte unique device ID that is printed as part of proj_cm4 project. This uniquie ID remains unique for each silicon.
  • After the script completes execution, certificate.c file is created in the same folder and should have the certificate details.
  • Copy the contents of certificate.c file to proj_cm4\main.c file by replacing the existing certificate..
  1. Change the TRANSITION_TO_RMA flag from 0 to 1 in ./proj_cm4/Makefile to enable the RMA functionality and make the changes in the code to transition the device to SECURE/SECURE_WITH_DEBUG lifecycle as mentioned in eFuse programming for debug access restrictions and lifecycle section above.
  2. Once the above steps are followed, build and flash the binary. The device VDDIO0 supply must be at 2.5 V while programming the binaries, because the RMA eFuse is to be programmed. (Any programming of eFuse bits requires the VDDIO0 to be 2.5 V). After the device is reset or power cycled, it boots up in SECURE/SECURE WITH DEBUG life cycle mode, displays the lifecycle state on terminal and immediately moves to RMA state.

Figure 24. RMA transition

RMA successful log 5. Once the device successfully enters the RMA mode, we can not see any logs on the shell as the ports are disabled in RMA. Also, the device does not connect via Cypress Programmer while in RMA mode. 6. In RMA failure case, it prints the syscall failure code. The failure codes are explained in the TRM document.

Note: It is upto the customer to erase any sensitive date or proprietary code stored in the device before transition to RMA mode. Erase the flash at least four times to ensure there is no way to detect any residual code. The public key stored in SFlash must remain because it is used to transition to the RMA lifecycle stage and to allow Infineon to open the RMA later.

After you have performed these steps, you can send the device and certificate.c file to Infineon to allow failure analysis. Note that this certificate is unique to the part for which it was generated.

Pre- and post-build steps

Bootloader project: Pre-build steps

The pre-build steps are specified through the PREBUILD variable in proj_btldr_cm0p/Makefile.

  1. Initialize the Git submodules for MCUboot: This is required because the make getlibs command currently does not support initializing Git submodules while cloning a repo. This step executes only if the libs/mcuboot/ext/mbedtls directory (a submodule) does not exist or if the contents of the directory are empty.

Bootloader project: Post-build steps

The post-build steps are specified through the POSTBUILD variable in proj_btldr_cm0p/Makefile. The following actions are performed:

  1. Creates a backup of the original HEX and ELF files with the suffix "_unsigned" added to the filename

  2. Deletes the original HEX and ELF file

  3. Signs the "_unsigned.elf" file with the RSA-2048 private key using CyMCUElfTool to create the signed HEX and ELF files. These files are named the same as the original HEX and ELF files. This is because OpenOCD configurations use the APPNAME.hex/elf for programming and debugging.

CM0+/CM4 dual-CPU user projects: Post-build steps (for development)

The proj_cm4 project build includes the proj_cm0p image. Therefore, the the post-build steps are specified through the POSTBUILD variable only in proj_cm4/Makefile.

These steps generate the signed version of the image in HEX format using the imgtool Python module. The SIGN_ARGS variable holds the arguments passed to imgtool. The final image is in HEX format so that PSoC™ 6 MCU programmer tools can directly program the image into the device. If you are generating the image to use with a firmware update application running in the device, you may need to convert the image into binary (BIN) format.

The names of the output files generated depend on the IMG_TYPE variable. For IMG_TYPE=BOOT, the files have the suffix "_BOOT" and for IMG_TYPE=UPGRADE, the files have the suffix "_UPGRADE".

  1. Make a copy of the *.hex file into a *_raw.hex file.

  2. Delete the *.hex file because the final signed image will be generated with the same filename so that you can directly program the file either using the make program command or using the launch configurations in Eclipse IDE for ModusToolbox™.

  3. Relocate the address and generate a new *_unsigned.hex file from the *.elf file using the arm-none-eabi-objcopy tool.

  4. Sign the image using imgtool and generate the *.hex file.

  5. Only for IMG_TYPE=UPGRADE, the CYACD2 file is generated from the signed HEX file using the hextocyacd2.py Python script; the HEX file is deleted because it is not required. The hextocyacd2.py Python script is located in the proj_btldr_cm0p/scripts folder.

CM0+/CM4 dual-CPU user projects: Post-build steps (for production)

When the firmware is ready for production, the PRODUCTION Makefile variable in proj_cm4/Makefile can be used to merge the HEX files of all the three projects into a single binary.

To create the merged HEX file for production, set PRODUCTION to '1'.

PRODUCTION=1

The name of the merged HEX file generated is supplied by the PRODUCTION_HEX_NAME Makefile variable. This can be changed if required.

PRODUCTION_HEX_NAME=production

To merge the HEX files, cymcuelftool is used. This tool is located inside the ModusToolbox™ tools directory. By default, the production.hex file is generated in the proj_cm4 build directory.

Bootloader project: Custom device configuration

The bootloader project overrides the default device configuration provided in libs/TARGET_<kit>\COMPONENT_BSP_DESIGN_MODUS with the one provided in templates/TARGET_<kit> for the supported kits. The custom configuration just enables the serial communication block (SCB) in UART mode with the alias CYBSP_UART. The libs/mcuboot/boot/cypress/MCUBootApp/cy_retarget_io_pdl.c file uses this block to implement redirecting printf to UART.

CM4 user project: Custom device configuration

The CM4 user project overrides the default device configuration provided in libs/TARGET_<kit>\COMPONENT_BSP_DESIGN_MODUS with the one provided in templates/TARGET_<kit> for the supported kits. The custom configuration just enables the SCBs in UART mode with the alias DFU_UART for the DFU operation. It also enables the SCB in UART mode with the alias CYBSP_UART to print debug logs. The libs/mcuboot/boot/cypress/MCUBootApp/cy_retarget_io_pdl.c file uses this block to implement redirecting printf to UART.

Related resources

Resources Links
Application notes AN221111 – PSoC™ 6 MCU: Designing a secured system
AN228571 – Getting started with PSoC™ 6 MCU on ModusToolbox™ software
AN215656 – PSoC™ 6 MCU: Dual-CPU system design
Code examples Using ModusToolbox™ software on GitHub
Knowledge Base Articles KBA236748 - Working with Multi-Project Applications in ModusToolbox 3.0
Device documentation PSoC™ 6 MCU datasheets
PSoC™ 6 technical reference manuals
Development kits Select your kits from the Evaluation board finder.
Libraries on GitHub mtb-pdl-cat1 – PSoC™ 6 Peripheral Driver Library (PDL)
mtb-hal-cat1 – Hardware Abstraction Layer (HAL) library
retarget-io – Utility library to retarget STDIO messages to a UART port
Middleware on GitHub psoc6-middleware – Links to all PSoC™ 6 MCU middleware
Tools ModusToolbox™ – ModusToolbox™ software is a collection of easy-to-use libraries and tools enabling rapid development with Infineon MCUs for applications ranging from wireless and cloud-connected systems, edge AI/ML, embedded sense and control, to wired USB connectivity using PSoC™ Industrial/IoT MCUs, AIROC™ Wi-Fi and Bluetooth® connectivity devices, XMC™ Industrial MCUs, and EZ-USB™/EZ-PD™ wired connectivity controllers. ModusToolbox™ incorporates a comprehensive set of BSPs, HAL, libraries, configuration tools, and provides support for industry-standard IDEs to fast-track your embedded application development.

Other resources

Infineon provides a wealth of data at www.infineon.com to help you select the right device, and quickly and effectively integrate it into your design.

Document history

Document title: CE234992PSoC™ 6 MCU: Security application template

Version Description of change
1.0.0 New code example
2.0.0 Updated to support ModusToolbox™ software v3.0 and BSPs v4.x
3.0.0 Add support for RMA
3.0.1 Minor source files and README updates
3.1.0 Updated to support ModusToolbox™ v3.2

All referenced product or service names and trademarks are the property of their respective owners.

The Bluetooth® word mark and logos are registered trademarks owned by Bluetooth SIG, Inc., and any use of such marks by Infineon is under license.


© Cypress Semiconductor Corporation, 2020-2024. This document is the property of Cypress Semiconductor Corporation, an Infineon Technologies company, and its affiliates ("Cypress"). This document, including any software or firmware included or referenced in this document ("Software"), is owned by Cypress under the intellectual property laws and treaties of the United States and other countries worldwide. Cypress reserves all rights under such laws and treaties and does not, except as specifically stated in this paragraph, grant any license under its patents, copyrights, trademarks, or other intellectual property rights. If the Software is not accompanied by a license agreement and you do not otherwise have a written agreement with Cypress governing the use of the Software, then Cypress hereby grants you a personal, non-exclusive, nontransferable license (without the right to sublicense) (1) under its copyright rights in the Software (a) for Software provided in source code form, to modify and reproduce the Software solely for use with Cypress hardware products, only internally within your organization, and (b) to distribute the Software in binary code form externally to end users (either directly or indirectly through resellers and distributors), solely for use on Cypress hardware product units, and (2) under those claims of Cypress's patents that are infringed by the Software (as provided by Cypress, unmodified) to make, use, distribute, and import the Software solely for use with Cypress hardware products. Any other use, reproduction, modification, translation, or compilation of the Software is prohibited.
TO THE EXTENT PERMITTED BY APPLICABLE LAW, CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH REGARD TO THIS DOCUMENT OR ANY SOFTWARE OR ACCOMPANYING HARDWARE, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. No computing device can be absolutely secure. Therefore, despite security measures implemented in Cypress hardware or software products, Cypress shall have no liability arising out of any security breach, such as unauthorized access to or use of a Cypress product. CYPRESS DOES NOT REPRESENT, WARRANT, OR GUARANTEE THAT CYPRESS PRODUCTS, OR SYSTEMS CREATED USING CYPRESS PRODUCTS, WILL BE FREE FROM CORRUPTION, ATTACK, VIRUSES, INTERFERENCE, HACKING, DATA LOSS OR THEFT, OR OTHER SECURITY INTRUSION (collectively, "Security Breach"). Cypress disclaims any liability relating to any Security Breach, and you shall and hereby do release Cypress from any claim, damage, or other liability arising from any Security Breach. In addition, the products described in these materials may contain design defects or errors known as errata which may cause the product to deviate from published specifications. To the extent permitted by applicable law, Cypress reserves the right to make changes to this document without further notice. Cypress does not assume any liability arising out of the application or use of any product or circuit described in this document. Any information provided in this document, including any sample design information or programming code, is provided only for reference purposes. It is the responsibility of the user of this document to properly design, program, and test the functionality and safety of any application made of this information and any resulting product. "High-Risk Device" means any device or system whose failure could cause personal injury, death, or property damage. Examples of High-Risk Devices are weapons, nuclear installations, surgical implants, and other medical devices. "Critical Component" means any component of a High-Risk Device whose failure to perform can be reasonably expected to cause, directly or indirectly, the failure of the High-Risk Device, or to affect its safety or effectiveness. Cypress is not liable, in whole or in part, and you shall and hereby do release Cypress from any claim, damage, or other liability arising from any use of a Cypress product as a Critical Component in a High-Risk Device. You shall indemnify and hold Cypress, including its affiliates, and its directors, officers, employees, agents, distributors, and assigns harmless from and against all claims, costs, damages, and expenses, arising out of any claim, including claims for product liability, personal injury or death, or property damage arising from any use of a Cypress product as a Critical Component in a High-Risk Device. Cypress products are not intended or authorized for use as a Critical Component in any High-Risk Device except to the limited extent that (i) Cypress's published data sheet for the product explicitly states Cypress has qualified the product for use in a specific High-Risk Device, or (ii) Cypress has given you advance written authorization to use the product as a Critical Component in the specific High-Risk Device and you have signed a separate indemnification agreement.
Cypress, the Cypress logo, and combinations thereof, ModusToolbox, PSoC, CAPSENSE, EZ-USB, F-RAM, and TRAVEO are trademarks or registered trademarks of Cypress or a subsidiary of Cypress in the United States or in other countries. For a more complete list of Cypress trademarks, visit www.infineon.com. Other names and brands may be claimed as property of their respective owners.

About

This is a minimal starter dual-CPU security application template for PSoC™ 62/63 MCU devices. This code example is meant to be a companion to the AN221111 – PSoC™ 6 MCU: Designing a secured system application note. It demonstrates the following features to create a secured system as explained in the application note.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published