-
Notifications
You must be signed in to change notification settings - Fork 3
Bootloader
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.
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.
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 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
and0xff
, 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.
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.
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:
- 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.
- 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. -
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). - Either the
loader.bin
or thebootcode.bin
reads the GPU firmware (start.elf
). -
start.elf
looks for different ARM executables, all starting withkernel
and ending in.img
and also readsconfig.txt
andcmdline.txt
. - Once the kernel it's loaded, the GPU triggers the reset line on the ARM processor, which starts executing code.
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
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
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
.
Raspberry Pi Documentation - Boot options in config.txt
Author: thanoskoutr
Wiki Documentation: https://github.com/thanoskoutr/armOS/wiki
Doxygen Documentation: https://thanoskoutr.github.io/armOS/