                  A New Bootstrapper for Minix
                            Version 2

                           Glen Overby
                  North Dakota State University
                       Fargo, North Dakota



                          June 15, 1989



The objective of this project is to improve the verasility of the
Minix  boot-up  process by reading the major pieces of the system
from files on a filesystem, rather than from an image diskette.

In doing this, I have completely rewritten  the  Minix  bootstrap
process.  I now have a two-stage process to load the system and a
special hard disk loader program.

the first stage resides in the boot block of a  Minix  filesystem
and  is  loaded by the PC's ROM or the hard disks's loader.  When
stage 1 takes over, it reads the root directory of /dev/fd0 look-
ing for a stripped file (no "a.out" header) named "boot" to load.
After control is passed to stage 2, it loads four  "a.out"  files
containing  the  Kernel,  Memory  Manager,  File System and Init,
building a normal process stacks with process arguments for each.

The new hard disk loader, written by Motti Bazar, asks  the  user
which  partition  to  boot  from, and loads that partition's boot
block to 0:7C00H.  It then executes it, passing a pointer to  the
boot  partition's  disk  table  entry (somewhere in the relocated
hard disk boot loader located at 0:600H) and the cylinder  offset
of  the partition.  The need for these two parameters is the only
reason I changed from the standard DOS  boot  block  to  Motti's.
After  using itI have found it nice to be able to boot off of any
partition I want.

The first stage is written entirely in assembler by an  associate
of  mine,  Dan  Thureen.   Dan used the MicroSoft Macro Assembler
(version 4.0 works OK; I've  had  trouble  with  5.0  complaining
about  not  having a stack segment and such).  Microsoft's assem-
bler was used because we did  not  know  all  of  the  syntax  of
Minix's  asld,  and  there  were  a few required addressing modes
(such as jump indirect) that we did not know how to code.

I have heavily modified Dan's origional  loader  to  support  the
hard drive, and to fit better with my second stage loader.

Stage 2 is written primarily in C, with  some  assembler  support
routines.   It  loads  "a.out"  format  files  from  Minix format
filesystems on any disk or partition; it knows about  partitioned
hard  disks as well as floppy diskettes.  After all processes are
loaded, stacks are built for each of the processes.  The kernel's
stack  contains  "struct  proc" entries for kernel memory, MM, FS
and Init.  These are used by the proc table  initialization  rou-
tines as a replacement for the sizes[] array.

File loader.c contains the code that does all of  the  filesystem
reading.   Routines  with double sides are the only ones intended
for use outside this module.


                                =================
                                ||  Open_File  ||
                                =================
                         _______/       |       \_______
                        /               |               \
                ---------------         |               --------------
                | Follow_Path |         |               | Device_Map |
                ---------------         |               --------------
         _______/      /    \           |
        /            /        \         |
-------------      /    --------------  |
| Next_Name |    /      | Search_Dir |  |
-------------  /        --------------  |
             /            /             |
           /            /               |
         /      ===============         |               ===============
        |       || Read_File ||         |               || Load_File ||
        |       ===============          \              ===============
        |               |   \_________     \               /     |
        |               |             |      \           /       |
--------------  -----------------     |   ____ \  _____/    -----------------
| Read_Inode |  | L_Load_Blocks |     |  |       \          | F_Load_Blocks |
--------------  -----------------     |  |         \        -----------------
        \                    \        |  |   _______ \  _________/    |
          \                   \       |  |  |          \              |
            \                  \      |  |  |    --------------  -------------
              \                 \     |  |  |    | Read_Super |  | Phys_Copy |
                \                \    |  |  |    --------------  -------------
                  \_____________  \   |  |  |   _____/      \
                                \  \  |  |  |  /              \
                                 --------------         -------------
                                 | Block_Read |         | Read_Part |
                                 --------------         -------------
                                        |     ________________/
                                        |    /
                                -----------------
                                | LL_Block_Read |
                                -----------------
                                        |
                                   ----------
                                   | diskio |
                                   ----------


The filenames used by the loader  have  been  extended  to  allow
specification  of  what device to load the file from, in the for-
mat:
                  device[.partition]:path

The devices that loader knows about are:
     fd0, fd1, fd2, fd3          floppy diskettes
     hd0.1, hd0.2, hd0.3, hd0.4  hard disk 0 parititons 1-4
     hd1.1, hd1.2, hd1.3, hd1.4  hard disk 1 parititons 1-4


CHANGES TO  MINIX

I attempted to keep the number of changes to the Minix  internals
to a minimum.  I think I have succeeded fairly well with this.

The Kernel start-up in mpx88 was changed to expect  arguments  on
the  stack  for main.  This is passed along in the same manner as
for a normal process.  The kernel's "proc"  table  initialization
section copies from the arguments rather than calculating it from
the "sizes" array, which no longer  exists.   The  first  element
(argv[0])  contains  information about the kernel; the next three
elements (argv[1,2,3]) are for MM,  FS  and  Init,  respectively.
With  the  removal  of  the sizes array, changes to the interrupt
vector  initialization  and  memory  driver  initialization  (for
/dev/kmem) were requred.  Set_Vec was changed to use the physical
data segment of the "Hardware" process rather than calculating it
from  "base_click+sizes[0]".   The  memory  driver was similarily
modified, but using the virtual address of the stack segment  for
the size of the kmem driver.

The Memory Manager no longer waits for the file system to tell it
the  top  of  the  ram disk; instead, it uses a call added to the
SYSTEM process, GET_MAP, to get a  process'  segment  maps.   The
"BRK2"  call has now been changed to allocate any size out of the
global memory pool, rather than within a process' 64K  data  seg-
ment.   This  call is used by the file system to allocate the ram
disk's memory.

The File System uses it's parameters to determine which device to
mount  as the root filesystem, and if it is necessary to pre-load
that device from another device (i.e. if it's a ram disk).   This
change  wasn't  necessary to to the bootstrap process, but it was
at the top of my list of change I wanted to make  and  I  did  it
while giving the bootstrapper some time to "break in".

CHANGES IN THE SECOND VERSION

My first version would not load from the hard drive; this  second
version has changed that.

The loader now offsets all requests with  the  cylinder  starting
sector  (passed  from  Motti's  hard  disk loader), and the drive
parameters for are configured from BIOS call 13h.  There  is  one
"hack"  to  calculate  the  drive number when using a partitioned
hard drive; the partition is calculated by subtracting  an  abso-
lute  address from the partition table entry passed from the main
hard disk loader.  There is now a define to determine which  type
of device (floppy or hard disk) is being booted from.

The second stage program now saves the default boot device passed
from  the bootblock.  I also fixed a bug in the hard disk parame-
ter settings; I had hard-coded the number of heads on  my  drive.
That is now obtained from the BIOS.

FUTURE ENHACNEMENTS

The block-read makes two ROM calls to read  each  sector  of  the
block.   This  should  be changed to one call, with logic for the
errors returned when a track or cylinder is crossed.

Memory size should be acquired from the ROM  and  passed  on  the
Memory  Manager's stack rather than using the current memory size
calculation which twiddles with the segment registers  and  pokes
thru all existing memory to find out how much there is there.

All RAM disk types should be separate minor devices in the Memory
driver.   This  would  theoretically  allow  three  RAM disks: PC
(under 640K), AT (Extended memory) and EMS.  Currently, it is ei-
ther  PC  or  AT type RAM disk, determined by the size of the RAM
disk.

Configuration of some device driver parameters (such as  keyboard
type,  primary  printer  port,  video adapter type, and CPU type)
could be done in the second stage and passed in on  the  Kernel's
stack.

More server processes could be configured into the system.   This
would require the constant "LOW_USER" to become a variable passed
to the kernel.

A Hard-Disk stage 1 bootstrapper needs to be written so Minix can
boot  fully  off  the  hard  drive.   One that might work, called
"BOOTCODE.ASM" by W.D. Caglewas posted in Oct. 87.

INSTALLING THE CHANGES

My changes add two directories to the Minix hierarchy,  "b1"  and
"b2b".   The directory "b2b" was origionally named "b2", but what
I'm sending out is the third major revision and  I  put  each  in
separate directories.  Directory "b1" contains the first stage of
the bootsrapper in source and binary.  If you wish to  reassemble
the  sources,  write bootblok.asm to a dos disk and reassemble it
from dos.  Follow the instructions at the beginning of  the  code
for  writing it directly to a Minix filesystem disk's boot block;
otherwise, run uudecode on the ".uu" file in the "b1"  directory,
and use
        dd if=bootblok of=/dev/fd0
to write it to the boot block of a Minix filesystem.

Compiling the second stage, in "b2b" simply requires a "make"  in
that directory.  Before compiling you may want to change the dev-
ice and file names of the system files in main.c.  It would real-
ly  be  nice  to  have a configuration file to tell what files to
load for each piece of the system, but  I  haven't  written  that
yet.

Next, patch all the diffs into your Kernel, FS,  MM,  header  and
library  files,  and copy in the new mpx88.s file.  All diffs are
context diffs and require "patch" to install them.   If  you  are
patching  into  a full set of Minix sources, you will not be able
to use the makefiles.  The way I do most  of  my  development  is
with  a  parallel  copy  of  the  sources, only copying necessary
files.  My work  source  directory  is  /usr/src/minix,  and  the
parallel  directory is /usr/src/minix/newboot.  If you do not use
the makefiles, you will need to merge some changes I have made to
them  into  the generic Minix ones; first, I use "crtso.s" rather
than "head.s" for FS, MM and Init.  This allows me to  link  with
"cc"  rather  than "asld".  I have added the changed library file
"syslib.s" to the end of my link commands so that I don't have to
rebuild my entire library with the changed file.  This was simply
easier for testing.  Lastly, I "chmem" all  executables  down  to
2000 bytes of stack space.























