5.2. AM65xx SBL

5.2.1. Introduction

The Secondary Bootloader (SBL) for AM65xx initializes the execution environment for multi-core applications and this can be used to demonstrate a real world product experience. This section covers additional details including execution sequence, tools and additional flashing instructions.

The SBL is essentially a baremetal application, and it uses many components from the Processor SDK

  • <PDK>/packages/ti/build : For build infrastructure

  • <PDK>/packages/ti/csl : For initialization and SoC addresses

  • <PDK>/packages/ti/board : For board and usecase specific initialization

  • <PDK>/packages/ti/drv/spi : For reading applications from OSPI flash

  • <PDK>/packages/ti/drv/udma : For reading data from boot media using DMA

  • <PDK>/packages/ti/drv/mmcsd : For reading applications from MMC/SD/eMMC

  • <PDK>/packages/ti/fs/fatfs : For reading files from MMC/SD/eMMC

  • <PDK>/packages/ti/drv/sciclient : For communicating with DMSC sub-system

  • <PDK>/packages/ti/drv/uart : For log messages

  • <PDK>/packages/ti/osal : Primitives required by ti/drv components

The SBL is in turn used by the board framework to load and start diagnostics

Bootloader Execution Sequence

  • Power On Reset

  • ROM Bootloader (RBL)

    • Software pre-programmed in AM65xx ROM memory starts executing

    • The RBL performs platform configuration and initialization.

    • It then checks sysboot pins and chooses booting device

    • The RBL then configures PLL and clock settings for R5, and boot media like eMMC, SD/MMC, OSPI, UART, PCIe, Ethernet etc for reliable boot.

    • If no valid bootloader found on booting device, the RBL checks for next booting device, based on sysboot pins

    • It then gets image size and load address by checking the X.509 certificate that is part of the bootloader image.

    • The RBL then verifies, optionally decrypts and loads the binary to internal memory at the load address specified in the X.509 certificate.

    • Finally it resets the R5 and passes control to Secondary Bootloader(SBL) running on the R5.

  • Secondary bootloader(SBL)

    • User level secondary bootloader(SBL) begins execution from internal memory. It enables ATCM, starts PMU timers for profiling, initializes the MCU, and sets up the stack, heap and globals. It then jumps to main().

    • Board Initialization is done by calls to Board_init() API.For additional details refer Processor SDK Board Support.

    • The RAT is setup. Pin MUX and UART console are setup by calling Board_init() API. The system firmware (SYSFW or TIFS) is then loaded from the boot media into the DMSC subsystem.

    • Once the system firmware is up and running, the rest of the initialization can be done.

    • This includes optionally using Board_init() to configure PLLs, LPSCs and DDR.

    • The SBL then loads the application from the boot media. If the image is signed, the application will be copied into a user specified reserved memory, and the SBL will attempt to verify the image by calling system firmware APIs. On HS devices, the boot proceeds only if image verification passes.

    • The SBL parses application image(s) for each of the core(s) from boot media and scatter loads it to memory.

    • Once the application is loaded, the SBL communicates with the system firmware to setup the clocks for the core(s) and release it from reset.

    • The core then starts executing from application entry point.

NOTE

  • RBL requires boot loader (SBL) to be in a special format with the binary image appended to a X.509 certificate. The certificate contains the load address, size and SHA of the bootloader image.

  • For a detailed description of ROM bootloader and more information on the image format expected by the RBL refer the initialization chapter in the AM65xx Technical Reference Manual

  • In addition to the bootloader and application, the DMSC firmware binary is also needed for the SoC to complete the system boot flow.

  • The first 256 bytes of the ATCM are reserved by SBL for its use. The SBL initializes the ATCM with 0xFF before it uses it.

  • If the multicore application image is signed using the TI Dummy Key, instead of a degenerate key (default setting) the same binary can be used on GP and HS devices. For information on the application’s X.509 certificate format, please refer Security X509 Certificate Documentation

  • When the R5 is released from reset, it will always fetch and execute the first intruction from address 0x0.

5.2.2. Block Diagram

../_images/k3_sbl_arch_block_diag.png

5.2.3. Memory Map

../_images/k3_sbl_mem_usage.png

5.2.4. Directory structure

sbl
│
├── board
│   └── k3
│       └── sbl_main.c                                      <= define main() for SBL, board specific init
│
├── build
│   ├── makefile                                            <= makefile for the SBL component
│   ├── sbl_am65xx.sh                                       <= For legacy, called by Yocto build
│   ├── sbl_boot_test.mk                                    <= Builds SBL single core tests
│   ├── sbl_smp_test.mk                                     <= Builds example app for using SBL lib
│   ├── sbl_mcu0_boot_perf_test.mk                          <= Builds example app for SBL performance tuning
│   ├── sbl_mcu0_boot_xip_entry.mk                          <= Builds example trampoline app to demonstrate transitioning to a XIP app from SBL
│   ├── sbl_mcu0_boot_xip_test.mk                           <= Builds example app to demonstrate XIP execution from XIP capable boot media
│   ├── sbl_img.mk                                          <= builds SBL image that is loaded and executed by ROM code
│   ├── sbl_lib.mk                                          <= Builds sbl library that other apps can link into
│   ├── sbl_multicore_smp.mk                                <= Builds multi-core image from SBL lib eg. test to demonstrate symmetric multiprocessor boot (SMP)
│   └── sbl_multicore_amp.mk                                <= Builds multi-core image from single core tests to demonstrate asymmetric multiprocessor boot (AMP)
│
├── example
│   └── k3MulticoreApp
│       ├── binary
│       │   └── [soc]
│       │       ├── sbl_baremetal_*.appimage                <= SBL loadable board specific sample apps for testing SBL boot flow on GP devices
│       │       ├── sbl_baremetal_*.appimage.signed         <= SBL loadable board specific signed sample apps for testing SBL boot flow on HS devices
│       │       └── sbl_baremetal_*_release.x*.bin          <= Binary image that can be eXecuted In Place on XIP capable boot media
|       ├── [soc]
│       │   ├── mcuAmplinker.lds                            <= Linker command file when TI CGT is used for Asym. Multiproc. boot
│       │   ├── mpuAmplinker.lds                            <= GCC linker command file (for Cortex Axx cores) for Asym. Multiproc. boot
│       │   ├── mcuXiplinker.lds                            <= Linker command file for XIP trampoline app
│       │   └── xip_entry.lds                                       <= Linker command file for XIP test case
│       ├── mcuBootPerfLinker_j7.lds                        <= TI CGT Linker command file for SBL performance tuning example (J721E)
│       ├── mcuBootPerfLinker.lds                           <= TI CGT Linker command file for SBL performance tuning example (AM65xx)
|       ├── mcuBootPerfLinker_small.lds                     <= TI CGT Linker command file for SBL performance tuning example (for boot with MCU domain only)
│       ├── mcu[core#]LockStepLinker.lds                    <= Linker command file when TI CGT is used for R5 lock-step boot
│       ├── mpuSmplinker.lds                                <= GCC linker command file (for Cortex Axx cores) for SMP boot
│       ├── xip_entry.asm                                   <= Entry point of XIP trampoline app
│       ├── xip_stub.c                                      <= Simple SBL test app that demonstrates transitioning to a XIP app
│       ├── sbl_amp_multicore.c                             <= Simple SBL test that displays UART message
│       ├── sbl_amp_multicore_sections.h                    <= Allows same source to be loaded to different sections for different cores.
│       ├── sbl_mcu_0_boot_perf_benchmark.c                 <= SBL Test to tune boot performance.
│       ├── sbl_multicore_a53.asm                           <= Test case entry point  for Cortex-Axx cores
│       ├── sbl_multicore_r5.asm                            <= Test case entry point for Cortex-R5 cores
│       ├── sbl_multicore_r5_sections.inc                   <= Allows same source to be loaded to different sections for different MCUs.
│       ├── sbl_printf.c                                    <= Lightweight UART printf function for SBL testing
│       ├── sbl_smp_multicore.c                             <= Simple SBL SMP test that uses SBL lib to reset MPUs
│       └── sbl_smp_r5.asm                                  <= Provides dummy override function for __mpu_init for SMP testcase.
│
├── binary                                                  <= ROM bootable SBL images for each board/boot media
│   ├── [board]
│       └── [bootmedia]
│           └── bin
│               └── sbl_[bootmedia]_img_mcu1_0_release.tiimage
│
├── lib                                                     <= SBL lib for each boot media/board supported
│   ├── [bootmedia]
│   │   └── [board]
│   │       └── r5f
│   │           └── release
│   │               └── sbl_lib_[bootmedia].aer5f
│   └── cust
│       └── [board]
│           └── r5f
│               └── release
│                   └── sbl_lib_cust.aer5f
│
├── soc                                                     <= SOC specific SBL code
│   └── k3
│       ├── [soc]
|       |   └── linker.cmd                                  <= Linker file used for generating ROM loadable SBL image.
│       ├── sbl_err_trap.h                                  <= Error loops for SBL
│       ├── sbl_init.asm                                    <= SBL Entry point
│       ├── sbl_misc.asm                                    <= SBL Assembly utility functions
│       ├── sbl_log.h                                       <= SBL logging framework
│       ├── sbl_sci_client.c                                <= Calls system firmware on DMSC
│       ├── sbl_sci_client.h
│       ├── sbl_slave_core_boot.c                           <= Code that contains the sequence to release a core from reset
│       ├── sbl_slave_core_boot.h
│       ├── sbl_soc.c                                       <= Cache Ops, PMU init, image verfication, etc & SoC specific code like RAT Init..
│       ├── sbl_soc_cfg.h                                   <= Abstraction layer for hiding SoC level changes from SBL
│       └── sbl_profile.h                                   <= SBL profiling framework
│
├── src                                                     <= Common drivers used across SOCs
│   ├── mmcsd
│   ├── hyperflash
│   ├── ospi
│   ├── qspi
│   ├── uart
│   ├── rprc                                                <= RPRC image parser used by SBL
│   └── spi
│
└── tools
    ├── btoccs
    ├── byteswap
    ├── ccsutil
    ├── combined_appimage                                   <= Creates a "combined" .appimage file for booting HLOS images (e.g., ATF,U-boot,Linux)
    │   ├── bin
    │   │   └── [board]
    │   │       ├── base-board.dtb                          <= Default (example) Linux DTB per platform - to be replaced with desired DTB
    │   │       └── combined.appimage                       <= Output "combined" .appimage for HLOS + RTOS images boot (after build)
    │   ├── config.mk                                       <= Configuration make include file. Use this to specify images to include in combined.appimage
    │   └── makefile                                        <= combined.appimage Makefile
    ├── flashWriter                                         <= Unused for AM65xx/J721E. AM65xx/J721E uses Uniflash to program flashes.
    ├── multicoreImageGen                                   <= Stitches multiple RPRC images for different cores into a single image
    ├── omapl13x_boot_utils                                 <= Unused for AM65xx/J721E
    ├── omapl13x_sd_card_format                             <= Unused for AM65xx/J721E
    ├── out2rprc                                            <= Converts .out into .rprc files, so that SBL can load non-continuous memory sections
    ├── scripts                                             <= Scripts used by .out  generated by CCS projects into SBL loadable images
    │   ├── K3ImageGen.bat
    │   └── K3ImageGen.sh
    └── tiImageGen                                          <= Unused for AM65xx/J721E. Image generation is handled by PDK build framework (<sdk_install_path>/pdk_*/packages/ti/build/)

5.2.5. Image Formats

SBL format:

To generate the a bootable image, the SBL build uses the x509CertificateGen script to sign the sbl binary with so that the ROM Boot Loader (RBL) can parse it. The image format expected by the RBL has been described in detail in the Image Format Section of the AM65xx Technical Reference Manual

Note

For HS devices, the SBL and system firmware have to be signed with the MPK. For an easy out-of-box experience, the Processor SDK for HS devices signs the SBL and system firmware with a TI Dummy Key. Images signed with a TI dummy key will boot on both GP and HS boards from TI. The build system invokes the script <PDK>/packages/ti/build/makerules/x509CertificateGen* which inturn calls OpenSSL to create the X509 certificate.

Note

For compatibility, all signed certificates must include a software revision extension with a minimum value of 1 as ROM will use this to enforce the revision programmed into the device efuses for anti-rollback protection. This default value of 1 is set into the SDK scripts but must be incremented during the lifecycle of the device if or when the efuse value is incremented. See https://software-dl.ti.com/tisci/esd/latest/6_topic_user_guides/otp_revision.html for more details.

Warning

The TI Dummy Key(s) MUST be replaced by customers during production with their own Private Keys. If the TI Dummy Keys are used in a production system, the system will be open to security attacks. The path of the default (dummy) key used by the signing script for HS devices is <PDK>/packages/ti/build/makerules/k3_dev_mpk.pem

Warning

While SBL and system firmware images signed with the TI Dummy Keys will work on both GP and HS devices, the boot time will be significantly impacted on GP devices. Using SBL signed by TI Dummy Keys on GP devices is only recommended during the prototyping phase - when porting code developed on GP to HS devices.

Application image format:

Two utilities - out2rprc and multicoreImageGen are used to convert an application elf image(s) into an image loadable by the SBL. The structure of a multicore application image is provided below:

../_images/multicore_app_image.png

RPRC File Header Format

Offset

Binary value

0x00000000

Magic Word(43525052)

0x00000004

Entry Point (Location)

0x00000008

Reserved Addr

0x0000000C

Section Count

0x00000010

Version

RPRC Section Header Format

Offset

Binary value

0x00000000

Section start Address

0x00000004

Reserved Addr

0x00000008

Size

0x0000000C

Reserved CRC

0x00000010

Reserved

Multicore boot image format

Meta Header Start

Offset

Binary value

0x00000000

Magic String (0x5254534D)

0x00000004

Number of Files

0x00000008

Device ID

0x0000000C

Reserved

Meta Header per Core

Offset

Binary value

0x00000000

Core ID

0x00000004

Image Offset

Signed application image format:

To convert the multicore application image into a format that can be verified, the build flow uses the x509CertificateGen script to create a x509 certificate for the app image. Images that have a x509 certificate are called signed images. Signed applications images are mandatory for HS devices, but will work also work on GP devices.

Signed images are automatically detected by the SBL and loaded into a scratch memory area specified during SBL build. The scratch memory area used by default is specified in sbl_lib.mk via the flags SBL_SCRATCH_MEM_START and SBL_SCRATCH_MEM_SIZE. The SBL_SCRATCH_MEM* options can also be specified for custom builds to override the defaults.

The SBL scratch memory is unavailable to applications during app load time, as the SBL is still active. Once the SBL transfers control to the application, this memory is available for app use - in other words SBL_SCRATCH_MEM* is available during app runtime.

For information on the application’s X.509 certificate format, please refer Security X509 Certificate Documentation

5.2.6. Building the SBL and its components

This section will cover compiling SBL for GP and HS devices. It will also show how to compile a loadable appimage file from an example application, which can be used as a reference to compile your own custom application.

5.2.6.1. Pre-requisites to Building

  • Set your environment using pdksetupenv.bat or pdksetupenv.sh located in <PDK>/packages directory. Refer to Processor SDK RTOS Building for information on setting up your build environment

NOTE

  • SBL needs openssl to build. To check if openssl is present, type the following at the linux or windows prompt.

openssl version
  • To build on Linux, you need to have mono installed.

  • Refer Build Dependencies for instructions on how to install these tools, if they are not already present on your system.

5.2.6.2. Compiling SBL for GP (General Purpose) Device

Compiling the SBL

To build all the SBL components:

cd <PDK>/packages/ti/boot/sbl/build
gmake clean all (for windows)
make clean all  (for Linux)
  • SBL image files are be located at: <PDK>/packages/ti/boot/sbl/binary/

  • SBL examples are located at <PDK>/packages/ti/boot/sbl/examples/k3MulticoreApp/binary

  • SBL lib are located at <PDK>/packages/ti/boot/sbl/lib/

Compile time options for the SBL

The SBL supports several compile time options to tweak the SBL to satisfy requirements of ease of use, boot time and size. These can be enabled or disabled by editing sbl/sbl_component.mk

  • SBL_LOG_LEVEL : Controls amount of SBL logs (on the MCU UART) and system firmware logs(on WAKEUP UART). Varies from 0(no logs) to 3 (all logs)

  • SBL_USE_DMA : Valid values are 0 (use CPU to access boot media) or 1 (use DMA to access boot media).

  • SBL_DISPLAY_PROFILE_INFO : At the end of the boot process, displays a log of timestamps at which different SBL profile points are hit. This is useful to see how much time the SBL spends in different functions. SBL_LOG_LEVEL can significantly affect performance numbers.

  • SBL_ENABLE_PLL : Dials up all the PLLs calling Board_init(). Makes it easier for applications as they no longer have to initialize the PLLs. However, enabling this significantly increases boot time and power consumption. Requires system firmware to be loaded.

  • SBL_ENABLE_CLOCKS : Enables all the module clocks by calling Board_init(). Makes it easier for applications as they no longer have to enable clocks.

  • SBL_ENABLE_DDR : Initializes the DDR. At the cost of boot time, this enables applications to run from and use DDR. SBL_ENABLE_CLOCKS and SBL_ENABLE_PLL must also be enabed for this to work. Enabling this option increases the boot time.

  • SBL_SKIP_MCU_RESET : Jumps to the MCU0 application entry point without resetting the core. Enables faster boot time. Will not change the MCU’s mode (lock-step/split). Application also inherits the MCU state as the SBL left it in.

  • SBL_ENABLE_DEV_GRP_MCU : Will cause the system firmware to only use MCU domain resources during system firmware initialization. This can be done either to support boot when the main power domain is off, or to save boot time.

  • SBL_ENABLE_HLOS_BOOT: SBL will take some extra steps to prepare certain peripherals and resources to be handed over for HLOS (e.g., Linux) control from the Cortex-A cores.

  • SBL_HLOS_OWNS_FLASH : Ensures the SBL will leave the OSPI flash in single SPI mode, so that the MAIN domain Cortex-A code (e.g., HLOS) can reset the flash and take control of it, if needed.

  • SBL_SKIP_PINMUX_ENABLE : SBL will skip any PINMUX init being done in the bootloader and expect that it will be handled by a subsequent application.

  • SBL_SKIP_LATE_INIT : SBL will skip calling the SoC Late Init functions, normally contained in SBL_SocLateInit()

  • SBL_USE_MCU_DOMAIN_ONLY : SBL will configure & boot MCU domain cores ONLY. Saves boot time when configuring & using MCU domain only (especially when testing MCU-only boot or measuring Early CAN response).

The SBL also supports a “custom” build, in addition to standard out-of-box builds. A custom build is a useful way of testing out the effect of different build options - like when optimizing for boot time, or enabling custom usecases like eXecute In Place (XIP) to reduce memory usage.

For an example of how to use such custom builds, please refer to sbl/sbl_component.mk. It shows how to specify a select list of build options while building SBL images and libs.

HLOS boot

The SBL now also supports booting ARM Trusted Firmware (ATF) along with either U-boot or HLOS images (e.g., Linux + DTB) on the Cortex-A cores of the device, when used together with the “combined_appimage” make facility in the SBL tools dir.

To boot the combined.appimage that is produced, simply build an alternate SBL bootloader target with “_hlos” (GP device) or “_hlos_hs” (HS device) appended to the build target name (only for MMCSD or OSPI boot modes).

SBL Build Target Examples for HLOS Boot:

  • GP device : To boot from SD card, use the “sbl_mmcsd_img_hlos” build target. For OSPI boot mode, use “sbl_ospi_img_hlos”.

  • HS device : To boot from SD card, use the “sbl_mmcsd_img_hlos_hs” build target. For OSPI boot mode, use “sbl_ospi_img_hlos_hs”.

SBL Startup

The SBL can specify the R5 configuration (lockstep or split) that ROM needs to use when it starts up the SBL. This info is passed to ROM as a field in the X509 certificate. The value in this field can be controlled by editing the build flag R5_STARTUP_MODE in sbl/build/sbl_img.mk

  • EFUSE_DEFAULT : SBL will run with the same R5 configuration the boot rom ran in.

  • SPLIT_MODE : ROM will switch the R5 to split mode before starting the SBL (default).

Enabling/Disabling JTAG on secure devices

JTAG access is controlled using a field in the X509 certificate.

By default, for an easy out of box experience, the Processor SDK enables debug via JTAG on High Secure devices. Leaving JTAG enabled, while making it easy for software development, creates a major security hole in production devices.

To disable/change the level of JTAG access on HS devices, update the value of the debugType field in the signing scripts build/makerules/x509template.txt (when building from windows) and build/makerules/x509CertificateGen.sh (when building from linux).

Valid values are:

  • 0 : Disable all JTAG access (most secure and most restrictive)

  • 1 : Use device defaults (most secure and most restrictive)

  • 2 : Allow debug of non-secure code, when the CPU is running in secure mode, JTAG connectivity will be lost

  • 4 : Allow debug of both secure and non-secure code (least secure and least restrictive). This is the default.