| // SPDX-License-Identifier: GPL-2.0 |
| // Copyright 2022-2023 Google LLC |
| // Author: Ard Biesheuvel <ardb@google.com> |
| |
| use core::fmt::Write; |
| use core::mem::MaybeUninit; |
| use log::{Metadata, Record}; |
| use mmio::{Allow, Deny, VolBox}; |
| use once_cell::race::OnceRef; |
| use spinning_top::Spinlock; |
| |
| pub struct DumbSerialConsole { |
| out: Spinlock<VolBox<u32, Deny, Allow>>, |
| } |
| |
| struct DumbSerialConsoleWriter<'a> { |
| console: &'a DumbSerialConsole, |
| } |
| |
| pub fn init(base: usize) -> &'static DumbSerialConsole { |
| // Statically allocated so we can init the console before the heap |
| static mut _CON: MaybeUninit<DumbSerialConsole> = MaybeUninit::uninit(); |
| |
| OUT.get_or_init(|| unsafe { |
| let v = VolBox::<u32, Deny, Allow>::new(base as *mut u32); |
| _CON.write(DumbSerialConsole { |
| out: Spinlock::new(v), |
| }) |
| }) |
| } |
| |
| impl DumbSerialConsole { |
| fn puts(&self, s: &str) { |
| let mut out = self.out.lock(); |
| |
| for b in s.as_bytes().iter() { |
| if *b == b'\n' { |
| out.write(b'\r' as u32); |
| } |
| out.write(*b as u32) |
| } |
| } |
| |
| pub fn write_wchar_array(&self, s: *const u16) { |
| let mut out = self.out.lock(); |
| let mut offset: isize = 0; |
| loop { |
| match unsafe { *s.offset(offset) } { |
| 0 => break, |
| 0x80.. => (), |
| w => { |
| if w == b'\n' as u16 { |
| out.write(b'\r' as u32); |
| } |
| out.write(w as u32); |
| } |
| } |
| offset += 1; |
| } |
| } |
| } |
| |
| impl Write for DumbSerialConsoleWriter<'_> { |
| fn write_str(&mut self, s: &str) -> core::fmt::Result { |
| Ok(self.console.puts(s)) |
| } |
| } |
| |
| impl log::Log for DumbSerialConsole { |
| fn enabled(&self, metadata: &Metadata) -> bool { |
| metadata.level() <= log::max_level() |
| } |
| |
| fn log(&self, record: &Record) { |
| if self.enabled(record.metadata()) { |
| let mut out = DumbSerialConsoleWriter { console: &self }; |
| write!(&mut out, "efilite {} - {}", record.level(), record.args()).ok(); |
| } |
| } |
| |
| fn flush(&self) {} |
| } |
| |
| pub static OUT: OnceRef<DumbSerialConsole> = OnceRef::new(); |