Amd64/misc 64bit fixes (#236)
[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 KeI386MachineType;
31 ULONG KeI386NpxPresent = 1;
32 ULONG KeLargestCacheLine = 0x40;
33 ULONG KiDmaIoCoherency = 0;
34 BOOLEAN KiSMTProcessorsPresent;
35
36 /* Freeze data */
37 KIRQL KiOldIrql;
38 ULONG KiFreezeFlag;
39
40 /* Flush data */
41 volatile LONG KiTbFlushTimeStamp;
42
43 /* CPU Signatures */
44 static const CHAR CmpIntelID[] = "GenuineIntel";
45 static const CHAR CmpAmdID[] = "AuthenticAMD";
46 static const CHAR CmpCyrixID[] = "CyrixInstead";
47 static const CHAR CmpTransmetaID[] = "GenuineTMx86";
48 static const CHAR CmpCentaurID[] = "CentaurHauls";
49 static const CHAR CmpRiseID[] = "RiseRiseRise";
50
51 /* FUNCTIONS *****************************************************************/
52
53 VOID
54 NTAPI
55 KiSetProcessorType(VOID)
56 {
57 CPU_INFO CpuInfo;
58 ULONG Stepping, Type;
59
60 /* Do CPUID 1 now */
61 KiCpuId(&CpuInfo, 1);
62
63 /*
64 * Get the Stepping and Type. The stepping contains both the
65 * Model and the Step, while the Type contains the returned Type.
66 * We ignore the family.
67 *
68 * For the stepping, we convert this: zzzzzzxy into this: x0y
69 */
70 Stepping = CpuInfo.Eax & 0xF0;
71 Stepping <<= 4;
72 Stepping += (CpuInfo.Eax & 0xFF);
73 Stepping &= 0xF0F;
74 Type = CpuInfo.Eax & 0xF00;
75 Type >>= 8;
76
77 /* Save them in the PRCB */
78 KeGetCurrentPrcb()->CpuID = TRUE;
79 KeGetCurrentPrcb()->CpuType = (UCHAR)Type;
80 KeGetCurrentPrcb()->CpuStep = (USHORT)Stepping;
81 }
82
83 ULONG
84 NTAPI
85 KiGetCpuVendor(VOID)
86 {
87 PKPRCB Prcb = KeGetCurrentPrcb();
88 CPU_INFO CpuInfo;
89
90 /* Get the Vendor ID and null-terminate it */
91 KiCpuId(&CpuInfo, 0);
92
93 /* Copy it to the PRCB and null-terminate it */
94 *(ULONG*)&Prcb->VendorString[0] = CpuInfo.Ebx;
95 *(ULONG*)&Prcb->VendorString[4] = CpuInfo.Edx;
96 *(ULONG*)&Prcb->VendorString[8] = CpuInfo.Ecx;
97 Prcb->VendorString[12] = 0;
98
99 /* Now check the CPU Type */
100 if (!strcmp((PCHAR)Prcb->VendorString, CmpIntelID))
101 {
102 return CPU_INTEL;
103 }
104 else if (!strcmp((PCHAR)Prcb->VendorString, CmpAmdID))
105 {
106 return CPU_AMD;
107 }
108 else if (!strcmp((PCHAR)Prcb->VendorString, CmpCentaurID))
109 {
110 DPRINT1("VIA CPUs not fully supported\n");
111 return CPU_VIA;
112 }
113 else if (!strcmp((PCHAR)Prcb->VendorString, CmpRiseID))
114 {
115 DPRINT1("Rise CPUs not fully supported\n");
116 return 0;
117 }
118
119 /* Invalid CPU */
120 return CPU_UNKNOWN;
121 }
122
123 ULONG
124 NTAPI
125 KiGetFeatureBits(VOID)
126 {
127 PKPRCB Prcb = KeGetCurrentPrcb();
128 ULONG Vendor;
129 ULONG FeatureBits = KF_WORKING_PTE;
130 CPU_INFO CpuInfo;
131
132 /* Get the Vendor ID */
133 Vendor = KiGetCpuVendor();
134
135 /* Make sure we got a valid vendor ID at least. */
136 if (!Vendor) return FeatureBits;
137
138 /* Get the CPUID Info. */
139 KiCpuId(&CpuInfo, 1);
140
141 /* Set the initial APIC ID */
142 Prcb->InitialApicId = (UCHAR)(CpuInfo.Ebx >> 24);
143
144 /* Convert all CPUID Feature bits into our format */
145 if (CpuInfo.Edx & X86_FEATURE_VME) FeatureBits |= KF_V86_VIS | KF_CR4;
146 if (CpuInfo.Edx & X86_FEATURE_PSE) FeatureBits |= KF_LARGE_PAGE | KF_CR4;
147 if (CpuInfo.Edx & X86_FEATURE_TSC) FeatureBits |= KF_RDTSC;
148 if (CpuInfo.Edx & X86_FEATURE_CX8) FeatureBits |= KF_CMPXCHG8B;
149 if (CpuInfo.Edx & X86_FEATURE_SYSCALL) FeatureBits |= KF_FAST_SYSCALL;
150 if (CpuInfo.Edx & X86_FEATURE_MTTR) FeatureBits |= KF_MTRR;
151 if (CpuInfo.Edx & X86_FEATURE_PGE) FeatureBits |= KF_GLOBAL_PAGE | KF_CR4;
152 if (CpuInfo.Edx & X86_FEATURE_CMOV) FeatureBits |= KF_CMOV;
153 if (CpuInfo.Edx & X86_FEATURE_PAT) FeatureBits |= KF_PAT;
154 if (CpuInfo.Edx & X86_FEATURE_DS) FeatureBits |= KF_DTS;
155 if (CpuInfo.Edx & X86_FEATURE_MMX) FeatureBits |= KF_MMX;
156 if (CpuInfo.Edx & X86_FEATURE_FXSR) FeatureBits |= KF_FXSR;
157 if (CpuInfo.Edx & X86_FEATURE_SSE) FeatureBits |= KF_XMMI;
158 if (CpuInfo.Edx & X86_FEATURE_SSE2) FeatureBits |= KF_XMMI64;
159
160 if (CpuInfo.Ecx & X86_FEATURE_SSE3) FeatureBits |= KF_SSE3;
161 //if (CpuInfo.Ecx & X86_FEATURE_MONITOR) FeatureBits |= KF_MONITOR;
162 //if (CpuInfo.Ecx & X86_FEATURE_SSSE3) FeatureBits |= KF_SSE3SUP;
163 if (CpuInfo.Ecx & X86_FEATURE_CX16) FeatureBits |= KF_CMPXCHG16B;
164 //if (CpuInfo.Ecx & X86_FEATURE_SSE41) FeatureBits |= KF_SSE41;
165 //if (CpuInfo.Ecx & X86_FEATURE_POPCNT) FeatureBits |= KF_POPCNT;
166 if (CpuInfo.Ecx & X86_FEATURE_XSAVE) FeatureBits |= KF_XSTATE;
167
168 /* Check if the CPU has hyper-threading */
169 if (CpuInfo.Edx & X86_FEATURE_HT)
170 {
171 /* Set the number of logical CPUs */
172 Prcb->LogicalProcessorsPerPhysicalProcessor = (UCHAR)(CpuInfo.Ebx >> 16);
173 if (Prcb->LogicalProcessorsPerPhysicalProcessor > 1)
174 {
175 /* We're on dual-core */
176 KiSMTProcessorsPresent = TRUE;
177 }
178 }
179 else
180 {
181 /* We only have a single CPU */
182 Prcb->LogicalProcessorsPerPhysicalProcessor = 1;
183 }
184
185 /* Check extended cpuid features */
186 KiCpuId(&CpuInfo, 0x80000000);
187 if ((CpuInfo.Eax & 0xffffff00) == 0x80000000)
188 {
189 /* Check if CPUID 0x80000001 is supported */
190 if (CpuInfo.Eax >= 0x80000001)
191 {
192 /* Check which extended features are available. */
193 KiCpuId(&CpuInfo, 0x80000001);
194
195 /* Check if NX-bit is supported */
196 if (CpuInfo.Edx & X86_FEATURE_NX) FeatureBits |= KF_NX_BIT;
197
198 /* Now handle each features for each CPU Vendor */
199 switch (Vendor)
200 {
201 case CPU_AMD:
202 if (CpuInfo.Edx & 0x80000000) FeatureBits |= KF_3DNOW;
203 break;
204 }
205 }
206 }
207
208 /* Return the Feature Bits */
209 return FeatureBits;
210 }
211
212 VOID
213 NTAPI
214 KiGetCacheInformation(VOID)
215 {
216 PKIPCR Pcr = (PKIPCR)KeGetPcr();
217 ULONG Vendor;
218 ULONG CacheRequests = 0, i;
219 ULONG CurrentRegister;
220 UCHAR RegisterByte;
221 BOOLEAN FirstPass = TRUE;
222 CPU_INFO CpuInfo;
223
224 /* Set default L2 size */
225 Pcr->SecondLevelCacheSize = 0;
226
227 /* Get the Vendor ID and make sure we support CPUID */
228 Vendor = KiGetCpuVendor();
229 if (!Vendor) return;
230
231 /* Check the Vendor ID */
232 switch (Vendor)
233 {
234 /* Handle Intel case */
235 case CPU_INTEL:
236
237 /*Check if we support CPUID 2 */
238 KiCpuId(&CpuInfo, 0);
239 if (CpuInfo.Eax >= 2)
240 {
241 /* We need to loop for the number of times CPUID will tell us to */
242 do
243 {
244 /* Do the CPUID call */
245 KiCpuId(&CpuInfo, 2);
246
247 /* Check if it was the first call */
248 if (FirstPass)
249 {
250 /*
251 * The number of times to loop is the first byte. Read
252 * it and then destroy it so we don't get confused.
253 */
254 CacheRequests = CpuInfo.Eax & 0xFF;
255 CpuInfo.Eax &= 0xFFFFFF00;
256
257 /* Don't go over this again */
258 FirstPass = FALSE;
259 }
260
261 /* Loop all 4 registers */
262 for (i = 0; i < 4; i++)
263 {
264 /* Get the current register */
265 CurrentRegister = CpuInfo.AsUINT32[i];
266
267 /*
268 * If the upper bit is set, then this register should
269 * be skipped.
270 */
271 if (CurrentRegister & 0x80000000) continue;
272
273 /* Keep looping for every byte inside this register */
274 while (CurrentRegister)
275 {
276 /* Read a byte, skip a byte. */
277 RegisterByte = (UCHAR)(CurrentRegister & 0xFF);
278 CurrentRegister >>= 8;
279 if (!RegisterByte) continue;
280
281 /*
282 * Valid values are from 0x40 (0 bytes) to 0x49
283 * (32MB), or from 0x80 to 0x89 (same size but
284 * 8-way associative.
285 */
286 if (((RegisterByte > 0x40) &&
287 (RegisterByte <= 0x49)) ||
288 ((RegisterByte > 0x80) &&
289 (RegisterByte <= 0x89)))
290 {
291 /* Mask out only the first nibble */
292 RegisterByte &= 0x0F;
293
294 /* Set the L2 Cache Size */
295 Pcr->SecondLevelCacheSize = 0x10000 <<
296 RegisterByte;
297 }
298 }
299 }
300 } while (--CacheRequests);
301 }
302 break;
303
304 case CPU_AMD:
305
306 /* Check if we support CPUID 0x80000006 */
307 KiCpuId(&CpuInfo, 0x80000000);
308 if (CpuInfo.Eax >= 6)
309 {
310 /* Get 2nd level cache and tlb size */
311 KiCpuId(&CpuInfo, 0x80000006);
312
313 /* Set the L2 Cache Size */
314 Pcr->SecondLevelCacheSize = (CpuInfo.Ecx & 0xFFFF0000) >> 6;
315 }
316 break;
317 }
318 }
319
320 VOID
321 NTAPI
322 KeFlushCurrentTb(VOID)
323 {
324 /* Flush the TLB by resetting CR3 */
325 __writecr3(__readcr3());
326 }
327
328 VOID
329 NTAPI
330 KiRestoreProcessorControlState(PKPROCESSOR_STATE ProcessorState)
331 {
332 /* Restore the CR registers */
333 __writecr0(ProcessorState->SpecialRegisters.Cr0);
334 // __writecr2(ProcessorState->SpecialRegisters.Cr2);
335 __writecr3(ProcessorState->SpecialRegisters.Cr3);
336 __writecr4(ProcessorState->SpecialRegisters.Cr4);
337 __writecr8(ProcessorState->SpecialRegisters.Cr8);
338
339 /* Restore the DR registers */
340 __writedr(0, ProcessorState->SpecialRegisters.KernelDr0);
341 __writedr(1, ProcessorState->SpecialRegisters.KernelDr1);
342 __writedr(2, ProcessorState->SpecialRegisters.KernelDr2);
343 __writedr(3, ProcessorState->SpecialRegisters.KernelDr3);
344 __writedr(6, ProcessorState->SpecialRegisters.KernelDr6);
345 __writedr(7, ProcessorState->SpecialRegisters.KernelDr7);
346
347 /* Restore GDT, IDT, LDT and TSS */
348 __lgdt(&ProcessorState->SpecialRegisters.Gdtr.Limit);
349 // __lldt(&ProcessorState->SpecialRegisters.Ldtr);
350 // __ltr(&ProcessorState->SpecialRegisters.Tr);
351 __lidt(&ProcessorState->SpecialRegisters.Idtr.Limit);
352
353 // __ldmxcsr(&ProcessorState->SpecialRegisters.MxCsr); // FIXME
354 // ProcessorState->SpecialRegisters.DebugControl
355 // ProcessorState->SpecialRegisters.LastBranchToRip
356 // ProcessorState->SpecialRegisters.LastBranchFromRip
357 // ProcessorState->SpecialRegisters.LastExceptionToRip
358 // ProcessorState->SpecialRegisters.LastExceptionFromRip
359
360 /* Restore MSRs */
361 __writemsr(X86_MSR_GSBASE, ProcessorState->SpecialRegisters.MsrGsBase);
362 __writemsr(X86_MSR_KERNEL_GSBASE, ProcessorState->SpecialRegisters.MsrGsSwap);
363 __writemsr(X86_MSR_STAR, ProcessorState->SpecialRegisters.MsrStar);
364 __writemsr(X86_MSR_LSTAR, ProcessorState->SpecialRegisters.MsrLStar);
365 __writemsr(X86_MSR_CSTAR, ProcessorState->SpecialRegisters.MsrCStar);
366 __writemsr(X86_MSR_SFMASK, ProcessorState->SpecialRegisters.MsrSyscallMask);
367
368 }
369
370 VOID
371 NTAPI
372 KiSaveProcessorControlState(OUT PKPROCESSOR_STATE ProcessorState)
373 {
374 /* Save the CR registers */
375 ProcessorState->SpecialRegisters.Cr0 = __readcr0();
376 ProcessorState->SpecialRegisters.Cr2 = __readcr2();
377 ProcessorState->SpecialRegisters.Cr3 = __readcr3();
378 ProcessorState->SpecialRegisters.Cr4 = __readcr4();
379 ProcessorState->SpecialRegisters.Cr8 = __readcr8();
380
381 /* Save the DR registers */
382 ProcessorState->SpecialRegisters.KernelDr0 = __readdr(0);
383 ProcessorState->SpecialRegisters.KernelDr1 = __readdr(1);
384 ProcessorState->SpecialRegisters.KernelDr2 = __readdr(2);
385 ProcessorState->SpecialRegisters.KernelDr3 = __readdr(3);
386 ProcessorState->SpecialRegisters.KernelDr6 = __readdr(6);
387 ProcessorState->SpecialRegisters.KernelDr7 = __readdr(7);
388
389 /* Save GDT, IDT, LDT and TSS */
390 __sgdt(&ProcessorState->SpecialRegisters.Gdtr.Limit);
391 __sldt(&ProcessorState->SpecialRegisters.Ldtr);
392 __str(&ProcessorState->SpecialRegisters.Tr);
393 __sidt(&ProcessorState->SpecialRegisters.Idtr.Limit);
394
395 // __stmxcsr(&ProcessorState->SpecialRegisters.MxCsr);
396 // ProcessorState->SpecialRegisters.DebugControl =
397 // ProcessorState->SpecialRegisters.LastBranchToRip =
398 // ProcessorState->SpecialRegisters.LastBranchFromRip =
399 // ProcessorState->SpecialRegisters.LastExceptionToRip =
400 // ProcessorState->SpecialRegisters.LastExceptionFromRip =
401
402 /* Save MSRs */
403 ProcessorState->SpecialRegisters.MsrGsBase = __readmsr(X86_MSR_GSBASE);
404 ProcessorState->SpecialRegisters.MsrGsSwap = __readmsr(X86_MSR_KERNEL_GSBASE);
405 ProcessorState->SpecialRegisters.MsrStar = __readmsr(X86_MSR_STAR);
406 ProcessorState->SpecialRegisters.MsrLStar = __readmsr(X86_MSR_LSTAR);
407 ProcessorState->SpecialRegisters.MsrCStar = __readmsr(X86_MSR_CSTAR);
408 ProcessorState->SpecialRegisters.MsrSyscallMask = __readmsr(X86_MSR_SFMASK);
409 }
410
411 VOID
412 NTAPI
413 KeFlushEntireTb(IN BOOLEAN Invalid,
414 IN BOOLEAN AllProcessors)
415 {
416 KIRQL OldIrql;
417
418 // FIXME: halfplemented
419 /* Raise the IRQL for the TB Flush */
420 OldIrql = KeRaiseIrqlToSynchLevel();
421
422 /* Flush the TB for the Current CPU, and update the flush stamp */
423 KeFlushCurrentTb();
424
425 /* Update the flush stamp and return to original IRQL */
426 InterlockedExchangeAdd(&KiTbFlushTimeStamp, 1);
427 KeLowerIrql(OldIrql);
428
429 }
430
431 KAFFINITY
432 NTAPI
433 KeQueryActiveProcessors(VOID)
434 {
435 PAGED_CODE();
436
437 /* Simply return the number of active processors */
438 return KeActiveProcessors;
439 }
440
441 NTSTATUS
442 NTAPI
443 KxSaveFloatingPointState(OUT PKFLOATING_SAVE FloatingState)
444 {
445 UNREFERENCED_PARAMETER(FloatingState);
446 return STATUS_SUCCESS;
447 }
448
449 NTSTATUS
450 NTAPI
451 KxRestoreFloatingPointState(IN PKFLOATING_SAVE FloatingState)
452 {
453 UNREFERENCED_PARAMETER(FloatingState);
454 return STATUS_SUCCESS;
455 }
456
457 BOOLEAN
458 NTAPI
459 KeInvalidateAllCaches(VOID)
460 {
461 /* Invalidate all caches */
462 __wbinvd();
463 return TRUE;
464 }
465
466 /*
467 * @implemented
468 */
469 ULONG
470 NTAPI
471 KeGetRecommendedSharedDataAlignment(VOID)
472 {
473 /* Return the global variable */
474 return KeLargestCacheLine;
475 }
476
477 /*
478 * @implemented
479 */
480 VOID
481 __cdecl
482 KeSaveStateForHibernate(IN PKPROCESSOR_STATE State)
483 {
484 /* Capture the context */
485 RtlCaptureContext(&State->ContextFrame);
486
487 /* Capture the control state */
488 KiSaveProcessorControlState(State);
489 }
490
491 /*
492 * @implemented
493 */
494 VOID
495 NTAPI
496 KeSetDmaIoCoherency(IN ULONG Coherency)
497 {
498 /* Save the coherency globally */
499 KiDmaIoCoherency = Coherency;
500 }