Initialization sequence in GNU/Linux

The process of booting your PC, from power to prompt

Download the whole article as PDF

Write a full post in response to this!


The login prompt is a nice place to be. Poised, fingers on keyboards, ready to send mail, surf the web, or do a little programming. However, from power-on to login prompt there is a long road for our GNU-powered friend to travel.

The boot up

The first step on this journey is the BIOS power on, system test. Or POST for short. BIOS stands for Basic Input Output System, and is the custom chip on the motherboard that holds a small program to kickstart the whole boot-up. Its job is to check the low-level hardware components, such as memory and hard disks. Configuration of the BIOS can be a complex task, and is certainly an article in itself. If you’re curious, hold down the delete key during boot-up to see the BIOS configuration screen. Control is passed from here to the boot loader.

The beginning of the POST
The beginning of the POST

The boot loader is a very small program that lives on the hard drive. It is not stored as a file, since that requires a file system—and one doesn’t exist yet since we haven’t loaded an operating system. So instead, it is stored in the very first 512 bytes of the disk (also known as the master boot record, or MBR). The BIOS only needs to know the physical layout of the hard drive (which it obtains from the POST) to load this program into memory, and execute it.

Typical configuration data discovered by the BIOS
Typical configuration data discovered by the BIOS

The whole boot process follows this pattern of small incremental steps; each doing a specific job, and passing control to the next program. The term “boot” stems from the phrase “bootstrapping”, meaning to lift yourself up by your bootstraps.

The term “boot” stems from the phrase “bootstrapping”, meaning to lift yourself up by your bootstraps

The boot loader program itself is operating system-independent. Indeed, one boot loader can provide you with access to several OSes, often through a basic menu screen, facilitating a dual-boot machine. Most GNU/Linux distributions ship with a choice of two boot loaders, Lilo and GRUB. Lilo, for example, uses /etc/lilo.conf to determine which kernel, or kernels, can be loaded at boot time. This file can also be used to pass options from Lilo into the kernel. In order to create or change the Lilo boot loader you need to edit /etc/lilo.conf and run the /sbin/lilo program. This takes the loader and places it directly into the MBR. The most common change of this kind occurs after compiling a new kernel, as the boot loader needs to know where the new kernel lives. Since 512 bytes doesn’t provide much room for code, most boot loaders are (transparently) loaded in two parts. The next evident activity comes from the kernel, in this case, Linux.

Linux, regardless of version, will always issue a flood of messages to the screen as it runs. These describe the computer system, as the kernel sees it, to aid troubleshooting. The messages themselves are also written into a log file at /var/log/kern.log, or can be retrieved using the dmesg command.

The kernel doesn’t have any programs to manage yet, so it does little more than initialize itself. This includes preparation of the all-important file system. Most file systems will be built into the kernel

directly, but for some drivers (such as SCSI) these will be loaded into the RAM disk.

The RAM disk (or initdisk or initrd) is a memory-based file system that is created by the boot loader before Linux is run. A more exotic system configuration can be created using the /linuxrc file to load other drivers, or mount additional components into the file system. Linuxrc may be either a program, or a script. However, the latter would require a shell interpreter in order to run, and is thus rarer.

The Linux kernel, as its final act during boot-up, runs init. This is a program normally stored as /sbin/init.

Alternate locations for init

By default, init will live in /sbin/init, and is the first place the kernel will look, followed by /etc/init and /bin/init, in that order. Should all of these fail, a shell (/bin/sh) will be executed instead, enabling you to recover the system. You can also specify a different location for init by passing it as an argument to the kernel. Lilo users, for example, can include an append line in lilo.conf to use a completely different program. This line can also specify a runlevel that will take precedence over the one in inittab.

append="init=/sbin/myinit 5"

It is init, and not the kernel, which then configures the system, starts services (a more correct term for applications such as Apache) and opens virtual terminals. And this is where the real fun begins!

Once the kernel has started

init prepares the machine to work in a particular way: what software should be running, what terminals should be open, and which network services are to be allowed. It does this using runlevels. A runlevel describes the basic running state of the system, so naturally you can only be in one runlevel at a time.

A runlevel describes the basic running state of the system

There are a number of runlevels that are, by convention, used to describe a working Linux system, with 2 or 3 being usual for a multi-user configuration. The complete list is given below (according the Linux Standards Base - LSB).

  • Runlevel 0 (halt) - Shuts down everything and brings the system to halt.
  • Runlevel 1 (single user) - Useful for maintenance work.
  • Runlevel 2 (multi-user) - multi-user, but with no network services exported.
  • Runlevel 3 (multi-user) - normal/full multi-user mode.
  • Runlevel 4 (multi-user) - reserved for local use. Usually the same as 3.
  • Runlevel 5 (multi-user) - multiuser, but boots up into X Window, using xdm, or similar.
  • Runlevel 6 (Reboot) - As 0, but reboots after closing everything down.

Most systems default to 2, 3 or 5.

Although the kernel starts init at the default runlevel, this can be changed at any time, provided you are the superuser, without rebooting your computer.

# init 2

This will switch the system into runlevel 2, starting all services that should be running at this runlevel, and killing those that shouldn’t. Using runlevels as a profile in this manner lets you remove services during system maintenance, such as the network, very simply.

Looking at the runlevel table again you will notice runlevel zero is called “halt”. This is not a misprint! Since a runlevel describes what services should be running, switching to a runlevel that closes all of its services and runs a program to halt the processor would be a considered shutdown procedure. Therefore:

# init 0

is equivalent to the more descriptive:

# shutdown -h now
Don't miss out on the other pages!
123next ›last »

Write a full post in response to this!

Similar articles

0

Do you like this post?
Vote for it!

Copyright information

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is available at http://www.gnu.org/copyleft/fdl.html.

Biography

Steven Goodwin: When builders go down to the pub they talk about football. Presumably therefore, when footballers go down to the pub they talk about builders! When Steven Goodwin goes down the pub he doesn’t talk about football. Or builders. He talks about computers. Constantly... He is also known as the angry man of open source. Steven Goodwin a blog that no one reads that, and a beer podcast that no one listens to :)