Zynq 7000 Tips and Tricks

This page contains a collection of tips and tricks specific to Zynq 7000, oriented around bare metal (non-Linux) designs in a Microcontroller environment.

Table of Contents

 

Introduction

Zynq 7000 has been in production for many years and still continues to be used in many lower cost designs. This page contains a number of small recipes that might be helpful in these designs. This page should be viewed more as a lab notebook with helpful hints assuming the user has a good knowledge of Zynq 7000 and the associated tools. It is not a tutorial for any of the required tools and the solution is not provided in any prebuilt images, so some work is required for success. A source code repository is provided at https://github.com/Xilinx-Wiki-Projects/software-prototypes with some of the primary changes required to the FSBL and SSBL based on the 2022.1 tools. The default FSBL source code is located at 2022.1 FSBL. The source code changes that follow might be more tactical, assuming a more refined/maintainable solution can be based on them and this is left as an exercise for the user.

DDR-less System

Most Zynq 7000 systems use DDR for system memory but some users want to use Zynq 7000 as a MicroBlaze replacement or as a typical Microcontroller with only internal memory and a boot media. The following DDR-less prototype system was created and tested for a specific system use case with QSPI flash as the boot media, with both unsigned and RSA signed images. Other system modes, such as other boot media types, encrypted images, etc. might not be supported by the code snippets illustrated in the following subparagraphs.

There are documented methods for DDR-less systems, such as , which are more complex and that complexity might not be required for many systems. There is also a documented method, Answer Record 56044 , which this solution is based on. A DDR-less system is not supported out of the box but only requires small changes to be supported. Some features of the system are impacted by a DDR-less system including security. The following screen shot illustrates a Vivado IP Integrator system with the “Enable DDR” checkbox unchecked for no DDR.

 

 

A number of smaller FSBL changes are required to support various features without DDR. A key to making the following FSBL changes is to turn on debug in the build as all of the image details are output during boot image processing. See the Zynq 7000 FSBL wiki page at Zynq 7000 FSBL for build details. The following boot log snippet illustrates details when debug is turned on and allows boot image details to be correlated to FSBL processing with respect to image addresses.

Partition Number: 2 Header Dump Image Word Len: 0x00001FC2 Data Word Len: 0x00001FC2 Partition Word Len:0x00002180 Load Addr: 0xFFFF0100 Exec Addr: 0xFFFF0100 Partition Start: 0x000C0000 Partition Attr: 0x00008010 Partition Checksum Offset: 0x00000000 Section Count: 0x00000001 Checksum: 0xFFE8FABA Application RSA Signed PCAP:StatusReg = 0x40000F30 PCAP:device ready PCAP:Clear done PCAP register dump: PCAP CTRL 0xF8007000: 0x4C00E07F PCAP LOCK 0xF8007004: 0x0000001A PCAP CONFIG 0xF8007008: 0x00000508 PCAP ISR 0xF800700C: 0x00033004 PCAP IMR 0xF8007010: 0xFFFFFFFF PCAP STATUS 0xF8007014: 0x50000F30 PCAP DMA SRC ADDR 0xF8007018: 0xFC300001 PCAP DMA DEST ADDR 0xF800701C: 0xFFFF0101 PCAP DMA SRC LEN 0xF8007020: 0x00002180 PCAP DMA DEST LEN 0xF8007024: 0x00002180 PCAP ROM SHADOW CTRL 0xF8007028: 0xFFFFFFFF PCAP MBOOT 0xF800702C: 0x8000C000 PCAP SW ID 0xF8007030: 0x00000000 PCAP UNLOCK 0xF8007034: 0x757BDF0D PCAP MCTRL 0xF8007080: 0x30800110 DMA Done ! Authentication Done

By default, FSBL uses conditional compilation with XPAR_PS7_DDR* and fails to boot without DDR. The following code snippet illustrates a minor change to FSBL in the main() function in main.c where the conditional compilation with XPAR_PS7_DDR* is removed for a large block of code and a new conditional compilation block is added around the DDR initialization only.

#if 1 // was #ifdef XPAR_PS7_DDR_0_S_AXI_BASEADDR /* No DDR is a valid operating mode with a few other changes. */ #ifdef XPAR_PS7_DDR_0_S_AXI_BASEADDR /* * DDR Read/write test */ Status = DDRInitCheck(); if (Status == XST_FAILURE) { fsbl_printf(DEBUG_GENERAL,"DDR_INIT_FAIL \r\n"); /* Error Handling here */ OutputStatus(DDR_INIT_FAIL); /* * Calling FsblHookFallback instead of Fallback * since, devcfg driver is not yet initialized */ FsblHookFallback(); } #endif

The LoadBootImage() function in the image_mover.c source file of the FSBL is altered to remove DDR address validation for image loading by adding conditional compilation with XPAR_PS7_DDR_0_S_AXI_BASEADDR. A hardware system built without DDR in Vivado removes the definition of this symbol in xparameters.h. The following code snippet illustrates the addition of conditional compilation to remove the DDR address validation such that images using internal memory can be loaded.

/* * Load address check * Loop will break when PS load address zero and partition is * un-signed or un-encrypted */ #ifdef XPAR_PS7_DDR_0_S_AXI_BASEADDR if ((PSPartitionFlag == 1) && (PartitionLoadAddr < DDR_START_ADDR)) { if ((PartitionLoadAddr == 0) && (!((SignedPartitionFlag == 1) || (EncryptedPartitionFlag == 1)))) { break; } else { fsbl_printf(DEBUG_GENERAL, "INVALID_LOAD_ADDRESS_FAIL\r\n"); OutputStatus(INVALID_LOAD_ADDRESS_FAIL); FsblFallback(); } } if (PSPartitionFlag && (PartitionLoadAddr > DDR_END_ADDR)) { fsbl_printf(DEBUG_GENERAL, "INVALID_LOAD_ADDRESS_FAIL\r\n"); OutputStatus(INVALID_LOAD_ADDRESS_FAIL); FsblFallback(); } #endif

Partitions are normally moved from the boot media to DDR. A DDR-less use case should only move images located in internal memory (OCM or BRAM). The LoadBootImage() function in the image_mover.c source file of the FSBL is altered in the following code snippet which illustrates an example of adding conditions to prevent some images from being moved by not calling the PartitionMove() function.

Execute In Place (XIP)

Due to the limited amount of internal memory, both in On Chip Memory (OCM) and Block RAM (BRAM) in the PL, users might require more memory for the application and XIP could be a solution. XIP with Zynq 7000 is less common and can be a bit challenging when reviewing the documentation and FSBL image processing. An application is built for XIP by linking the text sections for the linear QSPI flash memory and the data sections for OCM. As illustrated below in the capture from the TRM (UG585), FSBL with both RSA and XIP is not supported by the BootROM such that the prototype system described on this page only supports user applications (not FSBL) built in XIP mode.

 

A key to making an XIP image run is to make sure that the application image ends up in flash at the same address where the image is linked. This is done by using the offset property in the BIF file when building the boot image with BootGen and making sure the partition containing the text is before any data partition in the address space and boot image as described in Boot Images paragraph of this page.

OCM

FSBL by default is linked for all of OCM, but can be linked such that it occupies the lowest 192 KB of OCM leaving 64 KB of OCM for applications. A small application that fits into 64 KB of OCM is the easiest solution. The next easier solution is an XIP application with data which fits into the 64 KB of OCM. And the most complex solution is an XIP application with data that is too large to fit into the 64 KB of OCM. The prototype system described assumes the most complex solution with a Second Stage Boot Loader (SSBL). The following diagram illustrates the memory map for the described systems.

 

Block RAM (BRAM)

The PL contains BRAM that can be used together with AXI infrastructure to allow the CPU to execute from the BRAM or use it for data. FSBL cannot normally load applications into BRAM as the PL is not fully operational until late in FSBL operation at the handoff to an application. The PL bitstream is loaded first by FSBL such that the PL BRAM can be up and running prior to other image processing. The following code snippet illustrates adding conditional compilation for when a BRAM is in the design to call ps7_post_config() in the FsblHookAfterBitStreamDload() function of the fsbl_hooks.c source file to cause the PL BRAM to be ready to load applications.

Secondary Stage Boot Loader (SSBL)

For XIP applications that require more than 64 KB of OCM, a more complex solution is required with a Secondary Stage Boot Loader (SSBL) which FSBL starts after it is complete. The SSBL is linked and runs from the high 64 KB of OCM allowing the XIP application data to consume the lower 192 KB of OCM. The SSBL copies the XIP application data section from QSPI to OCM and then starts the XIP application running from QSPI memory. This solution also assumes the system never needs FSBL again as it is overwritten by the XIP application data.

The XIP application data and the XIP application execution address in QSPI memory are needed by the SSBL to load and start the XIP application. FSBL is altered to use OCM addresses for shared memory communicating the previously described addresses between itself and SSBL. Using the shared memory helps prevent duplication of FSBL functionality in SSBL as security duplication would be complex.

SSBL remaps the low 192 KB of OCM, where FSBL was executing at address zero, up high at 0xFFFC_0000 to match the linked XIP application data section as explained in the Boot Images paragraph. SSBL must also prepare the CPU, such as disabling the caches and MMU, to start the XIP application. FSBL contains this processing in the handoff code which can be re-used by SSBL. The following illustration shows a high level description of the boot flow from power up to the execution of the XIP application.

 

SSBL Details

The following code snippets illustrate the major functionality required for an SSBL application. These changes must be combined with FSBL changes to create the shared memory variables which contain the XIP application data address and execution address.

SSBL maps the lower 192 KB of OCM from the low address of zero up to the high address of 0xFFFC_0000. The remapping must be done prior to loading the XIP application data which is linked for high OCM. The following code snippet illustrates mapping the memory high.

SSBL copies the XIP application data from the QSPI to the high OCM. The following code snippet illustrates SSBL using the shared data (FLASH_DATA_PTR_ADDR) which FSBL created to get the address of the XIP application data and copy it to the high OCM as 0xFFFC_0000.

Before handing off execution to the XIP application it must make the CPU ready just as FSBL does in the handoff code. The SsblHandoffExit() function is copied from the FsblHandoffExit() in the fsbl_handoff.S source file into the project and then called at the end of SSBL. The following code snippet illustrates the code of the handoff to get the CPU ready for a new application to be started.

The following code snippet illustrates calling the handoff function using the shared data (HANDOFF_PTR_ADDR) which FSBL created when the XIP application image was processed.

FSBL Changes For SSBL

In the LoadBootImage() function of the image_mover.c source file, the SSBL required data should be added in the partition handling loop to allow the XIP application execution address (handoff pointer) and the data to be found. The following code snippet illustrates processing to find the XIP application and write the addresses to the lowest addresses of the high 64 KB of OCM where SSBL will use them.

Boot Images

The BootGen tool generates a boot image consisting of a set of application images and a bitstream which is written to a boot media such as QSPI flash memory. A boot image contains partitions for the applications and the bitstream which can be individually controlled with respect to the location in the boot image. DDR based systems allow application text and data to be linked and located in the same large continuous memory which creates a simple single partition. DDR-less systems using XIP require application text sections to be linked and located in the boot media while application data sections are linked and located for RAM and therefore create a more complex boot image due to discontinuous text and data memories.

The tools do not support Position Independent Code. As a result, an XIP application must be linked for the address where it will be executing, such as QSPI in linear address mode, with the data being linked for RAM. The memory sections of the application, text and data, are multiple memories such that they are discontinuous and BootGen generates a multi-partition image for the application. The partitions of the multi-partition image are in the order of address, so the text partition must be first (using a lower address) to allow a predictable address matched to the linked address.

BootGen allows images to be located at specific offsets in the boot image but it does not allow the individual partitions of a multi-partition image to be individually located. This is not an issue when the text section of the application is at a lower address than the data section, but is a challenge with data memory at a lower address than the text, such as with OCM mapped low or BRAM.

QSPI flash in linear mode starts at address 0xFC00_0000 and OCM can be mapped high in the address space starting at 0xFFFC_0000, so this works nicely for XIP mode. BRAM does not work easily for the data section because it is mapped at 0x4XXX_XXXX or 0x8XXX_XXXX in the address map. The following illustration shows the memory map when FSBL is executing, followed by the memory map when SSBL is executing to illustrate OCM moving from low addresses to high addresses.

RSA Authentication Support

RSA processing is done in both the BootROM and FSBL. The FSBL assumes DDR is present such that the image is copied into DDR prior to performing the RSA signature verification. A DDR-less FSBL requires changes to support RSA, so that it performs the RSA signature verification from QSPI. Security of the system should also be considered by users with the DDR-less system as the CPU spends more time accessing the external memory while performing the RSA algorithm. Boot time might be another consideration for fast booting systems and boot time was not a factor in the proposed solution.

FSBL changes to support RSA authentication from the QSPI include using the address of the image in QSPI for the authentication, and removal of the DDR as a temporary buffer for the PL bitstream. These are illustrated in the following code snippet of the image_mover.c source file and the LoadBootImage() function. Note the addition of conditional compilation for when DDR is in the system.

The following snippet of code illustrates the change to the GetNAuthImageHeader() function in image_mover.c which causes the DDR-less system to allocate a temporary buffer in OCM rather than DDR for the authentication header.

Load Failures

For any security failures, such as a bad RSA signature, the FSBL normally causes a boot failure and makes the BootROM do multi-boot searching for the next valid image in the boot media. This might not make sense for all systems as it might be valid to boot into a secure application that recognizes the failure and then updates the failing images. The following code snippet illustrates FSBL failing to authenticate an image and doing fallback to the BootROM.

Boot Image Generation

Generating the boot image is critical for success. The following BIF file is an example for the prototype system which includes RSA keys, the FSBL, a PL bitstream, the SSBL application, a test application (hello world), and a second copy of the FSBL in BRAM for CPU warm reset. Images are placed at specific places in flash (offsets) to allow testing as the QSPI can only be erased in 128K sectors.

System Updates

For QSPI flash memory, DDR-less systems with XIP require that the system update software execute from another memory rather than QSPI. The QSPI memory is addressed in linear address mode for XIP which is a read only mode. The update application uses the QSPI driver and flash example to write to QSPI using I/O mode while running from OCM.

Vitis Debug

When programming flash memory or doing debug using an FSBL rather than using ps7_init.tcl, the DDR-less FSBL must be used for all Vitis operations that require FSBL. An FSBL for DDR will fail such that normal operation is not possible, causing failures such as a failure when trying to program flash memory.

RSA Authentication

RSA Without eFuses

It can be useful to test RSA security without the need to program eFuses on the board. This is not a full security test, but it is a useful test prior to programming eFuses and allows the FSBL RSA processing to be tested. A minor change is required to the FSBL to support this feature as illustrated in the code snippet below. The code snippet is inserted at the point in the image_mover.c source file and the LoadBootImage() function where the eFuse Status Register is being read. It uses conditional compilation to turn on this feature with RSA_WITHOUT_EFUSES.

CPU Warm Reset

Resets with the Zynq 7000 architecture include POR and SRST which include rebooting through the BootROM. There are use cases for CPU warm resets without going through the BootROM such as reinitializing the software to a known state while keeping the PL in an operational state. A warm reset causes the CPU to run the FSBL again without going through the BootROM so that images are reloaded and restarted. A CPU warm reset of the type described in the following paragraphs is most suited for simpler systems which do not include AXI masters in the PL, which might be accessing PS resources.

AWDT

The Cortex A9 CPUs of the Zynq 7000 each include a private watchdog timer referred to as the AWDT in the TRM. The AWDT has the ability to reset the CPU. The AWDT must be configured to cause a CPU reset rather than a system reset.

Reset Effects

The following illustration from the TRM at Zynq 7000 SoC TRM (UG585) shows the details of the resets noting that the AWDT with a CPU only reset cannot be detected in a register after the warm reset.

Watchdog Timer Reset Control

The following illustration from the TRM shows the bits of the control register which determines which kind of reset the AWDT causes.

 

The following code snippet illustrates altering the AWDT to cause a CPU reset rather than a system reset.

AWDT Reset Detection

The Multiboot Register is persistent across CPU and SRST resets, and provides a number of bits for user specific purposes. Assuming an application sets a bit in the Multiboot Register, the FSBL can detect the CPU reset and perform application specific processing, such as not reloading the PL.

The following code snippet illustrates setting the MSB of the register which is done before the AWDT causes a CPU reset.

AWDT Driver

A bare metal driver is provided for the AWDT in Vitis and is named xscuwdt. An example application in a source file named xscuwdt_polled_example.c is provided to start the AWDT and cause a CPU reset. The application must be altered to configure the CPU reset, rather than a system reset, and allow the AWDT to timeout to cause the CPU reset.

FSBL

The FSBL must reside in OCM for a CPU reset to be performed. DDR-less systems might require the FSBL to be restored from QSPI to OCM to facilitate the CPU reset. In a non-secure system, the FSBL can be copied by SSBL from QSPI into low OCM. In a secure system, a copy of the FSBL can be loaded by the FSBL into BRAM so that an authenticated FSBL can be reloaded into OCM by SSBL.

Alternative Designs

Another potentially useful method to create a CPU reset is to use the A9_RST0 bit of the slcr.A9_CPU_RST_CTRL Register. More detailed investigation shows that this is not a method that can be used by a CPU to reset itself, but is designed to be used by another CPU such as the other Cortex A9.

© Copyright 2019 - 2022 Xilinx Inc. Privacy Policy