\documentclass[12pt,a4paper]{article}
\usepackage{times}
\usepackage{html}
\title{Getting Linux into Small Machines}
\author{L.C. Benschop}
\begin{document}
\maketitle

Copyright \copyright{}2002, 2003, L.C. Benschop, Eindhoven, The
Netherlands. Permission is granted to make verbatim copies of this
document. This is version 1.1 which has some minor corrections.

\tableofcontents

\section{Introduction}

This document serves as an instruction to build a minimal Linux system
for use on rescue diskettes, installation diskettes and embedded
projects. 

The Bootdisk Howto from the Linux Documentation Project also describes
how to build a bootable diskette, but a diskette created in this way
has a few shortcomings:
\begin{itemize}
\item It carries a lot of ballast such as {\tt inittab}, {\tt getty} and
  {\tt login}. For a simple to use rescue disk, these programs and their
  associated configuration files are not necessary.
\item It contains full featured GNU shell utilities that occupy a lot
  of space.
\item It contains the real GNU C libraries, which are very large indeed.
\end{itemize}
Therefore a boot disk created in this way contains not many useful
programs and it needs a comparatively large RAM disk to load. If you
have 8MB of RAM, this works, but you can forget this on a 4MB or even
2MB machine. 

There are two excellent software packages that are specially designed
for saving precious memory and disk space when you are on a tight budget:
\begin{itemize}
\item \htmladdnormallinkfoot{Busybox}{http://www.busybox.net} is a
  combination of a Unix shell and many common Unix utility programs in
  a single executable. The size of Busybox is about half that of the
  typical {\tt bash} shell and at that it already contains a few dozen
  Unix commands, ranging from {\tt ls} to {\tt gzip}. These are
  trimmed down versions of course, but adequate in most cases.
\item \htmladdnormallinkfoot{uClibc}{http://www.uclibc.org} is a
  scaled down Unix library. The GNU C library is huge, has every
  feature on the planet and adheres to every conceivable standard on
  every conceivable platform. uClibc is adequate for many applications
  and uses much less space.
\end{itemize}
While the use of Busybox on rescue disks is common, uClibc is rarely
used. There are toolkits to create Busybox based diskettes, but IMHO there is
no good instructional document that describes how to create a bootable Linux
diskette with both Busybox and uClibc. The \htmladdnormallinkfoot{{\tt BootE}
diskette}{http://www.everywhere.dk} is a bootable Linux diskette with {\tt
Busybox} and {\tt uClibc}. When I wrote the original text, there used to be no
instructions on the site how to customize that disk to your needs, but now at
least there is a tar archive with useful scripts and documentation.

In order to achieve huge space savings, we need to recompile
everything from source.

\subsection{The Mission}

Suppose we have an old 386 machine in the basement that comes with
only 4MB of RAM. We want to show our friends that this old beast can
still run Linux. 

We must be able to perform the following tasks:
\begin{itemize}
\item Partition a hard disk.
\item Make a swap partition on the hard disk an use it.
\item Create an ext2 file system on the hard disk and make it usable as the
  root file system. 
\item Mount diskettes and a hard disk.
\item Edit files.
\end{itemize}

So basically we have everything to install a Linux root file system on
the hard disk.

\subsection{What needs to be on the diskette?}

In order to get a Linux system up and running we need the following items:
\begin{itemize}
\item A boot loader. This  program is loaded by the PC BIOS and this
  makes it possible to load another program, such as the Linux kernel.
\item the Linux kernel. This is the heart of the operating system.
\item a root file system. This is the file system that is mounted when
  the kernel is started. The first program that runs (typically {\tt
  /sbin/init} has to be in the root file system. The root file system
  can exist on a diskette, it can be loaded in RAM at boot time or it
  can exist on the hard disk.
\end{itemize}

The root file system has to contain the following items:
\begin{itemize}
\item Binaries that we want to run.
\item Startup scripts and other configuration files.
\item Shared libraries.
\item Device files.
\item Mount points.
\end{itemize}


\subsection{The Host and Target System}

The host system is the computer on which we build the bootable
diskette. It is assumed to be a fairly modern PC with a modern
installation of Linux. We will assume that it is a Pentium with at
least 32MB of RAM.

Also we assume that it contains a modern Linux system that contains
the following software:
\begin{itemize}
\item Linux kernel 2.4
\item recent gcc (2.95 or later)
\item Loop devices (a kernel feature that allows you to mount a file
  system on a file instead of a block device).
\item Bzip2
\item a recent LILO
\end{itemize}

You will need lots of hard disk space. Around 300MB would be
enough. The unpacked Linux kernel source tree alone takes around 150MB
these days. Paradoxically enough the end result will fit on a single
1.44MB diskette.

The target system is an old 386 PC with 4MB of RAM or more and zero,
one or two hard disks.

\section{First Preparation}

First create a directory where we will build the whole project. I
chose the name {\tt myboot}. I will use this name throughout the
document. Type the following command in your home directory:
\begin{verbatim}
mkdir myboot
\end{verbatim}

Obtain the following source packages and collect them into the
directory {\tt myboot}:
\begin{itemize}
\item The Linux kernel. In our example we take version 2.4.18, which
  was the latest version at the time of writing. It may be desirable
  to use a kernel from the 2.2 series instead as it requires less
  memory. Even a kernel from the 2.0 series may do the job, it's still
  maintained, but don't ask me for how long. Download it from the
  \htmladdnormallinkfoot{ main kernel site}{http://www.kernel.org}.
\item The small C library 
  \htmladdnormallinkfoot{{\tt uClibc}}{http://www.uclibc.org}.
\item The shell and utilities 
  \htmladdnormallinkfoot{{\tt Busybox}}{http://www.busybox.net}.
\item The utility programs in {\tt util-linux}. These can be found at
  the main kernel site in the kernel archive, the {\tt utils} 
  subdirectory.
\item The package \htmladdnormallinkfoot{{\tt
  e2fsprogs}}{http://e2fsprogs.sourceforge.net} with programs to create
  and repair file systems. .
\end{itemize}

Some of these packages may already be present in your Linux
distribution. For all packages except {\tt uClibc} and {\tt Busybox}
this is very likely. But of course there may exist more recent
versions.

After you have downloaded all the sources, your {\tt myboot} directory
may look like this. Of course you may have different (more recent)
versions of all programs:
{\scriptsize
\begin{verbatim}
total 27776
-rw-rw-r--    1 lennartb lennartb   613464 Jun  9 11:44 busybox-0.60.3.tar.bz2
-rw-rw-r--    1 lennartb lennartb  1376698 Jun 12 19:56 e2fsprogs-1.27.tar.gz
-rw-rw-r--    1 lennartb lennartb 24161675 Jun  8 19:28 linux-2.4.18.tar.bz2
-rw-rw-r--    1 lennartb lennartb  1170790 Jun  8 19:00 uClibc-snapshot.tar.bz2
-rw-rw-r--    1 lennartb lennartb  1065574 Jun  9 16:01 util-linux-2.11r.tar.bz2
\end{verbatim}
}

So let's unpack what we've got. Type the following commands when
inside the {\tt myboot} directory:
\begin{verbatim}
bunzip2 -c busybox-0.60.3.tar.bz2 | tar xvf -
gunzip -c e2fsprogs-1.27.tar.gz | tar xvf -
bunzip2 -c linux-2.4.18.tar.bz2 | tar xvf -
bunzip2 -c uClibc-snapshot.tar.bz2 | tar xvf -
bunzip2 -c util-linux-2.11r.tar.bz2 | tar xvf -
\end{verbatim}
After this you should have the sources of  the five packages,
each in its own subdirectory.

Note: the {\tt myboot} directory is assumed to be created under a
user's home directory. In several places in this text we will use an
absolute path to this directory and on my system this is 
{\tt /home/lennartb/myboot}. Other users should replace this with their
own home directory.

Note: in this document you see many sequences of shell commands. Of
course you can put them into shell scripts, so you need not retype
them when you try to build a modified boot disk.

\section{Building uClibc}

The trickiest part to get right is probably the C library, especially
because we want to use shared libraries. The space savings are
tremendous and once this is done right, you can fit many more
utilities on a diskette. The directory where the shared libraries exist
on the target system (where they will be used) is different from the
directory where they exist on the host system. Without special tricks,
the binaries that are compiled with {\tt uClibc} won't run on the host
system. 

First create the following subdirectories under the {\tt myboot}
directory.
\begin{itemize}
\item {\tt uclibc-dev} is the directory that contains everything you
  need to compile programs with {\tt uClibc}. Int contains the include
  files for the {\tt uClibc} library and special versions of {\tt gcc}
  and similar programs. In fact it is a kind of cross-compiler, albeit
  for the same processor architecture.
\item {\tt rootfs} is the directory where everything goes that will be
  on your bootable diskette.
\end{itemize}

Next {\tt cd} into the {\tt myboot/uClibc} directory. There run the following
command:
\begin{verbatim}
ln -s extra/Configs/Config.i386 Config
\end{verbatim}

Next edit the {\tt Config} file as follows:
\begin{itemize}
\item Your native compiler will probably compile for a 386. If not,
  you can edit the line with CROSS=
\item Change the line with KERNEL\_SOURCE to
\begin{verbatim} 
  KERNEL_SOURCE=/home/lennartb/myboot/linux
\end{verbatim}
  It is important that this directory matches the kernel that will
  eventually be used on the boot diskette.
\item Check the configuration options. They look reasonable at the
  moment, except that you have to set {\tt LFS = true}. Even though
  large file system support seems unnecessary on old 386 machines with
  hard disks well under 2GB, some programs will complain if it is not there.
\item Below the BIG FAT WARNING: change the line to 
\begin{verbatim}
  SHARED_LIB_LOADER_PATH=/lib
\end{verbatim}
\item Change the line with DEVEL\_PREFIX to 
  \begin{verbatim}
   DEVEL_PREFIX=/home/lennartb/myboot/uclibc-dev
  \end{verbatim}
\end{itemize}

Run the following commands to make and install the library. Note that
we do {\em not} install the library as root as we do not install it in
a system-wide directory.
\begin{verbatim}
make
make install
make PREFIX=/home/lennartb/myboot/rootfs install_target
\end{verbatim}

The first command compiles the libraries, the second command installs
the development code into the uclibc-dev directory and the last
command installs the shared libraries into the rootfs directory. These
will end up on the root file system of the bootable diskette.

Compiling with uClibc can be as simple as putting the {\tt uclibc-dev}
directory first in your path and just running {\tt make}. Note that
you cannot run the programs you have just made on the host system.

\section{Building Busybox}

First {\tt cd} into the {\tt myboot/busybox-0.60.3} subdirectory. 


Edit the file {\tt Conf.h} as follows:
\begin{itemize}
\item Add or remove support for programs you do or do not want. For
  each program there is a {\tt \#define BB\_XXX} line that can be
  commented out or not. Uncomment the BB\_VI line, as you would
  probably need an editor. Leave the network related programs
  commented out if you do not enable network support, otherwise
  uncomment them. In our example we will not use network support. It's
  basically your choice what to put in or not. Though it may be
  possible to start Linux with an interactive shell instead of init,
  we will leave the init program in.
\item Uncomment the {\tt BB\_FEATURE\_USE\_TERMIOS} line.
\end{itemize}

Edit the {\tt Makefile} as follows:
\begin{itemize}
\item Append {\tt -m386} to the {\tt CFLAGS\_EXTRA} line.
\item Uncomment the {\tt CC=} line below the comment about uClibc and
  change it to {\tt CC=/home/lennartb/myboot/uclibc-dev/bin/gcc} 
\item You could enable LFS support, as you already have selected it in
  the {\tt uClibc} library as well.
\end{itemize}

Now build the program.
\begin{verbatim}
make
make PREFIX=/home/lennartb/myboot/rootfs install
\end{verbatim}

Because you have linked with the dynamic {\tt uClibc} library and
these are not installed in the host system's {\tt /lib} directory,
the program cannot run. There is a trick to work around it: by using
the chroot command, you can run a program whose root directory is the
specified directory. Become root and type the following command:
\begin{verbatim}
/usr/sbin/chroot /home/lennartb/myboot/rootfs /bin/sh
\end{verbatim}
The shell that you are now in is the shell inside the\\
{\tt /home/lennartb/myboot/rootfs} directory. This shell thinks that
this {\tt rootfs} directory is in fact the root directory: even the
shared libraries of {\tt uClibc} in the {\tt /lib} directory will be
found. Type the command {\tt ls /} and it will be clear. Exit the {\tt
  chroot} subshell with Control-D and everything will be back to normal.

Now you have most common Unix utilities including an editor and a
shell and you've spent only 576kB of disk space!

\section{Other Essential Binaries}

While Busybox offers us many essential Unix utilities, we still miss a
few essential programs for our mission. We cannot partition a hard
disk and we cannot create or repair ext2 file systems. Busybox can be
made to include {\tt mkfs} and {\tt fsck} for Minix file systems, but
not for the much more common Ext2 file system. Both util-linx and
e2fsprogs complain if you had not built {\tt uClibc} with large file
support.

First start another shell and type the following command:
\begin{verbatim}
export PATH=/home/lennartb/myboot/uclibc-dev/bin:$PATH
\end{verbatim}
From now on, the {\tt uClibc} version of {\tt gcc} will be used
instead of the normal version.

For now we need util-linux only for the {\tt fdisk} utility. The build
procedure is as follows:
\begin{itemize}
\item {\tt cd} into the util-linux source directory.
\item Edit the {\tt MCONFIG} file as follows:
   \begin{itemize}
   \item Change the CPU line near the top of the file to {\tt
   CPU=i386}.
   \item Add another line to the large CFLAGS statement near the
   bottom of the file:
   \begin{verbatim}
      -D__NO_CTYPE \
   \end{verbatim}
   This line must look like the other lines in the same statement,
   including the backslash with a space before it and nothing after
   it. \footnote{This option causes real functions to be used for {\tt
   tolower()} and friends, instead of macros. The macros
   evaluate their arguments twice, where {\tt fdisk} uses a call to an
   input function as argument to {\tt tolower()}.}
   \end{itemize}
\item Run make.
\item Make stops with an error while trying to build {\tt mount}. We
  already have a mount in {\tt busybox}, so we leave it that way.
\item {\tt cd} into the fdisk directory.
\item Run make.
\item Move the file {\tt fdisk} to the directory\\
  {\tt /home/lennartb/myboot/roofts/sbin}.
\end{itemize}

Now we will build e2fsprogs as follows:
\begin{itemize}
\item Create a directory named {\tt build} under the e2fsprogs source
  directory and {\tt cd} to it.
\item Configure and build the programs:
\footnote{The BUILD\_CC option specifies that we want to use the normal
  {\tt gcc} for building a certain program that must be run on the
  host system. Otherwise it would be linked with {\tt uClibc} and
  would not run.} 
\begin{verbatim}
./configure
make BUILD_CC=/usr/bin/gcc
\end{verbatim}
\item Strip and move e2fsck and mke2fs to the {\tt rootfs} directory.
\begin{verbatim}
strip e2fsck/e2fsck.shared
mv e2fsck/e2fsck.shared \
  /home/lennartb/myboot/rootfs/sbin/e2fsck
strip mke2fs
mv misc/mke2fs /home/lennartb/myboot/rootfs/sbin
\end{verbatim}

\end{itemize}

This is the time to build any other programs you will need. Link them
with {\tt uClibc} and move them to the one of the binary
subdirectories in the {\tt myboot/rootfs} directory. If linking with
{\tt uClibc} does not work, try to link statically using the ordinary
{\tt gcc}.


\section{Populating the Root File System}


The binaries and libraries are already installed in the {\tt rootfs}
directory. Now we will complete the root file system.
First create the remaining directories in rootfs.
\begin{verbatim}
cd /home/lennartb/myboot/rootfs
mkdir dev tmp etc proc mnt etc/init.d
\end{verbatim}

Add the device nodes. We will only add the necessary device nodes: two
floppy disks, two hard disks with 8 partitions each and four
terminals. Further we need some memory related devices and a ram
disk. Become root and cd to the {\tt dev} subdirectory in the {\tt
myboot/rootfs} file system.
\begin{verbatim}
mknod fd0 b 2 0
mknod fd1 b 2 1
mknod hda b 3 0
mknod hda1 b 3 1
mknod hda2 b 3 2
mknod hda3 b 3 3
mknod hda4 b 3 4
mknod hda5 b 3 5
mknod hda6 b 3 6
mknod hda7 b 3 7
mknod hda8 b 3 8
mknod hdb b 3 64
mknod hdb1 b 3 65
mknod hdb2 b 3 66
mknod hdb3 b 3 67
mknod hdb4 b 3 68
mknod hdb5 b 3 69
mknod hdb6 b 3 70
mknod hdb7 b 3 71
mknod hdb8 b 3 72
mknod tty c 5 0
mknod console c 5 1
mknod tty1 c 4 1
mknod tty2 c 4 2
mknod tty3 c 4 3
mknod tty4 c 4 4
mknod ram b 1 1
mknod mem c 1 1
mknod kmem c 1 2
mknod null c 1 3
mknod zero c 1 5
\end{verbatim}

Add files in the {\tt /etc} subdirectory. The {\tt init} program from
{\tt busybox} works without a login procedure, so the {\tt passwd} and
{\tt group} files are not really needed. You could of course create
single line versions for the root user and group. Even the {\tt
  inittab} file is not essential and {\tt busybox} provides a
reasonable default. You are free to copy the {\tt scripts/busybox}
file from the source directory and customize it.
The only file I added in {\tt /etc} was {\tt init.d/rcS}, 
which must have execute permissions.
\begin{verbatim}
#!/bin/sh
mount -t proc none /proc
\end{verbatim}

Make all files in the root file system owned by root:
\begin{verbatim}
chown -R 0:0 /home/lennartb/myboot/rootfs
\end{verbatim}

Now we have a complete root file system in a directory. We still need
a kernel and a way to boot. Further we need to transfer the file
system to a floppy disk.

\section{Building a Kernel}

Now it is time to build a kernel. For the target system we will build
a kernel that is different from the host system kernel. W build it
under the {\tt myboot} directory. First {\tt cd} to the {\tt
  myboot/linux} subdirectory.

The most important job is configuring the kernel. Run the following
command:
\begin{verbatim}
make menuconfig
\end{verbatim}
Instead of {\tt menuconfig} you can use {\tt config} (not
recommended!) or {\tt xconfig}. This will give a usable kernel for the
target system.
\begin{itemize}
\item Processor type menu: processor family must be 386, enable math
  emulation, switch off everything else. Most 386 systems have no 387
  coprocessor, so they do need math emulation.
\item General setup menu: switch off networking support, PCI support,
  system V IPC
  and sysctl support. Support ELF binaries, other formats can be
  disabled.
\item Code maturity, Module support, Memory Technology, Parallel port,
Plug and play, Multi-device, Telephony, SCSI, I2O, Amateur radio,
ISDN, Old CDROM, Input core, Multimedia, Sound, USB and kernel hacking
submenus: disable everything.
\item Block device submenu: support floppy, RAM disk and initial RAM
  disk.
\item ATA/IDE/MFM/RLL submenu: support, keep everything under the
  ATA/IDE\ldots{} block devices submenu the default.
\item Character devices submenu: Support virtual terminal, console on
  virtual terminal, Unix 98 PTY, disable everything else.
\item File systems. Keep second extended, proc and dev PTS enabled. If
  you want to mount DOS diskettes, enable fat, msdos and maybe
  vfat. If you want to mount a CDROM, enable ISO9660.
\item Console drivers.  Keep VGA text console enabled.
\item Exit and say Yes to save changes.
\end{itemize}
Of course you must adapt the configuration to the target system you
are using. If your target system has PCI, it would be better to
enable it. In that case, you probably have a 486DX or a Pentium, so
the math emulation may go. If you have SCSI on your target system, you
should of course enable support for it and for the host adapter you
are using. If you have SCSI and no IDE devices installed, you can
disable ATA/IDE/MFM/RLL support.

Now we only need to build the kernel:
\begin{verbatim}
make clean
make dep
make zImage
\end{verbatim}
The kernel described here should be around 400kB and it should work
with {\tt make zImage}. Use {\tt make bzImage} instead if you build a
kernel with more features, e.g. networking support.

\section{Making a Bootable Diskette}

We will describe three methods to boot Linux from a diskette.
\begin{itemize}
\item Booting the kernel directly from a diskette and mount a root
  file system on a different diskette.
\item Booting the kernel with LILO and mount a root file system on a
  diskette (possibly the same diskette).
\item Booting the kernel with LILO and add a RAM disk for the root
  file system.
\end{itemize}
Instead of LILO we could use another boot loader, such as SYSLINUX or
GRUB. This is considered to be outside the scope of this text.

For the boot diskettes we have to
format 1.44MB floppy disks or take formatted disks that may be
erased. In Linux there are two programs to format a diskette. One program is
{\tt fdformat}. A diskette is formatted as follows:
\begin{verbatim}
fdformat /dev/fd0H1440
\end{verbatim}
Some distributions have {\tt superformat} instead. This is used as follows:
\begin{verbatim}
superformat --hd /dev/fd0
\end{verbatim}
We assume 3.5'' HD diskettes and we only format them in the standard
way (1440kB), so we do not try to get a few more sectors per track or
a few more tracks.

All commands in this section should be done as root.

\subsection{Booting Linux directly from a diskette}

We do not have to use a complicated boot loader such a LILO in order
to boot a Linux system. The Linux kernel has its own primitive boot
loader. When the kernel is transferred directly to a diskette with the
{\tt dd} command, the kernel can boot itself. This way we cannot
supply a command line and it works only with diskettes. We also cannot
use the {\tt initrd} feature, but there is a different way of loading
a RAM disk, which we will not discuss (it is discussed in the Bootdisk
HOWTO).

First we have to create a file system on the root diskette and
transfer the files to it. Type the following commands:
\begin{verbatim}
mke2fs /dev/fd0
mkdir /home/lennartb/myboot/mnt
mount /dev/fd0 /home/lennartb/myboot/mnt
cp -a /home/lennartb/myboot/rootfs/* \
   /home/lennartb/myboot/mnt
umouunt /dev/fd0
\end{verbatim}
The root file system will be mounted read-only. If this is not
desired, add the following line to the file {\tt etc/init.d/rcS} while
the floppy is mounted:
\begin{verbatim}
mount -o remount /dev/fd0 /
\end{verbatim}

Next we create the boot disk. With a different diskette in the drive
type  the following command:
\begin{verbatim}
dd if=/home/lennartb/myboot/linux/arch/boot/zImage \
   of=/dev/fd0
rdev /dev/fd0 /dev/fd0
\end{verbatim}
The {\tt rdev} command selects the device on which the root file
system should be mounted by the kernel after booting. We could use the
following command to make the diskette mount the root file system on
the first hard disk partition.
\begin{verbatim}
rdev /dev/fd0 /dev/hda1
\end{verbatim}

\subsection{LILO bootable disk}

First make the root diskette as described in the previous
section. There are two ways to proceed:
\begin{itemize}
\item Mount the root diskette and install the kernel and LILO on
  it. This way we have a self-contained diskette that boots and has
  the root file system. It works for the kernel and the utilities as
  described in this article, but you would quickly run out of disk
  space when adding more features to the kernel or more utilities to
  the root file system.
\item {\tt mke2fs} a different diskette for the kernel and LILO. This
  way we still have two diskettes and more space on each.
\end{itemize}
The LILO diskette is either the root diskette to which we will add
LILO or the separate diskette on which we will install LILO.

Mount the LILO diskette and add the kernel and boot loader to it:
\begin{verbatim}
mount /dev/fd0 /home/lennartb/myboot/mnt/
mkdir /home/lennartb/myboot/mnt/boot
cp /home/lennartb/myboot/linux/arch/i386/boot/zImage \
   /home/lennartb/myboot/mnt/boot
cp /boot/lilo/boot.b /home/lennartb/myboot/mnt/boot
\end{verbatim}

Create the file {\tt /home/lennartb/myboot/lilo.conf} as follows:
\begin{verbatim}
boot=/dev/fd0
install=/home/lennartb/myboot/mnt/boot/boot.b
map=/home/lennartb/myboot/mnt/boot/map
delay=100
compact
image=/home/lennartb/myboot/mnt/boot/zImage
  label=linux
  root=/dev/fd0
\end{verbatim}
All relevant files mentioned in {\tt lilo.conf}  are on the mounted diskette.
The {\tt delay} option will wait 10 seconds, so we have the
opportunity to type a command line in LILO. The {\tt compact} option
makes loading much faster. Try it without and compare.

Run LILO. This will add a {\tt map} file to the {\tt /boot} directory
on the diskette and it will add a boot sector to the diskette. The
boot sector will load the loader in boot.b, this will load the map
file and the map file contains a list of sectors of the kernel, so
this can be loaded.
\begin{verbatim}
lilo -C /home/lennartb/myboot/lilo.conf
\end{verbatim}

Finally unmount the LILO diskette.
\begin{verbatim}
unount /dev/fd0
\end{verbatim}

\subsection{RAM disk}

A RAM disk has the following advantages.
\begin{itemize}
\item Once the system is booted, programs will load faster.
\item Once the system is booted, the diskette can be removed from the
  drive. Therefore the floppy drive can be used to load other programs
  or to restore a hard disk partition from backup diskettes.
\item The RAM disk image can be stored compressed on the diskette. A
  full 1.44MB or even 2MB file system can be stored compressed on a
  diskette together with a kernel. A compressed 4MB or 8MB file system
  is also possible as long as it is not completely filled. After
  booting the system, you can copy programs from other diskettes into
  the RAM disk.
\end{itemize}

The RAM disk has the following disadvantages:
\begin{itemize}
\item It requires more RAM to run. The RAM disk configuration
  described in this system will boot on a system with 4MB of RAM, but
  this is pretty much the limit. More kernel features or more
  utilities would make this RAM disk unusable on a 4MB system.
\item It requires more steps to create or to adapt the root file system.
\item Changes made to the root file system are not permanent. This is
  either an advantage (security) or a disadvantage (configuration
  changes are not possible). 
\end{itemize}

First we have to create an image file for the RAM disk. We limit its
size to 1000K, so it still runs on a 4MB machine. Create a file system
on the image file. The {\tt -N 200} option is necessary to create
enough inodes on the file system, as there are a lot of symbolic links.
\begin{verbatim}
dd if=/dev/zero of=/home/lennartb/myboot/root.img \
   bs=1k count=1000
mke2fs -F -N 200 /home/lennartb/myboot/root.img
\end{verbatim}

Next mount the image file using a loop device and copy all files of
the root file system to it. The loop option to mount makes it possible
to mount a regular file as if it were a block device.
\begin{verbatim}
mount -o loop /home/lennartb/myboot/root.img \
   /home/lennartb/myboot/mnt
cp -a /home/lennartb/myboot/rootfs/* \
   /home/lennartb/myboot/mnt
umount /home/lennartb/myboot/mnt
\end{verbatim}

Compress the root file system image. This image file will be copied to
a diskette.
\begin{verbatim}
gzip -9 /home/lennartb/myboot/root.img
\end{verbatim}

Create a new LILO diskette, mount it and add the kernel, root file
system image and boot loader to it:
\begin{verbatim}
mke2fs /dev/fd0
mount /dev/fd0 /home/lennartb/myboot/mnt/
mkdir /home/lennartb/myboot/mnt/boot
cp /home/lennartb/myboot/linux/arch/i386/boot/zImage \
   /home/lennartb/myboot/mnt/boot
cp /home/lennartb/myboot/root.img.gz \
   /home/lennartb/myboot/mnt/boot
cp /boot/lilo/boot.b /home/lennartb/myboot/mnt/boot
\end{verbatim}

Create the file {\tt /home/lennartb/myboot/lilo-initrd.conf} as follows:
\begin{verbatim}
boot=/dev/fd0
install=/home/lennartb/myboot/mnt/boot/boot.b
map=/home/lennartb/myboot/mnt/boot/map
delay=100
compact
image=/home/lennartb/myboot/mnt/boot/zImage
  label=linux
  root=/dev/ram
  initrd=/home/lennartb/myboot/mnt/boot/root.img.gz
image=/home/lennartb/myboot/mnt/boot/zImage
  label=noram
  root=/dev/fd0
\end{verbatim}
The configuration file is almost the same, except for the {\tt initrd}
option. This causes the boot loader to load a RAM disk image into
memory. The Linux kernel will decompress it to a RAM disk device and
mount this as the root file system \footnote{The {\tt initrd} feature
  makes it possible to mount the root file system twice, once on the
  RAM disk loaded by the boot loader and once on another device (most
  likely a disk partition). The RAM disk can contain an initialization
  routine to load the required modules to mount the root disk. This
  two stage root file system feature is not used here.}.
Further we added a {\tt noram} option, so it is also possible to use this
LILO diskette without a RAM disk.

Run LILO:
\begin{verbatim}
lilo -C /home/lennartb/myboot/lilo-initrd.conf
\end{verbatim}

Finally unmount the LILO diskette:
\begin{verbatim}
unount /dev/fd0
\end{verbatim}

\section{Using the Boot Disks}

First boot Linux by putting the appropriate Linux diskette into the
floppy drive.
\begin{itemize}
\item If you boot from a diskette without LILO, you should see a
  ``Loading'' message right away. After some disk activity you should
  see the message ``Uncompressing Linux'' and a little later you
  should see the kernel messages. Next it prompts for the root
  diskette. Remove the boot disk and insert the root diskette and press
  enter. 
\item If you boot from a diskette with LILO, you should see the LILO
  message. If you press the space bar, you should see the boot prompt
  from LILO, if you don't you should see the message ``Loading linux''
  after 10 seconds. After some disk activity you should see the
  ``Uncompressing Linux'' message, some kernel messages and next the
  kernel will prompt for a root diskette. If the LILO diskette
  contains the root file system, you just press enter, otherwise you
  have to swap disks first.
\item If you boot from a diskette with LILO and a RAM disk, everything
  starts the same as in the previous case. Instead of prompting you
  for a boot disk, the kernel should display a message that a
  compressed RAM disk image was found. It automatically proceeds after
  decompressing. 
\end{itemize}
As soon as the root file system is mounted, you should see a message
from Busybox. A few seconds later you are invited to press
enter. After you press enter, you get a root shell prompt, which
should be very familiar. With the function keys ALT-F1, ALT-F2, ALT-F3
and ALT-F4 you can switch to four virtual terminals and you should be
able to get a shell prompt on all four of them.

WARNING: If your root file system is on a floppy disk (you are not using a RAM
disk), do not remove this diskette from the drive when Linux is
running. If you use a RAM disk or if you moved all of your root file
system to the hard disk and booted with the option {\tt
  root=/dev/hd??}, then it is OK to remove the diskette as soon as
Linux has started.

Type the {\tt reboot} command in order to shut the system
down. If you are using a root file system on a diskette,
you should wait until the PC has rebooted before removing the
diskette.

What we can do is installing the linux root file system on the hard
disk. First we have to (re)partition the hard disk. Type the following
command:
\begin{verbatim}
fdisk /dev/hda
\end{verbatim}
While inside {\tt fdisk} use the {\tt p} command to show the current
partition table. Maybe you find an old DOS partition that you still
want to backup. If so, quit {\tt fdisk} now using the {\tt q}
command. If you can part with that old DOS partition, you can delete
partitions with the {\tt d} command and create new partitions with the
{\tt n} command. Finally you can write the modified partition table
with the {\tt w} command. Using {\tt fdisk} you should be able to
create the following partitions:
\begin{itemize}
\item A swap partition (set type to 0x82 with the {\tt t} command) of
  around 16MB. Suppose this is partition 2 ({\tt /dev/hda2}).
\item A Linux partition occupying the rest of the disk. Suppose this
  is partition 1 ({\tt /dev/hda1}).
\end{itemize}

After partitioning the hard disk, create a swap partition with the
{\tt mkswap} command, create an ext2 file system and copy all data to
it. Type the following commands. Of course we assume that the Linux
partition is {\tt /dev/hda1} and the swap partition is {\tt
  /dev/hda2}. Otherwise you must supply appropriate device names.
\begin{verbatim}
mkswap /dev/hda2
swapon /dev/hda2
mke2fs /dev/hda1
mount /dev/hda1 /mnt
mkdir /mnt/proc /mnt/mnt
cp -a /bin /sbin /usr /etc /lib /dev /tmp  /mnt
\end{verbatim}

Edit the file {\tt /mnt/etc/init.d/rcS}. If you haven't learned {\tt
  vi} by now, tough luck.
\begin{verbatim}
#!/bin/sh
mount -a
swapon -a
\end{verbatim}

Edit the file {\tt /mnt/etc/fstab} as follows:
\begin{verbatim}
/dev/hda1 /     ext2 defaults 0 0
none      /proc proc defaults 0 0
/dev/hda2 swap  swap defaults 0 0
\end{verbatim}

Now we can shut the system down.
\begin{verbatim}
umouunt /dev/hda1
reboot
\end{verbatim}

Reboot the system with the boot diskette in the drive.

As soon as you see the word LILO, press the SHIFT key. Now you see a
boot prompt. If you use a boot diskette without a RAM disk, type:
\begin{verbatim}
linux root=/dev/hda1
\end{verbatim}

If you use a boot diskette with a RAM disk, type this at the boot prompt:
\begin{verbatim}
noram root=/dev/hda1
\end{verbatim}

If you have a boot diskette without LILO, you have to go to the host
system and change the root device using the {\tt rdev} command:
\begin{verbatim}
rdev /dev/fd0 /dev/hda1
\end{verbatim}
After this, reboot the target system with the modified diskette.

In any case, your system should now mount the root file system on your
hard disk and your floppy drive will be free to mount other diskettes,
so you can copy more files to the hard disk.

\section{And Further}

We showed you how to create a boot diskette with one set of
features. Now you know how to do this, you should be able to customize
it to your needs. You can turn it into a full featured rescue disk, an
installation disk for your brand new Linux distribution, a
demonstration disk or an embedded project, such as a router or print
server. 

First try to add kernel module support. Modules come in very handy for
devices that are seldom used or are only available on some target
systems. Serial ports, network adapters and SCSI features may be
candidates for compiling as modules, as well as additional file
systems. In order to use modules you have to
do the following:
\begin{itemize}
\item Reconfigure the kernel with module support enabled. Configure
  certain features to be compiled as modules.
\item Rebuild the kernel.
\item Run the additional make step {\tt make modules}. 
\item Copy the kernel to the boot disk (and run LILO if necessary).
\item Copy the modules to the root file system or a different
  diskette.
\item Rebuild busybox with the {\tt insmod} and {\tt rmmod} commands
  enabled. Move this to the root file system as well.
\item If you use a RAM disk, you should recreate a RAM disk image,
  compress it and rerun LILO on your boot disk . If you hadn't made a
  shell script to perform all these tasks, you should do by now.
\end{itemize}
One additional feature that you might try (it only exists in 2.4
kernels) is the {\tt devfs} file system. Instead of a {\tt /dev}
directory with hundreds of useless device node  you mount a pseudo file
system on the {\tt /dev} directory, not unlike the {\tt /proc} file
system. There the device nodes appear for only the devices that exist.

After module support you may want to add network support. Once you
have added an Ethernet adapter to your old 386, you can connect it to
your LAN and you do not need diskettes so often. With a little bit of
luck, this still runs on a 4MB machine, but forget about using a RAM
disk.
\begin{itemize}
\item Rebuild the kernel with networking enabled. Of course you have
  to rebuild the modules as well.
\item Rebuild Busybox with network commands enabled (ifconfig, telnet,
  ping etc.)
\item Copy all relevant files to their respective places.
\item Recreate the RAM disk image and rerun LILO if appropriate.
\end{itemize} 

You can add additional programs and libraries to the target system.
\begin{itemize}
\item Many programs need {\tt curses}. The {\tt ncurses} library is reported
  to be usable with {\tt uClibc}. You must recompile it in order to
  achieve this. You will probably need a stripped down {\tt termcap} file on
  your target system as well.
\item With {\tt ncurses} and the standard libraries of {\tt uClibc},
  you should really be able to compile a lot of programs that do not
  require X.
\item Some make files try to run the programs you have just
  built. This can be a problem. It should be possible to copy the {\tt
  uClibc} shared libraries to the {\tt /lib} directory of the host
  system, as their names are different from the {\tt glibc}
  libraries. The programs linked against {\tt glibc} will still work
  and the {\tt uClibc} programs will work too. I just haven't tried
  this, so don't do it on a life-critical system or if you haven't
  made a backup.
\item Even {\tt gcc} and {\tt X} are reported to work with {\tt
  uClibc}, so give them a try! A target system with {\tt uClibc} as
  the only C library should therefore be able to run a C development
  environment and X. Building this is certainly not for beginners.
\end{itemize}

The RAM disk version of the boot disk runs on a 4MB machine, the
version without RAM disk should run with 3MB or RAM, but nothing so
far has run on a machine with just 2MB of RAM. In the good old days,
people ran Linux routinely on such machines and it should still be
possible with modern (if not the newest) software. Some hints:
\begin{itemize}
\item Do not use a RAM disk.
\item Remove more features from the kernel. RAM disk support can be
  removed, use the disk-only driver instead of the more functional IDE
  driver, remove file systems such as FAT and ISO9660. If you do have
  a 387 in that 2MB box, get rid of math emulation.
\item Use an older kernel, 2.2 or even 2.0. Note: if you use 2.0,
  remember to use the {\tt -O none} option on mke2fs if you make a
  file system for the target system. Kernel 2.0 does not understand
  some features added by later kernels.
\item Remove more functions from busybox. This should not help much as
  busybox will be demand loaded. Parts that are not demanded, will not
  be loaded. It may help to a certain degree. Features like color {\tt
  ls} and command line editing can be removed and a more primitive
  shell can be utilized.
\item Remove init and start {\tt /bin/sh} directly at startup.
\item If this lets you do do {\tt fdisk}, {\tt mkswap} and {\tt
  swapon}, you can get swapping enabled on the target system. From
  there you should be fine.
\end{itemize}

\section{Other Useful Resources}

This article should have shown you how to create useful bootable
diskettes and minimal Linux systems with just the programs you
need. You cannot be without the following resources:
\begin{itemize}
\item \htmladdnormallinkfoot{Linux from
  scratch}{http://www.linuxfromscratch.org}. 
  If you
  got the taste of creating your own Linux system, one program at a
  time, one file at a time, compiling everything from source, then this
  is the next big thing. This site contains a detailed instruction how
  to compile a complete Linux system completely from source, including
  the libraries, C compiler and utilities. The target system is created on
  the hard disk and not on a diskette. 
\item \htmladdnormallinkfoot{Freshmeat}{
  http://www.freshmeat.net}.  This site
  contains an index of almost all programs available for Linux. Most
  open source programs can be found there.
\item \htmladdnormallinkfoot{The Linux Documentation Project}{http://www.tldp.org}. 
  This site contains all Linux related documentation you ever wanted.
\item \htmladdnormallinkfoot{My
  homepage}{http://www.xs4all.nl/\~{}lennartb} contains the online
  version of this document.
\end{itemize}

\end{document}