                  A New Bootstrapper for Minix

                           Glen Overby
                  North Dakota State University
                       Fargo, North Dakota



                         April 30, 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.

To achieve this, I have developed a two-stage process to load the
system.   The  first  stage  resides in the boot block of a Minix
filesystem and is loaded by the PC's ROM.   When  stage  1  takes
over,  it  reads  the  root  directory  of /dev/fd0 looking 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 con-
taining the Kernel, Memory Manager, File System and Init,  build-
ing a normal process stacks with process arguments for each.

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.

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".

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.



























































