Skip to content

Commit c2ea82d

Browse files
committed
Split logger from OS.
Fixes #97.
1 parent 852b458 commit c2ea82d

2 files changed

Lines changed: 121 additions & 75 deletions

File tree

pixie-uefi/src/os/logger.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
use alloc::{collections::vec_deque::VecDeque, string::String};
2+
use core::fmt::Write;
3+
use log::Level;
4+
use spin::Mutex;
5+
use uefi::{boot::ScopedProtocol, proto::console::serial::Serial};
6+
7+
use crate::os::{timer::Timer, UefiOS};
8+
9+
static MESSAGES: Mutex<VecDeque<LogEntry>> = Mutex::new(VecDeque::new());
10+
static SERIAL: Mutex<Option<SerialWrapper>> = Mutex::new(None);
11+
12+
pub(super) struct LogEntry {
13+
pub time: f64,
14+
pub level: Level,
15+
pub target: String,
16+
pub msg: String,
17+
}
18+
19+
struct SerialWrapper(ScopedProtocol<Serial>);
20+
21+
// SAFETY: There are no threads.
22+
unsafe impl Send for SerialWrapper {}
23+
24+
struct Logger {}
25+
26+
pub(super) fn init() {
27+
let serial = uefi::boot::find_handles::<Serial>()
28+
.ok()
29+
.map(|handles| uefi::boot::open_protocol_exclusive::<Serial>(handles[0]).unwrap());
30+
31+
*SERIAL.lock() = serial.map(SerialWrapper);
32+
33+
log::set_logger(&Logger {}).unwrap();
34+
log::set_max_level(log::LevelFilter::Trace);
35+
}
36+
37+
fn append_message(time: f64, level: log::Level, target: &str, msg: String) {
38+
if let Some(serial) = &mut *SERIAL.lock() {
39+
let style = match level {
40+
Level::Trace => anstyle::AnsiColor::Cyan.on_default(),
41+
Level::Debug => anstyle::AnsiColor::Blue.on_default(),
42+
Level::Info => anstyle::AnsiColor::Green.on_default(),
43+
Level::Warn => anstyle::AnsiColor::Yellow.on_default(),
44+
Level::Error => anstyle::AnsiColor::Red.on_default().bold(),
45+
};
46+
write!(
47+
serial.0,
48+
"[{time:.1}s {style}{level:5}{style:#} {target}] {msg}\r\n"
49+
)
50+
.unwrap();
51+
}
52+
53+
{
54+
let mut logs = MESSAGES.try_lock().expect("messages are locked");
55+
logs.push_back(LogEntry {
56+
time,
57+
level,
58+
target: target.into(),
59+
msg,
60+
});
61+
const MAX_MESSAGES: usize = 10;
62+
if logs.len() > MAX_MESSAGES {
63+
logs.pop_front();
64+
}
65+
}
66+
67+
if level <= Level::Warn {
68+
UefiOS { cant_build: () }.force_ui_redraw()
69+
}
70+
}
71+
72+
pub(super) fn for_each_log<F: FnMut(&LogEntry)>(f: F) {
73+
MESSAGES
74+
.try_lock()
75+
.expect("messages are locked")
76+
.iter()
77+
.for_each(f);
78+
}
79+
80+
impl log::Log for Logger {
81+
fn enabled(&self, _metadata: &log::Metadata) -> bool {
82+
true
83+
}
84+
85+
fn log(&self, record: &log::Record) {
86+
let now = Timer::micros() as f64 * 0.000_001;
87+
append_message(
88+
now,
89+
record.level(),
90+
record.target(),
91+
format!("{}", record.args()),
92+
);
93+
}
94+
95+
fn flush(&self) {
96+
// no-op
97+
}
98+
}

pixie-uefi/src/os/mod.rs

Lines changed: 23 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use alloc::boxed::Box;
2-
use alloc::collections::VecDeque;
32
use alloc::string::{String, ToString};
43
use alloc::vec::Vec;
54
use core::cell::RefMut;
@@ -11,10 +10,11 @@ use core::task::Poll;
1110

1211
use pixie_shared::util::BytesFmt;
1312
use uefi::boot::{EventType, ScopedProtocol, Tpl};
14-
use uefi::proto::console::serial::Serial;
1513
use uefi::proto::console::text::{Color, Input, Key, Output};
1614
use uefi::{Event, Status};
1715

16+
use crate::os::logger::{for_each_log, LogEntry};
17+
1818
use self::error::Result;
1919
use self::executor::Executor;
2020
use self::sync::SyncRefCell;
@@ -24,6 +24,7 @@ pub mod boot_options;
2424
pub mod disk;
2525
pub mod error;
2626
pub mod executor;
27+
mod logger;
2728
pub mod memory;
2829
pub mod net;
2930
pub mod sync;
@@ -32,8 +33,6 @@ mod timer;
3233
struct UefiOSImpl {
3334
input: ScopedProtocol<Input>,
3435
vga: ScopedProtocol<Output>,
35-
serial: Option<ScopedProtocol<Serial>>,
36-
messages: VecDeque<(f64, log::Level, String, String)>,
3736
ui_buf: Vec<(String, Color, Color)>,
3837
ui_pos: usize,
3938
ui_drawer: Option<Box<dyn Fn(UefiOS) + 'static>>,
@@ -137,10 +136,6 @@ impl UefiOS {
137136
let input_handles = uefi::boot::find_handles::<Input>().unwrap();
138137
let input = uefi::boot::open_protocol_exclusive::<Input>(input_handles[0]).unwrap();
139138

140-
let serial = uefi::boot::find_handles::<Serial>()
141-
.ok()
142-
.map(|handles| uefi::boot::open_protocol_exclusive::<Serial>(handles[0]).unwrap());
143-
144139
let vga_handles = uefi::boot::find_handles::<Output>().unwrap();
145140
let mut vga = uefi::boot::open_protocol_exclusive::<Output>(vga_handles[0]).unwrap();
146141

@@ -149,18 +144,14 @@ impl UefiOS {
149144
*OS.borrow_mut() = Some(UefiOSImpl {
150145
input,
151146
vga,
152-
serial,
153-
messages: VecDeque::new(),
154147
ui_buf: vec![],
155148
ui_pos: 0,
156149
ui_drawer: None,
157150
});
158151

159152
let os = UefiOS { cant_build: () };
160153

161-
log::set_logger(&UefiOS { cant_build: () }).unwrap();
162-
log::set_max_level(log::LevelFilter::Trace);
163-
154+
logger::init();
164155
net::init();
165156

166157
Executor::spawn("init", async move {
@@ -261,20 +252,25 @@ impl UefiOS {
261252
os.maybe_advance_to_col(cols);
262253

263254
// TODO(veluca): find a better solution.
264-
let messages: Vec<_> = os.messages.iter().cloned().collect();
265-
266-
for (time, level, target, msg) in messages {
267-
let fg_color = match level {
268-
log::Level::Trace => Color::Cyan,
269-
log::Level::Debug => Color::Blue,
270-
log::Level::Info => Color::Green,
271-
log::Level::Warn => Color::Yellow,
272-
log::Level::Error => Color::Red,
273-
};
274-
os.write_with_color(&format!("[{time:.1}s "), Color::White, Color::Black);
275-
os.write_with_color(&format!("{level:5}"), fg_color, Color::Black);
276-
os.write_with_color(&format!(" {target}] {msg}\n"), Color::White, Color::Black);
277-
}
255+
for_each_log(
256+
|LogEntry {
257+
time,
258+
level,
259+
target,
260+
msg,
261+
}| {
262+
let fg_color = match level {
263+
log::Level::Trace => Color::Cyan,
264+
log::Level::Debug => Color::Blue,
265+
log::Level::Info => Color::Green,
266+
log::Level::Warn => Color::Yellow,
267+
log::Level::Error => Color::Red,
268+
};
269+
os.write_with_color(&format!("[{time:.1}s "), Color::White, Color::Black);
270+
os.write_with_color(&format!("{level:5}"), fg_color, Color::Black);
271+
os.write_with_color(&format!(" {target}] {msg}\n"), Color::White, Color::Black);
272+
},
273+
);
278274
os.write_with_color("\n", Color::Black, Color::Black);
279275
}
280276
{
@@ -295,52 +291,4 @@ impl UefiOS {
295291
pub fn set_ui_drawer<F: Fn(UefiOS) + 'static>(&self, f: F) {
296292
self.borrow_mut().ui_drawer = Some(Box::new(f));
297293
}
298-
299-
fn append_message(&self, time: f64, level: log::Level, target: &str, msg: String) {
300-
{
301-
let mut os = self.borrow_mut();
302-
303-
if let Some(serial) = &mut os.serial {
304-
let style = match level {
305-
log::Level::Trace => anstyle::AnsiColor::Cyan.on_default(),
306-
log::Level::Debug => anstyle::AnsiColor::Blue.on_default(),
307-
log::Level::Info => anstyle::AnsiColor::Green.on_default(),
308-
log::Level::Warn => anstyle::AnsiColor::Yellow.on_default(),
309-
log::Level::Error => anstyle::AnsiColor::Red.on_default().bold(),
310-
};
311-
write!(
312-
serial,
313-
"[{time:.1}s {style}{level:5}{style:#} {target}] {msg}\r\n"
314-
)
315-
.unwrap();
316-
}
317-
318-
os.messages.push_back((time, level, target.into(), msg));
319-
const MAX_MESSAGES: usize = 10;
320-
if os.messages.len() > MAX_MESSAGES {
321-
os.messages.pop_front();
322-
}
323-
}
324-
self.force_ui_redraw();
325-
}
326-
}
327-
328-
impl log::Log for UefiOS {
329-
fn enabled(&self, _metadata: &log::Metadata) -> bool {
330-
true
331-
}
332-
333-
fn log(&self, record: &log::Record) {
334-
let now = Timer::micros() as f64 * 0.000_001;
335-
self.append_message(
336-
now,
337-
record.level(),
338-
record.target(),
339-
format!("{}", record.args()),
340-
);
341-
}
342-
343-
fn flush(&self) {
344-
// no-op
345-
}
346294
}

0 commit comments

Comments
 (0)