Replace "logger" with a TTY. Added serial and UEFI TTYs.
parent
42af83395b
commit
5445ead12b
|
@ -2,6 +2,7 @@ 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;
|
||||||
|
|
||||||
use crate::graphics::color::{COLOR_BLACK, COLOR_WHITE};
|
use crate::graphics::color::{COLOR_BLACK, COLOR_WHITE};
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
use crate::println;
|
||||||
use crate::graphics::color::{Color, RGB};
|
use crate::graphics::color::{Color, RGB};
|
||||||
use crate::graphics::display::Display;
|
use crate::graphics::display::Display;
|
||||||
|
use crate::graphics::tty::Tty;
|
||||||
use uefi::proto::console::gop::{FrameBuffer, GraphicsOutput, ModeInfo, PixelFormat};
|
use uefi::proto::console::gop::{FrameBuffer, GraphicsOutput, ModeInfo, PixelFormat};
|
||||||
|
|
||||||
const PIXEL_WIDTH_BYTES: usize = 4;
|
const PIXEL_WIDTH_BYTES: usize = 4;
|
||||||
|
@ -24,7 +26,7 @@ impl GopDisplay<'_> {
|
||||||
}
|
}
|
||||||
let mode = mode.expect("No usable pixel formats found.");
|
let mode = mode.expect("No usable pixel formats found.");
|
||||||
let (width, height) = mode.info().resolution();
|
let (width, height) = mode.info().resolution();
|
||||||
crate::log!("Using mode: {}x{} {:?}", width, height, mode.info().pixel_format());
|
println!("Using mode: {}x{} {:?}", width, height, mode.info().pixel_format());
|
||||||
gop.set_mode(&mode).expect("Failed to set UEFI Graphics Output mode.").unwrap();
|
gop.set_mode(&mode).expect("Failed to set UEFI Graphics Output mode.").unwrap();
|
||||||
|
|
||||||
let info = gop.current_mode_info();
|
let info = gop.current_mode_info();
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
|
pub mod serial;
|
||||||
pub mod terminal;
|
pub mod terminal;
|
||||||
|
pub mod uefi;
|
||||||
|
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use crate::graphics::tty::serial::SerialTty;
|
||||||
|
|
||||||
pub trait Tty {
|
pub trait Tty {
|
||||||
fn putc(&mut self, c: char);
|
fn putc(&mut self, c: char);
|
||||||
|
@ -6,3 +11,69 @@ pub trait Tty {
|
||||||
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;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print {
|
||||||
|
($( $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 {
|
||||||
|
($( $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 {
|
||||||
|
($( $arg:expr ),* ) => {
|
||||||
|
let mut tty;
|
||||||
|
unsafe {
|
||||||
|
tty = crate::graphics::tty::STDOUT.clone().unwrap();
|
||||||
|
}
|
||||||
|
tty.puts(&alloc::format!($( $arg ),*));
|
||||||
|
tty.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! eprintln {
|
||||||
|
($( $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! panic {
|
||||||
|
($( $arg:expr ),* ) => {
|
||||||
|
crate::eprintln!($( $arg ),*);
|
||||||
|
crate::misc::halt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
|
panic!("{}", info);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
use alloc::string::String;
|
||||||
|
use crate::graphics::tty::Tty;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SerialTty {
|
||||||
|
port: u16,
|
||||||
|
buffer: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SerialTty {
|
||||||
|
pub unsafe fn new(port: u16) -> SerialTty {
|
||||||
|
SerialTty {
|
||||||
|
port: port,
|
||||||
|
buffer: String::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn outb(&self, cmd: u8) {
|
||||||
|
unsafe {
|
||||||
|
asm!("out dx, al", in("dx") self.port, in("al") cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tty for SerialTty {
|
||||||
|
fn putc(&mut self, c: char) {
|
||||||
|
self.buffer.push(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn puts(&mut self, s: &str) {
|
||||||
|
self.buffer.push_str(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self) {
|
||||||
|
// VT100 escape code to reset the terminal: `ESC C`.
|
||||||
|
self.puts("\u{1B}c");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) {
|
||||||
|
for b in self.buffer.bytes() {
|
||||||
|
self.outb(b);
|
||||||
|
}
|
||||||
|
self.buffer.clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
use alloc::string::String;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use crate::graphics::tty::Tty;
|
||||||
|
use uefi::proto::console::text::Output;
|
||||||
|
|
||||||
|
struct UefiTty<'boot> {
|
||||||
|
// It is impossible to get ownership of an Output,
|
||||||
|
// so instead we must pass in the entire boot system table.
|
||||||
|
output: Output<'boot>,
|
||||||
|
buffer: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UefiTty<'_> {
|
||||||
|
pub fn new<'boot>(output: Output<'boot>) -> UefiTty<'boot> {
|
||||||
|
UefiTty {
|
||||||
|
output: output,
|
||||||
|
buffer: String::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tty for UefiTty<'_> {
|
||||||
|
fn putc(&mut self, c: char) {
|
||||||
|
self.buffer.push(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn puts(&mut self, s: &str) {
|
||||||
|
self.buffer.push_str(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self) {
|
||||||
|
// VT100 escape code to reset the terminal: `ESC C`.
|
||||||
|
self.output.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) {
|
||||||
|
let mut codes: Vec<u16> = Vec::new();
|
||||||
|
for c in self.buffer.chars() {
|
||||||
|
codes.push(c as u16);
|
||||||
|
}
|
||||||
|
codes.push(0);
|
||||||
|
|
||||||
|
let s = uefi::CStr16::from_u16_with_nul(&codes)
|
||||||
|
.unwrap_or_else(|_| panic!("Failed to convert to UCS-2: {}", self.buffer));
|
||||||
|
self.output.output_string(s).unwrap().unwrap();
|
||||||
|
|
||||||
|
self.buffer.clear();
|
||||||
|
}
|
||||||
|
}
|
101
src/logger.rs
101
src/logger.rs
|
@ -1,101 +0,0 @@
|
||||||
use core::fmt::Write;
|
|
||||||
|
|
||||||
pub enum LoggerBackend {
|
|
||||||
None,
|
|
||||||
// It is impossible to get ownership of an Output,
|
|
||||||
// so instead we must pass in the entire boot system table.
|
|
||||||
UefiStdio(uefi::prelude::SystemTable<uefi::prelude::Boot>),
|
|
||||||
}
|
|
||||||
|
|
||||||
enum LoggerOutput {
|
|
||||||
Stdout,
|
|
||||||
Stderr
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Logger<'a> {
|
|
||||||
backend: &'a LoggerBackend,
|
|
||||||
output: LoggerOutput
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LoggerBackend {
|
|
||||||
pub fn stdout<'a>(&'a self) -> Logger<'a> {
|
|
||||||
Logger {
|
|
||||||
backend: self,
|
|
||||||
output: LoggerOutput::Stdout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn stderr<'a>(&'a self) -> Logger<'a> {
|
|
||||||
Logger {
|
|
||||||
backend: self,
|
|
||||||
output: LoggerOutput::Stderr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Write for Logger<'_> {
|
|
||||||
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
|
|
||||||
match self.backend {
|
|
||||||
LoggerBackend::UefiStdio(st) => {
|
|
||||||
let output = match &self.output {
|
|
||||||
LoggerOutput::Stdout => st.stdout(),
|
|
||||||
LoggerOutput::Stderr => st.stderr()
|
|
||||||
};
|
|
||||||
output.write_str(s)
|
|
||||||
},
|
|
||||||
LoggerBackend::None => {
|
|
||||||
// There's pretty much no way to recover from a missing logger.
|
|
||||||
// What are we supposed to do-- log the error?
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static mut LOGGER_BACKEND: LoggerBackend = LoggerBackend::None;
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! log {
|
|
||||||
($( $arg:expr ),* ) => {
|
|
||||||
unsafe {
|
|
||||||
use core::fmt::Write;
|
|
||||||
core::writeln!(crate::logger::LOGGER_BACKEND.stderr(), $( $arg ),*).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! print {
|
|
||||||
($( $arg:expr ),* ) => {
|
|
||||||
unsafe {
|
|
||||||
use core::fmt::Write;
|
|
||||||
core::write!(crate::logger::LOGGER_BACKEND.stdout(), $( $arg ),*).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! println {
|
|
||||||
($( $arg:expr ),* ) => {
|
|
||||||
unsafe {
|
|
||||||
use core::fmt::Write;
|
|
||||||
core::writeln!(crate::logger::LOGGER_BACKEND.stdout(), $( $arg ),*).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! panic {
|
|
||||||
($( $arg:expr ),* ) => {
|
|
||||||
{
|
|
||||||
use crate::misc::halt;
|
|
||||||
crate::log!($( $arg ),*);
|
|
||||||
halt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[panic_handler]
|
|
||||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
|
||||||
panic!("{}", info);
|
|
||||||
}
|
|
20
src/main.rs
20
src/main.rs
|
@ -6,16 +6,17 @@
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
mod allocator;
|
mod allocator;
|
||||||
|
#[macro_use]
|
||||||
mod graphics;
|
mod graphics;
|
||||||
mod logger;
|
|
||||||
mod misc;
|
mod misc;
|
||||||
|
|
||||||
use crate::allocator::{Allocator, ALLOCATOR};
|
use alloc::boxed::Box;
|
||||||
use crate::logger::{LoggerBackend, LOGGER_BACKEND};
|
|
||||||
use crate::misc::halt;
|
|
||||||
|
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::slice;
|
use core::slice;
|
||||||
|
use crate::allocator::{Allocator, ALLOCATOR};
|
||||||
|
use crate::graphics::tty::{Tty, STDOUT, STDERR};
|
||||||
|
use crate::graphics::tty::serial::SerialTty;
|
||||||
|
use crate::misc::halt;
|
||||||
use uefi::prelude::*;
|
use uefi::prelude::*;
|
||||||
use uefi::table::boot::{AllocateType, MemoryDescriptor, MemoryType};
|
use uefi::table::boot::{AllocateType, MemoryDescriptor, MemoryType};
|
||||||
|
|
||||||
|
@ -23,6 +24,7 @@ fn setup(st: &SystemTable<Boot>, _handle: Handle) {
|
||||||
st.stdout().reset(false).expect_success("Failed to reset UEFI stdout.");
|
st.stdout().reset(false).expect_success("Failed to reset UEFI stdout.");
|
||||||
|
|
||||||
println!("Booting...");
|
println!("Booting...");
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
for entry in st.config_table() {
|
for entry in st.config_table() {
|
||||||
use uefi::table::cfg::*;
|
use uefi::table::cfg::*;
|
||||||
|
@ -50,7 +52,8 @@ fn efi_main(handle: Handle, st_boot: SystemTable<Boot>) -> Status {
|
||||||
// Tasks that require the UEFI boot services.
|
// Tasks that require the UEFI boot services.
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
LOGGER_BACKEND = LoggerBackend::UefiStdio(st_boot.unsafe_clone());
|
STDOUT = Some(SerialTty::new(0x3F8));
|
||||||
|
STDERR = Some(SerialTty::new(0x3F8));
|
||||||
ALLOCATOR = Allocator::Uefi(st_boot.unsafe_clone());
|
ALLOCATOR = Allocator::Uefi(st_boot.unsafe_clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,11 +77,10 @@ fn efi_main(handle: Handle, st_boot: SystemTable<Boot>) -> Status {
|
||||||
|
|
||||||
// Tasks that do not require the UEFI boot services.
|
// Tasks that do not require the UEFI boot services.
|
||||||
|
|
||||||
// I do not currently have an adequate stdout for post-UEFI, but the UEFI one is now invalid.
|
|
||||||
unsafe {
|
unsafe {
|
||||||
LOGGER_BACKEND = LoggerBackend::None;
|
// TODO: An allocator that works out of UEFI mode.
|
||||||
ALLOCATOR = Allocator::None;
|
ALLOCATOR = Allocator::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
main(st_runtime, mmap);
|
main(st_runtime, mmap)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue