#![no_std]
use x86_64::instructions::interrupts::without_interrupts;
#[allow(unused_imports)]
use {
bootloader_api::{
info::{
FrameBufferInfo,
PixelFormat,
}
},
conquer_once::{
spin::{
OnceCell,
}
},
core::{
fmt::{
self,
Write,
},
ptr,
},
noto_sans_mono_bitmap::{
get_raster,
get_raster_width,
RasterizedChar,
RasterHeight,
FontWeight,
},
spinning_top::{
Spinlock,
}
};
pub struct LockedPrintk(Spinlock<Printk>);
impl LockedPrintk {
#[allow(dead_code)]
pub fn new(buf: &'static mut [u8], i: FrameBufferInfo) -> Self {
LockedPrintk(Spinlock::new(Printk::new(buf, i)))
}
#[allow(dead_code)]
pub unsafe fn force_unlock(&self) {
self.0.force_unlock()
}
}
impl log::Log for LockedPrintk {
fn enabled(&self, _metadata: &log::Metadata) -> bool {
true
}
fn log(&self, record: &log::Record) {
let mut printk = self.0.lock();
writeln!(printk, "{}", record.args()).unwrap();
printk.move_down(2);
}
fn flush(&self) {
}
}
pub struct Printk {
buffer: &'static mut [u8],
info: FrameBufferInfo,
x: usize,
y: usize,
}
impl Printk {
#[allow(dead_code)]
pub fn new(buffer: &'static mut [u8], info: FrameBufferInfo) -> Self {
let mut printk = Self {
buffer,
info,
x: 0,
y: 0,
};
printk.clear();
printk
}
pub fn draw_grayscale(&mut self, x: usize, y: usize, intensity: u8) {
let poff = y * self.info.stride + x;
let u8_intensity = {
if intensity > 200 {
0xf
} else {
0
}
};
let color = match self.info.pixel_format {
PixelFormat::Rgb => {
[intensity, intensity, intensity/2, 0]
},
PixelFormat::Bgr => {
[intensity/2, intensity, intensity, 0]
},
PixelFormat::U8 => {
[u8_intensity, 0, 0, 0]
},
_ => panic!("Unknown pixel format")
};
let bpp = self.info.bytes_per_pixel;
let boff = poff*bpp;
self.buffer[boff..(boff+bpp)].copy_from_slice(&color[..bpp]);
let _ = unsafe { ptr::read_volatile(&self.buffer[boff]) };
}
pub fn render(&mut self, rendered: RasterizedChar) {
for (y, ln) in rendered.raster().iter().enumerate() {
for (x, col) in ln.iter().enumerate() {
self.draw_grayscale(self.x+x, self.y+y, *col)
}
}
self.x += rendered.width();
}
pub fn move_down(&mut self, distance: usize) {
self.y += distance;
}
pub fn home(&mut self) {
self.x = 0;
}
pub fn next_line(&mut self) {
self.move_down(16);
self.home();
}
pub fn page_up(&mut self) {
self.y = 0;
}
pub fn clear(&mut self) {
self.home();
self.page_up();
self.buffer.fill(0);
}
pub fn width(&self) -> usize {
self.info.width
}
pub fn height(&self) -> usize {
self.info.height
}
pub fn putch(&mut self, c: char) {
match c {
'\n' => self.next_line(),
'\r' => self.home(),
c => {
if self.x >= self.width() {
self.next_line();
}
const LETTER_WIDTH: usize = get_raster_width(FontWeight::Regular, RasterHeight::Size16);
if self.y >= (self.height() - LETTER_WIDTH) {
self.clear();
}
let mapped = get_raster(c, FontWeight::Regular, RasterHeight::Size16).unwrap();
self.render(mapped);
}
}
}
}
unsafe impl Send for Printk {}
unsafe impl Sync for Printk {}
impl fmt::Write for Printk {
fn write_str(&mut self, s: &str) -> fmt::Result {
for c in s.chars() {
without_interrupts(|| {
self.putch(c)
})
}
Ok(())
}
}