[BROWSEUI] SHExplorerParseCmdLine: Fix parsing of /root (#6752)
[reactos.git] / ntoskrnl / ke / amd64 / cpu.c
index 3ec6ee5..b2b40b0 100644 (file)
 /* INCLUDES *****************************************************************/
 
 #include <ntoskrnl.h>
+#include <x86x64/Cpuid.h>
+#include <x86x64/Msr.h>
 #define NDEBUG
 #include <debug.h>
 
-/* FIXME: Local EFLAGS defines not used anywhere else */
-#define EFLAGS_IOPL     0x3000
-#define EFLAGS_NF       0x4000
-#define EFLAGS_RF       0x10000
-#define EFLAGS_ID       0x200000
-
 /* GLOBALS *******************************************************************/
 
 /* The Boot TSS */
@@ -33,190 +29,192 @@ ULONG KeLargestCacheLine = 0x40;
 ULONG KiDmaIoCoherency = 0;
 BOOLEAN KiSMTProcessorsPresent;
 
-/* Freeze data */
-KIRQL KiOldIrql;
-ULONG KiFreezeFlag;
-
 /* Flush data */
 volatile LONG KiTbFlushTimeStamp;
 
 /* CPU Signatures */
 static const CHAR CmpIntelID[]       = "GenuineIntel";
 static const CHAR CmpAmdID[]         = "AuthenticAMD";
-static const CHAR CmpCyrixID[]       = "CyrixInstead";
-static const CHAR CmpTransmetaID[]   = "GenuineTMx86";
 static const CHAR CmpCentaurID[]     = "CentaurHauls";
-static const CHAR CmpRiseID[]        = "RiseRiseRise";
 
-/* SUPPORT ROUTINES FOR MSVC COMPATIBILITY ***********************************/
-
-VOID
-NTAPI
-CPUID(IN ULONG InfoType,
-      OUT PULONG CpuInfoEax,
-      OUT PULONG CpuInfoEbx,
-      OUT PULONG CpuInfoEcx,
-      OUT PULONG CpuInfoEdx)
+typedef union _CPU_SIGNATURE
 {
-    ULONG CpuInfo[4];
-
-    /* Perform the CPUID Operation */
-    __cpuid((int*)CpuInfo, InfoType);
-
-    /* Return the results */
-    *CpuInfoEax = CpuInfo[0];
-    *CpuInfoEbx = CpuInfo[1];
-    *CpuInfoEcx = CpuInfo[2];
-    *CpuInfoEdx = CpuInfo[3];
-}
+    struct
+    {
+        ULONG Step : 4;
+        ULONG Model : 4;
+        ULONG Family : 4;
+        ULONG Unused : 4;
+        ULONG ExtendedModel : 4;
+        ULONG ExtendedFamily : 8;
+        ULONG Unused2 : 4;
+    };
+    ULONG AsULONG;
+} CPU_SIGNATURE;
 
 /* FUNCTIONS *****************************************************************/
 
-VOID
-NTAPI
-KiSetProcessorType(VOID)
-{
-    ULONG64 EFlags;
-    INT Reg[4];
-    ULONG Stepping, Type;
-
-    /* Start by assuming no CPUID data */
-    KeGetCurrentPrcb()->CpuID = 0;
-
-    /* Save EFlags */
-    EFlags = __readeflags();
-
-    /* Do CPUID 1 now */
-    __cpuid(Reg, 1);
-
-    /*
-     * Get the Stepping and Type. The stepping contains both the
-     * Model and the Step, while the Type contains the returned Type.
-     * We ignore the family.
-     *
-     * For the stepping, we convert this: zzzzzzxy into this: x0y
-     */
-    Stepping = Reg[0] & 0xF0;
-    Stepping <<= 4;
-    Stepping += (Reg[0] & 0xFF);
-    Stepping &= 0xF0F;
-    Type = Reg[0] & 0xF00;
-    Type >>= 8;
-
-    /* Save them in the PRCB */
-    KeGetCurrentPrcb()->CpuID = TRUE;
-    KeGetCurrentPrcb()->CpuType = (UCHAR)Type;
-    KeGetCurrentPrcb()->CpuStep = (USHORT)Stepping;
-
-    /* Restore EFLAGS */
-    __writeeflags(EFlags);
-}
-
 ULONG
 NTAPI
 KiGetCpuVendor(VOID)
 {
     PKPRCB Prcb = KeGetCurrentPrcb();
-    INT Vendor[5];
+    CPU_INFO CpuInfo;
 
     /* Get the Vendor ID and null-terminate it */
-    __cpuid(Vendor, 0);
+    KiCpuId(&CpuInfo, 0);
 
     /* Copy it to the PRCB and null-terminate it */
-    *(ULONG*)&Prcb->VendorString[0] = Vendor[1]; // ebx
-    *(ULONG*)&Prcb->VendorString[4] = Vendor[3]; // edx
-    *(ULONG*)&Prcb->VendorString[8] = Vendor[2]; // ecx
-    *(ULONG*)&Prcb->VendorString[12] = 0;
+    *(ULONG*)&Prcb->VendorString[0] = CpuInfo.Ebx;
+    *(ULONG*)&Prcb->VendorString[4] = CpuInfo.Edx;
+    *(ULONG*)&Prcb->VendorString[8] = CpuInfo.Ecx;
+    Prcb->VendorString[12] = 0;
 
     /* Now check the CPU Type */
     if (!strcmp((PCHAR)Prcb->VendorString, CmpIntelID))
     {
-        return CPU_INTEL;
+        Prcb->CpuVendor = CPU_INTEL;
     }
     else if (!strcmp((PCHAR)Prcb->VendorString, CmpAmdID))
     {
-        return CPU_AMD;
+        Prcb->CpuVendor = CPU_AMD;
     }
-    else if (!strcmp((PCHAR)Prcb->VendorString, CmpCyrixID))
+    else if (!strcmp((PCHAR)Prcb->VendorString, CmpCentaurID))
     {
-        DPRINT1("Cyrix CPUs not fully supported\n");
-        return 0;
+        DPRINT1("VIA CPUs not fully supported\n");
+        Prcb->CpuVendor = CPU_VIA;
     }
-    else if (!strcmp((PCHAR)Prcb->VendorString, CmpTransmetaID))
+    else
     {
-        DPRINT1("Transmeta CPUs not fully supported\n");
-        return 0;
+        /* Invalid CPU */
+        DPRINT1("%s CPU support not fully tested!\n", Prcb->VendorString);
+        Prcb->CpuVendor = CPU_UNKNOWN;
     }
-    else if (!strcmp((PCHAR)Prcb->VendorString, CmpCentaurID))
+
+    return Prcb->CpuVendor;
+}
+
+VOID
+NTAPI
+KiSetProcessorType(VOID)
+{
+    CPU_INFO CpuInfo;
+    CPU_SIGNATURE CpuSignature;
+    BOOLEAN ExtendModel;
+    ULONG Stepping, Type, Vendor;
+
+    /* This initializes Prcb->CpuVendor */
+    Vendor = KiGetCpuVendor();
+
+    /* Do CPUID 1 now */
+    KiCpuId(&CpuInfo, 1);
+
+    /*
+     * Get the Stepping and Type. The stepping contains both the
+     * Model and the Step, while the Type contains the returned Family.
+     *
+     * For the stepping, we convert this: zzzzzzxy into this: x0y
+     */
+    CpuSignature.AsULONG = CpuInfo.Eax;
+    Stepping = CpuSignature.Model;
+    ExtendModel = (CpuSignature.Family == 15);
+#if ( (NTDDI_VERSION >= NTDDI_WINXPSP2) && (NTDDI_VERSION < NTDDI_WS03) ) || (NTDDI_VERSION >= NTDDI_WS03SP1)
+    if (CpuSignature.Family == 6)
     {
-        DPRINT1("VIA CPUs not fully supported\n");
-        return 0;
+        ExtendModel |= (Vendor == CPU_INTEL);
+#if (NTDDI_VERSION >= NTDDI_WIN8)
+        ExtendModel |= (Vendor == CPU_CENTAUR);
+#endif
     }
-    else if (!strcmp((PCHAR)Prcb->VendorString, CmpRiseID))
+#endif
+    if (ExtendModel)
     {
-        DPRINT1("Rise CPUs not fully supported\n");
-        return 0;
+        /* Add ExtendedModel to distinguish from non-extended values. */
+        Stepping |= (CpuSignature.ExtendedModel << 4);
+    }
+    Stepping = (Stepping << 8) | CpuSignature.Step;
+    Type = CpuSignature.Family;
+    if (CpuSignature.Family == 15)
+    {
+        /* Add ExtendedFamily to distinguish from non-extended values.
+         * It must not be larger than 0xF0 to avoid overflow. */
+        Type += min(CpuSignature.ExtendedFamily, 0xF0);
     }
 
-    /* Invalid CPU */
-    return 0;
+    /* Save them in the PRCB */
+    KeGetCurrentPrcb()->CpuID = TRUE;
+    KeGetCurrentPrcb()->CpuType = (UCHAR)Type;
+    KeGetCurrentPrcb()->CpuStep = (USHORT)Stepping;
 }
 
-ULONG
+/*!
+    \brief Evaluates the KeFeatureFlag bits for the current CPU.
+
+    \return The feature flags for this CPU.
+
+    \see https://www.geoffchappell.com/studies/windows/km/ntoskrnl/structs/kprcb/featurebits.htm
+
+    \todo
+     - KF_VIRT_FIRMWARE_ENABLED 0x08000000 (see notes from Geoff Chappell)
+     - KF_FPU_LEAKAGE 0x0000020000000000ULL
+     - KF_CAT 0x0000100000000000ULL
+     - KF_CET_SS 0x0000400000000000ULL
+*/
+ULONG64
 NTAPI
 KiGetFeatureBits(VOID)
 {
     PKPRCB Prcb = KeGetCurrentPrcb();
     ULONG Vendor;
-    ULONG FeatureBits = KF_WORKING_PTE;
-    INT Reg[4];
-    ULONG CpuFeatures = 0;
+    ULONG64 FeatureBits = 0;
+    CPUID_SIGNATURE_REGS signature;
+    CPUID_VERSION_INFO_REGS VersionInfo;
+    CPUID_EXTENDED_FUNCTION_REGS extendedFunction;
 
     /* Get the Vendor ID */
-    Vendor = KiGetCpuVendor();
+    Vendor = Prcb->CpuVendor;
 
     /* Make sure we got a valid vendor ID at least. */
-    if (!Vendor) return FeatureBits;
+    if (Vendor == CPU_UNKNOWN) return FeatureBits;
 
-    /* Get the CPUID Info. Features are in Reg[3]. */
-    __cpuid(Reg, 1);
+    /* Get signature CPUID for the maximum function */
+    __cpuid(signature.AsInt32, CPUID_SIGNATURE);
 
-    /* Set the initial APIC ID */
-    Prcb->InitialApicId = (UCHAR)(Reg[1] >> 24);
+    /* Get the CPUID Info. */
+    __cpuid(VersionInfo.AsInt32, CPUID_VERSION_INFO);
 
-    /* Set the current features */
-    CpuFeatures = Reg[3];
+    /* Set the initial APIC ID */
+    Prcb->InitialApicId = (UCHAR)VersionInfo.Ebx.Bits.InitialLocalApicId;
 
     /* Convert all CPUID Feature bits into our format */
-    if (CpuFeatures & 0x00000002) FeatureBits |= KF_V86_VIS | KF_CR4;
-    if (CpuFeatures & 0x00000008) FeatureBits |= KF_LARGE_PAGE | KF_CR4;
-    if (CpuFeatures & 0x00000010) FeatureBits |= KF_RDTSC;
-    if (CpuFeatures & 0x00000100) FeatureBits |= KF_CMPXCHG8B;
-    if (CpuFeatures & 0x00000800) FeatureBits |= KF_FAST_SYSCALL;
-    if (CpuFeatures & 0x00001000) FeatureBits |= KF_MTRR;
-    if (CpuFeatures & 0x00002000) FeatureBits |= KF_GLOBAL_PAGE | KF_CR4;
-    if (CpuFeatures & 0x00008000) FeatureBits |= KF_CMOV;
-    if (CpuFeatures & 0x00010000) FeatureBits |= KF_PAT;
-    if (CpuFeatures & 0x00200000) FeatureBits |= KF_DTS;
-    if (CpuFeatures & 0x00800000) FeatureBits |= KF_MMX;
-    if (CpuFeatures & 0x01000000) FeatureBits |= KF_FXSR;
-    if (CpuFeatures & 0x02000000) FeatureBits |= KF_XMMI;
-    if (CpuFeatures & 0x04000000) FeatureBits |= KF_XMMI64;
-
-#if 0
-    if (Reg[2] & 0x00000001) FeatureBits |= KF_SSE3NEW;
-    if (Reg[2] & 0x00000008) FeatureBits |= KF_MONITOR;
-    if (Reg[2] & 0x00000200) FeatureBits |= KF_SSE3SUP;
-    if (Reg[2] & 0x00002000) FeatureBits |= KF_CMPXCHG16B;
-    if (Reg[2] & 0x00080000) FeatureBits |= KF_SSE41;
-    if (Reg[2] & 0x00800000) FeatureBits |= KF_POPCNT;
-#endif
+    if (VersionInfo.Edx.Bits.VME) FeatureBits |= KF_CR4;
+    if (VersionInfo.Edx.Bits.PSE) FeatureBits |= KF_LARGE_PAGE | KF_CR4;
+    if (VersionInfo.Edx.Bits.TSC) FeatureBits |= KF_RDTSC;
+    if (VersionInfo.Edx.Bits.CX8) FeatureBits |= KF_CMPXCHG8B;
+    if (VersionInfo.Edx.Bits.SEP) FeatureBits |= KF_FAST_SYSCALL;
+    if (VersionInfo.Edx.Bits.MTRR) FeatureBits |= KF_MTRR;
+    if (VersionInfo.Edx.Bits.PGE) FeatureBits |= KF_GLOBAL_PAGE | KF_CR4;
+    if (VersionInfo.Edx.Bits.CMOV) FeatureBits |= KF_CMOV;
+    if (VersionInfo.Edx.Bits.PAT) FeatureBits |= KF_PAT;
+    if (VersionInfo.Edx.Bits.DS) FeatureBits |= KF_DTS;
+    if (VersionInfo.Edx.Bits.MMX) FeatureBits |= KF_MMX;
+    if (VersionInfo.Edx.Bits.FXSR) FeatureBits |= KF_FXSR;
+    if (VersionInfo.Edx.Bits.SSE) FeatureBits |= KF_XMMI;
+    if (VersionInfo.Edx.Bits.SSE2) FeatureBits |= KF_XMMI64;
+
+    if (VersionInfo.Ecx.Bits.SSE3) FeatureBits |= KF_SSE3;
+    if (VersionInfo.Ecx.Bits.SSSE3) FeatureBits |= KF_SSSE3;
+    if (VersionInfo.Ecx.Bits.CMPXCHG16B) FeatureBits |= KF_CMPXCHG16B;
+    if (VersionInfo.Ecx.Bits.SSE4_1) FeatureBits |= KF_SSE4_1;
+    if (VersionInfo.Ecx.Bits.XSAVE) FeatureBits |= KF_XSTATE;
+    if (VersionInfo.Ecx.Bits.RDRAND) FeatureBits |= KF_RDRAND;
 
     /* Check if the CPU has hyper-threading */
-    if (CpuFeatures & 0x10000000)
+    if (VersionInfo.Edx.Bits.HTT)
     {
         /* Set the number of logical CPUs */
-        Prcb->LogicalProcessorsPerPhysicalProcessor = (UCHAR)(Reg[1] >> 16);
+        Prcb->LogicalProcessorsPerPhysicalProcessor =
+            VersionInfo.Ebx.Bits.MaximumAddressableIdsForLogicalProcessors;
         if (Prcb->LogicalProcessorsPerPhysicalProcessor > 1)
         {
             /* We're on dual-core */
@@ -229,25 +227,115 @@ KiGetFeatureBits(VOID)
         Prcb->LogicalProcessorsPerPhysicalProcessor = 1;
     }
 
+    /* Check if CPUID_THERMAL_POWER_MANAGEMENT (0x06) is supported */
+    if (signature.MaxLeaf >= CPUID_THERMAL_POWER_MANAGEMENT)
+    {
+        /* Read CPUID_THERMAL_POWER_MANAGEMENT */
+        CPUID_THERMAL_POWER_MANAGEMENT_REGS PowerInfo;
+        __cpuid(PowerInfo.AsInt32, CPUID_THERMAL_POWER_MANAGEMENT);
+
+        if (PowerInfo.Undoc.Ecx.ACNT2) FeatureBits |= KF_ACNT2;
+    }
+
+    /* Check if CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS (0x07) is supported */
+    if (signature.MaxLeaf >= CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS)
+    {
+        /* Read CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS */
+        CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_REGS ExtFlags;
+        __cpuidex(ExtFlags.AsInt32,
+            CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS,
+            CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_SUB_LEAF_INFO);
+
+        if (ExtFlags.Ebx.Bits.SMEP) FeatureBits |= KF_SMEP;
+        if (ExtFlags.Ebx.Bits.FSGSBASE) FeatureBits |= KF_RDWRFSGSBASE;
+        if (ExtFlags.Ebx.Bits.SMAP) FeatureBits |= KF_SMAP;
+    }
+
+    /* Check if CPUID_EXTENDED_STATE (0x0D) is supported */
+    if (signature.MaxLeaf >= CPUID_EXTENDED_STATE)
+    {
+        /* Read CPUID_EXTENDED_STATE */
+        CPUID_EXTENDED_STATE_SUB_LEAF_EAX_REGS ExtStateSub;
+        __cpuidex(ExtStateSub.AsInt32,
+            CPUID_EXTENDED_STATE,
+            CPUID_EXTENDED_STATE_SUB_LEAF);
+
+        if (ExtStateSub.Eax.Bits.XSAVEOPT) FeatureBits |= KF_XSAVEOPT;
+        if (ExtStateSub.Eax.Bits.XSAVES)  FeatureBits |= KF_XSAVES;
+    }
+
     /* Check extended cpuid features */
-    __cpuid(Reg, 0x80000000);
-    if ((Reg[0] & 0xffffff00) == 0x80000000)
+    __cpuid(extendedFunction.AsInt32, CPUID_EXTENDED_FUNCTION);
+    if ((extendedFunction.MaxLeaf & 0xffffff00) == 0x80000000)
     {
-        /* Check if CPUID 0x80000001 is supported */
-        if (Reg[0] >= 0x80000001)
+        /* Check if CPUID_EXTENDED_CPU_SIG (0x80000001) is supported */
+        if (extendedFunction.MaxLeaf >= CPUID_EXTENDED_CPU_SIG)
         {
-            /* Check which extended features are available. */
-            __cpuid(Reg, 0x80000001);
+            /* Read CPUID_EXTENDED_CPU_SIG */
+            CPUID_EXTENDED_CPU_SIG_REGS ExtSig;
+            __cpuid(ExtSig.AsInt32, CPUID_EXTENDED_CPU_SIG);
 
             /* Check if NX-bit is supported */
-            if (Reg[3] & 0x00100000) FeatureBits |= KF_NX_BIT;
+            if (ExtSig.Intel.Edx.Bits.NX) FeatureBits |= KF_NX_BIT;
+            if (ExtSig.Intel.Edx.Bits.Page1GB) FeatureBits |= KF_HUGEPAGE;
+            if (ExtSig.Intel.Edx.Bits.RDTSCP) FeatureBits |= KF_RDTSCP;
+
+            /* AMD specific */
+            if (Vendor == CPU_AMD)
+            {
+                if (ExtSig.Amd.Edx.Bits.ThreeDNow) FeatureBits |= KF_3DNOW;
+            }
+        }
+    }
+
+    /* Vendor specific */
+    if (Vendor == CPU_INTEL)
+    {
+        FeatureBits |= KF_GENUINE_INTEL;
+
+        /* Check for models that support LBR */
+        if (VersionInfo.Eax.Bits.FamilyId == 6)
+        {
+            if ((VersionInfo.Eax.Bits.Model == 15) ||
+                (VersionInfo.Eax.Bits.Model == 22) ||
+                (VersionInfo.Eax.Bits.Model == 23) ||
+                (VersionInfo.Eax.Bits.Model == 26))
+            {
+                FeatureBits |= KF_BRANCH;
+            }
+        }
 
-            /* Now handle each features for each CPU Vendor */
-            switch (Vendor)
+        /* Check if VMX is available */
+        if (VersionInfo.Ecx.Bits.VMX)
+        {
+            /* Read PROCBASED ctls and check if secondary are allowed */
+            MSR_IA32_VMX_PROCBASED_CTLS_REGISTER ProcBasedCtls;
+            ProcBasedCtls.Uint64 = __readmsr(MSR_IA32_VMX_PROCBASED_CTLS);
+            if (ProcBasedCtls.Bits.Allowed1.ActivateSecondaryControls)
             {
-                case CPU_AMD:
-                    if (Reg[3] & 0x80000000) FeatureBits |= KF_3DNOW;
-                    break;
+                /* Read secondary controls and check if EPT is allowed */
+                MSR_IA32_VMX_PROCBASED_CTLS2_REGISTER ProcBasedCtls2;
+                ProcBasedCtls2.Uint64 = __readmsr(MSR_IA32_VMX_PROCBASED_CTLS2);
+                if (ProcBasedCtls2.Bits.Allowed1.EPT)
+                    FeatureBits |= KF_SLAT;
+            }
+        }
+    }
+    else if (Vendor == CPU_AMD)
+    {
+        FeatureBits |= KF_AUTHENTICAMD;
+        FeatureBits |= KF_BRANCH;
+
+        /* Check extended cpuid features */
+        if ((extendedFunction.MaxLeaf & 0xffffff00) == 0x80000000)
+        {
+            /* Check if CPUID_AMD_SVM_FEATURES (0x8000000A) is supported */
+            if (extendedFunction.MaxLeaf >= CPUID_AMD_SVM_FEATURES)
+            {
+                /* Read CPUID_AMD_SVM_FEATURES and check if Nested Paging is available */
+                CPUID_AMD_SVM_FEATURES_REGS SvmFeatures;
+                __cpuid(SvmFeatures.AsInt32, CPUID_AMD_SVM_FEATURES);
+                if (SvmFeatures.Edx.Bits.NP) FeatureBits |= KF_SLAT;
             }
         }
     }
@@ -256,17 +344,86 @@ KiGetFeatureBits(VOID)
     return FeatureBits;
 }
 
+#if DBG
+VOID
+KiReportCpuFeatures(IN PKPRCB Prcb)
+{
+    ULONG CpuFeatures = 0;
+    CPU_INFO CpuInfo;
+
+    if (Prcb->CpuVendor)
+    {
+        KiCpuId(&CpuInfo, 1);
+        CpuFeatures = CpuInfo.Edx;
+    }
+
+    DPRINT1("Supported CPU features: ");
+
+#define print_kf_bit(kf_value) if (Prcb->FeatureBits & kf_value) DbgPrint(#kf_value " ")
+    print_kf_bit(KF_SMEP);
+    print_kf_bit(KF_RDTSC);
+    print_kf_bit(KF_CR4);
+    print_kf_bit(KF_CMOV);
+    print_kf_bit(KF_GLOBAL_PAGE);
+    print_kf_bit(KF_LARGE_PAGE);
+    print_kf_bit(KF_MTRR);
+    print_kf_bit(KF_CMPXCHG8B);
+    print_kf_bit(KF_MMX);
+    print_kf_bit(KF_DTS);
+    print_kf_bit(KF_PAT);
+    print_kf_bit(KF_FXSR);
+    print_kf_bit(KF_FAST_SYSCALL);
+    print_kf_bit(KF_XMMI);
+    print_kf_bit(KF_3DNOW);
+    print_kf_bit(KF_XSAVEOPT);
+    print_kf_bit(KF_XMMI64);
+    print_kf_bit(KF_BRANCH);
+    print_kf_bit(KF_00040000);
+    print_kf_bit(KF_SSE3);
+    print_kf_bit(KF_CMPXCHG16B);
+    print_kf_bit(KF_AUTHENTICAMD);
+    print_kf_bit(KF_ACNT2);
+    print_kf_bit(KF_XSTATE);
+    print_kf_bit(KF_GENUINE_INTEL);
+    print_kf_bit(KF_SLAT);
+    print_kf_bit(KF_VIRT_FIRMWARE_ENABLED);
+    print_kf_bit(KF_RDWRFSGSBASE);
+    print_kf_bit(KF_NX_BIT);
+    print_kf_bit(KF_NX_DISABLED);
+    print_kf_bit(KF_NX_ENABLED);
+    print_kf_bit(KF_RDRAND);
+    print_kf_bit(KF_SMAP);
+    print_kf_bit(KF_RDTSCP);
+    print_kf_bit(KF_HUGEPAGE);
+    print_kf_bit(KF_XSAVES);
+    print_kf_bit(KF_FPU_LEAKAGE);
+    print_kf_bit(KF_CAT);
+    print_kf_bit(KF_CET_SS);
+    print_kf_bit(KF_SSSE3);
+    print_kf_bit(KF_SSE4_1);
+    print_kf_bit(KF_SSE4_2);
+#undef print_kf_bit
+
+#define print_cf(cpu_flag) if (CpuFeatures & cpu_flag) DbgPrint(#cpu_flag " ")
+    print_cf(X86_FEATURE_PAE);
+    print_cf(X86_FEATURE_HT);
+#undef print_cf
+
+    DbgPrint("\n");
+}
+#endif // DBG
+
 VOID
 NTAPI
 KiGetCacheInformation(VOID)
 {
     PKIPCR Pcr = (PKIPCR)KeGetPcr();
     ULONG Vendor;
-    INT Data[4];
     ULONG CacheRequests = 0, i;
     ULONG CurrentRegister;
     UCHAR RegisterByte;
     BOOLEAN FirstPass = TRUE;
+    CPU_INFO CpuInfo;
 
     /* Set default L2 size */
     Pcr->SecondLevelCacheSize = 0;
@@ -282,14 +439,14 @@ KiGetCacheInformation(VOID)
         case CPU_INTEL:
 
             /*Check if we support CPUID 2 */
-            __cpuid(Data, 0);
-            if (Data[0] >= 2)
+            KiCpuId(&CpuInfo, 0);
+            if (CpuInfo.Eax >= 2)
             {
                 /* We need to loop for the number of times CPUID will tell us to */
                 do
                 {
                     /* Do the CPUID call */
-                    __cpuid(Data, 2);
+                    KiCpuId(&CpuInfo, 2);
 
                     /* Check if it was the first call */
                     if (FirstPass)
@@ -298,8 +455,8 @@ KiGetCacheInformation(VOID)
                          * The number of times to loop is the first byte. Read
                          * it and then destroy it so we don't get confused.
                          */
-                        CacheRequests = Data[0] & 0xFF;
-                        Data[0] &= 0xFFFFFF00;
+                        CacheRequests = CpuInfo.Eax & 0xFF;
+                        CpuInfo.Eax &= 0xFFFFFF00;
 
                         /* Don't go over this again */
                         FirstPass = FALSE;
@@ -309,7 +466,7 @@ KiGetCacheInformation(VOID)
                     for (i = 0; i < 4; i++)
                     {
                         /* Get the current register */
-                        CurrentRegister = Data[i];
+                        CurrentRegister = CpuInfo.AsUINT32[i];
 
                         /*
                          * If the upper bit is set, then this register should
@@ -351,14 +508,14 @@ KiGetCacheInformation(VOID)
         case CPU_AMD:
 
             /* Check if we support CPUID 0x80000006 */
-            __cpuid(Data, 0x80000000);
-            if (Data[0] >= 6)
+            KiCpuId(&CpuInfo, 0x80000000);
+            if (CpuInfo.Eax >= 6)
             {
                 /* Get 2nd level cache and tlb size */
-                __cpuid(Data, 0x80000006);
+                KiCpuId(&CpuInfo, 0x80000006);
 
                 /* Set the L2 Cache Size */
-                Pcr->SecondLevelCacheSize = (Data[2] & 0xFFFF0000) >> 6;
+                Pcr->SecondLevelCacheSize = (CpuInfo.Ecx & 0xFFFF0000) >> 6;
             }
             break;
     }
@@ -397,7 +554,7 @@ KiRestoreProcessorControlState(PKPROCESSOR_STATE ProcessorState)
 //    __ltr(&ProcessorState->SpecialRegisters.Tr);
     __lidt(&ProcessorState->SpecialRegisters.Idtr.Limit);
 
-//    __ldmxcsr(&ProcessorState->SpecialRegisters.MxCsr); // FIXME
+    _mm_setcsr(ProcessorState->SpecialRegisters.MxCsr);
 //    ProcessorState->SpecialRegisters.DebugControl
 //    ProcessorState->SpecialRegisters.LastBranchToRip
 //    ProcessorState->SpecialRegisters.LastBranchFromRip
@@ -439,7 +596,7 @@ KiSaveProcessorControlState(OUT PKPROCESSOR_STATE ProcessorState)
     __str(&ProcessorState->SpecialRegisters.Tr);
     __sidt(&ProcessorState->SpecialRegisters.Idtr.Limit);
 
-//    __stmxcsr(&ProcessorState->SpecialRegisters.MxCsr);
+    ProcessorState->SpecialRegisters.MxCsr = _mm_getcsr();
 //    ProcessorState->SpecialRegisters.DebugControl =
 //    ProcessorState->SpecialRegisters.LastBranchToRip =
 //    ProcessorState->SpecialRegisters.LastBranchFromRip =