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 /* FIXME: Local EFLAGS defines not used anywhere else */
16 #define EFLAGS_IOPL 0x3000
17 #define EFLAGS_NF 0x4000
18 #define EFLAGS_RF 0x10000
19 #define EFLAGS_ID 0x200000
21 /* GLOBALS *******************************************************************/
26 /* The TSS to use for Double Fault Traps (INT 0x9) */
27 UCHAR KiDoubleFaultTSS
[KTSS_IO_MAPS
];
29 /* The TSS to use for NMI Fault Traps (INT 0x2) */
30 UCHAR KiNMITSS
[KTSS_IO_MAPS
];
32 /* The Boot GDT (FIXME: should have more entries */
33 KGDTENTRY KiBootGdt
[12] =
35 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_NULL */
36 {0xffff, 0x0000, {{0x00, 0x9a, 0xcf, 0x00}}}, /* KGDT_R0_CODE */
37 {0xffff, 0x0000, {{0x00, 0x92, 0xcf, 0x00}}}, /* KGDT_R0_DATA */
38 {0xffff, 0x0000, {{0x00, 0xfa, 0xcf, 0x00}}}, /* KGDT_R3_CODE */
39 {0xffff, 0x0000, {{0x00, 0xf2, 0xcf, 0x00}}}, /* KGDT_R3_DATA*/
40 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_TSS */
41 {0x0fff, 0x0000, {{0x00, 0x92, 0x00, 0xff}}}, /* KGDT_R0_PCR */
42 {0x0fff, 0x0000, {{0x00, 0xf2, 0x00, 0x00}}}, /* KGDT_R3_TEB */
43 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_UNUSED */
44 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_LDT */
45 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_DF_TSS */
46 {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}} /* KGDT_NMI_TSS */
50 KDESCRIPTOR KiGdtDescriptor
= {sizeof(KiBootGdt
), (ULONG
)KiBootGdt
};
52 /* CPU Features and Flags */
55 ULONG KeProcessorArchitecture
;
56 ULONG KeProcessorLevel
;
57 ULONG KeProcessorRevision
;
59 ULONG KiFastSystemCallDisable
= 1;
60 ULONG KeI386NpxPresent
= 0;
61 ULONG KiMXCsrMask
= 0;
62 ULONG MxcsrFeatureMask
= 0;
63 ULONG KeI386XMMIPresent
= 0;
64 ULONG KeI386FxsrPresent
= 0;
65 ULONG KeI386MachineType
;
66 ULONG Ke386Pae
= FALSE
;
67 ULONG Ke386NoExecute
= FALSE
;
68 ULONG KeLargestCacheLine
= 0x40;
69 ULONG KeDcacheFlushCount
= 0;
70 ULONG KeIcacheFlushCount
= 0;
71 ULONG KiDmaIoCoherency
= 0;
72 CHAR KeNumberProcessors
;
73 KAFFINITY KeActiveProcessors
= 1;
74 BOOLEAN KiI386PentiumLockErrataPresent
;
75 BOOLEAN KiSMTProcessorsPresent
;
78 static const CHAR CmpIntelID
[] = "GenuineIntel";
79 static const CHAR CmpAmdID
[] = "AuthenticAMD";
80 static const CHAR CmpCyrixID
[] = "CyrixInstead";
81 static const CHAR CmpTransmetaID
[] = "GenuineTMx86";
82 static const CHAR CmpCentaurID
[] = "CentaurHauls";
83 static const CHAR CmpRiseID
[] = "RiseRiseRise";
85 /* SUPPORT ROUTINES FOR MSVC COMPATIBILITY ***********************************/
89 CPUID(OUT ULONG CpuInfo
[4],
92 Ki386Cpuid(InfoType
, &CpuInfo
[0], &CpuInfo
[1], &CpuInfo
[2], &CpuInfo
[3]);
96 WRMSR(IN ULONG Register
,
99 LARGE_INTEGER LargeVal
;
100 LargeVal
.QuadPart
= Value
;
101 Ke386Wrmsr(Register
, LargeVal
.HighPart
, LargeVal
.LowPart
);
105 RDMSR(IN ULONG Register
)
107 LARGE_INTEGER LargeVal
;
108 Ke386Rdmsr(Register
, LargeVal
.HighPart
, LargeVal
.LowPart
);
109 return LargeVal
.QuadPart
;
112 /* FUNCTIONS *****************************************************************/
116 KiSetProcessorType(VOID
)
118 ULONG EFlags
, NewEFlags
;
120 ULONG Stepping
, Type
;
122 /* Start by assuming no CPUID data */
123 KeGetCurrentPrcb()->CpuID
= 0;
126 Ke386SaveFlags(EFlags
);
128 /* XOR out the ID bit and update EFlags */
129 NewEFlags
= EFlags
^ EFLAGS_ID
;
130 Ke386RestoreFlags(NewEFlags
);
132 /* Get them back and see if they were modified */
133 Ke386SaveFlags(NewEFlags
);
134 if (NewEFlags
!= EFlags
)
136 /* The modification worked, so CPUID exists. Set the ID Bit again. */
138 Ke386RestoreFlags(EFlags
);
140 /* Peform CPUID 0 to see if CPUID 1 is supported */
148 * Get the Stepping and Type. The stepping contains both the
149 * Model and the Step, while the Type contains the returned Type.
150 * We ignore the family.
152 * For the stepping, we convert this: zzzzzzxy into this: x0y
154 Stepping
= Reg
[0] & 0xF0;
156 Stepping
+= (Reg
[0] & 0xFF);
158 Type
= Reg
[0] & 0xF00;
161 /* Save them in the PRCB */
162 KeGetCurrentPrcb()->CpuID
= TRUE
;
163 KeGetCurrentPrcb()->CpuType
= (UCHAR
)Type
;
164 KeGetCurrentPrcb()->CpuStep
= (USHORT
)Stepping
;
168 DPRINT1("CPUID Support lacking\n");
173 DPRINT1("CPUID Support lacking\n");
177 Ke386RestoreFlags(EFlags
);
184 PKPRCB Prcb
= KeGetCurrentPrcb();
188 /* Assume no Vendor ID and fail if no CPUID Support. */
189 Prcb
->VendorString
[0] = 0;
190 if (!Prcb
->CpuID
) return 0;
192 /* Get the Vendor ID and null-terminate it */
196 /* Re-arrange vendor string */
198 Vendor
[2] = Vendor
[3];
201 /* Copy it to the PRCB and null-terminate it again */
202 RtlCopyMemory(Prcb
->VendorString
,
204 sizeof(Prcb
->VendorString
) - sizeof(CHAR
));
205 Prcb
->VendorString
[sizeof(Prcb
->VendorString
) - sizeof(CHAR
)] = ANSI_NULL
;
207 /* Now check the CPU Type */
208 if (!strcmp(Prcb
->VendorString
, CmpIntelID
))
212 else if (!strcmp(Prcb
->VendorString
, CmpAmdID
))
216 else if (!strcmp(Prcb
->VendorString
, CmpCyrixID
))
218 DPRINT1("Cyrix CPUs not fully supported\n");
221 else if (!strcmp(Prcb
->VendorString
, CmpTransmetaID
))
223 DPRINT1("Transmeta CPUs not fully supported\n");
226 else if (!strcmp(Prcb
->VendorString
, CmpCentaurID
))
228 DPRINT1("VIA CPUs not fully supported\n");
231 else if (!strcmp(Prcb
->VendorString
, CmpRiseID
))
233 DPRINT1("Rise CPUs not fully supported\n");
243 KiGetFeatureBits(VOID
)
245 PKPRCB Prcb
= KeGetCurrentPrcb();
247 ULONG FeatureBits
= KF_WORKING_PTE
;
249 BOOLEAN ExtendedCPUID
= TRUE
;
250 ULONG CpuFeatures
= 0;
252 /* Get the Vendor ID */
253 Vendor
= KiGetCpuVendor();
255 /* Make sure we got a valid vendor ID at least. */
256 if (!Vendor
) return FeatureBits
;
258 /* Get the CPUID Info. Features are in Reg[3]. */
261 /* Set the initial APIC ID */
262 Prcb
->InitialApicId
= (UCHAR
)(Reg
[1] >> 24);
264 /* Check for AMD CPU */
265 if (Vendor
== CPU_AMD
)
267 /* Check if this is a K5 or higher. */
268 if ((Reg
[0] & 0x0F00) >= 0x0500)
270 /* Check if this is a K5 specifically. */
271 if ((Reg
[0] & 0x0F00) == 0x0500)
273 /* Get the Model Number */
274 switch (Reg
[0] & 0x00F0)
276 /* Check if this is the Model 1 */
279 /* Check if this is Step 0 or 1. They don't support PGE */
280 if ((Reg
[0] & 0x000F) > 0x03) break;
284 /* Model 0 doesn't support PGE at all. */
290 /* K6-2, Step 8 and over have support for MTRR. */
291 if ((Reg
[0] & 0x000F) >= 0x8) FeatureBits
|= KF_AMDK6MTRR
;
296 /* As does the K6-3 */
297 FeatureBits
|= KF_AMDK6MTRR
;
307 /* Families below 5 don't support PGE, PSE or CMOV at all */
308 Reg
[3] &= ~(0x08 | 0x2000 | 0x8000);
310 /* They also don't support advanced CPUID functions. */
311 ExtendedCPUID
= FALSE
;
314 /* Set the current features */
315 CpuFeatures
= Reg
[3];
318 /* Now check if this is Intel */
319 if (Vendor
== CPU_INTEL
)
321 /* Check if it's a P6 */
322 if (Prcb
->CpuType
== 6)
324 /* Perform the special sequence to get the MicroCode Signature */
327 Prcb
->UpdateSignature
.QuadPart
= RDMSR(0x8B);
329 else if (Prcb
->CpuType
== 5)
331 /* On P5, enable workaround for the LOCK errata. */
332 KiI386PentiumLockErrataPresent
= TRUE
;
335 /* Check for broken P6 with bad SMP PTE implementation */
336 if (((Reg
[0] & 0x0FF0) == 0x0610 && (Reg
[0] & 0x000F) <= 0x9) ||
337 ((Reg
[0] & 0x0FF0) == 0x0630 && (Reg
[0] & 0x000F) <= 0x4))
339 /* Remove support for correct PTE support. */
340 FeatureBits
&= ~KF_WORKING_PTE
;
343 /* Set the current features */
344 CpuFeatures
= Reg
[3];
347 /* Convert all CPUID Feature bits into our format */
348 if (CpuFeatures
& 0x00000002) FeatureBits
|= KF_V86_VIS
| KF_CR4
;
349 if (CpuFeatures
& 0x00000008) FeatureBits
|= KF_LARGE_PAGE
| KF_CR4
;
350 if (CpuFeatures
& 0x00000010) FeatureBits
|= KF_RDTSC
;
351 if (CpuFeatures
& 0x00000100) FeatureBits
|= KF_CMPXCHG8B
;
352 if (CpuFeatures
& 0x00000800) FeatureBits
|= KF_FAST_SYSCALL
;
353 if (CpuFeatures
& 0x00001000) FeatureBits
|= KF_MTRR
;
354 if (CpuFeatures
& 0x00002000) FeatureBits
|= KF_GLOBAL_PAGE
| KF_CR4
;
355 if (CpuFeatures
& 0x00008000) FeatureBits
|= KF_CMOV
;
356 if (CpuFeatures
& 0x00010000) FeatureBits
|= KF_PAT
;
357 if (CpuFeatures
& 0x00800000) FeatureBits
|= KF_MMX
;
358 if (CpuFeatures
& 0x01000000) FeatureBits
|= KF_FXSR
;
359 if (CpuFeatures
& 0x02000000) FeatureBits
|= KF_XMMI
;
360 if (CpuFeatures
& 0x04000000) FeatureBits
|= KF_XMMI64
;
362 /* Check if the CPU has hyper-threading */
363 if (CpuFeatures
& 0x10000000)
365 /* Set the number of logical CPUs */
366 Prcb
->LogicalProcessorsPerPhysicalProcessor
= (UCHAR
)(Reg
[1] >> 16);
367 if (Prcb
->LogicalProcessorsPerPhysicalProcessor
> 1)
369 /* We're on dual-core */
370 KiSMTProcessorsPresent
= TRUE
;
375 /* We only have a single CPU */
376 Prcb
->LogicalProcessorsPerPhysicalProcessor
= 1;
379 /* Check if CPUID 0x80000000 is supported */
383 CPUID(Reg
, 0x80000000);
384 if ((Reg
[0] & 0xffffff00) == 0x80000000)
386 /* Check if CPUID 0x80000001 is supported */
387 if (Reg
[0] >= 0x80000001)
389 /* Check which extended features are available. */
390 CPUID(Reg
, 0x80000001);
392 /* Now handle each features for each CPU Vendor */
396 if (Reg
[3] & 0x80000000) FeatureBits
|= KF_3DNOW
;
403 /* Return the Feature Bits */
409 KiGetCacheInformation(VOID
)
411 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
414 ULONG CacheRequests
= 0, i
;
415 ULONG CurrentRegister
;
417 BOOLEAN FirstPass
= TRUE
;
419 /* Set default L2 size */
420 Pcr
->SecondLevelCacheSize
= 0;
422 /* Get the Vendor ID and make sure we support CPUID */
423 Vendor
= KiGetCpuVendor();
426 /* Check the Vendor ID */
429 /* Handle Intel case */
432 /*Check if we support CPUID 2 */
436 /* We need to loop for the number of times CPUID will tell us to */
439 /* Do the CPUID call */
442 /* Check if it was the first call */
446 * The number of times to loop is the first byte. Read
447 * it and then destroy it so we don't get confused.
449 CacheRequests
= Data
[0] & 0xFF;
450 Data
[0] &= 0xFFFFFF00;
452 /* Don't go over this again */
456 /* Loop all 4 registers */
457 for (i
= 0; i
< 4; i
++)
459 /* Get the current register */
460 CurrentRegister
= Data
[i
];
463 * If the upper bit is set, then this register should
466 if (CurrentRegister
& 0x80000000) continue;
468 /* Keep looping for every byte inside this register */
469 while (CurrentRegister
)
471 /* Read a byte, skip a byte. */
472 RegisterByte
= (UCHAR
)(CurrentRegister
& 0xFF);
473 CurrentRegister
>>= 8;
474 if (!RegisterByte
) continue;
477 * Valid values are from 0x40 (0 bytes) to 0x49
478 * (32MB), or from 0x80 to 0x89 (same size but
481 if (((RegisterByte
> 0x40) &&
482 (RegisterByte
<= 0x49)) ||
483 ((RegisterByte
> 0x80) &&
484 (RegisterByte
<= 0x89)))
486 /* Mask out only the first nibble */
487 RegisterByte
&= 0x0F;
489 /* Set the L2 Cache Size */
490 Pcr
->SecondLevelCacheSize
= 0x10000 <<
495 } while (--CacheRequests
);
502 DPRINT1("Not handling AMD caches yet\n");
513 /* Save current CR0 */
516 /* If this is a 486, enable Write-Protection */
517 if (KeGetCurrentPrcb()->CpuType
> 3) Cr0
|= CR0_WP
;
525 KiInitializeTSS2(IN PKTSS Tss
,
526 IN PKGDTENTRY TssEntry OPTIONAL
)
530 /* Make sure the GDT Entry is valid */
534 TssEntry
->LimitLow
= sizeof(KTSS
) - 1;
535 TssEntry
->HighWord
.Bits
.LimitHi
&= 0xF0;
538 /* Now clear the I/O Map */
539 RtlFillMemory(Tss
->IoMaps
[0].IoMap
, 8096, -1);
541 /* Initialize Interrupt Direction Maps */
542 p
= (PUCHAR
)(Tss
->IoMaps
[0].DirectionMap
);
543 RtlZeroMemory(p
, 32);
545 /* Add DPMI support for interrupts */
550 /* Initialize the default Interrupt Direction Map */
551 p
= Tss
->IntDirectionMap
;
552 RtlZeroMemory(Tss
->IntDirectionMap
, 32);
554 /* Add DPMI support */
562 KiInitializeTSS(IN PKTSS Tss
)
564 /* Set an invalid map base */
565 Tss
->IoMapBase
= KiComputeIopmOffset(IO_ACCESS_MAP_NONE
);
567 /* Disable traps during Task Switches */
570 /* Set LDT and Ring 0 SS */
572 Tss
->Ss0
= KGDT_R0_DATA
;
577 Ki386InitializeTss(IN PKTSS Tss
,
581 PKGDTENTRY TssEntry
, TaskGateEntry
;
583 /* Initialize the boot TSS. */
584 TssEntry
= &Gdt
[KGDT_TSS
/ sizeof(KGDTENTRY
)];
585 TssEntry
->HighWord
.Bits
.Type
= I386_TSS
;
586 TssEntry
->HighWord
.Bits
.Pres
= 1;
587 TssEntry
->HighWord
.Bits
.Dpl
= 0;
588 KiInitializeTSS2(Tss
, TssEntry
);
589 KiInitializeTSS(Tss
);
591 /* Load the task register */
592 Ke386SetTr(KGDT_TSS
);
594 /* Setup the Task Gate for Double Fault Traps */
595 TaskGateEntry
= (PKGDTENTRY
)&Idt
[8];
596 TaskGateEntry
->HighWord
.Bits
.Type
= I386_TASK_GATE
;
597 TaskGateEntry
->HighWord
.Bits
.Pres
= 1;
598 TaskGateEntry
->HighWord
.Bits
.Dpl
= 0;
599 ((PKIDTENTRY
)TaskGateEntry
)->Selector
= KGDT_DF_TSS
;
601 /* Initialize the TSS used for handling double faults. */
602 Tss
= (PKTSS
)KiDoubleFaultTSS
;
603 KiInitializeTSS(Tss
);
604 Tss
->CR3
= _Ke386GetCr(3);
605 Tss
->Esp0
= PtrToUlong(KiDoubleFaultStack
);
606 Tss
->Eip
= PtrToUlong(KiTrap8
);
607 Tss
->Cs
= KGDT_R0_CODE
;
608 Tss
->Fs
= KGDT_R0_PCR
;
609 Tss
->Ss
= Ke386GetSs();
610 Tss
->Es
= KGDT_R3_DATA
| RPL_MASK
;
611 Tss
->Ds
= KGDT_R3_DATA
| RPL_MASK
;
613 /* Setup the Double Trap TSS entry in the GDT */
614 TssEntry
= &Gdt
[KGDT_DF_TSS
/ sizeof(KGDTENTRY
)];
615 TssEntry
->HighWord
.Bits
.Type
= I386_TSS
;
616 TssEntry
->HighWord
.Bits
.Pres
= 1;
617 TssEntry
->HighWord
.Bits
.Dpl
= 0;
618 TssEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Tss
& 0xFFFF);
619 TssEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Tss
>> 16);
620 TssEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Tss
>> 24);
621 TssEntry
->LimitLow
= KTSS_IO_MAPS
;
623 /* Now setup the NMI Task Gate */
624 TaskGateEntry
= (PKGDTENTRY
)&Idt
[2];
625 TaskGateEntry
->HighWord
.Bits
.Type
= I386_TASK_GATE
;
626 TaskGateEntry
->HighWord
.Bits
.Pres
= 1;
627 TaskGateEntry
->HighWord
.Bits
.Dpl
= 0;
628 ((PKIDTENTRY
)TaskGateEntry
)->Selector
= KGDT_NMI_TSS
;
630 /* Initialize the actual TSS */
631 Tss
= (PKTSS
)KiNMITSS
;
632 KiInitializeTSS(Tss
);
633 Tss
->CR3
= _Ke386GetCr(3);
634 Tss
->Esp0
= PtrToUlong(KiDoubleFaultStack
);
635 Tss
->Eip
= PtrToUlong(KiTrap2
);
636 Tss
->Cs
= KGDT_R0_CODE
;
637 Tss
->Fs
= KGDT_R0_PCR
;
638 Tss
->Ss
= Ke386GetSs();
639 Tss
->Es
= KGDT_R3_DATA
| RPL_MASK
;
640 Tss
->Ds
= KGDT_R3_DATA
| RPL_MASK
;
642 /* And its associated TSS Entry */
643 TssEntry
= &Gdt
[KGDT_NMI_TSS
/ sizeof(KGDTENTRY
)];
644 TssEntry
->HighWord
.Bits
.Type
= I386_TSS
;
645 TssEntry
->HighWord
.Bits
.Pres
= 1;
646 TssEntry
->HighWord
.Bits
.Dpl
= 0;
647 TssEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Tss
& 0xFFFF);
648 TssEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Tss
>> 16);
649 TssEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Tss
>> 24);
650 TssEntry
->LimitLow
= KTSS_IO_MAPS
;
655 KeFlushCurrentTb(VOID
)
657 /* Flush the TLB by resetting CR3 */
658 _Ke386SetCr(3, _Ke386GetCr(3));
663 KiSaveProcessorControlState(IN PKPROCESSOR_STATE ProcessorState
)
665 /* Save the CR registers */
666 ProcessorState
->SpecialRegisters
.Cr0
= _Ke386GetCr(0);
667 ProcessorState
->SpecialRegisters
.Cr2
= _Ke386GetCr(2);
668 ProcessorState
->SpecialRegisters
.Cr3
= _Ke386GetCr(3);
669 ProcessorState
->SpecialRegisters
.Cr4
= _Ke386GetCr(4);
671 /* Save the DR registers */
672 ProcessorState
->SpecialRegisters
.KernelDr0
= _Ke386GetDr(0);
673 ProcessorState
->SpecialRegisters
.KernelDr1
= _Ke386GetDr(1);
674 ProcessorState
->SpecialRegisters
.KernelDr2
= _Ke386GetDr(2);
675 ProcessorState
->SpecialRegisters
.KernelDr3
= _Ke386GetDr(3);
676 ProcessorState
->SpecialRegisters
.KernelDr6
= _Ke386GetDr(6);
677 ProcessorState
->SpecialRegisters
.KernelDr7
= _Ke386GetDr(7);
680 /* Save GDT, IDT, LDT and TSS */
681 Ke386GetGlobalDescriptorTable(ProcessorState
->SpecialRegisters
.Gdtr
);
682 Ke386GetInterruptDescriptorTable(ProcessorState
->SpecialRegisters
.Idtr
);
683 Ke386GetTr(ProcessorState
->SpecialRegisters
.Tr
);
684 Ke386GetLocalDescriptorTable(ProcessorState
->SpecialRegisters
.Ldtr
);
689 KiInitializeMachineType(VOID
)
691 /* Set the Machine Type we got from NTLDR */
692 KeI386MachineType
= KeLoaderBlock
->u
.I386
.MachineType
& 0x000FF;
697 KiLoadFastSyscallMachineSpecificRegisters(IN ULONG_PTR Context
)
700 Ke386Wrmsr(0x174, KGDT_R0_CODE
, 0);
701 Ke386Wrmsr(0x175, KeGetCurrentPrcb()->DpcStack
, 0);
704 Ke386Wrmsr(0x176, KiFastCallEntry
, 0);
710 KiRestoreFastSyscallReturnState(VOID
)
712 /* FIXME: NT has support for SYSCALL, IA64-SYSENTER, etc. */
714 /* Check if the CPU Supports fast system call */
715 if (KeFeatureBits
& KF_FAST_SYSCALL
)
717 /* Do an IPI to enable it */
718 KeIpiGenericCall(KiLoadFastSyscallMachineSpecificRegisters
, 0);
724 Ki386EnableDE(IN ULONG_PTR Context
)
727 Ke386SetCr4(Ke386GetCr4() | CR4_DE
);
733 Ki386EnableFxsr(IN ULONG_PTR Context
)
736 Ke386SetCr4(Ke386GetCr4() | CR4_FXSR
);
742 Ki386EnableXMMIExceptions(IN ULONG_PTR Context
)
744 /* FIXME: Support this */
745 DPRINT1("Your machine supports XMMI exceptions but ReactOS doesn't\n");
751 KiI386PentiumLockErrataFixup(VOID
)
753 /* FIXME: Support this */
754 DPRINT1("WARNING: Your machine has a CPU bug that ReactOS can't bypass!\n");
757 /* PUBLIC FUNCTIONS **********************************************************/
764 KeSaveFloatingPointState(OUT PKFLOATING_SAVE Save
)
766 PFNSAVE_FORMAT FpState
;
767 ASSERT_IRQL(DISPATCH_LEVEL
);
768 DPRINT1("%s is not really implemented\n", __FUNCTION__
);
770 /* check if we are doing software emulation */
771 if (!KeI386NpxPresent
) return STATUS_ILLEGAL_FLOAT_CONTEXT
;
773 FpState
= ExAllocatePool(NonPagedPool
, sizeof (FNSAVE_FORMAT
));
774 if (!FpState
) return STATUS_INSUFFICIENT_RESOURCES
;
776 *((PVOID
*) Save
) = FpState
;
778 asm volatile("fnsave %0\n\t" : "=m" (*FpState
));
786 KeGetCurrentThread()->DispatcherHeader
.NpxIrql
= KeGetCurrentIrql();
787 return STATUS_SUCCESS
;
795 KeRestoreFloatingPointState(IN PKFLOATING_SAVE Save
)
797 PFNSAVE_FORMAT FpState
= *((PVOID
*) Save
);
798 ASSERT(KeGetCurrentThread()->DispatcherHeader
.NpxIrql
== KeGetCurrentIrql());
799 DPRINT1("%s is not really implemented\n", __FUNCTION__
);
802 asm volatile("fnclex\n\t");
803 asm volatile("frstor %0\n\t" : "=m" (*FpState
));
813 return STATUS_SUCCESS
;
821 KeGetRecommendedSharedDataAlignment(VOID
)
823 /* Return the global variable */
824 return KeLargestCacheLine
;
832 KeFlushEntireTb(IN BOOLEAN Invalid
,
833 IN BOOLEAN AllProcessors
)
837 /* Raise the IRQL for the TB Flush */
838 OldIrql
= KeRaiseIrqlToSynchLevel();
841 /* FIXME: Support IPI Flush */
842 #error Not yet implemented!
845 /* Flush the TB for the Current CPU */
848 /* Return to Original IRQL */
849 KeLowerIrql(OldIrql
);
857 KeSetDmaIoCoherency(IN ULONG Coherency
)
859 /* Save the coherency globally */
860 KiDmaIoCoherency
= Coherency
;
868 KeQueryActiveProcessors(VOID
)
872 /* Simply return the number of active processors */
873 return KeActiveProcessors
;
881 KeSaveStateForHibernate(IN PKPROCESSOR_STATE State
)
883 /* Capture the context */
884 RtlCaptureContext(&State
->ContextFrame
);
886 /* Capture the control state */
887 KiSaveProcessorControlState(State
);