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 KeI386XMMIPresent
= 0;
37 ULONG KeI386FxsrPresent
= 0;
38 ULONG KeLargestCacheLine
= 0x40;
39 ULONG KiDmaIoCoherency
= 0;
40 CHAR KeNumberProcessors
= 0;
41 KAFFINITY KeActiveProcessors
= 1;
42 BOOLEAN KiI386PentiumLockErrataPresent
;
43 BOOLEAN KiSMTProcessorsPresent
;
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 /* FUNCTIONS *****************************************************************/
61 KiSetProcessorType(VOID
)
67 /* Start by assuming no CPUID data */
68 KeGetCurrentPrcb()->CpuID
= 0;
71 Ke386SaveFlags(EFlags
);
77 * Get the Stepping and Type. The stepping contains both the
78 * Model and the Step, while the Type contains the returned Type.
79 * We ignore the family.
81 * For the stepping, we convert this: zzzzzzxy into this: x0y
83 Stepping
= Reg
[0] & 0xF0;
85 Stepping
+= (Reg
[0] & 0xFF);
87 Type
= Reg
[0] & 0xF00;
90 /* Save them in the PRCB */
91 KeGetCurrentPrcb()->CpuID
= TRUE
;
92 KeGetCurrentPrcb()->CpuType
= (UCHAR
)Type
;
93 KeGetCurrentPrcb()->CpuStep
= (USHORT
)Stepping
;
96 Ke386RestoreFlags(EFlags
);
103 PKPRCB Prcb
= KeGetCurrentPrcb();
107 /* Assume no Vendor ID and fail if no CPUID Support. */
108 Prcb
->VendorString
[0] = 0;
109 if (!Prcb
->CpuID
) return 0;
111 /* Get the Vendor ID and null-terminate it */
115 /* Re-arrange vendor string */
117 Vendor
[2] = Vendor
[3];
120 /* Copy it to the PRCB and null-terminate it again */
121 RtlCopyMemory(Prcb
->VendorString
,
123 sizeof(Prcb
->VendorString
) - sizeof(CHAR
));
124 Prcb
->VendorString
[sizeof(Prcb
->VendorString
) - sizeof(CHAR
)] = ANSI_NULL
;
126 /* Now check the CPU Type */
127 if (!strcmp((PCHAR
)Prcb
->VendorString
, CmpIntelID
))
131 else if (!strcmp((PCHAR
)Prcb
->VendorString
, CmpAmdID
))
135 else if (!strcmp((PCHAR
)Prcb
->VendorString
, CmpCyrixID
))
137 DPRINT1("Cyrix CPUs not fully supported\n");
140 else if (!strcmp((PCHAR
)Prcb
->VendorString
, CmpTransmetaID
))
142 DPRINT1("Transmeta CPUs not fully supported\n");
145 else if (!strcmp((PCHAR
)Prcb
->VendorString
, CmpCentaurID
))
147 DPRINT1("VIA CPUs not fully supported\n");
150 else if (!strcmp((PCHAR
)Prcb
->VendorString
, CmpRiseID
))
152 DPRINT1("Rise CPUs not fully supported\n");
162 KiGetFeatureBits(VOID
)
164 PKPRCB Prcb
= KeGetCurrentPrcb();
166 ULONG FeatureBits
= KF_WORKING_PTE
;
168 ULONG CpuFeatures
= 0;
170 /* Get the Vendor ID */
171 Vendor
= KiGetCpuVendor();
173 /* Make sure we got a valid vendor ID at least. */
174 if (!Vendor
) return FeatureBits
;
176 /* Get the CPUID Info. Features are in Reg[3]. */
179 /* Set the initial APIC ID */
180 Prcb
->InitialApicId
= (UCHAR
)(Reg
[1] >> 24);
182 /* Set the current features */
183 CpuFeatures
= Reg
[3];
185 /* Convert all CPUID Feature bits into our format */
186 if (CpuFeatures
& 0x00000002) FeatureBits
|= KF_V86_VIS
| KF_CR4
;
187 if (CpuFeatures
& 0x00000008) FeatureBits
|= KF_LARGE_PAGE
| KF_CR4
;
188 if (CpuFeatures
& 0x00000010) FeatureBits
|= KF_RDTSC
;
189 if (CpuFeatures
& 0x00000100) FeatureBits
|= KF_CMPXCHG8B
;
190 if (CpuFeatures
& 0x00000800) FeatureBits
|= KF_FAST_SYSCALL
;
191 if (CpuFeatures
& 0x00001000) FeatureBits
|= KF_MTRR
;
192 if (CpuFeatures
& 0x00002000) FeatureBits
|= KF_GLOBAL_PAGE
| KF_CR4
;
193 if (CpuFeatures
& 0x00008000) FeatureBits
|= KF_CMOV
;
194 if (CpuFeatures
& 0x00010000) FeatureBits
|= KF_PAT
;
195 if (CpuFeatures
& 0x00200000) FeatureBits
|= KF_DTS
;
196 if (CpuFeatures
& 0x00800000) FeatureBits
|= KF_MMX
;
197 if (CpuFeatures
& 0x01000000) FeatureBits
|= KF_FXSR
;
198 if (CpuFeatures
& 0x02000000) FeatureBits
|= KF_XMMI
;
199 if (CpuFeatures
& 0x04000000) FeatureBits
|= KF_XMMI64
;
201 /* Check if the CPU has hyper-threading */
202 if (CpuFeatures
& 0x10000000)
204 /* Set the number of logical CPUs */
205 Prcb
->LogicalProcessorsPerPhysicalProcessor
= (UCHAR
)(Reg
[1] >> 16);
206 if (Prcb
->LogicalProcessorsPerPhysicalProcessor
> 1)
208 /* We're on dual-core */
209 KiSMTProcessorsPresent
= TRUE
;
214 /* We only have a single CPU */
215 Prcb
->LogicalProcessorsPerPhysicalProcessor
= 1;
218 /* Check extended cpuid features */
219 __cpuid(Reg
, 0x80000000);
220 if ((Reg
[0] & 0xffffff00) == 0x80000000)
222 /* Check if CPUID 0x80000001 is supported */
223 if (Reg
[0] >= 0x80000001)
225 /* Check which extended features are available. */
226 __cpuid(Reg
, 0x80000001);
228 /* Check if NX-bit is supported */
229 if (Reg
[3] & 0x00100000) FeatureBits
|= KF_NX_BIT
;
231 /* Now handle each features for each CPU Vendor */
235 if (Reg
[3] & 0x80000000) FeatureBits
|= KF_3DNOW
;
241 /* Return the Feature Bits */
247 KiInitializeCpuFeatures()
249 /* Enable Write-Protection */
250 __writecr0(__readcr0() | CR0_WP
);
252 /* Disable fpu monitoring */
253 __writecr0(__readcr0() & ~CR0_MP
);
255 /* Enable fx save restore support */
256 __writecr4(__readcr4() | CR4_FXSR
);
262 KiGetCacheInformation(VOID
)
264 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
267 ULONG CacheRequests
= 0, i
;
268 ULONG CurrentRegister
;
270 BOOLEAN FirstPass
= TRUE
;
272 /* Set default L2 size */
273 Pcr
->SecondLevelCacheSize
= 0;
275 /* Get the Vendor ID and make sure we support CPUID */
276 Vendor
= KiGetCpuVendor();
279 /* Check the Vendor ID */
282 /* Handle Intel case */
285 /*Check if we support CPUID 2 */
289 /* We need to loop for the number of times CPUID will tell us to */
292 /* Do the CPUID call */
295 /* Check if it was the first call */
299 * The number of times to loop is the first byte. Read
300 * it and then destroy it so we don't get confused.
302 CacheRequests
= Data
[0] & 0xFF;
303 Data
[0] &= 0xFFFFFF00;
305 /* Don't go over this again */
309 /* Loop all 4 registers */
310 for (i
= 0; i
< 4; i
++)
312 /* Get the current register */
313 CurrentRegister
= Data
[i
];
316 * If the upper bit is set, then this register should
319 if (CurrentRegister
& 0x80000000) continue;
321 /* Keep looping for every byte inside this register */
322 while (CurrentRegister
)
324 /* Read a byte, skip a byte. */
325 RegisterByte
= (UCHAR
)(CurrentRegister
& 0xFF);
326 CurrentRegister
>>= 8;
327 if (!RegisterByte
) continue;
330 * Valid values are from 0x40 (0 bytes) to 0x49
331 * (32MB), or from 0x80 to 0x89 (same size but
334 if (((RegisterByte
> 0x40) &&
335 (RegisterByte
<= 0x49)) ||
336 ((RegisterByte
> 0x80) &&
337 (RegisterByte
<= 0x89)))
339 /* Mask out only the first nibble */
340 RegisterByte
&= 0x0F;
342 /* Set the L2 Cache Size */
343 Pcr
->SecondLevelCacheSize
= 0x10000 <<
348 } while (--CacheRequests
);
354 /* Check if we support CPUID 0x80000006 */
355 __cpuid(Data
, 0x80000000);
358 /* Get 2nd level cache and tlb size */
359 __cpuid(Data
, 0x80000006);
361 /* Set the L2 Cache Size */
362 Pcr
->SecondLevelCacheSize
= (Data
[2] & 0xFFFF0000) >> 6;
371 Ki386InitializeTss(IN PKTSS64 Tss
,
376 PKGDTENTRY64 TssEntry
;
378 /* Initialize the TSS descriptor entry */
379 TssEntry
= (PVOID
)((ULONG64
)Gdt
+ KGDT_TSS
);
380 TssEntry
->Bits
.Type
= 9;//AMD64_TSS;
381 TssEntry
->Bits
.Dpl
= 0;
382 TssEntry
->Bits
.Present
= 1;
383 TssEntry
->Bits
.System
= 0;
384 TssEntry
->Bits
.LongMode
= 0;
385 TssEntry
->Bits
.DefaultBig
= 0;
386 TssEntry
->Bits
.Granularity
= 0;
388 /* Descriptor base is the TSS address */
389 TssEntry
->BaseLow
= (ULONG64
)Tss
& 0xffff;
390 TssEntry
->Bits
.BaseMiddle
= ((ULONG64
)Tss
>> 16) & 0xff;
391 TssEntry
->Bits
.BaseHigh
= ((ULONG64
)Tss
>> 24) & 0xff;
392 TssEntry
->BaseUpper
= (ULONG64
)Tss
>> 32;
395 TssEntry
->LimitLow
= sizeof(KTSS64
) -1;
396 TssEntry
->Bits
.LimitHigh
= 0;
398 /* FIXME: I/O Map? */
401 /* Setup ring 0 stack pointer */
404 /* Setup a stack for Double Fault Traps */
405 Tss
->Ist
[1] = (ULONG64
)KiDoubleFaultStack
;
407 /* Setup a stack for CheckAbort Traps */
408 Tss
->Ist
[2] = (ULONG64
)KiDoubleFaultStack
;
410 /* Setup a stack for NMI Traps */
411 Tss
->Ist
[3] = (ULONG64
)KiDoubleFaultStack
;
413 /* Load the task register */
414 Ke386SetTr(KGDT_TSS
);
420 KeFlushCurrentTb(VOID
)
422 /* Flush the TLB by resetting CR3 */
423 __writecr3(__readcr3());
428 KiRestoreProcessorControlState(PKPROCESSOR_STATE ProcessorState
)
430 /* Restore the CR registers */
431 __writecr0(ProcessorState
->SpecialRegisters
.Cr0
);
432 // __writecr2(ProcessorState->SpecialRegisters.Cr2);
433 __writecr3(ProcessorState
->SpecialRegisters
.Cr3
);
434 __writecr4(ProcessorState
->SpecialRegisters
.Cr4
);
435 __writecr8(ProcessorState
->SpecialRegisters
.Cr8
);
437 /* Restore the DR registers */
438 __writedr(0, ProcessorState
->SpecialRegisters
.KernelDr0
);
439 __writedr(1, ProcessorState
->SpecialRegisters
.KernelDr1
);
440 __writedr(2, ProcessorState
->SpecialRegisters
.KernelDr2
);
441 __writedr(3, ProcessorState
->SpecialRegisters
.KernelDr3
);
442 __writedr(6, ProcessorState
->SpecialRegisters
.KernelDr6
);
443 __writedr(7, ProcessorState
->SpecialRegisters
.KernelDr7
);
445 /* Restore GDT, IDT, LDT and TSS */
446 __lgdt(&ProcessorState
->SpecialRegisters
.Gdtr
.Limit
);
447 __lldt(&ProcessorState
->SpecialRegisters
.Ldtr
);
448 __ltr(&ProcessorState
->SpecialRegisters
.Tr
);
449 __lidt(&ProcessorState
->SpecialRegisters
.Idtr
.Limit
);
451 __ldmxcsr(&ProcessorState
->SpecialRegisters
.MxCsr
);
452 // ProcessorState->SpecialRegisters.DebugControl
453 // ProcessorState->SpecialRegisters.LastBranchToRip
454 // ProcessorState->SpecialRegisters.LastBranchFromRip
455 // ProcessorState->SpecialRegisters.LastExceptionToRip
456 // ProcessorState->SpecialRegisters.LastExceptionFromRip
459 __writemsr(X86_MSR_GSBASE
, ProcessorState
->SpecialRegisters
.MsrGsBase
);
460 __writemsr(X86_MSR_KERNEL_GSBASE
, ProcessorState
->SpecialRegisters
.MsrGsSwap
);
461 __writemsr(X86_MSR_STAR
, ProcessorState
->SpecialRegisters
.MsrStar
);
462 __writemsr(X86_MSR_LSTAR
, ProcessorState
->SpecialRegisters
.MsrLStar
);
463 __writemsr(X86_MSR_CSTAR
, ProcessorState
->SpecialRegisters
.MsrCStar
);
464 __writemsr(X86_MSR_SFMASK
, ProcessorState
->SpecialRegisters
.MsrSyscallMask
);
470 KiSaveProcessorControlState(OUT PKPROCESSOR_STATE ProcessorState
)
472 /* Save the CR registers */
473 ProcessorState
->SpecialRegisters
.Cr0
= __readcr0();
474 ProcessorState
->SpecialRegisters
.Cr2
= __readcr2();
475 ProcessorState
->SpecialRegisters
.Cr3
= __readcr3();
476 ProcessorState
->SpecialRegisters
.Cr4
= __readcr4();
477 ProcessorState
->SpecialRegisters
.Cr8
= __readcr8();
479 /* Save the DR registers */
480 ProcessorState
->SpecialRegisters
.KernelDr0
= __readdr(0);
481 ProcessorState
->SpecialRegisters
.KernelDr1
= __readdr(1);
482 ProcessorState
->SpecialRegisters
.KernelDr2
= __readdr(2);
483 ProcessorState
->SpecialRegisters
.KernelDr3
= __readdr(3);
484 ProcessorState
->SpecialRegisters
.KernelDr6
= __readdr(6);
485 ProcessorState
->SpecialRegisters
.KernelDr7
= __readdr(7);
487 /* Save GDT, IDT, LDT and TSS */
488 __sgdt(&ProcessorState
->SpecialRegisters
.Gdtr
.Limit
);
489 __sldt(&ProcessorState
->SpecialRegisters
.Ldtr
);
490 __str(&ProcessorState
->SpecialRegisters
.Tr
);
491 __sidt(&ProcessorState
->SpecialRegisters
.Idtr
.Limit
);
493 // __stmxcsr(&ProcessorState->SpecialRegisters.MxCsr);
494 // ProcessorState->SpecialRegisters.DebugControl =
495 // ProcessorState->SpecialRegisters.LastBranchToRip =
496 // ProcessorState->SpecialRegisters.LastBranchFromRip =
497 // ProcessorState->SpecialRegisters.LastExceptionToRip =
498 // ProcessorState->SpecialRegisters.LastExceptionFromRip =
501 ProcessorState
->SpecialRegisters
.MsrGsBase
= __readmsr(X86_MSR_GSBASE
);
502 ProcessorState
->SpecialRegisters
.MsrGsSwap
= __readmsr(X86_MSR_KERNEL_GSBASE
);
503 ProcessorState
->SpecialRegisters
.MsrStar
= __readmsr(X86_MSR_STAR
);
504 ProcessorState
->SpecialRegisters
.MsrLStar
= __readmsr(X86_MSR_LSTAR
);
505 ProcessorState
->SpecialRegisters
.MsrCStar
= __readmsr(X86_MSR_CSTAR
);
506 ProcessorState
->SpecialRegisters
.MsrSyscallMask
= __readmsr(X86_MSR_SFMASK
);
512 KiInitializeMachineType(VOID
)
514 /* Set the Machine Type we got from NTLDR */
515 KeI386MachineType
= KeLoaderBlock
->u
.I386
.MachineType
& 0x000FF;
520 KeFlushEntireTb(IN BOOLEAN Invalid
,
521 IN BOOLEAN AllProcessors
)
528 KeQueryActiveProcessors(VOID
)
532 /* Simply return the number of active processors */
533 return KeActiveProcessors
;
538 KeSaveFloatingPointState(OUT PKFLOATING_SAVE Save
)
541 return STATUS_UNSUCCESSFUL
;
546 KeRestoreFloatingPointState(IN PKFLOATING_SAVE Save
)
549 return STATUS_UNSUCCESSFUL
;
554 KeFreezeExecution(IN PKTRAP_FRAME TrapFrame
,
555 IN PKEXCEPTION_FRAME ExceptionFrame
)
559 /* Disable interrupts and get previous state */
560 Flags
= __readeflags();
561 //Flags = __getcallerseflags();
564 /* Save freeze flag */
567 /* Save the old IRQL */
568 KiOldIrql
= KeGetCurrentIrql();
570 /* Return whether interrupts were enabled */
571 return (Flags
& EFLAGS_INTERRUPT_MASK
) ? TRUE
: FALSE
;
576 KeThawExecution(IN BOOLEAN Enable
)
578 /* Cleanup CPU caches */
581 /* Re-enable interrupts */
582 if (Enable
) _enable();
587 KeInvalidateAllCaches(VOID
)
589 /* Only supported on Pentium Pro and higher */
590 if (KeI386CpuType
< 6) return FALSE
;
592 /* Invalidate all caches */
602 KeGetRecommendedSharedDataAlignment(VOID
)
604 /* Return the global variable */
605 return KeLargestCacheLine
;
613 KeSaveStateForHibernate(IN PKPROCESSOR_STATE State
)
615 /* Capture the context */
616 RtlCaptureContext(&State
->ContextFrame
);
618 /* Capture the control state */
619 KiSaveProcessorControlState(State
);
627 KeSetDmaIoCoherency(IN ULONG Coherency
)
629 /* Save the coherency globally */
630 KiDmaIoCoherency
= Coherency
;