Windows2000/private/ntos/ke/i386/kimacro.inc
2020-09-30 17:12:32 +02:00

1452 lines
35 KiB
PHP

; Copyright (c) 1989 Microsoft Corporation
; Module Name:
; kimacro.inc
; Abstract:
; This module contains the macros used by kernel assembler code.
; It includes macros to manipulate interrupts, support system
; entry and exit for syscalls, faults, and interrupts, and
; manipulate floating point state.
; Author:
; Shie-Lin (shielint) 24-Jan-1990
; Revision History:
; BryanWi 17-Aug-90
; Replace GENERATE_MACHINE... and RESTORE... with ENTER_...
; and EXIT_ALL macros.
; These constants are used by the fpo directives in this file.
; This directive causes the assembler to output a .debug$f segment
; in the obj file. The segment will contain 1 fpo record for each
; directive present during assembly.
; Although the assembler will accept all valid values, the value of 7
; in the FPO_REGS field indicates to the debugger that a trap frame is
; generated by the function. The value of 7 can be used because the
; C/C++ compiler puts a maximum value of 3 in the field.
FPO_LOCALS equ 0 ; 32 bits, size of locals in dwords
FPO_PARAMS equ 0 ; 32 bits, size of parameters in dwords
FPO_PROLOG equ 0 ; 12 bits, 0-4095, # of bytes in prolog
FPO_REGS equ 0 ; 3 bits, 0-7, # regs saved in prolog
FPO_USE_EBP equ 0 ; 1 bit, 0-1, is ebp used?
FPO_TRAPFRAME equ 1 ; 2 bits, 0=fpo, 1=trap frame, 2=tss
; POLL_DEBUGGER
; Macro Description:
; Call the debugger so it can check for control-c. If it finds
; it, it will report our iret address as address of break-in.
; N.B. This macro should be used when all the caller's registers
; have been restored. (Otherwise, the kernel debugger register
; dump will not have correct state.) The only exception is
; fs. This is because Kd may need to access PCR or PRCB.
; Arguments:
; There MUST be an iret frame on the stack when this macro
; is invoked.
; Exit:
; Debugger will iret for us, so we don't usually return from
; this macro, but remember that it generates nothing for non-DEVL
; kernels.
POLL_DEBUGGER macro
local a, b, c_
if DEVL
EXTRNP _DbgBreakPointWithStatus,1
stdCall _KdPollBreakIn
or al,al
jz short c_
stdCall _DbgBreakPointWithStatus,<DBG_STATUS_CONTROL_C>
c_:
endif ; DEVL
endm
; ASSERT_FS
; Try to catch funky condition wherein we get FS=r3 value while
; running in kernel mode.
ASSERT_FS macro
local a,b
if DBG
EXTRNP _KeBugCheck,1
mov bx,fs
cmp bx,KGDT_R0_PCR
jnz short a
cmp dword ptr fs:[0], 0
jne short b
a:
stdCall _KeBugCheck,<-1>
align 4
b:
endif
endm
; Copy data from various places into base of TrapFrame, net effect
; is to allow dbg KB command to trace accross trap frame, and to
; allow user to find arguments to system calls.
; USE ebx and edi.
SET_DEBUG_DATA macro
ife FPO
; This macro is used by ENTER_SYSTEM_CALL, ENTER_TRAP and ENTER_INTERRUPT
; and is used at the end of above macros. It is safe to destroy ebx, edi.
mov ebx,[ebp]+TsEbp
mov edi,[ebp]+TsEip
mov [ebp]+TsDbgArgPointer,edx
mov [ebp]+TsDbgArgMark,0BADB0D00h
mov [ebp]+TsDbgEbp,ebx
mov [ebp]+TsDbgEip,edi
endif
endm
; ENTER_DR_ASSIST EnterLabel, ExitLabel, NoAbiosAssist, NoV86Assist
; Macro Description:
; Jumped to by ENTER_ macros to deal with DR register work,
; abios work and v86 work. The main purpose of this macro is
; that interrupt/trap/systemCall EnterMacros can jump here to
; deal with some special cases such that most of the times the
; main ENTER_ execution flow can proceed without being branched.
; If (previousmode == usermode) {
; save DR* in trapframe
; load DR* from Prcb
; }
; Arguments:
; EnterLabel - label to emit
; ExitLabel - label to branch to when done
; Entry-conditions:
; Dr work:
; DebugActive == TRUE
; (esi)->Thread object
; (esp)->base of trap frame
; (ebp)->base of trap frame
; Abios work:
; v86 work:
; Exit-conditions:
; Dr work:
; Interrupts match input state (this routine doesn't change IEF)
; (esp)->base of trap frame
; (ebp)->base of trap frame
; Preserves entry eax, edx
; Abios work:
; v86 work:
ENTER_DR_ASSIST macro EnterLabel, ExitLabel, NoAbiosAssist, NoV86Assist, V86R
local a,b
public Dr_&EnterLabel
align 4
Dr_&EnterLabel:
; Test if we came from user-mode. If not, do nothing.
test dword ptr [ebp]+TsEFlags,EFLAGS_V86_MASK
jnz short a
test dword ptr [ebp]+TsSegCs,MODE_MASK
jz Dr_&ExitLabel ; called from kmode, go continue
; Save user-mode Dr* regs in TrapFrame
; We are safe to destroy ebx, ecx, edi because in ENTER_INTERRUPT and
; ENTER_TRAP these registers are saved already. In ENTER_SYSTEMCALL
; ebx, edi is saved and ecx is don't-care.
a: mov ebx,dr0
mov ecx,dr1
mov edi,dr2
mov [ebp]+TsDr0,ebx
mov [ebp]+TsDr1,ecx
mov [ebp]+TsDr2,edi
mov ebx,dr3
mov ecx,dr6
mov edi,dr7
mov [ebp]+TsDr3,ebx
mov [ebp]+TsDr6,ecx
mov ebx,0
mov [ebp]+TsDr7,edi
; Make Dr7 safe before loading junk from save area
mov dr7,ebx
; Load KernelDr* into processor
mov edi,dword ptr fs:[PcPrcb]
mov ebx,[edi].PbProcessorState.PsSpecialRegisters.SrKernelDr0
mov ecx,[edi].PbProcessorState.PsSpecialRegisters.SrKernelDr1
mov dr0,ebx
mov dr1,ecx
mov ebx,[edi].PbProcessorState.PsSpecialRegisters.SrKernelDr2
mov ecx,[edi].PbProcessorState.PsSpecialRegisters.SrKernelDr3
mov dr2,ebx
mov dr3,ecx
mov ebx,[edi].PbProcessorState.PsSpecialRegisters.SrKernelDr6
mov ecx,[edi].PbProcessorState.PsSpecialRegisters.SrKernelDr7
mov dr6,ebx
mov dr7,ecx
ifnb <V86R>
test dword ptr [ebp]+TsEFlags,EFLAGS_V86_MASK
jz short b
jmp Dr_&V86R
endif
b:
jmp Dr_&ExitLabel
ifb <NoAbiosAssist>
public Abios_&EnterLabel
align 4
Abios_&EnterLabel:
; INTERRUPT_STACK16_TO_STACK32
; This macro remaps current 32bit stack to 16bit stack at interrupt
; time.
; Arguments:
; (esp)->trap frame.
; (eax)->Entry Esp.
mov eax, [esp].TsErrCode ; (eax) = Entry Esp
mov ecx, KGDT_R0_DATA
mov edx, esp
shl eax, 16
add edx, fs:[PcstackLimit]
mov [esp].TsErrCode, eax
mov ss, cx
mov esp, edx ; Interrupts are off
mov ebp, edx
jmp Abios_&ExitLabel
endif ; NoAbiosAssist
ifb <NoV86Assist>
public V86_&EnterLabel
align 4
V86_&EnterLabel:
; Move the V86 segment registers to the correct place in the frame
mov eax,dword ptr [ebp].TsV86Fs
mov ebx,dword ptr [ebp].TsV86Gs
mov ecx,dword ptr [ebp].TsV86Es
mov edx,dword ptr [ebp].TsV86Ds
mov [ebp].TsSegFs,ax
mov [ebp].TsSegGs,bx
mov [ebp].TsSegEs,cx
mov [ebp].TsSegDs,dx
jmp V86_&ExitLabel
endif ; NoV86Assist
endm
; ENTER_SYSCALL AssistLabel, TagetLabel, NoFSLoad
; Macro Description:
; Build the frame and set registers needed by a system call.
; Save:
; Errorpad,
; Non-volatile regs,
; FS,
; ExceptionList,
; PreviousMode
; Don't Save:
; Volatile regs
; Seg regs
; Floating point state
; Set:
; FS,
; ExceptionList,
; PreviousMode,
; Direction
; Arguments:
; AssistLabel - label ENTER_ASSIST macro is at
; TargetLabel - label to emit for ENTER_ASSIST to jump to
; NoFSLoad - Don't set FS(it is already set to KGDT_R0_PCR at entry).
; Exit-conditions:
; Interrupts match input state (this routine doesn't change IEF)
; (esp)->base of trap frame
; (ebp)->base of trap frame
; Preserves entry eax, edx
; Note:
; The DS: reference to PreviousMode is *required* for correct
; functioning of lazy selector loads. If you remove this use
; of DS:, put a DS: override on something.
ENTER_SYSCALL macro AssistLabel, TargetLabel, NoFSLoad
.FPO ( FPO_LOCALS, FPO_PARAMS, FPO_PROLOG, FPO_REGS, FPO_USE_EBP, FPO_TRAPFRAME )
ifdef KERNELONLY
; Construct trap frame.
; N.B. The initial part of the trap frame is constructed by pushing values
; on the stack. If the format of the trap frame is changed, then the
; following code must alos be changed.
push 0 ; put pad dword for error on stack
push ebp ; save the non-volatile registers
push ebx ;
push esi ;
push edi ;
ifb <NoFSLoad>
push fs ; save and set FS to PCR.
mov ebx,KGDT_R0_PCR ; set PCR segment number
mov fs,bx ;
else
; FS already contains KGDT_R0_PCR(entry via PentiumPro fast system call)
push KGDT_R3_TEB OR RPL_MASK
endif ; NoFSLoad
; Save the old exception list in trap frame and initialize a new empty
; exception list.
push PCR[PcExceptionList] ; save old exception list
mov PCR[PcExceptionList],EXCEPTION_CHAIN_END ; set new empty list
; Save the old previous mode in trap frame, allocate remainder of trap frame,
; and set the new previous mode.
mov esi,PCR[PcPrcbData+PbCurrentThread] ; get current thread address
push [esi]+ThPreviousMode ; save old previous mode
sub esp,TsPreviousPreviousMode ; allocate remainder of trap frame
mov ebx,[esp+TsSegCS] ; compute new previous mode
and ebx,MODE_MASK ;
mov [esi]+ThPreviousMode,bl ; set new previous mode
; Save the old trap frame address and set the new trap frame address.
mov ebp,esp ; set trap frame address
mov ebx,[esi].ThTrapFrame ; save current trap frame address
mov [ebp].TsEdx,ebx ;
mov [esi].ThTrapFrame,ebp ; set new trap frame address
cld ; make sure direction is forward
SET_DEBUG_DATA ; Note this destroys edi
test byte ptr [esi]+ThDebugActive,-1 ; test if debugging active
jnz Dr_&AssistLabel ; if nz, debugging is active on thread
Dr_&TargetLabel: ;
sti ; enable interrupts
else
%out ENTER_SYSCAL outside of kernel
.err
endif
endm
; ENTER_INTERRUPT AssistLabel, TargetLabel
; Macro Description:
; Build the frame and set registers needed by an interrupt.
; Save:
; Errorpad,
; Non-volatile regs,
; FS,
; ExceptionList,
; PreviousMode
; Volatile regs
; Seg regs from V86 mode
; DS, ES, GS
; Don't Save:
; Floating point state
; Set:
; FS,
; ExceptionList,
; Direction,
; DS, ES
; Don't Set:
; PreviousMode
; Arguments:
; AssistLabel - label ENTER_ASSIST macro is at
; TargetLabel - label to emit for ENTER_ASSIST to jump to
; Exit-conditions:
; Interrupts match input state (this routine doesn't change IEF)
; (esp)->base of trap frame
; (ebp)->base of trap frame
; Preserves entry eax, ecx, edx
ENTER_INTERRUPT macro AssistLabel, TargetLabel, PassParm
local b
.FPO ( FPO_LOCALS+2, FPO_PARAMS, FPO_PROLOG, FPO_REGS, FPO_USE_EBP, FPO_TRAPFRAME )
; Fill in parts of frame we care about
ifb <PassParm>
push esp ; Use Error code field to save 16bit esp
endif
push ebp ; Save the non-volatile registers
push ebx
push esi
push edi
sub esp, TsEdi
mov ebp,esp
mov [esp]+TsEax, eax ; Save volatile registers
mov [esp]+TsEcx, ecx
mov [esp]+TsEdx, edx
if DBG
mov dword ptr [esp]+TsPreviousPreviousMode, -1 ; ThPreviousMode not pushed on interrupt
endif
test dword ptr [esp].TsEflags,EFLAGS_V86_MASK
jnz V86_&AssistLabel
cmp word ptr [esp]+TsSegCs, KGDT_R0_CODE
jz short @f
mov [esp]+TsSegFs, fs ; Save and set FS to PCR.
mov [esp]+TsSegDs, ds
mov [esp]+TsSegEs, es
mov [esp]+TsSegGs, gs
V86_&TargetLabel:
mov ebx,KGDT_R0_PCR
mov eax,KGDT_R3_DATA OR RPL_MASK
mov fs, bx
mov ds, ax
mov es, ax
@@:
mov ebx, fs:[PcExceptionList] ;Save, set ExceptionList
mov fs:[PcExceptionList],EXCEPTION_CHAIN_END
mov [esp]+TsExceptionList, ebx
ifnb <PassParm>
lea eax, [esp].TsErrCode
lea ecx, [esp].TsEip ; Move eax to EIP field
mov ebx, ss:[eax] ; (ebx) = parameter to pass
mov ss:[eax], ecx ; save 16bit esp
endif
; Remap ABIOS 16 bit stack to 32 bit stack, if necessary.
cmp esp, 10000h
jb Abios_&AssistLabel
mov dword ptr [esp].TsErrCode, 0 ; Indicate no remapping.
Abios_&TargetLabel:
; end of Abios stack checking
cld
ifnb <PassParm>
push ebx ; push parameter as argument
endif
SET_DEBUG_DATA
test byte ptr PCR[PcDebugActive], -1
jnz Dr_&AssistLabel
Dr_&TargetLabel:
endm
; ENTER_INTERRUPT_FORCE_STATE AssistLabel, TargetLabel
; Macro Description:
; Build the frame and set registers needed by an interrupt.
; This macro is the same as ENTER_INTERRUPT except that it forces the
; needed state and does not save previous state.
; This macro is currently only used by HalpApicRebootService which does not
; return;
; Save:
; Errorpad,
; Non-volatile regs,
; ExceptionList,
; PreviousMode
; Volatile regs
; Seg regs from V86 mode
; Don't Save:
; FS,
; DS, ES, GS
; Floating point state
; Set:
; FS,
; ExceptionList,
; Direction,
; DS, ES
; Don't Set:
; PreviousMode
; Arguments:
; AssistLabel - label ENTER_ASSIST macro is at
; TargetLabel - label to emit for ENTER_ASSIST to jump to
; Exit-conditions:
; Interrupts match input state (this routine doesn't change IEF)
; (esp)->base of trap frame
; (ebp)->base of trap frame
; Preserves entry eax, ecx, edx
ENTER_INTERRUPT_FORCE_STATE macro AssistLabel, TargetLabel, PassParm
local b
.FPO ( FPO_LOCALS+2, FPO_PARAMS, FPO_PROLOG, FPO_REGS, FPO_USE_EBP, FPO_TRAPFRAME )
; Fill in parts of frame we care about
ifb <PassParm>
push esp ; Use Error code field to save 16bit esp
endif
push ebp ; Save the non-volatile registers
push ebx
push esi
push edi
sub esp, TsEdi
mov ebp,esp
mov [esp]+TsEax, eax ; Save volatile registers
mov [esp]+TsEcx, ecx
mov [esp]+TsEdx, edx
if DBG
mov dword ptr [esp]+TsPreviousPreviousMode, -1 ; ThPreviousMode not pushed on interrupt
endif
test dword ptr [esp].TsEflags,EFLAGS_V86_MASK
jnz V86_&AssistLabel
V86_&TargetLabel:
mov ebx,KGDT_R0_PCR
mov eax,KGDT_R3_DATA OR RPL_MASK
mov fs, bx
mov ds, ax
mov es, ax
@@:
mov ebx, fs:[PcExceptionList] ;Save, set ExceptionList
mov fs:[PcExceptionList],EXCEPTION_CHAIN_END
mov [esp]+TsExceptionList, ebx
ifnb <PassParm>
lea eax, [esp].TsErrCode
lea ecx, [esp].TsEip ; Move eax to EIP field
mov ebx, ss:[eax] ; (ebx) = parameter to pass
mov ss:[eax], ecx ; save 16bit esp
endif
; Remap ABIOS 16 bit stack to 32 bit stack, if necessary.
cmp esp, 10000h
jb Abios_&AssistLabel
mov dword ptr [esp].TsErrCode, 0 ; Indicate no remapping.
Abios_&TargetLabel:
; end of Abios stack checking
cld
ifnb <PassParm>
push ebx ; push parameter as argument
endif
SET_DEBUG_DATA
test byte ptr PCR[PcDebugActive], -1
jnz Dr_&AssistLabel
Dr_&TargetLabel:
endm
; ENTER_TRAP AssistLabel, TargetLabel
; Macro Description:
; Build the frame and set registers needed by a trap or exception.
; Save:
; Non-volatile regs,
; FS,
; ExceptionList,
; PreviousMode,
; Volatile regs
; Seg Regs from V86 mode
; DS, ES, GS
; Don't Save:
; Floating point state
; Set:
; FS,
; Direction,
; DS, ES
; Don't Set:
; PreviousMode,
; ExceptionList
; Arguments:
; AssistLabel - label ENTER_ASSIST macro is at
; TargetLabel - label to emit for ENTER_ASSIST to jump to
; Exit-conditions:
; Interrupts match input state (this routine doesn't change IEF)
; (esp)->base of trap frame
; (ebp)->base of trap frame
; Preserves entry eax
ENTER_TRAP macro AssistLabel, TargetLabel
local b
.FPO ( FPO_LOCALS, FPO_PARAMS, FPO_PROLOG, FPO_REGS, FPO_USE_EBP, FPO_TRAPFRAME )
; Fill in parts of frame we care about
if DBG
ifndef _Ki16BitStackException
EXTRNP _Ki16BitStackException
endif
endif ; DBG
mov word ptr [esp+2], 0 ; Clear upper word of ErrorCode
push ebp ; Save the non-volatile registers
push ebx
push esi
push edi
push fs ; Save and set FS to PCR.
mov ebx,KGDT_R0_PCR
mov fs,bx
mov ebx, fs:[PcExceptionList] ;Save ExceptionList
push ebx
if DBG
push -1 ; Don't need to save ThPreviousMode from trap
else
sub esp, 4 ; pad dword
endif
push eax ; Save the volatile registers
push ecx
push edx
push ds ; Save segments
push es
push gs
; Skip allocate reset of trap frame and Set up DS/ES, they may be trash
mov ax,KGDT_R3_DATA OR RPL_MASK
sub esp,TsSegGs
mov ds,ax
mov es,ax
if DBG
; The code here check if the exception occurred in ring 0
; ABIOS code. If yes, this is a fatal condition. We will
; put out message and bugcheck.
cmp esp, 10000h ; Is the trap in abios?
jb _Ki16BitStackException ; if b, yes, switch stack and bugcheck.
endif ; DBG
mov ebp,esp
test dword ptr [esp].TsEflags,EFLAGS_V86_MASK
jnz V86_&AssistLabel
V86_&TargetLabel:
cld
SET_DEBUG_DATA
test byte ptr PCR[PcDebugActive], -1
jnz Dr_&AssistLabel
Dr_&TargetLabel:
endm
; EXIT_ALL NoRestoreSegs, NoRestoreVolatiles, NoPreviousMode
; Macro Description:
; Load a syscall frame back into the machine.
; Restore:
; Volatile regs, IF NoRestoreVolatiles blank
; NoPreviousMode,
; ExceptionList,
; FS,
; Non-volatile regs
; If the frame is a kernel mode frame, AND esp has been edited,
; then TsSegCs will have a special value. Test for that value
; and execute special code for that case.
; N.B. This macro generates an IRET! (i.e. It exits!)
; Arguments:
; NoRestoreSegs - non-blank if DS, ES, GS are NOT to be restored
; NoRestoreVolatiles - non-blank if Volatile regs are NOT to be restored
; NoPreviousMode - if nb pop ThPreviousMode
; Entry-conditions:
; (esp)->base of trap frame
; (ebp)->Base of trap frame
; Exit-conditions:
; Does not exit, returns.
; Preserves eax, ecx, edx, IFF NoRestoreVolatiles is set
?adjesp = 0
?RestoreAll = 1
EXIT_ALL macro NoRestoreSegs, NoRestoreVolatiles, NoPreviousMode
local a, b, f, x
local Abios_ExitHelp, Abios_ExitHelp_Target1, Abios_ExitHelp_Target2
local Dr_ExitHelp, Dr_ExitHelp_Target, V86_ExitHelp, V86_ExitHelp_Target
local Db_NotATrapFrame, Db_A, Db_NotValidEntry, NonFlatPm_Target
; Sanity check some values and setup globals for macro
?adjesp = TsSegGs
?RestoreAll = 1
ifnb <NoRestoreSegs>
?RestoreAll = 0
?adjesp = ?adjesp + 12
endif
ifnb <NoRestoreVolatiles>
if ?RestoreAll eq 1
%out "EXIT_ALL NoRestoreVolatiles requires NoRestoreSegs"
.err
endif
?adjesp = ?adjesp + 12
endif
ifb <NoPreviousMode>
ifndef KERNELONLY
%out EXIT_ALL can not restore previousmode outside kernel
.err
endif
endif
; All callers are responsible for getting here with interrupts disabled.
if DBG
pushfd
pop edx
test edx, EFLAGS_INTERRUPT_MASK
jnz Db_NotValidEntry
cmp esp, ebp ; make sure esp = ebp
jne Db_NotValidEntry
; Make sure BADB0D00 sig is present. If not this isn't a trap frame!
Db_A: sub [esp]+TsDbgArgMark,0BADB0D00h
jne Db_NotATrapFrame
endif
ASSERT_FS
mov edx, [esp]+TsExceptionList
if DBG
or edx, edx
jnz short @f
int 3
@@:
endif
mov ebx, fs:[PcDebugActive] ; (ebx) = DebugActive flag
mov fs:[PcExceptionList], edx ; Restore ExceptionList
ifb <NoPreviousMode>
mov ecx, [esp]+TsPreviousPreviousMode ; Restore PreviousMode
if DBG
cmp ecx, -1 ; temporary debugging code
jne @f ; to make sure no one tries to pop ThPreviousMode
int 3 ; when it wasn't saved
@@:
endif
mov esi,fs:[PcPrcbData+PbCurrentThread]
mov [esi]+ThPreviousMode,cl
else
if DBG
mov ecx, [esp]+TsPreviousPreviousMode
cmp ecx, -1 ; temporary debugging code
je @f ; to make sure no one pushed ThPreviousMode and
int 3 ; is now exiting without restoreing it
@@:
endif
endif
test ebx, 0fh
jnz Dr_ExitHelp
Dr_ExitHelp_Target:
test dword ptr [esp].TsEflags,EFLAGS_V86_MASK
jnz V86_ExitHelp
test word ptr [esp]+TsSegCs,FRAME_EDITED
jz b ; Edited frame pop out.
if ?RestoreAll eq 0
.errnz MODE_MASK-1
cmp word ptr [esp]+TsSegCs,KGDT_R3_CODE OR RPL_MASK ; set/clear ZF
bt word ptr [esp]+TsSegCs,0 ; test MODE_MASK set/clear CF
cmc ; (CF=1 and ZF=0)
ja f ; jmp if CF=0 and ZF=0
endif
ifb <NoRestoreVolatiles>
ifb <NoRestoreSegs> ; must restore eax before any
mov eax, [esp].TsEax ; selectors! (see trap0e handler)
endif
endif
ifb <NoRestoreVolatiles>
mov edx, [ebp]+TsEdx ; Restore volitales
mov ecx, [ebp]+TsEcx
ifb <NoRestoreSegs>
else
mov eax, [ebp]+TsEax
endif
endif ; NoRestoreVolatiles
cmp word ptr [ebp]+TsSegCs, KGDT_R0_CODE
jz short @f
ifb <NoRestoreSegs>
lea esp, [ebp]+TsSegGs
pop gs ; Restore Segs
pop es
pop ds
endif
NonFlatPm_Target:
lea esp, [ebp]+TsSegFs
pop fs
@@:
V86_ExitHelp_Target:
lea esp, [ebp]+TsEdi ; Skip PreMode, ExceptList and fs
pop edi ; restore non-volatiles
pop esi
pop ebx
pop ebp
; Esp MUST point to the Error Code on the stack. Because we use it to
; store the entering esp.
cmp word ptr [esp+8], 80h ; check for abios code segment?
ja Abios_ExitHelp
Abios_ExitHelp_Target1:
add esp, 4 ; remove error code from trap frame
Abios_ExitHelp_Target2:
; End of ABIOS stack check
ifnb <NoRestoreVolatiles>
test _KeFeatureBits, KF_FAST_SYSCALL
jz @f
;; If returning to kernel mode, use iretd
test dword ptr [esp+4], MODE_MASK
jz @f ; Return to kmode. use iretd
;; If returning to V86 mode, use iretd
test dword ptr [esp+8], EFLAGS_V86_MASK
jnz @f ; Return to user V86 mode
pop edx ; pop EIP
add esp, 8 ; Remove CS & Eflags
pop ecx ; pop ESP
sti ; sysexit does not reload flags
SYSEXIT_INSTR
@@:
endif ;; <NoRestoreVolatiles>
iretd ; return
if DBG
Db_NotATrapFrame:
add [esp]+TsDbgArgMark,0BADB0D00h ; put back the orig value
Db_NotValidEntry:
int 3
jmp Db_A
endif
; EXIT_HELPER
; if (PreviousMode == UserMode) {
; DR* regs = TF.Dr* regs
; }
; Entry-Conditions:
; DebugActive == TRUE
; (ebp)->TrapFrame
align dword
Dr_ExitHelp:
test dword ptr [ebp]+TsEFlags,EFLAGS_V86_MASK
jnz short x
test dword ptr [ebp]+TsSegCs,MODE_MASK
jz Dr_ExitHelp_Target
x: mov ebx,0
mov esi,[ebp]+TsDr0
mov edi,[ebp]+TsDr1
mov dr7,ebx
mov dr0,esi
mov ebx,[ebp]+TsDr2
mov dr1,edi
mov dr2,ebx
mov esi,[ebp]+TsDr3
mov edi,[ebp]+TsDr6
mov ebx,[ebp]+TsDr7
mov dr3,esi
mov dr6,edi
mov dr7,ebx
jmp Dr_ExitHelp_Target
align dword
Abios_ExitHelp:
; INTERRUPT_STACK32_TO_STACK16
; This macro remaps current 32bit stack to 16bit stack at interrupt
; time.
; Arguments:
; (esp)->TsEip.
; PERFNOTE shielint We should check if there is any other H/W interrupt
; pending. If yes, don't switch back to 16 bit stack. This way
; we can get better performance.
cmp word ptr [esp+2], 0 ; (esp+2) = Low word of error code
jz Abios_ExitHelp_Target1
cmp word ptr [esp], 0 ; (esp) = High word of error code
jnz Abios_ExitHelp_Target1
shr dword ptr [esp], 16
mov word ptr [esp + 2], KGDT_STACK16
lss sp, dword ptr [esp]
movzx esp, sp
jmp Abios_ExitHelp_Target2
; Restore volatiles for V86 mode, and move seg regs
align dword
V86_ExitHelp:
add esp,TsEdx
pop edx
pop ecx
pop eax
jmp V86_ExitHelp_Target
if ?RestoreAll eq 0
; Restore segs and volatiles for non-flat R3 PM (VDM in PM)
f: mov eax,[esp].TsEax ; restore eax before any selectors
; (see trap0e handler)
add esp,TsSegGs
pop gs
pop es
pop ds
pop edx
pop ecx
jmp NonFlatPm_Target
endif ; not ?RestoreAll
; TsSegCs contains the special value that means the frame was edited
; in a way that affected esp, AND it's a kernel mode frame.
; (Special value is null selector except for RPL.)
; Put back the real CS.
; push eflags, eip onto target stack
; restore
; switch to target stack
; iret
b: mov ebx,[esp]+TsTempSegCs
mov [esp]+TsSegCs,ebx
; There is no instruction that will load esp with an arbitrary value
; (i.e. one out of a frame) and do a return, if no privledge transition
; is occuring. Therefore, if we are returning to kernel mode, and
; esp has been edited, we must "emulate" a kind of iretd.
; We do this by logically pushing the eip,cs,eflags onto the new
; logical stack, loading that stack, and doing an iretd. This
; requires that the new logical stack is at least 1 dword higher
; than the unedited esp would have been. (i.e. It is not legal
; to edit esp to have a new value < the old value.)
; KeContextToKframes enforces this rule.
; Compute new logical stack address
mov ebx,[esp]+TsTempEsp
sub ebx,12
mov [esp]+TsErrCode,ebx
; Copy eip,cs,eflags to new stack. note we do this high to low
mov esi,[esp]+TsEflags
mov [ebx+8],esi
mov esi,[esp]+TsSegCs
mov [ebx+4],esi
mov esi,[esp]+TsEip
mov [ebx],esi
; Do a standard restore sequence.
; Observe that RestoreVolatiles is honored. Editing a volatile
; register has no effect when returning from a system call.
ifb <NoRestoreVolatiles>
mov eax,[esp].TsEax
endif
; add esp,TsSegGs
;ifb <NoRestoreSegs>
; pop gs
; pop es
; pop ds
;else
; add esp,12
;endif
ifb <NoRestoreVolatiles>
mov edx, [esp]+TsEdx
mov ecx, [esp]+TsEcx
endif
;ifnb <NoPreviousMode>
; add esp, 4 ; Skip previous mode
;else
; pop ebx ; Restore PreviousMode
; mov esi,fs:[PcPrcbData+PbCurrentThread]
; mov ss:[esi]+ThPreviousMode,bl
;endif
; pop ebx
; mov fs:[PcExceptionList], ebx ;Restore ExceptionList
; pop fs
add esp, TsEdi
pop edi ; restore non-volatiles
pop esi
pop ebx
pop ebp
; (esp)->TsErrCode, where we saved the new esp
mov esp,[esp] ; Do move not push to avoid increment
iretd
endm
; INTERRUPT_EXIT
; Macro Description:
; This macro is executed on return from an interrupt vector service
; service routine. Its function is to restore privileged processor
; state, and continue thread execution. If control is returning to
; user mode and there is a user APC pending, then APC level interupt
; will be requested and control is transfered to the user APC delivery
; routine, if no higher level interrupt pending.
; Arguments:
; (TOS) = previous irql
; (TOS+4) = irq vector to eoi
; (TOS+8 ...) = machine_state frame
; (ebp)-> machine state frame (trap frame)
INTERRUPT_EXIT macro DebugCheck
local a
ifnb <DebugCheck>
POLL_DEBUGGER
endif
if DBG ; save current eip for
a: mov esi, offset a ; debugging bad trap frames
endif
ifdef __imp_Kei386EoiHelper@0
cli
call _HalEndSystemInterrupt@8
jmp dword ptr [__imp_Kei386EoiHelper@0]
else
cli
call dword ptr [__imp__HalEndSystemInterrupt@8]
jmp Kei386EoiHelper@0
endif
endm
; SPURIOUS_INTERRUPT_EXIT
; Macro Description:
; To exit an interrupt without performing the EOI.
; Arguments:
; (TOS) = machine_state frame
; (ebp)-> machine state frame (trap frame)
SPURIOUS_INTERRUPT_EXIT macro
local a
if DBG ; save current eip for
a: mov esi, offset a ; debugging bad trap frames
endif
ifdef __imp_Kei386EoiHelper@0
jmp dword ptr [__imp_Kei386EoiHelper@0]
else
jmp Kei386EoiHelper@0
endif
endm
; ENTER_TRAPV86
; Macro Description:
; Construct trap frame for v86 mode traps.
ENTER_TRAPV86 macro DRENTER,V86ENTER,LOADES
sub esp, TsErrCode
mov word ptr [esp].TsErrCode + 2, 0
mov [esp].TsEbx, ebx
mov [esp].TsEax, eax
mov [esp].TsEbp, ebp
mov [esp].TsEsi, esi
mov [esp].TsEdi, edi
mov ebx, KGDT_R0_PCR
mov eax, KGDT_R3_DATA OR RPL_MASK
mov [esp].TsEcx, ecx
mov [esp].TsEdx, edx
if DBG
mov [esp].TsPreviousPreviousMode, -1
mov [esp]+TsDbgArgMark, 0BADB0D00h
endif
mov fs, bx
mov ds, ax
ifnb <LOADES>
mov es, ax
endif
mov ebp, esp
cld ; CHECKIT_SUDEEP ; do we really need it
test byte ptr PCR[PcDebugActive], -1
jnz Dr_&DRENTER
Dr_&V86ENTER:
endm
; Taken from ntos\vdm\i386\vdmtb.inc
FIXED_NTVDMSTATE_LINEAR_PC_AT equ 0714H
FIXED_NTVDMSTATE_LINEAR_PC_98 equ 0614H
MACHINE_TYPE_MASK equ 0ff00H
VDM_VIRTUAL_INTERRUPTS equ 0200H
; EXIT_TRAPV86
; Macro Description:
; if UserApc is pending deliver it
; if User Context is v86 mode
; Exit from kernel (does not return)
; else
; return (expected to execute EXIT_ALL)
EXIT_TRAPV86 macro
local w, x, y, z
z: mov ebx, PCR[PcPrcbData+PbCurrentThread]
mov byte ptr [ebx]+ThAlerted, 0
cmp byte ptr [ebx]+ThApcState.AsUserApcPending, 0
jne short w
; Kernel exit to V86 mode
add esp,TsEdx
pop edx
pop ecx
pop eax
test byte ptr PCR[PcDebugActive], -1
jnz short x
y:
add esp,12 ; unused fields
pop edi
pop esi
pop ebx
pop ebp
add esp,4 ; clear error code
iretd
x: mov esi,[ebp]+TsDr0
mov edi,[ebp]+TsDr1
mov ebx,[ebp]+TsDr2
mov dr0,esi
mov dr1,edi
mov dr2,ebx
mov esi,[ebp]+TsDr3
mov edi,[ebp]+TsDr6
mov ebx,[ebp]+TsDr7
mov dr3,esi
mov dr6,edi
mov dr7,ebx
jmp short y
w:
; Dispatch user mode APC
; The APC routine runs with interrupts on and at APC level
mov ecx, APC_LEVEL
fstCall KfRaiseIrql
push eax ; Save OldIrql
sti
stdCall _KiDeliverApc, <1, 0, ebp> ; ebp - Trap frame
; 0 - Null exception frame
; 1 - Previous mode
pop ecx ; (TOS) = OldIrql
fstCall KfLowerIrql
cli
; UserApc may have changed to vdm Monitor context (user flat 32)
; If it has cannot use the v86 only kernel exit
test dword ptr [ebp]+TsEFlags,EFLAGS_V86_MASK
jnz short z
; Exit to do EXIT_ALL
endm