This article will discuss the steps needed to download and compile a Bootable (SD) Linux Image for the ZCU102 using the OSL flow.
Table of Contents
Introduction
The recommended flow for building a Linux system is to use the Petalinux tools. However, this article offers an alternative for users that want full visibility into the Image.
This assumes that the users has downloaded Vitis (used to by the devcetree generator). I have structured this in a way that users can copy this into their Makefile for ease of use.
Some steps are duplicated. For example, the cross_compile steps. This is intentional to allow the users to build each image in isolation.
However, users must use the same tag, as there are dependencies between pmufw and atf for example.The rootFS is downloaded from the released images from here.
NOTE: If building on an Ubuntu (or derivative machine), ensure that the default shell has been changed from Dash to Bash. Compiling in Dash may result in syntax errors within the Makefile that will prevent the code from compiling.
Makefile params:
SHELL := /bin/bash TOOLS ?= /proj/gsd/vivado/Vitis VERSION ?= 2020.2 BOARD ?= ZCU102
Note: Make sure that the tools patch point to your relevant install on your machine
Getting Sources:
get_sources: if [ ! -d "./bootgen" ];then \ git clone https://github.com/Xilinx/bootgen; \ $(MAKE) -C bootgen; \ fi if [ ! -d "./linux-xlnx" ];then \ git clone https://github.com/Xilinx/linux-xlnx; \ cd linux-xlnx && git checkout xilinx-v$(VERSION); \ fi if [ ! -d "./repo" ];then \ mkdir -p repo/my_dtg; \ cd repo/my_dtg && git clone https://github.com/Xilinx/device-tree-xlnx; \ cd device-tree-xlnx && git checkout xilinx-v$(VERSION); \ fi if [ ! -d "./u-boot-xlnx" ];then \ git clone https://github.com/Xilinx/u-boot-xlnx; \ cd u-boot-xlnx && git checkout xilinx-v$(VERSION); \ fi if [ ! -d "./arm-trusted-firmware" ];then \ git clone https://github.com/Xilinx/arm-trusted-firmware; \ cd arm-trusted-firmware && git checkout xilinx-v$(VERSION); \ fi if [ ! -d "./dtc" ];then \ git clone https://git.kernel.org/pub/scm/utils/dtc/dtc.git; \ $(MAKE) -C dtc; \ fi
Build FSBL
Create, or append the proc below to your xsct_script.tcl
proc fsbl {args} { set board 0 for {set i 0} {$i < [llength $args]} {incr i} { if {[lindex $args $i] == "-board"} { set board [string toupper [lindex $args [expr {$i + 1}]]] } } set xsa [glob -nocomplain -directory [pwd] -type f *.xsa *.hdf] hsi::open_hw_design $xsa set fsbl_design [hsi::create_sw_design fsbl_1 -proc psu_cortexa53_0 -app zynqmp_fsbl] if {$board != 0} { common::set_property -name APP_COMPILER_FLAGS -value "-DXPS_BOARD_${board}" -objects $fsbl_design } hsi::generate_app -dir zynqmp_fsbl -compile hsi::close_hw_design [hsi::current_hw_design] }
Note: if you have a development board such as the ZCU102, then you can pass this as a symbol to the compiler
Then call this from your Makefile:
fsbl: $(RM) -r zynqmp_fsbl $(TOOLS)/$(VERSION)/bin/xsct -eval "source xsct_script.tcl; fsbl -board $(BOARD)"
Build PMU Firmware
Create, or append the proc below to your xsct_script.tcl
proc pmufw {} { set xsa [glob -nocomplain -directory [pwd] -type f *.xsa *.hdf] hsi::open_hw_design $xsa hsi::generate_app -app zynqmp_pmufw -proc psu_pmu_0 -dir zynqmp_pmufw -compile hsi::close_hw_design [hsi::current_hw_design] }
Then call this from your Makefile:
pmufw: $(RM) -r zynqmp_pmufw $(TOOLS)/$(VERSION)/bin/xsct -eval "source xsct_script.tcl; pmufw"
Build ATF
atf: $(MAKE) -C arm-trusted-firmware clean source $(TOOLS)/$(VERSION)/settings64.sh; \ export CROSS_COMPILE=aarch64-none-elf-; \ cd arm-trusted-firmware; \ $(MAKE) -f Makefile DEBUG=0 RESET_TO_BL31=1 PLAT=zynqmp bl31
Note: If users want to debug (ie use the symbols) the ATF in Vitis, then set the DEBUG=1. This will place the ATF in DDR at 0x1000
Build u-boot
uboot: $(MAKE) -C u-boot-xlnx clean source $(TOOLS)/$(VERSION)/settings64.sh; \ export CROSS_COMPILE=aarch64-linux-gnu-; \ export ARCH=aarch64; \ export CC=aarch64-linux-gnu-gcc; \ export PATH=$$PATH:$(shell pwd)/dtc; \ cd u-boot-xlnx; \ $(MAKE) -f Makefile xilinx_zynqmp_virt_defconfig; \ $(MAKE) -f Makefile all -j 32
Note: If users want to debug (ie use the symbols) the u-boot in Vitis, then use the u-boot (renamed u-boot.elf) in the boot image.
Build Linux Image:
kernel: $(MAKE) -C linux-xlnx clean source $(TOOLS)/$(VERSION)/settings64.sh; \ export CROSS_COMPILE=aarch64-linux-gnu-; \ export ARCH=arm64; \ export CC=aarch64-linux-gnu-gcc; \ cd linux-xlnx; \ $(MAKE) -f Makefile xilinx_zynqmp_defconfig; \ $(MAKE) -f Makefile all -j 32; \ $(MAKE) -f Makefile modules_install INSTALL_MOD_PATH=.
Build device-tree
- Create a xsct_script.tcl file with the following contents:
proc build_dts {} { set xsa [glob -nocomplain -directory [pwd] -type f *.xsa] hsi::open_hw_design $xsa hsi::set_repo_path ./repo hsi::create_sw_design device-tree -os device_tree -proc psu_cortexa53_0 hsi::generate_target -dir my_dts hsi::close_hw_design [hsi::current_hw_design] }
Then we can call this from our Makefile:
build_dts: $(RM) -r my_dts $(TOOLS)/$(VERSION)/bin/xsct -eval "source xsct_script.tcl; build_dts"
Do do this, open my_dts/system-top.dts and update the gem3 node, by appending the content below:
&gem3 { status = "okay"; local-mac-address = [00 0a 35 00 02 90]; phy-mode = "rgmii-id"; phy-handle = <&phy0>; phy0: phy@c { reg = <0xc>; ti,rx-internal-delay = <0x8>; ti,tx-internal-delay = <0xa>; ti,fifo-depth = <0x1>; }; };
Users can also add the dtsi here to my_dts directory, and include this into the DT structure. For a quick guide on Devicetree debugging, see the wiki here
Compile the devicetree (DTB)
build_dtb: $(RM) -r system.dtb export PATH=$$PATH:$(shell pwd)/dtc; \ gcc -I my_dts -E -nostdinc -undef -D__DTS__ -x assembler-with-cpp -o my_dts/system-top.dts.tmp my_dts/system-top.dts; \ dtc -I dts -O dtb -o system.dtb my_dts/system-top.dts.tmp
Create SD image
Create the BIF file with the contents below:
the_ROM_image: { [fsbl_config] a53_x64 [bootloader, destination_cpu=a53-0] zynqmp_fsbl/executable.elf [pmufw_image] zynqmp_pmufw/executable.elf [destination_device=pl] design_1_wrapper.bit [destination_cpu=a53-0, load=0x00100000] system.dtb [destination_cpu=a53-0,exception_level=el-3,trustzone] arm-trusted-firmware/build/zynqmp/release/bl31/bl31.elf [destination_cpu=a53-0,exception_level=el-2] u-boot-xlnx/u-boot.elf }
bootimage: export PATH=$$PATH:$(shell pwd)/bootgen; \ bootgen -arch zynqMP -image bootgen.bif -w -o BOOT.BIN
Creating the FIT image:
/dts-v1/; / { description = "U-Boot fitImage for plnx_aarch64 kernel"; #address-cells = <1>; images { kernel@0 { description = "Linux Kernel"; data = /incbin/("./linux-xlnx/arch/arm64/boot/Image"); type = "kernel"; arch = "arm64"; os = "linux"; compression = "none"; load = <0x80000>; entry = <0x80000>; hash@1 { algo = "sha1"; }; }; fdt@0 { description = "Flattened Device Tree blob"; data = /incbin/("./system.dtb"); type = "flat_dt"; arch = "arm64"; compression = "none"; hash@1 { algo = "sha1"; }; }; ramdisk@0 { description = "ramdisk"; data = /incbin/("./petalinux-user-image-plnx_aarch64.cpio.gz"); type = "ramdisk"; arch = "arm64"; os = "linux"; compression = "none"; hash@1 { algo = "sha1"; }; }; }; configurations { default = "conf@1"; conf@1 { description = "Boot Linux kernel with FDT blob + ramdisk"; kernel = "kernel@0"; fdt = "fdt@0"; ramdisk = "ramdisk@0"; hash@1 { algo = "sha1"; }; }; conf@2 { description = "Boot Linux kernel with FDT blob"; kernel = "kernel@0"; fdt = "fdt@0"; hash@1 { algo = "sha1"; }; }; }; };
fit_image: export PATH=$$PATH:$(shell pwd)/dtc; \ ./u-boot-xlnx/tools/mkimage -f fitimage.its image.ub
- u-boot-xlnx/tools/mkimage -f fitimage.its image.ub
Load the BOOT.BIN and the image.ub and boot.scr on the SD card and boot.