A minimal GNU/Linux distribution for the ZedBoard
This page explains how to create a minimal GNU/Linux distribution for the ZedBoard (Linux kernel, U-Boot, device tree, root file system).
Create a directory for all downloads and builds
Example with /opt/build
:
export BUILDDIR=/opt/build
rm -rf $BUILDDIR
mkdir -p $BUILDDIR
Get all git repositories
cd $BUILDDIR
git clone https://github.com/Xilinx/device-tree-xlnx.git
git clone http://github.com/Xilinx/u-boot-xlnx.git
git clone https://github.com/Xilinx/linux-xlnx.git
git clone http://git.buildroot.net/git/buildroot.git
Set environment variables
export CROSS_COMPILE=arm-xilinx-linux-gnueabi-
export PATH=$PATH:path-to-Xilinx-tools/SDK/<version>/gnu/arm/lin/bin
${CROSS_COMPILE}gcc --version
Note the result of the last command, we will need it later.
Compile the Linux kernel
cd $BUILDDIR/linux-xlnx
make mrproper
make ARCH=arm O=build xilinx_zynq_defconfig
make ARCH=arm O=build
export PATH=$PATH:$BUILDDIR/linux-xlnx/build/scripts/dtc
Compile U-Boot
cd $BUILDDIR/u-boot-xlnx
make mrproper
make O=build zynq_zed_config
make O=build
cp build/u-boot $BUILDDIR/u-boot.elf
export PATH=$PATH:$BUILDDIR/u-boot-xlnx/build/tools
Generate the U-Boot image of the Linux kernel
cd $BUILDDIR
mkimage -A arm -O linux -C none -T kernel -a 0x8000 -e 0x8000 -d linux-xlnx/build/arch/arm/boot/zImage uImage
Adapt the load address (-a 0x8000
) and entry point (-e 0x8000
) to your memory configuration.
Configure and build a root file system
Use buildroot
to configure your root file system, starting from the default. We will first configure busybox
:
cd $BUILDDIR/buildroot
make O=$BUILDDIR/initramfs zedboard_defconfig
make O=$BUILDDIR/initramfs busybox-menuconfig
In the busybox
configuration menu you may want to change:
Busybox Settings -> General Configuration -> Enable options for full-blown desktop systems -> no
Busybox Settings -> General Configuration -> Enable locale support (system needs locale for this to work) -> yes
Busybox Settings -> General Configuration -> Support Unicode -> yes
Busybox Settings -> General Configuration -> Use libc routines for Unicode (else uses internal ones) -> yes
Busybox Settings -> General Configuration -> Runtime SUID/SGID configuration via /etc/busybox.conf -> yes
Quit with saving and start configuring buildroot
:
make O=$BUILDDIR/initramfs menuconfig
In the buildroot
configuration menus you may want to change a few things:
Build options -> Location to save buildroot config -> <BUILDDIR>/buildroot.config
Build options -> Enable compiler cache -> yes (faster build)
Build options -> gcc optimization level -> 3 (optimize for speed)
Toolchain -> Toolchain type -> External toolchain
Toolchain -> Toolchain -> Custom toolchain
Toolchain -> Toolchain path -> <path-to-Xilinx-tools>/SDK/<version>/gnu/arm/lin
Toolchain -> Toolchain prefix -> arm-xilinx-linux-gnueabi (no "-" at the end)
Toolchain -> External toolchain gcc version -> <the-toolchain-version-you-noted>
Toolchain -> External toolchain C library -> glibc/eglibc
Toolchain -> Toolchain has RPC support? -> yes
Toolchain -> Toolchain has C++ support? -> yes
Toolchain -> Purge unwanted locales -> yes
Toolchain -> Locales to keep -> C en_US
Toolchain -> Generate locale data -> en_US.UTF-8
System configuration -> System hostname -> secbus
System configuration -> System banner -> Welcome to SecBus (c) Telecom ParisTech. Root password: secbus
System configuration -> Root password -> secbus
Kernel -> Linux Kernel -> no
Target packages -> BusyBox configuration file to use? -> <BUILDDIR>/busybox.config
Bootloaders -> U-Boot -> no
Note: do not use the $BUILDDIR
environment variable. Replace by the absolute path (/opt/build
in our example) in the examples above. Quit with saving. We are almost done. Save the buildroot
and busybox
configurations and build the root file system:
make O=$BUILDDIR/initramfs savedefconfig
make O=$BUILDDIR/initramfs busybox-update-config
make O=$BUILDDIR/initramfs
If you get an error:
Incorrect selection of kernel headers: expected x.x.x, got y.y.y
note the y.y.y
run again the buildroot
configuration:
make O=$BUILDDIR/initramfs menuconfig
change:
Toolchain -> External toolchain kernel headers series -> the-kernel-version-you-noted
quit with saving, save again the configuration and build:
make O=$BUILDDIR/initramfs savedefconfig
make O=$BUILDDIR/initramfs
Generate the U-Boot image of the root file system image
cd $BUILDDIR
mkimage -A arm -T ramdisk -C gzip -d initramfs/images/rootfs.cpio.gz rootfs.cpio.uboot
Generate the Device Tree Sources (DTS) for your system
We assume that you used Vivado to create a Zynq design and that you synthesized it. You should find its Hardware Description File (HDF) in the Vivado output results. Its name is something like xxx.sysdef
. We also assume that you have the Xilinx tools in your PATH
. Download the provided dts.hsi.tcl TCL script and save it in $BUILDDIR
. Use it to generate the DTS using the hsi
utility from the Xilinx SDK:
mkdir $BUILDDIR/hw
cd $BUILDDIR/hw
hsi -mode batch -quiet -notrace -source ../dts.hsi.tcl -tclargs <some-path>/xxx.sysdef $BUILDDIR/device-tree-xlnx ../dts
The Device Tree Sources are in $BUILDDIR/dts
.
Edit the Device Tree Sources (DTS)
Edit the DTS files if needed. Examples of things you may want to change:
In $BUILDDIR/dts/system.dts
(top level) you may want to change the definition of the physical memory base address and size:
memory {
device_type = "memory";
reg = <0x0 0x20000000>;
};
For instance, if you want to use the [0x4800_0000...0x6000_0000[
range instead, replace the above lines by:
memory {
device_type = "memory";
linux,usable-memory = <0x48000000 0x18000000>;
};
In the same $BUILDDIR/dts/system.dts
you may want to enable some of the 4 PS-to-PL clocks. To enable clocks FPGA1 and FPGA3, for instance, replace:
&clkc {
fclk-enable = <some-value>;
ps-clk-frequency = <33333333>;
};
by:
&clkc {
fclk-enable = <0xa>;
ps-clk-frequency = <33333333>;
};
If you decided to disable the CPU caches, in the$BUILDDIR/dts/zynq-7000.dtsi
included DTS file, you may want to comment out the L2 cache controller:
/*
L2: cache-controller@f8f02000 {
compatible = "arm,pl310-cache";
...
};
*/
Compile the Device Tree Blob (DTB)
Once your DTS files are adapted to your needs, compile the device tree blob:
cd $BUILDDIR
dtc -I dts -O dtb -o devicetree.dtb dts/system.dts
Generate the First Stage Boot Loader (FSBL) for your system
Download the provided fsbl.hsi.tcl TCL script and save it in $BUILDDIR
. Use it to generate the FSBL using the hsi
utility from the Xilinx SDK:
cd $BUILDDIR/hw
hsi -mode batch -quiet -notrace -source ../fsbl.hsi.tcl -tclargs <some-path>/xxx.sysdef ../fsbl
The FSBL ELF is $BUILDDIR/fsbl/executable.elf
.
Generate the boot image
Pack the FSBL ELF, the bitstream (if any) for the programmable logic and the U-Boot ELF. First Download the provided boot.bif boot image specification file and save it in $BUILDDIR
. If you do not have a bitstream for the programmable logic edit boot.bif
and comment out the line corresponding to the bitstream:
// bitstream.bit
Else, copy the bitstream (which should be in the same directory where you found the xxx.sysdef
Hardware Description File) in $BUILDDIR
:
cd $BUILDDIR
cp <some-path>/xxx.bit bitstream.bit
Generate the boot image:
cd $BUILDDIR
bootgen -w -image boot.bif -o boot.bin
Copy on a SD card and boot
Copy all the elements on a SD card:
cp boot.bin devicetree.dtb rootfs.cpio.uboot uImage /media/SDCard
Unmount and eject the SD card, plug it to the ZedBoard, connect the USB UART cable, launch a serial console (minicom, cu, putty, screen...) and finally power up the ZedBoard. The first time you boot, the U-Boot environment variables are probably not what they should be. Stop the U-Boot count-down, restore the default environment variables (print and save the previous configuration if needed):
zynq-uboot> env default -a -f
Modify the following U-Boot environment variable to reflect the name of our root file system:
zynq-uboot> setenv ramdisk_image rootfs.cpio.uboot
This should be sufficient to boot our GNU/Linux distribution. To avoid typing this each time, save the variable definition on the on-board flash:
zynq-uboot> saveenv