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