You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
336 lines
8.7 KiB
336 lines
8.7 KiB
page ,132
|
|
title Command Stub
|
|
;/*
|
|
; * Microsoft Confidential
|
|
; * Copyright (C) Microsoft Corporation 1991
|
|
; * All Rights Reserved.
|
|
; */
|
|
|
|
;
|
|
; Revision History
|
|
; ================
|
|
;
|
|
; M003 SR 07/16/90 Check if UMB loading enabled and if so
|
|
; turn it off on return from Exec
|
|
;
|
|
; M005 SR 07/20/90 Carousel hack. Added a hard-coded far
|
|
; jump to the actual int 2fh entry
|
|
; point to fix Carousel problems.
|
|
;
|
|
; M009 SR 08/01/90 Restore the UMB state before the Exec
|
|
; from the saved state in LoadHiFlg.
|
|
;
|
|
; M035 SR 10/27/90 Enable interrupts at the start of
|
|
; the dispatch code. Otherwise interrupts
|
|
; remain disabled through a whole
|
|
; of code which is not good.
|
|
;
|
|
; M049 SR 1/16/91 Bug #5075. Reworked the scheduling
|
|
; strategy. There is no common
|
|
; dispatcher now. Each entry point
|
|
; now checks A20 and then does a far
|
|
; jump to the appropriate code. This
|
|
; added about 15 bytes of code but the
|
|
; speed increase and reentrancy are
|
|
; well worth the price.
|
|
;
|
|
|
|
|
|
|
|
;
|
|
;This file contains the low memory stub for command.com which hooks all the
|
|
;entry points into the resident command.com and directs the calls to the
|
|
;appropriate routines in the resident code which may be located in HIMEM.
|
|
; The stub has been made part of the resident data and will always
|
|
;be duplicated on every invocation of command.com. However, the only stubs
|
|
;that actually hook the interrupt vectors belong to either the first
|
|
;command.com or to any other command.com executed with the /p switch.
|
|
; The stub also keeps track of the current active data segment. The
|
|
;INIT code of each command.com updates this variable via an int 2fh mechanism
|
|
;with its own data segment. The INIT code also updates a pointer in its data
|
|
;segment to the previous resident data segment. Whenever a command.com exits,
|
|
;the exit code picks up the previous data segment pointer from the current
|
|
;data segment and patches it into the CurResDataSeg variable in the stub.
|
|
; Right now the stub does not bother about A20 switching. We assume
|
|
;A20 is always on. It just does a far jump to the resident code with the
|
|
;value of the current data segment in one of the registers. A20 toggle
|
|
;support maybe added as a future enhancement, if the need is felt.
|
|
;
|
|
|
|
|
|
include comseg.asm
|
|
include xmm.inc
|
|
|
|
INIT segment
|
|
|
|
extrn ConProc:near
|
|
|
|
INIT ends
|
|
|
|
CODERES segment
|
|
|
|
extrn MsgInt2fHandler :near
|
|
extrn Int_2e :near
|
|
extrn Contc :near
|
|
extrn DskErr :near
|
|
|
|
CODERES ends
|
|
|
|
DATARES segment
|
|
assume cs:DATARES,ds:nothing,es:nothing,ss:nothing
|
|
Org 0
|
|
ZERO = $
|
|
|
|
Org 100h
|
|
ProgStart:
|
|
jmp RESGROUP:ConProc
|
|
|
|
db ? ;make following table word-alligned
|
|
|
|
|
|
;
|
|
;All the entry points declared below are patched in at INIT time with the
|
|
;proper segment and offset values after the resident code segment has been
|
|
;moved to its final location
|
|
;
|
|
public Int2f_Entry, Int2e_Entry, Ctrlc_Entry, CritErr_Entry, Lodcom_Entry
|
|
public Exec_Entry, RemCheck_Entry, TrnLodCom1_Entry, MsgRetrv_Entry
|
|
public HeadFix_Entry
|
|
public XMMCallAddr, ComInHMA
|
|
|
|
;!!!WARNING!!!
|
|
; All the dword ptrs from Int2f_Entry till MsgRetrv_Entry should be contiguous
|
|
;because the init routine 'Patch_stub' (in init.asm) relies on this to patch
|
|
;in the correct segments and offsets
|
|
;
|
|
|
|
Int2f_Entry label dword
|
|
dw offset RESGROUP:MsgInt2fHandler ;Address of int 2fh handler
|
|
dw 0
|
|
|
|
Int2e_Entry label dword
|
|
dw offset RESGROUP:Int_2e ;Address of int 2eh handler
|
|
dw 0
|
|
|
|
Ctrlc_Entry label dword
|
|
dw offset RESGROUP:ContC ;Address of Ctrl-C handler
|
|
dw 0
|
|
|
|
CritErr_Entry label dword
|
|
dw offset RESGROUP:DskErr ;Address of critical error handler
|
|
dw 0
|
|
|
|
Exec_Entry dd ? ;Entry from transient to Ext_Exec
|
|
RemCheck_Entry dd ? ;Entry from transient to TRemCheck
|
|
TrnLodCom1_Entry dd ? ;Entry from transient to LodCom1
|
|
LodCom_Entry dd ? ;Entry after exit from command.com
|
|
MsgRetrv_Entry dd ? ;Entry from external to MsgRetriever
|
|
HeadFix_Entry dd ? ;Entry from trans to HeadFix
|
|
|
|
UMBOff_Entry dd ? ;Entry from here to UMBOff routine; M003
|
|
|
|
XMMCallAddr dd ? ;Call address for XMM functions
|
|
ComInHMA db 0 ;Flags if command.com in HMA
|
|
|
|
public Int2f_Trap, Int2e_Trap, Ctrlc_Trap, CritErr_Trap
|
|
public Exec_Trap, RemCheck_Trap, LodCom_Trap, MsgRetrv_Trap, TrnLodcom1_Trap
|
|
public HeadFix_Trap
|
|
|
|
|
|
Int2f_Trap:
|
|
sti
|
|
call CheckA20
|
|
push ds ;push current ds value
|
|
push cs ;push resident data segment value
|
|
jmp Int2f_Entry
|
|
|
|
Int2e_Trap:
|
|
sti
|
|
call CheckA20
|
|
push ds ;push current ds value
|
|
push cs ;push resident data segment value
|
|
jmp Int2e_Entry
|
|
|
|
Ctrlc_Trap:
|
|
sti
|
|
call CheckA20
|
|
push ds ;push current ds value
|
|
push cs ;push resident data segment value
|
|
jmp Ctrlc_Entry
|
|
|
|
CritErr_Trap:
|
|
sti
|
|
call CheckA20
|
|
push ds ;push current ds value
|
|
push cs ;push resident data segment value
|
|
jmp CritErr_Entry
|
|
|
|
Exec_Trap:
|
|
call CheckA20
|
|
push ds ;push current ds value
|
|
push cs ;push resident data segment value
|
|
jmp Exec_Entry
|
|
|
|
RemCheck_Trap:
|
|
call CheckA20
|
|
push ds ;push current ds value
|
|
push cs ;push resident data segment value
|
|
jmp RemCheck_Entry
|
|
|
|
TrnLodCom1_Trap:
|
|
call CheckA20
|
|
push ds ;push current ds value
|
|
push cs ;push resident data segment value
|
|
jmp TrnLodCom1_Entry
|
|
|
|
LodCom_Trap:
|
|
call CheckA20
|
|
push ds ;push current ds value
|
|
push cs ;push resident data segment value
|
|
jmp LodCom_Entry
|
|
|
|
MsgRetrv_Trap:
|
|
call CheckA20
|
|
push ds ;push current ds value
|
|
push cs ;push resident data segment value
|
|
jmp MsgRetrv_Entry
|
|
|
|
HeadFix_Trap:
|
|
call CheckA20
|
|
push ds ;push current ds value
|
|
push cs ;push resident data segment value
|
|
jmp HeadFix_Entry
|
|
|
|
CheckA20 proc
|
|
|
|
pushf ;save current flags
|
|
push ax
|
|
cmp cs:ComInHMA,0 ;is resident in HMA?
|
|
jz A20_on ;no, jump to resident
|
|
|
|
call QueryA20
|
|
jnc A20_on ;A20 is on, jump to resident
|
|
|
|
call EnableA20 ;turn A20 on
|
|
A20_on:
|
|
pop ax
|
|
popf ;flags have to be unchanged
|
|
ret
|
|
|
|
CheckA20 endp
|
|
|
|
|
|
;
|
|
; M005; This is a far jump to the actual int 2fh entry point. The renormalized
|
|
; M005; int 2fh cs:ip points here. We hardcode a far jump here to the int 2fh
|
|
; M005; handler. Note that we have to hardcode a jump and we cannot use any
|
|
; M005; pointers because our cs is going to be different. The segment to
|
|
; M005; jump to is patched in at init time. (in init.asm)
|
|
;
|
|
|
|
public Carousel_i2f_Hook ; M005
|
|
Carousel_i2f_Hook: ; M005
|
|
db 0eah ; far jump opcode; M005
|
|
dw offset DATARES:Int2f_Trap ; int 2fh offset ; M005
|
|
dw ? ; int 2fh segment; M005
|
|
|
|
|
|
QueryA20 proc near
|
|
|
|
push bx
|
|
push ax
|
|
mov ah, XMM_QUERY_A20
|
|
call cs:XMMCallAddr
|
|
or ax, ax
|
|
pop ax
|
|
pop bx
|
|
jnz short QA20_ON ; AX = 1 => ON
|
|
|
|
stc ; OFF
|
|
ret
|
|
QA20_ON:
|
|
clc ; ON
|
|
ret
|
|
|
|
QueryA20 endp
|
|
|
|
|
|
|
|
EnableA20 proc near
|
|
|
|
push bx
|
|
push ax
|
|
mov ah, XMM_LOCAL_ENABLE_A20
|
|
call cs:XMMCallAddr
|
|
or ax, ax
|
|
jz XMMerror ; AX = 0 fatal error
|
|
pop ax
|
|
pop bx
|
|
ret
|
|
;
|
|
;If we get an error, we just loop forever
|
|
;
|
|
XMMerror:
|
|
jmp short XMMerror
|
|
|
|
EnableA20 endp
|
|
|
|
|
|
;
|
|
;The Exec call has to be issued from the data segment. The reason for this
|
|
;is TSRs. When a TSR does a call to terminate and stay resident, the call
|
|
;returns with all registers preserved and so all our segment registers are
|
|
;still set up. However, if the TSR unloads itself later on, it still
|
|
;comes back here. In this case the segment registers and the stack are
|
|
;not set up and random things can happen. The only way to setup all the
|
|
;registers is to use the cs value and this can only be done when we are in
|
|
;the data segment ourselves. So, this piece of code had to be moved from
|
|
;the code segment to the data segment.
|
|
;
|
|
|
|
extrn RStack:WORD
|
|
extrn LoadHiFlg:BYTE
|
|
|
|
public Issue_Exec_Call
|
|
Issue_Exec_Call:
|
|
int 21h
|
|
;
|
|
;We disable interrupts while changing the stack because there is a bug in
|
|
;some old 8088 processors where interrupts are let through while ss & sp
|
|
;are being changed.
|
|
;
|
|
cli
|
|
push cs
|
|
pop ss
|
|
mov sp,offset DATARES:RStack ;stack is set up
|
|
sti
|
|
push cs
|
|
pop ds ;ds = DATARES
|
|
;
|
|
; M009; Restore UMB state to that before Exec
|
|
;
|
|
;; save execution status(carry flag)
|
|
;; and the error code(AL)
|
|
pushf ;save flags ; M003
|
|
push ax
|
|
mov al,LoadHiFlg ;current UMB state ; M009
|
|
test al,80h ;did we try to loadhigh? ;M009
|
|
jz no_lh ;no, dont restore ;M009
|
|
and al,7fh ;clear indicator bit ;M009
|
|
call dword ptr UMBOff_Entry ;restore UMB state ; M009
|
|
no_lh: ; M009
|
|
and LoadHiFlg,7fh ;clear loadhigh indicator bit
|
|
;M009
|
|
pop ax
|
|
popf ; M003; *bugbug -- popff??
|
|
;
|
|
;We now jump to the stub trap which returns us to the resident code. All
|
|
;flags are preserved by the stub code.
|
|
;
|
|
jmp Exec_Trap
|
|
|
|
|
|
DATARES ends
|
|
end ProgStart
|
|
|
|
|