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::download_uefi_mu_msvm::MuMsvmArch;
17use crate::resolve_openhcl_kernel_package::OpenhclKernelPackageArch;
18use crate::resolve_openhcl_kernel_package::OpenhclKernelPackageKind;
19use crate::resolve_openvmm_deps::OpenvmmDepsArch;
20use crate::run_cargo_build::BuildProfile;
21use crate::run_cargo_build::common::CommonArch;
22use crate::run_cargo_build::common::CommonPlatform;
23use crate::run_cargo_build::common::CommonTriple;
24use flowey::node::prelude::*;
25use igvmfilegen_config::ResourceType;
26use std::collections::BTreeMap;
27use std::collections::BTreeSet;
28
29#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
30pub enum OpenhclKernelPackage {
31    /// Kernel from the hcl-main branch
32    Main,
33    /// CVM kernel from the hcl-main branch
34    Cvm,
35    /// Kernel from the hcl-dev branch
36    Dev,
37    /// CVM kernel from the hcl-dev brnach
38    CvmDev,
39}
40
41/// Vtl0 kernel type
42#[derive(Serialize, Deserialize, Debug, Clone)]
43pub enum Vtl0KernelType {
44    Example,
45    LocalOnlyCustom(PathBuf),
46}
47
48#[derive(Serialize, Deserialize, Clone, Debug)]
49pub enum IgvmManifestPath {
50    /// Name of an in-tree manifest (located under `vm/loader/manifests`)
51    InTree(String),
52    /// An absolute path to a custom manifest (for local use only)
53    LocalOnlyCustom(PathBuf),
54}
55
56#[derive(Serialize, Deserialize, Clone, Debug)]
57pub struct OpenhclIgvmRecipeDetails {
58    pub local_only: Option<OpenhclIgvmRecipeDetailsLocalOnly>,
59
60    pub igvm_manifest: IgvmManifestPath,
61    pub openhcl_kernel_package: OpenhclKernelPackage,
62    pub openvmm_hcl_features: BTreeSet<OpenvmmHclFeature>,
63    pub target: CommonTriple,
64    pub vtl0_kernel_type: Option<Vtl0KernelType>,
65    pub with_uefi: bool,
66    pub with_interactive: bool,
67    pub with_sidecar: bool,
68    pub max_trace_level: MaxTraceLevel,
69}
70
71#[derive(Serialize, Deserialize, Clone, Debug)]
72pub struct OpenhclIgvmRecipeDetailsLocalOnly {
73    pub openvmm_hcl_no_strip: bool,
74    pub openhcl_initrd_extra_params: Option<OpenhclInitrdExtraParams>,
75    pub custom_openvmm_hcl: Option<PathBuf>,
76    pub custom_openhcl_boot: Option<PathBuf>,
77    pub custom_kernel: Option<PathBuf>,
78    pub custom_sidecar: Option<PathBuf>,
79    pub custom_extra_rootfs: Vec<PathBuf>,
80}
81
82#[expect(clippy::large_enum_variant)]
83#[derive(Debug, Serialize, Deserialize, Clone)]
84pub enum OpenhclIgvmRecipe {
85    LocalOnlyCustom(OpenhclIgvmRecipeDetails),
86    X64,
87    X64Devkern,
88    X64TestLinuxDirect,
89    X64TestLinuxDirectDevkern,
90    X64Cvm,
91    X64CvmDevkern,
92    Aarch64,
93    Aarch64Devkern,
94}
95
96impl OpenhclIgvmRecipe {
97    pub fn recipe_details(&self, release_cfg: bool) -> OpenhclIgvmRecipeDetails {
98        let base_openvmm_hcl_features = || {
99            let mut m = BTreeSet::new();
100
101            m.insert(OpenvmmHclFeature::Tpm);
102
103            if !release_cfg {
104                m.insert(OpenvmmHclFeature::Gdb);
105            }
106
107            m
108        };
109
110        let in_repo_template = |debug_manifest: &'static str, release_manifest: &'static str| {
111            IgvmManifestPath::InTree(if release_cfg {
112                release_manifest.into()
113            } else {
114                debug_manifest.into()
115            })
116        };
117
118        // Debug configurations include --interactive by default, for busybox, gdbserver, and perf.
119        let with_interactive = !release_cfg;
120
121        // Save memory and cycles in hot paths by limiting the trace level in
122        // release builds.
123        let max_trace_level = if release_cfg {
124            MaxTraceLevel::Debug
125        } else {
126            MaxTraceLevel::Trace
127        };
128
129        match self {
130            Self::LocalOnlyCustom(details) => details.clone(),
131            Self::X64 => OpenhclIgvmRecipeDetails {
132                local_only: None,
133                igvm_manifest: in_repo_template("openhcl-x64-dev.json", "openhcl-x64-release.json"),
134                openhcl_kernel_package: OpenhclKernelPackage::Main,
135                openvmm_hcl_features: base_openvmm_hcl_features(),
136                target: CommonTriple::X86_64_LINUX_MUSL,
137                vtl0_kernel_type: None,
138                with_uefi: true,
139                with_interactive,
140                with_sidecar: true,
141                max_trace_level,
142            },
143            Self::X64Devkern => OpenhclIgvmRecipeDetails {
144                local_only: None,
145                igvm_manifest: in_repo_template("openhcl-x64-dev.json", "openhcl-x64-release.json"),
146                openhcl_kernel_package: OpenhclKernelPackage::Dev,
147                openvmm_hcl_features: base_openvmm_hcl_features(),
148                target: CommonTriple::X86_64_LINUX_MUSL,
149                vtl0_kernel_type: None,
150                with_uefi: true,
151                with_interactive,
152                with_sidecar: true,
153                max_trace_level,
154            },
155            Self::X64CvmDevkern => OpenhclIgvmRecipeDetails {
156                local_only: None,
157                igvm_manifest: in_repo_template(
158                    "openhcl-x64-cvm-dev.json",
159                    "openhcl-x64-cvm-release.json",
160                ),
161                openhcl_kernel_package: OpenhclKernelPackage::CvmDev,
162                openvmm_hcl_features: base_openvmm_hcl_features(),
163                target: CommonTriple::X86_64_LINUX_MUSL,
164                vtl0_kernel_type: None,
165                with_uefi: true,
166                with_interactive,
167                with_sidecar: false,
168                max_trace_level,
169            },
170            Self::X64TestLinuxDirect => OpenhclIgvmRecipeDetails {
171                local_only: None,
172                igvm_manifest: in_repo_template(
173                    "openhcl-x64-direct-dev.json",
174                    "openhcl-x64-direct-release.json",
175                ),
176                openhcl_kernel_package: OpenhclKernelPackage::Main,
177                openvmm_hcl_features: base_openvmm_hcl_features(),
178                target: CommonTriple::X86_64_LINUX_MUSL,
179                vtl0_kernel_type: Some(Vtl0KernelType::Example),
180                with_uefi: false,
181                with_interactive,
182                with_sidecar: true,
183                max_trace_level,
184            },
185            Self::X64TestLinuxDirectDevkern => OpenhclIgvmRecipeDetails {
186                local_only: None,
187                igvm_manifest: in_repo_template(
188                    "openhcl-x64-direct-dev.json",
189                    "openhcl-x64-direct-release.json",
190                ),
191                openhcl_kernel_package: OpenhclKernelPackage::Dev,
192                openvmm_hcl_features: base_openvmm_hcl_features(),
193                target: CommonTriple::X86_64_LINUX_MUSL,
194                vtl0_kernel_type: Some(Vtl0KernelType::Example),
195                with_uefi: false,
196                with_interactive,
197                with_sidecar: true,
198                max_trace_level,
199            },
200            Self::X64Cvm => OpenhclIgvmRecipeDetails {
201                local_only: None,
202                igvm_manifest: in_repo_template(
203                    "openhcl-x64-cvm-dev.json",
204                    "openhcl-x64-cvm-release.json",
205                ),
206                openhcl_kernel_package: OpenhclKernelPackage::Cvm,
207                openvmm_hcl_features: base_openvmm_hcl_features(),
208                target: CommonTriple::X86_64_LINUX_MUSL,
209                vtl0_kernel_type: None,
210                with_uefi: true,
211                with_interactive,
212                with_sidecar: false,
213                max_trace_level,
214            },
215            Self::Aarch64 => OpenhclIgvmRecipeDetails {
216                local_only: None,
217                igvm_manifest: in_repo_template(
218                    "openhcl-aarch64-dev.json",
219                    "openhcl-aarch64-release.json",
220                ),
221                openhcl_kernel_package: OpenhclKernelPackage::Main,
222                openvmm_hcl_features: base_openvmm_hcl_features(),
223                target: CommonTriple::AARCH64_LINUX_MUSL,
224                vtl0_kernel_type: None,
225                with_uefi: true,
226                with_interactive: false, // #1234
227                with_sidecar: false,
228                max_trace_level,
229            },
230            Self::Aarch64Devkern => OpenhclIgvmRecipeDetails {
231                local_only: None,
232                igvm_manifest: in_repo_template(
233                    "openhcl-aarch64-dev.json",
234                    "openhcl-aarch64-release.json",
235                ),
236                openhcl_kernel_package: OpenhclKernelPackage::Dev,
237                openvmm_hcl_features: base_openvmm_hcl_features(),
238                target: CommonTriple::AARCH64_LINUX_MUSL,
239                vtl0_kernel_type: None,
240                with_uefi: true,
241                with_interactive: false, // #1234
242                with_sidecar: false,
243                max_trace_level,
244            },
245        }
246    }
247}
248
249flowey_request! {
250    pub struct Request {
251        pub build_profile: OpenvmmHclBuildProfile,
252        pub release_cfg: bool,
253        pub recipe: OpenhclIgvmRecipe,
254        pub custom_target: Option<CommonTriple>,
255
256        pub built_openvmm_hcl: WriteVar<crate::build_openvmm_hcl::OpenvmmHclOutput>,
257        pub built_openhcl_boot: WriteVar<crate::build_openhcl_boot::OpenhclBootOutput>,
258        pub built_openhcl_igvm: WriteVar<crate::run_igvmfilegen::IgvmOutput>,
259        pub built_sidecar: WriteVar<Option<crate::build_sidecar::SidecarOutput>>,
260    }
261}
262
263new_simple_flow_node!(struct Node);
264
265impl SimpleFlowNode for Node {
266    type Request = Request;
267
268    fn imports(ctx: &mut ImportCtx<'_>) {
269        ctx.import::<crate::build_igvmfilegen::Node>();
270        ctx.import::<crate::build_openhcl_boot::Node>();
271        ctx.import::<crate::build_openhcl_initrd::Node>();
272        ctx.import::<crate::build_openvmm_hcl::Node>();
273        ctx.import::<crate::build_sidecar::Node>();
274        ctx.import::<crate::resolve_openhcl_kernel_package::Node>();
275        ctx.import::<crate::resolve_openvmm_deps::Node>();
276        ctx.import::<crate::download_uefi_mu_msvm::Node>();
277        ctx.import::<crate::git_checkout_openvmm_repo::Node>();
278        ctx.import::<crate::run_igvmfilegen::Node>();
279        ctx.import::<crate::run_split_debug_info::Node>();
280    }
281
282    fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
283        let Request {
284            build_profile,
285            release_cfg,
286            recipe,
287            custom_target,
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            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        let OpenhclIgvmRecipeDetailsLocalOnly {
308            openvmm_hcl_no_strip,
309            openhcl_initrd_extra_params,
310            custom_openvmm_hcl,
311            custom_openhcl_boot,
312            custom_kernel,
313            custom_sidecar,
314            custom_extra_rootfs,
315        } = local_only.unwrap_or(OpenhclIgvmRecipeDetailsLocalOnly {
316            openvmm_hcl_no_strip: false,
317            openhcl_initrd_extra_params: None,
318            custom_openvmm_hcl: None,
319            custom_openhcl_boot: None,
320            custom_kernel: None,
321            custom_sidecar: None,
322            custom_extra_rootfs: Vec::new(),
323        });
324
325        let target = custom_target.unwrap_or(target);
326        let arch = CommonArch::from_triple(&target.as_triple())
327            .ok_or_else(|| anyhow::anyhow!("cannot build openHCL from recipe on {target}"))?;
328
329        let openvmm_repo_path = ctx.reqv(crate::git_checkout_openvmm_repo::req::GetRepoDir);
330
331        let kernel_arch = match arch {
332            CommonArch::X86_64 => OpenhclKernelPackageArch::X86_64,
333            CommonArch::Aarch64 => OpenhclKernelPackageArch::Aarch64,
334        };
335
336        let kernel_kind = match openhcl_kernel_package {
337            OpenhclKernelPackage::Main => OpenhclKernelPackageKind::Main,
338            OpenhclKernelPackage::Cvm => OpenhclKernelPackageKind::Cvm,
339            OpenhclKernelPackage::Dev => OpenhclKernelPackageKind::Dev,
340            OpenhclKernelPackage::CvmDev => OpenhclKernelPackageKind::CvmDev,
341        };
342
343        // Get the kernel package root for initrd building (needs metadata)
344        let vtl2_kernel_package_root =
345            ctx.reqv(
346                |v| crate::resolve_openhcl_kernel_package::Request::GetPackageRoot {
347                    kind: kernel_kind,
348                    arch: kernel_arch,
349                    pkg: v,
350                },
351            );
352
353        // Get the modules path from the resolve node
354        let vtl2_kernel_modules =
355            ctx.reqv(
356                |v| crate::resolve_openhcl_kernel_package::Request::GetModules {
357                    kind: kernel_kind,
358                    arch: kernel_arch,
359                    modules: v,
360                },
361            );
362
363        // Get the kernel metadata path from the resolve node
364        let vtl2_kernel_metadata =
365            ctx.reqv(
366                |v| crate::resolve_openhcl_kernel_package::Request::GetMetadata {
367                    kind: kernel_kind,
368                    arch: kernel_arch,
369                    metadata: v,
370                },
371            );
372
373        let uefi_resource = with_uefi.then(|| UefiResource {
374            msvm_fd: ctx.reqv(|v| crate::download_uefi_mu_msvm::Request::GetMsvmFd {
375                arch: match arch {
376                    CommonArch::X86_64 => MuMsvmArch::X86_64,
377                    CommonArch::Aarch64 => MuMsvmArch::Aarch64,
378                },
379                msvm_fd: v,
380            }),
381        });
382
383        let vtl0_kernel_resource = vtl0_kernel_type.map(|typ| {
384            let kernel = if let Vtl0KernelType::LocalOnlyCustom(path) = typ {
385                ReadVar::from_static(path)
386            } else {
387                match typ {
388                    Vtl0KernelType::Example => ctx.reqv(|v| {
389                        crate::resolve_openvmm_deps::Request::GetLinuxTestKernel(
390                            match arch {
391                                CommonArch::X86_64 => OpenvmmDepsArch::X86_64,
392                                CommonArch::Aarch64 => OpenvmmDepsArch::Aarch64,
393                            },
394                            v,
395                        )
396                    }),
397                    Vtl0KernelType::LocalOnlyCustom(_) => unreachable!("special cased above"),
398                }
399            };
400
401            let initrd = ctx.reqv(|v| {
402                crate::resolve_openvmm_deps::Request::GetLinuxTestInitrd(
403                    match arch {
404                        CommonArch::X86_64 => OpenvmmDepsArch::X86_64,
405                        CommonArch::Aarch64 => OpenvmmDepsArch::Aarch64,
406                    },
407                    v,
408                )
409            });
410
411            Vtl0KernelResource { kernel, initrd }
412        });
413
414        // build sidecar
415        let sidecar_bin = if with_sidecar {
416            let sidecar_bin = if let Some(path) = custom_sidecar {
417                ctx.emit_rust_stepv("set custom_sidecar", |_ctx| {
418                    |_rt| {
419                        let fake_dbg_path = std::env::current_dir()?
420                            .join("fake_sidecar.dbg")
421                            .absolute()?;
422                        fs_err::write(&fake_dbg_path, "")?;
423
424                        Ok(crate::build_sidecar::SidecarOutput {
425                            bin: path,
426                            dbg: fake_dbg_path,
427                        })
428                    }
429                })
430            } else {
431                ctx.reqv(|v| crate::build_sidecar::Request {
432                    build_params: crate::build_sidecar::SidecarBuildParams {
433                        arch,
434                        profile: match build_profile {
435                            OpenvmmHclBuildProfile::Debug => {
436                                crate::build_sidecar::SidecarBuildProfile::Debug
437                            }
438                            OpenvmmHclBuildProfile::Release
439                            | OpenvmmHclBuildProfile::OpenvmmHclShip => {
440                                crate::build_sidecar::SidecarBuildProfile::Release
441                            }
442                        },
443                    },
444                    sidecar: v,
445                })
446            };
447            sidecar_bin.write_into(ctx, built_sidecar, Some);
448            Some(sidecar_bin)
449        } else {
450            built_sidecar.write_static(ctx, None);
451            None
452        };
453
454        // build openvmm_hcl bin
455        let openvmm_hcl_bin = ctx.reqv(|v| {
456            crate::build_openvmm_hcl::Request {
457                build_params: crate::build_openvmm_hcl::OpenvmmHclBuildParams {
458                    target: target.clone(),
459                    profile: build_profile,
460                    features: openvmm_hcl_features,
461                    // manually strip later, depending on provided igvm flags
462                    no_split_dbg_info: true,
463                    max_trace_level,
464                },
465                openvmm_hcl_output: v,
466            }
467        });
468
469        // build igvmfilegen (always built for host arch)
470        let igvmfilegen_arch = match ctx.arch() {
471            FlowArch::X86_64 => CommonArch::X86_64,
472            FlowArch::Aarch64 => CommonArch::Aarch64,
473            arch => anyhow::bail!("unsupported arch {arch}"),
474        };
475
476        let igvmfilegen = ctx.reqv(|v| crate::build_igvmfilegen::Request {
477            build_params: crate::build_igvmfilegen::IgvmfilegenBuildParams {
478                target: CommonTriple::Common {
479                    arch: igvmfilegen_arch,
480                    platform: CommonPlatform::LinuxGnu,
481                },
482                profile: BuildProfile::Light,
483            },
484            igvmfilegen: v,
485        });
486
487        // build openhcl_boot
488        let openhcl_boot_bin = if let Some(path) = custom_openhcl_boot {
489            ctx.emit_rust_stepv("set custom_openhcl_boot", |_ctx| {
490                |_rt| {
491                    let fake_dbg_path = std::env::current_dir()?.join("fake.dbg").absolute()?;
492                    fs_err::write(&fake_dbg_path, "")?;
493
494                    Ok(crate::build_openhcl_boot::OpenhclBootOutput {
495                        bin: path,
496                        dbg: fake_dbg_path,
497                    })
498                }
499            })
500        } else {
501            ctx.reqv(|v| crate::build_openhcl_boot::Request {
502                build_params: crate::build_openhcl_boot::OpenhclBootBuildParams {
503                    arch,
504                    profile: match build_profile {
505                        OpenvmmHclBuildProfile::Debug => {
506                            crate::build_openhcl_boot::OpenhclBootBuildProfile::Debug
507                        }
508                        OpenvmmHclBuildProfile::Release
509                        | OpenvmmHclBuildProfile::OpenvmmHclShip => {
510                            crate::build_openhcl_boot::OpenhclBootBuildProfile::Release
511                        }
512                    },
513                },
514                openhcl_boot: v,
515            })
516        };
517        openhcl_boot_bin.write_into(ctx, built_openhcl_boot, |x| x);
518
519        let use_stripped_openvmm_hcl = {
520            if custom_openvmm_hcl.is_some() {
521                // trust the user knows what they are doing if they specified a
522                // custom bin
523                false
524            } else {
525                !openvmm_hcl_no_strip
526            }
527        };
528
529        // use the stripped or unstripped openvmm_hcl as requested
530        let openvmm_hcl_bin = if use_stripped_openvmm_hcl {
531            let (read, write) = ctx.new_var();
532            let (read_dbg, write_dbg) = ctx.new_var();
533
534            let in_bin = openvmm_hcl_bin.map(ctx, |o| o.bin);
535            ctx.req(crate::run_split_debug_info::Request {
536                arch,
537                in_bin,
538                out_bin: write,
539                out_dbg_info: write_dbg,
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: kernel_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}