Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 13 May 1996 11:46:36 -0400 (EDT)
From:      Bill Paul <wpaul@skynet.ctr.columbia.edu>
To:        freebsd-hackers@freebsd.org
Cc:        wpaul@skynet.ctr.columbia.edu (Bill Paul)
Subject:   Making a three-stage boot
Message-ID:  <199605131546.LAA01112@skynet.ctr.columbia.edu>

next in thread | raw e-mail | index | archive | help
Lately I've been experimenting with creating a three-sgate bootstrap
program. (No, I don't know why. It isn't as if I don't have enough to
do already.) Unfortunately, much as I expected, I've hit a wall.
And I can't get up.

The idea I had was to create a bootstrap similar to the one used by
SunOS, which works as follows:

- There is a standalong program called /boot. This program should run
  in protected mode, but have the same ability to perform real mode
  BIOS operations as the existing second-stage bootstrap. I believe it
  has to be limited to having at most 64K of text and data, though I
  may be mistaken about this. This is the program which will ultimately
  read the kernel image from the filesystem and run it.

- The /boot program is loaded by a second stage bootstrap, which is
  by design very dumb and limited in function. It has a compiled-in
  array of disk blocks which tell it where the the /boot program resides
  on disk. It also has a compiled-in value for the filesystem blocksize,
  and possibly some other magic values. In essence, this second stage
  is very much like the one we have now, except that it can only load
  one program: it doesn't need to know how the filesystem is structured
  since it knows exactly what blocks to look for, which means it doesn't
  need any code to grok a UFS filesystem; it doesn't need any keyboard or 
  serial port I/O code since it doesn't have to interact with the user.
  All it needs to do is read a list of pre-defined sectors and jump to
  the new program.

- The second stage bootstrap is read in by the first stage, which is
  a boot block exactly like the one we have now.

Now, here's how this is used: when the operating system is installed,
the first and second stages are written to disk using a special installboot
program (which may be merged with disklabel to simplify things). The
installboot program actually scans the standalone /boot program and
determines what physical blocks it occupies on disk, as well as the
underlying filesystem blocksize. This information is then patched directly
into the second stage bootstrap image and the patched image is then
slapped onto the disk.

I started by writing a simple installboot program, which at this point
only scans the /boot program and patches a second stage image -- I'm
still using disklabel to write the patched images to disk. The patching
is done by compiling the initial bootstrap images with the disk block
arrays populated with magic numbers. The installboot program reads in
the second stage image and stops when it reaches the magic numbers, then
overwrites them with the proper disk block values. (This is ugly, but
it's the only way I could find to do it without a symbol table.)

What I'm really trying to do here is effectivaly split the existing
second stage into two pieces: rather than giving the second stage all
the brains, which takes up too much space, I want to move most of the
work into third stage and make the second stage just smart enough
to load it. Also, by patching values into the bootstrap, we can save
other information, such as the proper disk geometry of the boot drive,
or anything else that it would be useful to save. The one restriction
here is that /boot must remain where it is. If it is moved, the installboot
program must be run again in order to install a new second stage boot
with a new set of physical block numbers.

Now all I have to do is turn the existing second stage bootstrap into
a standalone program. Unfortunately, I don't know how to do it. There
are several questions I can't answer:

- The standalone image obviously needs some sort of assembly language
  startup routine, only I'm not adept enough at 386 protected-mode
  assembly language to write it myself. (What would really help is if
  we had some sort of 'libsa' standalone library. 4.4BSD-Lite had one
  for the i386 architecture, but it relied on special protected-mode
  drivers. It would be terrific if we had one that used the BIOS
  instead.)

- Assuming I had a startup routine (and the right code to do the real-mode
  BIOS operations), how exactly do I link the image?

	o Should it be a ZMAGIC binary like the kernel? Or should it
          be OMAGIC like the existing bootstrap?

	o What start address should it be linked for? Should it be
	  linked at address 0 like the bootstrap or should it be
	  linked for the address at which it will be loaded, like
	  the kernel?

	o For that matter, where in memory should it be loaded?

	o Should it have an a.out header or not?

	o Should it be stripped?

- How do I hand off control to the standalone image from the second
  stage bootstrap? Can I use the same startprog() routine that the
  existing bootstrap uses to kick off the kernel? If not, what do I
  use instead?

After hunting around a bit, I discovered a bootstrap program from
OSF Mach version 3 which seems to be similar to what I need, but it
appears to be incomplete: there is a mach_kboot program which is meant
to be loaded in place of the kernel that starts in protected mode and
then copies itself over the existing bootstrap. I was even able to
compile and link the mach_kboot program in FreeBSD. Unfortunately, 
this is only the 'third' stage and the first and second stages appear to
be incomplete or missing (meaning that I can't find the code that loads
and runs this part of the bootstrap, which is what I really need). The
README with he code gives some clues but doesn't tell me everything I
need to put all the pieces together.

Basically, this is deep magic, and I'm not yet a clever enough magician
to make it all work. I _want_ to learn how to do this, but I'm not making
much progress. If anyone can shed some light on this subject, either
by pointing me at some in-depth documentation (that preferably doesn't
need to be viewed with a stinking web browser) or answering some of the 
above questions, I'd greatly appreciate it.

-Bill

-- 
=============================================================================
-Bill Paul            (212) 854-6020 | System Manager
Work:         wpaul@ctr.columbia.edu | Center for Telecommunications Research
Home:  wpaul@skynet.ctr.columbia.edu | Columbia University, New York City
=============================================================================
License error: The license for this .sig file has expired. You must obtain
a new license key before any more witty phrases will appear in this space.
=============================================================================



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199605131546.LAA01112>