Skip to content

Commit 1b22c9c

Browse files
Merge pull request #1454 from nicholasbishop/bishop-use-ovmf-prebuilt-api
Use ovmf-prebuilt
2 parents 92275d1 + 98d1ed2 commit 1b22c9c

File tree

4 files changed

+75
-176
lines changed

4 files changed

+75
-176
lines changed

Cargo.lock

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

xtask/Cargo.toml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,14 @@ fatfs = { version = "0.3.6", default-features = false, features = ["alloc", "std
1212
fs-err = "3.0.0"
1313
heck = "0.5.0"
1414
itertools = "0.13.0"
15-
lzma-rs = "0.3.0"
15+
log.workspace = true
1616
mbrman = "0.5.1"
1717
nix = { version = "0.29.0", default-features = false, features = ["fs"] }
18-
os_info = { version = "3.6.0", default-features = false }
18+
ovmf-prebuilt = "0.2.0"
1919
proc-macro2 = { version = "1.0.46", features = ["span-locations"] }
2020
quote = "1.0.21"
2121
regex = "1.10.2"
2222
serde_json = "1.0.73"
23-
sha2 = "0.10.6"
2423
syn = { version = "2.0.0", features = ["full"] }
25-
tar = "0.4.38"
2624
tempfile = "3.6.0"
2725
walkdir = "2.4.0"
28-
ureq = "2.8.0"

xtask/src/main.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use arch::UefiArch;
1717
use cargo::{Cargo, CargoAction, Feature, Package, TargetTypes};
1818
use clap::Parser;
1919
use itertools::Itertools;
20+
use log::{LevelFilter, Metadata, Record};
2021
use opt::{Action, BuildOpt, ClippyOpt, CovOpt, DocOpt, Opt, QemuOpt, TpmVersion};
2122
use std::process::Command;
2223
use util::run_cmd;
@@ -322,9 +323,33 @@ fn has_cmd(target_cmd: &str) -> bool {
322323
run_cmd(cmd).is_ok()
323324
}
324325

326+
fn install_logger() {
327+
struct Logger;
328+
329+
impl log::Log for Logger {
330+
fn enabled(&self, _: &Metadata) -> bool {
331+
true
332+
}
333+
334+
fn log(&self, record: &Record) {
335+
println!("[{}] {}", record.level(), record.args());
336+
}
337+
338+
fn flush(&self) {}
339+
}
340+
341+
static LOGGER: Logger = Logger;
342+
343+
log::set_logger(&LOGGER)
344+
.map(|()| log::set_max_level(LevelFilter::Info))
345+
.unwrap();
346+
}
347+
325348
fn main() -> Result<()> {
326349
let opt = Opt::parse();
327350

351+
install_logger();
352+
328353
match &opt.action {
329354
Action::Build(build_opt) => build(build_opt),
330355
Action::CheckRaw(_) => check_raw::check_raw(),

xtask/src/qemu.rs

Lines changed: 39 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,15 @@ use crate::tpm::Swtpm;
66
use crate::util::command_to_string;
77
use crate::{net, platform};
88
use anyhow::{bail, Context, Result};
9+
use ovmf_prebuilt::{FileType, Prebuilt, Source};
910
use regex::bytes::Regex;
1011
use serde_json::{json, Value};
11-
use sha2::{Digest, Sha256};
1212
use std::env;
1313
use std::ffi::OsString;
14-
use std::io::{BufRead, BufReader, Cursor, Read, Write};
14+
use std::io::{BufRead, BufReader, Read, Write};
1515
use std::path::{Path, PathBuf};
1616
use std::process::{Child, Command, Stdio};
17-
use tar::Archive;
1817
use tempfile::TempDir;
19-
use ureq::Agent;
2018
#[cfg(target_os = "linux")]
2119
use {std::fs::Permissions, std::os::unix::fs::PermissionsExt};
2220

@@ -38,161 +36,41 @@ const ENV_VAR_OVMF_VARS: &str = "OVMF_VARS";
3836
/// Environment variable for overriding the path of the OVMF shell file.
3937
const ENV_VAR_OVMF_SHELL: &str = "OVMF_SHELL";
4038

41-
/// Download `url` and return the raw data.
42-
fn download_url(url: &str) -> Result<Vec<u8>> {
43-
let agent: Agent = ureq::AgentBuilder::new()
44-
.user_agent("uefi-rs-ovmf-downloader")
45-
.build();
46-
47-
// Limit the size of the download.
48-
let max_size_in_bytes = 5 * 1024 * 1024;
49-
50-
// Download the file.
51-
println!("downloading {url}");
52-
let resp = agent.get(url).call()?;
53-
let mut data = Vec::with_capacity(max_size_in_bytes);
54-
resp.into_reader()
55-
.take(max_size_in_bytes.try_into().unwrap())
56-
.read_to_end(&mut data)?;
57-
println!("received {} bytes", data.len());
58-
59-
Ok(data)
60-
}
61-
62-
// Extract the tarball's files into `prebuilt_dir`.
63-
//
64-
// `tarball_data` is raw decompressed tar data.
65-
fn extract_prebuilt(tarball_data: &[u8], prebuilt_dir: &Path) -> Result<()> {
66-
let cursor = Cursor::new(tarball_data);
67-
let mut archive = Archive::new(cursor);
68-
69-
// Extract each file entry.
70-
for entry in archive.entries()? {
71-
let mut entry = entry?;
72-
73-
// Skip directories.
74-
if entry.size() == 0 {
75-
continue;
39+
impl From<UefiArch> for ovmf_prebuilt::Arch {
40+
fn from(arch: UefiArch) -> Self {
41+
match arch {
42+
UefiArch::AArch64 => Self::Aarch64,
43+
UefiArch::IA32 => Self::Ia32,
44+
UefiArch::X86_64 => Self::X64,
7645
}
77-
78-
let path = entry.path()?;
79-
// Strip the leading directory, which is the release name.
80-
let path: PathBuf = path.components().skip(1).collect();
81-
82-
let dir = path.parent().unwrap();
83-
let dst_dir = prebuilt_dir.join(dir);
84-
let dst_path = prebuilt_dir.join(path);
85-
println!("unpacking to {}", dst_path.display());
86-
fs_err::create_dir_all(dst_dir)?;
87-
entry.unpack(dst_path)?;
8846
}
89-
90-
Ok(())
9147
}
9248

93-
/// Update the local copy of the prebuilt OVMF files. Does nothing if the local
94-
/// copy is already up to date.
95-
fn update_prebuilt() -> Result<PathBuf> {
96-
let prebuilt_dir = Path::new(OVMF_PREBUILT_DIR);
97-
let hash_path = prebuilt_dir.join("sha256");
98-
99-
// Check if the hash file already has the expected hash in it. If so, assume
100-
// that we've already got the correct prebuilt downloaded and unpacked.
101-
if let Ok(current_hash) = fs_err::read_to_string(&hash_path) {
102-
if current_hash == OVMF_PREBUILT_HASH {
103-
return Ok(prebuilt_dir.to_path_buf());
49+
/// Get a user-provided path for the given OVMF file type.
50+
///
51+
/// This uses the command-line arg if present, otherwise it falls back to an
52+
/// environment variable. If neither is present, returns `None`.
53+
fn get_user_provided_path(file_type: FileType, opt: &QemuOpt) -> Option<PathBuf> {
54+
let opt_path;
55+
let var_name;
56+
match file_type {
57+
FileType::Code => {
58+
opt_path = &opt.ovmf_code;
59+
var_name = ENV_VAR_OVMF_CODE;
10460
}
105-
}
106-
107-
let base_url = "https://github.com/rust-osdev/ovmf-prebuilt/releases/download";
108-
let url = format!(
109-
"{base_url}/{release}/{release}-bin.tar.xz",
110-
release = OVMF_PREBUILT_TAG
111-
);
112-
113-
let data = download_url(&url)?;
114-
115-
// Validate the hash.
116-
let actual_hash = format!("{:x}", Sha256::digest(&data));
117-
if actual_hash != OVMF_PREBUILT_HASH {
118-
bail!(
119-
"file hash {actual_hash} does not match {}",
120-
OVMF_PREBUILT_HASH
121-
);
122-
}
123-
124-
// Unpack the tarball.
125-
println!("decompressing tarball");
126-
let mut decompressed = Vec::new();
127-
let mut compressed = Cursor::new(data);
128-
lzma_rs::xz_decompress(&mut compressed, &mut decompressed)?;
129-
130-
// Clear out the existing prebuilt dir, if present.
131-
let _ = fs_err::remove_dir_all(prebuilt_dir);
132-
133-
// Extract the files.
134-
extract_prebuilt(&decompressed, prebuilt_dir)?;
135-
136-
// Rename the x64 directory to x86_64, to match `Arch::as_str`.
137-
fs_err::rename(prebuilt_dir.join("x64"), prebuilt_dir.join("x86_64"))?;
138-
139-
// Write out the hash file. When we upgrade to a new release of
140-
// ovmf-prebuilt, the hash will no longer match, triggering a fresh
141-
// download.
142-
fs_err::write(&hash_path, actual_hash)?;
143-
144-
Ok(prebuilt_dir.to_path_buf())
145-
}
146-
147-
#[derive(Clone, Copy, Debug)]
148-
enum OvmfFileType {
149-
Code,
150-
Vars,
151-
Shell,
152-
}
153-
154-
impl OvmfFileType {
155-
fn as_str(&self) -> &'static str {
156-
match self {
157-
Self::Code => "code",
158-
Self::Vars => "vars",
159-
Self::Shell => "shell",
61+
FileType::Vars => {
62+
opt_path = &opt.ovmf_vars;
63+
var_name = ENV_VAR_OVMF_VARS;
16064
}
161-
}
162-
163-
fn extension(&self) -> &'static str {
164-
match self {
165-
Self::Code | Self::Vars => "fd",
166-
Self::Shell => "efi",
65+
FileType::Shell => {
66+
opt_path = &None;
67+
var_name = ENV_VAR_OVMF_SHELL;
16768
}
16869
}
169-
170-
/// Get a user-provided path for the given OVMF file type.
171-
///
172-
/// This uses the command-line arg if present, otherwise it falls back to an
173-
/// environment variable. If neither is present, returns `None`.
174-
fn get_user_provided_path(self, opt: &QemuOpt) -> Option<PathBuf> {
175-
let opt_path;
176-
let var_name;
177-
match self {
178-
Self::Code => {
179-
opt_path = &opt.ovmf_code;
180-
var_name = ENV_VAR_OVMF_CODE;
181-
}
182-
Self::Vars => {
183-
opt_path = &opt.ovmf_vars;
184-
var_name = ENV_VAR_OVMF_VARS;
185-
}
186-
Self::Shell => {
187-
opt_path = &None;
188-
var_name = ENV_VAR_OVMF_SHELL;
189-
}
190-
}
191-
if let Some(path) = opt_path {
192-
Some(path.clone())
193-
} else {
194-
env::var_os(var_name).map(PathBuf::from)
195-
}
70+
if let Some(path) = opt_path {
71+
Some(path.clone())
72+
} else {
73+
env::var_os(var_name).map(PathBuf::from)
19674
}
19775
}
19876

@@ -210,8 +88,8 @@ impl OvmfPaths {
21088
/// 1. Command-line arg
21189
/// 2. Environment variable
21290
/// 3. Prebuilt file (automatically downloaded)
213-
fn find_ovmf_file(file_type: OvmfFileType, opt: &QemuOpt, arch: UefiArch) -> Result<PathBuf> {
214-
if let Some(path) = file_type.get_user_provided_path(opt) {
91+
fn find_ovmf_file(file_type: FileType, opt: &QemuOpt, arch: UefiArch) -> Result<PathBuf> {
92+
if let Some(path) = get_user_provided_path(file_type, opt) {
21593
// The user provided an exact path to use; verify that it
21694
// exists.
21795
if path.exists() {
@@ -224,22 +102,21 @@ impl OvmfPaths {
224102
);
225103
}
226104
} else {
227-
let prebuilt_dir = update_prebuilt()?;
105+
let prebuilt = Prebuilt::fetch(Source {
106+
tag: OVMF_PREBUILT_TAG,
107+
sha256: OVMF_PREBUILT_HASH,
108+
}, OVMF_PREBUILT_DIR)?;
228109

229-
Ok(prebuilt_dir.join(format!(
230-
"{arch}/{}.{}",
231-
file_type.as_str(),
232-
file_type.extension()
233-
)))
110+
Ok(prebuilt.get_file(arch.into(), file_type))
234111
}
235112
}
236113

237114
/// Find path to OVMF files by the strategy documented for
238115
/// [`Self::find_ovmf_file`].
239116
fn find(opt: &QemuOpt, arch: UefiArch) -> Result<Self> {
240-
let code = Self::find_ovmf_file(OvmfFileType::Code, opt, arch)?;
241-
let vars = Self::find_ovmf_file(OvmfFileType::Vars, opt, arch)?;
242-
let shell = Self::find_ovmf_file(OvmfFileType::Shell, opt, arch)?;
117+
let code = Self::find_ovmf_file(FileType::Code, opt, arch)?;
118+
let vars = Self::find_ovmf_file(FileType::Vars, opt, arch)?;
119+
let shell = Self::find_ovmf_file(FileType::Shell, opt, arch)?;
243120

244121
Ok(Self { code, vars, shell })
245122
}

0 commit comments

Comments
 (0)