JTAG Booting an Embedded Linux image on Zynq UltraScale+ MPSoc
You may already know that my last article was about booting an Embedded Linux image on a Zynq SoC using JTAG and XSCT. In that article, I examined in which situations you would require to boot an image over JTAG and I also showed how you can do it by utilizing the XSCT utility provided by Xilinx. The tutorial was covering the JTAG booting process of both the Bare-Metal and more sophisticated images such as Embedded Linux. In this tutorial, we will cover a similar but more sophisticated process. By following this hands-on guide step-by-step you will be able to boot up any image on your Zynq UltraScale+ from JTAG.
The hardware requirements of both projects are the same. You will of course need a Zynq UltraScale+ based target that supports JTAG debugging, a JTAG cable, and a development computer with XSDB/XSCT utility that comes with installing the Xilinx SDK or Vitis. To understand what actually the XSCT tool is and how we will utilize it, you can take a brief look at the corresponding section of the previous article.
Step-by-step JTAG Booting
Similar to any other booting technique, the JTAG booting is also quite fragile. It can easily be corrupted and you can end up with a black, meaningless screen which you cannot diagnose what’s actually going on under the hood. So, you should follow each step with extra care until you get used to dealing with problems solely. Even if the initial learning process is hard, it is worth all your effort. By booting up your board once with JTAG, you will love how powerful it makes you when it comes to developing embedded software.
In summary, the booting process will be handled in multiple steps. Each step has a unique purpose and order which should never be changed. Roughly, the steps are as below. Notice how each step contributes incrementally to the booting process.
The XSCT utility supports the TCL language syntax in any operation. As our operations are quite simple, you don’t need to have a deep TCL knowledge or background.
Launching the XSCT Server
The XSCT server and any other Xilinx utility can be found under your Xilinx Tools installation path. In my case, I launch it from?<INSTALLATION_PATH>/Xilinx/Vitis/2021.1/bin/xsct.
When launched, the prompt appears on the command line waiting for you to interact with it. It’s also possible to launch the utility with a properly prepared TCL script. We will talk about it later.
11:38:24 ~ > /opt/Xilinx/Vitis/2021.1/bin/xsct
****** Xilinx Software Commandline Tool (XSCT) v2021.1
**** SW Build 3246112 on 2021-06-09-14:19:56
** Copyright 1986-2021 Xilinx, Inc. All Rights Reserved.
xsct% help
Available Help Categories
breakpoints - Target Breakpoints/Watchpoints.
connections - Target Connection Management.
device - Device Configuration System.
download - Target Download FPGA/BINARY.
hsi - HSI commands.
ipi - IPI commands to Versal PMC.
jtag - JTAG Access.
memory - Target Memory.
miscellaneous - Miscellaneous.
petalinux - Petalinux commands.
projects - Vitis Projects.
registers - Target Registers.
reset - Target Reset.
running - Program Execution.
streams - Jtag UART.
svf - SVF Operations.
tfile - Target File System.
Type "help" followed by above "category" for more details or
help" followed by the keyword "commands" to list all the commands
xsct%
Target Connection
The XSCT isn’t the only utility that Xilinx provides. There are other utilities that serve different purposes. Any utility can utilize the other by making proper calls. The XSCT and other utilities call the Hardware Server to connect to the JTAG kits. In XSCT, you can do it by calling the?connect?command as below.
connect -url tcp:<DEVICE_IP>:3121
The device IP varies according to the JTAG kit that you use for the connection.
The default port for each connection is?3121, I never saw a case in which I had to use another port.
Listing the JTAG Targets
After connecting the JTAG cable, we are able to list the targets connected to our JTAG chain. A simple call to?targets?will list your devices on the JTAG chain.
xsct% targets
1 PS TAP
2 PMU
3 PL
4 PSU
5 RPU (Reset)
6 Cortex-R5 #0 (No Power)
7 Cortex-R5 #1 (No Power)
8 APU
9 Cortex-A53 #0 (Running)
10 Cortex-A53 #1 (Running)
11 Cortex-A53 #2 (Running)
12 Cortex-A53 #3 (Running)
The list you see when you invoke the?targets?command represents each device connected to the JTAG chain. The device can be a unit, a CPU core, FPGA, etc. You can manage each one by selecting it explicitly. There can be times when you cannot establish a reliable connection between your target and the JTAG cable. In such cases, you should inspect the error messages and take action according to them. For instance, when either there is no JTAG connection or the board power is off, the error prompt appears as below.
xsct% targets
1 whole scan chain (board power off)
The most common issue that you will face will be related to the JTAG frequency that you use. The hardware structure of the JTAG chain affects its optimal frequency severely. Some physical properties might affect the suitable JTAG frequency such as the cable length, number of targets, etc. In that case, the XSCT utility creates some error messages indicating an unreliable connection with the target. You can see some of them below.
xsct% targets
1 whole scan chain (Unknown device configuration)
xsct% targets
1 whole scan chain (Unknown IR length)
xsct% targets
1 whole scan chain (too many devices)
When such outputs are seen, you should readjust your JTAG frequency to establish a reliable, robust connection. Supported JTAG frequencies for a JTAG cable can be found by calling the?jtag frequency -list?as below. You can then select a proper frequency from the given list. An arbitrary frequency can also be chosen, utility handles the rounding in that case.
xsct% jtag targets 1
xsct% jtag frequency -list
125000 250000 500000 1000000 2000000 3000000 4000000 6000000 7500000 10000000 12000000 13000000
15000000 20000000 30000000 40000000 50000000 60000000 70000000 80000000 90000000 100000000
xsct% jtag frequency 7500000
7500000
xsct% jtag frequency 7000000
7017543
Interrupting the System
Before beginning operations, the processing system should be interrupted and reset to its initial state. Without this step, you can not manage the processing system. This step is different in the Zynq SoC. To reset the system:
xsct% targets -set -nocase -filter {name =~ "*PSU*"}
xsct% rst
xsct% Info: Cortex-A53 #0 (target 9) Stopped at 0xffff0000 (Reset Catch)
xsct% targets
1 PS TAP
2 PMU
3 PL
4* PSU
5 RPU (Reset)
6 Cortex-R5 #0 (No Power)
7 Cortex-R5 #1 (No Power)
8 APU
9 Cortex-A53 #0 (Reset Catch, EL3(S)/A64)
10 Cortex-A53 #1 (Reset)
11 Cortex-A53 #2 (Reset)
12 Cortex-A53 #3 (Reset)
Configuring the FPGA
As the Zynq UltraScale+ SoC is actually an FPGA chip, it requires a hardware image to provide access to its underlying components like the DDR, Ethernet, serial interfaces, etc. Downloading a full FPGA image via JTAG is quite simple. You just need to use the?fpga?command as below.
xsct% targets
1 PS TAP
2 PMU
3 PL
4* PSU
5 RPU (Reset)
6 Cortex-R5 #0 (No Power)
7 Cortex-R5 #1 (No Power)
8 APU
9 Cortex-A53 #0 (Reset Catch, EL3(S)/A64)
10 Cortex-A53 #1 (Reset)
11 Cortex-A53 #2 (Reset)
12 Cortex-A53 #3 (Reset)
xsct% targets -set -nocase -filter {name =~ "*PS TAP*"}
xsct% fpga "system.bit"
100% 25MB 1.2MB/s 00:21
Downloading the FPGA image clears the existing PL image and replaces it with the given one immediately. You can also manage the programmable logic by providing options to the same command. Enter?help fpga?to inspect further. Downloading the FPGA image to the hardware is enough for now, the rest is out of the scope of this tutorial.
PMU Firmware
The Zynq UltraScale+ SoC includes a dedicated MicroBlaze processor to perform platform management. The name PMU stands for the Platform Management Unit. Its main duties are to initialize some of the system components prior to booting, manage the power distributed to power islands, and system error handling. The firmware has the ability to communicate with the user applications running on the Processing System Unit. Users can create requests to manage the platform according to their will. It is also possible to modify the PMU Firmware using the Vitis IDE. You can further inspect the details and usage scenarios of PMU Firmware by taking a look at the Technical Reference Manual of Zynq UltraScale+,?i.e. UG1085.
The MicroBlaze processor residing inside the Platform Management Unit cannot be accessed without disabling some of the security gates on the Processing System Unit(PSU). So, our first action is to disable the security gates. And then, we will download the PMU Firmware to the target processor and run it. To ensure security, we will re-enable the security gates.
xsct% targets -set -nocase -filter {name =~ "*PSU*"}
xsct% targets
1 PS TAP
2 PMU
3 PL
4* PSU
5 RPU (Reset)
6 Cortex-R5 #0 (No Power)
7 Cortex-R5 #1 (No Power)
8 APU
9 Cortex-A53 #0 (Reset Catch, EL3(S)/A64)
10 Cortex-A53 #1 (Reset)
11 Cortex-A53 #2 (Reset)
12 Cortex-A53 #3 (Reset)
xsct% mask_write 0xFFCA0038 0x1C0 0x1C0
xsct% targets
1 PS TAP
2 PMU
13 MicroBlaze PMU (Sleeping. No clock)
3 PL
4* PSU
5 RPU (Reset)
6 Cortex-R5 #0 (No Power)
7 Cortex-R5 #1 (No Power)
8 APU
9 Cortex-A53 #0 (Reset Catch, EL3(S)/A64)
10 Cortex-A53 #1 (Reset)
11 Cortex-A53 #2 (Reset)
12 Cortex-A53 #3 (Reset)
As you can see, the MicroBlaze core appears on the JTAG target chain immediately after we disable the security gates. By gathering access to the processor, we are now able to download and run the PMU firmware.
领英推荐
xsct% targets -set -nocase -filter {name =~ "*MicroBlaze PMU*"}
xsct% dow "pmufw.elf"
Downloading Program -- pmufw.elf
section, .vectors.reset: 0xffdc0000 - 0xffdc0007
section, .vectors.sw_exception: 0xffdc0008 - 0xffdc000f
section, .vectors.interrupt: 0xffdc0010 - 0xffdc0017
section, .vectors.hw_exception: 0xffdc0020 - 0xffdc0027
section, .text: 0xffdc0050 - 0xffdd1057
section, .rodata: 0xffdd1058 - 0xffdd2287
section, .data: 0xffdd2288 - 0xffdd639b
section, .sdata2: 0xffdd639c - 0xffdd639f
section, .sdata: 0xffdd63a0 - 0xffdd639f
section, .sbss: 0xffdd63a0 - 0xffdd639f
section, .bss: 0xffdd63a0 - 0xffdda0db
section, .srdata: 0xffdda0dc - 0xffdda9f7
section, .stack: 0xffdda9f8 - 0xffddb9f7
section, .xpbr_serv_ext_tbl: 0xffddf6e0 - 0xffddfadf
100% 0MB 0.2MB/s 00:00
Setting PC to Program Start Address 0xffdd0a04
Successfully downloaded pmufw.elf
xsct% Info: MicroBlaze PMU (target 13) Stopped at 0xffdc8534 (Stop)
xsct% con
Info: MicroBlaze PMU (target 13) Running
If everything is well, we can re-enable the security gates in order to prevent access to the MicroBlaze PMU and move on to the PSU initialization.
xsct% targets -set -nocase -filter {name =~ "*PSU*"}
xsct% mask_write 0xFFCA0038 0x1C0 0x0
xsct% targets
1 PS TAP
2 PMU
3 PL
4* PSU
5 RPU (Reset)
6 Cortex-R5 #0 (No Power)
7 Cortex-R5 #1 (No Power)
8 APU
9 Cortex-A53 #0 (Reset Catch, EL3(S)/A64)
10 Cortex-A53 #1 (Reset)
11 Cortex-A53 #2 (Reset)
12 Cortex-A53 #3 (Reset)
APU and PSU Initialization
Prior to downloading the First Stage Boot-Loader to the Application Processor Unit(APU), the resets must be removed. In addition, the Processing System Unit must be initialized according to your hardware image?(HDF/XSA file). A TCL script named?“psu_init.tcl”?exists in the hardware image exported from the Vivado Design Tool. Here are the commands for these steps.
xsct% targets -set -nocase -filter {name =~ "*APU*"}
xsct% targets
1 PS TAP
2 PMU
3 PL
5 PSU
6 RPU (Reset)
7 Cortex-R5 #0 (No Power)
8 Cortex-R5 #1 (No Power)
9* APU
10 Cortex-A53 #0 (Reset Catch, EL3(S)/A64)
11 Cortex-A53 #1 (Reset)
12 Cortex-A53 #2 (Reset)
13 Cortex-A53 #3 (Reset)
xsct% mwr 0xffff0000 0x14000000
xsct% mask_write 0xFD1A0104 0x501 0x0
xsct% source psu_init.tcl
xsct% psu_init
You will not see any output on the screen if the PSU is initialized successfully. By completing this step, we gained access to the PSU resources.
First Stage Boot-Loader (FSBL)
The FSBL is the first?(actually the second, BootROM first)?program to be run on the Application Processors when booting a Zynq UltraScale+. It’s responsible for configuring the hardware and initializing some components prior to invoking either the SSBL?(Second Stage Boot Loader)?or the Bare-Metal application you want. You can either use an auto-generated FSBL or write your own. To download and run the FSBL, call the following commands. Note that the FSBL must be run on the first Cortex-A53 core of the Application Processing Unit. So, we choose the target accordingly.
xsct% targets -set -nocase -filter {name =~ "*A53 #0*"}
xsct% targets
1 PS TAP
2 PMU
3 PL
5 PSU
6 RPU (Reset)
7 Cortex-R5 #0 (No Power)
8 Cortex-R5 #1 (No Power)
9 APU
10* Cortex-A53 #0 (Reset Catch, EL3(S)/A64)
11 Cortex-A53 #1 (Reset)
12 Cortex-A53 #2 (Reset)
13 Cortex-A53 #3 (Reset)
xsct% dow "zynqmp_fsbl.elf"
Downloading Program -- zynqmp_fsbl.elf
section, .text: 0xfffc0000 - 0xfffcf88b
section, .note.gnu.build-id: 0xfffcf88c - 0xfffcf8af
section, .init: 0xfffcf8c0 - 0xfffcf8f3
section, .fini: 0xfffcf900 - 0xfffcf933
section, .rodata: 0xfffcf940 - 0xfffcfe6f
section, .sys_cfg_data: 0xfffcfe80 - 0xfffd0657
section, .mmu_tbl0: 0xfffd1000 - 0xfffd100f
section, .mmu_tbl1: 0xfffd2000 - 0xfffd3fff
section, .mmu_tbl2: 0xfffd4000 - 0xfffd7fff
section, .data: 0xfffd8000 - 0xfffd932f
section, .sbss: 0xfffd9330 - 0xfffd933f
section, .bss: 0xfffd9340 - 0xfffdb87f
section, .heap: 0xfffdb880 - 0xfffdbc7f
section, .stack: 0xfffdbc80 - 0xfffddc7f
section, .dup_data: 0xfffddc80 - 0xfffdefaf
section, .handoff_params: 0xfffe9e00 - 0xfffe9e87
section, .bitstream_buffer: 0xffff0040 - 0xfffffc3f
100% 0MB 0.3MB/s 00:00
Setting PC to Program Start Address 0xfffc0000
Successfully downloaded zynqmp_fsbl.elf
xsct% con
Info: Cortex-A53 #0 (target 10) Running
xsct% after 4000; stop
Info: Cortex-A53 #0 (target 10) Stopped at 0xfffce2f0 (External Debug Request)
After starting the FSBL, we are giving it some amount of time to complete its operations. And then, we are manually stopping it at the handoff point. As I’m on a custom board where the boot pins are hard-configured to the QSPI boot mode, I modified the FSBL code to force it to JTAG boot mode. Here is my UART output:
Xilinx Zynq MP First Stage Boot Loader (Modified)
Release 2021.1 Jun 20 2022 - 10:55:15
This FSBL has been modified in order to boot from the JTAG only!
Forcing the Boot Mode as JTAG! Check the xfsbl_initialization.c file.
Second Stage Boot-Loader (U-Boot)
Similar to the regular booting procedures, the SSBL follows the FSBL. In our case, since I’m using the PetaLinux build system for image generation, we will use the commonly used U-Boot as the SSBL program. You can have different boot-loaders, but the process shall be similar.
The U-Boot requires a Device Tree Binary, so we need to place it in the memory prior to booting the U-Boot. The device must be downloaded to a pre-determined address in the memory. In PetaLinux projects, this configuration can be found under the name?CONFIG_SUBSYSTEM_UBOOT_DEVICETREE_OFFSET. You can find a simple, single-line Bash command in my previous article to find the required configuration faster. In my case, it is?0x100000. Notice that we use the?-data?option to download the binary since it’s not an executable file.
xsct% targets -set -nocase -filter {name =~ "*A53 #0*"}
xsct% dow -data "system.dtb" 0x100000
100% 0MB 0.2MB/s 00:00
Successfully downloaded system.dtb
The U-Boot is now ready to be downloaded into the memory.
xsct% targets -set -nocase -filter {name =~ "*A53 #0*"}
xsct% dow "u-boot.elf"
Downloading Program -- u-boot.elf
section, .text: 0x08000000 - 0x080001af
section, .efi_runtime: 0x080001b0 - 0x080011bf
section, .text_rest: 0x08001800 - 0x080c8c23
section, .rodata: 0x080c8c28 - 0x080fa111
section, .hash: 0x080fa118 - 0x080fa12f
section, .data: 0x080fa130 - 0x0810863f
section, .got: 0x08108640 - 0x08108647
section, .got.plt: 0x08108648 - 0x0810865f
section, .u_boot_list: 0x08108660 - 0x0810d3f7
section, .efi_runtime_rel: 0x0810d3f8 - 0x0810d5a7
section, .rela.dyn: 0x0810d5a8 - 0x08125877
section, .bss_start: 0x08125878 - 0x08125877
section, .bss: 0x08125880 - 0x0813e3c7
section, .bss_end: 0x0813e3c8 - 0x0813e3c7
100% 1MB 0.3MB/s 00:04
Setting PC to Program Start Address 0x08000000
Successfully downloaded u-boot.elf
Did you notice something? This step is actually a bit tricky and hard to figure out when an error occurs. Unlike the FSBL, we didn’t start the U-Boot immediately after downloading it to the memory. This is because of that things are a bit more complicated in Zynq UltraScale+ compared to the Zynq SoC due to the architectural differences. In the Zynq UltraScale+, the Application Processors are based on the ARM-v8 architecture while in Zynq they are based on ARMv7.
To conform to the ARVv8 topology, when the Linux kernel is booted, it runs at the ARM Exception Level 1/0. In that exception level, the Linux kernel has hardware-limited access to the system or security-critical registers. All interactions from Linux to that limited devices are routed through the ARM Trusted Firmware which runs at Exception Level 3. Without the ATF, your Linux image might not even boot at all.
ARM Trusted Firmware (ATF)
As mentioned in the previous section, the ARM Trusted Firmware is required to access the privileged regions. The ATF acts as a proxy to modify system-critical settings on behalf of the operating system. In order for the operating system,?i.e. Linux in our case, to gain access to these resources, it must be modified to support the Secure Monitor Calls exported by ATF to the OS itself. Those steps are beyond the context of this tutorial. You may want to take a look at?Chapter 16-System Protection Units of UG1085, Zynq UltraScale+ Technical Reference Manual. Let’s download the ATF to the memory.
xsct% targets -set -nocase -filter {name =~ "*A53 #0*"}
xsct% targets
1 PS TAP
2 PMU
3 PL
5 PSU
6 RPU
7 Cortex-R5 #0 (No Power)
8 Cortex-R5 #1 (No Power)
9 APU
10* Cortex-A53 #0 (External Debug Request, EL3(S)/A64)
11 Cortex-A53 #1 (Reset)
12 Cortex-A53 #2 (Reset)
13 Cortex-A53 #3 (Reset)
xsct% dow "bl31.elf"
Downloading Program -- bl31.elf
section, .text: 0xfffea000 - 0xffff1fff
section, .rodata: 0xffff2000 - 0xffff2fff
section, .data: 0xffff3000 - 0xffff679d
section, stacks: 0xffff67c0 - 0xffff78bf
section, .bss: 0xffff78c0 - 0xffff863f
section, xlat_table: 0xffff9000 - 0xffffdfff
section, coherent_ram: 0xffffe000 - 0xffffefff
100% 0MB 0.3MB/s 00:00
Setting PC to Program Start Address 0xfffea000
Successfully downloaded bl31.elf
We didn’t start the processors again because one thing is still missing, that is the Linux kernel itself.
Complete Linux Image
The last step of this tutorial is to download the Linux kernel image into the DDR memory and boot it via U-Boot. The address to be used to download the image has limitations. You must place the image into an empty section of the DDR. It mustn’t corrupt any other image residing in the memory. If you’ve created a PetaLinux project, you can find the suitable address in the configuration file with the tag?CONFIG_SUBSYSTEM_UBOOT_FIT_IMAGE_OFFSET.
Note that the Linux Kernel requires a device tree binary and a mountable root file system to complete its boot process. For a quick demonstration, I prepared an INITRAMFS image and packed the Kernel, RootFS, and Device Tree Binary into a single image file using PetaLinux tools. You can choose other methods arbitrarily.
xsct% targets -set -nocase -filter {name =~ "*A53 #0*"}
xsct% dow -data "image.ub" 0x10000000
100% 24MB 0.3MB/s 01:37
Successfully downloaded image.ub
Downloading the Linux kernel takes a while as it is our biggest image of the whole process. Let’s release the APU and see what happens on the device by inspecting the serial channel.
Firstly, the ARM Trusted Firmware runs. Its output is as below.
NOTICE: ATF running on XCZU9EG/silicon v4/RTL5.1 at 0xfffea000
NOTICE: BL31: v2.4(release):v1.1-7609-g851523ea2
NOTICE: BL31: Built : 08:27:07, Apr 28 2021
When the ATF finishes exporting the Secure Monitor Calls to the OS, U-Boot handoff occurs.
U-Boot 2021.01 (Jun 01 2021 - 11:54:06 +0000)
Board: Xilinx ZynqMP
DRAM: 4 GiB
PMUFW: v1.1
EL Level: EL2
Chip ID: zu9eg
NAND: 0 MiB
MMC: mmc@ff160000: 0, mmc@ff170000: 1
In: serial
Out: serial
Err: serial
Bootmode: QSPI_MODE
Reset reason: DEBUG
Net:
ZYNQ GEM: ff0b0000, mdio bus ff0b0000, phyaddr -1, interface rgmii-id
eth0: ethernet@ff0b0000
Hit any key to stop autoboot: 0
ZynqMP>
When the U-Boot prompt has been seen on the terminal, you can type?bootm 0x10000000?to boot the downloaded Linux kernel image. As the image is complete?i.e. it has kernel, rootfs, and device tree, it will boot up automatically.
## Loading kernel from FIT Image at 10000000 ...
Using 'conf-system-top.dtb' configuration
Trying 'kernel-1' kernel subimage
Description: Linux kernel
Created: 2021-06-04 15:57:16 UTC
Type: Kernel Image
Compression: gzip compressed
Data Start: 0x100000f8
Data Size: 9356113 Bytes = 8.9 MiB
Architecture: AArch64
OS: Linux
Load Address: 0x00200000
Entry Point: 0x00200000
Hash algo: sha256
Hash value: b4f7073afddc350f3c14f3e9ac1bf6ef8604c602951d13bbe58548bd0d415241
Verifying Hash Integrity ... sha256+ OK
## Loading ramdisk from FIT Image at 10000000 ...
Using 'conf-system-top.dtb' configuration
Trying 'ramdisk-1' ramdisk subimage
Description: petalinux-image-minimal
Created: 2021-06-04 15:57:16 UTC
Type: RAMDisk Image
Compression: uncompressed
Data Start: 0x108fa12c
Data Size: 16778258 Bytes = 16 MiB
Architecture: AArch64
OS: Linux
Load Address: unavailable
Entry Point: unavailable
Hash algo: sha256
Hash value: 6fcf87930415873cac0aa2232786dace5b65379e68e42b0a6c30f77b870807bc
Verifying Hash Integrity ... sha256+ OK
## Loading fdt from FIT Image at 10000000 ...
Using 'conf-system-top.dtb' configuration
Trying 'fdt-system-top.dtb' fdt subimage
Description: Flattened Device Tree blob
Created: 2021-06-04 15:57:16 UTC
Type: Flat Device Tree
Compression: uncompressed
Data Start: 0x108ec55c
Data Size: 56061 Bytes = 54.7 KiB
Architecture: AArch64
Hash algo: sha256
Hash value: 9bf95db6c5106f1f1945af67bbb43f2269539e514acadf88c4615f4ae7d6b595
Verifying Hash Integrity ... sha256+ OK
Booting using the fdt blob at 0x108ec55c
Uncompressing Kernel Image
Loading Ramdisk to 7cd11000, end 7dd11412 ... OK
Loading Device Tree to 000000007cd00000, end 000000007cd10afc ... OK
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd034]
[ 0.000000] Linux version 5.10.0-xilinx-v2021.1 (oe-user@oe-host) (aarch64-xilinx-linux-gcc (GCC) 10.2.0, GNU ld (GNU Binutils) 2.35.1) #1 SMP Fri Jun 4 15:57
:16 UTC 2021
[ 0.000000] Machine model: xlnx,zynqmp
...............
<Skipped for readability>
...............
PetaLinux 2021.1 ZynqUS_Linux ttyPS0
root@ZynqUS_Linux:~ > uname -r
5.10.0-xilinx-v2021.1
Here you go with a fully booted Linux image on your precious hardware :) If any question pops up, leave a comment or send me a message.
As always, this article is open to suggestions and criticism. Feel free to ask, comment, or contribute.