Skip to content

Commit 9226847

Browse files
committed
feat: only reset SYS_CNTPCT_EL0 if KVM_CAP_COUNTER_OFFSET is present
Now when KVM is a separate object, we can query optional capabilities when configuring vcpus on aarch64 and only reset the SYS_CNTPCT_EL0 if KVM_CAP_COUNTER_OFFSET is present. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent bd1a418 commit 9226847

File tree

5 files changed

+63
-23
lines changed

5 files changed

+63
-23
lines changed

src/vmm/src/arch/aarch64/vcpu.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use log::warn;
1414

1515
use super::get_fdt_addr;
1616
use super::regs::*;
17+
use crate::vstate::kvm::OptionalCapabilities;
1718
use crate::vstate::memory::GuestMemoryMmap;
1819

1920
/// Errors thrown while setting aarch64 registers.
@@ -79,6 +80,7 @@ pub fn setup_boot_regs(
7980
cpu_id: u8,
8081
boot_ip: u64,
8182
mem: &GuestMemoryMmap,
83+
optional_capabilities: &OptionalCapabilities,
8284
) -> Result<(), VcpuError> {
8385
let kreg_off = offset_of!(kvm_regs, regs);
8486

@@ -113,17 +115,16 @@ pub fn setup_boot_regs(
113115
// Resetting KVM_REG_ARM_PTIMER_CNT for single vcpu is enough because there is only
114116
// one timer struct with offsets per VM.
115117
// Because the access to KVM_REG_ARM_PTIMER_CNT is only present starting 6.4 kernel,
116-
// we don't fail if ioctl returns an error.
118+
// we only do the reset if KVM_CAP_COUNTER_OFFSET is present as it was added
119+
// in the same patch series as the ability to set the KVM_REG_ARM_PTIMER_CNT register.
117120
// Path series which introduced the needed changes:
118121
// https://lore.kernel.org/all/[email protected]/
119122
// Note: the value observed by the guest will still be above 0, because there is a delta
120123
// time between this resetting and first call to KVM_RUN.
121-
let zero: u64 = 0;
122-
if vcpufd
123-
.set_one_reg(KVM_REG_ARM_PTIMER_CNT, &zero.to_le_bytes())
124-
.is_err()
125-
{
126-
warn!("Unable to reset VM physical counter. VM will use host value instead.");
124+
if optional_capabilities.counter_offset {
125+
vcpufd
126+
.set_one_reg(KVM_REG_ARM_PTIMER_CNT, &[0; 8])
127+
.map_err(|err| VcpuError::SetOneReg(id, err))?;
127128
}
128129
}
129130
Ok(())
@@ -245,8 +246,9 @@ mod tests {
245246
let vm = kvm.fd.create_vm().unwrap();
246247
let vcpu = vm.create_vcpu(0).unwrap();
247248
let mem = arch_mem(layout::FDT_MAX_SIZE + 0x1000);
249+
let optional_capabilities = kvm.optional_capabilities();
248250

249-
let res = setup_boot_regs(&vcpu, 0, 0x0, &mem);
251+
let res = setup_boot_regs(&vcpu, 0, 0x0, &mem, &optional_capabilities);
250252
assert!(matches!(
251253
res.unwrap_err(),
252254
VcpuError::SetOneReg(0x6030000000100042, _)
@@ -256,14 +258,17 @@ mod tests {
256258
vm.get_preferred_target(&mut kvi).unwrap();
257259
vcpu.vcpu_init(&kvi).unwrap();
258260

259-
setup_boot_regs(&vcpu, 0, 0x0, &mem).unwrap();
261+
setup_boot_regs(&vcpu, 0, 0x0, &mem, &optional_capabilities).unwrap();
260262

261263
// Check that the register is reset on compatible kernels.
262264
// Because there is a delta in time between we reset the register and time we
263265
// read it, we cannot compare with 0. Instead we read CNTVNT_EL0 (Virtual counter)
264266
// from the host. The host value should be much bigger than the VM physical counter.
265-
let mut reg_bytes = [0_u8; 8];
266-
if vcpu.get_one_reg(SYS_CNTPCT_EL0, &mut reg_bytes).is_ok() {
267+
if optional_capabilities.counter_offset {
268+
let mut reg_bytes = [0_u8; 8];
269+
vcpu.get_one_reg(SYS_CNTPCT_EL0, &mut reg_bytes).unwrap();
270+
let counter_value = u64::from_le_bytes(reg_bytes);
271+
267272
let virt_count = unsafe {
268273
// Rust is so smart, it cannot figure out that `virt_count`
269274
// is read later in the assert!, so it complains about unused assignment.
@@ -276,7 +281,7 @@ mod tests {
276281
);
277282
virt_count
278283
};
279-
let counter_value = u64::from_le_bytes(reg_bytes);
284+
280285
assert!(counter_value < virt_count);
281286
}
282287
}

src/vmm/src/builder.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -811,16 +811,16 @@ pub fn configure_system_for_boot(
811811
cpu_config,
812812
};
813813

814-
// Configure vCPUs with normalizing and setting the generated CPU configuration.
815-
for vcpu in vcpus.iter_mut() {
816-
vcpu.kvm_vcpu
817-
.configure(vmm.guest_memory(), entry_addr, &vcpu_config)
818-
.map_err(VmmError::VcpuConfigure)
819-
.map_err(Internal)?;
820-
}
821-
822814
#[cfg(target_arch = "x86_64")]
823815
{
816+
// Configure vCPUs with normalizing and setting the generated CPU configuration.
817+
for vcpu in vcpus.iter_mut() {
818+
vcpu.kvm_vcpu
819+
.configure(vmm.guest_memory(), entry_addr, &vcpu_config)
820+
.map_err(VmmError::VcpuConfigure)
821+
.map_err(Internal)?;
822+
}
823+
824824
// Write the kernel command line to guest memory. This is x86_64 specific, since on
825825
// aarch64 the command line will be specified through the FDT.
826826
let cmdline_size = boot_cmdline
@@ -855,6 +855,19 @@ pub fn configure_system_for_boot(
855855
}
856856
#[cfg(target_arch = "aarch64")]
857857
{
858+
let optional_capabilities = vmm.kvm.optional_capabilities();
859+
// Configure vCPUs with normalizing and setting the generated CPU configuration.
860+
for vcpu in vcpus.iter_mut() {
861+
vcpu.kvm_vcpu
862+
.configure(
863+
vmm.guest_memory(),
864+
entry_addr,
865+
&vcpu_config,
866+
&optional_capabilities,
867+
)
868+
.map_err(VmmError::VcpuConfigure)
869+
.map_err(Internal)?;
870+
}
858871
let vcpu_mpidr = vcpus
859872
.iter_mut()
860873
.map(|cpu| cpu.kvm_vcpu.get_mpidr())

src/vmm/src/vstate/kvm.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,13 @@ impl Kvm {
131131
Ok(())
132132
}
133133
}
134-
134+
#[cfg(target_arch = "aarch64")]
135+
/// Optional capabilities.
136+
#[derive(Debug, Default)]
137+
pub struct OptionalCapabilities {
138+
// KVM_CAP_COUNTER_OFFSET
139+
pub counter_offset: bool,
140+
}
135141
#[cfg(target_arch = "aarch64")]
136142
impl Kvm {
137143
const DEFAULT_CAPABILITIES: [u32; 7] = [
@@ -144,6 +150,16 @@ impl Kvm {
144150
kvm_bindings::KVM_CAP_ONE_REG,
145151
];
146152

153+
/// Returns struct with optional capabilities statuses.
154+
pub fn optional_capabilities(&self) -> OptionalCapabilities {
155+
OptionalCapabilities {
156+
counter_offset: self
157+
.fd
158+
.check_extension_raw(kvm_bindings::KVM_CAP_COUNTER_OFFSET.into())
159+
!= 0,
160+
}
161+
}
162+
147163
/// Saves and returns the Kvm Vm state.
148164
pub fn save_state(&self) -> KvmState {
149165
KvmState {

src/vmm/src/vstate/vcpu/aarch64.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::cpu_config::aarch64::custom_cpu_template::VcpuFeatures;
2222
use crate::cpu_config::templates::CpuConfiguration;
2323
use crate::logger::{error, IncMetric, METRICS};
2424
use crate::vcpu::{VcpuConfig, VcpuError};
25-
use crate::vstate::kvm::Kvm;
25+
use crate::vstate::kvm::{Kvm, OptionalCapabilities};
2626
use crate::vstate::memory::{Address, GuestAddress, GuestMemoryMmap};
2727
use crate::vstate::vcpu::VcpuEmulation;
2828
use crate::vstate::vm::Vm;
@@ -116,6 +116,7 @@ impl KvmVcpu {
116116
guest_mem: &GuestMemoryMmap,
117117
kernel_load_addr: GuestAddress,
118118
vcpu_config: &VcpuConfig,
119+
optional_capabilities: &OptionalCapabilities,
119120
) -> Result<(), KvmVcpuError> {
120121
for reg in vcpu_config.cpu_config.regs.iter() {
121122
self.fd
@@ -128,6 +129,7 @@ impl KvmVcpu {
128129
self.index,
129130
kernel_load_addr.raw_value(),
130131
guest_mem,
132+
optional_capabilities,
131133
)
132134
.map_err(KvmVcpuError::ConfigureRegisters)?;
133135

@@ -338,7 +340,8 @@ mod tests {
338340

339341
#[test]
340342
fn test_configure_vcpu() {
341-
let (_, _, mut vcpu, vm_mem) = setup_vcpu(0x10000);
343+
let (kvm, _, mut vcpu, vm_mem) = setup_vcpu(0x10000);
344+
let optional_capabilities = kvm.optional_capabilities();
342345

343346
let vcpu_config = VcpuConfig {
344347
vcpu_count: 1,
@@ -349,6 +352,7 @@ mod tests {
349352
&vm_mem,
350353
GuestAddress(crate::arch::get_kernel_start()),
351354
&vcpu_config,
355+
&optional_capabilities,
352356
)
353357
.unwrap();
354358

@@ -358,6 +362,7 @@ mod tests {
358362
&vm_mem,
359363
GuestAddress(crate::arch::get_kernel_start()),
360364
&vcpu_config,
365+
&optional_capabilities,
361366
);
362367
assert_eq!(
363368
err.unwrap_err(),

src/vmm/src/vstate/vcpu/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,7 @@ pub(crate) mod tests {
10081008
smt: false,
10091009
cpu_config: crate::cpu_config::aarch64::CpuConfiguration::default(),
10101010
},
1011+
&kvm.optional_capabilities(),
10111012
)
10121013
.expect("failed to configure vcpu");
10131014

0 commit comments

Comments
 (0)