A Guided Tour of a Linux Boot

The firmware and software programs output various messages as the computer and Linux come to life. These notes attempt to help clarify what routines and devices are doing.


Craig Van Degrift / craig@yosemitefoothills.com / revised December 8, 1999
  1. The Motherboard BIOS Triggers the Video Display Card BIOS Initialization

    The Matrox Millennium adapter BIOS sends the following to the screen:

    MATROX POWER GRAPHICS ACCELERATOR
    
    MGA Series
    
    VGA/VBE BIOS, Version V2.2
    Copyright (C) 1995, Matrox Graphic, Inc.
    Copyright (C), LSI Logic Corporation, Inc. 1990-1991
    
    

    The screen is cleared.

  2. Motherboard BIOS Initializes Itself

    The Motherboard BIOS sends the following to the screen:

    *Award Modular BIOS  v4.60PGA, An Energy Star Ally
    Copyright (C) 1984-98, Award Software, Inc.
    
    Version 1.15JE33
    
    Cyrix M II/IBM 6x86MX-233 CPU Found
    
    Memory Test: 131072K OK
    
    Award Plug and Play BIOS Extension v1.0A
    Copyright (C) 1998, Award Software, Inc.
    
    
    Press DEL to enter SETUP
    11/19/1998 - VP3 - 536B - W877 - 2A5LEF09C - 00  
    

    The screen is cleared.

  3. SCSI Controller BIOS Initializes

    The SCSI controller BIOS sends the following to the screen:

    Adaptec AHA-2940 Ultra/Ultra W BIOS v 1.23
    (c) 1996 Adaptec, Inc. All Rights Reserved.
    <<< Press <Ctrl><A> for SCSISelect(TM)
    
    
    SCSI ID:LUNNUMBER #:# 0:0 - MICROP  3243-19 1128RQAV - Drive C: (80h)
    SCSI ID:LUNNUMBER #:# 1:0 - SEAGATE ST51080N         - Drive D: (81h)
    SCSI ID:LUNNUMBER #:# 2:0 - HP      C2520A
    SCSI ID:LUNNUMBER #:# 5:0 - Sony    CD-R-625
    
    Bios installed successfully!
    

    The screen is cleared.

  4. Hardware Summary

    The motherboard BIOS then displays the following summary of its hardware inventory:

    Award Software, Inc.
    ________________________________________________________________________
    |
    | CPU Type     : Cyrix M II/IBM 6x86MX     Base Memory    :      640K  |
    | Co-Processor : Installed                 Extended Memory:   130048K  |
    | CPU Clock    : 233                       Cache Memory   :     1024K  |
    ________________________________________________________________________
    |
    | Diskette Drive A: 1.44M, 3.5 in.        Display Type       : EGA/VGA |
    | Diskette Drive B: 1.44M, 3.5 in.        Serial Port(s)     : 3F8 2F8 |
    | Pri. Master Disk: None                  Parallel Port(s)   : 278     |
    | Pri. Slave Disk : None                  Bank 0/1 DRAM Type : None    |
    | Sec. Master Disk: None                  Bank 2/3 DRAM Type : EDO     |
    | Sec. Slave Disk : None                  Bank 4/5 DRAM Type : EDO     |
    ________________________________________________________________________
    

    And Runs its Virus checking code that looks for changed boot sectors.

    !!!! Trend ChipAwayVirus  On Guard !!!!
    Now Detecting Boot Sector Type Virus...
    ChipAwayVirus BIOS Version 1.62
    Verifying DMI Pool Data.......
    

    The screen is cleared.

  5. OS/2 BootManager Menu

    The Master Boot Record (MBR) on the first hard disk is read, by DOS tradition, into address 0x00007c00, and the processor starts executing instructions there. This MBR boot code loads the first sector of code on the active DOS partition. In my case this is the OS/2 BootManager which displays the following menu of OS choices:

    ________________________________________________________________________
    |                                                                      |
    |                            Boot Manager                              |
    ________________________________________________________________________
    |
    |    DOS 7.1       Disk 1    C:Primary     408M        FAT             |
    |    OS2Warp4      Disk 1    E:Logical    2573M        HPFS            |
    |    TinyWarp      Disk 1    F:Logical     142M        HPFS            |
    |    BigLinux      Disk 2      Logical    1020M        Type 83         |
    |                                                                      |
    ________________________________________________________________________
    |                                                                      |
    | Timer Disabled, a timeout boot will not occur                        |
    |                                                                      |
    | Use ^ or V to select.  Press Enter to boot.                          |
    ________________________________________________________________________
    
  6. Lilo is started

    If the BigLinux selection is chosen and if Linux has been installed with Lilo, Lilo is loaded into address 0x00007c00.

    Lilo prints

    LILO
    

    with its progress revealed by individually printing the letters. The first "L" is printed after Lilo moves itself to a better location at 0x0009A000. The "I" is printed just before it starts its secondary boot loader code.

    Lilo's secondary boot loader prints the next "L", loads descriptors pointing to parts of the kernel, and then prints the final "O". The descriptors are placed at 0x0009d200.

    The boot message and a prompt line, if specified, are printed. The pressing "Tab" at the prompt, allows the user to specify a system and to provide command-line specifications to the Linux Kernel, its drivers, and the "init" program. Also, environment variables may be defined at this point.

    The following line is from /boot/message:

    >>> Press <TAB> to list available boot image labels.
    

    The following line is the prompt from /sbin/lilo:

    boot:
    

    Note: If Lilo is not used, then the boot code built into the head of the Linux kernel, linux/arch/i386/boot/bootsect.S prints "Loading" and continues.

    Lilo displays the following as it loads the kernel code. It gets the text "Linux-2.2.12" from the "label=..." specification in lilo.conf.

    Loading linux-2.2.12..........
    
  7. The Linux Kernel Initializes

    The kernel code in /linux/arch/i386/boot/setup.S arranges the transition from the processor running in real mode (DOS mode) to protected mode (full 32-bit mode). Blocks of code named Trampoline.S and Trampoline32.S help with the transition.

    Small kernel images (zImage) are decompressed and loaded at 0x00010000. Large kernel images (bzImage) are loaded instead at 0x00100000. This code sets up the registers, decompresses the compressed kernel (which has linux/arch/i386/head.S at its start), printing the following 2 lines from linux/arch/i386/boot/compressed/misc.c

    Uncompressing Linux... Ok. Booting the kernel.
    

    The i386-specific setup.S code has now completed its job and it jumps to 0x00010000 (or 0x00100000) to start the generic Linux kernel code.

    This is the end of the messages saved in the kernel and available by using /bin/dmesg.

  8. Init Program (Process 1) Startup

    The program /sbin/init is started by the "idle" process (Process 0) code in linux/init/main.c and becomes process 1. /sbin/init then completes the initialization by running scripts and forking additional processes as specified in /etc/inittab. It starts by printing:

    INIT: version 2.76 booting
    

    and reads /etc/inittab, a copy of which follows:

    # /etc/inittab: init(8) configuration.
    # $Id: inittab,v 1.8 1998/05/10 10:37:50 miquels Exp $
    
    # The default runlevel.
    id:2:initdefault:
    
    # Boot-time system configuration/initialization script.
    # This is run first except when booting in emergency (-b) mode.
    si::sysinit:/etc/init.d/rcS
    b::boot:echo "INIT: boot action..."
    bw::bootwait:echo "INIT: boot wait action - sleeping 5 seconds..."; sleep(5); echo "done napping..."
    
    # What to do in single-user mode.
    ~~:S:wait:/sbin/sulogin
    
    # /etc/init.d/rc executes the Snn and Knn scripts in order upon change
    # of runlevel.
    #
    # Runlevel 0 is halt.
    # Runlevel 1 is single-user.
    # Runlevels 2-5 are multi-user.
    # Runlevel 6 is reboot.
    
    l0:0:wait:/etc/init.d/rc 0
    l1:1:wait:/etc/init.d/rc 1
    l2:2:wait:/etc/init.d/rc 2
    l3:3:wait:/etc/init.d/rc 3
    l4:4:wait:/etc/init.d/rc 4
    l5:5:wait:/etc/init.d/rc 5
    l6:6:wait:/etc/init.d/rc 6
    
    # The following run when you do 'telinit A' or 'telinit B' and are disconnected from
    # getting Ctrl-C, Ctrl-\, and Ctrl-Z from the keyboard.  Ctrl-D will logout from the
    # current version of bash that has been temporarily replaced by the "demand" program.
    # The demand program's parent is init, not bash, and bash can still be used even
    # though the output from the demand program is going to the same terminal.
    #
    la:A:wait:/home/c/sigplayposix
    lb:B:wait:/home/c/sigplayold
    # Normally not reached, but fallthrough in case of emergency.
    z6:6:respawn:/sbin/sulogin
    
    # What to do when CTRL-ALT-DEL is pressed.
    ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now
    
    # shutdown -t1 => 1 second pause before shutdown
    # shutdown -a  => use /etc/shutdown.allow (root always allowed)
    # shutdown -r  => reboot after shutdown
    # shutdown -h  => halt after shutdown
    
    # What to do when the power fails/returns.
    pf::powerwait:/etc/init.d/powerfail start
    pn::powerfailnow:/etc/init.d/powerfail now
    po::powerokwait:/etc/init.d/powerfail stop
    
    # /sbin/getty invocations for the runlevels.
    #
    # The "id" field MUST be the same as the last
    # characters of the device (after "tty").
    #
    # Format:
    #  <id>:<runlevels>:<action>:<process>
    1:12345:respawn:/sbin/agetty 9600 tty1
    2:2345:respawn:/sbin/agetty 9600 tty2
    3:2345:respawn:/sbin/agetty 9600 tty3
    4:2345:respawn:/sbin/agetty 9600 tty4
    5:2345:respawn:/sbin/agetty 9600 tty5
    6:2345:respawn:/sbin/agetty 9600 tty6
    
    x:5:respawn:/usr/X11R6/bin/xdm -nodaemon
    
    #n1:234:wait:/etc/init.d/rc.inet1
    #n2:234:wait:/etc/init.d/rc.inet2
    
    # Example how to put a getty on a serial line (for a terminal)
    #
    #T0:23:respawn:/sbin/getty -L ttyS0 9600 vt100
    #T1:23:respawn:/sbin/getty -L ttyS1 9600 vt100
    
    # Example how to put a getty on a modem line.
    #
    #T3:23:respawn:/sbin/mgetty -x0 -s 57600 ttyS3
    

    When this is processed at the very end of the booting process, the following lines are printed:

    Activating swap...
    Checking root filesystem...
    Parallelizing fsck version 1.04 (16-May-96)
    Checking all file systems.
    [/sbin/fsck.ext2]fsck.ext2 -a /dev/sdb5
    /dev/sdb5: clean, 26562/261120 files, 545241/1044193 blocks
    Checking all filesystems...
    Parallelizing fsck version 1.04 (16-May-96)
    /dev/sda2: clean, 28715/376832 files, 1174190/1502077 blocks
    /dev/sda7: clean, 450/26104 files, 15544/104391 blocks
    Mounting local file systems...
    /proc on /proc type proc (rw)
    /dev/sda2 on /mnt/extra type ext2 (rw)
    /dev/sdia7 on /mnt/backup type ext2 (rw)
    Telling the kernel that the machine time is local, not GMT
    Mon Nov 29 19:47:59 PST 1999
    Cleaning up: /tmp /var/lock /var/run.
    Starting System logger: syslogd.
    Starting Kernel logger: klogd.
    
    Starting BSD Printer daemon lpd: lpd.
    Initializing random number generator... done.
    INIT: Bootwait action - sleeping 5 seconds...
    INIT: Boot (no wait) - sleeping 15 seconds...
    INIT: Bootwait - Done napping.
    

    Upon entering run level 2 it prints:

    INIT: Entering runlevel: 2
    

    Notice how /sbin/init waited for the bootwait action to finish before going to run level 2, the default runlevel specified by the id:2:default: entry in /etc/inittab. At this point all actions which are associated with runlevel 2 are started. Specifically, for this simplified /etc/inittab these are:

    rc 2
    

    /etc/init.d/rc takes the parameter 2 and walks through each link in the directory /etc/rc2.d, killing ("K") or starting ("S") scripts in the order specified by their numbering ("00" through "99"). An alternate arrangement for these script files has them placed one directory lower in (/etc/rc.d/rc2.d, etc.).

    /etc/inittab also specifies that all 6 virtual consoles shall be set up in run level 2:

    /sbin/agetty 9600 tty1
    /sbin/agetty 9600 tty2
    /sbin/agetty 9600 tty3
    /sbin/agetty 9600 tty4
    /sbin/agetty 9600 tty5
    /sbin/agetty 9600 tty6
    

    Each of the agetty's starts a login shell, /sbin/login, and after a log-in, starts /bin/sh which is typically a symbolic link to /bin/bash.

    At this point most distributions clear the screen and set the cursor set to the top left character.

    For illustrative purposes, I have made my /etc/init.d/rcS script indicate when it is started and we get the following:

    Starting initscript...
    Starting initscript...
    Starting initscript...
    Starting initscript...
    Starting initscript...
    Starting initscript...
    Starting initscript...
    

    /sbin/login copies the file /etc/issue to the screen before prompting for the user name and password:

    Kanji-Flash Softworks
    
    
    Baldy login: INIT: Boot (no wait) - Done napping.root
    
    Password:
    Last login: Mon Nov 29 17:54:57 1999 on tty2
    Linux Baldy 2.2.12 #1 Thu Nov 4 19:44:40 PST 1999 i686 unknown
    
  9. The Bash Shell is Started

    The bash shell, /bin/bash is then started up. Bash initialization begins by executing script in /etc/profile which set the system-wide environment variables:

    # /etc/profile
    # System wide environment and startup programs
    # Functions and aliases go in $HOME/.bashrc
    
    export PATH="/bin:/usr/bin:/usr/X11R6/bin:/opt/bin:/usr/local/bin:/usr/local/java/bin:./"
    
    umask 022
    
    if [ `id -gn` = `id -un` ] && [ `id -u` != 0 ]; then
    umask 002
    fi
    
    if [ -z "$UID" ]; then
    UID=`id -u`
    fi
    
    if [ "$UID" = 0 ]; then
    PATH=/sbin:/usr/sbin:$PATH
    else
    PATH=$PATH:
    fi
    
    export USER=`id -un`
    export LOGNAME=$USER
    export HOSTNAME=`/bin/hostname`
    export LOCATE_PATH=/var/state/misc/locatedb
    

    Next, Bash executes the script in /root/.profile for user-specific customizations:

    # ~/.profile --
    #   The  personal  initialization  file,  executed  for login shells
    
    if [ -n "$BASH_VERSION" ]; then
    if [ -r "$HOME/.bashrc" ]; then
    # login shells are always interactive, are they?
    . $HOME/.bashrc
    fi
    fi
    

    In this case, it merely has the shell execute the script .bashrc in the user's home directory. Both .profile and .bashrc set user-specific customizations, but only .bashrc is run at each shell invocation. .profile is only run at log-in.

    In my case for root, /root/.bashrc contains:

    #Make backspace work as expected by PC users but otherwise leave as expected by remote terminal users.
    if [ -z "$TERM" ]; then
    echo ".bashrc: TERM empty: this shouldn't happen!" 1>&2
    echo "   Please contact 'support@lst.de'" 1>&2
    else
    case $TERM in
    linux*)
    stty erase '^?'
    ;;
    *)
    stty erase '^H'
    ;;
    esac
    fi
    
    #Exports some environmental variables:
    
    #export GROFF_TYPESETTER=latin1
    #export LC_CTYPE=iso-8859-1
    #export METAMAIL_PAGER=less
    
    export LESSCHARSET=latin1
    export PS1="\[\033[0m\033[1;32m\][\d - \@: \w]\\$\[\033[1;37m\] "
    export TERMINFO=/usr/lib/terminfo
    export HISTSIZE=200
    export LD_LIBRARY_PATH=/usr/local/lib
    export PRINTER=magic
    export LS_COLORS='no=01;37:fi=01:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.deb=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.mpg=01;37:*.avi=01;37:*.gl=01;37:*.dl=01;37:'
    
    #Set some aliases:
    
    alias which='type -path'
    alias ll="ls --almost-all -l --classify --full-time --color"
    alias ls="ls -A --color"
    alias showhex="/usr/bin/hexdump -f /etc/hexdump.fmt"
    alias cc="gcc -DEOF=-1 -Wall -lintl"
    alias whatfor="whatfor --color --all"
    alias last="last -n 10 -a -x"
    alias less="less --raw-control-chars --LONG-PROMPT --force"
    alias pssig="ps -sx --forest"
    alias psx="ps -o user,ppid,pid,pgid,tty,stat,command --forest x"
    alias psw="ps -aux --forest"
    
    #Set some key bindings for bash's command line input:
    
    # Home
    bind '"\e[1~": beginning-of-line'
    # Insert
    bind '"\e[2~": abort'
    # Delete
    bind '"\e[3~": delete-char'
    # End
    bind '"\e[4~": end-of-line'
    # Page Up
    bind '"\e[5~": abort'
    # Page Down
    bind '"\e[6~": abort'
    
    #Sets tab stops to every 4th character:
    
    setterm -clrtabs
    setterm -regtabs 4
    

    Finally, bash initialization is complete and we get the bash prompt!!!!!

    [Mon Nov 29 06:33pm: ~]#
    

Last updated: April 8, 2006

Valid CSS!Valid XHTML 1.0 Strict

Contact Craig Van Degrift if you have problems or questions with this web site.