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