Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!sun-barr!apple!agate!linus!linus!gwr From: gwr@linus.mitre.org (Gordon W. Ross) Newsgroups: comp.unix.sysv386 Subject: BOOTMENU and PFDISK 1.2 (part 2/2) Summary: primary boot sector program with menu Keywords: boot partition menu Message-ID: <119451@linus.mitre.org> Date: 7 Sep 90 22:41:02 GMT Reply-To: gwr@linus.mitre.org (Gordon W. Ross) Organization: The MITRE Corporation, Bedford, MA. Lines: 841 Here is part 2 of the BOOTMENU and PFDISK 2.1 distribution. More detailed descriptions are found in the README file at the beginning of the first shell archive. #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # SStor.txt # s_msdos.c # bootmenu.asm # bootauto.asm # asm2bin.bat # make_msc.bat # This archive created: Fri Sep 7 18:37:59 1990 # By: Gordon W. Ross (The MITRE Corporation, Bedford, MA.) export PATH; PATH=/bin:$PATH echo shar: extracting "'SStor.txt'" '(1027 characters)' if test -f 'SStor.txt' then echo shar: will not over-write existing file "'SStor.txt'" else cat << \SHAR_EOF > 'SStor.txt' Note: SpeedStor (sstor) modifies MANY locations in the boot sector! The SpeedStor manual says it does not modify locations 0xEA -- 0x17D BUT THEY LIE! If you use the "Parameter Override" feature, sstor (evidently) puts the new disk parameters in locations 0xEA -- 0xF9. If you install BOOTAUTO and then run sstor, using the parameter override feature, you will have clobbered the BOOTAUTO program in a way such that it hangs or repeats its menu when you make a selection! (Yes, I learned this the hard way...) To get around this problem, I wrote a slimmed-down version of the boot program, called BOOTMENU, which is designed to carefully avoid the locations clobbered by SpeedStor. Though this version has the advantage of SpeedStor compatibility, it does not have the ability to do automatic, unattended reboots the way BOOTAUTO can. Oh well. For future reference, also note that sstor will modify locations 0x17E -- 0x1BD if you create SpeedStor partitions. To their credit, this is indeed mentioned in the manual. SHAR_EOF if test 1027 -ne "`wc -c < 'SStor.txt'`" then echo shar: error transmitting "'SStor.txt'" '(should have been 1027 characters)' fi fi # end of overwriting check echo shar: extracting "'s_msdos.c'" '(3787 characters)' if test -f 's_msdos.c' then echo shar: will not over-write existing file "'s_msdos.c'" else cat << \SHAR_EOF > 's_msdos.c' /* This file contains system-specific functions for MS-DOS. * The program pfdisk.c calls these routines. */ #include #include #include #include #include #define extern #include "sysdep.h" #undef extern int usage(prog) /* print a usage message */ char *prog; /* program name */ { fprintf(stderr,"Usage: %s \n", prog); fprintf(stderr,"\twhere is a digit [0-9]\n"); } int getGeometry(name, c, h, s) char *name; /* device name */ int *c,*h,*s; /* cyls, heads, sectors */ { int dev; /* hard disk number */ union REGS regs; struct SREGS sregs; if (name[0] < '0' || name[0] > '9' || name[1] != 0 ) { fprintf(stderr,"%s: device name must be a digit\n", name); return(-1); } dev = (name[0] - '0'); regs.h.ah = 8; /* get param. */ regs.h.dl = dev | 0x80; int86x(0x13,®s,®s,&sregs); /* Are that many drives responding? */ if (regs.h.dl <= dev ) { fprintf(stderr,"%s: drive not found\n", name); return(-1); } if (regs.x.cflag) { fprintf(stderr,"%s: can't get disk parameters\n", name); return(-1); } *c = ((((int) regs.h.cl << 2) & 0x300) | regs.h.ch) + 1; *h = regs.h.dh + 1; *s = regs.h.cl & 0x3F; return(0); } int getFile(name, buf, len) /* read file into buffer */ char *name, *buf; int len; { /* (open, read, close) */ int devfd, retval; devfd = open(name, O_RDONLY|O_BINARY, 0); if (devfd < 0) { fprintf(stderr,"%s: can't open for reading\n", name); return(devfd); } retval = read(devfd, buf, len); if (retval < 0) fprintf(stderr,"%s: read failed\n", name); close(devfd); return(retval); } int putFile(name, buf, len) /* write buffer to file */ char *name, *buf; int len; { /* (open, write, close) */ int devfd, retval; devfd = open(name, O_WRONLY|O_CREAT|O_BINARY, S_IREAD|S_IWRITE ); /* stupid DOS... */ if (devfd < 0) { fprintf(stderr,"%s: can't open for writing\n", name); return(devfd); } retval = write(devfd, buf, len); if (retval < 0) fprintf(stderr,"%s: write failed\n", name); close(devfd); return(retval); } int getBBlk(name, buf) /* read boot block into buffer */ char *name, *buf; { /* BIOS absolute disk read */ int dev; union REGS regs; struct SREGS sregs; if (name[0] < '0' || name[0] > '9' || name[1] != 0 ) { fprintf(stderr,"%s: device name must be a digit\n",name); return(-1); } dev = (name[0] - '0'); segread(&sregs); /* get ds */ sregs.es = sregs.ds; /* buffer address */ regs.x.bx = (int) buf; regs.h.ah = 2; /* read */ regs.h.al = 1; /* sector count */ regs.h.ch = 0; /* track */ regs.h.cl = 1; /* start sector */ regs.h.dh = 0; /* head */ regs.h.dl = dev|0x80; /* drive */ int86x(0x13,®s,®s,&sregs); if (regs.x.cflag) { fprintf(stderr,"%s: read failed\n", name); return(-1); } return(SECSIZE); } int putBBlk(name, buf) /* write buffer to boot block */ char *name, *buf; { /* BIOS absolute disk write */ int dev; union REGS regs; struct SREGS sregs; if (name[0] < '0' || name[0] > '9' || name[1] != 0 ) { fprintf(stderr,"%s: device name must be a digit\n", name); return(-1); } dev = (name[0] - '0'); segread(&sregs); /* get ds */ sregs.es = sregs.ds; /* buffer address */ regs.x.bx = (int) buf; regs.h.ah = 3; /* write */ regs.h.al = 1; /* sector count */ regs.h.ch = 0; /* track */ regs.h.cl = 1; /* start sector */ regs.h.dh = 0; /* head */ regs.h.dl = dev|0x80; /* drive */ int86x(0x13,®s,®s,&sregs); if (regs.x.cflag) { fprintf(stderr,"%s: write failed\n",name); return(-1); } return(SECSIZE); } SHAR_EOF if test 3787 -ne "`wc -c < 's_msdos.c'`" then echo shar: error transmitting "'s_msdos.c'" '(should have been 3787 characters)' fi fi # end of overwriting check echo shar: extracting "'bootmenu.asm'" '(5005 characters)' if test -f 'bootmenu.asm' then echo shar: will not over-write existing file "'bootmenu.asm'" else cat << \SHAR_EOF > 'bootmenu.asm' PAGE 60,132 ; bootmenu: BOOT Hard Disk Partition ; by Gordon W. Ross, Aug 1990 ; ; See the file bootmenu.doc for user instructions. ; ; This version of bootmenu is compatible with SpeedStor. ; See the file sstor-bug.txt for the gory details. ; ; The following is an outline of the program: ; ; Relocate self from 0x7c00 to 0x0600 ; Display partition menu ; Prompt for and read user selection ; ; Boot from the selected partition: ; (was selected by user, or was active) ; Read first sector of selected partition into 0x7c00 ; Verify good second-stage boot sector (magic word) ; Set-up correct register values and jump to it. ; CODEORG equ 0600h ; offset of this code in code seg ; All values computed from offsets in codeseg need to be ; adjusted by adding CODEORG to each. The obvious method, ; using "org CODEORG" causes MASM/LINK to fill in the space. codeseg segment assume cs:codeseg, ds:codeseg ; Initial program entry point ; (Assembler is told this is at offset zero.) main: ; Set up the stack xor ax,ax mov si,7C00h ; just before load location cli mov ss,ax mov sp,si sti ; Relocate this code from 0:7C00h to 0:CODEORG mov ds,ax mov es,ax mov si,7C00h ; where this program is initially loaded mov di,CODEORG mov cx,0100h cld rep movsw ; Jump to relocated code (0:CODEORG) jmp far ptr begin1 begin equ $ ; The above jump lands here. ; Print partition menu from name table menu: call putnl ; print newline mov si, offset pnames ; no org fix-up here! mov al, '1' prname: push si push ax call putc mov al,' ' call putc mov cx,8 ; maximum name length call putn call putnl pop ax pop si add si,8 inc al cmp al,'4' jbe prname ; Prompt for and read user selection select: call putnl ; print prompt mov si, offset prompt + CODEORG call puts mov ah,0 ; Read a keystroke and print it int 16h push ax call putc call putnl pop ax sub al,'1' ; range check and convert to index cmp al,04 jnb select boot: ; Boot from the selected partition. ; On entry to this section: AL = index of ptable element ; get address of ptable element (si = & ptable[AL]) mov si, offset ptable ; no org fix-up here mov cl,16 ; size of array element mul cl ; ax = al * cl add si,ax ; Check for valid system ID (non-zero) mov al,[si+4] cmp al,0 jnz id_ok mov si, offset msgempty + CODEORG jmp error id_ok: ; Read first sector of selected partition into 0x7c00 ; Also, mark this entry active (in RAM only) in case the ; secondary boot program looks at it (which it may). mov al,80h ; active flag mov [si], al mov cx,5 ; retry count retry: push cx mov dx,[si] ; drive, head mov cx,[si+2] ; cyl, sector mov bx,7C00h ; destination (es=0) mov ax,0201h ; BIOS read one sector int 13h jnc rd_ok xor ax,ax ; reset disk int 13h pop cx loop retry mov si, offset msgread + CODEORG jmp error rd_ok: pop cx ; Check for valid magic number in secondary boot sector mov ax, 0AA55h assume ds:seg0 ; Actually, codeseg == seg0 cmp ax, magic2 assume ds:codeseg jz magic_ok mov si, offset msginvalid + CODEORG jmp error magic_ok: ; Make sure ds:si points to the booted partition, and ; Jump to the secondary boot program. jmp far ptr begin2 ; Jump here with si=error-message error: call puts call putnl jmp menu ;************************************************************* ; Subroutines ;************************************************************* CR EQU 13 LF EQU 10 TAB EQU 9 putc proc near ; print char in AL mov ah, 0Eh ; uses: ax, bx mov bx, 07 int 10h ret putc endp putnl proc near ; print a newline mov al, CR ; uses: ax, bx call putc mov al, LF call putc ret putnl endp puts proc near ; print string at address SI mov cx,80 ; Stop at null or CX chars putn: lodsb ; uses: ax, bx, cx, si cmp al,0 jz puts_e push cx call putc pop cx loop putn puts_e: ret puts endp ;********************************************************** ; A little space here makes this program live happily with ; SpeedStor, which wants to write type-override stuff here. ;********************************************************** org 100h ;********************************************************** ; Strings ;********************************************************** prompt db "Boot partition? (1-4) ",0 msgempty db "Empty!",0 msgread db "Read error!",0 msginvalid db "Invalid!",0 codeseg ends ; Declares some offsets in segment zero seg0 segment at 0 org CODEORG + (offset begin - offset main) begin1 equ $ ; Here is the name table used for the partition menu. ; The accompanying fdisk program updates this table. org CODEORG + 180h pnames db 32 dup(?) ; The locations after 1AE are (reportedly) used by some ; Western Digital controllers in "auto-configure" mode. ; Don't put anything critical between here and ptable. ; Here is the partition table org CODEORG + 1BEh ptable db (4 * 16) dup(?) ; Here is where the secondary boot sector is loaded. org 7C00h begin2 equ $ org 7DFEh magic2 dw ? seg0 ends end main SHAR_EOF if test 5005 -ne "`wc -c < 'bootmenu.asm'`" then echo shar: error transmitting "'bootmenu.asm'" '(should have been 5005 characters)' fi fi # end of overwriting check echo shar: extracting "'bootauto.asm'" '(6427 characters)' if test -f 'bootauto.asm' then echo shar: will not over-write existing file "'bootauto.asm'" else cat << \SHAR_EOF > 'bootauto.asm' PAGE 60,132 ; bootauto: Auto-boot version of BOOTMENU program ; by Gordon W. Ross, Aug 1990 ; ; See the file bootmenu.doc for user instructions. ; ; The following is an outline of the program: ; ; Relocate self from 0x7C00 to 0x0600 ; Display message "Booting from HD0," ; Search partition table for an active entry ; If an active partition is found, ; Delay while watching for key press (5 sec.) ; If (key pressed) GOTO menu: ; Else GOTO boot: ; EndIf ; Else (no active partition) ; menu: Display partition menu ; Prompt for and read user selection ; EndIf ; boot: Boot from the selected partition: ; (was selected by user, or was active) ; Read first sector of selected partition into 0x7c00 ; Verify good second-stage boot sector (magic word) ; Set-up correct register values and jump to it. ; If (Errors during boot) { complain; GOTO menu: } ; DELAY equ 5*18 ; in ticks (1/18 sec.) CODEORG equ 0600h ; offset of this code in code seg ; All values computed from offsets in codeseg need to be ; adjusted by adding CODEORG to each. The obvious method, ; using "org CODEORG" causes MASM/LINK to fill in the space. codeseg segment assume cs:codeseg, ds:codeseg ; Initial program entry point ; (Assembler is told this is at offset zero.) main: ; Set up the stack xor ax,ax mov si,7C00h ; just before load location cli mov ss,ax mov sp,si sti ; Relocate this code from 0:7C00h to 0:CODEORG mov ds,ax mov es,ax mov si,7C00h ; where this program is initially loaded mov di,CODEORG mov cx,0100h cld rep movsw ; Jump to relocated code (0:CODEORG) jmp far ptr begin1 begin equ $ mov bp,sp ; frame pointer = 0x7C00 sub sp,4 ; 2 words of local storage: ; [bp-2] = ptable index [0-3] ; [bp-4] = temporary value ; Display message "Boot device: HD0" mov si, offset bootdev + CODEORG call puts ; Search partition table for an active entry mov al,0 search: call addr_pt ; si = & ptable[AL] mov DL,[si] cmp DL,80h jz found inc al cmp al,04 jb search ; Active partition not found jmp menu found: ; Found a partition marked active. mov [bp-2],ax ; Save the ptable array index ; Delay while watching for key press (2 sec.) ; Get start time, compute end time. mov ah,00 int 1Ah ; BIOS get time of day add dx, DELAY ; compute end time mov [bp-4],dx ; save expiration time ; Check for key press waitkey: mov ah,1 int 16h ; BIOS Keyboard jnz menu ; key pressed ; Check for expiration of delay mov ah,00 int 1Ah ; BIOS get time of day sub dx,[bp-4] js waitkey ; delay not expired ; Delay has expired, so boot the active partition mov al,',' call putc mov ax,[bp-2] ; ptable index ; the index and newline are printed later jmp boot ; Display partition menu menu: mov ah,1 ; flush input int 16h jz fl_done mov ah,0 int 16h jmp menu fl_done: ; Print partition menu from name table call putnl ; print newline mov si, offset pnames ; no org fix-up here mov al, '1' prname: push si push ax call putc mov al,' ' call putc mov cx,8 ; maximum name length call putn call putnl pop ax pop si add si,8 inc al cmp al,'4' jbe prname ; Prompt for and read user selection select: call putnl mov si, offset prompt + CODEORG call puts ; Read a key and convert it to a number mov ah,0 int 16h sub al,'1' cmp al,04 jnb select ; The key and a newline are printed below boot: ; Boot from the selected partition. ; On entry to this section: AL = index of ptable element ; get address of ptable element call addr_pt ; si = & ptable[AL] ; print the parition index and a newline add al,'1' call putc call putnl ; Check for valid system ID (non-zero) mov al,[si+4] cmp al,0 jnz id_ok mov si, offset msgempty + CODEORG jmp error id_ok: ; Read first sector of selected partition into 0x7c00 ; Also, mark this entry active (in RAM only) in case the ; secondary boot program looks at it (which it may). mov al,80h ; active flag mov [si], al mov cx,5 ; retry count retry: push cx mov dx,[si] ; drive, head mov cx,[si+2] ; cyl, sector mov bx,7C00h ; destination (es=0) mov ax,0201h ; BIOS read one sector int 13h jnc rd_ok xor ax,ax ; reset disk int 13h pop cx loop retry mov si, offset msgread + CODEORG jmp error rd_ok: pop cx ; Check for valid magic number in secondary boot sector mov ax, 0AA55h assume ds:seg0 ; Actually, codeseg == seg0 cmp ax, magic2 assume ds:codeseg jz magic_ok mov si, offset msginvalid + CODEORG jmp error magic_ok: ; Make sure ds:si points to the booted partition, and ; Jump to the secondary boot program. jmp far ptr begin2 ; Jump here with si=error-message error: call puts call putnl jmp menu ;************************************************************* ; Subroutines ;************************************************************* CR EQU 13 LF EQU 10 TAB EQU 9 putc proc near ; print char in AL mov ah, 0Eh ; uses: ax, bx mov bx, 07 int 10h ret putc endp putnl proc near ; print a newline mov al, CR ; uses: ax, bx call putc mov al, LF call putc ret putnl endp puts proc near ; print string at address SI mov cx,80 ; Stop at null or CX chars putn: lodsb ; uses: ax, bx, cx, si cmp al,0 jz puts_e push cx call putc pop cx loop putn puts_e: ret puts endp addr_pt proc near ; set SI = address of ptable[al] push ax ; uses: cx (but preserves ax) mov si, offset ptable ; no org fix-up here mov cl,16 ; size of array element mul cl ; ax = al * cl add si,ax pop ax ret addr_pt endp ;********************************************************** ; Strings ;********************************************************** bootdev db "Boot device: hd0",0 prompt db "Boot partition? (1-4) ",0 msgempty db "Empty!",0 msgread db "Read error!",0 msginvalid db "Invalid!",0 org 180h ; this pads the length (it seems) codeseg ends ; Declares some offsets in segment zero seg0 segment at 0 org CODEORG + (offset begin - offset main) begin1 equ $ ; Here is the name table used for the partition menu. ; The accompanying fdisk program updates this table. org CODEORG + 180h pnames db 32 dup(?) ; The locations after 1AE are (reportedly) used by some ; Western Digital controllers in "auto-configure" mode. ; Don't put anything critical between here and ptable. ; Here is the partition table org CODEORG + 1BEh ptable db (4 * 16) dup(?) ; Here is where the secondary boot sector is loaded. org 7C00h begin2 equ $ org 7DFEh magic2 dw ? seg0 ends end main SHAR_EOF if test 6427 -ne "`wc -c < 'bootauto.asm'`" then echo shar: error transmitting "'bootauto.asm'" '(should have been 6427 characters)' fi fi # end of overwriting check echo shar: extracting "'asm2bin.bat'" '(262 characters)' if test -f 'asm2bin.bat' then echo shar: will not over-write existing file "'asm2bin.bat'" else cat << \SHAR_EOF > 'asm2bin.bat' @echo off REM This batch file builds file.bin from file.asm if not arg%1==arg%1 goto arg echo supply base name of file.asm, i.e. file goto exit :arg echo on masm %1,,; link boot-hdp,; @echo Ignore the 'no stack...' warning del %1.obj exe2bin %1 del %1.exe :exit SHAR_EOF if test 262 -ne "`wc -c < 'asm2bin.bat'`" then echo shar: error transmitting "'asm2bin.bat'" '(should have been 262 characters)' fi fi # end of overwriting check echo shar: extracting "'make_msc.bat'" '(104 characters)' if test -f 'make_msc.bat' then echo shar: will not over-write existing file "'make_msc.bat'" else cat << \SHAR_EOF > 'make_msc.bat' REM this batch file uses Microsoft C to build pfdisk.exe cl -o pfdisk.exe pfdisk.c syscodes.c s_msdos.c SHAR_EOF if test 104 -ne "`wc -c < 'make_msc.bat'`" then echo shar: error transmitting "'make_msc.bat'" '(should have been 104 characters)' fi fi # end of overwriting check # End of shell archive exit 0 -- Gordon W. Ross (M/S E095) | internet: gwr@linus.mitre.org The MITRE Corporation | uucp: (backbone-host)!linus!gwr Burlington Road | Day-phone: 617-271-3205 Bedford, MA 01730 (U.S.A.) |