This article describes a flow to build a CentOS 8 system for Zynq UltraScale+ which includes building UEFI firmware, building the CentOS 8 kernel and installing these images on a prebuilt CentOS 8 disk OpenStack cloud image.
Table of Contents
Table of Contents | ||||
---|---|---|---|---|
|
Introduction
Embedded Linux systems are typically lightweight and cross compiled from build frameworks such as Yocto, Petalinux or Buildroot. However, as embedded systems become more powerful and look more like embedded servers, ARM64 machines are capable of running these higher level Linux distributions. Distros such as CentOS provide attractive features such as SELinux which are security enhancements including mandatory access controls (MAC), updated security patches, package managers such as Yum or DNF for installing software remotely from trusted repositories, a stable ABI for maintaining compatible software and modules and a well known compute environment. These distros maintain their own kernel repositories by pulling from mainline and applying patches. Xilinx is committed to upstreaming drivers, so drivers accepted by mainline will automatically get merged into the distro kernel source when they pull a corresponding release. Distros also provide a build system generally based on the package manager to authenticate source, sign binaries and automate the build (fetch, patch, configure, build, package).
...
Note |
---|
Building a CentOS 8 system for Zynq UltraScale+ is currently a proof-of-concept (POCPoC). You should not assume this builds a Xilinx supported, production-ready CentOS 8 system. Please do your due diligence before deploying CentOS 8 and regression test against your system requirements. |
Requirements
CentOS 8 VM or bare-metal host machine
Minimum hard disk space
25 GB without UEFI build
50 GB with UEFI build
Sudo privileges
Terminal emulator
Internet access
ZCU102 evaluation board
SD card (8 GB ( minimum)/16 GB ( recommended) SD card
Porting Philosophy and Strategy
The philosophy was to make the ZCU102 look as much like a standard Linux PC or server and rely on CentOS for most of the heavy lifting. Essentially we want to do as little work as possible. The strategy was to isolate the components where Xilinx tools build the low level architecture dependent components, UEFI firmware and DTB and the distro provides the kernel source, bootloader components and the root filesystem. The focus is on the kernel, which needs to be configured and built to support Xilinx platforms. Fortunately Xilinx has committed to upstreaming drivers, so many of the required drivers needed to boot the system are already present in the CentOS 8 kernel tree. That said, that the timing of getting these commits accepted upstream can be lengthy, so there may be significant lags until they are accepted. Therefore upstream kernel versions may not have the equivalent driver support of a similar kernel version in the Xilinx GitHub repository. If you need patches or drivers that are not upstreamed, then you will need to backport them yourself or build a kernel from the Xilinx GitHub repository.
CentOS 8 Host Machine
Install Host Package Dependencies
At this point I assume you have administered a base CentOS 8 machine including sudo privilege, terminal emulator and internet access. I recommend allocating 25 GB or more free space. If you are building the UEFI firmware, then you should allocate a minimum of 50 GB. First lets install some host dependencies.
...
Code Block | ||
---|---|---|
| ||
PATH="$HOME/bin:$HOME/bin/gcc-arm-8.2-2019.01-x86_64-aarch64-linux-gnu/bin:$PATH" |
Prepare Workspace
Here we are going to simply create a basic top level directory structure from which we will build our system.
Code Block | ||
---|---|---|
| ||
$ export COS_BUILD=$HOME/centos8-dev $ mkdir -p $COS_BUILD/rpmbuild $COS_BUILD/images/{efi,boot,rootfs} $COS_BUILD/deploy/{efi/dtb/xilinx,boot} |
Build the UEFI Firmware
In order to boot a Zynq UltraScale+ device, the boot ROM expects a “boot.bin” binary image. The “boot.bin” is composed of partitions that hold images for various portions of the boot process and run-time. In a Linux system this image generally holds the FSBL, PMU firmware, PL bitstream and u-boot. For the purposes of this article, I am going to ignore the PL bitstream. These images can be built and packaged in several ways, but I’ll show how to build it it through Xilinx Yocto.
...
Code Block | ||
---|---|---|
| ||
$ cp tmp/deploy/images/zcu102-zynqmp/BOOT-zcu102-zynqmp.bin $COS_BUILD/deploy/efi/boot.bin |
Build the Kernel
This section walks through two builds of the kernel. The first is a bootstrap kernel, which is a straight forward make build. The bootstrap kernel does not rely on any kernel modules to mount the final root filesystem. The second kernel is built with the CentOS RPM build system. This build system pulls directly from the CentOS kernel repository which also includes patches, kernel configurations and build scripts.
Clone the CentOS 8 Kernel Source
Here we are going to clone “centos-git-common” which includes build scripts and the “kernel” repository which includes source and spec files for the RPM build. The “get_sources.sh” script will fetch the kernel source tarball.
Code Block | ||
---|---|---|
| ||
$ cd $COS_BUILD/rpmbuild $ git clone https://git.centos.org/centos-git-common.git $ git clone https://git.centos.org/rpms/kernel.git $ cd kernel $ git checkout -b kernel-4.18.0-147.3.1.el8_1.xlnx imports/c8/kernel-4.18.0-147.3.1.el8_1 $ ../centos-git-common/get_sources.sh |
Build a Bootstrap Kernel
Because the installed CentOS kernel image may not include some critical configurations required for Zynq UltraScale+, you may need to build a bootstrap kernel. Once we boot the bootstrap kernel, we can formally install the kernel RPMS which will installs the newly configured kernel and updates the initrd and GRUB configuration.
...
Code Block |
---|
$ make distclean |
Build the Kernel RPM Packages
Create a Kernel Configuration Fragment
Create the configuration fragment file “kernel-aarch64-zynqmp.cfg” in the SOURCES directory with the kernel configuration as shown below.
...
Code Block | ||
---|---|---|
| ||
$ cd $COS_BUILD/rpmbuild/kernel/SOURCES $ cat << EOF > kernel-aarch64-zynqmp.cfg CONFIG_ARCH_ZYNQMP=y CONFIG_SERIAL_XILINX_PS_UART=y CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y CONFIG_MMC_SDHCI_OF_ARASAN=m CONFIG_I2C_CADENCE=m CONFIG_GPIO_ZYNQ=m CONFIG_NET_CADENCE=y CONFIG_MACB=m CONFIG_RTC_DRV_ZYNQMP=m CONFIG_CADENCE_WATCHDOG=m CONFIG_USB_DWC3=m CONFIG_XILINX_ZYNQMP_DMA=m CONFIG_SPI_ZYNQMP_GQSPI=m EOF |
Create a Custom Kernel SPEC File
The SPEC file is the script which controls the build of an RPM package. We will make a few edits to a copy of the default aarch64 SPEC file to support Zynq UltraScale+.
...
Code Block | ||
---|---|---|
| ||
$ git add SPECS/kernel-xlnx.spec SOURCES/kernel-aarch64-zynqmp.cfg $ git commit -m'added zynqmp machine' -a |
Build the Kernel RPM Packages
Code Block | ||
---|---|---|
| ||
$ cd $COS_BUILD/rpmbuild/kernel $ rpmbuild --define "%_topdir `pwd`" -bb SPECS/kernel-xlnx.spec --with cross --target aarch64 --with baseonly --without debuginfo \ --without tools --without perf --without bpftool --without selftests --nodeps --noclean |
...
Code Block | ||
---|---|---|
| ||
cp RPMS/aarch64/*.rpm $COS_BUILD/deploy/boot/ |
Install UEFI and Kernel on a Preinstalled CentOS Disk Image
We will install the bootloader and kernel on a prebuilt CentOS 8 Stream raw OpenStack cloud disk image.
Installing Centos 8 from an ISO is beyond the scope of this article. Please see Virtually Install CentOS and Fedora on Zynq UltraScale+ to install from an ISO.
...
Since we are not using UEFI secure boot, we want to will boot GRUB directly. So we will need to replace shim (bootaa64.efi) with GRUB (grubaa64.efi).
...
Since we are installing on a cloud image, we need to disable the cloud-init to make it look more like a standard distro. If you are installing on a disk image generated from an ISO, this step should be skipped.
Code Block |
---|
$ sudo touch rootfs/etc/cloud/cloud-init.disabled |
Skip this step if you are installing on a disk image generated from an ISO or want to keep the OpenStack initialization.
Finally, let’s unmount the partitions and cleanup the device mappings.
...
Info |
---|
You may use “dmesg” to find the device node corresponding to your SD card. |
Booting ZCU102
Open a terminal emulator of your choice on your host machine and connect to the serial port on the ZCU102. Insert the SD card on the ZCU102, make sure the dip switches are set to SD boot and power on the board. If everything goes well, you should see an FSBL banner, PMU firmware version and U-boot messages.
...
Before we install the kernel, we need to ensure that the SD/MMC modules are included in the initramfs by adding it to a dracut conf configuration file as shown below. If you need any additional kernel modules for boot that are not included by default, you may add them here as well.
...
Code Block | ||
---|---|---|
| ||
# vi /etc/default/grub ## add "noefi" and any additional kernel options to GRUB_CMDLINE_LINUX andthen save # grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg |
...
Once you get to the GRUB menu, you should see that the first option is your updated kernel.
...
References
...