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} ;
@@ -391,6 +394,8 @@ pub enum BuildMicrovmFromSnapshotError {
391394 SetTsc ( #[ from] crate :: arch:: SetTscError ) ,
392395 /// Failed to restore microVM state: {0}
393396 RestoreState ( #[ from] crate :: vstate:: vm:: ArchVmError ) ,
397+ /// Failed to get snapshot state from file: {0}
398+ LoadState ( #[ from] SnapshotStateFromFileError ) ,
394399 /// Failed to update microVM configuration: {0}
395400 VmUpdateConfig ( #[ from] MachineConfigError ) ,
396401 /// Failed to restore MMIO device: {0}
@@ -411,19 +416,19 @@ pub enum BuildMicrovmFromSnapshotError {
411416 ACPIDeviManager ( #[ from] ACPIDeviceManagerRestoreError ) ,
412417 /// VMGenID update failed: {0}
413418 VMGenIDUpdate ( std:: io:: Error ) ,
419+ /// Failed to restore guest memory: {0}
420+ Memory ( #[ from] RestoreMemoryError ) ,
414421}
415422
416423/// Builds and starts a microVM based on the provided MicrovmState.
417424///
418425/// An `Arc` reference of the built `Vmm` is also plugged in the `EventManager`, while another
419426/// is returned.
420- #[ allow( clippy:: too_many_arguments) ]
421427pub fn build_microvm_from_snapshot (
422428 instance_info : & InstanceInfo ,
423429 event_manager : & mut EventManager ,
424430 microvm_state : MicrovmState ,
425- guest_memory : Vec < GuestRegionMmap > ,
426- uffd : Option < Uffd > ,
431+ mem_backend : & MemBackendConfig ,
427432 seccomp_filters : & BpfThreadMap ,
428433 vm_resources : & mut VmResources ,
429434) -> Result < Arc < Mutex < Vmm > > , BuildMicrovmFromSnapshotError > {
@@ -437,11 +442,63 @@ pub fn build_microvm_from_snapshot(
437442 )
438443 . map_err ( StartMicrovmError :: Internal ) ?;
439444
445+ let track_dirty_pages = vm_resources. machine_config . track_dirty_pages ;
446+ let huge_pages = vm_resources. machine_config . huge_pages ;
447+
448+ let mem_backend_path = & mem_backend. backend_path ;
449+
450+ let mem_file = match mem_backend. backend_type {
451+ MemBackendType :: File => Some ( mem_backend_path) ,
452+ MemBackendType :: Uffd => None ,
453+ } ;
454+
455+ let guest_memory = restore_memory (
456+ & microvm_state. vm_state . memory ,
457+ mem_file,
458+ huge_pages,
459+ track_dirty_pages,
460+ 0 ,
461+ ) ?;
462+ let io_memory = restore_memory (
463+ & microvm_state. vm_state . io_memory ,
464+ mem_file,
465+ huge_pages,
466+ track_dirty_pages,
467+ guest_memory. iter ( ) . map ( |r| r. len ( ) ) . sum ( ) ,
468+ ) ?;
469+
440470 vmm. vm
441471 . register_memory_regions ( guest_memory)
442472 . map_err ( VmmError :: Vm )
443473 . map_err ( StartMicrovmError :: Internal ) ?;
444- vmm. uffd = uffd;
474+
475+ for region in io_memory {
476+ vmm. vm
477+ . register_swiotlb_region ( region)
478+ . map_err ( VmmError :: Vm )
479+ . map_err ( StartMicrovmError :: Internal ) ?;
480+ }
481+
482+ vmm. uffd = match mem_backend. backend_type {
483+ MemBackendType :: File => None ,
484+ MemBackendType :: Uffd => {
485+ let ( uffd, mut mappings) = vmm
486+ . vm
487+ . create_uffd ( )
488+ . map_err ( RestoreMemoryError :: UffdCreate ) ?;
489+
490+ #[ allow( deprecated) ]
491+ mappings. iter_mut ( ) . for_each ( |mapping| {
492+ mapping. page_size = vm_resources. machine_config . huge_pages . page_size ( ) ;
493+ mapping. page_size_kib = vm_resources. machine_config . huge_pages . page_size ( ) ;
494+ } ) ;
495+
496+ send_uffd_handshake ( mem_backend_path, & mappings, & uffd)
497+ . map_err ( RestoreMemoryError :: UffdHandshake ) ?;
498+
499+ Some ( uffd)
500+ }
501+ } ;
445502
446503 #[ cfg( target_arch = "x86_64" ) ]
447504 {
0 commit comments