1 #ifndef __NTOSKRNL_INCLUDE_INTERNAL_I386_KE_H
2 #define __NTOSKRNL_INCLUDE_INTERNAL_I386_KE_H
10 // Thread Dispatcher Header DebugActive Mask
12 #define DR_MASK(x) (1 << (x))
13 #define DR_REG_MASK 0x4F
15 #define IMAGE_FILE_MACHINE_ARCHITECTURE IMAGE_FILE_MACHINE_I386
18 // INT3 is 1 byte long
20 #define KD_BREAKPOINT_TYPE UCHAR
21 #define KD_BREAKPOINT_SIZE sizeof(UCHAR)
22 #define KD_BREAKPOINT_VALUE 0xCC
25 // Macros for getting and setting special purpose registers in portable code
27 #define KeGetContextPc(Context) \
30 #define KeSetContextPc(Context, ProgramCounter) \
31 ((Context)->Eip = (ProgramCounter))
33 #define KeGetTrapFramePc(TrapFrame) \
36 #define KeGetContextReturnRegister(Context) \
39 #define KeSetContextReturnRegister(Context, ReturnValue) \
40 ((Context)->Eax = (ReturnValue))
43 // Macro to get trap and exception frame from a thread stack
45 #define KeGetTrapFrame(Thread) \
46 (PKTRAP_FRAME)((ULONG_PTR)((Thread)->InitialStack) - \
47 sizeof(KTRAP_FRAME) - \
50 #define KeGetExceptionFrame(Thread) \
54 // Macro to get context switches from the PRCB
55 // All architectures but x86 have it in the PRCB's KeContextSwitches
57 #define KeGetContextSwitches(Prcb) \
58 CONTAINING_RECORD(Prcb, KIPCR, PrcbData)->ContextSwitches
61 // Returns the Interrupt State from a Trap Frame.
62 // ON = TRUE, OFF = FALSE
64 #define KeGetTrapFrameInterruptState(TrapFrame) \
65 BooleanFlagOn((TrapFrame)->EFlags, EFLAGS_INTERRUPT_MASK)
68 // Flags for exiting a trap
70 #define KTE_SKIP_PM_BIT (((KTRAP_EXIT_SKIP_BITS) { { .SkipPreviousMode = TRUE } }).Bits)
71 #define KTE_SKIP_SEG_BIT (((KTRAP_EXIT_SKIP_BITS) { { .SkipSegments = TRUE } }).Bits)
72 #define KTE_SKIP_VOL_BIT (((KTRAP_EXIT_SKIP_BITS) { { .SkipVolatiles = TRUE } }).Bits)
74 typedef union _KTRAP_EXIT_SKIP_BITS
78 UCHAR SkipPreviousMode
:1;
80 UCHAR SkipVolatiles
:1;
84 } KTRAP_EXIT_SKIP_BITS
, *PKTRAP_EXIT_SKIP_BITS
;
88 // Flags used by the VDM/V8086 emulation engine for determining instruction prefixes
90 #define PFX_FLAG_ES 0x00000100
91 #define PFX_FLAG_CS 0x00000200
92 #define PFX_FLAG_SS 0x00000400
93 #define PFX_FLAG_DS 0x00000800
94 #define PFX_FLAG_FS 0x00001000
95 #define PFX_FLAG_GS 0x00002000
96 #define PFX_FLAG_OPER32 0x00004000
97 #define PFX_FLAG_ADDR32 0x00008000
98 #define PFX_FLAG_LOCK 0x00010000
99 #define PFX_FLAG_REPNE 0x00020000
100 #define PFX_FLAG_REP 0x00040000
105 // All VDM/V8086 opcode emulators have the same FASTCALL function definition.
106 // We need to keep 2 parameters while the original ASM implementation uses 4:
107 // TrapFrame, PrefixFlags, Eip, InstructionSize;
109 // We pass the trap frame, and prefix flags, in our two parameters.
111 // We then realize that since the smallest prefix flag is 0x100, this gives us
112 // a count of up to 0xFF. So we OR in the instruction size with the prefix flags
114 // We further realize that we always have access to EIP from the trap frame, and
115 // that if we want the *current instruction* EIP, we simply have to add the
116 // instruction size *MINUS ONE*, and that gives us the EIP we should be looking
117 // at now, so we don't need to use the stack to push this parameter.
119 // We actually only care about the *current instruction* EIP in one location,
120 // so although it may be slightly more expensive to re-calculate the EIP one
121 // more time, this way we don't redefine ALL opcode handlers to have 3 parameters,
122 // which would be forcing stack usage in all other scenarios.
124 #define KiVdmSetVdmEFlags(x) InterlockedOr((PLONG)KiNtVdmState, (x));
125 #define KiVdmClearVdmEFlags(x) InterlockedAnd((PLONG)KiNtVdmState, ~(x))
126 #define KiCallVdmHandler(x) KiVdmOpcode##x(TrapFrame, Flags)
127 #define KiCallVdmPrefixHandler(x) KiVdmOpcodePrefix(TrapFrame, Flags | x)
128 #define KiVdmUnhandledOpcode(x) \
131 KiVdmOpcode##x(IN PKTRAP_FRAME TrapFrame, \
134 /* Not yet handled */ \
140 C_ASSERT(NPX_FRAME_LENGTH
== sizeof(FX_SAVE_AREA
));
145 typedef struct _KV86_FRAME
150 } KV86_FRAME
, *PKV86_FRAME
;
153 // Virtual Stack Frame
155 typedef struct _KV8086_STACK_FRAME
157 KTRAP_FRAME TrapFrame
;
158 FX_SAVE_AREA NpxArea
;
160 } KV8086_STACK_FRAME
, *PKV8086_STACK_FRAME
;
163 // Registers an interrupt handler with an IDT vector
167 KeRegisterInterruptHandler(IN ULONG Vector
,
172 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
175 // Get the entry from the HAL
177 Entry
= HalVectorToIDTEntry(Vector
);
178 Address
= PtrToUlong(Handler
);
183 Pcr
->IDT
[Entry
].ExtendedOffset
= (USHORT
)(Address
>> 16);
184 Pcr
->IDT
[Entry
].Offset
= (USHORT
)Address
;
188 // Returns the registered interrupt handler for a given IDT vector
192 KeQueryInterruptHandler(IN ULONG Vector
)
194 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
198 // Get the entry from the HAL
200 Entry
= HalVectorToIDTEntry(Vector
);
203 // Read the entry from the IDT
205 return (PVOID
)(((Pcr
->IDT
[Entry
].ExtendedOffset
<< 16) & 0xFFFF0000) |
206 (Pcr
->IDT
[Entry
].Offset
& 0xFFFF));
210 // Invalidates the TLB entry for a specified address
214 KeInvalidateTlbEntry(IN PVOID Address
)
216 /* Invalidate the TLB entry for this address */
222 KeFlushProcessTb(VOID
)
224 /* Flush the TLB by resetting CR3 */
225 __writecr3(__readcr3());
230 KeGetCurrentThread(VOID
)
232 /* Return the current thread */
233 return ((PKIPCR
)KeGetPcr())->PrcbData
.CurrentThread
;
238 KiRundownThread(IN PKTHREAD Thread
)
241 /* Check if this is the NPX Thread */
242 if (KeGetCurrentPrcb()->NpxThread
== Thread
)
245 KeGetCurrentPrcb()->NpxThread
= NULL
;
267 KiGetCacheInformation(VOID
);
277 KiIsNpxErrataPresent(
283 KiSetProcessorType(VOID
);
287 KiGetFeatureBits(VOID
);
291 KiThreadStartup(VOID
);
295 Ke386GetGdtEntryThread(
298 IN PKGDTENTRY Descriptor
304 IN FLOATING_SAVE_AREA
*SaveArea
310 IN PKTRAP_FRAME TrapFrame
315 Ki386SetupAndExitToV86Mode(
327 Ki386EnableGlobalPage(
328 IN
volatile ULONG_PTR Context
333 KiI386PentiumLockErrataFixup(
351 KiAmdK6InitializeMTRR(
357 KiRestoreFastSyscallReturnState(
375 Ki386EnableXMMIExceptions(
382 IN PKTRAP_FRAME TrapFrame
388 IN PKTRAP_FRAME TrapFrame
,
394 Ki386HandleOpcodeV86(
395 IN PKTRAP_FRAME TrapFrame
402 IN PKTRAP_FRAME TrapFrame
407 Ki386BiosCallReturnAddress(
408 IN PKTRAP_FRAME TrapFrame
414 IN PKTRAP_FRAME TrapFrame
420 KiDispatchExceptionFromTrapFrame(
422 IN ULONG_PTR Address
,
423 IN ULONG ParameterCount
,
424 IN ULONG_PTR Parameter1
,
425 IN ULONG_PTR Parameter2
,
426 IN ULONG_PTR Parameter3
,
427 IN PKTRAP_FRAME TrapFrame
431 // Global x86 only Kernel data
433 extern PVOID Ki386IopmSaveArea
;
434 extern ULONG KeI386EFlagsAndMaskV86
;
435 extern ULONG KeI386EFlagsOrMaskV86
;
436 extern BOOLEAN KeI386VirtualIntExtensions
;
437 extern KIDTENTRY KiIdt
[MAXIMUM_IDTVECTOR
];
438 extern KDESCRIPTOR KiIdtDescriptor
;
439 extern ULONG Ke386GlobalPagesEnabled
;
440 extern BOOLEAN KiI386PentiumLockErrataPresent
;
441 extern ULONG KeI386NpxPresent
;
442 extern ULONG KeI386XMMIPresent
;
443 extern ULONG KeI386FxsrPresent
;
444 extern ULONG KiMXCsrMask
;
445 extern ULONG KeI386CpuType
;
446 extern ULONG KeI386CpuStep
;
447 extern ULONG Ke386CacheAlignment
;
448 extern ULONG KiFastSystemCallDisable
;
449 extern UCHAR KiDebugRegisterTrapOffsets
[9];
450 extern UCHAR KiDebugRegisterContextOffsets
[9];
451 extern VOID __cdecl
KiTrap02(VOID
);
452 extern VOID __cdecl
KiTrap08(VOID
);
453 extern VOID __cdecl
KiTrap13(VOID
);
454 extern VOID __cdecl
KiFastCallEntry(VOID
);
455 extern VOID NTAPI
ExpInterlockedPopEntrySListFault(VOID
);
456 extern VOID __cdecl
CopyParams(VOID
);
457 extern VOID __cdecl
ReadBatch(VOID
);
458 extern VOID __cdecl
FrRestore(VOID
);
459 extern CHAR KiSystemCallExitBranch
[];
460 extern CHAR KiSystemCallExit
[];
461 extern CHAR KiSystemCallExit2
[];
466 #include "../trap_x.h"
469 // Returns a thread's FPU save area
473 KiGetThreadNpxArea(IN PKTHREAD Thread
)
475 return (PFX_SAVE_AREA
)((ULONG_PTR
)Thread
->InitialStack
- sizeof(FX_SAVE_AREA
));
479 // Sanitizes a selector
483 Ke386SanitizeSeg(IN ULONG Cs
,
484 IN KPROCESSOR_MODE Mode
)
487 // Check if we're in kernel-mode, and force CPL 0 if so.
488 // Otherwise, force CPL 3.
490 return ((Mode
== KernelMode
) ?
491 (Cs
& (0xFFFF & ~RPL_MASK
)) :
492 (RPL_MASK
| (Cs
& 0xFFFF)));
500 Ke386SanitizeFlags(IN ULONG Eflags
,
501 IN KPROCESSOR_MODE Mode
)
504 // Check if we're in kernel-mode, and sanitize EFLAGS if so.
505 // Otherwise, also force interrupt mask on.
507 return ((Mode
== KernelMode
) ?
508 (Eflags
& (EFLAGS_USER_SANITIZE
| EFLAGS_INTERRUPT_MASK
)) :
509 (EFLAGS_INTERRUPT_MASK
| (Eflags
& EFLAGS_USER_SANITIZE
)));
513 // Gets a DR register from a CONTEXT structure
517 KiDrFromContext(IN ULONG Dr
,
520 return *(PVOID
*)((ULONG_PTR
)Context
+ KiDebugRegisterContextOffsets
[Dr
]);
524 // Gets a DR register from a KTRAP_FRAME structure
528 KiDrFromTrapFrame(IN ULONG Dr
,
529 IN PKTRAP_FRAME TrapFrame
)
531 return (PVOID
*)((ULONG_PTR
)TrapFrame
+ KiDebugRegisterTrapOffsets
[Dr
]);
535 // Sanitizes a Debug Register
539 Ke386SanitizeDr(IN PVOID DrAddress
,
540 IN KPROCESSOR_MODE Mode
)
543 // Check if we're in kernel-mode, and return the address directly if so.
544 // Otherwise, make sure it's not inside the kernel-mode address space.
545 // If it is, then clear the address.
547 return ((Mode
== KernelMode
) ? DrAddress
:
548 (DrAddress
<= MM_HIGHEST_USER_ADDRESS
) ? DrAddress
: 0);
552 // Exception with no arguments
557 KiDispatchException0Args(IN NTSTATUS Code
,
558 IN ULONG_PTR Address
,
559 IN PKTRAP_FRAME TrapFrame
)
561 /* Helper for exceptions with no arguments */
562 KiDispatchExceptionFromTrapFrame(Code
, Address
, 0, 0, 0, 0, TrapFrame
);
566 // Exception with one argument
571 KiDispatchException1Args(IN NTSTATUS Code
,
572 IN ULONG_PTR Address
,
574 IN PKTRAP_FRAME TrapFrame
)
576 /* Helper for exceptions with no arguments */
577 KiDispatchExceptionFromTrapFrame(Code
, Address
, 1, P1
, 0, 0, TrapFrame
);
581 // Exception with two arguments
586 KiDispatchException2Args(IN NTSTATUS Code
,
587 IN ULONG_PTR Address
,
590 IN PKTRAP_FRAME TrapFrame
)
592 /* Helper for exceptions with no arguments */
593 KiDispatchExceptionFromTrapFrame(Code
, Address
, 2, P1
, P2
, 0, TrapFrame
);
597 // Performs a system call
601 KiSystemCallTrampoline(IN PVOID Handler
,
608 * This sequence does a RtlCopyMemory(Stack - StackBytes, Arguments, StackBytes)
609 * and then calls the function associated with the system call.
611 * It's done in assembly for two reasons: we need to muck with the stack,
612 * and the call itself restores the stack back for us. The only way to do
613 * this in C is to do manual C handlers for every possible number of args on
614 * the stack, and then have the handler issue a call by pointer. This is
615 * wasteful since it'll basically push the values twice and require another
616 * level of call indirection.
618 * The ARM kernel currently does this, but it should probably be changed
619 * later to function like this as well.
625 "movl %%esp, %%edi\n"
635 : "%esp", "%esi", "%edi"
642 // Checks for pending APCs
646 KiCheckForApcDelivery(IN PKTRAP_FRAME TrapFrame
)
651 /* Check for V8086 or user-mode trap */
652 if ((TrapFrame
->EFlags
& EFLAGS_V86_MASK
) || (KiUserTrap(TrapFrame
)))
655 Thread
= KeGetCurrentThread();
658 /* Turn off the alerted state for kernel mode */
659 Thread
->Alerted
[KernelMode
] = FALSE
;
661 /* Are there pending user APCs? */
662 if (!Thread
->ApcState
.UserApcPending
) break;
664 /* Raise to APC level and enable interrupts */
665 OldIrql
= KfRaiseIrql(APC_LEVEL
);
669 KiDeliverApc(UserMode
, NULL
, TrapFrame
);
671 /* Restore IRQL and disable interrupts once again */
672 KfLowerIrql(OldIrql
);
679 // Converts a base thread to a GUI thread
683 KiConvertToGuiThread(VOID
)
689 * Converting to a GUI thread safely updates ESP in-place as well as the
690 * current Thread->TrapFrame and EBP when KeSwitchKernelStack is called.
692 * However, PsConvertToGuiThread "helpfully" restores EBP to the original
693 * caller's value, since it is considered a nonvolatile register. As such,
694 * as soon as we're back after the conversion and we try to store the result
695 * which will probably be in some stack variable (EBP-based), we'll crash as
696 * we are touching the de-allocated non-expanded stack.
698 * Thus we need a way to update our EBP before EBP is touched, and the only
699 * way to guarantee this is to do the call itself in assembly, use the EAX
700 * register to store the result, fixup EBP, and then let the C code continue
708 "call _PsConvertToGuiThread@0\n"
712 : "=r"(Result
), "=r"(StackFrame
)
714 : "%esp", "%ecx", "%edx"
721 // Switches from boot loader to initial kernel stack
725 KiSwitchToBootStack(IN ULONG_PTR InitialStack
)
727 /* We have to switch to a new stack before continuing kernel initialization */
733 "jmp _KiSystemStartupBootStack@0\n"
736 "i"(NPX_FRAME_LENGTH
+ KTRAP_FRAME_ALIGN
+ KTRAP_FRAME_LENGTH
),
737 "i"(CR0_EM
| CR0_TS
| CR0_MP
)
743 #endif /* __NTOSKRNL_INCLUDE_INTERNAL_I386_KE_H */