AUTHOR:		Csaba Henk <ekho@math-inst.hu>

DATE: 2003-10-27

LICENSE: The MIT License

SYNOPSIS: Making an uClibc-based bootfloppy

PRIMARY URI: http://www.math-inst.hu/~ekho/lowlife/ 

DESCRIPTION:
This hints shows how to create a cutting-edge bootfloppy from scratch,
based on uClibc, a lightweight C library.

PREREQUISITES:
This hint should be useable on any not too aged Linux installation with
a non-broken toolchain. It was tested on a (by and large) LFS-4.0
system. The sudo utility is advised to have.

ATTACHMENTS:
http://www.linuxfromscratch.org/hints/downloads/attachments/uclibc-bootfloppy/busybox-0.60.5-Config.h
http://www.linuxfromscratch.org/hints/downloads/attachments/uclibc-bootfloppy/linux-2.4.22-.config
http://www.linuxfromscratch.org/hints/downloads/attachments/uclibc-bootfloppy/mkbootdisk
http://www.linuxfromscratch.org/patches/downloads/devfsd/devfsd-1.3.25-uclibc-1.patch

HINT:

Contents
--------

Preface
Introduction
What do we need?
The concept
Setting up the development environment
Compiling the linux kernel
Installing uClibc on the development platform
Creating the root filesystem
Installing uClibc for the bootdisk
Installing busybox
Installing gpm
Other programs
Creating the bootdisk
Bugs and weirdnesses, todo

Preface
-------

* This hint is co-developed with the svnc-thinclient hint in the
framework of the lowlife project,

http://www.math-inst.hu/~ekho/lowlife/

This file belongs to lowlife-0.5.1.

* For the most recent version check out 

http://www.math-inst.hu/~ekho/lowlife/uclibc-bootfloppy.txt

* Comments, ideas, critics, flames are welcome.

* (If you are an LFS user, you can skip this.) Although this document is
formally an LFS hint, you can see use of it without knowing what LFS is
(I tried to write it keeping this possibility in mind). Anyway, I
recommend you to check out what LFS is. If you are not familiar with
compiling source code in unix/linux environment, then there is no use of
going on without checking out what LFS is. Consult the following docs
first:

http://www.linuxfromscratch.org/lfs/whatislfs.html
http://www.linuxfromscratch.org/faq/
http://www.linuxfromscratch.org/hints/downloads/files/essential_prereading.txt
http://www.linuxfromscratch.org/lfs/view/stable/preface/prerequisites.html

Introduction
------------

When you are to put together a Linux bootfloppy, you need to decide what
implementation of the standard C libraries will you use. 

One possibility is using the C library implementation which is common on
Linux based systems: glibc. It's advantage is that you have it at hand:
to make a glibc-based bootfloppy, the only thing you have to do is to is
to copy the necessary libs to the filesystem you will put on the floppy.
This is way chosen by the rescue floppy described in the BLFS-book:

http://linuxfromscratch.org/blfs/view/test/postlfs/bootdisk.html

However, glibc is far from being lightweight, and eats up much of the
rather limited space you have when working with a floppy. So you might
like seek for an alternative which suits much better to the capabilities
of the floppy environment.

Here we will create a bootfloppy based on the uClibc C library, which is
just made for such purposes. 

The bootfloppy will be cutting edge: uses uClibc and Busybox which are
actively developed projects for the embedded platform. Moreover, I used
a kernel from the 2.4.* branch (but feel free to use other kernel
releases). It is a good question to ask whether this is useful: many floppy
distros use older kernels for reducing resource usage. I can say the
following: on the one hand, I can afford using a recent kernel as my
bootfloppy merrily runs on my 486 with 8M RAM; on the other hand, from
the moment I began to use this up-to-date stuff, the problems with handling
the terminal buffer and plip timeouts vanished. So unless you are really
tight in resources, I think using a recent kernel is a good idea. 

We will also use some kind of development environment, just to stay on
the safe side.

This hint has a continuation: there we will describe how to install the
svga vncviewer on the bootfloppy, which then becomes capable of turning a
machine to an X terminal. (Check out the svnc-thinclient hint:

http://www.linuxfromscratch.org/hints/downloads/files/svnc-thinclient.txt
http://www.math-inst.hu/~ekho/lowlife/svnc-thinclient.txt

) 

Additional info and downloadable bootdisk image with svnc can be found
at the lowlife homepage (or at its mirror):

http://www.math-inst.hu/~ekho/lowlife/
http://www.personal.ceu.hu/students/01/Csaba_Henk/lowlife/

In this hint the assumption of using an x86 PC (both for making and
booting the floppy) and gcc is set. You may try to port it to another
architecture / compiler. Doing it on another architecture should not
be hard. Doing it with another compiler depends on how much does
uClibc support that compiler.  

If you copy command from this hint to your shell, be careful that
line-terminating backslashes (\) keep their position (no whitespace
characters should follow them). A possible solution is open this hint in
the Vim GUI, and copy'n'paste from there.

What do we need?
----------------

We will need the following programs; in general, most recent stable
versions are recommended. Those programs where I have a certain
important comment on the version are marked with (!) and you can find
the comment at the beginning of the respective install instructons.

* Addons for the development platform:

sudo (optional)
 ftp://ftp.sudo.ws/pub/sudo/

* Programs for the bootfloppy:

linux-2.4.* (!)
 http://www.kernel.org
uClibc
 http://www.uclibc.org/downloads/
busybox-0.60.5 (!)
 http://www.busybox.net/downloads/
gpm (optional)
 ftp://arcana.linux.it/pub/gpm

The concept
-----------

In LFS, bootstrapping a linux system goes in the following fashion: one
first installs kernel headers, then builds a toolchain against these
headers, finally builds a kernel using the shiny new toolchain.

We don't need to produce a new toolchain: we will use the one of the
host distro (to which we'll refer as "development environment") (though
when making the userspace of our tiny linux system, we will access that
toolchain via the uClibc wrappers). 

This lets us to proceed in a much simpler way: first we compile the
kernel, then build uClibc using the headers of this kernel, finally
build the userspace against uClibc.

We will use optimization for size (we'll pass the -Os flag to gcc). In
general you can delete sources after compilation if there is no specific
reasons to keep them. In those cases when you should *not* delete the
source I'll tell about it explicitly.

Setting up the development environment
--------------------------------------

We definitely need some kind of development environment to protect
us from mucking up our system; eg., if we are in the file system
which we will put on the floppy, it is very easy to mistake usr with
/usr, and without such a protection, you can imagine that this
mistake can have serious consequences... 

We will create a non-privileged user named bootdisk for doing the
job. First choose a home directory for bootdisk and store this value
in $BDISKHOME. Then type:

groupadd bootdisk &&
useradd -g bootdisk -s /bin/bash -d $BDISKHOME bootdisk &&
mkdir -p $BDISKHOME &&
cat > $BDISKHOME/.bash_profile << "EOF"
export CFLAGS=-Os
export PATH=/usr/i386-linux-uclibc/bin/:$PATH:$HOME/bin
export CC=i386-uclibc-gcc
EOF

Of course, you may specify more cflags, like -march=i486. The above
setting of the $PATH variable assumes that the usual directories to
be contained in the path are already set in /etc/profile. 

So the idea is that we will work as user bootdisk; however, there are
some tasks during the bootdisk creation which require a privileged user
-- namely, mounting ext2 files and raw-copying to a floppy. 

We can do two things about this problem: 

1) Ignore it, and execute these tasks as root.  

2) Make a script named mkbootdisk for doing this tasks. This script must
be executable only by root (mode 744). With the help of the sudo utility
we let the bootdisk user to use this script as well. That is, we put it
to $BDISKHOME/bin and then type:

echo "
bootdisk ALL = NOPASSWD: $BDISKHOME/bin/mkbootdisk" >> /etc/sudoers
     
A realization of mkbootdisk can be found as an attachment of this hint
at

http://www.linuxfromscratch.org/hints/downloads/attachments/uclibc-bootfloppy/

or at

http://www.math-inst.hu/~ekho/lowlife/mkbootdisk

or in the current directory if you read this hint as a file of the
lowlife tarball avaliable at

http://www.math-inst.hu/~ekho/lowlife

Typing "mkbootdisk -h" will print a brief information on usage.

We have the desired environment. We go on compiling the programs. Become
user bootdisk:

su - bootdisk

In the rest of the hint we will act as user bootdisk, with the following
exceptions:

* as uClibc will be installed systemwise, you should install it as root;

* if you don't use a mkbootdisk script, then the appropriate actions
are to be done as root;

* doing a chroot test of your filesystem for the floppy is possible only
as root.

This means that if you use a mkbootdisk script, then those steps of
creating the bootfloppy which shouldn't affect your development
platform, *can't* affect the development platform (provided your
mkbootdisk script doesn't do anything weird, which I think is
fulfilled by the one written by me).

Some of the commands below assume that the actual source archive is
decompressed in $HOME (which is the same as the prior $BDISKHOME). 
Software installation instructions always start at the point when the
source tarball is already decompressed and you entered the source
directory (unless we explicitely claim to act differently).

Compiling the linux kernel
--------------------------

At the moment the latest stable release of the linux kernel belong to
the 2.4.* branch, but 2.6.0-test* releases are already out. This
situaton might change any time by the release of linux-2.6.0. The
following instructions regard to the 2.4.* releases; if you want to try
linux-2.6.*, not only the kernel compilation instructions but the whole
bootdisk creation procedure is to be revised (eg., you can't boot a
2.6.* kernel without a boot loader). After linux-2.6.0 will be out I
might consider to upgrade this hint to that version.

We will compile a network-aware kernel optimized to size. I don't give
a complete reference, I just highlight some crucial points.If you need
not network-awareness, you may omit TCP/IP netowrking and network
drivers; but even in this case it is strongly recommended to include
"Unix domain sockets". 

In the kernel source tree type:

sed -e 's%-O2%-Os%g' -e '/^CFLAGS_KERNEL/s%\(^.*$\)%\1 -Os%' Makefile > \
 Makefile.tmp &&
mv Makefile.tmp Makefile

The above commands set optimization for size in the Makefile. Edit the
Makefile if you want further optimizations. 

Now you should configure the kernel with "make menuconfig". Choose
carefully the value in the "Processor type and features  --->  Processor
family" menupoint. When choosing options, it is advised to include only
those features you really need. Some important ones:

Networking options  --->
	<*> Unix domain sockets
	[*] TCP/IP networking

In the "Network device support  --->" menupoint choose those network
drivers you intend to use. If you want to use plip, choose it as a
module, and also set:

Parallel port support  --->
	<*> Parallel port support
	<M>   PC-style hardware

This is advised because of the following: as I experienced, if no
option is given, the kernel initializes the parallel port (PC-style)
IRQ-less!  At boot time we won't have the possibility to pass options
to the kernel, as we won't use a boot loader or initrd. Thus we can
set the appropriate IRQ value only if we load the parallel port
driver as module. Also, to gain more control over the NIC drivers,
consider building them as modules.

In this hint we use the devfs facility, so choose 

File systems  --->
	[*] /dev file system support
  	[*]   Automatically mount at boot

(See a more detailed description in the devfs hint:

http://www.linuxfromscratch.org/hints/downloads/files/devfs+kernel_modules.txt

). 

And don't forget to include support for the mouse type you will use with
the bootfloppy (if you will use any). 

OK, one more remark. Here I don't digress on how to use initrd, but you may
have some reason for doing that. In this case with some kernels (eg., with 
linux-2.4.22) you might encounter with booting problems, which can be cured
by the appropriate kernel patch. For info on initrd and the patch you can
consult the "Creating a Custom Boot Disk" chapter of the BLFS-book, 
referenced in the Introduction.  
 
Now compile the kernel with the 

make dep && make bzImage && make modules

commands. Then type

mkdir $HOME/rfloppy/lib/modules

and copy the NIC driver modules from the drivers/net directory to
$HOME/rfloppy/lib/modules, and also the other modules you built. Eg., if
you use plip, you will need the drivers/parport/parport_pc.o
module.
 
Do not delete the kernel source. 

If you have troubles with configuring the kernel properly, my .config file
might be of your help:

http://www.linuxfromscratch.org/hints/downloads/attachments/uclibc-bootfloppy/
http://www.math-inst.hu/~ekho/lowlife/linux-2.4.22/.config

Installing uClibc on the development platform
---------------------------------------------

Usually we will optimize to size; in case of uClibc it's done
automatically.

We install uClibc systemwise, thus the commands of this installation are
to be executed as root.

In the uClibc source tree type

make menuconfig

uClibc now has a configuration interface similar to that of the linux
kernel. Apply the following settings:

Target Architecture Features and Options  --->
	($BDISKHOME/<dir of your linux kernel for the floppy>) 
		Linux kernel header location
Library Installation Options  --->
	(/lib) Shared library loader path 

This was enough for uClibc-0.9.19; in case of uClibc-0.9.21 we also need
the following:

General Library Settings  --->
	[ ] Support gprof profiling
String and Stdio Support  --->
	[*] Support sys_siglist[] (bsd-compat)

[Explanation: with profiling support set, uClibc wasn't willing to build
for me. The sys_siglist[] support will be needed by busybox which
encorporates some BSD code by having ash as its shell.]

(Other uClibc versions may have their own gotchas.)

Apart from this, the default configuration is quite suitable, probably
you need not change anything (especially you need not use full math
support). However, taking a look at the options never hurts; eg., you
may consider fine-tuning the target processor type. After you exit, 

make &&
make install

Further on we assume that you installed uClibc into
/usr/i386-linux-uclibc/ (the default installation location). 

Creating the root filesystem
----------------------------

We will put the files of the root filesysem of the floppy to a directory
named rfloppy. Firstly we create the directory and a basic tree of
subdirectories which vaguley resembles the FHS idea:

cd &&
mkdir -p rfloppy/{dev,proc,etc/init.d,sbin,bin,lib,mnt,usr,var/log} &&
cat > rfloppy/etc/init.d/rcS << "EOF" &&
#!/bin/sh
mount proc /proc -t proc
EOF

The etc/init.d/rcS file will be the startup script for the floppy. Put
there what you want to be done in the beginnig -- eg., syslogd, klogd,
loading modules, starting gpm, etc.  

A very minimal etc directory is used in this setup. Enriching it (with
files like passwd, group, fstab, modules.conf, and so on) is up to you
-- this minimalist solution works anyway. 

Installing uClibc for the bootdisk 
----------------------------------

We copy the necessary libraries of uClibc to the bootdisk.

cp -a /usr/i386-linux-uclibc/lib/{ld-uClibc*,libc.so.0,libuClibc-*} \
 ~/rfloppy/lib 

Installing busybox
------------------

At the moment busybox has two branches: the development branch
(1.00-pre* releases) and the stable branch (0.60.* releases), but this
situation might change any time by busybox-1.00 being released. The
following instructions regard to the 0.60.* versions. The 1.00-pre*
versions differ greatly (encorporate much more utilities, eg.), so if
you go experimenting with them, these instructions probably need to be
changed.  When the now-devel branch get stable (1.00 comes out), this
document will probably be upgraded to that version of busybox.

Before making it, adjust the Config.h file according to your needs. To
make busybox work with devfs, be sure that the 

#define BB_FEATURE_DEVFS

line is uncommented (not prefixed with "//"); and it is advised to
enable standard Unix utilities, moreover if you want to use network with
the floppy, consider uncommenting: 

#define BB_IFCONFIG
#define BB_TELNET
#define BB_TFTP
#define BB_FEATURE_IFCONFIG_STATUS

Then install it with

make CROSS=i386-uclibc- &&
make PREFIX=$HOME/rfloppy install

If you have troubles with configuring busybox properly, my Config.h file
might be of your help:

http://www.linuxfromscratch.org/hints/downloads/attachments/uclibc-bootfloppy/
http://www.math-inst.hu/~ekho/lowlife/busybox-0.60.5/Config.h

Installing gpm
--------------

Having mouse at the console is not necessary, but very comfortable for a
bootfloppy as well. If you want it, install gpm by running the following
commands:

./configure &&
LDFLAGS="-lm" make && 
strip src/gpm &&
mkdir -p $HOME/rfloppy/{usr/sbin,var/run} &&
cp src/gpm $HOME/rfloppy/usr/sbin &&
cp -a /usr/i386-linux-uclibc/lib/{libm-*,libm.so.0} ~/rfloppy/lib

[The /var/run directory is needed for gpm at runtime.]

Other programs
--------------

Now if there is anything more you want to have on the floppy, compile it
and put it to the appropriate place under $HOME/rfloppy. A list of some
possible extensions: 

* devfsd (

http://ftp.kernel.org/pub/linux/daemons/devfsd/

) is not necessary for the bootfloppy, devfs work fine without it. So
install it only if you know what you are doing. However, it needs to be
hacked to get it compiled against uClibc. There is a patch for devfsd at:

http://www.linuxfromscratch.org/patches/downloads/devfsd/devfsd-1.3.25-uclibc.patch

or at

http://www.math-inst.hu/~ekho/lowlife/patches/devfsd-1.3.25-uclibc.patch

(or in the patches directory if you read this hint as a file of the lowlife
tarball) and you can find some explanation on it at

http://www.math-inst.hu/~ekho/lowlife/

Note that devfsd depends on the libdl.so.0 library of uClibc (which is a
symlink to libdl-0.9.*.so). You have to put these to the /lib of your
filesystem.

* The svnc-thinclient hint tells you how to compile and install svgalib
and the svga vncviewer to the floppy, giving the bootfloppy the
capabilities of an X terminal.

The (functionality of the) following utilities are already encorporated
in the development versions of busybox.

* You can put tinylogin (

http://tinylogin.busybox.net/

) to the floppy if you want a correct login system on it (with the
configuration described in this hint you just get a prompt after
booting).

* You can put utelnetd ( 

http://www.pengutronix.de/software/utelnetd_en.html

) to the floppy if you want to access it remotely. However, don't forget
that communication is not encrypted under telnet!

* One more useful program is hdparm (

http://ftp.ibiblio.org/pub/Linux/system/hardware

): if you boot with this floppy, the harddisk is probably not used, but
still is a source of noise by its spinning. You can stop it with
hdparm. (See its -y option.)

Creating the bootdisk
---------------------

Before creating the floppy, you may wish to test the proposed filesystem
by chrooting to it; if so, execute as root:

chroot $BDISKHOME/rfloppy /bin/sh

Typing this you get the prompt of the busybox shell, and you should be
able to run those utilities which do not require much I/O (ls, cat,
echo,...). Proceed on again as the bootdisk user.

Put a floppy to the floppy drive (if you are not sure about its
integrity, you might want to run fdformat on it). If you use my
mkbootdisk script, check whether the device name of the floppy drive is
set correctly in the script (it is set to /dev/fd0 and no option can
change it, in order to prevent the bootdisk user in being able to muck
up the development platform), and whether the $MKE2FSAPP, $RDEVAPP
variables in the script store the correct path to the mke2fs, rdev
utilities in your system (they should if you follow standards). If
everything is fine, simply run 

cd &&
sudo mkbootdisk

If you don't use the mkbootdisk script, become root, store the name of
your floppy device (typically /dev/fd0) in the variable $DISK. Now its
time to find out how big the root filesystem of the floppy should be,
and how much inodes should it have. Concerning the size, I think the
size of the stuff in the rfloppy directory + 150k is enough; concerning
the number of inodes, I think the number of files in rfloppy + 100 is
enough. But you should know. Store the chosen filesystem size in the
variable $SIZE (the number of kilobytes), and the chosen number of
inodes in the variable $INODES. Then type the following:

cd $BDISKHOME &&
# We we create and compress the root filesystem of the floppy:
dd if=/dev/zero of=rootfs bs=1k count=$SIZE &&
yes | mke2fs -m 0 -N $INODES rootfs &&
mkdir -p loop &&
mount rootfs -o loop loop &&
rmdir loop/lost+found &&
cp -a rfloppy/* loop &&
chown -R 0:0 loop/* &&
umount loop &&
dd if=rootfs bs=1k | gzip -v9 > rootfs.gz 

Now check whether rootfs.gz and your kernel image (probably
linux-2.4.*/arch/i386/boot/bzImage) fit on a floppy together (a floppy
is of 1440k usually but it can be formatted to bigger sizes as well). If
everything is fine, go on:

# We copy the kernel to the floppy:
let KERNELSIZE=`dd bs=1k of=$DISK < linux-2.4.*/arch/i386/boot/bzImage 2>&1 | 
 sed -n '1s%\([0-9][0-9]*\).*%\1%p'`+1 &&
# We perform some adjustments on the kernel copied to the floppy:
rdev $DISK 0,0 &&
rdev -R $DISK 0 &&
rdev -r $DISK `expr 16384 + $KERNELSIZE` &&
# Finally we copy the compressed filesystem to its appropriate place \
# on the floppy:
dd if=rootfs.gz of=$DISK bs=1k seek=$KERNELSIZE

[Explanation -- also for those who wonder how the mkbootdisk script
works

"yes | mke2fs -m 0 -N $INODES rootfs":

This pipe construct is a common trick for answering stupid questions
non-interactively.

"# We copy the kernel to the floppy" :

In the command after this comment we not only copy the kernel to floppy,
but we also store the number of transferred kb's in the variable
$KERNELSIZE.

"# We perform some adjustments on the kernel copied to the floppy" :

We won't have a bootloader to tell the kernel where to find its root
filesystem. The commands after this comment set some specified bits
in the kernel, thus hardwiring the location of the root filesystem to
it: firstly, we tell the kernel to seek for the filesystem in the
floppy, secondly, we tell the kernel that a ramdisk is to be made and
the filesystem is to be decompressed to it, thirdly, we tell the
kernel the location of the filesystem within the floppy. The number
16384 = 2^14 is used for shifting within the range of bits in the
kernel devoted for describing these data. For more information
consult with the Bootdisk HOWTO available at tldp.org. 

"# Finally we copy [...]" :

In the dd command after this comment we use the seek option to copy the
compressed filesystem nicely after the kernel image.]

Now you have the floppy, boot & enjoy! 

Bugs and weirdnesses, todo
--------------------------

This hint is co-developed with the svnc-thinclient hint in the framework
of the lowlife project. These informations can be found in the svnc-thinclient
hint. 

ACKNOWLEDGEMENTS:

This hint is co-developed with the svnc-thinclient hint in the framework
of the lowlife project. These informations can be found in the svnc-thinclient
hint. 

CHANGELOG:

This hint is co-developed with the svnc-thinclient hint in the framework
of the lowlife project. These informations can be found in the svnc-thinclient
hint. 
