...
CentOS 8 supports GCC 8.2.1, so I recommend sticking with the same version for to guarantee ABI compatibility. You may install GCC from any provider such as ARM, Linaro , or Xilinx ( Vitis), etc. The link below will pull the aarch64 cross compiler 8.2.1 binaries from ARM.
...
Once the cross compiler is downloaded, extract it to a location of your choice and add the bin directory to your PATH. For example, I installed it in $HOME/bin and prepended PATH in my “.bashrc” file.
Code Block | ||
---|---|---|
| ||
PATH="$HOME/bin:$HOME/bin/gcc-arm-8.2-2019.01-x86_64-aarch64-linux-gnu/bin:$PATH" |
...
Copy the generated “boot.bin” into the deploy directory we created earlier.
Code Block | ||
---|---|---|
| ||
$ cp tmp/deploy/images/zcu102-zynqmp/BOOT-zcu102-zynqmp.bin $COS_BUILD/deploy/efi/boot.bin |
Build the Kernel
This build section walks through two builds of the kernel. The first is a bootstrap kernel, which is a straight forward make build. The second uses the official boostrap 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 for CentOS. The This build system pulls directly from the CentOS kernel repository which also includes patches, kernel configurations and utility build scripts.
Clone the CentOS 8 Kernel Source
Here we are going to clone “centos-git-common” which includes utility build scripts for CentOS and the CentOS “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 |
As a good measure, lets install any additional package dependencies required by the SPEC file that we may have missed.
Code Block |
---|
sudo dnf builddep SPECS/kernel.spec |
Note |
---|
This may may cause your host to hang on a reboot. Try building without this first and install any missing packages manually. |
Build a Bootstrap Kernel
...
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 |
---|
$ cp BUILDROOT/kernel-4.18.0-147.3.1.el8.xlnx.aarch64/boot/dtb-4.18.0-147.3.1.el8.xlnx.aarch64/xilinx/zynqmp-zcu102-rev1.0.dtb $COS_BUILD/deploy/efi/dtb/xilinx/ |
Code Block | ||
---|---|---|
| ||
cp RPMS/aarch64/kernel-4.18.0-147.3.1.el8.xlnx.aarch64.rpm RPMS/aarch64/kernel-core-4.18.0-147.3.1.el8.xlnx.aarch64.rpm \ RPMS/aarch64/kernel-modules-4.18.0-147.3.1.el8.xlnx.aarch64.rpm $COS_BUILD/*.rpm $COS_BUILD/deploy/boot/ |
Install UEFI and Kernel on a Preinstalled CentOS Disk Image
We will start with a install the bootloader and kernel on a prebuilt CentOS 8 Stream raw disk image of a CentOS server as the basis for our system.
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 a CentOS 8 image before proceedingfrom an ISO.
Code Block | ||
---|---|---|
| ||
$ cd $COS_BUILD/images #$ copy the qcow2 image here |
...
wget https://cloud.centos.org/centos/8-stream/aarch64/images/CentOS-Stream-GenericCloud-8-20200113.0.aarch64.qcow2 |
Change the root password with “virt-customize” to “zynqmp” or a password of your choice.
Code Block | ||
---|---|---|
| ||
$ virt-customize -a CentOS-Stream-GenericCloud-8-aarch64-1905-dvd120200113.0.aarch64.qcow2 --root-password password:zynqmppassword password:zynqmp [ 0.0] Examining the guest ... [ 33.4] Setting a random seed [ 33.7] Setting the machine ID in /etc/machine-id [ 33.8] Setting passwords [ 51.3] Finishing off |
The installed file is a QCOW2 (QEMU copy-on-write) virtual disk, so we need to convert it to a raw disk image.
Code Block | ||
---|---|---|
| ||
$ qemu-img convert CentOS-Stream-GenericCloud-8-aarch64-1905-dvd120200113.0.aarch64.qcow2 CentOS-Stream-GenericCloud-8-aarch64-1905-dvd120200113.0.aarch64.raw |
Now lets examine the partitions in this disk image. You will see there are 3 partitions. The first is the EFI System Partition (ESP) which is a FAT formatted partition. The second partition is an EXT4 a Linux formatted partition. The third partition is an LVM root filesystem.
Code Block | ||
---|---|---|
| ||
$ fdisk -l CentOS-Stream-GenericCloud-8-aarch64-1905-dvd120200113.0.aarch64.raw Disk CentOS-Stream-GenericCloud-8-aarch64-1905-dvd120200113.0.aarch64.raw: 710 GiB, 751619276810737418240 bytes, 1468006420971520 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: gpt Disk identifier: E51C2C48079AB561-87F2A1E1-419D4340-BA13A744-687E3930A160C041B93E2E67 Device Start End Sectors Size Type CentOS-Stream-GenericCloud-8-aarch64-1905-dvd120200113.0.aarch64.raw1 2048 1230847 1228800 600M EFI System CentOS-8Stream-aarch64GenericCloud-19058-dvd1.raw2 1230848 3327999 2097152 1G Linux filesystem CentOS-8-aarch64-1905-dvd1.raw3 3328000 14678015 11350016 5.4G Linux LVM20200113.0.aarch64.raw2 1230848 17614847 16384000 7.8G Linu |
The first thing we note is that “Disklabel type” is set to “gpt”. However, Zynq UltraScale+ only support MBR partitioned disks, so we need to convert from GPT to MBR with “sgdisk”.
Code Block | ||
---|---|---|
| ||
$ sgdisk -m 1:2:3 CentOS-Stream-GenericCloud-8-aarch64-1905-dvd120200113.0.aarch64.raw Warning: The kernel is still using the old partition table. The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8) GPT data structures destroyed! You may now partition the disk using fdisk or other utilities. |
...
Code Block |
---|
$ sfdisk -A CentOS-Stream-GenericCloud-8-aarch64-1905-dvd120200113.0.aarch64.raw 1 The bootable flag on partition 1 is enabled now. The partition table has been altered. Syncing disks. |
...
Code Block |
---|
$ fdisk -l CentOS-Stream-GenericCloud-8-aarch64-1905-dvd120200113.0.aarch64.raw Disk CentOS-Stream-GenericCloud-8-aarch64-1905-dvd120200113.0.aarch64.raw: 710 GiB, 751619276810737418240 bytes, 1468006420971520 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x00000000 Device Boot Start End Sectors Size Id Type CentOS-Stream-GenericCloud-8-aarch64-1905-dvd120200113.0.aarch64.raw1 * 2048 1230847 1228800 600M ef EFI (FAT-12/16/32) CentOS-8-aarch64-1905-dvd1.raw2 1230848 3327999 2097152 1G 83 Linux CentOSStream-GenericCloud-8-aarch64-1905-dvd1.raw320200113.0.aarch64.raw2 33280001230848 1467801517614847 1135001616384000 57.4G8G 8e83 Linux LVMLinu |
We need to setup the map devices for the raw disk image we prepared earlier. Mount the first two partitions on “efi” and “boot” “rootfs” respectively.
Code Block |
---|
$ cd $COS_BUILD/images $ sudo kpartx -va CentOS-Stream-GenericCloud-8-aarch64-1905-dvd120200113.0.aarch64.raw add map loop0p1 (253:123): 0 1228800 linear 7:40 2048 add map loop0p2 (253:134): 0 209715216384000 linear 7:40 1230848 add map loop0p3 (253:14): 0 11350016 linear 7:4 3328000 $ sudo mount /dev/mapper/loop0p1 efi $ sudo mount /dev/mapper/loop0p2 bootrootfs |
The Zynq UltraScale+ boot ROM will search for “boot.bin” on the first partition. The boot ROM will load FSBL and PMU firmware. FSBL will in turn load u-boot. U-boot acting as the UEFI firmware will search the current partition for the corresponding board DTB file and pass it to the EFI bootloader through the EFI configuration table. If it doesn’t find one, it will pass its own DTB to the EFI bootloader. However, this DTB may not be compatible with your kernel version, so I recommend using the DTB built with the kernel. So let's install the UEFI firmware (boot.bin) and ZCU102 DTB as shown below from the deploy directory.
...
Since we are not using UEFI secure boot, we want to boot GRUB directly. So we need to will replace shim (bootaa64.efi) with GRUB (grubaa64.efi).
...
grubaa64.efi).
Code Block | ||
---|---|---|
| ||
$ sudo cp efi/EFI/centos/grubaa64.efi efi/EFI/BOOT/bootaa64.efi |
UEFI firmware will search for an image named bootaa64.efi which is why we needed to rename the EFI image.
Next lets install the bootstrap kernel and kernel RPM packages into the BOOT directory.
Code Block | ||
---|---|---|
| ||
$ sudo cp efi../EFIdeploy/centosboot/grubaa64.efi* efirootfs/EFIboot/BOOT/bootaa64.efi |
UEFI firmware will search for an image named bootaa64.efi which is why we needed to rename the EFI image.
Next lets install the bootstrap kernel and kernel RPM packages into the BOOT directory.
Code Block | ||
---|---|---|
| ||
$ sudo cp ../deploy/boot/* boot/ |
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 |
Finally, let’s unmount the partitions and cleanup the device mappings.
Code Block | ||
---|---|---|
| ||
$ sudo umount efi $ sudo umount bootrootfs $ sudo kpartx -d CentOS-Stream-GenericCloud-8-aarch64-1905-dvd120200113.0.aarch64.raw loop deleted : /dev/loop0 |
Now the raw disk image is ready to write to the SD card. With the CD SD card plugged into your CentOS machine, note the device node of your card (/dev/sdX) and install the image as shown below.
Code Block | ||
---|---|---|
| ||
$ sudo dd if=CentOS-Stream-GenericCloud-8-aarch64-1905-dvd120200113.0.aarch64.raw of=/dev/sdX bs=4M iflag=fullblock oflag=direct status=progress; sync |
...