Steps to first boot
To boot the system, you will need:
- Boot loader
For boot loader, we will use u-boot. There is a version of u-boot customised to boot A10 SoC, we will get it from https://github.com/linux-sunxi/u-boot-sunxi
We will use Linux kernel customised for A10 SoC, from https://github.com/linux-sunxi/linux-sunxi
- Root filesystem
We will use Busybox as the root filesystem.
All of the above are source packages; we need to build them. The tools required to build them are:
We will need a cross-compiler which runs on x86_64 and generates code for ARM. We will use two cross-compilers:
- Linaro cross compiler (https://launchpad.net/linaro-toolchain-binaries/+download)
specifically this one: https://launchpad.net/linaro-toolchain-binaries/trunk/2013.04/+download/gcc-linaro-arm-linux-gnueabihf-4.7-2013.04-20130415_linux.tar.xz
This compiler will be used to build the boot loader and the kernel.
- Aboriginal cross compiler (http://www.landley.net/aboriginal/downloads/binaries/)
specifically this one: http://www.landley.net/aboriginal/downloads/binaries/cross-compiler-armv6l.tar.bz2
This compiler will be used to build busybox.
- Board configuration
A SoC is a versatile device and can be configured in many different ways. Every manufacturer that builds a system out of an SoC (tablet vendor, settop boxes, router, etc) most likely configure the hardware to run differently (e.g the RAM address could be in a different location, the serial ports may be connected to different devices, etc).
To be able to boot on the system, we need to know exactly how the system was configured by the manufacturer: it is not enough just to know the CPU and the RAM; and this is where the "board configuration" comes into play. We will get ours from https://github.com/linux-sunxi/sunxi-boards
- Sunxi-tools The board configuration above is given in text format. We need to convert them before they can be used - thus the need for this tool. This tool also contains other useful tools too. It is available from https://github.com/linux-sunxi/sunxi-tools
We will also need Fatdog's devx package (obviously) and 32-bit SFS package as the Linaro compiler above can only run on 32-bit operating system.
Early success is important, because it provides confirmation that we are on the right path, and encouragement to explore further.
Using ready-made compilers known to work ensure that we focus on the system development process instead of tool development process. In later phases we will show how the tools get prepared.
Preparing the tools
1. Extract the two compilers anywhere, for the sake of discussion let's say that you extract linaro's one in /path/to/linaro (so that /path/to/linaro/bin will contain the binaries), and aboriginal's one in /path/to/abo (again, with the binaries in /path/to/abo/bin).
2. Add both compilers to your path:
3. Load Fatdog's devx and the 32-bit SFS (Linaro's compiler requires it).
4. Build sunxi-tools - just run "
make" in sunxi-tools directory.
Preparation done, we're good to do the actual build.
Building the boot-loader
Next, we build the boot loader (u-boot). We have to use Linaro's compiler (gcc 4.7) because aboriginal's one (gcc 4.2.1) will not compile it; is too old.
cd /path/to/u-boot-sunxi make mele_a1000 CROSS_COMPILE=arm-linux-gnueabihf- cp tools/mkimage to /usr/bin
Building the kernel
Next, we build the boot loader. As with u-boot, we need to use Linaro's tool here for the reason (aboriginal's compiler cannot build armv7 code).
cd /path/to/linux-sunxi git checkout origin/sunxi-3.0 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- sun4i_defconfig make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j5 uImage modules make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules_install INSTALL_MOD_PATH=output
While the kernel is compiling, you may want to start building
This is a hardware configuration file that the kernel will later use to
initialise and configure the devices on the A10 SoC.
In newer kernels, this file is replaced with "device tree", but since we're
using the default 3.0 kernel, we still need this.
There is no BIOS in the ARM (or any other embedded) system, thus all the hard work must be done by the boot loader and the kernel - mostly the kernel.
The use of script.bin and/or device-tree is considered as a major advancement in Linux kernel development as it separates the board-specific settings from architecture-specific settings (e.g the same A10 SoC may be made into two different boards - one for tablets, one for settop boxes), and it enables one generic kernel to be used on different boards, by providing a separate configuration file for each.
The configuration settings for many A10-based boards are kept in sunxi-boards. They are stored in human readable form (called *fex* format), which must be converted into a binary format usable by the format. That's what the tools in sunxi-tools are for.
For my development system:
cd /path/to/sunxi-boards cd sys_config cd a10 cp mele_a1000.fex myconfig.fex geany myconfig.fex (see below) /path/to/sunxi-tools/fex2bin myconfig.fex script.bin
Before you convert the file, there is one information which needs to be modified - the MAC address. This specified here would become the MAC address of the ethernet (and on some systems, the wireless LAN too). Edit the file, find the following sections, and change the MAC address to your original system's MAC address.
Change the zeros with your own MAC address (invent one if you don't know).
[dynamic] MAC = "000000000000"
You only need the shell applet to get a minimal boot. But that would get boring pretty quickly, as you can't do much with it. I suggest you enable a more applets.
The only caveat here is that busybox must be configured as static binary. Then build it like this:
cd /path/to/busybox-source make menuconfig make CROSS_COMPILE=armv6l-
We use aboriginal compiler so that our static binary is smaller.
Preparing SD Card
There are only three simple rules in preparing the SD Card. First, you need at least 2 partitions. Second, the first one must be FAT. Third, it has to start at last on 1MB boundary and at least 32MB big.
You can make the second partition anything that supports being a root filesystem for Linux, and its size can be anything depending on what you plan to put on it.
For me, I created 256 MB FAT partition and 32 MB ext4 partition (for I will need the space on the FAT partition much later; and the second partition can easily be extended if needed).
Installing boot loader
Once the SD card has been partitioned, install the boot loader.
/dev/sdXXX with the device that represents your
SD Card. If you specify the wrong device you can easily and permanently wipe
off the data from your disk, so be extra careful. You have been warned.
/dev/sdXXXX1 represents the first partition of /dev/sdXXX, we will mount it to /mnt/sdcard.
cd /path/to/u-boot-sunxi dd if=spl/sunxi-spl.bin of=/dev/sdXXX bs=1024 seek=8 dd if=u-boot.bin of=/dev/sdXXX bs=1024 seek=32 mount /dev/sdXXX1 /mnt/sdcard cp ./sunxi-boards/sys_config/a10/script.bin /mnt/sdcard
Configuring the boot loader
To configure the boot loader (tell it what kernel to load, what kernel
parameters to pass), you create a
boot.scr file (this is similar to
menu.lst or syslinux.conf, although much simpler - simply because there isn't
a simple way to access its full capabilities without a serial terminal).
Unlike syslinux.conf and menu.lst which are simple text files, boot.scr is a binary file which needs to be "compiled" from it source text file. The text file is commonly called boot.cmd although of course you can name it anything.
The u-boot-sunxi comes with default configuration (which can be changed by
recompiling it - it's inside
and will boot without boot.scr, but it is so much better to change the boot.scr
rather than rebuilding u-boot each time.
Create a file calld
boot.cmd somewhere. To make it easier, do it on
/mnt/sdcard itself (so you'll remember the boot.cmd that corresponds to
your boot.scr. Put the following entries in it:
fatload mmc 0 0x43000000 script.bin fatload mmc 0 0x48000000 uImage bootm 0x48000000
Then save the file, and convert it to boot.scr this way:
mkimage -C none -A arm -T script -d boot.cmd boot.scr
Copy boot.scr to /mnt/sdcard if you didn't create it there.
When done, create another file called uEnv.txt on /mnt/sdcard. This file contains "variables" which can be passed to boot.scr. Again, this file isn't strictly needed but since it is a regular text file (no conversion is necessary), it is handy to use to specify variables that we may want to change later. For now, we will only keep the variable "bootargs" which represents the command line to be passed to the kernel.
bootargs=console=tty0 root=/dev/mmcblk0p2 rootwait panic=10
which means, use
tty0 as the console (which will be the framebuffer
console, that is, your TV screen) as opposed to
ttyS0 which is the serial
console (which you can't see unless you attach an USB-to-serial to your
/dev/mmcblk0p2 as the root device (second partiton of your SD
card --- we don't use /dev/sdXXX2 because /dev/sdXXX2 is how we see it from
our system; when the kernel boots up this is how it will see the partition);
rootwait means wait as long as needed until the root device appears
(SD card can be slow to initialise), and the last one tells the kernel
to wait 10 seconds before automatically rebooting if it "panics".
setenv bootargs console=tty0 root=/dev/mmcblk0p2 rootwait panic=10
With the /dev/sdXXX1 still mounted on /mnt/sdcard, do:
cd /path/to/linux-sunxi cp arch/arm/boot/uImage
Preparing root filesystem
Umount /dev/sdXXX1, and mount /dev/sdXXX2 (this would be the second partition of the SD card). Let's assume it is mounted in /mnt/sdcard.
You need to create at least
/sbin. Put busybox
binaries in /bin and create the necessary applet links (at least shell is
needed), and create a shell script in /sbin/init, like this:
umount /mnt/sdcard mount /dev/sdXXX2 /mnt/sdcard cd /mnt/sdcard mkdir dev bin sbin cp /path/to/busybox-source/busybox bin/busybox ln -s busybox bin/sh touch sbin/init cat > sbin/init << EOF #!/bin/sh exec /bin/sh
If you wish to experiment with modules, copy all the modules from the kernel too (of course when you would need busybox to have module-utils too, otherwise there is no way to use them).
cp -a /path/to/linux-sunxi/output/lib .
Every SoC boot differently. The following is specific to A10 (and only in SD Card boot mode), so take this as an illustration rather than as a hard fact (I'm also simplifying things):
- A10 starts up and execute code in BROM (Boot ROM) - outside our control
- BROM loads spl.bin from block 8kb of SD Card (to address 0x20 in SRAM) and jumps to it
- spl.bin loads u-boot from block 32kb of SD Card (to address 0x4A000000 in DRAM) and jumps to it
- u-boot loads:
- Runs its internal script, which loads:
- uEnv.txt (setting values to variables)
- boot.scr, which will:
- Load kernel (uImage) at address 0x48000000
- Load script.bin (the hardware configuration) at address 0x43000000
- Parse and run any other commands
- Starts the kernel (bootm command)
- bootm relocates kernel from 0x48000000 to 0x40008000 (ZRELADDR) and starts executing virtual address 0xC0008000 (PAGE_OFFSET of 0xC0000000 and TEXT_BASE of 0x8000)
- Kernel (uImage) starts
- Read hardware config from 0x43000000 and initialise A10 SoC
- Kernel mounts the root filesystem (/dev/mmcblk0p2)
- Kernel launches /sbin/init
- /sbin/init launches our shell.
- Shell prompt
Our next step would be to compile AUFS-enabled kernel and see where and how we can load initrd.