Tutorial describing steps to make Orange Pi Zero boot natively from network
To make the experience fit your profile, pick a username and tell us what interests you.
We found and based on your interests.
In the last step we're use Armbian distribution to take snapshot of the root filesystem, as well as boot artifacts.
Alternatively to that we can generate root filesystem as well as boot artifacts using [buildroot](https://github.com/buildroot/buildroot)
In short this is a set of tools and scripts that allows you to generate and build small yet extremely powerfull (and very much configurable) linux distribution. It will build u-boot (we don't need that), kernel and root filesystem specifically for our Orange Pi.
Execute following step on the dev machine
$ cd ~/pi-boot/ $ git clone https://github.com/anabolyc/buildroot-orange-pi-zero && cd buildroot-orange-pi-zero $ git submodule update --init $ cd buildroot $ make orangepi_zero_defconfig # optional, but you might want to configure root password, host name or something else to your taste $ make menuconfig $ make
This will take a while, and in the end it will output
[...]
INFO: vfat(boot.vfat): cmd: "dd if=/dev/zero of="/media/dronische/storage/buildroot-orange-pi-zero/buildroot/output/images/boot.vfat" seek=10485760 count=0 bs=1 2>/dev/null" (stderr):
INFO: vfat(boot.vfat): cmd: "mkdosfs '/media/dronische/storage/buildroot-orange-pi-zero/buildroot/output/images/boot.vfat'" (stderr):
INFO: vfat(boot.vfat): adding file 'zImage' as 'zImage' ...
INFO: vfat(boot.vfat): cmd: "MTOOLS_SKIP_CHECK=1 mcopy -bsp -i '/media/dronische/storage/buildroot-orange-pi-zero/buildroot/output/images/boot.vfat' '/media/dronische/storage/buildroot-orange-pi-zero/buildroot/output/images/zImage' '::'" (stderr):
INFO: vfat(boot.vfat): adding file 'sun8i-h2-plus-orangepi-zero.dtb' as 'sun8i-h2-plus-orangepi-zero.dtb' ...
INFO: vfat(boot.vfat): cmd: "MTOOLS_SKIP_CHECK=1 mcopy -bsp -i '/media/dronische/storage/buildroot-orange-pi-zero/buildroot/output/images/boot.vfat' '/media/dronische/storage/buildroot-orange-pi-zero/buildroot/output/images/sun8i-h2-plus-orangepi-zero.dtb' '::'" (stderr):
INFO: vfat(boot.vfat): adding file 'boot.scr' as 'boot.scr' ...
INFO: vfat(boot.vfat): cmd: "MTOOLS_SKIP_CHECK=1 mcopy -bsp -i '/media/dronische/storage/buildroot-orange-pi-zero/buildroot/output/images/boot.vfat' '/media/dronische/storage/buildroot-orange-pi-zero/buildroot/output/images/boot.scr' '::'" (stderr):
INFO: hdimage(sdcard.img): adding partition 'u-boot' from 'u-boot-sunxi-with-spl.bin' ...
INFO: hdimage(sdcard.img): adding partition 'boot' (in MBR) from 'boot.vfat' ...
INFO: hdimage(sdcard.img): adding partition 'rootfs' (in MBR) from 'rootfs.ext4' ...
INFO: hdimage(sdcard.img): writing MBR
Now we have everything we need locally, just need to copy that to both NFS and TFTP servers
$ mkdir -p ~/pi-boot/mnt/{sdc,nfs} && cd ~/pi-boot
$ sudo mount 192.168.1.3:/srv/exports mnt/nfs
$ sudo mkdir mnt/nfs/01-02-42-94-b4-99-28-buildroot
$ ls -la mnt/nfs
total 16
drwxr-xr-x 4 root root 4096 sie 13 10:25 .
drwxrwxr-x 4 dronische dronische 4096 sie 13 08:52 ..
drwxr-xr-x 18 root root 4096 sie 13 09:54 01-02-42-94-b4-99-28
drwxr-xr-x 16 root root 4096 sie 12 21:10 01-02-42-94-b4-99-28-buildroot
$ sudo rsync -va ~/pi-boot/buildroot-orange-pi-zero/buildroot/output/staging/ mnt/nfs/01-02-42-94-b4-99-28-buildroot
Next lets copy kernel and device tree to TFTP share
$ scp ~/pi-boot/buildroot-orange-pi-zero/buildroot/output/images/{zImage,sun8i-h2-plus-orangepi-zero.dtb} 192.168.1.2:/srv/tftp
And edit boot config (from TFTP server now)
$ cd /srv/tftp $ sudo mkdir dtb-buildroot && mv sun8i-h2-plus-orangepi-zero.dtb ./dtb-buildroot $ sudo nano pxelinux.cfg/01-02-42-94-b4-99-28
Content of the file
LABEL linux
KERNEL vmlinuz-5.10.43-sunxi
FDTDIR dtb-5.10.43-sunxi
APPEND root=/dev/nfs initrd=uInitrd-5.10.43-sunxi nfsroot=192.168.1.3:/srv/exports/01-02-42-94-b4-99-28 ip=dhcp rw
LABEL buildroot
KERNEL zImage
FDTDIR dtb-buildroot
APPEND root=/dev/nfs nfsroot=192.168.1.3:/srv/exports/01-02-42-94-b4-99-28-buildroot,vers=4 ip=dhcp rw
DEFAULT buildroot
Now let's reboot our PI
U-Boot SPL 2020.10-armbian...
Read more »
Now we need to prepare Pi specific files. There are number of ways doing this. Simplest one is to take files from SD card that we have prepared earlier. But first let's prepare last server in the setup - NFS server. This will provide root filesystem fro our Pi over network and preferably should have fast storage and wide connection to PI. But of course that is only optional.
In my case it is ubuntu machine under 192.168.1.3 IP, but it can be combined with TFTP and/or DHCP server as well.
$ sudo apt install nfs-kernel-server -y
$ sudo mkdir -p /srv/exports/01-02-42-94-b4-99-28
$ sudo nano /etc/exports
Contents of exports config:
/srv/exports 192.168.1.0/24(rw,no_root_squash,async,insecure,no_subtree_check,crossmnt)
You can play around with settings, above those working best for me. Key issue you might address is that all machines in the network are allowed to connect to that NFS export without authorisation. This is okay for me, but you might want to have different setup, perhaps not as much trusted.
Now lets update service
$ sudo exportfs -rv
Now we're back at dev machine, where we can take snapshot from SD card
$ mkdir -p ~/pi-boot/mnt/{sdc,nfs} && cd ~/pi-boot
$ sudo mount /dev/sdc1 mnt/sdc
$ sudo mount 192.168.1.3:/srv/exports mnt/nfs
$ ls -la mnt/nfs/
total 12
drwxr-xr-x 3 root root 4096 sie 13 08:49 .
drwxrwxr-x 4 dronische dronische 4096 sie 13 08:52 ..
drwxr-xr-x 2 root root 4096 sie 13 08:49 01-02-42-94-b4-99-28
$ sudo rsync -va mnt/sdc/ mnt/nfs/01-02-42-94-b4-99-28
sent 987,891,328 bytes received 708,418 bytes 6,009,724.90 bytes/sec
total size is 985,196,807 speedup is 1.00
Few small fixes that we need to apply on the root filesystem
# we no longer need this, it is stored on TFTP now
$ sudo rm -rf mnt/nfs/01-02-42-94-b4-99-28/boot
# edit fstab
$ sudo nano mnt/nfs/01-02-42-94-b4-99-28/etc/fstab
Need to comment first line, since we no longer have SD-card
# UUID=3dbf7aef-312c-456c-a992-e6bde7857d3f / ext4 defaults,noatime,commit=600,errors=remount-ro 0 1
tmpfs /tmp tmpfs defaults,nosuid 0 0
Next we need to prepare boot artifacts on TFTP server
$ cd ~/pi-boot/mnt/sdc/boot
$ scp -r uInitrd-5.10.43-sunxi vmlinuz-5.10.43-sunxi dtb-5.10.43-sunxi 192.168.1.2:/srv/tftp
Note that names above are those specified in boot config file created at previous step.
Last thing is to restore permissions on the TFTP share
$ sudo chown root:root /srv/tftp -R
New let's try to boot Pi
Autoboot in 1 seconds
MMC: no card present
Device 0: unknown device
ethernet@1c30000 Waiting for PHY auto negotiation to complete. done
BOOTP broadcast 1
DHCP client bound to address 192.168.1.49 (9 ms)
Using ethernet@1c30000 device
TFTP from server 192.168.1.2; our IP address is 192.168.1.49
Filename '/pxelinux.0'.
Load address: 0x42000000
Loading: *
TFTP error: 'File not found' (1)
Not retrying...
missing environment variable: pxeuuid
Retrieving file: /pxelinux.cfg/01-02-42-94-b4-99-28
Using ethernet@1c30000 device
TFTP from server 192.168.1.2; our IP address is 192.168.1.49
Filename '/pxelinux.cfg/01-02-42-94-b4-99-28'.
Load address: 0x43200000
Loading: #
63.5 KiB/s
done
Bytes transferred = 195 (c3 hex)
Config file found
1: linux
Retrieving file: /uInitrd-5.10.43-sunxi
Using ethernet@1c30000 device
TFTP from server 192.168.1.2; our IP address is 192.168.1.49
Filename '/uInitrd-5.10.43-sunxi'.
Load address: 0x43300000
Loading: #################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
...
Read more »
When Pi boots it will request certain files from TFTP server. It is very simple server with no authentication and it only server few files, among which kernel, initrd and boot config.
First we will configure some TFTP server, then we will upload those resources.
So next commands are executed on 192.168.1.2 machine, which is ubuntu in my case
$ sudo apt install tftpd-hpa -y $ sudo nano /etc/default/tftpd-hpa $ sudo chown $UID:$UID /srv/tftp -R $ mkdir /srv/tftp/pxelinux.cfg $ nano /srv/tftp/pxelinux.cfg $ nano /srv/tftp/pxelinux.cfg/01-02-42-94-b4-99-28
Content of that file is
LABEL linux
KERNEL vmlinuz-5.10.43-sunxi
FDTDIR dtb-5.10.43-sunxi
APPEND root=/dev/nfs initrd=uInitrd-5.10.43-sunxi nfsroot=192.168.1.3:/srv/exports/01-02-42-94-b4-99-28 ip=dhcp rw
DEFAULT linux
As you can see above, configuration is per MAC address, so I can have multiple device configurations in the network.
For now we don't have yet kernel, initrd and dtb files, we will fix that in a minute. Also we inform that NFS server will be under 192.168.1.3 address which not exists yet.
In the Pi boot log we're one step closer
[...]
Autoboot in 1 seconds
MMC: no card present
Device 0: unknown device
ethernet@1c30000 Waiting for PHY auto negotiation to complete. done
BOOTP broadcast 1
DHCP client bound to address 192.168.1.49 (8 ms)
Using ethernet@1c30000 device
TFTP from server 192.168.1.2; our IP address is 192.168.1.49
Filename '/pxelinux.0'.
Load address: 0x42000000
Loading: *
TFTP error: 'File not found' (1)
Not retrying...
missing environment variable: pxeuuid
Retrieving file: /pxelinux.cfg/01-02-42-94-b4-99-28
Using ethernet@1c30000 device
TFTP from server 192.168.1.2; our IP address is 192.168.1.49
Filename '/pxelinux.cfg/01-02-42-94-b4-99-28'.
Load address: 0x43200000
Loading: #
43.9 KiB/s
done
Bytes transferred = 183 (b7 hex)
Config file found
1: linux
Retrieving file: /initrd.img-5.10.43-sunxi
[...]
Next we'll prepare files specific for Pi both on TFTP server and NFS server
Now when our Pi asking to boot from network we need someone to answer it. First to respond will be DHCP server, whose role is to assign IP address (I prefer static one, but it is not strictly necessary) and instruct to get boot resources from TFTP server.
I assume you already have some kind of DHCP server within your network, normally that would be a network router, but might be dedicated machine. Im my case it is running [OpenWrt](https://openwrt.org/) and I'm able to ssh in it.
Following changes are executed at router filesystem.
# nano /etc/config/dhcp
Add below config to the bottom
config boot 'linux'
option filename '/pxelinux.0'
option serveraddress '192.168.1.2'
option servername 'netbootsrv'
config host
option name 'opi-zero-z4'
option mac '02:42:94:b4:99:28'
option ip '192.168.1.48'
For boot section we define basic structure that expected to exist on TFTP server and actual IP of netboot server, which is 192.168.1.2 in my case.
For Pi section ame is friendly name of your pi, mac is unique HW address of your Pi (I look for it in DHCP logs, but there are number of ways to find it). IP address is up to you, you just need to remember it for the future steps.
If we boot Pi now
[...]
Autoboot in 1 seconds
MMC: no card present
Device 0: unknown device
ethernet@1c30000 Waiting for PHY auto negotiation to complete. done
BOOTP broadcast 1
DHCP client bound to address 192.168.1.49 (6 ms)
Using ethernet@1c30000 device
TFTP from server 192.168.1.2; our IP address is 192.168.1.49
Filename '/pxelinux.0'.
Load address: 0x42000000
Both of our settings are accepted, but TFTP server is not responding, that what we're going to fix in next step
Next step is to flash u-boot (ie bootloader) to SPI flash.
When Pi starts normally first stage bootloader (this one is hard-coded into the CPU itself) will look for boot device. Normally it will find sd-card and boot from it (it has highest priority).
When it is not present however it will try luck with other boot sources, including SPI flash. So it will actually initialize SPI bus all on it's own and look for bootloader there (u-boot in our case). So in this step we will flash it there. Alternatively you may programm SPI flash directly on the Pi, but this is more advanced scenario and it is not covered in this tutorial.
Next steps are run on Pi
$ sudo apt update $ sudo apt upgrade $ sudo apt-get install flashrom
Next we will enable SPI flash to gain access to it (it is disabled by default) by adding device tree layer named spi-spidev
$ sudo nano /boot/armbianEnv.txt
File will look like this after edit
verbosity=1
bootlogo=false
console=serial
disp_mode=1920x1080p60
overlay_prefix=sun8i-h3
overlays=usbhost2 usbhost3 spi-spidev
rootdev=UUID=3dbf7aef-312c-456c-a992-e6bde7857d3f
rootfstype=ext4
usbstoragequirks=0x2537:0x1066:u,0x2537:0x1068:u
param_spidev_spi_bus=0
We reboot after that to confirm presense of SPI device
$ sudo reboot
[...]
$ ls -l /dev/spi*
crw------- 1 root root 153, 0 Aug 11 22:19 /dev/spidev0.0
Device is present, we can start preparing image to flash.
$ mkdir spiflash && cd spiflash # create empty image, ouf flash chip can be larger, but for our purposes it is just enough $ dd if=/dev/zero count=2048 bs=1K | tr '\000' '\377' > spi.img # let's find u-boot binary in the local filesystem $ ls -al /usr/lib/linux-u-boot-*_armhf/*.bin -rw-rw-r-- 1 root root 469855 Aug 8 14:21 /usr/lib/linux-u-boot-current-orangepizero_21.08.1_armhf/u-boot-sunxi-with-spl.bin $ dd if=/usr/lib/linux-u-boot-current-orangepizero_21.08.1_armhf/u-boot-sunxi-with-spl.bin of=spi.img bs=1k conv=notrunc
Now we have an image in spi.img file, that we just need to flash
$ sudo flashrom -p linux_spi:dev=/dev/spidev0.0 -w spi.img -c MX25L1605A/MX25L1606E/MX25L1608E
flashrom v1.2 on Linux 5.10.43-sunxi (armv7l)
flashrom is free software, get the source code at https://flashrom.org
Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
Using default 2000kHz clock. Use 'spispeed' parameter to override.
Found Macronix flash chip "MX25L1605A/MX25L1606E/MX25L1608E" (2048 kB, SPI) on linux_spi.
Reading old flash chip contents... done.
Erasing and writing flash chip... Erase/write done.
Verifying flash... VERIFIED.
Now we're ready to reboot and try out boot without SD-card present
$ sudo poweroff
Upon reboot without SD-card
U-Boot SPL 2020.10-armbian (Aug 08 2021 - 16:21:05 +0200)
DRAM: 256 MiB
Trying to boot from sunxi SPI
U-Boot 2020.10-armbian (Aug 08 2021 - 16:21:05 +0200) Allwinner Technology
CPU: Allwinner H3 (SUN8I 1680)
Model: Xunlong Orange Pi Zero
DRAM: 256 MiB
MMC: mmc@1c0f000: 0, mmc@1c10000: 1
Loading Environment from FAT... MMC: no card present
In: serial
Out: serial
Err: serial
Net: phy interface0
eth0: ethernet@1c30000
starting USB...
Bus usb@1c1a000: USB EHCI 1.00
Bus usb@1c1a400: USB OHCI 1.0
Bus usb@1c1b000: USB EHCI 1.00
Bus usb@1c1b400: USB OHCI 1.0
Bus usb@1c1c000: USB EHCI 1.00
Bus usb@1c1c400: USB OHCI 1.0
scanning bus usb@1c1a000 for devices... 1 USB Device(s) found
scanning bus usb@1c1a400 for devices... 1 USB Device(s) found
scanning bus usb@1c1b000 for devices... 1 USB Device(s) found
scanning bus usb@1c1b400 for devices... 1 USB Device(s) found
scanning bus usb@1c1c000 for devices... 1 USB Device(s) found
scanning bus usb@1c1c400 for devices... 1 USB Device(s) found
scanning usb for storage devices... 0 Storage Device(s) found
Autoboot in 1 seconds
MMC: no card present
Device 0: unknown device
ethernet@1c30000 Waiting for PHY auto negotiation to complete. done
BOOTP broadcast 1
DHCP client bound to address 192.168.1.202 (8 ms)
What happens above is Pi able...
Read more »First we would need bootable SD-card. As mentioned before we will use it to (a) flash onboard SPI and (b) take snapshot of the root FS.
1. I'll start with Armbian, later on we might want to take another distro. Go to Armbian website and get latest image, at the moment of writing it is Armbian_21.05.6_Orangepizero_focal_current_5.10.43.img.xz
2. Insert SD card and note its name. It is sdc in my case. No need to mount or format it.
$ lsblk
[...]
sdc 8:32 1 14,6G 0 disk
└─sdc1 8:33 1 14,5G 0 part
3. Flash the image to SD card
$ xz --decompress Armbian_21.05.6_Orangepizero_focal_current_5.10.43.img.xz $ sudo dd if=Armbian_21.05.6_Orangepizero_focal_current_5.10.43.img of=/dev/sdc bs=1M 1144+0 records in 1144+0 records out 1199570944 bytes (1,2 GB, 1,1 GiB) copied, 214,305 s, 5,6 MB/s $sudo sync
Let's boot it and perform initial configuration, like account creation, setting up passwords and whatever else you need to claim it ready for taking snapshot
I'll start screen to monitor boot process via USB-UART adapter by issuing command
$ screen /dev/ttyUSB0 115200
Result is below
U-Boot SPL 2021.04-armbian (Jun 21 2021 - 15:06:33 +0000)
DRAM: 256 MiB
Trying to boot from MMC1
U-Boot 2021.04-armbian (Jun 21 2021 - 15:06:33 +0000) Allwinner Technology
CPU: Allwinner H3 (SUN8I 1680)
Model: Xunlong Orange Pi Zero
DRAM: 256 MiB
MMC: mmc@1c0f000: 0, mmc@1c10000: 1
Loading Environment from FAT... Unable to use mmc 0:1... In: serial
Out: serial
Err: serial
Net: phy interface0
eth0: ethernet@1c30000
starting USB...
[...]
[ OK ] Started Network Manager Script Dispatcher Service.
[ OK ] Started Dispatcher daemon for systemd-networkd.
[ OK ] Reached target Multi-User System.
[ OK ] Reached target Graphical Interface.
Starting Update UTMP about System Runlevel Changes...
[ OK ] Finished Update UTMP about System Runlevel Changes.
orangepizero login: root (automatic login)
___ ____ _ _____
/ _ \| _ \(_) |__ /___ _ __ ___
| | | | |_) | | / // _ \ '__/ _ \
| |_| | __/| | / /| __/ | | (_) |
\___/|_| |_| /____\___|_| \___/
Welcome to Armbian 21.05.6 Focal with Linux 5.10.43-sunxi
System load: 100% Up time: 2 min
Memory usage: 47% of 238M IP:
CPU temp: 54°C Usage of /: 8% of 15G
RX today: n/a
[ General system configuration (beta): armbian-config ]
New to Armbian? Documentation: https://docs.armbian.com Support: https://forum.armbian.com
New root password:
Next step is to enable SPI flash and flash it with u-boot
Recently I was playing around Orange Pi Zero (actually checking if I'd be able to boot it without any storage). Almost accidentally I found out that recent u-boot able to use onboard Ethernet for boot purposes. Checked everything and it did indeed worked. I want to note my steps for anyone willing to repeat that process.
First of all prerequisites:
- Orange Pi Zero - tutorial would not work for just any Orange Pi out there. I'm using onboard SPI flash to start boot process, and per my knowledge only Orange Pi Zero has both SPI flash and Ethernet PHY.
- To configure Orange Pi we need SD card. One finished it will be no longer required. It is not strictly necessary, but makes things easier.
- (optional) To debug whole process it is really helpful to have USB-UART adapter. It will cost you around $1 if you still don't have one. It is not strictly necessary, but will help a lot in understanding the process
From your network perspective
- (A) Some router serving as DHCP server. When Pi will bot it will need clear instruction where boot components should be taken from.
- (B) Some network server with storage, preferably fast one. It will store Pi filesystems
- (C) Some network server with boot artifacts exposed via TFTP server.
All of the above can be combined in single physical machine, or split roles in every possible combination.
From the perspective of going through this tutorial we would need some wokrplace PC or laptop with access to the same network. This is where we're sitting and deploying all the magic.
The process in general will look like this
1. We prepare standard bootable image on SD card and boot it on our Pi. We will need it to (a) flash u-boot to onboard SPI flash and (b) to take filesystem snapshot
2. We will configure NFS (network accessible filesystem) and take snapshot from running system.
3. We will configure TFTP service on network boot server and configure DHCP to instruct our Pi to use it.
Boot process in short:
Create an account to leave a comment. Already have an account? Log In.
Become a member to follow this project and never miss any updates