DIY Fully working Alpine Linux for Allwinner and Other ARM SOCs

From Alpine Linux
Revision as of 13:56, 10 April 2016 by Atlury (talk | contribs)

This is taken from multiple sources and is copyright of the respective authors, albiet copied shamelessly. If you are an author of a particular section and wish to be listed please dont hesitate to contact me at oneinsect@gmail.com

Please note that most of is specific to Orange Pi PC and Nanopi m1 but can be extended to any SOC with understanding

Nanopi m1 and Orange Pi PC are very similar except for 512MB more RAM in Orange Pi PC, they have almost similar specifications (USBs, Ethernet, I/Os etc)

Comprehensive Introduction

Why do we need alpine linux when there are so many xyz distros available? Well it is one the most lightweight platforms with hot swap support for SD-cards and USB devices. There are options for allocation of SD-card free space for application storage.

There are possibilities to completely upgrade a device running remotely with minimum downtime. Console logins are possible with USB null modems for field servicing. Most importantly you can be rest assured that it can survive against power cuts, restarts. For devices without onboard mmc, especially working on sd-card its way more important.

The philosophy of commit only when required, keeps the entire OS read-only and in-memory without touching the storage at all. Thus devices can survive for longer times without crash.

Arm devices unlike x86 dont come with bios in general. BIOS in x86 PCs is generally, a firmware configuring and connecting the hardware to the operating system and it offers support for a variety of OS and supports new OS versions.

ARM use a different approach involving a boot loader for hardware configuration and operating system start-up. The boot loader is developed specifically for the application, adapted to one well-defined hardware SOC configuration, one operating system and only one version of it, which means you cannot probably use it for other SOCs without significant changes.

We here generally talk about Allwinner especially H3 SOCs but you could probably apply this philosophy to other SOCs. The nanopi m1, Orange pi pc and Orange pi lite are only around $10 making them great home servers, firewalls for lowest possible cost.

A linux os cannot be started just like that on an ARM Device, without a small amount of machine specific code to initialize that system.

There are typically 4 stages involved in the ARM Device boot-up process

  • (stage 1) ROM - Reads from initialized persistent storage (selected by boot mode), loads SPL into internal Ram
  • (stage 2) SPL Loader - SPL once loaded does additional setup and loads from persistent storage bootloader (u-boot) into DDR RAM
  • (stage 3) U-boot - U-boot once loaded continues the processor setup and reads the Linux Kernel into DDR RAM
  • (stage 4) Kernel - Once Kernel is loaded, it boots Linux and initializes the user run time environment

Each stage adds functionality. It is important to note that SPL, U-Boot and the Linux Kernel are all statically linked to start running at specific locations from a memory map defined by the CPU. That memory map is nothing but a layout that defines where both internal memory and DDR are mapped to.

In here we are concerned with SD-Cards, and depending on how the SD card is connected, the location to where to write the data to can be different.

OKAY WAIT!!! WRITING DATA???

Dont be confused, yes you will need to compile from source the SPL Loader and write it to SD-Card in a particular way and then compile u-boot from source and write it in a particular and same goes for the rest. Otherwise how will you boot our favorite alpine linux?

But where do you get the sources? Generally if the SOC is supported in Linux (its called mainline) you can directly use the latest kernel, otherwise you will need to get the sources from the SOC manufacturer.

Below is a SD-CARD layout for typical Allwinner which generally combine U-boot with the SPL loader from block 8. This then loads initramfs etc.

"start" is a 1k-block number here. (Multiply it by two to get the corresponding sector number - assuming 512 byte sectors). This layout works generally for Linux Mainline Kernels 4.x and above

start size usage
0 8KB Unused, available for partition table
8 1024KB Initial SPL loader + u-boot (raw format preferred/vfat)
1024 till end vmlinuz + initramfs + modloop + dtb (format fat + enable boot flag)

Notice I have combined SPL with U-boot, it is now possible to generate a single file say "u-boot-sunxi-with-spl.bin"

Boot-loaders aka U-Boot

Let us being. The first is to understand U-boot.

Distros like alpine linux for that matter any linux do not need to manipulate any kind of bootloader-specific configuration data to indicate which storage device the system should boot from.

Distros simply need to copy the boot configuration files in an ext2/3/4 or FAT partition, mark the partition bootable (via the MBR bootable flag, or GPT legacy_bios_bootable attribute), and U-Boot (or any other bootloader) will find those boot files and execute them. This is conceptually identical to creating a grub2 configuration file on a desktop PC.

Note that in the absence of any partition that is explicitly marked bootable, U-Boot falls back to searching the first valid partition of a disk for boot configuration files. Other bootloaders are recommended to do the same, since I believe that partition table bootable flags aren't so commonly used outside the realm of x86 PCs.

U-Boot can also search for boot configuration files from a TFTP server. The standard format for boot configuration files is that of extlinux.conf, as handled by U-Boot's "syslinux" (disk) or "pxe boot" (network).

U-Boot searches for /extlinux/extlinux.conf then /boot/extlinux/extlinux.conf on disk, or pxelinux.cfg/default over the network.

One example extlinux.conf generated by the Alpine Linux installer is:


 LABEL grsec
 MENU DEFAULT
 MENU LABEL Linux grsec
 LINUX /boot/vmlinuz-grsec
 INITRD /boot/initramfs-grsec
 DEVICETREEDIR /boot/dtbs
 APPEND BOOT_IMAGE=/boot/vmlinuz-grsec modules=loop,squashfs,sd-mod,usb-storage modloop=/boot/modloop-grsec console=${console}

Another example extlinux.conf is:


 LABEL Linux Mailine 4.6RC2
 LINUX /boot/vmlinuz-4.6.0-rc1-sunxi
 INITRD /boot/initramfs-new.uImage
 FDT /boot/sun8i-h3-orangepi-pc.dtb
 APPEND BOOT_IMAGE=/boot/vmlinuz-4.6.0-rc1-sunxi modules=loop,squashfs,sd-mod,usb-storage modloop=/boot/modloop-sunxi console=${console}

What to compile

What are you basically looking for? What files do you need to compile, how and where do you need to compile from? And where do you need to put them? How do you need to put them? Well dont worry we will cover them here.

You will need the following files (incase of mainline or 4.x latest kernels incase your SOC is supported - In our case yes Allwinner H3)


  • U-boot bootloader (aka u-boot-sunxi-with-spl.bin file say for Orange pi pc Allwinner H3) - compiled separately
  • Device specific .dtb file (in here called sun8i-h3-orangepi-pc.dtb) generated as part of your mainline kernel compilation
  • Linux Kernel Image either uImage/zImage (In our case zImage called vmlinuz-4.6-rc1-sunxi)
  • Initramfs file (what is it? you will learn as we progress)
  • modloop file (what is it again? you will learn as we progress)
  • boot.scr or extlinux.conf file for telling U-boot where to find all our files

Incase of legacy kernels (3.x etc) you will need the following which we will not cover here


  • uImage (linux kernel)
  • script.bin (converted from fex format, notice we dont talk about dtb files here)
  • ext4/ext3 rootfs file system
  • U-boot bootloader etc

Let us write to the SD-Card, I will assume here you already have compiled you kernel, u-boot and move forward. Dont worry we will come back to it at the last.

When we need to actually put things on the SD card, be careful with dd it can and will wipe your hard disk if you make a mistake. In my case I had an SD card reader so I set things to point at that slot only by using the by-id links from udev. These by-id links which include the serial number which helped to avoid mistakes. The following commands assume you have done the same and are using by-id links.

How to burn to SD Card

In linux blank the first 1MB of the card using the following (my sd-card is /dev/sda1

  • dd if=/dev/zero of=/dev/sda bs=1M count=1

But you need to be careful when using dd on special files (i.e., devices).

For example, the below command will write one tape block of 1024 bytes;

  • dd if=(whatever input) of=(a magnetic tape device) bs=1024 count=1

However, the below command will write 1024 small blocks of one byte each

  • dd if=(whatever input) of=(a magnetic tape device) bs=1 count=1024

These are not the same; the 1024 small blocks will take up more room on the tape than the one large block, because of inter-record gaps, and may cause problems for reading the tape.

Now Assuming you have got the file u-boot-sunxi-with-spl.bin, it just has to be burned to sd card using the following command:

  • dd if=u-boot-sunxi-with-spl.bin of=/dev/sda bs=1024 seek=8

Sometimes depending on you compile you can generate spl and u-boot separately (it is not recommended by me) you can install the components separately using

  • dd if=spl/sunxi-spl.bin of=/dev/sda bs=1024 seek=8
  • dd if=u-boot.img of=/dev/sda bs=1024 seek=40

Please note, if you are using old source (v2013.07 or earlier, then the procedure is slightly different)

  • dd if=spl/sunxi-spl.bin of=/dev/sdX bs=1024 seek=8
  • dd if=u-boot.bin of=/dev/sdX bs=1024 seek=32

Typically for understanding, this is how the layout for SD-Card in above cases is;

start size usage
0 8KB Unused, available for partition table etc.
8 32KB Initial SPL loader (8 to 24KB prior to 2013.07 and earlier)
40 504KB U-Boot (32KB to 512KB for 2013.07 and earlier)
544 128KB environment
672 352KB reserved
1024 - Free for partitions

Remember to leave sufficient space for all u-boot files when partitioning the card. The u-boot will not have any partition type defined. Recommended to have first fat partition start at sector 2048 (1MB)

  • Next Using fdisk, create a new primary partition on the card (so far there are no partitions, only uboot has been burned on the card), set the starting sector of the card as 2048
  • Using fdisk, set the bootable flag of the partition

When setting the bootable flag of the partition, to create a FAT32 partition, if you are using fdisk, the FAT32 partition type is called W95 FAT32 (LBA) and its ID is 0xc

  • Now install fat file system on the newly created partition by running mkfs.fat /dev/sda1

Please note that with recent U-Boot it's fine to use ext2/ext3/ext4 as boot partition, or as in our case fat file-systems in the any partition.


There is debug serial port which you can use to connect to PC using putty set @ 115200 kbps. You should able to watch the following.

U-Boot SPL 2016.03-armbian (Apr 08 2016 - 01:09:18)
DRAM: 512 MiB
Failed to set core voltage! Can't set CPU frequency
Trying to boot from MMC1
U-Boot 2016.03-armbian (Apr 08 2016 - 01:09:18 +0530) Allwinner Technology
CPU:   Allwinner H3 (SUN8I 1680)
Model: Xunlong Orange Pi PC
I2C:   ready
DRAM:  512 MiB
MMC:   SUNXI SD/MMC: 0
*** Warning - bad CRC, using default environment
In:    serial
Out:   serial
Err:   serial
Net:   No ethernet found.
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
Hit any key to stop autoboot:  0
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
Found /boot/extlinux/extlinux.conf
Retrieving file: /boot/extlinux/extlinux.conf
reading /boot/extlinux/extlinux.conf
232 bytes read in 29 ms (7.8 KiB/s)
1:      Linux Mailine 4.6RC2
Retrieving file: /boot/uinitrd
reading /boot/uinitrd
 **Unable to read file /boot/uinitrd
 for failure retrieving initrd
SCRIPT FAILED: continuing...
USB device 0: unknown device
No ethernet found.
missing environment variable: pxeuuid
Retrieving file: /boot/extlinux/pxelinux.cfg/00000000
No ethernet found.
Retrieving file: /boot/extlinux/pxelinux.cfg/0000000
No ethernet found.
Retrieving file: /boot/extlinux/pxelinux.cfg/000000
No ethernet found.
Retrieving file: /boot/extlinux/pxelinux.cfg/00000
No ethernet found.
Retrieving file: /boot/extlinux/pxelinux.cfg/0000
No ethernet found.
Retrieving file: /boot/extlinux/pxelinux.cfg/000
No ethernet found.
Retrieving file: /boot/extlinux/pxelinux.cfg/00
No ethernet found.
Retrieving file: /boot/extlinux/pxelinux.cfg/0
No ethernet found.
Retrieving file: /boot/extlinux/pxelinux.cfg/default-arm-sunxi
No ethernet found.
Retrieving file: /boot/extlinux/pxelinux.cfg/default-arm
No ethernet found.
Retrieving file: /boot/extlinux/pxelinux.cfg/default
No ethernet found.
Config file not found
No ethernet found.
=>

Next step would require simply copying the required files like boot configuration files, kernels etc in the above FAT partition (note there is only one FAT partition and it is marked as bootable and U-Boot (or any other bootloader) will find those boot files and execute them.

  • Assuming you have compiled vmlinuz-4.6.0-rc1-sunxi, you can create directory called /boot in the micro-sd fat partition and copy it there.

  • Similarly create another folder called /dtbs and copy the corresponding sun8i-h3-orangepi-pc.dtb file


  • fatls mmc 0:1 boot