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 KeI386MachineType
;
31 ULONG KeI386NpxPresent
= 1;
32 ULONG KeLargestCacheLine
= 0x40;
33 ULONG KiDmaIoCoherency
= 0;
34 BOOLEAN KiSMTProcessorsPresent
;
41 volatile LONG KiTbFlushTimeStamp
;
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";
51 /* FUNCTIONS *****************************************************************/
55 KiSetProcessorType(VOID
)
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.
68 * For the stepping, we convert this: zzzzzzxy into this: x0y
70 Stepping
= CpuInfo
.Eax
& 0xF0;
72 Stepping
+= (CpuInfo
.Eax
& 0xFF);
74 Type
= CpuInfo
.Eax
& 0xF00;
77 /* Save them in the PRCB */
78 KeGetCurrentPrcb()->CpuID
= TRUE
;
79 KeGetCurrentPrcb()->CpuType
= (UCHAR
)Type
;
80 KeGetCurrentPrcb()->CpuStep
= (USHORT
)Stepping
;
87 PKPRCB Prcb
= KeGetCurrentPrcb();
90 /* Get the Vendor ID and null-terminate it */
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;
99 /* Now check the CPU Type */
100 if (!strcmp((PCHAR
)Prcb
->VendorString
, CmpIntelID
))
104 else if (!strcmp((PCHAR
)Prcb
->VendorString
, CmpAmdID
))
108 else if (!strcmp((PCHAR
)Prcb
->VendorString
, CmpCentaurID
))
110 DPRINT1("VIA CPUs not fully supported\n");
113 else if (!strcmp((PCHAR
)Prcb
->VendorString
, CmpRiseID
))
115 DPRINT1("Rise CPUs not fully supported\n");
125 KiGetFeatureBits(VOID
)
127 PKPRCB Prcb
= KeGetCurrentPrcb();
129 ULONG FeatureBits
= KF_WORKING_PTE
;
132 /* Get the Vendor ID */
133 Vendor
= KiGetCpuVendor();
135 /* Make sure we got a valid vendor ID at least. */
136 if (!Vendor
) return FeatureBits
;
138 /* Get the CPUID Info. */
139 KiCpuId(&CpuInfo
, 1);
141 /* Set the initial APIC ID */
142 Prcb
->InitialApicId
= (UCHAR
)(CpuInfo
.Ebx
>> 24);
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
;
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
;
168 /* Check if the CPU has hyper-threading */
169 if (CpuInfo
.Edx
& X86_FEATURE_HT
)
171 /* Set the number of logical CPUs */
172 Prcb
->LogicalProcessorsPerPhysicalProcessor
= (UCHAR
)(CpuInfo
.Ebx
>> 16);
173 if (Prcb
->LogicalProcessorsPerPhysicalProcessor
> 1)
175 /* We're on dual-core */
176 KiSMTProcessorsPresent
= TRUE
;
181 /* We only have a single CPU */
182 Prcb
->LogicalProcessorsPerPhysicalProcessor
= 1;
185 /* Check extended cpuid features */
186 KiCpuId(&CpuInfo
, 0x80000000);
187 if ((CpuInfo
.Eax
& 0xffffff00) == 0x80000000)
189 /* Check if CPUID 0x80000001 is supported */
190 if (CpuInfo
.Eax
>= 0x80000001)
192 /* Check which extended features are available. */
193 KiCpuId(&CpuInfo
, 0x80000001);
195 /* Check if NX-bit is supported */
196 if (CpuInfo
.Edx
& X86_FEATURE_NX
) FeatureBits
|= KF_NX_BIT
;
198 /* Now handle each features for each CPU Vendor */
202 if (CpuInfo
.Edx
& 0x80000000) FeatureBits
|= KF_3DNOW
;
208 /* Return the Feature Bits */
214 KiGetCacheInformation(VOID
)
216 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
218 ULONG CacheRequests
= 0, i
;
219 ULONG CurrentRegister
;
221 BOOLEAN FirstPass
= TRUE
;
224 /* Set default L2 size */
225 Pcr
->SecondLevelCacheSize
= 0;
227 /* Get the Vendor ID and make sure we support CPUID */
228 Vendor
= KiGetCpuVendor();
231 /* Check the Vendor ID */
234 /* Handle Intel case */
237 /*Check if we support CPUID 2 */
238 KiCpuId(&CpuInfo
, 0);
239 if (CpuInfo
.Eax
>= 2)
241 /* We need to loop for the number of times CPUID will tell us to */
244 /* Do the CPUID call */
245 KiCpuId(&CpuInfo
, 2);
247 /* Check if it was the first call */
251 * The number of times to loop is the first byte. Read
252 * it and then destroy it so we don't get confused.
254 CacheRequests
= CpuInfo
.Eax
& 0xFF;
255 CpuInfo
.Eax
&= 0xFFFFFF00;
257 /* Don't go over this again */
261 /* Loop all 4 registers */
262 for (i
= 0; i
< 4; i
++)
264 /* Get the current register */
265 CurrentRegister
= CpuInfo
.AsUINT32
[i
];
268 * If the upper bit is set, then this register should
271 if (CurrentRegister
& 0x80000000) continue;
273 /* Keep looping for every byte inside this register */
274 while (CurrentRegister
)
276 /* Read a byte, skip a byte. */
277 RegisterByte
= (UCHAR
)(CurrentRegister
& 0xFF);
278 CurrentRegister
>>= 8;
279 if (!RegisterByte
) continue;
282 * Valid values are from 0x40 (0 bytes) to 0x49
283 * (32MB), or from 0x80 to 0x89 (same size but
286 if (((RegisterByte
> 0x40) &&
287 (RegisterByte
<= 0x49)) ||
288 ((RegisterByte
> 0x80) &&
289 (RegisterByte
<= 0x89)))
291 /* Mask out only the first nibble */
292 RegisterByte
&= 0x0F;
294 /* Set the L2 Cache Size */
295 Pcr
->SecondLevelCacheSize
= 0x10000 <<
300 } while (--CacheRequests
);
306 /* Check if we support CPUID 0x80000006 */
307 KiCpuId(&CpuInfo
, 0x80000000);
308 if (CpuInfo
.Eax
>= 6)
310 /* Get 2nd level cache and tlb size */
311 KiCpuId(&CpuInfo
, 0x80000006);
313 /* Set the L2 Cache Size */
314 Pcr
->SecondLevelCacheSize
= (CpuInfo
.Ecx
& 0xFFFF0000) >> 6;
322 KeFlushCurrentTb(VOID
)
324 /* Flush the TLB by resetting CR3 */
325 __writecr3(__readcr3());
330 KiRestoreProcessorControlState(PKPROCESSOR_STATE ProcessorState
)
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
);
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
);
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
);
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
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
);
372 KiSaveProcessorControlState(OUT PKPROCESSOR_STATE ProcessorState
)
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();
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);
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
);
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 =
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
);
413 KeFlushEntireTb(IN BOOLEAN Invalid
,
414 IN BOOLEAN AllProcessors
)
418 // FIXME: halfplemented
419 /* Raise the IRQL for the TB Flush */
420 OldIrql
= KeRaiseIrqlToSynchLevel();
422 /* Flush the TB for the Current CPU, and update the flush stamp */
425 /* Update the flush stamp and return to original IRQL */
426 InterlockedExchangeAdd(&KiTbFlushTimeStamp
, 1);
427 KeLowerIrql(OldIrql
);
433 KeQueryActiveProcessors(VOID
)
437 /* Simply return the number of active processors */
438 return KeActiveProcessors
;
443 KxSaveFloatingPointState(OUT PKFLOATING_SAVE FloatingState
)
445 UNREFERENCED_PARAMETER(FloatingState
);
446 return STATUS_SUCCESS
;
451 KxRestoreFloatingPointState(IN PKFLOATING_SAVE FloatingState
)
453 UNREFERENCED_PARAMETER(FloatingState
);
454 return STATUS_SUCCESS
;
459 KeInvalidateAllCaches(VOID
)
461 /* Invalidate all caches */
471 KeGetRecommendedSharedDataAlignment(VOID
)
473 /* Return the global variable */
474 return KeLargestCacheLine
;
482 KeSaveStateForHibernate(IN PKPROCESSOR_STATE State
)
484 /* Capture the context */
485 RtlCaptureContext(&State
->ContextFrame
);
487 /* Capture the control state */
488 KiSaveProcessorControlState(State
);
496 KeSetDmaIoCoherency(IN ULONG Coherency
)
498 /* Save the coherency globally */
499 KiDmaIoCoherency
= Coherency
;