1f4ee01aaf553e887292589da00bed8caeb5df9c
[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 KeGetContextReturnRegister(Context) \
37 ((Context)->Eax)
38
39 #define KeSetContextReturnRegister(Context, ReturnValue) \
40 ((Context)->Eax = (ReturnValue))
41
42 //
43 // Macro to get trap and exception frame from a thread stack
44 //
45 #define KeGetTrapFrame(Thread) \
46 (PKTRAP_FRAME)((ULONG_PTR)((Thread)->InitialStack) - \
47 sizeof(KTRAP_FRAME) - \
48 sizeof(FX_SAVE_AREA))
49
50 #define KeGetExceptionFrame(Thread) \
51 NULL
52
53 //
54 // Macro to get context switches from the PRCB
55 // All architectures but x86 have it in the PRCB's KeContextSwitches
56 //
57 #define KeGetContextSwitches(Prcb) \
58 CONTAINING_RECORD(Prcb, KIPCR, PrcbData)->ContextSwitches
59
60 //
61 // Returns the Interrupt State from a Trap Frame.
62 // ON = TRUE, OFF = FALSE
63 //
64 #define KeGetTrapFrameInterruptState(TrapFrame) \
65 BooleanFlagOn((TrapFrame)->EFlags, EFLAGS_INTERRUPT_MASK)
66
67 //
68 // Flags for exiting a trap
69 //
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)
73
74 typedef union _KTRAP_EXIT_SKIP_BITS
75 {
76 struct
77 {
78 UCHAR SkipPreviousMode:1;
79 UCHAR SkipSegments:1;
80 UCHAR SkipVolatiles:1;
81 UCHAR Reserved:5;
82 };
83 UCHAR Bits;
84 } KTRAP_EXIT_SKIP_BITS, *PKTRAP_EXIT_SKIP_BITS;
85
86
87 //
88 // Flags used by the VDM/V8086 emulation engine for determining instruction prefixes
89 //
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
101
102 //
103 // VDM Helper Macros
104 //
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;
108 //
109 // We pass the trap frame, and prefix flags, in our two parameters.
110 //
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
113 //
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.
118 //
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.
123 //
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) \
129 BOOLEAN \
130 FASTCALL \
131 KiVdmOpcode##x(IN PKTRAP_FRAME TrapFrame, \
132 IN ULONG Flags) \
133 { \
134 /* Not yet handled */ \
135 UNIMPLEMENTED; \
136 while (TRUE); \
137 return TRUE; \
138 }
139
140 C_ASSERT(NPX_FRAME_LENGTH == sizeof(FX_SAVE_AREA));
141
142 //
143 // Local parameters
144 //
145 typedef struct _KV86_FRAME
146 {
147 PVOID ThreadStack;
148 PVOID ThreadTeb;
149 PVOID PcrTeb;
150 } KV86_FRAME, *PKV86_FRAME;
151
152 //
153 // Virtual Stack Frame
154 //
155 typedef struct _KV8086_STACK_FRAME
156 {
157 KTRAP_FRAME TrapFrame;
158 FX_SAVE_AREA NpxArea;
159 KV86_FRAME V86Frame;
160 } KV8086_STACK_FRAME, *PKV8086_STACK_FRAME;
161
162 //
163 // Registers an interrupt handler with an IDT vector
164 //
165 FORCEINLINE
166 VOID
167 KeRegisterInterruptHandler(IN ULONG Vector,
168 IN PVOID Handler)
169 {
170 UCHAR Entry;
171 ULONG_PTR Address;
172 PKIPCR Pcr = (PKIPCR)KeGetPcr();
173
174 //
175 // Get the entry from the HAL
176 //
177 Entry = HalVectorToIDTEntry(Vector);
178 Address = PtrToUlong(Handler);
179
180 //
181 // Now set the data
182 //
183 Pcr->IDT[Entry].ExtendedOffset = (USHORT)(Address >> 16);
184 Pcr->IDT[Entry].Offset = (USHORT)Address;
185 }
186
187 //
188 // Returns the registered interrupt handler for a given IDT vector
189 //
190 FORCEINLINE
191 PVOID
192 KeQueryInterruptHandler(IN ULONG Vector)
193 {
194 PKIPCR Pcr = (PKIPCR)KeGetPcr();
195 UCHAR Entry;
196
197 //
198 // Get the entry from the HAL
199 //
200 Entry = HalVectorToIDTEntry(Vector);
201
202 //
203 // Read the entry from the IDT
204 //
205 return (PVOID)(((Pcr->IDT[Entry].ExtendedOffset << 16) & 0xFFFF0000) |
206 (Pcr->IDT[Entry].Offset & 0xFFFF));
207 }
208
209 //
210 // Invalidates the TLB entry for a specified address
211 //
212 FORCEINLINE
213 VOID
214 KeInvalidateTlbEntry(IN PVOID Address)
215 {
216 /* Invalidate the TLB entry for this address */
217 __invlpg(Address);
218 }
219
220 FORCEINLINE
221 VOID
222 KeFlushProcessTb(VOID)
223 {
224 /* Flush the TLB by resetting CR3 */
225 __writecr3(__readcr3());
226 }
227
228 FORCEINLINE
229 PRKTHREAD
230 KeGetCurrentThread(VOID)
231 {
232 /* Return the current thread */
233 return ((PKIPCR)KeGetPcr())->PrcbData.CurrentThread;
234 }
235
236 FORCEINLINE
237 VOID
238 KiRundownThread(IN PKTHREAD Thread)
239 {
240 #ifndef CONFIG_SMP
241 /* Check if this is the NPX Thread */
242 if (KeGetCurrentPrcb()->NpxThread == Thread)
243 {
244 /* Clear it */
245 KeGetCurrentPrcb()->NpxThread = NULL;
246 Ke386FnInit();
247 }
248 #else
249 /* Nothing to do */
250 #endif
251 }
252
253 VOID
254 FASTCALL
255 Ki386InitializeTss(
256 IN PKTSS Tss,
257 IN PKIDTENTRY Idt,
258 IN PKGDTENTRY Gdt
259 );
260
261 VOID
262 NTAPI
263 KiSetCR0Bits(VOID);
264
265 VOID
266 NTAPI
267 KiGetCacheInformation(VOID);
268
269 BOOLEAN
270 NTAPI
271 KiIsNpxPresent(
272 VOID
273 );
274
275 BOOLEAN
276 NTAPI
277 KiIsNpxErrataPresent(
278 VOID
279 );
280
281 VOID
282 NTAPI
283 KiSetProcessorType(VOID);
284
285 ULONG
286 NTAPI
287 KiGetFeatureBits(VOID);
288
289 VOID
290 NTAPI
291 KiThreadStartup(VOID);
292
293 NTSTATUS
294 NTAPI
295 Ke386GetGdtEntryThread(
296 IN PKTHREAD Thread,
297 IN ULONG Offset,
298 IN PKGDTENTRY Descriptor
299 );
300
301 VOID
302 NTAPI
303 KiFlushNPXState(
304 IN FLOATING_SAVE_AREA *SaveArea
305 );
306
307 VOID
308 NTAPI
309 Ki386AdjustEsp0(
310 IN PKTRAP_FRAME TrapFrame
311 );
312
313 VOID
314 NTAPI
315 Ki386SetupAndExitToV86Mode(
316 OUT PTEB VdmTeb
317 );
318
319 VOID
320 NTAPI
321 KeI386VdmInitialize(
322 VOID
323 );
324
325 ULONG_PTR
326 NTAPI
327 Ki386EnableGlobalPage(
328 IN volatile ULONG_PTR Context
329 );
330
331 VOID
332 NTAPI
333 KiI386PentiumLockErrataFixup(
334 VOID
335 );
336
337 VOID
338 NTAPI
339 KiInitializePAT(
340 VOID
341 );
342
343 VOID
344 NTAPI
345 KiInitializeMTRR(
346 IN BOOLEAN FinalCpu
347 );
348
349 VOID
350 NTAPI
351 KiAmdK6InitializeMTRR(
352 VOID
353 );
354
355 VOID
356 NTAPI
357 KiRestoreFastSyscallReturnState(
358 VOID
359 );
360
361 ULONG_PTR
362 NTAPI
363 Ki386EnableDE(
364 IN ULONG_PTR Context
365 );
366
367 ULONG_PTR
368 NTAPI
369 Ki386EnableFxsr(
370 IN ULONG_PTR Context
371 );
372
373 ULONG_PTR
374 NTAPI
375 Ki386EnableXMMIExceptions(
376 IN ULONG_PTR Context
377 );
378
379 BOOLEAN
380 NTAPI
381 VdmDispatchBop(
382 IN PKTRAP_FRAME TrapFrame
383 );
384
385 BOOLEAN
386 FASTCALL
387 KiVdmOpcodePrefix(
388 IN PKTRAP_FRAME TrapFrame,
389 IN ULONG Flags
390 );
391
392 BOOLEAN
393 FASTCALL
394 Ki386HandleOpcodeV86(
395 IN PKTRAP_FRAME TrapFrame
396 );
397
398 VOID
399 FASTCALL
400 DECLSPEC_NORETURN
401 KiEoiHelper(
402 IN PKTRAP_FRAME TrapFrame
403 );
404
405 VOID
406 FASTCALL
407 Ki386BiosCallReturnAddress(
408 IN PKTRAP_FRAME TrapFrame
409 );
410
411 ULONG_PTR
412 FASTCALL
413 KiExitV86Mode(
414 IN PKTRAP_FRAME TrapFrame
415 );
416
417 VOID
418 NTAPI
419 DECLSPEC_NORETURN
420 KiDispatchExceptionFromTrapFrame(
421 IN NTSTATUS Code,
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
428 );
429
430 //
431 // Global x86 only Kernel data
432 //
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[];
462
463 //
464 // Trap Macros
465 //
466 #include "../trap_x.h"
467
468 //
469 // Returns a thread's FPU save area
470 //
471 PFX_SAVE_AREA
472 FORCEINLINE
473 KiGetThreadNpxArea(IN PKTHREAD Thread)
474 {
475 return (PFX_SAVE_AREA)((ULONG_PTR)Thread->InitialStack - sizeof(FX_SAVE_AREA));
476 }
477
478 //
479 // Sanitizes a selector
480 //
481 FORCEINLINE
482 ULONG
483 Ke386SanitizeSeg(IN ULONG Cs,
484 IN KPROCESSOR_MODE Mode)
485 {
486 //
487 // Check if we're in kernel-mode, and force CPL 0 if so.
488 // Otherwise, force CPL 3.
489 //
490 return ((Mode == KernelMode) ?
491 (Cs & (0xFFFF & ~RPL_MASK)) :
492 (RPL_MASK | (Cs & 0xFFFF)));
493 }
494
495 //
496 // Sanitizes EFLAGS
497 //
498 FORCEINLINE
499 ULONG
500 Ke386SanitizeFlags(IN ULONG Eflags,
501 IN KPROCESSOR_MODE Mode)
502 {
503 //
504 // Check if we're in kernel-mode, and sanitize EFLAGS if so.
505 // Otherwise, also force interrupt mask on.
506 //
507 return ((Mode == KernelMode) ?
508 (Eflags & (EFLAGS_USER_SANITIZE | EFLAGS_INTERRUPT_MASK)) :
509 (EFLAGS_INTERRUPT_MASK | (Eflags & EFLAGS_USER_SANITIZE)));
510 }
511
512 //
513 // Gets a DR register from a CONTEXT structure
514 //
515 FORCEINLINE
516 PVOID
517 KiDrFromContext(IN ULONG Dr,
518 IN PCONTEXT Context)
519 {
520 return *(PVOID*)((ULONG_PTR)Context + KiDebugRegisterContextOffsets[Dr]);
521 }
522
523 //
524 // Gets a DR register from a KTRAP_FRAME structure
525 //
526 FORCEINLINE
527 PVOID*
528 KiDrFromTrapFrame(IN ULONG Dr,
529 IN PKTRAP_FRAME TrapFrame)
530 {
531 return (PVOID*)((ULONG_PTR)TrapFrame + KiDebugRegisterTrapOffsets[Dr]);
532 }
533
534 //
535 // Sanitizes a Debug Register
536 //
537 FORCEINLINE
538 PVOID
539 Ke386SanitizeDr(IN PVOID DrAddress,
540 IN KPROCESSOR_MODE Mode)
541 {
542 //
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.
546 //
547 return ((Mode == KernelMode) ? DrAddress :
548 (DrAddress <= MM_HIGHEST_USER_ADDRESS) ? DrAddress : 0);
549 }
550
551 //
552 // Exception with no arguments
553 //
554 VOID
555 FORCEINLINE
556 DECLSPEC_NORETURN
557 KiDispatchException0Args(IN NTSTATUS Code,
558 IN ULONG_PTR Address,
559 IN PKTRAP_FRAME TrapFrame)
560 {
561 /* Helper for exceptions with no arguments */
562 KiDispatchExceptionFromTrapFrame(Code, Address, 0, 0, 0, 0, TrapFrame);
563 }
564
565 //
566 // Exception with one argument
567 //
568 VOID
569 FORCEINLINE
570 DECLSPEC_NORETURN
571 KiDispatchException1Args(IN NTSTATUS Code,
572 IN ULONG_PTR Address,
573 IN ULONG P1,
574 IN PKTRAP_FRAME TrapFrame)
575 {
576 /* Helper for exceptions with no arguments */
577 KiDispatchExceptionFromTrapFrame(Code, Address, 1, P1, 0, 0, TrapFrame);
578 }
579
580 //
581 // Exception with two arguments
582 //
583 VOID
584 FORCEINLINE
585 DECLSPEC_NORETURN
586 KiDispatchException2Args(IN NTSTATUS Code,
587 IN ULONG_PTR Address,
588 IN ULONG P1,
589 IN ULONG P2,
590 IN PKTRAP_FRAME TrapFrame)
591 {
592 /* Helper for exceptions with no arguments */
593 KiDispatchExceptionFromTrapFrame(Code, Address, 2, P1, P2, 0, TrapFrame);
594 }
595
596 //
597 // Performs a system call
598 //
599 NTSTATUS
600 FORCEINLINE
601 KiSystemCallTrampoline(IN PVOID Handler,
602 IN PVOID Arguments,
603 IN ULONG StackBytes)
604 {
605 NTSTATUS Result;
606
607 /*
608 * This sequence does a RtlCopyMemory(Stack - StackBytes, Arguments, StackBytes)
609 * and then calls the function associated with the system call.
610 *
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.
617 *
618 * The ARM kernel currently does this, but it should probably be changed
619 * later to function like this as well.
620 *
621 */
622 __asm__ __volatile__
623 (
624 "subl %1, %%esp\n"
625 "movl %%esp, %%edi\n"
626 "movl %2, %%esi\n"
627 "shrl $2, %1\n"
628 "rep movsd\n"
629 "call *%3\n"
630 "movl %%eax, %0\n"
631 : "=r"(Result)
632 : "c"(StackBytes),
633 "d"(Arguments),
634 "r"(Handler)
635 : "%esp", "%esi", "%edi"
636 );
637
638 return Result;
639 }
640
641 //
642 // Checks for pending APCs
643 //
644 VOID
645 FORCEINLINE
646 KiCheckForApcDelivery(IN PKTRAP_FRAME TrapFrame)
647 {
648 PKTHREAD Thread;
649 KIRQL OldIrql;
650
651 /* Check for V8086 or user-mode trap */
652 if ((TrapFrame->EFlags & EFLAGS_V86_MASK) || (KiUserTrap(TrapFrame)))
653 {
654 /* Get the thread */
655 Thread = KeGetCurrentThread();
656 while (TRUE)
657 {
658 /* Turn off the alerted state for kernel mode */
659 Thread->Alerted[KernelMode] = FALSE;
660
661 /* Are there pending user APCs? */
662 if (!Thread->ApcState.UserApcPending) break;
663
664 /* Raise to APC level and enable interrupts */
665 OldIrql = KfRaiseIrql(APC_LEVEL);
666 _enable();
667
668 /* Deliver APCs */
669 KiDeliverApc(UserMode, NULL, TrapFrame);
670
671 /* Restore IRQL and disable interrupts once again */
672 KfLowerIrql(OldIrql);
673 _disable();
674 }
675 }
676 }
677
678 //
679 // Converts a base thread to a GUI thread
680 //
681 NTSTATUS
682 FORCEINLINE
683 KiConvertToGuiThread(VOID)
684 {
685 NTSTATUS Result;
686 PVOID StackFrame;
687
688 /*
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.
691 *
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.
697 *
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
701 * on its merry way.
702 *
703 */
704 __asm__ __volatile__
705 (
706 "movl %%ebp, %1\n"
707 "subl %%esp, %1\n"
708 "call _PsConvertToGuiThread@0\n"
709 "addl %%esp, %1\n"
710 "movl %1, %%ebp\n"
711 "movl %%eax, %0\n"
712 : "=r"(Result), "=r"(StackFrame)
713 :
714 : "%esp", "%ecx", "%edx"
715 );
716
717 return Result;
718 }
719
720 //
721 // Switches from boot loader to initial kernel stack
722 //
723 VOID
724 FORCEINLINE
725 KiSwitchToBootStack(IN ULONG_PTR InitialStack)
726 {
727 /* We have to switch to a new stack before continuing kernel initialization */
728 __asm__ __volatile__
729 (
730 "movl %0, %%esp\n"
731 "subl %1, %%esp\n"
732 "pushl %2\n"
733 "jmp _KiSystemStartupBootStack@0\n"
734 :
735 : "c"(InitialStack),
736 "i"(NPX_FRAME_LENGTH + KTRAP_FRAME_ALIGN + KTRAP_FRAME_LENGTH),
737 "i"(CR0_EM | CR0_TS | CR0_MP)
738 : "%esp"
739 );
740 }
741
742 #endif
743 #endif /* __NTOSKRNL_INCLUDE_INTERNAL_I386_KE_H */