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