	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 Saul 
	mov	cx,5		; maximum name length Saul
	call	putn
	call	putnl

	pop	ax
	pop	si
;	add	si,8; Saul
	add	si,5; Saul
	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 Saul
	org	CODEORG + 1AAh ;Saul
;pnames	db	32 dup(?) Saul
pnames	db	20 dup(?); Saul

; 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
