Skip to content

Commit aa7750e

Browse files
committed
Add initial code
1 parent c1328d7 commit aa7750e

File tree

16 files changed

+964
-0
lines changed

16 files changed

+964
-0
lines changed

src/guid.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use core::fmt;
2+
3+
/// A globally unique identifier.
4+
///
5+
/// GUIDs are used by to identify protocols and other objects.
6+
///
7+
/// The difference from regular UUIDs is that the first 3 fields are
8+
/// always encoded as little endian.
9+
///
10+
/// The `Display` formatter prints GUIDs in the UEFI-defined format:
11+
/// `aabbccdd-eeff-gghh-iijj-kkllmmnnoopp`
12+
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
13+
#[repr(C)]
14+
pub struct Guid {
15+
/// The low field of the timestamp.
16+
a: u32,
17+
/// The middle field of the timestamp.
18+
b: u16,
19+
/// The high field of the timestamp multiplexed with the version number.
20+
c: u16,
21+
/// Contains:
22+
/// - The high field of the clock sequence multiplexed with the variant.
23+
/// - The low field of the clock sequence.
24+
/// - Spatially unique node identifier.
25+
d: [u8; 8],
26+
}
27+
28+
impl Guid {
29+
/// Creates a new GUID from its component values.
30+
pub const fn from_values(a: u32, b: u16, c: u16, d: [u8; 8]) -> Self {
31+
Guid { a, b, c, d }
32+
}
33+
}
34+
35+
impl fmt::Display for Guid {
36+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
37+
let (a, b, c) = (self.a, self.b, self.c);
38+
39+
let d = {
40+
let (low, high) = (self.d[0] as u16, self.d[1] as u16);
41+
42+
(low << 8) | high
43+
};
44+
45+
let e = {
46+
let node = &self.d[2..8];
47+
let mut e = 0;
48+
49+
for i in 0..6 {
50+
e |= u64::from(node[5 - i]) << (i * 8);
51+
}
52+
53+
e
54+
};
55+
56+
write!(fmt, "{:08x}-{:04x}-{:04x}-{:04x}-{:012x}", a, b, c, d, e)
57+
}
58+
}

src/lib.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//! Rusty wrapper for the Unified Extensible Firmware Interface.
2+
3+
#![feature(try_trait)]
4+
#![feature(optin_builtin_traits)]
5+
#![feature(const_fn)]
6+
#![feature(decl_macro)]
7+
#![feature(use_extern_macros)]
8+
#![feature(conservative_impl_trait)]
9+
10+
#![no_std]
11+
12+
#![warn(missing_docs)]
13+
#![cfg_attr(feature = "cargo-clippy", warn(clippy))]
14+
15+
#[macro_use]
16+
extern crate bitflags;
17+
18+
mod guid;
19+
pub use self::guid::Guid;
20+
21+
mod status;
22+
pub use self::status::Status;
23+
24+
use core::result;
25+
/// Return type of many UEFI functions.
26+
pub type Result<T> = result::Result<T, Status>;
27+
28+
/// A pointer to an opaque data structure.
29+
pub type Handle = *mut ();
30+
31+
pub mod table;
32+
33+
pub mod proto;

src/proto/console/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//! Console support protocols.
2+
//!
3+
//! The console represents the various input and output methods
4+
//! used by the user to interact with the early boot platform.
5+
6+
pub mod text;

src/proto/console/text/input.rs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use {Status, Result, proto};
2+
use core::mem;
3+
4+
/// Interface for text-based input devices.
5+
#[repr(C)]
6+
pub struct Input {
7+
reset: extern fn(this: &mut Input, extended: bool) -> Status,
8+
read_key_stroke: extern fn(this: &mut Input, key: &mut Key) -> Status,
9+
}
10+
11+
impl Input {
12+
/// Resets the input device hardware.
13+
pub fn reset(&mut self, extended: bool) -> Result<()> {
14+
(self.reset)(self, extended).into()
15+
}
16+
17+
/// Reads the next keystroke from the input device.
18+
///
19+
/// Returns `Err(NotReady)` if no keystroke is available yet.
20+
pub fn read_key(&mut self) -> Result<Key> {
21+
let mut key = unsafe { mem::uninitialized() };
22+
(self.read_key_stroke)(self, &mut key)?;
23+
Ok(key)
24+
}
25+
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) => match code {
33+
// Wait for key press.
34+
Status::NotReady => (),
35+
// Exit on error, no point in looping.
36+
_ => return Err(code),
37+
}
38+
}
39+
}
40+
}
41+
}
42+
43+
/// A key read from the console.
44+
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
45+
#[repr(C)]
46+
pub struct Key {
47+
/// The key's scan code.
48+
pub scan_code: ScanCode,
49+
/// Associated Unicode character,
50+
/// or 0 if not printable.
51+
pub unicode_char: u16,
52+
}
53+
54+
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
55+
#[repr(u16)]
56+
#[allow(missing_docs)]
57+
pub enum ScanCode {
58+
Null,
59+
/// Move cursor up 1 row.
60+
Up,
61+
/// Move cursor down 1 row.
62+
Down,
63+
/// Move cursor right 1 column.
64+
Right,
65+
/// Move cursor left 1 column.
66+
Left,
67+
Home,
68+
End,
69+
Insert,
70+
Delete,
71+
PageUp,
72+
PageDown,
73+
Function1,
74+
Function2,
75+
Function3,
76+
Function4,
77+
Function5,
78+
Function6,
79+
Function7,
80+
Function8,
81+
Function9,
82+
Function10,
83+
Function11,
84+
Function12,
85+
Escape,
86+
87+
Function13 = 0x68,
88+
Function14,
89+
Function15,
90+
Function16,
91+
Function17,
92+
Function18,
93+
Function19,
94+
Function20,
95+
Function21,
96+
Function22,
97+
Function23,
98+
Function24,
99+
100+
Mute = 0x7F,
101+
102+
VolumeUp = 0x80,
103+
VolumeDown,
104+
105+
BrightnessUp = 0x100,
106+
BrightnessDown,
107+
Suspend,
108+
Hibernate,
109+
ToggleDisplay,
110+
Recovery,
111+
Eject,
112+
}
113+
114+
proto::impl_proto! {
115+
protocol Input {
116+
GUID = 0x387477c1, 0x69c7, 0x11d2, [0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b];
117+
}
118+
}

src/proto/console/text/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//! Text I/O.
2+
3+
mod input;
4+
pub use self::input::{Input, Key, ScanCode};
5+
6+
mod output;
7+
pub use self::output::{Output, OutputMode};

src/proto/console/text/output.rs

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
use {Status, Result, proto};
2+
3+
/// Interface for text-based output devices.
4+
#[repr(C)]
5+
pub struct Output {
6+
reset: extern fn(this: &Output, extended: bool) -> Status,
7+
output_string: extern fn(this: &Output, string: *const u16) -> Status,
8+
test_string: extern fn(this: &Output, string: *const u16) -> Status,
9+
query_mode: extern fn(this: &Output, mode: i32, columns: &mut usize, rows: &mut usize) -> Status,
10+
set_mode: extern fn(this: &mut Output, mode: i32) -> Status,
11+
_pad: [usize; 4],
12+
data: &'static OutputData,
13+
}
14+
15+
impl Output {
16+
/// Resets the text output device hardware.
17+
#[inline]
18+
pub fn reset(&mut self, extended: bool) -> Result<()> {
19+
(self.reset)(self, extended).into()
20+
}
21+
22+
/// Writes a string to the output device.
23+
#[inline]
24+
pub fn output_string(&mut self, string: *const u16) -> Result<()> {
25+
(self.output_string)(self, string).into()
26+
}
27+
28+
/// Checks if a string contains only supported characters.
29+
/// True indicates success.
30+
///
31+
/// UEFI applications are encouraged to try to print a string even if it contains
32+
/// some unsupported characters.
33+
#[inline]
34+
pub fn test_string(&mut self, string: *const u16) -> bool {
35+
match (self.test_string)(self, string) {
36+
Status::Success => true,
37+
_ => false,
38+
}
39+
}
40+
41+
/// Returns an iterator of all supported text modes.
42+
// TODO: fix the ugly lifetime parameter.
43+
#[inline]
44+
pub fn modes<'a>(&'a mut self) -> impl Iterator<Item = OutputMode> + 'a {
45+
let max = self.data.max_mode;
46+
OutputModeIter {
47+
output: self,
48+
current: 0,
49+
max,
50+
}
51+
}
52+
53+
/// Returns the width (column count) and height (row count) of this mode.
54+
fn query_mode(&self, index: i32) -> Result<(usize, usize)> {
55+
let (mut columns, mut rows) = (0, 0);
56+
(self.query_mode)(self, index, &mut columns, &mut rows)?;
57+
Ok((columns, rows))
58+
}
59+
60+
/// Sets a mode as current.
61+
#[inline]
62+
pub fn set_mode(&mut self, mode: OutputMode) -> Result<()> {
63+
(self.set_mode)(self, mode.index).into()
64+
}
65+
66+
/// Returns the the current text mode.
67+
#[inline]
68+
pub fn current_mode(&self) -> Result<OutputMode> {
69+
let index = self.data.mode;
70+
let dims = self.query_mode(index)?;
71+
Ok(OutputMode { index, dims } )
72+
}
73+
}
74+
75+
/// The text mode (resolution) of the output device.
76+
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
77+
pub struct OutputMode {
78+
index: i32,
79+
dims: (usize, usize),
80+
}
81+
82+
impl OutputMode {
83+
/// Returns the index of this mode.
84+
#[inline]
85+
pub fn index(&self) -> i32 {
86+
self.index
87+
}
88+
89+
/// Returns the width in columns.
90+
#[inline]
91+
pub fn columns(&self) -> usize {
92+
self.dims.0
93+
}
94+
95+
/// Returns the height in rows.
96+
#[inline]
97+
pub fn rows(&self) -> usize {
98+
self.dims.1
99+
}
100+
}
101+
102+
/// An iterator of the text modes (possibly) supported by a device.
103+
struct OutputModeIter<'a> {
104+
output: &'a mut Output,
105+
current: i32,
106+
max: i32,
107+
}
108+
109+
impl<'a> Iterator for OutputModeIter<'a> {
110+
type Item = OutputMode;
111+
112+
fn next(&mut self) -> Option<Self::Item> {
113+
let index = self.current;
114+
if index < self.max {
115+
self.current += 1;
116+
117+
if let Ok(dims) = self.output.query_mode(index) {
118+
Some(OutputMode { index, dims })
119+
} else {
120+
self.next()
121+
}
122+
} else {
123+
None
124+
}
125+
}
126+
}
127+
128+
/// Additional data of the output device.
129+
#[derive(Debug)]
130+
#[repr(C)]
131+
struct OutputData {
132+
/// The number of modes supported by the device.
133+
max_mode: i32,
134+
/// The current output mode.
135+
mode: i32,
136+
/// The current character output attribute.
137+
attribute: i32,
138+
/// The cursor’s column.
139+
cursor_column: i32,
140+
/// The cursor’s row.
141+
cursor_row: i32,
142+
/// Whether the cursor is currently visible or not.
143+
cursor_visible: bool,
144+
}
145+
146+
proto::impl_proto! {
147+
protocol Output {
148+
GUID = 0x387477c2, 0x69c7, 0x11d2, [0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b];
149+
}
150+
}

src/proto/macros.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use super::Protocol;
2+
use Guid;
3+
4+
/// Implements the `Protocol` trait for a type.
5+
/// Also marks the type as not sync and not send.
6+
pub macro impl_proto (
7+
protocol $p:ident {
8+
GUID = $a:expr, $b:expr, $c:expr, $d:expr;
9+
}
10+
) {
11+
impl Protocol for $p {
12+
const GUID: Guid = Guid::from_values($a, $b, $c, $d);
13+
}
14+
15+
// Most UEFI functions expect to be called on the bootstrap processor.
16+
impl !Send for $p {}
17+
// Most UEFI functions do not support multithreaded access.
18+
impl !Sync for $p {}
19+
}

0 commit comments

Comments
 (0)