Use `log` crate instead of ad-hoc print macros.
parent
f2db3d581d
commit
ae7e7d3a80
|
@ -29,6 +29,7 @@ name = "bootproof"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"log",
|
||||
"num-integer",
|
||||
"uefi",
|
||||
"x86_64",
|
||||
|
@ -75,9 +76,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.18"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
|
||||
checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
@ -93,9 +94,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.34"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "936cae2873c940d92e697597c5eee105fb570cd5689c695806f672883653349b"
|
||||
checksum = "fb7f4c519df8c117855e19dd8cc851e89eb746fe7a73f0157e0d95fdec5369b0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
@ -12,6 +12,10 @@ compiler_builtins = { git = "https://github.com/rust-lang/compiler-builtins" }
|
|||
uefi = "0.4.7"
|
||||
x86_64 = "0.11.1"
|
||||
|
||||
[dependencies.log]
|
||||
version = "0.4.11"
|
||||
default-features = false
|
||||
|
||||
[dependencies.num-integer]
|
||||
version = "0.1.36"
|
||||
default-features = false
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use crate::graphics::tty::Tty;
|
||||
use crate::println;
|
||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||
|
||||
static mut IDT: InterruptDescriptorTable = InterruptDescriptorTable::new();
|
||||
|
@ -12,5 +10,5 @@ pub fn load() {
|
|||
}
|
||||
|
||||
extern "x86-interrupt" fn breakpoint_handler(_: &mut InterruptStackFrame) {
|
||||
println!("Breakpoint reached!");
|
||||
log::info!("Breakpoint reached!");
|
||||
}
|
||||
|
|
|
@ -2,5 +2,4 @@ pub mod color;
|
|||
pub mod display;
|
||||
pub mod font;
|
||||
pub mod terminal;
|
||||
#[macro_use]
|
||||
pub mod tty;
|
||||
|
|
|
@ -125,7 +125,6 @@ impl Glyph for PSFGlyph {
|
|||
|
||||
fn get(&self, x: usize, y: usize) -> bool {
|
||||
if x > self.width || y > self.height {
|
||||
use crate::graphics::tty::Tty;
|
||||
crate::panic!("Glyph pixel index out of bounds.");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,115 +1,9 @@
|
|||
pub mod serial;
|
||||
pub mod terminal;
|
||||
|
||||
use crate::graphics::tty::serial::SerialTty;
|
||||
|
||||
pub trait Tty {
|
||||
fn putc(&mut self, c: char);
|
||||
fn puts(&mut self, s: &str);
|
||||
fn clear(&mut self);
|
||||
fn flush(&mut self);
|
||||
}
|
||||
|
||||
pub static mut STDOUT: Option<SerialTty> = None;
|
||||
pub static mut STDERR: Option<SerialTty> = None;
|
||||
|
||||
// HACK: These macros are horribly repetitive. There's got to be a better way...
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! print {
|
||||
// These additional single-argument cases are necessary because `format!` requires allocation,
|
||||
// which I don't necessarily *have* (not to mention it's inefficient).
|
||||
($s:expr) => {{
|
||||
let mut tty;
|
||||
unsafe {
|
||||
tty = crate::graphics::tty::STDOUT.clone().unwrap();
|
||||
}
|
||||
tty.puts($s);
|
||||
tty.flush();
|
||||
}};
|
||||
($($arg:expr),*) => {{
|
||||
let mut tty;
|
||||
unsafe {
|
||||
tty = crate::graphics::tty::STDOUT.clone().unwrap();
|
||||
}
|
||||
tty.puts(&alloc::format!($($arg),*));
|
||||
tty.flush();
|
||||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! println {
|
||||
($s:expr) => {{
|
||||
let mut tty;
|
||||
unsafe {
|
||||
tty = crate::graphics::tty::STDOUT.clone().unwrap();
|
||||
}
|
||||
tty.puts($s);
|
||||
tty.putc('\n');
|
||||
tty.flush();
|
||||
}};
|
||||
($($arg:expr),*) => {{
|
||||
let mut tty;
|
||||
unsafe {
|
||||
tty = crate::graphics::tty::STDOUT.clone().unwrap();
|
||||
}
|
||||
tty.puts(&alloc::format!($($arg),*));
|
||||
tty.putc('\n');
|
||||
tty.flush();
|
||||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! eprint {
|
||||
($s:expr) => {{
|
||||
let mut tty;
|
||||
unsafe {
|
||||
tty = crate::graphics::tty::STDERR.clone().unwrap();
|
||||
}
|
||||
tty.puts($s);
|
||||
tty.flush();
|
||||
}};
|
||||
($($arg:expr),*) => {{
|
||||
let mut tty;
|
||||
unsafe {
|
||||
tty = crate::graphics::tty::STDERR.clone().unwrap();
|
||||
}
|
||||
tty.puts(&alloc::format!($($arg),*));
|
||||
tty.flush();
|
||||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! eprintln {
|
||||
($s:expr) => {{
|
||||
let mut tty;
|
||||
unsafe {
|
||||
tty = crate::graphics::tty::STDERR.clone().unwrap();
|
||||
}
|
||||
tty.puts($s);
|
||||
tty.putc('\n');
|
||||
tty.flush();
|
||||
}};
|
||||
($($arg:expr),*) => {{
|
||||
let mut tty;
|
||||
unsafe {
|
||||
tty = crate::graphics::tty::STDERR.clone().unwrap();
|
||||
}
|
||||
tty.puts(&alloc::format!($($arg),*));
|
||||
tty.putc('\n');
|
||||
tty.flush();
|
||||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! panic {
|
||||
($($arg:expr),*) => {{
|
||||
crate::eprintln!($($arg),*);
|
||||
crate::arch::x86_64::halt()
|
||||
}}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
panic!("{}", info);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
use alloc::format;
|
||||
use core::cell::UnsafeCell;
|
||||
use crate::graphics::tty::Tty;
|
||||
use crate::graphics::tty::serial::SerialTty;
|
||||
use log::{Record, LevelFilter, Metadata, SetLoggerError};
|
||||
|
||||
enum GlobalLogger {
|
||||
None,
|
||||
// Hardcoding as SerialTty for now.
|
||||
// I can worry about dealing with other implementation types when necessary.
|
||||
Tty(UnsafeCell<SerialTty>),
|
||||
}
|
||||
|
||||
use GlobalLogger::*;
|
||||
|
||||
impl log::Log for GlobalLogger {
|
||||
fn enabled(&self, _metadata: &Metadata) -> bool {
|
||||
match self {
|
||||
None => false,
|
||||
_ => true
|
||||
}
|
||||
}
|
||||
|
||||
fn log(&self, record: &Record) {
|
||||
match self {
|
||||
None => {},
|
||||
Tty(tty) => unsafe {
|
||||
// TODO: Lose the dependency on the `format!` macro
|
||||
// so we don't have to allocate a String here.
|
||||
(*tty.get()).puts(&format!("{} - {}", record.level(), record.args()));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&self) {
|
||||
match self {
|
||||
None => {},
|
||||
Tty(tty) => unsafe {
|
||||
(*tty.get()).flush();
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The logger is not thread-safe, but for now we only use one processor.
|
||||
// FIXME: Support multiple processors.
|
||||
unsafe impl Sync for GlobalLogger {}
|
||||
unsafe impl Send for GlobalLogger {}
|
||||
|
||||
static mut LOGGER: GlobalLogger = GlobalLogger::None;
|
||||
|
||||
pub fn init() -> Result<(), SetLoggerError> {
|
||||
unsafe {
|
||||
log::set_logger(&LOGGER)
|
||||
.map(|()| log::set_max_level(LevelFilter::Info))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_tty(tty: SerialTty) {
|
||||
unsafe {
|
||||
LOGGER = GlobalLogger::Tty(UnsafeCell::new(tty));
|
||||
}
|
||||
}
|
34
src/main.rs
34
src/main.rs
|
@ -9,11 +9,11 @@ extern crate alloc;
|
|||
|
||||
mod allocator;
|
||||
mod arch;
|
||||
#[macro_use]
|
||||
mod graphics;
|
||||
|
||||
mod logger;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use crate::graphics::tty::{Tty, STDOUT, STDERR};
|
||||
use crate::graphics::tty::serial::SerialTty;
|
||||
use uefi::prelude::*;
|
||||
|
||||
|
@ -36,20 +36,8 @@ fn efi_main(handle: Handle, st_boot: SystemTable<Boot>) -> Status {
|
|||
// which is undefined behavior.
|
||||
ALLOCATOR = GlobalAllocator::Uefi(UefiAllocator::new(st_boot.unsafe_clone()));
|
||||
|
||||
// Although serial ports don't physically exist on modern devices,
|
||||
// they're still supposed by emulators (for QEMU you can set `-serial stdio`),
|
||||
// and they're extremely useful for debugging
|
||||
// because they don't require any setup and are trivial to use.
|
||||
STDOUT = Some({
|
||||
let mut stdout = SerialTty::new(0x3F8);
|
||||
stdout.clear();
|
||||
stdout
|
||||
});
|
||||
STDERR = Some({
|
||||
let mut stderr = SerialTty::new(0x3F8);
|
||||
stderr.clear();
|
||||
stderr
|
||||
});
|
||||
logger::set_tty(SerialTty::new(0x3F8));
|
||||
logger::init().unwrap();
|
||||
}
|
||||
|
||||
// Our first task is to exit the UEFI boot services.
|
||||
|
@ -119,3 +107,17 @@ fn main(_st: SystemTable<uefi::table::Runtime>) -> ! {
|
|||
// We do *not* disable interrupts to allow for testing the interrupt handlers.
|
||||
loop { x86_64::instructions::hlt(); }
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! panic {
|
||||
($($arg:expr),*) => {{
|
||||
log::error!($($arg),*);
|
||||
// FIXME: Panic shouldn't depend on an architecture-specific function.
|
||||
crate::arch::x86_64::halt()
|
||||
}}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
panic!("{}", info);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue