The Arm Morello is an experimental architecture protection model that extends the Armv8.2-A profile. It includes the Morello System Development Platform (SDP) and the Morello FVP model platform.
The Morello platform Open Source Software (OSS) is delivered as an integrated software stack, which both support SDP and FVP model platform. The focus of this guide is on the FVP model platform.
This guide describes the following items:
The Morello platform Open Source Software (OSS) is delivered as an integrated software stack. It includes scripts that are provided to build and run the complete stack. It also includes firmware components and supports related filesystems, such as BusyBox, Debian, Ubuntu, etc.
Morello Software Stack and FVP model consist of:
Code repositories, which are based on standard open source software components, including SCP firmware, Trusted Firmware TF-A, and UEFI EDK2:
FVP model for Morello Platform
For the Morello software stack, you must set up the workspace first. This involves downloading the software stack and building the related image for the next debugging steps.
This guide uses the BusyBox file system from the mainline repository as an example.
Step 1: Download the software stack from mainline branch
mkdir <morello_workspace> cd <morello_workspace> repo init -u https://git.morello-project.org/morello/manifest.git -b morello/mainline -g busybox repo sync
Step 2: Build the software stack for the FVP platform
./build-scripts/build-all.sh -p fvp -f busybox all
Note: You might encounter build issues because of outdated environment variables of CROSS_COMPILE in your host environment. You can check and clear CROSS_COMPILE by using the following commands:
CROSS_COMPILE
echo $CROSS_COMPILE export CROSS_COMPILE=
Step 3: Check the built image
For example, the output directory ($workspace/output/fvp) for the FVP platform is as follows:
$workspace/output/fvp
The related firmware images are as follows:
Step 4: Run the software stack
You can run the software stack by using the following command:
./run-scripts/run_model.sh -m <model binary path> -f busybox
Then, you can see that the system is booted successfully.
The following figure shows the system booting into EDK2 Shell:
The following figure shows the system booting into Linux:
The Arm DS does not include the morello FVP model by default. Therefore, you must add the Morello FVP model to Arm DS for debugging purposes.
Step 1: Create a new debug connection for Morello FVP model
You can create a new debug connection as shown in the following figure:
Step 2: Configure the new debug connection
1. Select Model Connection as the connection type as follows:
2. Specify the debug connection name, for example morello-fvp, as follows:
morello-fvp
Step 3: Click Add a new model, select CADI for morello FVP model, and click Next
Step 4: Select Launch and connect to specific model and click Next
Step 5: Navigate to the model path that is installed on the Host PC and click Finish
Step 6: Set the CPU type to A-Generic and click Yes to save changes
Step 7: Finish the steps and run the Morello fast model
The TF-A firmware is the first bootloader of the Morello software stack for the Application Processor. The TF-A firmware runs in the Secure world, starting from EL3. It includes several boot stages: BL1 -> BL2 -> BL31. The BL31 boot stage transfers the boot flow into the Non-secure world of BL33. The BL33 is the UEFI (EDK2) firmware for the Morello software stack.
The following are the steps for debugging the TF-A firmware, typically including the BL1 and BL31 stages.
Step 1: Set the model parameters for the connection debug
For example, the model parameters are set as follows:
--data Morello_Top.css.scp.armcortexm7ct=/data/jetzho01/morello_busybox_mainline/bsp/rom-binaries/scp_romfw.bin@0x0 --data Morello_Top.css.mcp.armcortexm7ct=/data/jetzho01/morello_busybox_mainline/bsp/rom-binaries/mcp_romfw.bin@0x0 -C Morello_Top.soc.scp_qspi_loader.fname=/data/jetzho01/morello_busybox_mainline/output/fvp/firmware/scp_fw.bin -C Morello_Top.soc.mcp_qspi_loader.fname=/data/jetzho01/morello_busybox_mainline/output/fvp/firmware/mcp_fw.bin -C css.scp.armcortexm7ct.INITVTOR=0x0 -C css.mcp.armcortexm7ct.INITVTOR=0x0 -C css.trustedBootROMloader.fname=/data/jetzho01/morello_busybox_mainline/bsp/rom-binaries/bl1.bin -C board.ap_qspi_loader.fname=/data/jetzho01/morello_busybox_mainline/output/fvp/firmware/fip.bin -C board.virtioblockdevice.image_path=/data/jetzho01/morello_busybox_mainline/output/fvp/busybox.img -C css.pl011_uart_ap.unbuffered_output=1 -C displayController=1 -C board.virtio_rng.enabled=1 -C board.virtio_rng.seed=0 -C num_clusters=2 -C num_cores=2 -C board.virtio_net.hostbridge.userNetworking=1 -C board.virtio_net.enabled=1 -C board.virtio_net.transport=legacy -C board.virtio_net.hostbridge.userNetPorts=5555=5555
The following figure shows you how to set model parameters:
Step 2: Load debug symbol files
1. Edit Debug Configuration as follows:
2. Added the related debug symbol files for the BL1, BL2, or BL31 image based on your needs.
3. Check whether these symbol files are applied successfully.
4. Debug the firmware during the BL31 boot stage:
You can set the breakpoints in the commands window, for example, b bl1_setup as follows:
b bl1_setup
5. Debug the firmware during the BL31 boot stage:
Similarly, you can set the breakpoints in the commands window, for example b bl31_main as you do for the bl1 stage.
b bl31_main
The BL31 is the last stage for trusted firmware. Then the BL31 tranfers the boot flow to Non-secure world. It is BL33 UEFI (edk2) for the morello platform.
The following code shows you how the boot flow is transferred to BL33 from BL31.
/* Fill BL33 related information */ { .image_id = BL33_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), # ifdef PRELOADED_BL33_BASE .ep_info.pc = PRELOADED_BL33_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), # else .ep_info.pc = PLAT_ARM_NS_IMAGE_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = PLAT_ARM_NS_IMAGE_BASE, .image_info.image_max_size = ARM_DRAM1_BASE + ARM_DRAM1_SIZE - PLAT_ARM_NS_IMAGE_BASE, # endif /* PRELOADED_BL33_BASE */
The image base and entrypoint is defined by PLAT_ARM_NS_IMAGE_BASE as follows:
PLAT_ARM_NS_IMAGE_BASE
/* Load address of Non-Secure Image for CSS platform ports */ #define PLAT_ARM_NS_IMAGE_BASE U(0xE0000000)
You can check the routine of el3_exit for exit from BL31 to BL33 UEFI firmware as shown in the following figure. You can set the breakpoint b el3_exit in the same way.
el3_exit
b el3_exit
Run to the code line by clicking Run to Selection to check the el3_elr register, which is the exception return address from BL31.
el3_elr
You can dump the register, it is the value 0xE0000000 as follows:
0xE0000000
You can find that the register value is the entry point of the BL33 image.
The UEFI EDK2 firmware is the non-secure bootloader of the Morello software stack for the Application Processor. It is the BL33 image of the firmware package (FIP). The UEFI EDK2 firmware will boot the Linux OS for the Morello software stack. You can follow the steps below to debug the UEFI EDK2 firmware.
Step 1 :Modify the configuration for the toolchain
Modify the file uefi/edk2/BaseTool/Conf/tools_def.template as follows:
uefi/edk2/BaseTool/Conf/tools_def.template
-Os
DEFINE GCC_ALL_CC_FLAGS
–g to DEFINE GCC_ASM_FLAGS
The following code shows the changes made to the tools_def.template file:
tools_def.template
diff --git a/BaseTools/Conf/tools_def.template b/BaseTools/Conf/tools_def.template index 90f4105506..d004c7426f 100755 --- a/BaseTools/Conf/tools_def.template +++ b/BaseTools/Conf/tools_def.template @@ -739,7 +739,7 @@ NOOPT_*_*_OBJCOPY_ADDDEBUGFLAG = --add-gnu-debuglink="$(DEBUG_DIR)/$(MODULE_ *_*_*_DTCPP_PATH = DEF(DTCPP_BIN) *_*_*_DTC_PATH = DEF(DTC_BIN) -DEFINE GCC_ALL_CC_FLAGS = -g -Os -fshort-wchar -fno-builtin -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -include AutoGen.h -fno-common +DEFINE GCC_ALL_CC_FLAGS = -g -fshort-wchar -fno-builtin -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -include AutoGen.h -fno-common^M DEFINE GCC_ARM_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -mlittle-endian -mabi=aapcs -fno-short-enums -funsigned-char -ffunction-sections -fdata-sections -fomit-frame-pointer -Wno-address -mthumb -fno-pic -fno-pie DEFINE GCC_LOONGARCH64_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -mabi=lp64d -fno-asynchronous-unwind-tables -fno-plt -Wno-address -fno-short-enums -fsigned-char -ffunction-sections -fdata-sections DEFINE GCC_ARM_CC_XIPFLAGS = -mno-unaligned-access @@ -759,7 +759,7 @@ DEFINE GCC_ARM_ASLDLINK_FLAGS = DEF(GCC_ARM_DLINK_FLAGS) -Wl,--entry,Refere DEFINE GCC_AARCH64_ASLDLINK_FLAGS = DEF(GCC_AARCH64_DLINK_FLAGS) -Wl,--entry,ReferenceAcpiTable -u $(IMAGE_ENTRY_POINT) DEF(GCC_ARM_AARCH64_ASLDLINK_FLAGS) DEFINE GCC_LOONGARCH64_ASLDLINK_FLAGS = DEF(GCC_LOONGARCH64_DLINK_FLAGS) -Wl,--entry,ReferenceAcpiTable -u $(IMAGE_ENTRY_POINT) DEFINE GCC_IA32_X64_DLINK_FLAGS = DEF(GCC_IA32_X64_DLINK_COMMON) --entry _$(IMAGE_ENTRY_POINT) --file-alignment 0x20 --section-alignment 0x20 -Map $(DEST_DIR_DEBUG)/$(BASE_NAME).map -DEFINE GCC_ASM_FLAGS = -c -x assembler -imacros AutoGen.h +DEFINE GCC_ASM_FLAGS = -g -c -x assembler -imacros AutoGen.h^M DEFINE GCC_PP_FLAGS = -E -x assembler-with-cpp -include AutoGen.h DEFINE GCC_VFRPP_FLAGS = -x c -E -P -DVFRCOMPILE --include $(MODULE_NAME)StrDefs.h DEFINE GCC_ASLPP_FLAGS = -x c -E -include AutoGen.h @@ -1970,8 +1970,8 @@ DEFINE CLANGDWARF_ARM_DLINK_FLAGS = DEF(CLANGDWARF_ARM_TARGET) DEF(GCC_ARM_DLI *_CLANGDWARF_ARM_ASLPP_FLAGS = DEF(GCC_ASLPP_FLAGS) DEF(CLANGDWARF_ARM_TARGET) *_CLANGDWARF_ARM_CC_XIPFLAGS = DEF(GCC_ARM_CC_XIPFLAGS) - DEBUG_CLANGDWARF_ARM_CC_FLAGS = DEF(CLANGDWARF_ARM_CC_FLAGS) $(PLATFORM_FLAGS) -flto -O1 - DEBUG_CLANGDWARF_ARM_DLINK_FLAGS = DEF(CLANGDWARF_ARM_DLINK_FLAGS) -flto -Wl,-O1 -fuse-ld=lld -L$(WORKSPACE)/ArmPkg/Library/GccLto -llto-arm -Wl,-plugin-opt=-pass-through=-llto-arm -Wl,--no-pie,--no-relax + DEBUG_CLANGDWARF_ARM_CC_FLAGS = DEF(CLANGDWARF_ARM_CC_FLAGS) $(PLATFORM_FLAGS) -flto -O0^M + DEBUG_CLANGDWARF_ARM_DLINK_FLAGS = DEF(CLANGDWARF_ARM_DLINK_FLAGS) -flto -Wl,-O0 -fuse-ld=lld -L$(WORKSPACE)/ArmPkg/Library/GccLto -llto-arm -Wl,-plugin-opt=-pass-through=-llto-arm -Wl,--no-pie,--no-relax^M NOOPT_CLANGDWARF_ARM_CC_FLAGS = DEF(CLANGDWARF_ARM_CC_FLAGS) $(PLATFORM_FLAGS) -O0 NOOPT_CLANGDWARF_ARM_DLINK_FLAGS = DEF(CLANGDWARF_ARM_DLINK_FLAGS) -fuse-ld=lld -Wl,--no-pie,--no-relax RELEASE_CLANGDWARF_ARM_CC_FLAGS = DEF(CLANGDWARF_ARM_CC_FLAGS) $(PLATFORM_FLAGS) -flto -O3 @@ -2016,8 +2016,8 @@ DEFINE CLANGDWARF_AARCH64_DLINK_FLAGS = DEF(CLANGDWARF_AARCH64_TARGET) DEF(GCC_ *_CLANGDWARF_AARCH64_ASLPP_FLAGS = DEF(GCC_ASLPP_FLAGS) DEF(CLANGDWARF_AARCH64_TARGET) *_CLANGDWARF_AARCH64_CC_XIPFLAGS = DEF(GCC_AARCH64_CC_XIPFLAGS) - DEBUG_CLANGDWARF_AARCH64_CC_FLAGS = DEF(CLANGDWARF_AARCH64_CC_FLAGS) $(PLATFORM_FLAGS) -flto -O1 - DEBUG_CLANGDWARF_AARCH64_DLINK_FLAGS = DEF(CLANGDWARF_AARCH64_DLINK_FLAGS) -flto -Wl,-O1 -fuse-ld=lld -L$(WORKSPACE)/ArmPkg/Library/GccLto -llto-aarch64 -Wl,-plugin-opt=-pass-through=-llto-aarch64 -Wl,--no-pie,--no-relax + DEBUG_CLANGDWARF_AARCH64_CC_FLAGS = DEF(CLANGDWARF_AARCH64_CC_FLAGS) $(PLATFORM_FLAGS) -flto -O0^M + DEBUG_CLANGDWARF_AARCH64_DLINK_FLAGS = DEF(CLANGDWARF_AARCH64_DLINK_FLAGS) -flto -Wl,-O0 -fuse-ld=lld -L$(WORKSPACE)/ArmPkg/Library/GccLto -llto-aarch64 -Wl,-plugin-opt=-pass-through=-llto-aarch64 -Wl,--no-pie,--no-relax^M NOOPT_CLANGDWARF_AARCH64_CC_FLAGS = DEF(CLANGDWARF_AARCH64_CC_FLAGS) $(PLATFORM_FLAGS) -O0 NOOPT_CLANGDWARF_AARCH64_DLINK_FLAGS = DEF(CLANGDWARF_AARCH64_DLINK_FLAGS) -fuse-ld=lld -Wl,--no-pie,--no-relax RELEASE_CLANGDWARF_AARCH64_CC_FLAGS = DEF(CLANGDWARF_AARCH64_CC_FLAGS) $(PLATFORM_FLAGS) -flto -O3
If you have previously built the stack, update the uefi/edk2/Conf/tools_def.txt file as follows:
uefi/edk2/Conf/tools_def.txt
$ cp uefi/edk2/BaseTools/Conf/tools_def.template uefi/edk2/Conf/tools_def.txt
Step 2: Import the debug script of edk2 platform
1. Click the Scripts tab in Arm DS.2. Click the icon highlighted in the following figure and choose Import a script or directory -> Import a DS or Jython script.
3. Select the script $workspace/bsp/uefi/edk2/ArmPlatformPkg/Scripts/Ds5/cmd_load_symbols.py to import, after the script is import done. Then, right-click the script in the list, and select Parameters.
$workspace/bsp/uefi/edk2/ArmPlatformPkg/Scripts/Ds5/cmd_load_symbols.py
4. Enter parameters in script parameter dialog as shown in the following figure:
The parameters are briefly described as follows:
-f (<UEFI entry point>, 0x20000)
-a -v
-i <path to UART log file>
-o <path to objdump executable>
This is the path to aarch64-none-linux-gnu-objdump. If you follow the installation instructions, the executable file is located at ~/rd-infra/tools/gcc/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-objdump.
~/rd-infra/tools/gcc/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-objdump
Now, the script is set up.
5. Restart the FVP, click the Connect button in Arm DS and click Continue to enter the UEFI firmware (0xE0000000).
6. Load the debug symbols by right-clicking the Scripts tab and selecting Run.
All the debug symbols are loaded as shown in the following figure. You can debug BL33 firmware now.
Step 3: Run BL33 UEFI to enter the EL2 entry point.
The boot flow jumps to the entry point (0xE0000000) of BL33 from the BL31 stage.
Then, the boot flow jumps to the module PrePeiCore, which is the SEC phase of the UEFI boot stage. The first instruction of the module is B ModuleEntrypoint, which is located at address 0xE001E720, as shown in the following figure:
B ModuleEntrypoint
0xE001E720
After that, the boot flow jumps to the CPU cache initialization routine as shown in the following figure:
Therefore, you can find that the AP firmware, including the Secure firmware of TF-A and the UEFI EDK2 firmware of the Morello software stack, can be debugged using Arm DS according to this guide.