Jeff's loader

Jeff Mock
jeff@mock.com
(c) 2002

version 0.1.0

This is a linux bootloader for embedded X86 PC architecture systems.  The
bootloader is intended to be small, easy to understand, and easy
to adapt to the special requirements of embedded systems without 
becoming an expert on bootloaders.

The bootloader is not nearly as sophisticated as grub or lilo.  There
are many things it does not know how to do:

    Boot from from ext2 partitions
    Serial port consoles
    Support for raid configurations
    Boot from extended partitions
    Boot from anything other than the first IDE device (/dev/hda)
    Present sophisticated menus for the user
    Load old kernels

It has a few nice features

    Mostly written in C
    Boot from cramfs root partition
    Change to VESA video mode and present splash screen before 
        kernel is loaded.
    Utility script to build disk image for embedded system without
        root priveledges or using fdisk, lilo, etc.

Program structure:

    The loader image jlo consists of two pieces.  The first
    piece is made from mbr.S, a 512-byte boot sector containing
    a partition table and a small program to load the secondary
    bootstrap.  The MBR has a table of sectors to load the secondary
    bootstrap.  A utility program might modify this table to
    suit a boot environment, but the table is by default loaded to 
    read the secondary bootstrap starting from the second sector 
    on the disk.

    The secondary bootstrap is a C program that is hopefully
    easy to modify for particular applications without becoming
    an expert is in the subtleties of booting.

    The secondary bootstrap is about 6k bytes.
    It is a 16-bit real-mode C program.  It initializes
    the display to a VESA graphics mode, loads a splash screen
    and then loads a linux kernel from the first partition in
    the partition table marked active.

User Interface

    The loader has a very simple user interface. By default
    it loads and starts the kernel with no user interaction.
    There are a few things you can do to change this process
    during development.

    If you hold the shift-key down during booting, the MBR
    will bail and return to the BIOS.  On many motherboards
    (like VIA mini-ITX) this will drop into the PXE ROM
    for network booting, often very useful for embedded development.

    If you hold down the ctrl-key during booting, the boot
    process will proceed as usual but the console is left in
    text mode, the splash screen is not displayed, and the video
    mode parameter passed to the kernel leaves the console
    in text mode.  This lets you see jlo and linux booting
    messages for debug.

    If you hold down the atl-key during booting the loader
    will present a very simple user interface to manually
    select a partition for booting.

Installing
    After running make you hopefully wind up with a file called jlo.
    This is the MBR and secondary loader together.  This should be
    put on the first sectors of the boot device.  For development I
    am using a VIA mini-ITX motherboard with a compact flash adapter.
    My boot device is a compact flash card that appears as /dev/hda on
    the target machine.

    After putting the bootloader on the device, the partition table
    needs to be configured to make some partitions.

    After creating the partition table a cramfs filesystem needs to be
    put on one of the partitions.

    A perl program is included for building an image for a boot device.
    mkimage needs to know the disk geometry of the boot device.
    By default it uses the geometry for a generic 8MB compact flash card.
    This is probably not what you want.

    You run mkimage something like:

        % ./mkimage --sectors=32 --heads=2 --cylinders=248 --p1=myfs
            --image=cf.img

    This will create a file called cf.img that is an image of an
    8MB flash card containing the bootloader and a partition containing
    the file myfs.  myfs should be an image file of a cramfs 
    filesystem.

    Create the myfs image of the cramfs filesystem using mkcramfs.
    To make a bootable cramfs image use the "-i" option to mkcramfs
    to insert a kernel image into the cramfs filesystem.  Something
    like:

        % mkcramfs -i bzImage root myfs

    The file bzImage should not be under "root", this is a waste of
    space.  The kernel is inserted at the beginning the filesystem 
    image and is not part of the filesystem.

    Once the image of the device is made you can use dd to copy 
    it to an actual device for booting:
    
        % dd if=cf.img of=/dev/xxx bs=512
            
    A host program called writecf is also included to make writing
    the file image more efficient.  writecf only writes used sectors
    rather than writing all of the sectors like dd.  This speeds
    up writing large flash cards quite a lot.

    The utilities bootpart.c and update might useful for the target
    machine.  The idea is to keep two cramfs partitions on the boot
    device, one for booting and the other for updates.  The update script
    downloads a new image, copies it into the unused partition, verifies
    the partition and then changes the default boot partition to the new
    partition only after the download has been verified.  This limits
    the exposure for failure during a software upgrade to a very small
    window when the active parititon of the boot sector is written.
    If these utilities are used, the original device image should be 
    created using the --p1-size and --p2-size options to make sure 
    the partitions are large enough to hold future updates even if the
    initial filesystem is smaller.
 
Splash Screens
    An optional splash screen is stored in the boot partition along
    with the kernel.  There are two ways to go.  If the file inserted
    into the cramfs partition is a bzImage kernel file then the 
    system will boot without changing the video mode just like lilo.

    The other way to go is to create a run-length encoded image to use
    as a splash screen while the kernel is being loaded.  The perl
    script mkrle takes a PNG image and turns it into a splash format.
    There are a few extra options to mkrle to set the background color
    and screen offset for the image if the image is less than full
    screen.  By default jlo will center a smaller image on the screen
    with a black background if the options aren't set.

    One day mkrle might have a few different methods for RLE 
    encoding the image, but right now it just knows one format. RLE64.
    This format places some constraints on the source image.  The 
    image must contain no more than 64 different colors, the format
    builds a 64-entry color map table and will barf if the image 
    contains too many colors.  Photoshop does a nice job dithering down
    to 64 different colors.  Run mkrle something like:

            % ./mkrle --png=splash.png --mode=0x111 --out=img.rle --bg

    In the above example, the image will be centered on the screen
    since --xoff and --yoff weren't specified. If the image is smaller
    than fullscreen the --bg option sets the background color the same as
    the color of the pixel in the upper left corner of the image.  If
    you want to specify the background color manually use the --r, --g,
    and --b options to mkrle.  The --mode option to mkrle sets the 
    VESA graphics mode.  In this example 0x111 is 640x480x16 with the
    pixels organized as 5-6-5 RGB.

    Once you create the splash RLE image, the splash image needs to 
    be combined with the kernel something like:

            % cat img.rle bzImage > bootfile
            % mkcramfs -i bootfile  (...)

    When the combined splash/kernel is inserted into the cramfs 
    image jlo will put up the splash screen in the desired video
    mode and then load the kernel.  If the enclosed kernel patch
    is applied, the kernel will smoothly transition to to create
    a /dev/fb0 device in vesafb mode with this video mode without
    any annoying flashing or glitches.

Command line options to kernel

    jlo builds a simple command line for the kernel.  It sends the 
    "auto" option, sets the root device with root=/dev/hdaN, passes the
    video mode used by the splash screen with video=0xnnn option.
    
    If the application needs more command line options these can be
    passed in the header of the splash screen image.  mkrle has an 
    option to append options to kernel command line.  Use it something
    like:

            # mkrle --png=splash.png --out-img.rle --cmd="vesa=ypan"

    If you want to pass command line options or set the video mode from
    the bootloader, you must included a splash screen.  This information
    is stored in the header of the splash screen image prepended to the
    kernel.

Tools

    Building jlo requires bcc, as86, and ld86.  These are 
    16-bit real-mode x86 tools.  These are included in most
    big modern linux distributions, but you can get the 
    latest dev86 tools from:

        http://www.cix.co.uk/~mayday/dev86/

    At this writing, jlo is built using 0.16.0 of dev86.

Kernel patch

    You don't need to patch the kernel, but the following patch
    improves the boot process with a splash screen.  With the patch
    the kernel checks to see if the video mode has already been
    set before setting the video mode.  This way the there is no
    screen flashing between the boot loader splash screen and 
    linux booting.  The patch is against 2.4.20 in the file 
    patch.linux.