|
|
title "Fast Protected Mode services" ;++ ; ; Copyright (c) 1989 Microsoft Corporation ; ; Module Name: ; ; fastpm.asm ; ; Abstract: ; ; This module implements a fast entry to and exit from protected mode ; ; Author: ; ; Dave Hastings (daveh) 26-Jul-91 ; ;-- .386p
include ks386.inc include callconv.inc include bop.inc include vint.inc include vdmtib.inc
_TEXT SEGMENT PARA PUBLIC 'CODE' ASSUME DS:NOTHING, ES:NOTHING, SS:FLAT, FS:NOTHING, GS:NOTHING _TEXT ENDS
_DATA SEGMENT DWORD PUBLIC 'DATA'
public _NTVDMpLockPrefixTable _NTVDMpLockPrefixTable label dword dd offset FLAT:_ntvdmlock1 dd offset FLAT:_ntvdmlock2 dd 0
ClientPMStack df ? ClientPMEntry df ?
_DATA ENDS
_TEXT SEGMENT
; Interrupt type definitions CPU_YODA_INT equ 4 BIT_CPU_YODA_INT equ 0 CPU_HW_RESET equ 0 BIT_CPU_HW_RESET equ 1 CPU_TIMER_TICK equ 1 BIT_CPU_TIMER_TICK equ 2 CPU_HW_INT equ 3 BIT_CPU_HW_INT equ 3
assume DS:NOTHING cPublicProc _VdmTrapcHandler, 0
; ; On entry, [ebx]->VdmContext ;
; ; zero higher 16bit of esp. (The Iretd in kernel trap handler puts higher 16bit ; of kernel esp back to our user mode esp even though the higher 16bit of ; TrapFrame.HardwareEsp is zeroed. ; and esp, 0ffffh ;@@:
; ; Note, here we use app's stack to do the far return ;
push [ebx].VtVdmContext.CsSegCs push [ebx].VtVdmContext.CsEip mov ebx, [ebx].VtVdmContext.CsEbx retf
stdENDP _VdmTrapcHandler
page ,132 subttl "FastEnterPm" ;++ ; ; Routine Description: ; ; This routine is a faster way to enter 16 bit vdm protected mode. ; Instead of making a system call, we just save the 32 bit state ; into the VdmTib, restore the Vdm state from the VdmTib, and do ; a far return to the application. ; ; Arguments: ; ; ss:sp + 4 = pointer to VdmTib ; ; Returns: ; ; nothing. ; assume DS:FLAT cPublicProc _FastEnterPm,0
push ebp mov ebp,esp ; set up stack frame
push ebx ; free up reg for pointer
mov ebx, KGDT_R3_TEB OR RPL_MASK mov fs, ebx mov ebx, fs:[PcTeb] mov ebx, dword ptr [ebx].TeVdm
; translate the interrupt flag to the virtual interrupt flag
test [ebx].VtVdmContext.CsEFlags,dword ptr EFLAGS_INTERRUPT_MASK jz fe10
_ntvdmlock1: lock or dword ptr ds:FIXED_NTVDMSTATE_LINEAR,dword ptr VDM_VIRTUAL_INTERRUPTS test dword ptr ds:FIXED_NTVDMSTATE_LINEAR,dword ptr VDM_INTERRUPT_PENDING jz fe20
; set up event info for an interrupt acknowlege
mov word ptr [ebx].VtEventInfo.EiEvent,VdmIntAck mov word ptr [ebx].VtEventInfo.EiInstructionSize,0 mov word ptr [ebx].VtEventInfo.EiIntAckInfo,0
pop ebx mov esp,ebp pop ebp stdRET _FastEnterPm
fe10: _ntvdmlock2: lock and dword ptr ds:FIXED_NTVDMSTATE_LINEAR, NOT VDM_VIRTUAL_INTERRUPTS fe20: mov [ebx].VtMonitorContext.CsEax,eax mov eax,[ebp - 4] mov [ebx].VtMonitorContext.CsEbx,eax mov [ebx].VtMonitorContext.CsEcx,ecx mov [ebx].VtMonitorContext.CsEdx,edx mov [ebx].VtMonitorContext.CsEsi,esi mov [ebx].VtMonitorContext.CsEdi,edi mov eax,[ebp] mov [ebx].VtMonitorContext.CsEbp,eax mov eax,ebp
add eax,8 ; pop ebp and ret addr
mov [ebx].VtMonitorContext.CsEsp,eax mov eax,[ebp + 4] mov [ebx].VtMonitorContext.CsEip,eax mov eax,cs mov [ebx].VtMonitorContext.CsSegCs,eax mov eax,ss mov [ebx].VtMonitorContext.CsSegSs,eax mov eax,ds mov [ebx].VtMonitorContext.CsSegDs,eax mov eax,es mov [ebx].VtMonitorContext.CsSegEs,eax mov eax,fs mov [ebx].VtMonitorContext.CsSegFs,eax mov eax,gs mov [ebx].VtMonitorContext.CsSegGs,eax pushfd pop eax mov [ebx].VtMonitorContext.CsEflags,eax
test [ebx].VtVdmContext.CsEflags, EFLAGS_TF_MASK ; debugging? jz fe_atomic ; no, return the robust way
; ; Beginning STACK-BASED return ; ; The following code transitions us back to client code in protect mode ; using the client's stack. This is not a good thing to do in general ; since this is not how things worked on win31. But it is necessary if ; we are setting the trap flag in the EFLAGS register in order to break ; on the correct instruction. ; mov eax,[ebx].VtVdmContext.CsSegSs mov es,eax mov edi,[ebx].VtVdmContext.CsEsp ; es:edi -> stack lar eax,eax test eax,400000h ; big? jnz fe30
movzx edi,di fe30: mov eax,[ebx].VtVdmContext.CsEflags sub edi,4 mov es:[edi],eax ; push Eflags mov eax,[ebx].VtVdmContext.CsSegCs sub edi,4 mov es:[edi],eax ; push cs mov eax,[ebx].VtVdmContext.CsEip sub edi,4 mov es:[edi],eax ; push ip sub edi,4 mov eax,[ebx].VtVdmContext.CsEbp ; push ebp mov es:[edi],eax
fe40: push es push edi ; push ss:esp for lss esp mov eax,esp ; save sp for pushad
; simulate pushad push dword ptr [ebx].VtVdmContext.CsEax push dword ptr [ebx].VtVdmContext.CsEcx push dword ptr [ebx].VtVdmContext.CsEdx push dword ptr [ebx].VtVdmContext.CsEbx push eax push ebp ; save pointer to stack frame push dword ptr [ebx].VtVdmContext.CsEsi push dword ptr [ebx].VtVdmContext.CsEdi
; push seg regs push dword ptr [ebx].VtVdmContext.CsSegFs push dword ptr [ebx].VtVdmContext.CsSegGs push dword ptr [ebx].VtVdmContext.CsSegDs push dword ptr [ebx].VtVdmContext.CsSegEs
; set up VDM seg regs pop es pop ds pop gs ; pop es,fs,gs of invalid selectors are trapped in ntoskrnl, pop fs ; and handled by setting to zero
; set up VDM general regs popad
; set up vdm stack lss esp,[ebp - 12]
; restore ebp pop ebp
; return to VDM iretd
; ; Beginning STACK-LESS return ; ; WARNING: ; The following code does the final dispatch to the Client code. ; It uses STATIC data to hold CS, EIP, SS, ESP. THAT MAKES THIS CODE ; NON-REENTRANT. For correct operation, the rest of this code in this ; routine must execute to completion before coming back through. All ; ntvdm support code must honor this arrangement. ; ; The reason this code has this restriction is to avoid using the ; client's stack. Originally, this routine built a stack frame on the ; client stack, and IRET'd to it. This breaks some DPMI applications, ; either at a point where they have a transient condition with an invalid ; stack pointer, or because they expect unused stack space to be left ; alone by the system. ; fe_atomic: mov eax,[ebx].VtVdmContext.CsSegCs mov word ptr ClientPmEntry+4, ax mov eax,[ebx].VtVdmContext.CsEip mov dword ptr ClientPmEntry, eax mov eax,[ebx].VtVdmContext.CsSegSs mov word ptr ClientPmStack+4, ax mov eax,[ebx].VtVdmContext.CsEsp ; es:edi -> stack mov dword ptr ClientPmStack, eax
mov eax,esp ; save sp for pushad
; simulate pushad push dword ptr [ebx].VtVdmContext.CsEax push dword ptr [ebx].VtVdmContext.CsEcx push dword ptr [ebx].VtVdmContext.CsEdx push dword ptr [ebx].VtVdmContext.CsEbx push eax push dword ptr [ebx].VtVdmContext.CsEbp push dword ptr [ebx].VtVdmContext.CsEsi push dword ptr [ebx].VtVdmContext.CsEdi
; push seg regs push dword ptr [ebx].VtVdmContext.CsSegFs push dword ptr [ebx].VtVdmContext.CsSegGs push dword ptr [ebx].VtVdmContext.CsSegDs push dword ptr [ebx].VtVdmContext.CsSegEs
push dword ptr [ebx].VtVdmContext.CsEflags popfd
; set up VDM seg regs pop es pop ds pop gs ; pop fs,gs of invalid selectors are trapped in ntoskrnl, pop fs ; and handled by setting to zero
; set up VDM general regs popad
lss esp, cs:ClientPMStack jmp fword ptr cs:ClientPMEntry
stdENDP _FastEnterPm
page ,132 subttl "GetFastBopEntry" ;++ ; ; Routine Description: ; ; This routine supplies the address of the routine that segmented ; protected mode code should call to switch to flat mode. ; ; Arguments: ; ; esp + 4 = pointer to VdmTib->VdmContext ; ; Returns: ; ; nothing. ; assume DS:FLAT cPublicProc _GetFastBopEntryAddress,1
push ebp mov ebp,esp push ebx push eax mov ebx,[ebp + 8] mov [ebx].CsSegEs,cs mov eax,offset FLAT:_FastLeavePm mov word ptr [ebx].CsEbx,ax shr eax,16 mov word ptr [ebx].CsEdx,ax pop eax pop ebx mov esp,ebp pop ebp stdRET _GetFastBopEntryAddress
stdENDP _GetFastBopEntryAddress
page ,132 subttl "FastLeavePm" ;++ ; ; Routine Description: ; ; This routine switches from the VDM context to the monitor context. ; ; Arguments: ; ; none ; ; Returns: ; ; executing with monitor context ; assume DS:Nothing,ES:Nothing,SS:Nothing ALIGN 16 cPublicProc _FastLeavePm,0 push ebx
mov bx,ds push bx ; so push and pop size same mov bx,KGDT_R3_DATA OR RPL_MASK mov ds,bx assume ds:FLAT
push fs mov ebx, KGDT_R3_TEB OR RPL_MASK mov fs, bx mov ebx, fs:[PcTeb] mov ebx, dword ptr [ebx].TeVdm pop fs
pushfd mov dword ptr [ebx].VtVdmContext.CsEax,eax pop eax mov dword ptr [ebx].VtVdmContext.CsEFlags,eax pop ax mov word ptr [ebx].VtVdmContext.CsSegDs,ax pop eax mov dword ptr [ebx].VtVdmContext.CsEbx,eax mov dword ptr [ebx].VtVdmContext.CsEcx,ecx mov dword ptr [ebx].VtVdmContext.CsEdx,edx mov dword ptr [ebx].VtVdmContext.CsEsi,esi mov dword ptr [ebx].VtVdmContext.CsEdi,edi mov dword ptr [ebx].VtVdmContext.CsEbp,ebp mov word ptr [ebx].VtVdmContext.CsSegEs,es mov word ptr [ebx].VtVdmContext.CsSegFs,fs mov word ptr [ebx].VtVdmContext.CsSegGs,gs pop eax mov dword ptr [ebx].VtVdmContext.CsEip,eax pop eax mov word ptr [ebx].VtVdmContext.CsSegCs,ax mov dword ptr [ebx].VtVdmContext.CsEsp,esp mov word ptr [ebx].VtVdmContext.CsSegSs,ss
; switch Stacks .errnz (CsEsp + 4 - CsSegSS) lss esp, [ebx].VtMonitorContext.CsEsp
; Now running on Monitor stack
; set up event info mov word ptr [ebx].VtEventInfo.EiEvent,VdmBop mov dword ptr [ebx].VtEventInfo.EiInstructionSize,BOP_SIZE mov ax,[ebx].VtVdmContext.CsSegCs mov es,ax ; BUGBUG 16 or 32 bit !!!!! mov di,[ebx].VtVdmContext.CsEip mov al,byte ptr es:[di] movzx eax,al mov [ebx].VtEventInfo.EiBopNumber,eax sub di,2 mov word ptr [ebx].VtVdmContext.CsEip,di ; set up bop bias
; set up for IRET push dword ptr [ebx].VtMonitorContext.CsEFlags push dword ptr [ebx].VtMonitorContext.CsSegCs push dword ptr [ebx].VtMonitorContext.CsEip
; simulate pushad mov eax,esp push dword ptr [ebx].VtMonitorContext.CsEax push dword ptr [ebx].VtMonitorContext.CsEcx push dword ptr [ebx].VtMonitorContext.CsEdx push dword ptr [ebx].VtMonitorContext.CsEbx push eax push dword ptr [ebx].VtMonitorContext.CsEbp push dword ptr [ebx].VtMonitorContext.CsEsi push dword ptr [ebx].VtMonitorContext.CsEdi
; push seg regs push dword ptr [ebx].VtMonitorContext.CsSegFs push dword ptr [ebx].VtMonitorContext.CsSegGs push dword ptr [ebx].VtMonitorContext.CsSegDs push dword ptr [ebx].VtMonitorContext.CsSegEs
test ds:FIXED_NTVDMSTATE_LINEAR,dword ptr VDM_VIRTUAL_INTERRUPTS jz fl10
or [ebx].VtVdmContext.CsEFlags,dword ptr EFLAGS_INTERRUPT_MASK jmp fl20
fl10: and dword ptr [ebx].VtVdmContext.CsEFlags, NOT EFLAGS_INTERRUPT_MASK fl20: ; set up Monitor seg regs pop es pop ds pop gs pop fs
; set up Monitor general regs popad
xor eax,eax ; indicate success
; clear the NT bit in EFLAGS and return with iret pushfd and dword ptr [esp], 0ffffbfffH popfd iretd stdENDP _FastLeavePm
_TEXT ends end
|