1607 lines
41 KiB
NASM
1607 lines
41 KiB
NASM
PAGE ,132
|
|
TITLE DXVCPIBT.ASM -- Dos Extender VCPI Support Code (initialization)
|
|
|
|
; Copyright (c) Microsoft Corporation 1990-1991. All Rights Reserved.
|
|
|
|
;*** dxvcpibt.asm - vcpi detection/setup code (discardable)
|
|
;
|
|
; Copyright <C> 1990, Microsoft Corporation
|
|
;
|
|
; Purpose:
|
|
;
|
|
; Revision History:
|
|
;
|
|
;
|
|
; 08-07-90 earleh rearranged memory map to allow building full-sized
|
|
; Pmode data structures in v86 mode, allow booting to Pmode
|
|
; without a LIM 3.2 page frame, fixed up detection code to
|
|
; work with various strange interpretations of LIM 4.0 by
|
|
; Limulator vendors. Allow use of entire linear space below
|
|
; 16 Meg by DOSX and VCPI server.
|
|
;
|
|
; 05/07/90 jimmat Started incorporating VCPI changes from languages group.
|
|
;
|
|
; [] 20-Feb-1990 Dans Created
|
|
;
|
|
;
|
|
; note that this should only be called on a 386, except
|
|
; CheckForVCPI, which can be called from 286 machines.
|
|
;
|
|
; this code is for the real mode portion of the dos extender and
|
|
; is released back to DOS prior to switching to protect mode the
|
|
; first time. NO DATA defined here in either segment as it will
|
|
; be discarded.
|
|
;
|
|
;************************************************************************/
|
|
|
|
.286p
|
|
|
|
; -------------------------------------------------------
|
|
; INCLUDE FILE DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
.xlist
|
|
.sall
|
|
include segdefs.inc
|
|
include gendefs.inc
|
|
include pmdefs.inc
|
|
.list
|
|
|
|
; This entire file is only for VCPI support
|
|
|
|
if VCPI
|
|
|
|
.xlist
|
|
.sall
|
|
include dxvcpi.inc
|
|
.list
|
|
|
|
;
|
|
; data
|
|
;
|
|
|
|
DXDATA segment
|
|
|
|
;
|
|
; Externs
|
|
;
|
|
|
|
extrn idCpuType:word
|
|
extrn segBootPmode:word
|
|
extrn pPteFirst:dword
|
|
extrn cPteMax:dword
|
|
extrn bpdxsyspages:dword
|
|
extrn iddxsystype:byte
|
|
extrn hmem_System_Block:word
|
|
extrn fEMS:byte
|
|
extrn fVCPI:byte
|
|
extrn cFreePages:dword
|
|
extrn bpGDT:fword
|
|
extrn bpGDTbase:dword
|
|
extrn bpGDTcb:word
|
|
extrn bpIDT:fword
|
|
extrn bpIDTbase:dword
|
|
extrn bpIDTcb:word
|
|
extrn selGDT:word
|
|
extrn segGDT:word
|
|
extrn selIDT:word
|
|
extrn segIDT:word
|
|
extrn cdscGDTMax:word
|
|
extrn cdscIDTMax:word
|
|
extrn segPSP:word
|
|
extrn selPSP:word
|
|
extrn selGDTFree:word
|
|
extrn sysTSS:WORD
|
|
ifdef NOT_NTVDM_NOT
|
|
extrn fHPVectra:BYTE
|
|
endif
|
|
extrn lpfnXMSFunc:DWORD
|
|
extrn rgbXfrBuf1:BYTE
|
|
|
|
DMAServiceSegment equ 040h ;40:7B bit 5 indicates DMA services
|
|
DMAServiceByte equ 07Bh ; are currently required
|
|
DMAServiceBit equ 020h
|
|
extrn bDMAServiceBit:BYTE
|
|
|
|
if DEBUG
|
|
extrn fTraceBug:WORD
|
|
ifdef CV_TSS
|
|
extrn FaultStack:word
|
|
endif
|
|
endif
|
|
|
|
EXTRN hmem_XMS_Table:WORD
|
|
EXTRN hmem_XMS_Count:WORD
|
|
|
|
extrn fDebug:BYTE
|
|
|
|
DXDATA ends
|
|
|
|
|
|
DXSTACK segment
|
|
|
|
extrn rgw0Stack:WORD
|
|
|
|
DXSTACK ends
|
|
|
|
|
|
DXCODE segment
|
|
|
|
extrn CodeEnd:NEAR
|
|
extrn CallVCPI:NEAR
|
|
extrn ResetVCPI:NEAR
|
|
extrn segDXCode:WORD
|
|
|
|
DXCODE ends
|
|
|
|
|
|
DXPMCODE segment
|
|
|
|
;
|
|
; Externs
|
|
;
|
|
extrn fnVCPIPMoff:dword
|
|
extrn CodeEndPM:near
|
|
|
|
extrn PMIntr31:NEAR
|
|
extrn PMIntr28:NEAR
|
|
extrn PMIntr25:NEAR
|
|
extrn PMIntr26:NEAR
|
|
extrn PMIntr4B:NEAR
|
|
extrn PMIntr70:NEAR
|
|
extrn PMIntrDos:NEAR
|
|
extrn PMIntrMisc:NEAR
|
|
extrn PMIntrVideo:NEAR
|
|
extrn PMIntrMouse:NEAR
|
|
extrn PMIntrIgnore:NEAR
|
|
extrn PMInt2FHandler:NEAR
|
|
extrn PMIntrEntryVector:NEAR
|
|
extrn PMFaultEntryVector:NEAR
|
|
extrn HPxBIOS:NEAR
|
|
extrn PMFaultReflectorIRET:FAR
|
|
|
|
if DEBUG
|
|
extrn PMDebugInt:NEAR
|
|
endif
|
|
|
|
externFP NSetSegmentDscr
|
|
|
|
DXPMCODE ends
|
|
|
|
DXCODE segment
|
|
|
|
assume cs:DXCODE, ds:DXDATA, es:nothing
|
|
|
|
extrn WdebVCPI:BYTE
|
|
|
|
;
|
|
; Definitions
|
|
;
|
|
rgbEMMDrv db 'EMMXXXX0',0 ; emm device driver name
|
|
rbgQEMMDrv db 'EMMQXXX0',0 ; QEMM v. 5.0 with "FRAME=NONE"
|
|
|
|
DebOut_Int equ 41h ;Wdeb386 pMode interface Interrupt
|
|
DS_VCPI_Notify equ 005Bh ;Notify Wdeb386 of VCPI interface
|
|
|
|
extrn ER_QEMM386:BYTE
|
|
ERC_QEMM386 equ offset ER_QEMM386
|
|
extrn DisplayErrorMsg:FAR
|
|
|
|
;
|
|
; Externs
|
|
;
|
|
extrn fnVCPIoff:dword
|
|
extrn V86ToPm:word
|
|
extrn laVTP:dword
|
|
|
|
;extrn FreeEMSHandle:proc
|
|
externNP FreeEMSHandle
|
|
extrn SetupHimemDriver:proc
|
|
|
|
|
|
;*** QEMM386Trap
|
|
;
|
|
; Purpose: A device driver or TSR has just failed the Windows INT 2Fh
|
|
; AX = 1605H startup broadcast. Version 5.1 and 5.11 of
|
|
; QEMM386 will do this for any version of DOSX which it
|
|
; doesn't know how to patch to work with VCPI. Since we
|
|
; do know how to work with VCPI now, QEMM386 is behaving in
|
|
; an inappropriate manner. Furthermore, QEMM386 is required
|
|
; to output an informative message if it does this, and it
|
|
; does not.
|
|
;
|
|
; This routine will ask the user for permission
|
|
; to proceed.
|
|
;
|
|
; Uses:
|
|
;
|
|
; Input: A process has told DOSX not to load by returning
|
|
; non-zero in CX on an INT 2Fh, AX=1605h.
|
|
;
|
|
; Output: AX = Zero, proceed.
|
|
; AX = Non-zero, abort.
|
|
;
|
|
;************************************************************************/
|
|
cProc QEMM386Trap,<NEAR,PUBLIC>,<ds,es>
|
|
cBegin
|
|
|
|
mov dx,cs ;pass msg ptr in DX:AX
|
|
mov ax,ERC_QEMM386
|
|
call DisplayErrorMsg ; Tell the user something
|
|
|
|
mov ah, 8 ; Get a character from the keyboard
|
|
int 21h
|
|
or al,20h ; Force lower case.
|
|
cmp al,'y' ; Party if it's a 'y'.
|
|
mov ax,0
|
|
jne IQ_Abort
|
|
jmp IQ_Exit
|
|
|
|
IQ_Abort:
|
|
dec ax
|
|
IQ_Exit:
|
|
IQ_Not_Open:
|
|
or ax,ax
|
|
cEnd
|
|
|
|
;*** CheckForEMS
|
|
;
|
|
; Purpose: see if an ems driver is loaded
|
|
;
|
|
; Register
|
|
; Usage: ax, cx
|
|
;
|
|
; Input: ES:BX contains int 67h vector.
|
|
;
|
|
; Output: none
|
|
;
|
|
; Returns: carry not set if ems is loaded, set if not
|
|
;
|
|
; Exceptions: none
|
|
;
|
|
; Notes: This checks for a LIM 4.0 driver. It also checks
|
|
; for a driver named 'EMMQXXX0' which could be QEMM 5.0
|
|
; without a page frame.
|
|
;
|
|
;************************************************************************/
|
|
|
|
cProc CheckForEMS,<NEAR,PUBLIC>,<di,si,ds>
|
|
cBegin
|
|
|
|
mov di, 0ah ; es:di has string to look at
|
|
|
|
mov ax, cs
|
|
mov ds, ax
|
|
|
|
assume ds:DXCODE,ss:DGROUP
|
|
|
|
mov si, offset DXCODE:rgbEMMDrv ; ds:si has driver string
|
|
mov cx, CBEMMSTR ; cx has rep count
|
|
repe cmpsb
|
|
jne short CheckFor_QEMM
|
|
; try QEMM driver with
|
|
; non-standard name for
|
|
; "FRAME=NONE"
|
|
|
|
emscall GETEMSVER
|
|
or ah, ah
|
|
jz @F
|
|
xor ax, ax
|
|
@@:
|
|
cmp al, 40h ; LIM 4.0?
|
|
jb Failure_Exit ; No, can't use it.
|
|
|
|
inc fEMS ; set flag
|
|
clc ; return success
|
|
jmp CheckForEMS_ret
|
|
CheckFor_QEMM: ; look for QEMM signature
|
|
mov di, 0ah ; es:di has string to look at
|
|
mov si, offset DXCODE:rbgQEMMDrv ; ds:si has driver string
|
|
mov cx, CBEMMSTR ; cx has rep count
|
|
repe cmpsb
|
|
jne short Failure_Exit ; if not equal, exit
|
|
inc fEMS ; set flag
|
|
clc
|
|
jmp CheckForEMS_ret
|
|
|
|
Failure_Exit:
|
|
stc ; zero out return value first
|
|
CheckForEMS_ret:
|
|
cEnd
|
|
|
|
assume ds:DGROUP
|
|
|
|
|
|
;*** CheckForVCPI
|
|
;
|
|
; Purpose: to see if a vcpi server is loaded
|
|
;
|
|
; Register
|
|
; Usage: ax, bx, cx
|
|
;
|
|
; Input: none
|
|
;
|
|
; Output: none
|
|
;
|
|
; Returns: ax = vcpi version if it is loaded, 0 otherwise
|
|
;
|
|
; Exceptions: none
|
|
;
|
|
; Notes: this calls CheckForEMS first, and EMSVer as well
|
|
;
|
|
;************************************************************************/
|
|
cProc CheckForVCPI,<NEAR,PUBLIC>,<es>
|
|
cBegin
|
|
|
|
cmp idCpuType, 3 ; must be 386 or better to have
|
|
jnb @F
|
|
jmp novcpi286 ; vcpi server running.
|
|
@@:
|
|
.386
|
|
mov ax, 03500h+EMS_INT ; ah = get interrupt, al = vector to get
|
|
int 021h ; returns with es:bx == int vector
|
|
mov ax,es ; int vector set?
|
|
or ax,bx
|
|
jz novcpi ; No.
|
|
|
|
call CheckForEMS
|
|
jc novcpi ; no ems, can't be any vcpi
|
|
|
|
call SwitchToV86 ; force v86 mode
|
|
or al, al
|
|
jz novcpi ; failed to allocate, out of here
|
|
|
|
RMvcpi vcpiVER ; see if vcpi is available
|
|
or ah, ah
|
|
jnz novcpi
|
|
|
|
inc fVCPI ; set flag
|
|
|
|
jc novcpi
|
|
|
|
|
|
movzx eax,segBootPmode
|
|
shl eax,4
|
|
add eax,GDTOFF
|
|
shr eax,4
|
|
|
|
mov selGDT,ax ; save it for later
|
|
mov segGDT,ax ; save it for later
|
|
|
|
; If this is changed, then GetVCPIInterface must be changed
|
|
; to save correct value in pPteFirst.
|
|
.ERRE VCPIPTOFF EQ 0
|
|
|
|
cCall GetVCPIInterface,<segBootPmode,VCPIPTOFF,ax,SEL_VCPI>
|
|
|
|
call SetupPageTables ;
|
|
jc novcpi ; had a problem setting up page table
|
|
;
|
|
; Load the VDS-implemented bit from the BIOS data area.
|
|
;
|
|
mov ax,DMAServiceSegment
|
|
mov es,ax
|
|
mov al,byte ptr es:[DMAServiceByte]
|
|
and al,DMAServiceBit
|
|
mov [bDMAServiceBit],al
|
|
|
|
RMvcpi vcpiVER ; refetch VCPI version
|
|
mov ax,bx ; put it in AX
|
|
jmp CheckForVCPI_exit ; return no error
|
|
.286p
|
|
novcpi:
|
|
call FreeEMSHandle ; free the handle we allocated.
|
|
novcpi286: ; (Free routine uses 386 instructions.)
|
|
xor ax, ax ; none loaded
|
|
CheckForVCPI_exit:
|
|
cEnd
|
|
|
|
DXCODE ends
|
|
|
|
;**************************************************************
|
|
; 386 only code from here on down!!!
|
|
;**************************************************************
|
|
.386p
|
|
include prot386.inc
|
|
|
|
DXCODE segment
|
|
|
|
assume cs:DXCODE, ds:DXDATA, es:nothing
|
|
|
|
;*** SwitchToV86
|
|
;
|
|
; Purpose: Switch to v86 mode in preparation for vcpi calls
|
|
;
|
|
; Register
|
|
; Usage: eax, bx, ecx, es
|
|
;
|
|
; Input: none
|
|
;
|
|
; Output: hEMM is updated, pages are mapped into ems frame
|
|
; segBootPmode setup
|
|
;
|
|
; Returns: al == 1 if successful, al == 0 otherwise
|
|
;
|
|
; Exceptions: none
|
|
;
|
|
; Notes: By allocating an ems handle/page, we force the lim 4.0
|
|
; emulator to switch from real mode to v86 mode. Do not free
|
|
; the ems memory until exit time.
|
|
;
|
|
;************************************************************************/
|
|
cProc SwitchToV86,<NEAR,PUBLIC>,<es,si,edi,cx>
|
|
cBegin
|
|
;
|
|
smsw ax
|
|
test al,01h ; In V86 mode?
|
|
jz stv_badexit ; We don't know how to turn on
|
|
; a VCPI server without allocating
|
|
; EMS memory.
|
|
mov cx,(offset CodeEnd) + CBPAGE386 - 1
|
|
shr cx,4
|
|
mov ax,segDXCode
|
|
add ax,cx
|
|
and ax,0FF00H ; page align DOS block
|
|
|
|
mov segBootPmode,ax
|
|
mov es,ax ; zero it out
|
|
|
|
mov al,1
|
|
|
|
jmp stvExit
|
|
|
|
stv_badexit:
|
|
call FreeEMSHandle
|
|
xor al, al
|
|
stvExit:
|
|
cEnd
|
|
|
|
;*** GetVCPIInterface
|
|
;
|
|
; Purpose: To retrieve the vcpi protect mode interface data
|
|
;
|
|
; Register
|
|
; Usage: es, ax, edx, ebx
|
|
;
|
|
; Input: lpPT: far ptr to a page table
|
|
; lprggdte: far ptr to a range of 3 gdt entries.
|
|
;
|
|
; Output: fnVCPIoff updated with 32-bit offset of pm entry point
|
|
; for vcpi calls
|
|
; *lpPT updated with 4k vcpi 0th page table
|
|
; *lprggdte updated with vcpi server code segment, extras
|
|
;
|
|
;
|
|
; Returns: nothing
|
|
;
|
|
; Exceptions:
|
|
;
|
|
; Notes: only call in real mode prior to relocation of DosExtender,
|
|
; as it sets up a variable in DXPMCODE that needs to be
|
|
; copied up when relocated.
|
|
;
|
|
;************************************************************************/
|
|
cProc GetVCPIInterface,<NEAR,PUBLIC>,<es>
|
|
parmD lpPT
|
|
parmD lprggdte
|
|
cBegin
|
|
push ds ; save ds
|
|
les di, lpPT ; es:di -> vcpi's page table
|
|
lds si, lprggdte ; ds:si -> vcpi's gdt entries
|
|
|
|
assume ds:nothing
|
|
|
|
RMvcpi vcpiPMINTERFACE
|
|
mov word ptr pPteFirst,di
|
|
mov ax, CBPAGE386 ; AX = size of page table
|
|
sub ax, di ; AX = #bytes left over in zeroth PT
|
|
shr ax, 2 ; AX = #PTEs left over
|
|
add ax, DXPTMAX shr 2 ; AX = total # user PTEs available,
|
|
mov word ptr cPteMax, ax ; counting those in zeroth PT
|
|
pop ds ; restore ds
|
|
|
|
assume ds:DXDATA
|
|
|
|
mov fnVCPIoff, ebx
|
|
mov ax, seg DXPMCODE
|
|
mov es, ax
|
|
|
|
assume es:DXPMCODE
|
|
|
|
mov fnVCPIPMoff, ebx ; set pm call
|
|
;
|
|
; Refer to VCPI spec. Version 1.0 for why this call sequence is used to
|
|
; find the number of VCPI pages we may allocate.
|
|
;
|
|
emscall GETNUMOFPAGES
|
|
movzx ebx,bx ; BX = unallocated EMS pages
|
|
shl ebx, 2 ; EBX = unallocated VCPI pages
|
|
mov cFreePages, ebx ; Never allocate more than this amt.
|
|
|
|
cEnd
|
|
|
|
assume es:nothing
|
|
|
|
;*****************************************************************************
|
|
; Memory map of system tables buffer prior to switch to protected
|
|
; mode under vcpi.
|
|
;
|
|
; __+-------------------------------+->USERPTOFF
|
|
; __+-------------------------------+->LDTTOP
|
|
; ~100k | |
|
|
; | |
|
|
; | LDT, 64k (8190 entries) |
|
|
; | |
|
|
; | |
|
|
; |_______________________________|->
|
|
; | |
|
|
; | |
|
|
; | |
|
|
; | DXPMCODE (~18.5k) |
|
|
; | Exact size may be found from |
|
|
; | codeendPM symbol. |
|
|
; | |
|
|
; __|_______________________________|
|
|
; | |->DXPMCODEOFF (GDTTOP)
|
|
; | GDT |
|
|
; __|_______________________________|
|
|
; | |->GDTOFF
|
|
; | TSS space (2 of them for 386) |
|
|
; 18k __|_______________________________|
|
|
; | IDT, 2k |->TSSOFF
|
|
; 16k __|_______________________________|
|
|
; | |->IDTOFF
|
|
; | |
|
|
; | page directory (DXPD) |
|
|
; 12k __|_______________________________|
|
|
; | |->DXPDOFF
|
|
; | DOSX Pmode page table (DXPT2) |
|
|
; | (DXLINEARBASE) |
|
|
; 8k __|_______________________________|
|
|
; | |->DXPTSYSOFF
|
|
; | 1st user page table (DXPT1) |
|
|
; | (4-8 Meg) |
|
|
; 4k __|_______________________________|
|
|
; | |->DXPT1OFF = DXTEMPPTOFF
|
|
; | 0th page table (VCPIPT) |
|
|
; | (0-4 Meg) |
|
|
; 0k __|_______________________________|->VCPIPTOFF
|
|
; | Wasted for page alignment |
|
|
; CodeEnd --->|-------------------------------|
|
|
; Label
|
|
;
|
|
; System data structures and DOSX Pmode code will be located at linear
|
|
; addresses pointed to by the page table which begins at DXPTSYSOFF.
|
|
; During the first switch to Pmode, these addresses will exist in a
|
|
; block of conventional memory allocated from DOS. After the first
|
|
; switch, a block of extended memory allocated from VCPI will be used.
|
|
; The user page table starting at DXTEMPPTOFF will be used to access the
|
|
; second block of memory for initialization purposes.
|
|
;
|
|
; Note that the first page, which contains the zeroth page table, shared
|
|
; with the VCPI server, must use the same physical page of memory before
|
|
; and after the switch.
|
|
;
|
|
; Terms:
|
|
; DXPMCODE Dos eXtender Protect Mode CODE
|
|
; IDT Interrupt Descriptor Table
|
|
; GDT Global Descriptor Table
|
|
; DXPTx Dos eXtender Page Table number x
|
|
; VCPIPT VCPI Pate Table (we can't touch this one)
|
|
; DXPD Dos eXtender Page Directory
|
|
;
|
|
;*****************************************************************************
|
|
|
|
;*** SetupPageTables
|
|
;
|
|
; Purpose: To set up page tables and directory in ems
|
|
; frame (as described above)
|
|
;
|
|
; Register
|
|
; Usage: eax, bx, cx, edx, esi, edi
|
|
;
|
|
; Input: none
|
|
;
|
|
; Output: DXPD, DXPTx, GDT setup.
|
|
;
|
|
; Returns: cy set if error
|
|
;
|
|
; Exceptions:
|
|
;
|
|
; Notes:
|
|
;
|
|
;************************************************************************/
|
|
cProc SetupPageTables,<NEAR,PUBLIC>,<ds,es>
|
|
cBegin
|
|
|
|
mov cdscGDTMax,8190 ; max out the GDT size
|
|
|
|
mov bx, segBootPmode
|
|
mov es, bx
|
|
mov di,DXBOOTPTOFF
|
|
shr bx, 8 ; convert to 16-bit page aligned
|
|
|
|
;
|
|
; Our extended memory stuff is located in a single contiguous
|
|
; block of DOS memory.
|
|
;
|
|
mov ecx, DXPMPAGES
|
|
physaddrloop:
|
|
xchg cx, bx ; put page number in cx, save count
|
|
; in bx
|
|
RMvcpi vcpiPHYSADDRPAGE ; get the physical address
|
|
or ah, ah
|
|
jnz badexit
|
|
and dx, 0f000h ; mask off 12 lsb's
|
|
or dx, NEWPTEMASK ; store with decent page flags
|
|
mov es:[ di ], edx ; store physical in DXPT1
|
|
add di, 4 ; advance to next
|
|
xchg cx, bx ; get loop counter in cx,
|
|
inc bx ; advance to next page in ems frame
|
|
loop physaddrloop
|
|
pagesmapped:
|
|
;
|
|
; Save away the page directory base for cr3 loading
|
|
;
|
|
mov eax, es:[DXBOOTPTOFF + (DXPDOFF shr 10)]
|
|
; Save the pte (physical addr) of
|
|
and ax, 0f000h ; page directory, mask 12 lsb's
|
|
mov V86ToPm.zaCr3VTP, eax ; store it
|
|
;
|
|
; Save the linear address of bpGDT and bpIDT in V86ToPm as well
|
|
;
|
|
xor eax, eax
|
|
mov ax, DXDATA ; dgroup segment, masked hi word
|
|
shl eax, 4 ; linearize it
|
|
mov ebx, eax ; save it
|
|
add eax, offset DGROUP:bpGDT; add in offset
|
|
mov V86ToPm.laGdtrVTP, eax ; save it in vcpi v86 to pm structure
|
|
mov eax, ebx ; restore linear dgroup
|
|
add eax, offset DGROUP:bpIDT; add in offset
|
|
mov V86ToPm.laIdtrVTP, eax ; save it in vcpi v86 to pm structure
|
|
xor eax, eax
|
|
mov ax, cs ; get current code segment
|
|
shl eax, 4 ; linear dxcode
|
|
add eax, offset DXCODE:V86ToPm ; add in offset of v86 to pm structure
|
|
mov laVTP, eax ; save linear ptr of v86 to pm structure
|
|
;
|
|
; set up the page directory (DXPD)
|
|
; with 0-x to be VCPIPT thru DXPTx (x+1 total)
|
|
;
|
|
; (copy them out of dxpt1, starting with the 2nd entry)
|
|
;
|
|
|
|
mov edi, DXPDOFF
|
|
push ds
|
|
push es ; make ds point to emspageframe
|
|
pop ds ; as well
|
|
assume ds:nothing
|
|
mov esi, DXBOOTPTOFF + (VCPIPTOFF shr 10) ; point to 2nd entry in DXPT1
|
|
; (must be VCPIPT)
|
|
mov ecx, CPTDX + 1 ; # of user pt's + vcpi's pt
|
|
rep movsd
|
|
; point DXLINEARBASE at system area
|
|
mov esi,DXBOOTPTOFF + (DXBOOTPTOFF shr 10)
|
|
mov edi,DXPDOFF + (DXLINEARBASE shr 20)
|
|
movsd
|
|
|
|
pop es
|
|
assume es:DGROUP
|
|
;
|
|
; Allocate a block of VCPI 4k pages, enough to copy our system tables
|
|
; and Pmode code into once we have achieved protected mode operation.
|
|
; Map these pages into one of the page tables that is unused until
|
|
; heap initialization time.
|
|
;
|
|
; If there is insufficient VCPI memory to complete this operation, then
|
|
; we try to grab XMS memory instead.
|
|
;
|
|
lea di,bpdxsyspages
|
|
|
|
cmp cFreePages, DXPMPAGES-1
|
|
jc tryXMSServer ; insufficient VCPI pages to
|
|
; build this block
|
|
mov cx,DXPMPAGES-1
|
|
allocate_syspage_from_VCPI:
|
|
RMvcpi vcpiALLOCPAGE
|
|
or ah,ah
|
|
jnz badexit
|
|
mov eax,edx
|
|
stosd
|
|
loop allocate_syspage_from_VCPI
|
|
|
|
sub cFreePages, DXPMPAGES-1
|
|
|
|
mov iddxsystype,DXINVCPI
|
|
;
|
|
; Map these pages into a temporary area, which we use later to move most
|
|
; of the stuff in this DOS block up into extended memory.
|
|
;
|
|
push es
|
|
pop ds
|
|
assume es:nothing,ds:DGROUP
|
|
mov ax, segBootPmode
|
|
mov es, ax
|
|
lea si,bpdxsyspages
|
|
mov cx,DXPMPAGES-1
|
|
mov di,DXTEMPPTOFF
|
|
mov eax,es:[DXBOOTPTOFF + (VCPIPTOFF shr 10)]
|
|
stosd
|
|
copy_syspage:
|
|
lodsd
|
|
or eax,NEWPTEMASK
|
|
stosd
|
|
loop copy_syspage
|
|
jmp goodexit
|
|
tryXMSServer:
|
|
assume es:nothing,ds:DGROUP
|
|
push es
|
|
pop ds
|
|
call SetupHimemDriver ; Need XMS driver now.
|
|
mov dx,DXPMPAGES shl 2 ; kbytes = pages times 4
|
|
xmssvc 09h ; allocate an XMS block
|
|
cmp ax,1 ; got a block?
|
|
jne goodexit ; no, try using DOS mem.
|
|
mov hmem_System_Block,dx
|
|
xmssvc 0ch ; lock the block
|
|
cmp ax,1 ; did it work?
|
|
je @F
|
|
mov dx,hmem_System_Block ; No, free it up.
|
|
mov hmem_System_Block,0
|
|
xmssvc 0ah
|
|
jmp goodexit ; and try to run in DOS mem
|
|
@@:
|
|
shl edx,10h ; DX:BX = locked block address
|
|
mov dx,bx ; EDX = locked block address
|
|
;
|
|
; Make sure the locked XMS block is page aligned. If is not, then we
|
|
; will have to adjust the bottom address used and shrink the GDT by a
|
|
; full 386 page.
|
|
;
|
|
test dx,MASK allbitsPTE
|
|
jz XMSpagealigned
|
|
and dx,MASK pfaPTE
|
|
sub cdscGDTMax,CBPAGE386 / 8 ; shrink the GDT size
|
|
XMSpagealigned:
|
|
mov ax, segBootPmode
|
|
mov es, ax
|
|
mov di,DXTEMPPTOFF
|
|
mov eax,es:[DXBOOTPTOFF + (VCPIPTOFF shr 10)]
|
|
stosd
|
|
mov cx,DXPMPAGES-1
|
|
mov eax,edx
|
|
or eax,NEWPTEMASK
|
|
insertXMSpage:
|
|
stosd
|
|
add eax,CBPAGE386
|
|
loop insertXMSpage
|
|
mov iddxsystype,DXINXMS
|
|
goodexit:
|
|
clc
|
|
jmp exit
|
|
badexit:
|
|
stc
|
|
exit:
|
|
|
|
cEnd
|
|
|
|
assume ds:DXDATA
|
|
|
|
|
|
;*** InitGDTVCPI - initialize the gdt when running under vcpi
|
|
;
|
|
; Purpose:
|
|
;
|
|
; Register
|
|
; Usage: uses eax, all others preserved
|
|
;
|
|
; Input: none
|
|
;
|
|
; Output: gdt/ldt is initialized
|
|
;
|
|
; Returns: returns carry set if failure to map EMS pages
|
|
;
|
|
; Exceptions:
|
|
;
|
|
; Notes:
|
|
;
|
|
;************************************************************************/
|
|
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
public InitGDTVCPI
|
|
cProc InitGDTVCPI,<NEAR,PUBLIC>,<ebx,ecx,edx,di,es>
|
|
cBegin
|
|
mov edx,LADXGDTBASE ; set gdt linear address
|
|
mov bpGDTbase,edx
|
|
mov ecx,GDT_SIZE - 1 ; set the GDT segment size
|
|
mov bpGDTcb,cx
|
|
mov bh, STD_DATA ; make it be a data segment
|
|
mov ax, SEL_GDT
|
|
cCall NSetSegmentDscr,<SEL_GDT,edx,ecx,STD_DATA>
|
|
|
|
; Set up a descriptor for the LDT and an LDT data alias.
|
|
|
|
mov edx,LADXLDTBASE
|
|
movzx ecx,cdscGDTMax
|
|
shl ecx,3
|
|
dec ecx
|
|
cCall NSetSegmentDscr,<SEL_LDT,edx,ecx,STD_LDT>
|
|
|
|
;
|
|
; Set up the descriptors for the page directory and page tables
|
|
;
|
|
mov eax,LADXPDBASE
|
|
cCall NSetSegmentDscr,<SEL_DXPD,eax,0,CBPAGE386LIM,STD_DATA>
|
|
|
|
mov edx, LADXPTBASE ; EDX = user page tables linear base
|
|
|
|
mov ecx, ( (CPTDX + 1) shl 12 ) - 1
|
|
; # of user PTE's + vcpi's PTE's minus one
|
|
cCall NSetSegmentDscr,<SEL_DXPT,edx,ecx,STD_DATA>
|
|
|
|
; Setup a selector and data alias for the TSS
|
|
|
|
mov edx,LADXTSS1BASE ;get base address of TSS
|
|
mov ecx,(TYPE TSS386) - 1
|
|
cCall NSetSegmentDscr,<SEL_TSS,edx,ecx,STD_TSS386>
|
|
|
|
mov eax,DXLINEARBASE
|
|
xor ecx,ecx
|
|
dec cx
|
|
cCall NSetSegmentDscr,<SEL_LDT_ALIAS,eax,ecx,STD_DATA>
|
|
mov eax,DX_TEMP_LINEARBASE
|
|
cCall NSetSegmentDscr,<SEL_TSS_ALIAS,eax,ecx,STD_DATA>
|
|
|
|
|
|
; Set up a descriptor for our protected mode code.
|
|
|
|
mov dx,cs
|
|
movzx edx,dx ;our code segment paragraph address
|
|
shl edx,4 ;convert to linear byte address
|
|
cCall NSetSegmentDscr,<SEL_DXCODE,edx,0,0ffffh,STD_CODE>
|
|
|
|
; Set up another one, but ring 0 this time.
|
|
|
|
cCall NSetSegmentDscr,<SEL_DXCODE0,edx,0,0ffffh,ARB_CODE0>
|
|
|
|
mov edx,LADXPMCODEBASE ; EDX = LADXPMCODEBASE
|
|
mov ecx, offset DXPMCODE:CodeEndPM + 10h
|
|
cCall NSetSegmentDscr,<SEL_DXPMCODE,edx,ecx,STD_CODE>
|
|
;
|
|
; Set up the Ring 0 DXPMCODE alias for handling protected mode processor
|
|
; exceptions.
|
|
;
|
|
cCall NSetSegmentDscr,<SEL_EH,edx,ecx,EH_CODE>
|
|
|
|
; Set up a descriptor for our protected mode data and stack area.
|
|
|
|
mov dx,ds
|
|
movzx edx,dx ;our data segment paragraph address
|
|
shl edx,4 ;convert to linear byte address
|
|
mov ecx,0FFFFh
|
|
cCall NSetSegmentDscr,<SEL_DXDATA,edx,ecx,STD_DATA>
|
|
|
|
; And another one of those for ring 0
|
|
|
|
cCall NSetSegmentDscr,<SEL_DXDATA0,edx,ecx,ARB_DATA0>
|
|
|
|
; Set up descriptors pointing to our PSP and environment.
|
|
|
|
movzx edx, segPSP ; segment address of the PSP
|
|
shl edx, 4 ; linear address of PSP
|
|
cCall NSetSegmentDscr,<SEL_PSP,edx,ecx,STD_DATA>
|
|
mov selPSP, SEL_PSP
|
|
|
|
; set up environment selector
|
|
|
|
push es
|
|
mov es,segPSP
|
|
assume es:PSPSEG
|
|
movzx edx,segEnviron ;segment addr of environment
|
|
shl edx,4 ;linear address of env
|
|
mov ecx,7FFFh ;environments can only be 32k
|
|
; byte by DOS
|
|
cCall NSetSegmentDscr,<SEL_ENVIRON,edx,ecx,STD_DATA>
|
|
pop es
|
|
assume es:DGROUP
|
|
|
|
; Set up a descriptor pointing to the BIOS code and data areas
|
|
|
|
mov edx, 0f0000h ; set to linear f0000 (f000:0000)
|
|
mov ecx, 0ffffh ; make it be a 64k segment
|
|
cCall NSetSegmentDscr,<SEL_BIOSCODE,edx,ecx,STD_CODE>
|
|
|
|
mov edx, 40h * 16 ; linear byte addr of BIOS data area
|
|
cCall NSetSegmentDscr,<SEL_BIOSDATA,edx,ecx,STD_DATA>
|
|
|
|
; Set up a descriptor pointing to the real mode interrupt vector table.
|
|
xor edx, edx ; the IVT is at linear address 0,
|
|
;other registers are still set up
|
|
; 64k data segment from last one
|
|
cCall NSetSegmentDscr,<SEL_RMIVT,edx,ecx,STD_DATA>
|
|
|
|
; And, set up a selector for VCPI/WDEB386 to use to access all of memory.
|
|
xor edx,edx
|
|
mov ecx,edx
|
|
dec ecx
|
|
cCall NSetSegmentDscr,<SEL_VCPIALLMEM,edx,ecx,ARB_DATA0>
|
|
|
|
; Set up the call gate descriptor for the reset to V86 mode routine.
|
|
|
|
mov ecx,offset DXCODE:ResetVCPI
|
|
@@: mov edx,SEL_DXCODE0
|
|
cCall NSetSegmentDscr,<SEL_RESET,edx,ecx,STD_CALL>
|
|
|
|
; Set up a call gate to invoke the VCPI pMode interface in ring 0.
|
|
|
|
mov ecx,offset DXCODE:CallVCPI
|
|
cCall NSetSegmentDscr,<SEL_CALLVCPI,edx,ecx,STD_CALL>
|
|
|
|
; Init call gate descriptors for all the DynaLink services.
|
|
|
|
if DEBUG ;------------------------------------------------------------
|
|
|
|
extrn DXOutDebugStr:NEAR
|
|
|
|
mov ax,SEL_DYNALINK + (OutDebugStr shl 3)
|
|
mov ecx,offset DXCODE:DXOutDebugStr
|
|
mov edx,(SEL_DXCODE0 or EH_RING) or 00080000h ;copy 8 stack words
|
|
cCall NSetSegmentDscr,<ax,edx,ecx,STD_CALL>
|
|
|
|
extrn DXTestDebugIns:NEAR
|
|
|
|
mov ax,SEL_DYNALINK + (TestDebugIns shl 3)
|
|
movzx edx,dx ;copy 0 stack words
|
|
mov ecx,offset DXCODE:DXTestDebugIns
|
|
cCall NSetSegmentDscr,<ax,edx,ecx,STD_CALL>
|
|
|
|
endif ;DEBUG ---------------------------------------------------------
|
|
|
|
; Set up the fault reflector IRET call gate.
|
|
|
|
mov ax,offset DXPMCODE:PMFaultReflectorIRET
|
|
cCall NSetSegmentDscr,<SEL_RZIRET,5,SEL_EH,0,ax,STD_CALL>
|
|
|
|
clc
|
|
cEnd
|
|
|
|
|
|
;*** InitIDTVCPI ;[ds]
|
|
;
|
|
; Purpose: to initialize the idt when running under vcpi
|
|
;
|
|
; Register
|
|
; Usage: eax, all others preserved
|
|
;
|
|
; Input: none
|
|
;
|
|
; Output: idt is initialized
|
|
;
|
|
; Returns: can't fail, cy clear
|
|
;
|
|
; Exceptions:
|
|
;
|
|
; Notes: only under real mode!!!!!
|
|
;
|
|
;************************************************************************/
|
|
cProc InitIDTVCPI,<NEAR,PUBLIC>,<ebx,ecx,edx,di,es>
|
|
cBegin
|
|
|
|
jnc @F
|
|
jmp InitIDTVCPI_ret
|
|
@@:
|
|
movzx eax, segBootPmode ; set up segIDT,selIDT with
|
|
shl eax, 4 ; the RM seg of the idt
|
|
add eax, IDTOFF
|
|
;
|
|
; IDT must be paragraph aligned!!!!! (guarenteed--see dxvcpi.inc)
|
|
;
|
|
shr eax, 4
|
|
mov segIDT, ax ; base of IDT
|
|
mov selIDT, ax ;
|
|
|
|
movzx ecx, cdscIDTMax ; number of descriptors in table
|
|
shl cx, 3 ; convert to count of bytes
|
|
dec cx ; compute segment size limit
|
|
|
|
mov bpIDTcb, cx ; set up idtr with limit,
|
|
mov edx, LADXIDTBASE ; ...and...
|
|
mov bpIDTbase, edx ; ...linear base
|
|
cCall NSetSegmentDscr,<SEL_IDT,edx,ecx,STD_DATA>
|
|
|
|
; Fill the IDT with interrupt gates that point to the interrupt reflector
|
|
; entry vector.
|
|
|
|
mov es, segIDT
|
|
xor di,di
|
|
mov dx,offset DXPMCODE:PMFaultEntryVector ;the 1st 32 go here
|
|
mov cx,32
|
|
@@: mov es:[di].offDest,dx
|
|
mov es:[di].selDest,SEL_EH or EH_RING
|
|
mov es:[di].cwParam,0
|
|
mov es:[di].arbGate,STD_INTR
|
|
mov es:[di].rsvdGate,0
|
|
add dx,3
|
|
add di,8
|
|
loop @b
|
|
|
|
mov dx,offset DXPMCODE:PMIntrEntryVector+(32*3) ; the rest go here
|
|
mov cx,cdscIDTMax
|
|
sub cx,32
|
|
@@: mov es:[di].offDest,dx
|
|
mov es:[di].selDest,SEL_DXPMCODE or STD_RING
|
|
mov es:[di].cwParam,0
|
|
mov es:[di].arbGate,STD_INTR
|
|
mov es:[di].rsvdGate,0
|
|
add dx,3
|
|
add di,8
|
|
loop @b
|
|
|
|
; Now, fix up the ones that don't point to the interrupt reflector.
|
|
|
|
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:[2Fh*8].offDest,offset DXPMCODE:PMInt2FHandler
|
|
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
|
|
|
|
if DEBUG ;-------------------------------------------------------------
|
|
|
|
cmp fTraceBug,0
|
|
jz @f
|
|
mov es:[41h*8].offDest,offset DXCODE:PMDebugInt
|
|
mov es:[41h*8].selDest,SEL_DXCODE or STD_RING
|
|
@@:
|
|
endif ;DEBUG ---------------------------------------------------------
|
|
|
|
mov es:[4Bh*8].offDest,offset DXPMCODE:PMIntr4B
|
|
|
|
ifdef NOT_NTVDM_NOT
|
|
; HP Extended BIOS System Call handler
|
|
|
|
test fHPVectra,0ffh ;only do this for an HP Vectra
|
|
jz NoHPBios
|
|
|
|
; Supposedly the system driver is going to force the HP Bios to
|
|
; use interrupt 6Fh while Windows is running, so we don't need to
|
|
; search for the moveable HP Bios interrupt--just use Int 6Fh.
|
|
|
|
mov es:[6Fh*8].offDest,offset HPxBios
|
|
|
|
NoHPBios:
|
|
endif
|
|
mov es:[70h*8].offDest,offset DXPMCODE:PMIntr70
|
|
|
|
clc ; return success
|
|
InitIDTVCPI_ret:
|
|
|
|
cEnd
|
|
|
|
;*** InitTSSVCPI - initialize the tss for use under vcpi
|
|
;
|
|
; Purpose:
|
|
;
|
|
; Register
|
|
; Usage: uses eax, all others preserved
|
|
;
|
|
; Input: none
|
|
;
|
|
; Output: tss is setup
|
|
;
|
|
; Returns: none
|
|
;
|
|
; Exceptions: none
|
|
;
|
|
; Notes: none
|
|
;
|
|
;************************************************************************/
|
|
cProc InitTSSVCPI,<NEAR,PUBLIC>,<es,di>
|
|
cBegin
|
|
|
|
jnc @F
|
|
jmp InitTSSVCPI_ret
|
|
@@:
|
|
mov ax, segBootPmode
|
|
add ax, ( (TSSOFF shr 16d) shl 12d )
|
|
mov es, ax
|
|
mov di, TSSOFF AND 0FFFFH
|
|
|
|
mov es:[di + ts3_ldt],SEL_LDT ;set the LDT selector
|
|
|
|
; Set the ring 0 stack seg/pointer, we don't bother to set the others
|
|
; since nothing runs below user privilege level. Currently very little
|
|
; code runs ring 0 - just when switching between real/proteted modes.
|
|
|
|
mov es:[di + ts3_ss0],SEL_DXDATA0
|
|
mov word ptr es:[di + ts3_esp0],offset DGROUP:rgw0Stack
|
|
|
|
clc
|
|
InitTSSVCPI_ret:
|
|
|
|
cEnd
|
|
|
|
;
|
|
;************************************************************************/
|
|
;
|
|
; The rest of this file is code which is called during protected mode
|
|
; initialization.
|
|
;
|
|
;************************************************************************/
|
|
;
|
|
;**************************************************************
|
|
;*** CallVCPIPM
|
|
;
|
|
; Utility routine to call VCPI server in protected mode. Masks out
|
|
; interrupts during the call because QEMM enables the processor
|
|
; interrupt flag when you call it.
|
|
;
|
|
; Entry: AX = VCPI function code.
|
|
; Uses: Depends upon call.
|
|
;
|
|
; Note: There is a copy of this routine in dxvcpi.asm and another
|
|
; in dxvcpibt.asm. This is to allow near calls. The copy
|
|
; in dxvcpibt.asm is discarded after initialization time.
|
|
;
|
|
;**************************************************************
|
|
cProc CallVCPIPM,<NEAR>,<si>
|
|
cBegin
|
|
|
|
push ax ; save function code
|
|
;
|
|
; Shut out all interrupts.
|
|
; QEMM 5.0 enables interrupts during this call. All our interrupt
|
|
; handlers are in the user code ring. A workaround is to shut off
|
|
; hardware interrupts during the call.
|
|
;
|
|
|
|
in al,INTA01
|
|
IO_Delay
|
|
mov si, ax
|
|
mov al,0FFh
|
|
out INTA01,al
|
|
IO_Delay
|
|
|
|
pop ax ;restore function code
|
|
db 9Ah ;call far SEL_CALLVCPI:0
|
|
dw 0,SEL_CALLVCPI or STD_RING
|
|
|
|
; Restore the state of the interrupt mask register
|
|
|
|
xchg si, ax
|
|
out INTA01,al
|
|
IO_Delay
|
|
xchg si, ax
|
|
cEnd
|
|
;**************************************************************
|
|
; This variable is used to allow calling NSetSegmentDscr from
|
|
; the DXCODE segment in protected mode.
|
|
;
|
|
NSetSegmentDscrCall label dword
|
|
dw OFFSET DXPMCODE:NSetSegmentDscr,SEL_DXPMCODE or STD_RING
|
|
|
|
extrn EnterProtectedMode:NEAR
|
|
extrn EnterRealMode:NEAR
|
|
|
|
DXCODE ends
|
|
|
|
DXPMCODE segment
|
|
extrn XMScontrol:FAR
|
|
DXPMCODE ends
|
|
|
|
DXCODE segment
|
|
|
|
XMScontrolCall label dword
|
|
dw OFFSET DXPMCODE:XMScontrol,SEL_DXPMCODE or STD_RING
|
|
|
|
pmxmssvc macro fcn
|
|
ifnb <fcn>
|
|
mov ah, fcn
|
|
endif
|
|
call XMScontrolCall
|
|
endm
|
|
|
|
;************************************************************************/
|
|
;*** GrowPageTables
|
|
;
|
|
; Purpose: To grow the user memory page tables large enough to
|
|
; accomodate any expected memory allocation request.
|
|
;
|
|
; Register
|
|
; Usage: NONE
|
|
;
|
|
; Input: NONE
|
|
;
|
|
; Output: Page tables grown to anticipated demand. cPteMax updated.
|
|
; Page table segment limit extended.
|
|
;
|
|
; Returns:
|
|
;
|
|
; Exceptions:
|
|
;
|
|
; Notes: Fails unless there is an XMS block to hold the new page
|
|
; tables. Cannot extend the page tables using VCPI memory.
|
|
;
|
|
;************************************************************************/
|
|
cProc GrowPageTables,<NEAR,PUBLIC>,<ebx,ecx,edx,si,di,es>
|
|
|
|
cBegin
|
|
|
|
PMvcpi vcpiCFREEPAGES ; Fetch current VCPI free pages
|
|
mov ecx,edx
|
|
pmxmssvc 08h ; Query free extended memory
|
|
shr ax,2 ; convert to pages
|
|
movzx eax,ax
|
|
add ecx,eax ; ECX = theoretical pages we could
|
|
; allocate
|
|
sub ecx,cPteMax ; minus what we have room for
|
|
jna GPT_ret ; enough space already
|
|
;
|
|
; So we work on machines with more than 64 Meg. RAM, we should put in a check
|
|
; here to see whether it looks like we have more.
|
|
;
|
|
shr ecx,8 ; ECX = kilobytes to hold this stuff
|
|
;
|
|
; Instead, we do this quick hack for now. If there appears to be more
|
|
; than 60 Mb available, then grow the page tables to 512k.
|
|
;
|
|
cmp ecx,60
|
|
jb @F
|
|
mov ecx,512
|
|
@@:
|
|
mov dx,cx
|
|
add dx,3 ; need to page align
|
|
|
|
pmxmssvc 09h ; Allocate a chunk of XMS to hold it
|
|
or ax,ax
|
|
jz GPT_ret
|
|
|
|
lea si, hmem_XMS_Table ; SI points to saved handles buffer
|
|
inc [hmem_XMS_Count] ; bump XMS handle count
|
|
mov [si],dx ; save handle for later disposal
|
|
|
|
pmxmssvc 0Ch ; lock the handle
|
|
or ax,ax
|
|
jnz @F ; jump on success
|
|
mov dx,[si] ; couldn't lock handle
|
|
pmxmssvc 0Dh ; free it
|
|
dec [hmem_XMS_Count] ; decrement count of allocated handles
|
|
jmp GPT_ret ; out of here
|
|
@@:
|
|
shl edx,16 ; EDX = physical address of extended
|
|
mov dx,bx ; page tables
|
|
|
|
shr edx,10
|
|
add edx,3 ; begin on a page boundary
|
|
shr edx,2
|
|
shl edx,12
|
|
or dl,NEWPTEMASK ; EDX = first PTE
|
|
|
|
mov selGDT,SEL_GDT
|
|
mov ax,SEL_DXPT
|
|
lsl ebx,eax
|
|
shl ecx,10 ; ECX = extra space in bytes
|
|
add ebx,ecx ; EBX = page table segment limit
|
|
mov eax, LADXPTBASE ; EAX = user page tables linear base
|
|
cCall [NSetSegmentDscrCall],<SEL_DXPT,eax,ebx,STD_DATA>
|
|
mov selGDT,SEL_LDT_ALIAS
|
|
|
|
mov eax,ecx
|
|
shr eax,2 ; ECX = new PTEs
|
|
add cPteMax,eax
|
|
|
|
add ecx,CBPAGE386 - 1
|
|
shr ecx,12 ; ECX = pages of page tables
|
|
mov ax,SEL_DXPD
|
|
mov es,ax
|
|
mov edi, ( CPTDX + 1 ) shl 2
|
|
|
|
push ecx
|
|
push edi
|
|
mov eax,edx
|
|
|
|
;
|
|
; Map the new page tables into the page directory.
|
|
;
|
|
GPT_add_PD:
|
|
stos dword ptr es:[edi]
|
|
add eax,CBPAGE386
|
|
dec ecx
|
|
jnz GPT_add_PD
|
|
|
|
;
|
|
; Map the new page tables into the page table segment, by copying
|
|
; the page directory entries.
|
|
;
|
|
mov eax, DXLINEARBASE + DXPTSYSOFF + ( USERPT shl 2 )
|
|
xor ecx,ecx
|
|
dec cx
|
|
cCall [NSetSegmentDscrCall],<SEL_SCR0,eax,ecx,STD_DATA>
|
|
pop edi
|
|
mov esi,edi
|
|
pop ecx
|
|
push ds
|
|
assume ds:nothing
|
|
mov ax,es
|
|
mov ds,ax
|
|
mov ax,SEL_SCR0 or STD_TBL_RING
|
|
mov es,ax
|
|
rep movsd
|
|
pop ds
|
|
assume ds:DGROUP
|
|
|
|
GPT_ret:
|
|
|
|
cEnd
|
|
|
|
;************************************************************************/
|
|
;*** VCPIBootStrap
|
|
;
|
|
; Purpose: Move the Pmode memory block into extended memory.
|
|
;
|
|
; Register Usage:
|
|
; EAX, BX, CX, SI, DI, Flags.
|
|
;
|
|
; Input: System is in Pmode.
|
|
;
|
|
; Output: If successful, the entire block of memory at DXLINEARBASE
|
|
; is copied to DX_TEMP_LINEARBASE. Then the page directory
|
|
; and page tables are swapped around, and a new cr3 value is
|
|
; loaded, so that the new block is placed at DXLINEARBASE.
|
|
; The VCPI server reloads cr3.
|
|
;
|
|
; Exceptions:
|
|
; No defined errors. A bug in this routine will most likely
|
|
; crash the program.
|
|
;
|
|
; Returns: Nothing.
|
|
;************************************************************************/
|
|
|
|
cProc VCPIBootStrap,<NEAR,PUBLIC>,<eax,ecx,si,di>
|
|
cBegin
|
|
|
|
assume ds:DGROUP,ss:DGROUP
|
|
|
|
call EnterProtectedMode
|
|
|
|
cmp fDebug,0
|
|
jz SkipVCPIDebugINIT
|
|
|
|
mov ax,SEL_DXCODE or STD_RING
|
|
mov es,ax
|
|
assume es:NOTHING
|
|
mov di,offset DXCODE:WdebVCPI
|
|
mov ax,DS_VCPI_Notify
|
|
int DebOut_Int
|
|
|
|
push ds
|
|
pop es
|
|
assume es:DGROUP
|
|
SkipVCPIDebugINIT:
|
|
|
|
push es
|
|
push ds
|
|
assume ds:NOTHING,es:NOTHING
|
|
mov ax,SEL_LDT_ALIAS
|
|
mov ds,ax
|
|
mov ax,SEL_TSS_ALIAS
|
|
mov es,ax
|
|
|
|
;
|
|
; Copy the block of memory at DXLINEARBASE, which is really in a DOS
|
|
; memory block in conventional memory, to DX_TEMP_LINEARBASE.
|
|
;
|
|
xor si,si
|
|
mov di,si
|
|
mov cx,LDTOFF shr 2
|
|
rep movsd
|
|
;
|
|
; Manipulate the page tables and page directory in the extended
|
|
; memory block, so that all our selectors point to the new area.
|
|
;
|
|
mov ax,es
|
|
mov ds,ax
|
|
mov si,DXTEMPPTOFF
|
|
mov di,DXPTSYSOFF
|
|
mov cx,CBPAGE386 shr 2
|
|
rep movsd
|
|
;
|
|
; Zero out the temporary page table that was used to copy our stuff
|
|
; up here.
|
|
;
|
|
mov di,DXTEMPPTOFF
|
|
mov cx,CBPAGE386 shr 2
|
|
xor eax,eax
|
|
rep stosd
|
|
;
|
|
; Fill in the new page directory. First, the low memory page tables.
|
|
;
|
|
mov si,DXPTSYSOFF + (VCPIPTOFF shr 10)
|
|
mov di,DXPDOFF
|
|
mov cx,CPTDX + 1
|
|
rep movsd
|
|
;
|
|
; Second, the entry for our high memory system area.
|
|
;
|
|
mov si,DXPTSYSOFF + (DXPTSYSOFF shr 10)
|
|
mov di,DXPDOFF + (DXLINEARBASE shr 20)
|
|
movsd
|
|
|
|
;
|
|
; Copy the two user page table page table entries to their final location.
|
|
;
|
|
mov cx,2
|
|
mov si,DXPTSYSOFF
|
|
mov di,DXPTSYSOFF + ( USERPT shl 2 )
|
|
rep movsd
|
|
;
|
|
; Zero out the original entries.
|
|
;
|
|
mov cx,2
|
|
mov di,DXPTSYSOFF
|
|
xor eax,eax
|
|
rep stosd
|
|
;
|
|
; Move our protected mode code segment up.
|
|
;
|
|
mov di,DXPMCODEOFF
|
|
mov ax,SEL_GDT
|
|
mov ds,ax
|
|
mov si,SEL_LDT_ALIAS
|
|
mov dx,DXPMCODE
|
|
mov ax,dx
|
|
shl ax,4
|
|
shr dx,12
|
|
mov ds:[si].adrBaseLow,ax
|
|
mov ds:[si].adrBaseHigh,dl
|
|
mov ds:[si].adrbBaseHi386,dh
|
|
mov cx,offset DXPMCODE:CodeEndPM + 10h
|
|
shr cx,2
|
|
xor si,si
|
|
mov ax,SEL_LDT_ALIAS
|
|
mov ds,ax
|
|
rep movsd
|
|
;
|
|
; Fetch page directory address for later cr3 loading.
|
|
;
|
|
mov eax, es:[DXPTSYSOFF + (DXPDOFF shr 10)]
|
|
pop ds
|
|
assume ds:DGROUP
|
|
pop es
|
|
push eax
|
|
|
|
call EnterRealMode
|
|
|
|
pop eax ; get new page directory address
|
|
; Save the pte (physical addr) of
|
|
and ax, 0f000h ; page directory, mask 12 lsb's
|
|
mov V86ToPm.zaCr3VTP, eax ; store it
|
|
;
|
|
; VCPI server will load new CR3 value when we do the next real
|
|
; to protected mode switch.
|
|
;
|
|
call EnterProtectedMode
|
|
|
|
; Set up a descriptor for the LDT data alias.
|
|
|
|
mov edx,LADXLDTBASE
|
|
movzx ecx,cdscGDTMax
|
|
shl ecx,3
|
|
dec ecx
|
|
mov selGDT,SEL_GDT
|
|
cCall [NSetSegmentDscrCall],<SEL_LDT_ALIAS,edx,ecx,STD_DATA>
|
|
xor eax,eax
|
|
cCall [NSetSegmentDscrCall],<SEL_TSS_ALIAS,eax,eax,STD_DATA>
|
|
mov selGDT,SEL_LDT_ALIAS
|
|
|
|
call EnterRealMode
|
|
|
|
cEnd
|
|
|
|
;************************************************************************/
|
|
;*** AddXMStoVCPIHeap
|
|
;
|
|
; Purpose: Allocate extended memory for the DOS Extender heap by
|
|
; allocating and locking blocks of XMS memory. Fill in
|
|
; user page tables to point to the allocated memory.
|
|
;
|
|
; Register
|
|
; Usage: eax, edx
|
|
;
|
|
; Input: ES:DI points to beginning of user page tables.
|
|
;
|
|
; Output: ES:DI points to next unused page table entry.
|
|
;
|
|
; Returns:
|
|
;
|
|
; Exceptions:
|
|
;
|
|
; Notes: This function should not be called if memory has already been
|
|
; allocated from another source.
|
|
;
|
|
;************************************************************************/
|
|
cProc AddXMStoVCPIHeap,<FAR,PUBLIC>,<bx,cx,si>
|
|
localD cVCPIFreePages
|
|
cBegin
|
|
cCall GrowPageTables
|
|
|
|
lea si, hmem_XMS_Table ; SI points to saved handles buffer
|
|
mov ax,[hmem_XMS_Count] ; Point to the first free one.
|
|
shl ax,1
|
|
add si,ax
|
|
|
|
AXVH_begin:
|
|
|
|
xor eax,eax
|
|
pmxmssvc 08h ; Query free extended memory
|
|
and ax,NOT 3 ; truncate to page size
|
|
or ax,ax ; any available?
|
|
jz AXVH_x ; no
|
|
mov ecx,cPteMax ; ECX = number of pages that will fit
|
|
shl ecx,2 ; ECX = number of kilobytes
|
|
cmp eax,ecx ; compare available to space in page tables
|
|
jb AXVH_0 ; will fit in page tables
|
|
mov ax,cx ; won't, ask for less
|
|
AXVH_0:
|
|
mov cx,ax ; save copy of size
|
|
or cx,cx
|
|
jz AXVH_x ; none left
|
|
PMvcpi vcpiCFREEPAGES ; Store current VCPI free pages
|
|
mov cVCPIFreePages,edx
|
|
mov dx,cx ; dx = #kilobytes requested
|
|
pmxmssvc 09h ; allocate extended memory block
|
|
cmp ax,1 ; got a block?
|
|
jne AXVH_x ; no
|
|
mov [si],dx ; yes, got one, save handle
|
|
PMvcpi vcpiCFREEPAGES ; Fetch VCPI free pages
|
|
cmp edx,cVCPIFreePages ; Count still the same?
|
|
jne AXVH_0a ; No, allocate the memory from VCPI.
|
|
mov dx,[si] ; fetch handle
|
|
pmxmssvc 0ch ; lock the block
|
|
cmp ax,1 ; did it work?
|
|
je AXVH_1 ; yes
|
|
AXVH_0a:
|
|
mov dx,[si] ; no, fetch handle, free it and exit
|
|
pmxmssvc 0ah
|
|
jmp AXVH_x ; (can't use unlocked blocks)
|
|
AXVH_1: ; handle to locked block is in
|
|
; [si], address in DX:BX
|
|
movzx eax,dx
|
|
shl eax,10h
|
|
mov ax,bx ; EAX = linear address of block
|
|
shr cx,2 ; CX = number of 386 pages in block
|
|
|
|
test ax,MASK allbitsPTE ; Page aligned?
|
|
jz AXVH_2 ; yes
|
|
and ax,NOT (MASK allbitsPTE)
|
|
add ax,CBPAGE386
|
|
dec cx
|
|
jcxz AXVH_x ; none left
|
|
AXVH_2:
|
|
movzx ecx,cx
|
|
sub cPteMax,ecx ; this many PTEs used up
|
|
or ax,NEWPTEMASK ; make it a page table entry
|
|
mov edx,CBPAGE386
|
|
cld
|
|
AXVH_AddPage:
|
|
stos dword ptr es:[edi]
|
|
add eax,edx
|
|
loop AXVH_AddPage
|
|
|
|
inc [hmem_XMS_Count] ; bump XMS handle count
|
|
add si,2 ; point to next slot in handle array
|
|
cmp si,(OFFSET hmem_XMS_Table) + ( CXMSBLOCKSDX * 2 )
|
|
jb AXVH_begin ; jump if more handles fit in array
|
|
|
|
AXVH_x:
|
|
cEnd
|
|
|
|
|
|
DXCODE ends
|
|
|
|
endif ;VCPI
|
|
end
|