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.
1284 lines
40 KiB
1284 lines
40 KiB
PAGE ,132
|
|
TITLE DXSTRT.ASM -- Dos Extender Startup Code
|
|
|
|
; Copyright (c) Microsoft Corporation 1988-1991. All Rights Reserved.
|
|
|
|
;****************************************************************
|
|
;* *
|
|
;* DXSTRT.ASM - Dos Extender Startup Code *
|
|
;* *
|
|
;****************************************************************
|
|
;* *
|
|
;* Module Description: *
|
|
;* *
|
|
;* This module contains the executive initialization code for *
|
|
;* the Dos Extender. The module DXBOOT.ASM contains the code *
|
|
;* specific to starting up the Dos Extender. The module *
|
|
;* DXINIT.ASM contains the code specific to starting up the *
|
|
;* child program of the Dos Extender. The code in these *
|
|
;* two modules is discarded at the end of the initialization. *
|
|
;* The code in this module calls the initialization routines *
|
|
;* in the other to init modules, and then performs the final *
|
|
;* juggling of things to throw away the low memory init code, *
|
|
;* and transfer control to start up the child program. *
|
|
;* *
|
|
;****************************************************************
|
|
;* Revision History: *
|
|
;* *
|
|
;* 01/09/91 amitc At exit time Co-Processor being reset *
|
|
;* 08/08/90 earleh DOSX and client privilege ring determined *
|
|
;* by equate in pmdefs.inc *
|
|
;* 12/08/89 jimmat Added call to reenable EMM driver. *
|
|
;* 08/29/89 jimmat Restores Int 2Fh vector at exit *
|
|
;* 08/20/89 jimmat Removed A20 code, since HIMEM version 2.07 *
|
|
;* A20 code now works properly. *
|
|
;* 06/28/89 jimmat Now calls OEM layer instead of NetMapper *
|
|
;* 06/16/89 jimmat Implemented Windows/386 startup/exit Int *
|
|
;* 2Fh calls and ifdef'd combined EXE code *
|
|
;* 05/17/89 jimmat ChildTerminationHandler sets its SS:SP *
|
|
;* 04/18/89 jimmat Added calls to init/term NetBIOS mapper *
|
|
;* 03/28/89 jimmat Incorporated bug fix from GeneA related *
|
|
;* to nested GP faults in ChildTermHandler *
|
|
;* 03/11/89 jimmat Added support for TSS & LDT *
|
|
;* 03/07/89 jimmat converted to use WDEB386 *
|
|
;* 02/27/89 (GeneA): shrink initial memory block size on entry *
|
|
;* 02/25/89 (GeneA): added support for combined exe file where *
|
|
;* the Dos Extender and the child reside in the same exe *
|
|
;* file. *
|
|
;* 02/17/89 (GeneA): fixed error termination code for startup *
|
|
;* errors that occur while in protected mode *
|
|
;* 02/14/89 (GeneA): added code to reduce size of real mode *
|
|
;* code segment to throw away initialization code. *
|
|
;* 01/31/89 (GeneA): created by copying code from the old *
|
|
;* DXINIT.ASM *
|
|
;* 18-Dec-1992 sudeepb Changed cli/sti to faster FCLI/FSTI
|
|
;****************************************************************
|
|
|
|
.286p
|
|
|
|
; -------------------------------------------------------
|
|
; INCLUDE FILE DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
.sall
|
|
.xlist
|
|
include segdefs.inc
|
|
include gendefs.inc
|
|
include pmdefs.inc
|
|
|
|
include hostdata.inc
|
|
include dpmi.inc
|
|
include intmac.inc
|
|
.list
|
|
|
|
; -------------------------------------------------------
|
|
; GENERAL SYMBOL DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
|
|
WIN386_INIT equ 1605h ;Win/386 startup Int 2Fh
|
|
WIN386_EXIT equ 1606h ;Win/386 shutdown Int 2Fh
|
|
|
|
WIN386_DOSX equ 0001h ;Win/386 init/exit really DOSX flag
|
|
|
|
|
|
; -------------------------------------------------------
|
|
; EXTERNAL SYMBOL DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
extrn InitDosExtender:NEAR
|
|
extrn RestoreRMIntrVectors:NEAR
|
|
extrn SaveRMIntrVectors:NEAR
|
|
extrn EnterRealMode:NEAR
|
|
extrn EnterProtectedMode:NEAR
|
|
extrn InitializeOEM:NEAR
|
|
extrn TerminateOEM:NEAR
|
|
externNP NSetSegmentAccess
|
|
extrn DupSegmentDscr:NEAR
|
|
|
|
extrn EMMEnable:NEAR
|
|
|
|
ifdef WOW_x86
|
|
externFP NSetSegmentDscr
|
|
else
|
|
externFP NSetGDTSegmentDscr
|
|
ENDIF; WOW_x86
|
|
|
|
extrn PMIntr19:NEAR
|
|
extrn PMIntr13:NEAR
|
|
extrn PMIntr31:NEAR
|
|
extrn PMIntr28:NEAR
|
|
extrn PMIntr25:NEAR
|
|
extrn PMIntr26:NEAR
|
|
extrn PMIntr4B:NEAR
|
|
extrn PMIntrDos:NEAR
|
|
extrn PMIntrMisc:NEAR
|
|
extrn PMIntrVideo:NEAR
|
|
extrn PMIntrMouse:NEAR
|
|
extrn PMIntrIgnore:NEAR
|
|
extrn PMIntrEntryVector:NEAR
|
|
extrn PMFaultEntryVector:NEAR
|
|
ifdef NEC_98 ;
|
|
extrn PMIntr11dummy:NEAR
|
|
extrn PMIntrPrinter:NEAR
|
|
extrn PMIntrCalTi:NEAR
|
|
extrn PMIntrGraph:NEAR
|
|
endif ;NEC_98 ;
|
|
|
|
; -------------------------------------------------------
|
|
; DATA SEGMENT DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
; -------------------------------------------------------
|
|
|
|
DXDATA segment
|
|
extrn A20EnableCount:WORD
|
|
extrn lpfnUserMouseHandler:DWORD
|
|
extrn lpfnUserPointingHandler:DWORD
|
|
extrn f286_287:BYTE
|
|
|
|
extrn cDPMIClients:WORD
|
|
extrn selCurrentHostData:WORD
|
|
extrn segCurrentHostData:WORD
|
|
|
|
ifdef WOW_x86
|
|
extrn FastBop:fword
|
|
endif
|
|
extrn DpmiFlags:WORD
|
|
|
|
org 0
|
|
|
|
public rgwStack,npEHStackLimit,npEHStacklet, selEHStack,
|
|
;
|
|
; Pmode fault handler stack used during initialization only.
|
|
;
|
|
dw 80h dup (?)
|
|
rgwStack label word
|
|
|
|
;
|
|
; This is the stack area used while running in the interrupt reflector.
|
|
; This is divided up into a number of stack frames to allow reentrant
|
|
; execution of the interrupt reflector. The stack pointer pbReflStack
|
|
; indicates the current stack frame to use. Each entry into the interrupt
|
|
; reflector decrements this variable by the size of the stack frame, and
|
|
; each exit from the interrupt reflector increments it.
|
|
|
|
C_STKFRAME = 36
|
|
CB_REFLSTACK = C_STKFRAME * CB_STKFRAME
|
|
|
|
if DEBUG ;--------------------------------------------------------
|
|
public StackGuard
|
|
StackGuard dw 1022h ;unlikely value to check for stk overrun
|
|
endif ;--------------------------------------------------------
|
|
|
|
public pbReflStack,bReflStack
|
|
if DBG
|
|
bReflStack db CB_REFLSTACK dup (0AAh)
|
|
else
|
|
bReflStack db CB_REFLSTACK dup (?)
|
|
endif
|
|
|
|
;----------------------------------------------------------------------------
|
|
; The following stack is used for hw interrupts while booting where
|
|
; the kernel or ntvdm switches the stack before an interrupt is reflected.
|
|
;----------------------------------------------------------------------------
|
|
CB_HWINTRSTACK = 1000h
|
|
if DBG
|
|
bHwIntrStack db CB_HWINTRSTACK dup (0AAh)
|
|
else
|
|
bHwIntrStack db CB_HWINTRSTACK dup (?)
|
|
endif
|
|
public pbHwIntrStack
|
|
pbHwIntrStack dw bHwIntrStack + CB_HWINTRSTACK
|
|
|
|
pbReflStack dw bReflStack + CB_REFLSTACK
|
|
|
|
npEHStackLimit dw offset DGROUP:rgwStack
|
|
npEHStacklet dw offset DGROUP:rgwStack
|
|
selEHStack dw 0
|
|
|
|
public cdscGDTMax, selGDTFree, segGDT, selGDT
|
|
|
|
cdscGDTMax dw CDSCGDTDEFAULT
|
|
|
|
selGDTFree dw ? ;head of list of free descriptors in GDT
|
|
|
|
segGDT dw 0 ;real mode paragraph address of the GDT
|
|
; This variable always stores the real mode
|
|
; paragraph address
|
|
|
|
selGDT dw 0 ;current mode segment/selector for the GDT
|
|
; segment. This variable holds the real
|
|
; mode paragraph address during initialization
|
|
; and then holds the protected mode selector
|
|
; when running in protected mode.
|
|
|
|
public bpGDT, bpGDTcb, bpGDTbase
|
|
|
|
bpGDT label fword
|
|
bpGDTcb dw ?
|
|
bpGDTbase dd ?
|
|
|
|
|
|
public segIDT, selIDT
|
|
|
|
segIDT dw 0
|
|
selIDT dw 0
|
|
|
|
public bpIDT, bpIDTcb, bpIDTbase
|
|
|
|
bpIDT label fword
|
|
bpIDTcb dw ?
|
|
bpIDTbase dd ?
|
|
|
|
public bpRmIVT
|
|
|
|
bpRmIVT dq 0FFFFh ;This is the segment descriptor for the real
|
|
; mode interrupt vector table.
|
|
|
|
public lpfnXMSFunc
|
|
|
|
lpfnXMSFunc dd 0 ;far pointer to XMS memory driver entry point
|
|
|
|
public idCpuType
|
|
|
|
idCpuType dw 0
|
|
|
|
public segPSP, selPSP
|
|
|
|
segPSP dw ? ;segment address of Dos Extender PSP
|
|
selPSP dw ? ;selector for Dos Extender PSP
|
|
; code during processing of GP faults
|
|
|
|
public selPSPChild, segPSPChild
|
|
|
|
segPSPChild dw ? ;real mode segment address of child's PSP
|
|
; note the following in 1, so that in low mem heap management, we can use
|
|
; selPSPChild to mark the owner of the memory.
|
|
selPSPChild dw 1 ;selector of child program's PSP
|
|
|
|
|
|
public DtaSegment, DtaOffset, DtaSelector
|
|
DtaSegment dw 0
|
|
DtaSelector dw 0
|
|
DtaOffset dw 0
|
|
|
|
|
|
public regChildSP, regChildSS, regChildIP, regChildCS
|
|
|
|
regChildSP dw ? ;initial user stack pointer from exe file
|
|
regChildSS dw ? ;initial user stack segment from exe file
|
|
regChildIP dw ? ;initial user program counter from exe file
|
|
regChildCS dw ? ;initial user code segment from exe file
|
|
|
|
public hmemDOSX
|
|
|
|
hmemDOSX dw 0
|
|
|
|
IFDEF ROM
|
|
public segDXCode, segDXData
|
|
|
|
segDXCode dw ? ;holds real mode paragraph address
|
|
; of the code segment
|
|
segDXData dw ? ;holds real mode paragraph address
|
|
; of the data segment
|
|
ENDIF
|
|
|
|
ifdef NEC_98
|
|
public fPCH98
|
|
|
|
fPCH98 db 0 ;NZ if running on a Micro Channel system
|
|
|
|
public fNHmode
|
|
|
|
fNHmode db 0 ;NZ if running on a Hmode system
|
|
endif ;!NEC_98
|
|
public fFaultAbort, ExitCode
|
|
|
|
fFaultAbort db 0 ;NZ if terminating due to unrecoverable fault
|
|
ExitCode db 0FFh ;exit code to use when terminating
|
|
fQuitting db 0
|
|
|
|
fEMbit db 0FFh ;MSW EM bit at startup (FF = not checked yet)
|
|
|
|
public fUsingHMA
|
|
fUsingHMA db 0
|
|
|
|
; The one and only Task State Segment is here (it's too small to allocate
|
|
; a block for it in extended memory)
|
|
|
|
public sysTSS
|
|
|
|
sysTSS TSS286 <>
|
|
|
|
; After initialization is complete, the following buffers (rgbXfrBuf0 and
|
|
; rgbXfrBuf1) are used to transfer data between real mode address space
|
|
; and protected mode address space during the processing of various interrupt
|
|
; function calls. During the initialization process, these buffers are also
|
|
; used as temporary work space as described below:
|
|
; CheckCPUType uses the first 6 bytes of rgbXfrBuf0 as scratch space.
|
|
; The functions for moving the Dos Extender protected mode code segment
|
|
; and the GDT and IDT use rgbXfrBuf0 as buffer space for building a
|
|
; parameter block. The child loading code in DXINIT.ASM uses the buffer
|
|
; RELOC_BUFFER for holding the base part of the file name (name.exe portion)
|
|
; of the child exe file while determining the complete path to the child
|
|
; in the case where the child name is specified on the command line. Note,
|
|
; this buffer is also used for holding sectors from the relocation table
|
|
; while loading the program, but that occurs after the child exe file name
|
|
; has been determined.
|
|
; The child loading code in DXINIT.ASM also uses rgbXfrBuf1 to hold several
|
|
; buffers as well. The locations and purposes of these buffers are
|
|
; described in GENDEFS.INC. All of the buffers are defined with equates
|
|
; named EXEC_?????
|
|
;
|
|
; The file search logic in DXFIND.ASM assumes some parameters are setup in
|
|
; the rgbXfrBuf1 file name buffers. Some of the code was moved from
|
|
; DXINIT.ASM to DXFIND.ASM.
|
|
|
|
public rgbXfrBuf0, rgbXfrBuf1
|
|
public npXfrBuf0, npXfrBuf1
|
|
|
|
align 2
|
|
|
|
rgbXfrBuf0 db CB_XFRBUF0 dup (?)
|
|
rgbXfrBuf1 db CB_XFRBUF1 dup (?)
|
|
|
|
npXfrBuf0 dw offset DGROUP:rgbXfrBuf0
|
|
npXfrBuf1 dw offset DGROUP:rgbXfrBuf1
|
|
|
|
DtaBuffer dw 128 dup (0) ; used as the dta for PM if dta changed
|
|
|
|
; Parameter block for passing to DOS EXEC call to run the child
|
|
; program.
|
|
;
|
|
public exec_par_blk
|
|
|
|
exec_par_blk dw 0
|
|
cmd_off dw OFFSET EXEC_CMNDLINE
|
|
cmd_seg dw DXDATA
|
|
dw OFFSET EXEC_FCB0
|
|
fcb1_seg dw DXDATA
|
|
dw OFFSET EXEC_FCB1
|
|
fcb2_seg dw DXDATA
|
|
|
|
|
|
; The following variables are used during reading the relocation table
|
|
; from the exe file and relocating the child program.
|
|
|
|
public fhExeFile
|
|
public clpRelocItem
|
|
public plpRelocItem
|
|
|
|
fhExeFile dw ? ;DOS file handle for the exe file
|
|
clpRelocItem dw ? ;number of relocation items in the exe file
|
|
plpRelocItem dw ? ;pointer to next relocation item in the table
|
|
|
|
szDebugHello label byte
|
|
if DEBUG
|
|
db 'DOSX: Beginning protected mode initialization.',13,10,0
|
|
endif
|
|
db 0
|
|
|
|
FreeMem dw 0
|
|
|
|
DXDATA ends
|
|
|
|
; -------------------------------------------------------
|
|
page
|
|
; -------------------------------------------------------
|
|
; CODE SEGMENT VARIABLES
|
|
; -------------------------------------------------------
|
|
|
|
DXCODE segment
|
|
|
|
extrn CodeEnd:NEAR
|
|
extrn ER_DXINIT:BYTE
|
|
extrn ER_REALMEM:BYTE
|
|
extrn RMDefaultInt24Handler:FAR
|
|
|
|
public segDXCode, segDXData, selDgroup
|
|
|
|
segDXCode dw ? ;holds the real mode paragraph address
|
|
; of the code segment
|
|
segDXData dw ? ;holds the real mode paragraph address
|
|
; of the data segment
|
|
|
|
selDgroup dw ? ;holds the paragraph address/selector for
|
|
; DGROUP depending on the current mode
|
|
|
|
public PrevInt2FHandler
|
|
|
|
PrevInt2FHandler dd ? ;previous real mode Int 2F handler
|
|
|
|
DXCODE ends
|
|
|
|
|
|
DXPMCODE segment
|
|
|
|
extrn CodeEndPM:NEAR
|
|
|
|
org 0
|
|
|
|
public selDgroupPM, segDXCodePM, segDXDataPM
|
|
|
|
selDgroupPM dw ? ;This variable always contains the
|
|
; data segment selector
|
|
segDXCodePM dw ? ;This variable contains the paragraph
|
|
; address of the real mode code segment
|
|
segDXDataPM dw ? ;This variable contains the paragraph
|
|
; address of the data segment
|
|
externFP NSetSegmentDscr
|
|
|
|
DXPMCODE ends
|
|
|
|
; -------------------------------------------------------
|
|
|
|
BeginLowSegment
|
|
|
|
; -------------------------------------------------------
|
|
; DOS EXTENDER ENTRY FUNCTION
|
|
; -------------------------------------------------------
|
|
;
|
|
; This is the program entry point for the Dos Extender. This
|
|
; function decides if the Dos Extender is being run as a single
|
|
; time operation to extend a single program, or if it is being
|
|
; run as a TSR to wait for programs to request its services
|
|
; later on.
|
|
;
|
|
|
|
assume ds:PSPSEG,es:PSPSEG,ss:NOTHING
|
|
public start
|
|
|
|
start:
|
|
|
|
; Set up the initial segment registers.
|
|
|
|
mov ax,DGROUP
|
|
mov ds,ax
|
|
assume ds:DGROUP
|
|
|
|
mov segPSP,es ;save the PSP segment address
|
|
|
|
mov ss,ax
|
|
mov sp,offset DGROUP:rgwStack
|
|
assume ss:DGROUP
|
|
|
|
;
|
|
; Set up the INT 24h handler. The default INT 24h handler fails the
|
|
; system call in progress, for DPMI compatibility.
|
|
;
|
|
|
|
push ds
|
|
mov ax,cs
|
|
mov ds,ax
|
|
mov dx,offset DXCODE:RMDefaultInt24Handler
|
|
mov ax,2524h
|
|
int 21h
|
|
pop ds
|
|
|
|
; Issue the Win/386 startup Int 2Fh (almost) first thing
|
|
|
|
push ds
|
|
|
|
mov ax,WIN386_INIT ;gives other PM software a chance
|
|
xor bx,bx ; to disable itself, release XMS, etc.
|
|
mov cx,bx
|
|
mov si,bx
|
|
mov ds,bx
|
|
mov es,bx
|
|
assume ds:NOTHING, es:NOTHING
|
|
mov dx,WIN386_DOSX
|
|
mov di,DXVERSION
|
|
int 2Fh
|
|
|
|
pop ax ;restore ds/es DGROUP addressability
|
|
mov ds,ax
|
|
mov es,ax
|
|
assume ds:DGROUP, es:DGROUP
|
|
|
|
|
|
jcxz Allow_Startup ;if cx still == 0, keep going (we ignore
|
|
; all the other possible return values)
|
|
|
|
mov ExitCode,2 ; otherwise we should abort now
|
|
jmp RealModeCleanUp
|
|
|
|
Allow_Startup:
|
|
|
|
; Initialize the Dos Extender
|
|
|
|
call InitDosExtender ;NOTE: passes data to InitChildProgram
|
|
jnc @F ; in rgbXfrBuf1 -- don't overwrite it!
|
|
jmp strt88
|
|
@@:
|
|
|
|
; Save the state of the MSW EM bit (Emulate Math coprocessor), and turn
|
|
; it off (win87em wants it off).
|
|
|
|
ifndef WOW_x86
|
|
smsw ax
|
|
|
|
out1 <What to do about this?>
|
|
|
|
test al,01h ;in V86 mode?
|
|
jnz @f ; can't do the lmsw if so
|
|
|
|
push ax
|
|
and al,04h
|
|
mov fEMbit,al
|
|
pop ax
|
|
and al,not 04h
|
|
lmsw ax
|
|
@@:
|
|
endif ; WOW_x86
|
|
; Switch the machine into protected mode.
|
|
|
|
FCLI
|
|
call SaveRMIntrVectors
|
|
|
|
SwitchToProtectedMode
|
|
|
|
public DXPMInit
|
|
DXPMInit LABEL BYTE
|
|
|
|
if DEBUG
|
|
Trace_Out "*******************************************************************************"
|
|
Trace_Out "*******************************************************************************"
|
|
Trace_Out "**** ****"
|
|
Trace_Out "**** THIS IS A DEBUG RELEASE THIS IS A DEBUG RELEASE ****"
|
|
Trace_Out "**** ****"
|
|
Trace_Out "*******************************************************************************"
|
|
Trace_Out "*******************************************************************************"
|
|
endif
|
|
|
|
assume ds:DGROUP,es:NOTHING
|
|
|
|
mov ax,SEL_IDT or STD_RING
|
|
mov selIDT,ax
|
|
mov ax,SEL_LDT_ALIAS OR STD_RING
|
|
mov selGDT,ax
|
|
|
|
; Initialize the LDT now that we are in protected mode. First, set the
|
|
; contents to zero.
|
|
|
|
mov es,selGDT ; actually LDT
|
|
assume es:NOTHING
|
|
mov cx,cdscGDTMax
|
|
IFDEF WOW
|
|
mov di,GDT_SIZE
|
|
sub cx,di
|
|
ENDIF
|
|
shl cx,2 ; CX = words in LDT segment
|
|
xor ax,ax ; AX = 0
|
|
IFNDEF WOW
|
|
mov di,ax
|
|
ENDIF
|
|
cld
|
|
rep stosw ; CX = 0
|
|
|
|
dec cx ; CX = 0FFFFh
|
|
|
|
push ax
|
|
push cx
|
|
mov ax,es ; LDT selector
|
|
lsl cx,ax ; LDT size
|
|
mov di,SEL_USER and SELECTOR_INDEX
|
|
DPMIBOP InitLDT
|
|
pop cx
|
|
pop ax
|
|
|
|
;
|
|
; Set the two scratch selectors to 64k data starting at zero. Actual
|
|
; addresses set as used.
|
|
;
|
|
cCall NSetSegmentDscr,<SEL_SCR0,ax,ax,ax,cx,STD_DATA>
|
|
cCall NSetSegmentDscr,<SEL_SCR1,ax,ax,ax,cx,STD_DATA>
|
|
ifndef WOW_x86
|
|
mov dx,40h*16
|
|
cCall NSetGDTSegmentDscr,<040h,ax,dx,ax,cx,STD_DATA>
|
|
endif
|
|
|
|
; Bop to initialize 32 bit support.
|
|
|
|
push es
|
|
mov ax,SEL_DXCODE OR STD_RING
|
|
mov es,ax
|
|
assume es:DXCODE
|
|
mov di, sp ;original stack offset
|
|
|
|
push ds
|
|
push offset DGROUP:DtaBuffer
|
|
push ds
|
|
push offset DGROUP:pbReflStack
|
|
push ds
|
|
push offset DGROUP:rgbXfrBuf1
|
|
push ds
|
|
push offset DGROUP:rgbXfrBuf0
|
|
|
|
mov si,sp ;pass stack offset
|
|
FBOP BOP_DPMI,InitDosx,FastBop
|
|
mov sp, di ;restore stack
|
|
pop es
|
|
assume es:nothing
|
|
|
|
call AllocateExceptionStack
|
|
FSTI ;don't need ints disabled
|
|
|
|
; Shrink the size of our real mode code segment to throw away init code.
|
|
|
|
SwitchToRealMode
|
|
|
|
mov bx,(offset CodeEnd) + 15
|
|
shr bx,4
|
|
add bx,segDXCode
|
|
sub bx,segPSP
|
|
push es
|
|
mov es,segPSP
|
|
dossvc 4Ah
|
|
pop es
|
|
|
|
call DetermineFreeMemory
|
|
mov FreeMem,bx
|
|
SwitchToProtectedMode
|
|
|
|
; Initialize the OEM layer. This can allocate DOS memory, so it goes
|
|
; after the final program shrink.
|
|
|
|
call InitializeOEM ;currently initializes NetBIOS mapper
|
|
|
|
if1
|
|
%OUT InitializeOEM can fail!!!!!
|
|
endif
|
|
|
|
FBOP BOP_DPMI,ResetLDTUserBase,FastBop
|
|
|
|
; Exec the child application
|
|
|
|
SwitchToRealMode
|
|
FSTI
|
|
;; bugbug hack ...... williamh
|
|
;; turn off A20 line before we terminate and keep resident.
|
|
cmp A20EnableCount, 0
|
|
jz A20IsOff
|
|
@@:
|
|
xmssvc 6
|
|
dec A20EnableCount
|
|
jnz @B
|
|
A20IsOff:
|
|
|
|
mov ax,segPSP
|
|
mov es,ax
|
|
assume es:nothing
|
|
mov ax,es:[2ch]
|
|
mov es,ax
|
|
dossvc 49h ; free env block
|
|
|
|
call DetermineFreeMemory
|
|
mov dx,(offset CodeEnd) + 15
|
|
shr dx,4
|
|
add dx,FreeMem
|
|
sub dx,bx
|
|
add dx,segDXCode
|
|
sub dx,segPSP
|
|
mov al,0
|
|
dossvc 31h ; tsr.
|
|
help: int 3 ; should never get here
|
|
jmp help
|
|
|
|
lea bx, exec_par_blk
|
|
lea dx, EXEC_PROGNAME
|
|
xor al, al
|
|
dossvc 4bh
|
|
|
|
; If we get here, the EXEC failed for some reason!
|
|
|
|
mov bx,offset DXCODE:ER_REALMEM ;assume insufficient memory
|
|
xchg ax,bx
|
|
cmp bx,8 ;is it really?
|
|
jz strt88
|
|
mov ax,offset DXCODE:ER_DXINIT ;no, use generic msg
|
|
|
|
strt88:
|
|
mov ExitCode,1 ;return NZ exit code
|
|
|
|
mov dx,cs ;pass msg ptr in DX:AX (ax already set)
|
|
|
|
push cs ;fake a far call so no fixup
|
|
push offset DXCODE:RealModeCleanUp ; needed -- return to clean up
|
|
jmp near ptr DisplayErrorMsg
|
|
|
|
; -------------------------------------------------------
|
|
; ChildTerminationHandler -- This routine receives control
|
|
; when the child program running under the Dos Extender
|
|
; terminates. It will free all resources being used by
|
|
; the child. If we were not running TSR, then the Dos
|
|
; Extender will complete cleaning up and terminate itself.
|
|
;
|
|
; Input: none
|
|
; Output: none
|
|
; Errors: none
|
|
; Uses:
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
|
|
public DosxTerminationHandler
|
|
DosxTerminationHandler:
|
|
|
|
mov ds,selDgroup
|
|
mov es,selDgroup
|
|
mov ss,selDgroup ;make sure we know where the
|
|
mov sp,offset DGROUP:rgwStack ; stack is when we get here
|
|
|
|
assume ds:DGROUP,es:DGROUP
|
|
|
|
; Check if we are already in the middle of a termination sequence and
|
|
; bail out if so. This will prevent us from hanging up in an infinite
|
|
; loop if we get a GP fault while we are quitting.
|
|
|
|
cmp fQuitting,0
|
|
jz @f
|
|
jmp chtm90
|
|
@@:
|
|
mov fQuitting,1
|
|
|
|
; Terminate the OEM layer
|
|
|
|
call TerminateOEM ;current term's NetBIOS mapper & low net heap
|
|
|
|
; Make sure that no interrupt vectors still point to us.
|
|
|
|
call RestoreRMIntrVectors
|
|
|
|
; if this is a 80286 & 80287 configuration, we should reset the Co-Processor.
|
|
|
|
cmp [f286_287],0 ;286 and 287 config ?
|
|
jz CTH_Not286And287 ;no.
|
|
|
|
; reset the 80287 Co-Processor to make sure that it gets out of protected
|
|
; mode.
|
|
|
|
xor al,al ;need to out 0
|
|
out 0F1H,al ;reset the coprocessor
|
|
|
|
CTH_Not286And287:
|
|
|
|
; If we're aborting due to a processor fault, do some extra clean-up on
|
|
; the mouse (just to be nice). If this is a normal termination, we leave
|
|
; it up to the child to save/restore the mouse state.
|
|
|
|
test fFaultAbort,0FFh
|
|
jz normal_exit
|
|
|
|
; Check if the mouse driver callback function has been set, and
|
|
; reset the mouse driver if so.
|
|
|
|
mov ax,word ptr lpfnUserMouseHandler
|
|
or ax,word ptr lpfnUserMouseHandler+2
|
|
jz @F
|
|
xor ax,ax
|
|
int 33h
|
|
@@:
|
|
|
|
; Check if the PS/2 Pointing Device Handler Address has been set and
|
|
; disable it if so.
|
|
|
|
ifndef NEC_98
|
|
mov ax,word ptr lpfnUserPointingHandler
|
|
or ax,word ptr lpfnUserPointingHandler+2
|
|
jz @f
|
|
mov ax,0C200h
|
|
xor bh,bh
|
|
int 15h
|
|
@@:
|
|
endif ;!NEC_98
|
|
|
|
; Hmmm, we have HP mouse code in dxhpbios.asm, but no clean up here...
|
|
|
|
normal_exit:
|
|
|
|
; Release the extended memory heap.
|
|
|
|
; call ReleaseXmemHeap
|
|
|
|
; Release the space being used for the descriptor tables and
|
|
; the protected mode code segment.
|
|
|
|
;
|
|
; If we have allocated an extended memory block, then free it.
|
|
; If we have allocated the HMA, then free it.
|
|
;
|
|
mov dx,hmemDOSX
|
|
or dx,dx
|
|
jz @F
|
|
xmssvc 0Dh
|
|
xmssvc 0Ah
|
|
@@:
|
|
cmp fUsingHMA,0
|
|
je @F
|
|
xmssvc 2
|
|
@@:
|
|
|
|
; Clean up after real mode code (and possible real mode incomplete
|
|
; initialization) -- restore real mode interrupt vectors.
|
|
|
|
chtm90:
|
|
RealModeCleanUp:
|
|
|
|
; Disable A20 if it was left enabled (normally 1 on 386 systems, 0 on 286)
|
|
|
|
mov cx,A20EnableCount
|
|
jcxz A20Okay
|
|
@@: xmssvc 6
|
|
loop @b
|
|
A20Okay:
|
|
|
|
; Restore the MSW EM bit (Emulate Math coprocessor) to its initial state
|
|
ifndef WOW_x86
|
|
inc fEMbit ;if fEMbit = FF, we never got far 'nuff to
|
|
jz @f ; change it
|
|
dec fEMbit
|
|
|
|
smsw ax
|
|
test al,01h ;in V86 mode?
|
|
jnz @f ; can't do the lmsw if so
|
|
or al,fEMbit
|
|
lmsw ax
|
|
@@:
|
|
endif
|
|
; Make sure DOS knows that the DOS extender is the current process
|
|
|
|
mov bx,segPSP
|
|
dossvc 50h
|
|
|
|
; Reenable a friendly EMM driver if we disabled it at startup
|
|
|
|
call EMMEnable
|
|
|
|
; Restore real mode interrupt vectors
|
|
|
|
push ds
|
|
|
|
lds dx,PrevInt2FHandler ;Int 2Fh handler
|
|
assume ds:NOTHING
|
|
|
|
mov ax,ds ;may not have gotten far enough to
|
|
or ax,dx ; set interrupt vectors, so make
|
|
jz @f ; sure before resotring.
|
|
|
|
mov ax,252Fh
|
|
int 21h
|
|
|
|
@@:
|
|
pop ds
|
|
assume ds:DGROUP
|
|
|
|
|
|
; We have cleaned up after ourselves, so now we can quit.
|
|
|
|
mov ax,WIN386_EXIT ;use Win/386 exit Int 2Fh to tell any
|
|
mov dx,WIN386_DOSX ; interested parties that we are
|
|
int 2Fh ; terminating
|
|
|
|
mov al,ExitCode ;exit the extender with either the exit
|
|
cmp al,0FFH ; status from the child, or a status
|
|
jnz @f ; that we have forced
|
|
dossvc 4Dh ;get child exit status if we haven't forced it
|
|
@@:
|
|
ifdef NEC_98
|
|
push ax
|
|
push es ; Dec IN_BIOS(0:456)
|
|
mov ax, 0040h
|
|
mov es, ax
|
|
test byte ptr es:[0], 20h ; check suspend/redume
|
|
jz @f
|
|
dec byte ptr es:[056h] ; for Y55
|
|
@@:
|
|
pop es
|
|
pop ax
|
|
endif ;NEC_98
|
|
dossvc 4Ch ;say goodnight Gracy...
|
|
|
|
; -------------------------------------------------------
|
|
; ChildTerminationHandler --
|
|
; Input: none
|
|
; Output: none
|
|
; Errors: none
|
|
; Uses:
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public ChildTerminationHandler
|
|
|
|
ChildTerminationHandler:
|
|
sub sp,4 ; room for far ret
|
|
push ds
|
|
push es
|
|
pusha
|
|
mov si,ss
|
|
mov di,sp
|
|
|
|
mov ds,selDgroup
|
|
mov es,selDgroup
|
|
mov ss,selDgroup ;make sure we know where the
|
|
|
|
mov sp,offset DGROUP:rgwStack ; stack is when we get here
|
|
|
|
assume ds:DGROUP,es:DGROUP
|
|
|
|
;bugbug less than zero?
|
|
dec cDPMIClients
|
|
|
|
test DpmiFlags,DPMI_32BIT
|
|
jz cth05
|
|
|
|
;
|
|
; Return the stack frame used by the Wow32Intr16 interrupt handler
|
|
;
|
|
add pbReflStack,CB_STKFRAME
|
|
cth05: cmp cDPMIClients,0
|
|
jne cth20
|
|
|
|
SwitchToProtectedMode
|
|
|
|
mov dx, selPspChild
|
|
mov cx, 0 ; No parent
|
|
FBOP BOP_DPMI,TerminateApp,FastBop
|
|
|
|
;
|
|
; Reset the exception stack pointer to indicate free'd memory
|
|
;
|
|
mov selEHStack,0
|
|
|
|
;
|
|
; Give back the xms memory
|
|
;
|
|
FCLI
|
|
|
|
call ReInitIdt
|
|
push 0
|
|
pop es
|
|
call ReInitGdt
|
|
FBOP BOP_DPMI,DpmiNoLongerInUse,FastBop
|
|
|
|
SwitchToRealMode
|
|
|
|
cth20: mov ax,[SegCurrentHostData]
|
|
mov es,ax
|
|
mov ax,es:[HdSegParent]
|
|
mov [SegCurrentHostData],ax
|
|
mov ax,es:[HdSelParent]
|
|
mov [SelCurrentHostData],ax
|
|
mov ax,es:[HdPSPParent]
|
|
mov dx, selPspChild ; save outging psp in dx
|
|
mov SelPSPChild,ax ; set new psp
|
|
|
|
cmp CDPMIClients, 0
|
|
je short @f
|
|
|
|
push es ; We need to preserve es. The SwitchToRealMode
|
|
; somehow trashes es. (bug?)
|
|
push dx
|
|
push ax
|
|
|
|
; free xmem allocated to this client
|
|
|
|
SwitchToProtectedMode
|
|
pop cx
|
|
pop dx
|
|
FBOP BOP_DPMI,TerminateApp,FastBop
|
|
SwitchToRealMode
|
|
pop es
|
|
@@:
|
|
mov ax,word ptr es:[HdPspTerminate + 2]
|
|
mov bx,word ptr es:[HdPspTerminate]
|
|
mov cx,segPSPChild
|
|
mov ds,cx
|
|
assume ds:nothing
|
|
;
|
|
; Restore termination vector (app may think it knows what's here)
|
|
;
|
|
mov ds:[0ah],bx
|
|
mov ds:[0ch],ax
|
|
xor cx,cx
|
|
mov ds,cx
|
|
;
|
|
; Restore int 22 vector (terminate) Just in case
|
|
;
|
|
mov ds:[22h * 4],bx
|
|
mov ds:[22h * 4 + 2],ax
|
|
mov es,si
|
|
mov es:[di+20],bx
|
|
mov es:[di+22],ax
|
|
mov ss,si
|
|
mov sp,di
|
|
popa
|
|
pop es
|
|
pop ds
|
|
retf
|
|
|
|
; -------------------------------------------------------
|
|
; DisplayErrorMsg -- Display an error message on the screen. We set the
|
|
; video adapter to a text mode so the msg is visable (and gets rid
|
|
; of any bizarre mode that others may have set (like WIN.COM)).
|
|
;
|
|
; Note: This routine can be executed in real OR protected mode, so
|
|
; don't do anything mode specific--keep is short and sweet.
|
|
;
|
|
; Input: AX - offset of msg to display
|
|
; DX - segment of msg to display
|
|
; Output: None.
|
|
; Uses: AX, DX modified, all else preserved
|
|
|
|
assume ds:NOTHING, es:NOTHING
|
|
public DisplayErrorMsg
|
|
|
|
DisplayErrorMsg proc far
|
|
|
|
push ds ;save current DS
|
|
push ax ;save msg offset
|
|
|
|
; Set a text mode (normally 3, but possibly 7)
|
|
|
|
ifdef NEC_98
|
|
mov ah,41h ;
|
|
int 18h
|
|
mov ah,0Ch ;
|
|
int 18h
|
|
else ;!NEC_98
|
|
mov ax,0003h ;set video mode 3
|
|
int 10h
|
|
mov ah,0Fh ;get video mode
|
|
int 10h
|
|
cmp al,03h ;did we change to 3?
|
|
jz @f
|
|
mov ax,0007h ;no, must be mode 7
|
|
int 10h
|
|
@@:
|
|
endif ;!NEC_98
|
|
|
|
; Display the msg
|
|
|
|
mov ds,dx
|
|
pop dx
|
|
dossvc 9
|
|
|
|
pop ds
|
|
|
|
ret
|
|
|
|
DisplayErrorMsg endp
|
|
|
|
; -------------------------------------------------------
|
|
; DetermineFreeMemory -- Determine how much memory is free
|
|
;
|
|
; Input: none
|
|
; Output: bx = #paragraphs free memory
|
|
; Uses: bx
|
|
;
|
|
assume ds:dgroup,es:nothing
|
|
public DetermineFreeMemory
|
|
|
|
DetermineFreeMemory proc near
|
|
push ax
|
|
mov bx,0ffffh ; allocate all of memory
|
|
dossvc 48h
|
|
jnc @f
|
|
|
|
pop ax
|
|
ret
|
|
|
|
;bugbug report error
|
|
@@: mov bx,0ffffh
|
|
pop ax
|
|
ret
|
|
DetermineFreeMemory endp
|
|
EndLowSegment
|
|
|
|
DXPMCODE segment
|
|
assume cs:DXPMCODE
|
|
;--------------------------------------------------------
|
|
; ReInitIdt -- Set Idt entries back to default values
|
|
;
|
|
; Input: none
|
|
; Output: none
|
|
; uses: none
|
|
;
|
|
assume ds:dgroup,es:nothing
|
|
public ReInitIdt
|
|
|
|
ReInitIdt proc near
|
|
|
|
push bx
|
|
push cx
|
|
push dx
|
|
push si
|
|
push di
|
|
push es
|
|
mov ax,SEL_IDT OR STD_RING
|
|
mov es,ax
|
|
|
|
; Fill the IDT with interrupt gates that point to the fault handler and
|
|
; interrupt reflector entry vector.
|
|
|
|
xor di,di
|
|
|
|
mov dx,offset DXPMCODE:PmIntrEntryVector
|
|
mov cx,256
|
|
iidt23: mov es:[di].offDest,dx
|
|
mov es:[di].selDest,SEL_DXPMCODE or STD_RING
|
|
mov es:[di].cwParam,0
|
|
mov es:[di].arbGate,STD_TRAP ; BUGBUG- int gates not set up
|
|
mov es:[di].rsvdGate,0
|
|
add dx,5
|
|
add di,8
|
|
loop iidt23
|
|
|
|
; Now, fix up the ones that don't point to the interrupt reflector.
|
|
IFDEF WOW_x86
|
|
mov es:[1h*8].offDest,offset PMIntrIgnore
|
|
mov es:[3h*8].offDest,offset PMIntrIgnore
|
|
ifdef NEC_98
|
|
mov es:[11h*8].offDest,offset PMIntr11dummy
|
|
mov es:[18h*8].offDest,offset PMIntrVideo
|
|
mov es:[1ah*8].offDest,offset PMIntrPrinter
|
|
mov es:[1bh*8].offDest,offset PMIntr13
|
|
mov es:[1ch*8].offDest,offset PMIntrCalTi
|
|
mov es:[1dh*8].offDest,offset PMIntrGraph
|
|
mov es:[1fh*8].offDest,offset PMIntrMisc
|
|
else ;!NEC_98
|
|
mov es:[10h*8].offDest,offset PMIntrVideo
|
|
mov es:[13h*8].offDest,offset PMIntr13
|
|
mov es:[15h*8].offDest,offset PMIntrMisc
|
|
mov es:[19h*8].offDest,offset PMIntr19
|
|
endif ;!NEC_98
|
|
ENDIF
|
|
|
|
mov es:[21h*8].offDest,offset DXPMCODE:PMIntrDos
|
|
mov es:[25h*8].offDest,offset DXPMCODE:PMIntr25
|
|
mov es:[26h*8].offDest,offset DXPMCODE:PMIntr26
|
|
mov es:[28h*8].offDest,offset DXPMCODE:PMIntr28
|
|
mov es:[30h*8].offDest,offset DXPMCODE:PMIntrIgnore
|
|
mov es:[31h*8].offDest,offset DXPMCODE:PMIntr31
|
|
mov es:[33h*8].offDest,offset DXPMCODE:PMIntrMouse
|
|
mov es:[41h*8].offDest,offset DXPMCODE:PMIntrIgnore
|
|
|
|
ifndef WOW_x86
|
|
mov es:[4Bh*8].offDest,offset DXPMCODE:PMIntr4B
|
|
ifdef NEC_98
|
|
; Sound BIOS Int D2h handler
|
|
mov es:[0D2h*8].offDest,offset DXPMCODE:PMIntrSound
|
|
|
|
; extended DOS Int DCh handler (KANA/KANJI)
|
|
mov es:[0DCh*8].offDest,offset DXPMCODE:PMIntrExDos
|
|
endif ;!NEC_98
|
|
endif
|
|
;
|
|
; Set up the IDT, and dpmi32 state
|
|
;
|
|
mov ax,es ; Idt selector
|
|
mov bx,VDM_INT_16
|
|
DPMIBOP InitIDT
|
|
|
|
mov ax,5 ; handler increment
|
|
mov cx,SEL_DXPMCODE OR STD_RING
|
|
mov dx,offset DXPMCODE:PmFaultEntryVector
|
|
|
|
DPMIBOP InitExceptionHandlers
|
|
|
|
IFDEF WOW_x86
|
|
; make the stacks 16 bit again
|
|
|
|
cCall NSetSegmentAccess,<selDgroupPM,STD_DATA>
|
|
cCall NSetSegmentAccess,<selEHStack,STD_DATA>
|
|
ENDIF
|
|
; All done
|
|
|
|
iidt90: pop es
|
|
pop di
|
|
pop si
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
ret
|
|
ReInitIdt endp
|
|
|
|
assume ds:DGROUP,es:NOTHING
|
|
public ReInitGdt
|
|
ReInitGdt proc near
|
|
|
|
push ax
|
|
push cx
|
|
push di
|
|
|
|
mov ax,selGDT ; LDT selector
|
|
lsl cx,ax ; LDT size
|
|
mov di,SEL_USER and SELECTOR_INDEX
|
|
DPMIBOP InitLDT
|
|
|
|
pop di
|
|
pop cx
|
|
pop ax
|
|
ret
|
|
ReInitGdt endp
|
|
|
|
;--------------------------------------------------------
|
|
; AllocateExceptionStack -- Get space for exception handler
|
|
;
|
|
; Input: none
|
|
; Output: none
|
|
; carry set on error
|
|
; uses: AX, BX, CX, DX, SI, DI
|
|
;
|
|
assume ds:dgroup,es:nothing
|
|
public AllocateExceptionStack
|
|
AllocateExceptionStack proc near
|
|
|
|
cmp selEHStack, 0 ;have we allocated one already
|
|
jnz aes_ok ;yes, return no carry
|
|
|
|
xor bx,bx
|
|
mov dx,bx
|
|
mov cx,1000h ;length of block
|
|
mov ax, 501h
|
|
push ds
|
|
FBOP BOP_DPMI, Int31Call, FastBop
|
|
jc @F
|
|
|
|
mov ax, SEL_USER_STACK or STD_RING
|
|
mov selEHStack,ax
|
|
|
|
cCall NSetSegmentDscr,<ax,bx,cx,0,0fffh,STD_DATA>
|
|
mov ax,selEHStack
|
|
|
|
mov cx,1000h ;reload length
|
|
dec cx
|
|
and cx,0fffeh ; Make sure SP is WORD aligned
|
|
mov npEHStackLimit,cx
|
|
|
|
;; mark the stack with 0DEADh
|
|
mov bx, cx
|
|
push ds
|
|
mov ds,ax
|
|
sub bx,2
|
|
mov word ptr [bx],0DEADh
|
|
pop ds
|
|
mov npEHStacklet, bx
|
|
|
|
push es
|
|
mov ax, selEHStack
|
|
mov es, ax
|
|
mov bx, npEHStackLimit
|
|
DPMIBOP InitPmStackInfo
|
|
pop es
|
|
|
|
aes_ok:
|
|
clc
|
|
@@:
|
|
ret
|
|
|
|
AllocateExceptionStack endp
|
|
|
|
DXPMCODE ends
|
|
|
|
;****************************************************************
|
|
|
|
end start
|