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