Synchronize with trunk.
[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 /* Diable interrupts and return whether they were enabled before */
167 FORCEINLINE
168 BOOLEAN
169 KeDisableInterrupts(VOID)
170 {
171 ULONG Flags;
172 BOOLEAN Return;
173
174 /* Get EFLAGS and check if the interrupt bit is set */
175 Flags = __readeflags();
176 Return = (Flags & EFLAGS_INTERRUPT_MASK) ? TRUE: FALSE;
177
178 /* Disable interrupts */
179 _disable();
180 return Return;
181 }
182
183 /* Restore previous interrupt state */
184 FORCEINLINE
185 VOID
186 KeRestoreInterrupts(BOOLEAN WereEnabled)
187 {
188 if (WereEnabled) _enable();
189 }
190
191 //
192 // Registers an interrupt handler with an IDT vector
193 //
194 FORCEINLINE
195 VOID
196 KeRegisterInterruptHandler(IN ULONG Vector,
197 IN PVOID Handler)
198 {
199 UCHAR Entry;
200 ULONG_PTR Address;
201 PKIPCR Pcr = (PKIPCR)KeGetPcr();
202
203 //
204 // Get the entry from the HAL
205 //
206 Entry = HalVectorToIDTEntry(Vector);
207 Address = PtrToUlong(Handler);
208
209 //
210 // Now set the data
211 //
212 Pcr->IDT[Entry].ExtendedOffset = (USHORT)(Address >> 16);
213 Pcr->IDT[Entry].Offset = (USHORT)Address;
214 }
215
216 //
217 // Returns the registered interrupt handler for a given IDT vector
218 //
219 FORCEINLINE
220 PVOID
221 KeQueryInterruptHandler(IN ULONG Vector)
222 {
223 PKIPCR Pcr = (PKIPCR)KeGetPcr();
224 UCHAR Entry;
225
226 //
227 // Get the entry from the HAL
228 //
229 Entry = HalVectorToIDTEntry(Vector);
230
231 //
232 // Read the entry from the IDT
233 //
234 return (PVOID)(((Pcr->IDT[Entry].ExtendedOffset << 16) & 0xFFFF0000) |
235 (Pcr->IDT[Entry].Offset & 0xFFFF));
236 }
237
238 //
239 // Invalidates the TLB entry for a specified address
240 //
241 FORCEINLINE
242 VOID
243 KeInvalidateTlbEntry(IN PVOID Address)
244 {
245 /* Invalidate the TLB entry for this address */
246 __invlpg(Address);
247 }
248
249 FORCEINLINE
250 VOID
251 KeFlushProcessTb(VOID)
252 {
253 /* Flush the TLB by resetting CR3 */
254 __writecr3(__readcr3());
255 }
256
257 FORCEINLINE
258 PRKTHREAD
259 KeGetCurrentThread(VOID)
260 {
261 /* Return the current thread */
262 return ((PKIPCR)KeGetPcr())->PrcbData.CurrentThread;
263 }
264
265 FORCEINLINE
266 VOID
267 KiRundownThread(IN PKTHREAD Thread)
268 {
269 #ifndef CONFIG_SMP
270 /* Check if this is the NPX Thread */
271 if (KeGetCurrentPrcb()->NpxThread == Thread)
272 {
273 /* Clear it */
274 KeGetCurrentPrcb()->NpxThread = NULL;
275 Ke386FnInit();
276 }
277 #else
278 /* Nothing to do */
279 #endif
280 }
281
282 FORCEINLINE
283 VOID
284 Ke386SetGdtEntryBase(PKGDTENTRY GdtEntry, PVOID BaseAddress)
285 {
286 GdtEntry->BaseLow = (USHORT)((ULONG_PTR)BaseAddress & 0xFFFF);
287 GdtEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)BaseAddress >> 16);
288 GdtEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)BaseAddress >> 24);
289 }
290
291 FORCEINLINE
292 VOID
293 KiSetTebBase(PKPCR Pcr, PVOID TebAddress)
294 {
295 Pcr->NtTib.Self = TebAddress;
296 Ke386SetGdtEntryBase(&Pcr->GDT[KGDT_R3_TEB / sizeof(KGDTENTRY)], TebAddress);
297 }
298
299 VOID
300 FASTCALL
301 Ki386InitializeTss(
302 IN PKTSS Tss,
303 IN PKIDTENTRY Idt,
304 IN PKGDTENTRY Gdt
305 );
306
307 VOID
308 NTAPI
309 KiSetCR0Bits(VOID);
310
311 VOID
312 NTAPI
313 KiGetCacheInformation(VOID);
314
315 BOOLEAN
316 NTAPI
317 KiIsNpxPresent(
318 VOID
319 );
320
321 BOOLEAN
322 NTAPI
323 KiIsNpxErrataPresent(
324 VOID
325 );
326
327 VOID
328 NTAPI
329 KiSetProcessorType(VOID);
330
331 ULONG
332 NTAPI
333 KiGetFeatureBits(VOID);
334
335 VOID
336 NTAPI
337 KiThreadStartup(VOID);
338
339 NTSTATUS
340 NTAPI
341 Ke386GetGdtEntryThread(
342 IN PKTHREAD Thread,
343 IN ULONG Offset,
344 IN PKGDTENTRY Descriptor
345 );
346
347 VOID
348 NTAPI
349 KiFlushNPXState(
350 IN FLOATING_SAVE_AREA *SaveArea
351 );
352
353 VOID
354 NTAPI
355 Ki386AdjustEsp0(
356 IN PKTRAP_FRAME TrapFrame
357 );
358
359 VOID
360 NTAPI
361 Ki386SetupAndExitToV86Mode(
362 OUT PTEB VdmTeb
363 );
364
365 VOID
366 NTAPI
367 KeI386VdmInitialize(
368 VOID
369 );
370
371 ULONG_PTR
372 NTAPI
373 Ki386EnableGlobalPage(
374 IN volatile ULONG_PTR Context
375 );
376
377 VOID
378 NTAPI
379 KiI386PentiumLockErrataFixup(
380 VOID
381 );
382
383 VOID
384 NTAPI
385 KiInitializePAT(
386 VOID
387 );
388
389 VOID
390 NTAPI
391 KiInitializeMTRR(
392 IN BOOLEAN FinalCpu
393 );
394
395 VOID
396 NTAPI
397 KiAmdK6InitializeMTRR(
398 VOID
399 );
400
401 VOID
402 NTAPI
403 KiRestoreFastSyscallReturnState(
404 VOID
405 );
406
407 ULONG_PTR
408 NTAPI
409 Ki386EnableDE(
410 IN ULONG_PTR Context
411 );
412
413 ULONG_PTR
414 NTAPI
415 Ki386EnableFxsr(
416 IN ULONG_PTR Context
417 );
418
419 ULONG_PTR
420 NTAPI
421 Ki386EnableXMMIExceptions(
422 IN ULONG_PTR Context
423 );
424
425 BOOLEAN
426 NTAPI
427 VdmDispatchBop(
428 IN PKTRAP_FRAME TrapFrame
429 );
430
431 BOOLEAN
432 FASTCALL
433 KiVdmOpcodePrefix(
434 IN PKTRAP_FRAME TrapFrame,
435 IN ULONG Flags
436 );
437
438 BOOLEAN
439 FASTCALL
440 Ki386HandleOpcodeV86(
441 IN PKTRAP_FRAME TrapFrame
442 );
443
444 DECLSPEC_NORETURN
445 VOID
446 FASTCALL
447 KiEoiHelper(
448 IN PKTRAP_FRAME TrapFrame
449 );
450
451 VOID
452 FASTCALL
453 Ki386BiosCallReturnAddress(
454 IN PKTRAP_FRAME TrapFrame
455 );
456
457 ULONG_PTR
458 FASTCALL
459 KiExitV86Mode(
460 IN PKTRAP_FRAME TrapFrame
461 );
462
463 DECLSPEC_NORETURN
464 VOID
465 NTAPI
466 KiDispatchExceptionFromTrapFrame(
467 IN NTSTATUS Code,
468 IN ULONG_PTR Address,
469 IN ULONG ParameterCount,
470 IN ULONG_PTR Parameter1,
471 IN ULONG_PTR Parameter2,
472 IN ULONG_PTR Parameter3,
473 IN PKTRAP_FRAME TrapFrame
474 );
475
476 //
477 // Global x86 only Kernel data
478 //
479 extern PVOID Ki386IopmSaveArea;
480 extern ULONG KeI386EFlagsAndMaskV86;
481 extern ULONG KeI386EFlagsOrMaskV86;
482 extern BOOLEAN KeI386VirtualIntExtensions;
483 extern KIDTENTRY KiIdt[MAXIMUM_IDTVECTOR+1];
484 extern KDESCRIPTOR KiIdtDescriptor;
485 extern BOOLEAN KiI386PentiumLockErrataPresent;
486 extern ULONG KeI386NpxPresent;
487 extern ULONG KeI386XMMIPresent;
488 extern ULONG KeI386FxsrPresent;
489 extern ULONG KiMXCsrMask;
490 extern ULONG KeI386CpuType;
491 extern ULONG KeI386CpuStep;
492 extern ULONG Ke386CacheAlignment;
493 extern ULONG KiFastSystemCallDisable;
494 extern UCHAR KiDebugRegisterTrapOffsets[9];
495 extern UCHAR KiDebugRegisterContextOffsets[9];
496 extern DECLSPEC_NORETURN VOID __cdecl KiTrap02(VOID);
497 extern VOID __cdecl KiTrap08(VOID);
498 extern VOID __cdecl KiTrap13(VOID);
499 extern VOID __cdecl KiFastCallEntry(VOID);
500 extern VOID NTAPI ExpInterlockedPopEntrySListFault(VOID);
501 extern VOID NTAPI ExpInterlockedPopEntrySListResume(VOID);
502 extern VOID __cdecl CopyParams(VOID);
503 extern VOID __cdecl ReadBatch(VOID);
504 extern VOID __cdecl FrRestore(VOID);
505 extern CHAR KiSystemCallExitBranch[];
506 extern CHAR KiSystemCallExit[];
507 extern CHAR KiSystemCallExit2[];
508
509 //
510 // Trap Macros
511 //
512 #include "trap_x.h"
513
514 //
515 // Returns a thread's FPU save area
516 //
517 PFX_SAVE_AREA
518 FORCEINLINE
519 KiGetThreadNpxArea(IN PKTHREAD Thread)
520 {
521 return (PFX_SAVE_AREA)((ULONG_PTR)Thread->InitialStack - sizeof(FX_SAVE_AREA));
522 }
523
524 //
525 // Sanitizes a selector
526 //
527 FORCEINLINE
528 ULONG
529 Ke386SanitizeSeg(IN ULONG Cs,
530 IN KPROCESSOR_MODE Mode)
531 {
532 //
533 // Check if we're in kernel-mode, and force CPL 0 if so.
534 // Otherwise, force CPL 3.
535 //
536 return ((Mode == KernelMode) ?
537 (Cs & (0xFFFF & ~RPL_MASK)) :
538 (RPL_MASK | (Cs & 0xFFFF)));
539 }
540
541 //
542 // Sanitizes EFLAGS
543 //
544 FORCEINLINE
545 ULONG
546 Ke386SanitizeFlags(IN ULONG Eflags,
547 IN KPROCESSOR_MODE Mode)
548 {
549 //
550 // Check if we're in kernel-mode, and sanitize EFLAGS if so.
551 // Otherwise, also force interrupt mask on.
552 //
553 return ((Mode == KernelMode) ?
554 (Eflags & (EFLAGS_USER_SANITIZE | EFLAGS_INTERRUPT_MASK)) :
555 (EFLAGS_INTERRUPT_MASK | (Eflags & EFLAGS_USER_SANITIZE)));
556 }
557
558 //
559 // Sanitizes a Debug Register
560 //
561 FORCEINLINE
562 PVOID
563 Ke386SanitizeDr(IN PVOID DrAddress,
564 IN KPROCESSOR_MODE Mode)
565 {
566 //
567 // Check if we're in kernel-mode, and return the address directly if so.
568 // Otherwise, make sure it's not inside the kernel-mode address space.
569 // If it is, then clear the address.
570 //
571 return ((Mode == KernelMode) ? DrAddress :
572 (DrAddress <= MM_HIGHEST_USER_ADDRESS) ? DrAddress : 0);
573 }
574
575 //
576 // Exception with no arguments
577 //
578 VOID
579 FORCEINLINE
580 DECLSPEC_NORETURN
581 KiDispatchException0Args(IN NTSTATUS Code,
582 IN ULONG_PTR Address,
583 IN PKTRAP_FRAME TrapFrame)
584 {
585 /* Helper for exceptions with no arguments */
586 KiDispatchExceptionFromTrapFrame(Code, Address, 0, 0, 0, 0, TrapFrame);
587 }
588
589 //
590 // Exception with one argument
591 //
592 VOID
593 FORCEINLINE
594 DECLSPEC_NORETURN
595 KiDispatchException1Args(IN NTSTATUS Code,
596 IN ULONG_PTR Address,
597 IN ULONG P1,
598 IN PKTRAP_FRAME TrapFrame)
599 {
600 /* Helper for exceptions with no arguments */
601 KiDispatchExceptionFromTrapFrame(Code, Address, 1, P1, 0, 0, TrapFrame);
602 }
603
604 //
605 // Exception with two arguments
606 //
607 VOID
608 FORCEINLINE
609 DECLSPEC_NORETURN
610 KiDispatchException2Args(IN NTSTATUS Code,
611 IN ULONG_PTR Address,
612 IN ULONG P1,
613 IN ULONG P2,
614 IN PKTRAP_FRAME TrapFrame)
615 {
616 /* Helper for exceptions with no arguments */
617 KiDispatchExceptionFromTrapFrame(Code, Address, 2, P1, P2, 0, TrapFrame);
618 }
619
620 //
621 // Performs a system call
622 //
623
624 /*
625 * This sequence does a RtlCopyMemory(Stack - StackBytes, Arguments, StackBytes)
626 * and then calls the function associated with the system call.
627 *
628 * It's done in assembly for two reasons: we need to muck with the stack,
629 * and the call itself restores the stack back for us. The only way to do
630 * this in C is to do manual C handlers for every possible number of args on
631 * the stack, and then have the handler issue a call by pointer. This is
632 * wasteful since it'll basically push the values twice and require another
633 * level of call indirection.
634 *
635 * The ARM kernel currently does this, but it should probably be changed
636 * later to function like this as well.
637 *
638 */
639 #ifdef __GNUC__
640 NTSTATUS
641 FORCEINLINE
642 KiSystemCallTrampoline(IN PVOID Handler,
643 IN PVOID Arguments,
644 IN ULONG StackBytes)
645 {
646 NTSTATUS Result;
647
648 __asm__ __volatile__
649 (
650 "subl %1, %%esp\n"
651 "movl %%esp, %%edi\n"
652 "movl %2, %%esi\n"
653 "shrl $2, %1\n"
654 "rep movsd\n"
655 "call *%3\n"
656 "movl %%eax, %0\n"
657 : "=r"(Result)
658 : "c"(StackBytes),
659 "d"(Arguments),
660 "r"(Handler)
661 : "%esp", "%esi", "%edi"
662 );
663 return Result;
664 }
665 #elif defined(_MSC_VER)
666 NTSTATUS
667 FORCEINLINE
668 KiSystemCallTrampoline(IN PVOID Handler,
669 IN PVOID Arguments,
670 IN ULONG StackBytes)
671 {
672 __asm
673 {
674 mov ecx, StackBytes
675 mov esi, Arguments
676 mov eax, Handler
677 sub esp, ecx
678 mov edi, esp
679 shr ecx, 2
680 rep movsd
681 call eax
682 }
683 /* Return with result in EAX */
684 }
685 #else
686 #error Unknown Compiler
687 #endif
688
689
690 //
691 // Checks for pending APCs
692 //
693 VOID
694 FORCEINLINE
695 KiCheckForApcDelivery(IN PKTRAP_FRAME TrapFrame)
696 {
697 PKTHREAD Thread;
698 KIRQL OldIrql;
699
700 /* Check for V8086 or user-mode trap */
701 if ((TrapFrame->EFlags & EFLAGS_V86_MASK) || (KiUserTrap(TrapFrame)))
702 {
703 /* Get the thread */
704 Thread = KeGetCurrentThread();
705 while (TRUE)
706 {
707 /* Turn off the alerted state for kernel mode */
708 Thread->Alerted[KernelMode] = FALSE;
709
710 /* Are there pending user APCs? */
711 if (!Thread->ApcState.UserApcPending) break;
712
713 /* Raise to APC level and enable interrupts */
714 OldIrql = KfRaiseIrql(APC_LEVEL);
715 _enable();
716
717 /* Deliver APCs */
718 KiDeliverApc(UserMode, NULL, TrapFrame);
719
720 /* Restore IRQL and disable interrupts once again */
721 KfLowerIrql(OldIrql);
722 _disable();
723 }
724 }
725 }
726
727 //
728 // Converts a base thread to a GUI thread
729 //
730 #ifdef __GNUC__
731 NTSTATUS
732 FORCEINLINE
733 KiConvertToGuiThread(VOID)
734 {
735 NTSTATUS Result;
736 PVOID StackFrame;
737
738 /*
739 * Converting to a GUI thread safely updates ESP in-place as well as the
740 * current Thread->TrapFrame and EBP when KeSwitchKernelStack is called.
741 *
742 * However, PsConvertToGuiThread "helpfully" restores EBP to the original
743 * caller's value, since it is considered a nonvolatile register. As such,
744 * as soon as we're back after the conversion and we try to store the result
745 * which will probably be in some stack variable (EBP-based), we'll crash as
746 * we are touching the de-allocated non-expanded stack.
747 *
748 * Thus we need a way to update our EBP before EBP is touched, and the only
749 * way to guarantee this is to do the call itself in assembly, use the EAX
750 * register to store the result, fixup EBP, and then let the C code continue
751 * on its merry way.
752 *
753 */
754 __asm__ __volatile__
755 (
756 "movl %%ebp, %1\n\t"
757 "subl %%esp, %1\n\t"
758 "call _PsConvertToGuiThread@0\n\t"
759 "addl %%esp, %1\n\t"
760 "movl %1, %%ebp"
761 : "=a"(Result), "=r"(StackFrame)
762 :
763 : "%esp", "%ecx", "%edx", "memory"
764 );
765 return Result;
766 }
767 #elif defined(_MSC_VER)
768 NTSTATUS
769 NTAPI
770 KiConvertToGuiThread(VOID);
771 #else
772 #error Unknown Compiler
773 #endif
774
775 //
776 // Switches from boot loader to initial kernel stack
777 //
778 VOID
779 FORCEINLINE
780 KiSwitchToBootStack(IN ULONG_PTR InitialStack)
781 {
782 /* We have to switch to a new stack before continuing kernel initialization */
783 #ifdef __GNUC__
784 __asm__
785 (
786 "movl %0, %%esp\n"
787 "subl %1, %%esp\n"
788 "pushl %2\n"
789 "jmp _KiSystemStartupBootStack@0\n"
790 :
791 : "c"(InitialStack),
792 "i"(NPX_FRAME_LENGTH + KTRAP_FRAME_ALIGN + KTRAP_FRAME_LENGTH),
793 "i"(CR0_EM | CR0_TS | CR0_MP)
794 : "%esp"
795 );
796 #elif defined(_MSC_VER)
797 VOID NTAPI KiSystemStartupBootStack(VOID);
798 __asm
799 {
800 mov esp, InitialStack
801 sub esp, (NPX_FRAME_LENGTH + KTRAP_FRAME_ALIGN + KTRAP_FRAME_LENGTH)
802 push (CR0_EM | CR0_TS | CR0_MP)
803 jmp KiSystemStartupBootStack
804 }
805 #else
806 #error Unknown Compiler
807 #endif
808 }
809
810 //
811 // Emits the iret instruction for C code
812 //
813 DECLSPEC_NORETURN
814 VOID
815 FORCEINLINE
816 KiIret(VOID)
817 {
818 #if defined(__GNUC__)
819 __asm__ __volatile__
820 (
821 "iret\n"
822 );
823 #elif defined(_MSC_VER)
824 __asm
825 {
826 iretd
827 }
828 #else
829 #error Unsupported compiler
830 #endif
831 UNREACHABLE;
832 }
833
834 //
835 // Normally this is done by the HAL, but on x86 as an optimization, the kernel
836 // initiates the end by calling back into the HAL and exiting the trap here.
837 //
838 VOID
839 FORCEINLINE
840 KiEndInterrupt(IN KIRQL Irql,
841 IN PKTRAP_FRAME TrapFrame)
842 {
843 /* Disable interrupts and end the interrupt */
844 _disable();
845 HalEndSystemInterrupt(Irql, TrapFrame);
846
847 /* Exit the interrupt */
848 KiEoiHelper(TrapFrame);
849 }
850
851 //
852 // PERF Code
853 //
854 VOID
855 FORCEINLINE
856 Ki386PerfEnd(VOID)
857 {
858 extern ULONGLONG BootCyclesEnd, BootCycles;
859 BootCyclesEnd = __rdtsc();
860 DbgPrint("Boot took %I64u cycles!\n", BootCyclesEnd - BootCycles);
861 DbgPrint("Interrupts: %u System Calls: %u Context Switches: %u\n",
862 KeGetCurrentPrcb()->InterruptCount,
863 KeGetCurrentPrcb()->KeSystemCalls,
864 KeGetContextSwitches(KeGetCurrentPrcb()));
865 }
866
867 FORCEINLINE
868 PULONG
869 KiGetUserModeStackAddress(void)
870 {
871 return &(KeGetCurrentThread()->TrapFrame->HardwareEsp);
872 }
873
874 #endif