DIY Fully working Alpine Linux for Allwinner and Other ARM SOCs: Difference between revisions

From Alpine Linux
No edit summary
No edit summary
Line 54: Line 54:
* (stage 3) U-boot - U-boot once loaded continues the processor setup and reads the Linux Kernel 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
* (stage 4) Kernel - Once Kernel is loaded, it boots Linux and initializes the user run time environment
The first stage of the boot process is the Secondary Program Loader (SPL). This preliminary piece of code is responsible for board initialization, loading the u-boot binary (“secondary program”) and handling the control flow over to the u-boot main program. It is device specific, and is often provided as a closed source binary blob by the SoC vendor.
The secondary program loader (SPL) and the u-boot binary reside in a special on-board flash memory region or on the first sectors of the uSD/eMMC card. ODROID devices use microSD or eMMC modules for storing the SPL and u-boot binary
At the second stage of the boot process, the u-boot main program is executed. U-boot first looks for a custom environment stored at a reserved space on the microSD or eMMC module, or falls back to the compile time default environment if needed. At this time, you can interrupt the automatic boot process by pressing a key on your serial console, which starts an interactive u-boot shell. The u-boot variable called bootdelay specifies the number of seconds to wait for a keypress before continuing automatic boot.
The automatic boot process executes a special u-boot macro, called bootcmd, which loads and executes the following procedures:
1. (opt.) a custom u-boot environment: uEnv.txt
2. (opt.) a precompiled u-boot macro: boot.scr
3. the kernel image, e.g. vmlinuz
4. (opt.) the device tree binary, e. g. .dtb
5. (opt.) the initial ramdisk, e. g. initramfs
The third stage is the loading of the Linux kernel. However, before the Linux kernel takes control, u-boot passes a command line to the kernel containing essential parameters. These parameters can be viewed after the operating system has booted by typing the following into a Terminal window:
$ cat /proc/cmdline
root=/dev/mmcblk0p2 rootwait rw console=ttyS0,115200n8 console=tty0 no_console_suspend vdaccfg=0xa000 logo=osd1,loaded,0x7900000,720p,full dmfc=3 cvbsmode=576cvbs hdmimode=1080p m_bpp=32 vout=hdmi disablehpd=true
The kernel initializes the hardware, mount the root filesystem (according to the root=... kernel parameter) and passes the control flow to /sbin/init.
The Linux kernel consists of the following components:
* Kernel image
  * 32 bit platform: <boot-partition>/zImage or <boot-partition>/uImage, depending on your u-boot's capabilities and configuration
  * 64 bit platform: <boot-partition>/Image
* Device tree binary, a low level device description, specific to your device (<boot-partition>/<board>.dtb)
* Kernel modules (/lib/modules/<kernel-version>/*)
* Device firmware (/lib/firmware/*)
* Kernel C header files (/usr/include/linux)
These components are build out of the kernel sources with the help of the make utility. Usually the kernel image and the device tree binary are loaded from a small vfat boot partition (mounted as /boot or /media/boot), whereas the rest resides in the root file system.
However for our case here, we will have one raw u-boot sector followed by a large fat partition


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.  
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.  
Line 129: Line 164:
* modloop file (what is it again? 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 from and how to find and load all above files into memory
* boot.scr or extlinux.conf file for telling U-boot where from and how to find and load all above files into memory
'''Note that we will be using boot.scr going forward instead of extlinux.conf, u-boot generally searches /boot.scr or /boot/boot.scr'''


Incase of legacy kernels (3.x etc) you will need the following which we will not cover here
Incase of legacy kernels (3.x etc) you will need the following which we will not cover here
Line 339: Line 376:
and under /boot directory, the following
and under /boot directory, the following
* /boot/dtbs/sun8i-h3-orangepi-pc.dtb
* /boot/dtbs/sun8i-h3-orangepi-pc.dtb
* /boot/extlinux/extlinux.conf
* /boot/boot.scr
* /boot/initramfs-new
* /boot/initramfs-new
* /boot/modloop-sunxi
* /boot/modloop-sunxi
Line 409: Line 446:
After the build succeeds, you can find the modules in the supplied INSTALL_MOD_PATH directory.
After the build succeeds, you can find the modules in the supplied INSTALL_MOD_PATH directory.


Armbian has an easy way of compiling kernel as well (just incase).
Armbian has an easy way of compiling kernel as well (just incase), so look below:
 
 
 
 




Line 421: Line 462:


But many distributions have to ship a binary kernel that should work on most, or even all, different combinations of hardware, storage, file-systems, etc. They can't obviously build all the possible modules into the kernel. So they ship a minimal, generic kernel, and use an initial RAM disk that contains most hardware modules and some logic to detect which modules need to be loaded to be able to continue to boot the system normally (ie from the hard drive).
But many distributions have to ship a binary kernel that should work on most, or even all, different combinations of hardware, storage, file-systems, etc. They can't obviously build all the possible modules into the kernel. So they ship a minimal, generic kernel, and use an initial RAM disk that contains most hardware modules and some logic to detect which modules need to be loaded to be able to continue to boot the system normally (ie from the hard drive).
An initramfs contains at least one file called /init. This file is executed by the kernel as the main init process (PID 1). It has to do all the work. In addition, there can be any number of additional files and directories that are required by /init. They are usually files you'll also find on any other root filesystem, such as /dev for device nodes, /proc for kernel information, /bin for binaries, and so on. The structure of an initramfs can be simple, or it can be complicated, depending on what you are planning to do.
When the kernel mounts the initramfs, your target root partition is not yet mounted, so you can't access any of your files. That means there is nothing but the initramfs. So everything you need, everything you want, you have to include it in your initramfs. If you want a shell, you have to include it in your initramfs. If you want to mount something, you need a mount utility. If you need to load a module, your initramfs has to provide both the module, as well as a utility to load it. If the utility depends on libraries in order to work, you have to include the libraries as well. This seems complicated, and it is, because the initramfs has to function independently.


This means that it's possible to boot the kernel, load some modules and run some tasks (from the RAM disk), and finally start the normal boot process (/sbin/init etc.).  
This means that it's possible to boot the kernel, load some modules and run some tasks (from the RAM disk), and finally start the normal boot process (/sbin/init etc.).  

Revision as of 18:04, 10 April 2016

WORK IN PROGRESS

This is taken from multiple sources and is copyright of the respective authors. If you are an author of a particular section and wish to be listed please dont hesitate to contact me at oneinsect@gmail.com. I hereby declare I have absolutely no rights over this material and in due course of time, you will find proper references. No time at the moment

You can also contact me at atlury@gmail.com

Prologue

  • Please note that most of the below is specific to Nanopi m1 but can be extended to any ARM 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)

Sometimes these SOCs are always being fed with constant 1.3V, like NANO Pi m1 in this case or an Orange PI One. An Orange Pi PC however has programable voltage generator and will reduce voltage.

Primitive voltage regulator feed the H3 all the time with 1.3V in some boards. In this mode throttling is rather inefficient since temperatures do not decrease that much when only clockspeed will be reduced. Therefore expect severe performance problems unless you choose to apply a large heatsink and an additional fan.

Sometimes you have to modify your dts file if your board has a fixed voltage regulator to limit the temperature and prevent the board from completing burning out when you are not using a heat-sink. However I would suggest you use some kind of passive/active cooling for H3 boards.

At the time of writing this article the Nanopi M1 still doesnt have its own .dtb file, hence we use a similar board .dtb file (Orange Pi PC).

You are free to try legacy kernels and the process may vary a bit, please linux-sunxi.org for more information and similar sites.

Infact your SOC may not be supported by mainline kernel itself, however you can still use alpine linux.

Lot of people are writing various .dtb files for example below is mainline kernel dts configuration for passive cooling of h3 based boards with fixed voltage regulator

https://github.com/megous/linux/wiki/Fixed-voltage-regulator-test

Written for orange pi one, when treating it as if it had a fixed voltage regulator and it was limiting temperature to ~75°C during stress test. You are free to play around. The internet is huge. Hang out in the IRC channels.

There are work around for issue wherein display doesnt show up if you use DVI to HDMI converter etc. Suggest you use VGA to HDMI or play around with the settings of boot.scr

We expect as the Alpinelinux kernel versions progress further, you will be able to use Alpinelinux more directly without recompiling your own kernel, initramfs files 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

The first stage of the boot process is the Secondary Program Loader (SPL). This preliminary piece of code is responsible for board initialization, loading the u-boot binary (“secondary program”) and handling the control flow over to the u-boot main program. It is device specific, and is often provided as a closed source binary blob by the SoC vendor.

The secondary program loader (SPL) and the u-boot binary reside in a special on-board flash memory region or on the first sectors of the uSD/eMMC card. ODROID devices use microSD or eMMC modules for storing the SPL and u-boot binary

At the second stage of the boot process, the u-boot main program is executed. U-boot first looks for a custom environment stored at a reserved space on the microSD or eMMC module, or falls back to the compile time default environment if needed. At this time, you can interrupt the automatic boot process by pressing a key on your serial console, which starts an interactive u-boot shell. The u-boot variable called bootdelay specifies the number of seconds to wait for a keypress before continuing automatic boot.

The automatic boot process executes a special u-boot macro, called bootcmd, which loads and executes the following procedures:

1. (opt.) a custom u-boot environment: uEnv.txt
2. (opt.) a precompiled u-boot macro: boot.scr
3. the kernel image, e.g. vmlinuz
4. (opt.) the device tree binary, e. g. .dtb
5. (opt.) the initial ramdisk, e. g. initramfs

The third stage is the loading of the Linux kernel. However, before the Linux kernel takes control, u-boot passes a command line to the kernel containing essential parameters. These parameters can be viewed after the operating system has booted by typing the following into a Terminal window:

$ cat /proc/cmdline root=/dev/mmcblk0p2 rootwait rw console=ttyS0,115200n8 console=tty0 no_console_suspend vdaccfg=0xa000 logo=osd1,loaded,0x7900000,720p,full dmfc=3 cvbsmode=576cvbs hdmimode=1080p m_bpp=32 vout=hdmi disablehpd=true

The kernel initializes the hardware, mount the root filesystem (according to the root=... kernel parameter) and passes the control flow to /sbin/init.

The Linux kernel consists of the following components:

  • Kernel image
 * 32 bit platform: <boot-partition>/zImage or <boot-partition>/uImage, depending on your u-boot's capabilities and configuration
 * 64 bit platform: <boot-partition>/Image
  • Device tree binary, a low level device description, specific to your device (<boot-partition>/<board>.dtb)
  • Kernel modules (/lib/modules/<kernel-version>/*)
  • Device firmware (/lib/firmware/*)
  • Kernel C header files (/usr/include/linux)

These components are build out of the kernel sources with the help of the make utility. Usually the kernel image and the device tree binary are loaded from a small vfat boot partition (mounted as /boot or /media/boot), whereas the rest resides in the root file system.

However for our case here, we will have one raw u-boot sector followed by a large fat partition

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 + Alpine apks folder (format fat + enable boot flag)

Notice that while discussing above, I told there are generally four stages, I have infact combined SPL with U-boot and shown as one stage; indeed it is now possible to generate a single file say "u-boot-sunxi-with-spl.bin" while compiling.

And yes, you saw it right, the partition that holds vmlinuz eta al is actually fat and no we will NOT have any issues with symbolic links etc. Yes its not your typical rootfs.

The idea is that Alpinelinux beautifully loads and compresses into memory the entire OS and maintains it there, so aspects of symbolic links issues etc never come into picture, as the fat partition is never touched and whenever any changes occur and if and only they are committed, they are saved in a pre-compressed tar.gz archive, saved and loaded back on fly during the next boot

Boot-loaders aka U-Boot

Let us begin. 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 from and how to find and load all above files into memory

Note that we will be using boot.scr going forward instead of extlinux.conf, u-boot generally searches /boot.scr or /boot/boot.scr

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 if we have fex, we dont need dtb files here)
  • ext4/ext3 rootfs file system
  • U-boot bootloader etc

Let us write to the SD-Card, I will assume here that you already have compiled your kernel, u-boot and want to move forward. Dont worry we will come back to compiling sources 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 how 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
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.
=>

You can use the following to browser through the sd-card

  • fatls mmc 0:1 boot

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 a directory called /boot in the root of micro-sd fat partition and copy it there.

  • Similarly create another folder called /dtbs in the root of the micro-sd card and copy the corresponding sun8i-h3-orangepi-pc.dtb file
  • Similarly create boot.scr and copy it to the /boot folder

Basically while booting, U-boot will look for uEnv.txt or boot.scr in the first partition FAT or it will look for extlinux.conf. In here we will define boot.scr.

boot.scr contains needed uboot commands for loading kernel, initrd, setting kernel parameters and booting.

To create boot.scr first make a u-boot script boot.cmd with the u-boot commands you need for booting the system:

  • setenv fdt_high ffffffff
  • setenv machid 1029
  • setenv bootargs earlyprintk /boot/vmlinuz-4.6.0-rc1-sunxi modules=loop,squashfs,sd-mod,usb-storage modloop=/boot/modloop-sunxi console=${console}
  • load mmc 0:1 0x43000000 boot/dtbs/sun8i-h3-orangepi-pc.dtb
  • load mmc 0:1 0x41000000 boot/vmlinuz-4.6.0-rc1-sunxi
  • load mmc 0:1 0x45000000 boot/initramfs-new
  • bootz 0x41000000 0x45000000 0x43000000

Then translate this to a boot.scr by using the mkimage command

mkimage -C none -A arm -T script -d boot.cmd boot.scr

If you are using an older U-Boot (you shouldn't - Which?), you might require the following line, fdt_high ffffffff to keep the extracted kernel from overwriting the device tree configuration:

setenv is for setting flags in the u-boot environment

The bootm/bootz command is used to start operating system images. From the image header it gets information about the type of the operating system, the file compression method used (if any), the load and entry point addresses, etc. The command will then load the image to the required memory address, uncompressing it on the fly if necessary. Depending on the OS it will pass the required boot arguments and start the OS at it's entry point.

The first argument to bootm is the memory address (in RAM, ROM or flash memory) where the image is stored, followed by optional arguments that depend on the OS. Load is nothing but loading the file into the RAM location.

Linux requires the flattened device tree blob to be passed at boot time, and bootm expects its third argument to be the address of the blob in memory.

Second argument to bootm depends on whether an initrd initial ramdisk image is to be used. If the kernel should be booted without the initial ramdisk, the second argument should be given as "-", otherwise it is interpreted as the start address of initrd (in RAM, ROM or flash memory).

To boot a Linux kernel image without a initrd ramdisk image, the following command can be used:

=> bootm ${kernel_addr} - ${fdt_addr} If a ramdisk image shall be used, you can type:

=> bootm ${kernel_addr} ${ramdisk_addr} ${fdt_addr} Both examples of course imply that the variables used are set to correct addresses for a kernel, fdt blob and a initrd ramdisk image

bootm <Linux uImage address> <mkimage wrapped ramdisk address> <device tree (dtb) address>

With the bootm/bootz command, U-Boot is relocating the images before it boots Linux such that the addresses above may not be what the kernel sees. U-Boot also alters the device tree to tell the kernel where the ramdisk image is located in memory (initrd-start and initrd-end). The command sets the r2 register to the address of the device tree in memory which is not done by the go command.

  • Remember the console=${console} is important for you to interact with Alpinelinux once it boots
  • Instead of bootm, you use bootz
  • bootz basically starts a kernel image loaded at the given address in RAM along with other images
  • You could possibly use 0x42000000 for your vmlinuz
  • the setenv machid commands asks nanopi m1 to report itself as orange pi pc as we loading orange pi pc dtb and kernel
  • all the above commands can also be run via the u-boot prompt and examined via the serial debug port without compiling boot.cmd

People generally caution as below:

  • The new kernels have CMA enabled by default. CMA is trying to reserve 192MB of physically contiguous memory between physical addresses 0x43000000 and 0x50000000. Using specifically this address range is important because CedarX hardware can work only with the first 256MB of physical DRAM (the base physical address of DRAM is 0x40000000). Now if initrd is placed by u-boot somewhere in the middle of this memory area (cutting it into two halves), then CMA can't reserve physically contiguous 192MB memory block there anymore. So the reservation of the CMA memory area fails at boot time:
  • The solution for this problem is not to place initrd anywhere between 0x43000000 and 0x50000000
  • Make sure you also create and copy the files modloop-sunxi, initramfs-new to the /boot folder
  • Lastly copy the apks folder to the root of the sdcard

The apks folder can be extracted by downloading the Generic ARM Image from http://www.alpinelinux.org/downloads/

Your SD-Card will look as below.

  • /boot
  • /apks

and under /boot directory, the following

  • /boot/dtbs/sun8i-h3-orangepi-pc.dtb
  • /boot/boot.scr
  • /boot/initramfs-new
  • /boot/modloop-sunxi
  • /boot/vmlinuz-4.6.0-rc1-sunxi

DONT SCRATCH YOUR HEAD YET, WE WILL GET TO COMPILING ABOVE FILES slowly in the next sections

Compiling U-boot

You can follow this process or compile it along with Armbian kernel in the next section. Assuming below that you are building on an x64 bit ubuntu 14.04 LTS

Determine your build target aka your board. Go to your u-boot tree and search in the directory configs/ for your board, the file name looks like <board_name>_defconfig. So, if your device is orange pi pc your build target is orangepi_pc_defconfig

  • make CROSS_COMPILE=arm-linux-gnueabihf- <board_name>_defconfig
  • make CROSS_COMPILE=arm-linux-gnueabihf- menuconfig (optional in-case you want to play with menuconfig)
  • make CROSS_COMPILE=arm-linux-gnueabihf-

When compiling natively on ARM board, omit the CROSS_COMPILE=…

When the build is completed, there will be u-boot-sunxi-with-spl.bin available in your u-boot tree.

create a file boot.cmd and configure it as above.

Compiling Kernel with .dtb file

The first and foremost thing to compiling a kernel is to verify your SOC is supported by mainline linux kernel. The kernel must also have these options enabled and compiled in, instead of a module (better)

CONFIG_SQUASHFS=y The squashfs 4.0 in misc under filesystems
CONFIG_BLK_DEV_LOOP=y This is under "Device drivers" -> "Block devices" -> "Loopback device support"
  • [*]Enable loadable module support --->
  • Device Drivers --->Graphics support --->Frame buffer Devices --->[*]support for frame buffer devices --->[*]Simple framebuffer support
  • Device Drivers --->Graphics support --->Console display driver support --->[*]Framebuffer Console support

simplefb is a quick and easy way to get a display up on a HDMI monitor is to build U-Boot with sunxi cfb console support and Don't forget to change your console in your boot.cmd/boot.scr to console=tty1 to enable the simple framebuffer driver.

Pickup stable release

or pick up the sunxi-next branch maintained with all the inclusions that have been accepted, merged and will be included in the next stable release

  • make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- sunxi_defconfig
  • make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig (you want to include above squashfs and blk_dev_loop with menuconfig)

to build run the following and after the compilation ends, you should have generated both the zImage in arch/arm/boot, and a device tree blob (.dtb) in arch/arm/boot/dts.

  • ARCH=arm CROSS_COMPILE=<toolchain-prefix> make zImage dtbs

This device tree blob (or simply dtb) gives to the kernel the description of the hardware it's currently running on.

In device tree blob (dtb) goal, it's pretty similar to the FEX scripts that Allwinner uses, yet far more generic. Dont worry remember we shown fex files incase of legacy kernels (3.x etc) converted to script.bin.

Dtb allows to compile a single kernel image that will run on several platforms.

To identify the dtb file that you will use on your board, first look into arch/arm/boot/dts. You should see a whole bunch of them, most being irrelevant to us because targeting boards based on other ARM SoCs. All the sunxi dtb follow the pattern <family>-<soc>-<board>.dtb

If you have configured certain drivers as modules, you need to build and install these as well:

  • ARCH=arm CROSS_COMPILE=<toolchain-prefix> INSTALL_MOD_PATH=<any-path-you-like> make modules modules_install

After the build succeeds, you can find the modules in the supplied INSTALL_MOD_PATH directory.

Armbian has an easy way of compiling kernel as well (just incase), so look below:




add patches Alpinelinux is expected to have a bleeding edge release option soon along with LTS releases.

Creating Initramfs File

The purpose of initrd and initramfs (also known, generically, as "initial RAM disk") is similar: they contain a minimal root file-system, along with some scripts. When the kernel boots, if it is instructed to use an initrd or initramfs (done with boot loader configuration) it unpacks the file in RAM, chroot()s into it, and run some predefined scripts. Finally, the "real" root file system is mounted, the kernel switches to it and the normal init process can begin.

Why do we need an initial RAM disk in the first place? You're probably wondering this if you use to build your own kernel with the necessary modules for your hardware built-in. In that case, you almost never need an initial RAM disk.

But many distributions have to ship a binary kernel that should work on most, or even all, different combinations of hardware, storage, file-systems, etc. They can't obviously build all the possible modules into the kernel. So they ship a minimal, generic kernel, and use an initial RAM disk that contains most hardware modules and some logic to detect which modules need to be loaded to be able to continue to boot the system normally (ie from the hard drive).

An initramfs contains at least one file called /init. This file is executed by the kernel as the main init process (PID 1). It has to do all the work. In addition, there can be any number of additional files and directories that are required by /init. They are usually files you'll also find on any other root filesystem, such as /dev for device nodes, /proc for kernel information, /bin for binaries, and so on. The structure of an initramfs can be simple, or it can be complicated, depending on what you are planning to do.

When the kernel mounts the initramfs, your target root partition is not yet mounted, so you can't access any of your files. That means there is nothing but the initramfs. So everything you need, everything you want, you have to include it in your initramfs. If you want a shell, you have to include it in your initramfs. If you want to mount something, you need a mount utility. If you need to load a module, your initramfs has to provide both the module, as well as a utility to load it. If the utility depends on libraries in order to work, you have to include the libraries as well. This seems complicated, and it is, because the initramfs has to function independently.

This means that it's possible to boot the kernel, load some modules and run some tasks (from the RAM disk), and finally start the normal boot process (/sbin/init etc.).

The initial RAM disk must contain a fully functional file system, including some essential programs and libraries.

For space reasons, small footprint binaries are usually used (eg ash, busybox, or klibc).

Once the initial RAM disk's job is over and the kernel has switched to the real root file system, the memory used by the RAM disk is freed.

As briefly mentioned, there are two types of initial RAM disk: initrd and initramfs. The main difference is that an initrd contain a raw filesystem image (eg ext2), while an initramfs contains a cpio archive (which, when expanded, produces a directory hierarchy). Note that there are quite a few other differences, not mentioned here.

In both cases, the image file is compressed (typically with gzip) and the kernel expands and mount it. All the recent Linux distribution that use an initial RAM disk use an initramfs image. initrd is being used less and less. To check if the file you're interested in is an initrd or an initramfs, you can decompress it and feed it to file:

  • gunzip -c /boot/initrd-2.6 | file -

Output is as below and that file is a real initrd

/dev/stdin: Linux rev 1.0 ext2 filesystem data

Here's what you'd see with an initramfs:

  • gunzip -c /boot/initrams | file -

Note the output which says "SVR4 with no CRC" format which will be useful later.

/dev/stdin: ASCII cpio archive (SVR4 with no CRC)

Modify initramfs-grsec taken the Generic ARM Image of Alpinelinux


As said, an initramfs image is a compressed cpio archive, although the file name may sometimes be deceiving; sometimes it still has "initrd" in its name, and also many times it does not end in .gz or other suffixes that indicate compression:

  • file /boot/initrd.img-2.6.24-19-generic
/boot/initrd.img-2.6.24-19-generic: gzip compressed data, from Unix, last modified: Wed May 26 11:55:59 2010, max compression

Now cpio is an ancient (and a bit weird) archive format. When de-archiving, it needs to read the archive from standard input (GNU cpio also has a --file option to specify the file on the command line). The directory hierarchy is created in the current working directory. So:

  • mkdir temp
  • cd temp
  • gunzip -c /boot/initrd.img-2.6.24-19-generic | cpio -i
  • ls -l
total 36
drwxr-xr-x  2 root root 4096 2010-05-28 14:16 bin
drwxr-xr-x  3 root root 4096 2010-05-28 14:16 conf
drwxr-xr-x  6 root root 4096 2010-05-28 14:16 etc
-rwxr-xr-x  1 root root 3355 2010-05-28 14:16 init
drwxr-xr-x  5 root root 4096 2010-05-28 14:16 lib
drwxr-xr-x  2 root root 4096 2010-05-28 14:16 modules
drwxr-xr-x  2 root root 4096 2010-05-28 14:16 sbin
drwxr-xr-x 12 root root 4096 2010-05-28 14:16 scripts
drwxr-xr-x  3 root root 4096 2010-05-28 14:16 var

Now you can finally edit and change the contents at will (no space limitations, unlike initrd). When you're done, you have to recreate the compressed cpio archive. Again, cpio is a bit weird when archiving, because it wants to read the names of the files to archive on standard input (and writes the archive on standard output). So you can do as follows:

  • pwd
/root/temp
  • find . | cpio -H newc -o | gzip -9 > /boot/initrd.img-2.6.24-19-generic-NEW
34207 blocks

The only catch is that the -H newc option must be specified because the cpio archive contained in the initramfs has to be in the (new) "SVR4 with no CRC" portable format, as we saw at the beginning. In case you're wondering, cpio can create archives in other formats: bin, odc, crc, tar, ustar, hpbin, hpodc are those listed in the info page for GNU cpio.

Note that the construct

  • find . | something

is generally considered unsafe and to be avoided in shell scripting, because files could have newlines and control characters in them that could deceive the consumer of those filenames. This is generally not the case for filenames contained in an initramfs image, so it is "safe enough" to use here.

mkimage -n initramfs-grsec -A arm -O linux -T ramdisk -C none -d initramfs-grsec initramfs-new

Creating modloop File

The modloop file contains the folders like below...

  • /modules/4.6.0-rc1-sunxi
  • /modules/4.6.0-rc1-sunxi/kernel
  • /modules/4.6.0-rc1-sunxi/arch
  • /modules/firmware

If you run the following command on modloop-grsec or any other similar modloop file got from the Generic ARM Image of Alpinelinux

  • file modloop-grsec

You will realize, it outpus as

Squashfs filesystem, little endian, version 4.0, xzy bytes, xyz nodes, blocksize: xzy bytes, created...

You can create a "squashfs-temp" directory and create a sub-dir "modules" and then copy above required files concerning your particular kernel and you are good to go. Then just run the command below.

  • mksquashfs [source folder] [SquashFS target file] -b 1048576 -comp xz -Xdict-size 100%
  • mksquashfs squashfs-temp modloop-sunxi -b 1048576 -comp xz -Xdict-size 100%

Please understand that mksquashfs compresses using gzip (deflate) as default, but if the compression time doesn’t matter as much, you should use the xz (LZMA2) option of more recent SquashFS version. Yes please use xz.

The command above activates xz using the highest possible compression options and the highest possible blocksize (1 MiB instead of the default 128 kiB). Therefore the process of creating the SquashFS file is slower than if using default options, but the resulting file is much smaller and might be (depending on disk IO time etc) a bit faster. LZMA2 is a highly asymmetric compression algorithm, so decompression is much faster than compression

The command compresses the entire source folder into the SquashFS target file.

Make sure that the SquashFS target file doesn’t exist before using this command. If it already exists, mksquashfs tries to update it, but this might yield undesirable results (I didn’t check that, it probably only produces a lot of error messages but a valid output file)

You can mount the resulting file using this command (assuming the target folder exists and is empty):

  • mount [SquashFS file] [folder you want to mount it in]

If this command fails, you might need to specify some options explicitly:

  • mount -o loop -t squashfs [SquashFS file] [folder you want to mount it in]

If you want to auto-mount the SquashFS, you can also add an _/etc/fstab _entry like this:

  • [SquashFS file] [folder you want to mount it in] squashfs auto,defaults 0 0

Conclusion

Practice, read, ask, hang out in the forums, channels and that is how you can learn. Dont worry about people not responding, they are not being rude, some could be busy, the ones that aren't will respond, finally dont be shy, drop an email to the mailing list.