Skip to main content

flowey_lib_hvlite/
build_openvmm_hcl.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Build `openvmm_hcl` binaries (NOT IGVM FILES!)
5
6use crate::common::CommonArch;
7use crate::common::CommonTriple;
8use flowey::node::prelude::*;
9use flowey_lib_common::_util::group_by;
10use flowey_lib_common::run_cargo_build::CargoFeatureSet;
11use std::collections::BTreeSet;
12
13#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
14pub enum OpenvmmHclFeature {
15    Gdb,
16    MiSecure,
17    Tpm,
18    ProductPolicy,
19    LocalOnlyCustom(String),
20}
21
22#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
23pub enum OpenvmmHclBuildProfile {
24    Debug,
25    Release,
26    OpenvmmHclShip,
27}
28
29#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
30pub enum MaxTraceLevel {
31    Trace,
32    Debug,
33    Info,
34    Warn,
35    Error,
36    Off,
37}
38
39impl MaxTraceLevel {
40    pub fn features(&self) -> Vec<String> {
41        let name = match self {
42            MaxTraceLevel::Trace => return Vec::new(),
43            MaxTraceLevel::Debug => "debug",
44            MaxTraceLevel::Info => "info",
45            MaxTraceLevel::Warn => "warn",
46            MaxTraceLevel::Error => "error",
47            MaxTraceLevel::Off => "off",
48        };
49        // Add both release and non-release variants of the feature
50        // regardless of the profile to work around `tracing` bugs.
51        vec![
52            format!("tracing/max_level_{}", name),
53            format!("tracing/release_max_level_{}", name),
54        ]
55    }
56}
57
58#[derive(Serialize, Deserialize)]
59pub struct OpenvmmHclOutput {
60    #[serde(rename = "openvmm_hcl")]
61    pub bin: PathBuf,
62    #[serde(rename = "openvmm_hcl.dbg")]
63    pub dbg: Option<PathBuf>,
64}
65
66impl Artifact for OpenvmmHclOutput {}
67
68#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
69pub struct OpenvmmHclBuildParams {
70    pub target: CommonTriple,
71    pub profile: OpenvmmHclBuildProfile,
72    pub features: BTreeSet<OpenvmmHclFeature>,
73    pub no_split_dbg_info: bool,
74    pub max_trace_level: MaxTraceLevel,
75}
76
77flowey_request! {
78    pub struct Request {
79        pub build_params: OpenvmmHclBuildParams,
80        pub openvmm_hcl_output: WriteVar<OpenvmmHclOutput>,
81    }
82}
83
84new_flow_node!(struct Node);
85
86impl FlowNode for Node {
87    type Request = Request;
88
89    fn imports(ctx: &mut ImportCtx<'_>) {
90        ctx.import::<crate::run_cargo_build::Node>();
91        ctx.import::<crate::init_openvmm_magicpath_openhcl_sysroot::Node>();
92    }
93
94    fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
95        let requests = group_by(
96            requests
97                .into_iter()
98                .map(|r| (r.build_params, r.openvmm_hcl_output)),
99        );
100
101        // -- end of req processing -- //
102
103        for (
104            OpenvmmHclBuildParams {
105                target,
106                profile,
107                features,
108                no_split_dbg_info,
109                max_trace_level,
110            },
111            outvars,
112        ) in requests
113        {
114            let mut pre_build_deps = Vec::new();
115
116            let target = target.as_triple();
117
118            let arch = CommonArch::from_triple(&target)
119                .with_context(|| format!("cannot build openvmm_hcl on {}", target.architecture))?;
120
121            let openhcl_deps_path = ctx
122                .reqv(|v| crate::init_openvmm_magicpath_openhcl_sysroot::Request { arch, path: v });
123
124            // required due to ambient dependencies in openvmm_hcl's source code
125            pre_build_deps.push(openhcl_deps_path.into_side_effect());
126
127            let mut features = features
128                .into_iter()
129                .map(|f| match f {
130                    OpenvmmHclFeature::Gdb => "gdb".into(),
131                    OpenvmmHclFeature::MiSecure => "mi-secure".into(),
132                    OpenvmmHclFeature::Tpm => "tpm".into(),
133                    OpenvmmHclFeature::ProductPolicy => "product_policy".into(),
134                    OpenvmmHclFeature::LocalOnlyCustom(s) => s,
135                })
136                .collect::<Vec<String>>();
137
138            features.extend(max_trace_level.features());
139
140            // Forbid cc-rs and CMake from compiling anything for the openvmm_hcl build.
141            // Every C library it links comes prebuilt out of the openvmm-deps
142            // sdk sysroot, so a build script reaching for either is a bug.
143            let extra_env = Some(ReadVar::from_static(crate::common::openhcl_build_env()));
144
145            let output = ctx.reqv(|v| crate::run_cargo_build::Request {
146                crate_name: "openvmm_hcl".into(),
147                out_name: "openvmm_hcl".into(),
148                crate_type: flowey_lib_common::run_cargo_build::CargoCrateType::Bin,
149                profile: match profile {
150                    OpenvmmHclBuildProfile::Debug => crate::run_cargo_build::BuildProfile::Debug,
151                    OpenvmmHclBuildProfile::Release => {
152                        crate::run_cargo_build::BuildProfile::Release
153                    }
154                    OpenvmmHclBuildProfile::OpenvmmHclShip => {
155                        crate::run_cargo_build::BuildProfile::UnderhillShip
156                    }
157                },
158                features: CargoFeatureSet::Specific(features),
159                target,
160                no_split_dbg_info,
161                extra_env,
162                pre_build_deps,
163                output: v,
164            });
165
166            ctx.emit_minor_rust_step("report built openvmm_hcl", |ctx| {
167                let outvars = outvars.claim(ctx);
168                let output = output.claim(ctx);
169                move |rt| {
170                    let output = match rt.read(output) {
171                        crate::run_cargo_build::CargoBuildOutput::ElfBin { bin, dbg } => {
172                            OpenvmmHclOutput { bin, dbg }
173                        }
174                        _ => unreachable!(),
175                    };
176
177                    rt.write_all(outvars, &output);
178                }
179            });
180        }
181
182        Ok(())
183    }
184}