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