11use std:: {
22 env, fmt, fs, io,
3+ mem:: { drop, take} ,
34 num:: NonZero ,
45 os:: unix:: prelude:: JoinHandleExt ,
56 path:: PathBuf ,
@@ -10,8 +11,9 @@ use std::{
1011
1112use core_affinity:: CoreId ;
1213use hermit_entry:: {
13- HermitVersion , UhyveIfVersion ,
14+ Format , HermitVersion , UhyveIfVersion ,
1415 boot_info:: { BootInfo , HardwareInfo , LoadInfo , PlatformInfo , RawBootInfo , SerialPortBase } ,
16+ config, detect_format,
1517 elf:: { KernelObject , LoadedKernel , ParseKernelError } ,
1618} ;
1719use internal:: VirtualizationBackendInternal ;
@@ -24,7 +26,7 @@ use crate::{
2426 consts:: * ,
2527 fdt:: Fdt ,
2628 generate_address,
27- isolation:: filemap:: UhyveFileMap ,
29+ isolation:: filemap:: { UhyveFileMap , UhyveMapLeaf } ,
2830 mem:: MmapMemory ,
2931 os:: KickSignal ,
3032 params:: { EnvVars , Params } ,
@@ -137,11 +139,126 @@ pub struct UhyveVm<VirtBackend: VirtualizationBackend> {
137139 pub ( crate ) kernel_info : Arc < KernelInfo > ,
138140}
139141impl < VirtBackend : VirtualizationBackend > UhyveVm < VirtBackend > {
140- pub fn new ( kernel_path : PathBuf , params : Params ) -> HypervisorResult < UhyveVm < VirtBackend > > {
142+ pub fn new ( kernel_path : PathBuf , mut params : Params ) -> HypervisorResult < UhyveVm < VirtBackend > > {
141143 let memory_size = params. memory_size . get ( ) ;
142144
143- let elf = fs:: read ( & kernel_path)
145+ let kernel_data = fs:: read ( & kernel_path)
144146 . map_err ( |_e| HypervisorError :: InvalidKernelPath ( kernel_path. clone ( ) ) ) ?;
147+
148+ // TODO: file_mapping not in kernel_info
149+ let mut file_mapping = UhyveFileMap :: new (
150+ & params. file_mapping ,
151+ params. tempdir . clone ( ) ,
152+ #[ cfg( target_os = "linux" ) ]
153+ params. io_mode ,
154+ ) ;
155+
156+ // `kernel_data` might be an Hermit image
157+ let elf = match detect_format ( & kernel_data[ ..] ) {
158+ None => return Err ( HypervisorError :: InvalidKernelPath ( kernel_path. clone ( ) ) ) ,
159+ Some ( Format :: Elf ) => kernel_data,
160+ Some ( Format :: Gzip ) => {
161+ {
162+ use io:: Read ;
163+
164+ // decompress image
165+ let mut buf_decompressed = Vec :: new ( ) ;
166+ flate2:: bufread:: GzDecoder :: new ( & kernel_data[ ..] )
167+ . read_to_end ( & mut buf_decompressed) ?;
168+ drop ( kernel_data) ;
169+
170+ // insert Hermit image tree into file map
171+ file_mapping. add_hermit_image ( & buf_decompressed[ ..] ) ?;
172+ }
173+
174+ // TODO: make `hermit_entry::config::DEFAULT_CONFIG_NAME` public and use that here instead.
175+ let config_data = if let Some ( UhyveMapLeaf :: Virtual ( data) ) =
176+ file_mapping. get_host_path ( "/hermit.toml" )
177+ {
178+ data
179+ } else {
180+ return Err ( HypervisorError :: HermitImageConfigNotFound ) ;
181+ } ;
182+
183+ let config: config:: Config < ' _ > = toml:: from_slice ( & config_data[ ..] ) ?;
184+
185+ // handle Hermit image configuration
186+ match config {
187+ config:: Config :: V1 {
188+ mut input,
189+ requirements,
190+ kernel,
191+ } => {
192+ // .input
193+ if params. kernel_args . is_empty ( ) {
194+ params. kernel_args . append (
195+ & mut take ( & mut input. kernel_args )
196+ . into_iter ( )
197+ . map ( |i| i. into_owned ( ) )
198+ . collect ( ) ,
199+ ) ;
200+ if !input. app_args . is_empty ( ) {
201+ params. kernel_args . push ( "--" . to_string ( ) ) ;
202+ params. kernel_args . append (
203+ & mut take ( & mut input. app_args )
204+ . into_iter ( )
205+ . map ( |i| i. into_owned ( ) )
206+ . collect ( ) ,
207+ )
208+ }
209+ }
210+ debug ! ( "Passing kernel arguments: {:?}" , & params. kernel_args) ;
211+
212+ // don't pass privileged env-var commands through
213+ input. env_vars . retain ( |i| i. contains ( '=' ) ) ;
214+
215+ if let EnvVars :: Set ( env) = & mut params. env {
216+ if let Ok ( EnvVars :: Set ( prev_env_vars) ) =
217+ EnvVars :: try_from ( & input. env_vars [ ..] )
218+ {
219+ // env vars from params take precedence
220+ let new_env_vars = take ( env) ;
221+ * env = prev_env_vars. into_iter ( ) . chain ( new_env_vars) . collect ( ) ;
222+ } else {
223+ warn ! ( "Unable to parse env vars from Hermit image configuration" ) ;
224+ }
225+ } else if input. env_vars . is_empty ( ) {
226+ info ! ( "Ignoring Hermit image env vars due to `-e host`" ) ;
227+ }
228+
229+ // .requirements
230+
231+ // TODO: what about default memory size?
232+ if let Some ( required_memory_size) = requirements. memory
233+ && params. memory_size . 0 < required_memory_size
234+ {
235+ return Err ( HypervisorError :: InsufficientGuestMemorySize {
236+ got : params. memory_size . 0 ,
237+ wanted : required_memory_size,
238+ } ) ;
239+ }
240+
241+ if params. cpu_count . get ( ) < requirements. cpus {
242+ return Err ( HypervisorError :: InsufficientGuestCPUs {
243+ got : params. cpu_count . get ( ) ,
244+ wanted : requirements. cpus ,
245+ } ) ;
246+ }
247+
248+ // .kernel
249+ if let Some ( UhyveMapLeaf :: Virtual ( data) ) =
250+ file_mapping. get_host_path ( & kernel)
251+ {
252+ data. to_vec ( )
253+ } else {
254+ error ! ( "Unable to find kernel in Hermit image" ) ;
255+ return Err ( HypervisorError :: InvalidKernelPath ( kernel_path. clone ( ) ) ) ;
256+ }
257+ }
258+ }
259+ }
260+ } ;
261+
145262 let object: KernelObject < ' _ > =
146263 KernelObject :: parse ( & elf) . map_err ( LoadKernelError :: ParseKernelError ) ?;
147264
@@ -203,13 +320,6 @@ impl<VirtBackend: VirtualizationBackend> UhyveVm<VirtBackend> {
203320 #[ cfg( not( target_os = "linux" ) ) ]
204321 let mut mem = MmapMemory :: new ( memory_size, guest_address, false , false ) ;
205322
206- // TODO: file_mapping not in kernel_info
207- let file_mapping = UhyveFileMap :: new (
208- & params. file_mapping ,
209- params. tempdir . clone ( ) ,
210- #[ cfg( target_os = "linux" ) ]
211- params. io_mode ,
212- ) ;
213323 let mounts: Vec < _ > = file_mapping. get_all_guest_dirs ( ) . collect ( ) ;
214324
215325 let serial = UhyveSerial :: from_params ( & params. output ) ?;
0 commit comments