        page ,132
        title   Command Stub
;
;                        IBM Confidential
;                        Copyright (C) IBM Corporation 1991-1993
;                        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
;                               shitload 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 versiona.inc
        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

;
; Make following table word-aligned, and at the same time, provide a
; signature that sysinit can use to (attempt to) validate the interpreter
;
        db      ((major_version AND 0Fh) SHL 4) OR (minor_version AND 0Fh)

;
;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

; VCB - Move QueryA20 and EnableA20 routines inline
;
;       pushf                           ;save current flags
;       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

        pushf                           ;Save flags
        cmp     cs:ComInHMA,0           ;Running in HMA ?
        jz      A20_ret                 ;No
        push    ax                      ;Save AX
        push    bx                      ;Save BX
        mov     ah, 07h                 ;Query A20 function
        call    cs:XMMCallAddr          ;Call XMM
        or      ax, ax                  ;A20 enabled ?
        jnz     A20_on                  ;Yes

        mov     ah, 05h                 ;Enable A20 function
        call    cs:XMMCallAddr          ;Call XMM
        or      ax, ax                  ;Error ?
        jz      XMMerror                ;Yes
A20_on:
        pop     bx                      ;Restore BX
        pop     ax                      ;Restore AX
A20_ret:
        popf                            ;Restore flags
        ret                             ;Return to caller

XMMerror:
        jmp     short XMMerror

; end A20 inline opt

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


; VCB - Move QueryA20 and EnableA20 routines inline to CheckA20
;
;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

;
; -----------------------------------------------------------------------------
;
HV_Extern       equ     1
HV_LoadHigh     equ     1
HV_Stub         equ     1
        include highvar.inc     ; Make high-memory variables external here
        include highexit.inc    ; And add code for UnHideUMBs
;
; -----------------------------------------------------------------------------
;

;
;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

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

        pushf                           ;    This call frees HIDDEN umb's,
        call    UnHideUMBs              ; <- restores the memory-allocation
        popf                            ;    strategy and link state, as app.

;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
