|
|
page ,132 title COMMAND Resident DATA ;/* ; * Microsoft Confidential ; * Copyright (C) Microsoft Corporation 1991 ; * All Rights Reserved. ; */
; ; Revision History ; ================ ; M003 SR 07/16/90 Added LoadHiFlg for LoadHigh support ; ; M004 SR 07/17/90 Transient is now moved to its final ; location at EndInit time by allocating ; the largest available block, moving ; the transient to the top of the block ; and then freeing up the block. ; ; M027 SR 9/20/90 Fixed bug #2827. EndInit was using ; INIT seg variables after INIT seg ; had been freed. ; ; M036 SR 11/1/90 Free up environment segment passed ; by Exec always. ;
.xlist .xcref include dossym.inc include pdb.inc include syscall.inc include comsw.asm include comseg.asm include resmsg.equ include comequ.asm include cmdsvc.inc .list .cref
; Equates for initialization (from COMEQU) ; ; Bugbug: Toss these after putting ctrl-c handler in init module.
INITINIT equ 01h ; initialization in progress INITSPECIAL equ 02h ; in initialization time/date routine INITCTRLC equ 04h ; already in ^C handler
CODERES segment public byte extrn Ext_Exec:near extrn MsgRetriever:far extrn TRemCheck:near
;SR; ; The stack has no right to be in the code segment. Moved it to DATARES ; ; bugbug: Why this odd stack size? And what should stack size be? ;; db (80h - 3) dup (?) ;;RStack label word ;; public RStack CODERES ends
INIT segment
extrn ConProc:near extrn Chuckenv:byte extrn UsedEnv:word extrn OldEnv:word extrn EnvSiz:word extrn TrnSize:word ; M004
INIT ends
TAIL segment
extrn TranStart :word
TAIL ends
TRANCODE segment public byte extrn Command:near TRANCODE ends
TRANSPACE segment
extrn TranSpaceEnd :byte
TRANSPACE ends
;SR; ; All the routines below are entry points into the stub from the transient. ;The stub will then transfer control to the appropriate routines in the ;resident code segment, wherever it is present. ;
DATARES segment
extrn Exec_Trap :near extrn RemCheck_Trap :near extrn MsgRetrv_Trap :near extrn HeadFix_Trap :near extrn Issue_Exec_Call :near
DATARES ends
DATARES segment public byte assume cs:DATARES Org 0 ZERO = $
;; Org 100h ;;ProgStart: ;; jmp RESGROUP:ConProc
public Abort_Char public Append_Flag public Append_State public BadFatSubst public Batch public Batch_Abort public BlkDevErrRw public BlkDevErrSubst public Call_Batch_Flag public Call_Flag public CDevAt public CharDevErrSubst public CharDevErrRw public Com_Fcb1 public Com_Fcb2 public Com_Ptr public ComDrv public ComSpec public ComSpec_End public Crit_Err_Info public Crit_Msg_Off public Crit_Msg_Seg public CritMsgPtrs public DataResEnd public Dbcs_Vector_Addr public DevName public DrvLet public EchoFlag public EnvirSeg public ErrCd_24 public ErrType public Exec_block public ExecErrSubst public Extcom public ExtMsgEnd public Fail_Char public fFail public ForFlag public ForPtr public FUCase_Addr public Handle01 public IfFlag public Ignore_Char public In_Batch public InitFlag public InPipePtr public Int_2e_Ret public Int2fHandler public Io_Save public Io_Stderr public LenMsgOrPathBuf public Loading public LTpa public MemSiz public MsgBuffer public MsgPtrLists public MySeg public MySeg1 public MySeg2 public MySeg3 public NeedVol public NeedVolSubst public Nest public Next_Batch public No_Char public NullFlag public NUMEXTMSGS public NUMPARSMSGS public OldErrNo public OldTerm public OutPipePtr public Parent public ParsMsgPtrs public PermCom public Pipe1 ;;; public Pipe1T public Pipe2 ;;; public Pipe2T public PipeFiles public PipeFlag public PipePtr public PipeStr public KSwitchFlag public PutBackComSpec public PutBackDrv public PutBackSubst public RDirChar public Re_Out_App public Re_OutStr public ResMsgEnd public Res_Tpa public RestDir public ResTest public RetCode public Retry_Char public RSwitChar public SafePathBuffer ; MSKK01 07/14/89 public Save_Pdb public SingleCom public Sum public Suppress public Trans public TranVarEnd public TranVars public TrnSeg public TrnMvFlg public VerVal public VolName public VolSer public Yes_Char
public ResSize public RStack public OldDS
public LoadHiFlg ;For LoadHigh support ; M003 public SCS_Is_First public SCS_REENTERED public SCS_FIRSTCOM
public SCS_PAUSE public SCS_CMDPROMPT public SCS_DOSONLY public SCS_PROMPT16 public SCS_FIRSTTSR public RES_RDRINFO public RES_BATSTATUS
extrn LodCom_Trap:near extrn Alloc_error:near
;*** Message substitution blocks
BlkDevErrSubst label byte BlkDevErrRw subst <STRING,> ; "reading" or "writing" subst <CHAR,DATARES:DrvLet> ; block device drive letter
DrvLet db 'A' ; drive letter
CharDevErrSubst label byte CharDevErrRw subst <STRING,> ; "reading" or "writing" CharDevErrDev subst <STRING,DATARES:DevName> ; character device name
DevName db 8 dup (?),0 ; device name, asciiz
NeedVolSubst label byte subst <STRING,DATARES:VolName> ; volume name subst <HEX,DATARES:VolSer+2> ; hi word of serial # subst <HEX,DATARES:VolSer> ; lo word of serial #
; NOTE: VolName and VolSer must be adjacent VolName db 11 dup (?),0 ; volume name VolSer dd 0 ; volume serial #
CDevAt db ?
BadFatSubst label byte subst <CHAR,DATARES:DrvLet> ; drive letter
PutBackSubst label byte PutBackComSpec subst <STRING,> ; comspec string subst <CHAR,DATARES:PutBackDrv> ; drive to put it in
PutBackDrv db ' ' ; drive letter
ExecErrSubst subst <STRING,DATARES:SafePathBuffer>
NeedVol dd ? ; ptr to volume name from get ext err ErrType db ? ; critical error message style, 0=old, 1=new
Int_2e_Ret dd ? ; magic command executer return address Save_Pdb dw ? Parent dw ? OldTerm dd ? ErrCd_24 dw ? Handle01 dw ? Loading db 0 Batch dw 0 ; assume no batch mode initially
;;;;SR; ;;;; This flag has been added for a gross hack introduced in batch processing. ;;;;We use it to indicate that this batch file has no CR-LF before EOF and that ;;;;we need to fake the CR-LF for the line to be properly processed ;;;; ;;;BatchEOF db 0
; Bugbug: ComSpec should be 64+3+12+1? ; What's this comspec_end about? ComSpec db 64 dup (0) ComSpec_End dw ?
Trans label dword dw TRANGROUP:Command TrnSeg dw ?
TrnMvFlg db 0 ; set if transient portion has been moved
In_Batch db 0 ; set if we are in batch processing mode Batch_Abort db 0 ; set if user wants to abort from batch mode
ComDrv db ? ; drive spec to load autoexec and command MemSiz dw ? Sum dw ? ExtCom db 1 ; for init, pretend just did an external RetCode dw ? Crit_Err_Info db ? ; hold critical error flags for r,i,f
; The echo flag needs to be pushed and popped around pipes and batch files. ; We implement this as a bit queue that is shr/shl for push and pop.
EchoFlag db 00000001b ; low bit true => echo commands Suppress db 1 ; used for echo, 1=echo line Io_Save dw ? Io_Stderr db ? RestDir db 0 PermCom db 0 ; true => permanent command SingleCom dw 0 ; true => single command version KSwitchFlag db 0 VerVal dw -1 fFail db 0 ; true => fail all int 24s IfFlag db 0 ; true => IF statement in progress
ForFlag db 0 ; true => FOR statement in progress ForPtr dw 0
Nest dw 0 ; nested batch file counter Call_Flag db 0 ; no CALL (batch command) in progress Call_Batch_Flag db 0 Next_Batch dw 0 ; address of next batch segment NullFlag db 0 ; flag if no command on command line FUCase_Addr db 5 dup (0) ; buffer for file ucase address ; Bugbug: don't need crit_msg_ anymore? Crit_Msg_Off dw 0 ; saved critical error message offset Crit_Msg_Seg dw 0 ; saved critical error message segment Dbcs_Vector_Addr dw 0 ; DBCS vector offset dw 0 ; DBCS vector segment
Append_State dw 0 ; current state of append ; (if Append_Flag is set) Append_Flag db 0 ; set if append state is valid
SCS_PAUSE db 0 ; yst 4-5-93
Re_Out_App db 0 Re_OutStr db 64+3+13 dup (?) SCS_Is_First db 1 SCS_REENTERED db 0 SCS_FIRSTCOM db 0 SCS_CMDPROMPT db 0 ; means on TSR/Shell out use command.com SCS_DOSONLY db 0 ; means by default run all binaries ; when at command.com prompt. if 1 means ; allow only dos binaries. SCS_PROMPT16 db 0 SCS_FIRSTTSR db 1 RES_RDRINFO DD 0 RES_BATSTATUS db 0
; We flag the state of COMMAND in order to correctly handle the ^Cs at ; various times. Here is the breakdown: ; ; INITINIT We are in the init code. ; INITSPECIAL We are in the date/time prompt ; INITCTRLC We are handling a ^C already. ; ; If we get a ^C in the initialization but not in the date/time prompt, we ; ignore the ^C. This is so the system calls work on nested commands. ; ; If we are in the date/time prompt at initialization, we stuff the user's ; input buffer with a CR to pretend an empty response. ; ; If we are already handling a ^C, we set the carry bit and return to the user ; (ourselves). We can then detect the carry set and properly retry the ; operation.
InitFlag db INITINIT
; Note: these two bytes are referenced as a word PipeFlag db 0 PipeFiles db 0
;--- 2.x data for piping ; ; All the "_" are substituted later, the one before the : is substituted ; by the current drive, and the others by the CreateTemp call with the ; unique file name. Note that the first 0 is the first char of the pipe ; name. -MU ; ;--- Order-dependent, do not change
;;;Pipe1 db "_:/" ;;;Pipe1T db 0 ;;; db "_______.___",0 ;;;Pipe2 db "_:/" ;;;Pipe2T db 0 ;;; db "_______.___",0
;SR ; Pipe1 & Pipe2 now need to store full-fledged pathnames ;
; Bugbug: can we find any way around maintaining these ; large buffers?
Pipe1 db 67+12 dup (?) Pipe2 db 67+12 dup (?)
PipePtr dw ?
PipeStr db 129 dup (?)
EndPipe label byte ; marks end of buffers; M004
;SR; ; We can move our EndInit code into above buffers. This way, the code will ;automatically be discarded after init. ; ; M004; We overlap our code with the Pipe buffers located above by changing ; M004; the origin. ; ORG Pipe1 ; M004
; Bugbug: really need a procedure header for EndInit, describing ; what it expects, what it does.
Public EndInit EndInit: push ds push es ;save segments push cs pop ds assume ds:RESGROUP
; ; M004; Save size of transient here before INIT segment is deallocated ; mov dx,TrnSize ; M004 ;M027 ; These variables are also defined in the INIT segment and need to be saved ;before we resize ; mov ax,OldEnv ; Old Environment seg ;M027 mov bx,EnvSiz ; Size of new environment ;M027 mov cx,UsedEnv ; Size of old environment ;M027 push ax ; Save all these values ;M027 push bx ; M027 push cx ; M027
; Bugbug: push ds, pop es here. mov bx,ds mov es,bx ;es = RESGROUP ; ;ResSize is the actual size to be retained -- only data for HIMEM COMMAND, ; code + data for low COMMAND ; mov bx,ResSize ;Total size of resident mov ah,SETBLOCK int 21h ;Set block to resident size ; ;We check if this is for autoexec.bat (PermCom = 1). If so, we then ;allocate a new batch segment, copy the old one into new batchseg and free ;the old batchseg. Remember that the old batchseg was allocated on top of the ;transient and we will leave a big hole if TSRs are loaded by autoexec.bat ; ; Bugbug: also describe why we alloc & copy batch seg BEFORE environment. cmp PermCom,1 ;permanent command.com? jne adjust_env ;no, do not free batchseg
cmp Batch,0 ;was there a valid batchseg? je adjust_env ;no, dont juggle
; NTVDM temp name of the batch file may be up to 63 bytes, plus NULL ; mov bx,((SIZE BatchSegment) + 15 + 1 + 0fh)/16 ;batchseg size mov bx,((SIZE BatchSegment) + 64 + 1 + 0fh)/16 ;batchseg size mov ah,ALLOC int 21h ; Bugbug: I just had a thought. If DOS or SHARE or somebody leaves ; a hole, the batch segment COULD already be in the ideal place. We ; could be making it worse! We're second-guessing where memory ; allocations go, which might not be such a great idea. Is there ; a strategy, short of doing something even worse like diddling ; arena headers, where we can minimize the possibility of fragmentation ; under all cases? Hmm.. jc adjust_env ;no memory, use old batchseg mov es,ax ;es = New batch segment xor di,di xor si,si
push ds mov ds,Batch ;ds = Old Batch Segment assume ds:nothing mov cx,SIZE BatchSegment ; NTVDM temp name of the batch file may be up to 63 bytes, plus NULL ; add cx,16 ;for the filename add cx,64 ; Bugbug: 16? Shouldn't this be a common equate or something? ; It's sure be bad if we copied more bytes than the batch segment ; holds! cld rep movsb pop ds assume ds:RESGROUP
mov cx,es ;save new batch segment mov es,Batch mov ah,DEALLOC int 21h ;free the old batch segment ; Bugbug: should we check for error?
mov Batch,cx ;store new batch segment address
adjust_env: pop cx ;cx = size of old env ;M027 pop bx ;bx = size of new env needed ;M027 pop bp ;bp = old env seg ;M027
; ;Allocate the correct size for the environment ; mov ah,ALLOC int 21h ;get memory jc init_env_err ;out of memory,signal error
; Bugbug: why not continue, leaving environment where it is?
mov EnvirSeg,ax ;Store new environment segment mov ds:PDB_Environ,ax ;Put new env seg in PSP mov es,ax ;es = address of allocated memory assume es:nothing
cmp PermCom, 1 jne copy_old_env
; ; First get the size of 32bit env ;
push bx mov bx, 0 CMDSVC SVC_GETINITENVIRONMENT mov ax, bx pop bx cmp ax, 0 ;bx returns 0, use old environment je copy_old_env
; ; now compute the new size ; [ax] = size of 32 bit env ;
add bx, ax mov ah, DEALLOC ;free the block int 21h mov ah, ALLOC ;and get a new block(don't use realloc please) int 21h jc nomem_err
mov EnvirSeg,ax ;Store new environment segment mov ds:PDB_Environ,ax ;Put new env seg in PSP mov es,ax ;es = address of allocated memory mov EnvSiz, bx ;new size push bx CMDSVC SVC_GETINITENVIRONMENT ;get new environment pop ax cmp bx, ax jbe adjust_env_done init_env_err: jmp short nomem_err copy_old_env: ; ;Copy the environment to the newly allocated segment ; push ds mov ds, bp ;ds = Old environment segment assume ds:nothing
xor si,si mov di,si ;Start transfer from 0
cld rep movsb ;Do the copy
pop ds ;ds = RESGROUP assume ds:RESGROUP adjust_env_done:
; ;We have to free the old environment block if it was allocated by INIT ; ; Bugbug: is this only for the case when we were NOT passed an environment, ; or does it also apply to passed environments? ;M036 ; Free up old env segment always because this is a copy passed by Exec and ;takes up memory that is never used ; ;M044 ;Go back to the old strategy of not freeing the environment. Freeing it leaves ;a hole behind that Ventura does not like. Basically, Ventura gives strange ;errors if it gets a memory alloc that it is below its load segment. The ;freed environment creates a large enough hole for some of its allocs to fit ;in ; cmp Chuckenv,0 ;has env been allocated by INIT? jne no_free ;no, do not free it
mov es,bp mov ah,DEALLOC int 21h ;Free it no_free:
; ; M004; Start of changes ;
; ; Move the transient now. We will allocate the biggest block available ; now and move the transient to the top of the block. We will then ; deallocate this block. When the resident starts executing, it will ; hopefully allocate this block again and find the transient intact. ; MOV TrnMvFlg, 1 ; Indicate that transient has been moved push es mov si,offset ResGroup:TranStart mov di,0 mov cx,offset TranGroup:TranSpaceEnd ;size to move ; ; Find the largest block available ; mov bx,0ffffh mov ah,ALLOC int 21h
; ; dx = size of transient saved previously ; cmp bx,dx ;enough memory? jb nomem_err ;not enough memory for transient
mov ah,ALLOC int 21h ;get the largest block jc nomem_err ;something is really messed up
push ax ;save memory address add ax,bx ;ax = top of my memory block sub ax,dx ;less size of transient mov TrnSeg,ax ;save transient segment mov es,ax ; pop ax ;restore our seg addr
; ; Everything is set for a move. We need to move in the reverse direction to ; make sure we dont overwrite ourselves while copying ; add si,cx dec si add di,cx dec di std rep movsb cld ; ; Now we have to free up this block so that resident can get hold of it ; mov es,ax mov ah,DEALLOC int 21h ;release the memory block
; ; M004; End of changes ;
mov InitFlag,FALSE ;indicate INIT is done
pop es pop ds ; Bugbug: did we need to save & restore seg reg's during EndInit? assume ds:nothing
jmp LodCom_Trap ;allocate transient
nomem_err: ; ;We call the error routine which will never return. It will either exit ;with an error ( if not the first COMMAND ) or just hang after an error ;message ( if first COMMAND ) ;
jmp Alloc_error
public EndCodeInit ; M004 EndCodeInit label byte ; M004
; ; M004; Check if the EndInit code will fit into the Pipe buffers above. ; M004; If not, we signal an assembly error ; IF2 IF ($ GT EndPipe) .err %out "ENDINIT CODE TOO BIG"
ENDIF ENDIF ; ; M004; Set the origin back to what it was at the end of the buffers ; ORG EndPipe ; M004
InPipePtr dw offset DATARES:Pipe1 OutPipePtr dw offset DATARES:Pipe2
Exec_Block label byte ; the data block for exec calls EnvirSeg dw ? Com_Ptr label dword dw 80h ; point at unformatted parameters dw ? Com_Fcb1 label dword dw 5Ch dw ? Com_Fcb2 label dword dw 6Ch dw ?
; variables passed to transient TranVars label byte dw offset DATARES:HeadFix_Trap MySeg dw 0 ; put our own segment here LTpa dw 0 ; will store tpa segment here RSwitChar db "/" RDirChar db "\" dw offset DATARES:Issue_Exec_Call MySeg1 dw ? dw offset DATARES:RemCheck_Trap MySeg2 dw 0 ResTest dw 0 Res_Tpa dw 0 ; original tpa (not rounded to 64k) TranVarEnd label byte
OldErrNo dw ?
;* NOTE: MsgBuffer and SafePathBuffer use the same ; memory. MsgBuffer is only used while a command ; is being executed. SafePathBuffer is no longer ; needed, since it is used for unsuccessful program ; launches.
MsgBuffer label byte ; buffer for messages from disk SafePathBuffer label byte ; resident pathname for EXEC ; db 128 dup (0) ; path + 'd:\' 'file.ext' + null db EXECPATHLEN dup (0) ; MAX_PATH+13 ntvdm extended LenMsgOrPathBuf equ $ - MsgBuffer
Int2fHandler dd ? ; address of next int 2f handler ResMsgEnd dw 0 ; holds offset of msg end (end of resident)
;SR; ; The three vars below have been added for a pure COMMAND.COM ;
ResSize dw ?
;SR; ; Moved the stack here from the code segment ; ; bugbug: Why this odd stack size? And what should stack size be? db (80h - 3) dup (?) RStack label word
OldDS dw ? ;keeps old ds value when jumping to ;resident code segments
LoadHiFlg db 0 ;Flag set to 1 if UMB loading enabled ; M003
ifdef BETA3WARN %out Take this out before we ship
public Beta3Warned Beta3Warned db 0 endif
;*** MESSAGES ; and other translatable text
include comrmsg.inc ;M00
DATARES ends end
|