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, ReadVar<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, ReadVar<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 local_paths.contains_key(&arch) {
49                        anyhow::bail!("Duplicate LocalPath requests for {:?}", arch,);
50                    }
51                    local_paths.insert(arch, path);
52                }
53                Request::GetMsvmFd { arch, msvm_fd } => reqs.entry(arch).or_default().push(msvm_fd),
54            }
55        }
56
57        if version.is_some() && !local_paths.is_empty() {
58            anyhow::bail!("Cannot specify both Version and LocalPath requests");
59        }
60
61        if version.is_none() && local_paths.is_empty() {
62            anyhow::bail!("Must specify a Version or LocalPath request");
63        }
64
65        // -- end of req processing -- //
66
67        if reqs.is_empty() {
68            return Ok(());
69        }
70
71        if !local_paths.is_empty() {
72            ctx.emit_rust_step("use local mu_msvm UEFI", |ctx| {
73                let reqs = reqs.claim(ctx);
74                let local_paths: BTreeMap<_, _> = local_paths
75                    .into_iter()
76                    .map(|(arch, var)| (arch, var.claim(ctx)))
77                    .collect();
78                move |rt| {
79                    for (arch, out_vars) in reqs {
80                        let msvm_fd_var = local_paths.get(&arch).ok_or_else(|| {
81                            anyhow::anyhow!("No local path specified for architecture {:?}", arch)
82                        })?;
83                        let msvm_fd = rt.read(msvm_fd_var.clone());
84                        for var in out_vars {
85                            log::info!(
86                                "using local uefi for {} at path {:?}",
87                                match arch {
88                                    MuMsvmArch::X86_64 => "x64",
89                                    MuMsvmArch::Aarch64 => "aarch64",
90                                },
91                                msvm_fd
92                            );
93                            rt.write(var, &msvm_fd);
94                        }
95                    }
96                    Ok(())
97                }
98            });
99
100            return Ok(());
101        }
102
103        let version = version.expect("local paths handled above");
104        let extract_zip_deps = flowey_lib_common::_util::extract::extract_zip_if_new_deps(ctx);
105
106        for (arch, out_vars) in reqs {
107            let file_name = match arch {
108                MuMsvmArch::X86_64 => "RELEASE-X64-artifacts.zip",
109                MuMsvmArch::Aarch64 => "RELEASE-AARCH64-artifacts.zip",
110            };
111
112            let mu_msvm_zip = ctx.reqv(|v| flowey_lib_common::download_gh_release::Request {
113                repo_owner: "microsoft".into(),
114                repo_name: "mu_msvm".into(),
115                needs_auth: false,
116                tag: format!("v{version}"),
117                file_name: file_name.into(),
118                path: v,
119            });
120
121            let zip_file_version = format!("{version}-{file_name}");
122
123            ctx.emit_rust_step(
124                {
125                    format!(
126                        "unpack mu_msvm package ({})",
127                        match arch {
128                            MuMsvmArch::X86_64 => "x64",
129                            MuMsvmArch::Aarch64 => "aarch64",
130                        },
131                    )
132                },
133                |ctx| {
134                    let extract_zip_deps = extract_zip_deps.clone().claim(ctx);
135                    let out_vars = out_vars.claim(ctx);
136                    let mu_msvm_zip = mu_msvm_zip.claim(ctx);
137                    move |rt| {
138                        let mu_msvm_zip = rt.read(mu_msvm_zip);
139
140                        let extract_dir = flowey_lib_common::_util::extract::extract_zip_if_new(
141                            rt,
142                            extract_zip_deps,
143                            &mu_msvm_zip,
144                            &zip_file_version,
145                        )?;
146
147                        let msvm_fd = extract_dir.join("FV/MSVM.fd");
148
149                        for var in out_vars {
150                            rt.write(var, &msvm_fd)
151                        }
152
153                        Ok(())
154                    }
155                },
156            );
157        }
158
159        Ok(())
160    }
161}