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
|
;
; xenix file calls for MSDOS
;
INCLUDE DOSSEG.ASM
IFNDEF KANJI
KANJI EQU 0 ;FALSE
ENDIF
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xlist
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
.cref
.list
TITLE XENIX - IO system to mimic UNIX
NAME XENIX
i_need NoSetDir,BYTE
i_need CURDRV,BYTE
i_need IOCALL,BYTE
i_need IOMED,BYTE
i_need IOSCNT,WORD
i_need IOXAD,DWORD
i_need DIRSTART,WORD
i_need ATTRIB,BYTE
i_need THISFCB,DWORD
i_need AuxStack,BYTE
i_need Creating,BYTE
i_need ThisDRV,BYTE
i_need NAME1,BYTE
i_need LastEnt,WORD
i_need ThisDPB,DWORD
i_need EntLast,WORD
i_need CurrentPDB,WORD
i_need sft_addr,DWORD ; pointer to head of table
i_need CURBUF,DWORD ; pointer to current buffer
i_need DMAADD,DWORD ; pointer to current dma address
BREAK <Local data>
CODE ENDS
DATA SEGMENT BYTE PUBLIC 'DATA'
PushSave DW ?
PushES DW ?
PushBX DW ?
xenix_count DW ?
DATA ENDS
CODE SEGMENT BYTE PUBLIC 'CODE'
BREAK <get_sf_from_sfn - translate a sfn into sf pointer>
;
; get_sf_from_sfn
; input: AX has sfn (0 based)
; DS is DOSGROUP
; output: JNC <found>
; ES:DI is sf entry
; JC <error>
; ES,DI indeterminate
;
procedure get_sf_from_sfn,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
PUSH AX ; we trash AX in process
LES DI,[sft_addr]
get_sfn_loop:
CMP DI,-1 ; end of chain of tables?
JZ get_sf_invalid ; I guess so...
SUB AX,ES:[DI].sft_count ; chop number of entries in this table
JL get_sf_gotten ; sfn is in this table
LES DI,ES:[DI].sft_link ; step to next table
JMP get_sfn_loop
get_sf_gotten:
ADD AX,ES:[DI].sft_count ; reset to index in this table
PUSH BX
MOV BX,SIZE sf_entry
MUL BL ; number of bytes offset into table
POP BX
ADD AX,sft_table ; offset into sf table structure
ADD DI,AX ; offset into memory
CLC
JMP SHORT get_sf_ret
get_sf_jfn_invalid:
get_sf_invalid:
STC
get_sf_jfn_ret:
get_sf_ret:
POP AX ; remember him?
RET
get_sf_from_sfn ENDP
BREAK <get_sf_from_jfn - translate a jfn into sf pointer>
;
; get_sf_from_jfn
; input: BX is jfn 0 based
; DS is DOSGROUP
; output: JNC <found>
; ES:DI is sf entry
; JC <error>
; ES,DI is indeterminate
;
procedure get_sf_from_jfn,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
PUSH AX ; save him
invoke get_jfn_pointer
JC get_sf_jfn_invalid
MOV AL,ES:[DI] ; get sfn
CMP AL,0FFh ; is it free?
JZ get_sf_jfn_invalid ; yep... error
XOR AH,AH
invoke get_sf_from_sfn ; check this sfn out...
JMP SHORT get_sf_jfn_ret ; condition codes are properly set
get_sf_from_jfn ENDP
BREAK <get_jfn_pointer - map a jfn into a pointer to jfn>
;
; get_jfn_pointer
; input: BX is jfn
; DS is DOSGROUP
; output: JNC <found>
; ES:DI is pointer to jfn
; JC <bad jfn>
;
procedure Get_jfn_pointer,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
CMP BX,FilPerProc
JAE get_jfn_bad
MOV ES,[CurrentPDB]
MOV DI,BX
ADD DI,PDB_JFN_Table
CLC
RET
get_jfn_bad:
STC
RET
get_jfn_pointer ENDP
BREAK <$Close - release a handle>
;
; Assembler usage:
; MOV BX, handle
; MOV AH, Close
; INT int_command
;
; Error return:
; AX = error_invalid_handle
;
procedure $Close,NEAR
ASSUME DS:NOTHING,ES:NOTHING
context DS
invoke get_jfn_pointer ; get jfn loc
JNC close_jfn
close_bad_handle:
error error_invalid_handle
close_jfn:
MOV AL,BYTE PTR ES:[DI]
CMP AL,0FFh
JE close_bad_handle
MOV BYTE PTR ES:[DI],0FFh;
XOR AH,AH
invoke get_sf_from_sfn
JC close_bad_handle
PUSH ES
POP DS
ASSUME DS:NOTHING
DEC [DI].sf_ref_count ; no more reference
LEA DX,[DI].sf_fcb
;
; need to restuff Attrib if we are closing a protected file
;
TEST [DI.sf_fcb.fcb_DevID],devid_file_clean+devid_device
JNZ close_ok
PUSH WORD PTR [DI].sf_attr
invoke MOVNAMENOSET
POP BX
MOV [Attrib],BL
invoke FCB_CLOSE_INNER
CMP AL,0FFh ; file not found error?
JNZ close_ok
error error_file_not_found
close_ok:
transfer SYS_RET_OK
$Close ENDP
BREAK <PushDMA, PopDMA, ptr_normalize - set up local dma and save old>
; PushDMA
; input: DS:DX is DMA
; output: DS:DX is normalized , ES:BX destroyed
; [DMAADD] is now set up to DS:DX
; old DMA is pushed
procedure PushDMA,NEAR
ASSUME DS:NOTHING,ES:NOTHING
MOV PushES,ES
MOV PushBX,BX
POP PushSave
LES BX,DWORD PTR [DMAADD] ; get old dma
PUSH ES
PUSH BX
PUSH PushSave
invoke ptr_normalize ; get new dma
MOV WORD PTR [DMAADD],DX ; save IT!
MOV WORD PTR [DMAADD+2],DS
MOV ES,PushES
MOV BX,PushBX
RET
PushDMA ENDP
; PopDMA
; input: old DMA under ret address on stack
; output: [DMAADD] set to old version and stack popped
procedure PopDMA,NEAR
ASSUME DS:NOTHING,ES:NOTHING
POP PushSave
POP WORD PTR [DMAADD]
POP WORD PTR [DMAADD+2]
PUSH PushSave
RET
PopDMA ENDP
; ptr_normalize
; input: DS:DX is a pointer
; output: DS:DX is normalized (DX < 10h)
procedure ptr_normalize,NEAR
PUSH CX ; T1 = CX
PUSH DX ; T2 = DX
MOV CL,4
SHR DX,CL ; DX = (DX >> 4) (using CX)
MOV CX,DS
ADD CX,DX
MOV DS,CX ; DS = DS + DX (using CX)
POP DX
AND DX,0Fh ; DX = T2 & 0Fh
POP CX ; CX = T1
; PUSH AX
; PUSH DX
; MOV AX,DS
; PUSH CX
; MOV CL,4
; SHR DX,CL ; get upper part of dx
; POP CX
; ADD AX,DX ; add into seg address
; MOV DS,AX
; POP DX
; AND DX,0Fh ; save low part
; POP AX
RET
ptr_normalize ENDP
BREAK <$Read - Do file/device I/O>
;
; Assembler usage:
; LDS DX, buf
; MOV CX, count
; MOV BX, handle
; MOV AH, Read
; INT int_command
; AX has number of bytes read
; Errors:
; AX = read_invalid_handle
; = read_access_denied
;
procedure $Read,NEAR
ASSUME DS:NOTHING,ES:NOTHING
invoke PushDMA
CALL IO_setup
JC IO_err
CMP ES:[DI].sf_mode,open_for_write
JNE read_setup
IO_bad_mode:
MOV AL,read_access_denied
IO_err:
invoke PopDMA
transfer SYS_RET_ERR
read_setup:
invoke $FCB_RANDOM_READ_BLOCK ; do read
IO_done:
invoke get_user_stack ; get old frame
MOV AX,[SI].user_CX ; get returned CX
MOV CX,xenix_count
MOV [SI].user_CX,CX ; stash our CX
invoke PopDMA ; get old DMA
transfer SYS_RET_OK
$Read ENDP
BREAK <$Write - Do file/device I/O>
;
; Assembler usage:
; LDS DX, buf
; MOV CX, count
; MOV BX, handle
; MOV AH, Write
; INT int_command
; AX has number of bytes written
; Errors:
; AX = write_invalid_handle
; = write_access_denied
;
procedure $Write,NEAR
ASSUME DS:NOTHING,ES:NOTHING
invoke PushDMA
CALL IO_setup
JC IO_err
CMP ES:[DI].sf_mode,open_for_read
JE IO_bad_mode
invoke $FCB_RANDOM_WRITE_BLOCK ; do write
JMP IO_done
$write ENDP
IO_setup:
ASSUME DS:NOTHING,ES:NOTHING
context DS
MOV xenix_count,CX
invoke Get_sf_from_jfn
; ES:DI is sf pointer
MOV AL,read_invalid_handle ;Assume an error
MOV CX,xenix_count
LEA DX,[DI].sf_fcb
PUSH ES
POP DS
ASSUME DS:NOTHING
RET
BREAK <$LSEEK - set random record field>
;
; Assembler usage:
; MOV DX, offsetlow
; MOV CX, offsethigh
; MOV BX, handle
; MOV AL, method
; MOV AH, LSeek
; INT int_command
; DX:AX has the new location of the pointer
; Error returns:
; AX = error_invalid_handle
; = error_invalid_function
procedure $LSEEK,NEAR
ASSUME DS:NOTHING,ES:NOTHING
CMP AL,3
JB lseek_get_sf
error error_invalid_function
lseek_get_sf:
context DS
invoke get_sf_from_jfn
PUSH ES
POP DS
ASSUME DS:NOTHING
JC lseek_bad
;
; don't seek device
;
TEST [DI.sf_fcb+fcb_devid],devid_device
JZ lseek_dispatch
XOR AX,AX
XOR DX,DX
JMP SHORT lseek_ret
lseek_dispatch:
DEC AL
JL lseek_beginning
DEC AL
JL lseek_current
; move from end of file
; first, get end of file
XCHG AX,DX ; AX <- low
XCHG DX,CX ; DX <- high
ASSUME DS:NOTHING
ADD AX,[DI+sf_fcb+fcb_FILSIZ]
ADC DX,[DI+sf_fcb+fcb_FILSIZ+2]
JMP SHORT lseek_ret
lseek_beginning:
XCHG AX,DX ; AX <- low
XCHG DX,CX ; DX <- high
lseek_ret:
MOV WORD PTR [DI+sf_fcb+fcb_RR],AX
MOV WORD PTR [DI+sf_fcb+fcb_RR+2],DX
invoke get_user_stack
MOV [SI.user_DX],DX
MOV [SI.user_AX],AX
transfer SYS_RET_OK
lseek_current:
; ES:DI is pointer to sf... need to invoke set random record for place
XCHG AX,DX ; AX <- low
XCHG DX,CX ; DX <- high
ADD AX,WORD PTR [DI+sf_fcb+fcb_RR]
ADC DX,WORD PTR [DI+sf_fcb+fcb_RR+2]
JMP lseek_ret
lseek_bad:
error error_invalid_handle
$lseek ENDP
BREAK <$IOCTL - return/set device dependent stuff>
;
; Assembler usage:
; MOV BX, Handle
; MOV DX, Data
;
; (or LDS DX,BUF
; MOV CX,COUNT)
;
; MOV AH, Ioctl
; MOV AL, Request
; INT 21h
;
; Error returns:
; AX = error_invalid_handle
; = error_invalid_function
; = error_invalid_data
procedure $IOCTL,NEAR
ASSUME DS:NOTHING,ES:NOTHING
MOV SI,DS ;Stash DS for calls 2,3,4 and 5
context DS
CMP AL,3
JA ioctl_check_block ;Block device
PUSH DX
invoke get_sf_from_jfn
POP DX ;Restore DATA
JNC ioctl_check_permissions ; have valid handle
error error_invalid_handle
ioctl_check_permissions:
CMP AL,2
JAE ioctl_control_string
CMP AL,0
MOV AL,BYTE PTR ES:[DI+sf_fcb+fcb_devid]
JZ ioctl_read ; read the byte
OR DH,DH
JZ ioctl_check_device ; can I set with this data?
error error_invalid_data ; no DH <> 0
ioctl_check_device:
TEST AL,devid_ISDEV ; can I set this handle?
JZ ioctl_bad_fun ; no, it is a file.
MOV BYTE PTR ES:[DI+sf_fcb+fcb_devid],DL
transfer SYS_RET_OK
ioctl_read:
XOR AH,AH
TEST AL,devid_ISDEV ; Should I set high byte
JZ ioctl_no_high ; no
LES DI,DWORD PTR ES:[DI+sf_fcb+fcb_FIRCLUS] ;Get device pointer
MOV AH,BYTE PTR ES:[DI.SDEVATT+1] ;Get high byte
ioctl_no_high:
invoke get_user_stack
MOV DX,AX
MOV [SI.user_DX],DX
transfer SYS_RET_OK
ioctl_control_string:
TEST BYTE PTR ES:[DI+sf_fcb+fcb_devid],devid_ISDEV ; can I?
JZ ioctl_bad_fun ; no, it is a file.
LES DI,DWORD PTR ES:[DI+sf_fcb+fcb_FIRCLUS] ;Get device pointer
XOR BL,BL ; Unit number of char dev = 0
JMP SHORT ioctl_do_string
ioctl_check_block:
DEC AL
DEC AL ;4=2,5=3,6=4,7=5
CMP AL,3
JBE ioctl_get_dev
MOV AH,1
SUB AL,4 ;6=0,7=1
JZ ioctl_get_status
MOV AH,3
DEC AL
JNZ ioctl_bad_fun
ioctl_get_status:
PUSH AX
invoke GET_IO_FCB
POP AX
JC ioctl_acc_err
invoke IOFUNC
MOV AH,AL
MOV AL,0FFH
JNZ ioctl_status_ret
INC AL
ioctl_status_ret:
transfer SYS_RET_OK
ioctl_bad_fun:
error error_invalid_function
ioctl_acc_err:
error error_access_denied
ioctl_get_dev:
PUSH CX
PUSH DX
PUSH AX
PUSH SI ;DS in disguise
MOV AL,BL ;Drive
invoke GETTHISDRV
JC ioctl_bad_drv
invoke FATREAD ;"get" the drive
MOV BL,ES:[BP.dpb_UNIT] ; Unit number
LES DI,ES:[BP.dpb_driver_addr]
CLC ;Make sure error jump not taken
ioctl_bad_drv:
POP SI
POP AX
POP DX
POP CX
JC ioctl_acc_err
ioctl_do_string:
TEST ES:[DI.SDEVATT],DEVIOCTL ;See if device accepts control
JZ ioctl_bad_fun ;NO
DEC AL
DEC AL
JZ ioctl_control_read
MOV [IOCALL.REQFUNC],DEVWRIOCTL
JMP SHORT ioctl_control_call
ioctl_control_read:
MOV [IOCALL.REQFUNC],DEVRDIOCTL
ioctl_control_call:
MOV AL,DRDWRHL
MOV AH,BL ;Unit number
MOV WORD PTR [IOCALL.REQLEN],AX
XOR AX,AX
MOV [IOCALL.REQSTAT],AX
MOV [IOMED],AL
MOV [IOSCNT],CX
MOV WORD PTR [IOXAD],DX
MOV WORD PTR [IOXAD+2],SI
PUSH ES
POP DS
ASSUME DS:NOTHING
MOV SI,DI ;DS:SI -> driver
PUSH SS
POP ES
MOV BX,OFFSET DOSGROUP:IOCALL ;ES:BX -> Call header
invoke DEVIOCALL2
MOV AX,[IOSCNT] ;Get actual bytes transferred
transfer SYS_RET_OK
$IOCTL ENDP
BREAK <File_Times - modify write times on a handle>
;
; Assembler usage:
; MOV AH, FileTimes
; MOV AL, func
; MOV BX, handle
; ; if AL = 1 then then next two are mandatory
; MOV CX, time
; MOV DX, date
; INT 21h
; ; if AL = 0 then CX/DX has the last write time/date
; ; for the handle.
;
; Error returns:
; AX = error_invalid_function
; = error_invalid_handle
;
procedure $File_times,near
CMP AL,2
JB filetimes_ok
error error_invalid_function
filetimes_ok:
PUSH SS
POP DS
CALL Get_sf_from_jfn
JNC filetimes_disp
error error_invalid_handle
filetimes_disp:
OR AL,AL
JNZ filetimes_set
MOV CX,ES:[DI.sf_fcb.fcb_FTIME]
MOV DX,ES:[DI.sf_fcb.fcb_FDATE]
invoke Get_user_stack
MOV [SI.user_CX],CX
MOV [SI.user_DX],DX
transfer SYS_RET_OK
filetimes_set:
MOV ES:[DI.sf_fcb.fcb_FTIME],CX
MOV ES:[DI.sf_fcb.fcb_FDATE],DX
AND ES:[DI.sf_fcb.fcb_DEVID],NOT devid_file_clean
transfer SYS_RET_OK
$file_times ENDP
do_ext
CODE ENDS
END
|