flowey_lib_hvlite/
build_openvmm.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Build `openvmm` binaries
5
6use crate::download_lxutil::LxutilArch;
7use crate::run_cargo_build::common::CommonProfile;
8use crate::run_cargo_build::common::CommonTriple;
9use flowey::node::prelude::*;
10use std::collections::BTreeSet;
11
12#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
13pub enum OpenvmmFeature {
14    Gdb,
15    Tpm,
16    UnstableWhp,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
20pub struct OpenvmmBuildParams {
21    pub profile: CommonProfile,
22    pub target: CommonTriple,
23    pub features: BTreeSet<OpenvmmFeature>,
24}
25
26#[derive(Serialize, Deserialize)]
27#[serde(untagged)]
28pub enum OpenvmmOutput {
29    WindowsBin {
30        #[serde(rename = "openvmm.exe")]
31        exe: PathBuf,
32        #[serde(rename = "openvmm.pdb")]
33        pdb: PathBuf,
34    },
35    LinuxBin {
36        #[serde(rename = "openvmm")]
37        bin: PathBuf,
38        #[serde(rename = "openvmm.dbg")]
39        dbg: PathBuf,
40    },
41}
42
43impl Artifact for OpenvmmOutput {}
44
45flowey_request! {
46    pub struct Request {
47        pub params: OpenvmmBuildParams,
48        pub openvmm: WriteVar<OpenvmmOutput>,
49    }
50}
51
52new_flow_node!(struct Node);
53
54impl FlowNode for Node {
55    type Request = Request;
56
57    fn imports(ctx: &mut ImportCtx<'_>) {
58        ctx.import::<crate::init_openvmm_magicpath_lxutil::Node>();
59        ctx.import::<crate::run_cargo_build::Node>();
60        ctx.import::<flowey_lib_common::install_dist_pkg::Node>();
61    }
62
63    fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
64        let installed_apt_deps =
65            ctx.reqv(|v| flowey_lib_common::install_dist_pkg::Request::Install {
66                package_names: vec!["libssl-dev".into(), "build-essential".into()],
67                done: v,
68            });
69
70        for Request {
71            params:
72                OpenvmmBuildParams {
73                    profile,
74                    target,
75                    features,
76                },
77            openvmm: openvmm_bin,
78        } in requests
79        {
80            let mut pre_build_deps = vec![installed_apt_deps.clone()];
81
82            let lxutil_arch = match target.as_triple().architecture {
83                target_lexicon::Architecture::Aarch64(_) => LxutilArch::Aarch64,
84                target_lexicon::Architecture::X86_64 => LxutilArch::X86_64,
85                arch => anyhow::bail!("no lxutil package for specified arch: {:?}", arch),
86            };
87
88            // NOTE: OpenVMM's code is currently hard-coded to assume lxutil
89            // package is in a particular place
90            pre_build_deps.push(ctx.reqv(|v| crate::init_openvmm_magicpath_lxutil::Request {
91                arch: lxutil_arch,
92                done: v,
93            }));
94
95            // TODO: also need to take into account any default features in
96            // openvmm's Cargo.toml?
97            //
98            // maybe we can do something clever and parse the openvmm Cargo.toml
99            // file to discover these defaults?
100            for feat in &features {
101                match feat {
102                    OpenvmmFeature::Gdb => {}
103                    OpenvmmFeature::Tpm => pre_build_deps.push(ctx.reqv(|v| {
104                        flowey_lib_common::install_dist_pkg::Request::Install {
105                            package_names: vec!["build-essential".into()],
106                            done: v,
107                        }
108                    })),
109                    OpenvmmFeature::UnstableWhp => {}
110                }
111            }
112
113            let output = ctx.reqv(|v| crate::run_cargo_build::Request {
114                crate_name: "openvmm".into(),
115                out_name: "openvmm".into(),
116                crate_type: flowey_lib_common::run_cargo_build::CargoCrateType::Bin,
117                profile: profile.into(),
118                features: features
119                    .into_iter()
120                    .map(|f| {
121                        match f {
122                            OpenvmmFeature::Gdb => "gdb",
123                            OpenvmmFeature::Tpm => "tpm",
124                            OpenvmmFeature::UnstableWhp => "unstable_whp",
125                        }
126                        .into()
127                    })
128                    .collect(),
129                target: target.as_triple(),
130                no_split_dbg_info: false,
131                extra_env: None,
132                pre_build_deps,
133                output: v,
134            });
135
136            ctx.emit_minor_rust_step("report built openvmm", |ctx| {
137                let openvmm_bin = openvmm_bin.claim(ctx);
138                let output = output.claim(ctx);
139                move |rt| {
140                    let output = match rt.read(output) {
141                        crate::run_cargo_build::CargoBuildOutput::WindowsBin { exe, pdb } => {
142                            OpenvmmOutput::WindowsBin { exe, pdb }
143                        }
144                        crate::run_cargo_build::CargoBuildOutput::ElfBin { bin, dbg } => {
145                            OpenvmmOutput::LinuxBin {
146                                bin,
147                                dbg: dbg.unwrap(),
148                            }
149                        }
150                        _ => unreachable!(),
151                    };
152
153                    rt.write(openvmm_bin, &output);
154                }
155            });
156        }
157
158        Ok(())
159    }
160}