]> wirehaze git hosting - MS-DOS.git/blob - v4.0/src/BIOS/MSLOAD.ASM

wirehaze git hosting

MZ is back!
[MS-DOS.git] / v4.0 / src / BIOS / MSLOAD.ASM
1
2 page ,132;\ f
3 title Non-Contiguous IBMBIO Loader (MSLOAD)
4 ;==============================================================================
5 ;REVISION HISTORY:
6 ;AN000 - New for DOS Version 4.00 - J.K.
7 ;AC000 - Changed for DOS Version 4.00 - J.K.
8 ;AN00x - PTMs for DOS Version 4.00 - J.K.
9 ;==============================================================================
10 ;AN001; - P1820 New Message SKL file 10/20/87 J.K.
11 ;AN002; - D381 For SYS.COM, put the version number 01/06/88 J.K.
12 ;==============================================================================
13 ;JK, 1987 -
14 ; For DOS 4.00, MSLOAD program has been changed to allow:
15 ; 1. 32 bit calculation,
16 ; 2. Reading a FAT sector when needed, instead of reading the whole FAT
17 ; sectors at once. This will make the Boot time faster, and eliminate
18 ; the memory size limitation problem,
19 ; 3. Solving the limitation of the file size (29 KB) of IBMBIO.COM,
20 ; 4. Adding the boot error message. Show the same boot error message
21 ; and do the same behavior when the read operation of IBMBIO.COM
22 ; failes as the MSBOOT program, since MSLOAD program is the
23 ; extention of MSBOOT program.
24 ;
25
26 IF1
27 %OUT ASSEMBLING: Non-Contiguous IBMBIO Loader (MSLOAD)
28 %OUT
29
30 ENDIF
31
32
33 DSKADR = 1Eh * 4 ;ROM bios diskette table vector position
34
35 bootseg segment at 0h
36
37
38 org 7C00h
39 Boot_Sector label byte
40 bootseg ends
41
42
43 dosloadseg segment at 70h
44 org 00h
45 IBMBIO_Address label byte
46
47 dosloadseg ends
48
49
50 cseg segment public para 'code'
51 assume cs:cseg,ds:nothing,es:nothing,ss:nothing
52
53 include MSload.inc
54 include Bootform.inc ;AN000; Extended bpb, boot record defintion.
55 include versiona.inc ;AN001; Version number for SYS.COM
56
57 sec9 equ 522h ;;** 8/3/87 DCL
58
59 BIOOFF equ 700h
60 ;
61 org 0h
62
63 start:
64 jmp Save_Input_Values
65 SYS_Version dw EXPECTED_VERSION ;AN001; From VERSIONA.INC file
66 Mystacks dw 64 dup (0) ;AN000; local stack
67 MyStack_ptr label word
68
69 ;local data
70 Number_Of_Heads dw 0
71 Size_Cluster dw 0
72 Start_Sector_L dw 0
73 Start_Sector_H dw 0 ;J.K.
74 Temp_H dw 0 ;J.K. For 32 bit calculation
75 Temp_Cluster dw 0 ;J.K. Temporary place for cluster number
76 Last_Fat_SecNum dw -1 ;Fat sector number starting from the first fat entry.
77 Sector_Count dw 0
78 Number_Of_FAT_Sectors dw 0
79 Hidden_Sectors_L dw 0
80 Hidden_Sectors_H dw 0 ;J.K.
81 Sector_Size dw 0
82 Reserved_Sectors dw 0
83 Last_Found_Cluster dw 0
84 Next_BIO_Location dw 0
85 First_Sector_L dw 0
86 First_Sector_H dw 0 ;J.K.
87 Drive_Lim_L dw 0 ;J.K. Max. number of sectors
88 Drive_Lim_H dw 0 ;J.K.
89 Sectors_Per_Track dw 0
90 Drive_Number db 0
91 FAT_Size db 0
92 Media_Byte db 0
93 EOF db 0
94 Org_Rom_Disktable dd 0
95 FAT_Segment dw 0
96 Sectors_Per_Cluster db 0
97
98 subttl Save Input Values
99 page
100 ;***********************************************************************
101 ; Save_Input_Values
102 ;***********************************************************************
103 ;
104 ; Input: none
105 ;
106 ; DL = INT 13 drive number we booted from
107 ; CH = media byte
108 ; BX = First data sector (low) on disk (0-based)
109 ; DS:SI = Original ROM BIOS DISKETTE Parameter table.
110 ;J.K. 6/2/87 If an extended Boot Record, then AX will be the First data sector
111 ;J.K. high word. Save AX and set First_Sector_H according to AX if it is an
112 ;J.K. extended boot record.
113 ; AX = First data sector (High) on disk ;
114 ; Output:
115 ;
116 ; BX = first data sector on disk
117 ;
118 ; Media_Byte = input CH
119 ; Drive_Number = input DL
120 ; First_Sector_L = input BX
121 ; First_Sector_H = input AX, if an extended Boot record.;J.K.
122 ; Drive_Lim_L = maximum sector number in this media ;J.K.
123 ; Drive_Lim_H = high word of the above
124 ; Hidden_Sectors_L = hidden secotrs
125 ; Hidden_Sectors_H
126 ; Reserved_Sectors = reserved sectors
127 ; Sectors_Per_Track = Sectors/track
128 ; Number_Of_Heads = heads/cylinder
129 ;
130 ; DS = 0
131 ; AX,DX,SI destroyed
132 ;
133 ; Calls: none
134 ;-----------------------------------------------------------------------
135 ;Function:
136 ; Save input information and BPB informations from the boot record.
137 ;
138 ;----------------------------------------------------------------------
139 Save_Input_Values:
140
141
142 mov First_Sector_L,bx ;AC000;
143 mov media_Byte,ch
144 mov Drive_Number,dl
145 mov word ptr Org_Rom_Disktable, si
146 push ds
147 pop word ptr Org_Rom_Disktable+2
148 xor cx,cx ;Segment 0
149 mov ds,cx
150 assume ds:Bootseg
151
152 push es ;;** DCL 8/3/87
153 mov es,cx ;;** DCL 8/3/87
154 assume es:Bootseg ;;** DCL 8/3/87
155
156 MOV SI,WORD PTR DS:DSKADR ; ARR 2.41
157 MOV DS,WORD PTR DS:DSKADR+2 ; DS:SI -> CURRENT TABLE ARR 2.41
158
159 MOV DI,SEC9 ; ES:DI -> NEW TABLE ARR 2.41
160 MOV CX,11 ; taken from ibmboot.asm ARR 2.41
161 CLD ;
162 REP MOVSB ; COPY TABLE ARR 2.41
163 PUSH ES ; ARR 2.41
164 POP DS ; DS = 0 ARR 2.41
165
166 MOV WORD PTR DS:DSKADR,SEC9 ; ARR 2.41
167 MOV WORD PTR DS:DSKADR+2,DS ; POINT DISK PARM VECTOR TO NEW TABLE
168 pop es ;;** DCL 8/3/87
169 assume es:nothing
170
171 mov cx,Boot_Sector.EXT_BOOT_BPB.EBPB_BYTESPERSECTOR ;AN000;
172 mov cs:Sector_Size, cx ;AN000;
173 mov cl,Boot_Sector.EXT_BOOT_BPB.EBPB_SECTORSPERCLUSTER ;AN000;
174 mov cs:Sectors_Per_Cluster, cl ;AN000;
175 mov cx,Boot_Sector.EXT_BOOT_BPB.EBPB_SECTORSPERTRACK ;Get Sectors per track
176 mov cs:Sectors_Per_Track,cx
177 mov cx,Boot_Sector.EXT_BOOT_BPB.EBPB_HEADS ;Get BPB heads per cylinder
178 mov cs:Number_Of_Heads,cx
179 mov cx,Boot_Sector.EXT_BOOT_BPB.EBPB_SECTORSPERFAT ;Get sectors per FAT
180 mov cs:Number_Of_FAT_Sectors,cx
181 mov cx,Boot_Sector.EXT_BOOT_BPB.EBPB_RESERVEDSECTORS ;Get Reserved Sectors
182 mov cs:Reserved_Sectors,cx
183 mov cx,word ptr Boot_Sector.EXT_BOOT_BPB.EBPB_HIDDENSECTOR ;Get hidden sectors
184 mov cs:Hidden_Sectors_L,cx
185 mov cx, Boot_Sector.EXT_BOOT_BPB.EBPB_TOTALSECTORS ;AN000;
186 mov cs:Drive_Lim_L, cx ;AN000;
187
188 ;J.K. First of all, check if it the boot record is an extended one.
189 ;J.K. This is just a safe guard in case some user just "copy" the 4.00 IBMBIO.COM
190 ;J.K. to a media with a conventional boot record.
191
192 cmp Boot_Sector.EXT_BOOT_SIG, EXT_BOOT_SIGNATURE ;AN000;
193 jne Relocate ;AN000;
194 mov cs:First_Sector_H, AX ;AN000; start data sector (high)
195 mov ax,word ptr Boot_Sector.EXT_BOOT_BPB.EBPB_HIDDENSECTOR+2 ;AN000;
196 mov cs:Hidden_Sectors_H,ax ;AN000;
197 cmp cx, 0 ;AN000; CX set already before (=Totalsectors)
198 jne Relocate ;AN000;
199 mov ax, word ptr Boot_Sector.EXT_BOOT_BPB.EBPB_BIGTOTALSECTORS ;AN000;
200 mov cs:Drive_Lim_L, ax ;AN000;
201 mov ax, word ptr Boot_Sector.EXT_BOOT_BPB.EBPB_BIGTOTALSECTORS+2 ;AN000;
202 mov cs:Drive_Lim_H, ax ;AN000;
203 subttl Relocate
204 page
205 ;
206 ;***********************************************************************
207 ; RELOCATE
208 ;***********************************************************************
209 ;
210 ; Notes:
211 ;
212 ; Relocate the loader code to top-of-memory.
213 ;
214 ; Input: none
215 ;
216 ; Output: Code and data relocated.
217 ; ax,cx,si,di destroyed
218 ;
219 ; Calls: none
220 ;-----------------------------------------------------------------------
221 ; Copy code from Start to Top of memory.
222 ;
223 ; The length to copy is Total_length
224 ;
225 ; Jump to relocated code
226 ;-----------------------------------------------------------------------
227 ;
228 Relocate:
229 assume ds:nothing
230 cld ;AN000;
231 xor si,si ;AN000;
232 mov di,si ;AN000;
233 ;SB34LOAD000****************************************************************
234 ;SB Determine the number of paragraphs (16 byte blocks) of memory.
235 ;SB This involves invoking the memory size determination interrupt,
236 ;SB which returns the number of 1K blocks of memory, and then
237 ;SB converting this to the number of paragraphs.
238 ;SB Leave the number of paragraphs of memory in AX.
239
240 int 12h ;get system memory size in Kbytes
241 mov cl,6 ;
242 shl ax,cl ;memory size in paragraphs
243 ;SB34LOAD000****************************************************************
244 mov cl,4 ;AN000;
245 mov dx, cs:Sector_Size ;AN000;
246 shr dx,cl ;AN000;
247 inc dx ;AN000;
248 sub ax, dx ;AN000;
249 mov cs:Fat_Segment, ax ;AN000;This will be used for FAT sector
250 mov dx, offset total_length ;AN000;
251 shr dx, cl ;AN000;
252 inc dx ;AN000;
253 sub ax, dx ;AN000;
254 mov es, ax ;AN000;es:di -> place be relocated.
255 push cs ;AN000;
256 pop ds ;AN000;ds:si -> source
257 mov cx, offset total_length ;AN000;
258 rep movsb ;AN000;
259
260 push es ;AN000;
261 mov ax, offset Setup_stack ;AN000;
262 push ax ;AN000;massage stack for destination of cs:ip
263 Dumbbb proc far ;AN000;
264 ret ;AN000;
265 Dumbbb endp ;AN000;
266
267
268 ; push cs ;Set up ds segreg
269 ; pop ds
270 ; xor ax,ax ;Set up ES segreg
271 ; mov es,ax
272 ;
273 ; assume es:bootseg,ds:cseg
274 ;
275 ; mov si,offset Start ;Source
276 ; mov di,offset Relocate_Start ;Target
277 ; mov cx,Relocate_Length ;Length
278 ; rep movsb ;Go do it
279 ; jmp far ptr Relocate_Start
280
281
282
283 subttl Setup Stack
284 page
285 ;***********************************************************************
286 ; Setup_Stack
287 ;***********************************************************************
288 ;
289 ; Input: none
290 ;
291 ; Output:
292 ;
293 ; SS:SP set
294 ; AX destroyed
295 ;-----------------------------------------------------------------------
296 ; First thing is to reset the stack to a better and more known place.
297 ;
298 ; Move the stack to just under the boot record and relocation area (0:7C00h)
299 ;
300 ; Preserve all other registers
301 ;----------------------------------------------------------------------
302
303 Setup_Stack:
304 assume ds:nothing, es:nothing, ss:nothing
305 ; CLI ;Stop interrupts till stack ok
306 mov ax,cs
307 MOV SS,AX ;Set up the stack to the known area.
308 mov sp, offset MyStack_Ptr
309 ; MOV SP,7C00h - 50 ;Leave room for stack frame
310 ; MOV BP,7C00h - 50 ;Point BP as stack index pointer
311 ; STI
312
313 subttl Find_Cluster_Size
314 page
315 ;***********************************************************************
316 ; Find_Cluster_Size
317 ;***********************************************************************
318 ;
319 ; Input: BPB information in loaded boot record at 0:7C00h
320 ;
321 ; Output:
322 ;
323 ; DS = 0
324 ; AX = Bytes/Cluster
325 ; BX = Sectors/Cluster
326 ; SI destroyed
327 ; Calls: none
328 ;-----------------------------------------------------------------------
329 ;
330 ; Get Bytes/sector from BPB
331 ;
332 ; Get sectors/cluster from BPB
333 ;
334 ; Bytes/cluster = Bytes/sector * sector/cluster
335 ;----------------------------------------------------------------------
336 Find_Cluster_Size:
337
338 ;For the time being just assume the boot record is valid and the BPB
339 ;is there.
340
341 xor ax,ax ;Segment 0
342 mov ds,ax
343
344 assume ds:bootseg
345
346 mov ax,Boot_Sector.EXT_BOOT_BPB.EBPB_BYTESPERSECTOR ;AC000;Get BPB bytes/sector
347 xor bx,bx
348 mov bl,Boot_Sector.EXT_BOOT_BPB.EBPB_SECTORSPERCLUSTER ;AC000;Get sectors/cluster
349 mul bx ;Bytes/cluster
350 mov cs:Size_Cluster,ax ;Save it
351
352
353 subttl Determine FAT size
354 page
355 ;***********************************************************************
356 ; Determine_FAT_Size
357 ;***********************************************************************
358 ;
359 ; Notes:
360 ;
361 ; Determine if FAT is 12 or 16 bit FAT. 12 bit FAT if floppy, read MBR
362 ; to find out what system id byte is.
363 ;
364 ; Input:
365 ;
366 ; Output:
367 ;
368 ; cs:Fat_Size = FAT12_bit or FAT16_bit
369 ; All other registers destroyed
370 ;
371 ;----------------------------------------------------------------------
372 Determine_FAT_Size:
373 mov cs:FAT_Size,FAT12_bit ;AN000;Assume 12 bit fat
374 mov dx, cs:Drive_Lim_H ;AN000;
375 mov ax, cs:Drive_Lim_L ;AN000;
376 sub ax, cs:Reserved_Sectors ;AN000;
377 sbb dx, 0 ;AN000;now, dx;ax = available total sectors
378 mov bx, cs:Number_Of_FAT_Sectors ;AN000;
379 shl bx, 1 ;AN000;2 FATs
380 sub ax, bx ;AN000;
381 sbb dx, 0 ;AN000;now, dx;ax = tatal sectors - fat sectors
382 mov bx, Boot_Sector.EXT_BOOT_BPB.EBPB_ROOTENTRIES ;AN000;
383 mov cl, 4 ;AN000;
384 shr bx, cl ;AN000;Sectors for dir entries = dir entries / Num_DIR_Sector
385 sub ax, bx ;AN000;
386 sbb dx, 0 ;AN000;
387 xor cx, cx ;AN000;
388 mov cl, Boot_Sector.EXT_BOOT_BPB.EBPB_SECTORSPERCLUSTER ;AN000;
389 push ax ;AN000;
390 mov ax, dx ;AN000;
391 xor dx, dx ;AN000;
392 div cx ;AN000;
393 mov cs:Temp_H, ax ;AN000;
394 pop ax ;AN000;
395 ;J.K. We assume that cx > dx.
396 div cx ;AN000;
397 cmp ax, 4096-10 ;AN000;
398 ; jb Determine_First_Cluster ;AN000;
399 jb Read_In_FirstClusters
400 mov cs:FAT_Size, FAT16_Bit ;AN000;16 bit fat
401
402 ; cmp cs:Media_Byte,0F8h ;Is it floppy
403 ; jne FAT_Size_Found ;Yep, all set
404 ; mov cs:Logical_Sector,0 ;Got hardfile, go get MBR
405 ; xor ax,ax
406 ; mov es,ax
407 ; mov di,offset Relocate_Start
408 ; mov cs:Sector_Count,1
409 ; call Disk_Read
410 ; mov si,offset Relocate_Start+1C2h
411 ; mov cx,4
412 ; xor ax,ax
413 ; mov ds,ax
414 ;Find_Sys_Id:
415 ; mov cs:FAT_Size,FAT12_bit ;Assume 12 bit fat
416 ; cmp byte ptr [si],1
417 ; je FAT_Size_Found
418 ; mov cs:FAT_Size,FAT16_bit ;Assume 12 bit fat
419 ; cmp byte ptr [si],4
420 ; je Fat_Size_Found
421 ; add si,16
422 ; loop Find_Sys_Id
423 ; ;xxxxxxxxxxxxxxxxxxxxxxxxxx error
424 ;FAT_Size_Found:
425
426
427 subttl Read_In_FirstClusters
428 page
429 ;***********************************************************************
430 ; Read_In_FirstClusters
431 ;***********************************************************************
432 ;
433 ; Notes: Read the start of the clusters that covers at least IBMLOADSIZE
434 ; fully. For example, if sector/cluster = 2, and IBMLOADSIZE=3
435 ; then we are going to re-read the second cluster to fully cover
436 ; MSLOAD program in the cluster boundary.
437 ;
438 ; Input:
439 ; IBMLOADSIZE - Make sure this value is the same as the one in
440 ; MSBOOT program when you build the new version!!!!!
441 ;
442 ; Sectors_Per_Cluster
443 ; Size_Cluster
444 ; First_Sector_L
445 ; First_Sector_H
446 ;
447 ; Output: MSLOAD program is fully covered in a cluster boundary.
448 ; AX = # of clusters we read in so far.
449 ;
450 ; Calls: Disk_Read
451 ; Logic:
452 ; AX; DX = IBMLOADSIZE / # of sector in a cluster.
453 ; if DX = 0 then Ok. (MSLOAD is in a cluster boundary.)
454 ; else (Has to read (AX+1)th cluster to cover MSLOAD)
455 ; read (AX+1)th cluster into the address after the clusters we
456 ; read in so far.
457 ;-----------------------------------------------------------------------
458
459 Read_In_FirstClusters:
460 mov ax, IBMLOADSIZE ;AN000;
461 div cs:Sectors_Per_Cluster ;AN000;
462 cmp ah, 0 ;AN000;
463 je Set_Next_Cluster_Number ;AN000;
464 xor ah, ah ;AN000;
465 push ax ;AN000;
466 mov cx, cs:First_Sector_L ;AN000;
467 mov cs:Start_Sector_L, cx ;AN000;
468 mov cx, cs:First_Sector_H ;AN000;
469 mov cs:Start_Sector_H, cx ;AN000;
470 mul cs:Sectors_Per_Cluster ;AN000; Now, AX=# of sectors
471 add cs:Start_Sector_L, ax ;AN000;
472 adc cs:Start_Sector_H, 0 ;AN000;
473 pop ax ;AN000;
474 push ax ;AN000;
475 mov di, BIOOFF ;AN000;
476 mul cs:Size_Cluster ;AN000;AX = # of bytes read in before this cluster
477 add di, ax ;AN000;
478 xor ax, ax ;AN000;
479 mov es, ax ;AN000;
480 mov al, cs:Sectors_Per_Cluster ;AN000;
481 mov cs:Sector_Count, ax ;AN000;
482 call Disk_Read ;AN000;
483 pop ax ;AN000;
484 inc ax ;AN000;# of clusters read in so far.
485
486 subttl Set_Next_Cluster_Number
487 page
488 ;***********************************************************************
489 ; Set_Next_Cluster_Number
490 ;***********************************************************************
491 ;
492 ; Notes: Set LAST_Found_Cluster for the next use.
493 ; Last_Found_Cluster is the cluster number we are in now.
494 ; Since cluster number is 0 based and there are 2 clusters int
495 ; the beginning of FAT table used by the system, we just add
496 ; 1 to set Last_Found_Cluster.
497 ;
498 ; Input:
499 ; AX = # of clusters read in so far.
500 ;
501 ; Output:
502 ;
503 ; cs:Last_Found_Cluster
504 ;
505 ; Calls: none
506 ;------------------------------------------------------------------
507 Set_Next_Cluster_Number:
508 inc ax ;AN000; For Last_Found_Cluster
509 mov cs:Last_Found_Cluster,ax ;2 is the first data cluster number(0 based)
510
511 subttl Read In FAT
512 page
513 ;***********************************************************************
514 ; Read_In_FAT
515 ;***********************************************************************
516 ;
517 ; Notes:
518 ;
519 ; Reads in the entire FAT at 800:0. This gives the relocated portion
520 ; of this loader a maximum size of 768 bytes (8000 - 7D00).
521 ; With 64 KB memory system, this can support maximum size of FAT to
522 ; be 32 KB. We assumes that the system memory size be 128 KB, if
523 ; the system has a big media with the total fat size bigger than
524 ; 32 KB.
525 ;
526 ; Input: none
527 ;
528 ; Output:
529 ;
530 ; ES = 0
531 ; All sectors destroyed
532 ;
533 ; Calls: READ DISK
534 ;-----------------------------------------------------------------------
535 ; Get number of sectors in FAT
536 ;
537 ; Set ES:DI to 800:0
538 ;
539 ; Read in the sectors
540 ;
541 ;----------------------------------------------------------------------
542 ;Read_In_FAT:
543 ; mov ax,cs:Number_Of_FAT_Sectors ;Get sectors/FAT
544 ; mov cs:Sector_Count,ax ;Number of sectors to read
545 ; mov ax,cs:Hidden_Sectors_L ;Hidden+Reserved = start of FAT sector
546 ; mov dx,cs:Hidden_Sectors_H ;AN000;
547 ; add ax,cs:Reserved_Sectors
548 ; adc dx, 0
549 ; mov cs:Start_Sector_L,ax ;AC000;Save it, setup for disk read
550 ; mov cs:Start_Sector_H,dx ;AN000;
551 ; mov di, 800h ;AC000;
552 ; mov es, di ;AC000;
553 ; xor di, di ;AC000;
554 ; assume es:nothing
555 ; call Disk_Read
556 ;
557 subttl Keep Loaded BIO
558 page
559 ;***********************************************************************
560 ; KEEP LOADED BIO
561 ;***********************************************************************
562 ;
563 ; Notes:
564 ;
565 ; Determine how much of IBMBIO was loaded in when the loader was loaded
566 ; by the boot record (only the portion that is guaranteed to be contiguous)
567 ;
568 ; Input:
569 ;
570 ; cs:Last_Found_Cluster = number of clusters used for loader+2
571 ;
572 ; Output:
573 ; ES=70h
574 ; DI = Next offset to load IBMBIO code
575 ; AX,BX,CX,DX,SI destroyed
576 ;
577 ; cs:Next_BIO_Location = DI on output
578 ; cs:Last_Cluster = last cluster loaded
579 ;
580 ; Calls: none
581 ;-----------------------------------------------------------------------
582 ;Number of clusters loaded+2 is in cs:Last_Found_Cluster
583 ;
584 ;Multiply cluster * cluster size in bytes to get total loaded for MSLOAD
585 ;
586 ;Subtract TOTAL_LOADED - LOADBIO_SIZE to get loaded IBMBIO in last cluster
587 ;
588 ;Relocate this piece of IBMBIO down to 70:0
589 ;
590 ;----------------------------------------------------------------------
591 Keep_Loaded_BIO:
592 push ds
593 mov ax,cs:Last_Found_Cluster ;Point to last cluster loaded
594 sub ax,1 ;Get number of clusters loaded
595 mul cs:Size_Cluster ;Get total bytes loaded by
596 ;This is always < 64k, so
597 ;lower 16 bits ok
598 sub ax,LoadBio_Size ;Get portion of IBMBIO loaded
599 mov cx,ax ;Save length to move
600 mov ax,70h ;Segment at 70h
601 mov ds,ax
602 mov es,ax
603 mov si,offset Total_Length ;Point at IBMBIO
604 mov di,0 ;Point at 70:0
605 rep movsb ;Relocate this code
606 mov cs:Next_Bio_Location,di ;Save where to load next
607 pop ds
608
609 subttl Get Contiguous Clusters
610 page
611 ;***********************************************************************
612 ; Get_Contiguous_Clusters
613 ;***********************************************************************
614 ;
615 ; Notes: Go find clusters as long as they are contiguous
616 ;
617 ;
618 ; Input:
619 ;
620 ; cs:Next_BIO_Location
621 ; cs:
622 ;
623 ;
624 ; Output:
625 ;
626 ;
627 ; Calls: Get_Next_FAT_Entry
628 ;-----------------------------------------------------------------------
629 ;
630 ;Set cs:Sector_Count to Sectors per cluster
631 ;
632 ;Call Get_Next_FAT_Entry to get next cluster in file
633 ;
634 ;Call Check_for_EOF
635 ;
636 ;IF (NC returned)
637 ;
638 ; {Call Get_Next_FAT_Entry
639 ;
640 ; IF (New cluster is contig to old cluster)
641 ; {Add sectors per cluster to cs:Sector_Count
642 ;
643 ; Call Check_For_EOF
644 ;
645 ; IF (NC returned)
646 ;
647 ;
648 ;----------------------------------------------------------------------
649 Get_Contiguous_Cluster:
650 xor ah,ah
651 mov al,cs:Sectors_Per_Cluster ;Assume we will get one cluster
652 mov cs:Sector_Count,ax
653 push cs:Sector_Count
654 call Get_Next_Fat_Entry ;Go get it in AX
655 pop cs:Sector_Count
656 mov cs:Last_Found_Cluster,ax ;Update the last one found
657 cmp cs:EOF,END_OF_FILE
658 je GO_IBMBIO
659
660 ; je GOTO_IBMBIO
661 ;Got_Contig_Clusters:
662
663 xor dx,dx ;AN000;
664 sub ax,2 ;Zero base the cluster
665 xor ch,ch
666 mov cl,cs:Sectors_Per_Cluster ;Get sectors per cluster
667 mul cx ;Get how many
668 add ax,cs:First_Sector_L ;AC000;See where the data sector starts
669 adc dx,cs:First_Sector_H ;AN000;
670 mov cs:Start_Sector_L,ax ;AC000;Save it
671 mov cs:Start_Sector_H,dx ;AN000;
672 mov di,cs:Next_Bio_Location ;Get where to put code
673 push cs:Sector_Count ;Save how many sectors
674 mov ax,dosloadseg ;Get area to load code
675 mov es,ax
676 call Disk_Read
677 pop ax ;Get back total sectors read in
678 ; jc ##########
679 mul cs:Sector_Size ;AC000;Get number of bytes we loaded
680 ; mul Boot_Sector.ByteSec
681 add cs:Next_Bio_Location,ax ;Point to where to load next
682 jmp Get_Contiguous_Cluster
683
684 subttl GOTO IBMBIO
685 page
686 ;***********************************************************************
687 ; GOTO_IBMBIO
688 ;***********************************************************************
689 ;
690 ; Notes:
691 ;
692 ; Set up required registers for IBMBIO, then jump to it (70:0)
693 ;
694 ; Input: none
695 ;
696 ; cs:Media_Byte = media byte
697 ; cs:Drive_Number = INT 13 drive number we booted from
698 ; cs:First_Sector_L = First data sector on disk (Low) (0-based)
699 ; cs:First_Sector_H = First data sector on disk (High)
700 ;
701 ; Output:
702 ;
703 ; Required by MSINIT
704 ; DL = INT 13 drive number we booted from
705 ; CH = media byte
706 ; BX = First data sector on disk (0-based)
707 ; AX = First data sector on disk (High)
708 ; DI = Sectors/FAT for the boot media.
709 ;
710 ; Calls: none
711 ;-----------------------------------------------------------------------
712 ;
713 ; Set up registers for MSINIT then do Far Jmp
714 ;
715 ;----------------------------------------------------------------------
716 GO_IBMBIO:
717 mov ch,cs:Media_Byte ;Restore regs required for MSINT
718 mov dl,cs:Drive_Number ;Physical Drive number we booted from.
719 mov bx,cs:First_Sector_L ;AC000;
720 mov ax,cs:First_Sector_H ;AN000; AX will be the First data sector (High)
721 ;J.K. Don't need this information any more.
722 ; mov di,cs:Number_Of_FAT_Sectors ;AN000
723 jmp far ptr IBMBIO_Address
724
725
726 subttl Disk Read
727 page
728 ;***********************************************************************
729 ; Disk_Read
730 ;***********************************************************************
731 ;
732 ; Notes:
733 ;
734 ; Read in the cs:Sector_Count number of sectors at ES:DI
735 ;
736 ;
737 ; Input: none
738 ;
739 ; DI = Offset of start of read
740 ; ES = Segment of read
741 ; cs:Sector_Count = number of sectors to read
742 ; cs:Start_sector_L = starting sector (Low)
743 ; cs:Start_sector_H = starting sector (High)
744 ; Following is BPB info that must be setup prior to call
745 ; cs:Number_Of_Heads
746 ; cs:Number_Of_Sectors
747 ; cs:Drive_Number
748 ; cs:Sectors_Per_Track
749 ;
750 ; Output:
751 ;
752 ; AX,BX,CX,DX,SI,DI destroyed
753 ;-----------------------------------------------------------------------
754 ; Divide start sector by sectors per track
755 ; The remainder is the actual sector number, 0 based
756 ;
757 ; Increment actual sector number to get 1 based
758 ;
759 ; The quotient is the number of tracks - divide by heads to get the cyl
760 ;
761 ; The remainder is actual head, the quotient is cylinder
762 ;
763 ; Figure the number of sectors in that track, set AL to this
764 ;
765 ; Do the read
766 ;
767 ; If Error, Do RESET, then redo the INT 13h
768 ;
769 ; If successful read, Subtract # sectors read from Sector_Count, Add to Logical
770 ; Sector, add #sectors read * Sector_Size to BX;
771 ;
772 ; If Sector_Count <> 0 Do next read
773 ;----------------------------------------------------------------------
774 Disk_Read:
775
776 ;
777 ; convert a logical sector into Track/sector/head. AX has the logical
778 ; sector number
779 ;
780 DODIV:
781 MOV cx,5 ;5 retries
782
783 Try_Read:
784 PUSH cx ;Save it
785 MOV AX,cs:Start_Sector_L ;AC000; Get starting sector
786 mov dx, cs:Start_Sector_H ;AN000;
787 ; XOR DX,DX
788 push ax ;AN000;
789 mov ax, dx ;AN000;
790 xor dx, dx ;AN000;
791 DIV word ptr cs:Sectors_Per_Track
792 mov cs:Temp_H, ax ;AN000;
793 pop ax ;AN000;
794 div word ptr cs:Sectors_Per_Track ;AN000;[temp_h];AX = track, DX = sector number
795 MOV bx,cs:Sectors_Per_Track ;Get number of sectors we can read in
796 sub bx,dx ;this track
797 mov si,bx
798 cmp cs:Sector_Count,si ;Is possible sectors in track more
799 jae Got_Length ;than what we need to read?
800 mov si,cs:Sector_Count ;Yes, only read what we need to
801 Got_Length:
802 INC DL ; sector numbers are 1-based
803 MOV bl,dl ;Start sector in DL
804 mov dx, cs:Temp_H ;AN000;now, dx;ax = track
805 ; XOR DX, DX
806 push ax ;AN000;
807 mov ax, dx ;AN000;
808 xor dx, dx ;AN000;
809 DIV word ptr cs:Number_Of_Heads ;Start cyl in ax,head in DL
810 mov cs:Temp_h, ax ;AN000;
811 pop ax ;AN000;
812 div word ptr cs:Number_of_Heads ;AN000;now [temp_h];AX = cyliner, dx = head
813 ;J.K. At this moment, we assume that Temp_h = 0, AX <= 1024, DX <= 255
814 MOV DH,DL
815 ;
816 ; Issue one read request. ES:BX have the transfer address, AL is the number
817 ; of sectors.
818 ;
819 MOV CL,6
820 SHL AH,CL ;Shift cyl high bits up
821 OR AH,BL ;Mix in with sector bits
822 MOV CH,AL ;Setup Cyl low
823 MOV CL,AH ;Setup Cyl/high - Sector
824 mov bx,di ;Get back offset
825 MOV DL,cs:Drive_Number ;Get drive
826 mov ax,si ;Get number of sectors to read (AL)
827
828 MOV AH,2 ;Read
829 push ax ;Save length of read
830 push di
831 ; Issue one read request. ES:BX have the transfer address, AL is the number
832 ; of sectors.
833 INT 13H
834 pop di
835 pop ax
836 pop cx ;Get retry count back
837 jnc Read_OK
838 mov bx,di ;Get offset
839 xor ah,ah
840 push cx
841 mov dl,cs:Drive_Number
842 push di
843 int 13h
844 pop di
845 pop cx
846 ; loop Try_Read ;AC000;
847 ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx error
848 dec cx ;AN000;
849 jz Read_Error ;AN000;
850 jmp Try_Read ;AN000;
851 Read_Error: ;AN000;
852 jmp ErrorOut ;AN000;
853
854 Read_OK:
855 xor ah,ah ;Mask out read command, just get # read
856 sub cs:Sector_Count,ax ;Bump number down
857 jz Read_Finished
858 add cs:Start_Sector_L,ax ;AC000;Where to start next time
859 adc cs:Start_Sector_H, 0 ;AN000;
860 xor bx,bx ;Get number sectors read
861 mov bl,al
862 mov ax,cs:Sector_Size ;Bytes per sector
863 mul bx ;Get total bytes read
864 add di,ax ;Add it to offset
865 jmp DODIV
866 Read_Finished:
867 RET
868
869 subttl GET NEXT FAT ENTRY
870 page
871 ;***********************************************************************
872 ; GET_NEXT_FAT_ENTRY
873 ;***********************************************************************
874 ;
875 ; Notes:
876 ;
877 ; Given the last cluster found, this will return the next cluster of
878 ; IBMBIO. If the last cluster is (F)FF8 - (F)FFF, then the final cluster
879 ; of IBMBIO has been loaded, and control is passed to GOTO_IBMBIO
880 ; MSLOAD can handle maximum FAT area size of 64 KB.
881 ;
882 ; Input:
883 ;
884 ; cs:Last_Found_Cluster
885 ; cs:Fat_Size
886 ;
887 ; Output:
888 ;
889 ; cs:Last_Found_Cluster (updated)
890 ;
891 ; Calls: Get_Fat_Sector
892 ;-----------------------------------------------------------------------
893 ; Get Last_Found_Cluster
894 ;
895 ; IF (16 bit FAT)
896 ; {IF (Last_Found_Cluster = FFF8 - FFFF)
897 ; {JMP GOTO_IBMBIO}
898 ; ELSE
899 ; {Get offset by multiply cluster by 2}
900 ;
901 ; ELSE
902 ; {IF (Last_Found_Cluster = FF8 - FFF)
903 ; {JMP GOTO_IBMBIO}
904 ; ELSE
905 ; {Get offset by - multiply cluster by 3
906 ;
907 ; Rotate right to divide by 2
908 ;
909 ; IF (CY set - means odd number)
910 ; {SHR 4 times to keep high twelve bits}
911 ;
912 ; ELSE
913 ; {AND with 0FFFh to keep low 12 bits}
914 ; }
915 ; }
916 ;
917 ;
918 ;----------------------------------------------------------------------
919 Get_Next_FAT_Entry:
920
921 push es ;AN000;
922 mov ax, cs:FAT_Segment ;AN000;
923 mov es, ax ;AN000; es-> Fat area segment
924 assume es:nothing
925
926 mov cs:EOF,End_Of_File ;Assume last cluster
927 mov ax,cs:Last_Found_Cluster ;Get last cluster
928 cmp cs:Fat_Size,FAT12_bit
929 jne Got_16_Bit
930 mov si, ax ;AN000;
931 shr ax, 1 ;AN000;
932 add si, ax ;AN000; si = ax*1.5 = ax+ax/2
933 call Get_Fat_Sector ;AN000;
934 jne Ok_cluster ;AN000;
935 mov al, byte ptr es:[bx] ;AN000;
936 mov byte ptr cs:Temp_cluster, al ;AN000;
937 inc si ;AN000;
938 call Get_Fat_Sector ;AN000;read next FAT sector
939 mov al, byte ptr es:[0] ;AN000;
940 mov byte ptr cs:Temp_cluster+1, al ;AN000;
941 mov ax, cs:Temp_cluster ;AN000;
942 jmp short Even_Odd ;AN000;
943 Ok_cluster: ;AN000;
944 mov ax, es:[bx] ;AN000;
945 Even_Odd: ;AN000;
946
947 ; xor bx,bx
948 ; mov bl,3 ;Mult by 3
949 ; mul bx
950 ; shr ax,1 ;Div by 2 to get 1.5
951 ; mov si,ax ;Get the final buffer offset
952 ; mov ax,[si]+8000h ;Get new cluster
953
954 test cs:Last_Found_Cluster,1 ;Was last cluster odd?
955 jnz Odd_Result ;If Carry set it was odd
956 and ax,0FFFh ;Keep low 12 bits
957 jmp short Test_EOF ;
958
959 Odd_Result:
960 mov cl,4 ;AN000;Keep high 12 bits for odd
961 shr ax,cl
962 Test_EOF:
963 cmp ax,0FF8h ;Is it last cluster?
964 jae Got_Cluster_Done ;Yep, all done here
965 jmp short Not_Last_CLuster
966
967 Got_16_Bit:
968 shl ax,1 ;Multiply cluster by 2
969 mov si,ax ;Get the final buffer offset
970 call Get_Fat_Sector ;AN000;
971 mov ax, es:[bx] ;AN000;
972 ; mov ax,[si]+8000h ;Get new cluster
973 cmp ax,0FFF8h
974 jae Got_Cluster_Done
975
976 Not_Last_Cluster:
977 mov cs:EOF,not END_OF_FILE ;Assume last cluster
978
979 Got_Cluster_Done:
980 pop es
981 ret
982
983
984 Get_Fat_Sector proc near
985 ;Function: Find and read the corresponding FAT sector into ES:0
986 ;In). SI = offset value (starting from FAT entry 0) of FAT entry to find.
987 ; ES = FAT sector segment
988 ; cs:Sector_Size
989 ;Out). Corresponding FAT sector read in.
990 ; BX = offset value of the corresponding FAT entry in the FAT sector.
991 ; CX destroyed.
992 ; Zero flag set if the FAT entry is splitted, i.e. when 12 bit FAT entry
993 ; starts at the last byte of the FAT sector. In this case, the caller
994 ; should save this byte, and read the next FAT sector to get the rest
995 ; of the FAT entry value. (This will only happen with the 12 bit fat).
996
997 push ax ;AN000;
998 push si ;AN000;
999 push di ;AN000;
1000 push dx ;AN000;
1001 xor dx, dx ;AN000;
1002 mov ax, si ;AN000;
1003 mov cx, cs:Sector_Size ;AN000;
1004 div cx ;AN000;ax = sector number, dx = offset
1005 cmp ax, cs:Last_Fat_SecNum ;AN000;the same fat sector?
1006 je GFS_Split_Chk ;AN000;don't need to read it again.
1007 mov cs:Last_Fat_SecNum, ax ;AN000;
1008 push dx ;AN000;
1009 xor dx, dx ;AN000;
1010 add ax, cs:Hidden_Sectors_L ;AN000;
1011 adc dx, cs:Hidden_Sectors_H ;AN000;
1012 add ax, cs:Reserved_Sectors ;AN000;
1013 adc dx, 0 ;AN000;
1014 mov cs:Start_Sector_L, ax ;AN000;
1015 mov cs:Start_Sector_H, dx ;AN000;set up for Disk_Read
1016 mov cs:Sector_Count, 1 ;AN000;1 sector
1017 xor di, di ;AN000;
1018 call Disk_Read ;AN000;
1019 pop dx ;AN000;
1020 mov cx, cs:Sector_Size ;AN000;
1021 GFS_Split_Chk: ;AN000;
1022 dec cx ;AN000;now, cx= sector size - 1
1023 cmp dx, cx ;AN000;if the last byte of the sector, then splitted entry.
1024 mov bx, dx ;AN000;Set BX to DX
1025 pop dx ;AN000;
1026 pop di ;AN000;
1027 pop si ;AN000;
1028 pop ax ;AN000;
1029 ret ;AN000;
1030 Get_Fat_Sector endp ;AN000;
1031
1032
1033 Errorout: ;AN000;
1034 push cs ;AN000;
1035 pop ds ;AN000;
1036 mov si, offset Sysmsg ;AN000;
1037 call write ;AN000;
1038 ;SB34LOAD001****************************************************************
1039 ;SB Wait for a keypress on the keyboard. Use the BIOS keyboard interrupt.
1040 ;SB 2 LOCS
1041
1042 xor ah,ah
1043 int 16h ;read keyboard
1044 ;SB34LOAD001****************************************************************
1045
1046 ;SB34LOAD002****************************************************************
1047 ;SB We have to restore the address of the original rom Disk parameter table
1048 ;SB to the location at [0:DSKADR]. The address of this original table has been
1049 ;SB saved previously in 0:Org_Rom_DiskTable and 0:Org_Rom_Disktable+2.
1050 ;SB After this table address has been restored we can reboot by
1051 ;SB invoking the bootstrap loader BIOS interrupt.
1052
1053 xor bx, bx
1054 mov ds, bx
1055 les bx, dword ptr ds:Org_Rom_DiskTable
1056 mov si, DSKADR
1057 mov word ptr ds:[si], bx ;restore offset
1058 mov word ptr ds:[si+2], es ;restore segment
1059 int 19h ;reboot
1060 ;SB34LOAD002****************************************************************
1061
1062 Write proc near ;show error messages
1063 ;In) DS:SI -> ASCIIZ string.
1064
1065 lodsb ;AN000;
1066 or al, al ;AN000;
1067 jz Endwr ;AN000;
1068 ;SB34LOAD003****************************************************************
1069 ;SB Write the character in al to the screen.
1070 ;SB Use Video service 'Write teletype to active page' (ROM_TELETYPE)
1071 ;SB Use normal character attribute
1072 mov ah, ROM_TELETYPE
1073 mov bl, 7 ;"normal" attribute ?
1074 int 10h ;video write
1075 ;SB34LOAD003****************************************************************
1076 jmp Write ;AN000;
1077 Endwr: ;AN000;
1078 ret ;AN000;
1079 Write endp
1080 ;
1081
1082 ;include MSbtmes.inc ;AN000;
1083 include MSbio.cl1 ;AN001;
1084
1085 Relocate_Length equ $ - start
1086 Total_Length label byte
1087 LoadBIO_Size equ $ - Start
1088
1089 cseg ends
1090 end start