Patina: R-EFI 6.0 migration#1480
Conversation
QEMU Validation FailedQEMU validation did not complete successfully or did not shutdown as expected. Workflow run: https://github.com/OpenDevicePartnership/patina/actions/runs/26074838332
|
| Job | Result |
|---|---|
| Gather Incoming PR Metadata | ✅ |
| Run Patina QEMU Validation / Preflight Checks | ✅ |
| Run Patina QEMU Validation / Post In-Progress Notification | ✅ |
| Run Patina QEMU Validation / Get Constants / Get Repository Constants | ✅ |
| Run Patina QEMU Validation / Validate QEMU - Q35 (Linux) | ❌ |
| Run Patina QEMU Validation / Validate QEMU Q35 (Windows) | ❌ |
| Run Patina QEMU Validation / Validate QEMU - SBSA (Linux) | ❌ |
| Run Patina QEMU Validation / Emit PR Metadata | ✅ |
Error Details
qemu-validation-logs-Linux-Q35/q35-linux.log (15 error/warning sections)
… (truncated)
error[E0308]: mismatched types
--> src/q35/component/service/smbios_platform.rs:125:30
|
125 | security_status: 0x02,
| ^^^^ expected `SecurityStatus`, found integer
error[E0308]: mismatched types
--> src/q35/component/service/smbios_platform.rs:155:28
|
155 | feature_flags: 0x01, // Board is a hosting board
| ^^^^ expected `FeatureFlags`, found integer
|
help: call `Into::into` on this expression to convert `{integer}` into `FeatureFlags`
|
155 | feature_flags: 0x01.into(), // Board is a hosting board
| +++++++
error[E0308]: mismatched types
--> src/q35/component/service/smbios_platform.rs:158:25
|
158 | board_type: 0x0A, // Motherboard
| ^^^^ expected `BoardType`, found integer
error[E0308]: mismatched types
--> src/q35/component/service/smbios_test.rs:45:49
|
45 | boot_services.locate_protocol_unchecked(&SMBIOS_PROTOCOL_GUID, core::ptr::null_mut()).map_err(|e| {
| ------------------------- ^^^^^^^^^^^^^^^^^^^^^ expected `r_efi::base::Guid`, found a different `r_efi::base::Guid`
| |
| arguments to this method are incorrect
|
note: there are multiple different versions of crate `r_efi` in the dependency graph
--> /.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/r-efi-6.0.0/src/base.rs:392:1
|
392 | pub struct Guid {
| ^^^^^^^^^^^^^^^ this is the expected type
|
::: /.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/r-efi-5.3.0/src/base.rs:392:1
|
392 | pub struct Guid {
| --------------- this is the found type
= help: you can use `cargo tree` to explore your dependency tree
note: method defined here
--> /__w/patina/patina/sdk/patina/src/boot_services.rs:826:15
|
826 | unsafe fn locate_protocol_unchecked(
| ^^^^^^^^^^^^^^^^^^^^^^^^^
For more information about this error, try `rustc --explain E0308`.
error: could not compile `qemu_dxe_core` (lib) due to 12 previous errors
warning: build failed, waiting for other jobs to finish...
[cargo-make] ERROR - Error while running duckscript: Source: Unknown Line: 113 - Error while executing command, exit code: 101
qemu-validation-logs-Windows-Q35/q35-windows.log (15 error/warning sections)
… (truncated)
error[E0308]: mismatched types
--> src\q35\component\service\smbios_platform.rs:125:30
|
125 | security_status: 0x02,
| ^^^^ expected `SecurityStatus`, found integer
error[E0308]: mismatched types
--> src\q35\component\service\smbios_platform.rs:155:28
|
155 | feature_flags: 0x01, // Board is a hosting board
| ^^^^ expected `FeatureFlags`, found integer
|
help: call `Into::into` on this expression to convert `{integer}` into `FeatureFlags`
|
155 | feature_flags: 0x01.into(), // Board is a hosting board
| +++++++
error[E0308]: mismatched types
--> src\q35\component\service\smbios_platform.rs:158:25
|
158 | board_type: 0x0A, // Motherboard
| ^^^^ expected `BoardType`, found integer
error[E0308]: mismatched types
--> src\q35\component\service\smbios_test.rs:45:49
|
45 | boot_services.locate_protocol_unchecked(&SMBIOS_PROTOCOL_GUID, core::ptr::null_mut()).map_err(|e| {
| ------------------------- ^^^^^^^^^^^^^^^^^^^^^ expected `r_efi::base::Guid`, found a different `r_efi::base::Guid`
| |
| arguments to this method are incorrect
|
note: there are multiple different versions of crate `r_efi` in the dependency graph
--> C:\Users\runneradmin\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\r-efi-6.0.0\src\base.rs:392:1
|
392 | pub struct Guid {
| ^^^^^^^^^^^^^^^ this is the expected type
|
::: C:\Users\runneradmin\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\r-efi-5.3.0\src\base.rs:392:1
|
392 | pub struct Guid {
| --------------- this is the found type
= help: you can use `cargo tree` to explore your dependency tree
note: method defined here
--> D:\a\patina\patina\sdk\patina\src\boot_services.rs:826:15
|
826 | unsafe fn locate_protocol_unchecked(
| ^^^^^^^^^^^^^^^^^^^^^^^^^
For more information about this error, try `rustc --explain E0308`.
error: could not compile `qemu_dxe_core` (lib) due to 12 previous errors
warning: build failed, waiting for other jobs to finish...
[cargo-make] ERROR - Error while running duckscript: Source: Unknown Line: 113 - Error while executing command, exit code: 101
qemu-validation-logs-Linux-SBSA/sbsa-linux.log (15 error/warning sections)
… (truncated)
error[E0308]: mismatched types
--> src/q35/component/service/smbios_platform.rs:125:30
|
125 | security_status: 0x02,
| ^^^^ expected `SecurityStatus`, found integer
error[E0308]: mismatched types
--> src/q35/component/service/smbios_platform.rs:155:28
|
155 | feature_flags: 0x01, // Board is a hosting board
| ^^^^ expected `FeatureFlags`, found integer
|
help: call `Into::into` on this expression to convert `{integer}` into `FeatureFlags`
|
155 | feature_flags: 0x01.into(), // Board is a hosting board
| +++++++
error[E0308]: mismatched types
--> src/q35/component/service/smbios_platform.rs:158:25
|
158 | board_type: 0x0A, // Motherboard
| ^^^^ expected `BoardType`, found integer
error[E0308]: mismatched types
--> src/q35/component/service/smbios_test.rs:45:49
|
45 | boot_services.locate_protocol_unchecked(&SMBIOS_PROTOCOL_GUID, core::ptr::null_mut()).map_err(|e| {
| ------------------------- ^^^^^^^^^^^^^^^^^^^^^ expected `r_efi::base::Guid`, found a different `r_efi::base::Guid`
| |
| arguments to this method are incorrect
|
note: there are multiple different versions of crate `r_efi` in the dependency graph
--> /.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/r-efi-6.0.0/src/base.rs:392:1
|
392 | pub struct Guid {
| ^^^^^^^^^^^^^^^ this is the expected type
|
::: /.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/r-efi-5.3.0/src/base.rs:392:1
|
392 | pub struct Guid {
| --------------- this is the found type
= help: you can use `cargo tree` to explore your dependency tree
note: method defined here
--> /__w/patina/patina/sdk/patina/src/boot_services.rs:826:15
|
826 | unsafe fn locate_protocol_unchecked(
| ^^^^^^^^^^^^^^^^^^^^^^^^^
For more information about this error, try `rustc --explain E0308`.
error: could not compile `qemu_dxe_core` (lib) due to 12 previous errors
warning: build failed, waiting for other jobs to finish...
[cargo-make] ERROR - Error while running duckscript: Source: Unknown Line: 113 - Error while executing command, exit code: 101
Dependencies
| Repository | Ref |
|---|---|
| patina | cc656fc |
| patina-dxe-core-qemu | e178e37 |
| patina-fw-patcher | d656f1d |
| patina-qemu firmware | v3.0.0 |
| patina-qemu build script | e0231b7 |
This comment was automatically generated by the Patina QEMU PR Validation Post workflow.
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
|
I haven't looked at the PR changes yet, but it should target the |
102fbd3 to
ede86cc
Compare
Michael, The branch is now updated to target major instead of main. |
ede86cc to
3e6fd6c
Compare
| &self, | ||
| boot_policy: bool, | ||
| parent_image_handle: efi::Handle, | ||
| file_path: *mut efi::protocols::device_path::Protocol, |
There was a problem hiding this comment.
there is a lot of "unsafe poisoning" downstream of these raw pointers to device_path::Protocol. Could we instead make a newtype of these with an unsafe constructor so that the safety invariant is not spread everywhere?
struct DevicePathPtr(*mut efi::protocols::device_path::Protocol);
impl DevicePathPtr {
/// Safety: Caller must guarantee that device path pointer is non-null and points to a valid device path.
pub unsafe fn new(ptr: *mut efi::Protocols::device_path::Protocol) -> Self {
Self(ptr)
}
pub fn as_raw(&mut self) -> *mut T {
self.0
}
}
pub load_image(
&self,
boot_policy: bool,
parent_image_handle: efi::Handle,
file_path: DevicePathPtr
) -> Result<etc> {
...
}
// Safety: my_raw_path is a properly constructed valid device path with static lifetime (or whatever)
let file_path = unsafe { DevicePathPtr::new(my_raw_path); }
PI_DISPATCHER.load_image(boot_policy, parent_image_handle, file_path); // safeThere was a problem hiding this comment.
I am prototyping safe DevicePathPtr around *mut efi::protocols::device_path::Protocol. This newtype looks very promising and resembles much like NonNull<T> type. And it feels like it is not limited to DevicePath and can be applicable to other raw pointer types which are used in Patina.
pub struct RawPtr<T>(*mut T);
impl<T> RawPtr<T> {
pub unsafe fn new(ptr: *mut T) -> Self {
Self(ptr)
}
pub unsafe fn from_raw(ptr: *mut T) -> Option<Self> {
if ptr.is_null() {
None
} else {
Some(unsafe { Self::new(ptr) })
}
}
pub fn as_ptr(self) -> *mut T {
self.0
}
}My only concern is that, the change will have far more impact beyond the scope of this PR. Especially, when patina\sdk\patina\src\device_path\walker.rs is also rewritten based on DevicePathPtr. So, I think it is better to pull in that change immediately after this PR. I can create a work item for tracking and can work on it.
There was a problem hiding this comment.
I'm not sure how I feel about a universal RawPtr safe wrapper. That seems a bit generic? But I guess it would be unsafe at both point of creation and point of deref; so I guess it doesn't do too much to mask unsafety.
| /// The caller must ensure that `image_handle` was obtained from a prior | ||
| /// successful call to [`Self::load_image`] and that the loaded image's | ||
| /// memory and entry point remain valid. | ||
| pub unsafe fn start_image(&'static self, image_handle: efi::Handle) -> Result<(), efi::Status> { |
There was a problem hiding this comment.
I'm not sure this needs to be unsafe. If the image_handle is not valid, you can just return an error. We can add additional validation (e.g. make sure that the handle is not only valid, but that it is actually associated with an image). The caller can't really uphold the invariant of whether the loaded_images memory and entry point are valid; those are upheld by load_image implementation.
There was a problem hiding this comment.
/// Starts execution of a previously loaded image.
///
/// The `image_handle` is validated against the protocol database and the
/// private image data map; an error is returned if the handle is unknown or
/// the image has already been started. However, a valid handle must still
/// refer to a properly loaded image whose entry point is executable code.
/// It is the caller's responsibility to first load such an image via
/// [`Self::load_image`] before calling this function.
///
/// # Safety
///
/// The caller must ensure that `image_handle` was obtained from a prior
/// successful call to [`Self::load_image`] and that the loaded image's
/// memory and entry point remain valid.
My thought process was about the case where a malformed PE image has a valid entry point but contains invalid code (or something similar), which we cannot guarantee against. LoadImage will load the image because it satisfies the PE format requirements, but StartImage can still fail during execution.
There was a problem hiding this comment.
I think concerns about a malformed image buffer should be on load_image. I think the promise chain goes: "This is a good image" -> load_image -> image_handle -> start_image. So start_image is basically relying on the fact that it is an image_handle to signify a promise that it was properly constructed. Practically speaking, if the image buffer is junk, you won't change the arguments to start_image, you'll change the arguments to load_image.
| /// load_image. See the EFI_BOOT_SERVICES::StartImage() API definition in | ||
| /// the UEFI spec for usage details. | ||
| /// | ||
| /// # Safety |
There was a problem hiding this comment.
The safety here is pretty much something like: "caller must uphold the UEFI spec contract with respect to the semantics of this API"
| /// # Safety | ||
| /// | ||
| /// The caller must ensure that `destination` and `source` are valid pointers for `length` bytes | ||
| /// and that the regions they point to do not violate Rust's aliasing rules for `core::ptr::copy`. |
There was a problem hiding this comment.
Since this is a UEFI spec function, I don't think the caller needs to be aware of or uphold rust's aliasing rules, unless it is a rust caller (in which case it should just use core::ptr::copy() directly).
| /// instances that are valid at the start of the call to ConnectController() | ||
| /// must remain valid for the duration of the ConnectController() call. If | ||
| /// this is not true, then behavior is undefined. This function is marked | ||
| /// unsafe for this reason. |
There was a problem hiding this comment.
I'm not sure the caller can directly uphold the "no weird edge cases exist in the platform where the driver is uninstalled between Supported() and Start()".
Other safety conditions hold tho.
There was a problem hiding this comment.
Agreed, I don't mean to make it as a caller's responsibility 😄. But I really want to document that edge case in the function comment so that the caller is aware of it. I will move it above the SAFETY comments.
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
Signed-off-by: Vineel Kovvuri[MSFT] <vineelko@microsoft.com>
3e6fd6c to
cc656fc
Compare
Description
R-EFI 6.0 Migration
Upstream r-efi 6.0 marks all
extern "efiapi"function pointers in EFI BootServices, Runtime Services, and other protocols as
unsafe, since their safetycannot be enforced by the Rust type system at compile time.
This PR audits almost all usage of UEFI service function pointers across the Patina
codebase for correctness and safety.
There are three primary areas where
unsafeusage has been audited:extern "efiapi"functionsBootServicestrait thateventually call into the FFI
Not all functions in the above categories need to be marked
unsafe. Forexample,
extern "efiapi" close_eventis not markedunsafebecause it cansafely be called with an arbitrary event parameter without causing undefined
behavior in the Patina implementation. The
eventparameter is treated as anopaque pointer and is never dereferenced.
That said, any indirect caller that dereferences this Boot Services function
pointer must still use an
unsafeblock, since the function pointer itself isdefined as
unsafein r-efi 6.0. In addition, inherently unsafe Rustfunctions (such as
core_free_pool()) are now explicitly markedunsafe.Each inspected function or call site is documented with appropriate safety
comments where necessary, and with explanations where
unsafeis notrequired.
There are no functional changes.
Clippy flags public functions that accept raw pointer parameters and pass them
across an FFI boundary without being marked
unsafe, with the followingwarning:
"this public function might dereference a raw pointer but is not marked
unsafe"In Patina, this pattern is common for functions that take
efi::Eventorefi::Handleparameters and call Boot Services function pointers. Weexplicitly suppress this lint for such functions because these types are
treated as opaque pointers and are never dereferenced:
#[allow(clippy::not_unsafe_ptr_arg_deref)]Geiger Unsafe Stats
How This Was Tested
Booted to UEFI Shell Q35/SBSA
Integration Instructions
All consumers of Patina will need to pick the newer Patina version when published and also should update their r-efi version to 6.0.0.