-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathMSDOS.ASM
4031 lines (3720 loc) · 108 KB
/
MSDOS.ASM
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
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; 86-DOS High-performance operating system for the 8086 version 1.25
; by Tim Paterson
; ****************** Revision History *************************
; >> EVERY change must noted below!! <<
;
; 0.34 12/29/80 General release, updating all past customers
; 0.42 02/25/81 32-byte directory entries added
; 0.56 03/23/81 Variable record and sector sizes
; 0.60 03/27/81 Ctrl-C exit changes, including register save on user stack
; 0.74 04/15/81 Recognize I/O devices with file names
; 0.75 04/17/81 Improve and correct buffer handling
; 0.76 04/23/81 Correct directory size when not 2^N entries
; 0.80 04/27/81 Add console input without echo, Functions 7 & 8
; 1.00 04/28/81 Renumber for general release
; 1.01 05/12/81 Fix bug in `STORE'
; 1.10 07/21/81 Fatal error trapping, NUL device, hidden files, date & time,
; RENAME fix, general cleanup
; 1.11 09/03/81 Don't set CURRENT BLOCK to 0 on open; fix SET FILE SIZE
; 1.12 10/09/81 Zero high half of CURRENT BLOCK after all (CP/M programs don't)
; 1.13 10/29/81 Fix classic "no write-through" error in buffer handling
; 1.20 12/31/81 Add time to FCB; separate FAT from DPT; Kill SMALLDIR;
; Add FLUSH and MAPDEV calls; allow disk mapping in DSKCHG;
; Lots of smaller improvements
; 1.21 01/06/82 HIGHMEM switch to run DOS in high memory
; 1.22 01/12/82 Add VERIFY system call to enable/disable verify after write
; 1.23 02/11/82 Add defaulting to parser; use variable escape character
; Don't zero extent field in IBM version (back to 1.01!)
; 1.24 03/01/82 Restore fcn. 27 to 1.0 level; add fcn. 28
; 1.25 03/03/82 Put marker (00) at end of directory to speed searches
;
; *************************************************************
; Interrupt Entry Points:
; INTBASE: ABORT
; INTBASE+4: COMMAND
; INTBASE+8: BASE EXIT ADDRESS
; INTBASE+C: CONTROL-C ABORT
; INTBASE+10H: FATAL ERROR ABORT
; INTBASE+14H: BIOS DISK READ
; INTBASE+18H: BIOS DISK WRITE
; INTBASE+40H: Long jump to CALL entry point
IF IBM
ESCCH EQU 0
CANCEL EQU 1BH ;Cancel with ESC
TOGLINS EQU TRUE ;One key toggles insert mode
TOGLPRN EQU TRUE ;One key toggles printer echo
NUMDEV EQU 6 ;Include "COM1" as I/O device name
ZEROEXT EQU TRUE
ELSE
ESCCH EQU 1BH
CANCEL EQU "X"-"@" ;Cancel with Ctrl-X
TOGLINS EQU FALSE ;Separate keys for insert mode on and off
TOGLPRN EQU FALSE ;Separate keys for printer echo on and off
NUMDEV EQU 5 ;Number of I/O device names
ZEROEXT EQU FALSE
ENDIF
MAXCALL EQU 36
MAXCOM EQU 46
INTBASE EQU 80H
INTTAB EQU 20H
ENTRYPOINTSEG EQU 0CH
ENTRYPOINT EQU INTBASE+40H
CONTC EQU INTTAB+3
EXIT EQU INTBASE+8
LONGJUMP EQU 0EAH
LONGCALL EQU 9AH
MAXDIF EQU 0FFFH
SAVEXIT EQU 10
; Field definition for FCBs
FCBLOCK STRUC
DB 12 DUP (?) ;Drive code and name
EXTENT DW ?
RECSIZ DW ? ;Size of record (user settable)
FILSIZ DW ? ;Size of file in bytes
DRVBP DW ? ;BP for SEARCH FIRST and SEARCH NEXT
FDATE DW ? ;Date of last writing
FTIME DW ? ;Time of last writing
DEVID DB ? ;Device ID number, bits 0-5
;bit 7=0 for file, bit 7=1 for I/O device
;If file, bit 6=0 if dirty
;If I/O device, bit 6=0 if EOF (input)
FIRCLUS DW ? ;First cluster of file
LSTCLUS DW ? ;Last cluster accessed
CLUSPOS DW ? ;Position of last cluster accessed
DB ? ;Forces NR to offset 32
NR DB ? ;Next record
RR DB 3 DUP (?) ;Random record
FCBLOCK ENDS
FILDIRENT = FILSIZ ;Used only by SEARCH FIRST and SEARCH NEXT
; Description of 32-byte directory entry (same as returned by SEARCH FIRST
; and SEARCH NEXT, functions 17 and 18).
;
; Location bytes Description
;
; 0 11 File name and extension ( 0E5H if empty)
; 11 1 Attributes. Bits 1 or 2 make file hidden
; 12 10 Zero field (for expansion)
; 22 2 Time. Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour
; 24 2 Date. Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980
; 26 2 First allocation unit ( < 4080 )
; 28 4 File size, in bytes (LSB first, 30 bits max.)
;
; The File Allocation Table uses a 12-bit entry for each allocation unit on
; the disk. These entries are packed, two for every three bytes. The contents
; of entry number N is found by 1) multiplying N by 1.5; 2) adding the result
; to the base address of the Allocation Table; 3) fetching the 16-bit word at
; this address; 4) If N was odd (so that N*1.5 was not an integer), shift the
; word right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry number
; zero is used as an end-of-file trap in the OS and as a flag for directory
; entry size (if SMALLDIR selected). Entry 1 is reserved for future use. The
; first available allocation unit is assigned entry number two, and even
; though it is the first, is called cluster 2. Entries greater than 0FF8H are
; end of file marks; entries of zero are unallocated. Otherwise, the contents
; of a FAT entry is the number of the next cluster in the file.
; Field definition for Drive Parameter Block
DPBLOCK STRUC
DEVNUM DB ? ;I/O driver number
DRVNUM DB ? ;Physical Unit number
SECSIZ DW ? ;Size of physical sector in bytes
CLUSMSK DB ? ;Sectors/cluster - 1
CLUSSHFT DB ? ;Log2 of sectors/cluster
FIRFAT DW ? ;Starting record of FATs
FATCNT DB ? ;Number of FATs for this drive
MAXENT DW ? ;Number of directory entries
FIRREC DW ? ;First sector of first cluster
MAXCLUS DW ? ;Number of clusters on drive + 1
FATSIZ DB ? ;Number of records occupied by FAT
FIRDIR DW ? ;Starting record of directory
FAT DW ? ;Pointer to start of FAT
DPBLOCK ENDS
DPBSIZ EQU 20 ;Size of the structure in bytes
DIRSEC = FIRREC ;Number of dir. sectors (init temporary)
DSKSIZ = MAXCLUS ;Size of disk (temp used during init only)
;The following are all of the segments used
;They are declared in the order that they should be placed in the executable
CODE SEGMENT
CODE ENDS
CONSTANTS SEGMENT BYTE
CONSTANTS ENDS
DATA SEGMENT WORD
DATA ENDS
DOSGROUP GROUP CODE,CONSTANTS,DATA
SEGBIOS SEGMENT
SEGBIOS ENDS
; BOIS entry point definitions
IF IBM
BIOSSEG EQU 60H
ENDIF
IF NOT IBM
BIOSSEG EQU 40H
ENDIF
SEGBIOS SEGMENT AT BIOSSEG
ORG 0
DB 3 DUP (?) ;Reserve room for jump to init code
BIOSSTAT DB 3 DUP (?) ;Console input status check
BIOSIN DB 3 DUP (?) ;Get console character
BIOSOUT DB 3 DUP (?) ;Output console character
BIOSPRINT DB 3 DUP (?) ;Output to printer
BIOSAUXIN DB 3 DUP (?) ;Get byte from auxilliary
BIOSAUXOUT DB 3 DUP (?) ;Output byte to auxilliary
BIOSREAD DB 3 DUP (?) ;Disk read
BIOSWRITE DB 3 DUP (?) ;Disk write
BIOSDSKCHG DB 3 DUP (?) ;Dsik-change status
BIOSSETDATE DB 3 DUP (?) ;Set date
BIOSSETTIME DB 3 DUP (?) ;Set time
BIOSGETTIME DB 3 DUP (?) ;Get time and date
BIOSFLUSH DB 3 DUP (?) ;Clear console input buffer
BIOSMAPDEV DB 3 DUP (?) ;Dynamic disk table mapper
SEGBIOS ENDS
; Location of user registers relative user stack pointer
STKPTRS STRUC
AXSAVE DW ?
BXSAVE DW ?
CXSAVE DW ?
DXSAVE DW ?
SISAVE DW ?
DISAVE DW ?
BPSAVE DW ?
DSSAVE DW ?
ESSAVE DW ?
IPSAVE DW ?
CSSAVE DW ?
FSAVE DW ?
STKPTRS ENDS
; Start of code
CODE SEGMENT
ASSUME CS:DOSGROUP,DS:DOSGROUP,ES:DOSGROUP,SS:DOSGROUP
ORG 0
CODSTRT EQU $
JMP DOSINIT
ESCCHAR DB ESCCH ;Lead-in character for escape sequences
ESCTAB:
IF NOT IBM
DB "S" ;Copy one char
DB "V" ;Skip one char
DB "T" ;Copy to char
DB "W" ;Skip to char
DB "U" ;Copy line
DB "E" ;Kill line (no change in template)
DB "J" ;Reedit line (new template)
DB "D" ;Backspace
DB "P" ;Enter insert mode
DB "Q" ;Exit insert mode
DB "R" ;Escape character
DB "R" ;End of table
ENDIF
IF IBM
DB 64 ;Crtl-Z - F6
DB 77 ;Copy one char - -->
DB 59 ;Copy one char - F1
DB 83 ;Skip one char - DEL
DB 60 ;Copy to char - F2
DB 62 ;Skip to char - F4
DB 61 ;Copy line - F3
DB 61 ;Kill line (no change to template ) - Not used
DB 63 ;Reedit line (new template) - F5
DB 75 ;Backspace - <--
DB 82 ;Enter insert mode - INS (toggle)
DB 65 ;Escape character - F7
DB 65 ;End of table
ENDIF
ESCTABLEN EQU $-ESCTAB
IF NOT IBM
HEADER DB 13,10,"MS-DOS version 1.25"
IF HIGHMEM
DB "H"
ENDIF
IF DSKTEST
DB "D"
ENDIF
DB 13,10
DB "Copyright 1981,82 Microsoft, Inc.",13,10,"$"
ENDIF
QUIT:
MOV AH,0
JMP SHORT SAVREGS
COMMAND: ;Interrupt call entry point
CMP AH,MAXCOM
JBE SAVREGS
BADCALL:
MOV AL,0
IRET: IRET
ENTRY: ;System call entry point and dispatcher
POP AX ;IP from the long call at 5
POP AX ;Segment from the long call at 5
POP CS:[TEMP] ;IP from the CALL 5
PUSHF ;Start re-ordering the stack
CLI
PUSH AX ;Save segment
PUSH CS:[TEMP] ;Stack now ordered as if INT had been used
CMP CL,MAXCALL ;This entry point doesn't get as many calls
JA BADCALL
MOV AH,CL
SAVREGS:
PUSH ES
PUSH DS
PUSH BP
PUSH DI
PUSH SI
PUSH DX
PUSH CX
PUSH BX
PUSH AX
IF DSKTEST
MOV AX,CS:[SPSAVE]
MOV CS:[NSP],AX
MOV AX,CS:[SSSAVE]
MOV CS:[NSS],AX
POP AX
PUSH AX
ENDIF
MOV CS:[SPSAVE],SP
MOV CS:[SSSAVE],SS
MOV SP,CS
MOV SS,SP
REDISP:
MOV SP,OFFSET DOSGROUP:IOSTACK
STI ;Stack OK now
MOV BL,AH
MOV BH,0
SHL BX,1
CLD
CMP AH,12
JLE SAMSTK
MOV SP,OFFSET DOSGROUP:DSKSTACK
SAMSTK:
CALL CS:[BX+DISPATCH]
LEAVE:
CLI
MOV SP,CS:[SPSAVE]
MOV SS,CS:[SSSAVE]
MOV BP,SP
MOV BYTE PTR [BP.AXSAVE],AL
IF DSKTEST
MOV AX,CS:[NSP]
MOV CS:[SPSAVE],AX
MOV AX,CS:[NSS]
MOV CS:[SSSAVE],AX
ENDIF
POP AX
POP BX
POP CX
POP DX
POP SI
POP DI
POP BP
POP DS
POP ES
IRET
; Standard Functions
DISPATCH DW ABORT ;0
DW CONIN
DW CONOUT
DW READER
DW PUNCH
DW LIST ;5
DW RAWIO
DW RAWINP
DW IN
DW PRTBUF
DW BUFIN ;10
DW CONSTAT
DW FLUSHKB
DW DSKRESET
DW SELDSK
DW OPEN ;15
DW CLOSE
DW SRCHFRST
DW SRCHNXT
DW DELETE
DW SEQRD ;20
DW SEQWRT
DW CREATE
DW RENAME
DW INUSE
DW GETDRV ;25
DW SETDMA
DW GETFATPT
DW GETFATPTDL
DW GETRDONLY
DW SETATTRIB ;30
DW GETDSKPT
DW USERCODE
DW RNDRD
DW RNDWRT
DW FILESIZE ;35
DW SETRNDREC
; Extended Functions
DW SETVECT
DW NEWBASE
DW BLKRD
DW BLKWRT ;40
DW MAKEFCB
DW GETDATE
DW SETDATE
DW GETTIME
DW SETTIME ;45
DW VERIFY
INUSE:
GETIO:
SETIO:
GETRDONLY:
SETATTRIB:
USERCODE:
MOV AL,0
RET
VERIFY:
AND AL,1
MOV CS:VERFLG,AL
RET
FLUSHKB:
PUSH AX
CALL FAR PTR BIOSFLUSH
POP AX
MOV AH,AL
CMP AL,1
JZ REDISPJ
CMP AL,6
JZ REDISPJ
CMP AL,7
JZ REDISPJ
CMP AL,8
JZ REDISPJ
CMP AL,10
JZ REDISPJ
MOV AL,0
RET
REDISPJ:JMP REDISP
READER:
AUXIN:
CALL STATCHK
CALL FAR PTR BIOSAUXIN
RET
PUNCH:
MOV AL,DL
AUXOUT:
PUSH AX
CALL STATCHK
POP AX
CALL FAR PTR BIOSAUXOUT
RET
UNPACK:
; Inputs:
; DS = CS
; BX = Cluster number
; BP = Base of drive parameters
; SI = Pointer to drive FAT
; Outputs:
; DI = Contents of FAT for given cluster
; Zero set means DI=0 (free cluster)
; No other registers affected. Fatal error if cluster too big.
CMP BX,[BP.MAXCLUS]
JA HURTFAT
LEA DI,[SI+BX]
SHR BX,1
MOV DI,[DI+BX]
JNC HAVCLUS
SHR DI,1
SHR DI,1
SHR DI,1
SHR DI,1
STC
HAVCLUS:
RCL BX,1
AND DI,0FFFH
RET
HURTFAT:
PUSH AX
MOV AH,80H ;Signal Bad FAT to INT 24H handler
MOV DI,0FFFH ;In case INT 24H returns (it shouldn't)
CALL FATAL
POP AX ;Try to ignore bad FAT
RET
PACK:
; Inputs:
; DS = CS
; BX = Cluster number
; DX = Data
; SI = Pointer to drive FAT
; Outputs:
; The data is stored in the FAT at the given cluster.
; BX,DX,DI all destroyed
; No other registers affected
MOV DI,BX
SHR BX,1
ADD BX,SI
ADD BX,DI
SHR DI,1
MOV DI,[BX]
JNC ALIGNED
SHL DX,1
SHL DX,1
SHL DX,1
SHL DX,1
AND DI,0FH
JMP SHORT PACKIN
ALIGNED:
AND DI,0F000H
PACKIN:
OR DI,DX
MOV [BX],DI
RET
DEVNAME:
MOV SI,OFFSET DOSGROUP:IONAME ;List of I/O devices with file names
MOV BH,NUMDEV ;BH = number of device names
LOOKIO:
MOV DI,OFFSET DOSGROUP:NAME1
MOV CX,4 ;All devices are 4 letters
REPE CMPSB ;Check for name in list
JZ IOCHK ;If first 3 letters OK, check for the rest
ADD SI,CX ;Point to next device name
DEC BH
JNZ LOOKIO
CRET:
STC ;Not found
RET
IOCHK:
IF IBM
CMP BH,NUMDEV ;Is it the first device?
JNZ NOTCOM1
MOV BH,2 ;Make it the same as AUX
NOTCOM1:
ENDIF
NEG BH
MOV CX,2 ;Check rest of name but not extension
MOV AX,2020H
REPE SCASW ;Make sure rest of name is blanks
JNZ CRET
RET1: RET ;Zero set so CREATE works
GETFILE:
; Same as GETNAME except ES:DI points to FCB on successful return
CALL MOVNAME
JC RET1
PUSH DX
PUSH DS
CALL FINDNAME
POP ES
POP DI
RET2: RET
GETNAME:
; Inputs:
; DS,DX point to FCB
; Function:
; Find file name in disk directory. First byte is
; drive number (0=current disk). "?" matches any
; character.
; Outputs:
; Carry set if file not found
; ELSE
; Zero set if attributes match (always except when creating)
; BP = Base of drive parameters
; DS = CS
; ES = CS
; BX = Pointer into directory buffer
; SI = Pointer to First Cluster field in directory entry
; [DIRBUF] has directory record with match
; [NAME1] has file name
; All other registers destroyed.
CALL MOVNAME
JC RET2 ;Bad file name?
FINDNAME:
MOV AX,CS
MOV DS,AX
CALL DEVNAME
JNC RET2
CALL STARTSRCH
CONTSRCH:
CALL GETENTRY
JC RET2
SRCH:
MOV AH,BYTE PTR [BX]
OR AH,AH ;End of directory?
JZ FREE
CMP AH,[DELALL] ;Free entry?
JZ FREE
MOV SI,BX
MOV DI,OFFSET DOSGROUP:NAME1
MOV CX,11
WILDCRD:
REPE CMPSB
JZ FOUND
CMP BYTE PTR [DI-1],"?"
JZ WILDCRD
NEXTENT:
CALL NEXTENTRY
JNC SRCH
RET3: RET
FREE:
CMP [ENTFREE],-1 ;Found a free entry before?
JNZ TSTALL ;If so, ignore this one
MOV CX,[LASTENT]
MOV [ENTFREE],CX
TSTALL:
CMP AH,[DELALL] ;At end of directory?
JZ NEXTENT ;No - continue search
STC ;Report not found
RET
FOUND:
;Check if attributes allow finding it
MOV AH,[ATTRIB] ;Attributes of search
NOT AH
AND AH,[SI] ;Compare with attributes of file
ADD SI,15
AND AH,6 ;Only look at bits 1 and 2
JZ RET3
TEST BYTE PTR [CREATING],-1 ;Pass back mismatch if creating
JZ NEXTENT ;Otherwise continue searching
RET
GETENTRY:
; Inputs:
; [LASTENT] has previously searched directory entry
; Function:
; Locates next sequential directory entry in preparation for search
; Outputs:
; Carry set if none
; ELSE
; AL = Current directory block
; BX = Pointer to next directory entry in [DIRBUF]
; DX = Pointer to first byte after end of DIRBUF
; [LASTENT] = New directory entry number
MOV AX,[LASTENT]
INC AX ;Start with next entry
CMP AX,[BP.MAXENT]
JAE NONE
GETENT:
MOV [LASTENT],AX
MOV CL,4
SHL AX,CL
XOR DX,DX
SHL AX,1
RCL DX,1 ;Account for overflow in last shift
MOV BX,[BP.SECSIZ]
AND BL,255-31 ;Must be multiple of 32
DIV BX
MOV BX,DX ;Position within sector
MOV AH,[BP.DEVNUM] ;AL=Directory sector no.
CMP AX,[DIRBUFID]
JZ HAVDIRBUF
PUSH BX
CALL DIRREAD
POP BX
HAVDIRBUF:
MOV DX,OFFSET DOSGROUP:DIRBUF
ADD BX,DX
ADD DX,[BP.SECSIZ]
RET
NEXTENTRY:
; Inputs:
; Same as outputs of GETENTRY, above
; Function:
; Update AL, BX, and [LASTENT] for next directory entry.
; Carry set if no more.
MOV DI,[LASTENT]
INC DI
CMP DI,[BP.MAXENT]
JAE NONE
MOV [LASTENT],DI
ADD BX,32
CMP BX,DX
JB HAVIT
INC AL ;Next directory sector
PUSH DX ;Save limit
CALL DIRREAD
POP DX
MOV BX,OFFSET DOSGROUP:DIRBUF
HAVIT:
CLC
RET
NONE:
CALL CHKDIRWRITE
STC
RET4: RET
DELETE: ; System call 19
CALL MOVNAME
MOV AL,-1
JC RET4
MOV AL,CS:[ATTRIB]
AND AL,6 ;Look only at hidden bits
CMP AL,6 ;Both must be set
JNZ NOTALL
MOV CX,11
MOV AL,"?"
MOV DI,OFFSET DOSGROUP:NAME1
REPE SCASB ;See if name is *.*
JNZ NOTALL
MOV BYTE PTR CS:[DELALL],0 ;DEL *.* - flag deleting all
NOTALL:
CALL FINDNAME
MOV AL,-1
JC RET4
OR BH,BH ;Check if device name
JS RET4 ;Can't delete I/O devices
DELFILE:
MOV BYTE PTR [DIRTYDIR],-1
MOV AH,[DELALL]
MOV BYTE PTR [BX],AH
MOV BX,[SI]
MOV SI,[BP.FAT]
OR BX,BX
JZ DELNXT
CMP BX,[BP.MAXCLUS]
JA DELNXT
CALL RELEASE
DELNXT:
CALL CONTSRCH
JNC DELFILE
CALL FATWRT
CALL CHKDIRWRITE
XOR AL,AL
RET
RENAME: ;System call 23
CALL MOVNAME
JC ERRET
ADD SI,5
MOV DI,OFFSET DOSGROUP:NAME2
CALL LODNAME
JC ERRET ;Report error if second name invalid
CALL FINDNAME
JC ERRET
OR BH,BH ;Check if I/O device name
JS ERRET ;If so, can't rename it
MOV SI,OFFSET DOSGROUP:NAME1
MOV DI,OFFSET DOSGROUP:NAME3
MOV CX,6 ;6 words (12 bytes)--include attribute byte
REP MOVSW ;Copy name to search for
RENFIL:
MOV DI,OFFSET DOSGROUP:NAME1
MOV SI,OFFSET DOSGROUP:NAME2
MOV CX,11
NEWNAM:
LODSB
CMP AL,"?"
JNZ NOCHG
MOV AL,[BX]
NOCHG:
STOSB
INC BX
LOOP NEWNAM
MOV BYTE PTR [DI],6 ;Stop duplicates with any attributes
CALL DEVNAME ;Check if giving it a device name
JNC RENERR
PUSH [LASTENT] ;Save position of match
MOV [LASTENT],-1 ;Search entire directory for duplicate
CALL CONTSRCH ;See if new name already exists
POP AX
JNC RENERR ;Error if found
CALL GETENT ;Re-read matching entry
MOV DI,BX
MOV SI,OFFSET DOSGROUP:NAME1
MOV CX,5
MOVSB
REP MOVSW ;Replace old name with new one
MOV BYTE PTR [DIRTYDIR],-1 ;Flag change in directory
MOV SI,OFFSET DOSGROUP:NAME3
MOV DI,OFFSET DOSGROUP:NAME1
MOV CX,6 ;Include attribute byte
REP MOVSW ;Copy name back into search buffer
CALL CONTSRCH
JNC RENFIL
CALL CHKDIRWRITE
XOR AL,AL
RET
RENERR:
CALL CHKDIRWRITE
ERRET:
MOV AL,-1
RET5: RET
MOVNAME:
; Inputs:
; DS, DX point to FCB or extended FCB
; Outputs:
; DS:DX point to normal FCB
; ES = CS
; If file name OK:
; BP has base of driver parameters
; [NAME1] has name in upper case
; All registers except DX destroyed
; Carry set if bad file name or drive
MOV CS:WORD PTR [CREATING],0E500H ;Not creating, not DEL *.*
MOV AX,CS
MOV ES,AX
MOV DI,OFFSET DOSGROUP:NAME1
MOV SI,DX
LODSB
MOV CS:[EXTFCB],AL ;Set flag if extended FCB in use
MOV AH,0 ;Set default attributes
CMP AL,-1 ;Is it an extended FCB?
JNZ HAVATTRB
ADD DX,7 ;Adjust to point to normal FCB
ADD SI,6 ;Point to drive select byte
MOV AH,[SI-1] ;Get attribute byte
LODSB ;Get drive select byte
HAVATTRB:
MOV CS:[ATTRIB],AH ;Save attributes
CALL GETTHISDRV
LODNAME:
; This entry point copies a file name from DS,SI
; to ES,DI converting to upper case.
CMP BYTE PTR [SI]," " ;Don't allow blank as first letter
STC ;In case of error
JZ RET5
MOV CX,11
MOVCHK:
CALL GETLET
JB RET5
JNZ STOLET ;Is it a delimiter?
CMP AL," " ;This is the only delimiter allowed
STC ;In case of error
JNZ RET5
STOLET:
STOSB
LOOP MOVCHK
CLC ;Got through whole name - no error
RET6: RET
GETTHISDRV:
CMP CS:[NUMDRV],AL
JC RET6
DEC AL
JNS PHYDRV
MOV AL,CS:[CURDRV]
PHYDRV:
MOV CS:[THISDRV],AL
RET
OPEN: ;System call 15
CALL GETFILE
DOOPEN:
; Enter here to perform OPEN on file already found
; in directory. DS=CS, BX points to directory
; entry in DIRBUF, SI points to First Cluster field, and
; ES:DI point to the FCB to be opened. This entry point
; is used by CREATE.
JC ERRET
OR BH,BH ;Check if file is I/O device
JS OPENDEV ;Special handler if so
MOV AL,[THISDRV]
INC AX
STOSB
XOR AX,AX
IF ZEROEXT
ADD DI,11
STOSW ;Zero low byte of extent field if IBM only
ENDIF
IF NOT ZEROEXT
ADD DI,12 ;Point to high half of CURRENT BLOCK field
STOSB ;Set it to zero (CP/M programs set low byte)
ENDIF
MOV AL,128 ;Default record size
STOSW ;Set record size
LODSW ;Get starting cluster
MOV DX,AX ;Save it for the moment
MOVSW ;Transfer size to FCB
MOVSW
MOV AX,[SI-8] ;Get date
STOSW ;Save date in FCB
MOV AX,[SI-10] ;Get time
STOSW ;Save it in FCB
MOV AL,[BP.DEVNUM]
OR AL,40H
STOSB
MOV AX,DX ;Restore starting cluster
STOSW ; first cluster
STOSW ; last cluster accessed
XOR AX,AX
STOSW ; position of last cluster
RET
OPENDEV:
ADD DI,13 ;point to 2nd half of extent field
XOR AX,AX
STOSB ;Set it to zero
MOV AL,128
STOSW ;Set record size to 128
XOR AX,AX
STOSW
STOSW ;Set current size to zero
CALL DATE16
STOSW ;Date is todays
XCHG AX,DX
STOSW ;Use current time
MOV AL,BH ;Get device number
STOSB
XOR AL,AL ;No error
RET
FATERR:
XCHG AX,DI ;Put error code in DI
MOV AH,2 ;While trying to read FAT
MOV AL,[THISDRV] ;Tell which drive
CALL FATAL1
JMP SHORT FATREAD
STARTSRCH:
MOV AX,-1
MOV [LASTENT],AX
MOV [ENTFREE],AX
FATREAD:
; Inputs:
; DS = CS
; Function:
; If disk may have been changed, FAT is read in and buffers are
; flagged invalid. If not, no action is taken.
; Outputs:
; BP = Base of drive parameters
; Carry set if invalid drive returned by MAPDEV
; All other registers destroyed
MOV AL,[THISDRV]
XOR AH,AH ;Set default response to zero & clear carry
CALL FAR PTR BIOSDSKCHG ;See what BIOS has to say
JC FATERR
CALL GETBP
MOV AL,[THISDRV] ;Use physical unit number
MOV SI,[BP.FAT]
OR AH,[SI-1] ;Dirty byte for FAT
JS NEWDSK ;If either say new disk, then it's so
JNZ MAPDRV
MOV AH,1
CMP AX,WORD PTR [BUFDRVNO] ;Does buffer have dirty sector of this drive?
JZ MAPDRV
NEWDSK:
CMP AL,[BUFDRVNO] ;See if buffer is for this drive
JNZ BUFOK ;If not, don't touch it
MOV [BUFSECNO],0 ;Flag buffers invalid
MOV WORD PTR [BUFDRVNO],00FFH
BUFOK:
MOV [DIRBUFID],-1
CALL FIGFAT
NEXTFAT:
PUSH AX
CALL DSKREAD
POP AX
JC BADFAT
SUB AL,[BP.FATCNT]
JZ NEWFAT
CALL FATWRT
NEWFAT:
MOV SI,[BP.FAT]
MOV AL,[BP.DEVNUM]
MOV AH,[SI] ;Get first byte of FAT
OR AH,0F8H ;Put in range
CALL FAR PTR BIOSMAPDEV
MOV AH,0
MOV [SI-2],AX ;Set device no. and reset dirty bit
MAPDRV:
MOV AL,[SI-2] ;Get device number
GETBP:
MOV BP,[DRVTAB] ;Just in case drive isn't valid
AND AL,3FH ;Mask out dirty bit
CMP AL,[NUMIO]
CMC
JC RET7
PUSH AX
MOV AH,DPBSIZ
MUL AH
ADD BP,AX
POP AX
RET7: RET
BADFAT: