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