Skip to content

[Misc] Add ResetNotification protocol. Add Misc to uefi-test-runner. #1116

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 8 commits into from
Apr 20, 2024
3 changes: 3 additions & 0 deletions uefi-raw/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# uefi-raw - [Unreleased]

## Added
- Added `ResetNotification`.

## Added
- Added `TimestampProtocol`.

Expand Down
23 changes: 23 additions & 0 deletions uefi-raw/src/protocol/misc.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{guid, Guid, Status};
use crate::table::runtime;

#[derive(Debug)]
#[repr(C)]
Expand All @@ -22,3 +23,25 @@ pub struct TimestampProperties {
/// example, a 24-bit counter would have an end value of `0xff_ffff`.
pub end_value: u64,
}

/// Properties of Reset Notification.
#[derive(Debug)]
#[repr(C)]
pub struct ResetNotificationProtocol {
pub register_reset_notify: unsafe extern "efiapi" fn(this: *const Self, reset_function: Option<ResetSystemFn>) -> Status,
pub unregister_reset_notify: unsafe extern "efiapi" fn(this: *const Self, reset_function: Option<ResetSystemFn>) -> Status,
}

impl ResetNotificationProtocol {
pub const GUID: Guid = guid!("9da34ae0-eaf9-4bbf-8ec3-fd60226c44be");
}


/// Raw reset notification function, to be called if you register it when a RestSystem() is executed.
// copy from uefi-raw/src/table/runtime.rs:53 at commit@6093205c3eb27b2e78be4c003c04d46679bff420
pub type ResetSystemFn = unsafe extern "efiapi" fn(
rt: runtime::ResetType,
status: Status,
data_size: usize,
data: *const u8,
);
80 changes: 80 additions & 0 deletions uefi-test-runner/src/proto/misc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use uefi::prelude::*;
use uefi::proto::misc::{ResetNotification, Timestamp};
use uefi::table::runtime;

///
/// you may see those log, it's nothing just for your computer firmware does not support the new UEFI feature.
///
/// ```sh
/// [ INFO]: uefi-test-runner\src\proto\misc.rs@012: Running loaded Timestamp Protocol test
/// [ WARN]: uefi-test-runner\src\proto\misc.rs@026: Failed to open Timestamp Protocol: Error { status: UNSUPPORTED, data: () }
/// [ INFO]: uefi-test-runner\src\proto\misc.rs@033: Running loaded ResetNotification protocol test
/// [ WARN]: uefi-test-runner\src\proto\misc.rs@068: Failed to open ResetNotification Protocol: Error { status: UNSUPPORTED, data: () }
/// ```
pub fn test(image: Handle, bt: &BootServices) {
test_timestamp(image, bt);
test_reset_notification(image, bt);
}

pub fn test_timestamp(image: Handle, bt: &BootServices) {
info!("Running loaded Timestamp Protocol test");

let result = bt
.open_protocol_exclusive::<Timestamp>(image);

match result {
Ok(timestamp_proto) => {
let timestamp = timestamp_proto.get_timestamp();
info!("Timestamp Protocol's timestamp: {:?}", timestamp);

let properties = timestamp_proto.get_properties();
info!("Timestamp Protocol's properties: {:?}", properties);
}
Err(err) => {
warn!("Failed to open Timestamp Protocol: {:?}", err);
}
}
}


pub fn test_reset_notification(image: Handle, bt: &BootServices) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This only tests to set hook but not that the hook is actually called. Can we fix/add that?

info!("Running loaded ResetNotification protocol test");

let result = bt
.open_protocol_exclusive::<ResetNotification>(image);

match result {
Ok(mut reset_notif_proto) => {
let result = reset_notif_proto.register_reset_notify(None);
info!("ResetNotification Protocol register null test: {:?}", result);

let result = reset_notif_proto.unregister_reset_notify(None);
info!("ResetNotification Protocol unregister null test: {:?}", result);



// value efi_reset_fn is the type of ResetSystemFn, a function pointer
unsafe extern "efiapi" fn efi_reset_fn(
rt: runtime::ResetType,
status: Status,
data_size: usize,
data: *const u8,
) {
info!("Inside the event callback, hi, efi_reset_fn");
info!("rt: {:?} status: {:?}", rt, status);
info!("size: {:?} data: {:?}", data_size, data);
// do what you want
}

let result = reset_notif_proto.register_reset_notify(Some(efi_reset_fn));
info!("ResetNotification Protocol register efi_reset_fn test: {:?}", result);

let result = reset_notif_proto.unregister_reset_notify(Some(efi_reset_fn));
info!("ResetNotification Protocol unregister efi_reset_fn test: {:?}", result);
}
Err(err) => {
warn!("Failed to open ResetNotification Protocol: {:?}", err);
}
}
}

21 changes: 11 additions & 10 deletions uefi-test-runner/src/proto/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use uefi::{Identify, proto};
use uefi::prelude::*;

use uefi::proto::loaded_image::LoadedImage;
use uefi::{proto, Identify};

pub fn test(image: Handle, st: &mut SystemTable<Boot>) {
info!("Testing various protocols");
Expand All @@ -22,12 +21,13 @@ pub fn test(image: Handle, st: &mut SystemTable<Boot>) {
rng::test(bt);
shell_params::test(bt);
string::test(bt);
misc::test(image, bt);

#[cfg(any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "arm",
target_arch = "aarch64"
target_arch = "x86",
target_arch = "x86_64",
target_arch = "arm",
target_arch = "aarch64"
))]
shim::test(bt);
tcg::test(bt);
Expand Down Expand Up @@ -66,11 +66,12 @@ mod pi;
mod rng;
mod shell_params;
#[cfg(any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "arm",
target_arch = "aarch64"
target_arch = "x86",
target_arch = "x86_64",
target_arch = "arm",
target_arch = "aarch64"
))]
mod shim;
mod string;
mod tcg;
mod misc;
3 changes: 3 additions & 0 deletions uefi/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# uefi - [Unreleased]

## Added
- Added `ResetNotification` protocol.

## Added
- Added `Timestamp` protocol.

Expand Down
64 changes: 62 additions & 2 deletions uefi/src/proto/misc.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! Miscellaneous protocols.

use crate::proto::unsafe_protocol;
use uefi_raw::protocol::misc::{ResetNotificationProtocol, ResetSystemFn, TimestampProperties, TimestampProtocol};

use crate::{Result, StatusExt};
use uefi_raw::protocol::misc::{TimestampProperties, TimestampProtocol};
use crate::proto::unsafe_protocol;

/// Protocol for retrieving a high-resolution timestamp counter.
#[derive(Debug)]
Expand All @@ -23,3 +24,62 @@ impl Timestamp {
unsafe { (self.0.get_properties)(&mut properties) }.to_result_with_val(|| properties)
}
}

/// Protocol to register for a notification when ResetSystem is called.
#[derive(Debug)]
#[repr(transparent)]
#[unsafe_protocol(ResetNotificationProtocol::GUID)]
pub struct ResetNotification(ResetNotificationProtocol);

impl ResetNotification {
/// Register a notification function to be called when ResetSystem() is called.
///
///
/// #example
/// ```rust
/// use log::info;
/// use uefi::Handle;
/// use uefi::prelude::BootServices;
/// use uefi::proto::misc::{ResetNotification};
/// use uefi_raw::Status;
/// use uefi_raw::table::runtime;
///
/// // value efi_reset_fn is the type of ResetSystemFn, a function pointer
/// unsafe extern "efiapi" fn efi_reset_fn(
/// rt: runtime::ResetType,
/// status: Status,
/// data_size: usize,
/// data: *const u8,
/// ){
/// info!("Inside the event callback");
/// // do what you want
/// }
///
/// pub fn test(image: Handle, bt: &BootServices) {
///
/// /* get protocol*/
/// let mut rn = bt
/// .open_protocol_exclusive::<ResetNotification>(image)
/// .expect("Failed to open Timestamp protocol");
/// rn.register_reset_notify(Some(efi_reset_fn));
/// }
/// ```
pub fn register_reset_notify(&mut self, reset_function: Option<ResetSystemFn>) -> Result {
unsafe {
(self.0.register_reset_notify)(&mut self.0, reset_function)
}.to_result()
}

/// Removes a reset notification function that has been previously registered with RegisterResetNotify().
/// Tips: RegisterResetNotify() has named as `register_reset_notify()` in uefi-rs.
pub fn unregister_reset_notify(&mut self, reset_function: Option<ResetSystemFn>) -> Result {
unsafe {
(self.0.unregister_reset_notify)(&mut self.0, reset_function)
}.to_result()
}
}


// !TODO: make a safe FFI for raw function 'ResetSystemFn'
// copy and edit from uefi-raw/src/table/runtime.rs:84 at commit@6093205c3eb27b2e78be4c003c04d46679bff420
// pub fn new(&self, rt: ResetType, status: Status, data: Option<&[u8]>) -> Option<ResetSystemFn>