Skip to content

Booting Linux with NFS Root

Brandon Perez edited this page Mar 25, 2017 · 9 revisions

Back to Home

Overview

This wiki describes how boot a Linux kernel from an SD card with a root NFS (network filesystem). The boot files for the kernel are still stored on an SD card.

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.

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 xilinx_zynq_defconfig kernel configuration in the Xilinx kernel has NFS support enabled. If you haven't already, then compile the boot files as described in Build the Boot Sources.

If you haven't already copied the boot files to the SD card, then insert the SD card, and copy the files to it:

cp "${SW_DIR}/boot_files/boot.bin" "/media/${USER}/boot/boot.bin"
cp "${SW_DIR}/boot_files/system.bit" "/media/${USER}/boot/system.bit"
cp "${SW_DIR}/boot_files/uImage" "/media/${USER}/boot/uImage"
cp "${SW_DIR}/boot_files/devicetree.dtb" "/media/${USER}/boot/devicetree.dtb"

Unmount the SD card:

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

Setup the Host Machine to Share Its Network

In this setup, we're going to assume that the Zedboard and the host machine are connected directly to each other via Ethernet with no intermediate router or switch. This means that the host machine will act as a router for the Zedboard, which is often referred to as network sharing. If the Zedboard is connected to a router, or directly to your network, you can skip this step.

Otherwise, we need to setup the host machine to share the network with the Zedboard. Goto System Settings, then Network, click on Wired in the sidebar, and then click on Options.... A new window will pop-up for your Ethernet interface. Click on the IPv4 Settings tab. Then, click on the Method drop-down menu, and select Shared to other computers. At the bottom of the page, check the box for Require IPv4 addressing for this connection to complete, and then click Save....

Note: This will make your Ethernet port unsuitable for use on normal networks, since it will solely be configured to share the network with whomever is connected to it. Thus, if you want to use your Ethernet port for connecting to the Internet and normal network operations, you need to undo the changes that have been made to the connection settings.

Determine the Host IP Address

Next, we need to determine what the IP address for the host machine is on the network, so that the board knows where to look for the root NFS.

Make sure that your host machine's Ethernet is connect and up and running. Then, extract the IP addresses of your host machine's Ethernet:

ifconfig eth0 | grep "inet addr" | sed -e 's/\s*\|inet addr:\|Bcast:.*//g'

This assumes that your machine only has one Ethernet port, and that it corresponds to the eth0 interface. This may not be the case if you have a different setup, or more than one Etherent port. Run the command ifconfig which will display all network interfaces on the machine. Look for a ethernet interface that has inet addr set, and the number following this should be the IP address of your machine on that connection.

In any case, once you determine the IP address, put it an environment variable (this will be referenced later):

export HOST_IPADDR=<Host IP Address>

Export the Filesystem on the Network Filesystem (NFS) Server

The configuration parameters for the NFS server are stored in /etc/exports. These tell the server which directories can be used as NFS, and what settings to configure for them (e.g. read/write vs readonly, etc.).

Add the root filesystem to the exports file:

sudo bash -c "cat << EOF >> /etc/exports

# Expose the Ubuntu core filesystem to the board
\"${SW_DIR}/ubuntu_14.04_corefs/\" 10.0.0.0/255.0.0.0(rw,sync,no_root_squash,no_subtree_check)
EOF"

The above commands assumes that your host computer and the board are directly connected, so it exposes the Ubuntu core filesystem on the 10.x.x.x local subnet. If you have an alternate configuration, then change the IP address and subnet mask to the appropriate values. For example, if the board and your host machine are connected locally via switch or router, then accepted mask should be 192.168.0.0/255.255.0.0. Otherwise, if they aren't on the same local network, you will need the exact IP addresses. For security reasons, it is wise to only expose the NFS to the board's exact IP address.

Notify the NFS server of the new filesystem and export it:

sudo exportfs -ra
sudo service nfs-kernel-server 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 with NFS, we need to inform the kernel of our desire to do so, and tell it where the NFS is located on the network. Thus, we need to update the kernel command line. Create the boot script for performing a root NFS boot:

cat << EOF > "${SW_DIR}/config/nfs_boot.script"
# Performs a SD boot 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
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=dhcp nfsroot=\${serverip}:\${nfsdir} rw rootwait earlyprintk ignore_loglevel nfsrootdebug'

# If it exists, load the bitstream into memory and then program the PL
setenv print_fpga_success 'echo Programming FPGA with \${bitstream_image} on the SD card...'
setenv print_fpga_failure 'echo No \${bitstream_image} found on the SD card, skipping FPGA programming.'
setenv load_fpga 'load mmc 0 \${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
setenv print_kernel 'echo Loading the kernel from \${kernel_image} on the SD card...'
setenv load_kernel 'load mmc 0 \${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} on the SD card...'
setenv load_devicetree 'load mmc 0 \${devicetree_load_address} \${devicetree_image}'
setenv do_load_devicetree 'run print_devicetree load_devicetree'

# Set the command we're using to boot
setenv print_boot_message 'echo Booting Linux from SD with a root NFS...'
setenv boot_kernel 'bootm \${kernel_load_address} - \${devicetree_load_address}'
setenv bootcmd 'run print_boot_message set_bootargs do_program_fpga do_load_kernel do_load_devicetree boot_kernel'

# 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, and you should be dropped into a terminal with a root NFS.

Next Steps

Now that you can boot with a network filesystem, you can take additional steps to make development time faster. Instead of storing the kernel boot files on the SD card, you can send them over the network at boot time through trivial file transfer protocol (TFTP).

For booting Linux over TFTP, see Booting Linux with TFTP.

References

The instructions for setting up NFS were adapted from the Linux Config wiki - Wiki Page

The solution to the NFS root hang at boot was found on the NVIDIA forums - Forum

Files

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

u-boot.elf - Prebuilt U-Boot binary from the Xilinx U-Boot 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, generated from the steps on the wiki.

uImage - Prebuilt Linux kernel image from the Xilinx Linux repository.

devicetree.dtb - Prebuilt device tree binary for the Zedboard from the Xilinx Linux repository.