Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c3a2b2f

Browse files
Event support and general console protocol cleanup (#44)
- Implemented basic support for awaiting UEFI events. - Made Handle and Event different newtypes of `void*` so assigning one to the other is an error * No ergonomics are lost since from the user's point of view these are opaque types anyway. - Clarified the stateful nature of Pointer::get_state - Made text input protocol more consistent with pointer protocol - Improved documentation and method ordering of text output protocol
1 parent 7907a68 commit c3a2b2f

File tree

7 files changed

+119
-44
lines changed

7 files changed

+119
-44
lines changed

‎src/data_types/mod.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1-
/// A pointer to an opaque data structure.
2-
pub type Handle = *mut ();
1+
use core::ffi::c_void;
2+
3+
/// Opaque handle to an UEFI entity (protocol, image...)
4+
#[derive(Clone, Copy)]
5+
#[repr(transparent)]
6+
pub struct Handle(*mut c_void);
7+
8+
/// Handle to an event structure
9+
#[derive(Clone, Copy)]
10+
#[repr(transparent)]
11+
pub struct Event(*mut c_void);
312

413
mod guid;
514
pub use self::guid::Guid;

‎src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ mod error;
3636
pub use self::error::{Result, Status};
3737

3838
mod data_types;
39-
pub use self::data_types::{Guid, Handle};
39+
pub use self::data_types::{Event,Guid, Handle};
4040

4141
pub mod table;
4242

‎src/proto/console/pointer/mod.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
//! Pointer device access.
22
33
use core::mem;
4-
use crate::{Result, Status};
4+
use crate::{Event,Result, Status};
55

66
/// Provides information about a pointer device.
77
#[repr(C)]
88
pub struct Pointer {
99
reset: extern "win64" fn(this: &mut Pointer, ext_verif: bool) -> Status,
1010
get_state: extern "win64" fn(this: &Pointer, state: &mut PointerState) -> Status,
11-
_wait_for_input:usize,
11+
wait_for_input:Event,
1212
mode: &'static PointerMode,
1313
}
1414

@@ -25,13 +25,15 @@ impl Pointer {
2525
(self.reset)(self, extended_verification).into()
2626
}
2727

28-
/// Retrieves the pointer device's current state.
28+
/// Retrieves the pointer device's current state, if a state change occured
29+
/// since the last time this function was called.
2930
///
30-
/// Will return None if the state has not changed since the last query.
31+
/// Use wait_for_input_event() with the BootServices::wait_for_event()
32+
/// interface in order to wait for input from the pointer device.
3133
///
3234
/// # Errors
3335
/// - `DeviceError` if there was an issue with the pointer device.
34-
pub fn state(&self) -> Result<Option<PointerState>> {
36+
pub fn read_state(&mutself) -> Result<Option<PointerState>> {
3537
let mut pointer_state = unsafe { mem::uninitialized() };
3638

3739
match (self.get_state)(self, &mut pointer_state) {
@@ -41,6 +43,12 @@ impl Pointer {
4143
}
4244
}
4345

46+
/// Event to use with BootServices::wait_for_event() to wait for input from
47+
/// the pointer device
48+
pub fn wait_for_input_event(&self) -> Event {
49+
self.wait_for_input
50+
}
51+
4452
/// Returns a reference to the pointer device information.
4553
pub fn mode(&self) -> &PointerMode {
4654
self.mode

‎src/proto/console/text/input.rs

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,50 @@
11
use core::mem;
2-
use crate::{Result, Status};
2+
use crate::{Event,Result, Status};
33

44
/// Interface for text-based input devices.
55
#[repr(C)]
66
pub struct Input {
77
reset: extern "win64" fn(this: &mut Input, extended: bool) -> Status,
88
read_key_stroke: extern "win64" fn(this: &mut Input, key: &mut Key) -> Status,
9+
wait_for_key: Event,
910
}
1011

1112
impl Input {
1213
/// Resets the input device hardware.
13-
pub fn reset(&mut self, extended: bool) -> Result<()> {
14-
(self.reset)(self, extended).into()
14+
///
15+
/// The `extended_verification` parameter is used to request that UEFI
16+
/// performs an extended check and reset of the input device.
17+
///
18+
/// # Errors
19+
///
20+
/// - `DeviceError` if the device is malfunctioning and cannot be reset.
21+
pub fn reset(&mut self, extended_verification: bool) -> Result<()> {
22+
(self.reset)(self, extended_verification).into()
1523
}
1624

17-
/// Reads the next keystroke from the input device.
25+
/// Reads the next keystroke from the input device, if any.
26+
///
27+
/// Use wait_for_key_event() with the BootServices::wait_for_event()
28+
/// interface in order to wait for a key to be pressed.
1829
///
19-
/// Returns `Err(NotReady)` if no keystroke is available yet.
20-
pub fn read_key(&mut self) -> Result<Key> {
30+
/// # Errors
31+
///
32+
/// - `DeviceError` if there was an issue with the input device
33+
pub fn read_key(&mut self) -> Result<Option<Key>> {
2134
let mut key = unsafe { mem::uninitialized() };
22-
(self.read_key_stroke)(self, &mut key)?;
23-
Ok(key)
24-
}
2535

26-
/// Blocks until a key is read from the device or an error occurs.
27-
pub fn read_key_sync(&mut self) -> Result<Key> {
28-
loop {
29-
match self.read_key() {
30-
// Received a key, exit loop.
31-
Ok(key) => return Ok(key),
32-
Err(code) => {
33-
match code {
34-
// Wait for key press.
35-
Status::NotReady => (),
36-
// Exit on error, no point in looping.
37-
_ => return Err(code),
38-
}
39-
}
40-
}
36+
match (self.read_key_stroke)(self, &mut key) {
37+
Status::Success => Ok(Some(key)),
38+
Status::NotReady => Ok(None),
39+
error => Err(error),
4140
}
4241
}
42+
43+
/// Event to use with BootServices::wait_for_event() to wait for a key to be
44+
/// available
45+
pub fn wait_for_key_event(&self) -> Event {
46+
self.wait_for_key
47+
}
4348
}
4449

4550
/// A key read from the console.

‎src/proto/console/text/output.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,16 @@ impl Output {
6262
}
6363
}
6464

65-
/// Returns the width (column count) and height (row count) of this mode.
65+
/// Returns the width (column count) and height (row count) of a text mode.
66+
///
67+
/// Devices are required to support at least an 80x25 text mode and to
68+
/// assign index 0 to it. If 80x50 is supported, then it will be mode 1,
69+
/// otherwise querying for mode 1 will return the `Unsupported` error.
70+
/// Modes 2+ will describe other text modes supported by the device.
71+
///
72+
/// If you want to iterate over all text modes supported by the device,
73+
/// consider using the iterator produced by `modes()` as a more ergonomic
74+
/// alternative to this method.
6675
fn query_mode(&self, index: i32) -> Result<(usize, usize)> {
6776
let (mut columns, mut rows) = (0, 0);
6877
(self.query_mode)(self, index, &mut columns, &mut rows)?;
@@ -81,23 +90,26 @@ impl Output {
8190
Ok(OutputMode { index, dims })
8291
}
8392

84-
/// Enables or disables the cursor.
93+
/// Make the cursor visible or invisible.
94+
///
95+
/// The output device may not support this operation, in which case an
96+
/// `Unsupported` error will be returned.
8597
pub fn enable_cursor(&mut self, visible: bool) -> Result<()> {
8698
(self.enable_cursor)(self, visible).into()
8799
}
88100

101+
/// Returns whether the cursor is currently shown or not.
102+
pub fn cursor_visible(&self) -> bool {
103+
self.data.cursor_visible
104+
}
105+
89106
/// Returns the column and row of the cursor.
90107
pub fn get_cursor_position(&self) -> (usize, usize) {
91108
let column = self.data.cursor_column;
92109
let row = self.data.cursor_row;
93110
(column as usize, row as usize)
94111
}
95112

96-
/// Returns whether the cursor is currently shown or not.
97-
pub fn is_cursor_visible(&self) -> bool {
98-
self.data.cursor_visible
99-
}
100-
101113
/// Sets the cursor's position, relative to the top-left corner, which is (0, 0).
102114
///
103115
/// This function will fail if the cursor's new position would exceed the screen's bounds.
@@ -255,7 +267,7 @@ impl_proto! {
255267
#[derive(Debug, Copy, Clone)]
256268
#[repr(u8)]
257269
pub enum Color {
258-
Black,
270+
Black = 0,
259271
Blue,
260272
Green,
261273
Cyan,

‎src/table/boot.rs

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
33
use super::Header;
44
use bitflags::bitflags;
5-
use core::{mem, ptr};
5+
use core::{mem, ptr, result};
66
use crate::proto::Protocol;
7-
use crate::{Guid, Handle, Result, Status};
7+
use crate::{Event,Guid, Handle, Result, Status};
88

99
/// Contains pointers to all of the boot services.
1010
#[repr(C)]
@@ -29,7 +29,9 @@ pub struct BootServices {
2929
// Event & timer functions
3030
create_event: usize,
3131
set_timer: usize,
32-
wait_for_event: usize,
32+
wait_for_event:
33+
extern "win64" fn(number_of_events: usize, events: *mut Event, out_index: &mut usize)
34+
-> Status,
3335
signal_event: usize,
3436
close_event: usize,
3537
check_event: usize,
@@ -203,6 +205,43 @@ impl BootServices {
203205
(self.free_pool)(addr).into()
204206
}
205207

208+
/// Stops execution until an event is signaled
209+
///
210+
/// This function must be called at priority level Tpl::Application. If an
211+
/// attempt is made to call it at any other priority level, an `Unsupported`
212+
/// error is returned.
213+
///
214+
/// The input Event slice is repeatedly iterated from first to last until an
215+
/// event is signaled or an error is detected. The following checks are
216+
/// performed on each event:
217+
///
218+
/// * If an event is of type NotifySignal, then an `InvalidParameter` error
219+
/// is returned together with the index of the event that caused the failure.
220+
/// * If an event is in the signaled state, the signaled state is cleared
221+
/// and the index of the event that was signaled is returned.
222+
/// * If an event is not in the signaled state but does have a notification
223+
/// function, the notification function is queued at the event's
224+
/// notification task priority level. If the execution of the event's
225+
/// notification function causes the event to be signaled, then the
226+
/// signaled state is cleared and the index of the event that was signaled
227+
/// is returned.
228+
///
229+
/// To wait for a specified time, a timer event must be included in the
230+
/// Event slice.
231+
///
232+
/// To check if an event is signaled without waiting, an already signaled
233+
/// event can be used as the last event in the slice being checked, or the
234+
/// check_event() interface may be used.
235+
pub fn wait_for_event(&self, events: &mut [Event]) -> result::Result<usize, (Status, usize)> {
236+
let (number_of_events, events) = (events.len(), events.as_mut_ptr());
237+
let mut index = unsafe { mem::uninitialized() };
238+
match (self.wait_for_event)(number_of_events, events, &mut index) {
239+
Status::Success => Ok(index),
240+
s @ Status::InvalidParameter => Err((s, index)),
241+
error => Err((error, 0)),
242+
}
243+
}
244+
206245
/// Query a handle for a certain protocol.
207246
///
208247
/// This function attempts to get the protocol implementation of a handle,

‎uefi-test-runner/src/proto/console/pointer.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ pub fn test(bt: &BootServices) {
1212
.reset(false)
1313
.expect("Failed to reset pointer device");
1414

15-
let state = pointer.state().expect("Failed to retrieve pointer state");
15+
let state = pointer
16+
.read_state()
17+
.expect("Failed to retrieve pointer state");
1618
if let Some(state) = state {
1719
info!("New pointer State: {:#?}", state);
1820
} else {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /