44//! Enables pre-boot setup, instantiation and booting of a Firecracker VMM.
55
66use std:: fmt:: Debug ;
7- use std:: io;
7+ use std:: io:: { self } ;
88#[ cfg( feature = "gdb" ) ]
99use std:: sync:: mpsc;
1010use std:: sync:: { Arc , Mutex } ;
1111
1212use event_manager:: { MutEventSubscriber , SubscriberOps } ;
1313use libc:: EFD_NONBLOCK ;
1414use linux_loader:: cmdline:: Cmdline as LoaderKernelCmdline ;
15- use userfaultfd:: Uffd ;
1615use utils:: time:: TimestampUs ;
16+ use vm_memory:: GuestMemoryRegion ;
1717#[ cfg( target_arch = "aarch64" ) ]
1818use vm_superio:: Rtc ;
1919use vm_superio:: Serial ;
@@ -50,14 +50,17 @@ use crate::devices::virtio::vsock::{Vsock, VsockUnixBackend};
5050use crate :: gdb;
5151use crate :: initrd:: { InitrdConfig , InitrdError } ;
5252use crate :: logger:: { debug, error} ;
53- use crate :: persist:: { MicrovmState , MicrovmStateError } ;
53+ use crate :: persist:: {
54+ MicrovmState , MicrovmStateError , RestoreMemoryError , SnapshotStateFromFileError ,
55+ restore_memory, send_uffd_handshake,
56+ } ;
5457use crate :: resources:: VmResources ;
5558use crate :: seccomp:: BpfThreadMap ;
5659use crate :: snapshot:: Persist ;
5760use crate :: vmm_config:: instance_info:: InstanceInfo ;
5861use crate :: vmm_config:: machine_config:: MachineConfigError ;
62+ use crate :: vmm_config:: snapshot:: { MemBackendConfig , MemBackendType } ;
5963use crate :: vstate:: kvm:: Kvm ;
60- use crate :: vstate:: memory:: GuestRegionMmap ;
6164use crate :: vstate:: vcpu:: { Vcpu , VcpuError } ;
6265use crate :: vstate:: vm:: Vm ;
6366use crate :: { EventManager , Vmm , VmmError , device_manager} ;
@@ -393,6 +396,8 @@ pub enum BuildMicrovmFromSnapshotError {
393396 SetTsc ( #[ from] crate :: arch:: SetTscError ) ,
394397 /// Failed to restore microVM state: {0}
395398 RestoreState ( #[ from] crate :: vstate:: vm:: ArchVmError ) ,
399+ /// Failed to get snapshot state from file: {0}
400+ LoadState ( #[ from] SnapshotStateFromFileError ) ,
396401 /// Failed to update microVM configuration: {0}
397402 VmUpdateConfig ( #[ from] MachineConfigError ) ,
398403 /// Failed to restore MMIO device: {0}
@@ -413,19 +418,19 @@ pub enum BuildMicrovmFromSnapshotError {
413418 ACPIDeviManager ( #[ from] ACPIDeviceManagerRestoreError ) ,
414419 /// VMGenID update failed: {0}
415420 VMGenIDUpdate ( std:: io:: Error ) ,
421+ /// Failed to restore guest memory: {0}
422+ Memory ( #[ from] RestoreMemoryError ) ,
416423}
417424
418425/// Builds and starts a microVM based on the provided MicrovmState.
419426///
420427/// An `Arc` reference of the built `Vmm` is also plugged in the `EventManager`, while another
421428/// is returned.
422- #[ allow( clippy:: too_many_arguments) ]
423429pub fn build_microvm_from_snapshot (
424430 instance_info : & InstanceInfo ,
425431 event_manager : & mut EventManager ,
426432 microvm_state : MicrovmState ,
427- guest_memory : Vec < GuestRegionMmap > ,
428- uffd : Option < Uffd > ,
433+ mem_backend : & MemBackendConfig ,
429434 seccomp_filters : & BpfThreadMap ,
430435 vm_resources : & mut VmResources ,
431436) -> Result < Arc < Mutex < Vmm > > , BuildMicrovmFromSnapshotError > {
@@ -439,11 +444,63 @@ pub fn build_microvm_from_snapshot(
439444 )
440445 . map_err ( StartMicrovmError :: Internal ) ?;
441446
447+ let track_dirty_pages = vm_resources. machine_config . track_dirty_pages ;
448+ let huge_pages = vm_resources. machine_config . huge_pages ;
449+
450+ let mem_backend_path = & mem_backend. backend_path ;
451+
452+ let mem_file = match mem_backend. backend_type {
453+ MemBackendType :: File => Some ( mem_backend_path) ,
454+ MemBackendType :: Uffd => None ,
455+ } ;
456+
457+ let guest_memory = restore_memory (
458+ & microvm_state. vm_state . memory ,
459+ mem_file,
460+ huge_pages,
461+ track_dirty_pages,
462+ 0 ,
463+ ) ?;
464+ let io_memory = restore_memory (
465+ & microvm_state. vm_state . io_memory ,
466+ mem_file,
467+ huge_pages,
468+ track_dirty_pages,
469+ guest_memory. iter ( ) . map ( |r| r. len ( ) ) . sum ( ) ,
470+ ) ?;
471+
442472 vmm. vm
443473 . register_memory_regions ( guest_memory)
444474 . map_err ( VmmError :: Vm )
445475 . map_err ( StartMicrovmError :: Internal ) ?;
446- vmm. uffd = uffd;
476+
477+ for region in io_memory {
478+ vmm. vm
479+ . register_swiotlb_region ( region)
480+ . map_err ( VmmError :: Vm )
481+ . map_err ( StartMicrovmError :: Internal ) ?;
482+ }
483+
484+ vmm. uffd = match mem_backend. backend_type {
485+ MemBackendType :: File => None ,
486+ MemBackendType :: Uffd => {
487+ let ( uffd, mut mappings) = vmm
488+ . vm
489+ . create_uffd ( )
490+ . map_err ( RestoreMemoryError :: UffdCreate ) ?;
491+
492+ #[ allow( deprecated) ]
493+ mappings. iter_mut ( ) . for_each ( |mapping| {
494+ mapping. page_size = vm_resources. machine_config . huge_pages . page_size ( ) ;
495+ mapping. page_size_kib = vm_resources. machine_config . huge_pages . page_size ( ) ;
496+ } ) ;
497+
498+ send_uffd_handshake ( mem_backend_path, & mappings, & uffd)
499+ . map_err ( RestoreMemoryError :: UffdHandshake ) ?;
500+
501+ Some ( uffd)
502+ }
503+ } ;
447504
448505 #[ cfg( target_arch = "x86_64" ) ]
449506 {
0 commit comments