From 66e1816debff04cc7a1519a218e062acf915024b Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Tue, 9 May 2023 20:49:23 -0400 Subject: [PATCH 1/2] Automatically download prebuilt OVMF files The code for trying to find where the OS has installed OVMF files has been removed. You can still pass your own OVMF files in via command-line or env vars, but by default the code will download prebuilt OVMF files from https://github.com/rust-osdev/ovmf-prebuilt. --- Cargo.lock | 412 +++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 5 + xtask/Cargo.toml | 4 + xtask/src/qemu.rs | 325 +++++++++++++++--------------------- 4 files changed, 556 insertions(+), 190 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 963a21e2e..36fba5dc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "1.0.1" @@ -23,6 +29,12 @@ version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "basic-toml" version = "0.1.2" @@ -71,6 +83,21 @@ dependencies = [ "wyz", ] +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + [[package]] name = "byteorder" version = "1.4.3" @@ -129,6 +156,59 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +[[package]] +name = "cpufeatures" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "either" version = "1.8.1" @@ -176,6 +256,37 @@ dependencies = [ "log", ] +[[package]] +name = "filetime" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.16", + "windows-sys 0.48.0", +] + +[[package]] +name = "flate2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + [[package]] name = "fs-err" version = "2.9.0" @@ -188,6 +299,16 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "glob" version = "0.3.1" @@ -206,6 +327,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "instant" version = "0.1.12" @@ -241,6 +372,15 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +[[package]] +name = "js-sys" +version = "0.3.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "libc" version = "0.2.144" @@ -262,6 +402,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "lzma-rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" +dependencies = [ + "byteorder", + "crc", +] + [[package]] name = "mbrman" version = "0.5.2" @@ -281,6 +431,15 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "nix" version = "0.26.2" @@ -309,6 +468,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + [[package]] name = "proc-macro2" version = "1.0.56" @@ -359,6 +524,15 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.3.5" @@ -385,6 +559,21 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + [[package]] name = "rustix" version = "0.37.19" @@ -399,6 +588,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "rustls" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + [[package]] name = "ryu" version = "1.0.13" @@ -414,6 +615,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "serde" version = "1.0.162" @@ -454,6 +665,23 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "static_assertions" version = "1.1.0" @@ -488,6 +716,17 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tar" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "tempfile" version = "3.5.0" @@ -496,7 +735,7 @@ checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.3.5", "rustix", "windows-sys 0.45.0", ] @@ -530,6 +769,21 @@ dependencies = [ "syn 2.0.15", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "trybuild" version = "1.0.80" @@ -545,6 +799,12 @@ dependencies = [ "termcolor", ] +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + [[package]] name = "ucs2" version = "0.3.2" @@ -621,12 +881,66 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "594cc87e268a7b43d625d46c63cf1605d0e61bf66e4b1cd58c058ec0191e1f81" +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + [[package]] name = "unicode-ident" version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "ureq" +version = "2.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "338b31dd1314f68f3aabf3ed57ab922df95ffcd902476ca7ba3c4ce7b908c46d" +dependencies = [ + "base64", + "flate2", + "log", + "once_cell", + "rustls", + "url", + "webpki", + "webpki-roots", +] + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "walkdir" version = "2.3.3" @@ -637,6 +951,89 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasm-bindgen" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.15", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" + +[[package]] +name = "web-sys" +version = "0.3.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki", +] + [[package]] name = "winapi" version = "0.3.9" @@ -809,6 +1206,15 @@ dependencies = [ "tap", ] +[[package]] +name = "xattr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" +dependencies = [ + "libc", +] + [[package]] name = "xtask" version = "0.0.0" @@ -819,6 +1225,7 @@ dependencies = [ "fs-err", "heck", "itertools", + "lzma-rs", "mbrman", "nix", "os_info", @@ -826,7 +1233,10 @@ dependencies = [ "quote", "regex", "serde_json", + "sha2", "syn 2.0.15", + "tar", "tempfile", + "ureq", "walkdir", ] diff --git a/Cargo.toml b/Cargo.toml index d8a49f9b8..5f7d241ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,8 @@ uefi = { path = "uefi" } uefi-macros = { path = "uefi-macros" } uefi-raw = { path = "uefi-raw" } uefi-services = { path = "uefi-services" } + +# Enable optimization for xtask itself, not for its dependencies. This speeds up +# OVMF prebuilt decompression without much increase in compilation time. +[profile.dev.package.xtask] +opt-level = 3 diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 311ef2243..13bd2b8ed 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -11,6 +11,7 @@ fatfs = { version = "0.3.6", default-features = false, features = ["alloc", "std fs-err = "2.6.0" heck = "0.4.0" itertools = "0.10.5" +lzma-rs = "0.3.0" mbrman = "0.5.1" nix = { version = "0.26.1", default-features = false, features = ["fs"] } os_info = { version = "3.6.0", default-features = false } @@ -18,6 +19,9 @@ proc-macro2 = { version = "1.0.46", features = ["span-locations"] } quote = "1.0.21" regex = "1.8.1" serde_json = "1.0.73" +sha2 = "0.10.6" syn = { version = "2.0.0", features = ["full"] } +tar = "0.4.38" tempfile = "3.5.0" walkdir = "2.3.3" +ureq = "2.6.2" diff --git a/xtask/src/qemu.rs b/xtask/src/qemu.rs index 44bf38b39..a63f1116a 100644 --- a/xtask/src/qemu.rs +++ b/xtask/src/qemu.rs @@ -5,18 +5,142 @@ use crate::pipe::Pipe; use crate::tpm::Swtpm; use crate::util::command_to_string; use crate::{net, platform}; -use anyhow::{anyhow, bail, Context, Result}; +use anyhow::{bail, Context, Result}; use regex::bytes::Regex; use serde_json::{json, Value}; +use sha2::{Digest, Sha256}; use std::env; use std::ffi::OsString; -use std::io::{BufRead, BufReader, Read, Write}; +use std::io::{BufRead, BufReader, Cursor, Read, Write}; use std::path::{Path, PathBuf}; use std::process::{Child, Command, Stdio}; +use tar::Archive; use tempfile::TempDir; +use ureq::Agent; #[cfg(target_os = "linux")] use {std::fs::Permissions, std::os::unix::fs::PermissionsExt}; +/// Name of the ovmf-prebuilt release tag. +const OVMF_PREBUILT_TAG: &str = "edk2-stable202211-r1"; + +/// SHA-256 hash of the release tarball. +const OVMF_PREBUILT_HASH: &str = "b085cfe18fd674bf70a31af1dc3e991bcd25cb882981c6d3523d81260f1e0d12"; + +/// Directory into which the prebuilts will be download (relative to the repo root). +const OVMF_PREBUILT_DIR: &str = "target/ovmf"; + +/// Environment variable for overriding the path of the OVMF code file. +const ENV_VAR_OVMF_CODE: &str = "OVMF_CODE"; + +/// Environment variable for overriding the path of the OVMF vars file. +const ENV_VAR_OVMF_VARS: &str = "OVMF_VARS"; + +/// Download `url` and return the raw data. +fn download_url(url: &str) -> Result> { + let agent: Agent = ureq::AgentBuilder::new() + .user_agent("uefi-rs-ovmf-downloader") + .build(); + + // Limit the size of the download. + let max_size_in_bytes = 4 * 1024 * 1024; + + // Download the file. + println!("downloading {url}"); + let resp = agent.get(url).call()?; + let mut data = Vec::with_capacity(max_size_in_bytes); + resp.into_reader() + .take(max_size_in_bytes.try_into().unwrap()) + .read_to_end(&mut data)?; + println!("received {} bytes", data.len()); + + Ok(data) +} + +// Extract the tarball's files into `prebuilt_dir`. +// +// `tarball_data` is raw decompressed tar data. +fn extract_prebuilt(tarball_data: &[u8], prebuilt_dir: &Path) -> Result<()> { + let cursor = Cursor::new(tarball_data); + let mut archive = Archive::new(cursor); + + // Extract each file entry. + for entry in archive.entries()? { + let mut entry = entry?; + + // Skip directories. + if entry.size() == 0 { + continue; + } + + let path = entry.path()?; + // Strip the leading directory, which is the release name. + let path: PathBuf = path.components().skip(1).collect(); + + let dir = path.parent().unwrap(); + let dst_dir = prebuilt_dir.join(dir); + let dst_path = prebuilt_dir.join(path); + println!("unpacking to {}", dst_path.display()); + fs_err::create_dir_all(dst_dir)?; + entry.unpack(dst_path)?; + } + + Ok(()) +} + +/// Update the local copy of the prebuilt OVMF files. Does nothing if the local +/// copy is already up to date. +fn update_prebuilt() -> Result { + let prebuilt_dir = Path::new(OVMF_PREBUILT_DIR); + let hash_path = prebuilt_dir.join("sha256"); + + // Check if the hash file already has the expected hash in it. If so, assume + // that we've already got the correct prebuilt downloaded and unpacked. + if let Ok(current_hash) = fs_err::read_to_string(&hash_path) { + if current_hash == OVMF_PREBUILT_HASH { + return Ok(prebuilt_dir.to_path_buf()); + } + } + + let base_url = "https://github.com/rust-osdev/ovmf-prebuilt/releases/download"; + let url = format!( + "{base_url}/{release}/{release}-bin.tar.xz", + release = OVMF_PREBUILT_TAG + ); + + let data = download_url(&url)?; + + // Validate the hash. + let actual_hash = format!("{:x}", Sha256::digest(&data)); + if actual_hash != OVMF_PREBUILT_HASH { + bail!( + "file hash {actual_hash} does not match {}", + OVMF_PREBUILT_HASH + ); + } + + // Unpack the tarball. + println!("decompressing tarball"); + let mut decompressed = Vec::new(); + let mut compressed = Cursor::new(data); + lzma_rs::xz_decompress(&mut compressed, &mut decompressed)?; + + // Clear out the existing prebuilt dir, if present. + let _ = fs_err::remove_dir_all(prebuilt_dir); + + // Extract the files. + extract_prebuilt(&decompressed, prebuilt_dir)?; + + // Rename the x64 directory to x86_64, to match `Arch::as_str`. + fs_err::rename(prebuilt_dir.join("x64"), prebuilt_dir.join("x86_64"))?; + + // Write out the hash file. When we upgrade to a new release of + // ovmf-prebuilt, the hash will no longer match, triggering a fresh + // download. + fs_err::write(&hash_path, actual_hash)?; + + Ok(prebuilt_dir.to_path_buf()) +} + #[derive(Clone, Copy, Debug)] enum OvmfFileType { Code, @@ -41,11 +165,11 @@ impl OvmfFileType { match self { Self::Code => { opt_path = &opt.ovmf_code; - var_name = "OVMF_CODE"; + var_name = ENV_VAR_OVMF_CODE; } Self::Vars => { opt_path = &opt.ovmf_vars; - var_name = "OVMF_VARS"; + var_name = ENV_VAR_OVMF_VARS; } } if let Some(path) = opt_path { @@ -62,177 +186,14 @@ struct OvmfPaths { } impl OvmfPaths { - /// If OVMF files can not or should not be found at well-known locations, - /// this optional environment variable can point to it. - /// - /// This variable points to the `_CODE.fd` file. - - const ENV_VAR_OVMF_CODE: &'static str = "OVMF_CODE"; - /// If OVMF files can not or should not be found at well-known locations, - /// this optional environment variable can point to it. - /// - /// This variable points to the `_VARS.fd` file. - const ENV_VAR_OVMF_VARS: &'static str = "OVMF_VARS"; - - fn get_path(&self, file_type: OvmfFileType) -> &Path { - match file_type { - OvmfFileType::Code => &self.code, - OvmfFileType::Vars => &self.vars, - } - } - - /// Get the Arch Linux OVMF paths for the given guest arch. - fn arch_linux(arch: UefiArch) -> Self { - match arch { - // Package "edk2-armvirt". - UefiArch::AArch64 => Self { - code: "/usr/share/edk2-armvirt/aarch64/QEMU_CODE.fd".into(), - vars: "/usr/share/edk2-armvirt/aarch64/QEMU_VARS.fd".into(), - }, - // Package "edk2-ovmf". - UefiArch::IA32 => Self { - code: "/usr/share/edk2-ovmf/ia32/OVMF_CODE.fd".into(), - vars: "/usr/share/edk2-ovmf/ia32/OVMF_VARS.fd".into(), - }, - // Package "edk2-ovmf". - UefiArch::X86_64 => Self { - code: "/usr/share/edk2-ovmf/x64/OVMF_CODE.fd".into(), - vars: "/usr/share/edk2-ovmf/x64/OVMF_VARS.fd".into(), - }, - } - } - - /// Get the CentOS OVMF paths for the given guest arch. - fn centos_linux(arch: UefiArch) -> Option { - match arch { - // Package "edk2-aarch64". - UefiArch::AArch64 => Some(Self { - code: "/usr/share/edk2/aarch64/QEMU_EFI-pflash.raw".into(), - vars: "/usr/share/edk2/aarch64/vars-template-pflash.raw".into(), - }), - // There's no official ia32 package. - UefiArch::IA32 => None, - // Package "edk2-ovmf". - UefiArch::X86_64 => Some(Self { - // Use the `.secboot` variant because the CentOS package - // doesn't have a plain "OVMF_CODE.fd". - code: "/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd".into(), - vars: "/usr/share/edk2/ovmf/OVMF_VARS.fd".into(), - }), - } - } - - /// Get the Debian OVMF paths for the given guest arch. These paths - /// also work on Ubuntu. - fn debian_linux(arch: UefiArch) -> Self { - match arch { - // Package "qemu-efi-aarch64". - UefiArch::AArch64 => Self { - code: "/usr/share/AAVMF/AAVMF_CODE.fd".into(), - vars: "/usr/share/AAVMF/AAVMF_VARS.fd".into(), - }, - // Package "ovmf-ia32". - UefiArch::IA32 => Self { - code: "/usr/share/OVMF/OVMF32_CODE_4M.secboot.fd".into(), - vars: "/usr/share/OVMF/OVMF32_VARS_4M.fd".into(), - }, - // Package "ovmf". - UefiArch::X86_64 => Self { - code: "/usr/share/OVMF/OVMF_CODE.fd".into(), - vars: "/usr/share/OVMF/OVMF_VARS.fd".into(), - }, - } - } - - /// Get the Fedora OVMF paths for the given guest arch. - fn fedora_linux(arch: UefiArch) -> Self { - match arch { - // Package "edk2-aarch64". - UefiArch::AArch64 => Self { - code: "/usr/share/edk2/aarch64/QEMU_EFI-pflash.raw".into(), - vars: "/usr/share/edk2/aarch64/vars-template-pflash.raw".into(), - }, - // Package "edk2-ovmf-ia32". - UefiArch::IA32 => Self { - code: "/usr/share/edk2/ovmf-ia32/OVMF_CODE.fd".into(), - vars: "/usr/share/edk2/ovmf-ia32/OVMF_VARS.fd".into(), - }, - // Package "edk2-ovmf". - UefiArch::X86_64 => Self { - code: "/usr/share/edk2/ovmf/OVMF_CODE.fd".into(), - vars: "/usr/share/edk2/ovmf/OVMF_VARS.fd".into(), - }, - } - } - - /// If a user uses NixOS, this function returns an error if the user didn't - /// set the environment variables `OVMF_CODE` and `OVMF_VARS`. - /// - /// It returns nothing as the environment variables are resolved at a - /// higher level. NixOS doesn't have globally installed software (without - /// hacky and non-idiomatic workarounds). - fn assist_nixos_users() -> Result<()> { - let os_info = os_info::get(); - if os_info.os_type() == os_info::Type::NixOS { - let code = env::var_os(Self::ENV_VAR_OVMF_CODE); - let vars = env::var_os(Self::ENV_VAR_OVMF_VARS); - if !matches!((code, vars), (Some(_), Some(_))) { - return Err(anyhow!("Run `$ nix-shell` for OVMF files.")); - } - } - Ok(()) - } - - /// Get the Windows OVMF paths for the given guest arch. - fn windows(arch: UefiArch) -> Self { - match arch { - UefiArch::AArch64 => Self { - code: r"C:\Program Files\qemu\share\edk2-aarch64-code.fd".into(), - vars: r"C:\Program Files\qemu\share\edk2-arm-vars.fd".into(), - }, - UefiArch::IA32 => Self { - code: r"C:\Program Files\qemu\share\edk2-i386-code.fd".into(), - vars: r"C:\Program Files\qemu\share\edk2-i386-vars.fd".into(), - }, - UefiArch::X86_64 => Self { - code: r"C:\Program Files\qemu\share\edk2-x86_64-code.fd".into(), - // There's no x86_64 vars file, but the i386 one works. - vars: r"C:\Program Files\qemu\share\edk2-i386-vars.fd".into(), - }, - } - } - - /// Get candidate paths where OVMF code/vars might exist for the - /// given guest arch and host platform. - fn get_candidate_paths(arch: UefiArch) -> Result> { - let mut candidates = Vec::new(); - if platform::is_linux() { - candidates.push(Self::arch_linux(arch)); - if let Some(candidate) = Self::centos_linux(arch) { - candidates.push(candidate); - } - candidates.push(Self::debian_linux(arch)); - candidates.push(Self::fedora_linux(arch)); - Self::assist_nixos_users()?; - } - if platform::is_windows() { - candidates.push(Self::windows(arch)); - } - Ok(candidates) - } - /// Search for an OVMF file (either code or vars). /// /// There are multiple locations where a file is searched at in the following /// priority: - /// 1. User-defined location: See [`OvmfFileType::get_user_provided_path`] - /// 2. Well-known location of common Linux distributions by using the - /// paths in `candidates`. - fn find_ovmf_file( - file_type: OvmfFileType, - opt: &QemuOpt, - candidates: &[Self], - ) -> Result { + /// 1. Command-line arg + /// 2. Environment variable + /// 3. Prebuilt file (automatically downloaded) + fn find_ovmf_file(file_type: OvmfFileType, opt: &QemuOpt, arch: UefiArch) -> Result { if let Some(path) = file_type.get_user_provided_path(opt) { // The user provided an exact path to use; verify that it // exists. @@ -246,31 +207,17 @@ impl OvmfPaths { ); } } else { - for candidate in candidates { - let path = candidate.get_path(file_type); - if path.exists() { - return Ok(path.to_owned()); - } - } + let prebuilt_dir = update_prebuilt()?; - bail!( - "no ovmf {} file found in candidates: {:?}", - file_type.as_str(), - candidates - .iter() - .map(|c| c.get_path(file_type)) - .collect::>(), - ); + Ok(prebuilt_dir.join(format!("{arch}/{}.fd", file_type.as_str()))) } } /// Find path to OVMF files by the strategy documented for /// [`Self::find_ovmf_file`]. fn find(opt: &QemuOpt, arch: UefiArch) -> Result { - let candidates = Self::get_candidate_paths(arch)?; - - let code = Self::find_ovmf_file(OvmfFileType::Code, opt, &candidates)?; - let vars = Self::find_ovmf_file(OvmfFileType::Vars, opt, &candidates)?; + let code = Self::find_ovmf_file(OvmfFileType::Code, opt, arch)?; + let vars = Self::find_ovmf_file(OvmfFileType::Vars, opt, arch)?; Ok(Self { code, vars }) } From 06b7e4dce16e21f55c0f96d19ed6fc09f7c496f5 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Wed, 10 May 2023 00:34:44 -0400 Subject: [PATCH 2/2] ci: Stop installing OVMF package --- .github/workflows/rust.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 4f6e03a91..4ef616e3f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -22,10 +22,10 @@ jobs: - uses: Swatinem/rust-cache@v2 - - name: Install qemu and OVMF + - name: Install qemu run: | sudo apt-get update - sudo apt-get install qemu-system-arm qemu-efi-aarch64 -y + sudo apt-get install qemu-system-arm -y - name: Run VM tests run: cargo xtask run --target aarch64 --headless --ci @@ -40,10 +40,10 @@ jobs: - uses: Swatinem/rust-cache@v2 - - name: Install qemu and OVMF + - name: Install qemu run: | sudo apt-get update - sudo apt-get install qemu-system-x86 ovmf swtpm -y + sudo apt-get install qemu-system-x86 swtpm -y - name: Run VM tests run: cargo xtask run --target x86_64 --headless --ci --tpm=v1 @@ -58,10 +58,10 @@ jobs: - uses: Swatinem/rust-cache@v2 - - name: Install qemu and OVMF + - name: Install qemu run: | sudo apt-get update - sudo apt-get install qemu-system-x86 ovmf-ia32 swtpm -y + sudo apt-get install qemu-system-x86 swtpm -y - name: Run VM tests run: cargo xtask run --target ia32 --headless --ci --tpm=v2 @@ -168,10 +168,10 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - - name: Install qemu and OVMF + - name: Install qemu run: | sudo apt-get update - sudo apt-get install qemu-system-x86 ovmf -y + sudo apt-get install qemu-system-x86 -y - name: Enable nightly toolchain run: cp .github/workflows/nightly_toolchain.toml rust-toolchain.toml