1 TITLE IBMBIO IBM BIOS FOR
MS-DOS
4.0
3 ; Modified for 3.0, July '83, Marc McDonald
6 ; split disk driver into separate file
8 ; split out console driver
10 ;::::::::::::::::::::::::::::::::::::::::::::::
12 ; IBM ADDRESSES FOR I/O
14 ;::::::::::::::::::::::::::::::::::::::::::::::
17 ;DEBUGFLG = 1 ; don't enable debug printfs
18 CONSFLAG
= 0 ; =1 to include console driver here
24 BIOSEG
=70H
;0070 SEGMENT FOR THE BIOS
25 SYSIZE
=100H
;Number of paragraphs in sysinit module
26 RSINIT
=0A3H ;RS232 INITIALIZATION
27 ;9600 BAUD:NO PARITY:1 STOP:8 BIT WORD
29 CR
=13 ;CARRIAGE RETURN
31 BRKADR
=6
CH ;006C BREAK VECTOR ADDRESS
32 DSKADR
=1EH
*4 ;ADDRESS OF PTR TO DISK PARAMETERS
33 SEC9
=522H
;ADDRESS OF DISK PARAMETERS
38 ;** Timer and Clock Definitions
40 SCHEDCOUNT EQU
50 ; # msec/scheduler tick
41 MOTORCOUNT EQU
55 ; # msec/ROM BIOS tick
43 EXTRN CURRENT_DOS_LOCATION
:WORD
44 EXTRN FINAL_DOS_LOCATION
:WORD
45 EXTRN DEVICE_LIST
:DWORD
46 EXTRN MEMORY_SIZE
:WORD
47 EXTRN DEFAULT_DRIVE
:BYTE
50 BiosSeg GROUP
Code,BiosInit
51 Code SEGMENT BYTE PUBLIC 'CODE'
53 ASSUME
CS:BiosSeg
,DS:NOTHING
,ES:NOTHING
58 DB 20 DUP (0) ; IBM WANTS SOME ZEROED AREA
60 SUBTTL Jump tables for devices
61 \f;--------------------------------------------------------------
65 ; BEWARE - These tables overlap somewhat! -c.p.
134 DW StatusNoXfer
; Printer doesn't read
153 SUBTTL Device
entry points
154 \f;---------------------------------------------------
158 CMDLEN
= 0 ;LENGTH OF THIS COMMAND
159 UNIT
= 1 ;SUB UNIT SPECIFIER
160 CMD
= 2 ;COMMAND CODE
162 MEDIA
= 13 ;MEDIA DESCRIPTOR
163 TRANS
= 14 ;TRANSFER ADDRESS
164 Dfun
= DWORD PTR 14 ; Passed addr of dos function
165 COUNT
= 18 ;COUNT OF BLOCKS OR CHARACTERS
166 START
= 20 ;FIRST BLOCK TO TRANSFER
168 AUXNUM
DB 0 ;WHICH AUX DEVICE WAS REQUESTED
170 ; Dos routine to do functions for device drivers
172 DosFunction
DD 0 ; Device help function entry point
173 ScrnIOok dd 0 ; (char *) true if in current screen locus
175 TIM_DRV
DB -1 ; TIME WHEN LAST DISK I/O PERFORMED
176 TIM_REM
DW 0 ; scheduler tics left until media presumed
179 ;** Debugging control:
181 ; Group Level Controls
182 ; 01 General BIOS, bootstrapping and initialization
183 ; 01 Device initialization
184 ; 02 MS-DOS bootstrapping
185 ; 04 Driver error conditions
186 ; 10 Command dispatch
190 ; 04 Details of read/write processing
191 ; 08 Hard disk driver
194 ; 10 Console display driver
198 BUGBITS
DB 000H ; group bits
252 Interrupt is the main part of the interrupt device
entry point
( a
253 misnomer
, actually is the execute function
entry ) for all devices
.
254 The various devices set up the dispatch table address
and unit choice
255 and then jump to Interrupt which then dispatches to the appropriate
259 SI Address of device dispatch table
260 AL Unit
# for Aux
/Prn
( stored
in AuxNum
)
261 ES:BX Device request packet address
263 Exit parameters
: ( to device routine
)
264 AL Unit
code from packet
265 AH Media descriptor
from packet
267 DX Start sector
from packet
268 ES:DI Buffer address
from packet
270 SS TaskArea
segment( from dos
call )
284 debug
1,10H
,< INTERRUPT cmdtbl $x
>,<si>
285 MOV CS:[AUXNUM
],AL ; Save unit choice of AUX/PRN
287 MOV DS,AX ; DS:BX also points to packet
289 MOV AL,DS:[BX].Cmd
; Get device command
292 ADD SI,AX ; Get Address of routine
293 CMP AL,18 ; Too high a command number?
294 JA CmdErr
; Yes, error
295 MOV AL,DS:[BX].UNIT
;AL = Unit code
296 MOV AH,DS:[BX].MEDIA
;AH = Media descriptor
297 MOV CX,DS:[BX].COUNT
;CX = Count
298 MOV DX,DS:[BX].START
;DX = Start sector
299 LES DI,DS:[BX].TRANS
; ES:DI = buffer addr
300 debug
1,10H
,<un $x xfer $x
:$x rtn $x
\n>,<ax,es,di,cs:[si]>
301 JMP WORD PTR CS:[SI] ; Do request
304 SUBTTL Routines
used by device routines
306 All routines
on this page are various exits for device functions
.
307 They each return different information
in the request packet for the
308 dos
. The routines are
as follows
:
311 The busy
and done bits are set
in the packet
. This
312 means that the device has input to be read
or can
313 do output without any waiting
.
316 The device was unable to do the I
/O for the requested
317 number of bytes
/blocks
. CX contains the number that are
318 left to do
. Fall
into StatusError to set error has
322 Set the error
and done bits
in the status
.
325 The device couldn
't do the read
or write
, set the
326 number of bytes transferred to
0, but don
't set the
330 The device actually completed the request
and every
-
331 thing was just fine
, so just set the done bit
in the
335 The device driver is for
3.0 and saw that it would
336 have to
wait in a
loop to do the request
, so instead
337 it will
not set the done bit which tells the dos to
338 put the task
into the I
/O
wait queue
.
340 Entry parameters
: ( for all of the above routines
)
341 DS:BX Address of device request packet
342 CX Count of bytes
/blocks left to transfer
if applicable
343 AL Error
code if applicable
346 ES:BX Pointer to packet
349 All other registers preserved
352 PUBLIC StatusDevReady
353 StatusDevReady PROC
NEAR ; Device has data or can send
354 MOV AH,00000011B ; Done + busy
359 CmdErr PROC
NEAR ; Bad device command number
360 debug
1,4,< CMDERR
- $b $x
\n>,<ax,si>
361 MOV AL,3 ; Unknown command error
364 StatusPartialXfer PROC
NEAR
365 SUB [BX].COUNT
,CX ;# of successful I/O's
366 StatusPartialXfer ENDP
369 StatusError PROC
NEAR
370 MOV AH,10000001B ; Error + done
374 StatusNoXfer PROC
NEAR
376 MOV [BX].COUNT
,AX ; No chars read
379 PUBLIC StatusComplete
380 StatusComplete PROC
NEAR
381 MOV AH,00000001B ; Done
386 MOV ES:WORD PTR [BX].STATUS
,AX ;MARK OPERATION COMPLETE
395 RET ;RESTORE REGS AND RETURN
400 MOV AH,0 ; Don't set done bit
401 MOV [BX].Count
,CX ; Set number completed
402 MOV WORD PTR [BX].Trans
,DI ; Set new offset
407 ; Set the address of the dos function routine for drivers
409 MOV AX,WORD PTR [BX].Dfun
410 MOV WORD PTR DosFunction
,AX
411 MOV AX,WORD PTR [BX+2].Dfun
412 MOV WORD PTR (DosFunction
+2),AX
417 mov word ptr ScrnIOok
,ax
418 mov word ptr ScrnIOok
+2,dx
423 ;-------------------------------------------------------------
425 ; CHROUT - WRITE OUT CHAR IN AL USING CURRENT ATTRIBUTE
434 MOV AH,14 ;WRITE CHARACTER
435 INT 10H
;SEND THE CHARACTER
440 ;----------------------------------------------
444 GETDX: MOV DL,[AUXNUM
]
448 SUBTTL
Console driver
450 This is the
console( CON
) device driver
. The input side is assigned
451 to the keyboard
and the output to the video screen
. The output
code
452 remains more
or less the same
as in 2.0. The input side
, however
, is
453 changed for
4.0 to
enter an I
/O
wait rather than
loop waiting for a
458 CONDEV
LABEL WORD ;HEADER FOR DEVICE "CON"
460 DW 1000000000010011B ;CON IN AND CON OUT + SPECIAL
470 Key2ndPart
DB 0 ; Leftover byte of 2 key codes
472 RomData
SEGMENT AT 40H
477 KeyBufLen equ
32 ; length of KeyBuffer
480 ; BREAK interrupt routine
481 ; ROM interrupt handler resets buffer pointers to beginning of buffer
482 ; and places a 0000h dummy character into the buffer.
485 mov Key2ndPart
,3 ; Force next char to be ^C( stop )
489 SUBTTL
Console read
and subroutines
493 The
console read dispatch tries to read the selected number of
494 characters
from the keyboard
. If at any point there is no key
in
495 the queue
, it returns to the dos to allow another process to run
496 until a key is depressed
.
499 ES:DI Pointer to buffer
in which to
store characters
500 CX Number of characters to read
501 DS:BX Pointer to device request packet
504 CX Number of characters left to read
505 DS:BX Pointer to device request packet
512 CALL ChrIn
;GET CHAR IN AL
514 STOSB ;STORE CHAR AT ES:DI
520 ChrIn attempts to read a character
from the keyboard queue that
521 is maintained by the ROM BIOS
. If the queue is
not empty
, the
code
522 is returned
. Otherwise
, the packet is added to the list of keyboard
523 reads
and carry is set to cause the driver routine to return to the
524 dos with the done bit
not set which results
in an I
/O
wait.
527 DS:BX Pointer to device request packet
530 AL Character
from keyboard
if present
536 XCHG AL,Key2ndPart
; GET CHARACTER & ZERO Key2ndPart
540 INT 16H
; Get the char
541 OR AX,AX ;Check for non-key after BREAK
543 CMP AX,7200H
;Check for CTRL-PRTSC
547 OR AL,AL ; 2 byte keycode?
548 JNZ KeyRet
; No, have whole code
549 MOV Key2ndPart
,AH ; Yes, store scan code for next read
555 The non
-destructive keyboard read routine returns the next char
556 in the queue
if there is one
.
559 DS:BX Pointer to device request packet
562 DS:BX Pointer to device request packet
572 JNZ NOTBRK
;CHECK FOR NULL AFTER BREAK
574 INT 16H
;READ THE NULL
575 JMP CON$RDND
;AND GET A REAL STATUS
576 NOTBRK: CMP AX,7200H
;CHECK FOR CTRL-PRTSC
581 EXVEC: JMP StatusComplete
582 CONBUS: JMP StatusDevReady
585 ;--------------------------------------------------------------
587 ; KEYBOARD FLUSH ROUTINE
590 MOV [Key2ndPart
],0 ;Clear out holding buffer
592 CALL Flush
; Flush the keyboard
603 CLI ; ** Disable interrupts
604 MOV AX,offset RomData
:KeyBuffer
; Start of Rom buffer
606 MOV BufferTail
,AX ; Empty the queue
607 STI ; ** enable interrupts
614 SUBTTL
Console output
( video
) routines
617 ;----------------------------------------------------------
619 ; CONSOLE WRITE ROUTINE
623 CON$LP
: MOV AL,ES:[DI] ;GET CHAR
627 INT CHROUT
;OUTPUT CHAR
630 LOOP CON$LP
;REPEAT UNTIL ALL THROUGH
633 SUBTTL Keyboard interrupt routine
635 ; Replacement for ROM keyboard interrupt, tacks on the front.
636 ; OldKeyInterrupt is set to original contents of INT 09H.
637 ; The input character is passed to the O.S. console input filter
638 ; to determine if any special action should be taken. The filter
639 ; return value indicates if the character should be saved in the
640 ; type ahead buffer or if it should be discarded. A keyboard
641 ; semaphore exists to indicate if a process is waiting for input.
642 ; If the keboard semaphore is set all of the processes sleeping on
646 KeySem db 0 ; non-zero if someone waiting on input
648 KeyboardInterrupt PROC
FAR
654 PUSHF ; Save flags to simulate INT
655 CALL CS:OldKeyInterrupt
; Now do ROM code
656 ; Now tell scheduler keyboard had char
657 cli ; interrupts off!
658 mov bx,BufferTail
; Get tail of queue
659 cmp bx,BufferHead
; Anything in keyboard queue?
660 JE NoKey
; No, don't requeue then
663 cmp bx,offset RomData
:KeyBuffer
664 jae kbi1
; no rap around in buffer
665 mov bx,offset RomData
:KeyBuffer
+KeyBufLen
667 mov ax,[bx] ; get last queued char.
668 mov dx,5 ; ConsInputFilter subfunction
670 jnz kbi2
; key should remain in buffer
671 mov BufferTail
,bx ; discard key from buffer
675 CMP KeySem
,0 ; Outstanding request?
676 JE NoKey
; No, may not be inited either
683 mov cs:byte ptr [bx],0 ; reset keyboard semaphore
685 call [DosFunction
] ; awaken anyone waiting on input
692 KeyBoardInterrupt ENDP
694 ;-------------------------------------------------------------
695 ; Keyboard INT 16 intercept routine to allow console input to sleep.
696 ; Only console input function 1 is intercepted, all other functions
697 ; are allowed to go directly to the ROM BIOS. For the function 1
698 ; the input status is checked, if a character is ready the function
699 ; is allowed to go to the ROM BIOS. Otherwise the keyboard semaphore
700 ; is set and the process is put to sleep on the address of the
701 ; semaphore. When a key is typed the keyboard interrupt routine
702 ; will wakeup any processes sleeping on this semaphore.
704 ; WARNING: The following routines can be entered recursively
705 ; due to the fact that the ROM BIOS routines called
706 ; reenable interrupts. It's not usually a problem
707 ; since interrupts will generally be processed faster
708 ; than anyone can type.
712 ;-------------------------------------------------------------
714 KeyBoardHandler proc
far
726 test byte ptr [bx],0FFh
742 test byte ptr [bx],0FFh
746 mov dx,9 ;; ProcBlock
747 call [DosFunction
] ; sleep until a char is typed
751 mov ah,1 ; get console status
752 pushf ; simulate INT to old handler
755 cli ; subfunction 1 unconditionally sets IF
756 jnz LocalRead
; go read character
759 mov cs:byte ptr [bx],0FFh ; set keyboard semaphore
761 mov dx,9 ;; ProcBlock
762 call [DosFunction
] ; sleep until a char is typed
770 jmp [OldKbdHandler
] ; read the character and return
777 \f;------------------------------------------------------
779 ; A U X - AUXILARY DEVICE DRIVER
781 AUXDEV
LABEL WORD ;HEADER FOR DEVICE "AUX"
804 ;-------------------------------------------------------
806 ; READ FROM AUXILARY DEVICE
812 XCHG AL,[BX] ;Get character and zero buffer
816 AUX2: STOSB ;STORE CHARACTER
818 EXVEC2: JMP StatusComplete
820 AUXIN: MOV AH,2 ;INDICATES A READ
821 CALL AUXOP
;READ THE AUXILIARY PORT
822 TEST AH,0EH ;Check framing, parity, overrun
824 POP AX ;Clean up the stack
825 MOV AL,0BH ;READ ERROR
826 JMP StatusPartialXfer
828 ;--------------------------------------------------------
830 ; AUX NON-DESTRUCTIVE READ, NO WAITING
834 MOV AL,[BX] ;GET KEY AND ZERO BUFFER
836 JNZ AUXRDX
;KEY IN BUFFER?
838 TEST AH,00000001B ;TEST DATA READY
840 TEST AL,00100000B ;TEST DATA SET READY
844 MOV [BX],AL ;GET AND SAVE KEY
845 AUXRDX: JMP StatusComplete
846 AUXBUS: JMP StatusDevReady
847 ;----------------------------------------------------------
853 TEST AL,00100000B ;TEST DATA SET READY
855 TEST AH,00100000B ;TEST CLEAR TO SEND
864 ;---------------------------------------------------------
866 ; FLUSH AUX INPUT BUFFER
872 ;---------------------------------------------------------
874 ; WRITE TO AUXILARY DEVICE
879 MOV AL,ES:[DI] ;GET CHAR
880 INC DI ;POINT TO NEXT ONE
881 MOV AH,1 ;INDICATES A WRITE
882 CALL AUXOP
;SEND CHARACTER OVER AUX PORT
883 TEST AH,80H
;CHECK FOR ERROR
885 MOV AL,10 ;INDICATE WRITE FAULT
886 JMP StatusPartialXfer
894 SUBTTL Printer driver
895 \f;-------------------------------------------------------------
897 ; P R N - PRINTER DEVICE
899 PRNDEV
LABEL WORD ;HEADER FOR DEVICE "PRN"
929 ;----------------------------------------------------------
931 ; WRITE TO PRINTER DEVICE
936 MOV AL,ES:[DI] ;GET CHAR INTO AL
937 INC DI ;POINT TO NEXT CHAR
938 MOV [ERRFLG
],0 ;INITIALIZE RETRY FLAG
940 PRETRY: XOR AH,AH ;AH=0
941 CALL PRNOP
;TO INDICATE PRINT CHAR IN AL
944 XOR [ERRFLG
],1 ;DO 1 AUTOMATIC RETRY
946 PMESSG: JMP StatusPartialXfer
;RETURN WITH THE ERROR
949 EXVEC3: JMP StatusComplete
950 ;--------------------------------------------------------
952 ; PRINTER STATUS ROUTINE
955 CALL PRNSTAT
;DEVICE IN DX
967 TEST AH,0001B ;TEST FOR NOT READY
970 MOV AL,10 ;WRITE FAULT CODE
971 TEST AH,1000B ;TEST FOR I/O ERROR
974 TEST AH,00100000B ;OUT-OF-PAPER?
976 MOV AL,9 ;OUT OF PAPER CODE
977 PRNOP1: OR AL,AL ;SET NZ FLAG
980 SUBTTL Timer
(clock
) driver
985 ; Uses clock with 1000 ticks per second. User sees only
986 ; time in hours, minutes, seconds, and 1/100 second, in registers
987 ; CH, CL, DH, DL respectively. (Each is a binary number.)
988 ; Modified for 4.0. The ROM bios timer routines are completely
989 ; replaced with code on this page. This provides a better time base
993 EXTRN Floppydevice
:NEAR
995 DW Floppydevice
,BIOSEG
1003 ;--------------------------------------------------------------------
1005 ; Settime sets the current time
1007 ; On entry ES:[DI] has the current time:
1009 ; number of days since 1-1-80 (WORD)
1010 ; minutes (0-59) (BYTE)
1011 ; hours (0-23) (BYTE)
1012 ; hundredths of seconds (0-99) (BYTE)
1013 ; seconds (0-59) (BYTE)
1015 ; Each number has been checked for the correct range.
1023 MUL CH ;Hours to minutes
1025 ADD AX,CX ;Total minutes
1026 MOV CX,60000 ;60*1000
1027 MUL CX ;Convert to milliseconds
1029 MOV BX,DX ; Save hours, min in Msecs in BX:SI
1030 MOV AL,ES:[DI+5] ; Get # seconds
1032 MUL CL ; Get seconds in 1/100s
1033 MOV CL,ES:[DI+4] ; Hundredths of second
1034 ADD AX,CX ; Now have seconds and 1/100ths
1036 MUL CX ; Get DX:AX = milliseconds
1040 MOV CS:TickHigh
,BX ; Set time in milliseconds
1045 ;***************************************
1047 ; Gettime reads date and time
1048 ; and returns the following information:
1050 ; ES:[DI] =count of days since 1-1-80
1053 ; ES:[DI+4]=hundredths of seconds
1056 ;***************************************
1063 MOV AX,CS:TickLow
; Get current time
1064 MOV CX,60000 ; # milliseconds in a minute
1065 DIV CX ; Get AX= minutes, DX = seconds&msecs
1066 MOV BX,DX ; Save seconds and fraction
1068 MOV CX,60 ; # minutes/hour
1069 DIV CX ; Get AX= hour, DX= minute
1071 STOSB ; Return minutes
1073 STOSB ; Return hours
1077 DIV CX ; Get AX= seconds, DX= milliseconds
1078 xchg ax,bx ; (bx) = seconds
1082 DIV CX ; Get hundredths of second
1083 STOSB ; Return hundredths of second
1085 STOSB ; Return second
1089 SUBTTL Clock interrupt
and replacement for ROM
code
1093 The clock
code in the ROM is replaced with the following
code which
1094 provides the clock interface to the scheduler
and a
1 ms time base
. The
1095 1
AH interrupt is simulated to return the approximate time for those
1096 routines which still
call 1
AH. The time period for motor start up is
1097 preserved since that
code has
not yet been rewritten
.
1100 RomData
SEGMENT AT 040H
1102 Motor_Status
DB 1 DUP(?
)
1103 Motor_Count
DB 1 DUP(?
)
1106 TickLow
DW ?
; Low part of time in Msec
1107 TickHigh
DW ?
; High part of time in msec
1108 MotorFlag
DB 0 ; There is an active motor
1109 MotorTick
DB MOTORCOUNT
; # ticks until 1/18.2 secs
1110 SchedTick
DB SCHEDCOUNT
; Scheduler countdown
1112 ; Interrupt 8H - timer interrupt
1115 TimerInterrupt PROC
FAR
1121 CMP TickHigh
,1318 ; Close to 24 hours?
1123 CMP TickLow
,23552 ; Reach 24 hours?
1125 ; Have reached a day, bump day count
1129 MOV TickLow
,AX ; Reset time of day
1131 ;; DEC MotorTick ; Time to decrement motor?
1132 ;; JNZ CheckSched ; No
1133 ;; MOV MotorTick,MOTORCOUNT ; Reset 1/18 sec worth of msecs
1137 ;; ASSUME DS:RomData
1139 ;; TEST MotorFlag,0FFH ; Active motor timer?
1140 ;; JZ CheckMotor ; No, see if new one
1142 ;; JNZ CheckMotor ; Not time to shut down
1143 ;; AND Motor_Status,0F0H ; Turn off motor running bits
1147 ;; OUT DX,AL ; Turn off the motors
1149 ;; MOV MotorFlag,0 ; No motor timeout running
1151 ;; JMP CheckSched ; Go see if time to sched
1154 ;; MOV AL,Motor_Count
1156 ;; JNZ CheckSched ; Motor already active
1157 ;; OR AL,AL ; Need to start countdown?
1158 ;; JZ CheckSched ; No
1159 ;; MOV MotorFlag,0FFH ; Yes, set flag
1160 ;; MOV MotorTick,MOTORCOUNT ; 1/18.2 sec later
1162 ; The scheduler is called every 10ms, rather than every 1 ms to see if
1163 ; it should switch tasks.
1165 ; First reset the timer so will interrupt again
1171 OUT 40H
,AL ; Set 1 msec delay
1173 OUT 20H
,AL ; Tell 8259 interrupt done
1174 ; Now see if should call scheduler
1175 DEC SchedTick
; Time to call scheduler?
1176 JNZ NoSched
; No, all done
1177 MOV SchedTick
,SCHEDCOUNT
; Reset countdown
1178 csch1: POP AX ; Stack is now clean
1179 INT 32H
; Save all regs
1180 CMP WORD PTR (DosFunction
+2),0 ; Dos installed?
1181 JE NoSchedActive
; Not yet, don't call sched
1182 sub dx,dx ; (dx) = 0 = tic subfunction
1183 mov ax,SCHEDCOUNT
; 10 milliseconds per tic
1184 CALL DosFunction
; Do the tick
1185 EXTRN FloppyTimer
:FAR
1186 CALL FloppyTimer
; timer service for floppy disk also
1192 INTRET: IRET ; All done
1195 ; INT 1AH - Get/Set time based in 55msec tick
1198 OR AH,AH ; Function 0: Read time?
1200 DEC AH ; Function 1: Write time?
1202 IRET ; No, bad function code
1204 ; Read old( 1/18.2 second tick ) time
1208 MOV CX,MOTORCOUNT
; # milliseconds in 1/18.2 secs
1209 DIV CX ; Get value in old ticks
1213 pop cx ; get high order count
1214 XOR AL,AL ; Never have oveflow
1215 IRET ; Return the time
1217 ; Set time using old resolution
1221 MOV BX,MOTORCOUNT
; Conversion factor
1223 MOV TickLow
,AX ; Set low part of time
1228 ADD AX,CX ; Combine high parts
1229 MOV TickHigh
,AX ; Set time
1230 IRET ; Return with new time set
1234 memsizmsg db 13,10,'Error - Interrupt 12',13,10,0
1237 memsizhandler proc
far
1244 mov SI,offset
CS:memsizmsg
1254 ;----------------------------------------------
1255 ; WRITE OUT MESSAGE POINTED TO BY [SI]
1257 WRMSG: LODSB ;GET THE NEXT CHARACTER OF THE MESSAGE
1258 AND AL,7FH
;SEE IF END OF MESSAGE
1261 MOV AH,14 ;WRITE CHARACTER
1262 INT 10H
;SEND THE CHARACTER
1272 SUBTTL Diskette driver
-- now
used only for bootup
1273 \f;-----------------------------------------------------------------
1275 ; DISK INTERFACE ROUTINES
1277 BiosInit
SEGMENT PARA
PUBLIC 'CODE'
1286 WRTVERIFY
LABEL WORD
1287 RFLAG
DB 2 ;2 for read, 3 for write
1288 VERIFY
DB 0 ;1 if verify after write
1289 SINGLE
DB 0 ;1 if single drive system
1290 SWPFLG
DB 0 ;1 if BIOS swapped out
1292 HARDNUM
DB 99 ;logical drive number of first hardfile
1295 DRVLIM
= 8 ;Number of sectors on device
1296 SECLIM
= 13 ;MAXIMUM SECTOR
1297 HDLIM
= 15 ;MAXIMUM HEAD
1298 HIDSEC
= 17 ;NUMBER OF HIDDEN SECTORS
1300 ;WARNING - preserve order of drive and curhd! -c.p.
1302 DRIVE
DB 0 ;PHYSICAL DRIVE CODE
1303 CURHD
DB 0 ;CURRENT HEAD
1304 CURSEC
DB 0 ;CURRENT SECTOR
1305 CURTRK
DW 0 ;CURRENT TRACK
1308 ERRIN: ;DISK ERRORS RETURNED FROM THE IBM ROM
1310 DB 40H
;Seek failure
1313 DB 4 ;SECTOR NOT FOUND
1314 DB 3 ;WRITE ATTEMPT TO WRITE-PROTECT DISK
1315 LSTERR
DB 0 ;ALL OTHER ERRORS
1318 ERROUT: ;RETURNED ERROR CODES CORRESPONDING TO ABOVE
1323 DB 8 ;SECTOR NOT FOUND
1324 DB 0 ;WRITE ATTEMPT ON WRITE-PROTECT DISK
1325 DB 12 ;GENERAL ERROR
1327 NUMERR
= ERROUT
-ERRIN
1328 ;---------------------------------------------------------------------
1329 SPSAV
DW 0 ;SAVE THE STACK POINTER
1336 MOV CL,AH ;SAVE MEDIA
1337 AND CL,0F8H ;NORMALIZE
1338 CMP CL,0F8H ;COMPARE WITH GOOD MEDIA BYTE
1340 MOV AH,0FEH ;DEFAULT TO 8-SECTOR, SINGLE-SIDED
1341 GOODID: MOV DI,OFFSET
CS:HDRIVE
1345 MOV DI,OFFSET
CS:DRIVEX
1348 GETBP1: MOV AL,1 ;SET NUMBER OF FAT SECTORS
1349 MOV BX,64*256+8 ;SET DIR ENTRIES AND SECTOR MAX
1350 MOV CX,40*8 ;SET SIZE OF DRIVE
1351 MOV DX,01*256+1 ;SET HEAD LIMIT AND SEC/ALL UNIT
1352 MOV DI,OFFSET
CS:FDRIVE
1353 TEST AH,00000010B ;TEST FOR 8 OR 9 SECTOR
1354 JNZ HAS8
;NZ = HAS 8 SECTORS
1355 INC AL ;INC NUMBER OF FAT SECTORS
1356 INC BL ;INC SECTOR MAX
1357 ADD CX,40 ;INCREASE SIZE
1358 HAS8: TEST AH,00000001B ;TEST FOR 1 OR 2 HEADS
1360 ADD CX,CX ;DOUBLE SIZE OF DISK
1361 MOV BH,112 ;INCREASE NUMBER OF DIRECTORY ENTRIES
1362 INC DH ;INC SEC/ALL UNIT
1363 INC DL ;INC HEAD LIMIT
1364 HAS1: MOV CS:[DI].2,DH
1377 ;*********************************************************************
1378 ; "FDRIVE" IS A FLOPPY DISK, VARIOUS PARAMETERS ARE PATCHED
1379 ; BY GETBP TO REFLECT THE TYPE OF MEDIA INSERTED
1381 DW 512 ;Physical sector size in bytes
1382 DB 1 ;Sectors/allocation unit
1383 DW 1 ;Reserved sectors for DOS
1384 DB 2 ;No. allocation tables
1385 DW 64 ;Number directory entries
1386 DW 9*40 ;Number sectors (at 512 bytes ea.)
1387 DB 11111100B ;Media descriptor
1388 DW 2 ;Number of FAT sectors
1391 DW 0 ;Hidden sector count
1393 ;------------------------------------------------------------
1397 ; AL = DRIVE NUMBER (0-3)
1398 ; AH = MEDIA DESCRIPTOR
1401 ; ES:DI = TRANSFER ADDRESS
1402 ; [RFLAG]=OPERATION (2=READ, 3=WRITE)
1403 ; [VERIFY]=1 FOR VERIFY AFTER WRITE
1405 ; IF SUCCESSFUL CARRY FLAG = 0
1406 ; ELSE CF=1 AND AL CONTAINS ERROR CODE
1409 debug
1,4,<DISKRD
: $x $x $x $x
:$x
\n>,<ax,cx,dx,es,di>
1414 MOV [TIM_DRV
],AL ;SAVE DRIVE LETTER
1416 MOV [SPSAV
],SP ;SAVE SP
1417 XCHG BX,DI ;ES:BX = TRANSFER ADDRESS
1418 CALL GETBP
;CS:DI = PTR TO B.P.B
1421 ADD DX,CS:[DI].HIDSEC
;ADD IN THE HIDDEN SECTORS
1422 CMP SI,CS:[DI].DRVLIM
;COMPARE AGAINST DRIVE MAX
1428 INRANGE:CMP AL,[HARDNUM
]
1430 MOV AL,CS:[HARDDRV
] ;SET DRIVE NUMBER OF HARDFILE
1435 NOTHARD:CMP [SINGLE
],1 ;SINGLE FLOPPY INSTALLED?
1437 CALL SWPDSK
;ASK USER FOR CORRECT DISK
1440 MOV [SECCNT
],CX ;SAVE SECTOR COUNT
1441 XCHG AX,DX ;SETUP LOGICAL SECTOR FOR DIVIDE
1443 DIV WORD PTR CS:[DI].SECLIM
;DIVIDE BY SEC PER TRACK
1445 MOV [CURSEC
],DL ;SAVE CURRENT SECTOR
1446 MOV CX,CS:[DI].HDLIM
;GET NUMBER OF HEADS
1447 XOR DX,DX ;DIVIDE TRACKS BY HEADS PER CYLINDER
1449 MOV [CURHD
],DL ;SAVE CURRENT HEAD
1450 MOV [CURTRK
],AX ;SAVE CURRENT TRACK
1452 debug
1,4,< Drv
$b Hd
$b Trk $x Sec
$b\n>,<<word ptr DRIVE
>,<word ptr CURHD
>,CURTRK
,<word ptr CURSEC
>>
1454 MOV SI,ES ;Check for 64k boundary error
1458 SHL SI,1 ;Segment converted to absolute address
1459 ADD SI,BX ;Combine with offset
1460 ADD SI,511 ;Add sector size and see if overflow
1461 JC BUFIO
;Must handle special if so
1465 MOV AH,128 ;Max. sectors in 64K
1466 SUB AH,BH ;Number of sectors left in this 64K
1469 CMP AH,AL ;Does it exceed total request?
1471 MOV AH,AL ;If so, limit transfer to the request
1473 ;At this point, AL=total number of sectors to be read, AH=number
1474 ; of sectors that can be read before 64K boundary error. AH<=AL.
1475 ; ES:BX points to load area, DS:DI points to B.P.B
1478 MOV AL,AH ;No. of sectors to read at once (<>0)
1479 CALL BLOCK
;Transfer portion before boundary
1486 PUSH BX ;SAVE CURRENT TRANSFER ADDRESS
1487 CALL SWAP
;SWAP BUFFER WITH BIOS CODE
1489 ADD BH,2 ;POINT TO TEMP BUFFER
1490 CALL DISK1
;Perform disk operation
1492 POP BX ;RECALL TRANSFER ADDRESS
1495 CALL SWAP
;SWAP BACK
1497 DEC AL ;Dec sectors to read by 1
1498 ADD BH,2 ;Add 200H to transfer address
1499 CALL BLOCK
;Read the remaining sectors
1501 debug
1,4,< DISKIO DONE
\n>
1503 RET ;From subroutine DISKIO
1505 ; Swap 512 bytes of BIOS with transfer address
1510 MOV DI,BX ;ES:DI POINTS TO USER BUFFER
1512 MOV SI,BX ;ES:SI POINTS TO TEMP BUFFER
1514 debug
1,4,< SWAP $x
:$x
<==> $x
:$x
\n>,<es,di,es,si>
1515 MOV CX,256 ;256 WORDS TO SWAP
1516 SWAP1: MOV BX,WORD PTR ES:[DI] ;GET USER WORD
1517 MOV AX,WORD PTR ES:[SI] ;GET SCRATCH WORD
1518 MOV WORD PTR ES:[SI],BX ;PUT SCRATCH WORD
1519 STOSW ;PUT BIOS WORD
1523 XOR [SWPFLG
],1 ;TOGGLE SWAPPED FLAG
1529 ;Read the number of sectors specified in AL, handling track boundaries
1531 BLOCK: OR AL,AL ;See if any sectors to read
1534 MOV AH,CS:[DI].SECLIM
;Sectors per track
1536 SUB AH,[CURSEC
] ;Number of sectors left on this track
1537 CMP AH,AL ;Compare with no. of sectors needed
1539 MOV AH,AL ;Limit to only those requested
1542 MOV AL,AH ;Put count where ROM needs it
1543 CALL DISK
;Call ROM and trap errors
1545 SUB AL,AH ;Reduce request by amount just done
1546 SHL AH,1 ;AH * 2^8 = no. of bytes
1547 ADD BH,AH ;Bump address pointer
1550 ;Perform disk I/O with retries
1551 ; AL = number of sectors (1-8, all on one track)
1552 ; ES:BX = Transfer address (must not cross a 64K physical boundary)
1553 ; [RFLAG] = 2 if read, 3 if write
1554 ; [VERIFY] = 0 for normal, 1 for verify after write
1556 DISK1: MOV AL,1 ;Only one sector for buffered I/O
1559 MOV AH,RFLAG
;Get read/write indicator
1563 CALLROM:MOV DX,[CURTRK
] ;Load current cylinder
1564 MOV CL,6 ;move high bits of cyl to sec
1568 XCHG CH,CL ;CL = sector, CH = cylinder
1569 MOV DX,WORD PTR [DRIVE
] ;Load physical drive number
1570 ;and current head number
1571 ;; debug 1,4,< CALLROM $x $x $x $x $x\n>,<ax,bx,cx,dx,es>
1572 INT 13H
;Request disk read/write
1574 POP AX ;Restore sector count
1576 CMP WRTVERIFY
,103H
;Check for write and verify
1578 MOV AH,4 ;Request verify
1582 ;; debug 1,4,< back from ROM\n>,<>
1584 AND CL,03FH ;Eliminate cylinder bits from sector
1586 SUB [SECCNT
],AX ;Reduce count of sectors to go
1587 ADD CL,AL ;Next sector
1589 CMP CL,CS:[DI].SECLIM
; Reached limit?
1592 MOV [CURSEC
],1 ;Start with first sector of next track
1595 CMP DH,CS:[DI].HDLIM
1598 INC [CURTRK
] ;NEXT TRACK
1599 NOXOR: MOV [CURHD
],DH
1604 debug
1,4,< DSKERR $x
>,<ax>
1605 PUSH AX ;Save error code
1606 MOV AH,0 ;Ask for disk reset
1608 POP AX ;Restore error code
1609 DEC SI ;decrement retry count
1611 CMP AH,80H
;Timeout?
1613 DSKERR1:POP AX ;Restore sector count
1617 CMP [SWPFLG
],0 ;If BIOS swapped out
1619 POP BX ;Get disk1 return address
1620 POP BX ;Get low part of transfer address
1621 POP ES ;Get high part of transfer address
1622 CALL SWAP
;swap it back in
1624 POP ES ;Make ES the local segment
1625 MOV AL,AH ;Put error code in AL
1626 MOV [LSTERR
],AL ;Terminate list with error code
1627 MOV CX,NUMERR
;Number of possible error conditions
1628 MOV DI,OFFSET
CS:ERRIN
;Point to error conditions
1630 MOV AL,es:NUMERR
-1[DI] ;Get translation
1631 MOV CX,SECCNT
;Get count of sectors to go
1632 MOV SP,[SPSAV
] ;Recover entry stack pointer
1633 STC ;Flag error condition
1643 RomData
SEGMENT AT 040H
1645 Seek_Status
DB 1 DUP(?
)
1649 ;-------------------------------------------------
1651 ; ASK TO SWAP THE DISK IN DRIVE A:
1654 XOR SI,SI ;Select segment 0
1656 MOV AH,AL ;Make copy of drive number
1657 XCHG AH,DS:LSTDRV
;Xchange with last drive used
1658 CMP AL,AH ;See if same as last drive
1660 ;Using a different drive in a one drive system so request the user change disks
1661 ADD AL,"A" ;Add "A" to convert to drive letter
1665 MOV SI,OFFSET
CS:SNGMSG
1667 CALL WRMSG
;Print disk change message
1669 INT 16H
;Wait for a keyboard character
1673 XOR AL,AL ;Always use drive 0
1677 SNGMSG
DB CR
,LF
,"Insert diskette for drive "
1678 DRVLET
DB "A: and strike",CR
,LF
,"any key when ready",CR
,LF
,LF
,0
1679 HNUM
DB 0 ;NUMBER OF HARDFILES
1682 ;** End of Permanently Resident BIOS
1685 HARDDRV
DB 80H
;Physical drive number of first hardfile
1686 ;**********************************************************************
1687 ; "HDRIVE" IS A HARD DISK WITH 512 BYTE SECTORS
1688 ;*********************************************************************
1691 DB 1 ;Sectors/allocation unit
1692 DW 1 ;Reserved sectors for DOS
1693 DB 2 ;No. of allocation tables
1694 DW 16 ;Number of directory entries
1695 DW 0000 ;Number of sectors (at 512 bytes each)
1696 DB 11111000B ;Media descriptor
1697 DW 1 ;Number of FAT sectors
1700 DW 00 ;Hidden sector count
1701 ;**********************************************************************
1702 ; "DRIVEX " IS AN EXTRA TYPE OF DRIVE USUALLY RESERVED FOR AN
1703 ; ADDITIONAL HARD FILE
1704 ;*********************************************************************
1707 DB 00 ;Sectors/allocation unit
1708 DW 1 ;Reserved sectors for DOS
1709 DB 2 ;No. of allocation tables
1710 DW 0000 ;Number of directory entries
1711 DW 0000 ;Number of sectors (at 512 bytes each)
1712 DB 11111000B ;Media descriptor
1713 DW 0000 ;Number of FAT sectors
1716 DW 00 ;Hidden sector count
1718 SUBTTL Bios initialization
1719 \f;*********************************************************
1720 ; SYSTEM INITIALIZATION
1722 ; THE ENTRY CONDITIONS ARE ESTABLISHED BY THE BOOTSTRAP
1723 ; LOADER AND ARE CONSIDERED UNKNOWN. THE FOLLOWING JOBS
1724 ; WILL BE PERFORMED BY THIS MODULE:
1726 ; 1. ALL DEVICE INITIALIZATION IS PERFORMED
1727 ; 2. A LOCAL STACK IS SET UP AND DS:SI ARE SET
1728 ; TO POINT TO AN INITIALIZATION TABLE. THEN
1729 ; AN INTER-SEGMENT CALL IS MADE TO THE FIRST
1731 ; 3. ONCE THE DOS RETURNS FROM THIS CALL THE DS
1732 ; REGISTER HAS BEEN SET UP TO POINT TO THE START
1733 ; OF FREE MEMORY. THE INITIALIZATION WILL THEN
1734 ; LOAD THE COMMAND PROGRAM INTO THIS AREA
1735 ; BEGINNING AT 100 HEX AND TRANSFER CONTROL TO
1738 ;********************************************************
1740 DRVFAT
DW 0000 ;DRIVE AND FAT ID OF DOS
1741 BIOS$
DW 0000 ;FIRST SECTOR OF DATA
1742 DOSCNT
DW 0000 ;HOW MANY SECTORS TO READ
1744 BootBufr EQU 17C0H
; High memory scratch area
1746 ASSUME
DS:NOTHING
,ES:NOTHING
1750 MOV SP,7C00h
;LOCAL STACK 1000:7C00
1752 PUSH CX ;Save number of floppies
1754 PUSH AX ;Save Drive info
1756 OUT AKPORT
,AL ;TURN ON THE TIMER
1758 MOV SI,OFFSET LPT3DEV
1759 CALL PRINT_INIT
;INIT LPT3
1760 MOV SI,OFFSET LPT2DEV
1761 CALL PRINT_INIT
;INIT LPT2
1762 MOV SI,OFFSET LPT1DEV
1763 CALL PRINT_INIT
;INIT LPT1
1765 MOV SI,OFFSET COM2DEV
1766 CALL AUX_INIT
;INIT COM2
1767 MOV SI,OFFSET COM1DEV
1768 CALL AUX_INIT
;INIT COM1
1769 ;* Can't do any DEBUG prints till now
1770 debug
1,1,<AUX
and PRN devices initialized
\n>,<>
1772 MOV DS,DX ;TO INITIALIZE PRINT SCREEN VECTOR
1775 MOV AX,CS ;FETCH SEGMENT
1778 MOV WORD PTR DS:BRKADR
,OFFSET
BREAK
1779 MOV DS:BRKADR
+2,AX ;VECTOR FOR BREAK
1780 MOV WORD PTR DS:(CHROUT
*4),OFFSET OUTCHR
1781 MOV DS:(CHROUT
*4+2),AX
1783 MOV WORD PTR DS:DSKADR
,SEC9
;DISK PARAMETERS
1787 MOV BX,OFFSET INTRET
; Rest just return
1791 STOSW ;INT 1 ;Location 6
1796 STOSW ;INT 3 ;Location 14
1800 STOSW ;INT 4 ;Location 18
1801 ; Set up some vectors for scheduler and change rom interrupts
1803 CLI ; Disable, changing int vectors
1804 ADD DI,3*4 ; Move up to INT 8
1805 MOV CX,OFFSET TimerInterrupt
1809 STOSW ; Set new INT 8: Timer
1811 MOV CX,DS:[DI] ; Save old addr to hook to
1812 MOV WORD PTR OldKeyInterrupt
,CX
1814 MOV WORD PTR (OldKeyInterrupt
+2),CX
1815 MOV CX,OFFSET KeyboardInterrupt
1819 STOSW ; Set new keyboard interrupt
1825 XCHG AX,BX ; INT 0A unused
1829 XCHG AX,BX ; INT 0B unused
1831 add di,4*6 ; skip 0C - 11
1832 MOV CX,DS:[DI] ; Save INT 12 addr to hook to
1833 MOV WORD PTR memsizint
,CX
1835 MOV WORD PTR (memsizint
+2),CX
1836 mov cx,offset memsizhandler
1841 add di,4*2 ; skip 13 - 14
1843 ; End of new 3.0 vectors
1845 STOSW ;INT 15 ;Location 60
1849 MOV CX,DS:[DI] ; Save INT 16 addr to hook to
1850 MOV WORD PTR OldKbdHandler
,CX
1852 MOV WORD PTR (OldKbdHandler
+2),CX
1853 MOV CX,OFFSET KeyboardHandler
1856 XCHG AX,CX ; Set new keyboard Handler
1858 ; Set new get/set time vector, time base changed
1859 ADD DI,4*3 ; skip 17 - 19
1861 ADD DI,4*4 ; skip 16 - 19
1863 MOV CX,OFFSET TimeOfDay
1865 STOSW ; setup 1A to TimeofDay
1868 ADD DI,4*23 ; skip 1B - 31
1870 STOSW ; no-op INT 32 until Sched:SchedInit
1873 debug
1,1,<Interrupt vectors initialized
\n>,<>
1875 MOV DS:WORD PTR 500H
,DX ;SET PRINT SCREEN & BREAK =0
1876 MOV DS:WORD PTR LSTDRV
,DX ;clean out last drive spec
1878 MOV DI,SEC9
;location of drive table
1879 MOV AX,02DFH ;Stuff the disk speedup/9 sector
1892 pushf ;simulate int 12h
1893 call memsizint
;Get memory size--1K blocks in AX
1895 SHL AX,CL ;Convert to 16-byte blocks(segment no.)
1896 POP CX ;Recall drive info
1897 MOV [DRVFAT
],CX ;SAVE DRIVE TO LOAD DOS
1902 ASSUME
DS:SEG SYSINIT
1906 MOV DEFAULT_DRIVE
,CL ;SAVE DEFAULT DRIVE SPEC
1909 MOV CURRENT_DOS_LOCATION
,dx ; load address of DOS
1911 MOV FINAL_DOS_LOCATION
,SEG BiosInit
1912 debug
1,2,<DOS will
load at $x
, will move to $x
\n>,<dx,FINAL_DOS_LOCATION
>
1913 MOV WORD PTR DEVICE_LIST
,OFFSET CONDEV
;DS:SI = ptr to device list
1915 MOV WORD PTR DEVICE_LIST
+2,AX
1916 ;**************************************************************
1917 ; WILL INITIALIZE THE NUMBER OF DRIVES
1918 ; AFTER THE EQUIPMENT CALL (INT 11H) BITS 6&7 WILL TELL
1919 ; THE INDICATIONS ARE AS FOLLOWS:
1926 ;**************************************************************
1932 ASSUME
DS:BiosSeg
,ES:BiosSeg
1934 INT 11H
;GET EQUIPMENT STATUS
1935 AND AL,11000000B ;MASK DRIVE BITS
1936 JNZ NOTSNGL
;Zero means single drive system
1937 INC [SINGLE
] ;REMEMBER THIS
1939 POP AX ;BOOT specifies number of floppies
1940 MOV [HARDNUM
],AL ;Remember which drive is hard disk
1941 MOV [DRVMAX
],AL ;And set initial number of drives
1944 INT 13H
;Request number of hardfiles attached
1945 JC ENDDRV
;Carry indicates old rom, so no hardfile
1949 MOV DI,OFFSET
CS:HDRIVE
1952 CALL SETHRD
;SET UP FIRST HARDFILE
1954 MOV DL,81H
;SET UP FOR NEXT CALL
1955 MOV DI,OFFSET
CS:DRIVEX
1961 NOTOK: MOV [HARDDRV
],DL
1962 MOV DI,OFFSET
CS:HDRIVE
1966 SETIT: CALL SETHRD
;SET UP SECOND HARDFILE
1970 ; End of drive initialization
1972 ITSOK: MOV AL,[HNUM
]
1978 JMP SHORT ITSOK2
;GO SET DESTINATION SEGMENT
1980 ITSOK1: CMP BYTE PTR [SINGLE
],1
1989 debug
1,1,<hardnum
/hnum $x drvfat $x
\n>,<<word ptr hnum
>,drvfat
>
1993 ASSUME
DS:BiosSeg
,ES:NOTHING
1995 CALL GETFAT
;READ IN THE FAT SECTOR
1997 MOV AL,ES:[DI] ;GET FAT ID BYTE
1998 MOV BYTE PTR DRVFAT
+1,AL ;SAVE FAT BYTE
1999 debug
1,2,< FAT ID
: $b ds:$x
\n>,<ax,ds>
2001 CALL GETBP
;GET DISK POINTER
2002 MOV CL,[DI+2] ;GET SECTORS/CLUSTER
2003 MOV AX,[DI].HIDSEC
;GET NUMBER OF HIDDEN SECTORS
2004 SUB [BIOS$
],AX ;SUBTRACT HIDDEN SECTOR OFFSET
2005 XOR CH,CH ;CX = SECTORS/CLUSTER
2010 ; THE BOOT PROGRAM HAS LEFT THE DIRECTORY AT 0:500
2012 MOV BX,DS:WORD PTR 53
AH ;GET FIRST CLUSTER OF DOS
2013 POP DS ;BX = FIRST CLUSTER OF DOS
2014 LOADIT: MOV AX,SEG SYSINIT
2016 MOV ES,AX ;ES:DI POINTS TO LOAD LOCATION
2017 CALL GETCLUS
;READ IN A CLUSTER
2019 JNZ LOADIT
;END OF FILE?
2021 EXTRN Disk_Init
:NEAR
2022 call Disk_Init
; do some device driver initialization
2023 debug
1,2,<System loaded
, going to sysinit
\n>,<>
2026 SUBTTL Routines for reading
in MSDOS
2029 ; READ A FAT SECTOR INTO 17C0:0
2031 GETFAT: debug
1,2,<GETFAT
.>,<>
2037 MOV AL,BYTE PTR DRVFAT
2041 ; READ A BOOT RECORD INTO 17C0:0
2043 GETBOOT:debug
1,2,<GETBOOT
.>,<>
2052 CMP WORD PTR ES:[1FEH
],0AA55H
2056 ; SETUP VARIABLE SIZED HARDFILE
2057 ; ON ENTRY DL=DRIVE NUMBER (80 OR 81)
2061 MOV AH,8 ;GET DRIVE PARAMETERS
2069 CALL GETBOOT
;GET THE BOOT RECORD
2072 SET1: CMP BYTE PTR ES:[BX],1
2077 SETRET: STC ;NOT FOUND SO USE DEFAULTS
2080 SET2: MOV AX,ES:[BX+4]
2081 MOV DS:[DI].HIDSEC
,AX ;SET HIDDEN SECTOR COUNT
2083 CMP AX,64 ;HAS TO BE AT LEAST 32K
2085 MOV DS:[DI].8,AX ;SAVE LOGICAL SECTOR COUNT
2086 MOV CX,0100H ;SET CLUS SIZE AND SHIFT COUNT
2087 MOV DX,64 ;SET NUMBER OF DIR ENTRIES
2106 CMP AX,32680 ;NOT 32768! MAX NUMBER OF CLUSTERS=4085
2114 ; DX=NUMBER OF DIR ENTRIES, CH=NUMBER OF SECTORS PER CLUSTER
2115 ; CL=LOG BASE 2 OF CH
2117 ; NOW CALCULATE SIZE OF FAT TABLE
2119 MOV [DI].6,DX ;SAVE NUMBER OF DIR ENTRIES
2120 MOV [DI].2,CH ;SAVE SECTORS PER CLUSTER
2125 SHR BX,CL ;DIVIDE BY SECTORS/CLUSTER
2127 AND BL,11111110B ;MAKE SURE COUNT IS EVEN
2130 ADD BX,SI ;MULTIPY BY 1.5
2133 MOV [DI].11,BH ;SAVE NUMBER OF FAT SECTORS
2137 ; READ CLUSTER SPECIFIED IN BX
2138 ; CX = SECTORS PER CLUSTER
2139 ; DI = LOAD LOCATION
2141 GETCLUS:debug
1,2,<GETCLUS
bx $x
cx $x
es:di $x
:$x
>,<bx,cx,es,di>
2144 MOV [DOSCNT
],CX ;SAVE NUMBER OF SECTORS TO READ
2148 MUL CX ;CONVERT TO LOGICAL SECTOR
2149 ADD AX,[BIOS$
] ;ADD IN FIRST DATA SECTOR
2150 MOV DX,AX ;DX = FIRST SECTOR TO READ
2152 GETCL1: CALL UNPACK
;SI = BX, BX = NEXT ALLOCATION UNIT
2154 CMP SI,-1 ;one apart?
2160 MOV AX,[DRVFAT
] ;GET DRIVE AND FAT SPEC
2162 CALL DISKRD
;READ THE CLUSTERS
2165 MOV AX,[DOSCNT
] ;GET NUMBER OF SECTORS READ
2166 XCHG AH,AL ;MULTIPLY BY 256
2167 SHL AX,1 ;TIMES 2 EQUAL 512
2168 ADD DI,AX ;UPDATE LOAD LOCATION
2169 POP CX ;RESTORE SECTORS/CLUSTER
2172 ; GET THE FAT ENTRY AT BX, WHEN FINISHED SI=ENTRY BX
2186 HAVCLUS:AND BX,0FFFH
2191 ; SI POINTS TO DEVICE HEADER
2202 MOV AL,CS:[SI+13] ;GET DEVICE NUMBER FROM THE NAME
2206 MOV AX,BX ;SET THE CALL