2025-04-27 07:49:33 -04:00

818 lines
22 KiB
NASM
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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