00001 ;++
00002 ;
00003 ;
Copyright (c) 1989 Microsoft Corporation
00004 ;
00005 ; Module
Name:
00006 ;
00007 ; kimacro.inc
00008 ;
00009 ; Abstract:
00010 ;
00011 ; This module contains
the macros used by kernel assembler code.
00012 ; It includes
macros to manipulate interrupts, support system
00013 ; entry and
exit for syscalls, faults, and interrupts, and
00014 ; manipulate floating point state.
00015 ;
00016 ; Author:
00017 ;
00018 ; Shie-Lin (shielint) 24-Jan-1990
00019 ;
00020 ; Revision
History:
00021 ;
00022 ; BryanWi 17-Aug-90
00023 ; Replace GENERATE_MACHINE... and
RESTORE... with ENTER_...
00024 ; and EXIT_ALL
macros.
00025 ;
00026 ;--
00027
00028 ;++
00029 ;
00030 ; These constants are used by
the fpo directives in
this file.
00031 ; This directive causes
the assembler to output a .debug$f segment
00032 ; in
the obj
file. The segment will contain 1 fpo record
for each
00033 ; directive present during assembly.
00034 ;
00035 ; Although
the assembler will accept all valid values,
the value of 7
00036 ; in
the FPO_REGS field indicates to
the debugger that a trap frame
is
00037 ; generated by
the function. The value of 7 can be used because
the
00038 ; C/C++ compiler puts a maximum value of 3 in
the field.
00039 ;
00040 FPO_LOCALS equ 0 ; 32 bits, size of locals in dwords
00041 FPO_PARAMS equ 0 ; 32 bits, size of parameters in dwords
00042 FPO_PROLOG equ 0 ; 12 bits, 0-4095, # of bytes in prolog
00043 FPO_REGS equ 0 ; 3 bits, 0-7, # regs saved in prolog
00044 FPO_USE_EBP equ 0 ; 1 bit, 0-1,
is ebp used?
00045 FPO_TRAPFRAME equ 1 ; 2 bits, 0=fpo, 1=trap frame, 2=tss
00046 ;
00047 ;--
00048
00049
00050 ;++
00051 ;
00052 ; POLL_DEBUGGER
00053 ;
00054 ; Macro
Description:
00055 ;
00056 ; Call
the debugger so
it can check
for control-
c. If
it finds
00057 ;
it,
it will report our iret address as address of
break-in.
00058 ;
00059 ; N.B. This macro should be used when all
the caller's registers
00060 ; have been restored. (Otherwise,
the kernel debugger
register
00061 ; dump will not have correct state.) The
only exception
is
00062 ; fs. This
is because Kd may need to access PCR or PRCB.
00063 ;
00064 ; Arguments:
00065 ;
00066 ; There MUST be an iret frame on
the stack when
this macro
00067 ;
is invoked.
00068 ;
00069 ; Exit:
00070 ;
00071 ; Debugger will iret
for us, so we don'
t usually
return from
00072 ;
this macro, but remember that
it generates nothing
for non-DEVL
00073 ; kernels.
00074 ;--
00075
00076 POLL_DEBUGGER macro
00077 local a, b, c_
00078
00079
if DEVL
00080 EXTRNP _DbgBreakPointWithStatus,1
00081 stdCall _KdPollBreakIn
00082 or al,al
00083 jz
short c_
00084 stdCall _DbgBreakPointWithStatus,<
DBG_STATUS_CONTROL_C>
00085 c_:
00086 endif ; DEVL
00087 endm
00088
00089 ;++
00090 ;
00091 ; ASSERT_FS
00092 ;
00093 ; Try to
catch funky condition wherein we get
FS=r3 value
while
00094 ; running in kernel mode.
00095 ;
00096 ;--
00097
00098 ASSERT_FS macro
00099 local a,b
00100
00101
if DBG
00102 EXTRNP _KeBugCheck,1
00103
00104 mov bx,fs
00105 cmp bx,KGDT_R0_PCR
00106 jnz
short a
00107
00108 cmp dword ptr fs:[0], 0
00109 jne
short b
00110
00111 a:
00112 stdCall _KeBugCheck,<-1>
00113 align 4
00114 b:
00115 endif
00116 endm
00117
00118
00119
00120 ;++
00121 ;
00122 ;
00123 ;
Copy data from various places into base of TrapFrame, net effect
00124 ;
is to allow dbg KB command to trace accross trap frame, and to
00125 ; allow user to find arguments to system calls.
00126 ;
00127 ; USE ebx and edi.
00128 ;--
00129
00130 SET_DEBUG_DATA macro
00131
00132 ife FPO
00133
00134 ;
00135 ; This macro
is used by ENTER_SYSTEM_CALL, ENTER_TRAP and ENTER_INTERRUPT
00136 ; and
is used at
the end of above
macros. It
is safe to destroy ebx, edi.
00137 ;
00138
00139 mov ebx,[ebp]+TsEbp
00140 mov edi,[ebp]+TsEip
00141 mov [ebp]+TsDbgArgPointer,edx
00142 mov [ebp]+TsDbgArgMark,0BADB0D00h
00143 mov [ebp]+TsDbgEbp,ebx
00144 mov [ebp]+TsDbgEip,edi
00145 endif
00146
00147 endm
00148
00149
00150 ;++
00151 ;
00152 ; ENTER_DR_ASSIST EnterLabel, ExitLabel, NoAbiosAssist, NoV86Assist
00153 ;
00154 ; Macro
Description:
00155 ;
00156 ; Jumped to by ENTER_
macros to deal with DR
register work,
00157 ; abios work and v86 work. The
main purpose of
this macro
is
00158 ; that interrupt/trap/systemCall EnterMacros can jump here to
00159 ; deal with some special cases such that most of
the times
the
00160 ;
main ENTER_ execution flow can proceed without being branched.
00161 ;
00162 ; If (previousmode == usermode) {
00163 ; save DR* in trapframe
00164 ; load DR* from Prcb
00165 ; }
00166 ;
00167 ; Arguments:
00168 ; EnterLabel - label to emit
00169 ; ExitLabel - label to branch to when done
00170 ;
00171 ; Entry-conditions:
00172 ; Dr work:
00173 ; DebugActive ==
TRUE
00174 ; (esi)->Thread object
00175 ; (esp)->base of trap frame
00176 ; (ebp)->base of trap frame
00177 ;
00178 ; Abios work:
00179 ; v86 work:
00180 ;
00181 ; Exit-conditions:
00182 ; Dr work:
00183 ; Interrupts match input state (
this routine doesn't change IEF)
00184 ; (esp)->base of trap frame
00185 ; (ebp)->base of trap frame
00186 ; Preserves entry eax, edx
00187 ; Abios work:
00188 ; v86 work:
00189 ;
00190 ;--
00191
00192 ENTER_DR_ASSIST macro EnterLabel, ExitLabel, NoAbiosAssist, NoV86Assist, V86R
00193 local a,b
00194
00195
public Dr_&EnterLabel
00196 align 4
00197 Dr_&EnterLabel:
00198
00199 ;
00200 ;
Test if we came from user-mode. If not,
do nothing.
00201 ;
00202
00203 test dword ptr [ebp]+TsEFlags,EFLAGS_V86_MASK
00204 jnz
short a
00205
00206 test dword ptr [ebp]+TsSegCs,MODE_MASK
00207 jz Dr_&ExitLabel ; called from kmode, go
continue
00208
00209
00210 ;
00211 ; Save user-mode Dr* regs in TrapFrame
00212 ;
00213 ; We are safe to destroy ebx, ecx, edi because in ENTER_INTERRUPT and
00214 ; ENTER_TRAP these registers are saved already. In ENTER_SYSTEMCALL
00215 ; ebx, edi
is saved and ecx
is don'
t-care.
00216 ;
00217
00218 a: mov ebx,dr0
00219 mov ecx,dr1
00220 mov edi,dr2
00221 mov [ebp]+TsDr0,ebx
00222 mov [ebp]+TsDr1,ecx
00223 mov [ebp]+TsDr2,edi
00224 mov ebx,dr3
00225 mov ecx,dr6
00226 mov edi,dr7
00227 mov [ebp]+TsDr3,ebx
00228 mov [ebp]+TsDr6,ecx
00229 mov ebx,0
00230 mov [ebp]+TsDr7,edi
00231
00232 ;
00233 ; Make Dr7 safe before loading junk from save area
00234 ;
00235 mov dr7,ebx
00236
00237 ;
00238 ; Load KernelDr* into processor
00239 ;
00240
00241 mov edi,dword ptr fs:[
PcPrcb]
00242 mov ebx,[edi].PbProcessorState.PsSpecialRegisters.SrKernelDr0
00243 mov ecx,[edi].PbProcessorState.PsSpecialRegisters.SrKernelDr1
00244 mov dr0,ebx
00245 mov dr1,ecx
00246 mov ebx,[edi].PbProcessorState.PsSpecialRegisters.SrKernelDr2
00247 mov ecx,[edi].PbProcessorState.PsSpecialRegisters.SrKernelDr3
00248 mov dr2,ebx
00249 mov dr3,ecx
00250 mov ebx,[edi].PbProcessorState.PsSpecialRegisters.SrKernelDr6
00251 mov ecx,[edi].PbProcessorState.PsSpecialRegisters.SrKernelDr7
00252 mov dr6,ebx
00253 mov dr7,ecx
00254
00255 ifnb <V86R>
00256 test dword ptr [ebp]+TsEFlags,EFLAGS_V86_MASK
00257 jz
short b
00258 jmp Dr_&V86R
00259 endif
00260 b:
00261 jmp Dr_&ExitLabel
00262
00263
00264 ifb <NoAbiosAssist>
00265
00266
public Abios_&EnterLabel
00267 align 4
00268 Abios_&EnterLabel:
00269
00270 ;
00271 ; INTERRUPT_STACK16_TO_STACK32
00272 ;
00273 ; This macro remaps current 32bit stack to 16bit stack at interrupt
00274 ; time.
00275 ;
00276 ; Arguments:
00277 ;
00278 ; (esp)->trap frame.
00279 ; (eax)->Entry Esp.
00280 ;
00281
00282 mov eax, [esp].TsErrCode ; (eax) = Entry Esp
00283 mov ecx, KGDT_R0_DATA
00284 mov edx, esp
00285 shl eax, 16
00286 add edx, fs:[PcstackLimit]
00287 mov [esp].TsErrCode, eax
00288 mov ss, cx
00289 mov esp, edx ; Interrupts are off
00290 mov ebp, edx
00291 jmp Abios_&ExitLabel
00292
00293 endif ; NoAbiosAssist
00294
00295 ifb <NoV86Assist>
00296
00297
public V86_&EnterLabel
00298 align 4
00299 V86_&EnterLabel:
00300
00301 ;
00302 ; Move
the V86 segment registers to
the correct place in
the frame
00303 ;
00304 mov eax,dword ptr [ebp].TsV86Fs
00305 mov ebx,dword ptr [ebp].TsV86Gs
00306 mov ecx,dword ptr [ebp].TsV86Es
00307 mov edx,dword ptr [ebp].TsV86Ds
00308 mov [ebp].TsSegFs,ax
00309 mov [ebp].TsSegGs,bx
00310 mov [ebp].TsSegEs,cx
00311 mov [ebp].TsSegDs,dx
00312 jmp V86_&ExitLabel
00313
00314 endif ; NoV86Assist
00315
00316 endm
00317
00318 ;++
00319 ;
00320 ; ENTER_SYSCALL AssistLabel, TagetLabel, NoFSLoad
00321 ;
00322 ; Macro
Description:
00323 ;
00324 ; Build
the frame and set registers needed by a system call.
00325 ;
00326 ; Save:
00327 ; Errorpad,
00328 ; Non-
volatile regs,
00329 ;
FS,
00330 ; ExceptionList,
00331 ; PreviousMode
00332 ;
00333 ; Don'
t Save:
00334 ;
Volatile regs
00335 ; Seg regs
00336 ; Floating point state
00337 ;
00338 ; Set:
00339 ;
FS,
00340 ; ExceptionList,
00341 ; PreviousMode,
00342 ; Direction
00343 ;
00344 ; Arguments:
00345 ; AssistLabel - label ENTER_ASSIST macro
is at
00346 ; TargetLabel - label to emit
for ENTER_ASSIST to jump to
00347 ; NoFSLoad - Don'
t set
FS(it is already set to KGDT_R0_PCR at entry).
00348 ;
00349 ; Exit-conditions:
00350 ; Interrupts match input state (
this routine doesn't change IEF)
00351 ; (esp)->base of trap frame
00352 ; (ebp)->base of trap frame
00353 ; Preserves entry eax, edx
00354 ;
00355 ; Note:
00356 ; The DS: reference to PreviousMode
is *required*
for correct
00357 ; functioning of lazy selector loads. If you remove
this use
00358 ; of DS:, put a DS: override on something.
00359 ;
00360 ;--
00361
00362 ENTER_SYSCALL macro AssistLabel, TargetLabel, NoFSLoad
00363
00364
00365 .FPO ( FPO_LOCALS, FPO_PARAMS, FPO_PROLOG, FPO_REGS, FPO_USE_EBP, FPO_TRAPFRAME )
00366
00367 ifdef KERNELONLY
00368
00369 ;
00370 ; Construct trap frame.
00371 ;
00372 ; N.B. The initial part of the trap frame is constructed by pushing values
00373 ; on the stack. If the format of the trap frame is changed, then the
00374 ; following code must alos be changed.
00375 ;
00376
00377 push 0 ; put pad dword for error on stack
00378 push ebp ; save the non-volatile registers
00379 push ebx ;
00380 push esi ;
00381 push edi ;
00382 ifb <NoFSLoad>
00383 push fs ; save and set FS to PCR.
00384 mov ebx,KGDT_R0_PCR ; set PCR segment number
00385 mov fs,bx ;
00386 else
00387 ; FS already contains KGDT_R0_PCR(entry via PentiumPro fast system call)
00388 push KGDT_R3_TEB OR RPL_MASK
00389 endif ; NoFSLoad
00390
00391 ;
00392 ; Save the old exception list in trap frame and initialize a new empty
00393 ; exception list.
00394 ;
00395
00396 push PCR[PcExceptionList] ; save old exception list
00397 mov PCR[PcExceptionList],EXCEPTION_CHAIN_END ; set new empty list
00398
00399 ;
00400 ; Save the old previous mode in trap frame, allocate remainder of trap frame,
00401 ; and set the new previous mode.
00402 ;
00403
00404 mov esi,PCR[PcPrcbData+PbCurrentThread] ; get current thread address
00405 push [esi]+ThPreviousMode ; save old previous mode
00406 sub esp,TsPreviousPreviousMode ; allocate remainder of trap frame
00407 mov ebx,[esp+TsSegCS] ; compute new previous mode
00408 and ebx,MODE_MASK ;
00409 mov [esi]+ThPreviousMode,bl ; set new previous mode
00410
00411 ;
00412 ; Save the old trap frame address and set the new trap frame address.
00413 ;
00414
00415 mov ebp,esp ; set trap frame address
00416 mov ebx,[esi].ThTrapFrame ; save current trap frame address
00417 mov [ebp].TsEdx,ebx ;
00418 mov [esi].ThTrapFrame,ebp ; set new trap frame address
00419 cld ; make sure direction is forward
00420
00421 SET_DEBUG_DATA ; Note this destroys edi
00422
00423 test byte ptr [esi]+ThDebugActive,-1 ; test if debugging active
00424 jnz Dr_&AssistLabel ; if nz, debugging is active on thread
00425
00426 Dr_&TargetLabel: ;
00427 sti ; enable interrupts
00428
00429 else
00430 %out ENTER_SYSCAL outside of kernel
00431 .err
00432 endif
00433 endm
00434
00435 ;++
00436 ;
00437 ; ENTER_INTERRUPT AssistLabel, TargetLabel
00438 ;
00439 ; Macro Description:
00440 ;
00441 ; Build the frame and set registers needed by an interrupt.
00442 ;
00443 ; Save:
00444 ; Errorpad,
00445 ; Non-volatile regs,
00446 ; FS,
00447 ; ExceptionList,
00448 ; PreviousMode
00449 ; Volatile regs
00450 ; Seg regs from V86 mode
00451 ; DS, ES, GS
00452 ;
00453 ; Don't Save:
00454 ; Floating point state
00455 ;
00456 ; Set:
00457 ; FS,
00458 ; ExceptionList,
00459 ; Direction,
00460 ; DS, ES
00461 ;
00462 ; Don't Set:
00463 ; PreviousMode
00464 ;
00465 ; Arguments:
00466 ; AssistLabel - label ENTER_ASSIST macro is at
00467 ; TargetLabel - label to emit for ENTER_ASSIST to jump to
00468 ;
00469 ; Exit-conditions:
00470 ; Interrupts match input state (this routine doesn't change IEF)
00471 ; (esp)->base of trap frame
00472 ; (ebp)->base of trap frame
00473 ; Preserves entry eax, ecx, edx
00474 ;
00475 ;--
00476
00477 ENTER_INTERRUPT macro AssistLabel, TargetLabel, PassParm
00478 local b
00479
00480 .FPO ( FPO_LOCALS+2, FPO_PARAMS, FPO_PROLOG, FPO_REGS, FPO_USE_EBP, FPO_TRAPFRAME )
00481
00482 ;
00483 ; Fill in parts of frame we care about
00484 ;
00485
00486 ifb <PassParm>
00487 push esp ; Use Error code field to save 16bit esp
00488 endif
00489 push ebp ; Save the non-volatile registers
00490 push ebx
00491 push esi
00492 push edi
00493
00494 sub esp, TsEdi
00495 mov ebp,esp
00496
00497 mov [esp]+TsEax, eax ; Save volatile registers
00498 mov [esp]+TsEcx, ecx
00499 mov [esp]+TsEdx, edx
00500 if DBG
00501 mov dword ptr [esp]+TsPreviousPreviousMode, -1 ; ThPreviousMode not pushed on interrupt
00502 endif
00503
00504 test dword ptr [esp].TsEflags,EFLAGS_V86_MASK
00505 jnz V86_&AssistLabel
00506
00507 cmp word ptr [esp]+TsSegCs, KGDT_R0_CODE
00508 jz
short @f
00509
00510 mov [esp]+TsSegFs, fs ; Save and set FS to PCR.
00511 mov [esp]+TsSegDs, ds
00512 mov [esp]+TsSegEs, es
00513 mov [esp]+TsSegGs, gs
00514
00515 V86_&TargetLabel:
00516 mov ebx,KGDT_R0_PCR
00517 mov eax,KGDT_R3_DATA OR RPL_MASK
00518 mov fs, bx
00519 mov ds, ax
00520 mov es, ax
00521 @@:
00522 mov ebx, fs:[PcExceptionList] ;Save, set ExceptionList
00523 mov fs:[PcExceptionList],EXCEPTION_CHAIN_END
00524 mov [esp]+TsExceptionList, ebx
00525
00526 ifnb <PassParm>
00527 lea eax, [esp].TsErrCode
00528 lea ecx, [esp].TsEip ; Move eax to EIP field
00529 mov ebx, ss:[eax] ; (ebx) = parameter to pass
00530 mov ss:[eax], ecx ; save 16bit esp
00531 endif
00532
00533 ;
00534 ; Remap ABIOS 16 bit stack to 32 bit stack, if necessary.
00535 ;
00536
00537 cmp esp, 10000h
00538 jb Abios_&AssistLabel
00539
00540 mov dword ptr [esp].TsErrCode, 0 ; Indicate no remapping.
00541 Abios_&TargetLabel:
00542
00543 ;
00544 ; end of Abios stack checking
00545 ;
00546
00547 cld
00548
00549 ifnb <PassParm>
00550 push ebx ; push parameter as argument
00551 endif
00552
00553
00554 SET_DEBUG_DATA
00555
00556 test byte ptr PCR[PcDebugActive], -1
00557 jnz Dr_&AssistLabel
00558
00559 Dr_&TargetLabel:
00560
00561 endm
00562
00563 ;++
00564 ;
00565 ; ENTER_INTERRUPT_FORCE_STATE AssistLabel, TargetLabel
00566 ;
00567 ; Macro Description:
00568 ;
00569 ; Build the frame and set registers needed by an interrupt.
00570 ;
00571 ; This macro is the same as ENTER_INTERRUPT except that it forces the
00572 ; needed state and does not save previous state.
00573 ;
00574 ; This macro is currently only used by HalpApicRebootService which does not
00575 ; return;
00576 ;
00577 ; Save:
00578 ; Errorpad,
00579 ; Non-volatile regs,
00580 ; ExceptionList,
00581 ; PreviousMode
00582 ; Volatile regs
00583 ; Seg regs from V86 mode
00584 ;
00585 ; Don't Save:
00586 ; FS,
00587 ; DS, ES, GS
00588 ; Floating point state
00589 ;
00590 ; Set:
00591 ; FS,
00592 ; ExceptionList,
00593 ; Direction,
00594 ; DS, ES
00595 ;
00596 ; Don't Set:
00597 ; PreviousMode
00598 ;
00599 ; Arguments:
00600 ; AssistLabel - label ENTER_ASSIST macro is at
00601 ; TargetLabel - label to emit for ENTER_ASSIST to jump to
00602 ;
00603 ; Exit-conditions:
00604 ; Interrupts match input state (this routine doesn't change IEF)
00605 ; (esp)->base of trap frame
00606 ; (ebp)->base of trap frame
00607 ; Preserves entry eax, ecx, edx
00608 ;
00609 ;--
00610
00611 ENTER_INTERRUPT_FORCE_STATE macro AssistLabel, TargetLabel, PassParm
00612 local b
00613
00614 .FPO ( FPO_LOCALS+2, FPO_PARAMS, FPO_PROLOG, FPO_REGS, FPO_USE_EBP, FPO_TRAPFRAME )
00615
00616 ;
00617 ; Fill in parts of frame we care about
00618 ;
00619
00620 ifb <PassParm>
00621 push esp ; Use Error code field to save 16bit esp
00622 endif
00623 push ebp ; Save the non-volatile registers
00624 push ebx
00625 push esi
00626 push edi
00627
00628 sub esp, TsEdi
00629 mov ebp,esp
00630
00631 mov [esp]+TsEax, eax ; Save volatile registers
00632 mov [esp]+TsEcx, ecx
00633 mov [esp]+TsEdx, edx
00634 if DBG
00635 mov dword ptr [esp]+TsPreviousPreviousMode, -1 ; ThPreviousMode not pushed on interrupt
00636 endif
00637
00638 test dword ptr [esp].TsEflags,EFLAGS_V86_MASK
00639 jnz V86_&AssistLabel
00640
00641 V86_&TargetLabel:
00642 mov ebx,KGDT_R0_PCR
00643 mov eax,KGDT_R3_DATA OR RPL_MASK
00644 mov fs, bx
00645 mov ds, ax
00646 mov es, ax
00647 @@:
00648 mov ebx, fs:[PcExceptionList] ;Save, set ExceptionList
00649 mov fs:[PcExceptionList],EXCEPTION_CHAIN_END
00650 mov [esp]+TsExceptionList, ebx
00651
00652 ifnb <PassParm>
00653 lea eax, [esp].TsErrCode
00654 lea ecx, [esp].TsEip ; Move eax to EIP field
00655 mov ebx, ss:[eax] ; (ebx) = parameter to pass
00656 mov ss:[eax], ecx ; save 16bit esp
00657 endif
00658
00659 ;
00660 ; Remap ABIOS 16 bit stack to 32 bit stack, if necessary.
00661 ;
00662
00663 cmp esp, 10000h
00664 jb Abios_&AssistLabel
00665
00666 mov dword ptr [esp].TsErrCode, 0 ; Indicate no remapping.
00667 Abios_&TargetLabel:
00668
00669 ;
00670 ; end of Abios stack checking
00671 ;
00672
00673 cld
00674
00675 ifnb <PassParm>
00676 push ebx ; push parameter as argument
00677 endif
00678
00679
00680 SET_DEBUG_DATA
00681
00682 test byte ptr PCR[PcDebugActive], -1
00683 jnz Dr_&AssistLabel
00684
00685 Dr_&TargetLabel:
00686
00687 endm
00688
00689 ;++
00690 ;
00691 ; ENTER_TRAP AssistLabel, TargetLabel
00692 ;
00693 ; Macro Description:
00694 ;
00695 ; Build the frame and set registers needed by a trap or exception.
00696 ;
00697 ; Save:
00698 ; Non-volatile regs,
00699 ; FS,
00700 ; ExceptionList,
00701 ; PreviousMode,
00702 ; Volatile regs
00703 ; Seg Regs from V86 mode
00704 ; DS, ES, GS
00705 ;
00706 ; Don't Save:
00707 ; Floating point state
00708 ;
00709 ; Set:
00710 ; FS,
00711 ; Direction,
00712 ; DS, ES
00713 ;
00714 ; Don't Set:
00715 ; PreviousMode,
00716 ; ExceptionList
00717 ;
00718 ; Arguments:
00719 ; AssistLabel - label ENTER_ASSIST macro is at
00720 ; TargetLabel - label to emit for ENTER_ASSIST to jump to
00721 ;
00722 ; Exit-conditions:
00723 ; Interrupts match input state (this routine doesn't change IEF)
00724 ; (esp)->base of trap frame
00725 ; (ebp)->base of trap frame
00726 ; Preserves entry eax
00727 ;
00728 ;--
00729
00730 ENTER_TRAP macro AssistLabel, TargetLabel
00731 local b
00732
00733 .FPO ( FPO_LOCALS, FPO_PARAMS, FPO_PROLOG, FPO_REGS, FPO_USE_EBP, FPO_TRAPFRAME )
00734
00735 ;
00736 ; Fill in parts of frame we care about
00737 ;
00738
00739 if DBG
00740 ifndef _Ki16BitStackException
00741 EXTRNP _Ki16BitStackException
00742 endif
00743 endif ; DBG
00744
00745 mov word ptr [esp+2], 0 ; Clear upper word of ErrorCode
00746
00747 push ebp ; Save the non-volatile registers
00748 push ebx
00749 push esi
00750 push edi
00751
00752 push fs ; Save and set FS to PCR.
00753 mov ebx,KGDT_R0_PCR
00754 mov fs,bx
00755 mov ebx, fs:[PcExceptionList] ;Save ExceptionList
00756 push ebx
00757 if DBG
00758 push -1 ; Don't need to save ThPreviousMode from trap
00759 else
00760 sub esp, 4 ; pad dword
00761 endif
00762 push eax ; Save the volatile registers
00763 push ecx
00764 push edx
00765
00766 push ds ; Save segments
00767 push es
00768 push gs
00769
00770 ;
00771 ; Skip allocate reset of trap frame and Set up DS/ES, they may be trash
00772 ;
00773
00774 mov ax,KGDT_R3_DATA OR RPL_MASK
00775 sub esp,TsSegGs
00776 mov ds,ax
00777 mov es,ax
00778
00779 if DBG
00780 ;
00781 ; The code here check if the exception occurred in ring 0
00782 ; ABIOS code. If yes, this is a fatal condition. We will
00783 ; put out message and bugcheck.
00784 ;
00785
00786 cmp esp, 10000h ; Is the trap in abios?
00787 jb _Ki16BitStackException ; if b, yes, switch stack and bugcheck.
00788
00789 endif ; DBG
00790
00791 mov ebp,esp
00792 test dword ptr [esp].TsEflags,EFLAGS_V86_MASK
00793 jnz V86_&AssistLabel
00794
00795 V86_&TargetLabel:
00796
00797 cld
00798 SET_DEBUG_DATA
00799
00800 test byte ptr PCR[PcDebugActive], -1
00801 jnz Dr_&AssistLabel
00802
00803 Dr_&TargetLabel:
00804
00805 endm
00806 ;++
00807 ;
00808 ; EXIT_ALL NoRestoreSegs, NoRestoreVolatiles, NoPreviousMode
00809 ;
00810 ; Macro Description:
00811 ;
00812 ; Load a syscall frame back into the machine.
00813 ;
00814 ; Restore:
00815 ; Volatile regs, IF NoRestoreVolatiles blank
00816 ; NoPreviousMode,
00817 ; ExceptionList,
00818 ; FS,
00819 ; Non-volatile regs
00820 ;
00821 ; If the frame is a kernel mode frame, AND esp has been edited,
00822 ; then TsSegCs will have a special value. Test for that value
00823 ; and execute special code for that case.
00824 ;
00825 ; N.B. This macro generates an IRET! (i.e. It exits!)
00826 ;
00827 ; Arguments:
00828 ;
00829 ; NoRestoreSegs - non-blank if DS, ES, GS are NOT to be restored
00830 ;
00831 ; NoRestoreVolatiles - non-blank if Volatile regs are NOT to be restored
00832 ;
00833 ; NoPreviousMode - if nb pop ThPreviousMode
00834 ;
00835 ; Entry-conditions:
00836 ;
00837 ; (esp)->base of trap frame
00838 ; (ebp)->Base of trap frame
00839 ;
00840 ; Exit-conditions:
00841 ;
00842 ; Does not exit, returns.
00843 ; Preserves eax, ecx, edx, IFF NoRestoreVolatiles is set
00844 ;
00845 ;--
00846
00847 ?adjesp = 0
00848 ?RestoreAll = 1
00849
00850 EXIT_ALL macro NoRestoreSegs, NoRestoreVolatiles, NoPreviousMode
00851 local a, b, f, x
00852 local Abios_ExitHelp, Abios_ExitHelp_Target1, Abios_ExitHelp_Target2
00853 local Dr_ExitHelp, Dr_ExitHelp_Target, V86_ExitHelp, V86_ExitHelp_Target
00854 local Db_NotATrapFrame, Db_A, Db_NotValidEntry, NonFlatPm_Target
00855
00856 ;
00857 ; Sanity check some values and setup globals for macro
00858 ;
00859
00860 ?adjesp = TsSegGs
00861 ?RestoreAll = 1
00862
00863 ifnb <NoRestoreSegs>
00864 ?RestoreAll = 0
00865 ?adjesp = ?adjesp + 12
00866 endif
00867
00868 ifnb <NoRestoreVolatiles>
00869 if ?RestoreAll eq 1
00870 %out "EXIT_ALL NoRestoreVolatiles requires NoRestoreSegs"
00871 .err
00872 endif
00873 ?adjesp = ?adjesp + 12
00874 endif
00875
00876 ifb <NoPreviousMode>
00877 ifndef KERNELONLY
00878 %out EXIT_ALL can not restore previousmode outside kernel
00879 .err
00880 endif
00881 endif
00882
00883 ; All callers are responsible for getting here with interrupts disabled.
00884
00885 if DBG
00886 pushfd
00887 pop edx
00888
00889 test edx, EFLAGS_INTERRUPT_MASK
00890 jnz Db_NotValidEntry
00891
00892 cmp esp, ebp ; make sure esp = ebp
00893 jne Db_NotValidEntry
00894
00895 ; Make sure BADB0D00 sig is present. If not this isn't a trap frame!
00896 Db_A: sub [esp]+TsDbgArgMark,0BADB0D00h
00897 jne Db_NotATrapFrame
00898 endif
00899
00900 ASSERT_FS
00901
00902 mov edx, [esp]+TsExceptionList
00903 if DBG
00904 or edx, edx
00905 jnz
short @f
00906
int 3
00907 @@:
00908 endif
00909 mov ebx, fs:[PcDebugActive] ; (ebx) = DebugActive flag
00910 mov fs:[PcExceptionList], edx ; Restore ExceptionList
00911
00912 ifb <NoPreviousMode>
00913 mov ecx, [esp]+TsPreviousPreviousMode ; Restore PreviousMode
00914 if DBG
00915 cmp ecx, -1 ; temporary debugging code
00916 jne @f ; to make sure no one tries to pop ThPreviousMode
00917
int 3 ; when it wasn't saved
00918 @@:
00919 endif
00920 mov esi,fs:[PcPrcbData+PbCurrentThread]
00921 mov [esi]+ThPreviousMode,cl
00922 else
00923 if DBG
00924 mov ecx, [esp]+TsPreviousPreviousMode
00925 cmp ecx, -1 ; temporary debugging code
00926 je @f ; to make sure no one pushed ThPreviousMode and
00927
int 3 ; is now exiting without restoreing it
00928 @@:
00929 endif
00930 endif
00931
00932 test ebx, 0fh
00933 jnz Dr_ExitHelp
00934
00935 Dr_ExitHelp_Target:
00936
00937 test dword ptr [esp].TsEflags,EFLAGS_V86_MASK
00938 jnz V86_ExitHelp
00939
00940 test word ptr [esp]+TsSegCs,FRAME_EDITED
00941 jz b ; Edited frame pop out.
00942
00943
00944 if ?RestoreAll eq 0
00945 .errnz MODE_MASK-1
00946 cmp word ptr [esp]+TsSegCs,KGDT_R3_CODE OR RPL_MASK ; set/clear ZF
00947 bt word ptr [esp]+TsSegCs,0 ; test MODE_MASK set/clear CF
00948 cmc ; (CF=1 and ZF=0)
00949 ja f ; jmp if CF=0 and ZF=0
00950 endif
00951 ifb <NoRestoreVolatiles>
00952 ifb <NoRestoreSegs> ; must restore eax before any
00953 mov eax, [esp].TsEax ; selectors! (see trap0e handler)
00954 endif
00955 endif
00956
00957 ifb <NoRestoreVolatiles>
00958 mov edx, [ebp]+TsEdx ; Restore volitales
00959 mov ecx, [ebp]+TsEcx
00960 ifb <NoRestoreSegs>
00961 else
00962 mov eax, [ebp]+TsEax
00963 endif
00964 endif ; NoRestoreVolatiles
00965
00966 cmp word ptr [ebp]+TsSegCs, KGDT_R0_CODE
00967 jz
short @f
00968
00969 ifb <NoRestoreSegs>
00970 lea esp, [ebp]+TsSegGs
00971 pop gs ; Restore Segs
00972 pop es
00973 pop ds
00974 endif
00975 NonFlatPm_Target:
00976 lea esp, [ebp]+TsSegFs
00977 pop fs
00978 @@:
00979 V86_ExitHelp_Target:
00980
00981 lea esp, [ebp]+TsEdi ; Skip PreMode, ExceptList and fs
00982
00983 pop edi ; restore non-volatiles
00984 pop esi
00985 pop ebx
00986 pop ebp
00987
00988 ;
00989 ; Esp MUST point to the Error Code on the stack. Because we use it to
00990 ; store the entering esp.
00991 ;
00992
00993 cmp word ptr [esp+8], 80h ; check for abios code segment?
00994 ja Abios_ExitHelp
00995
00996 Abios_ExitHelp_Target1:
00997
00998 add esp, 4 ; remove error code from trap frame
00999
01000 Abios_ExitHelp_Target2:
01001
01002 ;
01003 ; End of ABIOS stack check
01004 ;
01005
01006 ifnb <NoRestoreVolatiles>
01007
01008 test _KeFeatureBits, KF_FAST_SYSCALL
01009 jz @f
01010
01011 ;; If returning to kernel mode, use iretd
01012 test dword ptr [esp+4], MODE_MASK
01013 jz @f ; Return to kmode. use iretd
01014
01015 ;; If returning to V86 mode, use iretd
01016 test dword ptr [esp+8], EFLAGS_V86_MASK
01017 jnz @f ; Return to user V86 mode
01018
01019 pop edx ; pop EIP
01020 add esp, 8 ; Remove CS & Eflags
01021 pop ecx ; pop ESP
01022
01023 sti ; sysexit does not reload flags
01024
01025
01026 SYSEXIT_INSTR
01027
01028 @@:
01029 endif ;; <NoRestoreVolatiles>
01030
01031 iretd ; return
01032
01033 if DBG
01034 Db_NotATrapFrame:
01035 add [esp]+TsDbgArgMark,0BADB0D00h ; put back the orig value
01036 Db_NotValidEntry:
01037
int 3
01038 jmp Db_A
01039 endif
01040
01041 ;
01042 ; EXIT_HELPER
01043 ;
01044 ; if (PreviousMode == UserMode) {
01045 ; DR* regs = TF.Dr* regs
01046 ; }
01047 ;
01048 ; Entry-Conditions:
01049 ;
01050 ; DebugActive ==
TRUE
01051 ; (ebp)->TrapFrame
01052 ;
01053 ;--
01054
01055 align dword
01056 Dr_ExitHelp:
01057
01058 test dword ptr [ebp]+TsEFlags,EFLAGS_V86_MASK
01059 jnz
short x
01060
01061 test dword ptr [ebp]+TsSegCs,MODE_MASK
01062 jz Dr_ExitHelp_Target
01063
01064 x: mov ebx,0
01065 mov esi,[ebp]+TsDr0
01066 mov edi,[ebp]+TsDr1
01067 mov dr7,ebx
01068 mov dr0,esi
01069 mov ebx,[ebp]+TsDr2
01070 mov dr1,edi
01071 mov dr2,ebx
01072 mov esi,[ebp]+TsDr3
01073 mov edi,[ebp]+TsDr6
01074 mov ebx,[ebp]+TsDr7
01075 mov dr3,esi
01076 mov dr6,edi
01077 mov dr7,ebx
01078
01079 jmp Dr_ExitHelp_Target
01080
01081 align dword
01082 Abios_ExitHelp:
01083
01084 ;
01085 ; INTERRUPT_STACK32_TO_STACK16
01086 ;
01087 ; This macro remaps current 32bit stack to 16bit stack at interrupt
01088 ; time.
01089 ;
01090 ; Arguments:
01091 ;
01092 ; (esp)->TsEip.
01093 ;
01094 ;
01095 ; PERFNOTE shielint We should check
if there
is any other H/
W interrupt
01096 ; pending. If yes, don'
t switch back to 16 bit stack. This way
01097 ; we can get better performance.
01098 ;
01099
01100 cmp word ptr [esp+2], 0 ; (esp+2) = Low word of error code
01101 jz Abios_ExitHelp_Target1
01102 cmp word ptr [esp], 0 ; (esp) = High word of error code
01103 jnz Abios_ExitHelp_Target1
01104
01105 shr dword ptr [esp], 16
01106 mov word ptr [esp + 2],
KGDT_STACK16
01107 lss sp, dword ptr [esp]
01108 movzx esp, sp
01109 jmp Abios_ExitHelp_Target2
01110
01111 ;
01112 ; Restore volatiles
for V86 mode, and
move seg regs
01113 ;
01114
01115 align dword
01116 V86_ExitHelp:
01117
01118 add esp,TsEdx
01119 pop edx
01120 pop ecx
01121 pop eax
01122 jmp V86_ExitHelp_Target
01123
01124 ;
01125
if ?RestoreAll eq 0
01126 ;
01127 ; Restore segs and volatiles
for non-flat R3 PM (VDM in PM)
01128 ;
01129
01130 f: mov eax,[esp].TsEax ; restore eax before any selectors
01131 ; (see trap0e handler)
01132 add esp,TsSegGs
01133
01134 pop gs
01135 pop es
01136 pop
ds
01137
01138 pop edx
01139 pop ecx
01140 jmp NonFlatPm_Target
01141
01142 endif ; not ?RestoreAll
01143
01144
01145 ;
01146 ; TsSegCs contains
the special value that means
the frame was edited
01147 ; in a way that affected esp, AND
it's a kernel mode frame.
01148 ; (Special value
is null selector except
for RPL.)
01149 ;
01150 ; Put back
the real CS.
01151 ; push eflags, eip onto target stack
01152 ; restore
01153 ;
switch to target stack
01154 ; iret
01155 ;
01156
01157 b: mov ebx,[esp]+TsTempSegCs
01158 mov [esp]+TsSegCs,ebx
01159
01160 ;
01161 ; There
is no instruction that will load esp with an arbitrary value
01162 ; (i.e. one
out of a frame) and
do a
return,
if no privledge transition
01163 ;
is occuring. Therefore,
if we are returning to kernel mode, and
01164 ; esp has been edited, we must
"emulate" a kind of iretd.
01165 ;
01166 ; We
do this by logically pushing
the eip,cs,eflags onto
the new
01167 ; logical stack, loading that stack, and doing an iretd. This
01168 ; requires that
the new logical stack
is at least 1 dword higher
01169 ; than
the unedited esp would have been. (i.e. It
is not legal
01170 ; to edit esp to have a
new value <
the old value.)
01171 ;
01172 ;
KeContextToKframes enforces
this rule.
01173 ;
01174
01175 ;
01176 ; Compute
new logical stack address
01177 ;
01178
01179 mov ebx,[esp]+TsTempEsp
01180 sub ebx,12
01181 mov [esp]+TsErrCode,ebx
01182
01183 ;
01184 ;
Copy eip,cs,eflags to
new stack. note we
do this high to
low
01185 ;
01186
01187 mov esi,[esp]+TsEflags
01188 mov [ebx+8],esi
01189 mov esi,[esp]+TsSegCs
01190 mov [ebx+4],esi
01191 mov esi,[esp]+TsEip
01192 mov [ebx],esi
01193
01194 ;
01195 ; Do a standard restore sequence.
01196 ;
01197 ; Observe that RestoreVolatiles
is honored. Editing a
volatile
01198 ;
register has no effect when returning from a system call.
01199 ;
01200 ifb <NoRestoreVolatiles>
01201 mov eax,[esp].TsEax
01202 endif
01203 ; add esp,TsSegGs
01204 ;
01205 ;ifb <NoRestoreSegs>
01206 ; pop gs
01207 ; pop es
01208 ; pop
ds
01209 ;
else
01210 ; add esp,12
01211 ;endif
01212
01213 ifb <NoRestoreVolatiles>
01214 mov edx, [esp]+TsEdx
01215 mov ecx, [esp]+TsEcx
01216 endif
01217
01218 ;ifnb <NoPreviousMode>
01219 ; add esp, 4 ; Skip previous mode
01220 ;
else
01221 ; pop ebx ; Restore PreviousMode
01222 ; mov esi,fs:[PcPrcbData+
PbCurrentThread]
01223 ; mov ss:[esi]+ThPreviousMode,bl
01224 ;endif
01225 ;
01226 ; pop ebx
01227 ;
01228 ; mov fs:[PcExceptionList], ebx ;Restore ExceptionList
01229 ; pop fs
01230
01231 add esp, TsEdi
01232 pop edi ; restore non-volatiles
01233 pop esi
01234 pop ebx
01235 pop ebp
01236
01237 ;
01238 ; (esp)->TsErrCode, where we saved
the new esp
01239 ;
01240
01241 mov esp,[esp] ; Do
move not push to avoid increment
01242 iretd
01243
01244 endm
01245
01246
01247 ;++
01248 ;
01249 ; INTERRUPT_EXIT
01250 ;
01251 ; Macro
Description:
01252 ;
01253 ; This macro
is executed on
return from an interrupt vector service
01254 ; service routine. Its function
is to restore privileged processor
01255 ; state, and
continue thread execution. If
control is returning to
01256 ; user mode and there
is a user APC pending, then APC level interupt
01257 ; will be requested and
control is transfered to
the user APC delivery
01258 ; routine,
if no higher level interrupt pending.
01259 ;
01260 ; Arguments:
01261 ;
01262 ; (TOS) = previous irql
01263 ; (TOS+4) = irq vector to eoi
01264 ; (TOS+8 ...) = machine_state frame
01265 ; (ebp)-> machine state frame (trap frame)
01266 ;
01267 ;--
01268
01269 INTERRUPT_EXIT macro DebugCheck
01270 local a
01271
01272 ifnb <DebugCheck>
01273 POLL_DEBUGGER
01274 endif
01275
if DBG ; save current eip
for
01276 a: mov esi, offset a ; debugging bad trap frames
01277 endif
01278
01279 ifdef __imp_Kei386EoiHelper@0
01280 cli
01281 call _HalEndSystemInterrupt@8
01282 jmp dword ptr [__imp_Kei386EoiHelper@0]
01283
01284
else
01285 cli
01286 call dword ptr [__imp__HalEndSystemInterrupt@8]
01287 jmp Kei386EoiHelper@0
01288 endif
01289 endm
01290
01291
01292 ;++
01293 ;
01294 ; SPURIOUS_INTERRUPT_EXIT
01295 ;
01296 ; Macro
Description:
01297 ;
01298 ; To
exit an interrupt without performing
the EOI.
01299 ;
01300 ; Arguments:
01301 ;
01302 ; (TOS) = machine_state frame
01303 ; (ebp)-> machine state frame (trap frame)
01304 ;
01305 ;--
01306
01307 SPURIOUS_INTERRUPT_EXIT macro
01308 local a
01309
if DBG ; save current eip
for
01310 a: mov esi, offset a ; debugging bad trap frames
01311 endif
01312 ifdef __imp_Kei386EoiHelper@0
01313 jmp dword ptr [__imp_Kei386EoiHelper@0]
01314
else
01315 jmp Kei386EoiHelper@0
01316 endif
01317 endm
01318
01319 ;++
01320 ;
01321 ; ENTER_TRAPV86
01322 ;
01323 ; Macro
Description:
01324 ;
01325 ; Construct trap frame
for v86 mode traps.
01326 ;
01327 ;--
01328
01329 ENTER_TRAPV86 macro DRENTER,V86ENTER,LOADES
01330 sub esp, TsErrCode
01331 mov word ptr [esp].TsErrCode + 2, 0
01332 mov [esp].TsEbx, ebx
01333 mov [esp].TsEax, eax
01334 mov [esp].TsEbp, ebp
01335 mov [esp].TsEsi, esi
01336 mov [esp].TsEdi, edi
01337 mov ebx, KGDT_R0_PCR
01338 mov eax, KGDT_R3_DATA OR RPL_MASK
01339 mov [esp].TsEcx, ecx
01340 mov [esp].TsEdx, edx
01341
if DBG
01342 mov [esp].TsPreviousPreviousMode, -1
01343 mov [esp]+TsDbgArgMark, 0BADB0D00h
01344 endif
01345 mov fs, bx
01346 mov
ds, ax
01347 ifnb <LOADES>
01348 mov es, ax
01349 endif
01350 mov ebp, esp
01351 cld ; CHECKIT_SUDEEP ;
do we really need
it
01352 test byte ptr PCR[PcDebugActive], -1
01353 jnz Dr_&DRENTER
01354
01355 Dr_&V86ENTER:
01356 endm
01357
01358
01359 ;
01360 ; Taken from ntos\vdm\i386\vdmtb.inc
01361 ;
01362
01363 FIXED_NTVDMSTATE_LINEAR_PC_AT equ 0714H
01364 FIXED_NTVDMSTATE_LINEAR_PC_98 equ 0614H
01365 MACHINE_TYPE_MASK equ 0ff00H
01366
VDM_VIRTUAL_INTERRUPTS equ 0200H
01367
01368 ;++
01369 ;
01370 ; EXIT_TRAPV86
01371 ;
01372 ; Macro
Description:
01373 ;
01374 ;
if UserApc
is pending deliver
it
01375 ;
if User Context
is v86 mode
01376 ; Exit from kernel (does not
return)
01377 ;
else
01378 ;
return (expected to execute EXIT_ALL)
01379 ;--
01380
01381 EXIT_TRAPV86 macro
01382 local w, x, y, z
01383
01384 z: mov ebx, PCR[PcPrcbData+
PbCurrentThread]
01385 mov byte ptr [ebx]+ThAlerted, 0
01386 cmp byte ptr [ebx]+ThApcState.AsUserApcPending, 0
01387 jne
short w
01388
01389 ;
01390 ; Kernel
exit to V86 mode
01391 ;
01392
01393 add esp,TsEdx
01394 pop edx
01395 pop ecx
01396 pop eax
01397 test byte ptr PCR[PcDebugActive], -1
01398 jnz
short x
01399 y:
01400 add esp,12 ; unused fields
01401 pop edi
01402 pop esi
01403 pop ebx
01404 pop ebp
01405 add esp,4 ; clear error code
01406 iretd
01407
01408 x: mov esi,[ebp]+TsDr0
01409 mov edi,[ebp]+TsDr1
01410 mov ebx,[ebp]+TsDr2
01411 mov dr0,esi
01412 mov dr1,edi
01413 mov dr2,ebx
01414 mov esi,[ebp]+TsDr3
01415 mov edi,[ebp]+TsDr6
01416 mov ebx,[ebp]+TsDr7
01417 mov dr3,esi
01418 mov dr6,edi
01419 mov dr7,ebx
01420 jmp
short y
01421
01422 w:
01423 ;
01424 ; Dispatch user mode APC
01425 ; The APC routine runs with interrupts on and at APC level
01426 ;
01427
01428 mov ecx,
APC_LEVEL
01429 fstCall KfRaiseIrql
01430 push eax ; Save OldIrql
01431 sti
01432
01433 stdCall _KiDeliverApc, <1, 0, ebp> ; ebp - Trap frame
01434 ; 0 - Null exception frame
01435 ; 1 - Previous mode
01436
01437 pop ecx ; (TOS) = OldIrql
01438 fstCall KfLowerIrql
01439
01440 cli
01441
01442 ;
01443 ; UserApc may have changed to vdm Monitor context (user flat 32)
01444 ; If
it has cannot use
the v86
only kernel
exit
01445 ;
01446
01447 test dword ptr [ebp]+TsEFlags,EFLAGS_V86_MASK
01448 jnz
short z
01449
01450 ; Exit to
do EXIT_ALL
01451 endm