- NDK 0.98, now with versionned headers. Too many changes to list, see the TinyKRNL...
[reactos.git] / reactos / ntoskrnl / ke / i386 / kernel.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/i386/kernel.c
6 * PURPOSE: Initializes the kernel
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 ULONG KiPcrInitDone = 0;
20 static ULONG PcrsAllocated = 0;
21 static ULONG Ke386CpuidFlags2, Ke386CpuidExFlags, Ke386CpuidExMisc;
22 ULONG Ke386CacheAlignment;
23 CHAR Ke386CpuidModel[49] = {0,};
24 ULONG Ke386L1CacheSize;
25 BOOLEAN Ke386NoExecute = FALSE;
26 BOOLEAN Ke386Pae = FALSE;
27 BOOLEAN Ke386GlobalPagesEnabled = FALSE;
28 ULONG KiFastSystemCallDisable = 1;
29 ULONG KeI386NpxPresent = 0;
30 ULONG KeI386XMMIPresent = 0;
31 ULONG KeI386FxsrPresent = 0;
32 extern PVOID Ki386InitialStackArray[MAXIMUM_PROCESSORS];
33 extern ULONG IdleProcessorMask;
34 extern KIDTENTRY KiIdt[256];
35 static VOID INIT_FUNCTION Ki386GetCpuId(VOID);
36
37 #if defined (ALLOC_PRAGMA)
38 #pragma alloc_text(INIT, Ki386GetCpuId)
39 #pragma alloc_text(INIT, KeCreateApplicationProcessorIdleThread)
40 #pragma alloc_text(INIT, KePrepareForApplicationProcessorInit)
41 #pragma alloc_text(INIT, KeInit1)
42 #pragma alloc_text(INIT, KeInit2)
43 #pragma alloc_text(INIT, Ki386SetProcessorFeatures)
44 #endif
45
46 /* FUNCTIONS *****************************************************************/
47
48 static VOID INIT_FUNCTION
49 Ki386GetCpuId(VOID)
50 {
51 ULONG OrigFlags, Flags, FinalFlags;
52 ULONG MaxCpuidLevel;
53 ULONG Dummy, Eax, Ecx, Edx;
54 PKIPCR Pcr = (PKIPCR)KeGetCurrentKPCR();
55
56 Ke386CpuidFlags2 = Ke386CpuidExFlags = 0;
57 Ke386CacheAlignment = 32;
58
59 /* Try to toggle the id bit in eflags. */
60 Ke386SaveFlags(OrigFlags);
61 Flags = OrigFlags ^ X86_EFLAGS_ID;
62 Ke386RestoreFlags(Flags);
63 Ke386SaveFlags(FinalFlags);
64
65 Pcr->PrcbData.LogicalProcessorsPerPhysicalProcessor = 1;
66 Pcr->PrcbData.InitialApicId = 0xff;
67
68 if ((OrigFlags & X86_EFLAGS_ID) == (FinalFlags & X86_EFLAGS_ID))
69 {
70 /* No cpuid supported. */
71 Pcr->PrcbData.CpuID = FALSE;
72 Pcr->PrcbData.CpuType = 3;
73 return;
74 }
75 Pcr->PrcbData.CpuID = TRUE;
76
77 /* Get the vendor name and the maximum cpuid level supported. */
78 Ki386Cpuid(0, &MaxCpuidLevel, (PULONG)&Pcr->PrcbData.VendorString[0], (PULONG)&Pcr->PrcbData.VendorString[8], (PULONG)&Pcr->PrcbData.VendorString[4]);
79 if (MaxCpuidLevel > 0)
80 {
81 /* Get the feature flags. */
82 Ki386Cpuid(1, &Eax, &Ke386CpuidExMisc, &Ke386CpuidFlags2, &Pcr->PrcbData.FeatureBits);
83
84 DPRINT ("Model: %x\n", (Eax & 0xf00) == 0xf00 ? ((Eax >> 4) & 0xf) | ((Eax >> 12) & 0xf0) : (Eax >> 4) & 0xf);
85 DPRINT ("Family: %x\n", (Eax & 0xf00) == 0xf00 ? ((Eax >> 8) & 0xf) + ((Eax >> 20) & 0xff) : (Eax >> 8) & 0xf);
86
87 /* Get the cache alignment, if it is available */
88 if (Pcr->PrcbData.FeatureBits & (1<<19))
89 {
90 Ke386CacheAlignment = ((Ke386CpuidExMisc >> 8) & 0xff) * 8;
91 }
92 Pcr->PrcbData.CpuType = (Eax >> 8) & 0xf;
93 Pcr->PrcbData.CpuStep = (Eax & 0xf) | ((Eax << 4) & 0xf00);
94
95 Pcr->PrcbData.InitialApicId = (Ke386CpuidExMisc >> 24) & 0xff;
96
97 /* detect Hyper-Threading on Pentium 4 CPUs or later */
98 if ((Pcr->PrcbData.CpuType == 0xf || (Eax & 0x0f00000)) &&
99 !strncmp(Pcr->PrcbData.VendorString, "GenuineIntel", 12) &&
100 Pcr->PrcbData.FeatureBits & X86_FEATURE_HT)
101 {
102 Pcr->PrcbData.LogicalProcessorsPerPhysicalProcessor = (Ke386CpuidExMisc >> 16) & 0xff;
103 }
104 }
105 else
106 {
107 Pcr->PrcbData.CpuType = 4;
108 }
109
110 /* Get the maximum extended cpuid level supported. */
111 Ki386Cpuid(0x80000000, &MaxCpuidLevel, &Dummy, &Dummy, &Dummy);
112 if (MaxCpuidLevel > 0)
113 {
114 /* Get the extended feature flags. */
115 Ki386Cpuid(0x80000001, &Dummy, &Dummy, &Dummy, &Ke386CpuidExFlags);
116 }
117
118 /* Get the model name. */
119 if (MaxCpuidLevel >= 0x80000004)
120 {
121 PULONG v = (PULONG)Ke386CpuidModel;
122 Ki386Cpuid(0x80000002, v, v + 1, v + 2, v + 3);
123 Ki386Cpuid(0x80000003, v + 4, v + 5, v + 6, v + 7);
124 Ki386Cpuid(0x80000004, v + 8, v + 9, v + 10, v + 11);
125 }
126
127 /* Get the L1 cache size */
128 if (MaxCpuidLevel >= 0x80000005)
129 {
130 Ki386Cpuid(0x80000005, &Dummy, &Dummy, &Ecx, &Edx);
131 Ke386L1CacheSize = (Ecx >> 24)+(Edx >> 24);
132 if ((Ecx & 0xff) > 0)
133 {
134 Ke386CacheAlignment = Ecx & 0xff;
135 }
136 }
137
138 /* Get the L2 cache size */
139 if (MaxCpuidLevel >= 0x80000006)
140 {
141 Ki386Cpuid(0x80000006, &Dummy, &Dummy, &Ecx, &Dummy);
142 Pcr->SecondLevelCacheSize = Ecx >> 16;
143 }
144 }
145
146 VOID
147 KeApplicationProcessorInitDispatcher(VOID)
148 {
149 KIRQL oldIrql;
150 oldIrql = KeAcquireDispatcherDatabaseLock();
151 IdleProcessorMask |= (1 << KeGetCurrentProcessorNumber());
152 KeReleaseDispatcherDatabaseLock(oldIrql);
153 }
154
155 VOID
156 INIT_FUNCTION
157 KeCreateApplicationProcessorIdleThread(ULONG Id)
158 {
159 PETHREAD IdleThread;
160 PKPRCB Prcb = ((PKPCR)((ULONG_PTR)KPCR_BASE + Id * PAGE_SIZE))->Prcb;
161
162 PsInitializeIdleOrFirstThread(PsIdleProcess,
163 &IdleThread,
164 NULL,
165 KernelMode,
166 FALSE);
167 IdleThread->Tcb.State = Running;
168 IdleThread->Tcb.FreezeCount = 0;
169 IdleThread->Tcb.Affinity = 1 << Id;
170 IdleThread->Tcb.UserAffinity = 1 << Id;
171 IdleThread->Tcb.Priority = LOW_PRIORITY;
172 IdleThread->Tcb.BasePriority = LOW_PRIORITY;
173 Prcb->IdleThread = &IdleThread->Tcb;
174 Prcb->CurrentThread = &IdleThread->Tcb;
175
176 Ki386InitialStackArray[Id] = (PVOID)IdleThread->Tcb.StackLimit;
177
178 DPRINT("IdleThread for Processor %d has PID %d\n",
179 Id, IdleThread->Cid.UniqueThread);
180 }
181
182 VOID
183 INIT_FUNCTION
184 NTAPI
185 KePrepareForApplicationProcessorInit(ULONG Id)
186 {
187 PFN_TYPE PrcPfn;
188 PKIPCR Pcr;
189 PKIPCR BootPcr;
190
191 DPRINT("KePrepareForApplicationProcessorInit(Id %d)\n", Id);
192
193 BootPcr = (PKIPCR)KPCR_BASE;
194 Pcr = (PKIPCR)((ULONG_PTR)KPCR_BASE + Id * PAGE_SIZE);
195
196 MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &PrcPfn);
197 MmCreateVirtualMappingForKernel((PVOID)Pcr,
198 PAGE_READWRITE,
199 &PrcPfn,
200 1);
201 /*
202 * Create a PCR for this processor
203 */
204 memset(Pcr, 0, PAGE_SIZE);
205 Pcr->Number = Id;
206 Pcr->SetMember = 1 << Id;
207 Pcr->NtTib.Self = &Pcr->NtTib;
208 Pcr->Self = (PKPCR)Pcr;
209 Pcr->Prcb = &Pcr->PrcbData;
210 Pcr->Irql = SYNCH_LEVEL;
211
212 Pcr->PrcbData.SetMember = 1 << Id;
213 Pcr->PrcbData.MHz = BootPcr->PrcbData.MHz;
214 Pcr->StallScaleFactor = BootPcr->StallScaleFactor;
215
216 /* Mark the end of the exception handler list */
217 Pcr->NtTib.ExceptionList = (PVOID)-1;
218
219 KiGdtPrepareForApplicationProcessorInit(Id);
220
221 KeActiveProcessors |= 1 << Id;
222 }
223
224 VOID
225 NTAPI
226 KeApplicationProcessorInit(VOID)
227 {
228 ULONG Offset;
229 PKIPCR Pcr;
230
231 DPRINT("KeApplicationProcessorInit()\n");
232
233 if (Ke386GlobalPagesEnabled)
234 {
235 /* Enable global pages */
236 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE);
237 }
238
239
240 Offset = InterlockedIncrementUL(&PcrsAllocated) - 1;
241 Pcr = (PKIPCR)((ULONG_PTR)KPCR_BASE + Offset * PAGE_SIZE);
242
243 /*
244 * Initialize the GDT
245 */
246 KiInitializeGdt((PKPCR)Pcr);
247
248 /* Get processor information. */
249 Ki386GetCpuId();
250
251 /* Check FPU/MMX/SSE support. */
252 KiCheckFPU();
253
254 KeInitDpc(Pcr->Prcb);
255
256 if (Pcr->PrcbData.FeatureBits & X86_FEATURE_SYSCALL)
257 {
258 extern void KiFastCallEntry(void);
259
260 /* CS Selector of the target segment. */
261 Ke386Wrmsr(0x174, KGDT_R0_CODE, 0);
262 /* Target ESP. */
263 Ke386Wrmsr(0x175, 0, 0);
264 /* Target EIP. */
265 Ke386Wrmsr(0x176, (ULONG_PTR)KiFastCallEntry, 0);
266 }
267
268 /*
269 * It is now safe to process interrupts
270 */
271 KeLowerIrql(DISPATCH_LEVEL);
272
273 /*
274 * Initialize the TSS
275 */
276 Ki386ApplicationProcessorInitializeTSS();
277
278 /*
279 * Initialize a default LDT
280 */
281 Ki386InitializeLdt();
282
283 /* Now we can enable interrupts. */
284 Ke386EnableInterrupts();
285 }
286
287 VOID
288 INIT_FUNCTION
289 NTAPI
290 KeInit1(PCHAR CommandLine, PULONG LastKernelAddress)
291 {
292 PKIPCR KPCR;
293 BOOLEAN Pae = FALSE;
294 BOOLEAN NoExecute = FALSE;
295 PCHAR p1, p2;
296 extern USHORT KiBootGdt[];
297 extern KTSS KiBootTss;
298
299 /*
300 * Initialize the initial PCR region. We can't allocate a page
301 * with MmAllocPage() here because MmInit1() has not yet been
302 * called, so we use a predefined page in low memory
303 */
304
305 KPCR = (PKIPCR)KPCR_BASE;
306 memset(KPCR, 0, PAGE_SIZE);
307 KPCR->Self = (PKPCR)KPCR;
308 KPCR->Prcb = &KPCR->PrcbData;
309 KPCR->Irql = SYNCH_LEVEL;
310 KPCR->NtTib.Self = &KPCR->NtTib;
311 KPCR->GDT = KiBootGdt;
312 KPCR->IDT = KiIdt;
313 KPCR->TSS = &KiBootTss;
314 KPCR->Number = 0;
315 KPCR->SetMember = 1 << 0;
316 KeActiveProcessors = 1 << 0;
317 KPCR->PrcbData.SetMember = 1 << 0;
318 KiPcrInitDone = 1;
319 PcrsAllocated++;
320
321 KiInitializeGdt (NULL);
322 Ki386BootInitializeTSS();
323 Ki386InitializeLdt();
324
325 /* Get processor information. */
326 Ki386GetCpuId();
327
328 /* Check FPU/MMX/SSE support. */
329 KiCheckFPU();
330
331 /* Mark the end of the exception handler list */
332 KPCR->NtTib.ExceptionList = (PVOID)-1;
333
334 KeInitDpc(KPCR->Prcb);
335
336 KeInitExceptions ();
337 KeInitInterrupts ();
338
339 KeActiveProcessors |= 1 << 0;
340
341
342 if (KPCR->PrcbData.FeatureBits & X86_FEATURE_PGE)
343 {
344 ULONG Flags;
345 /* Enable global pages */
346 Ke386GlobalPagesEnabled = TRUE;
347 Ke386SaveFlags(Flags);
348 Ke386DisableInterrupts();
349 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE);
350 Ke386RestoreFlags(Flags);
351 }
352
353 /* Search for pae and noexecute */
354 p1 = (PCHAR)KeLoaderBlock.CommandLine;
355 while(*p1 && (p2 = strchr(p1, '/')))
356 {
357 p2++;
358 if (!_strnicmp(p2, "PAE", 3))
359 {
360 if (p2[3] == ' ' || p2[3] == 0)
361 {
362 p2 += 3;
363 Pae = TRUE;
364 }
365 }
366 else if (!_strnicmp(p2, "NOEXECUTE", 9))
367 {
368 if (p2[9] == ' ' || p2[9] == '=' || p2[9] == 0)
369 {
370 p2 += 9;
371 NoExecute = TRUE;
372 }
373 }
374 p1 = p2;
375 }
376 #if 0
377 /*
378 * FIXME:
379 * Make the detection of the noexecute feature more portable.
380 */
381 if(KPCR->PrcbData.CpuType == 0xf &&
382 RtlCompareMemory("AuthenticAMD", KPCR->PrcbData.VendorString, 12) == 12)
383 {
384 if (NoExecute)
385 {
386 ULONG Flags, l, h;
387 Ke386SaveFlags(Flags);
388 Ke386DisableInterrupts();
389
390 Ke386Rdmsr(0xc0000080, l, h);
391 l |= (1 << 11);
392 Ke386Wrmsr(0xc0000080, l, h);
393 Ke386NoExecute = TRUE;
394 Ke386RestoreFlags(Flags);
395 }
396 }
397 else
398 {
399 NoExecute=FALSE;
400 }
401 #endif
402
403 Ke386Pae = Ke386GetCr4() & X86_CR4_PAE ? TRUE : FALSE;
404 #if 0
405 /* Enable PAE mode */
406 if ((Pae && (KPCR->PrcbData.FeatureBits & X86_FEATURE_PAE)) || NoExecute)
407 {
408 MiEnablePAE((PVOID*)LastKernelAddress);
409 Ke386PaeEnabled = TRUE;
410 }
411 #endif
412 if (KPCR->PrcbData.FeatureBits & X86_FEATURE_SYSCALL)
413 {
414 extern void KiFastCallEntry(void);
415
416 /* CS Selector of the target segment. */
417 Ke386Wrmsr(0x174, KGDT_R0_CODE, 0);
418 /* Target ESP. */
419 Ke386Wrmsr(0x175, 0, 0);
420 /* Target EIP. */
421 Ke386Wrmsr(0x176, (ULONG_PTR)KiFastCallEntry, 0);
422 }
423
424 /* Does the CPU Support 'prefetchnta' (SSE) */
425 if(KPCR->PrcbData.FeatureBits & X86_FEATURE_SSE)
426 {
427 ULONG Protect;
428
429 Protect = MmGetPageProtect(NULL, (PVOID)RtlPrefetchMemoryNonTemporal);
430 MmSetPageProtect(NULL, (PVOID)RtlPrefetchMemoryNonTemporal, Protect | PAGE_IS_WRITABLE);
431 /* Replace the ret by a nop */
432 *(PCHAR)RtlPrefetchMemoryNonTemporal = 0x90;
433 MmSetPageProtect(NULL, (PVOID)RtlPrefetchMemoryNonTemporal, Protect);
434 }
435 }
436
437 VOID
438 INIT_FUNCTION
439 NTAPI
440 KeInit2(VOID)
441 {
442 PKIPCR Pcr = (PKIPCR)KeGetCurrentKPCR();
443
444 KiInitializeBugCheck();
445 KeInitializeDispatcher();
446 KiInitializeSystemClock();
447
448 if (Pcr->PrcbData.FeatureBits & X86_FEATURE_PAE)
449 {
450 DPRINT("CPU supports PAE mode\n");
451 if (Ke386Pae)
452 {
453 DPRINT("CPU runs in PAE mode\n");
454 if (Ke386NoExecute)
455 {
456 DPRINT("NoExecute is enabled\n");
457 }
458 }
459 else
460 {
461 DPRINT("CPU doesn't run in PAE mode\n");
462 }
463 }
464 if ((Pcr->PrcbData.FeatureBits & (X86_FEATURE_FXSR | X86_FEATURE_MMX | X86_FEATURE_SSE | X86_FEATURE_SSE2)) ||
465 (Ke386CpuidFlags2 & X86_EXT_FEATURE_SSE3))
466 {
467 DPRINT("CPU supports" "%s%s%s%s%s" ".\n",
468 ((Pcr->PrcbData.FeatureBits & X86_FEATURE_FXSR) ? " FXSR" : ""),
469 ((Pcr->PrcbData.FeatureBits & X86_FEATURE_MMX) ? " MMX" : ""),
470 ((Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE) ? " SSE" : ""),
471 ((Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE2) ? " SSE2" : ""),
472 ((Ke386CpuidFlags2 & X86_EXT_FEATURE_SSE3) ? " SSE3" : ""));
473 }
474 if (Ke386GetCr4() & X86_CR4_OSFXSR)
475 {
476 DPRINT("SSE enabled.\n");
477 }
478 if (Ke386GetCr4() & X86_CR4_OSXMMEXCPT)
479 {
480 DPRINT("Unmasked SIMD exceptions enabled.\n");
481 }
482 if (Pcr->PrcbData.VendorString[0])
483 {
484 DPRINT("CPU Vendor: %s\n", Pcr->PrcbData.VendorString);
485 }
486 if (Ke386CpuidModel[0])
487 {
488 DPRINT("CPU Model: %s\n", Ke386CpuidModel);
489 }
490
491 DPRINT("Ke386CacheAlignment: %d\n", Ke386CacheAlignment);
492 if (Ke386L1CacheSize)
493 {
494
495 DPRINT("Ke386L1CacheSize: %dkB\n", Ke386L1CacheSize);
496 }
497 if (Pcr->SecondLevelCacheSize)
498 {
499 DPRINT("Ke386L2CacheSize: %dkB\n", Pcr->SecondLevelCacheSize);
500 }
501 }
502
503 VOID INIT_FUNCTION
504 Ki386SetProcessorFeatures(VOID)
505 {
506 PKIPCR Pcr = (PKIPCR)KeGetCurrentKPCR();
507 OBJECT_ATTRIBUTES ObjectAttributes;
508 UNICODE_STRING KeyName =
509 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Kernel");
510 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"FastSystemCallDisable");
511 HANDLE KeyHandle;
512 ULONG ResultLength;
513 struct
514 {
515 KEY_VALUE_PARTIAL_INFORMATION Info;
516 UCHAR Buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,
517 Data[0]) + sizeof(ULONG)];
518 } ValueData;
519 NTSTATUS Status;
520 ULONG FastSystemCallDisable = 0;
521
522 SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = FALSE;
523 SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_EMULATED] = FALSE;
524 SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] =
525 (Pcr->PrcbData.FeatureBits & X86_FEATURE_CX8) ? TRUE : FALSE;
526 SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] =
527 (Pcr->PrcbData.FeatureBits & X86_FEATURE_MMX) ? TRUE : FALSE;
528 SharedUserData->ProcessorFeatures[PF_PPC_MOVEMEM_64BIT_OK] = FALSE;
529 SharedUserData->ProcessorFeatures[PF_ALPHA_BYTE_INSTRUCTIONS] = FALSE;
530 SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] =
531 (Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE) ? TRUE : FALSE;
532 SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] =
533 (Ke386CpuidExFlags & X86_EXT_FEATURE_3DNOW) ? TRUE : FALSE;
534 SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] =
535 (Pcr->PrcbData.FeatureBits & KF_RDTSC) ? TRUE : FALSE;
536 SharedUserData->ProcessorFeatures[PF_PAE_ENABLED] = Ke386Pae;
537 SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] =
538 (Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE2) ? TRUE : FALSE;
539
540 /* Does the CPU Support Fast System Call? */
541 if (Pcr->PrcbData.FeatureBits & X86_FEATURE_SYSCALL) {
542
543 /* FIXME: Check for Family == 6, Model < 3 and Stepping < 3 and disable */
544
545 /* Make sure it's not disabled in registry */
546 InitializeObjectAttributes(&ObjectAttributes,
547 &KeyName,
548 OBJ_CASE_INSENSITIVE,
549 NULL,
550 NULL);
551 Status = ZwOpenKey(&KeyHandle,
552 KEY_QUERY_VALUE,
553 &ObjectAttributes);
554
555 if (NT_SUCCESS(Status)) {
556
557 /* Read the Value then Close the Key */
558 Status = ZwQueryValueKey(KeyHandle,
559 &ValueName,
560 KeyValuePartialInformation,
561 &ValueData,
562 sizeof(ValueData),
563 &ResultLength);
564 if (NT_SUCCESS(Status))
565 {
566 if (ResultLength == sizeof(ValueData) &&
567 ValueData.Info.Type == REG_DWORD)
568 {
569 FastSystemCallDisable = *(PULONG)ValueData.Info.Data != 0;
570 }
571
572 ZwClose(KeyHandle);
573 }
574 }
575
576 } else {
577
578 /* Disable SYSENTER/SYSEXIT, because the CPU doesn't support it */
579 FastSystemCallDisable = 1;
580
581 }
582
583 if (FastSystemCallDisable) {
584 /* Use INT2E */
585 const unsigned char Entry[7] = {0x8D, 0x54, 0x24, 0x08, /* lea 0x8(%esp),%edx */
586 0xCD, 0x2E, /* int 0x2e */
587 0xC3}; /* ret */
588 memcpy(&SharedUserData->SystemCall, Entry, sizeof(Entry));
589 } else {
590 /* Use SYSENTER */
591 const unsigned char Entry[5] = {0x8B, 0xD4, /* movl %esp,%edx */
592 0x0F, 0x34, /* sysenter */
593 0xC3}; /* ret */
594 memcpy(&SharedUserData->SystemCall, Entry, sizeof(Entry));
595 /* Enable SYSENTER/SYSEXIT */
596 KiFastSystemCallDisable = 0;
597 }
598 }