|
|
;++ ; ; 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 across 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
.errnz (MODE_MASK AND 0FFFFFF00h) test byte 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 xor ebx,ebx 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, fs:[PcPrcb] ; get current PRCB address mov edx, [edx]+PbCurrentThread ; get current thread mov edx, [edx]+ThStackLimit ; get thread stack base shl eax, 16 add edx, esp 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, RejectVdmLabel
.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
mov esi,PCR[PcPrcbData+PbCurrentThread] ; get current thread address ; ; 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. ;
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 ; test [esi].ThDebugActive, 0ffh ; See if we need to save debug registers mov [esi].ThTrapFrame,ebp ; set new trap frame address cld ; make sure direction is forward
.errnz (DR7_ACTIVE AND 0FFFFFF00h) mov byte ptr [ebp].TsDr7, 0 jnz Dr_&AssistLabel ; if nz, debugging is active on thread
Dr_&TargetLabel: ;
SET_DEBUG_DATA ; Note this destroys edi 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 ;
ifdef PcPrcbData mov ecx,PCR[PcPrcbData+PbCurrentThread] ; get current thread address else mov ecx,PCR[PcPrcb] mov ecx,[ecx].PbCurrentThread ; get current thread address endif
cld
ifnb <PassParm> push ebx ; push parameter as argument endif
test byte ptr [ecx].ThDebugActive, 0ffh ; See if debug registers need saving .errnz (DR7_ACTIVE AND 0FFFFFF00h) mov [ebp].TsDr7, 0 jnz Dr_&AssistLabel
Dr_&TargetLabel:
SET_DEBUG_DATA
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 ;
ifdef PcPrcbData mov ecx,PCR[PcPrcbData+PbCurrentThread] ; get current thread address else mov ecx,PCR[PcPrcb] mov ecx,[ecx].PbCurrentThread ; get current thread address endif cld
ifnb <PassParm> push ebx ; push parameter as argument endif
test byte ptr [ecx].ThDebugActive, 0ffh ; See if debug registers need saving .errnz (DR7_ACTIVE AND 0FFFFFF00h) mov [ebp].TsDr7, 0 jnz Dr_&AssistLabel
Dr_&TargetLabel:
SET_DEBUG_DATA
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:
ifdef PcPrcbData mov ecx,PCR[PcPrcbData+PbCurrentThread] ; get current thread address else mov ecx,PCR[PcPrcb] mov ecx,[ecx].PbCurrentThread ; get current thread address endif cld test byte ptr [ecx].ThDebugActive, 0ffh ; See if debug registers need saving .errnz (DR7_ACTIVE AND 0FFFFFF00h) mov [ebp].TsDr7, 0 jnz Dr_&AssistLabel
Dr_&TargetLabel:
SET_DEBUG_DATA
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 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
.errnz (DR7_ACTIVE AND 0FFFFFF00h) test byte ptr [esp].TsDr7, DR7_ACTIVE 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:
test dword ptr [esp+8], EFLAGS_TF jne short _KiSystemCallExit
pop edx ; pop EIP add esp, 4 ; Remove CS and dword ptr [esp], NOT EFLAGS_INTERRUPT_MASK ; Disable interrupts in the flags popfd 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: xor ebx,ebx 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 mov eax, PCR[PcExceptionList] mov [esp]+TsExceptionList, eax mov eax, dr7 cld ; CHECKIT_SUDEEP ; do we really need it .errnz (DR7_ACTIVE AND 0FFFFFF00h) test al, DR7_ACTIVE mov [esp].TsDr7, eax 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 .errnz (DR7_ACTIVE AND 0FFFFFF00h) test byte ptr [ebp].TsDr7, DR7_ACTIVE 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: xor ebx, ebx mov esi,[ebp]+TsDr0 mov edi,[ebp]+TsDr1 mov dr7, ebx ; Turn off debug exceptions while reloading 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 ;
RaiseIrql APC_LEVEL push eax ; Save OldIrql sti
stdCall _KiDeliverApc, <1, 0, ebp> ; ebp - Trap frame ; 0 - Null exception frame ; 1 - Previous mode
pop ecx ; (TOS) = OldIrql LowerIrql ecx
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 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 extrn _CAP_Log_NInt: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
|