The boot process

As we seen in the previous sections, upon starting, the first step is to load the BIOS which runs a power-on self-test (POST) to check and initialize required devices such as memory and the PCI bus (including running embedded ROMs). After initializing required hardware, the BIOS goes through a pre-configured list of non-volatile storage devices ("boot device sequence") until it finds one that is bootable.

A bootable device is defined as one that can be read from, and where the last two bytes of the first sector contain the byte sequence 55h,AAh on disk (a.k.a. the MBR boot signature from the previous section).

Once the BIOS has found a bootable device, it loads the boot sector to linear address 7C00h and transfers execution to the boot code. In the case of a hard disk, this is referred to as the Master Boot Record (MBR). The conventional MBR code checks the MBR's partition table for a partition set as bootable (the one with active flag set). If an active partition is found, the MBR code loads the boot sector code from that partition, known as Volume Boot Record (VBR), and executes it. The VBR is often operating system specific while the MBR code is not operating system specific. However, in most operating systems its main function is to load and execute the operating system kernel, which continues the startup process.

In general terms, the MBR code is the first stage boot loader, while the VBR code is the Second-stage boot loader. Second-stage boot loaders, such as GNU GRUB, BOOTMGR, Syslinux, or NTLDR, are not themselves operating systems, but are able to load an operating system properly and transfer execution to it. This is why we sad that these codes are operating system specific.

The operating system subsequently initializes itself and may load extra device drivers. Many boot loaders (like GNU GRUB, newer Windows' BOOTMGR, and Windows NT/2000/XP's NTLDR) can be configured to give the user multiple booting choices. These choices can include different operating systems (for dual or multi-booting from different partitions or drives), different versions of the same operating system, different operating system loading options (e.g., booting into a rescue or safe mode), and some standalone programs that can function without an operating system, such as memory testers (e.g., memtest86+). This is the place where we can made a small remark: the boot loaders for Windows can be used to start Linux as well. This can be achieved with the usage of the previous section's dd command to made a copy of the boot sector of the partition containing the Linux operating system. Then we need to copy this file to the root partition of the Windows OS and placing one line into the boot manager"s configuration data.

The boot process can be considered complete when the computer is ready to interact with the user, or the operating system is capable of running system programs or application programs.

Windows boot process

Windows boot process starts when the computer finds a Windows boot loader, a portion of Windows operating system responsible for finding Microsoft Windows and starting it up. The boot loader is called Windows Boot Manager (BOOTMGR) starting from Vista. Prior to Windows Vista the boot loader was NTLDR.

Boot loaders

The boot loader searches for a Windows operating system. Windows Boot Manager does so by reading Boot Configuration Data (BCD), a complex firmware-independent database for boot-time configuration data. Its predecessor, NTLDR, does so by reading the simpler boot.ini. If the boot.ini file is missing, the boot loader will attempt to locate information from the standard installation directory.

Both databases may contain a list of installed Microsoft operating systems that may be loaded from the local hard disk drive or a remote computer on the local network. (As we remarked it in the previous section, both boot manager can be used to boot up non-Microsoft operating systems as well. They need only the boot sector for the new operating system.)

If  more than one operating system is installed, the boot loader shows a boot menu and allow the user to select an operating system. If a non NT-based operating system is selected (specified by an DOS style of path, e.g. C:\), then the boot loader loads the associated "boot sector" file listed in boot.ini or BCD and passes execution control to it. Otherwise, the boot process continues.

Kernel load

At this point in the boot process, the boot loader clears the screen and displays a textual progress bar (which is often not seen due to the initialization speed). If the user presses F8 during this phase, the advanced boot menu is displayed, containing various special boot modes including Safe mode, Last Known Good Configuration or with debugging enabled. Once a boot mode has been selected (or if F8 was never pressed) booting continues.

The Windows NT kernel ( Ntoskrnl.exe ) and the Hardware Abstraction Layer ( hal.dll ) are loaded into memory. The initialization of the kernel subsystem is done in two phases. During the first phase, basic internal memory structures are created, and each CPU's interrupt controller is initialized. The memory manager is initialized, creating areas for the file system cache, paged and non-paged pools of memory. The Object Manager initial security token for assignment to the first process on the system, and the Process Manager itself. The System idle process as well as the System process are created at this point. The second phase involves initializing the device drivers which were identified as being system drivers.

Session manager

Once all the Boot and System drivers have been loaded, the kernel starts the Session Manager Subsystem ( smss.exe ). At boot time, the Session Manager Subsystem:

  • Creates environment variables

  • Starts the kernel-mode side of the Win32 subsystem (win32k.sys).

  • Starts the user-mode side of the Win32 subsystem, the Client/Server Runtime Server Subsystem (csrss.exe).

  • Creates virtual memory paging files

  • Starts the Windows Logon Manager (winlogon.exe).

    Winlogon is responsible for handling interactive logons to a Windows system (local or remote). The Graphical Identification aNd Authentication (GINA) library is loaded inside the Winlogon process, and provides support for logging in as a local or domain user.

    Winlogon starts the Local Security Authority Subsystem Service (LSASS) and Service Control Manager (SCM), which in turn will start all the Windows services that are set to Auto-Start. It is also responsible for loading the user profile on logon, and optionally locking the computer when a screensaver is running.

Linux boot process

The Linux boot process follows the general booting model. The flow of control during a boot is from BIOS, to multi-stage boot loader, to kernel. When PC is powered up and the BIOS is loaded and a boot device is found, the first-stage boot loader is loaded into RAM and executed. This boot loader as we seen is less than 512 bytes in length, and its job is to load the second-stage boot loader. When the second-stage boot loader is in RAM and executing it task is to load into memory Linux (kernel) and an optional initial RAM disk (temporary root file system). When the images are loaded, the second-stage boot loader passes control to the kernel image and the kernel is decompressed and initialized. At this stage, the second-stage boot loader checks the system hardware, enumerates the attached hardware devices, mounts the root device, and then loads the necessary kernel modules. When complete, the first user-space program (init) starts, and high-level system initialization is performed. This can be seen on the following figure:

Boot loaders

In the Linux world the first- and second-stage boot loaders are combined. The first stage boot loader (in the MBR or the volume boot record ) loads the remainder of the boot loader, which typically gives a prompt asking which operating system the user wishes to initialize. The two most common boot loader are called Linux Loader (LILO) or GRand Unified Bootloader (GRUB).

Because LILO has some disadvantages that were corrected in GRUB, nowadays GRUB is the most common one. The great thing about GRUB is that it includes knowledge of Linux file systems. Instead of using raw sectors on the disk, as LILO does, GRUB can load a Linux kernel from an ext2 or ext3 file system. It does this by making the two-stage boot loader into a three-stage boot loader.

Stage 1 (MBR) boots a stage 1.5 boot loader that understands the particular file system containing the Linux kernel image. When the stage 1.5 boot loader is loaded and running, the stage 2 boot loader can be loaded. With stage 2 loaded, GRUB can display a list of available kernels. You can select a kernel and even amend it with additional kernel parameters. Optionally, you can use a command-line shell for greater manual control over the boot process.

With the second-stage boot loader in memory, the file system is consulted, and the default kernel image and initrd image are loaded into memory. With the images ready, the stage 2 boot loader invokes the kernel image.

grub>kernel /bzImage-2.6.9-89.0.20.ELsmp   
[Linux-bzImage, setup=0x1400, size=0x29672e]
grub>initrd /initrd-2.6.9-89.0.20.ELsmp
[Linux-initrd @ 0x5f13000, 0xcc199 bytes]
grub>boot
Uncompressing Linux... Ok, booting the kernel.

LILO, the older boot loader, is almost identical to GRUB in process, except that its command line interface allows only selection of options previously recorded in the boot sector and map file. Thus all changes must be made to its configuration and written to the boot sector and map file, and then the system restarted. An error in configuration can therefore leave a disk unable to be booted. However, LILO has a great feature. When LILO loads itself it displays the word “LILO”. Each letter is printed before or after some specific action. If LILO fails at some point, the letters printed so far can be used to identify the problem.

  • (nothing)

    No part of LILO has been loaded. LILO either isn't installed or the partition on which its boot sector is located isn't active. The boot media is incorrect or faulty.

  • L

    The first stage boot loader has been loaded and started, but it can't load the second stage boot loader. The two-digit error codes indicate the type of problem.

  • LI

    The first stage boot loader was able to load the second stage boot loader, but has failed to execute it.

  • LIL

    The second stage boot loader has been started, but it can't load the descriptor table from the map file.

  • LIL?

    The second stage boot loader has been loaded at an incorrect address.

  • LIL-

    The descriptor table is corrupt.

  • LILO

    All parts of LILO have been successfully loaded.

Kernel load

The kernel does the same in Linux as does it in all operating systems, such as memory management, task scheduling, I/O, interprocess communication and overall system control. In Linux this is loaded in two stages because the kernel image isn't so much an executable kernel, but a compressed kernel image. Typically this is a zImage (compressed image, less than 512KB) or a bzImage (big compressed image, greater than 512KB), that has been previously compressed with zlib.

In the first stage the kernel (as a compressed image file) is loaded into memory and decompressed, and a few fundamental functions such as basic memory management and similar tasks as we seen in Windows are set up. Once the kernel is fully operational – and as part of its startup, upon being loaded and executing – the kernel looks for an init process to run, which (separately) sets up a user space and the processes needed for a user environment and login. The kernel itself is then allowed to go idle, subject to calls from other processes.

During the kernel load and startup the following important step are performed:

With the call to start_kernel(), a long list of initialization functions are called to set up interrupts, perform further memory configuration, and load the initial RAM drive. During the boot of the kernel, the initial-RAM drive ( initrd ) - that was loaded into memory by the stage 2 boot loader - is copied into RAM and mounted.

Note

RAM drive is a block of  RAM ( primary storage  or  volatile memory ) that a computer's software is treating as if the memory were a disk drive or secondary storage. Data stored in a RAM disk can be accessed more quickly than data stored on a disk drive, but this data is erased whenever you turn off or reboot the computer. RAM drives are available from the 1970's.

The kernel always needs a root file system and during the boot process this RAM disk serves as a temporary root file system in RAM and allows the kernel to fully boot without having to mount any physical disks. 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. an SATA driver). After the kernel is booted, the root file system is pivoted where the initrd  root file system is unmounted and the real root file system is mounted.

At this point, with interrupts enabled, the scheduler can take control of the overall management of the system, to provide pre-emptive multi-tasking, and the init process is left to continue booting the user environment in user space.

The init process

After the kernel is booted and initialized, the kernel starts the first user-space application. Init is executed by the kernel and not a user process, and expects to have a process id of 1. As we found in the manual page of init:

init is the parent of all processes on the system, it is executed by the kernel and is responsible for starting all other processes;
it is the parent of all processes whose natural parents have died and it is responsible for reaping those when they die.

Essentially it establishes and operates the entire user space. This includes checking and mounting file systems, starting up necessary user services, and ultimately switching to a user-environment when system startup is completed. Originally, process ID 1 was not specifically reserved for init by any technical measures: it simply had this ID as a natural consequence of being the first process invoked by the kernel.

The init process starting the following two main types of processes:

  • daemon

    a computer program that runs as a background process, acts as a service and often started at boot time.

  • user process

    related for terminals (spawn gettys by init)

The startup configuration can be configured by the /etc/inittab file. Naturally one configuration could not be comfortable for all cases and therefore the Unix System V style systems introduced the run level term. A run level is a software configuration of the system which allows only a selected group of processes to exist. The processes spawned by init for each of these run levels are defined in the aforementioned /etc/inittab file.

After it has spawned all of the processes specified, init goes dormant, and waits for one of three events to happen:

  • processes it started to end or die

  • a power failure signal

  • a request via /sbin/telinit to further change the runlevel

This applies to SysV-style init.

Other init binaries behave differently, like systemd or the event-based Upstart introduced by Ubuntu in 2006. Because the traditional init process is strictly synchronous, blocking future tasks until the current one has completed, it can not react various task on modern computers, like attaching and deattaching USB tools or discoverying new devices without locking the system. Its tasks must also be defined in advance, and they only run when the init daemon changes state.

Upstart operates asynchronously — as well as handling the starting of tasks and services during boot and stopping them during shutdown, it supervises them while the system is running. Easy transition and backwards compatibility with init were explicit design goals. As such, Upstart is able to run init scripts unmodified and included in several Linux distributions (e.g.: Debian, RedHat, openSuse, Google's Chrome OS and Nokia's Maemo 5).

Runlevels

The term runlevel refers to a mode of operation in one of the computer operating systems that implement Unix System V-style initialization. A run level  is a state of  init  and the whole system that defines what system services are operating. Run levels are identified by numbers. Run levels stop at six for practical and historical reasons, but it is entirely possible to have more if desired.

Each mode has it's own list of settings for what services to start and what services to shutdown. Not only does this list contain what is supposed to be running, but also what order each service should be started in. The exact setup of these configurations will vary from OS to OS, and from one Linux distribution to another. Different runlevels are typically assigned to:

  • single-user mode

  • multi-user mode without network services started

  • multi-user mode with network services started

  • system shutdown

  • system reboot

In standard practice, when a computer enters runlevel zero, it halts, and when it enters runlevel six, it reboots. The intermediate runlevels (1-5) differ in terms of which drives are mounted, and which network services are started. Default runlevels are typically 3, 4, or 5. Lower run levels are useful for maintenance or emergency repairs, since they usually don't offer any network services at all.

The following list defines how most Linux Distributions define the different run levels.

  • 1 - Single-user mode (for special administration - mostly root login allowed only ).

  • 2 - Local Multi-user with Networking but without network service (like NFS)

  • 3 - Full Multi-user with Networking

  • 4 - Not Used, for own purposes.

  • 5 - Full Multi-user with Networking and the graphical interface X Windows

Like everything else in a Linux system, run levels are defined by files in the file system. All the run level files are found in the /etc directory according to the rcX.d  directory where X is the run level number. Each file is a symbolic link to a script residing in the  /etc/init.d  directory and controls the starting, or stopping of a program, or daemon (service).

When a system moves into a new runlevel, all the files that begin with S will be executed. When a system moves into a new runlevel all the files that begin with K will be executed. When you leave a runlevel, nothing happens. All the action takes place when you enter the new run level.

We can check the actual run level with the runlevel command. Here is the command and the output shown together due to the sparsity of the output:

morse:/home/user1# runlevel
N 2

It tells you two things: The last run level, and the current run level. The 'N' stands for none, meaning there has been no run level change since powering up.

The primary command used to change run levels is ' telinit ' ( "Tell Init" ).

morse:/home/user1# telinit 3