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, ®s, ®s);
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, ®s, ®s, &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, ®s, ®s, &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