Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / ntoskrnl / include / internal / i386 / ke.h
1 #pragma once
2
3 #ifndef __ASM__
4
5 #include "intrin_i.h"
6
7 //
8 // Thread Dispatcher Header DebugActive Mask
9 //
10 #define DR_MASK(x) (1 << (x))
11 #define DR_REG_MASK 0x4F
12
13 //
14 // INT3 is 1 byte long
15 //
16 #define KD_BREAKPOINT_TYPE UCHAR
17 #define KD_BREAKPOINT_SIZE sizeof(UCHAR)
18 #define KD_BREAKPOINT_VALUE 0xCC
19
20 //
21 // Macros for getting and setting special purpose registers in portable code
22 //
23 #define KeGetContextPc(Context) \
24 ((Context)->Eip)
25
26 #define KeSetContextPc(Context, ProgramCounter) \
27 ((Context)->Eip = (ProgramCounter))
28
29 #define KeGetTrapFramePc(TrapFrame) \
30 ((TrapFrame)->Eip)
31
32 #define KiGetLinkedTrapFrame(x) \
33 (PKTRAP_FRAME)((x)->Edx)
34
35 #define KeGetContextReturnRegister(Context) \
36 ((Context)->Eax)
37
38 #define KeSetContextReturnRegister(Context, ReturnValue) \
39 ((Context)->Eax = (ReturnValue))
40
41 //
42 // Macro to get trap and exception frame from a thread stack
43 //
44 #define KeGetTrapFrame(Thread) \
45 (PKTRAP_FRAME)((ULONG_PTR)((Thread)->InitialStack) - \
46 sizeof(KTRAP_FRAME) - \
47 sizeof(FX_SAVE_AREA))
48
49 #define KeGetExceptionFrame(Thread) \
50 NULL
51
52 //
53 // Macro to get context switches from the PRCB
54 // All architectures but x86 have it in the PRCB's KeContextSwitches
55 //
56 #define KeGetContextSwitches(Prcb) \
57 CONTAINING_RECORD(Prcb, KIPCR, PrcbData)->ContextSwitches
58
59 //
60 // Macro to get the second level cache size field name which differs between
61 // CISC and RISC architectures, as the former has unified I/D cache
62 //
63 #define KiGetSecondLevelDCacheSize() ((PKIPCR)KeGetPcr())->SecondLevelCacheSize
64
65 //
66 // Returns the Interrupt State from a Trap Frame.
67 // ON = TRUE, OFF = FALSE
68 //
69 #define KeGetTrapFrameInterruptState(TrapFrame) \
70 BooleanFlagOn((TrapFrame)->EFlags, EFLAGS_INTERRUPT_MASK)
71
72 //
73 // Flags for exiting a trap
74 //
75 #define KTE_SKIP_PM_BIT (((KTRAP_EXIT_SKIP_BITS) { { .SkipPreviousMode = TRUE } }).Bits)
76 #define KTE_SKIP_SEG_BIT (((KTRAP_EXIT_SKIP_BITS) { { .SkipSegments = TRUE } }).Bits)
77 #define KTE_SKIP_VOL_BIT (((KTRAP_EXIT_SKIP_BITS) { { .SkipVolatiles = TRUE } }).Bits)
78
79 typedef union _KTRAP_EXIT_SKIP_BITS
80 {
81 struct
82 {
83 UCHAR SkipPreviousMode:1;
84 UCHAR SkipSegments:1;
85 UCHAR SkipVolatiles:1;
86 UCHAR Reserved:5;
87 };
88 UCHAR Bits;
89 } KTRAP_EXIT_SKIP_BITS, *PKTRAP_EXIT_SKIP_BITS;
90
91
92 //
93 // Flags used by the VDM/V8086 emulation engine for determining instruction prefixes
94 //
95 #define PFX_FLAG_ES 0x00000100
96 #define PFX_FLAG_CS 0x00000200
97 #define PFX_FLAG_SS 0x00000400
98 #define PFX_FLAG_DS 0x00000800
99 #define PFX_FLAG_FS 0x00001000
100 #define PFX_FLAG_GS 0x00002000
101 #define PFX_FLAG_OPER32 0x00004000
102 #define PFX_FLAG_ADDR32 0x00008000
103 #define PFX_FLAG_LOCK 0x00010000
104 #define PFX_FLAG_REPNE 0x00020000
105 #define PFX_FLAG_REP 0x00040000
106
107 //
108 // VDM Helper Macros
109 //
110 // All VDM/V8086 opcode emulators have the same FASTCALL function definition.
111 // We need to keep 2 parameters while the original ASM implementation uses 4:
112 // TrapFrame, PrefixFlags, Eip, InstructionSize;
113 //
114 // We pass the trap frame, and prefix flags, in our two parameters.
115 //
116 // We then realize that since the smallest prefix flag is 0x100, this gives us
117 // a count of up to 0xFF. So we OR in the instruction size with the prefix flags
118 //
119 // We further realize that we always have access to EIP from the trap frame, and
120 // that if we want the *current instruction* EIP, we simply have to add the
121 // instruction size *MINUS ONE*, and that gives us the EIP we should be looking
122 // at now, so we don't need to use the stack to push this parameter.
123 //
124 // We actually only care about the *current instruction* EIP in one location,
125 // so although it may be slightly more expensive to re-calculate the EIP one
126 // more time, this way we don't redefine ALL opcode handlers to have 3 parameters,
127 // which would be forcing stack usage in all other scenarios.
128 //
129 #define KiVdmSetVdmEFlags(x) InterlockedOr((PLONG)KiNtVdmState, (x));
130 #define KiVdmClearVdmEFlags(x) InterlockedAnd((PLONG)KiNtVdmState, ~(x))
131 #define KiCallVdmHandler(x) KiVdmOpcode##x(TrapFrame, Flags)
132 #define KiCallVdmPrefixHandler(x) KiVdmOpcodePrefix(TrapFrame, Flags | x)
133 #define KiVdmUnhandledOpcode(x) \
134 BOOLEAN \
135 FASTCALL \
136 KiVdmOpcode##x(IN PKTRAP_FRAME TrapFrame, \
137 IN ULONG Flags) \
138 { \
139 /* Not yet handled */ \
140 UNIMPLEMENTED_DBGBREAK(); \
141 return FALSE; \
142 }
143
144 C_ASSERT(NPX_FRAME_LENGTH == sizeof(FX_SAVE_AREA));
145
146 //
147 // Local parameters
148 //
149 typedef struct _KV86_FRAME
150 {
151 PVOID ThreadStack;
152 PVOID ThreadTeb;
153 PVOID PcrTeb;
154 } KV86_FRAME, *PKV86_FRAME;
155
156 //
157 // Virtual Stack Frame
158 //
159 typedef struct _KV8086_STACK_FRAME
160 {
161 KTRAP_FRAME TrapFrame;
162 FX_SAVE_AREA NpxArea;
163 KV86_FRAME V86Frame;
164 } KV8086_STACK_FRAME, *PKV8086_STACK_FRAME;
165
166 //
167 // Large Pages Support
168 //
169 typedef struct _LARGE_IDENTITY_MAP
170 {
171 PHARDWARE_PTE TopLevelDirectory;
172 ULONG Cr3;
173 ULONG_PTR StartAddress;
174 ULONG PagesCount;
175 PVOID PagesList[30];
176 } LARGE_IDENTITY_MAP, *PLARGE_IDENTITY_MAP;
177
178 /* Diable interrupts and return whether they were enabled before */
179 FORCEINLINE
180 BOOLEAN
181 KeDisableInterrupts(VOID)
182 {
183 ULONG Flags;
184 BOOLEAN Return;
185
186 /* Get EFLAGS and check if the interrupt bit is set */
187 Flags = __readeflags();
188 Return = (Flags & EFLAGS_INTERRUPT_MASK) ? TRUE: FALSE;
189
190 /* Disable interrupts */
191 _disable();
192 return Return;
193 }
194
195 /* Restore previous interrupt state */
196 FORCEINLINE
197 VOID
198 KeRestoreInterrupts(BOOLEAN WereEnabled)
199 {
200 if (WereEnabled) _enable();
201 }
202
203 //
204 // Registers an interrupt handler with an IDT vector
205 //
206 FORCEINLINE
207 VOID
208 KeRegisterInterruptHandler(IN ULONG Vector,
209 IN PVOID Handler)
210 {
211 UCHAR Entry;
212 ULONG_PTR Address;
213 PKIPCR Pcr = (PKIPCR)KeGetPcr();
214
215 //
216 // Get the entry from the HAL
217 //
218 Entry = HalVectorToIDTEntry(Vector);
219 Address = PtrToUlong(Handler);
220
221 //
222 // Now set the data
223 //
224 Pcr->IDT[Entry].ExtendedOffset = (USHORT)(Address >> 16);
225 Pcr->IDT[Entry].Offset = (USHORT)Address;
226 }
227
228 //
229 // Returns the registered interrupt handler for a given IDT vector
230 //
231 FORCEINLINE
232 PVOID
233 KeQueryInterruptHandler(IN ULONG Vector)
234 {
235 PKIPCR Pcr = (PKIPCR)KeGetPcr();
236 UCHAR Entry;
237
238 //
239 // Get the entry from the HAL
240 //
241 Entry = HalVectorToIDTEntry(Vector);
242
243 //
244 // Read the entry from the IDT
245 //
246 return (PVOID)(((Pcr->IDT[Entry].ExtendedOffset << 16) & 0xFFFF0000) |
247 (Pcr->IDT[Entry].Offset & 0xFFFF));
248 }
249
250 //
251 // Invalidates the TLB entry for a specified address
252 //
253 FORCEINLINE
254 VOID
255 KeInvalidateTlbEntry(IN PVOID Address)
256 {
257 /* Invalidate the TLB entry for this address */
258 __invlpg(Address);
259 }
260
261 FORCEINLINE
262 VOID
263 KeFlushProcessTb(VOID)
264 {
265 /* Flush the TLB by resetting CR3 */
266 __writecr3(__readcr3());
267 }
268
269 FORCEINLINE
270 VOID
271 KeSweepICache(IN PVOID BaseAddress,
272 IN SIZE_T FlushSize)
273 {
274 //
275 // Always sweep the whole cache
276 //
277 UNREFERENCED_PARAMETER(BaseAddress);
278 UNREFERENCED_PARAMETER(FlushSize);
279 __wbinvd();
280 }
281
282 FORCEINLINE
283 PRKTHREAD
284 KeGetCurrentThread(VOID)
285 {
286 /* Return the current thread */
287 return ((PKIPCR)KeGetPcr())->PrcbData.CurrentThread;
288 }
289
290 FORCEINLINE
291 VOID
292 KiRundownThread(IN PKTHREAD Thread)
293 {
294 #ifndef CONFIG_SMP
295 /* Check if this is the NPX Thread */
296 if (KeGetCurrentPrcb()->NpxThread == Thread)
297 {
298 /* Clear it */
299 KeGetCurrentPrcb()->NpxThread = NULL;
300 Ke386FnInit();
301 }
302 #else
303 /* Nothing to do */
304 #endif
305 }
306
307 FORCEINLINE
308 VOID
309 Ke386SetGdtEntryBase(PKGDTENTRY GdtEntry, PVOID BaseAddress)
310 {
311 GdtEntry->BaseLow = (USHORT)((ULONG_PTR)BaseAddress & 0xFFFF);
312 GdtEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)BaseAddress >> 16);
313 GdtEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)BaseAddress >> 24);
314 }
315
316 FORCEINLINE
317 VOID
318 KiSetTebBase(PKPCR Pcr, PVOID TebAddress)
319 {
320 Pcr->NtTib.Self = TebAddress;
321 Ke386SetGdtEntryBase(&Pcr->GDT[KGDT_R3_TEB / sizeof(KGDTENTRY)], TebAddress);
322 }
323
324 VOID
325 FASTCALL
326 Ki386InitializeTss(
327 IN PKTSS Tss,
328 IN PKIDTENTRY Idt,
329 IN PKGDTENTRY Gdt
330 );
331
332 VOID
333 NTAPI
334 KiSetCR0Bits(VOID);
335
336 VOID
337 NTAPI
338 KiGetCacheInformation(VOID);
339
340 BOOLEAN
341 NTAPI
342 KiIsNpxPresent(
343 VOID
344 );
345
346 BOOLEAN
347 NTAPI
348 KiIsNpxErrataPresent(
349 VOID
350 );
351
352 VOID
353 NTAPI
354 KiSetProcessorType(VOID);
355
356 ULONG
357 NTAPI
358 KiGetFeatureBits(VOID);
359
360 VOID
361 NTAPI
362 KiThreadStartup(VOID);
363
364 NTSTATUS
365 NTAPI
366 Ke386GetGdtEntryThread(
367 IN PKTHREAD Thread,
368 IN ULONG Offset,
369 IN PKGDTENTRY Descriptor
370 );
371
372 VOID
373 NTAPI
374 KiFlushNPXState(
375 IN FLOATING_SAVE_AREA *SaveArea
376 );
377
378 VOID
379 NTAPI
380 Ki386AdjustEsp0(
381 IN PKTRAP_FRAME TrapFrame
382 );
383
384 VOID
385 NTAPI
386 Ki386SetupAndExitToV86Mode(
387 OUT PTEB VdmTeb
388 );
389
390 VOID
391 NTAPI
392 KeI386VdmInitialize(
393 VOID
394 );
395
396 ULONG_PTR
397 NTAPI
398 Ki386EnableGlobalPage(
399 IN ULONG_PTR Context
400 );
401
402 ULONG_PTR
403 NTAPI
404 Ki386EnableTargetLargePage(
405 IN ULONG_PTR Context
406 );
407
408 BOOLEAN
409 NTAPI
410 Ki386CreateIdentityMap(
411 IN PLARGE_IDENTITY_MAP IdentityMap,
412 IN PVOID StartPtr,
413 IN ULONG Length
414 );
415
416 VOID
417 NTAPI
418 Ki386FreeIdentityMap(
419 IN PLARGE_IDENTITY_MAP IdentityMap
420 );
421
422 VOID
423 NTAPI
424 Ki386EnableCurrentLargePage(
425 IN ULONG_PTR StartAddress,
426 IN ULONG Cr3
427 );
428
429 VOID
430 NTAPI
431 KiI386PentiumLockErrataFixup(
432 VOID
433 );
434
435 VOID
436 NTAPI
437 KiInitializePAT(
438 VOID
439 );
440
441 VOID
442 NTAPI
443 KiInitializeMTRR(
444 IN BOOLEAN FinalCpu
445 );
446
447 VOID
448 NTAPI
449 KiAmdK6InitializeMTRR(
450 VOID
451 );
452
453 VOID
454 NTAPI
455 KiRestoreFastSyscallReturnState(
456 VOID
457 );
458
459 ULONG_PTR
460 NTAPI
461 Ki386EnableDE(
462 IN ULONG_PTR Context
463 );
464
465 ULONG_PTR
466 NTAPI
467 Ki386EnableFxsr(
468 IN ULONG_PTR Context
469 );
470
471 ULONG_PTR
472 NTAPI
473 Ki386EnableXMMIExceptions(
474 IN ULONG_PTR Context
475 );
476
477 BOOLEAN
478 NTAPI
479 VdmDispatchBop(
480 IN PKTRAP_FRAME TrapFrame
481 );
482
483 BOOLEAN
484 NTAPI
485 VdmDispatchPageFault(
486 _In_ PKTRAP_FRAME TrapFrame
487 );
488
489 BOOLEAN
490 FASTCALL
491 KiVdmOpcodePrefix(
492 IN PKTRAP_FRAME TrapFrame,
493 IN ULONG Flags
494 );
495
496 BOOLEAN
497 FASTCALL
498 Ki386HandleOpcodeV86(
499 IN PKTRAP_FRAME TrapFrame
500 );
501
502 DECLSPEC_NORETURN
503 VOID
504 FASTCALL
505 KiEoiHelper(
506 IN PKTRAP_FRAME TrapFrame
507 );
508
509 VOID
510 FASTCALL
511 Ki386BiosCallReturnAddress(
512 IN PKTRAP_FRAME TrapFrame
513 );
514
515 ULONG_PTR
516 FASTCALL
517 KiExitV86Mode(
518 IN PKTRAP_FRAME TrapFrame
519 );
520
521 DECLSPEC_NORETURN
522 VOID
523 NTAPI
524 KiDispatchExceptionFromTrapFrame(
525 IN NTSTATUS Code,
526 IN ULONG Flags,
527 IN ULONG_PTR Address,
528 IN ULONG ParameterCount,
529 IN ULONG_PTR Parameter1,
530 IN ULONG_PTR Parameter2,
531 IN ULONG_PTR Parameter3,
532 IN PKTRAP_FRAME TrapFrame
533 );
534
535 NTSTATUS
536 NTAPI
537 KiConvertToGuiThread(
538 VOID
539 );
540
541 //
542 // Global x86 only Kernel data
543 //
544 extern PVOID Ki386IopmSaveArea;
545 extern ULONG KeI386EFlagsAndMaskV86;
546 extern ULONG KeI386EFlagsOrMaskV86;
547 extern BOOLEAN KeI386VirtualIntExtensions;
548 extern KIDTENTRY KiIdt[MAXIMUM_IDTVECTOR+1];
549 extern KDESCRIPTOR KiIdtDescriptor;
550 extern BOOLEAN KiI386PentiumLockErrataPresent;
551 extern ULONG KeI386NpxPresent;
552 extern ULONG KeI386XMMIPresent;
553 extern ULONG KeI386FxsrPresent;
554 extern ULONG KiMXCsrMask;
555 extern ULONG KeI386CpuType;
556 extern ULONG KeI386CpuStep;
557 extern ULONG KiFastSystemCallDisable;
558 extern UCHAR KiDebugRegisterTrapOffsets[9];
559 extern UCHAR KiDebugRegisterContextOffsets[9];
560 extern DECLSPEC_NORETURN VOID __cdecl KiTrap02(VOID);
561 extern VOID __cdecl KiTrap08(VOID);
562 extern VOID __cdecl KiTrap13(VOID);
563 extern VOID __cdecl KiFastCallEntry(VOID);
564 extern VOID NTAPI ExpInterlockedPopEntrySListFault(VOID);
565 extern VOID NTAPI ExpInterlockedPopEntrySListResume(VOID);
566 extern VOID __cdecl CopyParams(VOID);
567 extern VOID __cdecl ReadBatch(VOID);
568 extern CHAR KiSystemCallExitBranch[];
569 extern CHAR KiSystemCallExit[];
570 extern CHAR KiSystemCallExit2[];
571
572 //
573 // Trap Macros
574 //
575 #include "trap_x.h"
576
577 //
578 // Returns a thread's FPU save area
579 //
580 FORCEINLINE
581 PFX_SAVE_AREA
582 KiGetThreadNpxArea(IN PKTHREAD Thread)
583 {
584 ASSERT((ULONG_PTR)Thread->InitialStack % 16 == 0);
585 return (PFX_SAVE_AREA)((ULONG_PTR)Thread->InitialStack - sizeof(FX_SAVE_AREA));
586 }
587
588 //
589 // Sanitizes a selector
590 //
591 FORCEINLINE
592 ULONG
593 Ke386SanitizeSeg(IN ULONG Cs,
594 IN KPROCESSOR_MODE Mode)
595 {
596 //
597 // Check if we're in kernel-mode, and force CPL 0 if so.
598 // Otherwise, force CPL 3.
599 //
600 return ((Mode == KernelMode) ?
601 (Cs & (0xFFFF & ~RPL_MASK)) :
602 (RPL_MASK | (Cs & 0xFFFF)));
603 }
604
605 //
606 // Sanitizes EFLAGS
607 //
608 FORCEINLINE
609 ULONG
610 Ke386SanitizeFlags(IN ULONG Eflags,
611 IN KPROCESSOR_MODE Mode)
612 {
613 //
614 // Check if we're in kernel-mode, and sanitize EFLAGS if so.
615 // Otherwise, also force interrupt mask on.
616 //
617 return ((Mode == KernelMode) ?
618 (Eflags & (EFLAGS_USER_SANITIZE | EFLAGS_INTERRUPT_MASK)) :
619 (EFLAGS_INTERRUPT_MASK | (Eflags & EFLAGS_USER_SANITIZE)));
620 }
621
622 //
623 // Sanitizes a Debug Register
624 //
625 FORCEINLINE
626 PVOID
627 Ke386SanitizeDr(IN PVOID DrAddress,
628 IN KPROCESSOR_MODE Mode)
629 {
630 //
631 // Check if we're in kernel-mode, and return the address directly if so.
632 // Otherwise, make sure it's not inside the kernel-mode address space.
633 // If it is, then clear the address.
634 //
635 return ((Mode == KernelMode) ? DrAddress :
636 (DrAddress <= MM_HIGHEST_USER_ADDRESS) ? DrAddress : 0);
637 }
638
639 //
640 // Exception with no arguments
641 //
642 FORCEINLINE
643 DECLSPEC_NORETURN
644 VOID
645 KiDispatchException0Args(IN NTSTATUS Code,
646 IN ULONG_PTR Address,
647 IN PKTRAP_FRAME TrapFrame)
648 {
649 /* Helper for exceptions with no arguments */
650 KiDispatchExceptionFromTrapFrame(Code, 0, Address, 0, 0, 0, 0, TrapFrame);
651 }
652
653 //
654 // Exception with one argument
655 //
656 FORCEINLINE
657 DECLSPEC_NORETURN
658 VOID
659 KiDispatchException1Args(IN NTSTATUS Code,
660 IN ULONG_PTR Address,
661 IN ULONG P1,
662 IN PKTRAP_FRAME TrapFrame)
663 {
664 /* Helper for exceptions with no arguments */
665 KiDispatchExceptionFromTrapFrame(Code, 0, Address, 1, P1, 0, 0, TrapFrame);
666 }
667
668 //
669 // Exception with two arguments
670 //
671 FORCEINLINE
672 DECLSPEC_NORETURN
673 VOID
674 KiDispatchException2Args(IN NTSTATUS Code,
675 IN ULONG_PTR Address,
676 IN ULONG P1,
677 IN ULONG P2,
678 IN PKTRAP_FRAME TrapFrame)
679 {
680 /* Helper for exceptions with no arguments */
681 KiDispatchExceptionFromTrapFrame(Code, 0, Address, 2, P1, P2, 0, TrapFrame);
682 }
683
684 //
685 // Performs a system call
686 //
687
688 /*
689 * This sequence does a RtlCopyMemory(Stack - StackBytes, Arguments, StackBytes)
690 * and then calls the function associated with the system call.
691 *
692 * It's done in assembly for two reasons: we need to muck with the stack,
693 * and the call itself restores the stack back for us. The only way to do
694 * this in C is to do manual C handlers for every possible number of args on
695 * the stack, and then have the handler issue a call by pointer. This is
696 * wasteful since it'll basically push the values twice and require another
697 * level of call indirection.
698 *
699 * The ARM kernel currently does this, but it should probably be changed
700 * later to function like this as well.
701 *
702 */
703 #ifdef __GNUC__
704 FORCEINLINE
705 NTSTATUS
706 KiSystemCallTrampoline(IN PVOID Handler,
707 IN PVOID Arguments,
708 IN ULONG StackBytes)
709 {
710 NTSTATUS Result;
711
712 __asm__ __volatile__
713 (
714 "subl %1, %%esp\n\t"
715 "movl %%esp, %%edi\n\t"
716 "movl %2, %%esi\n\t"
717 "shrl $2, %1\n\t"
718 "rep movsd\n\t"
719 "call *%3\n\t"
720 "movl %%eax, %0"
721 : "=r"(Result)
722 : "c"(StackBytes),
723 "d"(Arguments),
724 "r"(Handler)
725 : "%esp", "%esi", "%edi"
726 );
727 return Result;
728 }
729 #elif defined(_MSC_VER)
730 FORCEINLINE
731 NTSTATUS
732 KiSystemCallTrampoline(IN PVOID Handler,
733 IN PVOID Arguments,
734 IN ULONG StackBytes)
735 {
736 __asm
737 {
738 mov ecx, StackBytes
739 mov esi, Arguments
740 mov eax, Handler
741 sub esp, ecx
742 mov edi, esp
743 shr ecx, 2
744 rep movsd
745 call eax
746 }
747 /* Return with result in EAX */
748 }
749 #else
750 #error Unknown Compiler
751 #endif
752
753
754 //
755 // Checks for pending APCs
756 //
757 FORCEINLINE
758 VOID
759 KiCheckForApcDelivery(IN PKTRAP_FRAME TrapFrame)
760 {
761 PKTHREAD Thread;
762 KIRQL OldIrql;
763
764 /* Check for V8086 or user-mode trap */
765 if ((TrapFrame->EFlags & EFLAGS_V86_MASK) || (KiUserTrap(TrapFrame)))
766 {
767 /* Get the thread */
768 Thread = KeGetCurrentThread();
769 while (TRUE)
770 {
771 /* Turn off the alerted state for kernel mode */
772 Thread->Alerted[KernelMode] = FALSE;
773
774 /* Are there pending user APCs? */
775 if (!Thread->ApcState.UserApcPending) break;
776
777 /* Raise to APC level and enable interrupts */
778 OldIrql = KfRaiseIrql(APC_LEVEL);
779 _enable();
780
781 /* Deliver APCs */
782 KiDeliverApc(UserMode, NULL, TrapFrame);
783
784 /* Restore IRQL and disable interrupts once again */
785 KfLowerIrql(OldIrql);
786 _disable();
787 }
788 }
789 }
790
791 //
792 // Switches from boot loader to initial kernel stack
793 //
794 FORCEINLINE
795 VOID
796 KiSwitchToBootStack(IN ULONG_PTR InitialStack)
797 {
798 VOID NTAPI KiSystemStartupBootStack(VOID);
799
800 /* We have to switch to a new stack before continuing kernel initialization */
801 #ifdef __GNUC__
802 __asm__
803 (
804 "movl %0, %%esp\n\t"
805 "subl %1, %%esp\n\t"
806 "pushl %2\n\t"
807 "jmp _KiSystemStartupBootStack@0"
808 :
809 : "c"(InitialStack),
810 "i"(NPX_FRAME_LENGTH + KTRAP_FRAME_ALIGN + KTRAP_FRAME_LENGTH),
811 "i"(CR0_EM | CR0_TS | CR0_MP),
812 "p"(KiSystemStartupBootStack)
813 : "%esp"
814 );
815 #elif defined(_MSC_VER)
816 __asm
817 {
818 mov esp, InitialStack
819 sub esp, (NPX_FRAME_LENGTH + KTRAP_FRAME_ALIGN + KTRAP_FRAME_LENGTH)
820 push (CR0_EM | CR0_TS | CR0_MP)
821 jmp KiSystemStartupBootStack
822 }
823 #else
824 #error Unknown Compiler
825 #endif
826 }
827
828 //
829 // Emits the iret instruction for C code
830 //
831 FORCEINLINE
832 DECLSPEC_NORETURN
833 VOID
834 KiIret(VOID)
835 {
836 #if defined(__GNUC__)
837 __asm__ __volatile__
838 (
839 "iret"
840 );
841 #elif defined(_MSC_VER)
842 __asm
843 {
844 iretd
845 }
846 #else
847 #error Unsupported compiler
848 #endif
849 UNREACHABLE;
850 }
851
852 //
853 // Normally this is done by the HAL, but on x86 as an optimization, the kernel
854 // initiates the end by calling back into the HAL and exiting the trap here.
855 //
856 FORCEINLINE
857 VOID
858 KiEndInterrupt(IN KIRQL Irql,
859 IN PKTRAP_FRAME TrapFrame)
860 {
861 /* Disable interrupts and end the interrupt */
862 _disable();
863 HalEndSystemInterrupt(Irql, TrapFrame);
864
865 /* Exit the interrupt */
866 KiEoiHelper(TrapFrame);
867 }
868
869 //
870 // PERF Code
871 //
872 FORCEINLINE
873 VOID
874 Ki386PerfEnd(VOID)
875 {
876 extern ULONGLONG BootCyclesEnd, BootCycles;
877 BootCyclesEnd = __rdtsc();
878 DbgPrint("Boot took %I64u cycles!\n", BootCyclesEnd - BootCycles);
879 DbgPrint("Interrupts: %u System Calls: %u Context Switches: %u\n",
880 KeGetCurrentPrcb()->InterruptCount,
881 KeGetCurrentPrcb()->KeSystemCalls,
882 KeGetContextSwitches(KeGetCurrentPrcb()));
883 }
884
885 FORCEINLINE
886 PULONG
887 KiGetUserModeStackAddress(void)
888 {
889 return &(KeGetCurrentThread()->TrapFrame->HardwareEsp);
890 }
891
892 #endif