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 MxcsrFeatureMask
= 0;
62 ULONG KeI386XMMIPresent
= 0;
63 ULONG KeI386FxsrPresent
= 0;
64 ULONG KeI386MachineType
;
65 ULONG Ke386Pae
= FALSE
;
66 ULONG Ke386GlobalPagesEnabled
= FALSE
;
67 ULONG Ke386NoExecute
= FALSE
;
68 BOOLEAN KiI386PentiumLockErrataPresent
;
69 ULONG KeLargestCacheLine
= 0x40;
70 ULONG KeDcacheFlushCount
= 0;
71 ULONG KeIcacheFlushCount
= 0;
72 ULONG KiDmaIoCoherency
= 0;
73 CHAR KeNumberProcessors
;
74 KAFFINITY KeActiveProcessors
= 1;
77 CHAR CmpIntelID
[] = "GenuineIntel";
78 CHAR CmpAmdID
[] = "AuthenticAMD";
79 CHAR CmpCyrixID
[] = "CyrixInstead";
80 CHAR CmpTransmetaID
[] = "GenuineTMx86";
81 CHAR CmpCentaurID
[] = "CentaurHauls";
82 CHAR CmpRiseID
[] = "RiseRiseRise";
84 /* SUPPORT ROUTINES FOR MSVC COMPATIBILITY ***********************************/
88 CPUID(IN ULONG CpuInfo
[4],
91 Ki386Cpuid(InfoType
, &CpuInfo
[0], &CpuInfo
[1], &CpuInfo
[2], &CpuInfo
[3]);
95 WRMSR(IN ULONG Register
,
98 LARGE_INTEGER LargeVal
;
99 LargeVal
.QuadPart
= Value
;
100 Ke386Wrmsr(Register
, LargeVal
.HighPart
, LargeVal
.LowPart
);
104 RDMSR(IN ULONG Register
)
106 LARGE_INTEGER LargeVal
;
107 Ke386Rdmsr(Register
, LargeVal
.HighPart
, LargeVal
.LowPart
);
108 return LargeVal
.QuadPart
;
111 /* FUNCTIONS *****************************************************************/
115 KiSetProcessorType(VOID
)
117 ULONG EFlags
, NewEFlags
;
119 ULONG Stepping
, Type
;
121 /* Start by assuming no CPUID data */
122 KeGetCurrentPrcb()->CpuID
= 0;
125 Ke386SaveFlags(EFlags
);
127 /* XOR out the ID bit and update EFlags */
128 NewEFlags
= EFlags
^ EFLAGS_ID
;
129 Ke386RestoreFlags(NewEFlags
);
131 /* Get them back and see if they were modified */
132 Ke386SaveFlags(NewEFlags
);
133 if (NewEFlags
!= EFlags
)
135 /* The modification worked, so CPUID exists. Set the ID Bit again. */
137 Ke386RestoreFlags(EFlags
);
139 /* Peform CPUID 0 to see if CPUID 1 is supported */
147 * Get the Stepping and Type. The stepping contains both the
148 * Model and the Step, while the Type contains the returned Type.
149 * We ignore the family.
151 * For the stepping, we convert this: zzzzzzxy into this: x0y
153 Stepping
= Reg
[0] & 0xF0;
155 Stepping
+= (Reg
[0] & 0xFF);
157 Type
= Reg
[0] & 0xF00;
160 /* Save them in the PRCB */
161 KeGetCurrentPrcb()->CpuID
= TRUE
;
162 KeGetCurrentPrcb()->CpuType
= (UCHAR
)Type
;
163 KeGetCurrentPrcb()->CpuStep
= (USHORT
)Stepping
;
167 DPRINT1("CPUID Support lacking\n");
172 DPRINT1("CPUID Support lacking\n");
176 Ke386RestoreFlags(EFlags
);
183 PKPRCB Prcb
= KeGetCurrentPrcb();
186 /* Assume no Vendor ID and fail if no CPUID Support. */
187 Prcb
->VendorString
[0] = 0;
188 if (!Prcb
->CpuID
) return 0;
190 /* Get the Vendor ID and null-terminate it */
194 /* Re-arrange vendor string */
195 Vendor
[5] = Vendor
[2];
196 Vendor
[2] = Vendor
[3];
197 Vendor
[3] = Vendor
[5];
199 /* Copy it to the PRCB and null-terminate it again */
200 RtlCopyMemory(Prcb
->VendorString
,
202 sizeof(Prcb
->VendorString
) - sizeof(CHAR
));
203 Prcb
->VendorString
[sizeof(Prcb
->VendorString
) - sizeof(CHAR
)] = ANSI_NULL
;
205 /* Now check the CPU Type */
206 if (!strcmp(Prcb
->VendorString
, CmpIntelID
))
210 else if (!strcmp(Prcb
->VendorString
, CmpAmdID
))
214 else if (!strcmp(Prcb
->VendorString
, CmpCyrixID
))
216 DPRINT1("Cyrix CPUs not fully supported\n");
219 else if (!strcmp(Prcb
->VendorString
, CmpTransmetaID
))
221 DPRINT1("Transmeta CPUs not fully supported\n");
224 else if (!strcmp(Prcb
->VendorString
, CmpCentaurID
))
226 DPRINT1("VIA CPUs not fully supported\n");
229 else if (!strcmp(Prcb
->VendorString
, CmpRiseID
))
231 DPRINT1("Rise CPUs not fully supported\n");
241 KiGetFeatureBits(VOID
)
243 PKPRCB Prcb
= KeGetCurrentPrcb();
245 ULONG FeatureBits
= KF_WORKING_PTE
;
247 BOOLEAN ExtendedCPUID
= TRUE
;
248 ULONG CpuFeatures
= 0;
250 /* Get the Vendor ID */
251 Vendor
= KiGetCpuVendor();
253 /* Make sure we got a valid vendor ID at least. */
254 if (!Vendor
) return FeatureBits
;
256 /* Get the CPUID Info. Features are in Reg[3]. */
259 /* Check for AMD CPU */
260 if (Vendor
== CPU_AMD
)
262 /* Check if this is a K5 or higher. */
263 if ((Reg
[0] & 0x0F00) >= 0x0500)
265 /* Check if this is a K5 specifically. */
266 if ((Reg
[0] & 0x0F00) == 0x0500)
268 /* Get the Model Number */
269 switch (Reg
[0] & 0x00F0)
271 /* Check if this is the Model 1 */
274 /* Check if this is Step 0 or 1. They don't support PGE */
275 if ((Reg
[0] & 0x000F) > 0x03) break;
279 /* Model 0 doesn't support PGE at all. */
285 /* K6-2, Step 8 and over have support for MTRR. */
286 if ((Reg
[0] & 0x000F) >= 0x8) FeatureBits
|= KF_AMDK6MTRR
;
291 /* As does the K6-3 */
292 FeatureBits
|= KF_AMDK6MTRR
;
302 /* Familes below 5 don't support PGE, PSE or CMOV at all */
303 Reg
[3] &= ~(0x08 | 0x2000 | 0x8000);
305 /* They also don't support advanced CPUID functions. */
306 ExtendedCPUID
= FALSE
;
309 /* Set the current features */
310 CpuFeatures
= Reg
[3];
313 /* Now check if this is Intel */
314 if (Vendor
== CPU_INTEL
)
316 /* Check if it's a P6 */
317 if (Prcb
->CpuType
== 6)
319 /* Perform the special sequence to get the MicroCode Signature */
322 Prcb
->UpdateSignature
.QuadPart
= RDMSR(0x8B);
324 else if (Prcb
->CpuType
== 5)
326 /* On P5, enable workaround for the LOCK errata. */
327 KiI386PentiumLockErrataPresent
= TRUE
;
330 /* Check for broken P6 with bad SMP PTE implementation */
331 if (((Reg
[0] & 0x0FF0) == 0x0610 && (Reg
[0] & 0x000F) <= 0x9) ||
332 ((Reg
[0] & 0x0FF0) == 0x0630 && (Reg
[0] & 0x000F) <= 0x4))
334 /* Remove support for correct PTE support. */
335 FeatureBits
&= ~KF_WORKING_PTE
;
338 /* Set the current features */
339 CpuFeatures
= Reg
[3];
342 /* Convert all CPUID Feature bits into our format */
343 if (CpuFeatures
& 0x00000002) FeatureBits
|= KF_V86_VIS
| KF_CR4
;
344 if (CpuFeatures
& 0x00000008) FeatureBits
|= KF_LARGE_PAGE
| KF_CR4
;
345 if (CpuFeatures
& 0x00000010) FeatureBits
|= KF_RDTSC
;
346 if (CpuFeatures
& 0x00000100) FeatureBits
|= KF_CMPXCHG8B
;
347 if (CpuFeatures
& 0x00000800) FeatureBits
|= KF_FAST_SYSCALL
;
348 if (CpuFeatures
& 0x00001000) FeatureBits
|= KF_MTRR
;
349 if (CpuFeatures
& 0x00002000) FeatureBits
|= KF_GLOBAL_PAGE
| KF_CR4
;
350 if (CpuFeatures
& 0x00008000) FeatureBits
|= KF_CMOV
;
351 if (CpuFeatures
& 0x00010000) FeatureBits
|= KF_PAT
;
352 if (CpuFeatures
& 0x00800000) FeatureBits
|= KF_MMX
;
353 if (CpuFeatures
& 0x01000000) FeatureBits
|= KF_FXSR
;
354 if (CpuFeatures
& 0x02000000) FeatureBits
|= KF_XMMI
;
356 /* Check if CPUID 0x80000000 is supported */
360 CPUID(Reg
, 0x80000000);
361 if ((Reg
[0] & 0xffffff00) == 0x80000000)
363 /* Check if CPUID 0x80000001 is supported */
364 if (Reg
[0] >= 0x80000001)
366 /* Check which extended features are available. */
367 CPUID(Reg
, 0x80000001);
369 /* Now handle each features for each CPU Vendor */
373 if (Reg
[3] & 0x80000000) FeatureBits
|= KF_3DNOW
;
380 /* Return the Feature Bits */
386 KiGetCacheInformation(VOID
)
388 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
391 ULONG CacheRequests
= 0, i
;
392 ULONG CurrentRegister
;
394 BOOLEAN FirstPass
= TRUE
;
396 /* Set default L2 size */
397 Pcr
->SecondLevelCacheSize
= 0;
399 /* Get the Vendor ID and make sure we support CPUID */
400 Vendor
= KiGetCpuVendor();
403 /* Check the Vendor ID */
406 /* Handle Intel case */
409 /*Check if we support CPUID 2 */
413 /* We need to loop for the number of times CPUID will tell us to */
416 /* Do the CPUID call */
419 /* Check if it was the first call */
423 * The number of times to loop is the first byte. Read
424 * it and then destroy it so we don't get confused.
426 CacheRequests
= Data
[0] & 0xFF;
427 Data
[0] &= 0xFFFFFF00;
429 /* Don't go over this again */
433 /* Loop all 4 registers */
434 for (i
= 0; i
< 4; i
++)
436 /* Get the current register */
437 CurrentRegister
= Data
[i
];
440 * If the upper bit is set, then this register should
443 if (CurrentRegister
& 0x80000000) continue;
445 /* Keep looping for every byte inside this register */
446 while (CurrentRegister
)
448 /* Read a byte, skip a byte. */
449 RegisterByte
= (UCHAR
)(CurrentRegister
& 0xFF);
450 CurrentRegister
>>= 8;
451 if (!RegisterByte
) continue;
454 * Valid values are from 0x40 (0 bytes) to 0x49
455 * (32MB), or from 0x80 to 0x89 (same size but
458 if (((RegisterByte
> 0x40) &&
459 (RegisterByte
<= 0x49)) ||
460 ((RegisterByte
> 0x80) &&
461 (RegisterByte
<= 0x89)))
463 /* Mask out only the first nibble */
464 RegisterByte
&= 0x0F;
466 /* Set the L2 Cache Size */
467 Pcr
->SecondLevelCacheSize
= 0x10000 <<
472 } while (--CacheRequests
);
479 DPRINT1("Not handling AMD caches yet\n");
490 /* Save current CR0 */
493 /* If this is a 486, enable Write-Protection */
494 if (KeGetCurrentPrcb()->CpuType
> 3) Cr0
|= CR0_WP
;
502 KiInitializeTSS2(IN PKTSS Tss
,
503 IN PKGDTENTRY TssEntry OPTIONAL
)
507 /* Make sure the GDT Entry is valid */
511 TssEntry
->LimitLow
= sizeof(KTSS
) - 1;
512 TssEntry
->HighWord
.Bits
.LimitHi
&= 0xF0;
515 /* Now clear the I/O Map */
516 RtlFillMemory(Tss
->IoMaps
[0].IoMap
, 8096, -1);
518 /* Initialize Interrupt Direction Maps */
519 p
= (PUCHAR
)(Tss
->IoMaps
[0].DirectionMap
);
520 RtlZeroMemory(p
, 32);
522 /* Add DPMI support for interrupts */
527 /* Initialize the default Interrupt Direction Map */
528 p
= Tss
->IntDirectionMap
;
529 RtlZeroMemory(Tss
->IntDirectionMap
, 32);
531 /* Add DPMI support */
539 KiInitializeTSS(IN PKTSS Tss
)
541 /* Set an invalid map base */
542 Tss
->IoMapBase
= KiComputeIopmOffset(IO_ACCESS_MAP_NONE
);
544 /* Disable traps during Task Switches */
547 /* Set LDT and Ring 0 SS */
549 Tss
->Ss0
= KGDT_R0_DATA
;
554 Ki386InitializeTss(IN PKTSS Tss
,
558 PKGDTENTRY TssEntry
, TaskGateEntry
;
560 /* Initialize the boot TSS. */
561 TssEntry
= &Gdt
[KGDT_TSS
/ sizeof(KGDTENTRY
)];
562 TssEntry
->HighWord
.Bits
.Type
= I386_TSS
;
563 TssEntry
->HighWord
.Bits
.Pres
= 1;
564 TssEntry
->HighWord
.Bits
.Dpl
= 0;
565 KiInitializeTSS2(Tss
, TssEntry
);
566 KiInitializeTSS(Tss
);
568 /* Load the task register */
569 Ke386SetTr(KGDT_TSS
);
571 /* Setup the Task Gate for Double Fault Traps */
572 TaskGateEntry
= (PKGDTENTRY
)&Idt
[8];
573 TaskGateEntry
->HighWord
.Bits
.Type
= I386_TASK_GATE
;
574 TaskGateEntry
->HighWord
.Bits
.Pres
= 1;
575 TaskGateEntry
->HighWord
.Bits
.Dpl
= 0;
576 ((PKIDTENTRY
)TaskGateEntry
)->Selector
= KGDT_DF_TSS
;
578 /* Initialize the TSS used for handling double faults. */
579 Tss
= (PKTSS
)KiDoubleFaultTSS
;
580 KiInitializeTSS(Tss
);
581 Tss
->CR3
= _Ke386GetCr(3);
582 Tss
->Esp0
= PtrToUlong(KiDoubleFaultStack
);
583 Tss
->Eip
= PtrToUlong(KiTrap8
);
584 Tss
->Cs
= KGDT_R0_CODE
;
585 Tss
->Fs
= KGDT_R0_PCR
;
586 Tss
->Ss
= Ke386GetSs();
587 Tss
->Es
= KGDT_R3_DATA
| RPL_MASK
;
588 Tss
->Ds
= KGDT_R3_DATA
| RPL_MASK
;
590 /* Setup the Double Trap TSS entry in the GDT */
591 TssEntry
= &Gdt
[KGDT_DF_TSS
/ sizeof(KGDTENTRY
)];
592 TssEntry
->HighWord
.Bits
.Type
= I386_TSS
;
593 TssEntry
->HighWord
.Bits
.Pres
= 1;
594 TssEntry
->HighWord
.Bits
.Dpl
= 0;
595 TssEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Tss
& 0xFFFF);
596 TssEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Tss
>> 16);
597 TssEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Tss
>> 24);
598 TssEntry
->LimitLow
= KTSS_IO_MAPS
;
600 /* Now setup the NMI Task Gate */
601 TaskGateEntry
= (PKGDTENTRY
)&Idt
[2];
602 TaskGateEntry
->HighWord
.Bits
.Type
= I386_TASK_GATE
;
603 TaskGateEntry
->HighWord
.Bits
.Pres
= 1;
604 TaskGateEntry
->HighWord
.Bits
.Dpl
= 0;
605 ((PKIDTENTRY
)TaskGateEntry
)->Selector
= KGDT_NMI_TSS
;
607 /* Initialize the actual TSS */
608 Tss
= (PKTSS
)KiNMITSS
;
609 KiInitializeTSS(Tss
);
610 Tss
->CR3
= _Ke386GetCr(3);
611 Tss
->Esp0
= PtrToUlong(KiDoubleFaultStack
);
612 Tss
->Eip
= PtrToUlong(KiTrap2
);
613 Tss
->Cs
= KGDT_R0_CODE
;
614 Tss
->Fs
= KGDT_R0_PCR
;
615 Tss
->Ss
= Ke386GetSs();
616 Tss
->Es
= KGDT_R3_DATA
| RPL_MASK
;
617 Tss
->Ds
= KGDT_R3_DATA
| RPL_MASK
;
619 /* And its associated TSS Entry */
620 TssEntry
= &Gdt
[KGDT_NMI_TSS
/ sizeof(KGDTENTRY
)];
621 TssEntry
->HighWord
.Bits
.Type
= I386_TSS
;
622 TssEntry
->HighWord
.Bits
.Pres
= 1;
623 TssEntry
->HighWord
.Bits
.Dpl
= 0;
624 TssEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Tss
& 0xFFFF);
625 TssEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Tss
>> 16);
626 TssEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Tss
>> 24);
627 TssEntry
->LimitLow
= KTSS_IO_MAPS
;
632 Ki386SetProcessorFeatures(VOID
)
634 OBJECT_ATTRIBUTES ObjectAttributes
;
635 UNICODE_STRING KeyName
=
636 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Kernel");
637 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"FastSystemCallDisable");
642 KEY_VALUE_PARTIAL_INFORMATION Info
;
646 ULONG FastSystemCallDisable
= 0;
648 SharedUserData
->ProcessorFeatures
[PF_FLOATING_POINT_PRECISION_ERRATA
] = FALSE
;
649 SharedUserData
->ProcessorFeatures
[PF_FLOATING_POINT_EMULATED
] = FALSE
;
650 SharedUserData
->ProcessorFeatures
[PF_COMPARE_EXCHANGE_DOUBLE
] =
651 (KeFeatureBits
& KF_CMPXCHG8B
) ? TRUE
: FALSE
;
652 SharedUserData
->ProcessorFeatures
[PF_MMX_INSTRUCTIONS_AVAILABLE
] =
653 (KeFeatureBits
& KF_MMX
) ? TRUE
: FALSE
;
654 SharedUserData
->ProcessorFeatures
[PF_PPC_MOVEMEM_64BIT_OK
] = FALSE
;
655 SharedUserData
->ProcessorFeatures
[PF_ALPHA_BYTE_INSTRUCTIONS
] = FALSE
;
656 SharedUserData
->ProcessorFeatures
[PF_XMMI_INSTRUCTIONS_AVAILABLE
] =
657 (KeFeatureBits
& KF_XMMI
) ? TRUE
: FALSE
;
658 SharedUserData
->ProcessorFeatures
[PF_RDTSC_INSTRUCTION_AVAILABLE
] =
659 (KeFeatureBits
& KF_RDTSC
) ? TRUE
: FALSE
;
661 /* Does the CPU Support Fast System Call? */
662 if (KeFeatureBits
& KF_FAST_SYSCALL
) {
664 /* FIXME: Check for Family == 6, Model < 3 and Stepping < 3 and disable */
666 /* Make sure it's not disabled in registry */
667 InitializeObjectAttributes(&ObjectAttributes
,
669 OBJ_CASE_INSENSITIVE
,
672 Status
= ZwOpenKey(&KeyHandle
,
676 if (NT_SUCCESS(Status
)) {
678 /* Read the Value then Close the Key */
679 Status
= ZwQueryValueKey(KeyHandle
,
681 KeyValuePartialInformation
,
685 if (NT_SUCCESS(Status
))
687 if (ResultLength
== sizeof(ValueData
) &&
688 ValueData
.Info
.Type
== REG_DWORD
)
690 FastSystemCallDisable
= *(PULONG
)ValueData
.Info
.Data
!= 0;
699 /* Disable SYSENTER/SYSEXIT, because the CPU doesn't support it */
700 FastSystemCallDisable
= 1;
704 if (FastSystemCallDisable
) {
706 const unsigned char Entry
[7] = {0x8D, 0x54, 0x24, 0x08, /* lea 0x8(%esp),%edx */
707 0xCD, 0x2E, /* int 0x2e */
709 memcpy(&SharedUserData
->SystemCall
, Entry
, sizeof(Entry
));
712 const unsigned char Entry
[5] = {0x8B, 0xD4, /* movl %esp,%edx */
713 0x0F, 0x34, /* sysenter */
715 memcpy(&SharedUserData
->SystemCall
, Entry
, sizeof(Entry
));
716 /* Enable SYSENTER/SYSEXIT */
717 KiFastSystemCallDisable
= 0;
723 KeFlushCurrentTb(VOID
)
725 /* Flush the TLB by resetting CR3 */
726 _Ke386SetCr(3, _Ke386GetCr(3));
731 KiSaveProcessorControlState(IN PKPROCESSOR_STATE ProcessorState
)
733 /* Save the CR registers */
734 ProcessorState
->SpecialRegisters
.Cr0
= _Ke386GetCr(0);
735 ProcessorState
->SpecialRegisters
.Cr2
= _Ke386GetCr(2);
736 ProcessorState
->SpecialRegisters
.Cr3
= _Ke386GetCr(3);
737 ProcessorState
->SpecialRegisters
.Cr4
= _Ke386GetCr(4);
739 /* Save the DR registers */
740 ProcessorState
->SpecialRegisters
.KernelDr0
= _Ke386GetDr(0);
741 ProcessorState
->SpecialRegisters
.KernelDr1
= _Ke386GetDr(1);
742 ProcessorState
->SpecialRegisters
.KernelDr2
= _Ke386GetDr(2);
743 ProcessorState
->SpecialRegisters
.KernelDr3
= _Ke386GetDr(3);
744 ProcessorState
->SpecialRegisters
.KernelDr6
= _Ke386GetDr(6);
745 ProcessorState
->SpecialRegisters
.KernelDr7
= _Ke386GetDr(7);
748 /* Save GDT, IDT, LDT and TSS */
749 Ke386GetGlobalDescriptorTable(ProcessorState
->SpecialRegisters
.Gdtr
);
750 Ke386GetInterruptDescriptorTable(ProcessorState
->SpecialRegisters
.Idtr
);
751 Ke386GetTr(ProcessorState
->SpecialRegisters
.Tr
);
752 Ke386GetLocalDescriptorTable(ProcessorState
->SpecialRegisters
.Ldtr
);
757 KiInitializeMachineType(VOID
)
759 /* Set the Machine Type we got from NTLDR */
760 KeI386MachineType
= KeLoaderBlock
->u
.I386
.MachineType
& 0x000FF;
763 /* PUBLIC FUNCTIONS **********************************************************/
770 KeSaveFloatingPointState(OUT PKFLOATING_SAVE Save
)
772 PFNSAVE_FORMAT FpState
;
773 ASSERT_IRQL(DISPATCH_LEVEL
);
774 DPRINT1("%s is not really implemented\n", __FUNCTION__
);
776 /* check if we are doing software emulation */
777 if (!KeI386NpxPresent
) return STATUS_ILLEGAL_FLOAT_CONTEXT
;
779 FpState
= ExAllocatePool(NonPagedPool
, sizeof (FNSAVE_FORMAT
));
780 if (!FpState
) return STATUS_INSUFFICIENT_RESOURCES
;
782 *((PVOID
*) Save
) = FpState
;
784 asm volatile("fnsave %0\n\t" : "=m" (*FpState
));
792 KeGetCurrentThread()->DispatcherHeader
.NpxIrql
= KeGetCurrentIrql();
793 return STATUS_SUCCESS
;
801 KeRestoreFloatingPointState(IN PKFLOATING_SAVE Save
)
803 PFNSAVE_FORMAT FpState
= *((PVOID
*) Save
);
804 ASSERT(KeGetCurrentThread()->DispatcherHeader
.NpxIrql
== KeGetCurrentIrql());
805 DPRINT1("%s is not really implemented\n", __FUNCTION__
);
808 asm volatile("fnclex\n\t");
809 asm volatile("frstor %0\n\t" : "=m" (*FpState
));
819 return STATUS_SUCCESS
;
827 KeGetRecommendedSharedDataAlignment(VOID
)
829 /* Return the global variable */
830 return KeLargestCacheLine
;
838 KeFlushEntireTb(IN BOOLEAN Invalid
,
839 IN BOOLEAN AllProcessors
)
843 /* Raise the IRQL for the TB Flush */
844 OldIrql
= KeRaiseIrqlToSynchLevel();
847 /* FIXME: Support IPI Flush */
848 #error Not yet implemented!
851 /* Flush the TB for the Current CPU */
854 /* Return to Original IRQL */
855 KeLowerIrql(OldIrql
);
863 KeSetDmaIoCoherency(IN ULONG Coherency
)
865 /* Save the coherency globally */
866 KiDmaIoCoherency
= Coherency
;
874 KeQueryActiveProcessors(VOID
)
878 /* Simply return the number of active processors */
879 return KeActiveProcessors
;
887 KeSaveStateForHibernate(IN PKPROCESSOR_STATE State
)
889 /* Capture the context */
890 RtlCaptureContext(&State
->ContextFrame
);
892 /* Capture the control state */
893 KiSaveProcessorControlState(State
);