December 9, 2016

Orange Pi PC - Armbian boot setup

This documents an investigation into how an Ambian card for the Orange Pi PC was set up for booting. In summary, several things are learned:

Partition layout

The flash card has only one partition that mounts up as ext4.
/dev/sdc1 on /run/media/tom/bb870b9b-0835-49be-9212-62c2cc05b755 type ext4 (rw

Disk /dev/sdc: 7.4 GiB, 7948206080 bytes, 15523840 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x86673d77

Device     Boot Start      End  Sectors  Size Id Type
/dev/sdc1        2048 15213343 15211296  7.3G 83 Linux
Note that the first partition starts 2048 sectors into the SD card. This leaves 1M of space for the partition table, spl, and U-boot. This offset could easily be increased.

There is no uEnv.txt in "/" or "/boot". The contents of the /boot directory are:

cd /boot
ls -l
drwxr-xr-x 2 root root    4096 Sep 14 22:31 bin
-rw-r--r-- 1 root root    6944 Sep 14 22:31 boot.bmp
-rw-r--r-- 1 root root    2814 Sep 14 22:29 boot.cmd
-rw-r--r-- 1 root root    2886 Sep 14 22:33 boot.scr
-rw-r--r-- 1 root root   94749 Sep 14 11:29 config-3.4.112-sun8i
-rw-r--r-- 1 root root 3114454 Sep 14 22:31 initrd.img-3.4.112-sun8i
lrwxrwxrwx 1 root root      18 Sep 14 22:31 script.bin -> bin/orangepipc.bin
-rw-r--r-- 1 root root 2119429 Sep 14 11:29 System.map-3.4.112-sun8i
-rw-r--r-- 1 root root 3114518 Sep 14 22:31 uInitrd
-rwxr-xr-x 1 root root 5025168 Sep 14 11:29 vmlinuz-3.4.112-sun8i
lrwxrwxrwx 1 root root      21 Sep 14 22:29 zImage -> vmlinuz-3.4.112-sun8i

Monkeywrench U-boot

I want to set up a card to have a customized U-boot running. Ultimately I want to have it boot via tftp over the network, but in order to understand how the Armbian U-boot is configured, I just want to get to the U-boot prompt as a first step. Often the boot timeout is set short, which makes for a fast boot of linux, but makes it hard to interrupt U-boot, so we do this:
dd if=Armbian_5.20_Orangepipc_Debian_jessie_3.4.112.img of=/dev/sdc bs=32M
46+1 records in
46+1 records out
1562378240 bytes (1.6 GB, 1.5 GiB) copied, 185.603 s, 8.4 MB/s
 -- unplug and replug card
mount /dev/sdc1 /mnt
cd /mnt
mv boot boot_ORIG
mkdir boot
This ought to confuse U-boot enough so that it drops into its prompt, but interestingly enough, it drops into a network boot scenario. It does give a short countdown where I can hit any key.
U-Boot SPL 2016.09-armbian (Sep 15 2016 - 07:28:57)
DRAM: 1024 MiB
Trying to boot from MMC1


U-Boot 2016.09-armbian (Sep 15 2016 - 07:28:57 +0200) Allwinner Technology

CPU:   Allwinner H3 (SUN8I 1680)
Model: Xunlong Orange Pi PC
I2C:   ready
DRAM:  1 GiB
MMC:   SUNXI SD/MMC: 0
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   phy interface0
eth0: ethernet@1c30000
Hit any key to stop autoboot:  0 
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
starting USB...
USB0:   USB EHCI 1.00
USB1:   USB OHCI 1.0
USB2:   USB EHCI 1.00
USB3:   USB OHCI 1.0
USB4:   USB EHCI 1.00
USB5:   USB OHCI 1.0
scanning bus 0 for devices... 1 USB Device(s) found
scanning bus 2 for devices... 1 USB Device(s) found
scanning bus 4 for devices... 1 USB Device(s) found

USB device 0: unknown device
BOOTP broadcast 1
BOOTP broadcast 2
BOOTP broadcast 3
BOOTP broadcast 4
DHCP client bound to address 192.168.0.69 (2268 ms)
*** Warning: no boot file name; using 'C0A80045.img'
Using ethernet@1c30000 device
TFTP from server 192.168.0.1; our IP address is 192.168.0.69
Filename 'C0A80045.img'.
Load address: 0x42000000
Loading: T T T 
Abort
missing environment variable: pxeuuid
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/01-02-20-26-57-ac-37
Using ethernet@1c30000 device
TFTP from server 192.168.0.1; our IP address is 192.168.0.69
Filename 'pxelinux.cfg/01-02-20-26-57-ac-37'.
Load address: 0x43200000
Indeed, getting to the prompt is not that hard, just cycle power and immediately start typing on the keyboard:
U-Boot SPL 2016.09-armbian (Sep 15 2016 - 07:28:57)
DRAM: 1024 MiB
Trying to boot from MMC1

U-Boot 2016.09-armbian (Sep 15 2016 - 07:28:57 +0200) Allwinner Technology

CPU:   Allwinner H3 (SUN8I 1680)
Model: Xunlong Orange Pi PC
I2C:   ready
DRAM:  1 GiB
MMC:   SUNXI SD/MMC: 0
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   phy interface0
eth0: ethernet@1c30000
Hit any key to stop autoboot:  0 

=>       
=> printenv
arch=arm
baudrate=115200
board=sunxi
board_name=sunxi
boot_a_script=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr}
boot_efi_binary=load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} efi/boot/bootarm.efi; if fdt addr ${fdt_addr_r}; then bootefi ${kernel_addr_r} ${fdt_addr_r};else bootefi ${kernel_addr_r} ${fdtcontroladdr};fi
boot_extlinux=sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}extlinux/extlinux.conf
boot_net_usb_start=usb start
boot_prefixes=/ /boot/
boot_script_dhcp=boot.scr.uimg
boot_scripts=boot.scr.uimg boot.scr
boot_targets=fel mmc0 usb0 pxe dhcp 
bootcmd=run distro_bootcmd
bootcmd_dhcp=run boot_net_usb_start; if dhcp ${scriptaddr} ${boot_script_dhcp}; then source ${scriptaddr}; fi;setenv efi_fdtfile ${fdtfile}; if test -z "${fdtfile}" -a -n "${soc}"; then setenv efi_fdtfile ${soc}-${board}${boardver}.dtb; fi; setenv efi_old_vci ${bootp_vci};setenv efi_old_arch ${bootp_arch};setenv bootp_vci PXEClient:Arch:00010:UNDI:003000;setenv bootp_arch 0xa;if dhcp ${kernel_addr_r}; then tftpboot ${fdt_addr_r} dtb/${efi_fdtfile};if fdt addr ${fdt_addr_r}; then bootefi ${kernel_addr_r} ${fdt_addr_r}; else bootefi ${kernel_addr_r} ${fdtcontroladdr};fi;fi;setenv bootp_vci ${efi_old_vci};setenv bootp_arch ${efi_old_arch};setenv efi_fdtfile;setenv efi_old_arch;setenv efi_old_vci;
bootcmd_fel=if test -n ${fel_booted} && test -n ${fel_scriptaddr}; then echo '(FEL boot)'; source ${fel_scriptaddr}; fi
bootcmd_mmc0=setenv devnum 0; run mmc_boot
bootcmd_pxe=run boot_net_usb_start; dhcp; if pxe get; then pxe boot; fi
bootcmd_sunxi_compat=setenv root /dev/mmcblk0p3 rootwait; if ext2load mmc 0 0x44000000 uEnv.txt; then echo Loaded environment from uEnv.txt; env import -t 0x44000000 ${filesize}; fi; setenv bootargs console=${console} root=${root} ${extraargs}; ext2load mmc 0 0x43000000 script.bin && ext2load mmc 0 0x48000000 uImage && bootm 0x48000000
bootcmd_usb0=setenv devnum 0; run usb_boot
bootdelay=2
bootm_size=0xa000000
console=ttyS0,115200
cpu=armv7
dfu_alt_info_ram=kernel ram 0x42000000 0x1000000;fdt ram 0x43000000 0x100000;ramdisk ram 0x43300000 0x4000000
distro_bootcmd=for target in ${boot_targets}; do run bootcmd_${target}; done
efi_dtb_prefixes=/ /dtb/ /dtb/current/
ethaddr=02:20:26:57:ac:37
fdt_addr_r=0x43000000
fdtcontroladdr=7bf3df28
fdtfile=sun8i-h3-orangepi-pc.dtb
kernel_addr_r=0x42000000
load_efi_dtb=load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${prefix}${efi_fdtfile}
mmc_boot=if mmc dev ${devnum}; then setenv devtype mmc; run scan_dev_for_boot_part; fi
pxefile_addr_r=0x43200000
ramdisk_addr_r=0x43300000
scan_dev_for_boot=echo Scanning ${devtype} ${devnum}:${distro_bootpart}...; for prefix in ${boot_prefixes}; do run scan_dev_for_extlinux; run scan_dev_for_scripts; done;run scan_dev_for_efi;
scan_dev_for_boot_part=part list ${devtype} ${devnum} -bootable devplist; env exists devplist || setenv devplist 1; for distro_bootpart in ${devplist}; do if fstype ${devtype} ${devnum}:${distro_bootpart} bootfstype; then run scan_dev_for_boot; fi; done
scan_dev_for_efi=setenv efi_fdtfile ${fdtfile}; if test -z "${fdtfile}" -a -n "${soc}"; then setenv efi_fdtfile ${soc}-${board}${boardver}.dtb; fi; for prefix in ${efi_dtb_prefixes}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${efi_fdtfile}; then run load_efi_dtb; fi;done;if test -e ${devtype} ${devnum}:${distro_bootpart} efi/boot/bootarm.efi; then echo Found EFI removable media binary efi/boot/bootarm.efi; run boot_efi_binary; echo EFI LOAD FAILED: continuing...; fi; setenv efi_fdtfile
scan_dev_for_extlinux=if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}extlinux/extlinux.conf; then echo Found ${prefix}extlinux/extlinux.conf; run boot_extlinux; echo SCRIPT FAILED: continuing...; fi
scan_dev_for_scripts=for script in ${boot_scripts}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${script}; then echo Found U-Boot script ${prefix}${script}; run boot_a_script; echo SCRIPT FAILED: continuing...; fi; done
scriptaddr=0x43100000
serial#=020046202657ac37
soc=sunxi
stderr=serial
stdin=serial
stdout=serial
usb_boot=usb start; if usb dev ${devnum}; then setenv devtype usb; run scan_dev_for_boot_part; fi

Environment size: 4358/131068 bytes

=> help
?       - alias for 'help'
base    - print or set address offset
bdinfo  - print Board Info structure
boot    - boot default, i.e., run 'bootcmd'
bootd   - boot default, i.e., run 'bootcmd'
bootefi - Boots an EFI payload from memory
bootelf - Boot from an ELF image in memory
bootm   - boot application image from memory
bootp   - boot image via network using BOOTP/TFTP protocol
bootvx  - Boot vxWorks from an ELF image
bootz   - boot Linux zImage image from memory
cmp     - memory compare
coninfo - print console devices and information
cp      - memory copy
crc32   - checksum calculation
dhcp    - boot image via network using DHCP/TFTP protocol
dm      - Driver model low level access
echo    - echo args to console
editenv - edit environment variable
env     - environment handling commands
exit    - exit script
ext2load- load binary file from a Ext2 filesystem
ext2ls  - list files in a directory (default /)
ext4load- load binary file from a Ext4 filesystem
ext4ls  - list files in a directory (default /)
ext4size- determine a file's size
false   - do nothing, unsuccessfully
fatinfo - print information about filesystem
fatload - load binary file from a dos filesystem
fatls   - list files in a directory (default /)
fatsize - determine a file's size
fatwrite- write file into a dos filesystem
fdt     - flattened device tree utility commands
fstype  - Look up a filesystem type
go      - start application at address 'addr'
gpio    - query and control gpio pins
help    - print command description/usage
i2c     - I2C sub-system
iminfo  - print header information for application image
imxtract- extract a part of a multi-image
itest   - return true/false on integer compare
load    - load binary file from a filesystem
loadb   - load binary file over serial line (kermit mode)
loads   - load S-Record file over serial line
loadx   - load binary file over serial line (xmodem mode)
loady   - load binary file over serial line (ymodem mode)
loop    - infinite loop on address range
ls      - list files in a directory (default /)
md      - memory display
mdio    - MDIO utility commands
mii     - MII utility commands
mm      - memory modify (auto-incrementing address)
mmc     - MMC sub system
mmcinfo - display MMC info
mw      - memory write (fill)
nfs     - boot image via network using NFS protocol
nm      - memory modify (constant address)
part    - disk partition related commands
ping    - send ICMP ECHO_REQUEST to network host
printenv- print environment variables
pxe     - commands to get and boot from pxe files
reset   - Perform RESET of the CPU
run     - run commands in an environment variable
save    - save file to a filesystem
saveenv - save environment variables to persistent storage
setenv  - set environment variables
setexpr - set environment variable as the result of eval expression
showvar - print local hushshell variables
size    - determine a file's size
sleep   - delay execution for some time
source  - run script from memory
sysboot - command to get and boot from syslinux files
test    - minimal test like /bin/sh
tftpboot- boot image via network using TFTP protocol
true    - do nothing, successfully
usb     - USB sub-system
usbboot - boot from USB device
version - print monitor, compiler and linker version
Getting the MAC address is a little problematic, but it is tucked away in the messages from the first boot:
Retrieving file: pxelinux.cfg/01-02-20-26-57-ac-37
Using the mac address, I add an entry to the /etc/dhcpd/dhcpd.conf file on my linux machine.
	    host orangepi {
		    hardware ethernet 02:20:26:57:ac:37;
		    fixed-address 192.168.0.69;
		    option host-name "orangepi";
		    server-name "trona";
		    filename "orange";
	    }
Issue the command "service dhcpd restart" and try again. U-boot picks up the "filename" entry which I set to "orange". I don't have a file there yet by that name.

In passing, I will note that its default is to construct the filename "C0A80045.img", where this is the IP address 192.168.0.69 in hexadecimal.

DHCP client bound to address 192.168.0.69 (4 ms)
Using ethernet@1c30000 device
TFTP from server 192.168.0.5; our IP address is 192.168.0.69
Filename 'orange'.
Load address: 0x42000000
Loading: *
TFTP error: 'File not found' (1)
I copy a file by this name into /var/lib/tftpboot and reboot the orange pi. I will note that U-boot has a "reset" command this is just the thing for this. Now I get the following:
DHCP client bound to address 192.168.0.69 (4 ms)
Using ethernet@1c30000 device
TFTP from server 192.168.0.5; our IP address is 192.168.0.69
Filename 'orange'.
Load address: 0x42000000
Loading: ###########
	 904.3 KiB/s
done
Bytes transferred = 158396 (26abc hex)
CACHE: Misaligned operation at range [42000000, 42026abc]
## Executing script at 43100000
Wrong image format for "source" command
This is success! The size of the file I copied is indeed 158396 bytes.
-rwxr-xr-x 1 root root 158396 Dec  9 17:20 orange
My file contains a program for an entirely different boards, so we can expect unpredicatable results. After this failure, U-boot attempts to source whatever might be at address 0x43100000, then tries loading a list of alternate executables, as follows (but loading them to 0x43200000 not 0x42000000):
Retrieving file: pxelinux.cfg/01-02-20-26-57-ac-37
Retrieving file: pxelinux.cfg/C0A80045
Retrieving file: pxelinux.cfg/C0A8004
Retrieving file: pxelinux.cfg/C0A800
Retrieving file: pxelinux.cfg/C0A80
Retrieving file: pxelinux.cfg/C0A8
Retrieving file: pxelinux.cfg/C0A
Retrieving file: pxelinux.cfg/C0
Retrieving file: pxelinux.cfg/C
Retrieving file: pxelinux.cfg/default-arm-sunxi
Retrieving file: pxelinux.cfg/default-arm
Retrieving file: pxelinux.cfg/default
Even after building an ARM binary with a single instruction (branch to self), I get:
TFTP from server 192.168.0.5; our IP address is 192.168.0.69
Filename 'orange'.
Load address: 0x42000000
Loading: #
     2 KiB/s
done
Bytes transferred = 4 (4 hex)
CACHE: Misaligned operation at range [42000000, 42000004]
....
....
## Starting EFI application at 0x42000000 ...
efi_load_pe: Invalid DOS Signature
## Application terminated, r = -2
It looks like the CACHE alignment message is just a warning I can ignore, but this business about an invalid DOS Signature is the real issue.

Look for a file "pe.h" with contents like:

typedef struct _IMAGE_DOS_HEADER {
	uint16_t e_magic;      /* 00: MZ Header signature */
	uint16_t e_cblp;       /* 02: Bytes on last page of file */
	uint16_t e_cp;         /* 04: Pages in file */
	uint16_t e_crlc;       /* 06: Relocations */
	uint16_t e_cparhdr;    /* 08: Size of header in paragraphs */
	uint16_t e_minalloc;   /* 0a: Minimum extra paragraphs needed */
	uint16_t e_maxalloc;   /* 0c: Maximum extra paragraphs needed */
	uint16_t e_ss;         /* 0e: Initial (relative) SS value */
	uint16_t e_sp;         /* 10: Initial SP value */
	uint16_t e_csum;       /* 12: Checksum */
	uint16_t e_ip;         /* 14: Initial IP value */
	uint16_t e_cs;         /* 16: Initial (relative) CS value */
	uint16_t e_lfarlc;     /* 18: File address of relocation table */
	uint16_t e_ovno;       /* 1a: Overlay number */
	uint16_t e_res[4];     /* 1c: Reserved words */
	uint16_t e_oemid;      /* 24: OEM identifier (for e_oeminfo) */
	uint16_t e_oeminfo;    /* 26: OEM information; e_oemid specific */
	uint16_t e_res2[10];   /* 28: Reserved words */
	uint32_t e_lfanew;     /* 3c: Offset to extended header */
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

#define IMAGE_DOS_SIGNATURE		0x5A4D     /* MZ   */
#define IMAGE_NT_SIGNATURE		0x00004550 /* PE00 */

#define IMAGE_FILE_MACHINE_ARM		0x01c0
#define IMAGE_FILE_MACHINE_THUMB	0x01c2
#define IMAGE_FILE_MACHINE_ARMNT	0x01c4
#define IMAGE_FILE_MACHINE_AMD64	0x8664
#define IMAGE_FILE_MACHINE_ARM64	0xaa64
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC	0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC	0x20b
#define IMAGE_SUBSYSTEM_EFI_APPLICATION	10
Actually, the thing to do is find the U-boot sources and/or find a way to just override the U-boot bootcmd so it does something more reasonable.

Looking at the U-boot setup, I don't think it will actually load uEnv.txt, so I really have no alternative besides rebuilding U-boot.


Have any comments? Questions? Drop me a line!

Tom's electronics pages / tom@mmto.org