We are on Ubuntu 24.04.4 with Vitis/Vivado 2025.2 installed on it.
Create a workspace and clone the necessary repositories:mkdir yocto-zynq
cd yocto-zynq
git clone -b scarthgap https://git.yoctoproject.org/poky
git clone -b scarthgap https://github.com/openembedded/meta-openembedded
git clone -b scarthgap https://git.yoctoproject.org/meta-arm
git clone -b rel-v2025.2 https://github.com/Xilinx/meta-xilinx
source poky/oe-init-build-env buildCreatecustomlayerfortheboard:
bitbake-layers create-layer ../meta-custom-zynq
bitbake-layers add-layer ../meta-custom-zynqNow your bblayers.conf in /home/mammad/yocto-zynq/build/conf must be like bellow:
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf# changes incompatiblyPOKY_BBLAYERS_CONF_VERSION = "2"BBPATH = "${TOPDIR}"BBFILES ?= ""BBLAYERS ?= " \/home/mammad/yocto-zynq/poky/meta \/home/mammad/yocto-zynq/poky/meta-poky \/home/mammad/yocto-zynq/poky/meta-yocto-bsp \"
Change the bblayers.conf to :
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf# changes incompatiblyPOKY_BBLAYERS_CONF_VERSION = "2"BBPATH = "${TOPDIR}"BBFILES ?= ""BBLAYERS ?= " \/home/mammad/yocto-zynq/poky/meta \/home/mammad/yocto-zynq/poky/meta-poky \/home/mammad/yocto-zynq/poky/meta-yocto-bsp \/home/mammad/yocto-zynq/meta-openembedded/meta-oe \/home/mammad/yocto-zynq/meta-openembedded/meta-python \/home/mammad/yocto-zynq/meta-openembedded/meta-networking \/home/mammad/yocto-zynq/meta-arm/meta-arm-toolchain \/home/mammad/yocto-zynq/meta-arm/meta-arm \/home/mammad/yocto-zynq/meta-xilinx/meta-xilinx-core \/home/mammad/yocto-zynq/meta-xilinx/meta-xilinx-bsp \/home/mammad/yocto-zynq/meta-xilinx/meta-xilinx-standalone \/home/mammad/yocto-zynq/meta-custom-zynq \"
The default boot.scr generated by meta-xilinx uses the bootm command, which expects a FIT image (image.ub) or a uImage. Because we configured Yocto to build a zImage, U-Boot loads it but doesn’t know how to execute it (a zImage requires the bootz command).
mkdir -p ../meta-custom-zynq/recipes-bsp/custom-boot-script/filesIn meta-custom-zynq/recipes-bsp/custom-boot-script/files create boot.cmd as follow:
# Set the boot arguments for serial console and rootfssetenv bootargs 'console=ttyPS0, 115200 root=/dev/mmcblk0p2 rw rootwait'fatload mmc 0 0x2080000 zImagefatload mmc 0 0x2000000 zynq-zed.dtb# Boot using bootz instead of bootmbootz 0x2080000 - 0x2000000
Create Yocto recipe in /recipes-bsp/custom-boot-script and named it:custom-boot-script.bb and then add the the following:
SUMMARY = "Custom U-Boot boot script for ZedBoard (zImage/bootz)"LICENSE = "MIT"LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"DEPENDS = "u-boot-mkimage-native"SRC_URI = "file://boot.cmd"S = "${WORKDIR}"inherit deploydo_compile() {# Compile the boot.cmd text file into a U-Boot readable boot.scrmkimage -A arm -O linux -T script -C none -a 0 -e 0 -n "ZedBoard Boot Script" -d ${S}/boot.cmd ${S}/boot.scr}do_deploy() {install -d ${DEPLOYDIR}install -m 0644 ${S}/boot.scr ${DEPLOYDIR}/boot.scr}addtask do_deploy after do_compile before do_buildCreate the custom machine configuration file:
mkdir -p ../meta-custom-zynq/conf/machineIn meta-custom-zynq/conf/machine create custom-zynq.conf as follow:
# ------------------------------------------------------------------# U-Boot Configuration# ------------------------------------------------------------------UBOOT_MACHINE = "xilinx_zynq_virt_defconfig"UBOOT_BOOT_SCRIPT = "u-boot-xlnx-scr"EXTRA_IMAGEDEPENDS += "u-boot-xlnx-scr"# ------------------------------------------------------------------# Kernel Configuration# ------------------------------------------------------------------# Set the primary kernel image typeKERNEL_IMAGETYPE = "zImage"# Remove uImage in case meta-xilinx or soc-zynq.inc tries to append it,# but do NOT manually append "zImage" here to avoid duplicates.KERNEL_IMAGETYPES:remove = "uImage"# ------------------------------------------------------------------# Disable BOOT.BIN Generation (Option 1)# ------------------------------------------------------------------# Prevent Yocto from trying to use xilinx-bootbin to package BOOT.BINEXTRA_IMAGEDEPENDS:remove = "virtual/boot-bin"MACHINE_ESSENTIAL_EXTRA_RDEPENDS:remove = "virtual/boot-bin"# ------------------------------------------------------------------# Image Output Configuration# ------------------------------------------------------------------# Define root filesystem typesIMAGE_FSTYPES = "ext4 tar.gz"# Define files to be copied to the boot partition of the SD card# Notice that BOOT.BIN is removed from this list so Wic does not failIMAGE_BOOT_FILES = "boot.scr zImage zynq-zed.dtb"# Remove default meta-xilinx boot script to avoid conflictsEXTRA_IMAGEDEPENDS:remove = "u-boot-xlnx-scr u-boot-zynq-scr"require conf/machine/include/soc-zynq.incWKS_FILE = "sdimage-bootpart.wks"# Force U-Boot to be built alongside the rootfsEXTRA_IMAGEDEPENDS += "u-boot-xlnx"# Force the Kernel and Device Tree to be builtMACHINE_ESSENTIAL_EXTRA_RDEPENDS += "kernel-image"EXTRA_IMAGEDEPENDS += "custom-boot-script"# Ensure the correct path for the ARM device tree in modern kernelsKERNEL_DEVICETREE = "xilinx/zynq-zed.dtb"PREFERRED_PROVIDER_virtual/kernel = "linux-xlnx"KERNEL_EXTRA_ARGS += "LOADADDR=0x00008000"SERIAL_CONSOLES = "115200;ttyPS0"
Edit local.conf in /home/mammad/yocto-zynq/build/conf Find the line that says MACHINE ??= "qemux86-64" and change it to:
MACHINE ?= "custom-zynq"
Scroll to the bottom of the file and add:
ACCEPT_EULA = "1"
Ubuntu 24.04. As a security enhancement, it disables unprivileged user namespaces by default, which BitBake relies on for sandboxing builds so re-enable this kernel feature. Before starting the build.
sudo sysctl -w kernel.unprivileged_userns_clone=1
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
bitbake core-image-minimalA successful build Yocto build generate following files in /yocto-zynq/buil/tmp/deploy/images/custom-zynq :
boot.scr
core-image-minimal-custom-zynq.rootfs-20260623101435.ext4
core-image-minimal-custom-zynq.rootfs-20260623101435.manifest
core-image-minimal-custom-zynq.rootfs-20260623101435.spdx.tar.zst
core-image-minimal-custom-zynq.rootfs-20260623101435.tar.gz
core-image-minimal-custom-zynq.rootfs-20260623101435.testdata.json
core-image-minimal-custom-zynq.rootfs.ext4
core-image-minimal-custom-zynq.rootfs.manifest
core-image-minimal-custom-zynq.rootfs.spdx.tar.zst
core-image-minimal-custom-zynq.rootfs.tar.gz
core-image-minimal-custom-zynq.rootfs.testdata.json
modules--6.12.40+git+v2025.20+31626ef92f-r0-custom-zynq-20260623101435.tgz
modules-custom-zynq.tgz
u-boot.bin
u-boot-custom-zynq-2025.01-xilinx-v2025.1+git-r0.bin
u-boot-custom-zynq-2025.01-xilinx-v2025.1+git-r0.dtb
u-boot-custom-zynq-2025.01-xilinx-v2025.1+git-r0.elf
u-boot-custom-zynq.bin
u-boot-custom-zynq.dtb
u-boot-custom-zynq.elf
u-boot.dtb
u-boot.elf
u-boot-nodtb.bin
u-boot-nodtb-custom-zynq-2025.01-xilinx-v2025.1+git-r0.bin
u-boot-nodtb-custom-zynq.bin
u-boot-nodtb.elf
u-boot-xlnx-initial-env
u-boot-xlnx-initial-env-custom-zynq
u-boot-xlnx-initial-env-custom-zynq-2025.01-xilinx-v2025.1+git-r0
zImage
zImage--6.12.40+git+v2025.20+31626ef92f-r0-custom-zynq-20260623101435.bin
zImage-custom-zynq.bin
zynq-zed--6.12.40+git+v2025.20+31626ef92f-r0-custom-zynq-20260623101435.dtb
zynq-zed-custom-zynq.dtb
zynq-zed.dtbNot time is ripe for us to generate create a Boot Image (BOOT.BIN) using Vitis.
source /Xilinx/2025.2/Vitis/settings64.sh
mkdir /yocto-zynq/vitis
vitisVitis -> Create Boot Image -> Zynq
Output BIF File Path /home/mammad/yoctoZynq/vitis/boot.bif+ File Path /home/mammad/yoctoZynq/vitis/fsbl.elf Type: bootloader -> OK+ File /home/mammad/yoctoZynq/vitis/uC_dsgn_wrapper.bit Type: datafile -> OK+ /home/mammad/yoctoZynq/build/tmp/deploy/images/zynqpatvaz/u-boot-.elf Type datafile -> OK
Now click Create Image and you will have BOOT.bin in /yocto-zynq/vitis.
Note: fsbl.elf and uC_dsgn_wrapper.bit are generated by Vitis and Vivado. If you don't know how to make them please see : https://www.hackster.io/daneshgar/vitis-2023-2-blink-led-b85da3Finally we have to format SD card with two partitions:
- Partition 1 (FAT32, Boot): Contains
BOOT.BIN,boot.scr,zImage, andzynq-zed.dtb. - Partition 2 (EXT4, Root): Contains the extracted contents of
core-image-minimal-custom-zynq.rootfs.tar.gz.
sudo mkfs.vfat -F 32 -n BOOT /dev/sdc1
sudo mkfs.ext4 -L ROOTFS /dev/sdc2
mkdir -p /mnt/BOOT
mkdir -p /mnt/ROOTFS
sudo mount /dev/sdc1 /mnt/BOOT
sudo mount /dev/sdc2 /mnt/ROOTFS
sudo cp vitis/BOOT.bin /mnt/BOOT/
sudo cp build/tmp/deploy/images/custom-zynq/boot.scr /mnt/BOOT
sudo cp build/tmp/deploy/images/custom-zynq/zImage /mnt/BOOT
sudo cp build/tmp/deploy/images/custom-zynq/zynq-zed.dtb /mnt/BOOT
sudo sync
sudo tar -xzf build/tmp/deploy/images/custom-zynq/core-image-minimal-custom-zynq.rootfs-20260623101435.tar.gz -C /mnt/ROOTFS
sudo sync
sudo umount /mnt/BOOT
sudo umount /mnt/ROOTFSBoottheboard:
- Insert the SD card into your board.
- Open a serial terminal on your computer such as Putty connected to the board’s COM port (Baud rate 115200).
- You should see
custom-zynq login: - Type username as root and Enter and You will see command prompt like
root@custom-zynq:~#
To test you can make an LED on the board on and off.
Firs run this command to find the base number assigned to Zyqn PS GPIO:
ls -l /sys/class/gpio/
--w------- 1 root root 4096 Jan 1 1970 export
lrwxrwxrwx 1 root root 0 Jan 1 1970 gpiochip512 -> ../../devices/soc0/axi/e000a000.gpio/gpio/gpiochip512
--w------- 1 root root 4096 Jan 1 1970 unexportAs we see the base PS GPIO number is 517 and for ZedBoard LED is MIO7. To turn the LED on run the following command:
echo 519 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio519/direction
echo 1 > /sys/class/gpio/gpio519/value






Comments