Repository: firecracker-microvm/firecracker
File: src/vmm/src/builder.rs (Rust)

Code before:
        EventFdTrigger::new(EventFd::new(EFD_NONBLOCK).map_err(VmmError::EventFd)?);
    let serial = Arc::new(Mutex::new(BusDevice::Serial(SerialWrapper {
        serial: Serial::with_events(
            interrupt_evt,
            SerialEventsWrapper {
                buffer_ready_event_fd: Some(kick_stdin_read_evt),
            },
            SerialOut::Stdout(out),
        ),
        input: Some(input),
    })));
    event_manager.add_subscriber(serial.clone());
    Ok(serial)
}

/// 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
#[cfg(target_arch = "aarch64")]
const STEALTIME_STRUCT_MEM_SIZE: u64 = 64;

/// Helper method to allocate steal time region
#[cfg(target_arch = "aarch64")]
fn allocate_pvtime_region(
    vmm: &mut Vmm,
    vcpu_count: usize,
    policy: vm_allocator::AllocPolicy,
) -> Result<GuestAddress, StartMicrovmError> {
    let size = STEALTIME_STRUCT_MEM_SIZE * vcpu_count as u64;
    let addr = vmm
        .resource_allocator
        .allocate_system_memory(size, STEALTIME_STRUCT_MEM_SIZE, policy)
        .map_err(StartMicrovmError::AllocateResources)?;
    Ok(GuestAddress(addr))
}

/// Sets up pvtime for all vcpus
#[cfg(target_arch = "aarch64")]
fn setup_pvtime(vmm: &mut Vmm, vcpus: &mut [Vcpu]) -> Result<(), StartMicrovmError> {
    // Alloc sys mem for steal time region
    let pvtime_mem: GuestAddress =
        allocate_pvtime_region(vmm, vcpus.len(), vm_allocator::AllocPolicy::LastMatch)?;

    // Register all vcpus with pvtime device
    for (i, vcpu) in vcpus.iter_mut().enumerate() {
        vcpu.kvm_vcpu
            .enable_pvtime(GuestAddress(
                pvtime_mem.0 + i as u64 * STEALTIME_STRUCT_MEM_SIZE,
            ))
            .map_err(StartMicrovmError::EnablePVTime)?;
    }

    Ok(())

Review comment (suggestion):
If you drop the call to this on the restore path, you can also drop this `policy` argument (and just inline this into `setup_pvtime` probably).

Code after:
    let kick_stdin_read_evt =
        EventFdTrigger::new(EventFd::new(EFD_NONBLOCK).map_err(VmmError::EventFd)?);
    let serial = Arc::new(Mutex::new(BusDevice::Serial(SerialWrapper {
        serial: Serial::with_events(
            interrupt_evt,
            SerialEventsWrapper {
                buffer_ready_event_fd: Some(kick_stdin_read_evt),
            },
            SerialOut::Stdout(out),
        ),
        input: Some(input),
    })));
    event_manager.add_subscriber(serial.clone());
    Ok(serial)
}

/// 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
#[cfg(target_arch = "aarch64")]
const STEALTIME_STRUCT_MEM_SIZE: u64 = 64;

/// Helper method to allocate steal time region
#[cfg(target_arch = "aarch64")]
fn allocate_pvtime_region(
    vmm: &mut Vmm,
    vcpu_count: usize,
    policy: vm_allocator::AllocPolicy,
) -> Result<GuestAddress, StartMicrovmError> {
    let size = STEALTIME_STRUCT_MEM_SIZE * vcpu_count as u64;
    let addr = vmm
        .resource_allocator
        .allocate_system_memory(size, STEALTIME_STRUCT_MEM_SIZE, policy)
        .map_err(StartMicrovmError::AllocateResources)?;
    Ok(GuestAddress(addr))
}

/// Sets up pvtime for all vcpus
#[cfg(target_arch = "aarch64")]
fn setup_pvtime(vmm: &mut Vmm, vcpus: &mut [Vcpu]) -> Result<(), StartMicrovmError> {
    // Alloc sys mem for steal time region
    let pvtime_mem: GuestAddress =
        allocate_pvtime_region(vmm, vcpus.len(), vm_allocator::AllocPolicy::LastMatch)?;

    // Register all vcpus with pvtime device
    for (i, vcpu) in vcpus.iter_mut().enumerate() {
        vcpu.kvm_vcpu
            .enable_pvtime(GuestAddress(
                pvtime_mem.0 + i as u64 * STEALTIME_STRUCT_MEM_SIZE,
            ))
            .map_err(StartMicrovmError::EnablePVTime)?;
    }