windows-nt/Source/XPSP1/NT/base/ntos/ke/i386/emxcptn.asm

658 lines
20 KiB
NASM
Raw Normal View History

2020-09-26 03:20:57 -05:00
page 78,132
;*******************************************************************************
; Copyright (c) Microsoft Corporation 1991
; All Rights Reserved
;
; ke\i386\emxcptn.asm
;
; Module to support getting/setting context to and from the R3
; emulator.
;
;Revision History:
;
;
;*******************************************************************************
.386p
_TEXT SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
;;*******************************************************************************
;;
;; Include some more macros and constants.
;;
;;*******************************************************************************
;
NT386 equ 1
include ks386.inc
include em387.inc ; Emulator TEB data layout
include callconv.inc
EXTRNP _KeGetCurrentIrql,0
EXTRNP _KeBugCheck,1
EXTRNP _ExRaiseStatus,1
extrn _Ki387RoundModeTable:dword
subttl _KiEm87StateToNpxFrame
page
;*** _KiEm87StateToNpxFrames
;
; Translates the R3 emulators state to the NpxFrame
;
; Returns TRUE if NpxFrame sucessfully completed.
; else FALSE
;
; Warning: This function can only be called at Irql 0 with interrupts
; enabled. It is intended to be called only to deal with R3 exceptions
; when the emulator is being used.
;
; Revision History:
;
;
;*******************************************************************************
cPublicProc _KiEm87StateToNpxFrame, 1
push ebp
mov ebp, esp
push ebx ; Save C runtime varibles
push edi
push esi
push esp ; Pass current Esp to handler
push offset stnpx_30 ; Set Handler address
push PCR[PcExceptionList] ; Set next pointer
mov PCR[PcExceptionList],esp ; Link us on
if DBG
pushfd ; Sanity check
pop ecx ; make sure interrupts are enabled
test ecx, EFLAGS_INTERRUPT_MASK
jz short stnpx_err
stdCall _KeGetCurrentIrql ; Sanity check
cmp al, DISPATCH_LEVEL ; make sure Irql is below DPC level
jnc short stnpx_err
endif
xor eax, eax ; set FALSE
mov ebx,PCR[PcPrcbData+PbCurrentThread]
mov ebx,[ebx]+ThApcState+AsProcess
cmp dword ptr [ebx]+PrVdmObjects,0 ; is this a vdm process?
jne short stnpx_10 ; Yes, then not supported
mov ebx, PCR[PcTeb] ; R3 Teb
cmp [ebx].Einstall, 0 ; Initialized?
je short stnpx_10 ; No, then don't return NpxFrame
test [ebx].CURErr, Summary ; Completed?
jz short stnpx_10 ; No, then don't return NpxFrame
mov esi, [ebp+8] ; (esi) = NpxFrame
call SaveState
mov eax, 1 ; Return TRUE
stnpx_10:
pop PCR[PcExceptionList] ; Remove our exception handle
add esp, 8 ; clear stack
pop esi
pop edi
pop ebx
pop ebp
stdRET _KiEm87StateToNpxFrame
stnpx_30:
;
; WARNING: Here we directly unlink the exception handler from the
; exception registration chain. NO unwind is performed. We can take
; this short cut because we know that our handler is a leaf-node.
;
mov esp, [esp+8] ; (esp)-> ExceptionList
xor eax, eax ; Return FALSE
jmp short stnpx_10
if DBG
stnpx_err:
stdCall _KeBugCheck <IRQL_NOT_LESS_OR_EQUAL>
endif
_KiEm87StateToNpxFrame ENDP
;*** SaveEnv
;
;
; ARGUMENTS
;
; (esi) = NpxFrame
; (ebx) = PcTeb
;
;
; DESCRIPTION
;
SaveEnv:
xor ax,ax
mov [esi].reserved1,ax
mov [esi].reserved2,ax
mov [esi].reserved3,ax
mov [esi].reserved4,ax
mov [esi].reserved5,ax
mov ax,[ebx].ControlWord
mov [esi].E32_ControlWord,ax
call GetEMSEGStatusWord
mov [esi].E32_StatusWord,ax
call GetTagWord
mov [esi].E32_TagWord,ax
mov ax,cs
mov [esi].E32_CodeSeg,ax ; NOTE: Not R0 code & stack
mov ax,ss
mov [esi].E32_DataSeg,ax
mov eax,[ebx].PrevCodeOff
mov [esi].E32_CodeOff,eax
mov eax,[ebx].PrevDataOff
mov [esi].E32_DataOff,eax
ret
;*** SaveState -
;
; ARGUMENTS
; (esi) = where to store environment
; (ebx) = PcTeb
;
; DESCRIPTION
;
; REGISTERS
; Destroys ALL, but EBX
;
SaveState: ; Enter here for debugger save state
mov dword ptr [esi].FpCr0NpxState, CR0_EM
call SaveEnv
add esi,size Env80x87_32 ;Skip over environment
mov ebp,NumLev ;Save entire stack
mov edi,[ebx].CURstk
ss_loop:
mov eax,[ebx+edi].ExpSgn
call StoreTempReal ;in emstore.asm
add esi,10
mov edi,[ebx].CURstk
;;; NextStackElem edi,SaveState
cmp edi,INITstk
jae short ss_wrap
add edi,Reg87Len
ss_continue:
mov [ebx].CURstk,edi
dec ebp
jnz short ss_loop
ret
ss_wrap:
mov edi, BEGstk
jmp short ss_continue
;*** GetTagWord - figures out what the tag word is from the numeric stack
; and returns the value of the tag word in ax.
;
; ARGUMENTS
; (ebx) = PcTeb
;
GetTagWord:
push esi
xor eax, eax
mov ecx, NumLev ; get tags for regs. 0, 7 - 1
mov esi, INITstk
GetTagLoop:
mov dh, [ebx+esi].bTag ; The top 2 bits of Tag are the X87 tag bits.
shld ax, dx, 2
sub esi, Reg87Len
loop GetTagLoop
rol ax, 2 ; This moves Tag(0) into the low 2 bits
pop esi
ret
;*** GetEMSEGStatusWord
;
; User status word returned in ax.
; Uses status word in per-thread data area, otherwise
; identical to GetStatusWord
;
; ARGUMENTS
; (ebx) = PcTeb
GetEMSEGStatusWord:
mov eax, [ebx].CURstk
sub eax, BEGstk
;
; Make sure the 'div' won't overflowed.
;
cmp eax, Reg87Len * (NumLev + 2)
ja short @f
mov dl,Reg87Len
div dl
inc eax
and eax, 7 ; eax is now the stack number
shl ax, 11
or ax, [ebx].StatusWord ; or in the rest of the status word.
ret
@@:
mov eax, STATUS_INTEGER_OVERFLOW
stdCall _ExRaiseStatus, <eax>
ret ; Should never come here ...
;*** StoreTempReal
;
;
; ARGUMENTS
; ??
; (ebx) = PcTeb
;
StoreTempReal:
mov edx,[ebx+edi].lManHi
mov edi,[ebx+edi].lManLo
;mantissa in edx:edi, exponent in high eax, sign in ah bit 7, tag in al
;memory destination is esi
mov ecx,eax ;get copy of sign and tag
shr ecx,16 ;Bring exponent down
cmp al,bTAG_ZERO
jz short StoreIEEE80 ;Skip bias if zero
add ecx,IexpBias-TexpBias ;Correct bias
cmp al,bTAG_DEN
jz short Denorm80
StoreIEEE80:
and eax,bSign shl 8
or ecx,eax ;Combine sign with exponent
mov [esi],edi
mov [esi+4],edx
mov [esi+8],cx
ret
Denorm80:
;Must change it to a denormal
dec ecx
neg ecx ;Use as shift count
cmp cl,32 ;Long shift?
jae LongDenorm
shrd edi,edx,cl
shr edx,cl
xor ecx,ecx ;Exponent is zero
jmp short StoreIEEE80
LongDenorm:
;edi must be zero if we have 32 bits to shift
xchg edx,edi ;32-bit right shift
shr edi,cl ;shift count is modulo-32
xor ecx,ecx ;Exponent is zero
jmp short StoreIEEE80
;****************************************************
;****************************************************
;****************************************************
;****************************************************
;*** _KiNpxFrameToEm87State
;
; Translates the NpxFrame to the R3 emulators state
;
; Returns TRUE if NpxFrame state sucessfully transfered.
; else FALSE
;
; Warning: This function can only be called at Irql 0 with interrupts
; enabled. It is intended to be called only to deal with R3 exceptions
; when the emulator is being used.
;
; Revision History:
;
;
;*******************************************************************************
cPublicProc _KiNpxFrameToEm87State, 1
push ebp
mov ebp, esp
push ebx ; Save C runtime varibles
push edi
push esi
push esp ; Pass current Esp to handler
push offset npxts_30 ; Set Handler address
push PCR[PcExceptionList] ; Set next pointer
mov PCR[PcExceptionList],esp ; Link us on
if DBG
pushfd ; Sanity check
pop ecx ; make sure interrupts are enabled
test ecx, EFLAGS_INTERRUPT_MASK
jz short npxts_err
stdCall _KeGetCurrentIrql ; Sanity check
cmp al, DISPATCH_LEVEL ; make sure Irql is below DPC level
jnc short npxts_err
endif
xor eax, eax ; set FALSE
mov ebx,PCR[PcPrcbData+PbCurrentThread]
mov ebx,[ebx]+ThApcState+AsProcess
cmp dword ptr [ebx]+PrVdmObjects,0 ; is this a vdm process?
jne short npxts_10 ; Yes, then not supported
mov ebx, PCR[PcTeb] ; R3 Teb
cmp [ebx].Einstall, 0 ; Initialized?
je short npxts_10 ; No, then don't set NpxFrame
mov esi, [ebp+8] ; (esi) = NpxFrame
call StorState
or [ebx].CURErr, Summary ; Set completed
mov eax, 1 ; Return TRUE
npxts_10:
pop PCR[PcExceptionList] ; Remove our exception handle
add esp, 8 ; clear stack
pop esi
pop edi
pop ebx
pop ebp
stdRet _KiNpxFrameToEm87State
npxts_30:
;
; WARNING: Here we directly unlink the exception handler from the
; exception registration chain. NO unwind is performed. We can take
; this short cut because we know that our handler is a leaf-node.
;
mov esp, [esp+8] ; (esp)-> ExceptionList
xor eax, eax ; Return FALSE
jmp short npxts_10
ret
if DBG
npxts_err:
stdCall _KeBugCheck <IRQL_NOT_LESS_OR_EQUAL>
endif
_KiNpxFrameToEm87State ENDP
;*** StorState - emulate FRSTOR [address]
;
; ARGUMENTS
; (esi) = where to get the environment
; (ebx) = PcTeb
;
;
; DESCRIPTION
; This routine emulates an 80387 FRSTOR (restore state)
StorState:
;First we set up the status word so that [CURstk] is initialized.
;The floating-point registers are stored in logical ST(0) - ST(7) order,
;not physical register order. We don't do a full load of the environment
;because we're not ready to use the tag word yet.
mov ax, [esi].E32_StatusWord
call SetEmStatusWord ;Initialize [CURstk]
add esi,size Env80x87_32 ;Skip over environment
;Load of temp real has one difference from real math chip: it is an invalid
;operation to load an unsupported format. By ensuring the exception is
;masked, we will convert unsupported format to Indefinite. Note that the
;mask and [CURerr] will be completely restored by the FLDENV at the end.
mov [ebx].CWmask,3FH ;Mask off invalid operation exception
mov edi,[ebx].CURstk
mov ebp,NumLev
FrstorLoadLoop:
push esi
call LoadTempReal ;In emload.asm
pop esi
add esi,10 ;Point to next temp real
;;; NextStackElem edi,Frstor
cmp edi,INITstk
jae short fr_wrap
add edi,Reg87Len
fr_continue:
dec ebp
jnz short FrstorLoadLoop
sub esi,NumLev*10+size Env80x87_32 ;Point to start of env.
;
; Stor Enviroment
; (esi) = where to get enviroment
; (ebx) = PcTeb
;
mov ax, [esi].E32_StatusWord
call SetEmStatusWord ; set up status word
mov ax, [esi].E32_ControlWord
call SetControlWord
mov ax, [esi].E32_TagWord
call UseTagWord
mov eax, [esi].E32_CodeOff
mov [ebx].PrevCodeOff, eax
mov eax, [esi].E32_DataOff
mov [ebx].PrevDataOff, eax
ret
fr_wrap:
mov edi, BEGstk
jmp short fr_continue
;*** SetEmStatusWord -
;
; Given user status word in ax, set into emulator.
; Destroys ebx only.
SetEmStatusWord:
and ax,7F7FH
mov cx,ax
and cx,3FH ; set up CURerr in case user
mov [ebx].CURerr,cl ; wants to force an exception
mov ecx, eax
and ecx, not (7 shl 11) ; remove stack field.
mov [ebx].StatusWord, cx
sub ah, 8 ; adjust for emulator's stack layout
and ah, 7 shl 3
mov al, ah
shr ah, 1
add al, ah ; stack field * 3 * 4
.erre Reg87Len eq 12
and eax, 255 ; eax is now 12*stack number
add eax, BEGstk
mov [ebx].CURstk, eax
ret
SetControlWord:
and ax,0F3FH ; Limit to valid values
mov [ebx].ControlWord, ax ; Store in the emulated control word
not al ;Flip mask bits for fast compare
and al,3FH ;Limit to valid mask bits
mov [ebx].ErrMask,al
and eax,(RoundControl + PrecisionControl) shl 8
.erre RoundControl eq 1100B
.erre PrecisionControl eq 0011B
shr eax,6 ;Put PC and RC in bits 2-5
mov ecx,_Ki387RoundModeTable
mov ecx,[ecx+eax] ;Get correct RoundMode vector
mov [ebx].RoundMode,ecx
mov [ebx].SavedRoundMode,ecx
and eax,RoundControl shl (8-6) ;Mask off precision control
mov ecx,_Ki387RoundModeTable
mov ecx,[ecx+(eax+PC64 shl (8-6))];Get correct RoundMode vector
mov [ebx].TransRound,ecx ;Round mode w/o precision
ret
;*** UseTagWord - Set up tags using tag word from environment
;
; ARGUMENTS
; ax - should contain the tag word
;
; Destroys ax,bx,cx,dx,di
UseTagWord:
ror ax, 2 ; mov Tag(0) into top bits of ax
mov edi,INITstk
mov ecx, NumLev
UseTagLoop:
mov dl,bTAG_EMPTY
cmp ah, 0c0h ;Is register to be tagged Empty?
jae short SetTag ;Yes, go mark it
mov dl,[ebx+edi].bTag ;Get current tag
cmp dl,bTAG_EMPTY ;Is register currently Empty?
je short SetTagNotEmpty ;If so, go figure out tag for it
SetTag:
mov [ebx+edi].bTag,dl
UseTagLoopCheck:
sub edi, Reg87Len
shl eax, 2
loop UseTagLoop
ret
SetTagEmpty:
mov [ebx+edi].bTag, bTAG_EMPTY
jmp short UseTagLoopCheck
SetTagNotEmpty:
;Register is currently tagged empty, but new tag word says it is not empty.
;Figure out a new tag for it. The rules are:
;
;1. Everything is either normalized or zero--unnormalized formats cannot
;get in. So if the high half mantissa is zero, the number is zero.
;
;2. Although the exponent bias is different, NANs and Infinities are in
;standard IEEE format - exponent is TexpMax, mantissa indicates NAN vs.
;infinity (mantissa for infinity is 800..000H).
;
;3. Denormals have an exponent less than TexpMin.
;
;4. If the low half of the mantissa is zero, it is tagged bTAG_SNGL
;
;5. Everything else is bTAG_VALID
cmp [ebx+edi].lManHi, 0
mov dl,bTAG_ZERO ;Try zero first
jz short SetTag ;Is mantissa zero?
mov edx,[ebx+edi].ExpSgn
mov dl,bTAG_DEN
cmp edx,TexpMin shl 16 ;Is it denormal?
jl short SetTag
cmp [ebx+edi].lManLo,0 ;Is low half zero?
.erre bTAG_VALID eq 1
.erre bTAG_SNGL eq 0
setnz dl ;if low half==0 then dl=0 else dl=1
cmp edx,TexpMax shl 16 ;Is it NAN or Infinity?
jl short SetTag ;If not, it's valid
.erre (bTAG_VALID - bTAG_SNGL) shl TAG_SHIFT eq (bTAG_NAN - bTAG_INF)
shl dl,TAG_SHIFT
add dl,bTAG_INF - bTAG_SNGL
;If the low bits were zero we have just changed bTAG_SNGL to bTAG_INF
;If the low bits weren't zero, we changed bTAG_VALID to bTAG_NAN
;See if infinity is really possible: is high half 80..00H?
cmp [ebx+edi].lManHi,1 shl 31 ;Is it infinity?
jz short SetTag ;Store tag for infinity or NAN
mov dl,bTAG_NAN
jmp short SetTag
;*** LoadTempReal
;
;
;
LoadTempReal:
mov ebx,[esi+4] ;Get high half of mantissa
mov cx,[esi+8] ;Get exponent and sign
mov esi,[esi] ;Get low half of mantissa
mov eax,ecx
and ch,7FH ;Mask off sign bit
shl ecx,16 ;Move exponent to high end
mov ch,ah ;Restore sign
jz short ZeroOrDenorm80
;Check for unsupported format: unnormals (MSB not set)
or ebx,ebx
jns short Unsupported
sub ecx,(IexpBias-TexpBias) shl 16 ;Correct the bias
cmp ecx,TexpMax shl 16
jge short NANorInf80
SetupTag:
or esi,esi ;Any bits in low half?
.erre bTAG_VALID eq 1
.erre bTAG_SNGL eq 0
setnz cl ;if low half==0 then cl=0 else cl=1
jmp short SaveStack
NANorInf80:
mov cl,bTAG_NAN
cmp ebx,1 shl 31 ;Only 1 bit set means infinity
jnz short SaveStack
or esi,esi
jnz short SaveStack
mov cl,bTAG_INF
jmp short SaveStack
ZeroOrDenorm80:
;Exponent is zero. Number is either zero or denormalized
or ebx,ebx
jnz short ShortNorm80 ;Are top 32 bits zero?
or esi,esi ;Are low 32 bits zero too?
jnz LongNorm80
mov cl,bTAG_ZERO
jmp short SaveStack
;This code accepts and works correctly with pseudo-denormals (MSB already set)
LongNorm80:
xchg ebx,esi ;Shift up 32 bits
sub ecx,32 shl 16 ;Correct exponent
ShortNorm80:
add ecx,(TexpBias-IexpBias+1-31) shl 16 ;Fix up bias
bsr edx,ebx ;Scan for MSB
;Bit number in edx ranges from 0 to 31
mov cl,dl
not cl ;Convert bit number to shift count
shld ebx,esi,cl
shl esi,cl
shl edx,16 ;Move exp. adjustment to high end
add ecx,edx ;Adjust exponent
jmp short SetUpTag
SaveStack:
mov eax, PCR[PcTeb]
mov [eax].CURstk,edi
mov [eax+edi].lManLo,esi
mov [eax+edi].lManHi,ebx
mov [eax+edi].ExpSgn,ecx
mov ebx, eax ; (ebx) = PcTeb
ret
Unsupported:
mov ebx, PCR[PcTeb]
or [ebx].CURerr,Invalid ; (assume it's masked?)
mov [ebx+edi].lManLo,0
mov [ebx+edi].lManHi,0C0000000H
mov [ebx+edi].ExpSgn,TexpMax shl 16 + bSign shl 8 + bTAG_NAN
mov [ebx].CURstk,edi ;Update top of stack
ret
_TEXT ENDS
END