From cee4007b0108adc469a4e51394f83878a35e067a Mon Sep 17 00:00:00 2001 From: Leon Hwang Date: Wed, 1 Oct 2025 17:06:08 +0800 Subject: [PATCH] [qemu] Add custom kvm cpu args support When improve `bpf_get_branch_snapshot()` helper, it requires passing LBR into the VM like `-cpu,host,pmu=on,lbr-fmt=0x5`. Then, in the VM, confirm the LBR is supported: ```bash root@(none):/# dmesg | grep -i lbr [ 0.394406] Performance Events: Skylake events, 32-deep LBR, full-width counters, Intel PMU driver. ``` With this commit, the VM can be created by `vmtest -k $(make -s image_name) --kvm-cpu-args 'host,pmu=on,lbr-fmt=0x5' -`. Signed-off-by: Leon Hwang --- src/config.rs | 10 ++++++++++ src/main.rs | 4 ++++ src/qemu.rs | 17 ++++++++++++----- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/config.rs b/src/config.rs index 83a49a2..1b58fac 100644 --- a/src/config.rs +++ b/src/config.rs @@ -100,6 +100,11 @@ pub struct Target { /// /// Arguments are only valid for kernel targets. pub kernel_args: Option, + /// KVM -cpu arguments are only valid for KVM enabled targets. + /// + /// Default: host + #[serde(default = "Target::default_kvm_cpu_args")] + pub kvm_cpu_args: Option, /// Path to rootfs to test against. /// /// * The path is relative to `vmtest.toml`. @@ -130,6 +135,10 @@ impl Target { pub fn default_arch() -> String { ARCH.to_string() } + /// Default kvm cpu args to use if none are specified. + pub fn default_kvm_cpu_args() -> Option { + Some("host".into()) + } } impl Default for Target { @@ -140,6 +149,7 @@ impl Default for Target { uefi: false, kernel: None, kernel_args: None, + kvm_cpu_args: None, rootfs: Self::default_rootfs(), arch: Self::default_arch(), qemu_command: None, diff --git a/src/main.rs b/src/main.rs index 3e705eb..a2227f5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,6 +37,9 @@ struct Args { /// Additional kernel command line arguments #[clap(long, conflicts_with = "config")] kargs: Option, + /// KVM -cpu arguments + #[clap(long, conflicts_with = "config", default_value = "host")] + kvm_cpu_args: Option, /// Location of rootfs, default to host's / #[clap(short, long, conflicts_with = "config", default_value = Target::default_rootfs().into_os_string())] rootfs: PathBuf, @@ -122,6 +125,7 @@ fn config(args: &Args) -> Result { rootfs: args.rootfs.clone(), arch: args.arch.clone(), kernel_args: args.kargs.clone(), + kvm_cpu_args: args.kvm_cpu_args.clone(), qemu_command: args.qemu_command.clone(), command: args.command.join(" "), vm: VMConfig::default(), diff --git a/src/qemu.rs b/src/qemu.rs index 9758110..627a2d6 100644 --- a/src/qemu.rs +++ b/src/qemu.rs @@ -251,13 +251,17 @@ fn guest_agent_args(sock: &Path) -> Vec { } /// Generate arguments for full KVM virtualization if host supports it -fn kvm_args(arch: &str) -> Vec<&'static str> { +fn kvm_args<'a>(arch: &str, kvm_cpu_args: &'a str) -> Vec<&'a str> { let mut args = Vec::new(); if host_supports_kvm(arch) { args.push("-enable-kvm"); args.push("-cpu"); - args.push("host"); + if kvm_cpu_args.is_empty() { + args.push("host"); + } else { + args.push(kvm_cpu_args); + } } else { args.push("-cpu"); match arch { @@ -365,7 +369,7 @@ fn kernel_args( kernel: &Path, arch: &str, init: &Path, - additional_kargs: Option<&String>, + additional_kargs: Option<&str>, ) -> Vec { let mut args = Vec::new(); @@ -669,7 +673,10 @@ impl Qemu { .stderr(Stdio::piped()) .arg("-serial") .arg("mon:stdio") - .args(kvm_args(&target.arch)) + .args(kvm_args( + &target.arch, + target.kvm_cpu_args.as_deref().unwrap_or("host"), + )) .args(machine_args(&target.arch)) .args(machine_protocol_args(&qmp_sock)) .args(guest_agent_args(&qga_sock)) @@ -691,7 +698,7 @@ impl Qemu { kernel, &target.arch, guest_init.as_path(), - target.kernel_args.as_ref(), + target.kernel_args.as_deref(), )); } else { panic!("Config validation should've enforced XOR");