Skip to main content

flowey_lib_hvlite/
build_openhcl_igvm_from_recipe.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Build an OpenHCL IGVM file using a particular known-good "recipe", which
5//! encodes the precise features / build parameters used by each constituent
6//! component.
7//!
8//! By having a clearly enumerated list of recipes, it is possible for multiple
9//! pipelines / flows to depend on _precisely_ the same IGVM file, without
10//! having to duplicate the non-trivial OpenHCL IGVM build chain.
11
12use crate::build_openhcl_initrd::OpenhclInitrdExtraParams;
13use crate::build_openvmm_hcl::MaxTraceLevel;
14use crate::build_openvmm_hcl::OpenvmmHclBuildProfile;
15use crate::build_openvmm_hcl::OpenvmmHclFeature;
16use crate::common::CommonArch;
17use crate::common::CommonPlatform;
18use crate::common::CommonTriple;
19use crate::resolve_openhcl_kernel_package::OpenhclKernelPackageKind;
20use crate::run_cargo_build::BuildProfile;
21use flowey::node::prelude::*;
22use igvmfilegen_config::ResourceType;
23use std::collections::BTreeMap;
24use std::collections::BTreeSet;
25
26#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
27pub enum OpenhclKernelPackage {
28    /// Kernel from the hcl-main branch
29    Main,
30    /// CVM kernel from the hcl-main branch
31    Cvm,
32    /// Kernel from the hcl-dev branch
33    Dev,
34    /// CVM kernel from the hcl-dev brnach
35    CvmDev,
36}
37
38/// Vtl0 kernel type
39#[derive(Serialize, Deserialize, Debug, Clone)]
40pub enum Vtl0KernelType {
41    Example,
42    LocalOnlyCustom(PathBuf),
43}
44
45#[derive(Serialize, Deserialize, Clone, Debug)]
46pub enum IgvmManifestPath {
47    /// Name of an in-tree manifest (located under `vm/loader/manifests`)
48    InTree(String),
49    /// An absolute path to a custom manifest (for local use only)
50    LocalOnlyCustom(PathBuf),
51}
52
53#[derive(Serialize, Deserialize, Clone, Debug)]
54pub struct OpenhclIgvmRecipeDetails {
55    pub local_only: Option<OpenhclIgvmRecipeDetailsLocalOnly>,
56
57    pub igvm_manifest: IgvmManifestPath,
58    pub openhcl_kernel_package: OpenhclKernelPackage,
59    pub openvmm_hcl_features: BTreeSet<OpenvmmHclFeature>,
60    pub target: CommonTriple,
61    pub vtl0_kernel_type: Option<Vtl0KernelType>,
62    pub with_uefi: bool,
63    pub with_interactive: bool,
64    pub with_sidecar: bool,
65    pub max_trace_level: MaxTraceLevel,
66}
67
68#[derive(Serialize, Deserialize, Clone, Debug)]
69pub struct OpenhclIgvmRecipeDetailsLocalOnly {
70    pub openvmm_hcl_no_strip: bool,
71    pub openhcl_initrd_extra_params: Option<OpenhclInitrdExtraParams>,
72    pub custom_openvmm_hcl: Option<PathBuf>,
73    pub custom_openhcl_boot: Option<PathBuf>,
74    pub custom_kernel: Option<PathBuf>,
75    pub custom_sidecar: Option<PathBuf>,
76    pub custom_extra_rootfs: Vec<PathBuf>,
77}
78
79#[expect(clippy::large_enum_variant)]
80#[derive(Debug, Serialize, Deserialize, Clone)]
81pub enum OpenhclIgvmRecipe {
82    LocalOnlyCustom(OpenhclIgvmRecipeDetails),
83    X64,
84    X64Devkern,
85    X64TestLinuxDirect,
86    X64TestLinuxDirectDevkern,
87    X64Cvm,
88    X64CvmDevkern,
89    Aarch64,
90    Aarch64Devkern,
91}
92
93impl OpenhclIgvmRecipe {
94    pub fn recipe_details(&self, release_cfg: bool) -> OpenhclIgvmRecipeDetails {
95        let base_openvmm_hcl_features = || {
96            let mut m = BTreeSet::new();
97
98            m.insert(OpenvmmHclFeature::Tpm);
99
100            if !release_cfg {
101                m.insert(OpenvmmHclFeature::Gdb);
102            }
103
104            m
105        };
106
107        let in_repo_template = |debug_manifest: &'static str, release_manifest: &'static str| {
108            IgvmManifestPath::InTree(if release_cfg {
109                release_manifest.into()
110            } else {
111                debug_manifest.into()
112            })
113        };
114
115        // Debug configurations include --interactive by default, for busybox, gdbserver, and perf.
116        let with_interactive = !release_cfg;
117
118        // Save memory and cycles in hot paths by limiting the trace level in
119        // release builds.
120        let max_trace_level = if release_cfg {
121            MaxTraceLevel::Debug
122        } else {
123            MaxTraceLevel::Trace
124        };
125
126        match self {
127            Self::LocalOnlyCustom(details) => details.clone(),
128            Self::X64 => OpenhclIgvmRecipeDetails {
129                local_only: None,
130                igvm_manifest: in_repo_template("openhcl-x64-dev.json", "openhcl-x64-release.json"),
131                openhcl_kernel_package: OpenhclKernelPackage::Main,
132                openvmm_hcl_features: base_openvmm_hcl_features(),
133                target: CommonTriple::X86_64_LINUX_MUSL,
134                vtl0_kernel_type: None,
135                with_uefi: true,
136                with_interactive,
137                with_sidecar: true,
138                max_trace_level,
139            },
140            Self::X64Devkern => OpenhclIgvmRecipeDetails {
141                local_only: None,
142                igvm_manifest: in_repo_template("openhcl-x64-dev.json", "openhcl-x64-release.json"),
143                openhcl_kernel_package: OpenhclKernelPackage::Dev,
144                openvmm_hcl_features: base_openvmm_hcl_features(),
145                target: CommonTriple::X86_64_LINUX_MUSL,
146                vtl0_kernel_type: None,
147                with_uefi: true,
148                with_interactive,
149                with_sidecar: true,
150                max_trace_level,
151            },
152            Self::X64CvmDevkern => OpenhclIgvmRecipeDetails {
153                local_only: None,
154                igvm_manifest: in_repo_template(
155                    "openhcl-x64-cvm-dev.json",
156                    "openhcl-x64-cvm-release.json",
157                ),
158                openhcl_kernel_package: OpenhclKernelPackage::CvmDev,
159                openvmm_hcl_features: base_openvmm_hcl_features(),
160                target: CommonTriple::X86_64_LINUX_MUSL,
161                vtl0_kernel_type: None,
162                with_uefi: true,
163                with_interactive,
164                with_sidecar: false,
165                max_trace_level,
166            },
167            Self::X64TestLinuxDirect => OpenhclIgvmRecipeDetails {
168                local_only: None,
169                igvm_manifest: in_repo_template(
170                    "openhcl-x64-direct-dev.json",
171                    "openhcl-x64-direct-release.json",
172                ),
173                openhcl_kernel_package: OpenhclKernelPackage::Main,
174                openvmm_hcl_features: base_openvmm_hcl_features(),
175                target: CommonTriple::X86_64_LINUX_MUSL,
176                vtl0_kernel_type: Some(Vtl0KernelType::Example),
177                with_uefi: false,
178                with_interactive,
179                with_sidecar: true,
180                max_trace_level,
181            },
182            Self::X64TestLinuxDirectDevkern => OpenhclIgvmRecipeDetails {
183                local_only: None,
184                igvm_manifest: in_repo_template(
185                    "openhcl-x64-direct-dev.json",
186                    "openhcl-x64-direct-release.json",
187                ),
188                openhcl_kernel_package: OpenhclKernelPackage::Dev,
189                openvmm_hcl_features: base_openvmm_hcl_features(),
190                target: CommonTriple::X86_64_LINUX_MUSL,
191                vtl0_kernel_type: Some(Vtl0KernelType::Example),
192                with_uefi: false,
193                with_interactive,
194                with_sidecar: true,
195                max_trace_level,
196            },
197            Self::X64Cvm => OpenhclIgvmRecipeDetails {
198                local_only: None,
199                igvm_manifest: in_repo_template(
200                    "openhcl-x64-cvm-dev.json",
201                    "openhcl-x64-cvm-release.json",
202                ),
203                openhcl_kernel_package: OpenhclKernelPackage::Cvm,
204                openvmm_hcl_features: base_openvmm_hcl_features(),
205                target: CommonTriple::X86_64_LINUX_MUSL,
206                vtl0_kernel_type: None,
207                with_uefi: true,
208                with_interactive,
209                with_sidecar: false,
210                max_trace_level,
211            },
212            Self::Aarch64 => OpenhclIgvmRecipeDetails {
213                local_only: None,
214                igvm_manifest: in_repo_template(
215                    "openhcl-aarch64-dev.json",
216                    "openhcl-aarch64-release.json",
217                ),
218                openhcl_kernel_package: OpenhclKernelPackage::Main,
219                openvmm_hcl_features: base_openvmm_hcl_features(),
220                target: CommonTriple::AARCH64_LINUX_MUSL,
221                vtl0_kernel_type: None,
222                with_uefi: true,
223                with_interactive: false, // #1234
224                with_sidecar: false,
225                max_trace_level,
226            },
227            Self::Aarch64Devkern => OpenhclIgvmRecipeDetails {
228                local_only: None,
229                igvm_manifest: in_repo_template(
230                    "openhcl-aarch64-dev.json",
231                    "openhcl-aarch64-release.json",
232                ),
233                openhcl_kernel_package: OpenhclKernelPackage::Dev,
234                openvmm_hcl_features: base_openvmm_hcl_features(),
235                target: CommonTriple::AARCH64_LINUX_MUSL,
236                vtl0_kernel_type: None,
237                with_uefi: true,
238                with_interactive: false, // #1234
239                with_sidecar: false,
240                max_trace_level,
241            },
242        }
243    }
244}
245
246flowey_request! {
247    pub struct Request {
248        pub build_profile: OpenvmmHclBuildProfile,
249        pub release_cfg: bool,
250        pub recipe: OpenhclIgvmRecipe,
251        pub custom_target: Option<CommonTriple>,
252        /// Additional features to enable on top of the recipe's defaults.
253        pub extra_features: BTreeSet<OpenvmmHclFeature>,
254
255        pub built_openvmm_hcl: WriteVar<crate::build_openvmm_hcl::OpenvmmHclOutput>,
256        pub built_openhcl_boot: WriteVar<crate::build_openhcl_boot::OpenhclBootOutput>,
257        pub built_openhcl_igvm: WriteVar<crate::run_igvmfilegen::IgvmOutput>,
258        pub built_sidecar: WriteVar<Option<crate::build_sidecar::SidecarOutput>>,
259    }
260}
261
262new_simple_flow_node!(struct Node);
263
264impl SimpleFlowNode for Node {
265    type Request = Request;
266
267    fn imports(ctx: &mut ImportCtx<'_>) {
268        ctx.import::<crate::build_igvmfilegen::Node>();
269        ctx.import::<crate::build_openhcl_boot::Node>();
270        ctx.import::<crate::build_openhcl_initrd::Node>();
271        ctx.import::<crate::build_openvmm_hcl::Node>();
272        ctx.import::<crate::build_sidecar::Node>();
273        ctx.import::<crate::resolve_openhcl_kernel_package::Node>();
274        ctx.import::<crate::resolve_openvmm_deps::Node>();
275        ctx.import::<crate::download_uefi_mu_msvm::Node>();
276        ctx.import::<crate::git_checkout_openvmm_repo::Node>();
277        ctx.import::<crate::run_igvmfilegen::Node>();
278        ctx.import::<crate::run_split_debug_info::Node>();
279    }
280
281    fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
282        let Request {
283            build_profile,
284            release_cfg,
285            recipe,
286            custom_target,
287            extra_features,
288            built_openvmm_hcl,
289            built_openhcl_boot,
290            built_openhcl_igvm,
291            built_sidecar,
292        } = request;
293
294        let OpenhclIgvmRecipeDetails {
295            local_only,
296            igvm_manifest,
297            openhcl_kernel_package,
298            mut openvmm_hcl_features,
299            target,
300            vtl0_kernel_type,
301            with_uefi,
302            with_interactive,
303            with_sidecar,
304            max_trace_level,
305        } = recipe.recipe_details(release_cfg);
306
307        openvmm_hcl_features.extend(extra_features);
308
309        let OpenhclIgvmRecipeDetailsLocalOnly {
310            openvmm_hcl_no_strip,
311            openhcl_initrd_extra_params,
312            custom_openvmm_hcl,
313            custom_openhcl_boot,
314            custom_kernel,
315            custom_sidecar,
316            custom_extra_rootfs,
317        } = local_only.unwrap_or(OpenhclIgvmRecipeDetailsLocalOnly {
318            openvmm_hcl_no_strip: false,
319            openhcl_initrd_extra_params: None,
320            custom_openvmm_hcl: None,
321            custom_openhcl_boot: None,
322            custom_kernel: None,
323            custom_sidecar: None,
324            custom_extra_rootfs: Vec::new(),
325        });
326
327        let target = custom_target.unwrap_or(target);
328        let arch = CommonArch::from_triple(&target.as_triple())
329            .with_context(|| format!("cannot build openHCL from recipe on {target}"))?;
330
331        let openvmm_repo_path = ctx.reqv(crate::git_checkout_openvmm_repo::req::GetRepoDir);
332
333        let kernel_kind = match openhcl_kernel_package {
334            OpenhclKernelPackage::Main => OpenhclKernelPackageKind::Main,
335            OpenhclKernelPackage::Cvm => OpenhclKernelPackageKind::Cvm,
336            OpenhclKernelPackage::Dev => OpenhclKernelPackageKind::Dev,
337            OpenhclKernelPackage::CvmDev => OpenhclKernelPackageKind::CvmDev,
338        };
339
340        // Get the kernel package root for initrd building (needs metadata)
341        let vtl2_kernel_package_root =
342            ctx.reqv(
343                |v| crate::resolve_openhcl_kernel_package::Request::GetPackageRoot {
344                    kind: kernel_kind,
345                    arch,
346                    pkg: v,
347                },
348            );
349
350        // Get the modules path from the resolve node
351        let vtl2_kernel_modules =
352            ctx.reqv(
353                |v| crate::resolve_openhcl_kernel_package::Request::GetModules {
354                    kind: kernel_kind,
355                    arch,
356                    modules: v,
357                },
358            );
359
360        // Get the kernel metadata path from the resolve node
361        let vtl2_kernel_metadata =
362            ctx.reqv(
363                |v| crate::resolve_openhcl_kernel_package::Request::GetMetadata {
364                    kind: kernel_kind,
365                    arch,
366                    metadata: v,
367                },
368            );
369
370        let uefi_resource = with_uefi.then(|| UefiResource {
371            msvm_fd: ctx
372                .reqv(|v| crate::download_uefi_mu_msvm::Request::GetMsvmFd { arch, msvm_fd: v }),
373        });
374
375        let vtl0_kernel_resource = vtl0_kernel_type.map(|typ| {
376            let kernel = if let Vtl0KernelType::LocalOnlyCustom(path) = typ {
377                ReadVar::from_static(path)
378            } else {
379                match typ {
380                    Vtl0KernelType::Example => ctx.reqv(|v| {
381                        crate::resolve_openvmm_deps::Request::Get(
382                            crate::resolve_openvmm_deps::OpenvmmDepFile::LinuxTestKernel,
383                            arch,
384                            v,
385                        )
386                    }),
387                    Vtl0KernelType::LocalOnlyCustom(_) => unreachable!("special cased above"),
388                }
389            };
390
391            let initrd = ctx.reqv(|v| {
392                crate::resolve_openvmm_deps::Request::Get(
393                    crate::resolve_openvmm_deps::OpenvmmDepFile::LinuxTestInitrd,
394                    arch,
395                    v,
396                )
397            });
398
399            Vtl0KernelResource { kernel, initrd }
400        });
401
402        // build sidecar
403        let sidecar_bin = if with_sidecar {
404            let sidecar_bin = if let Some(path) = custom_sidecar {
405                ctx.emit_rust_stepv("set custom_sidecar", |_ctx| {
406                    |_rt| {
407                        let fake_dbg_path = std::env::current_dir()?
408                            .join("fake_sidecar.dbg")
409                            .absolute()?;
410                        fs_err::write(&fake_dbg_path, "")?;
411
412                        Ok(crate::build_sidecar::SidecarOutput {
413                            bin: path,
414                            dbg: fake_dbg_path,
415                        })
416                    }
417                })
418            } else {
419                ctx.reqv(|v| crate::build_sidecar::Request {
420                    build_params: crate::build_sidecar::SidecarBuildParams {
421                        arch,
422                        profile: match build_profile {
423                            OpenvmmHclBuildProfile::Debug => {
424                                crate::build_sidecar::SidecarBuildProfile::Debug
425                            }
426                            OpenvmmHclBuildProfile::Release
427                            | OpenvmmHclBuildProfile::OpenvmmHclShip => {
428                                crate::build_sidecar::SidecarBuildProfile::Release
429                            }
430                        },
431                    },
432                    sidecar: v,
433                })
434            };
435            sidecar_bin.write_into(ctx, built_sidecar, Some);
436            Some(sidecar_bin)
437        } else {
438            built_sidecar.write_static(ctx, None);
439            None
440        };
441
442        // build openvmm_hcl bin
443        let openvmm_hcl_bin = if let Some(ref path) = custom_openvmm_hcl {
444            let path = path.clone();
445            ctx.emit_rust_stepv("set custom_openvmm_hcl", |_ctx| {
446                |_rt| {
447                    Ok(crate::build_openvmm_hcl::OpenvmmHclOutput {
448                        bin: path,
449                        dbg: None,
450                    })
451                }
452            })
453        } else {
454            ctx.reqv(|v| {
455                crate::build_openvmm_hcl::Request {
456                    build_params: crate::build_openvmm_hcl::OpenvmmHclBuildParams {
457                        target: target.clone(),
458                        profile: build_profile,
459                        features: openvmm_hcl_features,
460                        // manually strip later, depending on provided igvm flags
461                        no_split_dbg_info: true,
462                        max_trace_level,
463                    },
464                    openvmm_hcl_output: v,
465                }
466            })
467        };
468
469        // build igvmfilegen (always built for host arch)
470        let igvmfilegen_arch: CommonArch = ctx.arch().try_into()?;
471
472        let igvmfilegen = ctx.reqv(|v| crate::build_igvmfilegen::Request {
473            build_params: crate::build_igvmfilegen::IgvmfilegenBuildParams {
474                target: CommonTriple::Common {
475                    arch: igvmfilegen_arch,
476                    platform: CommonPlatform::LinuxGnu,
477                },
478                profile: BuildProfile::Light,
479            },
480            igvmfilegen: v,
481        });
482
483        // build openhcl_boot
484        let openhcl_boot_bin = if let Some(path) = custom_openhcl_boot {
485            ctx.emit_rust_stepv("set custom_openhcl_boot", |_ctx| {
486                |_rt| {
487                    let fake_dbg_path = std::env::current_dir()?.join("fake.dbg").absolute()?;
488                    fs_err::write(&fake_dbg_path, "")?;
489
490                    Ok(crate::build_openhcl_boot::OpenhclBootOutput {
491                        bin: path,
492                        dbg: fake_dbg_path,
493                    })
494                }
495            })
496        } else {
497            ctx.reqv(|v| crate::build_openhcl_boot::Request {
498                build_params: crate::build_openhcl_boot::OpenhclBootBuildParams {
499                    arch,
500                    profile: match build_profile {
501                        OpenvmmHclBuildProfile::Debug => {
502                            crate::build_openhcl_boot::OpenhclBootBuildProfile::Debug
503                        }
504                        OpenvmmHclBuildProfile::Release
505                        | OpenvmmHclBuildProfile::OpenvmmHclShip => {
506                            crate::build_openhcl_boot::OpenhclBootBuildProfile::Release
507                        }
508                    },
509                },
510                openhcl_boot: v,
511            })
512        };
513        openhcl_boot_bin.write_into(ctx, built_openhcl_boot, |x| x);
514
515        let use_stripped_openvmm_hcl = {
516            if custom_openvmm_hcl.is_some() {
517                // trust the user knows what they are doing if they specified a
518                // custom bin
519                false
520            } else {
521                !openvmm_hcl_no_strip
522            }
523        };
524
525        // use the stripped or unstripped openvmm_hcl as requested
526        let openvmm_hcl_bin = if use_stripped_openvmm_hcl {
527            let (read, write) = ctx.new_var();
528            let (read_dbg, write_dbg) = ctx.new_var();
529
530            let in_bin = openvmm_hcl_bin.map(ctx, |o| o.bin);
531            ctx.req(crate::run_split_debug_info::Request {
532                arch,
533                in_bin,
534                out_bin: write,
535                out_dbg_info: write_dbg,
536                reproducible_without_debuglink: matches!(
537                    ctx.platform(),
538                    FlowPlatform::Linux(FlowPlatformLinuxDistro::Nix)
539                ),
540            });
541
542            read.zip(ctx, read_dbg).map(ctx, |(bin, dbg)| {
543                crate::build_openvmm_hcl::OpenvmmHclOutput {
544                    bin,
545                    dbg: Some(dbg),
546                }
547            })
548        } else {
549            openvmm_hcl_bin
550        };
551
552        // report the built openvmm_hcl
553        openvmm_hcl_bin.write_into(ctx, built_openvmm_hcl, |x| x);
554
555        let initrd = {
556            let rootfs_config = [openvmm_repo_path.map(ctx, |p| p.join("openhcl/rootfs.config"))]
557                .into_iter()
558                .chain(
559                    custom_extra_rootfs
560                        .into_iter()
561                        .map(|p| ReadVar::from_static(p)),
562                )
563                .collect();
564            let openvmm_hcl_bin = openvmm_hcl_bin.map(ctx, |o| o.bin);
565
566            ctx.reqv(|v| crate::build_openhcl_initrd::Request {
567                interactive: with_interactive,
568                arch,
569                extra_params: openhcl_initrd_extra_params,
570                rootfs_config,
571                extra_env: None,
572                kernel_package_root: vtl2_kernel_package_root.clone(),
573                kernel_modules: vtl2_kernel_modules,
574                kernel_metadata: vtl2_kernel_metadata,
575                bin_openhcl: openvmm_hcl_bin,
576                initrd: v,
577            })
578        };
579
580        let kernel = if let Some(path) = custom_kernel {
581            ReadVar::from_static(path)
582        } else {
583            ctx.reqv(
584                |v| crate::resolve_openhcl_kernel_package::Request::GetKernel {
585                    kind: kernel_kind,
586                    arch,
587                    kernel: v,
588                },
589            )
590        };
591
592        let resources = ctx.emit_minor_rust_stepv("enumerate igvm resources", |ctx| {
593            let initrd = initrd.claim(ctx);
594            let kernel = kernel.claim(ctx);
595            let openhcl_boot_bin = openhcl_boot_bin.claim(ctx);
596            let sidecar_bin = sidecar_bin.claim(ctx);
597            let uefi_resource = uefi_resource.claim(ctx);
598            let vtl0_kernel_resource = vtl0_kernel_resource.claim(ctx);
599            |rt| {
600                let mut resources = BTreeMap::<ResourceType, PathBuf>::new();
601                resources.insert(ResourceType::UnderhillKernel, rt.read(kernel));
602                resources.insert(ResourceType::UnderhillInitrd, rt.read(initrd).initrd);
603                resources.insert(ResourceType::OpenhclBoot, rt.read(openhcl_boot_bin).bin);
604                if let Some(sidecar_bin) = sidecar_bin {
605                    resources.insert(ResourceType::UnderhillSidecar, rt.read(sidecar_bin).bin);
606                }
607                if let Some(uefi_resource) = uefi_resource {
608                    uefi_resource.add_to_resources(&mut resources, rt);
609                }
610                if let Some(vtl0_kernel_resource) = vtl0_kernel_resource {
611                    vtl0_kernel_resource.add_to_resources(&mut resources, rt);
612                }
613                resources
614            }
615        });
616
617        let igvmfilegen = igvmfilegen.map(ctx, |o| match o {
618            crate::build_igvmfilegen::IgvmfilegenOutput::LinuxBin { bin, dbg: _ } => bin,
619            crate::build_igvmfilegen::IgvmfilegenOutput::WindowsBin { exe, pdb: _ } => exe,
620        });
621
622        let manifest = match igvm_manifest {
623            IgvmManifestPath::InTree(path) => {
624                openvmm_repo_path.map(ctx, |p| p.join("vm/loader/manifests").join(path))
625            }
626            IgvmManifestPath::LocalOnlyCustom(p) => ReadVar::from_static(p),
627        };
628
629        ctx.req(crate::run_igvmfilegen::Request {
630            igvmfilegen,
631            manifest,
632            resources,
633            igvm: built_openhcl_igvm,
634        });
635
636        Ok(())
637    }
638}
639
640#[derive(Debug)]
641pub struct UefiResource<C = VarNotClaimed> {
642    pub msvm_fd: ReadVar<PathBuf, C>,
643}
644
645impl ClaimVar for UefiResource {
646    type Claimed = UefiResource<VarClaimed>;
647
648    fn claim(self, ctx: &mut StepCtx<'_>) -> UefiResource<VarClaimed> {
649        UefiResource {
650            msvm_fd: self.msvm_fd.claim(ctx),
651        }
652    }
653}
654
655impl UefiResource<VarClaimed> {
656    pub fn add_to_resources(
657        self,
658        resources: &mut BTreeMap<ResourceType, PathBuf>,
659        rt: &mut RustRuntimeServices<'_>,
660    ) {
661        let path = rt.read(self.msvm_fd);
662        resources.insert(ResourceType::Uefi, path);
663    }
664}
665
666pub struct Vtl0KernelResource<C = VarNotClaimed> {
667    pub kernel: ReadVar<PathBuf, C>,
668    pub initrd: ReadVar<PathBuf, C>,
669}
670
671impl ClaimVar for Vtl0KernelResource {
672    type Claimed = Vtl0KernelResource<VarClaimed>;
673
674    fn claim(self, ctx: &mut StepCtx<'_>) -> Vtl0KernelResource<VarClaimed> {
675        Vtl0KernelResource {
676            kernel: self.kernel.claim(ctx),
677            initrd: self.initrd.claim(ctx),
678        }
679    }
680}
681
682impl Vtl0KernelResource<VarClaimed> {
683    pub fn add_to_resources(
684        self,
685        resources: &mut BTreeMap<ResourceType, PathBuf>,
686        rt: &mut RustRuntimeServices<'_>,
687    ) {
688        let kernel = rt.read(self.kernel);
689        let initrd = rt.read(self.initrd);
690        resources.insert(ResourceType::LinuxKernel, kernel);
691        resources.insert(ResourceType::LinuxInitrd, initrd);
692    }
693}