- KdDebuggerNotPresent should be FALSE by default.
[reactos.git] / reactos / ntoskrnl / ke / i386 / cpu.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/i386/cpu.c
5 * PURPOSE: Routines for CPU-level support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* FIXME: Local EFLAGS defines not used anywhere else */
16 #define EFLAGS_IOPL 0x3000
17 #define EFLAGS_NF 0x4000
18 #define EFLAGS_RF 0x10000
19 #define EFLAGS_ID 0x200000
20
21 /* GLOBALS *******************************************************************/
22
23 /* The Boot TSS */
24 KTSS KiBootTss;
25
26 /* The TSS to use for Double Fault Traps (INT 0x9) */
27 UCHAR KiDoubleFaultTSS[KTSS_IO_MAPS];
28
29 /* The TSS to use for NMI Fault Traps (INT 0x2) */
30 UCHAR KiNMITSS[KTSS_IO_MAPS];
31
32 /* The Boot GDT */
33 KGDTENTRY KiBootGdt[256] =
34 {
35 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_NULL */
36 {0xffff, 0x0000, {{0x00, 0x9b, 0xcf, 0x00}}}, /* KGDT_R0_CODE */
37 {0xffff, 0x0000, {{0x00, 0x93, 0xcf, 0x00}}}, /* KGDT_R0_DATA */
38 {0xffff, 0x0000, {{0x00, 0xfb, 0xcf, 0x00}}}, /* KGDT_R3_CODE */
39 {0xffff, 0x0000, {{0x00, 0xf3, 0xcf, 0x00}}}, /* KGDT_R3_DATA*/
40 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_TSS */
41 {0x0fff, 0x0000, {{0x00, 0x93, 0xc0, 0xff}}}, /* KGDT_R0_PCR */
42 {0x0fff, 0x0000, {{0x00, 0xf3, 0x40, 0x00}}}, /* KGDT_R3_TEB */
43 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_UNUSED */
44 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_LDT */
45 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_DF_TSS */
46 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}} /* KGDT_NMI_TSS */
47 };
48
49 /* GDT Descriptor */
50 KDESCRIPTOR KiGdtDescriptor = {sizeof(KiBootGdt), (ULONG)KiBootGdt};
51
52 /* CPU Features and Flags */
53 ULONG KeI386CpuType;
54 ULONG KeI386CpuStep;
55 ULONG KeProcessorArchitecture;
56 ULONG KeProcessorLevel;
57 ULONG KeProcessorRevision;
58 ULONG KeFeatureBits;
59 ULONG KiFastSystemCallDisable = 1;
60 ULONG KeI386NpxPresent = 0;
61 ULONG KiMXCsrMask = 0;
62 ULONG MxcsrFeatureMask = 0;
63 ULONG KeI386XMMIPresent = 0;
64 ULONG KeI386FxsrPresent = 0;
65 ULONG KeI386MachineType;
66 ULONG Ke386Pae = FALSE;
67 ULONG Ke386NoExecute = FALSE;
68 ULONG KeLargestCacheLine = 0x40;
69 ULONG KeDcacheFlushCount = 0;
70 ULONG KeIcacheFlushCount = 0;
71 ULONG KiDmaIoCoherency = 0;
72 CHAR KeNumberProcessors;
73 KAFFINITY KeActiveProcessors = 1;
74 BOOLEAN KiI386PentiumLockErrataPresent;
75 BOOLEAN KiSMTProcessorsPresent;
76
77 /* Freeze data */
78 KIRQL KiOldIrql;
79 ULONG KiFreezeFlag;
80
81 /* CPU Signatures */
82 static const CHAR CmpIntelID[] = "GenuineIntel";
83 static const CHAR CmpAmdID[] = "AuthenticAMD";
84 static const CHAR CmpCyrixID[] = "CyrixInstead";
85 static const CHAR CmpTransmetaID[] = "GenuineTMx86";
86 static const CHAR CmpCentaurID[] = "CentaurHauls";
87 static const CHAR CmpRiseID[] = "RiseRiseRise";
88
89 /* SUPPORT ROUTINES FOR MSVC COMPATIBILITY ***********************************/
90
91 VOID
92 NTAPI
93 CPUID(OUT ULONG CpuInfo[4],
94 IN ULONG InfoType)
95 {
96 Ki386Cpuid(InfoType, &CpuInfo[0], &CpuInfo[1], &CpuInfo[2], &CpuInfo[3]);
97 }
98
99 VOID
100 WRMSR(IN ULONG Register,
101 IN LONGLONG Value)
102 {
103 LARGE_INTEGER LargeVal;
104 LargeVal.QuadPart = Value;
105 Ke386Wrmsr(Register, LargeVal.HighPart, LargeVal.LowPart);
106 }
107
108 LONGLONG
109 RDMSR(IN ULONG Register)
110 {
111 LARGE_INTEGER LargeVal;
112 Ke386Rdmsr(Register, LargeVal.HighPart, LargeVal.LowPart);
113 return LargeVal.QuadPart;
114 }
115
116 /* FUNCTIONS *****************************************************************/
117
118 VOID
119 NTAPI
120 KiSetProcessorType(VOID)
121 {
122 ULONG EFlags, NewEFlags;
123 ULONG Reg[4];
124 ULONG Stepping, Type;
125
126 /* Start by assuming no CPUID data */
127 KeGetCurrentPrcb()->CpuID = 0;
128
129 /* Save EFlags */
130 Ke386SaveFlags(EFlags);
131
132 /* XOR out the ID bit and update EFlags */
133 NewEFlags = EFlags ^ EFLAGS_ID;
134 Ke386RestoreFlags(NewEFlags);
135
136 /* Get them back and see if they were modified */
137 Ke386SaveFlags(NewEFlags);
138 if (NewEFlags != EFlags)
139 {
140 /* The modification worked, so CPUID exists. Set the ID Bit again. */
141 EFlags |= EFLAGS_ID;
142 Ke386RestoreFlags(EFlags);
143
144 /* Peform CPUID 0 to see if CPUID 1 is supported */
145 CPUID(Reg, 0);
146 if (Reg[0] > 0)
147 {
148 /* Do CPUID 1 now */
149 CPUID(Reg, 1);
150
151 /*
152 * Get the Stepping and Type. The stepping contains both the
153 * Model and the Step, while the Type contains the returned Type.
154 * We ignore the family.
155 *
156 * For the stepping, we convert this: zzzzzzxy into this: x0y
157 */
158 Stepping = Reg[0] & 0xF0;
159 Stepping <<= 4;
160 Stepping += (Reg[0] & 0xFF);
161 Stepping &= 0xF0F;
162 Type = Reg[0] & 0xF00;
163 Type >>= 8;
164
165 /* Save them in the PRCB */
166 KeGetCurrentPrcb()->CpuID = TRUE;
167 KeGetCurrentPrcb()->CpuType = (UCHAR)Type;
168 KeGetCurrentPrcb()->CpuStep = (USHORT)Stepping;
169 }
170 else
171 {
172 DPRINT1("CPUID Support lacking\n");
173 }
174 }
175 else
176 {
177 DPRINT1("CPUID Support lacking\n");
178 }
179
180 /* Restore EFLAGS */
181 Ke386RestoreFlags(EFlags);
182 }
183
184 ULONG
185 NTAPI
186 KiGetCpuVendor(VOID)
187 {
188 PKPRCB Prcb = KeGetCurrentPrcb();
189 ULONG Vendor[5];
190 ULONG Temp;
191
192 /* Assume no Vendor ID and fail if no CPUID Support. */
193 Prcb->VendorString[0] = 0;
194 if (!Prcb->CpuID) return 0;
195
196 /* Get the Vendor ID and null-terminate it */
197 CPUID(Vendor, 0);
198 Vendor[4] = 0;
199
200 /* Re-arrange vendor string */
201 Temp = Vendor[2];
202 Vendor[2] = Vendor[3];
203 Vendor[3] = Temp;
204
205 /* Copy it to the PRCB and null-terminate it again */
206 RtlCopyMemory(Prcb->VendorString,
207 &Vendor[1],
208 sizeof(Prcb->VendorString) - sizeof(CHAR));
209 Prcb->VendorString[sizeof(Prcb->VendorString) - sizeof(CHAR)] = ANSI_NULL;
210
211 /* Now check the CPU Type */
212 if (!strcmp(Prcb->VendorString, CmpIntelID))
213 {
214 return CPU_INTEL;
215 }
216 else if (!strcmp(Prcb->VendorString, CmpAmdID))
217 {
218 return CPU_AMD;
219 }
220 else if (!strcmp(Prcb->VendorString, CmpCyrixID))
221 {
222 DPRINT1("Cyrix CPUs not fully supported\n");
223 return 0;
224 }
225 else if (!strcmp(Prcb->VendorString, CmpTransmetaID))
226 {
227 DPRINT1("Transmeta CPUs not fully supported\n");
228 return 0;
229 }
230 else if (!strcmp(Prcb->VendorString, CmpCentaurID))
231 {
232 DPRINT1("VIA CPUs not fully supported\n");
233 return 0;
234 }
235 else if (!strcmp(Prcb->VendorString, CmpRiseID))
236 {
237 DPRINT1("Rise CPUs not fully supported\n");
238 return 0;
239 }
240
241 /* Invalid CPU */
242 return 0;
243 }
244
245 ULONG
246 NTAPI
247 KiGetFeatureBits(VOID)
248 {
249 PKPRCB Prcb = KeGetCurrentPrcb();
250 ULONG Vendor;
251 ULONG FeatureBits = KF_WORKING_PTE;
252 ULONG Reg[4];
253 BOOLEAN ExtendedCPUID = TRUE;
254 ULONG CpuFeatures = 0;
255
256 /* Get the Vendor ID */
257 Vendor = KiGetCpuVendor();
258
259 /* Make sure we got a valid vendor ID at least. */
260 if (!Vendor) return FeatureBits;
261
262 /* Get the CPUID Info. Features are in Reg[3]. */
263 CPUID(Reg, 1);
264
265 /* Set the initial APIC ID */
266 Prcb->InitialApicId = (UCHAR)(Reg[1] >> 24);
267
268 /* Check for AMD CPU */
269 if (Vendor == CPU_AMD)
270 {
271 /* Check if this is a K5 or higher. */
272 if ((Reg[0] & 0x0F00) >= 0x0500)
273 {
274 /* Check if this is a K5 specifically. */
275 if ((Reg[0] & 0x0F00) == 0x0500)
276 {
277 /* Get the Model Number */
278 switch (Reg[0] & 0x00F0)
279 {
280 /* Check if this is the Model 1 */
281 case 0x0010:
282
283 /* Check if this is Step 0 or 1. They don't support PGE */
284 if ((Reg[0] & 0x000F) > 0x03) break;
285
286 case 0x0000:
287
288 /* Model 0 doesn't support PGE at all. */
289 Reg[3] &= ~0x2000;
290 break;
291
292 case 0x0080:
293
294 /* K6-2, Step 8 and over have support for MTRR. */
295 if ((Reg[0] & 0x000F) >= 0x8) FeatureBits |= KF_AMDK6MTRR;
296 break;
297
298 case 0x0090:
299
300 /* As does the K6-3 */
301 FeatureBits |= KF_AMDK6MTRR;
302 break;
303
304 default:
305 break;
306 }
307 }
308 }
309 else
310 {
311 /* Families below 5 don't support PGE, PSE or CMOV at all */
312 Reg[3] &= ~(0x08 | 0x2000 | 0x8000);
313
314 /* They also don't support advanced CPUID functions. */
315 ExtendedCPUID = FALSE;
316 }
317
318 /* Set the current features */
319 CpuFeatures = Reg[3];
320 }
321
322 /* Now check if this is Intel */
323 if (Vendor == CPU_INTEL)
324 {
325 /* Check if it's a P6 */
326 if (Prcb->CpuType == 6)
327 {
328 /* Perform the special sequence to get the MicroCode Signature */
329 WRMSR(0x8B, 0);
330 CPUID(Reg, 1);
331 Prcb->UpdateSignature.QuadPart = RDMSR(0x8B);
332 }
333 else if (Prcb->CpuType == 5)
334 {
335 /* On P5, enable workaround for the LOCK errata. */
336 KiI386PentiumLockErrataPresent = TRUE;
337 }
338
339 /* Check for broken P6 with bad SMP PTE implementation */
340 if (((Reg[0] & 0x0FF0) == 0x0610 && (Reg[0] & 0x000F) <= 0x9) ||
341 ((Reg[0] & 0x0FF0) == 0x0630 && (Reg[0] & 0x000F) <= 0x4))
342 {
343 /* Remove support for correct PTE support. */
344 FeatureBits &= ~KF_WORKING_PTE;
345 }
346
347 /* Check if the CPU is too old to support SYSENTER */
348 if ((Prcb->CpuType < 6) ||
349 ((Prcb->CpuType == 6) && (Prcb->CpuStep < 0x0303)))
350 {
351 /* Disable it */
352 Reg[3] &= ~0x800;
353 }
354
355 /* Set the current features */
356 CpuFeatures = Reg[3];
357 }
358
359 /* Convert all CPUID Feature bits into our format */
360 if (CpuFeatures & 0x00000002) FeatureBits |= KF_V86_VIS | KF_CR4;
361 if (CpuFeatures & 0x00000008) FeatureBits |= KF_LARGE_PAGE | KF_CR4;
362 if (CpuFeatures & 0x00000010) FeatureBits |= KF_RDTSC;
363 if (CpuFeatures & 0x00000100) FeatureBits |= KF_CMPXCHG8B;
364 if (CpuFeatures & 0x00000800) FeatureBits |= KF_FAST_SYSCALL;
365 if (CpuFeatures & 0x00001000) FeatureBits |= KF_MTRR;
366 if (CpuFeatures & 0x00002000) FeatureBits |= KF_GLOBAL_PAGE | KF_CR4;
367 if (CpuFeatures & 0x00008000) FeatureBits |= KF_CMOV;
368 if (CpuFeatures & 0x00010000) FeatureBits |= KF_PAT;
369 if (CpuFeatures & 0x00200000) FeatureBits |= KF_DTS;
370 if (CpuFeatures & 0x00800000) FeatureBits |= KF_MMX;
371 if (CpuFeatures & 0x01000000) FeatureBits |= KF_FXSR;
372 if (CpuFeatures & 0x02000000) FeatureBits |= KF_XMMI;
373 if (CpuFeatures & 0x04000000) FeatureBits |= KF_XMMI64;
374
375 /* Check if the CPU has hyper-threading */
376 if (CpuFeatures & 0x10000000)
377 {
378 /* Set the number of logical CPUs */
379 Prcb->LogicalProcessorsPerPhysicalProcessor = (UCHAR)(Reg[1] >> 16);
380 if (Prcb->LogicalProcessorsPerPhysicalProcessor > 1)
381 {
382 /* We're on dual-core */
383 KiSMTProcessorsPresent = TRUE;
384 }
385 }
386 else
387 {
388 /* We only have a single CPU */
389 Prcb->LogicalProcessorsPerPhysicalProcessor = 1;
390 }
391
392 /* Check if CPUID 0x80000000 is supported */
393 if (ExtendedCPUID)
394 {
395 /* Do the call */
396 CPUID(Reg, 0x80000000);
397 if ((Reg[0] & 0xffffff00) == 0x80000000)
398 {
399 /* Check if CPUID 0x80000001 is supported */
400 if (Reg[0] >= 0x80000001)
401 {
402 /* Check which extended features are available. */
403 CPUID(Reg, 0x80000001);
404
405 /* Check if NX-bit is supported */
406 if (Reg[3] & 0x00100000) FeatureBits |= KF_NX_BIT;
407
408 /* Now handle each features for each CPU Vendor */
409 switch (Vendor)
410 {
411 case CPU_AMD:
412 if (Reg[3] & 0x80000000) FeatureBits |= KF_3DNOW;
413 break;
414 }
415 }
416 }
417 }
418
419 /* Return the Feature Bits */
420 return FeatureBits;
421 }
422
423 VOID
424 NTAPI
425 KiGetCacheInformation(VOID)
426 {
427 PKIPCR Pcr = (PKIPCR)KeGetPcr();
428 ULONG Vendor;
429 ULONG Data[4];
430 ULONG CacheRequests = 0, i;
431 ULONG CurrentRegister;
432 UCHAR RegisterByte;
433 BOOLEAN FirstPass = TRUE;
434
435 /* Set default L2 size */
436 Pcr->SecondLevelCacheSize = 0;
437
438 /* Get the Vendor ID and make sure we support CPUID */
439 Vendor = KiGetCpuVendor();
440 if (!Vendor) return;
441
442 /* Check the Vendor ID */
443 switch (Vendor)
444 {
445 /* Handle Intel case */
446 case CPU_INTEL:
447
448 /*Check if we support CPUID 2 */
449 CPUID(Data, 0);
450 if (Data[0] >= 2)
451 {
452 /* We need to loop for the number of times CPUID will tell us to */
453 do
454 {
455 /* Do the CPUID call */
456 CPUID(Data, 2);
457
458 /* Check if it was the first call */
459 if (FirstPass)
460 {
461 /*
462 * The number of times to loop is the first byte. Read
463 * it and then destroy it so we don't get confused.
464 */
465 CacheRequests = Data[0] & 0xFF;
466 Data[0] &= 0xFFFFFF00;
467
468 /* Don't go over this again */
469 FirstPass = FALSE;
470 }
471
472 /* Loop all 4 registers */
473 for (i = 0; i < 4; i++)
474 {
475 /* Get the current register */
476 CurrentRegister = Data[i];
477
478 /*
479 * If the upper bit is set, then this register should
480 * be skipped.
481 */
482 if (CurrentRegister & 0x80000000) continue;
483
484 /* Keep looping for every byte inside this register */
485 while (CurrentRegister)
486 {
487 /* Read a byte, skip a byte. */
488 RegisterByte = (UCHAR)(CurrentRegister & 0xFF);
489 CurrentRegister >>= 8;
490 if (!RegisterByte) continue;
491
492 /*
493 * Valid values are from 0x40 (0 bytes) to 0x49
494 * (32MB), or from 0x80 to 0x89 (same size but
495 * 8-way associative.
496 */
497 if (((RegisterByte > 0x40) &&
498 (RegisterByte <= 0x49)) ||
499 ((RegisterByte > 0x80) &&
500 (RegisterByte <= 0x89)))
501 {
502 /* Mask out only the first nibble */
503 RegisterByte &= 0x0F;
504
505 /* Set the L2 Cache Size */
506 Pcr->SecondLevelCacheSize = 0x10000 <<
507 RegisterByte;
508 }
509 }
510 }
511 } while (--CacheRequests);
512 }
513 break;
514
515 case CPU_AMD:
516
517 /* FIXME */
518 DPRINT1("Not handling AMD caches yet\n");
519 break;
520 }
521 }
522
523 VOID
524 NTAPI
525 KiSetCR0Bits(VOID)
526 {
527 ULONG Cr0;
528
529 /* Save current CR0 */
530 Cr0 = __readcr0();
531
532 /* If this is a 486, enable Write-Protection */
533 if (KeGetCurrentPrcb()->CpuType > 3) Cr0 |= CR0_WP;
534
535 /* Set new Cr0 */
536 __writecr0(Cr0);
537 }
538
539 VOID
540 NTAPI
541 KiInitializeTSS2(IN PKTSS Tss,
542 IN PKGDTENTRY TssEntry OPTIONAL)
543 {
544 PUCHAR p;
545
546 /* Make sure the GDT Entry is valid */
547 if (TssEntry)
548 {
549 /* Set the Limit */
550 TssEntry->LimitLow = sizeof(KTSS) - 1;
551 TssEntry->HighWord.Bits.LimitHi = 0;
552 }
553
554 /* Now clear the I/O Map */
555 RtlFillMemory(Tss->IoMaps[0].IoMap, 8096, -1);
556
557 /* Initialize Interrupt Direction Maps */
558 p = (PUCHAR)(Tss->IoMaps[0].DirectionMap);
559 RtlZeroMemory(p, 32);
560
561 /* Add DPMI support for interrupts */
562 p[0] = 4;
563 p[3] = 0x18;
564 p[4] = 0x18;
565
566 /* Initialize the default Interrupt Direction Map */
567 p = Tss->IntDirectionMap;
568 RtlZeroMemory(Tss->IntDirectionMap, 32);
569
570 /* Add DPMI support */
571 p[0] = 4;
572 p[3] = 0x18;
573 p[4] = 0x18;
574 }
575
576 VOID
577 NTAPI
578 KiInitializeTSS(IN PKTSS Tss)
579 {
580 /* Set an invalid map base */
581 Tss->IoMapBase = KiComputeIopmOffset(IO_ACCESS_MAP_NONE);
582
583 /* Disable traps during Task Switches */
584 Tss->Flags = 0;
585
586 /* Set LDT and Ring 0 SS */
587 Tss->LDT = 0;
588 Tss->Ss0 = KGDT_R0_DATA;
589 }
590
591 VOID
592 FASTCALL
593 Ki386InitializeTss(IN PKTSS Tss,
594 IN PKIDTENTRY Idt,
595 IN PKGDTENTRY Gdt)
596 {
597 PKGDTENTRY TssEntry, TaskGateEntry;
598
599 /* Initialize the boot TSS. */
600 TssEntry = &Gdt[KGDT_TSS / sizeof(KGDTENTRY)];
601 TssEntry->HighWord.Bits.Type = I386_TSS;
602 TssEntry->HighWord.Bits.Pres = 1;
603 TssEntry->HighWord.Bits.Dpl = 0;
604 KiInitializeTSS2(Tss, TssEntry);
605 KiInitializeTSS(Tss);
606
607 /* Load the task register */
608 Ke386SetTr(KGDT_TSS);
609
610 /* Setup the Task Gate for Double Fault Traps */
611 TaskGateEntry = (PKGDTENTRY)&Idt[8];
612 TaskGateEntry->HighWord.Bits.Type = I386_TASK_GATE;
613 TaskGateEntry->HighWord.Bits.Pres = 1;
614 TaskGateEntry->HighWord.Bits.Dpl = 0;
615 ((PKIDTENTRY)TaskGateEntry)->Selector = KGDT_DF_TSS;
616
617 /* Initialize the TSS used for handling double faults. */
618 Tss = (PKTSS)KiDoubleFaultTSS;
619 KiInitializeTSS(Tss);
620 Tss->CR3 = __readcr3();
621 Tss->Esp0 = PtrToUlong(KiDoubleFaultStack);
622 Tss->Eip = PtrToUlong(KiTrap8);
623 Tss->Cs = KGDT_R0_CODE;
624 Tss->Fs = KGDT_R0_PCR;
625 Tss->Ss = Ke386GetSs();
626 Tss->Es = KGDT_R3_DATA | RPL_MASK;
627 Tss->Ds = KGDT_R3_DATA | RPL_MASK;
628
629 /* Setup the Double Trap TSS entry in the GDT */
630 TssEntry = &Gdt[KGDT_DF_TSS / sizeof(KGDTENTRY)];
631 TssEntry->HighWord.Bits.Type = I386_TSS;
632 TssEntry->HighWord.Bits.Pres = 1;
633 TssEntry->HighWord.Bits.Dpl = 0;
634 TssEntry->BaseLow = (USHORT)((ULONG_PTR)Tss & 0xFFFF);
635 TssEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Tss >> 16);
636 TssEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Tss >> 24);
637 TssEntry->LimitLow = KTSS_IO_MAPS;
638
639 /* Now setup the NMI Task Gate */
640 TaskGateEntry = (PKGDTENTRY)&Idt[2];
641 TaskGateEntry->HighWord.Bits.Type = I386_TASK_GATE;
642 TaskGateEntry->HighWord.Bits.Pres = 1;
643 TaskGateEntry->HighWord.Bits.Dpl = 0;
644 ((PKIDTENTRY)TaskGateEntry)->Selector = KGDT_NMI_TSS;
645
646 /* Initialize the actual TSS */
647 Tss = (PKTSS)KiNMITSS;
648 KiInitializeTSS(Tss);
649 Tss->CR3 = __readcr3();
650 Tss->Esp0 = PtrToUlong(KiDoubleFaultStack);
651 Tss->Eip = PtrToUlong(KiTrap2);
652 Tss->Cs = KGDT_R0_CODE;
653 Tss->Fs = KGDT_R0_PCR;
654 Tss->Ss = Ke386GetSs();
655 Tss->Es = KGDT_R3_DATA | RPL_MASK;
656 Tss->Ds = KGDT_R3_DATA | RPL_MASK;
657
658 /* And its associated TSS Entry */
659 TssEntry = &Gdt[KGDT_NMI_TSS / sizeof(KGDTENTRY)];
660 TssEntry->HighWord.Bits.Type = I386_TSS;
661 TssEntry->HighWord.Bits.Pres = 1;
662 TssEntry->HighWord.Bits.Dpl = 0;
663 TssEntry->BaseLow = (USHORT)((ULONG_PTR)Tss & 0xFFFF);
664 TssEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Tss >> 16);
665 TssEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Tss >> 24);
666 TssEntry->LimitLow = KTSS_IO_MAPS;
667 }
668
669 VOID
670 NTAPI
671 KeFlushCurrentTb(VOID)
672 {
673 /* Flush the TLB by resetting CR3 */
674 __writecr3((ULONGLONG)__readcr3());
675 }
676
677 VOID
678 NTAPI
679 KiRestoreProcessorControlState(PKPROCESSOR_STATE ProcessorState)
680 {
681 return;
682 /* Restore the CR registers */
683 __writecr0(ProcessorState->SpecialRegisters.Cr0);
684 Ke386SetCr2(ProcessorState->SpecialRegisters.Cr2);
685 __writecr3(ProcessorState->SpecialRegisters.Cr3);
686 if (KeFeatureBits & KF_CR4) __writecr4(ProcessorState->SpecialRegisters.Cr4);
687
688 //
689 // Restore the DR registers
690 //
691 Ke386SetDr0(ProcessorState->SpecialRegisters.KernelDr0);
692 Ke386SetDr1(ProcessorState->SpecialRegisters.KernelDr1);
693 Ke386SetDr2(ProcessorState->SpecialRegisters.KernelDr2);
694 Ke386SetDr3(ProcessorState->SpecialRegisters.KernelDr3);
695 Ke386SetDr6(ProcessorState->SpecialRegisters.KernelDr6);
696 Ke386SetDr7(ProcessorState->SpecialRegisters.KernelDr7);
697
698 //
699 // Restore GDT, IDT, LDT and TSS
700 //
701 Ke386SetGlobalDescriptorTable(ProcessorState->SpecialRegisters.Gdtr);
702 Ke386SetInterruptDescriptorTable(ProcessorState->SpecialRegisters.Idtr);
703 Ke386SetTr(ProcessorState->SpecialRegisters.Tr);
704 Ke386SetLocalDescriptorTable(ProcessorState->SpecialRegisters.Ldtr);
705 }
706
707 VOID
708 NTAPI
709 KiSaveProcessorControlState(OUT PKPROCESSOR_STATE ProcessorState)
710 {
711 /* Save the CR registers */
712 ProcessorState->SpecialRegisters.Cr0 = __readcr0();
713 ProcessorState->SpecialRegisters.Cr2 = __readcr2();
714 ProcessorState->SpecialRegisters.Cr3 = __readcr3();
715 ProcessorState->SpecialRegisters.Cr4 = (KeFeatureBits & KF_CR4) ?
716 __readcr4() : 0;
717
718 /* Save the DR registers */
719 ProcessorState->SpecialRegisters.KernelDr0 = Ke386GetDr0();
720 ProcessorState->SpecialRegisters.KernelDr1 = Ke386GetDr1();
721 ProcessorState->SpecialRegisters.KernelDr2 = Ke386GetDr2();
722 ProcessorState->SpecialRegisters.KernelDr3 = Ke386GetDr3();
723 ProcessorState->SpecialRegisters.KernelDr6 = Ke386GetDr6();
724 ProcessorState->SpecialRegisters.KernelDr7 = Ke386GetDr7();
725 Ke386SetDr7(0);
726
727 /* Save GDT, IDT, LDT and TSS */
728 Ke386GetGlobalDescriptorTable(ProcessorState->SpecialRegisters.Gdtr);
729 Ke386GetInterruptDescriptorTable(ProcessorState->SpecialRegisters.Idtr);
730 Ke386GetTr(ProcessorState->SpecialRegisters.Tr);
731 Ke386GetLocalDescriptorTable(ProcessorState->SpecialRegisters.Ldtr);
732 }
733
734 VOID
735 NTAPI
736 KiInitializeMachineType(VOID)
737 {
738 /* Set the Machine Type we got from NTLDR */
739 KeI386MachineType = KeLoaderBlock->u.I386.MachineType & 0x000FF;
740 }
741
742 ULONG_PTR
743 NTAPI
744 KiLoadFastSyscallMachineSpecificRegisters(IN ULONG_PTR Context)
745 {
746 /* Set CS and ESP */
747 Ke386Wrmsr(0x174, KGDT_R0_CODE, 0);
748 Ke386Wrmsr(0x175, KeGetCurrentPrcb()->DpcStack, 0);
749
750 /* Set LSTAR */
751 Ke386Wrmsr(0x176, KiFastCallEntry, 0);
752 return 0;
753 }
754
755 VOID
756 NTAPI
757 KiRestoreFastSyscallReturnState(VOID)
758 {
759 /* FIXME: NT has support for SYSCALL, IA64-SYSENTER, etc. */
760
761 /* Check if the CPU Supports fast system call */
762 if (KeFeatureBits & KF_FAST_SYSCALL)
763 {
764 /* Do an IPI to enable it */
765 KeIpiGenericCall(KiLoadFastSyscallMachineSpecificRegisters, 0);
766 }
767 }
768
769 ULONG_PTR
770 NTAPI
771 Ki386EnableDE(IN ULONG_PTR Context)
772 {
773 /* Enable DE */
774 __writecr4(__readcr4() | CR4_DE);
775 return 0;
776 }
777
778 ULONG_PTR
779 NTAPI
780 Ki386EnableFxsr(IN ULONG_PTR Context)
781 {
782 /* Enable FXSR */
783 __writecr4(__readcr4() | CR4_FXSR);
784 return 0;
785 }
786
787 ULONG_PTR
788 NTAPI
789 Ki386EnableXMMIExceptions(IN ULONG_PTR Context)
790 {
791 #if 0 // needs kitrap13
792 PKIDTENTRY IdtEntry;
793
794 /* Get the IDT Entry for Interrupt 19 */
795 IdtEntry = ((PKIPCR)KeGetPcr())->IDT[19];
796
797 /* Set it up */
798 IdtEntry->Selector = KGDT_R0_CODE;
799 IdtEntry->Offset = (KiTrap13 & 0xFFFF);
800 IdtEntry->ExtendedOffset = (KiTrap13 >> 16) & 0xFFFF;
801 ((PKIDT_ACCESS)&IdtEntry->Access)->Dpl = 0;
802 ((PKIDT_ACCESS)&IdtEntry->Access)->Present = 1;
803 ((PKIDT_ACCESS)&IdtEntry->Access)->SegmentType = I386_INTERRUPT_GATE;
804 #endif
805
806 /* Enable XMMI exceptions */
807 __writecr4(__readcr4() | CR4_XMMEXCPT);
808 return 0;
809 }
810
811 VOID
812 NTAPI
813 KiI386PentiumLockErrataFixup(VOID)
814 {
815 KDESCRIPTOR IdtDescriptor;
816 PKIDTENTRY NewIdt, NewIdt2;
817
818 /* Allocate memory for a new IDT */
819 NewIdt = ExAllocatePool(NonPagedPool, 2 * PAGE_SIZE);
820
821 /* Put everything after the first 7 entries on a new page */
822 NewIdt2 = (PVOID)((ULONG_PTR)NewIdt + PAGE_SIZE - (7 * sizeof(KIDTENTRY)));
823
824 /* Disable interrupts */
825 _disable();
826
827 /* Get the current IDT and copy it */
828 Ke386GetInterruptDescriptorTable(IdtDescriptor);
829 RtlCopyMemory(NewIdt2,
830 (PVOID)IdtDescriptor.Base,
831 IdtDescriptor.Limit + 1);
832 IdtDescriptor.Base = (ULONG)NewIdt2;
833
834 /* Set the new IDT */
835 Ke386SetInterruptDescriptorTable(IdtDescriptor);
836 ((PKIPCR)KeGetPcr())->IDT = NewIdt2;
837
838 /* Restore interrupts */
839 _enable();
840
841 /* Set the first 7 entries as read-only to produce a fault */
842 MmSetPageProtect(NULL, NewIdt, PAGE_READONLY);
843 }
844
845 BOOLEAN
846 NTAPI
847 KeFreezeExecution(IN PKTRAP_FRAME TrapFrame,
848 IN PKEXCEPTION_FRAME ExceptionFrame)
849 {
850 ULONG Flags;
851
852 /* Disable interrupts and get previous state */
853 Ke386SaveFlags(Flags);
854 //Flags = __getcallerseflags();
855 _disable();
856
857 /* Save freeze flag */
858 KiFreezeFlag = 4;
859
860 /* Save the old IRQL */
861 KiOldIrql = KeGetCurrentIrql();
862
863 /* Return whether interrupts were enabled */
864 return (Flags & EFLAGS_INTERRUPT_MASK) ? TRUE: FALSE;
865 }
866
867 VOID
868 NTAPI
869 KeThawExecution(IN BOOLEAN Enable)
870 {
871 /* Cleanup CPU caches */
872 KeFlushCurrentTb();
873
874 /* Re-enable interrupts */
875 if (Enable) _enable();
876 }
877
878 /* PUBLIC FUNCTIONS **********************************************************/
879
880 /*
881 * @implemented
882 */
883 NTSTATUS
884 NTAPI
885 KeSaveFloatingPointState(OUT PKFLOATING_SAVE Save)
886 {
887 PFNSAVE_FORMAT FpState;
888 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
889 DPRINT1("%s is not really implemented\n", __FUNCTION__);
890
891 /* check if we are doing software emulation */
892 if (!KeI386NpxPresent) return STATUS_ILLEGAL_FLOAT_CONTEXT;
893
894 FpState = ExAllocatePool(NonPagedPool, sizeof (FNSAVE_FORMAT));
895 if (!FpState) return STATUS_INSUFFICIENT_RESOURCES;
896
897 *((PVOID *) Save) = FpState;
898 #ifdef __GNUC__
899 asm volatile("fnsave %0\n\t" : "=m" (*FpState));
900 #else
901 __asm
902 {
903 fnsave [FpState]
904 };
905 #endif
906
907 KeGetCurrentThread()->DispatcherHeader.NpxIrql = KeGetCurrentIrql();
908 return STATUS_SUCCESS;
909 }
910
911 /*
912 * @implemented
913 */
914 NTSTATUS
915 NTAPI
916 KeRestoreFloatingPointState(IN PKFLOATING_SAVE Save)
917 {
918 PFNSAVE_FORMAT FpState = *((PVOID *) Save);
919 ASSERT(KeGetCurrentThread()->DispatcherHeader.NpxIrql == KeGetCurrentIrql());
920 DPRINT1("%s is not really implemented\n", __FUNCTION__);
921
922 #ifdef __GNUC__
923 asm volatile("fnclex\n\t");
924 asm volatile("frstor %0\n\t" : "=m" (*FpState));
925 #else
926 __asm
927 {
928 fnclex
929 frstor [FpState]
930 };
931 #endif
932
933 ExFreePool(FpState);
934 return STATUS_SUCCESS;
935 }
936
937 /*
938 * @implemented
939 */
940 ULONG
941 NTAPI
942 KeGetRecommendedSharedDataAlignment(VOID)
943 {
944 /* Return the global variable */
945 return KeLargestCacheLine;
946 }
947
948 /*
949 * @implemented
950 */
951 VOID
952 NTAPI
953 KeFlushEntireTb(IN BOOLEAN Invalid,
954 IN BOOLEAN AllProcessors)
955 {
956 KIRQL OldIrql;
957
958 /* Raise the IRQL for the TB Flush */
959 OldIrql = KeRaiseIrqlToSynchLevel();
960
961 #ifdef CONFIG_SMP
962 /* FIXME: Support IPI Flush */
963 #error Not yet implemented!
964 #endif
965
966 /* Flush the TB for the Current CPU */
967 KeFlushCurrentTb();
968
969 /* Return to Original IRQL */
970 KeLowerIrql(OldIrql);
971 }
972
973 /*
974 * @implemented
975 */
976 VOID
977 NTAPI
978 KeSetDmaIoCoherency(IN ULONG Coherency)
979 {
980 /* Save the coherency globally */
981 KiDmaIoCoherency = Coherency;
982 }
983
984 /*
985 * @implemented
986 */
987 KAFFINITY
988 NTAPI
989 KeQueryActiveProcessors(VOID)
990 {
991 PAGED_CODE();
992
993 /* Simply return the number of active processors */
994 return KeActiveProcessors;
995 }
996
997 /*
998 * @implemented
999 */
1000 VOID
1001 __cdecl
1002 KeSaveStateForHibernate(IN PKPROCESSOR_STATE State)
1003 {
1004 /* Capture the context */
1005 RtlCaptureContext(&State->ContextFrame);
1006
1007 /* Capture the control state */
1008 KiSaveProcessorControlState(State);
1009 }