Skip to content

Booting Linux with TFTP

Brandon Perez edited this page Aug 3, 2016 · 5 revisions

Back to Home

Overview

This wiki describes how to boot a Linux kernel over TFTP (trivial file transfer protocol) with an NFS root on the Zedboard. This allows for the bitstream file, device tree binary, and the Linux kernel image to be transferred over the network, so they don't need to be stored on the SD card.

If you want to do just TFTP alone, you should be able to remove the NFS-related parts, and infer just the TFTP-related sections.

Prerequisites

Your boot sources must be built and the root filesystem must be setup as described in Build the Boot Sources and Create a Root Filesystem, respectively.

Your SD card must be formatted as described in Booting Linux from SD.

Your host machine and the Zedboard should be connected over the network to each other. If you're connecting the two directly via an Ethernet cable, make sure your host machine is setup as described in Booting Linux with NFS Root.

System Configuration

These instructions were run and tested with the following software and hardware:

  • Laptop OS: Ubuntu 14.04 (64-bit)

  • Board OS: Ubuntu 14.04 (32-bit)

  • Board: Zedboard

  • Board Architecture: ARM

  • Xilinx Tools:

    • Vivado Version: 2015.2
    • Xilinx SDK Version: 2015.2
    • Vivado HLS Version: 2015.2
  • U-Boot Version:

    • Version: 2016.03
    • Branch: master
  • Linux

    • Version: 4.4.0
    • Branch: master

For reference, we assume that the following environment variables are defined:

export SW_DIR=<Path to your software>
export THRS=$((2 * `cat /proc/cpuinfo | grep processor | wc -l`))

Recompiling the Boot Files

No changes are needed to the boot files, so they do not need recompiled. The zynq_zed_config U-Boot configuration in Xilinx's U-Boot fork has TFTP support enabled. If you haven't already, then compile the boot files as described in Build the Boot Sources.

When booting with TFTP, the devicetree binary, the bitstream file, and the kernel image are all transfered over TFTP. Thus, the only file needed on the SD card is boot.bin. If you haven't already copied this file to the SD card, then insert the SD card, and copy the file to it:

cp "${SW_DIR}/boot_files/boot.bin" "/media/${USER}/boot/boot.bin"

Unmount the SD card:

sync
umount "/media/${USER}/boot"
umount "/media/${USER}/rootfs"

Determine the Host and Board IP addresses

For TFTP booting, we need to know both the host and board IP addresses on the network. If you haven't already, determine your host machine's IP address. See Booting Linux with NFS Root for doing this.

To determine the board's IP address, boot the board up while it is connected to the network. Once you login, you can follow the same steps for determining the host machine's IP address, as described in Booting Linux with NFS Root. Simply type these commands in the board's shell.

Put both of these IP addresses into environment variables (these will be referenced later):

export HOST_IPADDR=<Host IP Address>
export BOARD_IPADDR=<Board IP Address>

Setup the TFTP Directory

We're going to use the boot files directory, ${SW_DIR}/boot_files, as the TFTP directory, since we'll be storing all of the needed files for booting here anyway. The TFTP directory is where the TFTP will look for files when the board requests them.

If you haven't already, then copy all of the boot files to the TFTP directory, boot_files:

cp <path to bitstream file> "${SW_DIR}/boot_files/system.bit"
cp "${SW_DIR}/linux/arch/arm/boot/uImage" "${SW_DIR}/boot_files/uImage"
cp "${SW_DIR}/linux/arch/arm/boot/dts/zynq-zed.dtb" "${SW_DIR}/boot_files/devicetree.dtb"

Export the TFTP Directory on the TFTP Server

The configuration parameters for the TFTP server are stored in /etc/default/tftpd-hpa. This file tells the server which directory to export, and controls various settings of the server (e.g. the port to use, IP address, etc.).

Change the exported TFTP directory to the boot files directory:

sudo sed -i -e "s|^TFTP_DIRECTORY=.*\$|TFTP_DIRECTORY=\"${SW_DIR}/boot_files\"|g" /etc/default/tftpd-hpa

Restart the TFTP server to notify it of the changed directory, exporting it:

sudo service tftpd-hpa restart

Boot the System

Make sure that the SD card is inserted into the Zedboard, and that the jumpers are in their proper settings. See Booting Linux from SD for a review of the setup.

To boot over TFTP, we need to inform U-Boot of desire to do so, and we need to tell U-Boot what the IP address of the Zedboard and the TFTP server are. The TFTP command requires both the board's IP address and the server's IP address. Thus, we need to update the U-Boot environment variables and change the command that is used to boot Linux. Create a boot script for performing a TFTP boot:

cat << EOF > "${SW_DIR}/config/tftp_nfs_boot.script"
# Performs a boot over TFTP (trivial file transfer protocol) with a root network filesystem (NFS)
# Assumes following variables are defined:
#   kernel_image, devicetree_image, kernel_load_address, devicetree_load_address, loadbit_addr, filesize

# Reset the environment to its default settings
env default -a

# Set the name of the bitstream file
setenv bitstream_image 'system.bit'
setenv bitstream_load_address '\${loadbit_addr}'

# Set the console and root filesystem we're going to use
setenv console 'ttyPS0,115200'
setenv root '/dev/nfs'

# Set the IP address and the path on the host machine of the NFS, and the board's IP address
setenv ipaddr '${BOARD_IPADDR}'
setenv serverip '${HOST_IPADDR}'
setenv nfsdir '${SW_DIR}/ubuntu_14.04_corefs'

# Dynamically set the boot arguments for the kernel (reads the environment variables)
setenv set_bootargs 'setenv bootargs console=\${console} root=\${root} ip=\${ipaddr}:\${serverip} nfsroot=\${serverip}:\${nfsdir} rw earlyprintk ignore_loglevel nfsrootdebug'

# If it exists in the TFTP directory, load the bitstream into memory and then program the PL
setenv print_fpga_success 'echo Programming FPGA with \${bitstream_image} over TFTP...'
setenv print_fpga_failure 'echo No \${bistream_image} found in the TFTP directory, skipping FPGA programming.'
setenv load_fpga 'tftpboot \${bitstream_load_address} \${bitstream_image}'
setenv program_fpga 'fpga loadb 0 \${bitstream_load_address} \${filesize}'
setenv do_program_fpga 'if run load_fpga program_fpga; then run print_fpga_success; else run print_fpga_failure; fi'

# Load Linux and the device tree into memory from the network over TFTP
setenv print_kernel 'echo Loading the kernel from \${kernel_image} over TFTP...'
setenv load_kernel 'tftpboot \${kernel_load_address} \${kernel_image}'
setenv do_load_kernel 'run print_kernel load_kernel'
setenv print_devicetree 'echo Loading the device tree from \${devicetree_image} over TFTP...'
setenv load_devicetree 'tftpboot \${devicetree_load_address} \${devicetree_image}'
setenv do_load_devicetree 'run print_devicetree load_devicetree'

# Setup a command to check if the network is ready, and wait for it to come up
setenv net_check 'sleep 1 && ping \${serverip} || sleep 7 && ping \${serverip}'
setenv print_net_failure 'echo Unable to ping host machine at \${serverip}, check that network is up'

# Set the command we're using to boot
setenv print_boot_message 'echo Booting Linux over TFTP with a root NFS...'
setenv boot_kernel 'bootm \${kernel_load_address} - \${devicetree_load_address}'
setenv do_boot_kernel 'run print_boot_message set_bootargs do_load_kernel do_load_devicetree do_program_fpga boot_kernel'
setenv bootcmd 'if run net_check; then run do_boot_kernel; else run print_net_failure; fi'

# Save the current environment in persistent storage, and reset
saveenv
reset
EOF

Connect to the Zedboard's serial console:

sudo minicom -D /dev/ttyACM0

On the Zedboard, press the PS-RST button (BTN7) to reset the system and begin the boot. Press any key to prevent automatic booting. Then, copy and paste the contents of the above file onto the U-Boot console. This will save this as the automatic boot configuration and reset. The system should then boot-up with TFTP, and then you should be dropped into a console.

Debugging Issues with the TFTP Server

Occasionally, when you try to boot on the Zedboard, you may see a message like the following appear on your U-Boot console:

TFTP server died; starting again

This message basically means that the TFTP server on your host machine is in a bad state. So, to get it working again, you need to reset the TFTP server. Run the following command:

sudo service tftpd-hpa restart

Next Steps

References

The TFTP setup instructions were taken from an Embedded Linux wiki page - Wiki

Files

tftp_nfs_boot_template.script - Template U-Boot script for a TFTP boot with an NFS root.

zynq_fsbl.elf - Prebuilt FSBL generated from the steps on the wiki.

u-boot.elf - Prebuilt U-Boot binary from the zynq_uboot repostiory.

boot.bin - Prebuilt bootloader image, which is the result of running bootgen on the FSBL and U-Boot binaries.

system.bit - "Empty" bitstream file for programming the FPGA.

uImage - Prebuilt Linux kernel image from this repository (zynq_linux).

devicetree.dtb - Prebuilt device tree binary from this repository (zynq_linux).

Clone this wiki locally