Skip to content
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()
}
}