Linux Boot Process — Part 2

A Cloud Chef
4 min readSep 3, 2018

--

In the previous article, we left right after after the kernel was loaded in memory and executed. Let’s pick from here and see how the kernel initialize itself.

Kernel Boot

Unfortunately, booting the kernel is not as simple as it seems. There are two main reasons:

  • The kernel starts in real mode, not protected mode. Since the real mode can't access more than 1 megabyte of memory, it has not enough memory to full load the kernel.
  • The kernel image data is compressed, only a small piece of the header is actual executable code. The header is kept under real mode memory limit, the remaining kernel is stored above and it's not accessible until the kernel switches to protected mode.

The kernel boot process follows these steps:

  1. Check whether the boot manager loaded its code following the layout required by the kernel boot protocol
  2. Detect memory layout, validates the CPU architecture and set up the keyboard and the terminal video mode.
  3. Prepare the system to switch to protected mode. It needs to perform two tasks: initialize a new Interrupt Handler Table and a Global Descriptor Table, both required by protected mode.
  4. Switch to protected mode and decompress the kernel. The kernel is decompressed in place: the memory pages holding the compressed image are replaced by the decompressed data. This is where you see the familiar messages "Decompressing Linux… done." and "Booting the kernel.".
  5. The actual kernel starts executing. Paging is enabled, interrupt handler table is initialized and start_kernel() is called. start_kernel() and the subsequent called functions have the process id 0, they are the ancestor of all kernel mode processes as well process id 1.
  6. start_kernel() initializes dozens of kernel subsystems. Among them, the task scheduler. It ends calling rest_init().
  7. rest_init() in its turn, spawns the very first user space process: kernel_init(). Its process id is 1 and it's special: it will become the direct or indirect ancestor of all user space processes. It also spawns kthreadd process (normally, process id 2), that's the parent of all kernel threads. Finally, it runs cpu_idle(), a process that takes over the CPU whenever there is no other process using it.
  8. kernel_init() will start any additional CPU core. If there is a initial RAM disk is defined, it will decompress and mount it. Then, it load the device drivers based on the BIOS ACPI tables, mount the root file system in read-only mode and finally call the init process (normally, in /sbin/init). As long as the computer is running, the init process remains the process id 1.

Initial RAM disk

The initial RAM disk is an optional resource used by the kernel boot process. It's a compressed disk image including kernel modules and command-line tools required by the kernel to mount the root file system. For example, if the root file system is a remote NFS exported directory, the initial RAM disk needs the network interface device drivers modules as well a DHCP client to retrieve the system IP address and portmap daemon. Tools for troubleshooting a system are included as well.

When the kernel initialize, it looks for the expected memory locations for initrd_addressand initrd_size (set by the boot loader, following the kernel boot protocol guidelines). If found, the correspondent pages are mapped to the special device file /dev/initrd (read-only). What happens next depends on the image format:

  • initrd: fixed-size block device image (optionally compressed) where the the files are stored inside a file system. The kernel copies it to /dev/ram0 and mount it as root. If the the /linuxrc file exists and is executable, it's executed by the kernel. Finally, the kernel tries to mount the root device (specified by the kernel command-line argument root, passed by the boot loader). Once mounted, it calls pivot_root()to switch the root file system. The initrd image will be mounted under /initrd if the directory exists in the new root, otherwise the contents of /dev/initrd and /dev/ram0 are discarded and the memory is reclaimed. Finally, the kernel will run the init process (usually /sbin/init, can be configured with the kernel command-line argument init)
  • initramdisk: CPIO archive (optionally compressed). The kernel extracts it directly to the file system (no need to mount a block device), then run /init. Unlike initrd, the kernel won't run the init process automatically nor mount and switch the root file system: initramdisk must do it itself. Also, unlike initrd, the image is not available after switching to the real root device.

Init Process

The final step in the boot process is when kernel_init()finishes and give place to the init process. Linux has at least three mainstream implementations of init process:

  • SysV init: the classic implementation of init process, currently considered obsolete.
  • Upstart: written by Canonical, was the first mainstream replacement for SysV init. Besides handling the initialization, its event-based infrastructure continues managing the system after the initialization: for example, it will automatically mount an USB flash drives when it's connected.
  • systemd: the current de facto standard on modern Linux distributions. Unlike SysV init and Upstart, its configuration describes the state the system must be after the initialization instead simply providing the scripts to reach that state.

While this article won't go deep on init, a list of some of most important tasks performed by it follows:

  • Check the root file system and remount it in read/write mode. Up to this point, root file system is mounted in read-only mode.
  • Check and mount additional file systems.
  • Initialize network cards. Some processes are triggered by the network card initialization, such ntpdate (used to synchronize local time with a network time server).
  • Start daemons. Some daemons support the system processes, such as crond and syslogd. Some allow remote access, such as sshd and telnetd. And some represent actual network services such as named and httpd.
  • Sets getty on physical or virtual terminals. This allows the user connected to a terminal to login and use the shell.

The following diagram should help understand how the boot process works.

Linux boot process

--

--