Morello ELF Topics

This appendix describes topics relevant to GNAT for bareboard Morello ELF and also presents a tutorial on building, running, and debugging an Ada application in GNATemulator and on the Arm Morello System Development Platform.

Note: Please be aware that unlike other GNAT Pro 25 products, GNAT Pro 25 for Morello ELF is based on GCC-11, binutils 2.35 and GDB 12.

Note: Unlike other GCC- or LLVM-based Morello ELF compilers, GNAT Pro for Morello ELF uses the triplet morello-elf to distinguish the compiler and tools from GNAT Pro for Aarch64. This is due to the older underlying GCC used by Morello ELF.

CHERI Support

CHERI Capabilities

GNAT for Morello implements System.Address as a 128-bit capability type. The package Interfaces.CHERI provides user operations for manipulating CHERI capabilities if required.

CHERI Exceptions

The Morello SoC performs CHERI run-time checks at the hardware level and raises processor exceptions when a run-time check fails. The Morello runtimes handle these exceptions and raise one of the following Ada exceptions in response at the source location where the exception occurred:

  • Interfaces.CHERI.Exceptions.Capability_Bound_Error is raised when an out-of-bounds access was attempted.

  • Interfaces.CHERI.Exceptions.Capability_Permission_Error is raised when an attempted. access exceeds the permissions granted by a capability.

  • Interfaces.CHERI.Exceptions.Capability_Sealed_Error is raised when a sealed capability was dereferenced.

  • Interfaces.CHERI.Exceptions.Capability_Tag_Error is raised when an invalid capability was dereferenced.

The embedded runtimes support exception propagation and allow these exceptions to be caught and handled like regular Ada exceptions. The light and light-tasking runtimes do not support exception propagation and so the occurrence of any CHERI exception invokes the Last Chance Handler.

Supported Processors and Run-Time Libraries

GNAT for Morello ELF targets the Arm Morello processor in pure capability mode. It uses the ARM Morello C64 instruction set.

GNAT Pro provides the following runtimes for the Arm Morello System Development Platform (SDP):

  • light-morello

  • light-tasking-morello

  • embedded-morello

  • light-morello-semihosting

  • light-tasking-semihosting

  • embedded-morello-semihosting

The regular Morello runtimes are configured to use UART0 for Ada.Text_IO while the semihosting runtimes (the runtimes that end with “-semihosting”) use semihosting instead.

All runtimes operate in pure capability mode and can be used in GNATemulator.

Resources used by the runtime

  • The GIC600 interrupt controller for interrupt support;

  • Armv8-A Generic Timer

  • UART0 or Semihosting for Ada.Text_IO depending on the runtime.

See the respective sections below for further details on each resource used by the GNAT runtime.

System Clocks

The Morello GNAT runtimes do not configure the processor clocks as they are configured by the System Control Processor on boot. Refer to the Arm Morello System Development Platform Technical Reference Manual for more information on clock configuration.

The Morello runtimes do need to know the clock speed of the Processor Clock and Global Timestamp Timer. If you modify either clock speed from their default (Processor Clock: 2.5 GHz; Global Timestamp Timer: 62.5 MHz), please update s-bbpara.ads and rebuild the runtime.

Startup Code

The Morello runtimes provide low-level startup code in start.S that contains the entry point of the application to be called from your bootloader and performs the low-level runtime initialization required before high-level Ada code is called. The startup code performs the following operations:

  • Initialization of core registers;

  • Enabling of the FPU;

  • Clearing the BSS section;

  • Loading of the DATA section to RAM if required;

  • Configuration of the MMU.

Outside of the startup code, the runtime will also configure the CPU’s Clocks and GIC. All other SoC initialization and configuration needs to be carried out by the Secondary Bootloader (SBL) prior to passing control over to the application. The SBL is also required to load the application into memory if required. Any peripherals the application may use should be configured by the SBL or the application directly prior to their use.

The configuration of the MMU is performed by the System.MMU package (smmu.adb). By default, the MMU configured to allow access to the memory regions defined in the linker script. The default MMU configuration can be replaced by providing your own implementation of

procedure Initialize with
   Export,
   Convention     => C,
   External_Name  => "__initialize_mmu",
   Linker_Section => ".boot";

In limited circumstances, start.S may be replaced with your own code that performs the above requirement and directly calls main, but please contact AdaCore if you need to modify the FPU settings as doing so may affect the conformance of the runtime to the Ada Standard.

Memory

The application memory is broken down into two primary memory regions:

  • Code, read-only data and the initial read-write data (Code Region)

  • Data and bss (zeroed data) sections (Data Region)

A set of default linker scripts are provided with the runtimes that load the Code and Data regions into RAM. These linker scripts can be found in the ld directory and consist of the following:

  • ram.ld: defines the layout of the Arm Morello SDP and maps the memory regions defined above to the platform’s RAM. Currently the linker script only provides a map for the platform’s RAM.

  • common.ld: defines the application entry point and sections. It uses the memory regions defined in ram.ld to allow this script to be used in different scenarios without modification.

While you can modify these scripts directly, it’s recommended to copy the scripts you need to modify to your project folder and modify them there. This allows you to preserve your scripts between runtime updates and is required if you will be using the runtime to run applications on different cores (as each application will need to be mapped to different memory locations).

To use your own linker scripts, specify the main linker script via the -T linker switch and use the -XLOADER=USER switch when building your application with GPRbuild.

When relocating the primary memory regions, please keep in mind the following guidance for each region.

Code Region

The Code Region contains the application code, read-only data and the initial state of the data section. This region can be located in RAM or read-only memory like FLASH. If located in RAM, it is the bootloader’s responsibility to load the Code Region to memory.

Data Region

The Data Region contains the data and bss sections. This region needs to be located in RAM. During runtime startup the runtime will zero the bss section and copy the initial state of the data section from the Code Region if the two regions are not located together. There is no need for the bootloader to load the Data Region to RAM if the Code Region is located in ROM.

Caches

The runtime enables the data and instruction cache during initialization.

Interrupts

External Interrupts

The Morello GNAT runtimes support connecting IRQ interrupts generated by the processor’s GIC600 to protected procedure handlers as documented in the Ada Reference Manual C.3.1. The list of interrupt names can be found in the package Ada.Interrupts.Names (gnarl/a-intnam.ads). The runtimes support nested priorities with 16 interrupt priority levels mapping to Ada Priorities 241-255.

Power Management

The runtime will place the CPU into standby mode if there are no tasks eligible to run.

Text_IO

The runtime provides a minimal version of the Ada.Text_IO package supporting character- and string-based input and output routines for basic I/O needs. It is recommended to implement your own I/O packages based around your I/O channel of choice.

Note: the semihosting run-times only support text output when running in GNATemulator.

The bodies of the Ada.Text_IO routines call through to a device-specific I/O package named System.Text_IO. See the package body in the file s-textio.adb in the gnat directory for more details.

System.Text_IO on the standard Morello runtimes uses UART0. UART0 is configured for 115200 baud with 8 data bits, one stop bit, and no parity. System.Text_IO on the semihosting Morello runtimes use Arm semihosting to print output using the debugger semihosting capabilities.

Getting Started

To use the Morello runtimes, configure your project to use the morello-elf toolchain and your desired runtime. This can be done through the GNAT Studio Project Properties page or by adding the following to your GPR file:

for Target use "morello-elf";
for Runtime ("Ada") use "<your runtime choice>";

After building your application you can run it either in GNATemulator or on the Arm Morello SDP.

GNATemulator

Programs built with the Morello run-times can be run in GNATemulator through GNAT Studio or from the command line with:

morello-elf-gnatemu <executable>

Arm Morello System Development Platform

The Arm Morello System Development Platform (SDP) can run Morello ELF programs by creating an Application Processor (AP) image. The Morello Project (https://git.morello-project.org/morello) provides the tools to build this image as a BL33 payload that the SDP’s Trusted Firmware-A (TF-A) bootloader will run at EL2. The following instructions are based on the Morello Project’s documentation found at https://git.morello-project.org/morello/docs. When navigating the Morello Project, select the branch corresponding to the Morello Project release you are using. This documentation is based on the Morello Project 1.6 release.

Prerequisites

Review the Morello Project’s host prerequisites at https://git.morello-project.org/morello/docs/-/blob/morello/release-1.6/common/prerequisites.rst and install the Morello LLVM toolchain (required to build an AP image). The Morello LLVM toolchain can be downloaded from the Morello Project with:

git clone -b morello/baremetal-release-<release number> https://git.morello-project.org/morello/llvm-project-releases.git

Where <release number> is the Morello Project version. For example for release 1.6:

git clone -b morello/baremetal-release-1.6 https://git.morello-project.org/morello/llvm-project-releases.git

To ease the creation of the AP image, set the $MORELLO_LLVM_PROJECT environment variable:

export MORELLO_LLVM_PROJECT=$PWD/llvm-project-releases

Building the Application Processor Image

To build the AP image, first create a Morello workspace replacing <release number> with the appropriate release number:

mkdir workspace
export MORELLO_WORKSPACE=$PWD/workspace
cd $MORELLO_WORKSPACE
repo init \
  -u https://git.morello-project.org/morello/manifest.git \
  -b morello/integration-<release number> \
  -g bsp
repo sync

Next convert the Ada ELF program into binary format with objcopy:

morello-elf-objcopy -Obinary <executable> <executable>.bin
export PRJ_EXECUTABLE=$PWD/<executable>.bin

where <executable> is the path to your executable that was built by GPRbuild.

From the Morello workspace, the AP image can now be built by running:

make -C "bsp/arm-tf" \
  PLAT=morello TARGET_PLATFORM=soc ENABLE_MORELLO_CAP=1 \
  CC=$MORELLO_LLVM_PROJECT/bin/clang clean

MBEDTLS_DIR=$MORELLO_WORKSPACE/bsp/deps/mbedtls \
  CROSS_COMPILE=$MORELLO_WORKSPACE/tools/clang/bin/llvm- \
  make -C "bsp/arm-tf" \
  CC=$MORELLO_LLVM_PROJECT/bin/clang \
  LD=$MORELLO_LLVM_PROJECT/bin/ld.lld \
  PLAT=morello ARCH=aarch64 TARGET_PLATFORM=soc ENABLE_MORELLO_CAP=1 \
  E=0 TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 ARM_ROTPK_LOCATION="devel_rsa" \
  ROT_KEY="plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem" \
  BL33=$PRJ_EXECUTABLE \
  OPENSSL_DIR=$MORELLO_WORKSPACE/output/soc/intermediates/host_openssl/install \
  all fip

The AP image file fip.bin will be created at $MORELLO_WORKSPACE/bsp/arm-tf/build/morello/release/fip.bin

Running the AP image

To run the resulting AP image on the Morello SDP copy the AP image fip.bin to the SDP’s microSD card by:

  1. Connect the power cable to the Arm Morello SDP.

  2. Connect a USB cable from your workstation to the DBG USB port on the back panel of the Arm Morello SDP.

  3. Turn on the Arm Morello SDP. After a short delay the board should power on and the microSD card should appear as a USB mass storage device.

  4. Open a file browser and navigate to the SOFTWARE directory on the mounted microSD card.

  5. Replace the fip.bin file with the fip.bin that was created in the previous section.

  6. Eject the microSD card’s USB mass storage device to flush any pending writes.

  7. Reboot the SDP.

The SPD will boot with the AP image.