Use `log` crate instead of ad-hoc print macros.
parent
f2db3d581d
commit
ae7e7d3a80
|
@ -29,6 +29,7 @@ name = "bootproof"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compiler_builtins",
|
"compiler_builtins",
|
||||||
|
"log",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"uefi",
|
"uefi",
|
||||||
"x86_64",
|
"x86_64",
|
||||||
|
@ -75,9 +76,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.18"
|
version = "1.0.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
|
checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
@ -93,9 +94,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.34"
|
version = "1.0.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "936cae2873c940d92e697597c5eee105fb570cd5689c695806f672883653349b"
|
checksum = "fb7f4c519df8c117855e19dd8cc851e89eb746fe7a73f0157e0d95fdec5369b0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
@ -12,6 +12,10 @@ compiler_builtins = { git = "https://github.com/rust-lang/compiler-builtins" }
|
||||||
uefi = "0.4.7"
|
uefi = "0.4.7"
|
||||||
x86_64 = "0.11.1"
|
x86_64 = "0.11.1"
|
||||||
|
|
||||||
|
[dependencies.log]
|
||||||
|
version = "0.4.11"
|
||||||
|
default-features = false
|
||||||
|
|
||||||
[dependencies.num-integer]
|
[dependencies.num-integer]
|
||||||
version = "0.1.36"
|
version = "0.1.36"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use crate::graphics::tty::Tty;
|
|
||||||
use crate::println;
|
|
||||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||||
|
|
||||||
static mut IDT: InterruptDescriptorTable = InterruptDescriptorTable::new();
|
static mut IDT: InterruptDescriptorTable = InterruptDescriptorTable::new();
|
||||||
|
@ -12,5 +10,5 @@ pub fn load() {
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn breakpoint_handler(_: &mut InterruptStackFrame) {
|
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 display;
|
||||||
pub mod font;
|
pub mod font;
|
||||||
pub mod terminal;
|
pub mod terminal;
|
||||||
#[macro_use]
|
|
||||||
pub mod tty;
|
pub mod tty;
|
||||||
|
|
|
@ -125,7 +125,6 @@ impl Glyph for PSFGlyph {
|
||||||
|
|
||||||
fn get(&self, x: usize, y: usize) -> bool {
|
fn get(&self, x: usize, y: usize) -> bool {
|
||||||
if x > self.width || y > self.height {
|
if x > self.width || y > self.height {
|
||||||
use crate::graphics::tty::Tty;
|
|
||||||
crate::panic!("Glyph pixel index out of bounds.");
|
crate::panic!("Glyph pixel index out of bounds.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,115 +1,9 @@
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
pub mod terminal;
|
pub mod terminal;
|
||||||
|
|
||||||
use crate::graphics::tty::serial::SerialTty;
|
|
||||||
|
|
||||||
pub trait Tty {
|
pub trait Tty {
|
||||||
fn putc(&mut self, c: char);
|
fn putc(&mut self, c: char);
|
||||||
fn puts(&mut self, s: &str);
|
fn puts(&mut self, s: &str);
|
||||||
fn clear(&mut self);
|
fn clear(&mut self);
|
||||||
fn flush(&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 allocator;
|
||||||
mod arch;
|
mod arch;
|
||||||
#[macro_use]
|
|
||||||
mod graphics;
|
mod graphics;
|
||||||
|
|
||||||
|
mod logger;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use crate::graphics::tty::{Tty, STDOUT, STDERR};
|
|
||||||
use crate::graphics::tty::serial::SerialTty;
|
use crate::graphics::tty::serial::SerialTty;
|
||||||
use uefi::prelude::*;
|
use uefi::prelude::*;
|
||||||
|
|
||||||
|
@ -36,20 +36,8 @@ fn efi_main(handle: Handle, st_boot: SystemTable<Boot>) -> Status {
|
||||||
// which is undefined behavior.
|
// which is undefined behavior.
|
||||||
ALLOCATOR = GlobalAllocator::Uefi(UefiAllocator::new(st_boot.unsafe_clone()));
|
ALLOCATOR = GlobalAllocator::Uefi(UefiAllocator::new(st_boot.unsafe_clone()));
|
||||||
|
|
||||||
// Although serial ports don't physically exist on modern devices,
|
logger::set_tty(SerialTty::new(0x3F8));
|
||||||
// they're still supposed by emulators (for QEMU you can set `-serial stdio`),
|
logger::init().unwrap();
|
||||||
// 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
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Our first task is to exit the UEFI boot services.
|
// 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.
|
// We do *not* disable interrupts to allow for testing the interrupt handlers.
|
||||||
loop { x86_64::instructions::hlt(); }
|
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