Skip to content

Commit 690c87e

Browse files
committed
Fixed kvm_set_device_attr error due to misalignment of steal_time struct
- Each vCPU now gets 64 bytes for its steal_time struct region (16 bytes reguired for data) - This satisfies 64 byte alignment the IPA requires MicroVM can now successfully be booted with pvtime in the boot process. Signed-off-by: Dakshin Devanand <[email protected]>
1 parent 6f9a355 commit 690c87e

File tree

2 files changed

+13
-42
lines changed

2 files changed

+13
-42
lines changed

Diff for: src/vmm/src/arch/aarch64/pvtime/mod.rs

+11-34
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ use displaydoc::Display;
66
use kvm_bindings::{KVM_ARM_VCPU_PVTIME_CTRL, KVM_ARM_VCPU_PVTIME_IPA};
77
use log::{debug, info, warn};
88
use thiserror::Error;
9+
use vm_memory::GuestAddress;
910

1011
use crate::device_manager::resources::ResourceAllocator;
1112

12-
/// Size of the stolen_time struct in bytes, see 3.2.2 in DEN0057A
13-
pub const STEALTIME_STRUCT_MEM_SIZE: u64 = 16;
13+
/// 64 bytes due to alignment requirement in 3.1 of https://www.kernel.org/doc/html/v5.8/virt/kvm/devices/vcpu.html#attribute-kvm-arm-vcpu-pvtime-ipa
14+
pub const STEALTIME_STRUCT_MEM_SIZE: u64 = 64;
1415

1516
/// Represent PVTime device for ARM
1617
#[derive(Debug)]
@@ -36,27 +37,21 @@ impl PVTime {
3637
resource_allocator: &mut ResourceAllocator,
3738
vcpu_count: u8,
3839
) -> Result<Self, PVTimeError> {
39-
info!("Creating PVTime for {vcpu_count} vCPUs...");
40-
// This returns the IPA(?) of the start of our shared memory region for all vCPUs.
41-
// Q: Confirm that allocate_system_memory returns an IPA?
42-
let base_addr = resource_allocator
40+
41+
// This returns the IPA of the start of our shared memory region for all vCPUs.
42+
let base_addr: GuestAddress = GuestAddress(resource_allocator
4343
.allocate_system_memory(
4444
STEALTIME_STRUCT_MEM_SIZE * vcpu_count as u64,
45-
16, // Q: We believe this to be 16, need confirmation.
45+
64,
4646
vm_allocator::AllocPolicy::LastMatch,
4747
)
48-
.map_err(|e| PVTimeError::AllocationFailed(e.to_string()))?;
48+
.map_err(|e| PVTimeError::AllocationFailed(e.to_string()))?);
4949

50-
debug!(
51-
"Allocated base address for PVTime stolen_time region: 0x{:x}",
52-
base_addr
53-
);
5450

5551
// Now we need to store the base IPA for each vCPU's steal_time struct.
5652
let mut steal_time_regions = HashMap::new();
5753
for i in 0..vcpu_count {
58-
let ipa = base_addr + (i as u64 * STEALTIME_STRUCT_MEM_SIZE);
59-
debug!("Assigned vCPU {} to stolen_time IPA 0x{:x}", i, ipa);
54+
let ipa = base_addr.0 + (i as u64 * STEALTIME_STRUCT_MEM_SIZE);
6055
steal_time_regions.insert(i, ipa);
6156
}
6257

@@ -70,40 +65,22 @@ impl PVTime {
7065
vcpu_index: u8,
7166
vcpu_fd: &kvm_ioctls::VcpuFd,
7267
) -> Result<(), PVTimeError> {
68+
7369
// Get IPA of the steal_time region for this vCPU
7470
let ipa = self
7571
.steal_time_regions
7672
.get(&vcpu_index)
7773
.ok_or(PVTimeError::InvalidVcpuIndex(vcpu_index))?;
7874

79-
debug!(
80-
"Registering vCPU {} with stolen_time IPA = 0x{:x}",
81-
vcpu_index, ipa
82-
);
83-
84-
// IMPORTANT QUESTION: We need to confirm this is safe. We need to somehow
85-
// ensure the ipa value is not dropped before we use it etc. since we
86-
// are creating a raw pointer? Do we need a Box?
87-
let ipa_val = *ipa;
88-
let ipa_ptr = &ipa_val as *const u64;
89-
debug!(
90-
"Registering vCPU {} with stolen_time IPA = 0x{:x} (at userspace addr 0x{:x})",
91-
vcpu_index, ipa_val, ipa_ptr as u64
92-
);
93-
9475
// Use KVM syscall (kvm_set_device_attr) to register the vCPU with the steal_time region
9576
let vcpu_device_attr = kvm_bindings::kvm_device_attr {
9677
group: KVM_ARM_VCPU_PVTIME_CTRL,
9778
attr: KVM_ARM_VCPU_PVTIME_IPA as u64,
98-
addr: ipa_ptr as u64, // userspace address of attr data
79+
addr: ipa as *const u64 as u64, // userspace address of attr data
9980
flags: 0,
10081
};
10182

10283
vcpu_fd.set_device_attr(&vcpu_device_attr).map_err(|err| {
103-
warn!(
104-
"Failed to set device attribute for vCPU {}: {:?}",
105-
vcpu_index, err
106-
);
10784
PVTimeError::DeviceAttribute(err, true, KVM_ARM_VCPU_PVTIME_CTRL)
10885
})?;
10986

Diff for: src/vmm/src/builder.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -568,11 +568,8 @@ pub fn setup_serial_device(
568568
/// Sets up the pvtime device.
569569
#[cfg(target_arch = "aarch64")]
570570
fn setup_pv_time(vmm: &mut Vmm, vcpus: &mut Vec<Vcpu>) -> Result<(), StartMicrovmError> {
571-
// Q: Is this bad practice, using crates in this scope?
572571
use crate::arch::aarch64::pvtime::PVTime;
573-
574-
info!("PVTime setup started");
575-
572+
576573
// Check if pvtime is enabled
577574
let pvtime_device_attr = kvm_bindings::kvm_device_attr {
578575
group: kvm_bindings::KVM_ARM_VCPU_PVTIME_CTRL,
@@ -589,8 +586,6 @@ fn setup_pv_time(vmm: &mut Vmm, vcpus: &mut Vec<Vcpu>) -> Result<(), StartMicrov
589586
.has_device_attr(&pvtime_device_attr)
590587
.map_err(StartMicrovmError::PVTimeNotSupported)?;
591588

592-
info!("PVTime is supported");
593-
594589
// Create the pvtime device
595590
let pv_time = PVTime::new(&mut vmm.resource_allocator, vcpus.len() as u8)
596591
.map_err(StartMicrovmError::CreatePVTime)?;
@@ -599,11 +594,10 @@ fn setup_pv_time(vmm: &mut Vmm, vcpus: &mut Vec<Vcpu>) -> Result<(), StartMicrov
599594
for i in 0..vcpus.len() {
600595
pv_time
601596
.register_vcpu(i as u8, &vcpus[i].kvm_vcpu.fd)
602-
.map_err(StartMicrovmError::CreatePVTime)?; // Change this to its own error
597+
.map_err(StartMicrovmError::CreatePVTime)?; // TODO: Change this to its own error
603598
}
604599

605600
// TODO: Store pv_time somewhere (in Vmm ?) for snapshotting later instead of dropping it
606-
info!("PVTime setup completed");
607601

608602
Ok(())
609603
}

0 commit comments

Comments
 (0)