Thursday, 9 October 2014

Linux basics kernel and bootloader

What is a bootloader

Bootloader is a piece of code that runs before any operating system is running.
Bootloader are used to boot other operating systems, usually each operating system has a set of bootloaders specific for it.
Bootloaders usually contain several ways to boot the OS kernel and also contain commands for debugging and/or modifying the kernel environment.
In this talk we will concentrate on Linux bootloaders.

Since it is usually the first software to run after powerup or reset, it is highly processor and board specific.

Processor and Board specific


  • Bootloader starts before any other software starts therefore it is highly processor specific and board specific.
  • The bootloader performs the necessary initializations to prepare the system for the Operating system.
  • The operating System is more general and usually contains minimum board or processor specific code.

Usually starts from ROM (Flash)

When a CPU starts, it has certain preset values in its registers, it usually knows nothing about on board memory. It expetcs to find program code at a specific address, this address usually points to ROM or Flash, this is the beginning of bootloader code. First task of boot loader is usually map the RAM to predefined addresses. After RAM is mapped Stack pointer is setup.
This is the minimal setup required, after that the bootloader starts it's work.


Moves itself to RAM for actual work


We now have RAM and Stack pointer and ready to do the real work. First of all since Flash memory is usually scarce resource and much slower then RAM, we move the actual bootloader code to RAM for actual execution. In many cases Flash memory is located in an address space that is not executable, for example serial flash that you can access by reading repeatativly from one address. Also in many cases, the actual bootloader code is compressed so it must first be uncompressed and then written to RAM.


Minimum peripheral initialization

The bootloader needs to initialize peripherals needed for its operation, usually we need the screen the keyboard and optionaly the mouse. In embedded systems we need a terminal. Sometimes when we boot from network we need network connection so we have to initialize ethernet card.

These initializations are usually just for the bootloader.
The Operating System usually overrides them or not using them at all.


Decide which OS image to start


Bootloaders can usually load one of few kernel images that are known to the bootloader This can be done in embedded systems to make sure we can upgrade a kernel without fear of power loss during upgrade, since we always have a backup kernel that will load. In PC environments this is done to let the user choose among several OS's or give the user a chance to try another kernel without losing his/her current kernel.


Get the kernel

Bootloaders must load the kernel image from a known location
most bootloaders provide several ways to loade the kernel:

  • Load kernel image from memory
  • Load kernel image from file (If the system has a disk)
  • Load kernel image from network using bootp
  • Load kernel image to memory using TFTP

Allow manual intervention

In some cases we need manual intervention to specify parameters for the OS,
bootloaders usually have a way to interrupt automatic loading and insert parameters. This is done by waiting a certain default time before autoloading, during this time the user has to press a specific key (Esc in case of LILO) or any key in case of UBOOT. When a key is pressed, a prompt is displayed and the user has a chance to change certain environment variable or maybe load a different kernel from memory, disk, network etc.


PC boot sequence

PC's have a different boot sequence, first a ROM BIOS starts that give minimal configuration to peripherals, usually just configuring the screen and keyboard. It then looks in its tables (CMOS RAM) for a boot device.
From the specified boot device it loads to RAM the first stage (from MBR)
control is transferred to first stage.

First stage bootloader loads the second stage that usually displays the boot menu. The user selects the OS to boot or a default OS is booted after a speficied time. In this stage the user have the option to add boot parameters to kernel. In several cases, the bootloader does not know how to load the OS and transfers the control to another bootloader, this is called chain loading, this is usually done when LILO or GRUB needs to load windows.


Prepare parameters for OS loading


The OS is usually generic and is not specificly tied to one board implementation, so in order for the OS to work as expected, it needs some information about the memory map, clocks etc. These parameters can be compiled into the kernel but this make the kernel very board specific and makes it difficult to replace kernels in the future. Most kernels allow passing information by means of command line and/or in memory structure.


Loads OS Image

After the bootloadr knows what OS Image (Kernel) to load, it loads the Image to RAM This usually must be done to a specific address the specific address is either hard coded into the bootloader or is read from the kernel image file.
The bootloader needs to be able to read and understand the object format of the OS kernel. It will extract the actual memory image from the object file and place it to memory according to the header of the object format and then jump to the entry point (also given in the object header).

In case of Linux which uses MMU the base address is usually virtual address and the bootloader needs to translate it to physical address, this is why we usually can't load linux using a bootloader written for other OS's that don't use MMU such as vxWorks.

Load optional RAM file system (initrd)


In Linux the kernel needs a root file system to work, this root file system can be on a disk or in RAM disk. RAM disk (initrd) is frequently used in linux distributions to keep the kernel small and to load only a required set of modules to work with the hardware. The initial RAM disk is used as a root file system, the init process of the RAM disk, loads the needed modules and then mounts the other filesystems from disk. In embedded system, many times there is no disk at all so the RAM file system is used.

Transfer control to OS kernel in RAM


After all images are loaded into RAM, we can start the OS itself. Starting the OS usually means copying it to a certain location in RAM, filling a memory structure and then transfer control to the OS code. In this stage the bootloader role is done and thus the OS can use the RAM area where the bootloader is.


Starting Linux

Until now we concentrated on the bootloader itself and what we discussed in general for all operating system, now we will discuss specific features needed to boot linux. Linux was created as an operating system for desktop or server, it was later adopted for embedded system environments and is thus different from other Embedded operating systems.

Linux must have a file system, this makes programming an embedded linux application easier as it is similar to programming a desktop application, you simply compile your program to a file linked with the appropriate libraries and then run this file. In other embedded operating system you link your application with the kernel itself and thus you actually write a kernel application. However since Linux must have a file system and embedded systems usually does not even have a disk, we use a RAM disk image of the file system. This RAM disk image can be included in the Kernel image as another section in the object file or used as a seperate file. The bootloader must know how to handle it. It must extract the file system image and put it in a certain known RAM location before it trasfers control to the kernel.

No comments:

Post a Comment