2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/i386/cpu.c
5 * PURPOSE: Routines for CPU-level support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES *****************************************************************/
15 /* GLOBALS *******************************************************************/
20 /* The TSS to use for Double Fault Traps (INT 0x9) */
21 UCHAR KiDoubleFaultTSS
[KTSS_IO_MAPS
];
23 /* The TSS to use for NMI Fault Traps (INT 0x2) */
24 UCHAR KiNMITSS
[KTSS_IO_MAPS
];
27 KGDTENTRY KiBootGdt
[256] =
29 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_NULL */
30 {0xffff, 0x0000, {{0x00, 0x9b, 0xcf, 0x00}}}, /* KGDT_R0_CODE */
31 {0xffff, 0x0000, {{0x00, 0x93, 0xcf, 0x00}}}, /* KGDT_R0_DATA */
32 {0xffff, 0x0000, {{0x00, 0xfb, 0xcf, 0x00}}}, /* KGDT_R3_CODE */
33 {0xffff, 0x0000, {{0x00, 0xf3, 0xcf, 0x00}}}, /* KGDT_R3_DATA*/
34 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_TSS */
35 {0x0001, 0xf000, {{0xdf, 0x93, 0xc0, 0xff}}}, /* KGDT_R0_PCR */
36 {0x0fff, 0x0000, {{0x00, 0xf3, 0x40, 0x00}}}, /* KGDT_R3_TEB */
37 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_UNUSED */
38 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_LDT */
39 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_DF_TSS */
40 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}} /* KGDT_NMI_TSS */
44 KDESCRIPTOR KiGdtDescriptor
= {0, sizeof(KiBootGdt
) - 1, (ULONG
)KiBootGdt
};
46 /* CPU Features and Flags */
49 ULONG KeProcessorArchitecture
;
50 ULONG KeProcessorLevel
;
51 ULONG KeProcessorRevision
;
53 ULONG KiFastSystemCallDisable
= 1;
54 ULONG KeI386NpxPresent
= 0;
55 ULONG KiMXCsrMask
= 0;
56 ULONG MxcsrFeatureMask
= 0;
57 ULONG KeI386XMMIPresent
= 0;
58 ULONG KeI386FxsrPresent
= 0;
59 ULONG KeI386MachineType
;
60 ULONG Ke386Pae
= FALSE
;
61 ULONG Ke386NoExecute
= FALSE
;
62 ULONG KeLargestCacheLine
= 0x40;
63 ULONG KeDcacheFlushCount
= 0;
64 ULONG KeIcacheFlushCount
= 0;
65 ULONG KiDmaIoCoherency
= 0;
66 CHAR KeNumberProcessors
;
67 KAFFINITY KeActiveProcessors
= 1;
68 BOOLEAN KiI386PentiumLockErrataPresent
;
69 BOOLEAN KiSMTProcessorsPresent
;
76 volatile LONG KiTbFlushTimeStamp
;
79 static const CHAR CmpIntelID
[] = "GenuineIntel";
80 static const CHAR CmpAmdID
[] = "AuthenticAMD";
81 static const CHAR CmpCyrixID
[] = "CyrixInstead";
82 static const CHAR CmpTransmetaID
[] = "GenuineTMx86";
83 static const CHAR CmpCentaurID
[] = "CentaurHauls";
84 static const CHAR CmpRiseID
[] = "RiseRiseRise";
86 /* SUPPORT ROUTINES FOR MSVC COMPATIBILITY ***********************************/
90 CPUID(OUT ULONG CpuInfo
[4],
93 Ki386Cpuid(InfoType
, &CpuInfo
[0], &CpuInfo
[1], &CpuInfo
[2], &CpuInfo
[3]);
97 WRMSR(IN ULONG Register
,
100 LARGE_INTEGER LargeVal
;
101 LargeVal
.QuadPart
= Value
;
102 Ke386Wrmsr(Register
, LargeVal
.HighPart
, LargeVal
.LowPart
);
106 RDMSR(IN ULONG Register
)
108 LARGE_INTEGER LargeVal
= {{0}};
109 Ke386Rdmsr(Register
, LargeVal
.HighPart
, LargeVal
.LowPart
);
110 return LargeVal
.QuadPart
;
113 /* FUNCTIONS *****************************************************************/
117 KiSetProcessorType(VOID
)
119 ULONG EFlags
= 0, NewEFlags
;
121 ULONG Stepping
, Type
;
123 /* Start by assuming no CPUID data */
124 KeGetCurrentPrcb()->CpuID
= 0;
127 Ke386SaveFlags(EFlags
);
129 /* XOR out the ID bit and update EFlags */
130 NewEFlags
= EFlags
^ EFLAGS_ID
;
131 Ke386RestoreFlags(NewEFlags
);
133 /* Get them back and see if they were modified */
134 Ke386SaveFlags(NewEFlags
);
135 if (NewEFlags
!= EFlags
)
137 /* The modification worked, so CPUID exists. Set the ID Bit again. */
139 Ke386RestoreFlags(EFlags
);
141 /* Peform CPUID 0 to see if CPUID 1 is supported */
149 * Get the Stepping and Type. The stepping contains both the
150 * Model and the Step, while the Type contains the returned Type.
151 * We ignore the family.
153 * For the stepping, we convert this: zzzzzzxy into this: x0y
155 Stepping
= Reg
[0] & 0xF0;
157 Stepping
+= (Reg
[0] & 0xFF);
159 Type
= Reg
[0] & 0xF00;
162 /* Save them in the PRCB */
163 KeGetCurrentPrcb()->CpuID
= TRUE
;
164 KeGetCurrentPrcb()->CpuType
= (UCHAR
)Type
;
165 KeGetCurrentPrcb()->CpuStep
= (USHORT
)Stepping
;
169 DPRINT1("CPUID Support lacking\n");
174 DPRINT1("CPUID Support lacking\n");
178 Ke386RestoreFlags(EFlags
);
185 PKPRCB Prcb
= KeGetCurrentPrcb();
189 /* Assume no Vendor ID and fail if no CPUID Support. */
190 Prcb
->VendorString
[0] = 0;
191 if (!Prcb
->CpuID
) return 0;
193 /* Get the Vendor ID and null-terminate it */
197 /* Re-arrange vendor string */
199 Vendor
[2] = Vendor
[3];
202 /* Copy it to the PRCB and null-terminate it again */
203 RtlCopyMemory(Prcb
->VendorString
,
205 sizeof(Prcb
->VendorString
) - sizeof(CHAR
));
206 Prcb
->VendorString
[sizeof(Prcb
->VendorString
) - sizeof(CHAR
)] = ANSI_NULL
;
208 /* Now check the CPU Type */
209 if (!strcmp(Prcb
->VendorString
, CmpIntelID
))
213 else if (!strcmp(Prcb
->VendorString
, CmpAmdID
))
217 else if (!strcmp(Prcb
->VendorString
, CmpCyrixID
))
219 DPRINT1("Cyrix CPUs not fully supported\n");
222 else if (!strcmp(Prcb
->VendorString
, CmpTransmetaID
))
224 DPRINT1("Transmeta CPUs not fully supported\n");
227 else if (!strcmp(Prcb
->VendorString
, CmpCentaurID
))
229 DPRINT1("VIA CPUs not fully supported\n");
232 else if (!strcmp(Prcb
->VendorString
, CmpRiseID
))
234 DPRINT1("Rise CPUs not fully supported\n");
244 KiGetFeatureBits(VOID
)
246 PKPRCB Prcb
= KeGetCurrentPrcb();
248 ULONG FeatureBits
= KF_WORKING_PTE
;
250 BOOLEAN ExtendedCPUID
= TRUE
;
251 ULONG CpuFeatures
= 0;
253 /* Get the Vendor ID */
254 Vendor
= KiGetCpuVendor();
256 /* Make sure we got a valid vendor ID at least. */
257 if (!Vendor
) return FeatureBits
;
259 /* Get the CPUID Info. Features are in Reg[3]. */
262 /* Set the initial APIC ID */
263 Prcb
->InitialApicId
= (UCHAR
)(Reg
[1] >> 24);
265 /* Check for AMD CPU */
266 if (Vendor
== CPU_AMD
)
268 /* Check if this is a K5 or higher. */
269 if ((Reg
[0] & 0x0F00) >= 0x0500)
271 /* Check if this is a K5 specifically. */
272 if ((Reg
[0] & 0x0F00) == 0x0500)
274 /* Get the Model Number */
275 switch (Reg
[0] & 0x00F0)
277 /* Check if this is the Model 1 */
280 /* Check if this is Step 0 or 1. They don't support PGE */
281 if ((Reg
[0] & 0x000F) > 0x03) break;
285 /* Model 0 doesn't support PGE at all. */
291 /* K6-2, Step 8 and over have support for MTRR. */
292 if ((Reg
[0] & 0x000F) >= 0x8) FeatureBits
|= KF_AMDK6MTRR
;
297 /* As does the K6-3 */
298 FeatureBits
|= KF_AMDK6MTRR
;
308 /* Families below 5 don't support PGE, PSE or CMOV at all */
309 Reg
[3] &= ~(0x08 | 0x2000 | 0x8000);
311 /* They also don't support advanced CPUID functions. */
312 ExtendedCPUID
= FALSE
;
315 /* Set the current features */
316 CpuFeatures
= Reg
[3];
319 /* Now check if this is Intel */
320 if (Vendor
== CPU_INTEL
)
322 /* Check if it's a P6 */
323 if (Prcb
->CpuType
== 6)
325 /* Perform the special sequence to get the MicroCode Signature */
328 Prcb
->UpdateSignature
.QuadPart
= RDMSR(0x8B);
330 else if (Prcb
->CpuType
== 5)
332 /* On P5, enable workaround for the LOCK errata. */
333 KiI386PentiumLockErrataPresent
= TRUE
;
336 /* Check for broken P6 with bad SMP PTE implementation */
337 if (((Reg
[0] & 0x0FF0) == 0x0610 && (Reg
[0] & 0x000F) <= 0x9) ||
338 ((Reg
[0] & 0x0FF0) == 0x0630 && (Reg
[0] & 0x000F) <= 0x4))
340 /* Remove support for correct PTE support. */
341 FeatureBits
&= ~KF_WORKING_PTE
;
344 /* Check if the CPU is too old to support SYSENTER */
345 if ((Prcb
->CpuType
< 6) ||
346 ((Prcb
->CpuType
== 6) && (Prcb
->CpuStep
< 0x0303)))
352 /* Set the current features */
353 CpuFeatures
= Reg
[3];
357 if (Vendor
== CPU_TRANSMETA
)
359 /* Enable CMPXCHG8B if the family (>= 5), model and stepping (>= 4.2) support it */
360 if ((Reg
[0] & 0x0F00) >= 0x0500 && (Reg
[0] & 0x00FF) >= 0x0042)
362 WRMSR(0x80860004, RDMSR(0x80860004) | 0x0100);
363 FeatureBits
|= KF_CMPXCHG8B
;
369 if (Vendor
== CPU_CENTAUR
)
371 /* If CMPXCHG8B is not detected, try to enable it */
372 if (!(CpuFeatures
& 0x00000100))
374 if ((Reg
[0] & 0x0F00) == 0x0500)
376 WRMSR(0x0107, RDMSR(0x0107) | 0x02);
377 FeatureBits
|= KF_CMPXCHG8B
;
379 else if ((Reg
[0] & 0x0F00) >= 0x0600)
381 WRMSR(0x1107, (RDMSR(0x1107) | 0x02) & ~((LONGLONG
)0x01));
382 FeatureBits
|= KF_CMPXCHG8B
;
389 if (Vendor
== CPU_RISE
)
391 /* Windows Vista assumes CMPXCHG8B is always supported on Rise */
392 FeatureBits
|= KF_CMPXCHG8B
;
396 /* Convert all CPUID Feature bits into our format */
397 if (CpuFeatures
& 0x00000002) FeatureBits
|= KF_V86_VIS
| KF_CR4
;
398 if (CpuFeatures
& 0x00000008) FeatureBits
|= KF_LARGE_PAGE
| KF_CR4
;
399 if (CpuFeatures
& 0x00000010) FeatureBits
|= KF_RDTSC
;
400 if (CpuFeatures
& 0x00000100) FeatureBits
|= KF_CMPXCHG8B
;
401 if (CpuFeatures
& 0x00000800) FeatureBits
|= KF_FAST_SYSCALL
;
402 if (CpuFeatures
& 0x00001000) FeatureBits
|= KF_MTRR
;
403 if (CpuFeatures
& 0x00002000) FeatureBits
|= KF_GLOBAL_PAGE
| KF_CR4
;
404 if (CpuFeatures
& 0x00008000) FeatureBits
|= KF_CMOV
;
405 if (CpuFeatures
& 0x00010000) FeatureBits
|= KF_PAT
;
406 if (CpuFeatures
& 0x00200000) FeatureBits
|= KF_DTS
;
407 if (CpuFeatures
& 0x00800000) FeatureBits
|= KF_MMX
;
408 if (CpuFeatures
& 0x01000000) FeatureBits
|= KF_FXSR
;
409 if (CpuFeatures
& 0x02000000) FeatureBits
|= KF_XMMI
;
410 if (CpuFeatures
& 0x04000000) FeatureBits
|= KF_XMMI64
;
412 /* Check if the CPU has hyper-threading */
413 if (CpuFeatures
& 0x10000000)
415 /* Set the number of logical CPUs */
416 Prcb
->LogicalProcessorsPerPhysicalProcessor
= (UCHAR
)(Reg
[1] >> 16);
417 if (Prcb
->LogicalProcessorsPerPhysicalProcessor
> 1)
419 /* We're on dual-core */
420 KiSMTProcessorsPresent
= TRUE
;
425 /* We only have a single CPU */
426 Prcb
->LogicalProcessorsPerPhysicalProcessor
= 1;
429 /* Check if CPUID 0x80000000 is supported */
433 CPUID(Reg
, 0x80000000);
434 if ((Reg
[0] & 0xffffff00) == 0x80000000)
436 /* Check if CPUID 0x80000001 is supported */
437 if (Reg
[0] >= 0x80000001)
439 /* Check which extended features are available. */
440 CPUID(Reg
, 0x80000001);
442 /* Check if NX-bit is supported */
443 if (Reg
[3] & 0x00100000) FeatureBits
|= KF_NX_BIT
;
445 /* Now handle each features for each CPU Vendor */
449 if (Reg
[3] & 0x80000000) FeatureBits
|= KF_3DNOW
;
456 /* Return the Feature Bits */
462 KiGetCacheInformation(VOID
)
464 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
467 ULONG CacheRequests
= 0, i
;
468 ULONG CurrentRegister
;
470 BOOLEAN FirstPass
= TRUE
;
472 /* Set default L2 size */
473 Pcr
->SecondLevelCacheSize
= 0;
475 /* Get the Vendor ID and make sure we support CPUID */
476 Vendor
= KiGetCpuVendor();
479 /* Check the Vendor ID */
482 /* Handle Intel case */
485 /*Check if we support CPUID 2 */
489 /* We need to loop for the number of times CPUID will tell us to */
492 /* Do the CPUID call */
495 /* Check if it was the first call */
499 * The number of times to loop is the first byte. Read
500 * it and then destroy it so we don't get confused.
502 CacheRequests
= Data
[0] & 0xFF;
503 Data
[0] &= 0xFFFFFF00;
505 /* Don't go over this again */
509 /* Loop all 4 registers */
510 for (i
= 0; i
< 4; i
++)
512 /* Get the current register */
513 CurrentRegister
= Data
[i
];
516 * If the upper bit is set, then this register should
519 if (CurrentRegister
& 0x80000000) continue;
521 /* Keep looping for every byte inside this register */
522 while (CurrentRegister
)
524 /* Read a byte, skip a byte. */
525 RegisterByte
= (UCHAR
)(CurrentRegister
& 0xFF);
526 CurrentRegister
>>= 8;
527 if (!RegisterByte
) continue;
530 * Valid values are from 0x40 (0 bytes) to 0x49
531 * (32MB), or from 0x80 to 0x89 (same size but
534 if (((RegisterByte
> 0x40) &&
535 (RegisterByte
<= 0x49)) ||
536 ((RegisterByte
> 0x80) &&
537 (RegisterByte
<= 0x89)))
539 /* Mask out only the first nibble */
540 RegisterByte
&= 0x0F;
542 /* Set the L2 Cache Size */
543 Pcr
->SecondLevelCacheSize
= 0x10000 <<
548 } while (--CacheRequests
);
554 /* Check if we support CPUID 0x80000006 */
555 CPUID(Data
, 0x80000000);
558 /* Get 2nd level cache and tlb size */
559 CPUID(Data
, 0x80000006);
561 /* Set the L2 Cache Size */
562 Pcr
->SecondLevelCacheSize
= (Data
[2] & 0xFFFF0000) >> 6;
574 /* Save current CR0 */
577 /* If this is a 486, enable Write-Protection */
578 if (KeGetCurrentPrcb()->CpuType
> 3) Cr0
|= CR0_WP
;
586 KiInitializeTSS2(IN PKTSS Tss
,
587 IN PKGDTENTRY TssEntry OPTIONAL
)
591 /* Make sure the GDT Entry is valid */
595 TssEntry
->LimitLow
= sizeof(KTSS
) - 1;
596 TssEntry
->HighWord
.Bits
.LimitHi
= 0;
599 /* Now clear the I/O Map */
600 RtlFillMemory(Tss
->IoMaps
[0].IoMap
, 8096, -1);
602 /* Initialize Interrupt Direction Maps */
603 p
= (PUCHAR
)(Tss
->IoMaps
[0].DirectionMap
);
604 RtlZeroMemory(p
, 32);
606 /* Add DPMI support for interrupts */
611 /* Initialize the default Interrupt Direction Map */
612 p
= Tss
->IntDirectionMap
;
613 RtlZeroMemory(Tss
->IntDirectionMap
, 32);
615 /* Add DPMI support */
623 KiInitializeTSS(IN PKTSS Tss
)
625 /* Set an invalid map base */
626 Tss
->IoMapBase
= KiComputeIopmOffset(IO_ACCESS_MAP_NONE
);
628 /* Disable traps during Task Switches */
631 /* Set LDT and Ring 0 SS */
633 Tss
->Ss0
= KGDT_R0_DATA
;
638 Ki386InitializeTss(IN PKTSS Tss
,
642 PKGDTENTRY TssEntry
, TaskGateEntry
;
644 /* Initialize the boot TSS. */
645 TssEntry
= &Gdt
[KGDT_TSS
/ sizeof(KGDTENTRY
)];
646 TssEntry
->HighWord
.Bits
.Type
= I386_TSS
;
647 TssEntry
->HighWord
.Bits
.Pres
= 1;
648 TssEntry
->HighWord
.Bits
.Dpl
= 0;
649 KiInitializeTSS2(Tss
, TssEntry
);
650 KiInitializeTSS(Tss
);
652 /* Load the task register */
653 Ke386SetTr(KGDT_TSS
);
655 /* Setup the Task Gate for Double Fault Traps */
656 TaskGateEntry
= (PKGDTENTRY
)&Idt
[8];
657 TaskGateEntry
->HighWord
.Bits
.Type
= I386_TASK_GATE
;
658 TaskGateEntry
->HighWord
.Bits
.Pres
= 1;
659 TaskGateEntry
->HighWord
.Bits
.Dpl
= 0;
660 ((PKIDTENTRY
)TaskGateEntry
)->Selector
= KGDT_DF_TSS
;
662 /* Initialize the TSS used for handling double faults. */
663 Tss
= (PKTSS
)KiDoubleFaultTSS
;
664 KiInitializeTSS(Tss
);
665 Tss
->CR3
= __readcr3();
666 Tss
->Esp0
= PtrToUlong(KiDoubleFaultStack
);
667 Tss
->Eip
= PtrToUlong(KiTrap8
);
668 Tss
->Cs
= KGDT_R0_CODE
;
669 Tss
->Fs
= KGDT_R0_PCR
;
670 Tss
->Ss
= Ke386GetSs();
671 Tss
->Es
= KGDT_R3_DATA
| RPL_MASK
;
672 Tss
->Ds
= KGDT_R3_DATA
| RPL_MASK
;
674 /* Setup the Double Trap TSS entry in the GDT */
675 TssEntry
= &Gdt
[KGDT_DF_TSS
/ sizeof(KGDTENTRY
)];
676 TssEntry
->HighWord
.Bits
.Type
= I386_TSS
;
677 TssEntry
->HighWord
.Bits
.Pres
= 1;
678 TssEntry
->HighWord
.Bits
.Dpl
= 0;
679 TssEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Tss
& 0xFFFF);
680 TssEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Tss
>> 16);
681 TssEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Tss
>> 24);
682 TssEntry
->LimitLow
= KTSS_IO_MAPS
;
684 /* Now setup the NMI Task Gate */
685 TaskGateEntry
= (PKGDTENTRY
)&Idt
[2];
686 TaskGateEntry
->HighWord
.Bits
.Type
= I386_TASK_GATE
;
687 TaskGateEntry
->HighWord
.Bits
.Pres
= 1;
688 TaskGateEntry
->HighWord
.Bits
.Dpl
= 0;
689 ((PKIDTENTRY
)TaskGateEntry
)->Selector
= KGDT_NMI_TSS
;
691 /* Initialize the actual TSS */
692 Tss
= (PKTSS
)KiNMITSS
;
693 KiInitializeTSS(Tss
);
694 Tss
->CR3
= __readcr3();
695 Tss
->Esp0
= PtrToUlong(KiDoubleFaultStack
);
696 Tss
->Eip
= PtrToUlong(KiTrap2
);
697 Tss
->Cs
= KGDT_R0_CODE
;
698 Tss
->Fs
= KGDT_R0_PCR
;
699 Tss
->Ss
= Ke386GetSs();
700 Tss
->Es
= KGDT_R3_DATA
| RPL_MASK
;
701 Tss
->Ds
= KGDT_R3_DATA
| RPL_MASK
;
703 /* And its associated TSS Entry */
704 TssEntry
= &Gdt
[KGDT_NMI_TSS
/ sizeof(KGDTENTRY
)];
705 TssEntry
->HighWord
.Bits
.Type
= I386_TSS
;
706 TssEntry
->HighWord
.Bits
.Pres
= 1;
707 TssEntry
->HighWord
.Bits
.Dpl
= 0;
708 TssEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Tss
& 0xFFFF);
709 TssEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Tss
>> 16);
710 TssEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Tss
>> 24);
711 TssEntry
->LimitLow
= KTSS_IO_MAPS
;
716 KeFlushCurrentTb(VOID
)
718 /* Flush the TLB by resetting CR3 */
719 __writecr3(__readcr3());
724 KiRestoreProcessorControlState(PKPROCESSOR_STATE ProcessorState
)
726 /* Restore the CR registers */
727 __writecr0(ProcessorState
->SpecialRegisters
.Cr0
);
728 Ke386SetCr2(ProcessorState
->SpecialRegisters
.Cr2
);
729 __writecr3(ProcessorState
->SpecialRegisters
.Cr3
);
730 if (KeFeatureBits
& KF_CR4
) __writecr4(ProcessorState
->SpecialRegisters
.Cr4
);
733 // Restore the DR registers
735 Ke386SetDr0(ProcessorState
->SpecialRegisters
.KernelDr0
);
736 Ke386SetDr1(ProcessorState
->SpecialRegisters
.KernelDr1
);
737 Ke386SetDr2(ProcessorState
->SpecialRegisters
.KernelDr2
);
738 Ke386SetDr3(ProcessorState
->SpecialRegisters
.KernelDr3
);
739 Ke386SetDr6(ProcessorState
->SpecialRegisters
.KernelDr6
);
740 Ke386SetDr7(ProcessorState
->SpecialRegisters
.KernelDr7
);
743 // Restore GDT, IDT, LDT and TSS
745 Ke386SetGlobalDescriptorTable(*(PKDESCRIPTOR
)&ProcessorState
->SpecialRegisters
.Gdtr
.Limit
);
746 Ke386SetInterruptDescriptorTable(*(PKDESCRIPTOR
)&ProcessorState
->SpecialRegisters
.Idtr
.Limit
);
747 Ke386SetTr(ProcessorState
->SpecialRegisters
.Tr
);
748 Ke386SetLocalDescriptorTable(ProcessorState
->SpecialRegisters
.Ldtr
);
753 KiSaveProcessorControlState(OUT PKPROCESSOR_STATE ProcessorState
)
755 /* Save the CR registers */
756 ProcessorState
->SpecialRegisters
.Cr0
= __readcr0();
757 ProcessorState
->SpecialRegisters
.Cr2
= __readcr2();
758 ProcessorState
->SpecialRegisters
.Cr3
= __readcr3();
759 ProcessorState
->SpecialRegisters
.Cr4
= (KeFeatureBits
& KF_CR4
) ?
762 /* Save the DR registers */
763 ProcessorState
->SpecialRegisters
.KernelDr0
= Ke386GetDr0();
764 ProcessorState
->SpecialRegisters
.KernelDr1
= Ke386GetDr1();
765 ProcessorState
->SpecialRegisters
.KernelDr2
= Ke386GetDr2();
766 ProcessorState
->SpecialRegisters
.KernelDr3
= Ke386GetDr3();
767 ProcessorState
->SpecialRegisters
.KernelDr6
= Ke386GetDr6();
768 ProcessorState
->SpecialRegisters
.KernelDr7
= Ke386GetDr7();
771 /* Save GDT, IDT, LDT and TSS */
772 Ke386GetGlobalDescriptorTable(*(PKDESCRIPTOR
)&ProcessorState
->SpecialRegisters
.Gdtr
.Limit
);
773 Ke386GetInterruptDescriptorTable(*(PKDESCRIPTOR
)&ProcessorState
->SpecialRegisters
.Idtr
.Limit
);
774 Ke386GetTr(ProcessorState
->SpecialRegisters
.Tr
);
775 Ke386GetLocalDescriptorTable(ProcessorState
->SpecialRegisters
.Ldtr
);
780 KiInitializeMachineType(VOID
)
782 /* Set the Machine Type we got from NTLDR */
783 KeI386MachineType
= KeLoaderBlock
->u
.I386
.MachineType
& 0x000FF;
788 KiLoadFastSyscallMachineSpecificRegisters(IN ULONG_PTR Context
)
791 Ke386Wrmsr(0x174, KGDT_R0_CODE
, 0);
792 Ke386Wrmsr(0x175, (ULONG
)KeGetCurrentPrcb()->DpcStack
, 0);
795 Ke386Wrmsr(0x176, (ULONG
)KiFastCallEntry
, 0);
801 KiRestoreFastSyscallReturnState(VOID
)
803 /* FIXME: NT has support for SYSCALL, IA64-SYSENTER, etc. */
805 /* Check if the CPU Supports fast system call */
806 if (KeFeatureBits
& KF_FAST_SYSCALL
)
808 /* Do an IPI to enable it */
809 KeIpiGenericCall(KiLoadFastSyscallMachineSpecificRegisters
, 0);
815 Ki386EnableDE(IN ULONG_PTR Context
)
818 __writecr4(__readcr4() | CR4_DE
);
824 Ki386EnableFxsr(IN ULONG_PTR Context
)
827 __writecr4(__readcr4() | CR4_FXSR
);
833 Ki386EnableXMMIExceptions(IN ULONG_PTR Context
)
837 /* Get the IDT Entry for Interrupt 19 */
838 IdtEntry
= &((PKIPCR
)KeGetPcr())->IDT
[19];
841 IdtEntry
->Selector
= KGDT_R0_CODE
;
842 IdtEntry
->Offset
= ((ULONG_PTR
)KiTrap19
& 0xFFFF);
843 IdtEntry
->ExtendedOffset
= ((ULONG_PTR
)KiTrap19
>> 16) & 0xFFFF;
844 ((PKIDT_ACCESS
)&IdtEntry
->Access
)->Dpl
= 0;
845 ((PKIDT_ACCESS
)&IdtEntry
->Access
)->Present
= 1;
846 ((PKIDT_ACCESS
)&IdtEntry
->Access
)->SegmentType
= I386_INTERRUPT_GATE
;
848 /* Enable XMMI exceptions */
849 __writecr4(__readcr4() | CR4_XMMEXCPT
);
855 KiI386PentiumLockErrataFixup(VOID
)
857 KDESCRIPTOR IdtDescriptor
= {0};
858 PKIDTENTRY NewIdt
, NewIdt2
;
860 /* Allocate memory for a new IDT */
861 NewIdt
= ExAllocatePool(NonPagedPool
, 2 * PAGE_SIZE
);
863 /* Put everything after the first 7 entries on a new page */
864 NewIdt2
= (PVOID
)((ULONG_PTR
)NewIdt
+ PAGE_SIZE
- (7 * sizeof(KIDTENTRY
)));
866 /* Disable interrupts */
869 /* Get the current IDT and copy it */
870 Ke386GetInterruptDescriptorTable(*(PKDESCRIPTOR
)&IdtDescriptor
.Limit
);
871 RtlCopyMemory(NewIdt2
,
872 (PVOID
)IdtDescriptor
.Base
,
873 IdtDescriptor
.Limit
+ 1);
874 IdtDescriptor
.Base
= (ULONG
)NewIdt2
;
876 /* Set the new IDT */
877 Ke386SetInterruptDescriptorTable(*(PKDESCRIPTOR
)&IdtDescriptor
.Limit
);
878 ((PKIPCR
)KeGetPcr())->IDT
= NewIdt2
;
880 /* Restore interrupts */
883 /* Set the first 7 entries as read-only to produce a fault */
884 MmSetPageProtect(NULL
, NewIdt
, PAGE_READONLY
);
889 KeFreezeExecution(IN PKTRAP_FRAME TrapFrame
,
890 IN PKEXCEPTION_FRAME ExceptionFrame
)
894 /* Disable interrupts and get previous state */
895 Ke386SaveFlags(Flags
);
896 //Flags = __getcallerseflags();
899 /* Save freeze flag */
902 /* Save the old IRQL */
903 KiOldIrql
= KeGetCurrentIrql();
905 /* Return whether interrupts were enabled */
906 return (Flags
& EFLAGS_INTERRUPT_MASK
) ? TRUE
: FALSE
;
911 KeThawExecution(IN BOOLEAN Enable
)
913 /* Cleanup CPU caches */
916 /* Re-enable interrupts */
917 if (Enable
) _enable();
922 KeInvalidateAllCaches(VOID
)
924 /* Only supported on Pentium Pro and higher */
925 if (KeI386CpuType
< 6) return FALSE
;
927 /* Invalidate all caches */
934 KeZeroPages(IN PVOID Address
,
937 /* Not using XMMI in this routine */
938 RtlZeroMemory(Address
, Size
);
941 /* PUBLIC FUNCTIONS **********************************************************/
948 KeSaveFloatingPointState(OUT PKFLOATING_SAVE Save
)
950 PFNSAVE_FORMAT FpState
;
951 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
952 DPRINT1("%s is not really implemented\n", __FUNCTION__
);
954 /* check if we are doing software emulation */
955 if (!KeI386NpxPresent
) return STATUS_ILLEGAL_FLOAT_CONTEXT
;
957 FpState
= ExAllocatePool(NonPagedPool
, sizeof (FNSAVE_FORMAT
));
958 if (!FpState
) return STATUS_INSUFFICIENT_RESOURCES
;
960 *((PVOID
*) Save
) = FpState
;
962 asm volatile("fnsave %0\n\t" : "=m" (*FpState
));
970 KeGetCurrentThread()->DispatcherHeader
.NpxIrql
= KeGetCurrentIrql();
971 return STATUS_SUCCESS
;
979 KeRestoreFloatingPointState(IN PKFLOATING_SAVE Save
)
981 PFNSAVE_FORMAT FpState
= *((PVOID
*) Save
);
982 ASSERT(KeGetCurrentThread()->DispatcherHeader
.NpxIrql
== KeGetCurrentIrql());
983 DPRINT1("%s is not really implemented\n", __FUNCTION__
);
986 asm volatile("fnclex\n\t");
987 asm volatile("frstor %0\n\t" : "=m" (*FpState
));
997 return STATUS_SUCCESS
;
1005 KeGetRecommendedSharedDataAlignment(VOID
)
1007 /* Return the global variable */
1008 return KeLargestCacheLine
;
1016 KeFlushEntireTb(IN BOOLEAN Invalid
,
1017 IN BOOLEAN AllProcessors
)
1021 /* Raise the IRQL for the TB Flush */
1022 OldIrql
= KeRaiseIrqlToSynchLevel();
1025 /* FIXME: Support IPI Flush */
1026 #error Not yet implemented!
1029 /* Flush the TB for the Current CPU */
1032 /* Return to Original IRQL */
1033 KeLowerIrql(OldIrql
);
1041 KeSetDmaIoCoherency(IN ULONG Coherency
)
1043 /* Save the coherency globally */
1044 KiDmaIoCoherency
= Coherency
;
1052 KeQueryActiveProcessors(VOID
)
1056 /* Simply return the number of active processors */
1057 return KeActiveProcessors
;
1065 KeSaveStateForHibernate(IN PKPROCESSOR_STATE State
)
1067 /* Capture the context */
1068 RtlCaptureContext(&State
->ContextFrame
);
1070 /* Capture the control state */
1071 KiSaveProcessorControlState(State
);