Booting a Linux installation it's a complex process involving multiple stages and software components. This book is going to focus on the kernel part of the booting process, leaving the rest to other books or documentation. However, we are going to outline the essential stages of the startup process to show where the kernel fits:

Hardware (including firmware) initialization

Execution of a boot loader (if any)

Loading the kernel image and startup of the kernel

User space initialization

Early stages of the Linux startup process heavily depend very much on the computer architecture. IBM PC compatible hardware is one architecture Linux is commonly used on; on these systems, the BIOS plays an important role, which might not have exact analogs on other systems. In the following example, IBM PC compatible hardware is assumed:

Once the hardware is enumerated and the hardware which is necessary for boot is initialized correctly, the BIOS loads and executes the boot code from the configured boot device. This boot code contains phase 1 of a Linux boot loader; phase 1 loads phase 2, which is the bulk of the boot loader code. Some loaders may use an intermediate phase (known as phase 1.5) to achieve this, since they are designed to be able to interpret filesystem layouts to locate the phase 2 loader.

The boot loader loads the kernel image, prepare the boot parameters to be read later by the kernel, and transfer control to the operating system by jumping to a position in memory.

When the kernel finishes its startup process, it must be able to provide a pre-emptive multi-tasking environment to user space. The kernel must also initialize the device needed to mount the root filesystem (as read only), specified by the boot loader using the parameter root=. The root file system contains the image of the first process to be launched by the kernel, called the init process, which PID is going to be 1. The kernel looks for it in /sbin/init by default, or in the path indicated by the init= boot parameter.

The init process manages user space initialization. It usually involves the execution of various startup scripts and daemons that set up all non-operating system services and structures in order to allow a user environment to be created.

This is loaded in two stages - in the first stage the kernel (as a compressed image file) is loaded into memory and decompressed, and a few fundamental functions such as essential hardware and basic memory management (memory paging) are set up. Control is then switched one final time to the main kernel start process calling start_kernel(), which then performs the majority of system setup (interrupts, the rest of memory management, device and driver initialization, etc.) before spawning separately, the idle process and scheduler, and the init process (which is executed in user space).

Kernel loading stage

The kernel as loaded is typically an image file, compressed into either zImage or bzImage formats with zlib. A routine at the head of it does a minimal amount of hardware setup, decompresses the image fully into high memory, and takes note of any RAM disk if configured. It then executes kernel startup via ./arch/i386/boot/head and the startup_32 () (for x86 based processors) process.

Kernel startup stage

The startup function for the kernel (also called the swapper or process 0) establishes memory management (paging tables and memory paging), detects the type of CPU and any additional functionality such as floating point capabilities, and then switches to non-architecture specific Linux kernel functionality via a call to start_kernel().

start_kernel executes a wide range of initialization functions. It sets up interrupt handling (IRQs), further configures memory, starts the init process (the first user-space process), and then starts the idle task via cpu_idle(). Notably, the kernel startup process also mounts the initial RAM disk ("initrd") that was loaded previously as the temporary root file system during the boot phase. The initrd allows driver modules to be loaded directly from memory, without reliance upon other devices (e.g. a hard disk) and the drivers that are needed to access them (e.g. a SATA driver). This split of some drivers statically compiled into the kernel and other drivers loaded from initrd allows for a smaller kernel. The root file system is later switched via a call to pivot_root() which unmounts the temporary root file system and replaces it with the use of the real one, once the latter is accessible. The memory used by the temporary root file system is then reclaimed.