* Sync to trunk HEAD (r53473).
[reactos.git] / ntoskrnl / ke / amd64 / cpu.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/amd64/cpu.c
5 * PURPOSE: Routines for CPU-level support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Timo Kreuzer (timo.kreuzer@reactos.org)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* FIXME: Local EFLAGS defines not used anywhere else */
17 #define EFLAGS_IOPL 0x3000
18 #define EFLAGS_NF 0x4000
19 #define EFLAGS_RF 0x10000
20 #define EFLAGS_ID 0x200000
21
22 /* GLOBALS *******************************************************************/
23
24 /* The Boot TSS */
25 KTSS64 KiBootTss;
26
27 /* CPU Features and Flags */
28 ULONG KeI386CpuType;
29 ULONG KeI386CpuStep;
30 ULONG KeProcessorArchitecture;
31 ULONG KeProcessorLevel;
32 ULONG KeProcessorRevision;
33 ULONG KeFeatureBits;
34 ULONG KeI386MachineType;
35 ULONG KeI386NpxPresent = 1;
36 ULONG KeLargestCacheLine = 0x40;
37 ULONG KiDmaIoCoherency = 0;
38 CHAR KeNumberProcessors = 0;
39 KAFFINITY KeActiveProcessors = 1;
40 BOOLEAN KiSMTProcessorsPresent;
41
42 /* Freeze data */
43 KIRQL KiOldIrql;
44 ULONG KiFreezeFlag;
45
46 /* Flush data */
47 volatile LONG KiTbFlushTimeStamp;
48
49 /* CPU Signatures */
50 static const CHAR CmpIntelID[] = "GenuineIntel";
51 static const CHAR CmpAmdID[] = "AuthenticAMD";
52 static const CHAR CmpCyrixID[] = "CyrixInstead";
53 static const CHAR CmpTransmetaID[] = "GenuineTMx86";
54 static const CHAR CmpCentaurID[] = "CentaurHauls";
55 static const CHAR CmpRiseID[] = "RiseRiseRise";
56
57 /* SUPPORT ROUTINES FOR MSVC COMPATIBILITY ***********************************/
58
59 VOID
60 NTAPI
61 CPUID(IN ULONG InfoType,
62 OUT PULONG CpuInfoEax,
63 OUT PULONG CpuInfoEbx,
64 OUT PULONG CpuInfoEcx,
65 OUT PULONG CpuInfoEdx)
66 {
67 ULONG CpuInfo[4];
68
69 /* Perform the CPUID Operation */
70 __cpuid((int*)CpuInfo, InfoType);
71
72 /* Return the results */
73 *CpuInfoEax = CpuInfo[0];
74 *CpuInfoEbx = CpuInfo[1];
75 *CpuInfoEcx = CpuInfo[2];
76 *CpuInfoEdx = CpuInfo[3];
77 }
78
79 /* FUNCTIONS *****************************************************************/
80
81 VOID
82 NTAPI
83 KiSetProcessorType(VOID)
84 {
85 ULONG64 EFlags;
86 INT Reg[4];
87 ULONG Stepping, Type;
88
89 /* Start by assuming no CPUID data */
90 KeGetCurrentPrcb()->CpuID = 0;
91
92 /* Save EFlags */
93 EFlags = __readeflags();
94
95 /* Do CPUID 1 now */
96 __cpuid(Reg, 1);
97
98 /*
99 * Get the Stepping and Type. The stepping contains both the
100 * Model and the Step, while the Type contains the returned Type.
101 * We ignore the family.
102 *
103 * For the stepping, we convert this: zzzzzzxy into this: x0y
104 */
105 Stepping = Reg[0] & 0xF0;
106 Stepping <<= 4;
107 Stepping += (Reg[0] & 0xFF);
108 Stepping &= 0xF0F;
109 Type = Reg[0] & 0xF00;
110 Type >>= 8;
111
112 /* Save them in the PRCB */
113 KeGetCurrentPrcb()->CpuID = TRUE;
114 KeGetCurrentPrcb()->CpuType = (UCHAR)Type;
115 KeGetCurrentPrcb()->CpuStep = (USHORT)Stepping;
116
117 /* Restore EFLAGS */
118 __writeeflags(EFlags);
119 }
120
121 ULONG
122 NTAPI
123 KiGetCpuVendor(VOID)
124 {
125 PKPRCB Prcb = KeGetCurrentPrcb();
126 INT Vendor[5];
127
128 /* Get the Vendor ID and null-terminate it */
129 __cpuid(Vendor, 0);
130
131 /* Copy it to the PRCB and null-terminate it */
132 *(ULONG*)&Prcb->VendorString[0] = Vendor[1]; // ebx
133 *(ULONG*)&Prcb->VendorString[4] = Vendor[3]; // edx
134 *(ULONG*)&Prcb->VendorString[8] = Vendor[2]; // ecx
135 *(ULONG*)&Prcb->VendorString[12] = 0;
136
137 /* Now check the CPU Type */
138 if (!strcmp((PCHAR)Prcb->VendorString, CmpIntelID))
139 {
140 return CPU_INTEL;
141 }
142 else if (!strcmp((PCHAR)Prcb->VendorString, CmpAmdID))
143 {
144 return CPU_AMD;
145 }
146 else if (!strcmp((PCHAR)Prcb->VendorString, CmpCyrixID))
147 {
148 DPRINT1("Cyrix CPUs not fully supported\n");
149 return 0;
150 }
151 else if (!strcmp((PCHAR)Prcb->VendorString, CmpTransmetaID))
152 {
153 DPRINT1("Transmeta CPUs not fully supported\n");
154 return 0;
155 }
156 else if (!strcmp((PCHAR)Prcb->VendorString, CmpCentaurID))
157 {
158 DPRINT1("VIA CPUs not fully supported\n");
159 return 0;
160 }
161 else if (!strcmp((PCHAR)Prcb->VendorString, CmpRiseID))
162 {
163 DPRINT1("Rise CPUs not fully supported\n");
164 return 0;
165 }
166
167 /* Invalid CPU */
168 return 0;
169 }
170
171 ULONG
172 NTAPI
173 KiGetFeatureBits(VOID)
174 {
175 PKPRCB Prcb = KeGetCurrentPrcb();
176 ULONG Vendor;
177 ULONG FeatureBits = KF_WORKING_PTE;
178 INT Reg[4];
179 ULONG CpuFeatures = 0;
180
181 /* Get the Vendor ID */
182 Vendor = KiGetCpuVendor();
183
184 /* Make sure we got a valid vendor ID at least. */
185 if (!Vendor) return FeatureBits;
186
187 /* Get the CPUID Info. Features are in Reg[3]. */
188 __cpuid(Reg, 1);
189
190 /* Set the initial APIC ID */
191 Prcb->InitialApicId = (UCHAR)(Reg[1] >> 24);
192
193 /* Set the current features */
194 CpuFeatures = Reg[3];
195
196 /* Convert all CPUID Feature bits into our format */
197 if (CpuFeatures & 0x00000002) FeatureBits |= KF_V86_VIS | KF_CR4;
198 if (CpuFeatures & 0x00000008) FeatureBits |= KF_LARGE_PAGE | KF_CR4;
199 if (CpuFeatures & 0x00000010) FeatureBits |= KF_RDTSC;
200 if (CpuFeatures & 0x00000100) FeatureBits |= KF_CMPXCHG8B;
201 if (CpuFeatures & 0x00000800) FeatureBits |= KF_FAST_SYSCALL;
202 if (CpuFeatures & 0x00001000) FeatureBits |= KF_MTRR;
203 if (CpuFeatures & 0x00002000) FeatureBits |= KF_GLOBAL_PAGE | KF_CR4;
204 if (CpuFeatures & 0x00008000) FeatureBits |= KF_CMOV;
205 if (CpuFeatures & 0x00010000) FeatureBits |= KF_PAT;
206 if (CpuFeatures & 0x00200000) FeatureBits |= KF_DTS;
207 if (CpuFeatures & 0x00800000) FeatureBits |= KF_MMX;
208 if (CpuFeatures & 0x01000000) FeatureBits |= KF_FXSR;
209 if (CpuFeatures & 0x02000000) FeatureBits |= KF_XMMI;
210 if (CpuFeatures & 0x04000000) FeatureBits |= KF_XMMI64;
211
212 #if 0
213 if (Reg[2] & 0x00000001) FeatureBits |= KF_SSE3NEW;
214 if (Reg[2] & 0x00000008) FeatureBits |= KF_MONITOR;
215 if (Reg[2] & 0x00000200) FeatureBits |= KF_SSE3SUP;
216 if (Reg[2] & 0x00002000) FeatureBits |= KF_CMPXCHG16B;
217 if (Reg[2] & 0x00080000) FeatureBits |= KF_SSE41;
218 if (Reg[2] & 0x00800000) FeatureBits |= KF_POPCNT;
219 #endif
220
221 /* Check if the CPU has hyper-threading */
222 if (CpuFeatures & 0x10000000)
223 {
224 /* Set the number of logical CPUs */
225 Prcb->LogicalProcessorsPerPhysicalProcessor = (UCHAR)(Reg[1] >> 16);
226 if (Prcb->LogicalProcessorsPerPhysicalProcessor > 1)
227 {
228 /* We're on dual-core */
229 KiSMTProcessorsPresent = TRUE;
230 }
231 }
232 else
233 {
234 /* We only have a single CPU */
235 Prcb->LogicalProcessorsPerPhysicalProcessor = 1;
236 }
237
238 /* Check extended cpuid features */
239 __cpuid(Reg, 0x80000000);
240 if ((Reg[0] & 0xffffff00) == 0x80000000)
241 {
242 /* Check if CPUID 0x80000001 is supported */
243 if (Reg[0] >= 0x80000001)
244 {
245 /* Check which extended features are available. */
246 __cpuid(Reg, 0x80000001);
247
248 /* Check if NX-bit is supported */
249 if (Reg[3] & 0x00100000) FeatureBits |= KF_NX_BIT;
250
251 /* Now handle each features for each CPU Vendor */
252 switch (Vendor)
253 {
254 case CPU_AMD:
255 if (Reg[3] & 0x80000000) FeatureBits |= KF_3DNOW;
256 break;
257 }
258 }
259 }
260
261 /* Return the Feature Bits */
262 return FeatureBits;
263 }
264
265 VOID
266 NTAPI
267 KiGetCacheInformation(VOID)
268 {
269 PKIPCR Pcr = (PKIPCR)KeGetPcr();
270 ULONG Vendor;
271 INT Data[4];
272 ULONG CacheRequests = 0, i;
273 ULONG CurrentRegister;
274 UCHAR RegisterByte;
275 BOOLEAN FirstPass = TRUE;
276
277 /* Set default L2 size */
278 Pcr->SecondLevelCacheSize = 0;
279
280 /* Get the Vendor ID and make sure we support CPUID */
281 Vendor = KiGetCpuVendor();
282 if (!Vendor) return;
283
284 /* Check the Vendor ID */
285 switch (Vendor)
286 {
287 /* Handle Intel case */
288 case CPU_INTEL:
289
290 /*Check if we support CPUID 2 */
291 __cpuid(Data, 0);
292 if (Data[0] >= 2)
293 {
294 /* We need to loop for the number of times CPUID will tell us to */
295 do
296 {
297 /* Do the CPUID call */
298 __cpuid(Data, 2);
299
300 /* Check if it was the first call */
301 if (FirstPass)
302 {
303 /*
304 * The number of times to loop is the first byte. Read
305 * it and then destroy it so we don't get confused.
306 */
307 CacheRequests = Data[0] & 0xFF;
308 Data[0] &= 0xFFFFFF00;
309
310 /* Don't go over this again */
311 FirstPass = FALSE;
312 }
313
314 /* Loop all 4 registers */
315 for (i = 0; i < 4; i++)
316 {
317 /* Get the current register */
318 CurrentRegister = Data[i];
319
320 /*
321 * If the upper bit is set, then this register should
322 * be skipped.
323 */
324 if (CurrentRegister & 0x80000000) continue;
325
326 /* Keep looping for every byte inside this register */
327 while (CurrentRegister)
328 {
329 /* Read a byte, skip a byte. */
330 RegisterByte = (UCHAR)(CurrentRegister & 0xFF);
331 CurrentRegister >>= 8;
332 if (!RegisterByte) continue;
333
334 /*
335 * Valid values are from 0x40 (0 bytes) to 0x49
336 * (32MB), or from 0x80 to 0x89 (same size but
337 * 8-way associative.
338 */
339 if (((RegisterByte > 0x40) &&
340 (RegisterByte <= 0x49)) ||
341 ((RegisterByte > 0x80) &&
342 (RegisterByte <= 0x89)))
343 {
344 /* Mask out only the first nibble */
345 RegisterByte &= 0x0F;
346
347 /* Set the L2 Cache Size */
348 Pcr->SecondLevelCacheSize = 0x10000 <<
349 RegisterByte;
350 }
351 }
352 }
353 } while (--CacheRequests);
354 }
355 break;
356
357 case CPU_AMD:
358
359 /* Check if we support CPUID 0x80000006 */
360 __cpuid(Data, 0x80000000);
361 if (Data[0] >= 6)
362 {
363 /* Get 2nd level cache and tlb size */
364 __cpuid(Data, 0x80000006);
365
366 /* Set the L2 Cache Size */
367 Pcr->SecondLevelCacheSize = (Data[2] & 0xFFFF0000) >> 6;
368 }
369 break;
370 }
371 }
372
373 VOID
374 FASTCALL
375 KiInitializeTss(IN PKTSS64 Tss,
376 IN UINT64 Stack)
377 {
378 PKGDTENTRY64 TssEntry;
379
380 /* Get pointer to the GDT entry */
381 TssEntry = KiGetGdtEntry(KeGetPcr()->GdtBase, KGDT64_SYS_TSS);
382
383 /* Initialize the GDT entry */
384 KiInitGdtEntry(TssEntry, (ULONG64)Tss, sizeof(KTSS64), AMD64_TSS, 0);
385
386 /* Zero out the TSS */
387 RtlZeroMemory(Tss, sizeof(KTSS64));
388
389 /* FIXME: I/O Map? */
390 Tss->IoMapBase = 0x68;
391
392 /* Setup ring 0 stack pointer */
393 Tss->Rsp0 = Stack;
394
395 /* Setup a stack for Double Fault Traps */
396 Tss->Ist[1] = (ULONG64)KiDoubleFaultStack;
397
398 /* Setup a stack for CheckAbort Traps */
399 Tss->Ist[2] = (ULONG64)KiDoubleFaultStack;
400
401 /* Setup a stack for NMI Traps */
402 Tss->Ist[3] = (ULONG64)KiDoubleFaultStack;
403
404 /* Load the task register */
405 __ltr(KGDT64_SYS_TSS);
406 }
407
408 VOID
409 NTAPI
410 KeFlushCurrentTb(VOID)
411 {
412 /* Flush the TLB by resetting CR3 */
413 __writecr3(__readcr3());
414 }
415
416 VOID
417 NTAPI
418 KiRestoreProcessorControlState(PKPROCESSOR_STATE ProcessorState)
419 {
420 /* Restore the CR registers */
421 __writecr0(ProcessorState->SpecialRegisters.Cr0);
422 // __writecr2(ProcessorState->SpecialRegisters.Cr2);
423 __writecr3(ProcessorState->SpecialRegisters.Cr3);
424 __writecr4(ProcessorState->SpecialRegisters.Cr4);
425 __writecr8(ProcessorState->SpecialRegisters.Cr8);
426
427 /* Restore the DR registers */
428 __writedr(0, ProcessorState->SpecialRegisters.KernelDr0);
429 __writedr(1, ProcessorState->SpecialRegisters.KernelDr1);
430 __writedr(2, ProcessorState->SpecialRegisters.KernelDr2);
431 __writedr(3, ProcessorState->SpecialRegisters.KernelDr3);
432 __writedr(6, ProcessorState->SpecialRegisters.KernelDr6);
433 __writedr(7, ProcessorState->SpecialRegisters.KernelDr7);
434
435 /* Restore GDT, IDT, LDT and TSS */
436 __lgdt(&ProcessorState->SpecialRegisters.Gdtr.Limit);
437 // __lldt(&ProcessorState->SpecialRegisters.Ldtr);
438 // __ltr(&ProcessorState->SpecialRegisters.Tr);
439 __lidt(&ProcessorState->SpecialRegisters.Idtr.Limit);
440
441 // __ldmxcsr(&ProcessorState->SpecialRegisters.MxCsr); // FIXME
442 // ProcessorState->SpecialRegisters.DebugControl
443 // ProcessorState->SpecialRegisters.LastBranchToRip
444 // ProcessorState->SpecialRegisters.LastBranchFromRip
445 // ProcessorState->SpecialRegisters.LastExceptionToRip
446 // ProcessorState->SpecialRegisters.LastExceptionFromRip
447
448 /* Restore MSRs */
449 __writemsr(X86_MSR_GSBASE, ProcessorState->SpecialRegisters.MsrGsBase);
450 __writemsr(X86_MSR_KERNEL_GSBASE, ProcessorState->SpecialRegisters.MsrGsSwap);
451 __writemsr(X86_MSR_STAR, ProcessorState->SpecialRegisters.MsrStar);
452 __writemsr(X86_MSR_LSTAR, ProcessorState->SpecialRegisters.MsrLStar);
453 __writemsr(X86_MSR_CSTAR, ProcessorState->SpecialRegisters.MsrCStar);
454 __writemsr(X86_MSR_SFMASK, ProcessorState->SpecialRegisters.MsrSyscallMask);
455
456 }
457
458 VOID
459 NTAPI
460 KiSaveProcessorControlState(OUT PKPROCESSOR_STATE ProcessorState)
461 {
462 /* Save the CR registers */
463 ProcessorState->SpecialRegisters.Cr0 = __readcr0();
464 ProcessorState->SpecialRegisters.Cr2 = __readcr2();
465 ProcessorState->SpecialRegisters.Cr3 = __readcr3();
466 ProcessorState->SpecialRegisters.Cr4 = __readcr4();
467 ProcessorState->SpecialRegisters.Cr8 = __readcr8();
468
469 /* Save the DR registers */
470 ProcessorState->SpecialRegisters.KernelDr0 = __readdr(0);
471 ProcessorState->SpecialRegisters.KernelDr1 = __readdr(1);
472 ProcessorState->SpecialRegisters.KernelDr2 = __readdr(2);
473 ProcessorState->SpecialRegisters.KernelDr3 = __readdr(3);
474 ProcessorState->SpecialRegisters.KernelDr6 = __readdr(6);
475 ProcessorState->SpecialRegisters.KernelDr7 = __readdr(7);
476
477 /* Save GDT, IDT, LDT and TSS */
478 __sgdt(&ProcessorState->SpecialRegisters.Gdtr.Limit);
479 __sldt(&ProcessorState->SpecialRegisters.Ldtr);
480 __str(&ProcessorState->SpecialRegisters.Tr);
481 __sidt(&ProcessorState->SpecialRegisters.Idtr.Limit);
482
483 // __stmxcsr(&ProcessorState->SpecialRegisters.MxCsr);
484 // ProcessorState->SpecialRegisters.DebugControl =
485 // ProcessorState->SpecialRegisters.LastBranchToRip =
486 // ProcessorState->SpecialRegisters.LastBranchFromRip =
487 // ProcessorState->SpecialRegisters.LastExceptionToRip =
488 // ProcessorState->SpecialRegisters.LastExceptionFromRip =
489
490 /* Save MSRs */
491 ProcessorState->SpecialRegisters.MsrGsBase = __readmsr(X86_MSR_GSBASE);
492 ProcessorState->SpecialRegisters.MsrGsSwap = __readmsr(X86_MSR_KERNEL_GSBASE);
493 ProcessorState->SpecialRegisters.MsrStar = __readmsr(X86_MSR_STAR);
494 ProcessorState->SpecialRegisters.MsrLStar = __readmsr(X86_MSR_LSTAR);
495 ProcessorState->SpecialRegisters.MsrCStar = __readmsr(X86_MSR_CSTAR);
496 ProcessorState->SpecialRegisters.MsrSyscallMask = __readmsr(X86_MSR_SFMASK);
497 }
498
499 VOID
500 NTAPI
501 KeFlushEntireTb(IN BOOLEAN Invalid,
502 IN BOOLEAN AllProcessors)
503 {
504 KIRQL OldIrql;
505
506 // FIXME: halfplemented
507 /* Raise the IRQL for the TB Flush */
508 OldIrql = KeRaiseIrqlToSynchLevel();
509
510 /* Flush the TB for the Current CPU, and update the flush stamp */
511 KeFlushCurrentTb();
512
513 /* Update the flush stamp and return to original IRQL */
514 InterlockedExchangeAdd(&KiTbFlushTimeStamp, 1);
515 KeLowerIrql(OldIrql);
516
517 }
518
519 KAFFINITY
520 NTAPI
521 KeQueryActiveProcessors(VOID)
522 {
523 PAGED_CODE();
524
525 /* Simply return the number of active processors */
526 return KeActiveProcessors;
527 }
528
529 NTSTATUS
530 NTAPI
531 KxSaveFloatingPointState(OUT PKFLOATING_SAVE FloatingState)
532 {
533 UNREFERENCED_PARAMETER(FloatingState);
534 return STATUS_SUCCESS;
535 }
536
537 NTSTATUS
538 NTAPI
539 KxRestoreFloatingPointState(IN PKFLOATING_SAVE FloatingState)
540 {
541 UNREFERENCED_PARAMETER(FloatingState);
542 return STATUS_SUCCESS;
543 }
544
545 BOOLEAN
546 NTAPI
547 KeInvalidateAllCaches(VOID)
548 {
549 /* Invalidate all caches */
550 __wbinvd();
551 return TRUE;
552 }
553
554 /*
555 * @implemented
556 */
557 ULONG
558 NTAPI
559 KeGetRecommendedSharedDataAlignment(VOID)
560 {
561 /* Return the global variable */
562 return KeLargestCacheLine;
563 }
564
565 /*
566 * @implemented
567 */
568 VOID
569 __cdecl
570 KeSaveStateForHibernate(IN PKPROCESSOR_STATE State)
571 {
572 /* Capture the context */
573 RtlCaptureContext(&State->ContextFrame);
574
575 /* Capture the control state */
576 KiSaveProcessorControlState(State);
577 }
578
579 /*
580 * @implemented
581 */
582 VOID
583 NTAPI
584 KeSetDmaIoCoherency(IN ULONG Coherency)
585 {
586 /* Save the coherency globally */
587 KiDmaIoCoherency = Coherency;
588 }