flowey_lib_hvlite/
download_uefi_mu_msvm.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Download pre-built mu_msvm package from its GitHub Release.
5
6use flowey::node::prelude::*;
7use std::collections::BTreeMap;
8
9#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
10pub enum MuMsvmArch {
11    X86_64,
12    Aarch64,
13}
14
15flowey_request! {
16    pub enum Request {
17        /// Specify version of mu_msvm to use
18        Version(String),
19        /// Use a local MSVM.fd path for a specific architecture
20        LocalPath(MuMsvmArch, PathBuf),
21        /// Download the mu_msvm package for the given arch
22        GetMsvmFd {
23            arch: MuMsvmArch,
24            msvm_fd: WriteVar<PathBuf>
25        }
26    }
27}
28
29new_flow_node!(struct Node);
30
31impl FlowNode for Node {
32    type Request = Request;
33
34    fn imports(ctx: &mut ImportCtx<'_>) {
35        ctx.import::<flowey_lib_common::install_dist_pkg::Node>();
36        ctx.import::<flowey_lib_common::download_gh_release::Node>();
37    }
38
39    fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
40        let mut version = None;
41        let mut local_paths: BTreeMap<MuMsvmArch, PathBuf> = BTreeMap::new();
42        let mut reqs: BTreeMap<MuMsvmArch, Vec<WriteVar<PathBuf>>> = BTreeMap::new();
43
44        for req in requests {
45            match req {
46                Request::Version(v) => same_across_all_reqs("Version", &mut version, v)?,
47                Request::LocalPath(arch, path) => {
48                    if let Some(existing) = local_paths.get(&arch) {
49                        if existing != &path {
50                            anyhow::bail!(
51                                "Conflicting LocalPath requests for {:?}: {:?} vs {:?}",
52                                arch,
53                                existing,
54                                path
55                            );
56                        }
57                    } else {
58                        local_paths.insert(arch, path);
59                    }
60                }
61                Request::GetMsvmFd { arch, msvm_fd } => reqs.entry(arch).or_default().push(msvm_fd),
62            }
63        }
64
65        if version.is_some() && !local_paths.is_empty() {
66            anyhow::bail!("Cannot specify both Version and LocalPath requests");
67        }
68
69        if version.is_none() && local_paths.is_empty() {
70            anyhow::bail!("Must specify a Version or LocalPath request");
71        }
72
73        // -- end of req processing -- //
74
75        if reqs.is_empty() {
76            return Ok(());
77        }
78
79        if !local_paths.is_empty() {
80            ctx.emit_rust_step("use local mu_msvm UEFI", |ctx| {
81                let reqs = reqs.claim(ctx);
82                let local_paths = local_paths.clone();
83                move |rt| {
84                    for (arch, out_vars) in reqs {
85                        let msvm_fd = local_paths.get(&arch).ok_or_else(|| {
86                            anyhow::anyhow!("No local path specified for architecture {:?}", arch)
87                        })?;
88                        for var in out_vars {
89                            log::info!(
90                                "using local uefi for {} at path {:?}",
91                                match arch {
92                                    MuMsvmArch::X86_64 => "x64",
93                                    MuMsvmArch::Aarch64 => "aarch64",
94                                },
95                                msvm_fd
96                            );
97                            rt.write(var, msvm_fd);
98                        }
99                    }
100                    Ok(())
101                }
102            });
103
104            return Ok(());
105        }
106
107        let version = version.expect("local paths handled above");
108        let extract_zip_deps = flowey_lib_common::_util::extract::extract_zip_if_new_deps(ctx);
109
110        for (arch, out_vars) in reqs {
111            let file_name = match arch {
112                MuMsvmArch::X86_64 => "RELEASE-X64-artifacts.zip",
113                MuMsvmArch::Aarch64 => "RELEASE-AARCH64-artifacts.zip",
114            };
115
116            let mu_msvm_zip = ctx.reqv(|v| flowey_lib_common::download_gh_release::Request {
117                repo_owner: "microsoft".into(),
118                repo_name: "mu_msvm".into(),
119                needs_auth: false,
120                tag: format!("v{version}"),
121                file_name: file_name.into(),
122                path: v,
123            });
124
125            let zip_file_version = format!("{version}-{file_name}");
126
127            ctx.emit_rust_step(
128                {
129                    format!(
130                        "unpack mu_msvm package ({})",
131                        match arch {
132                            MuMsvmArch::X86_64 => "x64",
133                            MuMsvmArch::Aarch64 => "aarch64",
134                        },
135                    )
136                },
137                |ctx| {
138                    let extract_zip_deps = extract_zip_deps.clone().claim(ctx);
139                    let out_vars = out_vars.claim(ctx);
140                    let mu_msvm_zip = mu_msvm_zip.claim(ctx);
141                    move |rt| {
142                        let mu_msvm_zip = rt.read(mu_msvm_zip);
143
144                        let extract_dir = flowey_lib_common::_util::extract::extract_zip_if_new(
145                            rt,
146                            extract_zip_deps,
147                            &mu_msvm_zip,
148                            &zip_file_version,
149                        )?;
150
151                        let msvm_fd = extract_dir.join("FV/MSVM.fd");
152
153                        for var in out_vars {
154                            rt.write(var, &msvm_fd)
155                        }
156
157                        Ok(())
158                    }
159                },
160            );
161        }
162
163        Ok(())
164    }
165}