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