windows-nt/Source/XPSP1/NT/base/ntos/ke/i386/kimacro.inc

1510 lines
36 KiB
PHP
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
;++
;
; 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 Dr_ExitHelp, Dr_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 V86ExitHelp
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>
mov edx, [esp]+TsEdx ; Restore volitales
mov ecx, [esp]+TsEcx
; must restore eax before any
mov eax, [esp].TsEax ; selectors! (see trap0e handler)
endif
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
@@:
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 AbiosExitHelp
add esp, 4 ; remove error code from trap frame
ifnb <NoRestoreVolatiles>
public _KiSystemCallExitBranch
public _KiSystemCallExit
public _KiSystemCallExit2
public _KiSystemCallExit3
; NoRestoreVolatiles is only used for return from System Service.
; If returning to Kernel mode, the processor state does not need
; to be altered (CS, CPL stays the same etc), so simply unwind the
; kernel frame and branch to the saved EIP.
test dword ptr [esp+4], MODE_MASK
; If the following branch is taken, we are returning to usermode.
; If this processor supports the SYSEXIT instruction, the branch
; will be adjusted at boot time to use the appropriate code sequence.
_KiSystemCallExitBranch:
jnz short _KiSystemCallExit
; Exit to kernel mode from system call, faster than IRETD,
; unwind the frame and branch to return address.
pop edx ; get eip
pop ecx ; remove CS from stack
popfd ; restore eflags
jmp edx
if 0
; one day we should test and see if the following is faster
; than the above (and still valid).
sti ; reenable interrupts
ret 8 ; return to @esp and pop CS and EFLAGs
endif
_KiSystemCallExit:
iretd ; return
_KiSystemCallExit2:
pop edx ; pop EIP
add esp, 8 ; Remove CS & Eflags
pop ecx ; pop ESP
sti ; sysexit does not reload flags
iSYSEXIT
_KiSystemCallExit3:
; AMD
pop ecx ; pop EIP
add esp, 8
pop esp
; mov esp, [esp+8] ; remove CS & Eflags, get ESP
iSYSRET
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
;
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
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
mov es, ax
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
;++
;
; KERNEL ICECAP PROBE MACROS
;
; Macro Description:
;
; Used to wrap selected calls in .asm routines with the same
; probe calls inserted by the C compiler when /fastcap is used.
; The X-suffix versions of the probe calls are used only in
; KiSystemService and log additional information such as
; Pid, Tid, image file name, etc.
;
; Arguments:
;
; Current Function
; Called Function
;
;--
IFDEF _CAPKERN
extrn __CAP_Start_Profiling@8:PROC
extrn __CAP_End_Profiling@4:PROC
CAPSTART macro ArgList
stdCall __CAP_Start_Profiling, <ArgList>
endm
CAPEND macro ArgList
stdCall __CAP_End_Profiling, <ArgList>
endm
CAPSTARTX macro ArgList
push eax
stdCall __CAP_ThreadID
pop eax
stdCall __CAP_Start_Profiling, <ArgList>
endm
CAPENDX macro ArgList
stdCall __CAP_End_Profiling, <ArgList>
push eax
stdCall __CAP_SetCPU
pop eax
endm
ELSE
CAPSTART macro ArgList
endm
CAPEND macro ArgList
endm
CAPSTARTX macro ArgList
endm
CAPENDX macro ArgList
endm
ENDIF
;++
;
; PERF_GET_TIMESTAMP
;
; Macro Description:
;
;
; Return a time stamp that for event tracing in EDX:EAX
;
; NOTE: This may trash ECX
;
; In retail, get the clock value from WmiGetCpuClock. Else if using
; reserved memory for logging, get cycle counter.
;
;--
PERF_GET_TIMESTAMP macro
extrn _WmiGetCpuClock:DWORD
call [_WmiGetCpuClock]
endm