Skip to content

Add doc on freestanding function migration #1315

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions docs/funcs_migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# API migration: Deprecating SystemTable/BootServices/RuntimeServices

Starting in uefi-0.31.0, a significant API change has been introduced. We are
transitioning away from modeling UEFI tables with structs, and instead providing
an API based on freestanding functions. These functions make use of a global
system table pointer that is set automatically by the `entry` macro.

A short example:

```rust
// Old API:
use uefi::table::boot::{BootServices, HandleBuffer};
fn find_loaded_image_handles(bt: &BootServices) -> Result<HandleBuffer> {
bt.locate_handle_buffer(SearchType::from_proto::<LoadedImage>())
}

// New API:
use uefi::boot::{self, HandleBuffer};
fn find_loaded_image_handles() -> Result<HandleBuffer> {
boot::locate_handle_buffer(SearchType::from_proto::<LoadedImage>())
}
```

The new functions generally have almost the same signature as the methods they
are replacing, so in most cases migration should be as simple as updating
imports and calling the freestanding function instead of a method on
`SystemTable`, `BootServices`, or `RuntimeServices`.

As of uefi-0.31.0, a few places in the API still require a reference to
`BootServices`. You can retrieve one by calling
`uefi::table::system_table_boot().boot_services()`.

In uefi-0.31.0, the old API has been deprecated, but can still be used. It will
be fully removed in a later release.

If you run into any issues with this migration, please feel free to chat with us
on [Zulip] or file an [issue].

## Reason for the change

See [issue #893][RFC] for the discussion that lead to this change.

### Safety of `exit_boot_services`

One of the main motivations for the old API was to make transitioning from boot
services to runtime services a safe operation. Calling `exit_boot_services`
would consume `SystemTable<Boot>` and return a `SystemTable<Runtime>`, ensuring
that it was no longer possible to call boot services methods.

That was the theory, but in practice it didn't always work. Many real-world
programs had to call `SystemTable::unsafe_clone` in order to get another handle
to the system table, and that immediately reintroduced the possibility of
unintentionally accessing boot services after calling `exit_boot_services`.

In addition, there are a great many kinds of resources that should not be
accessed after calling `exit_boot_services`, so even if the `SystemTable<Boot>`
was gone, it's very hard to _statically_ ensure that all references to
boot-services resources are dropped.

Realistically the `exit_boot_services` operation is just too complex to model as
part of Rust's safety guarantees. So in the end, we decided it is better to make
`exit_boot_services` an `unsafe` operation. We do make use of runtime checks
when possible to help catch mistakes (for example, calling a `boot` function
after exiting boot services will panic).

### API complexity

Some parts of the API need to free a pool allocation on drop, or do some other
type of resource cleanup. [`DevicePathToText`] is one example. The user has to
pass in a reference to `BootServices`, and that means the object containing the
allocation needs to hang on to that reference, so it needs a lifetime
parameter. That may "infect" other parts of the API, requiring adding references
and lifetimes to calling functions and to types containing the returned
value. By using a global table pointer instead, this complexity is hidden and
the API becomes simpler.

[`DevicePathToText`]: https://docs.rs/uefi/latest/uefi/proto/device_path/text/struct.DevicePathToText.html
[RFC]: https://github.com/rust-osdev/uefi-rs/issues/893
[Zulip]: https://rust-osdev.zulipchat.com/#narrow/stream/426438-uefi-rs
[issue]: https://github.com/rust-osdev/uefi-rs/issues/new
4 changes: 4 additions & 0 deletions uefi/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# uefi - [Unreleased]

See [Deprecating SystemTable/BootServices/RuntimeServices][funcmigrate] for
details of a significant change to the API in this release.

## Added
- `uefi::system` is a new module that provides freestanding functions for
accessing fields of the global system table.
Expand Down Expand Up @@ -39,6 +42,7 @@
> use uefi::table::boot::BootServices;
```

[funcmigrate]: ../docs/funcs_migration.md

# uefi - 0.30.0 (2024-08-02)

Expand Down