52c04c457d9cd0718bd4fc4e6933cee64bcd4b31
[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 extern ULONG Ke386CacheAlignment;
10
11 //
12 // Thread Dispatcher Header DebugActive Mask
13 //
14 #define DR_MASK(x) (1 << (x))
15 #define DR_REG_MASK 0x4F
16
17 #define IMAGE_FILE_MACHINE_ARCHITECTURE IMAGE_FILE_MACHINE_I386
18
19 //
20 // INT3 is 1 byte long
21 //
22 #define KD_BREAKPOINT_TYPE UCHAR
23 #define KD_BREAKPOINT_SIZE sizeof(UCHAR)
24 #define KD_BREAKPOINT_VALUE 0xCC
25
26 //
27 // Macros for getting and setting special purpose registers in portable code
28 //
29 #define KeGetContextPc(Context) \
30 ((Context)->Eip)
31
32 #define KeSetContextPc(Context, ProgramCounter) \
33 ((Context)->Eip = (ProgramCounter))
34
35 #define KeGetTrapFramePc(TrapFrame) \
36 ((TrapFrame)->Eip)
37
38 #define KeGetContextReturnRegister(Context) \
39 ((Context)->Eax)
40
41 #define KeSetContextReturnRegister(Context, ReturnValue) \
42 ((Context)->Eax = (ReturnValue))
43
44 //
45 // Macro to get trap and exception frame from a thread stack
46 //
47 #define KeGetTrapFrame(Thread) \
48 (PKTRAP_FRAME)((ULONG_PTR)((Thread)->InitialStack) - \
49 sizeof(KTRAP_FRAME) - \
50 sizeof(FX_SAVE_AREA))
51
52 #define KeGetExceptionFrame(Thread) \
53 NULL
54
55 //
56 // Macro to get context switches from the PRCB
57 // All architectures but x86 have it in the PRCB's KeContextSwitches
58 //
59 #define KeGetContextSwitches(Prcb) \
60 CONTAINING_RECORD(Prcb, KIPCR, PrcbData)->ContextSwitches
61
62 //
63 // Returns the Interrupt State from a Trap Frame.
64 // ON = TRUE, OFF = FALSE
65 //
66 #define KeGetTrapFrameInterruptState(TrapFrame) \
67 BooleanFlagOn((TrapFrame)->EFlags, EFLAGS_INTERRUPT_MASK)
68
69 //
70 // Flags for exiting a trap
71 //
72 #define KTE_SKIP_PM_BIT (((KTRAP_EXIT_SKIP_BITS) { { .SkipPreviousMode = TRUE } }).Bits)
73 #define KTE_SKIP_SEG_BIT (((KTRAP_EXIT_SKIP_BITS) { { .SkipSegments = TRUE } }).Bits)
74 #define KTE_SKIP_VOL_BIT (((KTRAP_EXIT_SKIP_BITS) { { .SkipVolatiles = TRUE } }).Bits)
75
76 typedef union _KTRAP_EXIT_SKIP_BITS
77 {
78 struct
79 {
80 UCHAR SkipPreviousMode:1;
81 UCHAR SkipSegments:1;
82 UCHAR SkipVolatiles:1;
83 UCHAR Reserved:5;
84 };
85 UCHAR Bits;
86 } KTRAP_EXIT_SKIP_BITS, *PKTRAP_EXIT_SKIP_BITS;
87
88
89 //
90 // Flags used by the VDM/V8086 emulation engine for determining instruction prefixes
91 //
92 #define PFX_FLAG_ES 0x00000100
93 #define PFX_FLAG_CS 0x00000200
94 #define PFX_FLAG_SS 0x00000400
95 #define PFX_FLAG_DS 0x00000800
96 #define PFX_FLAG_FS 0x00001000
97 #define PFX_FLAG_GS 0x00002000
98 #define PFX_FLAG_OPER32 0x00004000
99 #define PFX_FLAG_ADDR32 0x00008000
100 #define PFX_FLAG_LOCK 0x00010000
101 #define PFX_FLAG_REPNE 0x00020000
102 #define PFX_FLAG_REP 0x00040000
103
104 //
105 // VDM Helper Macros
106 //
107 // All VDM/V8086 opcode emulators have the same FASTCALL function definition.
108 // We need to keep 2 parameters while the original ASM implementation uses 4:
109 // TrapFrame, PrefixFlags, Eip, InstructionSize;
110 //
111 // We pass the trap frame, and prefix flags, in our two parameters.
112 //
113 // We then realize that since the smallest prefix flag is 0x100, this gives us
114 // a count of up to 0xFF. So we OR in the instruction size with the prefix flags
115 //
116 // We further realize that we always have access to EIP from the trap frame, and
117 // that if we want the *current instruction* EIP, we simply have to add the
118 // instruction size *MINUS ONE*, and that gives us the EIP we should be looking
119 // at now, so we don't need to use the stack to push this parameter.
120 //
121 // We actually only care about the *current instruction* EIP in one location,
122 // so although it may be slightly more expensive to re-calculate the EIP one
123 // more time, this way we don't redefine ALL opcode handlers to have 3 parameters,
124 // which would be forcing stack usage in all other scenarios.
125 //
126 #define KiVdmSetVdmEFlags(x) InterlockedOr((PLONG)KiNtVdmState, (x));
127 #define KiVdmClearVdmEFlags(x) InterlockedAnd((PLONG)KiNtVdmState, ~(x))
128 #define KiCallVdmHandler(x) KiVdmOpcode##x(TrapFrame, Flags)
129 #define KiCallVdmPrefixHandler(x) KiVdmOpcodePrefix(TrapFrame, Flags | x)
130 #define KiVdmUnhandledOpcode(x) \
131 BOOLEAN \
132 FASTCALL \
133 KiVdmOpcode##x(IN PKTRAP_FRAME TrapFrame, \
134 IN ULONG Flags) \
135 { \
136 /* Not yet handled */ \
137 UNIMPLEMENTED; \
138 while (TRUE); \
139 }
140
141
142 //
143 // Registers an interrupt handler with an IDT vector
144 //
145 FORCEINLINE
146 VOID
147 KeRegisterInterruptHandler(IN ULONG Vector,
148 IN PVOID Handler)
149 {
150 UCHAR Entry;
151 ULONG_PTR Address;
152 PKIPCR Pcr = (PKIPCR)KeGetPcr();
153
154 //
155 // Get the entry from the HAL
156 //
157 Entry = HalVectorToIDTEntry(Vector);
158 Address = PtrToUlong(Handler);
159
160 //
161 // Now set the data
162 //
163 Pcr->IDT[Entry].ExtendedOffset = (USHORT)(Address >> 16);
164 Pcr->IDT[Entry].Offset = (USHORT)Address;
165 }
166
167 //
168 // Returns the registered interrupt handler for a given IDT vector
169 //
170 FORCEINLINE
171 PVOID
172 KeQueryInterruptHandler(IN ULONG Vector)
173 {
174 PKIPCR Pcr = (PKIPCR)KeGetPcr();
175 UCHAR Entry;
176
177 //
178 // Get the entry from the HAL
179 //
180 Entry = HalVectorToIDTEntry(Vector);
181
182 //
183 // Read the entry from the IDT
184 //
185 return (PVOID)(((Pcr->IDT[Entry].ExtendedOffset << 16) & 0xFFFF0000) |
186 (Pcr->IDT[Entry].Offset & 0xFFFF));
187 }
188
189 //
190 // Invalidates the TLB entry for a specified address
191 //
192 FORCEINLINE
193 VOID
194 KeInvalidateTlbEntry(IN PVOID Address)
195 {
196 /* Invalidate the TLB entry for this address */
197 __invlpg(Address);
198 }
199
200 FORCEINLINE
201 VOID
202 KeFlushProcessTb(VOID)
203 {
204 /* Flush the TLB by resetting CR3 */
205 __writecr3(__readcr3());
206 }
207
208 FORCEINLINE
209 PRKTHREAD
210 KeGetCurrentThread(VOID)
211 {
212 /* Return the current thread */
213 return ((PKIPCR)KeGetPcr())->PrcbData.CurrentThread;
214 }
215
216 FORCEINLINE
217 VOID
218 KiRundownThread(IN PKTHREAD Thread)
219 {
220 #ifndef CONFIG_SMP
221 /* Check if this is the NPX Thread */
222 if (KeGetCurrentPrcb()->NpxThread == Thread)
223 {
224 /* Clear it */
225 KeGetCurrentPrcb()->NpxThread = NULL;
226 Ke386FnInit();
227 }
228 #else
229 /* Nothing to do */
230 #endif
231 }
232
233 VOID
234 FASTCALL
235 Ki386InitializeTss(
236 IN PKTSS Tss,
237 IN PKIDTENTRY Idt,
238 IN PKGDTENTRY Gdt
239 );
240
241 VOID
242 NTAPI
243 KiSetCR0Bits(VOID);
244
245 VOID
246 NTAPI
247 KiGetCacheInformation(VOID);
248
249 BOOLEAN
250 NTAPI
251 KiIsNpxPresent(
252 VOID
253 );
254
255 BOOLEAN
256 NTAPI
257 KiIsNpxErrataPresent(
258 VOID
259 );
260
261 VOID
262 NTAPI
263 KiSetProcessorType(VOID);
264
265 ULONG
266 NTAPI
267 KiGetFeatureBits(VOID);
268
269 #ifdef _NTOSKRNL_ /* FIXME: Move flags above to NDK instead of here */
270 VOID
271 NTAPI
272 KiThreadStartup(PKSYSTEM_ROUTINE SystemRoutine,
273 PKSTART_ROUTINE StartRoutine,
274 PVOID StartContext,
275 BOOLEAN UserThread,
276 KTRAP_FRAME TrapFrame);
277 #endif
278
279 NTSTATUS
280 NTAPI
281 Ke386GetGdtEntryThread(
282 IN PKTHREAD Thread,
283 IN ULONG Offset,
284 IN PKGDTENTRY Descriptor
285 );
286
287 VOID
288 NTAPI
289 KiFlushNPXState(
290 IN FLOATING_SAVE_AREA *SaveArea
291 );
292
293 VOID
294 NTAPI
295 Ki386AdjustEsp0(
296 IN PKTRAP_FRAME TrapFrame
297 );
298
299 VOID
300 NTAPI
301 Ki386SetupAndExitToV86Mode(
302 OUT PTEB VdmTeb
303 );
304
305 VOID
306 NTAPI
307 KeI386VdmInitialize(
308 VOID
309 );
310
311 ULONG_PTR
312 NTAPI
313 Ki386EnableGlobalPage(
314 IN volatile ULONG_PTR Context
315 );
316
317 VOID
318 NTAPI
319 KiI386PentiumLockErrataFixup(
320 VOID
321 );
322
323 VOID
324 NTAPI
325 KiInitializePAT(
326 VOID
327 );
328
329 VOID
330 NTAPI
331 KiInitializeMTRR(
332 IN BOOLEAN FinalCpu
333 );
334
335 VOID
336 NTAPI
337 KiAmdK6InitializeMTRR(
338 VOID
339 );
340
341 VOID
342 NTAPI
343 KiRestoreFastSyscallReturnState(
344 VOID
345 );
346
347 ULONG_PTR
348 NTAPI
349 Ki386EnableDE(
350 IN ULONG_PTR Context
351 );
352
353 ULONG_PTR
354 NTAPI
355 Ki386EnableFxsr(
356 IN ULONG_PTR Context
357 );
358
359 ULONG_PTR
360 NTAPI
361 Ki386EnableXMMIExceptions(
362 IN ULONG_PTR Context
363 );
364
365 BOOLEAN
366 NTAPI
367 VdmDispatchBop(
368 IN PKTRAP_FRAME TrapFrame
369 );
370
371 BOOLEAN
372 FASTCALL
373 KiVdmOpcodePrefix(
374 IN PKTRAP_FRAME TrapFrame,
375 IN ULONG Flags
376 );
377
378 BOOLEAN
379 FASTCALL
380 Ki386HandleOpcodeV86(
381 IN PKTRAP_FRAME TrapFrame
382 );
383
384 //
385 // Global x86 only Kernel data
386 //
387 extern PVOID Ki386IopmSaveArea;
388 extern ULONG KeI386EFlagsAndMaskV86;
389 extern ULONG KeI386EFlagsOrMaskV86;
390 extern BOOLEAN KeI386VirtualIntExtensions;
391 extern KIDTENTRY KiIdt[MAXIMUM_IDTVECTOR];
392 extern KDESCRIPTOR KiIdtDescriptor;
393 extern ULONG Ke386GlobalPagesEnabled;
394 extern BOOLEAN KiI386PentiumLockErrataPresent;
395 extern ULONG KeI386NpxPresent;
396 extern ULONG KeI386XMMIPresent;
397 extern ULONG KeI386FxsrPresent;
398 extern ULONG KiMXCsrMask;
399 extern ULONG KeI386CpuType;
400 extern ULONG KeI386CpuStep;
401 extern UCHAR KiDebugRegisterTrapOffsets[9];
402 extern UCHAR KiDebugRegisterContextOffsets[9];
403 extern VOID __cdecl KiTrap2(VOID);
404 extern VOID __cdecl KiTrap8(VOID);
405 extern VOID __cdecl KiTrap19(VOID);
406 extern VOID __cdecl KiFastCallEntry(VOID);
407 extern VOID NTAPI ExpInterlockedPopEntrySListFault(VOID);
408 extern VOID __cdecl CopyParams(VOID);
409 extern VOID __cdecl ReadBatch(VOID);
410 extern VOID __cdecl FrRestore(VOID);
411
412 //
413 // Sanitizes a selector
414 //
415 FORCEINLINE
416 ULONG
417 Ke386SanitizeSeg(IN ULONG Cs,
418 IN KPROCESSOR_MODE Mode)
419 {
420 //
421 // Check if we're in kernel-mode, and force CPL 0 if so.
422 // Otherwise, force CPL 3.
423 //
424 return ((Mode == KernelMode) ?
425 (Cs & (0xFFFF & ~RPL_MASK)) :
426 (RPL_MASK | (Cs & 0xFFFF)));
427 }
428
429 //
430 // Sanitizes EFLAGS
431 //
432 FORCEINLINE
433 ULONG
434 Ke386SanitizeFlags(IN ULONG Eflags,
435 IN KPROCESSOR_MODE Mode)
436 {
437 //
438 // Check if we're in kernel-mode, and sanitize EFLAGS if so.
439 // Otherwise, also force interrupt mask on.
440 //
441 return ((Mode == KernelMode) ?
442 (Eflags & (EFLAGS_USER_SANITIZE | EFLAGS_INTERRUPT_MASK)) :
443 (EFLAGS_INTERRUPT_MASK | (Eflags & EFLAGS_USER_SANITIZE)));
444 }
445
446 //
447 // Gets a DR register from a CONTEXT structure
448 //
449 FORCEINLINE
450 PVOID
451 KiDrFromContext(IN ULONG Dr,
452 IN PCONTEXT Context)
453 {
454 return *(PVOID*)((ULONG_PTR)Context + KiDebugRegisterContextOffsets[Dr]);
455 }
456
457 //
458 // Gets a DR register from a KTRAP_FRAME structure
459 //
460 FORCEINLINE
461 PVOID*
462 KiDrFromTrapFrame(IN ULONG Dr,
463 IN PKTRAP_FRAME TrapFrame)
464 {
465 return (PVOID*)((ULONG_PTR)TrapFrame + KiDebugRegisterTrapOffsets[Dr]);
466 }
467
468 //
469 // Sanitizes a Debug Register
470 //
471 FORCEINLINE
472 PVOID
473 Ke386SanitizeDr(IN PVOID DrAddress,
474 IN KPROCESSOR_MODE Mode)
475 {
476 //
477 // Check if we're in kernel-mode, and return the address directly if so.
478 // Otherwise, make sure it's not inside the kernel-mode address space.
479 // If it is, then clear the address.
480 //
481 return ((Mode == KernelMode) ? DrAddress :
482 (DrAddress <= MM_HIGHEST_USER_ADDRESS) ? DrAddress : 0);
483 }
484
485 #endif
486 #endif /* __NTOSKRNL_INCLUDE_INTERNAL_I386_KE_H */