From ae7e7d3a8041872dfbe2e3762a65ad8869e881d4 Mon Sep 17 00:00:00 2001 From: James Martin Date: Tue, 21 Jul 2020 13:48:39 -0700 Subject: [PATCH] Use `log` crate instead of ad-hoc print macros. --- Cargo.lock | 9 ++-- Cargo.toml | 4 ++ src/arch/x86_64/idt.rs | 4 +- src/graphics.rs | 1 - src/graphics/font/psf.rs | 1 - src/graphics/tty.rs | 106 --------------------------------------- src/logger.rs | 63 +++++++++++++++++++++++ src/main.rs | 34 +++++++------ 8 files changed, 91 insertions(+), 131 deletions(-) create mode 100644 src/logger.rs diff --git a/Cargo.lock b/Cargo.lock index 50a91b4..209a0db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index f10cdd2..3f76380 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 diff --git a/src/arch/x86_64/idt.rs b/src/arch/x86_64/idt.rs index 4a9e0b1..1d8e758 100644 --- a/src/arch/x86_64/idt.rs +++ b/src/arch/x86_64/idt.rs @@ -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!"); } diff --git a/src/graphics.rs b/src/graphics.rs index ffea653..1fe51e5 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -2,5 +2,4 @@ pub mod color; pub mod display; pub mod font; pub mod terminal; -#[macro_use] pub mod tty; diff --git a/src/graphics/font/psf.rs b/src/graphics/font/psf.rs index d0e6b37..1700e3b 100644 --- a/src/graphics/font/psf.rs +++ b/src/graphics/font/psf.rs @@ -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."); } diff --git a/src/graphics/tty.rs b/src/graphics/tty.rs index aaa0c59..6dbbcb4 100644 --- a/src/graphics/tty.rs +++ b/src/graphics/tty.rs @@ -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 = None; -pub static mut STDERR: Option = 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); -} diff --git a/src/logger.rs b/src/logger.rs new file mode 100644 index 0000000..3993595 --- /dev/null +++ b/src/logger.rs @@ -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), +} + +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)); + } +} diff --git a/src/main.rs b/src/main.rs index e542ad1..7a4cd4b 100644 --- a/src/main.rs +++ b/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) -> 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) -> ! { // 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); +}