This is an automated email from the ASF dual-hosted git repository.

raiden00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 1ea3c01062 arch/x86_64: Implement TSC frequency query via CPUID 
0x40000010
1ea3c01062 is described below

commit 1ea3c010627f68141caccf5f11992c6da1a464da
Author: ouyangxiangzhen <ouyangxiangz...@xiaomi.com>
AuthorDate: Fri Feb 21 18:00:37 2025 +0800

    arch/x86_64: Implement TSC frequency query via CPUID 0x40000010
    
    This commit introduces support for querying TSC frequency using CPUID 
0x40000010. This function can be tested with the following command: `sudo 
qemu-system-x86_64 -enable-kvm -cpu host,+invtsc,+vmware-cpuid-freq -m 2G 
-kernel nuttx -nographic -serial mon:stdio -s`
    
    Signed-off-by: ouyangxiangzhen <ouyangxiangz...@xiaomi.com>
---
 arch/x86_64/include/intel64/arch.h       |  1 +
 arch/x86_64/src/common/x86_64_internal.h | 10 ++++
 arch/x86_64/src/intel64/Kconfig          |  7 +++
 arch/x86_64/src/intel64/intel64_freq.c   | 95 +++++++++++++++++++++++++-------
 4 files changed, 94 insertions(+), 19 deletions(-)

diff --git a/arch/x86_64/include/intel64/arch.h 
b/arch/x86_64/include/intel64/arch.h
index 94d8334700..90c0bb2bfa 100644
--- a/arch/x86_64/include/intel64/arch.h
+++ b/arch/x86_64/include/intel64/arch.h
@@ -240,6 +240,7 @@
 #  define X86_64_CPUID_07_AVX512VL     (1 << 31)
 #define X86_64_CPUID_XSAVE             0x0d
 #define X86_64_CPUID_TSC               0x15
+#define X86_64_CPUID_TSC_VMWARE        0x40000010
 #define X86_64_CPUID_EXTINFO           0x80000001
 #  define X86_64_CPUID_EXTINFO_RDTSCP  (1 << 27)
 
diff --git a/arch/x86_64/src/common/x86_64_internal.h 
b/arch/x86_64/src/common/x86_64_internal.h
index 04830cd09a..a4b79fde51 100644
--- a/arch/x86_64/src/common/x86_64_internal.h
+++ b/arch/x86_64/src/common/x86_64_internal.h
@@ -193,6 +193,16 @@ extern uint8_t _etbss[];           /* End+1 of .tbss */
  * Inline Functions
  ****************************************************************************/
 
+static inline void x86_64_cpuid(uint32_t leaf, uint32_t subleaf,
+                                uint32_t *eax, uint32_t *ebx,
+                                uint32_t *ecx, uint32_t *edx)
+{
+  __asm__ volatile("cpuid"
+                   : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
+                   : "a" (leaf), "c" (subleaf)
+                   : "memory");
+}
+
 #ifdef CONFIG_ARCH_KERNEL_STACK
 static inline_function uint64_t *x86_64_get_ktopstk(void)
 {
diff --git a/arch/x86_64/src/intel64/Kconfig b/arch/x86_64/src/intel64/Kconfig
index 5c213f0117..b89dcb6c1a 100644
--- a/arch/x86_64/src/intel64/Kconfig
+++ b/arch/x86_64/src/intel64/Kconfig
@@ -88,6 +88,13 @@ config ARCH_INTEL64_CORE_FREQ_KHZ
                to set the TSC deadline timer frequency. If set to 0 we try to 
get
                frequency from CPUID.
 
+config ARCH_INTEL64_TSC_FREQ_VMWARE
+       bool "Use CPUID 0x40000010 to get CPU Core frequency"
+       default n
+       depends on ARCH_INTEL64_CORE_FREQ_KHZ = 0
+       ---help---
+               Use CPUID 0x40000010 defined by VMware to get CPU Core frequency
+               in virtualized environments.
 endif
 
 if ARCH_INTEL64_TSC
diff --git a/arch/x86_64/src/intel64/intel64_freq.c 
b/arch/x86_64/src/intel64/intel64_freq.c
index 3747d206d0..c2775fe6c6 100644
--- a/arch/x86_64/src/intel64/intel64_freq.c
+++ b/arch/x86_64/src/intel64/intel64_freq.c
@@ -36,12 +36,74 @@
 #include <nuttx/board.h>
 #include <arch/board/board.h>
 
+#include "x86_64_internal.h"
+
 /****************************************************************************
  * Public Data
  ****************************************************************************/
 
 unsigned long g_x86_64_timer_freq;
 
+/****************************************************************************
+ * Inline Functions
+ ****************************************************************************/
+
+static inline uint64_t x86_64_timer_tsc_freq_vmware(void)
+{
+  uint32_t eax_tsc;
+  uint32_t ebx_apic;
+  uint32_t ecx;
+  uint32_t edx;
+
+  /* CPUID Leaf 0x40000010, Timing Information.
+   * Timing information leaf first defined by VMware.
+   * It is also adopted by many hypervisors such as ACRN Hypervisor.
+   * The leaf returns the TSC frequency and APIC frequency.
+   * EAX - TSC frequency in kHz.
+   * EBX - APIC frequency in kHz.
+   */
+
+  x86_64_cpuid(X86_64_CPUID_TSC_VMWARE, 0x0,
+               &eax_tsc, &ebx_apic, &ecx, &edx);
+
+  /* Suppress the warning. */
+
+  UNUSED(ecx);
+  UNUSED(edx);
+  UNUSED(ebx_apic);
+
+  return 1000ul * eax_tsc;
+}
+
+static inline uint64_t x86_64_timer_tsc_freq_15h(void)
+{
+  uint32_t crystal_freq;
+  uint32_t numerator;
+  uint32_t denominator;
+  uint32_t edx;
+
+  /* CPUID Leaf 0x15h, TSC frequency properties.
+   * The leaf returns the TSC frequency properties.
+   * EAX - Denominator.
+   * EBX - Numerator.
+   * ECX - Crystal Frequency.
+   */
+
+  x86_64_cpuid(X86_64_CPUID_TSC, 0x0,
+               &denominator, &numerator, &crystal_freq, &edx);
+
+  /* Suppress the warning. */
+
+  UNUSED(edx);
+
+  if (numerator == 0 || denominator == 0 || crystal_freq == 0)
+    {
+      return 0;
+    }
+
+  return crystal_freq / denominator * numerator;
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -74,29 +136,24 @@ unsigned long g_x86_64_timer_freq;
 void x86_64_timer_calibrate_freq(void)
 {
 #ifdef CONFIG_ARCH_INTEL64_TSC_DEADLINE
-#  if CONFIG_ARCH_INTEL64_CORE_FREQ_KHZ == 0
-  unsigned long crystal_freq;
-  unsigned long numerator;
-  unsigned long denominator;
-
-  __asm__ volatile("cpuid"
-                   : "=c" (crystal_freq), "=b" (numerator),
-                     "=a" (denominator)
-                   : "a" (X86_64_CPUID_TSC)
-                   : "rdx", "memory");
+  g_x86_64_timer_freq = CONFIG_ARCH_INTEL64_CORE_FREQ_KHZ * 1000ul;
 
-  if (numerator == 0 || denominator == 0 || crystal_freq == 0)
-    {
-      PANIC();
-    }
-  else
+  if (CONFIG_ARCH_INTEL64_CORE_FREQ_KHZ == 0)
     {
-      g_x86_64_timer_freq = crystal_freq / denominator * numerator;
-    }
+#  ifndef CONFIG_ARCH_INTEL64_TSC_FREQ_VMWARE
+      g_x86_64_timer_freq = x86_64_timer_tsc_freq_15h();
 #  else
-  g_x86_64_timer_freq = CONFIG_ARCH_INTEL64_CORE_FREQ_KHZ * 1000L;
+      g_x86_64_timer_freq = x86_64_timer_tsc_freq_vmware();
 #  endif
+    }
 #elif defined(CONFIG_ARCH_INTEL64_TSC)
-  g_x86_64_timer_freq = CONFIG_ARCH_INTEL64_APIC_FREQ_KHZ * 1000L;
+  g_x86_64_timer_freq = CONFIG_ARCH_INTEL64_APIC_FREQ_KHZ * 1000ul;
 #endif
+
+  if (g_x86_64_timer_freq == 0)
+    {
+      /* The TSC frequency is not available */
+
+      PANIC();
+    }
 }

Reply via email to