Running a Debian distribution on the ZedBoard using tftp and NFS
This page explains how to run a regular Debian distribution on the ZedBord with:
- A minimal boot image on the SD card, containing only the First Stage Boot Loader (FSBL) and U-Boot
- Loading the kernel image and the device tree blob from a remote tftp server
- Mounting the root file system from a remote NFS server
This is not specific to SecBus and can be used for any development project on the ZedBoard.
This setup is extremely convenient as it almost completely avoids SD card manipulations. The Linux kernel and its device tree blob can be re-built any time, copied on the tftp server and re-loaded by the ZedBoard through its Ethernet link at the price of a single reboot. The Debian root file system can also be updated from the NFS server (thanks to Qemu and chroot) using the regular Debian tools. The changes are immediately reflected on the ZedBoard and, in most cases, without rebooting.
In the following we assume that:
-
<host>
is the hostname of the workstation we will use and to which the UART USB cable of the ZedBoard is attached - The Xilinx tool chain is installed on
<host>
and it is on the PATH -
<bistream>.bit
is the bistream file used to configure the Programmable Logic (PL), if any -
<server>
is the hostname of the remote tftp and NFS server (can be the same as<host>
) -
<server_ip_address>
is the IP address of<server>
-
<zedboard_mac_address>
is the Ethernet MAC address of the ZedBoard -
<zedboard_ip_address>
is the IP address of the ZedBoard -
<gateway_ip_address>
is the IP address of the gateway through which the ZedBoard connects to<server>
(if it connects directly<gateway_ip_address>
=<server_ip_address>
) -
<tftproot>
is the absolute path on<server>
of the root directory of the tftp server -
<tftproot>/<tftpdir>
is the absolute path on<server>
of the directory containing the tftp-served files -
<nfsdir>
is the absolute path on<server>
of the directory containing the NFS-served file systems - We are root on
<server>
which runs a Debian variant, has access to Internet and has Qemu installed
Note: there are several ways to configure the Programmable Logic (PL). In the following we present three of them:
- Copy the bitstream somewhere in the NFS share on
<server>
and send it to the/dev/xdevcfg
device after the Linux kernel booted. This method is very convenient because it allows to reconfigure the PL at run time without rebooting. On the other hand, it cannot be used when the PL must be configured before booting the Linux kernel. - Let U-Boot download the bitstream from the tftp server and configure the PL. This method is less flexible because the system must be rebooted to change the PL configuration. However, it can be used when the PL must be configured prior booting the Linux kernel.
- Include the bitstream in the boot image on the SD card and let the First Stage Boot Loader (FSBL) do the job. This method is the less flexible of all because changing the PL configuration not only requires to reboot but also to regenerate the boot image and store it on the SD card. But it is the only one that can be used if U-Boot needs the PL to be already configured when it boots.
Please adapt the following instructions to your own settings.
<server>
, the NFS server, prepare the root file system
On Create an empty image for the Debian root file system and mount it
server> cd <nfsdir>
server> dd if=/dev/zero of=debianrootfs4zynq.img bs=1024 count=1MB
server> sudo mkfs.ext3 -F debianrootfs4zynq.img
server> mkdir debianrootfs4zynq
server> sudo mount -o loop debianrootfs4zynq.img debianrootfs4zynq
Install a minimal Debian distribution
server> sudo debootstrap --verbose --arch armhf --variant=minbase --foreign wheezy debianrootfs4zynq http://ftp.fr.debian.org/debian
server> sudo modprobe binfmt_misc
server> sudo cp /usr/bin/qemu-arm-static debianrootfs4zynq/usr/bin
server> sudo mkdir debianrootfs4zynq/dev/pts
server> sudo mount -t devpts devpts debianrootfs4zynq/dev/pts
server> sudo mount -t proc proc debianrootfs4zynq/proc
Chroot into the file system and continue the Debian install
server> sudo chroot debianrootfs4zynq /bin/bash
server-chrooted> /debootstrap/debootstrap --second-stage
server-chrooted> cat <<! >> /etc/apt/sources.list
deb http://security.debian.org/ wheezy/updates main
deb-src http://security.debian.org/ wheezy/updates main
deb http://ftp.fr.debian.org/debian/ wheezy main
deb-src http://ftp.fr.debian.org/debian/ wheezy main
!
server-chrooted> apt-get update
server-chrooted> apt-get upgrade
server-chrooted> export LANG=C
server-chrooted> apt-get install apt-utils dialog locales
server-chrooted> dpkg-reconfigure locales
server-chrooted> export LANG=en_US.UTF-8
server-chrooted> apt-get install udev netbase ifupdown iproute openssh-server iputils-ping wget net-tools ntpdate nano less module-init-tools
Configure file systems, hostname, root password and serial console
server-chrooted> cat <<! >> /etc/fstab
/dev/nfs / nfs defaults 0 1
tmpfs /tmp tmpfs defaults 0 0
!
server-chrooted> echo "MyZedBoard" > /etc/hostname
server-chrooted> passwd
...
Comment out the tty1 to tty6 specifications in /etc/inittab
and add the serial console (use nano to edit the file):
#1:2345:respawn:/sbin/getty 38400 tty1
#2:23:respawn:/sbin/getty 38400 tty2
#3:23:respawn:/sbin/getty 38400 tty3
#4:23:respawn:/sbin/getty 38400 tty4
#5:23:respawn:/sbin/getty 38400 tty5
#6:23:respawn:/sbin/getty 38400 tty6
T0:23:respawn:/sbin/getty -L ttyPS0 115200 vt100
Allow the root user to log in through the serial console:
server-chrooted> cat <<! >> /etc/securetty
ttyPS0
!
Escape from the chroot and export the NFS share
server-chrooted> exit
server> sudo mkdir <nfsdir>/debianrootfs4zynq/opt/bitstreams
server> sudo cat <<! >> /etc/exports
<nfsdir>/debianrootfs4zynq <zedboard_ip_address>/32(rw,sync,no_root_squash,no_subtree_check,insecure)
!
server> sudo exportfs -v <zedboard_ip_address>/32:<nfsdir>/debianrootfs4zynq
<host>
build U-Boot, the Linux kernel, the device tree blob and generate the boot image
On Clone the U-Boot and Linux git repositories by Xilinx
host> export ROOTDIR=<some-path>
host> mkdir -p $ROOTDIR
host> cd $ROOTDIR
host> git clone http://github.com/Xilinx/u-boot-xlnx.git
host> git clone https://github.com/Xilinx/linux-xlnx.git
Configure and build U-Boot
host> cd $ROOTDIR/u-boot-xlnx
host> export CROSS_COMPILE=arm-xilinx-linux-gnueabi-
host> make O=build zynq_zed_config
host> make O=build
host> cp build/u-boot build/u-boot.elf
host> export PATH=$PATH:$ROOTDIR/u-boot-xlnx/build/tools
Configure and build the Linux kernel, compile the device tree blob, copy the image and the blob on the tftp server
Note: when configuring the Linux kernel do not forget to enable the NFS support if it is not already.
host> cd $ROOTDIR/linux-xlnx
host> make ARCH=arm xilinx_zynq_defconfig
host> make ARCH=arm menuconfig
host> make ARCH=arm UIMAGE_LOADADDR=0x8000 uImage
host> ./scripts/dtc/dtc -I dts -O dtb -o $ROOTDIR/devicetree.dtb arch/arm/boot/dts/zynq-zed.dts
host> scp arch/arm/boot/uImage $ROOTDIR/devicetree.dtb <server>:<tftproot>/<tftpdir>
host> ssh <server> chmod a+r <tftproot>/<tftpdir>/uImage <tftproot>/<tftpdir>/devicetree.dtb
<server>
Compile the kernel modules and install them in the NFS share on host> cd $ROOTDIR/linux-xlnx
host> make ARCH=arm INSTALL_MOD_PATH=$ROOTDIR/debianrootfs4zynq modules modules_install
host> cd $ROOTDIR
host> tar -pzcvf - debianrootfs4zynq | ssh root@<server> 'cd <nfsdir>; tar -pzxvf -'
To configure the PL from a running Linux kernel, copy the bistream file on the NFS server:
host> scp <bitstream>.bit <server>:<nfsdir>/debianrootfs4zynq/opt/bitstreams
To configure the PL with U-Boot copy the bistream file on the tftp server:
host> scp <bitstream>.bit <server>:<tftproot>/<tftpdir>
host> ssh <server> chmod a+r <tftproot>/<tftpdir>/<bitstream>.bit
Create and build the Board Support Package (BSP) and the FSBL, generate the boot image
Note: we use the zed_hw_platform
template provided with the Xilinx SDK.
Note: delete the <bitstream>.bit
line if the PL is not configured by the FSBL.
host> cd $ROOTDIR
host> cat <<! > fsbl.tcl
set_workspace ./fsbl
create_project -type app -name fsbl -app "Zynq FSBL" -proc ps7_cortexa9_0 -hwproject zed_hw_platform
build -name fsbl
quit
!
host> xsdk -batch -source fsbl.tcl
host> cat <<! > boot.bif
the_ROM_image:
{
[bootloader]./fsbl/fsbl/Debug/fsbl.elf
<bitstream>.bit
./u-boot-xlnx/build/u-boot.elf
}
!
host> bootgen -image ./boot.bif -o ./boot.bin -w on
host> cp boot.bin /media/SDCARD
host> sync
On the ZedBoard, set U-Boot environment variables and boot the Linux kernel
Unmount the SD card, insert it in the SD card slot of the ZedBoard, configure the jumpers to boot from the SD Card, connect the Ethernet cable, the USB UART cable, the power cable and power on. Launch minicom
(or equivalent) on <host>
:
host> minicom -D /dev/ttyACM0
and stop U-Boot by pressing a key before the end of the countdown.
Set the following U-Boot environment variables (please pay attention to the simple and double quotes):
zynq-uboot> setenv ethaddr <zedboard_mac_address>
zynq-uboot> setenv ipaddr <zedboard_ip_address>
zynq-uboot> setenv serverip <server_ip_address>
zynq-uboot> setenv nfsdir <nfsrootdir>/debianrootfs4zynq
zynq-uboot> setenv tftpdir <tftpdir>
zynq-uboot> setenv netboot 'tftpboot ${kernel_load_address} ${tftpdir}/${kernel_image} && tftpboot ${devicetree_load_address} ${tftpdir}/${devicetree_image} && bootm ${kernel_load_address} - ${devicetree_load_address}'
zynq-uboot> setenv bootargs "console=ttyPS0,115200 root=/dev/nfs rw nfsroot=${serverip}:${nfsdir} ip=${ipaddr}:${serverip}:${serverip}:255.255.255.0:zynq:eth0:off nfsrootdebug earlyprintk"
If the PL must be configured by U-Boot add the following netboot
variable redefinition:
setenv netboot "tftpboot 0x4000000 ${tftpdir}/<bitstream>.bit && fpga loadb 0 0x4000000 4045671 && ${netboot}"
Save the environment variables in the SPI flash memory of the ZedBoard:
zynq-uboot> saveenv
zynq-uboot> run netboot
...
Debian GNU/Linux 7 MyZedBoard ttyPS0
MyZedBoard login: root
Password:
Last login: Thu Jan 1 00:01:57 UTC 1970 on ttyPS0
Linux MyZedBoard 3.18.0-xilinx-06524-gd51de5a #1 SMP PREEMPT Fri Apr 10 14:39:03 CEST 2015 armv7l
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
root@MyZedBoard:~# df
Filesystem 1K-blocks Used Available Use% Mounted on
rootfs 967864 373036 544828 41% /
<server_ip_address>:<nfsdir>/debianrootfs4zynq 967864 373036 544828 41% /
devtmpfs 248100 0 248100 0% /dev
tmpfs 51284 132 51152 1% /run
tmpfs 5120 0 5120 0% /run/lock
tmpfs 102560 0 102560 0% /run/shm
tmpfs 256400 0 256400 0% /tmp
root@MyZedBoard:~#
If the PL must be configured from the running Linux kernel, this can be done with:
root@MyZedBoard:~# cat /opt/bistreams/<bitstream>.bit > /dev/xdevcfg
To avoid leaving your NFS root file system in an unstable state, always shut down properly:
root@MyZedBoard:~# poweroff
...
[info] Will now halt.
reboot: System halted
before turning the power off. Remember that the root file system is on <server>
and that resetting the ZedBoard or powering it off without a proper shut down can definitively compromise your NFS share.
Maintaining the NFS share
If the NFS share on <server>
still appears busy after the client ZedBoard has been properly shut down, as happens sometimes, it can be unmounted with:
server> sudo exportfs -u <zedboard_ip_address>/32:<nfsdir>/debianrootfs4zynq
server> sudo umount -l <nfsdir>/debianrootfs4zynq
To re-mount and re-export the NFS share on <server>
:
server> cd <nfsdir>
server> sudo mount -o loop debianrootfs4zynq.img debianrootfs4zynq
server> sudo mount -t devpts devpts debianrootfs4zynq/dev/pts
server> sudo mount -t proc proc debianrootfs4zynq/proc
server> sudo exportfs <zedboard_ip_address>/32:<nfsdir>/debianrootfs4zynq
To chroot in the NFS share:
server> sudo chroot debianrootfs4zynq /bin/bash
server-chrooted> apt-get update
...