11use std:: {
2- env, fmt, fs, io,
2+ env,
3+ ffi:: CString ,
4+ fmt, fs, io,
5+ mem:: { drop, take} ,
36 num:: NonZero ,
47 os:: unix:: prelude:: JoinHandleExt ,
58 path:: PathBuf ,
@@ -10,8 +13,9 @@ use std::{
1013
1114use core_affinity:: CoreId ;
1215use hermit_entry:: {
13- HermitVersion , UhyveIfVersion ,
16+ Format , HermitVersion , UhyveIfVersion ,
1417 boot_info:: { BootInfo , HardwareInfo , LoadInfo , PlatformInfo , RawBootInfo , SerialPortBase } ,
18+ config, detect_format,
1519 elf:: { KernelObject , LoadedKernel , ParseKernelError } ,
1620} ;
1721use internal:: VirtualizationBackendInternal ;
@@ -24,7 +28,7 @@ use crate::{
2428 consts:: * ,
2529 fdt:: Fdt ,
2630 generate_address,
27- isolation:: filemap:: UhyveFileMap ,
31+ isolation:: filemap:: { UhyveFileMap , UhyveTreeFile } ,
2832 mem:: MmapMemory ,
2933 os:: KickSignal ,
3034 params:: { EnvVars , Params } ,
@@ -137,11 +141,127 @@ pub struct UhyveVm<VirtBackend: VirtualizationBackend> {
137141 pub ( crate ) kernel_info : Arc < KernelInfo > ,
138142}
139143impl < VirtBackend : VirtualizationBackend > UhyveVm < VirtBackend > {
140- pub fn new ( kernel_path : PathBuf , params : Params ) -> HypervisorResult < UhyveVm < VirtBackend > > {
144+ pub fn new ( kernel_path : PathBuf , mut params : Params ) -> HypervisorResult < UhyveVm < VirtBackend > > {
141145 let memory_size = params. memory_size . get ( ) ;
142146
143- let elf = fs:: read ( & kernel_path)
147+ let kernel_data = fs:: read ( & kernel_path)
144148 . map_err ( |_e| HypervisorError :: InvalidKernelPath ( kernel_path. clone ( ) ) ) ?;
149+
150+ // TODO: file_mapping not in kernel_info
151+ let mut file_mapping = UhyveFileMap :: new (
152+ & params. file_mapping ,
153+ params. tempdir . clone ( ) ,
154+ #[ cfg( target_os = "linux" ) ]
155+ params. io_mode ,
156+ ) ;
157+
158+ // `kernel_data` might be an Hermit image
159+ let elf = match detect_format ( & kernel_data[ ..] ) {
160+ None => return Err ( HypervisorError :: InvalidKernelPath ( kernel_path. clone ( ) ) ) ,
161+ Some ( Format :: Elf ) => kernel_data,
162+ Some ( Format :: Gzip ) => {
163+ {
164+ use io:: Read ;
165+
166+ // decompress image
167+ let mut buf_decompressed = Vec :: new ( ) ;
168+ flate2:: bufread:: GzDecoder :: new ( & kernel_data[ ..] )
169+ . read_to_end ( & mut buf_decompressed) ?;
170+ drop ( kernel_data) ;
171+
172+ // insert Hermit image tree into file map
173+ file_mapping. add_hermit_image ( & buf_decompressed[ ..] ) ?;
174+ }
175+
176+ // TODO: make `hermit_entry::config::DEFAULT_CONFIG_NAME` public and use that here instead.
177+ let config_data = if let Some ( UhyveTreeFile :: Virtual ( data) ) =
178+ file_mapping. get_host_path ( & CString :: new ( "/hermit.toml" ) . unwrap ( ) )
179+ {
180+ data
181+ } else {
182+ return Err ( HypervisorError :: HermitImageConfigNotFound ) ;
183+ } ;
184+
185+ let config: config:: Config < ' _ > = toml:: from_slice ( & config_data[ ..] ) ?;
186+
187+ // handle Hermit image configuration
188+ match config {
189+ config:: Config :: V1 {
190+ mut input,
191+ requirements,
192+ kernel,
193+ } => {
194+ // .input
195+ if params. kernel_args . is_empty ( ) {
196+ params. kernel_args . append (
197+ & mut take ( & mut input. kernel_args )
198+ . into_iter ( )
199+ . map ( |i| i. into_owned ( ) )
200+ . collect ( ) ,
201+ ) ;
202+ if !input. app_args . is_empty ( ) {
203+ params. kernel_args . push ( "--" . to_string ( ) ) ;
204+ params. kernel_args . append (
205+ & mut take ( & mut input. app_args )
206+ . into_iter ( )
207+ . map ( |i| i. into_owned ( ) )
208+ . collect ( ) ,
209+ )
210+ }
211+ }
212+ debug ! ( "Passing kernel arguments: {:?}" , & params. kernel_args) ;
213+
214+ // don't pass privileged env-var commands through
215+ input. env_vars . retain ( |i| i. contains ( '=' ) ) ;
216+
217+ if let EnvVars :: Set ( env) = & mut params. env {
218+ if let Ok ( EnvVars :: Set ( prev_env_vars) ) =
219+ EnvVars :: try_from ( & input. env_vars [ ..] )
220+ {
221+ // env vars from params take precedence
222+ let new_env_vars = take ( env) ;
223+ * env = prev_env_vars. into_iter ( ) . chain ( new_env_vars) . collect ( ) ;
224+ } else {
225+ warn ! ( "Unable to parse env vars from Hermit image configuration" ) ;
226+ }
227+ } else if input. env_vars . is_empty ( ) {
228+ info ! ( "Ignoring Hermit image env vars due to `-e host`" ) ;
229+ }
230+
231+ // .requirements
232+
233+ // TODO: what about default memory size?
234+ if let Some ( required_memory_size) = requirements. memory {
235+ if params. memory_size . 0 < required_memory_size {
236+ return Err ( HypervisorError :: InsufficientGuestMemorySize {
237+ got : params. memory_size . 0 ,
238+ wanted : required_memory_size,
239+ } ) ;
240+ }
241+ }
242+
243+ if params. cpu_count . get ( ) < requirements. cpus {
244+ return Err ( HypervisorError :: InsufficientGuestCPUs {
245+ got : params. cpu_count . get ( ) ,
246+ wanted : requirements. cpus ,
247+ } ) ;
248+ }
249+
250+ // .kernel
251+ if let Some ( UhyveTreeFile :: Virtual ( data) ) =
252+ file_mapping. get_host_path ( & CString :: new ( kernel. into_owned ( ) ) . map_err (
253+ |_| HypervisorError :: PathContainedNullBytes ( "hermit image kernel" ) ,
254+ ) ?) {
255+ data. to_vec ( )
256+ } else {
257+ error ! ( "Unable to find kernel in Hermit image" ) ;
258+ return Err ( HypervisorError :: InvalidKernelPath ( kernel_path. clone ( ) ) ) ;
259+ }
260+ }
261+ }
262+ }
263+ } ;
264+
145265 let object: KernelObject < ' _ > =
146266 KernelObject :: parse ( & elf) . map_err ( LoadKernelError :: ParseKernelError ) ?;
147267
@@ -204,14 +324,9 @@ impl<VirtBackend: VirtualizationBackend> UhyveVm<VirtBackend> {
204324 let mut mem = MmapMemory :: new ( memory_size, guest_address, false , false ) ;
205325
206326 // TODO: file_mapping not in kernel_info
207- let file_mapping = Mutex :: new ( UhyveFileMap :: new (
208- & params. file_mapping ,
209- params. tempdir . clone ( ) ,
210- #[ cfg( target_os = "linux" ) ]
211- params. io_mode ,
212- ) ) ;
213- let mut mounts: Vec < _ > = file_mapping. lock ( ) . unwrap ( ) . get_all_guest_dirs ( ) . collect ( ) ;
327+ let mut mounts: Vec < _ > = file_mapping. get_all_guest_dirs ( ) . collect ( ) ;
214328 mounts. dedup ( ) ;
329+ let file_mapping = Mutex :: new ( file_mapping) ;
215330
216331 let serial = UhyveSerial :: from_params ( & params. output ) ?;
217332
0 commit comments