Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save tezeta/14fc617a6db43db6e1416fbb51cf309a to your computer and use it in GitHub Desktop.
Save tezeta/14fc617a6db43db6e1416fbb51cf309a to your computer and use it in GitHub Desktop.
Update note: Linux kernel commit feb627e8d6f69c9a319fe279710959efb3eba873
breaks this patch and will need to be reverted in order for this to work on
kernels starting with 5.16.
From 28e67537895c4b46b9721f19609ee4f2ccb8c132 Mon Sep 17 00:00:00 2001
From: pi <secret@hidden.mail>
Date: Sat, 7 Nov 2020 18:41:42 +0100
Subject: [PATCH] Add 'hide-hypervisor' QMP command
CAUTION: Extremely hacky stuff below. Use at own risk of bugs, breakage and
bear attacks.
Introduce a new QMP call to disable the hypervisor CPUID flag at runtime on
x86 KVM. Allows the guest OS to initialize with full hypervisor/PV support
while allowing broken guest applications that require a bare metal machine
to function. Enable 'hypervisor' flag on boot command, then wait for guest
boot, then run 'hide-hypervisor' via QMP. Might break guests that depend on
CPUID never changing at runtime, as is the case on real hardware (excluding
microcode updates, which are magic anyway).
---
diff --color -Naur qemu-6.1.0-orig/hw/core/machine-qmp-cmds.c qemu-6.1.0/hw/core/machine-qmp-cmds.c
--- qemu-6.1.0-orig/hw/core/machine-qmp-cmds.c 2021-12-24 20:10:34.724541848 -0500
+++ qemu-6.1.0/hw/core/machine-qmp-cmds.c 2021-12-24 20:11:32.218538421 -0500
@@ -21,6 +21,45 @@
#include "sysemu/hw_accel.h"
#include "sysemu/numa.h"
#include "sysemu/runstate.h"
+#include "sysemu/cpus.h"
+#include <linux/kvm.h>
+
+void qmp_hide_hypervisor(Error **errp)
+{
+ int32_t r;
+ CPUState *cpu;
+#if defined(TARGET_I386)
+ pause_all_vcpus();
+
+ CPU_FOREACH(cpu) {
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ cpu_synchronize_state(cpu);
+
+ struct {
+ struct kvm_cpuid2 cpuid;
+ struct kvm_cpuid_entry2 entries[KVM_MAX_CPUID_ENTRIES];
+ } *cpuid_data = x86_cpu->cpuid_data;
+
+ for (int32_t i = 0; i < cpuid_data->cpuid.nent; i++) {
+ struct kvm_cpuid_entry2 *entry = &cpuid_data->entries[i];
+
+ if (entry->function == 1) {
+ /* eax is 1, unset hypervisor bit */
+ entry->ecx &= ~CPUID_EXT_HYPERVISOR;
+ break;
+ }
+ }
+
+ r = kvm_vcpu_ioctl(cpu, KVM_SET_CPUID2, cpuid_data);
+ if (r) {
+ error_setg(errp, "KVM_SET_CPUID2 error");
+ break;
+ }
+ }
+
+ resume_all_vcpus();
+#endif
+}
static void cpustate_to_cpuinfo_s390(CpuInfoS390 *info, const CPUState *cpu)
{
diff --color -Naur qemu-6.1.0-orig/qapi/machine.json qemu-6.1.0/qapi/machine.json
--- qemu-6.1.0-orig/qapi/machine.json 2021-12-24 20:10:34.774541845 -0500
+++ qemu-6.1.0/qapi/machine.json 2021-12-24 20:10:52.998540759 -0500
@@ -962,6 +962,14 @@
##
{ 'command': 'query-hotpluggable-cpus', 'returns': ['HotpluggableCPU'],
'allow-preconfig': true }
+##
+# @hide-hypervisor:
+#
+# Hides the 'hypervisor' cpuid flag on all vCPUs at runtime.
+##
+{
+ 'command': 'hide-hypervisor'
+}
##
# @set-numa-node:
diff --color -Naur qemu-6.1.0-orig/target/i386/cpu.h qemu-6.1.0/target/i386/cpu.h
--- qemu-6.1.0-orig/target/i386/cpu.h 2021-12-24 20:10:34.843541841 -0500
+++ qemu-6.1.0/target/i386/cpu.h 2021-12-24 20:10:52.999540759 -0500
@@ -26,6 +26,8 @@
#include "exec/cpu-defs.h"
#include "qapi/qapi-types-common.h"
+#define KVM_MAX_CPUID_ENTRIES 100
+
/* The x86 has a strong memory model with some store-after-load re-ordering */
#define TCG_GUEST_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD)
@@ -1800,6 +1802,8 @@
int32_t thread_id;
int32_t hv_max_vps;
+
+ void *cpuid_data;
};
diff --color -Naur qemu-6.1.0-orig/target/i386/kvm/kvm.c qemu-6.1.0/target/i386/kvm/kvm.c
--- qemu-6.1.0-orig/target/i386/kvm/kvm.c 2021-12-24 20:10:34.843541841 -0500
+++ qemu-6.1.0/target/i386/kvm/kvm.c 2021-12-24 20:10:52.999540759 -0500
@@ -1538,8 +1538,6 @@
static Error *invtsc_mig_blocker;
-#define KVM_MAX_CPUID_ENTRIES 100
-
int kvm_arch_init_vcpu(CPUState *cs)
{
struct {
@@ -1919,6 +1917,10 @@
cpuid_data.cpuid.nent = cpuid_i;
cpuid_data.cpuid.padding = 0;
+
+ cpu->cpuid_data = malloc(sizeof(cpuid_data));
+ memcpy(cpu->cpuid_data, &cpuid_data, sizeof(cpuid_data));
+
r = kvm_vcpu_ioctl(cs, KVM_SET_CPUID2, &cpuid_data);
if (r) {
goto fail;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment