summaryrefslogtreecommitdiff
path: root/v4.0/src/BOOT/MSBOOT.ASM
blob: b2a410330b3ad9db3ec36df64a59f11b2636cdb2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
	Page 60,132 ;	    SCCSID = @(#)msboot.asm	    1.1 85/05/13
TITLE BOOT	SECTOR 1 OF TRACK 0 - BOOT LOADER

;   Rev 1.0 ChrisP, AaronR and others.	2.0 format boot
;
;   Rev 3.0 MarkZ   PC/AT enhancements
;		    2.50 in label
;   Rev 3.1 MarkZ   3.1 in label due to vagaries of SYSing to IBM drive D's
;		    This resulted in the BPB being off by 1.  So we now trust
;		    2.0 and 3.1 boot sectors and disbelieve 3.0.
;
;   Rev 3.2 LeeAc   Modify layout of extended BPB for >32M support
;		    Move PHYDRV to 3rd byte from end of sector
;		    so that it won't have to be moved again
;		    FORMAT and SYS count on PHYDRV being in a known location
;
;   Rev. 3.3 D.C. L. Changed Sec 9 EOT field from 15 to 18. May 29, 1986.
;
;   Rev 3.31 MarkT  The COUNT value has a bogus check (JBE????) to determine
;		    if we've loaded in all the sectors of IBMBIO. This will
;		    cause too big of a load if the sectors per track is high
;		    enough, causing either a stack overflow or the boot code
;		    to be overwritten.
;
;   Rev 4.00 J. K.  For DOS 4.00 Modified to handle the extended BPB, and
;		    32 bit sector number calculation to enable the primary
;		    partition be started beyond 32 MB boundary.
;
;
; The ROM in the IBM PC starts the boot process by performing a hardware
; initialization and a verification of all external devices.  If all goes
; well, it will then load from the boot drive the sector from track 0, head 0,
; sector 1.  This sector is placed at physical address 07C00h.	The initial
; registers are set up as follows:  CS=DS=ES=SS=0.  IP=7C00h, SP=0400H.
;
; The code in this sector is responsible for locating the MSDOS device drivers
; (IBMBIO) and for placing the directory sector with this information at
; physical address 00500h.  After loading in this sector, it reads in the
; entirety of the BIOS at BIOSEG:0 and does a long jump to that point.
;
; If no BIOS/DOS pair is found an error message is displayed and the user is
; prompted to reinsert another disk.  If there is a disk error during the
; process, a message is displayed and things are halted.
;
; At the beginning of the boot sector, there is a table which describes the
; MSDOS structure of the media.  This is equivalent to the BPB with some
; additional information describing the physical layout of the driver (heads,
; tracks, sectors)
;
;==============================================================================
;REVISION HISTORY:
;AN000 - New for DOS Version 4.00 - J.K.
;AC000 - Changed for DOS Version 4.00 - J.K.
;AN00x - PTM number for DOS Version 4.00 - J.K.
;==============================================================================
;AN001; d52 Make the fixed positioned variable "CURHD" to be local.  7/6/87 J.K.
;AN002; d48 Change head settle at boot time.			     7/7/87 J.K.
;AN003; P1820 New message SKL file				   10/20/87 J.K.
;AN004; D304 New structrue of Boot record for OS2.		   11/09/87 J.K.
;==============================================================================

ORIGIN	    EQU 7C00H			; Origin of bootstrap LOADER
BIOSEG	    EQU 70H			; destingation segment of BIOS
BioOff	    EQU 700H			; offset of bios
cbSec	    EQU 512
cbDirEnt    EQU 32
DirOff	    EQU 500h
IBMLOADSIZE equ 3			;J.K. Size of IBMLOAD module in sectors
ROM_DISKRD  equ 2
include version.inc

;
; Define the destination segment of the BIOS, including the initialization
; label
;
SEGBIOS SEGMENT AT BIOSEG
BIOS	LABEL	BYTE
SEGBIOS ENDS

CODE	SEGMENT
	ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING

;	 ORG	 DirOff + 1Ch
;BiosFS  LABEL	 WORD

	ORG	ORIGIN

DSKADR	=	1EH*4			;POINTER TO DRIVE PARAMETERS

Public $START
$START:
	JMP	START
;----------------------------------------------------------
;
;	THE FOLLOWING DATA CONFIGURES THE BOOT PROGRAM
;	FOR ANY TYPE OF DRIVE OR HARDFILE
;
;J.K. Extened_BPB

if ibmcopyright
	  DB	  "IBM  "
else
	  DB	  "MSDOS"
endif
	  DB	  "4.0"                 ;AN005;
ByteSec   DW	  cbSec 		; SIZE OF A PHYSICAL SECTOR
	  DB	  8			; SECTORS PER ALLOCATION UNIT
cSecRes   DW	  1			; NUMBER OF RESERVED SECTORS
cFat	  DB	  2			; NUMBER OF FATS
DirNum	  DW	  512			; NUMBER OF DIREC ENTRIES
cTotSec   DW	  4*17*305-1		; NUMBER OF SECTORS - NUMBER OF HIDDEN SECTORS
					;  (0 when 32 bit sector number)
MEDIA	  DB	  0F8H			; MEDIA BYTE
cSecFat   DW	  8			; NUMBER OF FAT SECTORS
SECLIM	  DW	  17			; SECTORS PER TRACK
HDLIM	  DW	  4			; NUMBER OF SURFACES
Ext_cSecHid label dword
cSecHid_L DW	  1			;AN000; NUMBER OF HIDDEN SECTORS
cSecHid_H dw	  0			;AN000; high order word of Hiden Sectors
Ext_cTotSec label dword
ctotsec_L dw	  0			;AN000; 32 bit version of NUMBER OF SECTORS
ctotsec_H dw	  0			;AN000; (when 16 bit version is zero)
;
Phydrv	  db	 80h			;AN004;
Curhd	  db	  0h			;AN004; Current Head
Ext_Boot_Sig	db    41		;AN000;
Boot_Serial	dd    0 		;AN000;
Boot_Vol_Label	db    'NO NAME    '     ;AN000;
Boot_System_id	db    'FAT12   '        ;AN000;

;J.K. Danger!!! If not 32 bit sector number calculation, FORMAT should
;set the value of cSecHid_h and Ext_cTotSec to 0 !!!
;

;
Public UDATA
UDATA	LABEL	byte
Sec9	  equ	byte ptr UDATA+0	;11 byte diskette parm. table
BIOS$_L   EQU	WORD PTR UDATA+11
BIOS$_H   equ	word ptr UDATA+13	;AN000;
CURTRK	  EQU	WORD PTR UDATA+15
CURSEC	  EQU	BYTE PTR UDATA+17
DIR$_L	  EQU	WORD PTR UDATA+18
Dir$_H	  equ	word ptr UDATA+20	;AN000;
START:

;
; First thing is to reset the stack to a better and more known place.  The ROM
; may change, but we'd like to get the stack in the correct place.
;
	CLI				;Stop interrupts till stack ok
	XOR	AX,AX
	MOV	SS,AX			;Work in stack just below this routine
	ASSUME	SS:CODE
	MOV	SP,ORIGIN
	PUSH	SS
	POP	ES
	ASSUME	ES:CODE
;
; We copy the disk parameter table into a local area.  We scan the table above
; for non-zero parameters.  Any we see get changed to their non-zero values.
;
;J.K. We copy the disk parameter table into a local area (overlayed into the
;code), and set the head settle time to 1, and End of Track to SECLIM given
;by FORMAT.

	MOV	BX,DSKADR
	LDS	SI,DWORD PTR SS:[BX]	; get address of disk table
	PUSH	DS			; save original vector for possible
	PUSH	SI			; restore
	PUSH	SS
	PUSH	BX
	MOV	DI,offset Sec9
	MOV	CX,11
	CLD
if	$ le BIOS$_L
	%OUT Don't destroy unexcuted code yet!!!
endif
	repz	movsb			;AN000;
	push	es			;AN000;
	pop	ds			;AN000; DS = ES = code = 0.
	assume	ds:code 		;AN000;
;	 mov	 byte ptr [di-2], 1	 ;AN000; Head settle time
;J.K. Change the head settle to 15 ms will slow the boot time quite a bit!!!
	mov	byte ptr [di-2], 0fh	;AN002; Head settle time
	mov	cx, SECLIM		;AN004;
	mov	byte ptr [di-7], cl	;AN000; End of Track
;
; Place in new disk parameter table vector.
;
	MOV	[BX+2],AX
	MOV	[BX],offset SEC9
;
; We may now turn interrupts back on.  Before this, there is a small window
; when a reboot command may come in when the disk parameter table is garbage
;
	STI				;Interrupts OK now
;
; Reset the disk system just in case any thing funny has happened.
;
	INT	13H			;Reset the system
;	 JC	 RERROR
	jc	CKErr			;AN000;
;
; The system is now prepared for us to begin reading.  First, determine
; logical sector numbers of the start of the directory and the start of the
; data area.

	xor	ax,ax			;AN000;
	cmp	cTotSec,ax		;AN000; 32 bit calculation?
	je	Dir_Cont		;AN000;
	mov	cx,cTotSec		;AN000;
	mov	cTotSec_L,cx		;AN000; cTotSec_L,cTotSec_H will be used for calculation
Dir_Cont:				;AN000;
	MOV	AL,cFat 		;Determine sector dir starts on
	MUL	cSecFat 		;DX;AX
	ADD	AX,cSecHid_L
	adc	DX,cSecHid_H		;AN000;
	ADD	AX,cSecRes
	ADC	DX,0
	MOV	[DIR$_L],AX		; DX;AX = cFat*cSecFat + cSecRes + cSecHid
	mov	[DIR$_H],DX		;AN000;
	MOV	[BIOS$_L],AX
	mov	[BIOS$_H],DX		;AN000;
;
; Take into account size of directory (only know number of directory entries)
;
	MOV	AX,cbDirEnt		; bytes per directory entry
	MUL	DirNum			; convert to bytes in directory
	MOV	BX,ByteSec		; add in sector size
	ADD	AX,BX
	DEC	AX			; decrement so that we round up
	DIV	BX			; convert to sector number
	ADD	[BIOS$_L],AX		; Start sector # of Data area
	adc	[BIOS$_H],0		;AN000;

;
; We load in the first directory sector and examine it to make sure the the
; BIOS and DOS are the first two directory entries.  If they are not found,
; the user is prompted to insert a new disk.  The directory sector is loaded
; into 00500h
;
	MOV	BX,DirOff		; sector to go in at 00500h
	mov	dx,[DIR$_H]		;AN000;
	MOV	AX,[DIR$_L]		; logical sector of directory
	CALL	DODIV			; convert to sector, track, head
	jc	CKErr			;AN000; Overflow? BPB must be wrong!!
;	 MOV	 AX,0201H		 ; disk read 1 sector
	mov	al, 1			;AN000; disk read 1 sector
	CALL	DOCALL			; do the disk read
	JB	CKERR			; if errors try to recover
;
; Now we scan for the presence of IBMBIO  COM and IBMDOS  COM.	Check the
; first directory entry.
;
	MOV	DI,BX
	MOV	CX,11
	MOV	SI,OFFSET BIO		; point to "ibmbio  com"
	REPZ	CMPSB			; see if the same
	JNZ	CKERR			; if not there advise the user
;
; Found the BIOS.  Check the second directory entry.
;
	LEA	DI,[BX+20h]
	MOV	SI,OFFSET DOS		; point to "ibmdos  com"
	MOV	CX,11
	REPZ	CMPSB
	JZ	DoLoad

;
; There has been some recoverable error.  Display a message and wait for a
; keystroke.
;
CKERR:	MOV	SI,OFFSET SYSMSG	; point to no system message
ErrOut: CALL	WRITE			; and write on the screen
	XOR	AH,AH			; wait for response
	INT	16H			; get character from keyboard
	POP	SI			; reset disk parameter table back to
	POP	DS			; rom
	POP	[SI]
	POP	[SI+2]
	INT	19h			; Continue in loop till good disk

Load_Failure:
	pop	ax			;adjust the stack
	pop	ax
	pop	ax
	jmp	short Ckerr		;display message and reboot.

;J.K. We don't have the following error message any more!!!
;J.K. Sysmsg is fine.  This will save space by eliminating DMSSG message.
;RERROR: MOV	 SI,OFFSET DMSSG	 ; DISK ERROR MESSAGE
;	 JMP	 ErrOut

;
; We now begin to load the BIOS in.  Compute the number of sectors needed.
; J.K. All we have to do is just read in sectors contiguously IBMLOADSIZE
; J.K. times.  We here assume that IBMLOAD module is contiguous.  Currently
; J.K. we estimate that IBMLOAD module will not be more than 3 sectors.

DoLoad:
	mov	BX,BioOff		;offset of ibmbio(IBMLOAD) to be loaded.
	mov	CX,IBMLOADSIZE		;# of sectors to read.
	mov	AX, [BIOS$_L]		;Sector number to read.
	mov	DX, [BIOS$_H]		;AN000;
Do_While:				;AN000;
	push	AX			;AN000;
	push	DX			;AN000;
	push	CX			;AN000;
	call	DODIV			;AN000; DX;AX = sector number.
	jc	Load_Failure		;AN000; Adjust stack. Show error message
	mov	al, 1			;AN000; Read 1 sector at a time.
					;This is to handle a case of media
					;when the first sector of IBMLOAD is the
					;the last sector in a track.
	call	DOCALL			;AN000; Read the sector.
	pop	CX			;AN000;
	pop	DX			;AN000;
	pop	AX			;AN000;
	jc	CkErr			;AN000; Read error?
	add	AX,1			;AN000; Next sector number.
	adc	DX,0			;AN000;
	add	BX,ByteSec		;AN000; adjust buffer address.
	loop	Do_While		;AN000;


;	 MOV	 AX,BiosFS		 ; get file size
;	 XOR	 DX,DX			 ; presume < 64K
;	 DIV	 ByteSec		 ; convert to sectors
;	 INC	 AL			 ; reading in one more can't hurt
;	 MOV	 COUNT,AL		 ; Store running count
;	 MOV	 AX,BIOS$		 ; get logical sector of beginning of BIOS
;	 MOV	 BIOSAV,AX		 ; store away for real bios later
;	 MOV	 BX,BioOff		 ; Load address from BIOSSEG
;
; Main read-in loop.
;   ES:BX points to area to read.
;   Count is the number of sectors remaining.
;   BIOS$ is the next logical sector number to read
;
;LOOPRD:
;	 MOV	 AX,BIOS$		 ; Starting sector
;	 CALL	 DODIV
;
; CurHD is the head for this next disk request
; CurTrk is the track for this next request
; CurSec is the beginning sector number for this request
;
; Compute the number of sectors that we may be able to read in a single ROM
; request.
;
;	 MOV	 AX,SECLIM
;	 SUB	 AL,CURSEC
;	 INC	 AX
;
; AX is the number of sectors that we may read.
;

;
;New code for Rev 3.31
;*****************************************************************************

;	 CMP	 COUNT,AL	   ;Is sectors we can read more than we need?
;	 JAE	 GOT_SECTORS	   ;No, it is okay
;	 MOV	 AL,COUNT	   ;Yes, only read in what is left

;GOT_SECTORS:

;*****************************************************************************
;End of change
;


;	 PUSH	 AX
;	 CALL	 DOCALL
;	 POP	 AX
;	 JB	 RERROR 		 ; If errors report and go to ROM BASIC
;	 SUB	 COUNT,AL		 ; Are we finished?
;
;Old code replaced by Rev 3.3
;********************************************************************
;	JBE	DISKOK			; Yes -- transfer control to the DOS
;********************************************************************
;New code for Rev 3.3
;

;	 JZ	 DISKOK 		 ; Yes -- transfer control to the DOS

;********************************************************************
;End of change
;
;	 ADD	 BIOS$,AX		 ; increment logical sector position
;	 MUL	 ByteSec		 ; determine next offset for read
;	 ADD	 BX,AX			 ; (BX)=(BX)+(SI)*(Bytes per sector)
;	 JMP	 LOOPRD 		 ; Get next track
;
; IBMINIT requires the following input conditions:
;
;   DL = INT 13 drive number we booted from
;   CH = media byte
;J.K.I1. BX was the First data sector on disk (0-based)
;J.K.I1. IBMBIO init routine should check if the boot record is the
;J.K.I1. extended one by looking at the extended_boot_signature.
;J.K.I1. If it is, then should us AX;BX for the starting data sector number.

DISKOK:
	MOV	CH,Media
	MOV	DL,PhyDrv
	MOV	bx,[BIOS$_L]		;AN000; J.K.I1.Get bios sector in bx
	mov	ax,[BIOS$_H]		;AN000; J.K.I1.
	JMP	FAR PTR BIOS		;CRANK UP THE DOS

WRITE:	LODSB				;GET NEXT CHARACTER
	OR	AL,AL			;clear the high bit
	JZ	ENDWR			;ERROR MESSAGE UP, JUMP TO BASIC
	MOV	AH,14			;WILL WRITE CHARACTER & ATTRIBUTE
	MOV	BX,7			;ATTRIBUTE
	INT	10H			;PRINT THE CHARACTER
	JMP	WRITE

; convert a logical sector into Track/sector/head.  AX has the logical
; sector number
; J.K. DX;AX has the sector number. Because of not enough space, we are
; going to use Simple 32 bit division here.
; Carry set if DX;AX is too big to handle.
;

DODIV:
	cmp	dx,Seclim		;AN000; To prevent overflow!!!
	jae	DivOverFlow		;AN000; Compare high word with the divisor.
	DIV	SECLIM			;AX = Total tracks, DX = sector number
	INC	DL			;Since we assume SecLim < 255 (a byte), DH =0.
					;Cursec is 1-based.
	MOV	CURSEC, DL		;save it
	XOR	DX,DX
	DIV	HDLIM
	MOV	CURHD,DL		;Also, Hdlim < 255.
	MOV	CURTRK,AX
	clc				;AN000;
	ret				;AN000;
DivOverFlow:				;AN000;
	stc				;AN000;
EndWR:
	ret

;
;J.K.We don't have space for the following full 32 bit division.
; convert a logical sector into Track/sector/head.  AX has the logical
; sector number
; J.K. DX;AX has the sector number.
;DODIV:
;	push	ax
;	mov	ax,dx
;	 xor	 dx,dx
;	 div	 SecLim
;	 mov	 Temp_H,ax
;	 pop	 ax
;	 div	 SecLim 		 ;J.K.Temp_H;AX = total tracks, DX=sector
;	 INC	 DL			 ;Since we assume SecLim < 255 (a byte), DH =0.
;					 ;Cursec is 1-based.
;	 MOV	 CURSEC, DL		 ;save it
;	 push	 ax
;	 mov	 ax,Temp_H
;	 XOR	 DX,DX
;	 DIV	 HDLIM
;	 mov	 Temp_H,ax
;	 pop	 ax
;	 div	 HdLim			 ;J.K.Temp_H;AX=total cyliners,DX=head
;	 MOV	 CURHD,DL		 ;Also, Hdlim < 255.
;	 cmp	 Temp_H,0
;	 ja	 TooBigToHandle
;	 cmp	 ax, 1024
;	 ja	 TooBigToHandle
;	 MOV	 CURTRK,AX
;ENDWR:  RET
;TooBigToHandle:
;	 stc
;	 ret

;
; Issue one read request.  ES:BX have the transfer address, AL is the number
; of sectors.
;
DOCALL: MOV	AH,ROM_DISKRD		;AC000;=2
	MOV	DX,CURTRK
	MOV	CL,6
	SHL	DH,CL
	OR	DH,CURSEC
	MOV	CX,DX
	XCHG	CH,CL
	MOV	DL, PHYDRV
	mov	dh, curhd
	INT	13H
	RET

;	 include ibmbtmes.inc
	include boot.cl1			;AN003;


	IF IBMCOPYRIGHT
BIO	DB	"IBMBIO  COM"
DOS	DB	"IBMDOS  COM"
	ELSE
BIO	DB	"IO      SYS"
DOS	DB	"MSDOS   SYS"
	ENDIF

Free	EQU (cbSec - 4) - ($-$start)		;AC000;
;Free	 EQU (cbSec - 5) - ($-$start)
if Free LT 0
    %out FATAL PROBLEM:boot sector is too large
endif

	org	origin + (cbSec - 2)		;AN004;
;	 org	 origin + (cbSec - 5)

;Warning!! Do not change the position of following unless
;Warning!! you change BOOTFORM.INC (in COMMON subdirectory) file.
;Format should set this EOT value for IBMBOOT.
;FEOT	 db	 12h			 ;AN000; set by FORMAT. AN004;Use SecLim in BPB instead.
; FORMAT and SYS count on CURHD,PHYDRV being right here
;J.K. CURHD has been deleted since it is not being used by anybody.
;CURHD	 DB	 ?			 ;AN001;Unitialized (J.K. Maybe don't need this).
;PHYDRV  db	 0			 ;AN000;moved into the header part.
; Boot sector signature
	db	55h,0aah

CODE	ENDS
	END