The Bootloader – Understanding, Modifying, Building and Installing

Once we have understood how our device boots up, we will then cover the technical aspects of how to flash our device. As in the boot sequence, the 3 main components that need to be transferred -“flashed”- to the board, are: The Bootloader, the Kernel and the OS (Android). We will cover them in different posts, starting here with The Bootloader.

As explained in the post explaining the boot sequence (here), the bootloader is the piece of software in charge of initializing most hardware components of our device and loading the kernel so that the system (OS) can start afterwards. The boot loader “knows” several things about the devices it is running on: Where to look for the different software components (kernel, OS, etc),  how the partition table and the MBR look like, or how to make a diagnosis of the board -hardware test- before trying to start the booting sequence  – among others. These capabilities vary from boot loader to boot loader, depending mainly on the commands and tools provided with it. In our case, we will use U-Boot. U-Boot is an universal boot loader for embedded systems, targeting different platforms including ARM. U-Boot, as any other boot loader can be installed in a boot ROM in order to carry out its labour [1] [2]. Sample features are [3]:

  • Serial Console Support
  • Integrated shell alike setup interface
  • Editable configuration space
  • Download software through tftp servers
  • Flash routines for EEPROMS
  • Run test applications directly
  • Load and boot up the kernel

Depending on the version, distribution and configuration of u-boot these features could change. The easiest way of checking which of them are available in our system is to access the u-boot console and check it. We will come back to this later in this same post. First, we will comment on how to build and flash u-boot as well as interesting files to make changes in.

U-Boot Source Code

One of the first things to check when we decide/have to deal with u-boot is to check which version we are running. In order to do this, check the Makefile (version and patchlevel). After this, check DENX’s documentation (here) to find out the available features.

Since u-boot is open source, we cane explore and modify the code to fulfil our needs. Most of the times, the features provided by u-boot are more than enough, nonetheless, here there is a list of interesting directories to check out.

  • Boards: In uboot/boards we can find the different boards supported by our version of u-boot – which will be the target platform when we build uboot. Boards are organized by fabricant/model, and once in the directory, we will find a C file (boardname.c) and several header files (headername.h) defining register addresses, pin layouts, clocks, etc. These files define the board itself and tell the compiler -when building uboot- and the boot loader itself which hardware components does the board count on and how they are wired. In case we want to port uboot to a new board, this is the place to start.
  • Partition Tables: When talking about the booting sequence, we mentioned that there were two types of partition tables: (i) the low partition table, which could be defined as a set of well-known addresses where the boot loader will look for software components (e.g. the kernel), and (ii) the partition table (as such) defined in the MBR and structuring the boot device space. It is indeed in the uboot code where these addresses are defined. Depending on the architecture and board, the size of the “partitions” and its starting address may vary. A “standard” path is: uboot/arch/$ARCH/include/asm/$BOARD/headerfile.h. As a example, the header file defining the partition tables for the Samsung’s Exynos 4 is located in: uboot/arm/include/asm/arch-exynos/movi_partition.h and it looks like:

  • Clocks and other early-stage initializations: Another intricate point when dealing when different boards and architectures is how to define the clocks, since the hardware components in each of them are different and therefore need of a low level piece of software (firmware) that tales care of this. Even when it will later on be the kernel the one taking control, it needs of the clocks -and other components0 to be set up. Therefore in a very early stage of the boot sequence, these components – clocks, voltages, pins, baud-rates, etc. – need to be considered. Once again, depending on the board and architecture the location of the file containing the code in charge of this may vary, and we will provide the files for the Samsung’s Exynos 4 as an example:
    • uboot/arch/arm/cpu/armv7/exynos/pmic_hkdk4210.c 
    • uboot/board/samsung/smdkv310/lowlevel_init.S
    • uboot/board/samsung/smdkv310/mem_setup.S
    • uboot/include/configs/smdkv310.h
    • uboot/board/samsung/smdkv310/smdkv310.c
  • Processor Special Modes: One of the parameters we can also play with during the booting sequence, is the processor modes (e.g. TrustZone, in compatible ARM processors) [4]. If we want to make use of these modes, we need to enable them, and this usually takes place when the processor start up and its components are initialized. This code is part of the boot loader. Normally, enabling/disabling a mode is as easy as uncomment/comment the definition of a global variable, which is used later on in an ifdef MACRO in the C pre-compiler so that code can be adapted to operate in that mode.

Building U-Boot

Once we have mede the changes we intended to in the u-boot code -if we needed any at all- we need to compile it before we can flash it into our device. Prior to this step, we need to (i) initialize objects and configurations and clean previous compilation attempts, (ii) create the uboot configuration file and finally (iii) generate the executable. Please remember that, before attempting to compile for a specific platform, we need a set up our environment to cross-compile for that platform. Please read this previous post on how to set up the system for Android development. Once our host machine is set up, we can run the following commands, which will build uboot:

  • cd uboot
  • make distclean
  • make $BOARD_NAME_config – For this we need to know the name of the board we are using as a target. In the case of the Exynos 4 (ODROID-PC) it is smdkv310. The command would be then: make smdkv310_config
  • make -j10

After make has finished, we can check that the u-boot.bin file has been successfully generated. After this we can just flash it (the u-boot.bin file) into ours device boot device – ROM, SDCard, USB, etc. Depending on the board, this process -once again- might vary. Taking as a example the same board we have used for our own development -hardkernel’s ODROID-PC– this board needs of a first level boot loader that adds a checksum and a header to the original u-boot.bin, and it is generated from the u-boot.bin file itself using a tool called sd_fuse. This first stage boot loader is called U-boot_bl1.bin in the ODROID-PC community. This tool is part of the ODRIOD-PC’s boot loader used by the hardkernel team in their boards and it can be downloaded here.

According to the ODROID-PC documentation, in order to create the u-boot_bl1.bin file the following commands are necessary:

  • cd uboot
  • cd sd_fuse
  • make
  • cd ..
  • ./sd_fuse/c210-mkbl1 u-boot.bin u-boot_bl1.bin 16384

The u-boot_bl1.bin file is generated in the uboot directory. Please remember that this last step is platform specific and most probably does not apply to other boards.

Fusing U-Boot

The last step we need to give is to flash the boot loader in our boot device. It could be that the fabricant provides the image of the boot loader (not the code), in that case, this step is still applicable when doing recovery of the board, flashing a new boot device or similar cases.

In order to flash the boot loader in a boot device, first we need to know which name this device is given by our host machine when we connect it to it. For this, do as follows:

  1. sudo fdisk -l
  2. Check the Boot Devices attached, they will look like /dev/sda1, /dev/sda2, /dev/sdb1, etc.
  3. Attach the boot device to your host machine: SDCard, USB, etc.
  4. sudo fdisk -l
  5. Check which device has been added (e.g. /dev/sdb*). This is out boot device.

Once this is done, we use the dd linux commnand to flash the boot loader image in the boot device. Once more, the block in which the internal ROM of a given device might look for the boot loader varies from board to board, but it should be clearly specified in the documentation (and in the worse case, it should be traceable in code). In the case of our ODROID-PC, the specific commands to flash our boot device are (considering /dev/sdb* as our boot device): (Please notice that this step is only possible when having an extractable boot device -SDCard, USB stick, etc.-, commonly used in development boards. If dealing with a phone or a tablet that are not meant for developers, the flash chip -boot device- would be integrated, and then we would need a programming board to be able to flash it. Rooting devices is beyond the scope of this set of tutorials -and sometimes illegal- and therefore we will not cover it here. The steps to be done are not that different from the ones given here though ;))

  • cd uboot
  • sudo umount /dev/sdb*
  • sudo dd if=./u-boot.bin of=/dev/sdb seek=33
  • sudo dd if=./u-boot_bl1.bin of=/dev/sdb seek=1
  • sync

What we do with the dd command is to copy the file u-boot.bin to the device /dev/sdb, “seeking” 33 sectors. This means that we will skip the first 32 sectors and of the boot device and star copying the u-boot.bin in the sector 33. Similarly, we copy the first stage bootloader, u-boot_bl1.bin, in our boot device, in the sector 1. Once question here is: Why in this specific sectors? In the case of the ODROID-PC, if we check the documentation, we can find the following image, from where we can easily deduct the information provided above. Other boards should not differ much from the one we are using here as an example, being the information given here easily portable to other platforms.

Once this is done we have the first component of the boot sequence already flashed in our device. If we now open a serial connection from our host machine and restart the board (power off > power on) we should see something like this: (Please refer to this tutorial to configure your console for serial communication – coming soon)

This means that we do have a simple shell to interact with our board. Type help to see the commands you have available and… Enjoy! 🙂

Two of the most popular and useful commands you will find are: fdisk and fastboot, follow the links for a small introduction to them. (coming soon)

Next Steps

  • Understand, modify, build and install the Kernel (post coming soon)
  • Understand, modify, build and install the OS – Android (post coming soon)

REFERENCES

[1] The DENX U-Boot (here)

[2] The U-boot boot loader – Presentation (here)

[3] U-Boot – linux-mips.org (here)

[4] ARM – TrustZone (here)

[5] ODROID – hardhernel (here)

3 thoughts on “The Bootloader – Understanding, Modifying, Building and Installing

  1. Pingback: Android Developer Tools – Fastboot « My Cellar Door

  2. Pingback: The Kernel – Understanding, Modifying, Building and Installing « My Cellar Door

  3. Pingback: Android – Understanding, Modifying, Building and Installing « My Cellar Door

Comments are closed.