Oct 31, 2014

Booting up Linux on Zedboard over network

In a previous post, I broke out of the constraints of an SD for the Linux root file system for my Zedboard.  I may start modifying the ARM Linux kernel soon, in which case copying the uImage to the SD card intermediate step seems mildly irritating.  On PCs, the PXE boot is a well-proven technology, and I wrote down how to do it a few years ago.  PXE is an Intel technology, and unavailable for ARM I think, but fortunately, other people (like Sven Anderson) have already figured out how to coax U-Boot download the kernel image over TFTP and then boot it.  I followed his "Zynq design from scratch" blog to setup Kernel netboot, as described below.

TFTP server (tftpd-hpa) on Ubuntu 14.04 LTS

Install the tftpd-hpa on the host:
$ sudo apt-get install tftpd-hpa
The default configuration file (/etc/default/tftpd-hpa) just needs some tweaks (my changes highlighted):

RUN_DAEMON="yes"
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/var/lib/tftpboot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure --ipv4"


For reasons I cannot recall now, I ran the TFTP as its own daemon instead of through inetd.  Because I have bigger fish to fry, I am moving on.  Serving all interfaces on the host is fine because my development box only has 1 NIC.  I originally allowed IPv6 to run on my server, but got fed up with apt-get taking forever to time out against canonical servers and turned off IPv6 on my desktop with this command, by appending the following to my /etc/sysctl.conf,

net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1

and then running

$ sudo sysctl -p

But turning off IPv6 requires IPv6 to be turned off in the TFTP config file, by changing TFTP_ADDRESS to the value shown above; note that the port number does not change.

The server must serve up the kernel image and device tree, which I put in TFTP_DIRECTORY defined in the config file above.

/var/lib/tftpboot$ sudo cp ~/work/zynq/buildroot/output/images/uImage zedImage
/var/lib/tftpboot$ sudo cp ~/work/zynq/buildroot/output/images/zynq-zed-adv7511.dtb .

No, I still cannot make the ftp server follow symbolic link, sigh...  For sanity test, install tftp on the host, and try "get"-ting one of the above files into your home folder.  So here is a post-build script to ease the pain; change the folders according to your own setup:

sudo rm -rf /export/root/zed/; sudo mkdir /export/root/zed/
sudo tar -C /export/root/zed -xf /mnt/work/zynq/buildroot/output/images/rootfs.tar

sudo cp /mnt/work/zynq/buildroot/output/images/uImage /var/lib/tftpboot/zedImage

Troubleshooting

If TFTP suddenly stops working when you have not changed the target side, then suspect the TFTP server--it often does not start or crashes.  To check,

$ sudo service tftpd-hpa status
ftpd-hpa start/running, process 5930

It should show print a PID if it's really running, as in the above example.  If not, try stopping and restarting

$ sudo service tftpd-hpa restart

Manually boot off TFTP

Logically, U-Boot needs to know 2 things to boot:

  1. What files to download over TFTP, and which memory to stick them.
    1. ipaddr and serverip U-Boot environment variables stay the same as the NFS root file system case.
    2. Leveraging the knowledge gained from the previous post, I will continue to mount the root file system over NFS, so I only need to download the kernel image (uImage) and DTB (because my eval board is ARM).  Copied for convenience, the kernel image should be at 0x3000000, and the device tree image should be at 0x2A00000.
  2. The boot command specifying the memory address containing the kernel.  From previous post, I already have a working boot command.  If I keep the memory addresses the same, I do NOT have to modify the boot command.
So let's focus on downloading the uImage and DTB files to the target.  I stop U-Boot in the serial console during the 3 second wait.  The U-Boot command to download a file from the TFTP server is (surprise!) "tftpboot".  So first, the device tree blob:
zynq-uboot> tftpboot 0x2A00000 192.168.1.2:zynq-zed-adv7511.dtb

The the kernel image itself:
zynq-uboot> tftpboot 0x3000000 192.168.1.2:zedImage
Then we can simply boot from memory:

zynq-uboot> bootm
...
Welcome to Zeboard!

zed login:

Codify the success as U-Boot sdboot script

Remember that the FSBL is still necessary to program the FPGA bitstream and kick off U-Boot (the 2nd stage boot loader).  All these files are still on the SD card, so when U-Boot loads, it will find itself in sdboot mode.   There is a matching environment variable "sdboot" which I configured in the previous post to load the uImage and the DTB files from SD's BOOT partition, and kick off the bootm command (used above).  So for TFTP boot, I just have to modify this sdboot environment variable to what worked above:

setenv serverip 192.168.1.2
setenv ipaddr 192.168.1.9
setenv kernel_image "zedImage"
setenv devicetree_image "zynq-zed-adv7511.dtb"

setenv sdboot 'if mmcinfo; then run uenvboot; echo Copying files over TFTP to RAM && tftpboot 0x2A00000 ${serverip}:${devicetree_image} && tftpboot 0x3000000 ${serverip}:${kernel_image} && bootm 0x3000000 - 0x2A00000; fi'

saveenv
boot

Enjoy!

1 comment:

  1. I got error "ARP Retry count exceeded; starting again". Could you please let me know what should I do?

    ReplyDelete