337 lines
8.7 KiB
NASM
337 lines
8.7 KiB
NASM
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
|
||
|
||
|