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