-/*
- * ReactOS kernel
- * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
+/* $Id$
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/*
+ * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
- * FILE: ntoskrnl/ke/kernel.c
+ * FILE: ntoskrnl/ke/i386/kernel.c
* PURPOSE: Initializes the kernel
- * PROGRAMMER: David Welch (welch@mcmail.com)
- * UPDATE HISTORY:
- * Created 22/05/98
+ *
+ * PROGRAMMERS: David Welch (welch@mcmail.com)
*/
/* INCLUDES *****************************************************************/
-#include <ddk/ntddk.h>
-#include <internal/ke.h>
-#include <internal/mm.h>
-#include <internal/ps.h>
-#include <internal/i386/fpu.h>
-
+#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
/* GLOBALS *******************************************************************/
ULONG KiPcrInitDone = 0;
+static ULONG PcrsAllocated = 0;
+static ULONG Ke386CpuidFlags2, Ke386CpuidExFlags, Ke386CpuidExMisc;
+ULONG Ke386CacheAlignment;
+CHAR Ke386CpuidModel[49] = {0,};
+ULONG Ke386L1CacheSize;
+ULONG Ke386CacheGranularity = 0x40; /* FIXME: Default to 64 bytes for RtlPrefetchMemoryNonTemporal(), need real size */
+BOOLEAN Ke386NoExecute = FALSE;
+BOOLEAN Ke386Pae = FALSE;
+BOOLEAN Ke386GlobalPagesEnabled = FALSE;
+ULONG KiFastSystemCallDisable = 1;
+extern PVOID Ki386InitialStackArray[MAXIMUM_PROCESSORS];
+extern ULONG IdleProcessorMask;
+
+static VOID INIT_FUNCTION Ki386GetCpuId(VOID);
+
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, Ki386GetCpuId)
+#pragma alloc_text(INIT, KeCreateApplicationProcessorIdleThread)
+#pragma alloc_text(INIT, KePrepareForApplicationProcessorInit)
+#pragma alloc_text(INIT, KeInit1)
+#pragma alloc_text(INIT, KeInit2)
+#pragma alloc_text(INIT, Ki386SetProcessorFeatures)
+#endif
/* FUNCTIONS *****************************************************************/
-VOID
-KeInit1(VOID)
+static VOID INIT_FUNCTION
+Ki386GetCpuId(VOID)
+{
+ ULONG OrigFlags, Flags, FinalFlags;
+ ULONG MaxCpuidLevel;
+ ULONG Dummy, Eax, Ecx, Edx;
+ PKIPCR Pcr = (PKIPCR)KeGetCurrentKPCR();
+
+ Ke386CpuidFlags2 = Ke386CpuidExFlags = 0;
+ Ke386CacheAlignment = 32;
+
+ /* Try to toggle the id bit in eflags. */
+ Ke386SaveFlags(OrigFlags);
+ Flags = OrigFlags ^ X86_EFLAGS_ID;
+ Ke386RestoreFlags(Flags);
+ Ke386SaveFlags(FinalFlags);
+
+ Pcr->PrcbData.LogicalProcessorsPerPhysicalProcessor = 1;
+ Pcr->PrcbData.InitialApicId = 0xff;
+
+ if ((OrigFlags & X86_EFLAGS_ID) == (FinalFlags & X86_EFLAGS_ID))
+ {
+ /* No cpuid supported. */
+ Pcr->PrcbData.CpuID = FALSE;
+ Pcr->PrcbData.CpuType = 3;
+ return;
+ }
+ Pcr->PrcbData.CpuID = TRUE;
+
+ /* Get the vendor name and the maximum cpuid level supported. */
+ Ki386Cpuid(0, &MaxCpuidLevel, (PULONG)&Pcr->PrcbData.VendorString[0], (PULONG)&Pcr->PrcbData.VendorString[8], (PULONG)&Pcr->PrcbData.VendorString[4]);
+ if (MaxCpuidLevel > 0)
+ {
+ /* Get the feature flags. */
+ Ki386Cpuid(1, &Eax, &Ke386CpuidExMisc, &Ke386CpuidFlags2, &Pcr->PrcbData.FeatureBits);
+
+ DPRINT ("Model: %x\n", (Eax & 0xf00) == 0xf00 ? ((Eax >> 4) & 0xf) | ((Eax >> 12) & 0xf0) : (Eax >> 4) & 0xf);
+ DPRINT ("Family: %x\n", (Eax & 0xf00) == 0xf00 ? ((Eax >> 8) & 0xf) + ((Eax >> 20) & 0xff) : (Eax >> 8) & 0xf);
+
+ /* Get the cache alignment, if it is available */
+ if (Pcr->PrcbData.FeatureBits & (1<<19))
+ {
+ Ke386CacheAlignment = ((Ke386CpuidExMisc >> 8) & 0xff) * 8;
+ }
+ Pcr->PrcbData.CpuType = (Eax >> 8) & 0xf;
+ Pcr->PrcbData.CpuStep = (Eax & 0xf) | ((Eax << 4) & 0xf00);
+
+ Pcr->PrcbData.InitialApicId = (Ke386CpuidExMisc >> 24) & 0xff;
+
+ /* detect Hyper-Threading on Pentium 4 CPUs or later */
+ if ((Pcr->PrcbData.CpuType == 0xf || (Eax & 0x0f00000)) &&
+ !strncmp(Pcr->PrcbData.VendorString, "GenuineIntel", 12) &&
+ Pcr->PrcbData.FeatureBits & X86_FEATURE_HT)
+ {
+ Pcr->PrcbData.LogicalProcessorsPerPhysicalProcessor = (Ke386CpuidExMisc >> 16) & 0xff;
+ }
+ }
+ else
+ {
+ Pcr->PrcbData.CpuType = 4;
+ }
+
+ /* Get the maximum extended cpuid level supported. */
+ Ki386Cpuid(0x80000000, &MaxCpuidLevel, &Dummy, &Dummy, &Dummy);
+ if (MaxCpuidLevel > 0)
+ {
+ /* Get the extended feature flags. */
+ Ki386Cpuid(0x80000001, &Dummy, &Dummy, &Dummy, &Ke386CpuidExFlags);
+ }
+
+ /* Get the model name. */
+ if (MaxCpuidLevel >= 0x80000004)
+ {
+ PULONG v = (PULONG)Ke386CpuidModel;
+ Ki386Cpuid(0x80000002, v, v + 1, v + 2, v + 3);
+ Ki386Cpuid(0x80000003, v + 4, v + 5, v + 6, v + 7);
+ Ki386Cpuid(0x80000004, v + 8, v + 9, v + 10, v + 11);
+ }
+
+ /* Get the L1 cache size */
+ if (MaxCpuidLevel >= 0x80000005)
+ {
+ Ki386Cpuid(0x80000005, &Dummy, &Dummy, &Ecx, &Edx);
+ Ke386L1CacheSize = (Ecx >> 24)+(Edx >> 24);
+ if ((Ecx & 0xff) > 0)
+ {
+ Ke386CacheAlignment = Ecx & 0xff;
+ }
+ }
+
+ /* Get the L2 cache size */
+ if (MaxCpuidLevel >= 0x80000006)
+ {
+ Ki386Cpuid(0x80000006, &Dummy, &Dummy, &Ecx, &Dummy);
+ Pcr->L2CacheSize = Ecx >> 16;
+ }
+}
+
+VOID
+KeApplicationProcessorInitDispatcher(VOID)
+{
+ KIRQL oldIrql;
+ oldIrql = KeAcquireDispatcherDatabaseLock();
+ IdleProcessorMask |= (1 << KeGetCurrentProcessorNumber());
+ KeReleaseDispatcherDatabaseLock(oldIrql);
+}
+
+VOID
+INIT_FUNCTION
+KeCreateApplicationProcessorIdleThread(ULONG Id)
+{
+ PETHREAD IdleThread;
+ PKPRCB Prcb = ((PKPCR)((ULONG_PTR)KPCR_BASE + Id * PAGE_SIZE))->Prcb;
+
+ PsInitializeIdleOrFirstThread(PsIdleProcess,
+ &IdleThread,
+ NULL,
+ KernelMode,
+ FALSE);
+ IdleThread->Tcb.State = Running;
+ IdleThread->Tcb.FreezeCount = 0;
+ IdleThread->Tcb.Affinity = 1 << Id;
+ IdleThread->Tcb.UserAffinity = 1 << Id;
+ IdleThread->Tcb.Priority = LOW_PRIORITY;
+ IdleThread->Tcb.BasePriority = LOW_PRIORITY;
+ Prcb->IdleThread = &IdleThread->Tcb;
+ Prcb->CurrentThread = &IdleThread->Tcb;
+
+ Ki386InitialStackArray[Id] = (PVOID)IdleThread->Tcb.StackLimit;
+
+ DPRINT("IdleThread for Processor %d has PID %d\n",
+ Id, IdleThread->Cid.UniqueThread);
+}
+
+VOID
+INIT_FUNCTION
+NTAPI
+KePrepareForApplicationProcessorInit(ULONG Id)
+{
+ PFN_TYPE PrcPfn;
+ PKIPCR Pcr;
+ PKIPCR BootPcr;
+
+ DPRINT("KePrepareForApplicationProcessorInit(Id %d)\n", Id);
+
+ BootPcr = (PKIPCR)KPCR_BASE;
+ Pcr = (PKIPCR)((ULONG_PTR)KPCR_BASE + Id * PAGE_SIZE);
+
+ MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &PrcPfn);
+ MmCreateVirtualMappingForKernel((PVOID)Pcr,
+ PAGE_READWRITE,
+ &PrcPfn,
+ 1);
+ /*
+ * Create a PCR for this processor
+ */
+ memset(Pcr, 0, PAGE_SIZE);
+ Pcr->Number = Id;
+ Pcr->SetMember = 1 << Id;
+ Pcr->NtTib.Self = &Pcr->NtTib;
+ Pcr->Self = (PKPCR)Pcr;
+ Pcr->Prcb = &Pcr->PrcbData;
+ Pcr->Irql = SYNCH_LEVEL;
+
+ Pcr->PrcbData.SetMember = 1 << Id;
+ Pcr->PrcbData.MHz = BootPcr->PrcbData.MHz;
+ Pcr->StallScaleFactor = BootPcr->StallScaleFactor;
+
+ /* Mark the end of the exception handler list */
+ Pcr->NtTib.ExceptionList = (PVOID)-1;
+
+ KiGdtPrepareForApplicationProcessorInit(Id);
+
+ KeActiveProcessors |= 1 << Id;
+}
+
+VOID
+NTAPI
+KeApplicationProcessorInit(VOID)
+{
+ ULONG Offset;
+ PKIPCR Pcr;
+
+ DPRINT("KeApplicationProcessorInit()\n");
+
+ if (Ke386GlobalPagesEnabled)
+ {
+ /* Enable global pages */
+ Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE);
+ }
+
+
+ Offset = InterlockedIncrementUL(&PcrsAllocated) - 1;
+ Pcr = (PKIPCR)((ULONG_PTR)KPCR_BASE + Offset * PAGE_SIZE);
+
+ /*
+ * Initialize the GDT
+ */
+ KiInitializeGdt((PKPCR)Pcr);
+
+ /* Get processor information. */
+ Ki386GetCpuId();
+
+ /* Check FPU/MMX/SSE support. */
+ KiCheckFPU();
+
+ KeInitDpc(Pcr->Prcb);
+
+ if (Pcr->PrcbData.FeatureBits & X86_FEATURE_SYSCALL)
+ {
+ extern void KiFastCallEntry(void);
+
+ /* CS Selector of the target segment. */
+ Ke386Wrmsr(0x174, KGDT_R0_CODE, 0);
+ /* Target ESP. */
+ Ke386Wrmsr(0x175, 0, 0);
+ /* Target EIP. */
+ Ke386Wrmsr(0x176, (ULONG_PTR)KiFastCallEntry, 0);
+ }
+
+ /*
+ * It is now safe to process interrupts
+ */
+ KeLowerIrql(DISPATCH_LEVEL);
+
+ /*
+ * Initialize the TSS
+ */
+ Ki386ApplicationProcessorInitializeTSS();
+
+ /*
+ * Initialize a default LDT
+ */
+ Ki386InitializeLdt();
+
+ /* Now we can enable interrupts. */
+ Ke386EnableInterrupts();
+}
+
+VOID
+INIT_FUNCTION
+NTAPI
+KeInit1(PCHAR CommandLine, PULONG LastKernelAddress)
{
+ PKIPCR KPCR;
+ BOOLEAN Pae = FALSE;
+ BOOLEAN NoExecute = FALSE;
+ PCHAR p1, p2;
+ extern USHORT KiBootGdt[];
+ extern KTSS KiBootTss;
+
+ /*
+ * Initialize the initial PCR region. We can't allocate a page
+ * with MmAllocPage() here because MmInit1() has not yet been
+ * called, so we use a predefined page in low memory
+ */
+
+ KPCR = (PKIPCR)KPCR_BASE;
+ memset(KPCR, 0, PAGE_SIZE);
+ KPCR->Self = (PKPCR)KPCR;
+ KPCR->Prcb = &KPCR->PrcbData;
+ KPCR->Irql = SYNCH_LEVEL;
+ KPCR->NtTib.Self = &KPCR->NtTib;
+ KPCR->GDT = KiBootGdt;
+ KPCR->IDT = (PUSHORT)KiIdt;
+ KPCR->TSS = &KiBootTss;
+ KPCR->Number = 0;
+ KPCR->SetMember = 1 << 0;
+ KeActiveProcessors = 1 << 0;
+ KPCR->PrcbData.SetMember = 1 << 0;
+ KiPcrInitDone = 1;
+ PcrsAllocated++;
+
+ KiInitializeGdt (NULL);
+ Ki386BootInitializeTSS();
+ Ki386InitializeLdt();
+
+ /* Get processor information. */
+ Ki386GetCpuId();
+
+ /* Check FPU/MMX/SSE support. */
KiCheckFPU();
+ /* Mark the end of the exception handler list */
+ KPCR->NtTib.ExceptionList = (PVOID)-1;
+
+ KeInitDpc(KPCR->Prcb);
+
KeInitExceptions ();
KeInitInterrupts ();
+
+ KeActiveProcessors |= 1 << 0;
+
+
+ if (KPCR->PrcbData.FeatureBits & X86_FEATURE_PGE)
+ {
+ ULONG Flags;
+ /* Enable global pages */
+ Ke386GlobalPagesEnabled = TRUE;
+ Ke386SaveFlags(Flags);
+ Ke386DisableInterrupts();
+ Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE);
+ Ke386RestoreFlags(Flags);
+ }
+
+ /* Search for pae and noexecute */
+ p1 = (PCHAR)KeLoaderBlock.CommandLine;
+ while(*p1 && (p2 = strchr(p1, '/')))
+ {
+ p2++;
+ if (!_strnicmp(p2, "PAE", 3))
+ {
+ if (p2[3] == ' ' || p2[3] == 0)
+ {
+ p2 += 3;
+ Pae = TRUE;
+ }
+ }
+ else if (!_strnicmp(p2, "NOEXECUTE", 9))
+ {
+ if (p2[9] == ' ' || p2[9] == '=' || p2[9] == 0)
+ {
+ p2 += 9;
+ NoExecute = TRUE;
+ }
+ }
+ p1 = p2;
+ }
+#if 0
+ /*
+ * FIXME:
+ * Make the detection of the noexecute feature more portable.
+ */
+ if(KPCR->PrcbData.CpuType == 0xf &&
+ RtlCompareMemory("AuthenticAMD", KPCR->PrcbData.VendorString, 12) == 12)
+ {
+ if (NoExecute)
+ {
+ ULONG Flags, l, h;
+ Ke386SaveFlags(Flags);
+ Ke386DisableInterrupts();
+
+ Ke386Rdmsr(0xc0000080, l, h);
+ l |= (1 << 11);
+ Ke386Wrmsr(0xc0000080, l, h);
+ Ke386NoExecute = TRUE;
+ Ke386RestoreFlags(Flags);
+ }
+ }
+ else
+ {
+ NoExecute=FALSE;
+ }
+#endif
+
+ Ke386Pae = Ke386GetCr4() & X86_CR4_PAE ? TRUE : FALSE;
+#if 0
+ /* Enable PAE mode */
+ if ((Pae && (KPCR->PrcbData.FeatureBits & X86_FEATURE_PAE)) || NoExecute)
+ {
+ MiEnablePAE((PVOID*)LastKernelAddress);
+ Ke386PaeEnabled = TRUE;
+ }
+#endif
+ if (KPCR->PrcbData.FeatureBits & X86_FEATURE_SYSCALL)
+ {
+ extern void KiFastCallEntry(void);
+
+ /* CS Selector of the target segment. */
+ Ke386Wrmsr(0x174, KGDT_R0_CODE, 0);
+ /* Target ESP. */
+ Ke386Wrmsr(0x175, 0, 0);
+ /* Target EIP. */
+ Ke386Wrmsr(0x176, (ULONG_PTR)KiFastCallEntry, 0);
+ }
}
-VOID
+VOID
+INIT_FUNCTION
+NTAPI
KeInit2(VOID)
{
- PVOID PcrPage;
-
- KeInitDpc();
- KeInitializeBugCheck();
+ PKIPCR Pcr = (PKIPCR)KeGetCurrentKPCR();
+
+ KiInitializeBugCheck();
KeInitializeDispatcher();
- KeInitializeTimerImpl();
-
- /*
- * Initialize the PCR region.
- * FIXME: This should be per-processor.
- */
- PcrPage = MmAllocPage(0);
- if (PcrPage == NULL)
- {
- DPRINT1("No memory for PCR page\n");
- KeBugCheck(0);
- }
- MmCreateVirtualMapping(NULL,
- (PVOID)KPCR_BASE,
- PAGE_READWRITE,
- (ULONG)PcrPage);
- memset((PVOID)KPCR_BASE, 0, 4096);
- KiPcrInitDone = 1;
+ KiInitializeSystemClock();
+
+ if (Pcr->PrcbData.FeatureBits & X86_FEATURE_PAE)
+ {
+ DPRINT("CPU supports PAE mode\n");
+ if (Ke386Pae)
+ {
+ DPRINT("CPU runs in PAE mode\n");
+ if (Ke386NoExecute)
+ {
+ DPRINT("NoExecute is enabled\n");
+ }
+ }
+ else
+ {
+ DPRINT("CPU doesn't run in PAE mode\n");
+ }
+ }
+ if ((Pcr->PrcbData.FeatureBits & (X86_FEATURE_FXSR | X86_FEATURE_MMX | X86_FEATURE_SSE | X86_FEATURE_SSE2)) ||
+ (Ke386CpuidFlags2 & X86_EXT_FEATURE_SSE3))
+ {
+ DPRINT("CPU supports" "%s%s%s%s%s" ".\n",
+ ((Pcr->PrcbData.FeatureBits & X86_FEATURE_FXSR) ? " FXSR" : ""),
+ ((Pcr->PrcbData.FeatureBits & X86_FEATURE_MMX) ? " MMX" : ""),
+ ((Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE) ? " SSE" : ""),
+ ((Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE2) ? " SSE2" : ""),
+ ((Ke386CpuidFlags2 & X86_EXT_FEATURE_SSE3) ? " SSE3" : ""));
+ }
+ if (Ke386GetCr4() & X86_CR4_OSFXSR)
+ {
+ DPRINT("SSE enabled.\n");
+ }
+ if (Ke386GetCr4() & X86_CR4_OSXMMEXCPT)
+ {
+ DPRINT("Unmasked SIMD exceptions enabled.\n");
+ }
+ if (Pcr->PrcbData.VendorString[0])
+ {
+ DPRINT("CPU Vendor: %s\n", Pcr->PrcbData.VendorString);
+ }
+ if (Ke386CpuidModel[0])
+ {
+ DPRINT("CPU Model: %s\n", Ke386CpuidModel);
+ }
+
+ DPRINT("Ke386CacheAlignment: %d\n", Ke386CacheAlignment);
+ if (Ke386L1CacheSize)
+ {
+
+ DPRINT("Ke386L1CacheSize: %dkB\n", Ke386L1CacheSize);
+ }
+ if (Pcr->L2CacheSize)
+ {
+ DPRINT("Ke386L2CacheSize: %dkB\n", Pcr->L2CacheSize);
+ }
}
+VOID INIT_FUNCTION
+Ki386SetProcessorFeatures(VOID)
+{
+ PKIPCR Pcr = (PKIPCR)KeGetCurrentKPCR();
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING KeyName =
+ RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Kernel");
+ UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"FastSystemCallDisable");
+ HANDLE KeyHandle;
+ ULONG ResultLength;
+ KEY_VALUE_PARTIAL_INFORMATION ValueData;
+ NTSTATUS Status;
+ ULONG FastSystemCallDisable = 0;
+
+ SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = FALSE;
+ SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_EMULATED] = FALSE;
+ SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] =
+ (Pcr->PrcbData.FeatureBits & X86_FEATURE_CX8);
+ SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] =
+ (Pcr->PrcbData.FeatureBits & X86_FEATURE_MMX);
+ SharedUserData->ProcessorFeatures[PF_PPC_MOVEMEM_64BIT_OK] = FALSE;
+ SharedUserData->ProcessorFeatures[PF_ALPHA_BYTE_INSTRUCTIONS] = FALSE;
+ SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] =
+ (Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE);
+ SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] =
+ (Ke386CpuidExFlags & X86_EXT_FEATURE_3DNOW);
+ SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] =
+ (Pcr->PrcbData.FeatureBits & X86_FEATURE_TSC);
+ SharedUserData->ProcessorFeatures[PF_PAE_ENABLED] = Ke386Pae;
+ SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] =
+ (Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE2);
+
+ /* Does the CPU Support 'prefetchnta' (SSE) */
+ if(Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE)
+ {
+ /* Replace the ret by a nop */
+ *(PCHAR)RtlPrefetchMemoryNonTemporal = 0x90;
+ }
+ /* Does the CPU Support Fast System Call? */
+ if (Pcr->PrcbData.FeatureBits & X86_FEATURE_SYSCALL) {
+ /* FIXME: Check for Family == 6, Model < 3 and Stepping < 3 and disable */
+ /* Make sure it's not disabled in registry */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
+ if (NT_SUCCESS(Status)) {
+ /* Read the Value then Close the Key */
+ Status = NtQueryValueKey(KeyHandle,
+ &ValueName,
+ KeyValuePartialInformation,
+ &ValueData,
+ sizeof(ValueData),
+ &ResultLength);
+ RtlMoveMemory(&FastSystemCallDisable, ValueData.Data, sizeof(ULONG));
+
+ NtClose(KeyHandle);
+ }
+
+ } else {
+
+ /* Disable SYSENTER/SYSEXIT, because the CPU doesn't support it */
+ FastSystemCallDisable = 1;
+
+ }
+
+ if (FastSystemCallDisable) {
+ /* Use INT2E */
+ const unsigned char Entry[7] = {0x8D, 0x54, 0x24, 0x08, /* lea 0x8(%esp),%edx */
+ 0xCD, 0x2E, /* int 0x2e */
+ 0xC3}; /* ret */
+ memcpy(&SharedUserData->SystemCall, Entry, sizeof(Entry));
+ } else {
+ /* Use SYSENTER */
+ const unsigned char Entry[5] = {0x8B, 0xD4, /* movl %esp,%edx */
+ 0x0F, 0x34, /* sysenter */
+ 0xC3}; /* ret */
+ memcpy(&SharedUserData->SystemCall, Entry, sizeof(Entry));
+ /* Enable SYSENTER/SYSEXIT */
+ KiFastSystemCallDisable = 0;
+ }
+}