diff --git a/headers/private/kernel/arch/x86/arch_cpu.h b/headers/private/kernel/arch/x86/arch_cpu.h index 9c6c3ae424..9d9a77affb 100644 --- a/headers/private/kernel/arch/x86/arch_cpu.h +++ b/headers/private/kernel/arch/x86/arch_cpu.h @@ -265,8 +265,9 @@ #define IA32_FEATURE_EXT_HYPERVISOR (1 << 31) // Running on a hypervisor // x86 features from cpuid eax 0x80000001, ecx register (AMD) -#define IA32_FEATURE_AMD_EXT_CMPLEGACY (1 << 1) // Core MP legacy mode -#define IA32_FEATURE_AMD_EXT_TOPOLOGY (1 << 22) // Topology extensions +#define IA32_FEATURE_AMD_EXT_CMPLEGACY (1 << 1) // Core MP legacy mode +#define IA32_FEATURE_AMD_EXT_TOPOLOGY (1 << 22) // Topology extensions +#define IA32_FEATURE_AMD_EXT_MWAITX (1 << 29) // MWAITX, MONITORX instructions // x86 features from cpuid eax 0x80000001, edx register (AMD) // only care about the ones that are unique to this register @@ -354,6 +355,7 @@ #define IA32_FEATURE_UMIP (1 << 2) // User-mode Instruction Prevention #define IA32_FEATURE_PKU (1 << 3) // Memory Protection Keys for User-mode pages #define IA32_FEATURE_OSPKE (1 << 4) // PKU enabled by OS +#define IA32_FEATURE_WAITPKG (1 << 5) // TPAUSE, UMONITOR, UMWAIT instructions #define IA32_FEATURE_AVX512VMBI2 (1 << 6) // AVX-512 Vector Bit Manipulation Instructions 2 #define IA32_FEATURE_GFNI (1 << 8) // Galois Field instructions #define IA32_FEATURE_VAES (1 << 9) // AES instruction set (VEX-256/EVEX) diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp b/src/system/kernel/arch/x86/arch_cpu.cpp index 043f3d226a..c9fea50cdc 100644 --- a/src/system/kernel/arch/x86/arch_cpu.cpp +++ b/src/system/kernel/arch/x86/arch_cpu.cpp @@ -500,6 +500,8 @@ dump_feature_string(int currentCPU, cpu_ent* cpu) strlcat(features, "rdrnd ", sizeof(features)); if (cpu->arch.feature[FEATURE_EXT] & IA32_FEATURE_EXT_HYPERVISOR) strlcat(features, "hypervisor ", sizeof(features)); + if (cpu->arch.feature[FEATURE_EXT_AMD_ECX] & IA32_FEATURE_AMD_EXT_MWAITX) + strlcat(features, "mwaitx ", sizeof(features)); if (cpu->arch.feature[FEATURE_EXT_AMD] & IA32_FEATURE_AMD_EXT_SYSCALL) strlcat(features, "syscall ", sizeof(features)); if (cpu->arch.feature[FEATURE_EXT_AMD] & IA32_FEATURE_AMD_EXT_NX) @@ -624,6 +626,8 @@ dump_feature_string(int currentCPU, cpu_ent* cpu) strlcat(features, "pku ", sizeof(features)); if (cpu->arch.feature[FEATURE_7_ECX] & IA32_FEATURE_OSPKE) strlcat(features, "ospke ", sizeof(features)); + if (cpu->arch.feature[FEATURE_7_ECX] & IA32_FEATURE_WAITPKG) + strlcat(features, "waitpkg ", sizeof(features)); if (cpu->arch.feature[FEATURE_7_ECX] & IA32_FEATURE_AVX512VMBI2) strlcat(features, "avx512vmbi2 ", sizeof(features)); if (cpu->arch.feature[FEATURE_7_ECX] & IA32_FEATURE_GFNI) diff --git a/src/system/kernel/arch/x86/arch_debug.cpp b/src/system/kernel/arch/x86/arch_debug.cpp index 6a1edfb6dd..bf9d665abd 100644 --- a/src/system/kernel/arch/x86/arch_debug.cpp +++ b/src/system/kernel/arch/x86/arch_debug.cpp @@ -11,6 +11,7 @@ #include +#include #include #include @@ -1357,9 +1358,52 @@ arch_debug_gdb_get_registers(char* buffer, size_t bufferSize) } +static void (*sDebugSnooze)(bigtime_t) = NULL; +static uint64 sDebugSnoozeConversionFactor = 0; + + +static void +debug_snooze_mwaitx(bigtime_t duration) +{ + uint32 delay = (duration * sDebugSnoozeConversionFactor) / 1000; + if (delay == 0) + delay = 1; + + // monitorx (r/eax = pointer, ecx = extensions, edx = hints) + asm volatile(".byte 0x0f, 0x01, 0xfa;" + :: "a" (sDebugSnooze), "c" (0), "d" (0)); + + // mwaitx (eax = hints, ecx = extensions, ebx = timeout) + asm volatile(".byte 0x0f, 0x01, 0xfb;" + :: "a" (0xf0 /* disable C-states */), "c" (0x2 /* enable timer */), "b" (delay)); +} + + +static void +debug_snooze_tpause(bigtime_t duration) +{ + uint32 delay = (duration * sDebugSnoozeConversionFactor) / 1000; + if (delay == 0) + delay = 1; + + memory_read_barrier(); + uint64 target = __rdtsc() + delay; + + // tpause (ecx = options, eax = target [low 32], edx = target [high 32]) + uint32 low = target, high = target >> 32; + asm volatile(".byte 0x66, 0x0f, 0xae, 0xf1;" + :: "c" (0x0), "a" (low), "d" (high)); +} + + void arch_debug_snooze(bigtime_t duration) { + if (sDebugSnooze != NULL) { + sDebugSnooze(duration); + return; + } + spin(duration); } @@ -1367,7 +1411,18 @@ arch_debug_snooze(bigtime_t duration) status_t arch_debug_init(kernel_args* args) { - // at this stage, the debugger command system is alive + bool haveMWAITX = x86_check_feature(IA32_FEATURE_AMD_EXT_MWAITX, FEATURE_EXT_AMD_ECX), + haveTPAUSE = x86_check_feature(IA32_FEATURE_WAITPKG, FEATURE_7_ECX); + if (haveMWAITX || haveTPAUSE) { + // Store the TSC frequency in kHz. + sDebugSnoozeConversionFactor = + (uint64(1000) << 32) / args->arch_args.system_time_cv_factor; + + if (haveMWAITX) + sDebugSnooze = debug_snooze_mwaitx; + else if (haveTPAUSE) + sDebugSnooze = debug_snooze_tpause; + } add_debugger_command("where", &stack_trace, "Same as \"sc\""); add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)");