https://git.reactos.org/?p=reactos.git;a=commitdiff;h=410b1030c02240e0a711b…
commit 410b1030c02240e0a711b0006023451fdd46a6d1
Author: Timo Kreuzer <timo.kreuzer(a)reactos.org>
AuthorDate: Sun Aug 27 15:07:30 2023 +0300
Commit: Timo Kreuzer <timo.kreuzer(a)reactos.org>
CommitDate: Tue Oct 3 19:45:44 2023 +0300
[NTOS:KE/x64] Implement detection of more KF_* feature flags
- Detect KF_SSSE3, KF_SSE4_1, KF_SSE4_2, KF_RDRAND, KF_BRANCH, KF_SLAT,
KF_GENUINE_INTEL, KF_AUTHENTICAMD, KF_ACNT2, KF_SMEP, KF_SMAP, KF_RDWRFSGSBASE,
KF_XSAVEOPT, KF_XSAVES, KF_HUGEPAGE, KF_RDTSCP
---
ntoskrnl/ke/amd64/cpu.c | 159 +++++++++++++++++++++++++++++++++----
sdk/include/ndk/amd64/ketypes.h | 2 +-
sdk/include/reactos/x86x64/Cpuid.h | 11 ++-
sdk/include/reactos/x86x64/Msr.h | 6 ++
4 files changed, 156 insertions(+), 22 deletions(-)
diff --git a/ntoskrnl/ke/amd64/cpu.c b/ntoskrnl/ke/amd64/cpu.c
index f01784f5b07..b2b40b0bf62 100644
--- a/ntoskrnl/ke/amd64/cpu.c
+++ b/ntoskrnl/ke/amd64/cpu.c
@@ -11,6 +11,7 @@
#include <ntoskrnl.h>
#include <x86x64/Cpuid.h>
+#include <x86x64/Msr.h>
#define NDEBUG
#include <debug.h>
@@ -146,6 +147,19 @@ KiSetProcessorType(VOID)
KeGetCurrentPrcb()->CpuStep = (USHORT)Stepping;
}
+/*!
+ \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/fea…
+
+ \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)
@@ -153,6 +167,7 @@ KiGetFeatureBits(VOID)
PKPRCB Prcb = KeGetCurrentPrcb();
ULONG Vendor;
ULONG64 FeatureBits = 0;
+ CPUID_SIGNATURE_REGS signature;
CPUID_VERSION_INFO_REGS VersionInfo;
CPUID_EXTENDED_FUNCTION_REGS extendedFunction;
@@ -160,7 +175,10 @@ KiGetFeatureBits(VOID)
Vendor = Prcb->CpuVendor;
/* Make sure we got a valid vendor ID at least. */
- if (!Vendor) return FeatureBits;
+ if (Vendor == CPU_UNKNOWN) return FeatureBits;
+
+ /* Get signature CPUID for the maximum function */
+ __cpuid(signature.AsInt32, CPUID_SIGNATURE);
/* Get the CPUID Info. */
__cpuid(VersionInfo.AsInt32, CPUID_VERSION_INFO);
@@ -189,6 +207,7 @@ KiGetFeatureBits(VOID)
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 (VersionInfo.Edx.Bits.HTT)
@@ -208,27 +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(extendedFunction.AsInt32, CPUID_EXTENDED_FUNCTION);
if ((extendedFunction.MaxLeaf & 0xffffff00) == 0x80000000)
{
- /* Check if CPUID 0x80000001 is supported */
- if (extendedFunction.MaxLeaf >= 0x80000001)
+ /* Check if CPUID_EXTENDED_CPU_SIG (0x80000001) is supported */
+ if (extendedFunction.MaxLeaf >= CPUID_EXTENDED_CPU_SIG)
{
- CPUID_EXTENDED_CPU_SIG_REGS extSig;
-
- /* Check which extended features are available. */
- __cpuid(extSig.AsInt32, CPUID_EXTENDED_CPU_SIG);
+ /* 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 (extSig.Intel.Edx.Bits.NX) 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;
- /* Now handle each features for each CPU Vendor */
- switch (Vendor)
+ /* AMD specific */
+ if (Vendor == CPU_AMD)
{
- case CPU_AMD:
- if (extSig.Amd.Edx.Bits.ThreeDNow) FeatureBits |= KF_3DNOW;
- break;
+ 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;
+ }
+ }
+
+ /* 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)
+ {
+ /* 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;
}
}
}
@@ -261,22 +368,40 @@ KiReportCpuFeatures(IN PKPRCB Prcb)
print_kf_bit(KF_LARGE_PAGE);
print_kf_bit(KF_MTRR);
print_kf_bit(KF_CMPXCHG8B);
- print_kf_bit(KF_CMPXCHG16B);
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_DTS);
+ 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_SSE3);
+ 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_XSTATE);
+ print_kf_bit(KF_SSE4_2);
#undef print_kf_bit
#define print_cf(cpu_flag) if (CpuFeatures & cpu_flag) DbgPrint(#cpu_flag "
")
diff --git a/sdk/include/ndk/amd64/ketypes.h b/sdk/include/ndk/amd64/ketypes.h
index 1f306de1d2c..81219a73f82 100644
--- a/sdk/include/ndk/amd64/ketypes.h
+++ b/sdk/include/ndk/amd64/ketypes.h
@@ -249,7 +249,7 @@ typedef enum
#define MSR_GS_SWAP 0xC0000102
#define MSR_MCG_STATUS 0x017A
#define MSR_AMD_ACCESS 0x9C5A203A
-#define MSR_IA32_MISC_ENABLE 0x01A0
+#define MSR_IA32_MISC_ENABLE 0x000001A0
#define MSR_LAST_BRANCH_FROM 0x01DB
#define MSR_LAST_BRANCH_TO 0x01DC
#define MSR_LAST_EXCEPTION_FROM 0x01DD
diff --git a/sdk/include/reactos/x86x64/Cpuid.h b/sdk/include/reactos/x86x64/Cpuid.h
index 0a27d581e17..39ece442c99 100644
--- a/sdk/include/reactos/x86x64/Cpuid.h
+++ b/sdk/include/reactos/x86x64/Cpuid.h
@@ -1,3 +1,9 @@
+/*
+ * PROJECT: ReactOS SDK
+ * LICENSE: MIT (
https://spdx.org/licenses/MIT)
+ * PURPOSE: Provides CPUID structure definitions
+ * COPYRIGHT: Copyright 2023 Timo Kreuzer <timo.kreuzer(a)reactos.org>
+ */
#define CHAR8 char
@@ -104,10 +110,7 @@ typedef union
UINT32 XSaveAreaSize; // The size in bytes of the XSAVE area containing all
states enabled by XCRO | IA32_XSS.
} Ebx;
CPUID_EXTENDED_STATE_SUB_LEAF_ECX Ecx;
- struct
- {
- UINT32 Edx; // Reports the supported bits of the upper 32 bits of the
IA32_XSS MSR.IA32_XSS[n + 32] can be set to 1 only if EDX[n] is 1.
- } Edx;
+ UINT32 Edx; // Reports the supported bits of the upper 32 bits of the IA32_XSS
MSR. IA32_XSS[n + 32] can be set to 1 only if EDX[n] is 1.
};
} CPUID_EXTENDED_STATE_SUB_LEAF_EAX_REGS;
diff --git a/sdk/include/reactos/x86x64/Msr.h b/sdk/include/reactos/x86x64/Msr.h
index 21e2a4df6ec..98b3e4d9ae1 100644
--- a/sdk/include/reactos/x86x64/Msr.h
+++ b/sdk/include/reactos/x86x64/Msr.h
@@ -1,3 +1,9 @@
+/*
+ * PROJECT: ReactOS SDK
+ * LICENSE: MIT (
https://spdx.org/licenses/MIT)
+ * PURPOSE: Provides CPUID structure definitions
+ * COPYRIGHT: Copyright 2023 Timo Kreuzer <timo.kreuzer(a)reactos.org>
+ */
#define SIZE_2KB 2048