CS HOME   CS 518   PROFESSOR ROSS
LINUX VIRTUAL FILE SYSTEM
CS 518 PROJECT WEB SITE
STUDENTS:
- Leif Wickland  leifw@cs.montana.edu
- Robert Ledford  ledford@cs.montana.edu
LINKS:
Project Home


Presentation (.ppt)

Presentation (.html)

Resources

Notes

IFE Diagram

Boot Process


The Linux Boot Process

   When a computer is turned on, well before the OS (operating system) gains control, the BIOS begins executing. The BIOS (basic input output system) is the software stored in read-only memory which performs basic hardware tests and configures fundamental aspects of the hardware at power up. Once these initial steps are complete, the BIOS searches for a boot record across the available boot devices such as hard drives, floppy drives, and CD-ROM drives. The boot record is stored at a specific location which the BIOS author prescribed and at which the OS author stored a small program called a boot loader. When the BIOS finds a boot loader, it copies the program into memory and transfers execution to the loader.

   The purpose of the boot loader is to copy the kernel, the operating system’s core, into memory. Once the kernel has been copied into memory, the boot loader transfers execution to the kernel. The boot loader has now completed its job.

   When the Linux kernel is copied to memory, only a small part of it is in an executable form; the majority of the kernel is stored in compressed form, in a similar fashion to the way files are stored in a ZIP file. Thus, the first step that the executable portion of the kernel takes is to decompress the remainder of the kernel. Execution then jumps to the decompressed portion of the kernel.

   While storing the kernel in compressed form may seem odd, it is justified. Memory (RAM) is much faster than storage (e.g. a hard drive). Consequently, a smaller, compressed kernel image can be copied from storage and uncompressed faster than a larger kernel can be copied to memory. Secondarily, a compressed kernel takes up less space in storage, which can be an important consideration in embedded systems and other devices with limited storage space.

   The first tasks of the uncompressed kernel are to initialize low-level aspects of the operating system. For example, one of these low-level tasks is to initialize virtual memory by setting up page tables and, if necessary, turning on virtual memory support in the processor. Other low-level tasks performed by the kernel include reading parameters passed from the boot loader to the kernel and detecting features of the host hardware.

   To this point in the kernel’s execution, the source code which produced the kernel was written in assembly language. Assembly language was used so that hardware specific tasks could be written more easily. Finally, the execution of the kernel has reached a point that the majority of tasks will be performed at a higher level and will be more hardware agnostic; consequently, a higher-level programming language can be used more productively to write the kernel. In the Linux kernel, C is the high-level language of choice.

   Initializing vectors for software and hardware interrupts is one of the first high-level tasks performed by the Linux kernel. Interrupt vectors are arrays of memory addresses in which each address points to a subroutine which can handle the trap or interrupt. Software interrupts, or traps, are used, for example, to initiate a system call, which is a function call from a user program to a kernel function. Hardware interrupts occur, for example, when a peripheral device needs to communicate with the processor. Other areas which the kernel needs to initialize include the array of process structures, the system clock timer interval, the file system, and the structures and memory areas related to forking a process or creating a thread.

   Thus far, the kernel has been the only software other than the BIOS to use the computer’s processor or processors. However, for the computer to do meaningful work, the kernel needs to allow other processes to run. These new processes will then use the kernel’s system calls as a set of subroutines. At the point other processes begin to run, the kernel runs in one of two contexts. In one context, the kernel runs as a subroutine of a process in response to a system call or interrupt. In this context, the kernel does not have its own thread of execution; it simply co-opts the execution of the process which was running when the system call or interrupt occurred. In the other context, the kernel does have its own thread of execution; however, it uses its execution to consume clock cycles for which no other process has use. Thus, in this mode, the kernel is called the idle process.

   So, when the kernel has nearly finished initialization, it begins preparing for the transition described above. This transition begins with the kernel adding an entry for itself, as the idle process, in the processes table. Of course, the idle process is given the least possible execution priority. Once the idle process table entry has been created, the kernel performs its first fork to create the first non-idle process, the init process.

   After the fork, the init process will begin execution because it has higher priority than the idle process. The init process is part of the kernel, but it is the kernel’s last throes. Before it gets to its real task, the init process will perform some housekeeping, such as freeing up now unnecessary kernel initialization memory. Another such task is setting up drivers for the computer’s hardware, which like housekeeping may sound simple, but is a great deal of work that no one likes to talk about.

   Once these preliminary tasks are complete, the init process sets to its real task, ensuring its own destruction; it searches a number of predefined locations in the file system for an init program which will start various other system level programs. Once the init program has been located, it is loaded into memory over the top of the init process and begins execution. Thus ends the init process.

   Although the init process has departed, the idle process remains. In fact, the idle process has most likely been executing intermittently since the forking of the init process. At moments when the init process had nothing to do, such as while waiting for the hard drive to return a piece of data, the idle process executed. When the idle process executes, it does as little as possible, periodically looking for a process which is ready to run. So after the kernel has finished the hard work of booting the computer, it settles into the tasks of acting as a subroutine and of executing when no other process has computation to perform.

Montana State University - Department of Computer Science