Skip to main content

flowey_lib_hvlite/
build_openhcl_boot.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Build `openhcl_boot` binaries
5
6use crate::common::CommonArch;
7use crate::run_cargo_build::BuildProfile;
8use flowey::node::prelude::*;
9use flowey_lib_common::run_cargo_build::CargoFeatureSet;
10use std::collections::BTreeMap;
11
12#[derive(Serialize, Deserialize)]
13pub struct OpenhclBootOutput {
14    #[serde(rename = "openhcl_boot")]
15    pub bin: PathBuf,
16    #[serde(rename = "openhcl_boot.dbg")]
17    pub dbg: PathBuf,
18}
19
20#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
21pub enum OpenhclBootBuildProfile {
22    Debug,
23    Release,
24}
25
26#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
27pub struct OpenhclBootBuildParams {
28    pub arch: CommonArch,
29    pub profile: OpenhclBootBuildProfile,
30}
31
32flowey_request! {
33    pub struct Request {
34        pub build_params: OpenhclBootBuildParams,
35        pub openhcl_boot: WriteVar<OpenhclBootOutput>,
36    }
37}
38
39new_flow_node!(struct Node);
40
41impl FlowNode for Node {
42    type Request = Request;
43
44    fn imports(ctx: &mut ImportCtx<'_>) {
45        ctx.import::<crate::run_cargo_build::Node>();
46    }
47
48    fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
49        // de-dupe incoming requests
50        let requests = requests
51            .into_iter()
52            .fold(BTreeMap::<_, Vec<_>>::new(), |mut m, r| {
53                let Request {
54                    build_params,
55                    openhcl_boot,
56                } = r;
57                m.entry(build_params).or_default().push(openhcl_boot);
58                m
59            });
60
61        for (OpenhclBootBuildParams { arch, profile }, openhcl_boot) in requests {
62            let target = target_lexicon::Triple {
63                architecture: arch.as_arch(),
64                operating_system: target_lexicon::OperatingSystem::None_,
65                environment: target_lexicon::Environment::Unknown,
66                vendor: target_lexicon::Vendor::Custom(target_lexicon::CustomVendor::Static(
67                    "minimal_rt",
68                )),
69                binary_format: target_lexicon::BinaryFormat::Unknown,
70            };
71
72            // We use special profiles for boot, convert from the standard ones:
73            let profile = match profile {
74                OpenhclBootBuildProfile::Debug => BuildProfile::BootDev,
75                OpenhclBootBuildProfile::Release => BuildProfile::BootRelease,
76            };
77
78            // Enable cvm_boot_log in debug builds to include TDX/SNP
79            // serial logging support.
80            let features = if matches!(profile, BuildProfile::BootDev) {
81                CargoFeatureSet::Specific(vec!["cvm_boot_log".into()])
82            } else {
83                CargoFeatureSet::None
84            };
85
86            let output = ctx.reqv(|v| crate::run_cargo_build::Request {
87                crate_name: "openhcl_boot".into(),
88                out_name: "openhcl_boot".into(),
89                crate_type: flowey_lib_common::run_cargo_build::CargoCrateType::Bin,
90                profile,
91                features,
92                target,
93                no_split_dbg_info: false,
94                extra_env: Some(ReadVar::from_static(
95                    [
96                        ("RUSTC_BOOTSTRAP".to_string(), "1".to_string()),
97                        ("CC_FORCE_DISABLE".to_string(), "1".to_string()),
98                        (
99                            "CMAKE".to_string(),
100                            "cmake-is-forbidden-during-openvmm-hcl-build".to_string(),
101                        ),
102                    ]
103                    .into_iter()
104                    .collect(),
105                )),
106                pre_build_deps: Vec::new(),
107                output: v,
108            });
109
110            ctx.emit_minor_rust_step("report built openhcl_boot", |ctx| {
111                let openhcl_boot = openhcl_boot.claim(ctx);
112                let output = output.claim(ctx);
113                move |rt| {
114                    let output = match rt.read(output) {
115                        crate::run_cargo_build::CargoBuildOutput::ElfBin { bin, dbg } => {
116                            OpenhclBootOutput {
117                                bin,
118                                dbg: dbg.unwrap(),
119                            }
120                        }
121                        _ => unreachable!(),
122                    };
123
124                    for var in openhcl_boot {
125                        rt.write(var, &output);
126                    }
127                }
128            });
129        }
130
131        Ok(())
132    }
133}