Module Name:    src
Committed By:   imil
Date:           Thu Mar  6 06:31:53 UTC 2025

Modified Files:
        src/sys/arch/x86/include: apicvar.h
        src/sys/arch/x86/x86: cpu.c identcpu_subr.c lapic.c

Log Message:
Add support for CPUID leaf 0x40000010, which enables VMware-compatible TSC
and LAPIC frequency detection for virtual machines.


To generate a diff of this commit:
cvs rdiff -u -r1.8 -r1.9 src/sys/arch/x86/include/apicvar.h
cvs rdiff -u -r1.210 -r1.211 src/sys/arch/x86/x86/cpu.c
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/x86/x86/identcpu_subr.c
cvs rdiff -u -r1.90 -r1.91 src/sys/arch/x86/x86/lapic.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/x86/include/apicvar.h
diff -u src/sys/arch/x86/include/apicvar.h:1.8 src/sys/arch/x86/include/apicvar.h:1.9
--- src/sys/arch/x86/include/apicvar.h:1.8	Sat Apr 25 15:26:18 2020
+++ src/sys/arch/x86/include/apicvar.h	Thu Mar  6 06:31:52 2025
@@ -1,4 +1,4 @@
-/* 	$NetBSD: apicvar.h,v 1.8 2020/04/25 15:26:18 bouyer Exp $ */
+/* 	$NetBSD: apicvar.h,v 1.9 2025/03/06 06:31:52 imil Exp $ */
 
 /*-
  * Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -56,5 +56,6 @@ void apic_format_redir(const char *, con
 
 /* For lapic.c */
 extern uint32_t lapic_per_second;
+extern bool lapic_from_cpuid;
 
 #endif /* !_X86_APICVAR_H_ */

Index: src/sys/arch/x86/x86/cpu.c
diff -u src/sys/arch/x86/x86/cpu.c:1.210 src/sys/arch/x86/x86/cpu.c:1.211
--- src/sys/arch/x86/x86/cpu.c:1.210	Mon Apr 22 23:07:47 2024
+++ src/sys/arch/x86/x86/cpu.c	Thu Mar  6 06:31:53 2025
@@ -1,4 +1,4 @@
-/*	$NetBSD: cpu.c,v 1.210 2024/04/22 23:07:47 andvar Exp $	*/
+/*	$NetBSD: cpu.c,v 1.211 2025/03/06 06:31:53 imil Exp $	*/
 
 /*
  * Copyright (c) 2000-2020 NetBSD Foundation, Inc.
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.210 2024/04/22 23:07:47 andvar Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.211 2025/03/06 06:31:53 imil Exp $");
 
 #include "opt_ddb.h"
 #include "opt_mpbios.h"		/* for MPDEBUG */
@@ -1416,7 +1416,8 @@ cpu_shutdown(device_t dv, int how)
 void
 cpu_get_tsc_freq(struct cpu_info *ci)
 {
-	uint64_t freq = 0, freq_from_cpuid, t0, t1;
+	static uint64_t freq_from_cpuid = 0;
+	uint64_t freq = 0, t0, t1;
 	int64_t overhead;
 
 	if (CPU_IS_PRIMARY(ci) && cpu_hascounter()) {
@@ -1426,7 +1427,13 @@ cpu_get_tsc_freq(struct cpu_info *ci)
 		 * The function also set lapic_per_second variable if it's
 		 * known. This is required for Intel's Comet Lake and newer
 		 * processors to set LAPIC timer correctly.
+		 *
+		 * If TSC freq is already known by CPUID, don't go through
+		 * tests again.
 		 */
+		if (freq_from_cpuid != 0)
+			return;
+
 		if (ci->ci_data.cpu_cc_freq == 0)
 			freq = freq_from_cpuid = cpu_tsc_freq_cpuid(ci);
 		if (freq != 0)

Index: src/sys/arch/x86/x86/identcpu_subr.c
diff -u src/sys/arch/x86/x86/identcpu_subr.c:1.9 src/sys/arch/x86/x86/identcpu_subr.c:1.10
--- src/sys/arch/x86/x86/identcpu_subr.c:1.9	Thu Oct  7 13:04:18 2021
+++ src/sys/arch/x86/x86/identcpu_subr.c	Thu Mar  6 06:31:53 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: identcpu_subr.c,v 1.9 2021/10/07 13:04:18 msaitoh Exp $ */
+/* $NetBSD: identcpu_subr.c,v 1.10 2025/03/06 06:31:53 imil Exp $ */
 
 /*-
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  * See src/usr.sbin/cpuctl/{Makefile, arch/i386.c}).
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: identcpu_subr.c,v 1.9 2021/10/07 13:04:18 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: identcpu_subr.c,v 1.10 2025/03/06 06:31:53 imil Exp $");
 
 #ifdef _KERNEL_OPT
 #include "lapic.h"
@@ -62,14 +62,44 @@ __KERNEL_RCSID(0, "$NetBSD: identcpu_sub
 #include "cpuctl_i386.h"
 #endif
 
-uint64_t
-cpu_tsc_freq_cpuid(struct cpu_info *ci)
+#ifdef _KERNEL
+static uint64_t
+tsc_freq_vmware_cpuid(struct cpu_info *ci)
+{
+	uint32_t descs[4];
+	uint64_t freq;
+
+	if (ci->ci_max_ext_cpuid < 0x40000010)
+		return 0;
+
+	x86_cpuid(0x40000010, descs);
+
+	freq = descs[0];
+	if (freq == 0)
+		return 0;
+
+	aprint_verbose(
+	    "got tsc frequency from vmware compatible cpuid\n");
+
+	if (descs[1] > 0) {
+		aprint_verbose(
+		    "got lapic frequency from vmware compatible cpuid\n");
+		lapic_per_second = descs[1] * 1000;
+		lapic_from_cpuid = true;
+	}
+
+	return freq * 1000;
+}
+#endif
+
+static uint64_t
+tsc_freq_cpuid(struct cpu_info *ci)
 {
 	uint64_t freq = 0, khz;
 	uint32_t descs[4];
 	uint32_t denominator, numerator;
 
-	if (!((ci->ci_max_cpuid >= 0x15) && (cpu_vendor == CPUVENDOR_INTEL)))
+	if (ci->ci_max_cpuid < 0x15)
 		return 0;
 
 	x86_cpuid(0x15, descs);
@@ -139,6 +169,21 @@ cpu_tsc_freq_cpuid(struct cpu_info *ci)
 		}
 #endif
 	}
+	return freq;
+}
+
+uint64_t
+cpu_tsc_freq_cpuid(struct cpu_info *ci)
+{
+	uint64_t freq = 0;
+
+	if (cpu_vendor == CPUVENDOR_INTEL)
+		freq = tsc_freq_cpuid(ci);
+#ifdef _KERNEL
+	/* VMware compatible tsc frequency query */
+	if (freq == 0 && vm_guest > VM_GUEST_NO)
+		freq = tsc_freq_vmware_cpuid(ci);
+#endif
 	if (freq != 0)
 		aprint_verbose_dev(ci->ci_dev, "TSC freq CPUID %" PRIu64
 		    " Hz\n", freq);

Index: src/sys/arch/x86/x86/lapic.c
diff -u src/sys/arch/x86/x86/lapic.c:1.90 src/sys/arch/x86/x86/lapic.c:1.91
--- src/sys/arch/x86/x86/lapic.c:1.90	Sun Feb 25 18:27:54 2024
+++ src/sys/arch/x86/x86/lapic.c	Thu Mar  6 06:31:53 2025
@@ -1,4 +1,4 @@
-/*	$NetBSD: lapic.c,v 1.90 2024/02/25 18:27:54 andvar Exp $	*/
+/*	$NetBSD: lapic.c,v 1.91 2025/03/06 06:31:53 imil Exp $	*/
 
 /*-
  * Copyright (c) 2000, 2008, 2020 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lapic.c,v 1.90 2024/02/25 18:27:54 andvar Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lapic.c,v 1.91 2025/03/06 06:31:53 imil Exp $");
 
 #include "acpica.h"
 #include "ioapic.h"
@@ -131,6 +131,7 @@ bool x2apic_enable = true;
 #else
 bool x2apic_enable = false;
 #endif
+bool lapic_from_cpuid = false;
 
 static bool lapic_broken_periodic __read_mostly;
 
@@ -606,9 +607,11 @@ lapic_initclock(void)
 		/*
 		 * Recalibrate the timer using the cycle counter, now that
 		 * the cycle counter itself has been recalibrated.
+		 *
+		 * Not needed when lapic_per_second is read from CPUID.
 		 */
-		lapic_calibrate_timer(true);
-
+		if (!lapic_from_cpuid)
+			lapic_calibrate_timer(true);
 		/*
 		 * Hook up time counter.  This assume that all LAPICs have
 		 * the same frequency.

Reply via email to