mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-25 11:37:56 +00:00
Obtained from: Whistle Communications
Add code to the boot blocks to allow the user to place default boot strings on block 1 of the disk (2nd block), should the correct magic numbers be present. If the correct options are used it will 'delete' the name used from block1, thereby assuring that if the boot fails it won't be stuck in an infinite loop. the boot strings are set by the utility "nextboot" (not yet checked in, but being tested.) By default these changes should have no effect on existing installations and if compiled without the NAMEBLOCK option should be essentially identical to the old ones.
This commit is contained in:
parent
86ff3944a1
commit
9ed24653f7
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=16983
@ -1,3 +1,6 @@
|
||||
Note: all my origianl references to 386BSD also refer to freeBSD and NetBSD
|
||||
which in some ways derived from 386BSD. --julian@freebsd.org
|
||||
|
||||
This Boot code is different from the original boot code that came with
|
||||
386BSD in that it uses the BIOS to load the kernel and to provide all i/o
|
||||
services. The advantage ofthis is that the same boot code exactly, can run
|
||||
@ -25,31 +28,45 @@ if it has (the same) magic numbers, jumps into it. In 386bsd this is the
|
||||
first stage boot, (or boot1) it is represented in /usr/mdec by
|
||||
wdboot, asboot and sdboot. If the disk has been set up without DOS partitioning
|
||||
then this block will be at block zero, and will have been loaded directly by
|
||||
the BIOS.
|
||||
the BIOS. This is the usual case with floppies.
|
||||
|
||||
4/ Boot1 will look at block0 (which might be itself if there are no DOS
|
||||
partitions) and will find the 386bsd partition, and using the information
|
||||
regarding the start position of that partition, will load the next 13 sectors
|
||||
or so, to around 90000 (640k - 64k). and will jump into it at the appropriate
|
||||
entry point. Since boot1 and boot2 were compiled together as one file
|
||||
and then split later, boot1 knows the exact position within boot2 of the
|
||||
entry point.
|
||||
partitions) and will find the 386bsd partition,
|
||||
|
||||
Boot 1 also contains a compiled in DOS partition table
|
||||
(in case it is at block 0), which contains a 386bsd partition starting
|
||||
at 0. This ensures that the same code can work whether or not
|
||||
boot1 is at block 0.
|
||||
|
||||
4A/ IF the NAMEBLOCK option is compiled into the bootcode, then the
|
||||
boot1 code will load and examine block1 (Usually unused) and
|
||||
look for a default boot string to use later.. (if the corrct magic number
|
||||
is present). If the option NAMEBLOCKWRITEBACK is also defined, then
|
||||
it will zero out that name after finding it, and write the block back,
|
||||
having "used up" that name. The block may contain multiple different
|
||||
boot strings which will be "used up" one after the other.. (one per boot)
|
||||
They are set using the "nextboot" utility.
|
||||
|
||||
4B/ Using the information found in step 4, regarding the start position
|
||||
of the BSD partition, boot1 will load the first 16 sectors of that partition,
|
||||
to around 0x10000 (64k). and will jump into it at the appropriate entry point.
|
||||
Since boot1 and boot2 were compiled together as one file and then split
|
||||
later, boot1 knows the exact position within boot2 of the entry point.
|
||||
|
||||
5/ Boot2 asks the user for a boot device, partition and filename, and then
|
||||
loads the MBR of the selected device. This may or may not be the device
|
||||
which was originally used to boot the first MBR. The partition table
|
||||
of the new MBR is searched for a 386bsd partition, and if one is found,
|
||||
that is then in turn searched for the disklabel. This could all be on the
|
||||
second disk at this point, if the user selected it.
|
||||
second disk at this point, if the user selected it. If the user makes no
|
||||
actions then a default string will be used.
|
||||
|
||||
6/On finding the disklabel, boot2 can find the correct unix partition
|
||||
within the 386bsd partition, and using cutdown filesystem code,
|
||||
look for the file to boot (e.g. 386bsd).
|
||||
If the NAMEBLOCK option is used, then the default string may have been
|
||||
loaded from block2. If none was found then a compiled in default will be used.
|
||||
|
||||
6/On finding the disklabel, on the disk th euser spacified, boot2 can find
|
||||
the correct unix partition within the 386bsd partition, and using cutdown
|
||||
filesystem code, look for the file to boot (e.g. 386bsd).
|
||||
|
||||
7/ Boot2 loads this file starting at the location specified by the a.out header,
|
||||
(see later) and leaps into it at the location specified in he header.
|
||||
@ -82,6 +99,8 @@ If you want to do it by hand remember that BIOS counts sectors starting at 1.
|
||||
|
||||
2/ you cannot overwrite the bottom 4k of ram until you have finished ALL
|
||||
bios calls, as BIOS uses this area as scratch memory.
|
||||
This is no longer really a probelm as we no-longer support loading the kernel
|
||||
at location 0.
|
||||
|
||||
3/ Since BIOS runs in REAL mode, and Boot2 runs in protected mode,
|
||||
Boot 2 switches back to real mode just before each BIOS call and then
|
||||
@ -92,6 +111,8 @@ In answering the prompt from Boot2:
|
||||
you can,
|
||||
1/ leave it alone.. it will boot the indicated file from the first
|
||||
partition of the first drive seen by the BIOS (C:)
|
||||
If the NAMEBLOCK option is in use, the default name might be taken from block1
|
||||
(2nd block) on that drive. (the drive on which boot 1 was loaded).
|
||||
|
||||
2/ enter only "-s" to boot the default to single user mode
|
||||
|
||||
@ -148,4 +169,4 @@ Before you do this ensure you have a booting floppy with correct
|
||||
disktab and bootblock files on it so that if it doesn't work, you can
|
||||
re-disklabel from the floppy.
|
||||
|
||||
$Id: README.386BSD,v 1.3 1995/02/16 12:02:08 jkh Exp $
|
||||
$Id: README.386BSD,v 1.4 1996/04/07 14:27:57 bde Exp $
|
||||
|
@ -24,7 +24,7 @@
|
||||
* the rights to redistribute these changes.
|
||||
*
|
||||
* from: Mach, Revision 2.7 92/02/29 15:33:41 rpd
|
||||
* $Id: asm.h,v 1.3 1993/10/16 19:11:29 rgrimes Exp $
|
||||
* $Id: asm.h,v 1.4 1995/05/30 07:58:25 rgrimes Exp $
|
||||
*/
|
||||
|
||||
#define S_ARG0 4(%esp)
|
||||
@ -142,3 +142,10 @@
|
||||
|
||||
#define Entry(x) .globl EXT(x); .align ALIGN; LEXT(x)
|
||||
#define DATA(x) .globl EXT(x); .align ALIGN; LEXT(x)
|
||||
|
||||
/* note, this calls the 'message' in boot1 */
|
||||
#define DEBUGMSG(msg) \
|
||||
data32 ;\
|
||||
mov $(msg), %esi ;\
|
||||
data32 ;\
|
||||
call EXT(message)
|
||||
|
@ -24,7 +24,7 @@
|
||||
* the rights to redistribute these changes.
|
||||
*
|
||||
* from: Mach, [92/04/03 16:51:14 rvb]
|
||||
* $Id: boot.c,v 1.49 1996/05/02 10:43:01 phk Exp $
|
||||
* $Id: boot.c,v 1.50 1996/05/11 04:27:24 bde Exp $
|
||||
*/
|
||||
|
||||
|
||||
@ -62,6 +62,7 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
#define NAMEBUF_LEN (8*1024)
|
||||
|
||||
char namebuf[NAMEBUF_LEN];
|
||||
extern char *dflt_name;
|
||||
struct exec head;
|
||||
struct bootinfo bootinfo;
|
||||
int loadflags;
|
||||
@ -126,8 +127,19 @@ boot(int drive)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* DAMN! I don't understand why this is not being set
|
||||
* by the code in boot2.S
|
||||
*/
|
||||
dflt_name= (char *)0x0000ffb0;
|
||||
loadstart:
|
||||
if( (dflt_name[0] == 'D') && (dflt_name[1] == 'N') && dflt_name[2] ) {
|
||||
name = dflt_name+2;
|
||||
dflt_name[0] = 0;
|
||||
} else {
|
||||
name = dflname; /* re-initialize in case of loop */
|
||||
}
|
||||
/* print this all each time.. (saves space to do so) */
|
||||
/* If we have looped, use the previous entries as defaults */
|
||||
printf("\n>> FreeBSD BOOT @ 0x%x: %d/%d k of memory\n"
|
||||
@ -137,7 +149,6 @@ boot(int drive)
|
||||
ouraddr, bootinfo.bi_basemem, bootinfo.bi_extmem,
|
||||
dosdev & 0x7f, devs[maj], unit, name);
|
||||
|
||||
name = dflname; /* re-initialize in case of loop */
|
||||
loadflags &= RB_SERIAL; /* clear all, but leave serial console */
|
||||
getbootdev(namebuf, &loadflags);
|
||||
ret = openrd();
|
||||
|
@ -24,7 +24,7 @@
|
||||
* the rights to redistribute these changes.
|
||||
*
|
||||
* from: Mach, Revision 2.2 92/04/04 11:35:26 rpd
|
||||
* $Id: boot2.S,v 1.5 1994/08/30 01:38:03 bde Exp $
|
||||
* $Id: boot2.S,v 1.6 1995/01/25 21:37:40 bde Exp $
|
||||
*/
|
||||
|
||||
#include "asm.h"
|
||||
@ -47,6 +47,7 @@
|
||||
|
||||
/*
|
||||
* boot2() -- second stage boot
|
||||
* SP points to default string if found
|
||||
*/
|
||||
|
||||
ENTRY(boot2)
|
||||
@ -57,6 +58,9 @@ ENTRY(boot2)
|
||||
mov %ax, %es
|
||||
data32
|
||||
shll $4, %eax
|
||||
addr32
|
||||
data32
|
||||
movl %esp, EXT(dflt_name)
|
||||
|
||||
/* fix up GDT entries for bootstrap */
|
||||
#define FIXUP(gdt_index) \
|
||||
|
@ -24,7 +24,7 @@
|
||||
* the rights to redistribute these changes.
|
||||
*
|
||||
* from: Mach, Revision 2.2 92/04/04 11:36:29 rpd
|
||||
* $Id: start.S,v 1.5 1994/10/06 09:41:05 rgrimes Exp $
|
||||
* $Id: start.S,v 1.6 1995/09/16 13:51:20 bde Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -60,6 +60,9 @@ NUMPART= 4 /* number of partitions in partition table */
|
||||
PARTSZ= 16 /* each partition table entry is 16 bytes */
|
||||
BSDPART= 0xA5 /* value of boot_ind, means bootable partition */
|
||||
BOOTABLE= 0x80 /* value of boot_ind, means bootable partition */
|
||||
NAMEBLOCKMAGIC= 0xfadefeed /* value of magicnumebr for block2 */
|
||||
|
||||
/* to debug this, Use the DEBUGMSG(msg) macro defined in asm.S */
|
||||
|
||||
.text
|
||||
|
||||
@ -80,18 +83,17 @@ start:
|
||||
data32
|
||||
mov $BOOTSEG, %eax
|
||||
mov %ax, %ss
|
||||
/*
|
||||
* make a little room on the stack for
|
||||
* us to save the default bootstring we might find..
|
||||
* effectively, we push the bootstring.
|
||||
*/
|
||||
data32
|
||||
mov $BOOTSTACK, %esp
|
||||
mov $(BOOTSTACK - 64), %esp
|
||||
|
||||
/* set up %es, (where we will load boot2 to) */
|
||||
mov %ax, %es
|
||||
|
||||
#ifdef DEBUG
|
||||
data32
|
||||
mov $one, %esi
|
||||
data32
|
||||
call message
|
||||
#endif
|
||||
|
||||
/* bootstrap passes us drive number in %dl */
|
||||
cmpb $0x80, %dl
|
||||
@ -108,44 +110,20 @@ fd:
|
||||
mov $0x0, %dl
|
||||
|
||||
/* reset the disk system */
|
||||
#ifdef DEBUG
|
||||
data32
|
||||
mov $two, %esi
|
||||
data32
|
||||
call message
|
||||
#endif
|
||||
movb $0x0, %ah
|
||||
int $0x13
|
||||
data32
|
||||
mov $0x0001, %ecx /* cyl 0, sector 1 */
|
||||
movb $0, %dh /* head */
|
||||
#ifdef DEBUG
|
||||
data32
|
||||
mov $three, %esi
|
||||
data32
|
||||
call message
|
||||
#endif
|
||||
data32
|
||||
jmp load
|
||||
|
||||
hd: /**** load sector 0 into the BOOTSEG ****/
|
||||
#ifdef DEBUG
|
||||
data32
|
||||
mov $four, %esi
|
||||
data32
|
||||
call message
|
||||
#endif
|
||||
data32
|
||||
mov $0x0201, %eax
|
||||
xor %ebx, %ebx /* %bx = 0 */
|
||||
data32
|
||||
mov $0x0001, %ecx
|
||||
#ifdef DEBUG
|
||||
data32
|
||||
mov $five, %esi
|
||||
data32
|
||||
call message
|
||||
#endif
|
||||
data32
|
||||
andl $0xff, %edx
|
||||
/*mov $0x0080, %edx*/
|
||||
@ -194,6 +172,164 @@ found:
|
||||
movl %es:2(%ebx), %ecx /*sect, cyl (+ 2 bytes junk in top word) */
|
||||
|
||||
load:
|
||||
#ifdef NAMEBLOCK
|
||||
/*
|
||||
* Load the second sector and see if it is a boot instruction block.
|
||||
* If it is then scan the contents for the first valid string and copy it to
|
||||
* the location of the default boot string.. then zero it out.
|
||||
* Finally write the block back to disk with the zero'd out entry..
|
||||
* I hate writing at this stage but we need this to be persistant.
|
||||
* If the boot fails, then the next boot will get the next string.
|
||||
* /etc/rc will regenerate a complete block2 iff teh boot succeeds.
|
||||
*
|
||||
* Format of block 2 is:
|
||||
* [NAMEBLOCKMAGIC] <--0xdeafc0de
|
||||
* [nulls]
|
||||
* [bootstring]NULL <---e.g. 0:wd(0,a)/kernel.experimental
|
||||
* [bootstring]NULL <---e.g. 0:wd(0,a)/kernel.old
|
||||
* ....
|
||||
* [bootstring]NULL <---e.g. 0:wd(0,f)/kernel
|
||||
* FF FF FF
|
||||
*/
|
||||
where:
|
||||
/*
|
||||
* save things we might smash
|
||||
* (that are not smashed immedatly after us anyway.)
|
||||
*/
|
||||
data32
|
||||
push %ecx /* preserve 'cyl,sector ' */
|
||||
data32
|
||||
push %edx
|
||||
/*
|
||||
* Load the second sector
|
||||
* BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
|
||||
* Call with %ah = 0x2
|
||||
* %al = number of sectors
|
||||
* %ch = cylinder
|
||||
* %cl = sector
|
||||
* %dh = head
|
||||
* %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
|
||||
* %es:%bx = segment:offset of buffer
|
||||
* Return:
|
||||
* %al = 0x0 on success; err code on failure
|
||||
*/
|
||||
data32
|
||||
movl $0x0201, %eax /function 2 (read) 1 sector */
|
||||
xor %ebx, %ebx /* %bx = 0 */ /* buffer address (ES:0) */
|
||||
data32
|
||||
movl $0x0002, %ecx /* sector 2, cylinder 0 */
|
||||
data32
|
||||
andl $0x00ff, %edx /* head 0, drive N */
|
||||
int $0x13
|
||||
data32
|
||||
jb read_error
|
||||
/*
|
||||
* confirm that it is one for us
|
||||
*/
|
||||
data32
|
||||
xorl %ebx, %ebx /* magic number at start of buffer */
|
||||
data32
|
||||
addr32
|
||||
movl %es:(%ebx), %eax
|
||||
data32
|
||||
cmpl $NAMEBLOCKMAGIC, %eax
|
||||
data32
|
||||
jne notours /* not ours so return to caller */
|
||||
/*
|
||||
* scan for a bootstring
|
||||
* Skip the magic number, and scan till we find a non-null,
|
||||
* or a -1
|
||||
*/
|
||||
incl %ebx /* quicker and smaller */
|
||||
incl %ebx
|
||||
incl %ebx
|
||||
scan:
|
||||
incl %ebx
|
||||
addr32
|
||||
movb %es:(%ebx), %al /* load the next byte */
|
||||
testb %al, %al /* and if it is null */
|
||||
data32 /* keep scanning (past deleted entries) */
|
||||
jz scan
|
||||
incb %al /* now look for -1 */
|
||||
data32
|
||||
jz notours /* if we reach the 0xFF then we have finished */
|
||||
|
||||
/*
|
||||
* save our settings.. we need them twice..
|
||||
*/
|
||||
data32
|
||||
push %ebx
|
||||
/*
|
||||
* copy it to the default string location
|
||||
* which is just above the stack for 64 bytes.
|
||||
*/
|
||||
data32
|
||||
movl $(BOOTSTACK-64), %ecx /* 64 bytes at the top of the stack */
|
||||
nxtbyte:
|
||||
addr32
|
||||
movb %es:(%ebx), %al /* get the next byte in */
|
||||
addr32
|
||||
movb %al, %es:(%ecx) /* and transfer it to the name buffer */
|
||||
incl %ebx /* get on with the next byte */
|
||||
incl %ecx /* get on with the next byte */
|
||||
testb %al, %al /* if it was 0 then quit this */
|
||||
data32
|
||||
jnz nxtbyte /* and looop if more to do */
|
||||
|
||||
/*
|
||||
* restore the saved settings and
|
||||
* zero it out so next time we don't try it again
|
||||
*/
|
||||
data32
|
||||
pop %ebx /* get back our starting location */
|
||||
#ifdef NAMEBLOCK_WRITEBACK
|
||||
nxtbyte2:
|
||||
addr32
|
||||
movb %es:(%ebx), %al /* get the byte */
|
||||
addr32
|
||||
movb $0, %es:(%ebx) /* zero it out */
|
||||
data32
|
||||
incl %ebx /* point to the next byte */
|
||||
testb %al, %al /* check if we have finished.. */
|
||||
data32
|
||||
jne nxtbyte2
|
||||
/*
|
||||
* Write the second sector back
|
||||
* Load the second sector
|
||||
* BIOS call "INT 0x13 Function 0x3" to write sectors from memory to disk
|
||||
* Call with %ah = 0x3
|
||||
* %al = number of sectors
|
||||
* %ch = cylinder
|
||||
* %cl = sector
|
||||
* %dh = head
|
||||
* %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
|
||||
* %es:%bx = segment:offset of buffer
|
||||
* Return:
|
||||
* %al = 0x0 on success; err code on failure
|
||||
*/
|
||||
data32
|
||||
movl $0x0301, %eax /* write 1 sector */
|
||||
xor %ebx, %ebx /* buffer is at offset 0 */
|
||||
data32
|
||||
movl $0x0002, %ecx /* block 2 */
|
||||
data32
|
||||
andl $0xff, %edx /* head 0 */
|
||||
int $0x13
|
||||
data32
|
||||
jnb notours
|
||||
data32
|
||||
mov $eread, %esi
|
||||
jmp err_stop
|
||||
#endif /* NAMEBLOCK_WRITEBACK */
|
||||
/*
|
||||
* return to the main-line
|
||||
*/
|
||||
notours:
|
||||
data32
|
||||
pop %edx
|
||||
data32
|
||||
pop %ecx
|
||||
#endif
|
||||
movb $0x2, %ah /* function 2 */
|
||||
movb $LOADSZ, %al /* number of blocks */
|
||||
xor %ebx, %ebx /* %bx = 0, put it at 0 in the BOOTSEG */
|
||||
@ -207,12 +343,6 @@ load:
|
||||
* as an internal buffer "intbuf".
|
||||
*/
|
||||
|
||||
#ifdef DEBUG
|
||||
data32
|
||||
mov $six, %esi
|
||||
data32
|
||||
call message
|
||||
#endif
|
||||
data32
|
||||
ljmp $BOOTSEG, $ EXT(boot2)
|
||||
|
||||
@ -231,6 +361,7 @@ err_stop:
|
||||
/*
|
||||
* message: write the error message in %ds:%esi to console
|
||||
*/
|
||||
ENTRY(message)
|
||||
message:
|
||||
/*
|
||||
* Use BIOS "int 10H Function 0Eh" to write character in teletype mode
|
||||
@ -269,15 +400,16 @@ stop: hlt
|
||||
|
||||
/* error messages */
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
one: String "1\r\n\0"
|
||||
two: String "2\r\n\0"
|
||||
three: String "3\r\n\0"
|
||||
four: String "4\r\n\0"
|
||||
five: String "5\r\n\0"
|
||||
six: String "6\r\n\0"
|
||||
seven: String "7\r\n\0"
|
||||
one: String "1-\0"
|
||||
two: String "2-\0"
|
||||
three: String "3-\0"
|
||||
four: String "4-\0"
|
||||
#endif DEBUG
|
||||
#ifdef NAMEBLOCK_WRITEBACK
|
||||
ewrite: String "Write error\r\n\0"
|
||||
#endif /* NAMEBLOCK_WRITEBACK */
|
||||
eread: String "Read error\r\n\0"
|
||||
enoboot: String "No bootable partition\r\n\0"
|
||||
endofcode:
|
||||
@ -291,6 +423,7 @@ endofcode:
|
||||
*/
|
||||
/* flag, head, sec, cyl, typ, ehead, esect, ecyl, start, len */
|
||||
. = EXT(boot1) + PARTSTART
|
||||
strttbl:
|
||||
.byte 0x0,0,0,0,0,0,0,0
|
||||
.long 0,0
|
||||
.byte 0x0,0,0,0,0,0,0,0
|
||||
|
@ -24,7 +24,7 @@
|
||||
* the rights to redistribute these changes.
|
||||
*
|
||||
* from: Mach, Revision 2.2 92/04/04 11:36:43 rpd
|
||||
* $Id: table.c,v 1.9 1996/03/08 05:15:54 bde Exp $
|
||||
* $Id: table.c,v 1.10 1996/04/07 14:28:05 bde Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -140,3 +140,4 @@ char *devs[] = { "wd", "dk", "fd", "wt", "sd", 0 };
|
||||
char dflname[] = "/kernel";
|
||||
char *name = dflname;
|
||||
unsigned long tw_chars = 0x5C2D2F7C; /* "\-/|" */
|
||||
char *dflt_name;
|
||||
|
Loading…
Reference in New Issue
Block a user