xtask/tasks/guest_test/uefi/
mod.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use crate::Xtask;
5use crate::shell::XtaskShell;
6use clap::Parser;
7use std::path::Path;
8use std::path::PathBuf;
9
10mod gpt_efi_disk;
11
12/// Build a UEFI test image.
13#[derive(Parser)]
14pub struct Uefi {
15    // Output disk image. If left blank, outputs disk at `<bootx64/bootaa64>.img`
16    // if only one EFI boot file is provided.
17    //
18    // Extension determines disk type.
19    //
20    // Only `.img` disk image files currently supported.
21    #[clap(long)]
22    output: Option<PathBuf>,
23
24    /// File to set as `bootx64.efi`. Builds `guest_test_uefi` for x64 if no file is provided (default).
25    #[clap(long)]
26    #[expect(clippy::option_option)]
27    bootx64: Option<Option<PathBuf>>,
28
29    /// File to set as `bootaa64.efi`. Builds `guest_test_uefi` for ARM64 if no file is provided.
30    #[clap(long)]
31    #[expect(clippy::option_option)]
32    bootaa64: Option<Option<PathBuf>>,
33}
34
35impl Xtask for Uefi {
36    fn run(self, _ctx: crate::XtaskCtx) -> anyhow::Result<()> {
37        let mut files = Vec::new();
38
39        // Default case: build x64
40        let bootx64 = if self.bootx64.is_none() && self.bootaa64.is_none() {
41            Some(None)
42        } else {
43            self.bootx64
44        };
45
46        if let Some(bootx64) = bootx64.as_ref() {
47            if let Some(bootx64) = bootx64 {
48                files.push((Path::new("efi/boot/bootx64.efi"), bootx64.as_path()));
49            } else {
50                let sh = XtaskShell::new()?;
51                sh.cmd("cargo")
52                    .args([
53                        "build",
54                        "-p",
55                        "guest_test_uefi",
56                        "--target",
57                        "x86_64-unknown-uefi",
58                    ])
59                    .run()?;
60
61                files.push((
62                    Path::new("efi/boot/bootx64.efi"),
63                    Path::new("./target/x86_64-unknown-uefi/debug/guest_test_uefi.efi"),
64                ));
65            }
66        }
67
68        if let Some(bootaa64) = self.bootaa64.as_ref() {
69            if let Some(bootaa64) = bootaa64 {
70                files.push((Path::new("efi/boot/bootaa64.efi"), bootaa64.as_path()))
71            } else {
72                let sh = XtaskShell::new()?;
73                sh.cmd("cargo")
74                    .args([
75                        "build",
76                        "-p",
77                        "guest_test_uefi",
78                        "--target",
79                        "aarch64-unknown-uefi",
80                    ])
81                    .run()?;
82
83                files.push((
84                    Path::new("efi/boot/bootaa64.efi"),
85                    Path::new("./target/aarch64-unknown-uefi/debug/guest_test_uefi.efi"),
86                ));
87            }
88        }
89
90        let out_img = match self.output {
91            Some(path) => path,
92            None => {
93                if files.len() != 1 {
94                    anyhow::bail!(
95                        "Multiple EFI files specified. Please provide an explicit output path."
96                    )
97                }
98                files[0].1.with_extension("img")
99            }
100        };
101
102        gpt_efi_disk::create_gpt_efi_disk(&out_img, &files)?;
103
104        Ok(())
105    }
106}