!	masterboot 1.5 - Master boot block code		Author: Kees J. Bot
!
! This code may be placed in the first sector (the boot sector) of a floppy,
! hard disk or hard disk primary partition.  There it will perform the
! following actions at boot time:
!
! - If the ALT key is held down, then '/dev/hd?' is typed and you are
!   expected to type a number key (0 - 9) to select the device to boot.
!
! - If locked into booting a certain partition, then do so.
!
! - If the booted device is a hard disk and one of the partitions is active
!   then the active partition is booted.
!
! - Otherwise the next floppy or hard disk device is booted, trying them one
!   by one.
!
! To make things a little clearer, the boot path might be:
!	/dev/fd0	- Floppy disk containing data, tries fd1 then hd0
!	[/dev/fd1]	- Drive empty
!	/dev/hd0	- Master boot block, selects active partition 3
!	/dev/hd3	- Submaster, selects active subpartition 1
!	/dev/hd3a	- Minix bootblock, reads secondary boot code /boot
!	Minix		- Started by secondary boot from /minix

	LOADOFF	   =	0x7C00	! 0x0000:LOADOFF is where this code is loaded
	BUFFER	   =	0x0600	! First free memory
	PART_TABLE =	   446	! Location of partition table within this code
	PENTRYSIZE =	    16	! Size of one partition table entry

	! minix/partition.h:
	bootind	   =	     0
	sysind	   =	     4
	lowsec	   =	     8


.define begtext, begdata, begbss, endtext, enddata, endbss, _main
.data
begdata:
.bss
begbss:
.text
begtext:
_main:

! Find active (sub)partition, load its first sector, run it.

master:
	jmp	over
fix:	.data1	0		! If 1-9 then always boot that device
over:
	xor	ax, ax
	mov	ds, ax
	mov	es, ax
	cli
	mov	ss, ax		! ds = es = ss = Vector segment
	mov	sp, #LOADOFF
	sti

! Copy this code to safety, then jump to it.
	mov	si, #LOADOFF	! si = start of this code
	mov	di, #BUFFER	! buffer area
	mov	cx, #512/2	! One sector
	cld
	rep
	movw
	jmpf	BUFFER+migrate, 0	! To safety
migrate:

! ALT key pressed to override active device boot?
key:
	movb	ah, #0x02	! Keyboard shift status
	int	0x16
	testb	al, #0x08	! Bit 3 = ALT key
	jz	noalt		! No ALT key pressed
	mov	si, #BUFFER+devhd
	call	print
getkey:	xorb	ah, ah		! Wait for keypress
	int	0x16
	movb	BUFFER+choice, al
	subb	al, #0x30	! al -= '0'
	cmpb	al, #10
	jae	getkey		! Key not in 0 - 9 range
	push	ax
	mov	si, #BUFFER+choice
	call	print		! Show the key typed
	pop	ax
	jmp	override
noalt:
	movb	al, BUFFER+fix	! Always boot a certain partition?
	testb	al, al
	jz	findactive	! No, boot the active partition
override:
	movb	dl, #0x80
	cmpb	al, #5		! Hard disk 0?
	jb	getit		! Yes
	incb	dl		! No, it's hard disk 1
	subb	al, #5
getit:	push	ax		! Save partition choice
	call	load0		! Get sector 0
	jb	error		! Unable to read it
	pop	ax		! Restore partition choice
	subb	al, #1		! Was it 0 or 5?
	jl	master+LOADOFF-BUFFER	! Jump to the master bootstrap
	mov	si, #LOADOFF+PART_TABLE	! si = new partition table
	mov	di, #BUFFER+PART_TABLE	! To buffer area
	mov	cx, #4*PENTRYSIZE/2
	rep
	movw
	mov	si, #BUFFER+PART_TABLE	! The loaded partition table
	movb	ah, #PENTRYSIZE
	mulb	ah			! ax = al * PENTRYSIZE
	add	si, ax			! si = address of partition entry
	jmp	loadpart		! Get the partition bootstrap

! Find the active partition
findactive:
	cmpb	dl, #0x80
	jb	nextdisk	! No partitions on floppies
	mov	si, #BUFFER+PART_TABLE
find:	movb	al, sysind(si)	! Partition type, nonzero when in use
	testb	al, al
	jz	nextpart
	movb	al, bootind(si)	! Active partition flag in bit 7
	testb	al, #0x80
	jz	nextpart	! It's not active
loadpart:
! Load partition bootstrap.  The obvious head, sector, cylinder numbers are
! ignored in favour of the more trustworthy absolute start of partition.
	push	dx		! Save drive code
	movb	ah, #0x08	! Code for drive parameters
	int	0x13
	andb	cl, #0x3F	! cl = max sector number (1-origin)
	incb	dh		! dh = 1 + max head number (0-origin)
	movb	al, cl		! al = cl = sectors per track
	mulb	dh		! dh = heads, ax = heads * sectors
	mov	bx, ax		! bx = sectors per cylinder = heads * sectors
	mov	ax, lowsec+0(si)
	mov	dx, lowsec+2(si)! dx:ax = sector within drive
	div	bx		! ax = cylinder, dx = sector within cylinder
	xchg	ax, dx		! ax = sector within cylinder, dx = cylinder
	movb	ch, dl		! ch = low 8 bits of cylinder
	divb	cl		! al = head, ah = sector (0-origin)
	xorb	dl, dl		! About to shift bits 8-9 of cylinder into dl
	shr	dx, #1
	shr	dx, #1		! dl[6..7] = high cylinder
	orb	dl, ah		! dl[0..5] = sector (0-origin)
	movb	cl, dl		! cl[0..5] = sector, cl[6..7] = high cyl
	incb	cl		! cl[0..5] = sector (1-origin)
	pop	dx		! Restore drive code in dl
	movb	dh, al		! dh = al = head
	mov	bx, #LOADOFF	! es:bx = where sector is loaded
	mov	ax, #0x0201	! Code for read, just one sector
	int	0x13		! Call the BIOS for a read
	jb	error		! Not supposed to fail
	jmp	master+LOADOFF-BUFFER	! Jump to the partition bootstrap
nextpart:
	add	si, #PENTRYSIZE
	cmp	si, #BUFFER+PART_TABLE+4*PENTRYSIZE
	jb	find
! No active partition, tell 'em
	mov	si, #BUFFER+noactive
	call	print

! There are no active partitions on this drive, try the next drive.
nextdisk:
	mov	si, #BUFFER+gonext	! Tell about next disk
	call	print
	incb	dl		! Increment dl for the next drive
	cmpb	dl, #0x80	! Hard disk?
	jae	nexthd
	int	0x11		! Get equipment configuration
	shl	ax, #1		! Highest floppy drive # in bits 6-7
	shl	ax, #1		! Now in bits 0-1 of ah
	andb	ah, #0x03	! Extract bits
	cmpb	dl, ah		! Must be dl <= ah for drive to exist
	jbe	next		! Go read floppy
sethd:	movb	dl, #0x80	! Try a hard disk next
nexthd:	movb	ah, #0x08	! Code for drive parameters
	push	dx		! Save dl
	int	0x13
	pop	dx		! Restore dl
	jb	error		! No such drive?
next:
	call	load0		! Read the next bootstrap
	jb	nextdisk	! It failed, next disk please
	jmp	master+LOADOFF-BUFFER	! Jump to the next master bootstrap


! Load sector 0 from the current device.  It's either a floppy bootstrap or
! a hard disk master bootstrap.
load0:
	mov	di, #3			! Three retries for floppy spinup
retry:	xorb	dh, dh			! Prepare for disk read
	mov	cx, #0x0001		! Cylinder 0, head 0, sector 1
	mov	bx, #LOADOFF		! es:bx = where sector is loaded
	mov	ax, #0x0201		! Code for read, just one sector
	int	0x13			! Call BIOS for the I/O
	jnb	ok0
	pushf				! Save carry flag
	dec	di
	jz	bad0			! One more retry?
	popf
	xorb	ah, ah
	int	0x13			! Reset
	jnb	retry			! Try again
	ret
bad0:	popf				! Restore carry flag
ok0:	ret


! A read error occurred, complain and hang
error:
	mov	si, #BUFFER+readerr
	call	print

! Hang forever waiting for CTRL-ALT-DEL
hang:	jmp	hang

print:	lodsb			! al = *si++ is char to be printed
	testb	al, al
	jz	prdone		! Null marks end
	movb	ah, #14		! 14 = print char
	mov	bx, #0x0001	! Page 0, foreground color
	int	0x10		! Call BIOS VIDEO_IO
	jmp	print
prdone:	ret

.data
devhd:		.ascii	"/dev/hd?\b"
choice:		.ascii	"\0\r\n\0"
noactive:	.ascii	"No active partition\r\n\0"
gonext:		.ascii	"Next disk\r\n\0"
readerr:	.ascii	"Read error \0"
.text
endtext:
.data
enddata:
.bss
endbss:
