partition booter for PC's

Thomas Hoberg tmh at prosun.first.gmd.de
Wed Mar 6 13:46:59 AEST 1991


-- 
I posted this before, but people are still asking for it. It's not too big, so
please no flames...

These programs allow you to boot any partition and thereby any OS on reset.
Works with just about any OS and does NOT require any spare sectors on the hard
disk.

















--- cut here ---
#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 03/06/1991 03:16 UTC by tmh at keks
# Source directory /home/keks2/doppel/tmh/pboot
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   2493 -rw-r----- pboot.doc
#    239 -rw-r----- makefile
#   7852 -rw-r----- pboot.asm
#   4448 -rw-r----- install.c
#
# ============= pboot.doc ==============
if test -f 'pboot.doc' -a X"$1" != X"-c"; then
	echo 'x - skipping pboot.doc (File already exists)'
else
echo 'x - extracting pboot.doc (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pboot.doc' &&
PBOOT.ASM and INSTALL.C: partition booter and intallation utility for FDISK
compatible disks.
X
PBOOT.ASM contains the source code for a partition booter small enough to fit
on the master boot block with the partition table and should thus be compatible
with just about any operating system and hardware (old Microport Unix systems
are an exception, as they sometimes wrote the physical disk parameters in the
boot block for disks not supported by the BIOS).
X
PBOOT reads the embedded partition tables of the first two disks on the first
controller, displays a menu of partitions with the names of the operating
systems it knows about (e.g.  DOS, 386/ix, and AX) along with the value of the
operating system marker. It then asks you to enter the number of the desired
boot from partition (1-4 for one disk, 1-8 for two), loads the first block of
that partition and gives control to it (the normal booting procedure).
X
PBOOT doesn't really care which partition is actually active, though most UNIX
versions require the UNIX partition containing the boot code to be active. Thus
for UNIX you will want to leave the UNIX partition active at all times. On
actuall boot up though you will be able to boot any partition.
X
You will probably want to modify PBOOT to recognize the markers of the
operating systems that you actually use. Note that you will have to modify the
appropriate values at several places in the code (I didn't want to invest any
time in cleaning up that code). Note, though, that you do not inadvertently
increase the size of the code. It's a very tight fit (currently, I believe,
there is ONE byte left over).
X
PBOOT was originally written by Reinhard Baier for AX (= Advanced Unix), a
research operating system developed at the Technical University of Berlin,
featureing a tiny message passing kernel with an extremely low context switch
overhead, run-time installable device drivers, file systems (DOS, UNIX, QNX),
system call emulators (DOS, UNIX, QNX) running on Intel processors in real and
protected mode.
X
Due to the greedyness and narrowmindedness of the professor overseeing the
project, who wanted to keep it to himself and market it embedded into products
that a company owned by him sold, it was never actively distributed among
universities or other interested parties (although it is in the public domain).
X
The installation utility I wrote myself in a hurry. It seems to work on my
system, but you may want to look at it real hard.
X
I hope it helps!
X
:-) Thomas
X
SHAR_EOF
chmod 0640 pboot.doc ||
echo 'restore of pboot.doc failed'
Wc_c="`wc -c < 'pboot.doc'`"
test 2493 -eq "$Wc_c" ||
	echo 'pboot.doc: original size 2493, current size' "$Wc_c"
fi
# ============= makefile ==============
if test -f 'makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping makefile (File already exists)'
else
echo 'x - extracting makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'makefile' &&
# make macros don't seem to be portable...
X
all: pboot.bin install.exe
X
pboot.bin: pboot.exe
X	exe2bin pboot.exe pboot.bin
X
pboot.exe: pboot.obj
X	tlink pboot.obj
X
pboot.obj: pboot.asm
X	tasm pboot.asm;
X
install.exe: install.c
X	tcc install.c
SHAR_EOF
chmod 0640 makefile ||
echo 'restore of makefile failed'
Wc_c="`wc -c < 'makefile'`"
test 239 -eq "$Wc_c" ||
	echo 'makefile: original size 239, current size' "$Wc_c"
fi
# ============= pboot.asm ==============
if test -f 'pboot.asm' -a X"$1" != X"-c"; then
	echo 'x - skipping pboot.asm (File already exists)'
else
echo 'x - extracting pboot.asm (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pboot.asm' &&
; pboot.asm
;
; originally written by Rainhard Baier of the Berlin Technical University
; converted from QNX ASM to TASM format by Thomas Hoberg
; view with tabs set to four spaces
; NOTE: you will want to adapt the operating system markers to your own taste.
; Make sure you don't increase the size of the code, it's a very tight squeeze!
;
; $Revision: 1.2 $
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                          ;
; Fixed disk     M A S T E R    B O O T    R O U T I N E   ;
;                                                          ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; If the system is unable to boot from diskette, it loads  ;
; the master boot record from the first fixed disk         ;
; and gives control to it. Then this routine copies        ;
; itselves to 0000:0600 and tries to read the partition    ;
; table of an eventually installed second disk.            ;
; If there is an active bootable partition defined,        ;
; the corresponding boot record will be loaded and         ;
; executed. If an error occurs the user will be asked      ;
; to enter the partition number which he wants to boot.    ;
; This happens also if there is no active partition.       ;
; To give the user some hints, a table is displayed        ;
; containing the most important dates about the four or    ;
; eight possible partitions.                               ;
; This routine does not check if there is more than one    ;
; active partition - the first one found will be booted.   ;
; The search order is from one to the last as described in ;
; the "DOS Version 3.00 Technical Reference Manual".       ;
; It is just a little bit surprising that the DOS-command  ;
; "FDISK" counts in reverse order...                       ;
; With this booter it is also possible to load an OS from  ;
; the second disk. But it is necessary that all OS-Booters ;
; determine the contents of register DL to see             ;
; on what physical disk they are. In this way              ;
; all disks may be used as first or second device in any   ;
; system. It should be avoided to boot an OS from a disk   ;
; different from that the booter was on.                   ;
;                                                          ;
;                                     -- 14.12.85  RaB --  ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
new_seg			= 060h
new_off			= 00000h
X
part_tab		= 1beh
num_entries		= 4
entry_size		= 010h
signature		= 1feh
last_byte		= 1ffh
X
boot_dev		= 80h
X
boot_ind		= 00h
head_b			= 01h
sector_b		= 02h
cyl_b			= 03h
syst_ind		= 04h
head_e			= 05h
sector_e		= 06h
cyl_e			= 07h
rel_sect_l		= 08h
rel_sect_l		= 0ah
num_sect_l		= 0ch
num_sect_l		= 0eh
X
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X
X		org		new_off
X		.model	tiny
X		.code
X		align 1
boot:
X		call	get_ip						; stack MUST be ready
get_ip:
X		pop		si							; get IP to this instruction
X		sub		si,3						; IP to boot:
X		push	cs
X		pop		ds							; get current CS to DS
X
X		xor		di,di
X		mov		ax,new_seg
X		mov		es,ax
X		cld
X		mov		cx,100h
X		repnz	movsw						; copy 512 Bytes DS:SI -> ES:DI
;	abs	jmp		loader, newseg
X		db		0eah
X		dw		loader, new_seg				; --------------
X											;              |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;              |
X											;              |
loader:                                     ; <-------------
X		mov		bx,si
X		sub		bx,200h						; use same buffer for 2nd partition block
X		push	ds
X		pop		es							; ES:BX points to buffer
X
X		mov		cx,1						; 1st sector
X		mov		dx,81h						; 2nd drive
X		call	read_sector
; initialize register dh with value 4 17.08.89
X		jnc		drive2_ok
X		mov		dh,'4'						; last valid partition (1 drive)
X		jmp		menu
X
drive2_ok:
X		cmp		signature[bx],0aa55h		;test for valid signature
X		jne		menu
X		lea		si,part_tab[bx]
X
X		push	cs
X		pop		es
X		mov		di,signature
X		mov		cx,num_entries * entry_size / 2
X
X		repnz	movsw						; copy second partition table after
X											; the first one
X
X		mov		dh,'8'						; last valid partion (2 drives active)
X
menu:
X		push	cs
X		pop		ds
X		xor		cl,cl						; active partition
X		mov		bx,part_tab
X		mov		dl,'1'
X
X		mov		si, offset header
X		call	prstr
X
check_entry:
X		mov		al,dl
X		call	prchar
X		mov		si,offset blank
X		call	prstr
X
X		mov		ch,syst_ind[bx]
X		mov		si,offset type_0
X		cmp		ch,0
X		je		show_it
X		mov		si,offset type_dos
X		cmp		ch,1
X		je		show_it
X		cmp		ch,4
X		je		show_it
X		mov		si,offset type_ax
X		cmp		ch,7
X		je		show_it
X		mov		si,offset type_sys5
X		cmp		ch,063h
X		je		show_it
X		mov		si,offset type_swap
X		cmp		ch,6
X		je		show_it
X		mov		si,offset type_X
show_it:
X		call	prstr
X		mov		al,'('
X		call	prchar
X		mov		al,ch
X		add		al,'0'
X		call	prchar
X		mov		al,')'
X		call	prchar
X		cmp		ch,063h
X		je		linefeed
X		cmp		byte ptr boot_ind[bx],80h
X		jne		linefeed
X		mov		cl,dl						; save number of active entry
linefeed:
X		mov		si,offset crlf
X		call	prstr
X
X		add		bx,entry_size
X		inc		dl
X		cmp		dl,dh
X		jle		check_entry
X
X		mov		si,offset crlf
X		call	prstr
;;; If the following statements are uncommented PBOOT will boot the active
;;; partition if no key is pressed.
;;; I find it hard to press the right key just in time (my BIOS flushes the
;;; keyboard queue immediately before executing this code) that's why I don't
;;; use it. If you need automatic reboots or something like that you might
;;; want to reenable it (watch out for code size!)
;		mov		ah,1	;if no key is pressed use the active
;		int		16h	;partition stored in cl (doesn't work
;		jnz		get_key	;for the first because cl is zero)
;		or		cl,cl
;		jz		get_key						; no active partition
;		mov		al,cl						; restore active partition
;		jmp		get_part
get_key:
X		mov		si,offset what_part
X		call	prstr
X		xor		ah,ah
X		int		16h
X		cmp		al,'0'
X		jle		error
X		cmp		al,dh
X		ja		error
X
get_part:
X		sub		al,31h
X		mov		dl,boot_dev
X		cmp		al,4
X		jl		drive_1
X		inc		dl
drive_1:
X		xor		ah,ah
X		mov		bl,entry_size
X		mul		bl
X		mov		bx,part_tab
X		add		bx,ax
X		cmp		byte ptr syst_ind[bx],0
X		jne		boot_it
X		jmp		error
boot_it:
X		push	dx							; save last valid partition in dh
X		mov		cx,sector_b[bx]
X		mov		dh,head_b[bx]
X		xor		ax,ax						; addr = ES:BX
X		mov		es,ax
X		mov		bx,7c00h
X		call	read_sector
X		pop		dx							; restore dh
X		jnc		read_ok
X		mov		si,offset load_error
X		call	prstr
X		jmp		error
X
read_ok:
X		cmp		signature[es:bx],0aa55h	;test for valid signature
X		je		boot_ok
X		mov		si,offset sig_missing
X		call	prstr
error:
X		mov		si,offset err_crlf
X		call	prstr
X		jmp		get_key						; try again
X
boot_ok:
; 17.8.89 it's better to print \n
X		mov		si,offset crlf
X		call	prstr
; 17.08.89 don't clear the screen
;		mov		ah,#15						; get card type
;		int		010h						; returned in al
X
;		xor		ah,ah						; set mode clears screen
;		int		10h							; and positions cursor home
X
X											; DL contains boot - drive
;	abs	jmp		7c00h,0000h					; goto partition boot record just loaded
X		db		0eah
X		dw		7c00h, 0000h
X
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X
prstr:										; si = "string"
X		lodsb
X		or		al,al
X		jz		end_prstr
X		call	prchar
X		jmp		prstr
end_prstr:
X		ret
X
prchar:										; al = 'char'
X		push	bx
X		xor		bl,bl						; foreground color graphics mode
X		mov		ah,14
X		int		10h
X		pop		bx
X		ret
X
read_sector:
X		mov		si,5						; retry_count
retry:
X		mov		ax,0201h					; read 1 sector
X		int		13h
X		jnc		end_read_sector
X		dec		si
X		jnz		retry
X		stc
end_read_sector:
X		ret
X
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X		.data
header:
X		db	"Part.  OS(type)", 0dh, 0ah, 0
blank:
X		db	"      ", 0
type_0:
X		db	"---  ", 0
type_dos:
X		db	"DOS  ", 0
type_ax:
X		db	"AX   ", 0
type_sys5:
X		db	"SysV ", 0
type_swap:
X		db	"Swap ", 0
type_X:
;		db	"???  ", 0
sig_missing:
X		db	"No OS", 0
X
err_crlf:
X		db	7
crlf:
X		db	0dh, 0ah, 0
X
what_part:
X		db	"Partition? ",0
load_error:
X		db	"Error", 0
X
X		end
SHAR_EOF
chmod 0640 pboot.asm ||
echo 'restore of pboot.asm failed'
Wc_c="`wc -c < 'pboot.asm'`"
test 7852 -eq "$Wc_c" ||
	echo 'pboot.asm: original size 7852, current size' "$Wc_c"
fi
# ============= install.c ==============
if test -f 'install.c' -a X"$1" != X"-c"; then
	echo 'x - skipping install.c (File already exists)'
else
echo 'x - extracting install.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'install.c' &&
/*
X * install.c -- install new boot code preserving the old partition table and
X * saving the old boot block (whatever for?)
X *
X * Nov 1st, 1990 Thomas Hoberg  tmh%gmdtub at tub.UUCP
X *
X * Unlimited Warranty: I hereby guarantee, that this program may or may not
X * do what you think it does, and that it might or might not destroy your data.
X * (I hate Disclaimers and Limited Warranties, let's stand up for our code!)
X */
X
#include <stdio.h>
#include <dos.h>
#include <string.h>
X
#define BLKSIZE 512		/* sizes in bytes */
#define PTBLSIZE 16*4
#define SIGNSIZE 2
#define BOOTSIZE BLKSIZE - (PTBLSIZE + SIGNSIZE)
#define SIGNATURE 0xAA55U
X
typedef struct mbb {
X	char bootcode[BOOTSIZE];
X	char ptable[PTBLSIZE];
X	unsigned short int signature;
} mbbT;
X
char *Usage =
"Partition booter installation program. See source and documantation for usage\n"
"details. It will basically copy a file to the disk\'s boot block while maintain-\n"
"ing the partition table (hopefully). If your master boot block was not instal-\n"
"led by DOS FDISK you better don\'t use this...\n"
"It will also write a copy of the old boot block, which can be restored via\n"
"the \'-r\' option. You will want to run the programm off an emergency boot disk\n"
"(*NOT* write protected).\n\n"
"USAGE: install <name-of-bootfile-to-install> <file-to-save-old-boot-code-into>\n"
"   OR: install -r <file-containing-old-boot-code>\n"
"NOTE : All parameters are mandatory (this is a hack, not a program).\n"
;
X
char *NoSignature =
"The block read does not contain a valid signature which means, that either\n"
"this program ain\'t working, or your system doesn\'t at this time contain\n"
"a valid boot block. If you are sure you want to go on, press <ENTER>,\n"
"otherwise hit <Ctrl-C>, <Ctrl-Break> or *RESET*, to abort.\n\b"
;
X
char *CodeTooBig =
"Your boot block is too big (> %d bytes). It would overwrite the embedded\n"
"partition table. Installation aborted.\n\b"
;
X
char *wrongSizeForBoot =
"A valid boot block should be exactly %d bytes in size. The one you supplied in"
"\'%s\' has an invalid size of %d. Hit <ENTER> now to continue with the install-"
"ation (risky) or <Ctrl-C>, <Ctrl-Break> or *RESET* to abort.\n\b"
;
X
X
mbbT oldMbb, newMbb;
FILE *inFile, *outFile;
char *inName;
union REGS regs;
struct SREGS sregs;
int install;
X
X	FILE *
doOpen(char *name, char  *mode) {
X
X	FILE *aFile;
X
X	if ((aFile = fopen(name, mode)) < 0) {
X		perror(name);
X		fprintf(stderr, "%s\b", Usage);
X		exit(1);
X	}
X	return aFile;
}
X
X	int
main (int argc, char *argv[]) {
X
X	size_t fc;
X
X	if (argc != 3) {
X		fprintf(stderr, "%s\b", Usage);
X		return 1;
X	}
X	install = strcmp(argv[1], "-r") != 0;
X	if (install) {
X		inName = argv[1];
X		inFile = doOpen(inName, "rb");
X		outFile = doOpen(argv[2], "wb");
X	} else {
X		inName = argv[2];
X		inFile = doOpen(inName, "rb");
X	}
X	if ((fc = fread(&newMbb, 1, BLKSIZE, inFile)) < 0) {
X		perror(inName);
X		fprintf(stderr, "%s\b", Usage);
X		return 2;
X	}
X	close(inFile);
X	if (install) {
X		if (fc > BOOTSIZE) {
X			fprintf(stderr, CodeTooBig, BOOTSIZE);
X			return 9;
X		}
X		regs.x.ax = 0;	/* reset disk */
X		regs.x.dx = 0x80;
X		int86(0x13, &regs, &regs);
X		if (regs.h.ah != 0) {
X			fprintf(stderr, "couldn\'t reset disk drive!\b\n");
X			return 3;
X		}
X		segread(&sregs);
X		regs.x.ax = 0x0201; /* read first sector */
X		regs.x.cx = 1;
X		regs.x.dx = 0x80;
X		regs.x.bx = (unsigned int) &oldMbb;
X		sregs.es = sregs.ds;
X		int86x(0x13, &regs, &regs, &sregs);
X		if (regs.h.ah != 0) {
X			fprintf(stderr, "couldn\'t read boot block!\b\n");
X			return 4;
X		}
X		if (oldMbb.signature != SIGNATURE) {
X			fprintf(stderr, NoSignature);
X			getchar();
X		}
X		fwrite(&oldMbb, BLKSIZE, 1, outFile);
X		close(outFile);
X		memcpy(newMbb.ptable, oldMbb.ptable, PTBLSIZE);
X		newMbb.signature = SIGNATURE;
X	} else { /* restore */
X		if (fc != BLKSIZE) {
X			fprintf(stderr, wrongSizeForBoot, BLKSIZE, argv[2], fc);
X			getchar();
X		}
X	} /* endif */
X	segread(&sregs);
X	regs.x.ax = 0x0301; /* write first sector */
X	regs.x.cx = 1;
X	regs.x.dx = 0x80; /* first fixed disk */
X	regs.x.bx = (unsigned int) &newMbb;
X	sregs.es = sregs.ds;
X	int86x(0x13, &regs, &regs, &sregs);
X	if (regs.h.ah != 0) {
X		fprintf(stderr, "Write of new boot block failed for some reason!\b\n");
X		return 8;
X	}
X	if (install) {
X		printf("New boot block \'%s\' installed, old block saved to \'%s\'\n",
X			argv[1], argv[2]);
X	} else {
X		printf("Boot block restored from \'%s\'\n", argv[2]);
X	}
X	printf("Sure hope it worked...\n");
X	return 0;
}
SHAR_EOF
chmod 0640 install.c ||
echo 'restore of install.c failed'
Wc_c="`wc -c < 'install.c'`"
test 4448 -eq "$Wc_c" ||
	echo 'install.c: original size 4448, current size' "$Wc_c"
fi
exit 0

----
Thomas M. Hoberg   | UUCP: tmh at bigfoot.first.gmd.de  or  tmh%gmdtub at tub.UUCP
c/o GMD Berlin     |       ...!unido!tub!gmdtub!tmh (Europe) or
D-1000 Berlin 12   |       ...!unido!tub!tmh
Hardenbergplatz 2  |       ...!pyramid!tub!tmh (World)
Germany            | BITNET: tmh%DB0TUI6.BITNET at DB0TUI11 or
+49-30-254 99 160  |         tmh at tub.BITNET



More information about the Comp.unix.sysv386 mailing list