|
| 1 | +# Network booting |
| 2 | + |
| 3 | +To network boot the bootrom does the following: |
| 4 | + |
| 5 | +* Initialise LAN9500 |
| 6 | +* Send DHCP request |
| 7 | +* Receive DHCP reply |
| 8 | +* (optional) Receive DHCP proxy reply |
| 9 | +* ARP to tftpboot server |
| 10 | +* ARP reply includes tftpboot server ethernet address |
| 11 | +* TFTP RRQ 'bootcode.bin' |
| 12 | + * File not found: Server replies with TFTP error response with textual error message |
| 13 | + * File exists: Server will reply with the first block (512 bytes) of data for the file with a block number in the header |
| 14 | + * Pi replys with TFTP ACK packet containing the block number, repeats until the last block which is not 512 bytes |
| 15 | +* TFTP RRQ 'bootsig.bin' |
| 16 | + * This will normally result in an error file not found... |
| 17 | + |
| 18 | +From this point the bootcode.bin code continues to load the system, the first file it will try to access is [`serial_number`]/start.elf if this does __not__ result in a error then any other files to be read will be pre-pended with the `serial_number`. This is useful because if enables you to create separate directories with separate start.elf / kernels for your Pis |
| 19 | +To get the serial number for the device you can either try this boot mode and see what file is accessed using tcpdump / wireshark or you can run a standard Raspbian SD card and `cat /proc/cpuinfo` |
| 20 | + |
| 21 | +If you put all your files into the root of your tftp directory then all following files will be accessed from there. |
| 22 | + |
| 23 | +# Setting up a DHCP / TFTP server |
| 24 | + |
| 25 | +This tutorial is written to explain how to set up a simple DHCP / TFTP server to boot a Raspberry Pi 3 from the network. This first tutorial assumes you only have a Raspberry Pi for the SERVER and a Pi 3 as a CLIENT to be booted. |
| 26 | + |
| 27 | +Install a standard Raspbian lite (or heavy if you want) from the [Downloads page](https://www.raspberrypi.org/downloads/raspbian/) onto an SD card using whatever process you like (dd or Win32DiskImager or something similar). Before booting the Client edit the config.txt and add the following to config.txt |
| 28 | + |
| 29 | +``` |
| 30 | +program_usb_boot_mode=1 |
| 31 | +``` |
| 32 | + |
| 33 | +Now copy [start.elf](start.elf) and [bootcode.bin](bootcode.bin) to the sdcard overwriting the currently existing start.elf and bootcode.bin, you should also: |
| 34 | + |
| 35 | +``` |
| 36 | +rm start_* fixup* |
| 37 | +``` |
| 38 | + |
| 39 | +Plug the SD card into the CLIENT and boot it with a keyboard and HDMI connected. When it boots, log in and check that the OTP is correctly programmed |
| 40 | + |
| 41 | +``` |
| 42 | +$ vcgencmd otp_dump | grep 17: |
| 43 | +17:3020000a |
| 44 | +``` |
| 45 | + |
| 46 | +Make sure the 0x3020000a is correct. |
| 47 | + |
| 48 | +Now, shutdown the Pi gracefully and re-edit the config.txt file to remove the `program_usb_boot_mode` (you don't actually have to do this, it will enable USB boot modes but shouldn't break anything.) |
| 49 | + |
| 50 | +Plug the SD card into the SERVER and boot the server, with it connected to the internet install some useful applications: |
| 51 | + |
| 52 | +``` |
| 53 | +sudo apt-get install tcpdump |
| 54 | +sudo apt-get install dnsmasq |
| 55 | +echo "denyinterfaces eth0" | sudo tee -a /etc/dhcpcd.conf |
| 56 | +``` |
| 57 | + |
| 58 | +After this we'll need to fix DNS because dnsmasq breaks it a bit... |
| 59 | + |
| 60 | +``` |
| 61 | +sudo rm /etc/resolvconf/update.d/dnsmasq |
| 62 | +sudo reboot |
| 63 | +``` |
| 64 | + |
| 65 | +Now Take an ethernet cable and plug it directly between the SERVER and the CLIENT and set a static IP address on the SERVER: |
| 66 | + |
| 67 | +``` |
| 68 | +sudo ifconfig eth0 down |
| 69 | +sudo ifconfig eth0 up 192.168.1.1 netmask 255.255.255.0 broadcast 192.168.1.255 |
| 70 | +sudo tcpdump -i eth0 |
| 71 | +``` |
| 72 | +Now power the CLIENT |
| 73 | + |
| 74 | +Check that the LEDs illuminate on the CLIENT after around 10 seconds, then you get a packet from the CLIENT "DHCP/BOOTP, Request from ..." |
| 75 | + |
| 76 | +Now we need to modify the dnsmasq configuration to enable DHCP to reply to the device ... |
| 77 | + |
| 78 | +``` |
| 79 | +sudo echo | sudo tee /etc/dnsmasq.conf |
| 80 | +sudo nano /etc/dnsmasq.conf |
| 81 | +``` |
| 82 | + |
| 83 | +Then replace the contents of dnsmasq.conf with: |
| 84 | + |
| 85 | +``` |
| 86 | +port=0 |
| 87 | +log-dhcp |
| 88 | +enable-tftp |
| 89 | +tftp-root=/tftpboot |
| 90 | +dhcp-range=eth0,192.168.1.100,192.168.1.150,12h |
| 91 | +pxe-service=0,"Raspberry Pi Boot" |
| 92 | +``` |
| 93 | + |
| 94 | +It's important that the 192.168.1.x matches the subnet you used in the static IP settings, the range is what it'll share |
| 95 | + |
| 96 | +Now create a /tftpboot directory |
| 97 | + |
| 98 | +``` |
| 99 | +$ sudo mkdir /tftpboot |
| 100 | +$ sudo chmod 777 /tftpboot |
| 101 | +$ sudo systemctl restart dnsmasq.service |
| 102 | +``` |
| 103 | + |
| 104 | +Next we can try the tcpdump again... |
| 105 | + |
| 106 | +``` |
| 107 | +sudo tcpdump -i eth0 |
| 108 | +``` |
| 109 | + |
| 110 | +You should see a DHCP REPLY packet and a TFTP read request packet, for "bootcode.bin" |
| 111 | + |
| 112 | +Next, you will need to copy [bootcode.bin](bootcode.bin) and [start.elf](start.elf) into the /tftpboot directory, you should be able to do this by just copying the files from /boot since they are the right ones... |
| 113 | + |
| 114 | +``` |
| 115 | +cp /boot/bootcode.bin /tftpboot |
| 116 | +cp /boot/start.elf /tftpboot |
| 117 | +``` |
| 118 | + |
| 119 | +Now when you power off and then power on the CLIENT tcpdump should give lots of data and the result should be the green LED flashing (this means it couldn't find the kernel, not surprising since we didn't give it one...) |
| 120 | + |
| 121 | +Next, we need to provide the other files (kernel and dt overlays etc) which are currently stored on the SERVER's boot directory, so: |
| 122 | + |
| 123 | +``` |
| 124 | +cp -r /boot/* /tftpboot |
| 125 | +``` |
| 126 | + |
| 127 | +This should now allow your Pi to boot through until it tried to load a root filesystem (which it doesn't have)... This is the point where you need to provide a filing system which is beyond this tutorial... Although I'll give you some clues for sharing the SERVERS filesystem with the client... |
| 128 | + |
| 129 | +* Reboot SERVER with a normal ethernet connection (you'll probably need to remove the dhcpcd.conf line to re-enable the client) |
| 130 | +* `sudo apt-get install nfs-kernel-server` |
| 131 | +* `sudo vi /etc/exports` |
| 132 | +* Add the line "/ *(rw,sync,no_subtree_check)" to exports |
| 133 | +* sudo systemctl restart rpcbind.service |
| 134 | +* sudo systemctl restart nfs-kernel-server.service |
| 135 | +* Reboot with the ethernet connected to the CLIENT and do the static IP thing again |
| 136 | +* Check the mount is working using something like `sudo mount 192.168.1.1:/ tmp` |
| 137 | +* edit /tftpboot/cmdline.txt and change to |
| 138 | + * "root=/dev/nfs nfsroot=192.168.1.1:/ rw ip=dhcp rootwait" |
| 139 | +* edit /etc/fstab and remove the /dev/mmcblkp1 and p2 lines |
| 140 | +* edit /boot/cmdline.txt (the SERVER's cmdline) and add "rw" to the line |
| 141 | + |
| 142 | +Think that's it... Good luck... |
0 commit comments