From 44ae0843ee3f0792703efa47af04784595b97e7c Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 6 Jul 2024 13:24:02 -0400 Subject: [PATCH 01/56] book: Publish the latest release instead of main --- .github/workflows/book.yml | 39 +++++++++++++++++++++++--------------- book/head_redirect.html | 8 -------- 2 files changed, 24 insertions(+), 23 deletions(-) delete mode 100644 book/head_redirect.html diff --git a/.github/workflows/book.yml b/.github/workflows/book.yml index ba1369f97..45268d67f 100644 --- a/.github/workflows/book.yml +++ b/.github/workflows/book.yml @@ -2,6 +2,7 @@ name: Book on: push: branches: [main] + tags: ['*'] permissions: contents: write # Adapted from: @@ -21,24 +22,32 @@ jobs: echo `pwd`/mdbook >> $GITHUB_PATH - name: Deploy GitHub Pages run: | - cd book - mdbook build - git worktree add gh-pages gh-pages + # Configure git user so that `git commit` works. git config user.name "Deploy from CI" git config user.email "" - cd gh-pages + + # Get the highest `uefi` release tag. + highest_tag="$(git tag --list | grep uefi-v | sort -V | tail -1)" + + # Create a worktree for the tag. + git worktree add wt-tag refs/tags/"${highest_tag}" + + # Create a worktree for the `gh-pages` branch. + git worktree add wt-gh-pages gh-pages + # Delete the ref to avoid keeping history. - git update-ref -d refs/heads/gh-pages - # Place the book under a "HEAD" directory so that we can later - # add other versions (e.g. "stable" or "v0.17") without breaking - # URLs. - rm -rf HEAD - mv ../book HEAD - git add HEAD - # Add an index in the root to redirect to HEAD. If we eventually - # serve multiple versions, this can be changed to a real index. - cp ../head_redirect.html index.html - git add index.html + git -C wt-gh-pages update-ref -d refs/heads/gh-pages + + # Build the book for the tag. Don't use `--dest-dir` because it will + # delete the destination directory including the worktree checkout's + # ".git". + mdbook build wt-tag/book + # Copy output to the destination directory. Note the "/." is needed at + # the end of the source path so that hidden files are included. + cp -r wt-tag/book/book/. wt-gh-pages + # Commit and push. + cd wt-gh-pages + git add . git commit -m "Deploy $GITHUB_SHA to gh-pages" git push --force diff --git a/book/head_redirect.html b/book/head_redirect.html deleted file mode 100644 index 7c75cfd02..000000000 --- a/book/head_redirect.html +++ /dev/null @@ -1,8 +0,0 @@ - - - -Redirecting to latest documentation - - - -Redirecting to ./HEAD... From 713120401d8e1ffb3495c9fd112436154cb38ecb Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 7 Jul 2024 13:34:41 -0400 Subject: [PATCH 02/56] Drop SystemTable arg from uefi::helpers::init Use the global system table pointer instead. --- template/src/main.rs | 4 ++-- uefi-test-runner/examples/hello_world.rs | 4 ++-- uefi-test-runner/examples/loaded_image.rs | 4 ++-- uefi-test-runner/examples/shell_params.rs | 4 ++-- uefi-test-runner/examples/sierpinski.rs | 4 ++-- uefi-test-runner/examples/timestamp.rs | 4 ++-- uefi-test-runner/src/bin/shell_launcher.rs | 4 ++-- uefi-test-runner/src/main.rs | 2 +- uefi/CHANGELOG.md | 3 +++ uefi/src/helpers/mod.rs | 9 +++++---- 10 files changed, 23 insertions(+), 19 deletions(-) diff --git a/template/src/main.rs b/template/src/main.rs index 64ae41733..d3bb8ad5f 100644 --- a/template/src/main.rs +++ b/template/src/main.rs @@ -4,8 +4,8 @@ use uefi::prelude::*; #[entry] -fn main(_handle: Handle, mut system_table: SystemTable) -> Status { - uefi::helpers::init(&mut system_table).unwrap(); +fn main(_handle: Handle, system_table: SystemTable) -> Status { + uefi::helpers::init().unwrap(); Status::SUCCESS } diff --git a/uefi-test-runner/examples/hello_world.rs b/uefi-test-runner/examples/hello_world.rs index a2b46d826..91081cb9e 100644 --- a/uefi-test-runner/examples/hello_world.rs +++ b/uefi-test-runner/examples/hello_world.rs @@ -11,10 +11,10 @@ use uefi::prelude::*; // ANCHOR: entry #[entry] -fn main(_image_handle: Handle, mut system_table: SystemTable) -> Status { +fn main(_image_handle: Handle, system_table: SystemTable) -> Status { // ANCHOR_END: entry // ANCHOR: services - uefi::helpers::init(&mut system_table).unwrap(); + uefi::helpers::init().unwrap(); // ANCHOR_END: services // ANCHOR: log info!("Hello world!"); diff --git a/uefi-test-runner/examples/loaded_image.rs b/uefi-test-runner/examples/loaded_image.rs index 01debc0cb..216af7a89 100644 --- a/uefi-test-runner/examples/loaded_image.rs +++ b/uefi-test-runner/examples/loaded_image.rs @@ -13,8 +13,8 @@ use uefi::{Identify, Result}; // ANCHOR: main #[entry] -fn main(image_handle: Handle, mut system_table: SystemTable) -> Status { - uefi::helpers::init(&mut system_table).unwrap(); +fn main(image_handle: Handle, system_table: SystemTable) -> Status { + uefi::helpers::init().unwrap(); let boot_services = system_table.boot_services(); print_image_path(boot_services).unwrap(); diff --git a/uefi-test-runner/examples/shell_params.rs b/uefi-test-runner/examples/shell_params.rs index ad95a89f4..90d72bcb8 100644 --- a/uefi-test-runner/examples/shell_params.rs +++ b/uefi-test-runner/examples/shell_params.rs @@ -17,10 +17,10 @@ use alloc::vec::Vec; // ANCHOR: entry #[entry] -fn main(image_handle: Handle, mut system_table: SystemTable) -> Status { +fn main(image_handle: Handle, system_table: SystemTable) -> Status { // ANCHOR_END: entry // ANCHOR: services - uefi::helpers::init(&mut system_table).unwrap(); + uefi::helpers::init().unwrap(); let boot_services = system_table.boot_services(); // ANCHOR_END: services diff --git a/uefi-test-runner/examples/sierpinski.rs b/uefi-test-runner/examples/sierpinski.rs index ac690eaef..f0b0912c3 100644 --- a/uefi-test-runner/examples/sierpinski.rs +++ b/uefi-test-runner/examples/sierpinski.rs @@ -144,8 +144,8 @@ fn draw_sierpinski(bt: &BootServices) -> Result { } #[entry] -fn main(_handle: Handle, mut system_table: SystemTable) -> Status { - uefi::helpers::init(&mut system_table).unwrap(); +fn main(_handle: Handle, system_table: SystemTable) -> Status { + uefi::helpers::init().unwrap(); let bt = system_table.boot_services(); draw_sierpinski(bt).unwrap(); Status::SUCCESS diff --git a/uefi-test-runner/examples/timestamp.rs b/uefi-test-runner/examples/timestamp.rs index deccc7e98..1ce578614 100644 --- a/uefi-test-runner/examples/timestamp.rs +++ b/uefi-test-runner/examples/timestamp.rs @@ -16,10 +16,10 @@ use uefi::proto::misc::Timestamp; // ANCHOR: entry #[entry] -fn main(image_handle: Handle, mut system_table: SystemTable) -> Status { +fn main(image_handle: Handle, system_table: SystemTable) -> Status { // ANCHOR_END: entry // ANCHOR: services - uefi::helpers::init(&mut system_table).unwrap(); + uefi::helpers::init().unwrap(); let boot_services = system_table.boot_services(); // ANCHOR_END: services diff --git a/uefi-test-runner/src/bin/shell_launcher.rs b/uefi-test-runner/src/bin/shell_launcher.rs index 4accdca6f..123307bd6 100644 --- a/uefi-test-runner/src/bin/shell_launcher.rs +++ b/uefi-test-runner/src/bin/shell_launcher.rs @@ -45,8 +45,8 @@ fn get_shell_app_device_path<'a>( } #[entry] -fn efi_main(image: Handle, mut st: SystemTable) -> Status { - uefi::helpers::init(&mut st).unwrap(); +fn efi_main(image: Handle, st: SystemTable) -> Status { + uefi::helpers::init().unwrap(); let boot_services = st.boot_services(); let mut storage = Vec::new(); diff --git a/uefi-test-runner/src/main.rs b/uefi-test-runner/src/main.rs index c61411e27..56c90f7f6 100644 --- a/uefi-test-runner/src/main.rs +++ b/uefi-test-runner/src/main.rs @@ -23,7 +23,7 @@ mod runtime; #[entry] fn efi_main(image: Handle, mut st: SystemTable) -> Status { // Initialize utilities (logging, memory allocation...) - uefi::helpers::init(&mut st).expect("Failed to initialize utilities"); + uefi::helpers::init().expect("Failed to initialize utilities"); // unit tests here diff --git a/uefi/CHANGELOG.md b/uefi/CHANGELOG.md index c0cf43177..e746ab9c9 100644 --- a/uefi/CHANGELOG.md +++ b/uefi/CHANGELOG.md @@ -1,5 +1,8 @@ # uefi - [Unreleased] +## Changed +- **Breaking:** `uefi::helpers::init` no longer takes an argument. + # uefi - 0.29.0 (2024-07-02) diff --git a/uefi/src/helpers/mod.rs b/uefi/src/helpers/mod.rs index e7afe9a6e..b3127a5af 100644 --- a/uefi/src/helpers/mod.rs +++ b/uefi/src/helpers/mod.rs @@ -54,18 +54,19 @@ pub fn system_table() -> SystemTable { /// **PLEASE NOTE** that these helpers are meant for the pre exit boot service /// epoch. Limited functionality might work after exiting them, such as logging /// to the debugcon device. -#[allow(unused_variables)] // `st` is unused if logger and allocator are disabled -pub fn init(st: &mut SystemTable) -> Result<()> { +pub fn init() -> Result<()> { // Setup logging and memory allocation #[cfg(feature = "logger")] unsafe { - logger::init(st); + let mut st = table::system_table_boot().expect("boot services are not active"); + logger::init(&mut st); } #[cfg(feature = "global_allocator")] unsafe { - crate::allocator::init(st); + let mut st = table::system_table_boot().expect("boot services are not active"); + crate::allocator::init(&mut st); } Ok(()) From 6b149bb4c795b396b1066173110b81a8333dafee Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 7 Jul 2024 13:43:01 -0400 Subject: [PATCH 03/56] uefi-macros: Allow zero-param function in the entry macro --- uefi-macros/CHANGELOG.md | 5 +++ uefi-macros/src/lib.rs | 44 +++++++++++++++++----- uefi-macros/tests/ui/pass/entry_no_args.rs | 9 +++++ 3 files changed, 49 insertions(+), 9 deletions(-) create mode 100644 uefi-macros/tests/ui/pass/entry_no_args.rs diff --git a/uefi-macros/CHANGELOG.md b/uefi-macros/CHANGELOG.md index ab6c8829b..2b3ffb624 100644 --- a/uefi-macros/CHANGELOG.md +++ b/uefi-macros/CHANGELOG.md @@ -1,5 +1,10 @@ # uefi-macros - [Unreleased] +## Changed + +- The `entry` macro now accepts a function with zero arguments in addition to + the two-argument form. + # uefi-macros - 0.14.0 (2024-07-02) diff --git a/uefi-macros/src/lib.rs b/uefi-macros/src/lib.rs index 09a67716e..08be64f54 100644 --- a/uefi-macros/src/lib.rs +++ b/uefi-macros/src/lib.rs @@ -8,8 +8,8 @@ use proc_macro2::TokenStream as TokenStream2; use quote::{quote, quote_spanned, TokenStreamExt}; use syn::spanned::Spanned; use syn::{ - parse_macro_input, parse_quote, Error, Expr, ExprLit, ExprPath, FnArg, Ident, ItemFn, - ItemStruct, Lit, Pat, Visibility, + parse_macro_input, parse_quote, parse_quote_spanned, Error, Expr, ExprLit, ExprPath, FnArg, + Ident, ItemFn, ItemStruct, Lit, Pat, Visibility, }; macro_rules! err { @@ -121,18 +121,34 @@ fn get_function_arg_name(f: &ItemFn, arg_index: usize, errors: &mut TokenStream2 /// Custom attribute for a UEFI executable entry point. /// /// This attribute modifies a function to mark it as the entry point for -/// a UEFI executable. The function must have two parameters, [`Handle`] -/// and [`SystemTable`], and return a [`Status`]. The function can -/// optionally be `unsafe`. +/// a UEFI executable. The function: +/// * Must return [`Status`]. +/// * Must have either zero parameters or two: [`Handle`] and [`SystemTable`]. +/// * Can optionally be `unsafe`. /// /// Due to internal implementation details the parameters must both be /// named, so `arg` or `_arg` are allowed, but not `_`. /// -/// The [`BootServices::set_image_handle`] function will be called -/// automatically with the image [`Handle`] argument. +/// The global system table pointer and global image handle will be set +/// automatically. /// /// # Examples /// +/// With no arguments: +/// +/// ```no_run +/// #![no_main] +/// +/// use uefi::prelude::*; +/// +/// #[entry] +/// fn main() -> Status { +/// Status::SUCCESS +/// } +/// ``` +/// +/// With two arguments: +/// /// ```no_run /// #![no_main] /// @@ -180,6 +196,18 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { )); } + let signature_span = f.sig.span(); + + // If the user doesn't specify any arguments to the entry function, fill in + // the image handle and system table arguments automatically. + if f.sig.inputs.is_empty() { + f.sig.inputs = parse_quote_spanned!( + signature_span=> + image_handle: ::uefi::Handle, + system_table: ::uefi::table::SystemTable<::uefi::table::Boot> + ); + } + let image_handle_ident = get_function_arg_name(&f, 0, &mut errors); let system_table_ident = get_function_arg_name(&f, 1, &mut errors); @@ -188,8 +216,6 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { return errors.into(); } - let signature_span = f.sig.span(); - f.sig.abi = Some(syn::parse2(quote_spanned! (signature_span=> extern "efiapi")).unwrap()); // allow the entry function to be unsafe (by moving the keyword around so that it actually works) diff --git a/uefi-macros/tests/ui/pass/entry_no_args.rs b/uefi-macros/tests/ui/pass/entry_no_args.rs new file mode 100644 index 000000000..e2271d5a2 --- /dev/null +++ b/uefi-macros/tests/ui/pass/entry_no_args.rs @@ -0,0 +1,9 @@ +use uefi::{entry, Status}; + +#[entry] +fn efi_main() -> Status { + Status::SUCCESS +} + +// trybuild requires a `main` function. +fn main() {} From 4b564bf7f66d5f5d87b49e3b71ba6ec893b0293d Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 7 Jul 2024 16:43:06 -0400 Subject: [PATCH 04/56] uefi: Fix return value lifetime for register_protocol_notify Due to the rules of lifetime elision (https://doc.rust-lang.org/reference/lifetime-elision.html), the lifetime of the `SearchType` returned from `register_protocol_notify` was infered to be the lifetime of `Self`. The correct lifetime is the `protocol` reference. --- uefi/CHANGELOG.md | 2 ++ uefi/src/table/boot.rs | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/uefi/CHANGELOG.md b/uefi/CHANGELOG.md index e746ab9c9..7d57ab742 100644 --- a/uefi/CHANGELOG.md +++ b/uefi/CHANGELOG.md @@ -2,6 +2,8 @@ ## Changed - **Breaking:** `uefi::helpers::init` no longer takes an argument. +- The lifetime of the `SearchType` returned from + `BootServices::register_protocol_notify` is now tied to the protocol GUID. # uefi - 0.29.0 (2024-07-02) diff --git a/uefi/src/table/boot.rs b/uefi/src/table/boot.rs index 1a27de37c..f492f495e 100644 --- a/uefi/src/table/boot.rs +++ b/uefi/src/table/boot.rs @@ -683,11 +683,11 @@ impl BootServices { /// /// * [`uefi::Status::OUT_OF_RESOURCES`] /// * [`uefi::Status::INVALID_PARAMETER`] - pub fn register_protocol_notify( + pub fn register_protocol_notify<'guid>( &self, - protocol: &Guid, + protocol: &'guid Guid, event: Event, - ) -> Result<(Event, SearchType)> { + ) -> Result<(Event, SearchType<'guid>)> { let mut key = ptr::null(); // Safety: we clone `event` a couple times, but there will be only one left once we return. unsafe { (self.0.register_protocol_notify)(protocol, event.as_ptr(), &mut key) } From f83ff34e0c7b8c587ba74493c5b31f1c981f08b5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 00:50:27 +0000 Subject: [PATCH 05/56] chore(deps): lock file maintenance --- Cargo.lock | 88 +++++++++++++++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fecb0d9ec..1fc4c8a4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -97,9 +97,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.0.101" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d" +checksum = "5208975e568d83b6b05cc0a063c8e7e9acc2b43bee6da15616a5b73e109d7437" [[package]] name = "cfg-if" @@ -142,7 +142,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.69", ] [[package]] @@ -577,11 +577,12 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.4" +version = "0.23.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" dependencies = [ "log", + "once_cell", "ring", "rustls-pki-types", "rustls-webpki", @@ -597,9 +598,9 @@ checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "rustls-webpki" -version = "0.102.4" +version = "0.102.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78" dependencies = [ "ring", "rustls-pki-types", @@ -623,9 +624,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] @@ -641,20 +642,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.69", ] [[package]] name = "serde_json" -version = "1.0.118" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "itoa", "ryu", @@ -706,9 +707,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.68" +version = "2.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" +checksum = "201fcda3845c23e8212cd466bfebf0bd20694490fc0356ae8e428e0824a915a6" dependencies = [ "proc-macro2", "quote", @@ -770,14 +771,14 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.69", ] [[package]] name = "tinyvec" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82" +checksum = "ce6b6a2fb3a985e99cebfaefa9faa3024743da73304ca1c683a36429613d3d22" dependencies = [ "tinyvec_macros", ] @@ -824,9 +825,9 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.96" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33a5f13f11071020bb12de7a16b925d2d58636175c20c11dc5f96cb64bb6c9b3" +checksum = "5b1e5645f2ee8025c2f1d75e1138f2dd034d74e6ba54620f3c569ba2a2a1ea06" dependencies = [ "glob", "serde", @@ -872,7 +873,7 @@ version = "0.14.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.69", "trybuild", "uefi", ] @@ -937,9 +938,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.9.7" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d11a831e3c0b56e438a28308e7c810799e3c118417f342d30ecec080105395cd" +checksum = "72139d247e5f97a3eff96229a7ae85ead5328a39efe76f8bf5a06313d505b6ea" dependencies = [ "base64", "flate2", @@ -947,7 +948,6 @@ dependencies = [ "once_cell", "rustls", "rustls-pki-types", - "rustls-webpki", "url", "webpki-roots", ] @@ -1014,9 +1014,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -1030,51 +1030,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" @@ -1124,7 +1124,7 @@ dependencies = [ "regex", "serde_json", "sha2", - "syn 2.0.68", + "syn 2.0.69", "tar", "tempfile", "ureq", From 68267940726e47c31bd1d28acfc6a0b4c92bc84b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 03:01:08 +0000 Subject: [PATCH 06/56] chore(deps): update crate-ci/typos action to v1.23.1 --- .github/workflows/qa.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index 080857889..3765f53a8 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -7,4 +7,4 @@ jobs: steps: - uses: actions/checkout@v4 # Executes "typos ." - - uses: crate-ci/typos@v1.22.9 + - uses: crate-ci/typos@v1.23.1 From 3880ef5d92b10694df8442e5acce1fd9820101d0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 9 Jul 2024 02:16:31 +0000 Subject: [PATCH 07/56] fix(deps): update rust crate syn to v2.0.70 --- Cargo.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1fc4c8a4e..b2e21f711 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -142,7 +142,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -648,7 +648,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -707,9 +707,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.69" +version = "2.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201fcda3845c23e8212cd466bfebf0bd20694490fc0356ae8e428e0824a915a6" +checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" dependencies = [ "proc-macro2", "quote", @@ -771,7 +771,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -873,7 +873,7 @@ version = "0.14.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", "trybuild", "uefi", ] @@ -1124,7 +1124,7 @@ dependencies = [ "regex", "serde_json", "sha2", - "syn 2.0.69", + "syn 2.0.70", "tar", "tempfile", "ureq", From 2b2640f07f971f2afe703947a388e6831f6b647e Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Mon, 8 Jul 2024 23:11:35 -0400 Subject: [PATCH 08/56] logger: Remove some unnecessary cfgs This whole module is already gated by `cfg(feature = "logger")`, so no need to do that inside the module. --- uefi/src/helpers/logger.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/uefi/src/helpers/logger.rs b/uefi/src/helpers/logger.rs index b8d8cfa41..e6fd103f7 100644 --- a/uefi/src/helpers/logger.rs +++ b/uefi/src/helpers/logger.rs @@ -19,14 +19,12 @@ use core::ptr; use core::sync::atomic::{AtomicPtr, Ordering}; /// Global logger object -#[cfg(feature = "logger")] static LOGGER: Logger = Logger::new(); /// Set up logging /// /// This is unsafe because you must arrange for the logger to be reset with /// disable() on exit from UEFI boot services. -#[cfg(feature = "logger")] pub unsafe fn init(st: &mut SystemTable) { // Connect the logger to stdout. LOGGER.set_output(st.stdout()); From 52f53ef73c8d47900861279f4dafa01331ba49b7 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Sat, 13 Jul 2024 11:25:04 +0200 Subject: [PATCH 09/56] uefi: _print more failsafe When one accidentally call println! after exit_boot_services, one now at least gets some more debugging info why the machine suddenly reboots. Specifically, this prints now info to `integration-test-debugcon.log` in such a case. --- uefi/src/helpers/println.rs | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/uefi/src/helpers/println.rs b/uefi/src/helpers/println.rs index 2a30eb1d5..2b9903e92 100644 --- a/uefi/src/helpers/println.rs +++ b/uefi/src/helpers/println.rs @@ -4,14 +4,25 @@ use core::fmt::Write; /// INTERNAL API! Helper for print macros. #[doc(hidden)] pub fn _print(args: core::fmt::Arguments) { - system_table_boot() - .expect("boot services are not active") - .stdout() - .write_fmt(args) - .expect("Failed to write to stdout"); + if let Some(mut bs) = system_table_boot() { + bs.stdout() + .write_fmt(args) + .expect("Failed to write to stdout"); + } else { + // Ease debugging: Depending on logger, this might write to serial or + // debugcon. + log::debug!("You are using `print!` after the boot services have been exited."); + } } -/// Prints to the standard output. +/// Prints to the standard output of the UEFI boot service console. +/// +/// # Usage +/// Use this similar to `print!` from the Rust standard library, but only +/// as long as boot services have not been exited. +/// +/// You should never use this macro in a custom Logger ([`log::Log`] impl) to +/// prevent a circular runtime dependency. /// /// # Panics /// Will panic if `SYSTEM_TABLE` is `None` (Before [`uefi::helpers::init()`] and @@ -28,7 +39,15 @@ macro_rules! print { ($($arg:tt)*) => ($crate::helpers::_print(core::format_args!($($arg)*))); } -/// Prints to the standard output, with a newline. +/// Prints to the standard output of the UEFI boot service console, but with a +/// newline. +/// +/// # Usage +/// Use this similar to `println!` from the Rust standard library, but only +/// as long as boot services have not been exited. +/// +/// You should never use this macro in a custom Logger ([`log::Log`] impl) to +/// prevent a circular runtime dependency. /// /// # Panics /// Will panic if `SYSTEM_TABLE` is `None` (Before [`uefi::helpers::init()`] and From bcb91aaf25a8d757964e68f38db85614f83d10fa Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Mon, 8 Jul 2024 13:16:19 +0200 Subject: [PATCH 10/56] uefi: MemoryMap -> MemoryMapOwned --- uefi/src/table/boot.rs | 40 ++++++++++++++++++++-------------------- uefi/src/table/system.rs | 6 +++--- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/uefi/src/table/boot.rs b/uefi/src/table/boot.rs index f492f495e..0908ca8e4 100644 --- a/uefi/src/table/boot.rs +++ b/uefi/src/table/boot.rs @@ -222,7 +222,7 @@ impl BootServices { } /// Stores the current UEFI memory map in an UEFI-heap allocated buffer - /// and returns a [`MemoryMap`]. + /// and returns a [`MemoryMapOwned`]. /// /// # Parameters /// @@ -237,7 +237,7 @@ impl BootServices { /// /// * [`uefi::Status::BUFFER_TOO_SMALL`] /// * [`uefi::Status::INVALID_PARAMETER`] - pub fn memory_map(&self, mt: MemoryType) -> Result { + pub fn memory_map(&self, mt: MemoryType) -> Result { let mut buffer = MemoryMapBackingMemory::new(mt)?; let meta = self.get_memory_map(buffer.as_mut_slice())?; @@ -251,7 +251,7 @@ impl BootServices { let len = map_size / desc_size; assert_eq!(map_size % desc_size, 0); assert_eq!(desc_version, MemoryDescriptor::VERSION); - Ok(MemoryMap { + Ok(MemoryMapOwned { key: map_key, buf: buffer, meta, @@ -1663,7 +1663,7 @@ pub struct MemoryMapKey(usize); /// The type is intended to be used like this: /// 1. create it using [`MemoryMapBackingMemory::new`] /// 2. pass it to [`BootServices::get_memory_map`] -/// 3. construct a [`MemoryMap`] from it +/// 3. construct a [`MemoryMapOwned`] from it #[derive(Debug)] #[allow(clippy::len_without_is_empty)] // this type is never empty pub(crate) struct MemoryMapBackingMemory(NonNull<[u8]>); @@ -1807,11 +1807,11 @@ impl MemoryMapMeta { /// An accessory to the memory map that can be either iterated or /// indexed like an array. /// -/// A [`MemoryMap`] is always associated with the unique [`MemoryMapKey`] +/// A [`MemoryMapOwned`] is always associated with the unique [`MemoryMapKey`] /// contained in the struct. /// -/// To iterate over the entries, call [`MemoryMap::entries`]. To get a sorted -/// map, you manually have to call [`MemoryMap::sort`] first. +/// To iterate over the entries, call [`MemoryMapOwned::entries`]. To get a sorted +/// map, you manually have to call [`MemoryMapOwned::sort`] first. /// /// ## UEFI pitfalls /// **Please note** that when working with memory maps, the `entry_size` is @@ -1821,7 +1821,7 @@ impl MemoryMapMeta { /// /// [0]: https://github.com/tianocore/edk2/blob/7142e648416ff5d3eac6c6d607874805f5de0ca8/MdeModulePkg/Core/PiSmmCore/Page.c#L1059 #[derive(Debug)] -pub struct MemoryMap { +pub struct MemoryMapOwned { /// Backing memory, properly initialized at this point. buf: MemoryMapBackingMemory, key: MemoryMapKey, @@ -1829,13 +1829,13 @@ pub struct MemoryMap { len: usize, } -impl MemoryMap { - /// Creates a [`MemoryMap`] from the give initialized memory map behind +impl MemoryMapOwned { + /// Creates a [`MemoryMapOwned`] from the give initialized memory map behind /// the buffer and the reported `desc_size` from UEFI. pub(crate) fn from_initialized_mem(buf: MemoryMapBackingMemory, meta: MemoryMapMeta) -> Self { assert!(meta.desc_size >= mem::size_of::()); let len = meta.entry_count(); - MemoryMap { + MemoryMapOwned { key: MemoryMapKey(0), buf, meta, @@ -1935,7 +1935,7 @@ impl MemoryMap { /// Returns an [`MemoryMapIter`] emitting [`MemoryDescriptor`]s. /// - /// To get a sorted map, call [`MemoryMap::sort`] first. + /// To get a sorted map, call [`MemoryMapOwned::sort`] first. /// /// # UEFI pitfalls /// Currently, only the descriptor version specified in @@ -1995,7 +1995,7 @@ impl MemoryMap { } } -impl core::ops::Index for MemoryMap { +impl core::ops::Index for MemoryMapOwned { type Output = MemoryDescriptor; fn index(&self, index: usize) -> &Self::Output { @@ -2003,7 +2003,7 @@ impl core::ops::Index for MemoryMap { } } -impl core::ops::IndexMut for MemoryMap { +impl core::ops::IndexMut for MemoryMapOwned { fn index_mut(&mut self, index: usize) -> &mut Self::Output { self.get_mut(index).unwrap() } @@ -2013,7 +2013,7 @@ impl core::ops::IndexMut for MemoryMap { /// associated with a unique [`MemoryMapKey`]. #[derive(Debug, Clone)] pub struct MemoryMapIter<'a> { - memory_map: &'a MemoryMap, + memory_map: &'a MemoryMapOwned, index: usize, } @@ -2170,18 +2170,18 @@ pub struct ProtocolSearchKey(NonNull); mod tests_mmap_artificial { use core::mem::{size_of, size_of_val}; - use crate::table::boot::{MemoryAttribute, MemoryMap, MemoryType}; + use crate::table::boot::{MemoryAttribute, MemoryMapOwned, MemoryType}; use super::{MemoryDescriptor, MemoryMapIter}; - fn buffer_to_map(buffer: &mut [MemoryDescriptor]) -> MemoryMap { + fn buffer_to_map(buffer: &mut [MemoryDescriptor]) -> MemoryMapOwned { let byte_buffer = { unsafe { core::slice::from_raw_parts_mut(buffer.as_mut_ptr() as *mut u8, size_of_val(buffer)) } }; - MemoryMap::from_raw(byte_buffer, size_of::()) + MemoryMapOwned::from_raw(byte_buffer, size_of::()) } #[test] @@ -2269,7 +2269,7 @@ mod tests_mmap_artificial { } // Added for debug purposes on test failure - impl core::fmt::Display for MemoryMap { + impl core::fmt::Display for MemoryMapOwned { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { writeln!(f)?; for desc in self.entries() { @@ -2323,7 +2323,7 @@ mod tests_mmap_real { let mut buf = MMAP_RAW; let buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr().cast::(), MMAP_META.map_size) }; - let mut mmap = MemoryMap::from_raw(buf, MMAP_META.desc_size); + let mut mmap = MemoryMapOwned::from_raw(buf, MMAP_META.desc_size); mmap.sort(); let entries = mmap.entries().copied().collect::>(); diff --git a/uefi/src/table/system.rs b/uefi/src/table/system.rs index 014169110..986e9cef2 100644 --- a/uefi/src/table/system.rs +++ b/uefi/src/table/system.rs @@ -7,7 +7,7 @@ use uefi::table::boot::{MemoryMapBackingMemory, MemoryMapMeta}; use crate::proto::console::text; use crate::{CStr16, Result, Status, StatusExt}; -use super::boot::{BootServices, MemoryDescriptor, MemoryMap, MemoryType}; +use super::boot::{BootServices, MemoryDescriptor, MemoryMapOwned, MemoryType}; use super::runtime::{ResetType, RuntimeServices}; use super::{cfg, Revision}; @@ -230,7 +230,7 @@ impl SystemTable { pub unsafe fn exit_boot_services( self, memory_type: MemoryType, - ) -> (SystemTable, MemoryMap) { + ) -> (SystemTable, MemoryMapOwned) { crate::helpers::exit(); // Reboot the device. @@ -255,7 +255,7 @@ impl SystemTable { table: self.table, _marker: PhantomData, }; - return (st, MemoryMap::from_initialized_mem(buf, memory_map)); + return (st, MemoryMapOwned::from_initialized_mem(buf, memory_map)); } Err(err) => { log::error!("Error retrieving the memory map for exiting the boot services"); From ab6edf900a0fe0905f19cb7824779e3dfa1262f5 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Mon, 8 Jul 2024 13:41:52 +0200 Subject: [PATCH 11/56] uefi: introduce traits MemoryMap and MemoryMapMut --- uefi/src/table/boot.rs | 97 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/uefi/src/table/boot.rs b/uefi/src/table/boot.rs index 0908ca8e4..66e104f5a 100644 --- a/uefi/src/table/boot.rs +++ b/uefi/src/table/boot.rs @@ -11,7 +11,7 @@ use crate::{Char16, Error, Event, Guid, Handle, Result, Status, StatusExt}; use core::cell::UnsafeCell; use core::ffi::c_void; use core::mem::{self, MaybeUninit}; -use core::ops::{Deref, DerefMut}; +use core::ops::{Deref, DerefMut, Index, IndexMut}; use core::ptr::NonNull; use core::sync::atomic::{AtomicPtr, Ordering}; use core::{ptr, slice}; @@ -1804,6 +1804,101 @@ impl MemoryMapMeta { } } +/// An accessory to the UEFI memory map that can be either iterated or indexed +/// like an array. +/// +/// A [`MemoryMap`] is always associated with the unique [`MemoryMapKey`] +/// bundled with the ma. +/// +/// To iterate over the entries, call [`MemoryMap::entries`]. +/// +/// ## UEFI pitfalls +/// **Please note** that when working with memory maps, the `entry_size` is +/// usually larger than `size_of:: { + // TODO also require IntoIterator?! :) + + /// Returns the associated [`MemoryMapMeta`]. + #[must_use] + fn meta(&self) -> MemoryMapMeta; + + /// Returns the associated [`MemoryMapKey`]. + #[must_use] + fn key(&self) -> MemoryMapKey; + + /// Returns the number of keys in the map. + #[must_use] + fn len(&self) -> usize; + + /// Returns if the memory map is empty. + #[must_use] + fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns a reference to the [`MemoryDescriptor`] at the given index, if + /// present. + #[must_use] + fn get(&self, index: usize) -> Option<&MemoryDescriptor> { + if index >= self.len() { + None + } else { + let offset = index * self.meta().desc_size; + unsafe { + self.buffer() + .as_ptr() + .add(offset) + .cast::() + .as_ref() + } + } + } + + /// Returns a reference to the underlying memory. + fn buffer(&self) -> &[u8]; + + /// Returns an Iterator of type [`MemoryMapIter`]. + fn entries(&self) -> MemoryMapIter<'_>; +} + +/// Extension to [`MemoryMap`] that adds mutable operations. This also includes +/// the ability to sort the memory map. +pub trait MemoryMapMut: MemoryMap + IndexMut { + /// Returns a mutable reference to the [`MemoryDescriptor`] at the given + /// index, if present. + #[must_use] + fn get_mut(&mut self, index: usize) -> Option<&mut MemoryDescriptor> { + if index >= self.len() { + None + } else { + let offset = index * self.meta().desc_size; + unsafe { + self.buffer_mut() + .as_mut_ptr() + .add(offset) + .cast::() + .as_mut() + } + } + } + + /// Sorts the memory map by physical address in place. This operation is + /// optional and should be invoked only once. + #[must_use] + fn sort(&mut self); + + /// Returns a reference to the underlying memory. + /// + /// # Safety + /// + /// This is unsafe as there is a potential to create invalid entries. + unsafe fn buffer_mut(&self) -> &mut [u8]; +} + /// An accessory to the memory map that can be either iterated or /// indexed like an array. /// From 831d8b54eebbe166d6a351735833b6b7165bc9cf Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Mon, 8 Jul 2024 14:12:54 +0200 Subject: [PATCH 12/56] uefi: introduce types MemoryMapOwned, MemoryMapRef, and MemoryMapRefMut This provides API users all the flexibility they need. The main motivation for the addition is that one can use a chunk of memory in a kernel (provided by a bootloader) and parse it as EFI memory map. The main motivation for the specific implementation (via traits) is code reduction. --- uefi-test-runner/src/boot/memory.rs | 2 +- uefi-test-runner/src/main.rs | 2 +- uefi/src/table/boot.rs | 262 ++++++++++++++-------------- 3 files changed, 135 insertions(+), 131 deletions(-) diff --git a/uefi-test-runner/src/boot/memory.rs b/uefi-test-runner/src/boot/memory.rs index 133110b43..05e7897ca 100644 --- a/uefi-test-runner/src/boot/memory.rs +++ b/uefi-test-runner/src/boot/memory.rs @@ -1,4 +1,4 @@ -use uefi::table::boot::{AllocateType, BootServices, MemoryType}; +use uefi::table::boot::{AllocateType, BootServices, MemoryMap, MemoryMapMut, MemoryType}; use alloc::vec::Vec; diff --git a/uefi-test-runner/src/main.rs b/uefi-test-runner/src/main.rs index 56c90f7f6..129db54c7 100644 --- a/uefi-test-runner/src/main.rs +++ b/uefi-test-runner/src/main.rs @@ -12,7 +12,7 @@ use uefi::prelude::*; use uefi::proto::console::serial::Serial; use uefi::proto::device_path::build::{self, DevicePathBuilder}; use uefi::proto::device_path::messaging::Vendor; -use uefi::table::boot::MemoryType; +use uefi::table::boot::{MemoryMap, MemoryType}; use uefi::{print, println, Result}; mod boot; diff --git a/uefi/src/table/boot.rs b/uefi/src/table/boot.rs index 66e104f5a..89e3696d7 100644 --- a/uefi/src/table/boot.rs +++ b/uefi/src/table/boot.rs @@ -18,6 +18,7 @@ use core::{ptr, slice}; #[cfg(feature = "alloc")] use alloc::vec::Vec; +use core::fmt::Debug; pub use uefi_raw::table::boot::{ EventType, InterfaceType, MemoryAttribute, MemoryDescriptor, MemoryType, Tpl, @@ -1723,18 +1724,6 @@ impl MemoryMapBackingMemory { mmm.map_size + extra_size } - /// Returns a raw pointer to the beginning of the allocation. - #[must_use] - pub fn as_ptr(&self) -> *const u8 { - self.0.as_ptr().cast() - } - - /// Returns a mutable raw pointer to the beginning of the allocation. - #[must_use] - pub fn as_mut_ptr(&mut self) -> *mut u8 { - self.0.as_ptr().cast() - } - /// Returns a slice to the underlying memory. #[must_use] pub fn as_slice(&self) -> &[u8] { @@ -1819,7 +1808,7 @@ impl MemoryMapMeta { /// a low level. /// /// [0]: https://github.com/tianocore/edk2/blob/7142e648416ff5d3eac6c6d607874805f5de0ca8/MdeModulePkg/Core/PiSmmCore/Page.c#L1059 -pub trait MemoryMap: Index { +pub trait MemoryMap: Debug { // TODO also require IntoIterator?! :) /// Returns the associated [`MemoryMapMeta`]. @@ -1867,7 +1856,7 @@ pub trait MemoryMap: Index { /// Extension to [`MemoryMap`] that adds mutable operations. This also includes /// the ability to sort the memory map. -pub trait MemoryMapMut: MemoryMap + IndexMut { +pub trait MemoryMapMut: MemoryMap { /// Returns a mutable reference to the [`MemoryDescriptor`] at the given /// index, if present. #[must_use] @@ -1888,7 +1877,6 @@ pub trait MemoryMapMut: MemoryMap + IndexMut { /// Sorts the memory map by physical address in place. This operation is /// optional and should be invoked only once. - #[must_use] fn sort(&mut self); /// Returns a reference to the underlying memory. @@ -1896,76 +1884,90 @@ pub trait MemoryMapMut: MemoryMap + IndexMut { /// # Safety /// /// This is unsafe as there is a potential to create invalid entries. - unsafe fn buffer_mut(&self) -> &mut [u8]; + unsafe fn buffer_mut(&mut self) -> &mut [u8]; } -/// An accessory to the memory map that can be either iterated or -/// indexed like an array. -/// -/// A [`MemoryMapOwned`] is always associated with the unique [`MemoryMapKey`] -/// contained in the struct. -/// -/// To iterate over the entries, call [`MemoryMapOwned::entries`]. To get a sorted -/// map, you manually have to call [`MemoryMapOwned::sort`] first. -/// -/// ## UEFI pitfalls -/// **Please note** that when working with memory maps, the `entry_size` is -/// usually larger than `size_of:: { + buf: &'a [u8], key: MemoryMapKey, meta: MemoryMapMeta, len: usize, } -impl MemoryMapOwned { - /// Creates a [`MemoryMapOwned`] from the give initialized memory map behind - /// the buffer and the reported `desc_size` from UEFI. - pub(crate) fn from_initialized_mem(buf: MemoryMapBackingMemory, meta: MemoryMapMeta) -> Self { - assert!(meta.desc_size >= mem::size_of::()); - let len = meta.entry_count(); - MemoryMapOwned { - key: MemoryMapKey(0), - buf, - meta, - len, +impl<'a> MemoryMap for MemoryMapRef<'a> { + fn meta(&self) -> MemoryMapMeta { + self.meta + } + + fn key(&self) -> MemoryMapKey { + self.key + } + + fn len(&self) -> usize { + self.len + } + + fn buffer(&self) -> &[u8] { + self.buf + } + + fn entries(&self) -> MemoryMapIter<'_> { + MemoryMapIter { + memory_map: self, + index: 0, } } +} - #[cfg(test)] - fn from_raw(buf: &mut [u8], desc_size: usize) -> Self { - let mem = MemoryMapBackingMemory::from_slice(buf); - Self::from_initialized_mem( - mem, - MemoryMapMeta { - map_size: buf.len(), - desc_size, - map_key: MemoryMapKey(0), - desc_version: MemoryDescriptor::VERSION, - }, - ) +/// Implementation of [`MemoryMapMut`] for the given buffer. +#[derive(Debug)] +pub struct MemoryMapRefMut<'a> { + buf: &'a mut [u8], + key: MemoryMapKey, + meta: MemoryMapMeta, + len: usize, +} + +impl<'a> MemoryMap for MemoryMapRefMut<'a> { + fn meta(&self) -> MemoryMapMeta { + self.meta } - #[must_use] - /// Returns the unique [`MemoryMapKey`] associated with the memory map. - pub fn key(&self) -> MemoryMapKey { + fn key(&self) -> MemoryMapKey { self.key } - /// Sorts the memory map by physical address in place. - /// This operation is optional and should be invoked only once. - pub fn sort(&mut self) { + fn len(&self) -> usize { + self.len + } + + fn buffer(&self) -> &[u8] { + self.buf + } + + fn entries(&self) -> MemoryMapIter<'_> { + MemoryMapIter { + memory_map: self, + index: 0, + } + } +} + +impl<'a> MemoryMapMut for MemoryMapRefMut<'a> { + fn sort(&mut self) { unsafe { self.qsort(0, self.len - 1); } } + unsafe fn buffer_mut(&mut self) -> &mut [u8] { + self.buf + } +} + +impl<'a> MemoryMapRefMut<'a> { /// Hoare partition scheme for quicksort. /// Must be called with `low` and `high` being indices within bounds. unsafe fn qsort(&mut self, low: usize, high: usize) { @@ -2027,80 +2029,85 @@ impl MemoryMapOwned { let elem = unsafe { &*self.buf.as_ptr().add(offset).cast::() }; elem.phys_start } +} - /// Returns an [`MemoryMapIter`] emitting [`MemoryDescriptor`]s. - /// - /// To get a sorted map, call [`MemoryMapOwned::sort`] first. - /// - /// # UEFI pitfalls - /// Currently, only the descriptor version specified in - /// [`MemoryDescriptor`] is supported. This is going to change if the UEFI - /// spec ever introduces a new memory descriptor version. - #[must_use] - pub fn entries(&self) -> MemoryMapIter { - MemoryMapIter { - memory_map: self, - index: 0, - } - } +/// Implementation of [`MemoryMapMut`] that owns the buffer on the UEFI heap. +#[derive(Debug)] +pub struct MemoryMapOwned { + /// Backing memory, properly initialized at this point. + buf: MemoryMapBackingMemory, + key: MemoryMapKey, + meta: MemoryMapMeta, + len: usize, +} - /// Returns a reference to the [`MemoryDescriptor`] at `index` or `None` if out of bounds. - #[must_use] - pub fn get(&self, index: usize) -> Option<&MemoryDescriptor> { - if index >= self.len { - return None; +impl MemoryMapOwned { + /// Creates a [`MemoryMapOwned`] from the give initialized memory map behind + /// the buffer and the reported `desc_size` from UEFI. + pub(crate) fn from_initialized_mem(buf: MemoryMapBackingMemory, meta: MemoryMapMeta) -> Self { + assert!(meta.desc_size >= mem::size_of::()); + let len = meta.entry_count(); + MemoryMapOwned { + key: MemoryMapKey(0), + buf, + meta, + len, } + } - let desc = unsafe { - &*self - .buf - .as_ptr() - .add(self.meta.desc_size * index) - .cast::() - }; + #[cfg(test)] + fn from_raw(buf: &mut [u8], desc_size: usize) -> Self { + let mem = MemoryMapBackingMemory::from_slice(buf); + Self::from_initialized_mem( + mem, + MemoryMapMeta { + map_size: buf.len(), + desc_size, + map_key: MemoryMapKey(0), + desc_version: MemoryDescriptor::VERSION, + }, + ) + } +} - Some(desc) +impl MemoryMap for MemoryMapOwned { + fn meta(&self) -> MemoryMapMeta { + self.meta } - /// Returns a mut reference to the [`MemoryDescriptor`] at `index` or `None` if out of bounds. - #[must_use] - pub fn get_mut(&mut self, index: usize) -> Option<&mut MemoryDescriptor> { - if index >= self.len { - return None; - } + fn key(&self) -> MemoryMapKey { + self.key + } - let desc = unsafe { - &mut *self - .buf - .as_mut_ptr() - .add(self.meta.desc_size * index) - .cast::() - }; + fn len(&self) -> usize { + self.len + } - Some(desc) + fn buffer(&self) -> &[u8] { + self.buf.as_slice() } - /// Provides access to the raw memory map. - /// - /// This is for example useful if you want to embed the memory map into - /// another data structure, such as a Multiboot2 boot information. - #[must_use] - pub fn as_raw(&self) -> (&[u8], MemoryMapMeta) { - (self.buf.as_slice(), self.meta) + fn entries(&self) -> MemoryMapIter<'_> { + MemoryMapIter { + memory_map: self, + index: 0, + } } } -impl core::ops::Index for MemoryMapOwned { - type Output = MemoryDescriptor; - - fn index(&self, index: usize) -> &Self::Output { - self.get(index).unwrap() +impl MemoryMapMut for MemoryMapOwned { + fn sort(&mut self) { + let mut reference = MemoryMapRefMut { + buf: self.buf.as_mut_slice(), + key: self.key, + meta: self.meta, + len: self.len, + }; + reference.sort(); } -} -impl core::ops::IndexMut for MemoryMapOwned { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - self.get_mut(index).unwrap() + unsafe fn buffer_mut(&mut self) -> &mut [u8] { + self.buf.as_mut_slice() } } @@ -2108,7 +2115,7 @@ impl core::ops::IndexMut for MemoryMapOwned { /// associated with a unique [`MemoryMapKey`]. #[derive(Debug, Clone)] pub struct MemoryMapIter<'a> { - memory_map: &'a MemoryMapOwned, + memory_map: &'a dyn MemoryMap, index: usize, } @@ -2116,7 +2123,7 @@ impl<'a> Iterator for MemoryMapIter<'a> { type Item = &'a MemoryDescriptor; fn size_hint(&self) -> (usize, Option) { - let sz = self.memory_map.len - self.index; + let sz = self.memory_map.len() - self.index; (sz, Some(sz)) } @@ -2132,7 +2139,7 @@ impl<'a> Iterator for MemoryMapIter<'a> { impl ExactSizeIterator for MemoryMapIter<'_> { fn len(&self) -> usize { - self.memory_map.len + self.memory_map.len() } } @@ -2263,12 +2270,9 @@ pub struct ProtocolSearchKey(NonNull); #[cfg(test)] mod tests_mmap_artificial { + use super::*; use core::mem::{size_of, size_of_val}; - use crate::table::boot::{MemoryAttribute, MemoryMapOwned, MemoryType}; - - use super::{MemoryDescriptor, MemoryMapIter}; - fn buffer_to_map(buffer: &mut [MemoryDescriptor]) -> MemoryMapOwned { let byte_buffer = { unsafe { From 94bef930c8dbf7debd34430153ba2803585bba1f Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Mon, 8 Jul 2024 14:26:33 +0200 Subject: [PATCH 13/56] uefi: impl Index and IndexMut for MemoryMapOwned, MemoryMapRef, and MemoryMapRefMut --- uefi/src/table/boot.rs | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/uefi/src/table/boot.rs b/uefi/src/table/boot.rs index 89e3696d7..b81ab08b0 100644 --- a/uefi/src/table/boot.rs +++ b/uefi/src/table/boot.rs @@ -1921,6 +1921,14 @@ impl<'a> MemoryMap for MemoryMapRef<'a> { } } +impl Index for MemoryMapRef<'_> { + type Output = MemoryDescriptor; + + fn index(&self, index: usize) -> &Self::Output { + self.get(index).unwrap() + } +} + /// Implementation of [`MemoryMapMut`] for the given buffer. #[derive(Debug)] pub struct MemoryMapRefMut<'a> { @@ -2031,6 +2039,20 @@ impl<'a> MemoryMapRefMut<'a> { } } +impl Index for MemoryMapRefMut<'_> { + type Output = MemoryDescriptor; + + fn index(&self, index: usize) -> &Self::Output { + self.get(index).unwrap() + } +} + +impl IndexMut for MemoryMapRefMut<'_> { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.get_mut(index).unwrap() + } +} + /// Implementation of [`MemoryMapMut`] that owns the buffer on the UEFI heap. #[derive(Debug)] pub struct MemoryMapOwned { @@ -2111,6 +2133,20 @@ impl MemoryMapMut for MemoryMapOwned { } } +impl Index for MemoryMapOwned { + type Output = MemoryDescriptor; + + fn index(&self, index: usize) -> &Self::Output { + self.get(index).unwrap() + } +} + +impl IndexMut for MemoryMapOwned { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.get_mut(index).unwrap() + } +} + /// An iterator of [`MemoryDescriptor`]. The underlying memory map is always /// associated with a unique [`MemoryMapKey`]. #[derive(Debug, Clone)] @@ -2355,7 +2391,10 @@ mod tests_mmap_artificial { let mut mem_map = buffer_to_map(&mut buffer); for index in 0..3 { - assert_eq!(mem_map.get(index), BUFFER.get(index)) + assert_eq!(mem_map.get(index), BUFFER.get(index)); + + // Test Index impl + assert_eq!(Some(&mem_map[index]), BUFFER.get(index)); } let mut_desc = mem_map.get_mut(2).unwrap(); From 66c42bc7a4456ed0869da884a50d660022a45383 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Mon, 8 Jul 2024 14:30:20 +0200 Subject: [PATCH 14/56] doc: update changelog --- uefi/CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/uefi/CHANGELOG.md b/uefi/CHANGELOG.md index 7d57ab742..1c8c17482 100644 --- a/uefi/CHANGELOG.md +++ b/uefi/CHANGELOG.md @@ -4,6 +4,11 @@ - **Breaking:** `uefi::helpers::init` no longer takes an argument. - The lifetime of the `SearchType` returned from `BootServices::register_protocol_notify` is now tied to the protocol GUID. +- The traits `MemoryMap` and `MemoryMapMut` have been introduced together with + the implementations `MemoryMapRef`, `MemoryMapRefMut`, and `MemoryMapOwned`. + The old `MemoryMap` was renamed to `MemoryMapOwned`. + - `pub fn memory_map(&self, mt: MemoryType) -> Result` now returns + a `MemoryMapOwned`. # uefi - 0.29.0 (2024-07-02) From 8264e47d49bd8443b33161bd4f8bfa70692562bb Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Sun, 14 Jul 2024 09:09:54 +0200 Subject: [PATCH 15/56] uefi: cleanup --- uefi/src/table/boot.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uefi/src/table/boot.rs b/uefi/src/table/boot.rs index b81ab08b0..7166441d7 100644 --- a/uefi/src/table/boot.rs +++ b/uefi/src/table/boot.rs @@ -2455,7 +2455,7 @@ mod tests_mmap_real { 7, 1048576, 0, 1792, 15, 0, 10, 8388608, 0, 8, 15, 0, 7, 8421376, 0, 3, 15, 0, 10, 8433664, 0, 1, 15, 0, 7, 8437760, 0, 4, 15, 0, 10, 8454144, 0, 240, 15, 0, ]; - extern crate std; + #[test] fn basic_functionality() { let mut buf = MMAP_RAW; From db5e9c85a5423acd6360aac2c19d617a8406f349 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Sun, 14 Jul 2024 09:09:13 +0200 Subject: [PATCH 16/56] doc: improve description of MemoryMap --- uefi/src/table/boot.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/uefi/src/table/boot.rs b/uefi/src/table/boot.rs index 7166441d7..778e51b3b 100644 --- a/uefi/src/table/boot.rs +++ b/uefi/src/table/boot.rs @@ -1793,15 +1793,22 @@ impl MemoryMapMeta { } } -/// An accessory to the UEFI memory map that can be either iterated or indexed -/// like an array. +/// An accessory to the UEFI memory map and associated metadata that can be +/// either iterated or indexed like an array. /// /// A [`MemoryMap`] is always associated with the unique [`MemoryMapKey`] -/// bundled with the ma. +/// bundled with the map. /// /// To iterate over the entries, call [`MemoryMap::entries`]. /// /// ## UEFI pitfalls +/// Note that a MemoryMap can quickly become outdated, as soon as any explicit +/// or hidden allocation happens. +/// +/// As soon as boot services are excited, all previous obtained memory maps must +/// be considered as outdated, except if the [`MemoryMapKey`] equals the one +/// returned by `exit_boot_services()`. +/// /// **Please note** that when working with memory maps, the `entry_size` is /// usually larger than `size_of:: Date: Mon, 15 Jul 2024 00:31:13 +0000 Subject: [PATCH 17/56] chore(deps): update crate-ci/typos action to v1.23.2 --- .github/workflows/qa.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index 3765f53a8..77034cd2d 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -7,4 +7,4 @@ jobs: steps: - uses: actions/checkout@v4 # Executes "typos ." - - uses: crate-ci/typos@v1.23.1 + - uses: crate-ci/typos@v1.23.2 From 5cfc5f0dd44e38511acab5fc8881336e6e6fd55d Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 7 Jul 2024 22:36:05 -0400 Subject: [PATCH 18/56] uefi: Add table::system_table_raw_panicking This is `pub(crate)`, not part of the public API currently. --- uefi/src/table/mod.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/uefi/src/table/mod.rs b/uefi/src/table/mod.rs index 078c0f79f..cd837bba8 100644 --- a/uefi/src/table/mod.rs +++ b/uefi/src/table/mod.rs @@ -11,13 +11,25 @@ pub use header::Header; pub use system::{Boot, Runtime, SystemTable}; pub use uefi_raw::table::Revision; -use core::ptr; +use core::ptr::{self, NonNull}; use core::sync::atomic::{AtomicPtr, Ordering}; /// Global system table pointer. This is only modified by [`set_system_table`]. static SYSTEM_TABLE: AtomicPtr = AtomicPtr::new(ptr::null_mut()); +/// Get the raw system table pointer. This may only be called after +/// `set_system_table` has been used to set the global pointer. +/// +/// # Panics +/// +/// Panics if the global system table pointer is null. +#[track_caller] +pub(crate) fn system_table_raw_panicking() -> NonNull { + let ptr = SYSTEM_TABLE.load(Ordering::Acquire); + NonNull::new(ptr).expect("global system table pointer is not set") +} + /// Update the global system table pointer. /// /// This is called automatically in the `main` entry point as part of From 7758fe48f5f81c109218055fc4c74d8456eb17a2 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 20 Apr 2024 12:07:35 -0400 Subject: [PATCH 19/56] Add uefi::system module This is similar to existing methods of `SystemTable`, but as freestanding functions that use the global system table pointer. --- uefi/CHANGELOG.md | 4 ++ uefi/src/lib.rs | 1 + uefi/src/system.rs | 146 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 uefi/src/system.rs diff --git a/uefi/CHANGELOG.md b/uefi/CHANGELOG.md index 1c8c17482..d73714c5e 100644 --- a/uefi/CHANGELOG.md +++ b/uefi/CHANGELOG.md @@ -1,5 +1,9 @@ # uefi - [Unreleased] +## Added +- `uefi::system` is a new module that provides freestanding functions for + accessing fields of the global system table. + ## Changed - **Breaking:** `uefi::helpers::init` no longer takes an argument. - The lifetime of the `SearchType` returned from diff --git a/uefi/src/lib.rs b/uefi/src/lib.rs index fb658d7c3..a40d4edac 100644 --- a/uefi/src/lib.rs +++ b/uefi/src/lib.rs @@ -119,6 +119,7 @@ pub use uguid::guid; mod result; pub use result::{Error, Result, ResultExt, Status, StatusExt}; +pub mod system; pub mod table; pub mod proto; diff --git a/uefi/src/system.rs b/uefi/src/system.rs new file mode 100644 index 000000000..1d19f4f72 --- /dev/null +++ b/uefi/src/system.rs @@ -0,0 +1,146 @@ +//! Functions for accessing fields of the system table. +//! +//! Some of these functions use a callback argument rather than returning a +//! reference to the field directly. This pattern is used because some fields +//! are allowed to change, and so a static lifetime cannot be used. +//! +//! Some functions can only be called while boot services are active, and will +//! panic otherwise. See each function's documentation for details. + +use crate::proto::console::text::{Input, Output}; +use crate::table::cfg::ConfigTableEntry; +use crate::table::{self, Revision}; +use crate::{CStr16, Char16}; +use core::slice; + +/// Get the firmware vendor string. +#[must_use] +pub fn firmware_vendor() -> &'static CStr16 { + let st = table::system_table_raw_panicking(); + // SAFETY: valid per requirements of `set_system_table`. + let st = unsafe { st.as_ref() }; + + let vendor: *const Char16 = st.firmware_vendor.cast(); + + // SAFETY: this assumes that the firmware vendor string is never mutated or freed. + unsafe { CStr16::from_ptr(vendor) } +} + +/// Get the firmware revision. +#[must_use] +pub fn firmware_revision() -> u32 { + let st = table::system_table_raw_panicking(); + // SAFETY: valid per requirements of `set_system_table`. + let st = unsafe { st.as_ref() }; + + st.firmware_revision +} + +/// Get the revision of the system table, which is defined to be the revision of +/// the UEFI specification implemented by the firmware. +#[must_use] +pub fn uefi_revision() -> Revision { + let st = table::system_table_raw_panicking(); + // SAFETY: valid per requirements of `set_system_table`. + let st = unsafe { st.as_ref() }; + + st.header.revision +} + +/// Call `f` with a slice of [`ConfigTableEntry`]. Each entry provides access to +/// a vendor-specific table. +pub fn with_config_table(f: F) -> R +where + F: Fn(&[ConfigTableEntry]) -> R, +{ + let st = table::system_table_raw_panicking(); + // SAFETY: valid per requirements of `set_system_table`. + let st = unsafe { st.as_ref() }; + + let ptr: *const ConfigTableEntry = st.configuration_table.cast(); + let len = st.number_of_configuration_table_entries; + let slice = if ptr.is_null() { + &[] + } else { + unsafe { slice::from_raw_parts(ptr, len) } + }; + f(slice) +} + +/// Call `f` with the [`Input`] protocol attached to stdin. +/// +/// # Panics +/// +/// This function will panic if called after exiting boot services, or if stdin +/// is not available. +pub fn with_stdin(f: F) -> R +where + F: Fn(&mut Input) -> R, +{ + let st = table::system_table_raw_panicking(); + // SAFETY: valid per requirements of `set_system_table`. + let st = unsafe { st.as_ref() }; + // The I/O protocols cannot be used after exiting boot services. + assert!(!st.boot_services.is_null(), "boot services are not active"); + assert!(!st.stdin.is_null(), "stdin is not available"); + + let stdin: *mut Input = st.stdin.cast(); + + // SAFETY: `Input` is a `repr(transparent)` wrapper around the raw input + // type. The underlying pointer in the system table is assumed to be valid. + let stdin = unsafe { &mut *stdin }; + + f(stdin) +} + +/// Call `f` with the [`Output`] protocol attached to stdout. +/// +/// # Panics +/// +/// This function will panic if called after exiting boot services, or if stdout +/// is not available. +pub fn with_stdout(f: F) -> R +where + F: Fn(&mut Output) -> R, +{ + let st = table::system_table_raw_panicking(); + // SAFETY: valid per requirements of `set_system_table`. + let st = unsafe { st.as_ref() }; + // The I/O protocols cannot be used after exiting boot services. + assert!(!st.boot_services.is_null(), "boot services are not active"); + assert!(!st.stdout.is_null(), "stdout is not available"); + + let stdout: *mut Output = st.stdout.cast(); + + // SAFETY: `Output` is a `repr(transparent)` wrapper around the raw output + // type. The underlying pointer in the system table is assumed to be valid. + let stdout = unsafe { &mut *stdout }; + + f(stdout) +} + +/// Call `f` with the [`Output`] protocol attached to stderr. +/// +/// # Panics +/// +/// This function will panic if called after exiting boot services, or if stderr +/// is not available. +pub fn with_stderr(f: F) -> R +where + F: Fn(&mut Output) -> R, +{ + let st = table::system_table_raw_panicking(); + // SAFETY: valid per requirements of `set_system_table`. + let st = unsafe { st.as_ref() }; + // The I/O protocols cannot be used after exiting boot services. + assert!(!st.boot_services.is_null(), "boot services are not active"); + assert!(!st.stderr.is_null(), "stderr is not available"); + + let stderr: *mut Output = st.stderr.cast(); + + // SAFETY: `Output` is a `repr(transparent)` wrapper around the raw output + // type. The underlying pointer in the system table is assumed to be valid. + let stderr = unsafe { &mut *stderr }; + + f(stderr) +} From fc637c8713f4e5522b62195ff649e15fabf1c927 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 13 Jul 2024 13:05:20 -0400 Subject: [PATCH 20/56] uefi: Add standard derives for ConfigTableEntry --- uefi/CHANGELOG.md | 1 + uefi/src/table/cfg.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/uefi/CHANGELOG.md b/uefi/CHANGELOG.md index d73714c5e..5119d3547 100644 --- a/uefi/CHANGELOG.md +++ b/uefi/CHANGELOG.md @@ -3,6 +3,7 @@ ## Added - `uefi::system` is a new module that provides freestanding functions for accessing fields of the global system table. +- Add standard derives for `ConfigTableEntry`. ## Changed - **Breaking:** `uefi::helpers::init` no longer takes an argument. diff --git a/uefi/src/table/cfg.rs b/uefi/src/table/cfg.rs index d5f5fb569..c6f19df94 100644 --- a/uefi/src/table/cfg.rs +++ b/uefi/src/table/cfg.rs @@ -14,7 +14,7 @@ use core::ffi::c_void; /// Contains a set of GUID / pointer for a vendor-specific table. /// /// The UEFI standard guarantees each entry is unique. -#[derive(Debug)] +#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(C)] pub struct ConfigTableEntry { /// The GUID identifying this table. From 46e47c7f1b1cb7e413fa8cd5fcddb3af9f72d404 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 13 Jul 2024 13:05:38 -0400 Subject: [PATCH 21/56] test-runner: Test the uefi::system module --- uefi-test-runner/src/main.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/uefi-test-runner/src/main.rs b/uefi-test-runner/src/main.rs index 129db54c7..09853acdd 100644 --- a/uefi-test-runner/src/main.rs +++ b/uefi-test-runner/src/main.rs @@ -13,7 +13,7 @@ use uefi::proto::console::serial::Serial; use uefi::proto::device_path::build::{self, DevicePathBuilder}; use uefi::proto::device_path::messaging::Vendor; use uefi::table::boot::{MemoryMap, MemoryType}; -use uefi::{print, println, Result}; +use uefi::{print, println, system, Result}; mod boot; mod fs; @@ -45,6 +45,9 @@ fn efi_main(image: Handle, mut st: SystemTable) -> Status { // Ensure the tests are run on a version of UEFI we support. check_revision(st.uefi_revision()); + // Check the `uefi::system` module. + check_system(&st); + // Test all the boot services. let bt = st.boot_services(); @@ -67,6 +70,8 @@ fn efi_main(image: Handle, mut st: SystemTable) -> Status { } fn check_revision(rev: uefi::table::Revision) { + assert_eq!(system::uefi_revision(), rev); + let (major, minor) = (rev.major(), rev.minor()); info!("UEFI {}.{}", major, minor / 10); @@ -78,6 +83,25 @@ fn check_revision(rev: uefi::table::Revision) { ); } +fn check_system(st: &SystemTable) { + assert_eq!(system::firmware_vendor(), cstr16!("EDK II")); + check_revision(system::uefi_revision()); + + assert_eq!(system::firmware_revision(), st.firmware_revision()); + system::with_config_table(|t| assert_eq!(t, st.config_table())); + + system::with_stdout(|stdout| { + stdout + .output_string(cstr16!("test system::with_stdout\n")) + .unwrap() + }); + system::with_stderr(|stdout| { + stdout + .output_string(cstr16!("test system::with_stderr\n")) + .unwrap() + }); +} + #[derive(Clone, Copy, Debug)] enum HostRequest { /// Tell the host to take a screenshot and compare against the From 1c68af3c525e796dfc3e8f570aa6fc01ba92fc2d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Jul 2024 00:44:44 +0000 Subject: [PATCH 22/56] chore(deps): lock file maintenance --- Cargo.lock | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b2e21f711..b5408d2ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -97,9 +97,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.0.105" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5208975e568d83b6b05cc0a063c8e7e9acc2b43bee6da15616a5b73e109d7437" +checksum = "9711f33475c22aab363b05564a17d7b789bf3dfec5ebabb586adee56f0e271b5" [[package]] name = "cfg-if" @@ -115,9 +115,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "clap" -version = "4.5.8" +version = "4.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d" +checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462" dependencies = [ "clap_builder", "clap_derive", @@ -125,9 +125,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.8" +version = "4.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708" +checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" dependencies = [ "anstyle", "clap_lex", @@ -142,7 +142,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -577,9 +577,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.10" +version = "0.23.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +checksum = "4828ea528154ae444e5a642dbb7d5623354030dc9822b83fd9bb79683c7399d0" dependencies = [ "log", "once_cell", @@ -648,7 +648,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -707,9 +707,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.70" +version = "2.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" +checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" dependencies = [ "proc-macro2", "quote", @@ -756,29 +756,29 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] name = "tinyvec" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6b6a2fb3a985e99cebfaefa9faa3024743da73304ca1c683a36429613d3d22" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -812,9 +812,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.14" +version = "0.22.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" +checksum = "d59a3a72298453f564e2b111fa896f8d07fabb36f51f06d7e875fc5e0b5a3ef1" dependencies = [ "indexmap", "serde", @@ -873,7 +873,7 @@ version = "0.14.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", "trybuild", "uefi", ] @@ -1124,7 +1124,7 @@ dependencies = [ "regex", "serde_json", "sha2", - "syn 2.0.70", + "syn 2.0.71", "tar", "tempfile", "ureq", From 2cd0d9180d9541944c7ce8582a81a3d4f5c6328f Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 14 Jul 2024 23:34:00 -0400 Subject: [PATCH 23/56] tcg: PcrEvent/PcrEventInputs: impl Align This is needed for make_boxed. --- uefi/src/proto/tcg/v1.rs | 8 +++++++- uefi/src/proto/tcg/v2.rs | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/uefi/src/proto/tcg/v1.rs b/uefi/src/proto/tcg/v1.rs index 7f0226806..d67665538 100644 --- a/uefi/src/proto/tcg/v1.rs +++ b/uefi/src/proto/tcg/v1.rs @@ -9,7 +9,7 @@ //! [TPM]: https://en.wikipedia.org/wiki/Trusted_Platform_Module use super::{AlgorithmId, EventType, HashAlgorithm, PcrIndex}; -use crate::data_types::PhysicalAddress; +use crate::data_types::{Align, PhysicalAddress}; use crate::polyfill::maybe_uninit_slice_as_mut_ptr; use crate::proto::unsafe_protocol; use crate::util::{ptr_write_unaligned_and_add, usize_from_u32}; @@ -200,6 +200,12 @@ impl PcrEvent { } } +impl Align for PcrEvent { + fn alignment() -> usize { + 1 + } +} + // Manual `Debug` implementation since it can't be derived for a packed DST. impl Debug for PcrEvent { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { diff --git a/uefi/src/proto/tcg/v2.rs b/uefi/src/proto/tcg/v2.rs index 86b3bb39c..324a3748d 100644 --- a/uefi/src/proto/tcg/v2.rs +++ b/uefi/src/proto/tcg/v2.rs @@ -11,7 +11,7 @@ //! [TPM]: https://en.wikipedia.org/wiki/Trusted_Platform_Module use super::{v1, AlgorithmId, EventType, HashAlgorithm, PcrIndex}; -use crate::data_types::{PhysicalAddress, UnalignedSlice}; +use crate::data_types::{Align, PhysicalAddress, UnalignedSlice}; use crate::proto::unsafe_protocol; use crate::util::{ptr_write_unaligned_and_add, usize_from_u32}; use crate::{Error, Result, Status, StatusExt}; @@ -213,6 +213,12 @@ impl PcrEventInputs { } } +impl Align for PcrEventInputs { + fn alignment() -> usize { + 1 + } +} + impl Debug for PcrEventInputs { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("PcrEventInputs") From 373c4eafc5de137859e33c1ecdc41a07d8e0ee3e Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 14 Jul 2024 23:39:16 -0400 Subject: [PATCH 24/56] tcg: PcrEvent/PcrEventInputs: return required size on error This is needed for make_boxed. --- uefi/src/proto/tcg/v1.rs | 10 +++++----- uefi/src/proto/tcg/v2.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/uefi/src/proto/tcg/v1.rs b/uefi/src/proto/tcg/v1.rs index d67665538..2700457ae 100644 --- a/uefi/src/proto/tcg/v1.rs +++ b/uefi/src/proto/tcg/v1.rs @@ -128,7 +128,7 @@ impl PcrEvent { /// # Errors /// /// Returns [`Status::BUFFER_TOO_SMALL`] if the `buffer` is not large - /// enough. + /// enough. The required size will be returned in the error data. /// /// Returns [`Status::INVALID_PARAMETER`] if the `event_data` size is too /// large. @@ -138,9 +138,9 @@ impl PcrEvent { event_type: EventType, digest: Sha1Digest, event_data: &[u8], - ) -> Result<&'buf mut Self> { - let event_data_size = - u32::try_from(event_data.len()).map_err(|_| Error::from(Status::INVALID_PARAMETER))?; + ) -> Result<&'buf mut Self, Option> { + let event_data_size = u32::try_from(event_data.len()) + .map_err(|_| Error::new(Status::INVALID_PARAMETER, None))?; let required_size = mem::size_of::() + mem::size_of::() @@ -149,7 +149,7 @@ impl PcrEvent { + event_data.len(); if buffer.len() < required_size { - return Err(Status::BUFFER_TOO_SMALL.into()); + return Err(Error::new(Status::BUFFER_TOO_SMALL, Some(required_size))); } let mut ptr: *mut u8 = maybe_uninit_slice_as_mut_ptr(buffer); diff --git a/uefi/src/proto/tcg/v2.rs b/uefi/src/proto/tcg/v2.rs index 324a3748d..fba342872 100644 --- a/uefi/src/proto/tcg/v2.rs +++ b/uefi/src/proto/tcg/v2.rs @@ -172,7 +172,7 @@ impl PcrEventInputs { /// # Errors /// /// Returns [`Status::BUFFER_TOO_SMALL`] if the `buffer` is not large - /// enough. + /// enough. The required size will be returned in the error data. /// /// Returns [`Status::INVALID_PARAMETER`] if the `event_data` size is too /// large. @@ -181,15 +181,15 @@ impl PcrEventInputs { pcr_index: PcrIndex, event_type: EventType, event_data: &[u8], - ) -> Result<&'buf Self> { + ) -> Result<&'buf Self, Option> { let required_size = mem::size_of::() + mem::size_of::() + event_data.len(); if buffer.len() < required_size { - return Err(Status::BUFFER_TOO_SMALL.into()); + return Err(Error::new(Status::BUFFER_TOO_SMALL, Some(required_size))); } - let size_field = - u32::try_from(required_size).map_err(|_| Error::from(Status::INVALID_PARAMETER))?; + let size_field = u32::try_from(required_size) + .map_err(|_| Error::new(Status::INVALID_PARAMETER, None))?; let mut ptr: *mut u8 = buffer.as_mut_ptr().cast(); From d83e1d57055ff14b2c05f3583eb7a30d1743e1ef Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 14 Jul 2024 23:47:57 -0400 Subject: [PATCH 25/56] tcg: PcrEvent/PcrEventInputs: use initialized buf for input This is needed for make_boxed. Technically it's slightly less efficient, since the input buf must now be initialized, but in practice these structs are quite small and not created all that often, so there's no meaningful difference. --- uefi-test-runner/src/proto/tcg.rs | 5 ++--- uefi/src/proto/tcg/v1.rs | 10 ++++------ uefi/src/proto/tcg/v2.rs | 5 ++--- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/uefi-test-runner/src/proto/tcg.rs b/uefi-test-runner/src/proto/tcg.rs index 21e0cce55..b74772578 100644 --- a/uefi-test-runner/src/proto/tcg.rs +++ b/uefi-test-runner/src/proto/tcg.rs @@ -1,5 +1,4 @@ use alloc::vec::Vec; -use core::mem::MaybeUninit; use uefi::proto::tcg::{v1, v2, AlgorithmId, EventType, HashAlgorithm, PcrIndex}; use uefi::table::boot::BootServices; @@ -63,7 +62,7 @@ fn test_tcg_v1(bt: &BootServices) { let pcr_index = PcrIndex(8); - let mut event_buf = [MaybeUninit::uninit(); 256]; + let mut event_buf = [0; 256]; let event = v1::PcrEvent::new_in_buffer( &mut event_buf, pcr_index, @@ -279,7 +278,7 @@ pub fn test_tcg_v2(bt: &BootServices) { // Create a PCR event. let pcr_index = PcrIndex(8); - let mut event_buf = [MaybeUninit::uninit(); 256]; + let mut event_buf = [0; 256]; let event_data = [0x12, 0x13, 0x14, 0x15]; let data_to_hash = b"some-data"; let event = diff --git a/uefi/src/proto/tcg/v1.rs b/uefi/src/proto/tcg/v1.rs index 2700457ae..45a8d73ae 100644 --- a/uefi/src/proto/tcg/v1.rs +++ b/uefi/src/proto/tcg/v1.rs @@ -10,14 +10,12 @@ use super::{AlgorithmId, EventType, HashAlgorithm, PcrIndex}; use crate::data_types::{Align, PhysicalAddress}; -use crate::polyfill::maybe_uninit_slice_as_mut_ptr; use crate::proto::unsafe_protocol; use crate::util::{ptr_write_unaligned_and_add, usize_from_u32}; use crate::{Error, Result, Status, StatusExt}; use core::fmt::{self, Debug, Formatter}; use core::marker::PhantomData; -use core::mem::{self, MaybeUninit}; -use core::ptr; +use core::{mem, ptr}; use ptr_meta::Pointee; /// 20-byte SHA-1 digest. @@ -133,7 +131,7 @@ impl PcrEvent { /// Returns [`Status::INVALID_PARAMETER`] if the `event_data` size is too /// large. pub fn new_in_buffer<'buf>( - buffer: &'buf mut [MaybeUninit], + buffer: &'buf mut [u8], pcr_index: PcrIndex, event_type: EventType, digest: Sha1Digest, @@ -152,7 +150,7 @@ impl PcrEvent { return Err(Error::new(Status::BUFFER_TOO_SMALL, Some(required_size))); } - let mut ptr: *mut u8 = maybe_uninit_slice_as_mut_ptr(buffer); + let mut ptr: *mut u8 = buffer.as_mut_ptr().cast(); unsafe { ptr_write_unaligned_and_add(&mut ptr, pcr_index); @@ -539,7 +537,7 @@ mod tests { #[test] fn test_new_pcr_event() { - let mut event_buf = [MaybeUninit::uninit(); 256]; + let mut event_buf = [0; 256]; #[rustfmt::skip] let digest = [ 0x00, 0x01, 0x02, 0x03, diff --git a/uefi/src/proto/tcg/v2.rs b/uefi/src/proto/tcg/v2.rs index fba342872..b3fbf5e71 100644 --- a/uefi/src/proto/tcg/v2.rs +++ b/uefi/src/proto/tcg/v2.rs @@ -18,7 +18,6 @@ use crate::{Error, Result, Status, StatusExt}; use bitflags::bitflags; use core::fmt::{self, Debug, Formatter}; use core::marker::PhantomData; -use core::mem::MaybeUninit; use core::{mem, ptr, slice}; use ptr_meta::{Pointee, PtrExt}; @@ -177,7 +176,7 @@ impl PcrEventInputs { /// Returns [`Status::INVALID_PARAMETER`] if the `event_data` size is too /// large. pub fn new_in_buffer<'buf>( - buffer: &'buf mut [MaybeUninit], + buffer: &'buf mut [u8], pcr_index: PcrIndex, event_type: EventType, event_data: &[u8], @@ -791,7 +790,7 @@ mod tests { #[test] fn test_new_event() { - let mut buf = [MaybeUninit::uninit(); 22]; + let mut buf = [0; 22]; let event_data = [0x12, 0x13, 0x14, 0x15]; let event = PcrEventInputs::new_in_buffer(&mut buf, PcrIndex(4), EventType::IPL, &event_data) From 6bead2e37aa59dc89a1891fac44f3dba02baebe1 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 14 Jul 2024 23:51:35 -0400 Subject: [PATCH 26/56] tcg: Impl Eq/PartialEq for PcrEventInputs A manual implementation is required since this is a packed struct. --- uefi/src/proto/tcg/v2.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/uefi/src/proto/tcg/v2.rs b/uefi/src/proto/tcg/v2.rs index b3fbf5e71..af3b96f39 100644 --- a/uefi/src/proto/tcg/v2.rs +++ b/uefi/src/proto/tcg/v2.rs @@ -157,7 +157,7 @@ struct EventHeader { /// `TCG_PCR_EVENT2` for reading events. To help clarify the usage, our /// API renames these types to `PcrEventInputs` and `PcrEvent`, /// respectively. -#[derive(Pointee)] +#[derive(Eq, Pointee)] #[repr(C, packed)] pub struct PcrEventInputs { size: u32, @@ -228,6 +228,15 @@ impl Debug for PcrEventInputs { } } +// Manual `PartialEq` implementation since it can't be derived for a packed DST. +impl PartialEq for PcrEventInputs { + fn eq(&self, other: &PcrEventInputs) -> bool { + self.size == other.size + && self.event_header == other.event_header + && self.event == other.event + } +} + #[repr(C, packed)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct AlgorithmDigestSize { From 6c726f3836559162b890ff82b59152e812e3fbad Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 14 Jul 2024 23:49:43 -0400 Subject: [PATCH 27/56] tcg: Return a mut ref from PcrEventInputs::new_in_buffer This is needed for make_boxed. --- uefi/src/proto/tcg/v2.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/uefi/src/proto/tcg/v2.rs b/uefi/src/proto/tcg/v2.rs index af3b96f39..1c27d67c9 100644 --- a/uefi/src/proto/tcg/v2.rs +++ b/uefi/src/proto/tcg/v2.rs @@ -180,7 +180,7 @@ impl PcrEventInputs { pcr_index: PcrIndex, event_type: EventType, event_data: &[u8], - ) -> Result<&'buf Self, Option> { + ) -> Result<&'buf mut Self, Option> { let required_size = mem::size_of::() + mem::size_of::() + event_data.len(); @@ -205,9 +205,9 @@ impl PcrEventInputs { ); ptr::copy(event_data.as_ptr(), ptr, event_data.len()); - let ptr: *const PcrEventInputs = - ptr_meta::from_raw_parts(buffer.as_ptr().cast(), event_data.len()); - Ok(&*ptr) + let ptr: *mut PcrEventInputs = + ptr_meta::from_raw_parts_mut(buffer.as_mut_ptr().cast(), event_data.len()); + Ok(&mut *ptr) } } } From 2e0be2a7c1be01f260801d382b71da83e34a4e0c Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 14 Jul 2024 23:58:56 -0400 Subject: [PATCH 28/56] tcg: PcrEvent/PcrEventInputs: add new_in_box constructors --- uefi/src/proto/tcg/v1.rs | 38 ++++++++++++++++++++++++++++++++++++++ uefi/src/proto/tcg/v2.rs | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/uefi/src/proto/tcg/v1.rs b/uefi/src/proto/tcg/v1.rs index 45a8d73ae..0fc55a7da 100644 --- a/uefi/src/proto/tcg/v1.rs +++ b/uefi/src/proto/tcg/v1.rs @@ -18,6 +18,12 @@ use core::marker::PhantomData; use core::{mem, ptr}; use ptr_meta::Pointee; +#[cfg(feature = "alloc")] +use {crate::mem::make_boxed, alloc::boxed::Box}; + +#[cfg(all(feature = "unstable", feature = "alloc"))] +use {alloc::alloc::Global, core::alloc::Allocator}; + /// 20-byte SHA-1 digest. pub type Sha1Digest = [u8; 20]; @@ -165,6 +171,32 @@ impl PcrEvent { } } + /// Create a new `PcrEvent` in a [`Box`]. + /// + /// # Errors + /// + /// Returns [`Status::INVALID_PARAMETER`] if the `event_data` size is too + /// large. + #[cfg(feature = "alloc")] + pub fn new_in_box( + pcr_index: PcrIndex, + event_type: EventType, + digest: Sha1Digest, + event_data: &[u8], + ) -> Result> { + #[cfg(not(feature = "unstable"))] + { + make_boxed(|buf| Self::new_in_buffer(buf, pcr_index, event_type, digest, event_data)) + } + #[cfg(feature = "unstable")] + { + make_boxed( + |buf| Self::new_in_buffer(buf, pcr_index, event_type, digest, event_data), + Global, + ) + } + } + /// PCR index for the event. #[must_use] pub fn pcr_index(&self) -> PcrIndex { @@ -575,6 +607,12 @@ mod tests { // Event data 0x14, 0x15, 0x16, 0x17, ]); + + // Check that `new_in_box` gives the same value. + assert_eq!( + event, + &*PcrEvent::new_in_box(PcrIndex(4), EventType::IPL, digest, &data).unwrap() + ); } #[test] diff --git a/uefi/src/proto/tcg/v2.rs b/uefi/src/proto/tcg/v2.rs index 1c27d67c9..df762f311 100644 --- a/uefi/src/proto/tcg/v2.rs +++ b/uefi/src/proto/tcg/v2.rs @@ -21,6 +21,12 @@ use core::marker::PhantomData; use core::{mem, ptr, slice}; use ptr_meta::{Pointee, PtrExt}; +#[cfg(feature = "alloc")] +use {crate::mem::make_boxed, alloc::boxed::Box}; + +#[cfg(all(feature = "unstable", feature = "alloc"))] +use {alloc::alloc::Global, core::alloc::Allocator}; + /// Version information. /// /// Layout compatible with the C type `EFI_TG2_VERSION`. @@ -210,6 +216,31 @@ impl PcrEventInputs { Ok(&mut *ptr) } } + + /// Create a new `PcrEventInputs` in a [`Box`]. + /// + /// # Errors + /// + /// Returns [`Status::INVALID_PARAMETER`] if the `event_data` size is too + /// large. + #[cfg(feature = "alloc")] + pub fn new_in_box( + pcr_index: PcrIndex, + event_type: EventType, + event_data: &[u8], + ) -> Result> { + #[cfg(not(feature = "unstable"))] + { + make_boxed(|buf| Self::new_in_buffer(buf, pcr_index, event_type, event_data)) + } + #[cfg(feature = "unstable")] + { + make_boxed( + |buf| Self::new_in_buffer(buf, pcr_index, event_type, event_data), + Global, + ) + } + } } impl Align for PcrEventInputs { @@ -838,6 +869,12 @@ mod tests { // Event data 0x12, 0x13, 0x14, 0x15, ]); + + // Check that `new_in_box` gives the same value. + assert_eq!( + event, + &*PcrEventInputs::new_in_box(PcrIndex(4), EventType::IPL, &event_data).unwrap() + ); } #[test] From 8bc76055948e6d9de0fd7c5ba2831a7ccc2fd3a1 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Mon, 15 Jul 2024 00:10:00 -0400 Subject: [PATCH 29/56] uefi: Update changelog --- uefi/CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/uefi/CHANGELOG.md b/uefi/CHANGELOG.md index 5119d3547..c00f2a651 100644 --- a/uefi/CHANGELOG.md +++ b/uefi/CHANGELOG.md @@ -4,6 +4,8 @@ - `uefi::system` is a new module that provides freestanding functions for accessing fields of the global system table. - Add standard derives for `ConfigTableEntry`. +- `PcrEvent`/`PcrEventInputs` impl `Align`, `Eq`, and `PartialEq`. +- Added `PcrEvent::new_in_box` and `PcrEventInputs::new_in_box`. ## Changed - **Breaking:** `uefi::helpers::init` no longer takes an argument. @@ -14,6 +16,9 @@ The old `MemoryMap` was renamed to `MemoryMapOwned`. - `pub fn memory_map(&self, mt: MemoryType) -> Result` now returns a `MemoryMapOwned`. +- **Breaking:** `PcrEvent::new_in_buffer` and `PcrEventInputs::new_in_buffer` + now take an initialized buffer (`[u8`] instead of `[MaybeUninit]`), and if + the buffer is too small the required size is returned in the error data. # uefi - 0.29.0 (2024-07-02) From ccf9897101a566552220947e2742a0dba9354150 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Wed, 17 Jul 2024 12:06:07 -0400 Subject: [PATCH 30/56] boot: Always impl Drop for MemoryMapBackingMemory Gating this on `cfg(not(test))` isn't necessary; during unit tests `system_table_boot()` will return `None` and so the drop won't do anything anyway. Also fix a typo, excited -> exited. --- uefi/src/table/boot.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/uefi/src/table/boot.rs b/uefi/src/table/boot.rs index 778e51b3b..79c2c50ec 100644 --- a/uefi/src/table/boot.rs +++ b/uefi/src/table/boot.rs @@ -1737,8 +1737,6 @@ impl MemoryMapBackingMemory { } } -// Don't drop when we use this in unit tests. -#[cfg(not(test))] impl Drop for MemoryMapBackingMemory { fn drop(&mut self) { if let Some(bs) = system_table_boot() { @@ -1747,7 +1745,7 @@ impl Drop for MemoryMapBackingMemory { log::error!("Failed to deallocate memory map: {e:?}"); } } else { - log::debug!("Boot services are excited. Memory map won't be freed using the UEFI boot services allocator."); + log::debug!("Boot services are exited. Memory map won't be freed using the UEFI boot services allocator."); } } } From 233a33abc3538df113716c3030abbd9eb556f3f5 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Fri, 19 Jul 2024 11:50:36 -0400 Subject: [PATCH 31/56] Add uefi::runtime module The initial version here just provides functions for getting and setting the system time. Later commits will add functions to get/set variables, handle update capsules, etc. Also added some tests for the new code in the test runner (note that there were no existing tests for the time-related functions of `RuntimeServices`). --- uefi-test-runner/src/runtime/mod.rs | 32 +++++++++++++++- uefi/CHANGELOG.md | 2 + uefi/src/lib.rs | 1 + uefi/src/runtime.rs | 57 +++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 uefi/src/runtime.rs diff --git a/uefi-test-runner/src/runtime/mod.rs b/uefi-test-runner/src/runtime/mod.rs index 9babae774..92769bfe4 100644 --- a/uefi-test-runner/src/runtime/mod.rs +++ b/uefi-test-runner/src/runtime/mod.rs @@ -1,8 +1,38 @@ +mod vars; + +use uefi::runtime::{self, Daylight, Time, TimeParams}; use uefi::table::runtime::RuntimeServices; pub fn test(rt: &RuntimeServices) { info!("Testing runtime services"); vars::test(rt); + test_time(); } -mod vars; +fn test_time() { + // Print the current time and time capabilities. + info!( + "Time with caps: {:?}", + runtime::get_time_and_caps().unwrap() + ); + + // Set the time. + let time = Time::new(TimeParams { + year: 2020, + month: 1, + day: 2, + hour: 3, + minute: 4, + second: 5, + nanosecond: 6, + time_zone: None, + daylight: Daylight::ADJUST_DAYLIGHT, + }) + .unwrap(); + unsafe { runtime::set_time(&time).unwrap() }; + + // Print the new time and check that the year was successfully changed. + let now = runtime::get_time().unwrap(); + info!("After setting time: {}", now); + assert_eq!(now.year(), 2020); +} diff --git a/uefi/CHANGELOG.md b/uefi/CHANGELOG.md index c00f2a651..c757db4fb 100644 --- a/uefi/CHANGELOG.md +++ b/uefi/CHANGELOG.md @@ -3,6 +3,8 @@ ## Added - `uefi::system` is a new module that provides freestanding functions for accessing fields of the global system table. +- `uefi::runtime` is a new module that provides freestanding functions for + runtime services using the global system table. - Add standard derives for `ConfigTableEntry`. - `PcrEvent`/`PcrEventInputs` impl `Align`, `Eq`, and `PartialEq`. - Added `PcrEvent::new_in_box` and `PcrEventInputs::new_in_box`. diff --git a/uefi/src/lib.rs b/uefi/src/lib.rs index a40d4edac..52ff54cbb 100644 --- a/uefi/src/lib.rs +++ b/uefi/src/lib.rs @@ -119,6 +119,7 @@ pub use uguid::guid; mod result; pub use result::{Error, Result, ResultExt, Status, StatusExt}; +pub mod runtime; pub mod system; pub mod table; diff --git a/uefi/src/runtime.rs b/uefi/src/runtime.rs new file mode 100644 index 000000000..56015bc60 --- /dev/null +++ b/uefi/src/runtime.rs @@ -0,0 +1,57 @@ +//! UEFI runtime services. +//! +//! These services are available both before and after exiting boot +//! services. Note that various restrictions apply when calling runtime services +//! functions after exiting boot services; see the "Calling Convention" section +//! of the UEFI specification for details. + +use crate::table::{self}; +use crate::{Result, StatusExt}; +use core::ptr::{self, NonNull}; + +pub use crate::table::runtime::{Daylight, Time, TimeCapabilities, TimeError, TimeParams}; + +fn runtime_services_raw_panicking() -> NonNull { + let st = table::system_table_raw_panicking(); + // SAFETY: valid per requirements of `set_system_table`. + let st = unsafe { st.as_ref() }; + NonNull::new(st.runtime_services).expect("runtime services are not active") +} + +/// Query the current time and date information. +pub fn get_time() -> Result