Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 May 1996 15:42:43 -0400 (EDT)
From:      Bill Paul <wpaul@skynet.ctr.columbia.edu>
To:        bde@zeta.org.au (Bruce Evans)
Cc:        freebsd-hackers@FreeBSD.org
Subject:   Re: three stage boot again
Message-ID:  <199605241942.PAA01258@skynet.ctr.columbia.edu>
In-Reply-To: <199605241400.AAA04777@godzilla.zeta.org.au> from "Bruce Evans" at May 25, 96 00:00:14 am

next in thread | previous in thread | raw e-mail | index | archive | help
Of all the gin joints in all the world, Bruce Evans had to walk into 
mine and say:

> >- The program is an OMAGIC binary link edited for address 0. This
> >  is necessary because of the real mode/protected mode switching
> >  business. When in real mode, we execute at physical memory location
> >  0x10000, but with a code segment descriptor that basically maps
> >  0x10000 to 0x0. (So the program thinks it's executing at 0x0 but
> >  really isn't.) In real mode, we're excuting at 0x1000:0, which again
> >  makes the code think it's executing at 0x0. (And this is why we
> >  can't make it larger than 64K, since that would cause the program
> >  to extend into 0x2000:0, and all the offsets and addresses calculated
> >  by the linker would no longer work.)
> 
> The 64K restriction could be avoided by linking the real mode parts
> separately accessing them through call gates or software interrupts.

In other words, more magic.

> >- The program untimately runs at 0x10000, which is the same location
> >  as the existing bootstrap (this was so that I could steal the
> >  existing global descriptor table values until I understood them
> >  well enough to change them). The program is actually loaded into
> >  memory at a different location and copies itself to 0x10000.
> >  (It could actually go somewhere else, like 0x20000. I'm saving
> >  that for later.)
> 
> It would probably have been easier to understand it first :-).  You
> can't just steal the existing GDT since it will be overwritten.  Extra
> care is required to avoid using the old table before the new one is
> installed.

I meant using the existing values. With the program I wrote, I can
relocate to any physical segment so long as I change the value of
RELOC_ADDRESS in the Makefile and recompile. This will initialize
the descriptor table base addresses and fix up the startup code
so that it copies itself to the right place. Oh, and BOOTSEG needs
to be changed accordingly as well (meaning that if RELOC_ADDRESS is
0x20000, BOOTSEG has to be 0x2000).

I'm not actually using the same table left behind by the bootstrap:
as soon as the program runs, it copies itself over the old bootstrap,
carrying with it its own compiled-in table, and it resets the GDTR
to use this table instead. The values in the table are actually
the same, but the location has changed.

This was one place where I got confused because of the differences 
between the Mach code and ours. The fact that our bootstrap actually sets 
some of the values at run time didn't help. For example, in table.c in 
the Mach code, a segment descriptor looks like this:

        {0xFFFF, 0x1000, 0x0, 0x9E, 0x40, 0x0}, /* 0x08 : boot code */

But in our biosboot code, the descriptor for the same segment looks
like this (after being filled in at run time, that is):

        {0xFFFF, 0x0, 0x1, 0x9E, 0x40, 0x0},   /* 0x18 : boot code */

I ended up sticking printf()s in the second stage boot to dump out
the contents in the table so that I could compare them. I suspect
weird byte ordering silliness afoot.
 
> >- The existing bootstrap needs to be modified slightly to allow loading
> >  of OMAGIC binaries. Currently, it expects to load ZMAGIC binaries,
> >  which I think have their sections page aligned. To account for this,
> >  the bootstrap skips a chunk of memory between loading the text and
> >  data segments; this makes the bootstrap blow up when it tries to load
> >  an OMAGIC binary. The code needs to be changed to check the magic
> >  value of the binary and only skip the space for ZMAGIC binaries
> >  instead of doing it unconditionally.
 
> It should know nothing about binary formats. It should simply load files
> and jump to offset 0 in them.  There should be code at offset 0 that
> understands the binary format.

Then you'd have to change the kernel too since it is written in a
particular binary format (a.out, ZMAGIC) which the bootstrap does
special things to accomodate. The trouble I was having was that the
second stage bootstrap was crashing right after it loaded the text
segment. I eventually figured out that this was happening because
of the following code from boot.c:

        /********************************************************/
        /* Load the Initialised data after the text             */
        /********************************************************/
        while (addr & PAGE_MASK)
                *(char *)addr++ = 0;

As far as I can tell, this pads the text segment out to a page boundary,
and it's needed because ZMAGIC binaries have their segments page aligned.
But OMAGIC binaries don't, so if you load one with the existing bootstrap,
everything blows up right here. I changed this to:

        if (head.a_magic == ZMAGIC) {
                while (addr & PAGE_MASK)
                        *(char *)addr++ = 0;
        }

This is not exactly right either, since it assumes that ZMAGIC binaries
are the only ones that need this treatment. That aside, with this hack,
OMAGIC binaries load correctly.

> >I also don't quite understand the
> >following gas syntax
> 
> >ENTRY(disklabel)
> >	. = EXT(boot1) + 400
> 	                 0x400
[chop]

Okay, I got it. :)

The program works. The only problem right now is that boot() does
not have a proper argument passed to it, so it always assumes a bogus
value for dosdev. I suppose I could hack the second stage bootstrap
to pass the correct dosdev value to the third stage, but I'll
save that for another week.

I've uploaded the code to the incoming directory on freefall, and
I've also placed a copy on skynet.ctr.columbia.edu under
/pub/freebsd/standalone. The file is called standboot.tar.gz.
This is basically the same code as the existing biosboot from
FreeBSD-current, except that it has a different startup routine
and a few small tweaks. These are outlined in the README included
with the archive.

Now what I'd really like to do is to slam biosboot and netboot
together at high speeds.

-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?199605241942.PAA01258>