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)
10 /* INCLUDES *****************************************************************/
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
22 /* GLOBALS *******************************************************************/
27 /* CPU Features and Flags */
30 ULONG KeProcessorArchitecture
;
31 ULONG KeProcessorLevel
;
32 ULONG KeProcessorRevision
;
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
;
47 volatile LONG KiTbFlushTimeStamp
;
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";
57 /* SUPPORT ROUTINES FOR MSVC COMPATIBILITY ***********************************/
61 CPUID(IN ULONG InfoType
,
62 OUT PULONG CpuInfoEax
,
63 OUT PULONG CpuInfoEbx
,
64 OUT PULONG CpuInfoEcx
,
65 OUT PULONG CpuInfoEdx
)
69 /* Perform the CPUID Operation */
70 __cpuid((int*)CpuInfo
, InfoType
);
72 /* Return the results */
73 *CpuInfoEax
= CpuInfo
[0];
74 *CpuInfoEbx
= CpuInfo
[1];
75 *CpuInfoEcx
= CpuInfo
[2];
76 *CpuInfoEdx
= CpuInfo
[3];
79 /* FUNCTIONS *****************************************************************/
83 KiSetProcessorType(VOID
)
89 /* Start by assuming no CPUID data */
90 KeGetCurrentPrcb()->CpuID
= 0;
93 EFlags
= __readeflags();
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.
103 * For the stepping, we convert this: zzzzzzxy into this: x0y
105 Stepping
= Reg
[0] & 0xF0;
107 Stepping
+= (Reg
[0] & 0xFF);
109 Type
= Reg
[0] & 0xF00;
112 /* Save them in the PRCB */
113 KeGetCurrentPrcb()->CpuID
= TRUE
;
114 KeGetCurrentPrcb()->CpuType
= (UCHAR
)Type
;
115 KeGetCurrentPrcb()->CpuStep
= (USHORT
)Stepping
;
118 __writeeflags(EFlags
);
125 PKPRCB Prcb
= KeGetCurrentPrcb();
128 /* Get the Vendor ID and null-terminate it */
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;
137 /* Now check the CPU Type */
138 if (!strcmp((PCHAR
)Prcb
->VendorString
, CmpIntelID
))
142 else if (!strcmp((PCHAR
)Prcb
->VendorString
, CmpAmdID
))
146 else if (!strcmp((PCHAR
)Prcb
->VendorString
, CmpCyrixID
))
148 DPRINT1("Cyrix CPUs not fully supported\n");
151 else if (!strcmp((PCHAR
)Prcb
->VendorString
, CmpTransmetaID
))
153 DPRINT1("Transmeta CPUs not fully supported\n");
156 else if (!strcmp((PCHAR
)Prcb
->VendorString
, CmpCentaurID
))
158 DPRINT1("VIA CPUs not fully supported\n");
161 else if (!strcmp((PCHAR
)Prcb
->VendorString
, CmpRiseID
))
163 DPRINT1("Rise CPUs not fully supported\n");
173 KiGetFeatureBits(VOID
)
175 PKPRCB Prcb
= KeGetCurrentPrcb();
177 ULONG FeatureBits
= KF_WORKING_PTE
;
179 ULONG CpuFeatures
= 0;
181 /* Get the Vendor ID */
182 Vendor
= KiGetCpuVendor();
184 /* Make sure we got a valid vendor ID at least. */
185 if (!Vendor
) return FeatureBits
;
187 /* Get the CPUID Info. Features are in Reg[3]. */
190 /* Set the initial APIC ID */
191 Prcb
->InitialApicId
= (UCHAR
)(Reg
[1] >> 24);
193 /* Set the current features */
194 CpuFeatures
= Reg
[3];
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
;
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
;
221 /* Check if the CPU has hyper-threading */
222 if (CpuFeatures
& 0x10000000)
224 /* Set the number of logical CPUs */
225 Prcb
->LogicalProcessorsPerPhysicalProcessor
= (UCHAR
)(Reg
[1] >> 16);
226 if (Prcb
->LogicalProcessorsPerPhysicalProcessor
> 1)
228 /* We're on dual-core */
229 KiSMTProcessorsPresent
= TRUE
;
234 /* We only have a single CPU */
235 Prcb
->LogicalProcessorsPerPhysicalProcessor
= 1;
238 /* Check extended cpuid features */
239 __cpuid(Reg
, 0x80000000);
240 if ((Reg
[0] & 0xffffff00) == 0x80000000)
242 /* Check if CPUID 0x80000001 is supported */
243 if (Reg
[0] >= 0x80000001)
245 /* Check which extended features are available. */
246 __cpuid(Reg
, 0x80000001);
248 /* Check if NX-bit is supported */
249 if (Reg
[3] & 0x00100000) FeatureBits
|= KF_NX_BIT
;
251 /* Now handle each features for each CPU Vendor */
255 if (Reg
[3] & 0x80000000) FeatureBits
|= KF_3DNOW
;
261 /* Return the Feature Bits */
267 KiGetCacheInformation(VOID
)
269 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
272 ULONG CacheRequests
= 0, i
;
273 ULONG CurrentRegister
;
275 BOOLEAN FirstPass
= TRUE
;
277 /* Set default L2 size */
278 Pcr
->SecondLevelCacheSize
= 0;
280 /* Get the Vendor ID and make sure we support CPUID */
281 Vendor
= KiGetCpuVendor();
284 /* Check the Vendor ID */
287 /* Handle Intel case */
290 /*Check if we support CPUID 2 */
294 /* We need to loop for the number of times CPUID will tell us to */
297 /* Do the CPUID call */
300 /* Check if it was the first call */
304 * The number of times to loop is the first byte. Read
305 * it and then destroy it so we don't get confused.
307 CacheRequests
= Data
[0] & 0xFF;
308 Data
[0] &= 0xFFFFFF00;
310 /* Don't go over this again */
314 /* Loop all 4 registers */
315 for (i
= 0; i
< 4; i
++)
317 /* Get the current register */
318 CurrentRegister
= Data
[i
];
321 * If the upper bit is set, then this register should
324 if (CurrentRegister
& 0x80000000) continue;
326 /* Keep looping for every byte inside this register */
327 while (CurrentRegister
)
329 /* Read a byte, skip a byte. */
330 RegisterByte
= (UCHAR
)(CurrentRegister
& 0xFF);
331 CurrentRegister
>>= 8;
332 if (!RegisterByte
) continue;
335 * Valid values are from 0x40 (0 bytes) to 0x49
336 * (32MB), or from 0x80 to 0x89 (same size but
339 if (((RegisterByte
> 0x40) &&
340 (RegisterByte
<= 0x49)) ||
341 ((RegisterByte
> 0x80) &&
342 (RegisterByte
<= 0x89)))
344 /* Mask out only the first nibble */
345 RegisterByte
&= 0x0F;
347 /* Set the L2 Cache Size */
348 Pcr
->SecondLevelCacheSize
= 0x10000 <<
353 } while (--CacheRequests
);
359 /* Check if we support CPUID 0x80000006 */
360 __cpuid(Data
, 0x80000000);
363 /* Get 2nd level cache and tlb size */
364 __cpuid(Data
, 0x80000006);
366 /* Set the L2 Cache Size */
367 Pcr
->SecondLevelCacheSize
= (Data
[2] & 0xFFFF0000) >> 6;
375 KiInitializeTss(IN PKTSS64 Tss
,
378 PKGDTENTRY64 TssEntry
;
380 /* Get pointer to the GDT entry */
381 TssEntry
= KiGetGdtEntry(KeGetPcr()->GdtBase
, KGDT64_SYS_TSS
);
383 /* Initialize the GDT entry */
384 KiInitGdtEntry(TssEntry
, (ULONG64
)Tss
, sizeof(KTSS64
), AMD64_TSS
, 0);
386 /* Zero out the TSS */
387 RtlZeroMemory(Tss
, sizeof(KTSS64
));
389 /* FIXME: I/O Map? */
390 Tss
->IoMapBase
= 0x68;
392 /* Setup ring 0 stack pointer */
395 /* Setup a stack for Double Fault Traps */
396 Tss
->Ist
[1] = (ULONG64
)KiDoubleFaultStack
;
398 /* Setup a stack for CheckAbort Traps */
399 Tss
->Ist
[2] = (ULONG64
)KiDoubleFaultStack
;
401 /* Setup a stack for NMI Traps */
402 Tss
->Ist
[3] = (ULONG64
)KiDoubleFaultStack
;
404 /* Load the task register */
405 __ltr(KGDT64_SYS_TSS
);
410 KeFlushCurrentTb(VOID
)
412 /* Flush the TLB by resetting CR3 */
413 __writecr3(__readcr3());
418 KiRestoreProcessorControlState(PKPROCESSOR_STATE ProcessorState
)
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
);
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
);
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
);
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
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
);
460 KiSaveProcessorControlState(OUT PKPROCESSOR_STATE ProcessorState
)
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();
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);
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
);
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 =
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
);
501 KeFlushEntireTb(IN BOOLEAN Invalid
,
502 IN BOOLEAN AllProcessors
)
506 // FIXME: halfplemented
507 /* Raise the IRQL for the TB Flush */
508 OldIrql
= KeRaiseIrqlToSynchLevel();
510 /* Flush the TB for the Current CPU, and update the flush stamp */
513 /* Update the flush stamp and return to original IRQL */
514 InterlockedExchangeAdd(&KiTbFlushTimeStamp
, 1);
515 KeLowerIrql(OldIrql
);
521 KeQueryActiveProcessors(VOID
)
525 /* Simply return the number of active processors */
526 return KeActiveProcessors
;
531 KxSaveFloatingPointState(OUT PKFLOATING_SAVE FloatingState
)
533 UNREFERENCED_PARAMETER(FloatingState
);
534 return STATUS_SUCCESS
;
539 KxRestoreFloatingPointState(IN PKFLOATING_SAVE FloatingState
)
541 UNREFERENCED_PARAMETER(FloatingState
);
542 return STATUS_SUCCESS
;
547 KeInvalidateAllCaches(VOID
)
549 /* Invalidate all caches */
559 KeGetRecommendedSharedDataAlignment(VOID
)
561 /* Return the global variable */
562 return KeLargestCacheLine
;
570 KeSaveStateForHibernate(IN PKPROCESSOR_STATE State
)
572 /* Capture the context */
573 RtlCaptureContext(&State
->ContextFrame
);
575 /* Capture the control state */
576 KiSaveProcessorControlState(State
);
584 KeSetDmaIoCoherency(IN ULONG Coherency
)
586 /* Save the coherency globally */
587 KiDmaIoCoherency
= Coherency
;