| When the PC is powered on, it reads the first block from the floppy
| disk into address 0x7C00 and jumps to it.  This boot block must contain
| the boot program in this file.  The boot program first copies itself to
| address 256K - 1536 (to get itself out of the way).  Then it loads the 
| operating system from the boot diskette into memory, and then jumps to menu.
| Loading is not trivial because the PC is unable to read a track into
| memory across a 64K boundary, so the positioning of everything is critical.
| The number of sectors to load is contained at address 504 of this block.
| The value is put there by the build program after it has discovered how
| big the operating system is.  When the bootblok program is finished loading,
| it jumps indirectly to the program (menu) which address is given by the
| last two words in the boot block. 
|
| Summary of the words patched into the boot block by build:
| Word at 504: # sectors to load
| Word at 506: # DS value for menu
| Word at 508: # PC value for menu
| Word at 510: # CS value for menu
|
| This version of the boot block must be assembled without separate I & D
| space.  

        LOADSEG = 0x0060         | here the boot block will start loading
        BIOSSEG = 0x07C0         | here the boot block itself is loaded
        BOOTSEG = 0x3FA0         | here it will copy itself (256K-1.5K)
        DSKBASE = 120            | 120 = 4 * 0x1E = ptr to disk parameters

final   = 504
menu_ds = 506
menu_pc = 508
menu_cs = 510


.globl begtext, begdata, begbss, endtext, enddata, endbss  | asld needs these
.text
begtext:
.data
begdata:
.bss
begbss:
.text

| copy bootblock to bootseg
        mov     ax,#BIOSSEG
        mov     ds,ax
        xor     si,si           | ds:si - original block
        mov     ax,#BOOTSEG
        mov     es,ax
        xor     di,di           | es:di - new block
        mov     cx,#256         | #  words to move
	rep
	movw			| copy loop
    
	
| start boot procedure
	jmpi	start, BOOTSEG	| set cs to BOOTSEG

start:
	mov     dx,cs
        mov     ds,dx           | set ds to cs
        xor     ax,ax
        mov     es,ax           | set es to 0
        mov     ss,dx           | set ss to cs i.e., stack in high core
        mov     sp,#1536        | initialize sp to high core

| print greeting
	mov	ax,#2		| reset video
	int	0x10

        mov     ax,#0x0200	| BIOS call in put cursor in ul corner
        xor     bx,bx
        xor     dx,dx
        int     0x10
        mov     bx,#greet
        call    print

| Initialize disk parameters
| Try 1.2M diskette by trying to read sector 15

	xor	ax,ax
	mov	es,ax
	mov	dx,ds
	mov	ax,#atpar
	seg	es
	mov	DSKBASE,ax
	seg	es
	mov	DSKBASE+2,dx

	xor	ax,ax	| reset drive
	int	0x13

	xor	ax,ax
	mov	es,ax
	mov	ax,#0x0201	| read sector, #sector = 1
	mov	bx,#0x0600	| es:bx buffer
	mov	cx,#0x000F	| track 0, sector 15
	mov	dx,#0x0000	| drive 0, head 0
	int	0x13
	jnb	L1

| Error. It wasn't 1.2M. Now set up for 720K

	mov	tracksiz,#9
	xor	ax,ax		| ps disk parameters are in ROM F01520
	mov	es,ax
	mov	ax,#0x1520
	seg	es
	mov	DSKBASE,ax
	mov	ax,#0xF000	
	seg	es
	mov	DSKBASE+2,ax

| Try 720K by trying to read track 64.
| 360K has 40 tracks, 720 has 80 tracks.

	xor	ax,ax	| diskette reset
	int	0x13
	mov	tracksiz,#9

	xor	ax,ax
	mov	es,ax
	mov	ax,#0x0201	| read sector, number of sectors is 1
	mov	bx,#0x0600	| es:bx buffer
	mov	cx,#0x4001	| track 64, sector 1
	mov	dx,#0x0000	| drive 0, head 0
	int	0x13
	jnb	L1

| Error. It wasn't 720K either. Now set up for 360K

	xor	ax,ax
	mov	es,ax
	mov	dx,ds
	mov	ax,#pcpar
	seg	es
	mov	DSKBASE,ax
	seg	es
	mov	DSKBASE+2,dx
	xor	ax,ax		| diskette reset
	int	0x13

L1:

| Load the operating system from diskette.
load:
	call	setreg		| set up ah, cx, dx
	mov	bx,disksec	| bx = number of next sector to read
	add	bx,#2		| diskette sector 1 goes at 1536 ("sector" 3)
	shl	bx,#1		| multiply sector number by 32
	shl	bx,#1		| ditto
	shl	bx,#1		| ditto
	shl	bx,#1		| ditto
	shl	bx,#1		| ditto
	mov	es,bx		| core address is es:bx (with bx = 0)
	xor	bx,bx		| see above
	add	disksec,ax	| ax tells how many sectors to read
	movb	ah,#2		| opcode for read
	int	0x13		| call the BIOS for a read
	jb	error		| jump on diskette error
	mov	ax,disksec	| see if we are done loading
	cmp	ax,final	| ditto
	jb	load		| jump if there is more to load

| Loading done.  Finish up.
        mov     dx,#0x03F2      | kill the motor
        mov     ax,#0x000C
        out
        cli
	mov	bx,tracksiz	| menu expects # sectors/track in bx
        mov     ax,menu_ds      | set segment registers
        mov     ds,ax           | when sep I&D DS != CS
        mov     es,ax           | otherwise they are the same.
        mov     ss,ax           | words 504 - 510 are patched by build

	seg cs
	jmpi	@menu_pc	| jmp to menu

| Given the number of the next disk block to read, disksec, compute the
| cylinder, sector, head, and number of sectors to read as follows:
| ah = # sectors to read;  cl = sector #;  ch = cyl;  dh = head; dl = 0
setreg:	
	mov	si,tracksiz	| 9 (PC) or 15 (AT) sectors per track
	mov 	ax,disksec	| ax = next sector to read
	xor	dx,dx		| dx:ax = 32-bit dividend
	div	si		| divide sector # by track size
	mov	cx,ax		| cx = track #; dx = sector (0-origin)
	mov	bx,dx		| bx = sector number (0-origin)
	mov	ax,disksec	| ax = next sector to read
	add	ax,si		| ax = last sector to read + 1
	dec	ax		| ax = last sector to read
	xor	dx,dx		| dx:ax = 32-bit dividend
	div	tracksiz	| divide last sector by track size
	cmpb	al,cl		| is starting track = ending track
	je	set1		| jump if whole read on 1 cylinder
	sub	si,dx		| compute lower sector count
	dec	si		| si = # sectors to read

| Check to see if this read crosses a 64K boundary (128 sectors).
| Such calls must be avoided.  The BIOS gets them wrong.
set1:	mov	ax,disksec	| ax = next sector to read
	add	ax,#2		| disk sector 1 goes in core sector 3
	mov	dx,ax		| dx = next sector to read
	add	dx,si		| dx = one sector beyond end of read
	dec	dx		| dx = last sector to read
	shl	ax,#1		| ah = which 64K bank does read start at
	shl	dx,#1		| dh = which 64K bank foes read end in
	cmpb	ah,dh		| ah != dh means read crosses 64K boundary
	je	set2		| jump if no boundary crossed
	shrb	dl,#1		| dl = excess beyond 64K boundary
	xorb	dh,dh		| dx = excess beyond 64K boundary
	sub	si,dx		| adjust si
	dec	si		| si = number of sectors to read

set2:	mov	ax,si		| ax = number of sectors to read
	xor	dx,dx		| dh = head, dl = drive
	movb	dh,cl		| dh = track
	andb	dh,#0x01	| dh = head
	movb	ch,cl		| ch = track to read
	shrb	ch,#1		| ch = cylinder
	movb	cl,bl		| cl = sector number (0-origin)
	incb	cl		| cl = sector number (1-origin)
	xorb	dl,dl		| dl = drive number (0)
	ret			| return values in ax, cx, dx


|-------------------------------+
|    error & print routines     |
|-------------------------------+

error:
        push    ax
        mov     bx,#fderr
        call    print           | print msg
	xor	cx,cx
err1:	mul	0		| delay
	loop	err1
	int	0x19


print:                          | print string (bx)
        movb	al,(bx)	        | al contains char to be printed
        testb   al,al           | null char?
        jne     prt1            | no
        ret                     | else return
prt1:   movb    ah,#14          | 14 = print char
        inc     bx              | increment string pointer
        push    bx              | save bx
        movb    bl,#1           | foreground color
	xorb	bh,bh		| page 0
        int     0x10            | call BIOS VIDEO_IO
        pop     bx              | restore bx
        jmp     print           | next character


disksec:.word 1
pcpar:	.byte	0xDF, 0x02, 25, 2, 9, 0x2A, 0xFF, 0x50, 0xF6, 1, 3 | for pc
atpar:	.byte	0xDF, 0x02, 25, 2,15, 0x1B, 0xFF, 0x54, 0xF6, 1, 8 | for at

fderr:	.asciz "Read error.  Automatic reboot.\r\n"
greet:	.asciz "\rBooting MINIX 1.5.  Copyright 1991 Prentice-Hall, Inc.\r\n"
tracksiz:.word 15	| changed to 9 for ps and pc

| Don't forget that words 504 - 510 are filled in by build.  The regular
| code had better not get that far.
.text
endtext:
.data
enddata:
.bss
endbss:
