This article will discuss the steps needed to download and compile a Bootable (SD) Linux Image for the ZCU102 using the OSL flow.
...
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 wiki in a way that users can copy this into their Makefile for ease of use. However, users will need to be careful of the makefile syntax while copy and pasting.
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.
...
Code Block |
---|
|
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
...
Code Block |
---|
language | c# |
---|
title | get_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
Code Block |
---|
|
proc fsbl {} {
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]
#common::set_property -name APP_COMPILER_FLAGS -value "-DXPS_BOARD_ZCU104" -objects $fsbl_design
hsi::generate_app -dir zynqmp_fsbl -compile
hsi::close_hw_design [hsi::current_hw_design]
} |
Note: if you have a customer board such as the ZCU104, then you can pass this as a symbol to the compiler
Then call this from your Makefile:
Code Block |
---|
language | c# |
---|
title | build_fsbl |
---|
|
fsbl:
$(RM) -r zynqmp_fsbl
$(TOOLS)/$(VERSION)/bin/xsct -eval "source xsct_script.tcl; fsbl" |
Build PMU Firmware
Create, or append the proc below to your xsct_script.tcl
Code Block |
---|
|
proc pmufw {} {
set xsa [glob -nocomplain -directory [pwd] -type f *.xsa *.hdf]
hsi::open_hw_design $xsa
if [ ! -d "./embeddedsw" ];then \
git clone https://github.com/Xilinx/embeddedsw; \
cd embeddedsw && git checkout xilinx-v$(VERSION); \
fi |
Build FSBL
Create, or append the proc below to your xsct_script.tcl
Code Block |
---|
|
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
if {[file isdirectory embeddedsw]} {
puts "INFO: Adding embeddedsw repo"
hsi::set_repo_path ./embeddedsw
}
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 -app zynqmp_pmufw -proc psu_pmu_0 -dir zynqmp_pmufwfsbl -compile
hsi::close_hw_design [hsi::current_hw_design]
} |
Then call this from your Makefile:
...
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:
Code Block |
---|
language | c# |
---|
title | build_pmufwfsbl |
---|
|
pmufwfsbl:
$(RM) -r zynqmp_pmufwfsbl
$(TOOLS)/$(VERSION)/bin/xsct -eval "source xsct_script.tcl; pmufw" |
Build ATF
Code Block |
---|
|
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
Code Block |
---|
|
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.
...
If users want to make modifications to the FSBL then they can do this in the embeddedsw/lib/sw_apps/zynqmp_fsbl/src. Or, if a valid patch then apply this to embeddedsw
Build PMU Firmware
Create, or append the proc below to your xsct_script.tcl
Code Block |
---|
|
proc pmufw {} {
set xsa [glob -nocomplain -directory [pwd] -type f *.xsa *.hdf]
hsi::open_hw_design $xsa
if {[file isdirectory embeddedsw]} {
puts "INFO: Adding embeddedsw repo"
hsi::set_repo_path ./embeddedsw
}
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:
Code Block |
---|
language | c# |
---|
title | kernelbuild_pmufw |
---|
|
kernelpmufw:
$(MAKERM) -C linux-xlnx clean
source r zynqmp_pmufw
$(TOOLS)/$(VERSION)/settings64.sh; \
export CROSS_COMPILE=aarch64-linux-gnu-; \
export ARCH=arm64; \
export CC=aarch64-linux-gnu-gcc; \
cd linux-xlnx; \
bin/xsct -eval "source xsct_script.tcl; pmufw" |
If users want to make modifications to the PMUFW then they can do this in the embeddedsw/lib/sw_apps/zynqmp_pmufw/src. Or, if a valid patch then apply this to embeddedsw
Build ATF
Code Block |
---|
|
atf:
$(MAKE) -C arm-ftrusted-firmware Makefile xilinx_zynqmp_defconfigclean
source $(TOOLS)/$(VERSION)/settings64.sh; \
$(MAKE) -f Makefile all -j 32export CROSS_COMPILE=aarch64-none-elf-; \
cd arm-trusted-firmware; \
$(MAKE) -f Makefile modules_install INSTALL_MOD_PATH=. |
Build device-tree
- Create a xsct_script.tcl file with the following contents:
Code Block |
---|
|
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:
Code Block |
---|
|
build_dts:
$(RM) -r my_dts
DEBUG=0 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. For more info see the ATF wiki here
Build u-boot
Code Block |
---|
|
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) 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:
Code Block |
---|
|
kernel:
$(MAKE) -C linux-xlnx clean
source $(TOOLS)/$(VERSION)/bin/xsct -eval "source xsct_script.tcl; build_dts" |
...
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 {args} {
set board 0
set version 2020.2
for {set i 0} {$i < [llength $args]} {incr i} {
if {[lindex $args $i] == "-board"} {
set board [string tolower [lindex $args [expr {$i + 1}]]]
}
if {[lindex $args $i] == "-version"} {
set version [string toupper [lindex $args [expr {$i + 1}]]]
}
}
set xsa [glob -nocomplain -directory [pwd] |
...
...
...
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]
if {$board != 0} {
foreach lib [glob -nocomplain |
...
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
-directory repo/my_dtg/device-tree-xlnx/device_tree/data/kernel_dtsi/${version}/include/dt-bindings -type d *] {
if {![file exists my_dts/include/dt-bindings/[file tail $lib]]} {
file copy -force $lib my_dts/include/dt-bindings
}
}
set dtsi_files [glob -nocomplain -directory repo/my_dtg/device-tree-xlnx/device_tree/data/kernel_dtsi/${version}/BOARD -type f *${board}*]
if {[llength $dtsi_files] != 0} {
file copy -force [lindex $dtsi_files end] my_dts
set fileId [open my_dts/system-user.dtsi "w"]
puts $fileId "/include/ \"[file tail [lindex $dtsi_files end]]\""
puts $fileId "/ {"
puts $fileId "};"
close $fileId
} else {
puts "Info: Board file: $board is not found and will not be added to the system-top.dts"
}
}
} |
If there is a valid board found, then it will added to dtsi files. Then we can call this from our Makefile:
Code Block |
---|
|
build_dts:
$(RM) -r my_dts
$(TOOLS)/$(VERSION)/bin/xsct -eval "source xsct_script.tcl; build_dts -version $(VERSION) -board $(BOARD)" |
Compile the devicetree (DTB)
Code Block |
---|
|
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.dts.tmp |
Note: Users can add the symbols by adding the -@ switch here. The symbols are added by default in petalinux
Create SD image
Create the BIF file with the contents below:
Code Block |
---|
|
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
} |
Then in bootgen command from your Makefile] u-boot-xlnx/u-boot.elf
} |
Then in bootgen command from your Makefile
Code Block |
---|
|
bootimage:
export PATH=$$PATH:$(shell pwd)/bootgen; \
bootgen -arch zynqmp -image bootgen.bif -w -o BOOT.BIN |
Downloading the RootFS:
There are released images for all Xilinx development boards. I will extract the rootfs from the image.ub here using dumpimage utility:
Code Block |
---|
| bootimage |
extract_rootfs:
export PATH=$$PATH:$(shell pwd)/bootgen; \
bootgen -arch zynqMP -image bootgen.bif -w -o BOOT.BINtar xvf $(VERSION)-$(BOARD)-release.tar.xz
./u-boot-xlnx/tools/dumpimage -T flat_dt -p 2 $(VERSION)-$(BOARD)-release/image.ub -o petalinux-image-minimal-zynqmp-generic.cpio.gz |
Creating the FIT image:
Code Block |
---|
|
/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";
};
};
};
}; |
Use the command below to created the .ub file:
...