Report Offensive Message

Understanding OSes: Booting

This is part one of the Understanding OSes series. Find more at the Table of Contents .
When a computer first boots, it starts up the BIOS (Basic
Input-Output System), a sort of rudimentary operating system designed
to work (hopefully) without user intervention. Its purpose is to find
and activate the bare minimum hardware needed to allow the discovery
and activation of an operating system that is actually designed to
interact with the user. The BIOS provides a central sort of
abstraction that accepts input from various devices and offers output
interfaces from which devices can receive data. This allows your
computer to trade information between components so that the processor
can access an operating system on your boot media (hard drive, floppy
disk, et cetera), load necessary bits of it into memory, and ultimately
begin running software so that it interacts with humans in the real
world in some way.

This leads to booting the operating system. Interestingly enough,
the operating system itself then has to redo everything the BIOS did,
but it has to do it in its own (generally much more complex) fashion so
that more than just the bare minimum hardware is detected and
activated, and so that more complex operations can be attempted. This
entire process is referred to as "booting", an evolution of the term
"bootstrapping", which in turn arose from the quaint image of pulling
oneself up by one's bootstraps. The idea is that the OS must create its
own foundation for operation in order to run effectively. It would be
very much like trying to lift oneself off the ground by tugging on
one's bootstraps if the BIOS wasn't there to provide a point of
leverage. In the case of large-kernel OSes (which is to say: anything
you're likely to encounter in a comparative discussion of modern OSes),
there is actually an intermediary step called the "bootloader", because
the BIOS is in fact too limited to access enough system resources to
load the entire kernel all by itself. Instead, it fires up the
bootloader, that intermediary pseudo-OS, which then in turn does for
the operating system proper what the BIOS did for it.

The most fundamental part of the operating system consists of the
kernel. In the process of discovering hardware, activating it, and
creating software interfaces with hardware (usually through the HAL, or
Hardware Abstraction Layer, in modern personal computer OSes), your OS
probably does some autoprobing. What this means is that the kernel's
boot process has a set of data describing hardware types, and it looks
around at what is available to see if anything matches the hardware
definitions in that set of data. It thus probes for hardware and keeps
track of what it finds. Where it's looking for this data is at I/O
ports, which are "addresses" of data buses. A data bus is basically a
pathway along which data can travel between hardware components, and
I/O ports are bus addresses that relate to data input and output
functionality.

If you're using an operating system that displays the results of
hardware autoprobing, you'll see a series of text messages on the
monitor of your computer (or hear it on a speech-only system, or
whatever suits your particular setup; for all I know, some of you might
operate systems by smell, though that would certainly require a very
customized setup). As it recognizes hardware at these I/O ports, your
OS kernel in some manner loads drivers: software components that
provide a means of communication between the hardware components and
the internal workings of the OS. In most modern OSes, there is a
particular part of the kernel whose job it is to gather input from
hardware and provide it to the rest of the kernel, and to pass kernel
output on to the I/O ports. That part of the kernel is the HAL, and it
provides a means for most of the kernel to be the same no matter what
hardware platform is being used to run the OS. Only the drivers and HAL
need to change between hardware platforms, providing for a great deal
of OS portability so that the hardware doesn't always have to be
exactly the same.

This all leads us to the first two major sticking points in
comparing the major personal computer OSes with which we're familiar.
How autoprobing is handled and how the HAL is designed create
significant differences in how the OS behaves under certain
circumstances. DOS and Windows (which inherits its autoprobing
capability almost unchanged from DOS, even after all this time) use a
very rigid, inflexible mechanism for hardware autoprobing. This
mechanism is bad at identifying hardware because it doesn't listen very
well. What it does, in general, is ask each I/O port "Are you this?"
over and over again for many values of "this", where each "this" is
some piece of hardware the OS has been told to expect. If you have
installed drivers tailored for a given piece of hardware at a given I/O
port, the kernel will default to that driver first and ask the hardware
"Are you this, for which I have a driver?" When there are no specific
drivers, the kernel must try only the very limited set of options given
to it at the "factory", one at a time, until it finds something that
looks like a match.

If you happen to have more than one set of drivers installed that a
particular type of hardware's answer might resemble, you might get a
hardware conflict situation. A piece of hardware that lurks beyond a
given I/O port will be asked "Are you this?" and will respond "I fit
that description", but if the driver is actually for another piece of
hardware that is simply similar enough that the OS isn't sure how to
differentiate, you get the wrong driver associated with a piece of
hardware. The autoprobe then fails. Microsoft tried to solve much of
this by introducing the PnP (Plug and Play) system, which essentially
consists of a huge database of drivers pre-installed but only activated
when hardware matches up with them, and by increasing the number of
characteristics the kernel uses to describe a hardware expectation when
probing at a given I/O port. This creates an inversely proportional
relationship between the amount of time spent autoprobing and the
likelihood that the right drivers will be identified for a given piece
of hardware.

The various unices tend to differ somewhat in how good they are at
autoprobing. This difference largely depends on how much developer time
has gone into hardware interaction performance for a given unix OS.
Some unices have placed more focus on security utilities, some on
number-crunching, and so on. Linux has, from the beginning, had a lot
of attention lavished on the performance of the kernel in relation to
hardware. One benefit of this has been a lot of attention on
autoprobing, and as a result the Linux kernel is very, very good at
autoprobing. It basically listens better than most other OSes, and is
designed to be very good at handling the data it gets from I/O ports
during autoprobing to choose driver modules. The term "driver modules"
will come up again later, by the way, in another of these articles.

There are those who theorize that it is the cleverness of the Linux
kernel's autoprobing that allowed it to be as rapidly successful among
developers (who are also users) as it has been. By being good at
autoprobing, it was easier to install than other unices: unices in
general have lacked "user friendly" installers for years, with the
exception of those proprietry unices that have been closely wedded to
proprietary hardware platforms so that autoprobing is largely
unnecessary. This means that the user who wishes to install a unix on a
given computer must do so with a fairly rudimentary installation
interface, if there is a cohesive installer at all. With the original
Linux installations, this actually had to be accomplished with no
installer whatsoever. Instead, a boot floppy was used to get started,
and part of the process involved compiling a kernel from source on the
machine on which you plan to run it. For those who know this process,
at least in theory, no further explanation is needed. For those who
don't, suffice to say that it is a long, involved process, and largely
irrelevant for this exposition on the OS boot process.

If it wasn't for the fact that it is as good at autoprobing as it
is, Linux would have taken much longer to move beyond that stage and
further advance in market share and mindshare. It attracted developers
because it is a unix, with all the power and flexibility that implies,
and because it was much easier to install than its brethren. Being an
open source project, the Linux kernel's popularity among developers
also ensured that it got more development, not only in improving on its
already clever autoprobing capability, but also on everything else it
did. As such, it broke away from the pack early and gained popularity,
performance, and functionality more quickly than it would otherwise
have done. That's the theory, anyway, and that's why it's now looking
at the situation of being a real contender for market niches previously
thought to be the sole province of Microsoft and Apple, with
bit-players like Amiga, BeOS, and NeXTstep momentarily hovering at the
fringes as technically superior, but undermarketed, alternatives.

Once hardware is identified, and drivers are in place, the first
stage of the boot process is complete. Your computer has reached what
unix hackers often call "run level 1". The next step involves running
an initiating process, often called "init". This process checks storage
media out and starts up other processes, such as unix daemons and
Windows services running in the background. These are the programs like
print spoolers, incoming mail listeners, and local web servers, which
are always paying attention for possible incoming instructions whether
from the network or from user applications that might call on them.
Once these background processes are running, the initiating process
will start up your interface (at least, that's the order of things in
theory, though Windows often violates that and unices can be made to do
so with startup scripts). In unices, getty (or equivalent) is started
to watch consoles for command line input at the shell. In Windows, a
GUI environment is started immediately, and in modern Windows versions
the console input processes aren't started at all unless the user or
some user application accesses the command line.

Then, finally, user applications and high-level demons and
background services are started. While your network may be initiated
early in the init process in Linux, for instance, networking servers
(such as an SSH server, an FTP server, and so on) are started after the
basic interface processes are begun. The same holds true for Windows.
This is because such processes actually use the interface as part of
their operation. Where the default interface is the GUI (Graphical User
Interface), where any CLI (Command Line Interface) is actually an
application running inside the GUI, this imposes quite a lot of
resource overhead on the operation of such services. This is part of
the reason that so many services in Windows have been incorporated into
the ever-more bloated kernel, and that those that haven't been
incorporated into the kernel often make use of services that behave in
unsafe ways such as by inappropriate use of RPCs (Remote Procedure
Calls), in an attempt to recapture performance otherwise lost to the
GUI's RAM and CPU demands. Such tricks to bypass the security enforced
by a strict separation of system processes from user processes are not
necessary with unices because of the fact that the GUI isn't integral
to the OS, and thus doesn't impose the same resource inefficiency on
the higher level services.

I don't mean to suggest, of course, that these are the only reasons
such things happen, or that these are the only consequences that
proceed from those causes, but they are the most relevant to this topic.

This concludes part one of the Understanding OSes series. Part two is Understanding OSes: Kernel Modularity
Posted by apotheon
Updated - 3rd Aug 2005