;       
;       bootauto:  Auto-boot version of BOOTMENU program
;       by Gordon W. Ross, Aug 1990
;       modified by dave safford for simple installation
;

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 prompt
doit:
	mov     si, offset prompt + CODEORG
	call    puts

; Search partition table for last active entry 
; store in [bp-2], and decativate all ptable entries 
	mov     ax,0; 
	mov     dh,0; 
search:
	call    addr_pt ; si = & ptable[AL]
	mov     DL,[si]
	cmp     DL,80h
	jnz inactive ;
	mov     [bp-2],ax       ; Save the ptable array index
	mov [si],ah ; make inactive
	mov dh,1 ; signal that active partition found 
inactive:
	inc     al
	cmp     al,04
	jb      search
	cmp dh,0 ; Was an active partition not found? 
	jnz found ; 
	xor ax,ax;
	mov [bp-2], ax; default to partition 1

found:  ; Found a partition marked active.

; Delay while watching for key press (2 sec.)
; Get start time, compute end time.
	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     select  ; 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     ax,[bp-2]       ; ptable index
	jmp     boot

; read user selection
select:
	; Read a key and convert it to a number
	mov     ah,0
	int     16h
	sub     al,'1'
	cmp     al,04
	jnb     doit
	; 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
; Invlidate all other partitions -- execpt DOS-12 or DOS-16 
	push si; 
	mov     ax,6200H;  makes ah dec 98, al zero
invalidate:  ;
	call    addr_pt ; si = & ptable[AL]  ;
	mov     DL,[si]  ;
	cmp     DL,80h  ;
	jz      cont; Active partition; don't invalidate this one  ;
	mov DL,[si+4]; System id  ;
	cmp DL,1h; DOS-12 partition; don't invalidate  ;
	jz cont  ;
	cmp DL,4h; DOS-16 partition; don't invalidate  ;
	jz cont  ;
	mov [si+4],ah ; invalidate, by changing sysid to dec 98  ;
cont:  ;
	inc     al  ;
	cmp     al,04  ;
	jb      invalidate  ;
	pop si; 

	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     doit

;*************************************************************
; 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
;**********************************************************

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 + 1AAh ;
pnames  db      20 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
