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 `ResetNotificationProtocol`.

## Added
- Added `TimestampProtocol`.
- Added `DevicePathToTextProtocol` and `DevicePathFromTextProtocol`.
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,3 +1,4 @@
use crate::table::runtime;
use crate::{guid, Guid, Status};

#[derive(Debug)]
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: *mut Self, reset_function: ResetSystemFn) -> Status,
pub unregister_reset_notify:
unsafe extern "efiapi" fn(this: *mut Self, reset_function: 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 ResetSystem() is executed.
pub type ResetSystemFn = unsafe extern "efiapi" fn(
rt: runtime::ResetType,
status: Status,
data_size: usize,
data: *const u8,
);
64 changes: 64 additions & 0 deletions uefi-test-runner/examples/timestamp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// ANCHOR: all
// ANCHOR: features
#![no_main]
#![no_std]
// ANCHOR_END: features

extern crate alloc;

use log::{info, warn};

// ANCHOR: use
use uefi::prelude::*;
use uefi::proto::misc::Timestamp;

// ANCHOR_END: use

// ANCHOR: entry
#[entry]
fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
// ANCHOR_END: entry
// ANCHOR: services
uefi::helpers::init(&mut system_table).unwrap();
let boot_services = system_table.boot_services();
// ANCHOR_END: services

// ANCHOR: params
test_timestamp(boot_services);
// ANCHOR_END: params

// ANCHOR: stall
boot_services.stall(10_000_000);
// ANCHOR_END: stall

// ANCHOR: return
Status::SUCCESS
}
// ANCHOR_END: return

// ANCHOR: test_timestamp
pub fn test_timestamp(bt: &BootServices) {
// ANCHOR_END: test_timestamp
info!("Running loaded Timestamp Protocol test");

let handle = bt.get_handle_for_protocol::<Timestamp>();

match handle {
Ok(handle) => {
let timestamp_proto = bt
.open_protocol_exclusive::<Timestamp>(handle)
.expect("Founded Timestamp Protocol but open failed");
// ANCHOR: text
let timestamp = timestamp_proto.get_timestamp();
info!("Timestamp Protocol's timestamp: {:?}", timestamp);

let properties = timestamp_proto.get_properties();
info!("Timestamp Protocol's properties: {:?}", properties);
// ANCHOR_END: text
}
Err(err) => {
warn!("Failed to found Timestamp Protocol: {:?}", err);
}
}
}
// ANCHOR_END: all
44 changes: 44 additions & 0 deletions uefi-test-runner/src/proto/misc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use uefi::prelude::*;
use uefi::proto::misc::ResetNotification;
use uefi::table::runtime;

pub fn test(bt: &BootServices) {
test_reset_notification(bt);
}

pub fn test_reset_notification(bt: &BootServices) {
info!("Running loaded ResetNotification protocol test");

let handle = bt
.get_handle_for_protocol::<ResetNotification>()
.expect("Failed to get handles for `ResetNotification` protocol");

let mut reset_notif_proto = bt
.open_protocol_exclusive::<ResetNotification>(handle)
.expect("Founded ResetNotification Protocol but open failed");

// 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(efi_reset_fn);
info!(
"ResetNotification Protocol register efi_reset_fn test: {:?}",
result
);

let result = reset_notif_proto.unregister_reset_notify(efi_reset_fn);
info!(
"ResetNotification Protocol unregister efi_reset_fn test: {:?}",
result
);
}
3 changes: 2 additions & 1 deletion uefi-test-runner/src/proto/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use uefi::prelude::*;

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

Expand All @@ -22,6 +21,7 @@ pub fn test(image: Handle, st: &mut SystemTable<Boot>) {
rng::test(bt);
shell_params::test(bt);
string::test(bt);
misc::test(bt);

#[cfg(any(
target_arch = "x86",
Expand Down Expand Up @@ -61,6 +61,7 @@ mod device_path;
mod driver;
mod loaded_image;
mod media;
mod misc;
mod network;
mod pi;
mod rng;
Expand Down
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.
- Added `UnalignedSlice::as_ptr`.
Expand Down
60 changes: 59 additions & 1 deletion uefi/src/proto/misc.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
//! Miscellaneous protocols.

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

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

/// Protocol for retrieving a high-resolution timestamp counter.
/// **Note:**
/// If your UEFI firmware not support timestamp protocol which first added at UEFI spec 2.4 2013.
/// you also could use `RDTSC` in rust, here is a demo [Slint-UI](https://github.com/slint-ui/slint/blob/2c0ba2bc0f151eba8d1fa17839fa2ac58832ca80/examples/uefi-demo/main.rs#L28-L62) who use uefi-rs.
#[derive(Debug)]
#[repr(transparent)]
#[unsafe_protocol(TimestampProtocol::GUID)]
Expand All @@ -23,3 +29,55 @@ 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");
/// info!("do what you want");
/// }
///
/// pub fn test(image: Handle, bt: &BootServices) {
///
/// let mut rn = bt
/// .open_protocol_exclusive::<ResetNotification>(image)
/// .expect("Failed to open Timestamp protocol");
///
/// rn.register_reset_notify(efi_reset_fn)
/// .expect("Failed to register a reset notification function!");
/// }
/// ```
pub fn register_reset_notify(&mut self, reset_function: ResetSystemFn) -> Result {
unsafe { (self.0.register_reset_notify)(&mut self.0, reset_function) }.to_result()
}

/// Remove a reset notification function that was previously registered with [`ResetNotification::register_reset_notify`].
pub fn unregister_reset_notify(&mut self, reset_function: ResetSystemFn) -> Result {
unsafe { (self.0.unregister_reset_notify)(&mut self.0, reset_function) }.to_result()
}
}