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