From owner-freebsd-hackers Mon May 13 08:47:47 1996 Return-Path: owner-hackers Received: (from root@localhost) by freefall.freebsd.org (8.7.3/8.7.3) id IAA29594 for hackers-outgoing; Mon, 13 May 1996 08:47:47 -0700 (PDT) Received: from skynet.ctr.columbia.edu (skynet.ctr.columbia.edu [128.59.64.70]) by freefall.freebsd.org (8.7.3/8.7.3) with SMTP id IAA29583 for ; Mon, 13 May 1996 08:47:37 -0700 (PDT) Received: (from wpaul@localhost) by skynet.ctr.columbia.edu (8.6.12/8.6.9) id LAA01112; Mon, 13 May 1996 11:46:37 -0400 From: Bill Paul Message-Id: <199605131546.LAA01112@skynet.ctr.columbia.edu> Subject: Making a three-stage boot To: freebsd-hackers@freebsd.org Date: Mon, 13 May 1996 11:46:36 -0400 (EDT) Cc: wpaul@skynet.ctr.columbia.edu (Bill Paul) X-Mailer: ELM [version 2.4 PL24] Content-Type: text Sender: owner-hackers@freebsd.org X-Loop: FreeBSD.org Precedence: bulk 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. =============================================================================