summaryrefslogtreecommitdiff
path: root/v2.0/source/XENIX2.ASM
blob: 1535dbb6b67797581279cfb288c819eac1c727a4 (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
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