Skip to content

Commit 901d82d

Browse files
committed
Add test framework
1 parent aa7750e commit 901d82d

File tree

6 files changed

+193
-0
lines changed

6 files changed

+193
-0
lines changed

tests/Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[package]
2+
name = "tests"
3+
version = "0.1.0"
4+
authors = ["Gabriel Majeri <[email protected]>"]
5+
publish = false
6+
7+
[lib]
8+
crate-type = ["staticlib"]
9+
10+
[dependencies]
11+
rlibc = "1"
12+
compiler_builtins = { git = "https://github.com/rust-lang-nursery/compiler-builtins" }
13+
14+
uefi = { path = ".." }
15+
uefi-logger = { path = "../uefi-logger" }
16+
log = { version = "0.3", default-features = false }

tests/src/lib.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#![no_std]
2+
3+
#![feature(lang_items)]
4+
#![feature(compiler_builtins_lib)]
5+
6+
extern crate uefi;
7+
extern crate uefi_logger;
8+
9+
#[macro_use]
10+
extern crate log;
11+
12+
mod no_std;
13+
14+
use uefi::{Handle, Status};
15+
use uefi::table;
16+
17+
#[no_mangle]
18+
pub extern fn uefi_start(handle: Handle, st: &'static table::SystemTable) -> Status {
19+
let stdout = st.stdout();
20+
stdout.reset(false);
21+
22+
let logger = uefi_logger::UefiLogger::new(stdout);
23+
24+
unsafe {
25+
log::set_logger_raw(|log_level| {
26+
// Log everything.
27+
log_level.set(log::LogLevelFilter::Info);
28+
29+
&logger
30+
}).unwrap(); // Can only fail if already initialized.
31+
}
32+
33+
info!("Hello world!");
34+
info!("Image handle: {:?}", handle);
35+
{
36+
let revision = st.uefi_revision();
37+
let (major, minor) = (revision.major(), revision.minor());
38+
39+
info!("UEFI {}.{}.{}", major, minor / 10, minor % 10);
40+
}
41+
42+
loop {
43+
44+
}
45+
46+
Status::Success
47+
}

tests/src/no_std.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
extern crate rlibc;
2+
extern crate compiler_builtins;
3+
4+
#[lang = "eh_personality"]
5+
fn eh_personality() {
6+
}
7+
8+
#[lang = "panic_fmt"]
9+
#[no_mangle]
10+
#[allow(private_no_mangle_fns)]
11+
pub fn panic_fmt() {
12+
}

uefi-logger/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "uefi-logger"
3+
version = "0.1.0"
4+
authors = ["Gabriel Majeri <[email protected]>"]
5+
publish = false
6+
7+
[dependencies]
8+
uefi = { path = ".." }
9+
log = { version = "0.3", default-features = false }

uefi-logger/src/lib.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#![no_std]
2+
3+
extern crate uefi;
4+
use uefi::proto::console::text::Output;
5+
6+
extern crate log;
7+
8+
use core::cell::UnsafeCell;
9+
10+
mod writer;
11+
use self::writer::OutputWriter;
12+
13+
/// Logging implementation which writes to a UEFI output stream.
14+
pub struct UefiLogger {
15+
writer: UnsafeCell<OutputWriter>,
16+
}
17+
18+
impl UefiLogger {
19+
/// Creates a new logger.
20+
pub fn new(output: &'static mut Output) -> Self {
21+
UefiLogger {
22+
writer: UnsafeCell::new(OutputWriter::new(output))
23+
}
24+
}
25+
}
26+
27+
impl log::Log for UefiLogger {
28+
fn enabled(&self, _metadata: &log::LogMetadata) -> bool {
29+
true
30+
}
31+
32+
fn log(&self, record: &log::LogRecord) {
33+
let args = record.args();
34+
35+
let writer = unsafe { &mut *self.writer.get() };
36+
use core::fmt::Write;
37+
writeln!(writer, "{}", args);
38+
}
39+
}
40+
41+
// The logger is not thread-safe, but the UEFI boot environment only uses one processor.
42+
unsafe impl Sync for UefiLogger {}
43+
unsafe impl Send for UefiLogger {}

uefi-logger/src/writer.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use super::Output;
2+
use core::{fmt, str};
3+
4+
/// Struct which is used to implement the `fmt::Write` trait on a UEFI output protocol.
5+
pub struct OutputWriter {
6+
output: &'static mut Output
7+
}
8+
9+
impl OutputWriter {
10+
pub fn new(output: &'static mut Output) -> Self {
11+
OutputWriter {
12+
output
13+
}
14+
}
15+
}
16+
17+
impl fmt::Write for OutputWriter {
18+
fn write_str(&mut self, s: &str) -> fmt::Result {
19+
// Allocate a small buffer on the stack.
20+
const BUF_SIZE: usize = 128;
21+
// Add 1 extra character for the null terminator.
22+
let mut buf = [0u16; BUF_SIZE + 1];
23+
24+
let mut i = 0;
25+
26+
// This closure writes the local buffer to the output and resets the buffer.
27+
let mut flush_buffer = |buf: &mut [u16], i: &mut usize| {
28+
buf[*i] = 0;
29+
*i = 0;
30+
31+
self.output.output_string(buf.as_ptr()).map_err(|_| fmt::Error)
32+
};
33+
34+
{
35+
// This closure converts a character to UCS-2 and adds it to the buffer,
36+
// flushing it as necessary.
37+
let mut add_char = |ch| {
38+
// UEFI only supports UCS-2 characters, not UTF-16,
39+
// so there are no multibyte characters.
40+
let ch = ch as u16;
41+
42+
buf[i] = ch;
43+
44+
i += 1;
45+
46+
if i == BUF_SIZE {
47+
flush_buffer(&mut buf, &mut i)
48+
} else {
49+
Ok(())
50+
}
51+
};
52+
53+
for ch in s.chars() {
54+
if ch == '\n' {
55+
// Prepend an '\r'.
56+
add_char('\r')?;
57+
}
58+
59+
add_char(ch)?;
60+
}
61+
}
62+
63+
// Flush whatever is left in the buffer.
64+
flush_buffer(&mut buf, &mut i)
65+
}
66+
}

0 commit comments

Comments
 (0)