page ,132
; 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 192K - 512 (to get itself out of the way).  Then it loads the 
; operating system from the boot diskette into memory, and then jumps to fsck.
; 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 (fsck) 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 fsck
; Word at 508: # PC value for fsck
; Word at 510: # CS value for fsck
;
; This version of the boot block must be assembled without separate I & D
; space.  

        LOADSEG = 0060h         ; here the boot block will start loading
        BIOSSEG = 07C0h         ; here the boot block itself is loaded
        BOOTSEG = 2FE0h         ; here it will copy itself (192K-512b)
        DSKBASE = 120           ; 120 = 4 * 0x1E = ptr to disk parameters
        JMPI    = 0EAh          ; opcode for jmp inter-segment (far jmp)

CODE    SEGMENT
        ASSUME cs:CODE,ds:CODE

;-------------------------------+
;          bootblok             ;
;-------------------------------+
;
; 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     movsw           ; copy loop

; start boot procedure
;       jmpi    start,BOOTSEG   ; set cs to bootseg

        DB      JMPI            ; normal MASM gets too complicated for this.
        DW      OFFSET start    ;  Use a trick and pre-code the
        DW      BOOTSEG         ;  instructions and addresses.

start:                          ; start < 16
        mov     dx,cs
        mov     ds,dx           ; set ds to cs
        xor     ax,ax
        mov     es,ax           ; set es to 0
        mov     ss,ax           ; set ss to 0
        mov     sp,1024         ; initialize sp (top of vector table)

; initialize disk parameters
	mov	ax,offset atpar
	mov	es:DSKBASE,ax	; tentatively assume 1.2M diskette
	mov	es:DSKBASE+2,dx

; print greeting
	mov	ax,2		; reset video
	int 	10h
        mov     ax,0200h        ; BIOS call to move cursor to ul corner
        xor     bx,bx
        xor     dx,dx
        int     10h
        mov     bx,offset greet
        call    print

; Determine if this is a 1.2M diskette by trying to read sector 15.
	xor	ax,ax
	int	13h
	xor	ax,ax
	mov	es,ax
	mov	ax,0201h
	mov	bx,0600h
	mov	cx,000fh
	mov	dx,0000h
	int	13h
	jnb	L1

; Error.  It wasn't 1.2M.  Now set up for 360K.
	mov	tracksiz,9	; 360K uses 9 sectors/track
	xor	ax,ax
	mov	es,ax
	mov	ax,offset pcpar
	mov	es:DSKBASE,ax
	int	13h		; diskette reset
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
	mov	ah,2		; opcode for read
	int	13h		; 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,03F2h        ; kill the motor
        mov     ax,000Ch
        out     dx,al
        cli
	mov	bx,tracksiz	; fsck expects # sectors/track in bx
        mov     ax,fsck_ds      ; set segment registers
        mov     ds,ax           ; when sep I&D ds != cs
        mov     es,ax           ; otherwise they are the same.
        mov     ss,ax           ; This gets patched by 'build'

        jmp     DWORD PTR cs:fsck_pc   ; call the booted program
                                       ; its address is at 508 (dec)

; 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 divident
	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
	cmp	al,cl		; is starting cyl = ending cyl
	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
	cmp	ah,dh		; ah != dh means read crosses 64K boundary
	je	set2		; jump if no boundary crossed
	shr	dl,1		; dl = excess beyond 64K boundary
	xor	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
	mov	dh,cl		; dh = track
	and	dh,1		; dh = head
	mov	ch,cl		; ch = track to read
	shr	ch,1		; ch = cylinder
	mov	cl,bl		; cl = sector number (0-origin)
	inc	cl		; cl = sector number (1-origin)
	xor	dl,dl		; dl = drive number (0)
	ret			; return values in ax, cx, dx


;-------------------------------+
;    error & print routines     ;
;-------------------------------+
;
error:
        push    ax
        mov     bx,offset fderr
        call    print           ; print msg
	xor	cx,cx
   err1:mul	bl		; delay
	loop	err1
	int	19h


print:                          ; print string (bx), ax destroyed
        mov     al,[bx]         ; al contains char to be printed
        test    al,al           ; null char?
        jne     prt1            ; no
        ret                     ; else return
prt1:   mov     ah,14           ; 14 = print char
        inc     bx              ; increment string pointer
        push    bx              ; save bx
        mov     bl,1            ; foreground color
	xor	bh,bh		; page 0
        int     10h             ; call BIOS VIDEO_IO
        pop     bx              ; restore bx
        jmp     print           ; next character



disksec  DW 	1
tracksiz DW 	15		; changed to 9 for 360K diskettes
pcpar	 DB	0DFh, 2, 25, 2, 9, 02Ah, 0FFh, 050h, 0F6h, 1, 3  ; for PC
atpar	 DB	0DFh, 2, 25, 2,15, 01Bh, 0FFh, 054h, 0F6h, 1, 8  ; for AT

fderr   DB      "Read error.  Please reboot ",0Dh,0Ah,0
greet   DB      "Booting Minix 1.1",0Dh,0Ah,0


        ORG     504     ; NOTE: there will be no error reported if
                        ; your code crosses this org-directive !
final    DW     0       ; # sectors to read (patched in by build)
fsck_ds  DW     0       ; ds-value for sep I&D
fsck_pc  DW     0       ; build patches these locations to the
fsck_cs  DW     0       ; starting address of the booted program

CODE    ENDS

        END
