Skip to content

patina-v21.1.0

Choose a tag to compare

@github-actions github-actions released this 27 May 18:30
· 112 commits to refs/heads/main since this release

What's Changed

  • [REBASE \& FF] Use CRLF for Log Messages @os-d (#1520)
    Change Details
      ## Description

    Currently Patina only uses LF for log message line endings. In some terminal emulators, the implicit CR is not added and so the logs look stilted, e.g.

    INFO - Some Log Message
                                                INFO - Oops, no CR
    

    This contains two commits to fix that. One is in the SDK to convert strings printed with log::!() to have CRLF as the line ending. The other is use write!() with CRLF explicitly stated instead of writeln!() as that only does LF.

    Note: This matches edk2 behavior and C drivers using DEBUG(()) already get CRLF as their line ending: https://github.com/tianocore/edk2/blob/b03a21a63e3bd001f52c527e5a57feddb53a690b/MdePkg/Library/BasePrintLib/PrintLibInternal.c#L1107-L1136

    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    On a physical ARM64 platform where the terminal emulator does not implicitly add CR.

    Integration Instructions

    N/A.




  • patina\_test: Gate component doctest on the test-runner feature (MSRV 1.89.0 compat) @makubacki (#1533)
    Change Details
      ## Description

    The component module is only public when feature = "test-runner" is enabled (or when rustdoc is generating docs with cfg(doc)).

    The Filter doctest in components/patina_test/src/component.rs imports from it.

    cargo test --doc fails prior to 1.92.0 with: "E0603: module component is private"

    The behavior appears to have changed somewhere between the 2025-09-16 (fail) and 2025-12-04 (pass) nightly releases specifically.

    It appears the logic to discover what's reachable changed such that rustdoc only extracts doctests from items that are reachable in the same configuration the library is built with.

    The current MSRV is 1.89.0, so this change uses cfg_attr to ignore the test when the test-runner feature is not enabled this allows the doctest to be compiled and run when the feature is enabled and gives compatibility with older toolchains.

    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    BEFORE

    • cargo +nightly-2025-09-19 test -p patina_test

      ---- components\patina_test\src\component.rs - component::Filter (line 26) stdout ----
      error[E0603]: module `component` is private
        --> components\patina_test\src\component.rs:28:18
         |
       5 | use patina_test::component::{TestRunner, Filter};
         |                  ^^^^^^^^^ private module
         |
      note: the module `component` is defined here
        --> C:\src\patina\components\patina_test\src\lib.rs:21:1
         |
      21 | mod component;
         | ^^^^^^^^^^^^^
      
      error[E0603]: module `component` is private
        --> components\patina_test\src\component.rs:28:18
         |
       5 | use patina_test::component::{TestRunner, Filter};
         |                  ^^^^^^^^^               ------ enum `Filter` is not publicly re-exported
         |                  |
         |                  private module
         |
      note: the module `component` is defined here
        --> C:\src\patina\components\patina_test\src\lib.rs:21:1
         |
      21 | mod component;
         | ^^^^^^^^^^^^^
      
    • cargo +nightly-2025-12-12 test -p patina_test
      all doctests ran in 1.15s; merged doctests compilation took 1.05s

    AFTER

    Both commands pass.

    Integration Instructions

    • N/A


  • component: Normalize core::any::type\_name output (1.89.0 MSRV compat) @makubacki (#1531)
    Change Details
      ## Description

    Resolves #1530

    The strings emitted by core::any::type_name::<T>() are explicitly best-effort and documented to vary between rustc releases. Per the official documentation:

    This is intended for diagnostic use. The exact contents and format
    of the string returned are not specified, other than being
    best-effort description of the type. For example, amongst the
    strings that type_name::<Option>() might return are
    "Option" and "std::option::Optionstd::string::String".

    The returned string must not be considered to be a unique
    identifier of a type as multiple types may map to the same type
    name. Similarly, there is no guarantee that all parts of a type
    will appear in the returned string. In addition, the output may
    change between versions of the compiler. For example, lifetime
    specifiers were omitted in some earlier versions.

    The current implementation uses the same infrastructure as
    compiler diagnostics and debuginfo, but this is not guaranteed.

    https://doc.rust-lang.org/beta/core/any/fn.type_name.html

    The component infrastructure embeds those strings directly in user-visible diagnostics (error messages, panic payloads, MetaData::name) and a handful of unit tests assert against their exact form. These unit tests currently fail on the MSRV 1.89.0 (which means consumers on 1.89.0) also see different strings.

    For example, recent/current toolchains render lifetime-parameterized generics as Config<'_, u32> while older ones render the same type as Config<u32>, and three tests in component::params and component::struct_component hardcode the more recent rendered form.

    This change introduces a small internal helper, component::type_name, that wraps core::any::type_name and strips anonymous lifetime tokens before returning the string.

    This stabilizes user-visible diagnostics, which always read Config<T> regardless of which toolchain compiled the build.

    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    • 1.89.0 equivalent:
      • cargo +nightly-2025-06-23 test -p patina
    • Current (1.93.1):
      • cargo test -p patina

    Integration Instructions

    • N/A


  • pi\_dispatcher: Add UI Names to Prints @os-d (#1514)
    Change Details
      ## Description

    Currently when various states occur, such as drivers not dispatched, only the GUID of the driver is printed. This is useful, but also it is nicer to have the UI name printed so the GUID does not have to be cross-referenced.

    This parses the UI name from the FV, if present, and also prints it.

    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    N/A.

    Integration Instructions

    N/A.




  • patina\_dxe\_core: Drop alloc\_error\_handler feature @os-d (#1525)
    Change Details
      ## Description

    The unstable alloc_error_handler feature is no longer required as the default_alloc_error_handler is stabilized. Patina is not doing anything special in this case, just panicking, so drop the unstable feature.

    Closes #807

    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    Booting Q35 to shell.

    Integration Instructions

    N/A.




  • patina\_dxe\_core: Fix test check for new goblin @cfernald (#1527)
    Change Details
      ## Description

    The updated goblin added some internal checks for PE consistency that is failing for aarch64 with our test binary. This commit updates the check to allow for either the patina or the goblin failures to be accepted.

    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    Local test execution

    Integration Instructions

    N/A




  • patina\_dxe\_core: install always-enabled silent logger for tests @makubacki (#1521)
    Change Details
      ## Description

    init_test_logger() is used by various modules to set up logging during tests.

    This was originally setup to use env_logger when RUST_LOG is set allowing simple control of log messages during interactive test runs and providing partial coverage of log messages in tests with the following description given (#1093):

    Since Patina relies on the log::* API for logging, not
    configuring a default logger can cause log::* calls to appear
    completely uncovered in llvm-cov reports, slightly reducing
    overall coverage. Adding a simple environment based logger avoids
    this issue.

    Although this change enables coverage for log::*,
    there are still cases that cannot be covered. For example, in the
    function below, there is no way to get coverage for lines 6 and 7.

    1   1   fn print() {
    2   1       let mut i = 0;
    3   11      for _ in 0..10 {
    4   10          log::info!(
    5   10              "This will be covered {} {}",
    6                   i,
    7                   "This and the above line will not be covered."
    8               );
    9   10          i = i + 1;
    10          }
    11  1   }
    

    This commit adds coverage of the log lines.

    init_test_logger previously defaulted env_logger to LevelFilter::Off when RUST_LOG was unset. That sets STATIC_MAX_LEVEL to Off and installs a logger whose enabled() returns false, so every log::*! macro short-circuits before it gets to the formatting and dispatch logic. Under cargo-llvm-cov this leaves log call sites flagged as uncovered, even though the surrounding code is exercised by tests.

    This change switches the unset-RUST_LOG path to a tiny custom log::Log implementation that reports every record as enabled but discards it, combined with set_max_level(Trace).

    This allows tests to stay silent, but log_enabled!() now returns true so the formatting branch of each log::*! invocation actually runs and gets counted by coverage.

    The RUST_LOG-set path is unchanged and still routes through env_logger for real output during interactive debugging.


    This change alone improved existing code coverage by:

    • Line Coverage: 85.72% -> 85.95%
    • Region Coverage: 84.47% -> 85.33%

    Before (Left). After (Right).

    image image
    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    • cargo make coverage before and after

    Integration Instructions

    • N/A


  • Improve local mdbook testing [Rebase \& FF] @makubacki (#1518)
    Change Details
      ## Description

    Changes to simplify testing mdbooks.


    Simplify local mdbook testing

    Today, trying to run mdbook tests locally is a bit of a pain because:

    1. The dev profile is used to build dependencies used by code in the mdbook, and it has LTO enabled. This means that the resulting rlibs don't contain machine code and can't be linked by rustdoc --test when running the doctests embedded in the mdbook. This results in link errors.
    2. mdbook defaults to using the stable toolchain ignoring the rust-toolchain.toml file, which means that you have to manually switch to the nightly toolchain before running the tests.
    3. The dependencies have to be built separately (cargo make build-lib). which are built using the toolchain in rust-toolchain.toml.

    This is accounted for in CI with manual steps:

    https://github.com/OpenDevicePartnership/patina-devops/blob/main/.github/workflows/MdbookWorkflow.yml

    This commit simplifies all of this by introducing a new profile specifically for mdbook that inherits from dev but disables LTO and adding a cargo-make task to build the dependencies using this profile and run mdbook test using the toolchain specified in rust-toolchain.toml.

    Another task was added called serve-mdbook to make it easier to open the mdbook locally similar to doc-open for the docs.

    • Test mdbook code: cargo make test-mdbook
    • Serve mdbook locally: cargo make serve-mdbook

    This also has the advantage that mdbook tests are checked during cargo make all now.


    book.toml: Change playpen to playground

    I could not find "playpen" in the mdbook documentation:

    https://rust-lang.github.io/mdBook/

    As far as I can tell, "playpen" is a deprecated name for "playground".

    This changes the name of the section in book.toml to align with current mdbook documentation.


    Note: I kept the dedicated job in ci-workflow.yml that calls to patina-devops/MdbookWorkflow.yml since all is not run in CI and having it in a separate job still seems reasonable even though the job itself has some redundancies now. I'll probably make some changes to MdbookWorkflow.yml in a patina-devops PR to remove complexity now handled by the make task.


    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    • cargo make test-mdbook
    • cargo make serve-mdbook

    Integration Instructions

    • N/A


  • mdbook: Update dependencies @makubacki (#1512)
    Change Details
      ## Description

    Updates dependencies to the latest compatible versions. The latest mdbook release is 0.5.2 but the latest mdbook-admonish release 1.20.0 is not compatible with mdbook 0.5.x. So, mdbook is updated to the latest 0.4.x release, which is 0.4.52.

    The CSS file for mdbook-admonish is checked into the repo, per the admonish documentation for compatibility and reproducible builds.

    The multilingual key is removed from book.toml since it will be deprecated in mdbook 0.5.x.

    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    • Install mdbook related crates
    • mdbook build ./docs
    • mdbook serve ./docs

    Integration Instructions

    • N/A


  • gcd: Move mapping memory range message prior to adding memory space @makubacki (#1509)
    Change Details
      ## Description

    Allows the memory range details to be visible if the call to GCD.add_memory_space() fails.

    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    • cargo make all
    • Boot and examine when the message is printed.

    Integration Instructions

    • N/A


🚀 Features & ✨ Enhancements

  • [x64] Do not issue `cli` if interrupt is not enabled @kuqin12 (#1524)
    Change Details
      ## Description

    The module could be used in the user environment, and cli will cause #GP.

    This change will check on the interrupt state and opt out the cli if it is already disabled.

    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    This was tested for building the uart module for ring 3 module and booted to OS desktop properly.

    Integration Instructions

    N/A




🐛 Bug Fixes

  • [AArch64] Fix unable to unregister handlers @kuqin12 (#1523)
    Change Details
      ## Description

    The current handler unregister logic was broken because the null check will never hit. This is because the extern "efiapi" fn will not be null pointer and the casting to c_void will just be optimized out.

    The change moves the hosted handler type to an option to check the validity of the incoming parameters.

    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    This was tested on physical hardware and can unregister handler successfully.

    Integration Instructions

    N/A




  • Small Set of FFI Safety Improvements [Rebase \& FF] @makubacki (#1515)
    Change Details
      ## Description

    Makes a few changes to improve FFI safety noticed while reviewing the r-efi v6.0.0 PR (pre-existing problems that can be fixed in this PR before v6.0.0 integration).

    I tried to find places where null checks and unaligned pointer accesses were not used and should be. Some places may have been missed if they didn't match a search pattern used.

    Also, I added tests within reason. In particular, there is a large code coverage gap in components/patina_acpi/src/acpi_protocol.rs and patina_dxe_core/src/protocols.rs which I did not address since the lines modified are insignificant relative to the surrounding code already lacking coverage.


    Treat C FFI pointers as unaligned consistently

    Several UEFI protocol entry points dereference caller-supplied
    pointers directly (*ptr or ptr.as_mut()). This can be undefined
    behavior when the C caller passes an unaligned address.

    The UEFI ABI does not guarantee that out-parameters or input
    structures meet Rust's natural alignment for the pointee type, so
    most loads and stores through a raw FFI pointer must go through
    read_unaligned() / write_unaligned().

    While we've followed this pattern in the past, some cases were missed
    that are updated in this change.

    Also adds a Pointer Alignment section to the FFI Authoring doc (ffi.md)
    that describes the rationale along with a few examples.


    Improve FFI pointer validation in a couple of places

    Two FFI entry points dereferenced caller-supplied pointers without
    validating them:

    • patina_dxe_core: copy_mem() and set_mem() called
      core::ptr::copy() / slice::from_raw_parts_mut() on a null
      pointer, if the caller passed one, with a non-zero length.
    • patina_adv_logger: adv_log_write() constructed a slice from
      buffer and a reference from this with no validation.

    The boot services functions now debug_assert!() on null with a
    non-zero length to catch caller bugs clearly in debug builds, then
    fall through to a safe early return in release. Since the function
    does not return a value, this prevents a panic from propagating across
    the FFI boundary.

    adv_log_write() now returns EFI_INVALID_PARAMETER when this is
    null or when buffer is null. The SAFETY comments are updated to reflect
    the new invariants.


    cpu_arch_protocol: Prevent panic on null this pointers

    CPU Arch Protocol functions call a common helper to convert the raw
    this pointer to a reference. Before, the helper panicked on null
    pointers. This commit changes the helper to return None on null
    pointers, so that the FFI entry points can return
    EFI_INVALID_PARAMETER instead of panicking across the FFI
    boundary.


    patina_adv_logger: Add unit tests to components.rs

    There are currently no unit tests for this module. Though the test
    support needed to write tests without much overhead are in place,
    such as UartNull.

    This commit adds some basic tests for adv_log_write that verify the
    pointer validation logic and calls to write the message when
    expectations are valid.


    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    • cargo make all
    • QEMU platform boot to EFI shell

    Integration Instructions

    • N/A


  • patina\_internal\_cpu: Serialize a missed unit test @makubacki (#1516)
    Change Details
      ## Description

    Adds the #[serial] attribute to the test_uefi_routine() unit test since it modifies the global EXCEPTION_HANDLERS array (matching neighboring functions that register exception handlers) and the CALLBACK_INVOKED global (which is only in the tests module), which might be used by other tests in the future.

    Also sets CALLBACK_INVOKED to false at the start of the test so that the test can assert that the callback was flipped to true by the test. Sets it back to false when done for clean exit state. This is currently the only test using it, so it's more for future-proofing than anything else.

    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    • cargo make all

    Integration Instructions

    • N/A


📖 Documentation Updates

  • Small Set of FFI Safety Improvements [Rebase \& FF] @makubacki (#1515)
    Change Details
      ## Description

    Makes a few changes to improve FFI safety noticed while reviewing the r-efi v6.0.0 PR (pre-existing problems that can be fixed in this PR before v6.0.0 integration).

    I tried to find places where null checks and unaligned pointer accesses were not used and should be. Some places may have been missed if they didn't match a search pattern used.

    Also, I added tests within reason. In particular, there is a large code coverage gap in components/patina_acpi/src/acpi_protocol.rs and patina_dxe_core/src/protocols.rs which I did not address since the lines modified are insignificant relative to the surrounding code already lacking coverage.


    Treat C FFI pointers as unaligned consistently

    Several UEFI protocol entry points dereference caller-supplied
    pointers directly (*ptr or ptr.as_mut()). This can be undefined
    behavior when the C caller passes an unaligned address.

    The UEFI ABI does not guarantee that out-parameters or input
    structures meet Rust's natural alignment for the pointee type, so
    most loads and stores through a raw FFI pointer must go through
    read_unaligned() / write_unaligned().

    While we've followed this pattern in the past, some cases were missed
    that are updated in this change.

    Also adds a Pointer Alignment section to the FFI Authoring doc (ffi.md)
    that describes the rationale along with a few examples.


    Improve FFI pointer validation in a couple of places

    Two FFI entry points dereferenced caller-supplied pointers without
    validating them:

    • patina_dxe_core: copy_mem() and set_mem() called
      core::ptr::copy() / slice::from_raw_parts_mut() on a null
      pointer, if the caller passed one, with a non-zero length.
    • patina_adv_logger: adv_log_write() constructed a slice from
      buffer and a reference from this with no validation.

    The boot services functions now debug_assert!() on null with a
    non-zero length to catch caller bugs clearly in debug builds, then
    fall through to a safe early return in release. Since the function
    does not return a value, this prevents a panic from propagating across
    the FFI boundary.

    adv_log_write() now returns EFI_INVALID_PARAMETER when this is
    null or when buffer is null. The SAFETY comments are updated to reflect
    the new invariants.


    cpu_arch_protocol: Prevent panic on null this pointers

    CPU Arch Protocol functions call a common helper to convert the raw
    this pointer to a reference. Before, the helper panicked on null
    pointers. This commit changes the helper to return None on null
    pointers, so that the FFI entry points can return
    EFI_INVALID_PARAMETER instead of panicking across the FFI
    boundary.


    patina_adv_logger: Add unit tests to components.rs

    There are currently no unit tests for this module. Though the test
    support needed to write tests without much overhead are in place,
    such as UartNull.

    This commit adds some basic tests for adv_log_write that verify the
    pointer validation logic and calls to write the message when
    expectations are valid.


    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    • cargo make all
    • QEMU platform boot to EFI shell

    Integration Instructions

    • N/A


  • docs: Add FFI docs @os-d (#1511)
    Change Details
      ## Description

    This adds a doc for guidance on writing C FFIs.

    Note: I wrote this document to have a place to document no VA_LIST across an FFI because there wasn't a good other place I could find. So, I added a small amount of other FFI guidance; if there is another spot folks want this, happy to move it, or if folks have suggestions for what else to add to this section, happy to add.

    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    N/A.

    Integration Instructions

    N/A.




  • Add Code First Files [Rebase \& FF] @makubacki (#1510)
    Change Details
      ## Description

    These are changes to the repo as a follow up to the Code First RFC being merged.


    .github: Add Code First issue template

    Adds a GitHub issue template that is used to submit code first
    tracking issues.

    The template and how it is used is described in the Patina Code First
    RFC:

    https://github.com/OpenDevicePartnership/patina/blob/HEAD/docs/src/rfc/text/0027-code-first.md


    mdbook: Add Code First Process page

    Adds a page to give a high-level intro to the Patina Code First
    process and link to the RFC.

    This page is meant to serve as a place in the book to get a quick
    understanding of when the process applies and how it used with the
    formal definition being maintained in the RFC.

    Also updates text in code_first/template.md to escape square brackets
    so they might not be interpreted as a markdown link.


    Example of the Code First GitHub issue form:

    image
    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    • cargo make cspell
    • mdbook build ./docs

    Integration Instructions

    N/A




  • RFC: Code First Process [Approved] @makubacki (#1491)
    Change Details
      ## Description

    Status: Approved

    Closes #1487

    Defines a code first process for Patina. At this time, the focus is on UEFI Forum specifications with the expectation that the process can be adapted for other standards bodies and specifications as needed in the future.

    • Impacts functionality?
    • Impacts security?
    • Breaking change?
    • Includes tests?
    • Includes documentation?

    How This Was Tested

    • cspell and markdownlint

    Integration Instructions

    • N/A


Full Changelog: patina-v21.0.4...v21.1.0