This will document the x86 boot process from a linux perspective. This document will attempt to provide a technical overview if you are not comfortable with hexidecimal, octal or binary you might want to brush up on them first.


Order of boot

  1. The BIOS completes it’s check (memory, cpu, video)
  2. The BIOS execututes the master boot code in the MBR
  3. The master boot code then has two functions identify any active partitions and any extended partitions.
  4. If the master boot code identifies a extended partition it follows the link to the extended partition and so on until it finds no additional partitions.
  5. The master boot loader moves to the active partition and turns over booting to that partition.
  6. The boot loader enters stage 1
  7. The boot loader enters stage 1.5 and displays the menu
  8. The boot loader enters stage 2 and waits for user input or default selection timout
  9. The Kernel initilizes the hardware.
  10. The boot loader loads drivers and modules out of the initrd in /boot/initrd
  11. The boot loader turns over booting to the kernel
  12. /sbin/init executes the rest of the system.
  13. int starts the run level scripts

The boot process starts with a 512 byte piece of code called the master boot record. The MBR is stored on the first 512 bytes of a drive. The BIOS accesses this section and it contains code that points to the rest of the boot process. The master boot record contains the partition table, bootloader and a section called the magic number. The bootloader takes the first 446 bytes. The partition table takes the next 64 bytes. The magic number takes the last 2 bytes.


The magic number is used as a crc check for your mbr it should always contain 0xAA55. You can dump the mbr on your system using:
dd if=/dev/hda of=/mbr.dump bs=512 count=1
This will dump the first 512 bytes of your hda drive to the file /mbr.dump. You can also rewrite this mbr to the file system using:
dd if=/mbr.dump of=/dev/hda bs=512 count=1
You can use strings to view the current boot loader:strings /mbr.dump

You can view the partitions on the disk by using:file /mbr.dumpThis will produce a output listing partitions and start and stop sectors:x86 boot sector;
partition 1: ID=0x83, starthead 1, startsector 63, 417627 sectors;
partition 2: ID=0x82, starthead 0, startsector 417690, 2104515 sectors; partition 3: ID=0x83, starthead 0, startsector 2522205, 4209030 sectors;
partition 4: ID=0xf, active, starthead 0, startsector 6731235, 149565150 sectors, code offset 0x48
You can see that partition 4 is active the ID displays a the type of partition. You can find a list of partition ID codes Here. Since each sector has 512 bytes we can find the size of each partition: For example partition 1 is 417627 sectors. You can find the size using:echo $(((417627/2)/1024))You can compare this information to a df -k outputFilesystem 1K-blocks  Used      Available Use%  Mounted on
/dev/hda5 20641788    5464224   14128924  28%   /
/dev/hda6 52964408    4147160   46126764   9%   /home
/dev/hdc1 244076732   100537572 143539160 42%   /data

You can dump hex of the mbr using: od -Ad -tx1 /mbr.dump

You can also dump it using hexdump

Color Description
RED Boot Loader
GREEN 1st Partition table
YELLOW 2nd Partition table
BROWN 3rd Partition table
PINK 4th Partition table
BLUE Magic Number

You can also do a hex dump using xxd /mbr.dump


You can manually decode the partition table using the following
information. Remember to flip the bytes to get the correct order e.g
0080 becomes 80 00.

Offset Size Description
0x00 1 byte Active flag 0x80 active otherwise 0x00
0x01 3 bytes Cylinder-head-sector address of the first sector in the partition
0x04 1 byte Partition type
0x05 3 bytes Cylinder-head-sector address of the last sector in the partition
0x08 4 bytes Logical block address of the first sector in the partition
0x0C 4 bytes Length of Parition in sectors

Decoding CHS

The CHS is used to decode the location of the first of the
partition if that location exists within the first 1024 cylinders of
the hard drive. When the location goes beyond that location the CHS
value is normaly set to the max values of 1024,254,63 or FE FF FF.
Decoding the values can be a challenge without switching to the binary
value. They are stored in the order of head, sector, and cylinder, the
cylinder value requires more than 8 bits (1 byte) the sector value uses
less than 8 bits, so you have to convert the values to binary to decode them:

If the ending value for cylinder is 1023 or above then you have to figure out the ending location by adding the size to the starting location.

Grub stands for GRand Unified Bootloader. It is the most common boot loader for linux today. The boot process with GRUB is as follows:

  1. Starts executing bootloader code (GRUB stage 1) (boot.img).
  2. Bootloader jumps to the sector number of next stage. The stage 1.5 located in the “DOS compat space” immediately after the MBR.
  3. Stage 1.5 loads the file system and make full drive size available for loading. (diskboot.img+kernel.img+pc.mod+ext2.mod)
  4. Stage 2 takes over and loads the boot menu. (normal.mod+_chain.mod)
  5. After your selection the operating system is loaded.
Grub files are located in /boot/grub here you can find the stage1 stage2 and the menu.1st or grub.conf files. The configuration is done in the menu.1st or grub.conf file.

To reinstall grub in your mbr type:grub-install /dev/hda      Configuration for grub is done inside grub.lst (normally in /boot/grub/grub.lst) this file has the following settings:# Comments inside grub.lst ae done with a hash mark (#)


# default defines the default choice to boot without user interaction
default 0
# Time out sets how long the boot menu will display before it loads default
timeout 30
# fallback provides a another choice in case default fails.
fallback 1
# hiddenmenu allows you to choose not to display the boot menu instead boot the default
# hiddenmenu
# OS definitions begin with a title title is what is displayed on the screen to the user
title openSUSE 10.2 –
# After the title description everything that follows is part of the same boot loader until the title tag appears again.
# Common entries in linux are root, kernel, and initrd
# root defines the root partition and tries to get the size of the partition hd0 partition 4
root (hd0,4)
# kernel attempts to load the kernel image off the root device
kernel /boot/vmlinuz- root=/dev/hda5 vga=0x31a resume=/dev/hda2 splash=silent showopts
# initrd Load an initial ramdisk (allows you to modify the kernel without a recompile
initrd /boot/initrd-
Command Line Options
While at the boot menu you can also pass grub command line variables like what runlevel to boot into or additional options. To choose the run level to boot the kernel into:

  • On the graphical menu highlight the kernel you wish to boot
  • Press the e button to edit the kernel selection
  • At the prompt type the number of the run level you wish to boot into (1 to 5) single or emergecy
  • Once returned to the grub menu press b too boot the kernel and runlevl selection

  • Ctrl-X to get boot:
  • Type linux runlevel


Once the boot loader has reached second stage it reads it’s configuration ahd displays a menu of available kernels to boot. Once the user or boot loader determines what kernel to load stage two boots the kernel file off the /boot partition. Once the kernel is loaded the first step is to initialize the hardware. Then the kernel loading is reading the initrd image this file contains drivers required by the kernel to load scsi devices and ext3 file systems. Once initrd image is completely loaded the boot loader turns the booting process over to the kernel file. The kernel creates a read-only root device and mounts it. At this point the kernel is loaded but since no user space files are loaded you cannot interact with it. This is where /sbin/init takes over.


init is what process the rest of the boot and provides the user environment. init becomes the parent or grandparent process for all processes on a system it has a pid of 1 always. It first runs the /etc/rc.d/rc.sysinit script that starts swap, system clock, check file systems and many other processes. It the runs /etc/inittab which sets up the run levels.



A runlevel is a collection of scripts used to start applications and services used by a system.  Linux supports multiple runlevels.  You can change between runlevels very quickly on a Linux system dismounting file systems as you go.  The configuration for the runlevels is done inside the /etc/inittab file.  You can find the default runlevel inside inittab:


The default run level on this system is 5 which is multiuser with graphical X windows interface.  inittab also possibly defines:

  • First script to be executed before runlevels /etc/init.d/boot
  • Defines the RC scripts to be executed with each run level
  • It also defines special keyboard commands
  • The getty-programs for each run level

    The /etc/init.d/boot defines the following settings:

  • Sets the terminal size and dimentions for the terminal
  • Starts the initial boot messages and coloring
  • Sets up /proc /sys /dev /sys/kernel/debug
  • Starts user defined scripts boot.local

The default runlevels for Linux are:

Runlevel  State 
 0  Shutdown
 1  Single User Mode
 2  Multiuser without network
 3  Multiuser text based
 4  Unused
 5  Multiuser with Graphical X
6  Reboot

You can quickly change the runlevels using:

init runlevel

Each runlevel executes the scripts contained inside /etc/init.d/rc_runlevel.  The scripts inside here are normaly symbolic links to scripts inside /etc/init.d/ these scripts should take at least two variables stop and start.  The links inside /etc/init.d/rc_runlevel are of two types kill (K) scripts and start (S) scripts.  The type is followed by a two digit number used to denote the order inside this runlevel for the script to be executed.  For example:

# ls -al
total 8
drwxr-xr-x  2 root root 4096 Sep  2 21:52 .
drwxr-xr-x 11 root root 4096 Nov 16 20:25 ..
lrwxrwxrwx  1 root root    9 Sep  2 21:52 K02single -> ../single
lrwxrwxrwx  1 root root   12 Sep  2 21:52 K13microcode -> ../microcode
lrwxrwxrwx  1 root root    9 Sep  2 21:52 K13splash -> ../splash
lrwxrwxrwx  1 root root    8 Sep  2 21:52 K21fbset -> ../fbset
lrwxrwxrwx  1 root root   15 Sep  2 21:52 K21irq_balancer -> ../irq_balancer
lrwxrwxrwx  1 root root    8 May 19 10:46 S01fbset -> ../fbset
lrwxrwxrwx  1 root root   15 May 19 10:45 S01irq_balancer -> ../irq_balancer
lrwxrwxrwx  1 root root    6 May 19 10:47 S09kbd -> ../kbd
lrwxrwxrwx  1 root root   12 May 19 10:51 S09microcode -> ../microcode
lrwxrwxrwx  1 root root    9 May 19 10:47 S09splash -> ../splash
lrwxrwxrwx  1 root root    9 May 19 10:47 S20single -> ../single
You can see that I have many files that start as part of runlevel 1 for example S09splash starts before S20single.  It is very easy to automatically add an item to a run level using chkconfig in linux.  For example if I wanted to see if a script in /etc/init.d is started at runtime use the following command:

# chkconfig -l apache2
apache2  0:off  1:off  2:off  3:on   4:off  5:on   6:off

chkconfig can also be used to turn on specific run levels using

#chkconfig service_name runlevel/runlevels 

For example:

#chkconfig apache2 235

Will start the apache2 script in /etc/init.d on runlevel 2, 3 and 5.  You can manually add the links using ln.  Also running chkconfig alone will display all scripts and they status at the current run level or chkconfig -l will display all runlevels.




© 2013, Joseph Griffiths. All rights reserved.

Leave a Reply