Skip to main content

flowey_lib_hvlite/
build_openhcl_igvm_from_recipe.rs

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