Skip to content

Bootloader

thanos edited this page Mar 22, 2021 · 5 revisions

Bootloader

x86 Bootloader

BIOS

When the PC is turned on, the computer will start a small program that adheres to the Basic Input Output System (BIOS) standard. This program is usually stored on a read only memory chip on the motherboard of the PC.

The original role of the BIOS program was to export some library functions for printing to the screen, reading keyboard input etc. Modern operating systems do not use the BIOS’ functions, they use drivers that interact directly with the hardware, bypassing the BIOS.

Today, BIOS mainly runs some early diagnostics (power-on-self-test) and then transfers control to the bootloader.

Reading from the Boot Sector

In order to boot to an Operating System, BIOS must read specific sectors of data (usually 512 bytes in size) from specific locations of the disk devices.

So, BIOS loops through each storage device, reads the boot sector into memory, and instructs the CPU to begin executing the first bootsector it finds that ends with the magic number (0xaa55).

In more detail, it examines the last two bytes of the first sector whether it has the boot record signature of 0x55, 0xaa. If so, then the BIOS loads the first sector to the address 0x7c00, set the program counter to that address and let the CPU executing code from there.

The first sector is called Master Boot Record, or MBR. The program in the first sector is called MBR Bootloader.

Transfer control to Bootloader

The BIOS program will transfer control of the PC to a program called a bootloader. The bootloader’s task is to transfer control to the operating system developers, and our code. The bootloader will start executing from memory address 0x7c00 (BIOS will load it there).

The bootloader (for x86 architectures) is often split into two parts:

  • The first part of the bootloader will transfer control to the second part.
    • It usually just tries to read more sectors from disk, in order to load the second part of the bootloader.
  • The second part will finally give control of the PC to the operating system.
    • The second part, is responsible form calling the main function of our kernel, in order to load the Operating System.

A valid Boot Sector

A simple yet valid boot sector is the following:

A machine code boot sector, with each byte displayed in hexadecimal.

e9 fd ff 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
*
00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa

Note that:

  • The initial 3 bytes, in hexadecimal as 0xe9, 0xfd and 0xff, are actually machine codes instructions, as defined by the CPU manufacturer, to perform an endless jump.
  • The last 2 bytes 0x55, 0xaa make up the magic number, which tells the BIOS that this is indeed a boot block.
  • The file is padded with zeros ("*" indicates zeros omitted for simplicity), in oder to position the magic number at the end of the 512 byte disk sector.

ARM Bootloader

A main difference between ARM and x86, is that ARM does not have a BIOS. ARM uses only a bootloader. The bootloader is the program that runs in an embedded processor immediately after a reset of the processor and is responsible for initializing the connected devices and starting the main software (for example, the kernel of an OS). The ARM bootloader defines the vector table of the computing environment.

Raspberry Pi Bootloader

The Raspberry Pi does not have a BIOS or a bootloader with the traditional meaning. The Raspberry Pi boot process is a little cryptic, meaning that the firmware is not open source, and the exact details are unkown. But the general boot sequence is the following:

  1. When the Raspberry Pi is first turned on, the ARM core is off, and the GPU core is on. At this point the SDRAM is disabled.
  2. The GPU starts executing the first stage bootloader, which is stored in ROM on the SoC. The first stage bootloader reads the SD card, and loads the second stage bootloader (bootcode.bin) into the L2 cache, and runs it.
  3. bootcode.bin enables SDRAM, and reads the third stage bootloader (loader.bin) from the SD card into RAM, and runs it. (More recent versions do not use a third stage bootloader).
  4. Either the loader.bin or the bootcode.bin reads the GPU firmware (start.elf).
  5. start.elf looks for different ARM executables, all starting with kernel and ending in .img and also reads config.txt and cmdline.txt.
  6. Once the kernel it's loaded, the GPU triggers the reset line on the ARM processor, which starts executing code.

Raspberry Pi - 32-bit Kernel

If we are booting a 32-bit kernel (in Aarch32 mode) the kernel image must have the following name:

  • For the Pi 1, Pi Zero: kernel.img
  • For the Pi 2, Pi 3: kernel7.img
  • For the Pi 4: kernel7l.img

Raspberry Pi - 64-bit Kernel

If we are booting a 64-bit kernel (in Aarch64 mode) the kernel image must have the following name:

  • For the Pi 3, Pi 4: kernel8.img

Raspberry Pi - Kernel Address

The memory address that the kernel image should be loaded.

  • For 32-bit kernels, kernel is loaded to address 0x8000.
  • For 64-bit kernels, kernel is loaded to address 0x80000.

References

Raspberry Pi Documentation - Boot options in config.txt

OSDev - Raspberry Pi Bare Bones

Previous Page

Installation

Next Page

ARM Arch

Clone this wiki locally