Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenke.h
Go to the documentation of this file.
00001 #pragma once 00002 00003 #ifndef __ASM__ 00004 00005 #include "intrin_i.h" 00006 00007 // 00008 // Thread Dispatcher Header DebugActive Mask 00009 // 00010 #define DR_MASK(x) (1 << (x)) 00011 #define DR_REG_MASK 0x4F 00012 00013 // 00014 // INT3 is 1 byte long 00015 // 00016 #define KD_BREAKPOINT_TYPE UCHAR 00017 #define KD_BREAKPOINT_SIZE sizeof(UCHAR) 00018 #define KD_BREAKPOINT_VALUE 0xCC 00019 00020 // 00021 // Macros for getting and setting special purpose registers in portable code 00022 // 00023 #define KeGetContextPc(Context) \ 00024 ((Context)->Eip) 00025 00026 #define KeSetContextPc(Context, ProgramCounter) \ 00027 ((Context)->Eip = (ProgramCounter)) 00028 00029 #define KeGetTrapFramePc(TrapFrame) \ 00030 ((TrapFrame)->Eip) 00031 00032 #define KiGetLinkedTrapFrame(x) \ 00033 (PKTRAP_FRAME)((x)->Edx) 00034 00035 #define KeGetContextReturnRegister(Context) \ 00036 ((Context)->Eax) 00037 00038 #define KeSetContextReturnRegister(Context, ReturnValue) \ 00039 ((Context)->Eax = (ReturnValue)) 00040 00041 // 00042 // Macro to get trap and exception frame from a thread stack 00043 // 00044 #define KeGetTrapFrame(Thread) \ 00045 (PKTRAP_FRAME)((ULONG_PTR)((Thread)->InitialStack) - \ 00046 sizeof(KTRAP_FRAME) - \ 00047 sizeof(FX_SAVE_AREA)) 00048 00049 #define KeGetExceptionFrame(Thread) \ 00050 NULL 00051 00052 // 00053 // Macro to get context switches from the PRCB 00054 // All architectures but x86 have it in the PRCB's KeContextSwitches 00055 // 00056 #define KeGetContextSwitches(Prcb) \ 00057 CONTAINING_RECORD(Prcb, KIPCR, PrcbData)->ContextSwitches 00058 00059 // 00060 // Macro to get the second level cache size field name which differs between 00061 // CISC and RISC architectures, as the former has unified I/D cache 00062 // 00063 #define KiGetSecondLevelDCacheSize() ((PKIPCR)KeGetPcr())->SecondLevelCacheSize 00064 00065 // 00066 // Returns the Interrupt State from a Trap Frame. 00067 // ON = TRUE, OFF = FALSE 00068 // 00069 #define KeGetTrapFrameInterruptState(TrapFrame) \ 00070 BooleanFlagOn((TrapFrame)->EFlags, EFLAGS_INTERRUPT_MASK) 00071 00072 // 00073 // Flags for exiting a trap 00074 // 00075 #define KTE_SKIP_PM_BIT (((KTRAP_EXIT_SKIP_BITS) { { .SkipPreviousMode = TRUE } }).Bits) 00076 #define KTE_SKIP_SEG_BIT (((KTRAP_EXIT_SKIP_BITS) { { .SkipSegments = TRUE } }).Bits) 00077 #define KTE_SKIP_VOL_BIT (((KTRAP_EXIT_SKIP_BITS) { { .SkipVolatiles = TRUE } }).Bits) 00078 00079 typedef union _KTRAP_EXIT_SKIP_BITS 00080 { 00081 struct 00082 { 00083 UCHAR SkipPreviousMode:1; 00084 UCHAR SkipSegments:1; 00085 UCHAR SkipVolatiles:1; 00086 UCHAR Reserved:5; 00087 }; 00088 UCHAR Bits; 00089 } KTRAP_EXIT_SKIP_BITS, *PKTRAP_EXIT_SKIP_BITS; 00090 00091 00092 // 00093 // Flags used by the VDM/V8086 emulation engine for determining instruction prefixes 00094 // 00095 #define PFX_FLAG_ES 0x00000100 00096 #define PFX_FLAG_CS 0x00000200 00097 #define PFX_FLAG_SS 0x00000400 00098 #define PFX_FLAG_DS 0x00000800 00099 #define PFX_FLAG_FS 0x00001000 00100 #define PFX_FLAG_GS 0x00002000 00101 #define PFX_FLAG_OPER32 0x00004000 00102 #define PFX_FLAG_ADDR32 0x00008000 00103 #define PFX_FLAG_LOCK 0x00010000 00104 #define PFX_FLAG_REPNE 0x00020000 00105 #define PFX_FLAG_REP 0x00040000 00106 00107 // 00108 // VDM Helper Macros 00109 // 00110 // All VDM/V8086 opcode emulators have the same FASTCALL function definition. 00111 // We need to keep 2 parameters while the original ASM implementation uses 4: 00112 // TrapFrame, PrefixFlags, Eip, InstructionSize; 00113 // 00114 // We pass the trap frame, and prefix flags, in our two parameters. 00115 // 00116 // We then realize that since the smallest prefix flag is 0x100, this gives us 00117 // a count of up to 0xFF. So we OR in the instruction size with the prefix flags 00118 // 00119 // We further realize that we always have access to EIP from the trap frame, and 00120 // that if we want the *current instruction* EIP, we simply have to add the 00121 // instruction size *MINUS ONE*, and that gives us the EIP we should be looking 00122 // at now, so we don't need to use the stack to push this parameter. 00123 // 00124 // We actually only care about the *current instruction* EIP in one location, 00125 // so although it may be slightly more expensive to re-calculate the EIP one 00126 // more time, this way we don't redefine ALL opcode handlers to have 3 parameters, 00127 // which would be forcing stack usage in all other scenarios. 00128 // 00129 #define KiVdmSetVdmEFlags(x) InterlockedOr((PLONG)KiNtVdmState, (x)); 00130 #define KiVdmClearVdmEFlags(x) InterlockedAnd((PLONG)KiNtVdmState, ~(x)) 00131 #define KiCallVdmHandler(x) KiVdmOpcode##x(TrapFrame, Flags) 00132 #define KiCallVdmPrefixHandler(x) KiVdmOpcodePrefix(TrapFrame, Flags | x) 00133 #define KiVdmUnhandledOpcode(x) \ 00134 BOOLEAN \ 00135 FASTCALL \ 00136 KiVdmOpcode##x(IN PKTRAP_FRAME TrapFrame, \ 00137 IN ULONG Flags) \ 00138 { \ 00139 /* Not yet handled */ \ 00140 UNIMPLEMENTED; \ 00141 while (TRUE); \ 00142 return TRUE; \ 00143 } 00144 00145 C_ASSERT(NPX_FRAME_LENGTH == sizeof(FX_SAVE_AREA)); 00146 00147 // 00148 // Local parameters 00149 // 00150 typedef struct _KV86_FRAME 00151 { 00152 PVOID ThreadStack; 00153 PVOID ThreadTeb; 00154 PVOID PcrTeb; 00155 } KV86_FRAME, *PKV86_FRAME; 00156 00157 // 00158 // Virtual Stack Frame 00159 // 00160 typedef struct _KV8086_STACK_FRAME 00161 { 00162 KTRAP_FRAME TrapFrame; 00163 FX_SAVE_AREA NpxArea; 00164 KV86_FRAME V86Frame; 00165 } KV8086_STACK_FRAME, *PKV8086_STACK_FRAME; 00166 00167 /* Diable interrupts and return whether they were enabled before */ 00168 FORCEINLINE 00169 BOOLEAN 00170 KeDisableInterrupts(VOID) 00171 { 00172 ULONG Flags; 00173 BOOLEAN Return; 00174 00175 /* Get EFLAGS and check if the interrupt bit is set */ 00176 Flags = __readeflags(); 00177 Return = (Flags & EFLAGS_INTERRUPT_MASK) ? TRUE: FALSE; 00178 00179 /* Disable interrupts */ 00180 _disable(); 00181 return Return; 00182 } 00183 00184 /* Restore previous interrupt state */ 00185 FORCEINLINE 00186 VOID 00187 KeRestoreInterrupts(BOOLEAN WereEnabled) 00188 { 00189 if (WereEnabled) _enable(); 00190 } 00191 00192 // 00193 // Registers an interrupt handler with an IDT vector 00194 // 00195 FORCEINLINE 00196 VOID 00197 KeRegisterInterruptHandler(IN ULONG Vector, 00198 IN PVOID Handler) 00199 { 00200 UCHAR Entry; 00201 ULONG_PTR Address; 00202 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 00203 00204 // 00205 // Get the entry from the HAL 00206 // 00207 Entry = HalVectorToIDTEntry(Vector); 00208 Address = PtrToUlong(Handler); 00209 00210 // 00211 // Now set the data 00212 // 00213 Pcr->IDT[Entry].ExtendedOffset = (USHORT)(Address >> 16); 00214 Pcr->IDT[Entry].Offset = (USHORT)Address; 00215 } 00216 00217 // 00218 // Returns the registered interrupt handler for a given IDT vector 00219 // 00220 FORCEINLINE 00221 PVOID 00222 KeQueryInterruptHandler(IN ULONG Vector) 00223 { 00224 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 00225 UCHAR Entry; 00226 00227 // 00228 // Get the entry from the HAL 00229 // 00230 Entry = HalVectorToIDTEntry(Vector); 00231 00232 // 00233 // Read the entry from the IDT 00234 // 00235 return (PVOID)(((Pcr->IDT[Entry].ExtendedOffset << 16) & 0xFFFF0000) | 00236 (Pcr->IDT[Entry].Offset & 0xFFFF)); 00237 } 00238 00239 // 00240 // Invalidates the TLB entry for a specified address 00241 // 00242 FORCEINLINE 00243 VOID 00244 KeInvalidateTlbEntry(IN PVOID Address) 00245 { 00246 /* Invalidate the TLB entry for this address */ 00247 __invlpg(Address); 00248 } 00249 00250 FORCEINLINE 00251 VOID 00252 KeFlushProcessTb(VOID) 00253 { 00254 /* Flush the TLB by resetting CR3 */ 00255 __writecr3(__readcr3()); 00256 } 00257 00258 FORCEINLINE 00259 PRKTHREAD 00260 KeGetCurrentThread(VOID) 00261 { 00262 /* Return the current thread */ 00263 return ((PKIPCR)KeGetPcr())->PrcbData.CurrentThread; 00264 } 00265 00266 FORCEINLINE 00267 VOID 00268 KiRundownThread(IN PKTHREAD Thread) 00269 { 00270 #ifndef CONFIG_SMP 00271 /* Check if this is the NPX Thread */ 00272 if (KeGetCurrentPrcb()->NpxThread == Thread) 00273 { 00274 /* Clear it */ 00275 KeGetCurrentPrcb()->NpxThread = NULL; 00276 Ke386FnInit(); 00277 } 00278 #else 00279 /* Nothing to do */ 00280 #endif 00281 } 00282 00283 VOID 00284 FASTCALL 00285 Ki386InitializeTss( 00286 IN PKTSS Tss, 00287 IN PKIDTENTRY Idt, 00288 IN PKGDTENTRY Gdt 00289 ); 00290 00291 VOID 00292 NTAPI 00293 KiSetCR0Bits(VOID); 00294 00295 VOID 00296 NTAPI 00297 KiGetCacheInformation(VOID); 00298 00299 BOOLEAN 00300 NTAPI 00301 KiIsNpxPresent( 00302 VOID 00303 ); 00304 00305 BOOLEAN 00306 NTAPI 00307 KiIsNpxErrataPresent( 00308 VOID 00309 ); 00310 00311 VOID 00312 NTAPI 00313 KiSetProcessorType(VOID); 00314 00315 ULONG 00316 NTAPI 00317 KiGetFeatureBits(VOID); 00318 00319 VOID 00320 NTAPI 00321 KiThreadStartup(VOID); 00322 00323 NTSTATUS 00324 NTAPI 00325 Ke386GetGdtEntryThread( 00326 IN PKTHREAD Thread, 00327 IN ULONG Offset, 00328 IN PKGDTENTRY Descriptor 00329 ); 00330 00331 VOID 00332 NTAPI 00333 KiFlushNPXState( 00334 IN FLOATING_SAVE_AREA *SaveArea 00335 ); 00336 00337 VOID 00338 NTAPI 00339 Ki386AdjustEsp0( 00340 IN PKTRAP_FRAME TrapFrame 00341 ); 00342 00343 VOID 00344 NTAPI 00345 Ki386SetupAndExitToV86Mode( 00346 OUT PTEB VdmTeb 00347 ); 00348 00349 VOID 00350 NTAPI 00351 KeI386VdmInitialize( 00352 VOID 00353 ); 00354 00355 ULONG_PTR 00356 NTAPI 00357 Ki386EnableGlobalPage( 00358 IN volatile ULONG_PTR Context 00359 ); 00360 00361 VOID 00362 NTAPI 00363 KiI386PentiumLockErrataFixup( 00364 VOID 00365 ); 00366 00367 VOID 00368 NTAPI 00369 KiInitializePAT( 00370 VOID 00371 ); 00372 00373 VOID 00374 NTAPI 00375 KiInitializeMTRR( 00376 IN BOOLEAN FinalCpu 00377 ); 00378 00379 VOID 00380 NTAPI 00381 KiAmdK6InitializeMTRR( 00382 VOID 00383 ); 00384 00385 VOID 00386 NTAPI 00387 KiRestoreFastSyscallReturnState( 00388 VOID 00389 ); 00390 00391 ULONG_PTR 00392 NTAPI 00393 Ki386EnableDE( 00394 IN ULONG_PTR Context 00395 ); 00396 00397 ULONG_PTR 00398 NTAPI 00399 Ki386EnableFxsr( 00400 IN ULONG_PTR Context 00401 ); 00402 00403 ULONG_PTR 00404 NTAPI 00405 Ki386EnableXMMIExceptions( 00406 IN ULONG_PTR Context 00407 ); 00408 00409 BOOLEAN 00410 NTAPI 00411 VdmDispatchBop( 00412 IN PKTRAP_FRAME TrapFrame 00413 ); 00414 00415 BOOLEAN 00416 FASTCALL 00417 KiVdmOpcodePrefix( 00418 IN PKTRAP_FRAME TrapFrame, 00419 IN ULONG Flags 00420 ); 00421 00422 BOOLEAN 00423 FASTCALL 00424 Ki386HandleOpcodeV86( 00425 IN PKTRAP_FRAME TrapFrame 00426 ); 00427 00428 DECLSPEC_NORETURN 00429 VOID 00430 FASTCALL 00431 KiEoiHelper( 00432 IN PKTRAP_FRAME TrapFrame 00433 ); 00434 00435 VOID 00436 FASTCALL 00437 Ki386BiosCallReturnAddress( 00438 IN PKTRAP_FRAME TrapFrame 00439 ); 00440 00441 ULONG_PTR 00442 FASTCALL 00443 KiExitV86Mode( 00444 IN PKTRAP_FRAME TrapFrame 00445 ); 00446 00447 DECLSPEC_NORETURN 00448 VOID 00449 NTAPI 00450 KiDispatchExceptionFromTrapFrame( 00451 IN NTSTATUS Code, 00452 IN ULONG_PTR Address, 00453 IN ULONG ParameterCount, 00454 IN ULONG_PTR Parameter1, 00455 IN ULONG_PTR Parameter2, 00456 IN ULONG_PTR Parameter3, 00457 IN PKTRAP_FRAME TrapFrame 00458 ); 00459 00460 // 00461 // Global x86 only Kernel data 00462 // 00463 extern PVOID Ki386IopmSaveArea; 00464 extern ULONG KeI386EFlagsAndMaskV86; 00465 extern ULONG KeI386EFlagsOrMaskV86; 00466 extern BOOLEAN KeI386VirtualIntExtensions; 00467 extern KIDTENTRY KiIdt[MAXIMUM_IDTVECTOR+1]; 00468 extern KDESCRIPTOR KiIdtDescriptor; 00469 extern BOOLEAN KiI386PentiumLockErrataPresent; 00470 extern ULONG KeI386NpxPresent; 00471 extern ULONG KeI386XMMIPresent; 00472 extern ULONG KeI386FxsrPresent; 00473 extern ULONG KiMXCsrMask; 00474 extern ULONG KeI386CpuType; 00475 extern ULONG KeI386CpuStep; 00476 extern ULONG Ke386CacheAlignment; 00477 extern ULONG KiFastSystemCallDisable; 00478 extern UCHAR KiDebugRegisterTrapOffsets[9]; 00479 extern UCHAR KiDebugRegisterContextOffsets[9]; 00480 extern DECLSPEC_NORETURN VOID __cdecl KiTrap02(VOID); 00481 extern VOID __cdecl KiTrap08(VOID); 00482 extern VOID __cdecl KiTrap13(VOID); 00483 extern VOID __cdecl KiFastCallEntry(VOID); 00484 extern VOID NTAPI ExpInterlockedPopEntrySListFault(VOID); 00485 extern VOID NTAPI ExpInterlockedPopEntrySListResume(VOID); 00486 extern VOID __cdecl CopyParams(VOID); 00487 extern VOID __cdecl ReadBatch(VOID); 00488 extern VOID __cdecl FrRestore(VOID); 00489 extern CHAR KiSystemCallExitBranch[]; 00490 extern CHAR KiSystemCallExit[]; 00491 extern CHAR KiSystemCallExit2[]; 00492 00493 // 00494 // Trap Macros 00495 // 00496 #include "trap_x.h" 00497 00498 // 00499 // Returns a thread's FPU save area 00500 // 00501 PFX_SAVE_AREA 00502 FORCEINLINE 00503 KiGetThreadNpxArea(IN PKTHREAD Thread) 00504 { 00505 return (PFX_SAVE_AREA)((ULONG_PTR)Thread->InitialStack - sizeof(FX_SAVE_AREA)); 00506 } 00507 00508 // 00509 // Sanitizes a selector 00510 // 00511 FORCEINLINE 00512 ULONG 00513 Ke386SanitizeSeg(IN ULONG Cs, 00514 IN KPROCESSOR_MODE Mode) 00515 { 00516 // 00517 // Check if we're in kernel-mode, and force CPL 0 if so. 00518 // Otherwise, force CPL 3. 00519 // 00520 return ((Mode == KernelMode) ? 00521 (Cs & (0xFFFF & ~RPL_MASK)) : 00522 (RPL_MASK | (Cs & 0xFFFF))); 00523 } 00524 00525 // 00526 // Sanitizes EFLAGS 00527 // 00528 FORCEINLINE 00529 ULONG 00530 Ke386SanitizeFlags(IN ULONG Eflags, 00531 IN KPROCESSOR_MODE Mode) 00532 { 00533 // 00534 // Check if we're in kernel-mode, and sanitize EFLAGS if so. 00535 // Otherwise, also force interrupt mask on. 00536 // 00537 return ((Mode == KernelMode) ? 00538 (Eflags & (EFLAGS_USER_SANITIZE | EFLAGS_INTERRUPT_MASK)) : 00539 (EFLAGS_INTERRUPT_MASK | (Eflags & EFLAGS_USER_SANITIZE))); 00540 } 00541 00542 // 00543 // Sanitizes a Debug Register 00544 // 00545 FORCEINLINE 00546 PVOID 00547 Ke386SanitizeDr(IN PVOID DrAddress, 00548 IN KPROCESSOR_MODE Mode) 00549 { 00550 // 00551 // Check if we're in kernel-mode, and return the address directly if so. 00552 // Otherwise, make sure it's not inside the kernel-mode address space. 00553 // If it is, then clear the address. 00554 // 00555 return ((Mode == KernelMode) ? DrAddress : 00556 (DrAddress <= MM_HIGHEST_USER_ADDRESS) ? DrAddress : 0); 00557 } 00558 00559 // 00560 // Exception with no arguments 00561 // 00562 VOID 00563 FORCEINLINE 00564 DECLSPEC_NORETURN 00565 KiDispatchException0Args(IN NTSTATUS Code, 00566 IN ULONG_PTR Address, 00567 IN PKTRAP_FRAME TrapFrame) 00568 { 00569 /* Helper for exceptions with no arguments */ 00570 KiDispatchExceptionFromTrapFrame(Code, Address, 0, 0, 0, 0, TrapFrame); 00571 } 00572 00573 // 00574 // Exception with one argument 00575 // 00576 VOID 00577 FORCEINLINE 00578 DECLSPEC_NORETURN 00579 KiDispatchException1Args(IN NTSTATUS Code, 00580 IN ULONG_PTR Address, 00581 IN ULONG P1, 00582 IN PKTRAP_FRAME TrapFrame) 00583 { 00584 /* Helper for exceptions with no arguments */ 00585 KiDispatchExceptionFromTrapFrame(Code, Address, 1, P1, 0, 0, TrapFrame); 00586 } 00587 00588 // 00589 // Exception with two arguments 00590 // 00591 VOID 00592 FORCEINLINE 00593 DECLSPEC_NORETURN 00594 KiDispatchException2Args(IN NTSTATUS Code, 00595 IN ULONG_PTR Address, 00596 IN ULONG P1, 00597 IN ULONG P2, 00598 IN PKTRAP_FRAME TrapFrame) 00599 { 00600 /* Helper for exceptions with no arguments */ 00601 KiDispatchExceptionFromTrapFrame(Code, Address, 2, P1, P2, 0, TrapFrame); 00602 } 00603 00604 // 00605 // Performs a system call 00606 // 00607 00608 /* 00609 * This sequence does a RtlCopyMemory(Stack - StackBytes, Arguments, StackBytes) 00610 * and then calls the function associated with the system call. 00611 * 00612 * It's done in assembly for two reasons: we need to muck with the stack, 00613 * and the call itself restores the stack back for us. The only way to do 00614 * this in C is to do manual C handlers for every possible number of args on 00615 * the stack, and then have the handler issue a call by pointer. This is 00616 * wasteful since it'll basically push the values twice and require another 00617 * level of call indirection. 00618 * 00619 * The ARM kernel currently does this, but it should probably be changed 00620 * later to function like this as well. 00621 * 00622 */ 00623 #ifdef __GNUC__ 00624 NTSTATUS 00625 FORCEINLINE 00626 KiSystemCallTrampoline(IN PVOID Handler, 00627 IN PVOID Arguments, 00628 IN ULONG StackBytes) 00629 { 00630 NTSTATUS Result; 00631 00632 __asm__ __volatile__ 00633 ( 00634 "subl %1, %%esp\n" 00635 "movl %%esp, %%edi\n" 00636 "movl %2, %%esi\n" 00637 "shrl $2, %1\n" 00638 "rep movsd\n" 00639 "call *%3\n" 00640 "movl %%eax, %0\n" 00641 : "=r"(Result) 00642 : "c"(StackBytes), 00643 "d"(Arguments), 00644 "r"(Handler) 00645 : "%esp", "%esi", "%edi" 00646 ); 00647 return Result; 00648 } 00649 #elif defined(_MSC_VER) 00650 NTSTATUS 00651 FORCEINLINE 00652 KiSystemCallTrampoline(IN PVOID Handler, 00653 IN PVOID Arguments, 00654 IN ULONG StackBytes) 00655 { 00656 __asm 00657 { 00658 mov ecx, StackBytes 00659 mov esi, Arguments 00660 mov eax, Handler 00661 sub esp, ecx 00662 mov edi, esp 00663 shr ecx, 2 00664 rep movsd 00665 call eax 00666 } 00667 /* Return with result in EAX */ 00668 } 00669 #else 00670 #error Unknown Compiler 00671 #endif 00672 00673 00674 // 00675 // Checks for pending APCs 00676 // 00677 VOID 00678 FORCEINLINE 00679 KiCheckForApcDelivery(IN PKTRAP_FRAME TrapFrame) 00680 { 00681 PKTHREAD Thread; 00682 KIRQL OldIrql; 00683 00684 /* Check for V8086 or user-mode trap */ 00685 if ((TrapFrame->EFlags & EFLAGS_V86_MASK) || (KiUserTrap(TrapFrame))) 00686 { 00687 /* Get the thread */ 00688 Thread = KeGetCurrentThread(); 00689 while (TRUE) 00690 { 00691 /* Turn off the alerted state for kernel mode */ 00692 Thread->Alerted[KernelMode] = FALSE; 00693 00694 /* Are there pending user APCs? */ 00695 if (!Thread->ApcState.UserApcPending) break; 00696 00697 /* Raise to APC level and enable interrupts */ 00698 OldIrql = KfRaiseIrql(APC_LEVEL); 00699 _enable(); 00700 00701 /* Deliver APCs */ 00702 KiDeliverApc(UserMode, NULL, TrapFrame); 00703 00704 /* Restore IRQL and disable interrupts once again */ 00705 KfLowerIrql(OldIrql); 00706 _disable(); 00707 } 00708 } 00709 } 00710 00711 // 00712 // Converts a base thread to a GUI thread 00713 // 00714 #ifdef __GNUC__ 00715 NTSTATUS 00716 FORCEINLINE 00717 KiConvertToGuiThread(VOID) 00718 { 00719 NTSTATUS Result; 00720 PVOID StackFrame; 00721 00722 /* 00723 * Converting to a GUI thread safely updates ESP in-place as well as the 00724 * current Thread->TrapFrame and EBP when KeSwitchKernelStack is called. 00725 * 00726 * However, PsConvertToGuiThread "helpfully" restores EBP to the original 00727 * caller's value, since it is considered a nonvolatile register. As such, 00728 * as soon as we're back after the conversion and we try to store the result 00729 * which will probably be in some stack variable (EBP-based), we'll crash as 00730 * we are touching the de-allocated non-expanded stack. 00731 * 00732 * Thus we need a way to update our EBP before EBP is touched, and the only 00733 * way to guarantee this is to do the call itself in assembly, use the EAX 00734 * register to store the result, fixup EBP, and then let the C code continue 00735 * on its merry way. 00736 * 00737 */ 00738 __asm__ __volatile__ 00739 ( 00740 "movl %%ebp, %1\n\t" 00741 "subl %%esp, %1\n\t" 00742 "call _PsConvertToGuiThread@0\n\t" 00743 "addl %%esp, %1\n\t" 00744 "movl %1, %%ebp" 00745 : "=a"(Result), "=r"(StackFrame) 00746 : 00747 : "%esp", "%ecx", "%edx", "memory" 00748 ); 00749 return Result; 00750 } 00751 #elif defined(_MSC_VER) 00752 NTSTATUS 00753 NTAPI 00754 KiConvertToGuiThread(VOID); 00755 #else 00756 #error Unknown Compiler 00757 #endif 00758 00759 // 00760 // Switches from boot loader to initial kernel stack 00761 // 00762 VOID 00763 FORCEINLINE 00764 KiSwitchToBootStack(IN ULONG_PTR InitialStack) 00765 { 00766 /* We have to switch to a new stack before continuing kernel initialization */ 00767 #ifdef __GNUC__ 00768 __asm__ 00769 ( 00770 "movl %0, %%esp\n" 00771 "subl %1, %%esp\n" 00772 "pushl %2\n" 00773 "jmp _KiSystemStartupBootStack@0\n" 00774 : 00775 : "c"(InitialStack), 00776 "i"(NPX_FRAME_LENGTH + KTRAP_FRAME_ALIGN + KTRAP_FRAME_LENGTH), 00777 "i"(CR0_EM | CR0_TS | CR0_MP) 00778 : "%esp" 00779 ); 00780 #elif defined(_MSC_VER) 00781 VOID NTAPI KiSystemStartupBootStack(VOID); 00782 __asm 00783 { 00784 mov esp, InitialStack 00785 sub esp, (NPX_FRAME_LENGTH + KTRAP_FRAME_ALIGN + KTRAP_FRAME_LENGTH) 00786 push (CR0_EM | CR0_TS | CR0_MP) 00787 jmp KiSystemStartupBootStack 00788 } 00789 #else 00790 #error Unknown Compiler 00791 #endif 00792 } 00793 00794 // 00795 // Emits the iret instruction for C code 00796 // 00797 DECLSPEC_NORETURN 00798 VOID 00799 FORCEINLINE 00800 KiIret(VOID) 00801 { 00802 #if defined(__GNUC__) 00803 __asm__ __volatile__ 00804 ( 00805 "iret\n" 00806 ); 00807 #elif defined(_MSC_VER) 00808 __asm 00809 { 00810 iretd 00811 } 00812 #else 00813 #error Unsupported compiler 00814 #endif 00815 UNREACHABLE; 00816 } 00817 00818 // 00819 // Normally this is done by the HAL, but on x86 as an optimization, the kernel 00820 // initiates the end by calling back into the HAL and exiting the trap here. 00821 // 00822 VOID 00823 FORCEINLINE 00824 KiEndInterrupt(IN KIRQL Irql, 00825 IN PKTRAP_FRAME TrapFrame) 00826 { 00827 /* Disable interrupts and end the interrupt */ 00828 _disable(); 00829 HalEndSystemInterrupt(Irql, TrapFrame); 00830 00831 /* Exit the interrupt */ 00832 KiEoiHelper(TrapFrame); 00833 } 00834 00835 // 00836 // PERF Code 00837 // 00838 VOID 00839 FORCEINLINE 00840 Ki386PerfEnd(VOID) 00841 { 00842 extern ULONGLONG BootCyclesEnd, BootCycles; 00843 BootCyclesEnd = __rdtsc(); 00844 DbgPrint("Boot took %I64d cycles!\n", BootCyclesEnd - BootCycles); 00845 DbgPrint("Interrupts: %d System Calls: %d Context Switches: %d\n", 00846 KeGetCurrentPrcb()->InterruptCount, 00847 KeGetCurrentPrcb()->KeSystemCalls, 00848 KeGetContextSwitches(KeGetCurrentPrcb())); 00849 } 00850 00851 FORCEINLINE 00852 PULONG 00853 KiGetUserModeStackAddress(void) 00854 { 00855 return &(KeGetCurrentThread()->TrapFrame->HardwareEsp); 00856 } 00857 00858 #endif Generated on Sun May 27 2012 04:33:22 for ReactOS by
1.7.6.1
|