Skip to main content

flowey_lib_hvlite/
build_snp_linux_direct_igvm.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Build the x86_64 SNP Linux-direct test IGVM.
5
6use crate::build_igvmfilegen::IgvmfilegenBuildParams;
7use crate::build_igvmfilegen::IgvmfilegenOutput;
8use crate::common::CommonArch;
9use crate::common::CommonPlatform;
10use crate::common::CommonProfile;
11use crate::common::CommonTriple;
12use crate::resolve_openvmm_test_linux_kernel::OpenvmmTestKernelFile;
13use crate::resolve_openvmm_test_linux_kernel::SNP_GUEST_LINUX_TEST_KERNEL_VERSION;
14use crate::run_cargo_build::BuildProfile;
15use anyhow::Context;
16use flowey::node::prelude::*;
17use igvmfilegen_config::ResourceType;
18use std::collections::BTreeMap;
19
20#[derive(Serialize, Deserialize)]
21pub struct SnpLinuxDirectIgvmOutput {
22    #[serde(rename = "snp-linux-direct.bin")]
23    pub igvm_bin: PathBuf,
24    #[serde(
25        rename = "snp-linux-direct.bin.map",
26        skip_serializing_if = "Option::is_none"
27    )]
28    pub igvm_map: Option<PathBuf>,
29}
30
31impl Artifact for SnpLinuxDirectIgvmOutput {}
32
33flowey_request! {
34    pub struct Request {
35        pub snp_linux_direct_igvm: WriteVar<SnpLinuxDirectIgvmOutput>,
36    }
37}
38
39new_simple_flow_node!(struct Node);
40
41impl SimpleFlowNode for Node {
42    type Request = Request;
43
44    fn imports(ctx: &mut ImportCtx<'_>) {
45        ctx.import::<crate::build_igvmfilegen::Node>();
46        ctx.import::<crate::build_pipette::Node>();
47        ctx.import::<crate::build_snp_bootshim::Node>();
48        ctx.import::<crate::git_checkout_openvmm_repo::Node>();
49        ctx.import::<crate::resolve_openvmm_test_linux_kernel::Node>();
50        ctx.import::<crate::resolve_openvmm_test_initrd::Node>();
51        ctx.import::<crate::run_igvmfilegen::Node>();
52    }
53
54    fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
55        if !matches!(ctx.platform(), FlowPlatform::Linux(_)) {
56            anyhow::bail!("SNP Linux-direct IGVM builds require a Linux host");
57        }
58
59        let host_arch: CommonArch = ctx.arch().try_into()?;
60        let igvmfilegen = ctx.reqv(|v| crate::build_igvmfilegen::Request {
61            build_params: IgvmfilegenBuildParams {
62                target: CommonTriple::Common {
63                    arch: host_arch,
64                    platform: CommonPlatform::LinuxGnu,
65                },
66                profile: BuildProfile::Light,
67            },
68            igvmfilegen: v,
69        });
70        let igvmfilegen = igvmfilegen.map(ctx, |o| match o {
71            IgvmfilegenOutput::LinuxBin { bin, .. } => bin,
72            IgvmfilegenOutput::WindowsBin { .. } => unreachable!("Linux host build"),
73        });
74        let bootshim = ctx.reqv(|v| crate::build_snp_bootshim::Request { snp_bootshim: v });
75        let kernel = ctx.reqv(|v| {
76            crate::resolve_openvmm_test_linux_kernel::Request::Get(
77                OpenvmmTestKernelFile::BzImage,
78                CommonArch::X86_64,
79                SNP_GUEST_LINUX_TEST_KERNEL_VERSION,
80                v,
81            )
82        });
83        let initrd =
84            ctx.reqv(|v| crate::resolve_openvmm_test_initrd::Request::Get(CommonArch::X86_64, v));
85        let pipette = ctx.reqv(|v| crate::build_pipette::Request {
86            target: CommonTriple::X86_64_LINUX_MUSL,
87            profile: CommonProfile::Release,
88            pipette: v,
89        });
90        let initrd = ctx.emit_rust_stepv("embed pipette in SNP test initrd", |ctx| {
91            claim_vars!(ctx, (initrd, pipette));
92            move |rt| {
93                let initrd = rt.read(initrd);
94                let pipette = match rt.read(pipette) {
95                    crate::build_pipette::PipetteOutput::LinuxBin { bin, .. } => bin,
96                    crate::build_pipette::PipetteOutput::WindowsBin { .. } => {
97                        anyhow::bail!("SNP guest requires a Linux pipette")
98                    }
99                };
100                let compressed = initrd_cpio::inject_into_initrd(
101                    &std::fs::read(&initrd).context("reading SNP test initrd")?,
102                    "pipette",
103                    &std::fs::read(&pipette).context("reading Linux pipette")?,
104                    0o100755,
105                )
106                .context("embedding pipette in SNP test initrd")?;
107                let path = rt.sh.current_dir().join("snp-linux-direct-initrd.cpio.gz");
108                std::fs::write(&path, compressed).context("writing SNP test initrd")?;
109                Ok(path)
110            }
111        });
112        let repo = ctx.reqv(crate::git_checkout_openvmm_repo::req::GetRepoDir);
113        let manifest = repo.map(ctx, |p| {
114            p.join("vm/loader/manifests/snp-linux-direct-pipette.json")
115        });
116
117        let resources = ctx.emit_minor_rust_stepv("enumerate SNP IGVM resources", |ctx| {
118            claim_vars!(ctx, (kernel, initrd, bootshim));
119            |rt| {
120                BTreeMap::from([
121                    (ResourceType::LinuxKernel, rt.read(kernel)),
122                    (ResourceType::LinuxInitrd, rt.read(initrd)),
123                    (ResourceType::SnpBootshim, rt.read(bootshim).bin),
124                ])
125            }
126        });
127        let igvm = ctx.reqv(|v| crate::run_igvmfilegen::Request {
128            igvmfilegen,
129            manifest,
130            resources,
131            disable_secure_avic: false,
132            confidential_debug: false,
133            add_temp_snp_id_block: false,
134            igvm: v,
135        });
136        igvm.write_into_with(ctx, request.snp_linux_direct_igvm, |o| {
137            SnpLinuxDirectIgvmOutput {
138                igvm_bin: o.igvm_bin,
139                igvm_map: o.igvm_map,
140            }
141        });
142
143        Ok(())
144    }
145}