Coherent4.2.10/boot/pboot.m
////////
/
/ Patched bootstrap block for the IBM PC.
/ This code, which lives in sector 1,
/ track 0 of the floppy (or sector 1 of a hard disk partition)
/ gets read into location 0x7C00 by the ROM.
/ The code relocates itself to location 0x2060:0x0000
/ (128K above the fixed memory used by the ROM). The system image is read
/ in beginning at paragraph 0x0060.
/
/ $Log: /newbits/conf/boot/RCS/pboot.m,v $
* Revision 1.2 91/05/29 09:42:16 bin
* bob h modified due to commented lines screwing the makefile
*
/ * Revision 1.1 91/05/29 08:30:45 bin
/ * Initial revision
/ *
/ Revision 1.1 88/03/24 16:44:09 src
/ Initial revision
/
/ 87/10/04 Allan Cornish /usr/src/sys/i8086/boot/boot.s
/ Number of heads now defined by NHD macro. Should be 1 for f*d*, 2 for f*a*.
/
/ 85/10/04 Allan Cornish /usr/src/sys/i8086/boot/boot.s
/ Bootstrap extended to increase max file size from 64 Kbytes to 128 Kbytes.
/ The private code segment is now loaded, where previously it had to be empty.
/ File name editing enhanced to help cursor stay in the 14 char entry field,
/ and to provide a destructive backspace.
/
/ 85/01/04 Allan Cornish
/ Added backspace editing of file name.
/
////////
////////
/ This is a patched version for machines with incorrect CMOS disk parameters.
/ The values in traks, sects, heads, cntrl and wpcc are assumed correct.
/ This BIOS is not interrogated to find the disk parameters.
/ The controller is reset with the appropriate values.
////////
#ifndef NHD
#define NHD 1 / heads per drive [1 for f9d0].
#endif
#ifndef NSPT
#define NSPT 9 / sectors per track on floppy.
#define NTRK 40 / tracks on floppy.
#endif
#ifndef CNTRL
#define CNTRL 8
#endif
#ifndef WPCC
#define WPCC 0xFFFF
#endif
NSTK = 256 / bytes of stack.
BS = 0x08 / BS character.
CR = 0x0D / CR character.
LF = 0x0A / LF character.
SP = 0x20 / Backspace character.
BOOTLC = 0x7C00 / Boot location (ROM).
BOOTS = 0 / boot segment (ROM).
RBOOTS = 0x2060 / Relocated boot segment.
BSHIFT = 9 / Shift, bytes to blocks.
ROOTINO = 2 / Root inode #
INOORG = 2 / First inode block.
IBSHIFT = 3 / Shift, inode to blocks
IOSHIFT = 6 / Shift, inode to bytes
INOMASK = 0x0007 / Mask, inode to offset
DIRSIZE = 14 / Directory size.
DIRSIZ2 = 7 / Directory size / 2.
BUFSIZE = 512 / Block size.
HDRSIZE = 44 / L.out header size.
HDRSIZ2 = 22 / L.out header size / 2.
BUFMSK2 = 0x00FF / Block [word] mask, for reads.
DISK = 0x13 / Disk Interrupt
KEYBD = 0x16 / Keyboard Interrupt
READ1 = 0x0201 / read one sector
ND = 10 / # of direct blocks.
NIND = 128 / # of blocks in indirect block.
ISIZE = 8 / Offset of "di_size".
IADDR = 12 / Offset of "di_addr".
JMPF = 0xEA / Jump far, direct.
LMAGIC = 0 / Offset of "l_magic"
LFLAG = 2 / Offset of "l_flag"
LSHRI = 10 / Offset of "l_ssize[SHRI]"
LPRVI = 14 / Offset of "l_ssize[PRVI]"
LSHRD = 22 / Offset of "l_ssize[SHRD]"
LPRVD = 26 / Offset of "l_ssize[PRVD]"
LBSSD = 30 / Offset of "l_ssize[BSSD]"
LFMAG = 0x0107 / Magic number.
LFSEP = 0x02 / Sep I/D flag bit.
SYSBASE = 0x0060 / System load base paragraph.
FIRST = 8 / relative start of partition
/ Hard disk controller port addresses.
HF_REG = 0x3F6
NSEC_REG= 0x1F2
SEC_REG = 0x1F3
HDRV_REG= 0x1F6
CSR_REG = 0x1F7
BSY_ST = 0x80
SETPARM_CMD= 0x91
////////
/
/ Bootstrap mainline. Relocate the
/ boot to high memory, so it wont be written
/ over by the system. Read in a file name. Look up
/ the file name by following out the directory
/ structure. Read in the image and jump to it.
/
////////
boot: xor di, di
mov ds, di
mov si, $BOOTLC / Make DS:SI point at the code
mov es, 1f(si) / Make ES:DI point at where it goes
mov cx, $512 / cx = # of bytes to move
cld
rep / Move the bootstrap
movsb / to high memory.
mov si, bp / set si to partition
mov di, $drive / point to drive
movsb / set drive
add si, $FIRST-1 / point to first block
movsw
movsw / fetch first block
/ Bang on disk controller.
/ See at.c/atreset().
#if 1
movb al, $4
mov dx, $HF_REG
outb dx, al / outb (HF_REG, 4);
mov cx, $-1
0: loop 0b / delay
movb al, cntrl
andb al, $0x0F
outb dx, al / outb (HF_REG, ctrl & 0xF);
/ call atbsyw
/ Wait for AT controller to become not busy.
/ From atas.s.
/ atbsyw:
mov cx, $-1
mov dx, $CSR_REG
0: inb al, dx
testb al, $BSY_ST
loopne 0b
mov ax, cx
/ ret
#endif
movb al, cntrl
mov dx, $HF_REG
outb dx, al / outb(HF_REG, cntrl);
movb al, sects
mov dx, $NSEC_REG
outb dx, al / outb(NSEC_REG, sects);
/ The following should have drive << 4 added in, this assumes drive 0.
/ Out of space to do it right now.
movb al, drive
sal ax, $4
addb al, $0x9F
addb al, heads
mov dx, $HDRV_REG
outb dx, al / outb(HDRV_REG, 0xA0+(drive<<4)+heads-1);
movb al, $SETPARM_CMD
mov dx, $CSR_REG
outb dx, al / outb(CSR_REG, SETPARM_CMD)
nop
nop / filler to make 512 byte bootstrap
/ Set registers.
0: mov bp, $stack+NSTK / stack pointer value
mov ax, es
mov ds, ax
mov ss, ax
mov sp, bp
/ call login / print signon message
/ Jump to (relocated) boot.
.byte JMPF
.word entry
1: .word RBOOTS
////////
/
/ Read the inode specified by "ax"
/ into the external variable "iaddr".
/ No checking is done to make sure that
/ the inumber is in range on the filesystem.
/ Sets dx and cx to 0.
/ Mungs si, di, ax.
/
////////
igrab: dec ax / Make origin 0 and
push ax / remember for later use.
movb cl, $IBSHIFT / Convert to
shr ax, cl / inode block number,
inc ax / then to physical block number,
inc ax
call bread / and read in the data.
pop ax / Get i-number back.
and ax, $INOMASK / Get inode within block
movb cl, $IOSHIFT / and convert to
shl ax, cl / a byte offset in the block.
add si, ax / si = inode pointer.
add si, $IADDR / Point at address field.
mov di, $iaddr / Copy out area.
movb cl, $ND / cx = # of direct blocks.
0: inc si / Skip 0th byte.
movsw / Move 1st (lsb) and 2nd (msb)
loop 0b / Do them all.
inc si / Skip 0th byte and
lodsw / grab block # of (first) indirect.
inc si / Skip 0th byte and
push (si) / remember block # of double indirect.
call bread / Read (first) indirect block.
movb cl, $NIND / cx = # of indirect maps (ch=0)
1: lodsw / Skip hi half (canon long)
movsw / and move low half.
loop 1b / Do them all.
pop ax
call bread / Read double indirect block.
lodsw
lodsw
call bread / Read (second) indirect block.
movb cl, $NIND / cx = # of indirect maps (ch=0)
2: lodsw / Skip hi half (canon long)
movsw / and move low half.
loop 2b / Do them all.
sub dx, dx / sets dx to first word
/ jmp iread / Done return through iread.
////////
/
/ This routine reads the virtual
/ block described by the ofs in "dx" into the
/ buffer "bbuf". It uses the mapping data that
/ has been provided by a previous call to igrab
/ On return "si" points at "bbuf".
/ Holes in files are correctly done.
/ mungs ax, bx, si.
/ clears cx.
/
///////
iread:
sub bx, bx / Convert from words to blocks.
movb bl, dh /
shl bx, $1 / Get 2 * block number into
mov ax, iaddr(bx) / physical block from the table.
/ jmp bread / Yes, return through "bread".
////////
/
/ Read a block from the floppy disk,
/ drive A:, using the code in the IBM firmware.
/ The physical block # is in "ax".
/
////////
bread: push es / Save registers
push di
push dx
push ds
pop es / set ES to the address of the buffer
mov di, bp / if block 0, clear buffer
mov cx, $BUFSIZE
rep
stosb
test ax, ax / if block 0, return zeroed buffer
jz 2f
xor dx, dx / extend block number
add ax, first / add first block
adc dx, first+2 / add rest
mov bx, ax / save block number
movb al, heads / get number of heads
movb cl, sects / get number of sectors
mulb cl / calculate sectors per cylinder
xchg bx,ax / swap block/sectors
div bx / calculate track
xchg dx, ax / put track in DX
divb cl / calculate head/sector
movb cl, ah / set sector
inc cx / sectors start at 1 [incb cl]
cmp dx, traks / check for second side
jb 0f
sub dx, traks / fold track
inc ax / next head [incb al]
0: rorb dh, $1 / rotate track(low) into
rorb dh, $1 / msbits of DX
orb cl, dh / set track(high)
movb ch, dl / set track(low)
movb dh, al / set head
movb dl, drive / set drive
mov bx, bp / set offset [bbuf]
mov ax, $READ1 / Read, 1 sector.
int DISK / Disk I/O.
jnc 2f / Jump if no error.
mov ax, $READ1 / try again
int DISK
jc error
2: mov si, bp / set SI to point to buffer for return
sub cx, cx / clear CX here to save space
pop dx / restore registers.
pop di
pop es
ret / return.
////////
/
/ Print signon message
/
////////
/ login: mov si, $msg00 / point si to message
print: lodsb / al=byte
cmpb al, $LF / check for end of message
call putc / Type it and
jne print / go back for more.
ret
/ Prompt with a "?" and read the file name
/ into the "nbuf". No character editing facilities
/ are provided.
error: mov sp, bp / Reset stack
/ call login / print boot message
input: mov di, $nbuf / di=name buffer pointer
mov cx, $DIRSIZE / cx=size of
movb al, $0x3F / set prompt to ?
0: call putc
1: movb ah, $0 / Get ASCII opcode.
int KEYBD / Read keyboard ROM call.
#if 0
/ Conditionalized out to make more space
cmpb al, $BS / BS ?
jne 2f /
cmpb cl, $DIRSIZE / At start of buffer?
je 1b / Yup, ignore BS
call putc / Output destructive backspace
movb al, $SP
call putc
movb al, $BS
dec di / Adjust pointer
inc cx / and char count
jmp 0b / and continue.
#endif
2: cmpb al, $CR / CR ?
je 3f / Yup, do next thing
jcxz 1b / skip over too big name
stosb / put it into the buffer,
dec cx / adjust char count
jmp 0b / and continue.
3: mov si, $crlf / Echo LF followed by CR.
call print
movb al, $0 / zero out
rep
stosb / rest of name
entry: mov ax, $ROOTINO / ax = current inode
call igrab / Read in inode and set dx
/ Search directory.
/ Assume directory size < 64 Kbytes.
search: orb dl, dl / On block boundry ?
jnz 0f / Nope.
call iread / Read block, set si.
0: movb cl, $DIRSIZE / cx = count left
mov di, $nbuf / Point at name buffer and
lodsw / ax = inumber, this entry.
or ax, ax / Empty directory slot ?
je 1f / Yes, skip.
repe / compare the
cmpsb / two file names.
je found / If eq, go and get inode.
1: add si, cx / Advance by count remaining.
add dx, $DIRSIZ2+1 / Bump [word] seek pointer
jg search / Scan up to 64 Kbytes of directory.
jmp input / File not found.
////////
/
/ Found the file so read it in.
/ ax = inode number of file
/
////////
found: call igrab / read in inode and first block
cmp LMAGIC(si),$LFMAG / Check the magic number.
jne error / not Ok.
/ push LBSSD(si) / Push the uninitialized data size.
mov ax, LSHRD(si) / Push the sum
add ax, LPRVD(si) / of the shared and private
push ax / [initialized] data sizes.
andb LFLAG(si), $LFSEP / check image flags.
pushf / Push result of test.
mov ax, LSHRI(si) / Get the sum of the
add ax, LPRVI(si) / shared and private code sizes.
mov dx, $HDRSIZ2 / Seek after header and
add si, $HDRSIZE / set buffer pointer appropriately.
mov es, 1f / Set ES:DI to point to the load
sub di, di / base of the new system.
call load / Load code.
popf / Pop sep I/D flag test
jz 0f / Not sep.
add di, $15 / Round up the system code
movb cl, $4 / size to 16 byte
shr di, cl / paragraphs.
mov ax, es / fetch program base
add ax, di / Compute the data base and
mov es, ax / set up ES:DI to point
sub di, di / at it.
0: pop ax / Pop off initialized data size and
call load / load the image.
/ pop cx / Pop off uninitialized data size and
/ rep / clear it.
/ stosb
.byte JMPF / Jump to offset
.word 0x0100 / 0x0100 (after base) in system
1: .word SYSBASE / code segment.
////////
/
/ Load a segment. The "dx" holds the
/ seek pointer into the file. The "si" holds
/ a pointer into the "bbuf". The "es:di" pair
/ holds the target address. The "ax" holds
/ the number of bytes to load. On return the
/ "ax" must equal 0 (the caller assumes this
/ and uses "al" to clear the BSS).
/
////////
load: or ax, ax / Any left ?
jz return / Jump if all loaded.
mov cx, $bbuf+BUFSIZE / Compute the number of bytes
sub cx, si / remaining in the block.
jnz 0f / Jump if some.
push ax / Save count registers, then
call iread / read the next block
pop ax / of the file.
mov cx, $BUFSIZE / We now have a full block.
0: cmp cx, ax / More than we need ?
jbe 1f / Nope.
mov cx, ax / Only take what we need.
1: sub ax, cx / Fix up the count
shr cx, $1 /
add dx, cx / Fix up the seek [word] address, then
rep / copy the words from the block
movsw / buffer to the load point and
jmp load / loop until done.
////////
/
/ Write the character in "al" out to
/ the display, using routines in the ROM.
/ Like most calls to the ROM, this routine spends
/ most of its time saving and restoring the
/ registers.
/
/ Note: The ZF in the PSW word must be preserved.
/
////////
putc: push si / Save registers.
push di
push bp
mov bx, $0x0007 / Page 0, white on black
movb ah, $0x0E / Write TTY.
int 0x10 / Call video I/O in ROM.
pop bp / Restore registers.
pop di
pop si
return: ret / Return
////////
/
/ Data. There is some pure data in
/ the "prvd" segment. This data is moved to the
/ new memory when the boot is relocated. All buffers
/ are in the BSS, and are not actually moved, or even
/ saved in the boot block.
/
////////
.prvd
nbuf: .ascii "autoboot" / Name buffer.
.blkb DIRSIZE-8 / rest of buffer
traks: .word NTRK
sects: .byte NSPT
heads: .byte NHD
cntrl: .byte CNTRL
wpcc: .word WPCC / not used currently
drive: .byte 0
first: .word 0
.word 0
/ msg00: .ascii "Boot"
crlf: .byte CR, LF
.byte 0x55,0xAA
.bssd
stack: .blkb NSTK / Local Stack and name buffer
bbuf: .blkb BUFSIZE / Block buffer [must follow stack].
iaddr: .blkw ND+NIND+NIND / Inode map words.