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