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
|
page 80,132
; SCCSID = @(#)command2.asm 4.3 85/10/16
; SCCSID = @(#)command2.asm 4.3 85/10/16
TITLE COMMAND2 - resident code for COMMAND.COM part II
NAME COMMAND2
.XCREF
.XLIST
INCLUDE DOSSYM.INC
INCLUDE comsw.asm
INCLUDE comequ.asm
INCLUDE resmsg.equ ;AN000;
.LIST
.CREF
tokenized = FALSE
CODERES SEGMENT PUBLIC BYTE ;AC000;
CODERES ENDS
DATARES SEGMENT PUBLIC BYTE
EXTRN append_state:word ;AN020;
EXTRN append_flag:byte ;AN020;
EXTRN COMDRV:BYTE
EXTRN comprmt1_block:byte ;AN000;
EXTRN comprmt1_subst:byte ;AN000;
EXTRN COMSPEC:BYTE
EXTRN cpdrv:byte
EXTRN envirseg:word
EXTRN EXTCOM:BYTE
EXTRN HANDLE01:WORD
EXTRN InitFlag:BYTE
EXTRN INT_2E_RET:DWORD ;AC000;
EXTRN IO_SAVE:WORD
EXTRN LOADING:BYTE
EXTRN LTPA:WORD
EXTRN MEMSIZ:WORD
EXTRN number_subst:byte ;AN000;
EXTRN OldTerm:DWORD ;AC000;
EXTRN PARENT:WORD ;AC000;
EXTRN PERMCOM:BYTE
EXTRN RDIRCHAR:BYTE
EXTRN RES_TPA:WORD
EXTRN RETCODE:WORD
EXTRN rsrc_xa_seg:word ;AN030;
EXTRN RSWITCHAR:BYTE
EXTRN SAVE_PDB:WORD
EXTRN SINGLECOM:WORD
EXTRN SUM:WORD
EXTRN TRANS:WORD
EXTRN TranVarEnd:BYTE
EXTRN TRANVARS:BYTE
EXTRN TRNSEG:WORD
EXTRN VERVAL:WORD
DATARES ENDS
BATARENA SEGMENT PUBLIC PARA ;AC000;
BATARENA ENDS
BATSEG SEGMENT PUBLIC PARA ;AC000;
BATSEG ENDS
ENVARENA SEGMENT PUBLIC PARA ;AC000;
ENVARENA ENDS
ENVIRONMENT SEGMENT PUBLIC PARA ; Default COMMAND environment
ENVIRONMENT ENDS
INIT SEGMENT PUBLIC PARA
EXTRN envsiz:word
EXTRN oldenv:word
EXTRN resetenv:byte
EXTRN usedenv:word
INIT ENDS
TAIL SEGMENT PUBLIC PARA
TAIL ENDS
TRANCODE SEGMENT PUBLIC PARA
TRANCODE ENDS
TRANDATA SEGMENT PUBLIC BYTE
EXTRN TRANDATAEND:BYTE
TRANDATA ENDS
TRANSPACE SEGMENT PUBLIC BYTE
EXTRN TRANSPACEEND:BYTE
EXTRN HEADCALL:DWORD
TRANSPACE ENDS
TRANTAIL SEGMENT PUBLIC PARA
TRANTAIL ENDS
RESGROUP GROUP CODERES,DATARES,BATARENA,BATSEG,ENVARENA,ENVIRONMENT,INIT,TAIL
TRANGROUP GROUP TRANCODE,TRANDATA,TRANSPACE,TRANTAIL
; START OF RESIDENT PORTION
CODERES SEGMENT PUBLIC BYTE ;AC000;
PUBLIC CHKSUM
PUBLIC endinit
PUBLIC GETCOMDSK2
PUBLIC INT_2E
PUBLIC LOADCOM
PUBLIC LODCOM
PUBLIC LODCOM1
PUBLIC RESTHAND
PUBLIC SAVHAND
PUBLIC SETVECT
PUBLIC THEADFIX
PUBLIC TREMCHECK
PUBLIC tjmp
ASSUME CS:RESGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
EXTRN contc:near
EXTRN DSKERR:NEAR
EXTRN rstack:word
;
; If we cannot allocate enough memory for the transient or there was some
; other allocation error, we display a message and then die.
;
BADMEMERR: ; Allocation error loading transient
MOV DX,BMEMMES ;AC000; get message number
FATALC:
PUSH CS
POP DS
ASSUME DS:ResGroup
invoke RPRINT
;
; If this is NOT a permanent (top-level) COMMAND, then we exit; we can't do
; anything else!
;
CMP PERMCOM,0
JZ FATALRET
;
; We are a permanent command. If we are in the process of the magic interrupt
; (Singlecom) then exit too.
;
CMP SINGLECOM,0 ; If PERMCOM and SINGLECOM
JNZ FATALRET ; Must take INT_2E exit
;
; Permanent command. We can't do ANYthing except halt.
;
MOV DX,HALTMES ;AC000; get message number
invoke RPRINT
STI
STALL:
JMP STALL ; Crash the system nicely
FATALRET:
MOV DX,FRETMES ;AC000; get message number
invoke RPRINT
FATALRET2:
CMP [PERMCOM],0 ; If we get here and PERMCOM,
JNZ RET_2E ; must be INT_2E
invoke reset_msg_pointers ;AN000; reset critical & parse error messages
MOV AX,[PARENT]
MOV WORD PTR CS:[PDB_Parent_PID],AX
MOV AX,WORD PTR OldTerm
MOV WORD PTR CS:[PDB_Exit],AX
MOV AX,WORD PTR OldTerm+2
MOV WORD PTR CS:[PDB_Exit+2],AX
MOV AX,(EXIT SHL 8) ; Return to lower level
INT int_command
RET_2E:
PUSH CS
POP DS
ASSUME DS:RESGROUP,ES:NOTHING,SS:NOTHING
MOV [SINGLECOM],0 ; Turn off singlecom
MOV ES,[RES_TPA]
MOV AH,DEALLOC
INT int_command ; Free up space used by transient
MOV BX,[SAVE_PDB]
MOV AH,SET_CURRENT_PDB
INT int_command ; Current process is user
MOV AX,[RETCODE]
CMP [EXTCOM],0
JNZ GOTECODE
XOR AX,AX ; Internals always return 0
GOTECODE:
MOV [EXTCOM],1 ; Force external
JMP [INT_2E_RET] ;"IRET"
INT_2E: ; Magic command executer
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
POP WORD PTR [INT_2E_RET]
POP WORD PTR [INT_2E_RET+2] ;Get return address
POP AX ;Chuck flags
PUSH CS
POP ES
MOV DI,80H
MOV CX,64
REP MOVSW
MOV AH,GET_CURRENT_PDB
INT int_command ; Get user's header
MOV [SAVE_PDB],BX
MOV AH,SET_CURRENT_PDB
MOV BX,CS
INT int_command ; Current process is me
MOV [SINGLECOM],81H
MOV [EXTCOM],1 ; Make sure this case forced
LODCOM: ; Termination handler
CMP [EXTCOM],0
jz lodcom1 ; if internal, memory already allocated
mov bx,0ffffh
MOV AH,ALLOC
INT int_command
CALL SetSize
ADD AX,20H
CMP BX,AX ; Is less than 512 byte buffer worth it?
JNC MEMOK
BADMEMERRJ:
JMP BADMEMERR ; Not enough memory
; SetSize - get transient size in paragraphs
Procedure SetSize,NEAR
MOV AX,OFFSET TRANGROUP:TRANSPACEEND + 15
MOV CL,4
SHR AX,CL
return
EndProc SetSize
MEMOK:
MOV AH,ALLOC
INT int_command
JC BADMEMERRJ ; Memory arenas probably trashed
MOV [EXTCOM],0 ; Flag not to ALLOC again
MOV [RES_TPA], AX ; Save current TPA segment
AND AX, 0F000H
ADD AX, 01000H ; Round up to next 64K boundary
JC BAD_TPA ; Memory wrap if carry set
; Make sure that new boundary is within allocated range
MOV DX, [RES_TPA]
ADD DX, BX ; Compute maximum address
CMP DX, AX ; Is 64K address out of range?
JBE BAD_TPA
; Must have 64K of usable space.
SUB DX, AX ; Compute the usable space
CMP DX, 01000H ; Is space >= 64K ?
JAE LTPASET
BAD_TPA:
MOV AX, [RES_TPA]
LTPASET:
MOV [LTPA],AX ; Usable TPA is 64k buffer aligned
MOV AX, [RES_TPA] ; Actual TPA is buffer allocated
ADD BX,AX
MOV [MEMSIZ],BX
CALL SetSize
SUB BX,AX
MOV [TRNSEG],BX ; Transient starts here
LODCOM1:
MOV AX,CS
MOV SS,AX
ASSUME SS:RESGROUP
MOV SP,OFFSET RESGROUP:RSTACK
MOV DS,AX
ASSUME DS:RESGROUP
CALL HEADFIX ; Make sure files closed stdin and stdout restored
XOR BP,BP ; Flag command ok
MOV AX,-1
XCHG AX,[VERVAL]
CMP AX,-1
JZ NOSETVER
MOV AH,SET_VERIFY_ON_WRITE ; AL has correct value
INT int_command
NOSETVER:
CMP [SINGLECOM],-1
JNZ NOSNG
JMP FATALRET2 ; We have finished the single command
NOSNG:
CALL CHKSUM ; Check the transient
CMP DX,[SUM]
JZ HAVCOM ; Transient OK
BOGUS_COM:
MOV [LOADING],1 ; Flag DSKERR routine
CALL LOADCOM
CHKSAME:
CALL CHKSUM
CMP DX,[SUM]
JZ HAVCOM ; Same COMMAND
ALSO_BOGUS:
CALL WRONGCOM
JMP SHORT CHKSAME
HAVCOM:
MOV AX,CHAR_OPER SHL 8
INT int_command
MOV [RSWITCHAR],DL
CMP DL,'/'
JNZ USESLASH
mov cl,'\'
MOV [RDIRCHAR],cl ; Select alt path separator
USESLASH:
MOV [LOADING],0 ; Flag to DSKERR
MOV SI,OFFSET RESGROUP:TRANVARS
MOV DI,OFFSET TRANGROUP:HEADCALL
MOV ES,[TRNSEG]
CLD
MOV CX,OFFSET ResGroup:TranVarEnd
SUB CX,SI
REP MOVSB ; Transfer INFO to transient
MOV AX,[MEMSIZ]
MOV WORD PTR DS:[PDB_block_len],AX ; Adjust my own header
; Just a public label so this spot can be found easily.
tjmp:
JMP DWORD PTR [TRANS]
; Far call to REMCHECK for TRANSIENT
TREMCHECK PROC FAR
CALL REMCHECK
RET
TREMCHECK ENDP
REMCHECK:
;All registers preserved. Returns ZF set if media removable, NZ if fixed
; AL is drive (0=DEF, 1=A,...).
SaveReg <AX,BX>
MOV BX,AX
MOV AX,(IOCTL SHL 8) + 8
INT 21h
jnc RCcont ; If an error occurred, assume the media
or ax,ax ; is NON-removable.
; AX contains the non-zero error code
; from the INT 21, so the OR AX,AX sets
; Non-zero. This behavior makes Network
; drives appear to be non-removable.
jmp SHORT ResRegs
RCcont:
AND AX,1
NOT AX
ResRegs:
RestoreReg <BX,AX>
return
; Far call to HEADFIX for TRANSIENT
THEADFIX PROC FAR
CALL HEADFIX
RET
THEADFIX ENDP
HEADFIX:
CALL SETVECT
XOR BX,BX ; Clean up header
MOV CX,[IO_SAVE]
MOV DX,WORD PTR DS:[PDB_JFN_Table]
CMP CL,DL
JZ CHK1 ; Stdin matches
MOV AH,CLOSE
INT int_command
MOV DS:[PDB_JFN_Table],CL ; Restore stdin
CHK1:
INC BX
CMP CH,DH ; Stdout matches
JZ CHKOTHERHAND
MOV AH,CLOSE
INT int_command
MOV DS:[PDB_JFN_Table+1],CH ; Restore stdout
CHKOTHERHAND:
ADD BX,4 ; Skip 2,3,4
MOV CX,FilPerProc - 5 ; Already done 0,1,2,3,4
CLOSELOOP:
MOV AH,CLOSE
INT int_command
INC BX
LOOP CLOSELOOP
push ds ;AN020; save data segment
push cs ;AN020; Get local segment into DS
pop ds ;AN020;
cmp append_flag,-1 ;AN020; Do we need to reset APPEND?
jnz append_fix_end ;AN030; no - just exit
mov ax,AppendSetState ;AN020; Set the state of Append
mov bx,Append_state ;AN020; back to the original state
int 2fh ;AN020;
mov append_flag,0 ;AN020; Set append flag to invalid
append_fix_end: ;AN030;
cmp [rsrc_xa_seg],no_xa_seg ;AN030; Is there any active XA segment?
jz xa_fix_end ;AN030; no - exit
push es ;AN030; Yes - deallocate it
mov es,rsrc_xa_seg ;AN030;
mov ax,(Dealloc SHL 8) ;AN030; Deallocate memory call
int int_command ;AN030;
pop es ;AN030;
mov [rsrc_xa_seg],no_xa_seg ;AN030; reset to no segment
xa_fix_end:
pop ds ;AN020; get data segment back
return
SAVHAND:
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
PUSH DS
PUSH BX ; Set stdin to sterr, stdout to stderr
PUSH AX
MOV AH,GET_CURRENT_PDB
INT int_command ; Get user's header
MOV DS,BX
LDS BX,DS:[PDB_JFN_POINTER] ; get pointer to JFN table...
MOV AX,WORD PTR DS:[BX]
MOV [HANDLE01],AX ; Save user's stdin, stdout
MOV AL,CS:[PDB_JFN_Table+2] ; get COMMAND stderr
MOV AH,AL
MOV WORD PTR DS:[BX],AX ; Dup stderr
POP AX
POP BX
POP DS
return
ASSUME DS:RESGROUP
GETCOMDSK2:
CALL GETCOMDSK
JMP LODCOM1 ; Memory already allocated
RESTHAND:
PUSH DS
PUSH BX ; Restore stdin, stdout to user
PUSH AX
MOV AH,GET_CURRENT_PDB
INT int_command ; Point to user's header
MOV AX,[HANDLE01]
MOV DS,BX
ASSUME DS:NOTHING
LDS BX,DS:[PDB_JFN_POINTER] ; get pointer to JFN table...
MOV WORD PTR DS:[BX],AX ; Stuff his old 0 and 1
POP AX
POP BX
POP DS
return
ASSUME DS:RESGROUP,SS:RESGROUP
HOPELESS:
MOV DX,COMBAD ;AC000;
JMP FATALC
GETCOMDSK:
mov al,[comdrv]
CALL REMCHECK
jNZ HOPELESS ;Non-removable media
getcomdsk3:
cmp dx,combad ;AC000;
jnz getcomdsk4
mov dx,combad ;AN000; get message number
invoke RPRINT ; Say command is invalid
getcomdsk4:
cmp [cpdrv],0 ;g is there a drive in the comspec?
jnz users_drive ;g yes - use it
mov ah,Get_default_drive ;g use default drive
int 21h ;g
add al,"A" ;g convert to ascii
mov [cpdrv],al ;g put in message to print out
users_drive: ;g
mov dx,comprmt1 ;AC000; Prompt for diskette containing command
IF tokenized
or byte ptr [si],80h
endif
MOV AL,COMPRMT1_SUBST ;AN000; get number of substitutions
MOV SI,OFFSET RESGROUP:COMPRMT1_BLOCK ;AN000; get address of subst block
MOV NUMBER_SUBST,AL ;AN000;
invoke rprint
if tokenized
and byte ptr [si],NOT 80h
endif
mov dx,prompt ;AN047; Tell the user to strike a key
invoke rprint ;AN047;
CALL GetRawFlushedByte
return
; flush world and get raw input
GetRawFlushedByte:
MOV AX,(STD_CON_INPUT_FLUSH SHL 8) OR RAW_CON_INPUT
INT int_command ; Get char without testing or echo
MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0
INT int_command
return
LOADCOM: ; Load in transient
INC BP ; Flag command read
MOV DX,OFFSET RESGROUP:COMSPEC
MOV AX,OPEN SHL 8
INT int_command ; Open COMMAND.COM
JNC READCOM
CMP AX,error_too_many_open_files
JNZ TRYDOOPEN
MOV DX,NOHANDMES ;AC000;
JMP FATALC ; Fatal, will never find a handle
TRYDOOPEN:
CALL GETCOMDSK
JMP LOADCOM
READCOM:
MOV BX,AX ; Handle
MOV DX,OFFSET RESGROUP:TRANSTART
XOR CX,CX ; Seek loc
MOV AX,LSEEK SHL 8
INT int_command
JC WRONGCOM1
MOV CX,OFFSET TRANGROUP:TRANSPACEEND - 100H
PUSH DS
MOV DS,[TRNSEG]
ASSUME DS:NOTHING
MOV DX,100H
MOV AH,READ
INT int_command
POP DS
ASSUME DS:RESGROUP
WRONGCOM1:
PUSHF
PUSH AX
MOV AH,CLOSE
INT int_command ; Close COMMAND.COM
POP AX
POPF
JC WRONGCOM ; If error on READ
CMP AX,CX
retz ; Size matched
WRONGCOM:
MOV DX,COMBAD ;AC000;
CALL GETCOMDSK
JMP LOADCOM ; Try again
CHKSUM: ; Compute transient checksum
PUSH DS
MOV DS,[TRNSEG]
MOV SI,100H
MOV CX,OFFSET TRANGROUP:TranDataEnd - 100H
CHECK_SUM:
CLD
SHR CX,1
XOR DX,DX
CHK:
LODSW
ADD DX,AX
ADC DX,0
LOOP CHK
POP DS
return
SETVECT: ; Set useful vectors
MOV DX,OFFSET RESGROUP:LODCOM
MOV AX,(SET_INTERRUPT_VECTOR SHL 8) OR 22H
MOV WORD PTR DS:[PDB_EXIT],DX
MOV WORD PTR DS:[PDB_EXIT+2],DS
INT int_command
MOV DX,OFFSET RESGROUP:CONTC
INC AL
INT int_command
MOV DX,OFFSET RESGROUP:DSKERR
INC AL
INT int_command
return
;
; This routine moves the environment to a newly allocated segment
; at the end of initialization
;
ENDINIT:
push ds ;g save segments
push es ;g
push cs ;g get resident segment to DS
pop ds ;g
ASSUME DS:RESGROUP
mov cx,usedenv ;g get number of bytes to move
mov es,envirseg ;g get target environment segment
ASSUME ES:NOTHING
mov DS:[PDB_environ],es ;g put new environment in my header ;AM067;
mov ds,oldenv ;g source environment segment ;AM067;
ASSUME DS:NOTHING ;AM067;
xor si,si ;g set up offsets to start of segments ;AM067;
xor di,di ;g ;AM067;
cld ;g make sure we move the right way! ;AM067;
rep movsb ;g move it ;AM067;
xor ax,ax ;g ;AM067;
stosb ;g make sure there are double 0 at end ;AM067;
cmp resetenv,1 ;eg Do we need to setblock to env end?
jnz noreset ;eg no - we already did it
mov bx,envsiz ;eg get size of environment in paragraphs
push es ;eg save environment - just to make sure
mov ah,SETBLOCK ;eg
int int_command ;eg
pop es ;eg
noreset:
mov InitFlag,FALSE ;AC042; Turn off init flag
pop es ;g
pop ds ;g
jmp lodcom ;g allocate transient
CODERES ENDS
; This TAIL segment is used to produce a PARA aligned label in the resident
; group which is the location where the transient segments will be loaded
; initial.
TAIL SEGMENT PUBLIC PARA
ORG 0
PUBLIC TranStart
TRANSTART LABEL WORD
TAIL ENDS
; This TAIL segment is used to produce a PARA aligned label in the transient
; group which is the location where the exec segments will be loaded
; initial.
TRANTAIL SEGMENT PUBLIC PARA
ORG 0
EXECSTART LABEL WORD
TRANTAIL ENDS
END
|