diff --git a/patches/0026-cpuid-leaf15.patch b/patches/0026-cpuid-leaf15.patch new file mode 100644 index 0000000..4414ba8 --- /dev/null +++ b/patches/0026-cpuid-leaf15.patch @@ -0,0 +1,26 @@ +qemu-spoof: CPUID leaf 0x15 (TSC / core-crystal ratio) + +Stock QEMU returns 0 for leaf 0x15; real Intel CPUs enumerate the TSC / nominal +core-crystal clock ratio. Fill EAX(denominator)/EBX(numerator)/ECX(crystal Hz) from +the module so TSC == the leaf-0x16 base frequency (24 MHz crystal * base_mhz / 24). +Intel only; the getters return 0 for an AMD persona or when off, matching stock. +(spoof.h include in target/i386 is added by 0013.) +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index c6fd1dc..aa0dd73 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -8811,6 +8811,14 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + break; + } ++ case 0x15: ++ /* qemu-spoof: TSC / nominal core-crystal ratio (stock QEMU returns 0). ++ * The getters return 0 when off or for an AMD persona, matching stock. */ ++ *eax = (uint32_t)spoof_cpu_tsc_den(0); ++ *ebx = (uint32_t)spoof_cpu_tsc_num(0); ++ *ecx = (uint32_t)spoof_cpu_crystal_hz(0); ++ *edx = 0; ++ break; + case 0x1C: /* Last Branch Records Information Leaf */ + *eax = 0; + *ebx = 0; diff --git a/src/spoof-cpu.c b/src/spoof-cpu.c index fea9c37..f0252cb 100644 --- a/src/spoof-cpu.c +++ b/src/spoof-cpu.c @@ -29,6 +29,12 @@ int spoof_cpu_bus_mhz(int def) { return spoof_on() ? 100 : def; } +/* CPUID leaf 0x15 (TSC / nominal core-crystal ratio). Intel enumerates it; AMD does + * not, so return the default for an AMD persona. Chosen so TSC == base frequency: + * ECX(24 MHz) * EBX(base_mhz) / EAX(24) = base_mhz * 1e6 Hz, consistent with 0x16. */ +int spoof_cpu_crystal_hz(int def) { return (spoof_on() && !spoof_anchor_vendor()) ? 24000000 : def; } +int spoof_cpu_tsc_num(int def) { return (spoof_on() && !spoof_anchor_vendor()) ? spoof_cpu_base_mhz(0) : def; } +int spoof_cpu_tsc_den(int def) { return (spoof_on() && !spoof_anchor_vendor()) ? 24 : def; } /* Microcode revision, returned already positioned for the MSR (IA32_UCODE_REV * 0x8B): Intel reports the revision in bits 63:32, AMD the patch level in 31:0. * Stock QEMU/KVM defaults (Intel 0x1_00000000, AMD 0x01000065) follow the same diff --git a/src/spoof.h b/src/spoof.h index 1e0ea38..efa0dca 100644 --- a/src/spoof.h +++ b/src/spoof.h @@ -52,6 +52,9 @@ const char *spoof_kvm_signature(const char *def); /* 12 bytes; vendor-ancho int spoof_cpu_base_mhz(int def); /* CPUID leaf 0x16 base freq */ int spoof_cpu_max_mhz(int def); /* CPUID leaf 0x16 max freq */ int spoof_cpu_bus_mhz(int def); /* CPUID leaf 0x16 bus freq */ +int spoof_cpu_crystal_hz(int def); /* CPUID leaf 0x15 ECX (Intel core crystal) */ +int spoof_cpu_tsc_num(int def); /* leaf 0x15 EBX (TSC ratio numerator) */ +int spoof_cpu_tsc_den(int def); /* leaf 0x15 EAX (TSC ratio denominator) */ uint64_t spoof_cpu_microcode(uint64_t def); /* IA32_UCODE_REV, vendor-positioned */ /* ---- PCI (spoof-pci.c) ---------------------------------------------------- */