Linux on Zynq

Posted on 30 Apr 2019 By Noah Hütter


In this post I will show you how to compile and install a vanilla Linux kernel and root file system on Zynq SoC.

Table of Contents

Disclaimer: This code is largely copied from, licensed under MIT license.


DO NOT WORK ON A SHARED FOLDER INSIDE VIRTUALBOX It will get messy, because the Linux kernel build uses a case sensitive file system, which Mac does not provide.

Clone my zynq-sandbox repository from github if you have not done so already.

git clone

Fix gmake:

sudo ln -s /usr/bin/make /usr/bin/gmake

Install some tools:

sudo apt install curl u-boot-tools libncurses-dev

Change to the Linux directory.

cd sw/linux

Step-by-step build

For educational build purposes, the Makefile was extended to build each component seperately. This guide will go through all components and briefly explain what they are needed for.

Create FSBL



This generates the source code and binary for the first level bootloader that is executed after power on. After project creation, the fsbl is compiled and the binary written.

rm -r build/*.fsbl
make fsbl

Devicetree source



The devicetree files from Xilinx are downloaded and a device tree project created from the hardware definition files. From these two sources, a set of dts (device tree sources) files are generated. Finally the makefile applies a patch to some output files. The patch file is generates by this command:

diff -rupN pcw.dtsi > devicetree.patch
rm -r build/*.tree
make dts

Linux Kernel



Now it is time to pull a vanilla Linux kernel, uncompress the sources, apply some patches, copy some config and finally build the kernel. Issue the following command and go for a walk:

rm -r build/linux*
make uimage

or if the sources are already downloaded and you don’t want to clean before build:

make -C build/linux-4.14 ARCH=arm xilinx_zynq_defconfig
make -C build/linux-4.14 ARCH=arm CFLAGS="-O2 -march=armv7-a \
 -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon -mfloat-abi=hard" \
 -j 4 \
 CROSS_COMPILE=arm-linux-gnueabihf- UIMAGE_LOADADDR=0x8000 uImage modules

U Boot



The bootloader is build from source pulled from Xilinxed repositoriers. Before build, some config files are copied and patches applied.

rm -r build/u-boot*
make uboot

Devicetree blob



Using the device tree sources generated previously, the devicetree compiler is used to generate the devicetree blob.

rm -r build/devicetree*
make dtb

Boot image



Now the three binaries can be tied to a single binary image.

rm -r build/boot.bin
make bootbin




For u-boot to know what linux version to load we have to generate a uEnv.txt file. This is done by running the following command:

rm -r build/uEnv.txt
make uenv

Copy contents to SD-Card

Create two partitions on a SD-Card:

  1. fat32 1.00GiB label:BOOT flags:boot
  2. ext4 label:root

Copy the following files on the boot partition:

First Boot!

Connect a serial console and power up the board. Hit a key to interrupt u-boot automatic boot process. To check if the uImage and devicetree are correct issue the following commands:

fatload mmc 0 0x2080000 uImage
fatload mmc 0 0x2000000 devicetree.dtb
iminfo 0x2000000
iminfo 0x2080000
setenv bootargs console=ttyPS0,115200 root=/dev/mmcblk0p2 ro rootfstype=ext4 earlyprintk rootwait
bootm 0x2080000 - 0x2000000

At this point the kernel should start but fail with a kernel panic because no init was found. For that we next generate the rootfs.


First we try the smallest rootf available: Busybox. To download, untar and build, run:

make busybox

To modify busybox and build manually:

cd build/busybox-*
make -j4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
make -j4 ARCH=arm INSTALL_PATH=build/ install

Now copy the installed busybox and some install scripts to the root partition of the SD-card.

./scripts/ /link/to/sdcard/root/

We should now be able bring up the network!

ifconfig eth0 up
udhcpc -i eth0 -p /var/run/
ifconfig eth0 netmask
route add default gw