@@ -459,6 +459,7 @@ type Result<T> = std::result::Result<T, Error>;
459
459
460
460
/// Describes all possible reasons which may cause the event loop to return to the caller in
461
461
/// the absence of errors.
462
+ #[ derive( Debug ) ]
462
463
pub enum EventLoopExitReason {
463
464
/// A break statement interrupted the event loop during normal execution. This is the
464
465
/// default exit reason.
@@ -779,7 +780,8 @@ pub struct VmmConfig {
779
780
vsock_device : Option < VsockDeviceConfig > ,
780
781
}
781
782
782
- struct Vmm {
783
+ /// Contains the state and associated methods required for the Firecracker VMM.
784
+ pub struct Vmm {
783
785
kvm : KvmContext ,
784
786
785
787
vm_config : VmConfig ,
@@ -813,7 +815,8 @@ struct Vmm {
813
815
}
814
816
815
817
impl Vmm {
816
- fn new (
818
+ /// Creates a new VMM object.
819
+ pub fn new (
817
820
api_shared_info : Arc < RwLock < InstanceInfo > > ,
818
821
control_fd : & AsRawFd ,
819
822
from_api : Receiver < Box < VmmAction > > ,
@@ -1096,16 +1099,20 @@ impl Vmm {
1096
1099
}
1097
1100
1098
1101
fn init_guest_memory ( & mut self ) -> std:: result:: Result < ( ) , StartMicrovmError > {
1099
- let mem_size = self
1100
- . vm_config
1101
- . mem_size_mib
1102
- . ok_or ( StartMicrovmError :: GuestMemory (
1103
- memory_model:: GuestMemoryError :: MemoryNotInitialized ,
1104
- ) ) ?
1105
- << 20 ;
1106
- let arch_mem_regions = arch:: arch_memory_regions ( mem_size) ;
1107
- self . guest_memory =
1108
- Some ( GuestMemory :: new ( & arch_mem_regions) . map_err ( StartMicrovmError :: GuestMemory ) ?) ;
1102
+ if self . guest_memory ( ) . is_none ( ) {
1103
+ let mem_size = self
1104
+ . vm_config
1105
+ . mem_size_mib
1106
+ . ok_or ( StartMicrovmError :: GuestMemory (
1107
+ memory_model:: GuestMemoryError :: MemoryNotInitialized ,
1108
+ ) ) ?
1109
+ << 20 ;
1110
+ let arch_mem_regions = arch:: arch_memory_regions ( mem_size) ;
1111
+ self . set_guest_memory (
1112
+ GuestMemory :: new ( & arch_mem_regions) . map_err ( StartMicrovmError :: GuestMemory ) ?,
1113
+ ) ;
1114
+ }
1115
+
1109
1116
self . vm
1110
1117
. memory_init (
1111
1118
self . guest_memory
@@ -1443,7 +1450,18 @@ impl Vmm {
1443
1450
Ok ( ( ) )
1444
1451
}
1445
1452
1446
- fn start_microvm ( & mut self ) -> std:: result:: Result < VmmData , VmmActionError > {
1453
+ /// Set the guest memory based on a pre-constructed `GuestMemory` object.
1454
+ pub fn set_guest_memory ( & mut self , guest_memory : GuestMemory ) {
1455
+ self . guest_memory = Some ( guest_memory) ;
1456
+ }
1457
+
1458
+ /// Returns a reference to the inner `GuestMemory` object if present, or `None` otherwise.
1459
+ pub fn guest_memory ( & self ) -> Option < & GuestMemory > {
1460
+ self . guest_memory . as_ref ( )
1461
+ }
1462
+
1463
+ /// Set up the initial microVM state and start the vCPU threads.
1464
+ pub fn start_microvm ( & mut self ) -> std:: result:: Result < VmmData , VmmActionError > {
1447
1465
info ! ( "VMM received instance start command" ) ;
1448
1466
if self . is_instance_initialized ( ) {
1449
1467
Err ( StartMicrovmError :: MicroVMAlreadyRunning ) ?;
@@ -1568,6 +1586,8 @@ impl Vmm {
1568
1586
Ok ( ( ) )
1569
1587
}
1570
1588
1589
+ /// Wait on VMM events and dispatch them to the appropriate handler. Returns to the caller
1590
+ /// when a control action occurs.
1571
1591
fn run_event_loop ( & mut self ) -> Result < EventLoopExitReason > {
1572
1592
// TODO: try handling of errors/failures without breaking this main loop.
1573
1593
loop {
@@ -1660,13 +1680,13 @@ impl Vmm {
1660
1680
. unwrap_or ( 0 as usize )
1661
1681
} ;
1662
1682
1663
- self . guest_memory
1664
- . as_ref ( )
1683
+ self . guest_memory ( )
1665
1684
. map ( |ref mem| mem. map_and_fold ( 0 , dirty_pages_in_region, std:: ops:: Add :: add) )
1666
1685
. unwrap_or ( 0 )
1667
1686
}
1668
1687
1669
- fn configure_boot_source (
1688
+ /// Set the guest boot source configuration.
1689
+ pub fn configure_boot_source (
1670
1690
& mut self ,
1671
1691
kernel_image_path : String ,
1672
1692
kernel_cmdline : Option < String > ,
@@ -1700,7 +1720,8 @@ impl Vmm {
1700
1720
Ok ( VmmData :: Empty )
1701
1721
}
1702
1722
1703
- fn set_vm_configuration (
1723
+ /// Set the machine configuration of the microVM.
1724
+ pub fn set_vm_configuration (
1704
1725
& mut self ,
1705
1726
machine_config : VmConfig ,
1706
1727
) -> std:: result:: Result < VmmData , VmmActionError > {
@@ -1745,7 +1766,8 @@ impl Vmm {
1745
1766
Ok ( VmmData :: Empty )
1746
1767
}
1747
1768
1748
- fn insert_net_device (
1769
+ /// Inserts a network device to be attached when the VM starts.
1770
+ pub fn insert_net_device (
1749
1771
& mut self ,
1750
1772
body : NetworkInterfaceConfig ,
1751
1773
) -> std:: result:: Result < VmmData , VmmActionError > {
@@ -1823,7 +1845,8 @@ impl Vmm {
1823
1845
Ok ( VmmData :: Empty )
1824
1846
}
1825
1847
1826
- fn set_vsock_device (
1848
+ /// Sets a vsock device to be attached when the VM starts.
1849
+ pub fn set_vsock_device (
1827
1850
& mut self ,
1828
1851
config : VsockDeviceConfig ,
1829
1852
) -> std:: result:: Result < VmmData , VmmActionError > {
@@ -1904,9 +1927,10 @@ impl Vmm {
1904
1927
Err ( VmmActionError :: from ( DriveError :: InvalidBlockDeviceID ) )
1905
1928
}
1906
1929
1930
+ /// Inserts a block to be attached when the VM starts.
1907
1931
// Only call this function as part of the API.
1908
1932
// If the drive_id does not exist, a new Block Device Config is added to the list.
1909
- fn insert_block_device (
1933
+ pub fn insert_block_device (
1910
1934
& mut self ,
1911
1935
block_device_config : BlockDeviceConfig ,
1912
1936
) -> std:: result:: Result < VmmData , VmmActionError > {
@@ -2093,6 +2117,11 @@ impl Vmm {
2093
2117
}
2094
2118
Ok ( ( ) )
2095
2119
}
2120
+
2121
+ /// Returns a reference to the inner KVM Vm object.
2122
+ pub fn kvm_vm ( & self ) -> & Vm {
2123
+ & self . vm
2124
+ }
2096
2125
}
2097
2126
2098
2127
// Can't derive PartialEq directly because the sender members can't be compared.
@@ -2647,7 +2676,7 @@ mod tests {
2647
2676
assert ! ( mmio_device
2648
2677
. device_mut( )
2649
2678
. activate(
2650
- vmm. guest_memory. as_ref ( ) . unwrap( ) . clone( ) ,
2679
+ vmm. guest_memory( ) . unwrap( ) . clone( ) ,
2651
2680
EventFd :: new( ) . unwrap( ) ,
2652
2681
Arc :: new( AtomicUsize :: new( 0 ) ) ,
2653
2682
vec![ Queue :: new( 0 ) , Queue :: new( 0 ) ] ,
@@ -2886,7 +2915,7 @@ mod tests {
2886
2915
// Test that creating a new block device returns the correct output.
2887
2916
assert ! ( vmm. insert_block_device( root_block_device. clone( ) ) . is_ok( ) ) ;
2888
2917
assert ! ( vmm. init_guest_memory( ) . is_ok( ) ) ;
2889
- assert ! ( vmm. guest_memory. is_some( ) ) ;
2918
+ assert ! ( vmm. guest_memory( ) . is_some( ) ) ;
2890
2919
assert ! ( vmm. setup_interrupt_controller( ) . is_ok( ) ) ;
2891
2920
2892
2921
vmm. default_kernel_config ( None ) ;
@@ -2910,7 +2939,7 @@ mod tests {
2910
2939
// Test that creating a new block device returns the correct output.
2911
2940
assert ! ( vmm. insert_block_device( root_block_device. clone( ) ) . is_ok( ) ) ;
2912
2941
assert ! ( vmm. init_guest_memory( ) . is_ok( ) ) ;
2913
- assert ! ( vmm. guest_memory. is_some( ) ) ;
2942
+ assert ! ( vmm. guest_memory( ) . is_some( ) ) ;
2914
2943
assert ! ( vmm. setup_interrupt_controller( ) . is_ok( ) ) ;
2915
2944
2916
2945
vmm. default_kernel_config ( None ) ;
@@ -2938,7 +2967,7 @@ mod tests {
2938
2967
. insert_block_device( non_root_block_device. clone( ) )
2939
2968
. is_ok( ) ) ;
2940
2969
assert ! ( vmm. init_guest_memory( ) . is_ok( ) ) ;
2941
- assert ! ( vmm. guest_memory. is_some( ) ) ;
2970
+ assert ! ( vmm. guest_memory( ) . is_some( ) ) ;
2942
2971
assert ! ( vmm. setup_interrupt_controller( ) . is_ok( ) ) ;
2943
2972
2944
2973
vmm. default_kernel_config ( None ) ;
@@ -2991,7 +3020,7 @@ mod tests {
2991
3020
fn test_attach_net_devices ( ) {
2992
3021
let mut vmm = create_vmm_object ( InstanceState :: Uninitialized ) ;
2993
3022
assert ! ( vmm. init_guest_memory( ) . is_ok( ) ) ;
2994
- assert ! ( vmm. guest_memory. is_some( ) ) ;
3023
+ assert ! ( vmm. guest_memory( ) . is_some( ) ) ;
2995
3024
2996
3025
vmm. default_kernel_config ( None ) ;
2997
3026
vmm. setup_interrupt_controller ( )
@@ -3096,7 +3125,7 @@ mod tests {
3096
3125
. is_ok( ) ) ;
3097
3126
3098
3127
assert ! ( vmm. init_guest_memory( ) . is_ok( ) ) ;
3099
- assert ! ( vmm. guest_memory. is_some( ) ) ;
3128
+ assert ! ( vmm. guest_memory( ) . is_some( ) ) ;
3100
3129
assert ! ( vmm. setup_interrupt_controller( ) . is_ok( ) ) ;
3101
3130
3102
3131
vmm. init_mmio_device_manager ( )
@@ -3418,11 +3447,11 @@ mod tests {
3418
3447
fn test_attach_legacy_devices_without_uart ( ) {
3419
3448
let mut vmm = create_vmm_object ( InstanceState :: Uninitialized ) ;
3420
3449
assert ! ( vmm. init_guest_memory( ) . is_ok( ) ) ;
3421
- assert ! ( vmm. guest_memory. is_some( ) ) ;
3450
+ assert ! ( vmm. guest_memory( ) . is_some( ) ) ;
3422
3451
3423
- let guest_mem = vmm. guest_memory . clone ( ) . unwrap ( ) ;
3452
+ let guest_mem = vmm. guest_memory ( ) . unwrap ( ) . clone ( ) ;
3424
3453
let device_manager = MMIODeviceManager :: new (
3425
- guest_mem. clone ( ) ,
3454
+ guest_mem,
3426
3455
& mut ( arch:: get_reserved_mem_addr ( ) as u64 ) ,
3427
3456
( arch:: IRQ_BASE , arch:: IRQ_MAX ) ,
3428
3457
) ;
@@ -3456,11 +3485,11 @@ mod tests {
3456
3485
fn test_attach_legacy_devices_with_uart ( ) {
3457
3486
let mut vmm = create_vmm_object ( InstanceState :: Uninitialized ) ;
3458
3487
assert ! ( vmm. init_guest_memory( ) . is_ok( ) ) ;
3459
- assert ! ( vmm. guest_memory. is_some( ) ) ;
3488
+ assert ! ( vmm. guest_memory( ) . is_some( ) ) ;
3460
3489
3461
- let guest_mem = vmm. guest_memory . clone ( ) . unwrap ( ) ;
3490
+ let guest_mem = vmm. guest_memory ( ) . unwrap ( ) . clone ( ) ;
3462
3491
let device_manager = MMIODeviceManager :: new (
3463
- guest_mem. clone ( ) ,
3492
+ guest_mem,
3464
3493
& mut ( arch:: get_reserved_mem_addr ( ) as u64 ) ,
3465
3494
( arch:: IRQ_BASE , arch:: IRQ_MAX ) ,
3466
3495
) ;
@@ -4167,4 +4196,23 @@ mod tests {
4167
4196
"VsockConfig(User, UpdateNotAllowedPostBoot)"
4168
4197
) ;
4169
4198
}
4199
+
4200
+ #[ test]
4201
+ fn test_misc ( ) {
4202
+ let mut vmm = create_vmm_object ( InstanceState :: Uninitialized ) ;
4203
+
4204
+ assert ! ( vmm. guest_memory( ) . is_none( ) ) ;
4205
+
4206
+ let mem = GuestMemory :: new ( & [ ( GuestAddress ( 0x1000 ) , 0x100 ) ] ) . unwrap ( ) ;
4207
+ vmm. set_guest_memory ( mem) ;
4208
+
4209
+ let mem_ref = vmm. guest_memory ( ) . unwrap ( ) ;
4210
+ assert_eq ! ( mem_ref. num_regions( ) , 1 ) ;
4211
+ assert_eq ! ( mem_ref. end_addr( ) , GuestAddress ( 0x1100 ) ) ;
4212
+
4213
+ assert_eq ! (
4214
+ vmm. kvm_vm( ) . get_fd( ) . as_raw_fd( ) ,
4215
+ vmm. vm. get_fd( ) . as_raw_fd( )
4216
+ ) ;
4217
+ }
4170
4218
}
0 commit comments