Minix1.1/usr/src/tools/C86/bootblok.asm
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