576fd8e4dfd9256afa153a79ccbacb8b78371ccd Implement CPUID leaf 0x40000010 in nvmm: VMware compatible TSC and LAPIC frequency detection
diff --git a/sys/arch/x86/include/cpuvar.h b/sys/arch/x86/include/cpuvar.h
index bdc617ee73f..78b75b7d421 100644
--- a/sys/arch/x86/include/cpuvar.h
+++ b/sys/arch/x86/include/cpuvar.h
@@ -124,6 +124,8 @@ void x86_cpu_idle_xen(void);
 void	cpu_get_tsc_freq(struct cpu_info *);
 void	pat_init(struct cpu_info *);
 
+bool	has_lapic(void);
+
 extern int cpu_vendor;
 extern bool x86_mp_online;
 
diff --git a/sys/arch/x86/x86/cpu.c b/sys/arch/x86/x86/cpu.c
index c2072448206..4d8ae05a1d4 100644
--- a/sys/arch/x86/x86/cpu.c
+++ b/sys/arch/x86/x86/cpu.c
@@ -1490,6 +1490,16 @@ cpu_get_tsc_freq(struct cpu_info *ci)
 	ci->ci_data.cpu_cc_freq = freq;
 }
 
+bool
+has_lapic(void)
+{
+#if NLAPIC > 0
+	return true;
+#else
+	return false;
+#endif
+}
+
 void
 x86_cpu_idle_mwait(void)
 {
diff --git a/sys/dev/nvmm/x86/nvmm_x86_svm.c b/sys/dev/nvmm/x86/nvmm_x86_svm.c
index 4b823d1c7ba..57e319cfba6 100644
--- a/sys/dev/nvmm/x86/nvmm_x86_svm.c
+++ b/sys/dev/nvmm/x86/nvmm_x86_svm.c
@@ -42,6 +42,7 @@ __KERNEL_RCSID(0, "$NetBSD: nvmm_x86_svm.c,v 1.86 2025/03/09 19:16:47 riastradh
 #include <uvm/uvm_extern.h>
 #include <uvm/uvm_page.h>
 
+#include <x86/apicvar.h>
 #include <x86/cputypes.h>
 #include <x86/specialreg.h>
 #include <x86/dbregs.h>
@@ -839,7 +840,7 @@ svm_inkernel_advance(struct vmcb *vmcb)
 }
 
 #define SVM_CPUID_MAX_BASIC		0xD
-#define SVM_CPUID_MAX_HYPERVISOR	0x40000000
+#define SVM_CPUID_MAX_HYPERVISOR	0x40000010
 #define SVM_CPUID_MAX_EXTENDED		0x8000001F
 static uint32_t svm_cpuid_max_basic __read_mostly;
 static uint32_t svm_cpuid_max_extended __read_mostly;
@@ -1001,6 +1002,15 @@ svm_inkernel_handle_cpuid(struct nvmm_cpu *vcpu, uint64_t eax, uint64_t ecx)
 		memcpy(&cpudata->gprs[NVMM_X64_GPR_RCX], "NVMM", 4);
 		memcpy(&cpudata->gprs[NVMM_X64_GPR_RDX], " ___", 4);
 		break;
+	case 0x40000010: /* VMware-style TSC and LAPIC freq */
+		cpudata->gprs[NVMM_X64_GPR_RAX] = curcpu()->ci_data.cpu_cc_freq / 1000;
+		if (has_lapic())
+			cpudata->gprs[NVMM_X64_GPR_RBX] = lapic_per_second / 1000;
+		else
+			cpudata->gprs[NVMM_X64_GPR_RBX] = 0;
+		cpudata->gprs[NVMM_X64_GPR_RCX] = 0;
+		cpudata->gprs[NVMM_X64_GPR_RDX] = 0;
+		break;
 
 	/*
 	 * extended CPUID range
diff --git a/sys/dev/nvmm/x86/nvmm_x86_vmx.c b/sys/dev/nvmm/x86/nvmm_x86_vmx.c
index 74c879f0890..289e71094e2 100644
--- a/sys/dev/nvmm/x86/nvmm_x86_vmx.c
+++ b/sys/dev/nvmm/x86/nvmm_x86_vmx.c
@@ -43,6 +43,7 @@ __KERNEL_RCSID(0, "$NetBSD: nvmm_x86_vmx.c,v 1.87 2025/03/09 19:16:47 riastradh
 #include <uvm/uvm_extern.h>
 #include <uvm/uvm_page.h>
 
+#include <x86/apicvar.h>
 #include <x86/cputypes.h>
 #include <x86/specialreg.h>
 #include <x86/dbregs.h>
@@ -1220,7 +1221,7 @@ error:
 }
 
 #define VMX_CPUID_MAX_BASIC		0x16
-#define VMX_CPUID_MAX_HYPERVISOR	0x40000000
+#define VMX_CPUID_MAX_HYPERVISOR	0x40000010
 #define VMX_CPUID_MAX_EXTENDED		0x80000008
 static uint32_t vmx_cpuid_max_basic __read_mostly;
 static uint32_t vmx_cpuid_max_extended __read_mostly;
@@ -1452,6 +1453,15 @@ vmx_inkernel_handle_cpuid(struct nvmm_machine *mach, struct nvmm_cpu *vcpu,
 		memcpy(&cpudata->gprs[NVMM_X64_GPR_RCX], "NVMM", 4);
 		memcpy(&cpudata->gprs[NVMM_X64_GPR_RDX], " ___", 4);
 		break;
+	case 0x40000010: /* VMware-style TSC and LAPIC freq */
+		cpudata->gprs[NVMM_X64_GPR_RAX] = curcpu()->ci_data.cpu_cc_freq / 1000;
+		if (has_lapic())
+			cpudata->gprs[NVMM_X64_GPR_RBX] = lapic_per_second / 1000;
+		else
+			cpudata->gprs[NVMM_X64_GPR_RBX] = 0;
+		cpudata->gprs[NVMM_X64_GPR_RCX] = 0;
+		cpudata->gprs[NVMM_X64_GPR_RDX] = 0;
+		break;
 
 	/*
 	 * extended CPUID range