asterinas/kernel/comps/framebuffer/src/lib.rs

211 lines
5.5 KiB
Rust
Raw Normal View History

2024-01-03 03:22:36 +00:00
// SPDX-License-Identifier: MPL-2.0
//! The framebuffer of Asterinas.
2023-03-25 09:24:34 +00:00
#![no_std]
#![deny(unsafe_code)]
2023-03-25 09:24:34 +00:00
#![feature(strict_provenance)]
extern crate alloc;
2024-02-27 16:44:55 +00:00
use alloc::{vec, vec::Vec};
2023-03-25 09:24:34 +00:00
use core::{
fmt,
ops::{Index, IndexMut},
};
use aster_frame::{
boot,
io_mem::IoMem,
mm::{VmIo, PAGE_SIZE},
sync::SpinLock,
};
use component::{init_component, ComponentInitError};
2022-08-16 02:41:25 +00:00
use font8x8::UnicodeFonts;
use spin::Once;
2023-03-25 09:24:34 +00:00
#[init_component]
fn framebuffer_init() -> Result<(), ComponentInitError> {
init();
Ok(())
}
2022-08-16 02:41:25 +00:00
pub(crate) static WRITER: Once<SpinLock<Writer>> = Once::new();
2023-03-06 06:19:23 +00:00
2024-02-27 16:44:55 +00:00
// ignore the warnings since we use the `todo!` macro.
#[allow(unused_variables)]
#[allow(unreachable_code)]
#[allow(clippy::diverging_sub_expression)]
2023-03-06 06:19:23 +00:00
pub(crate) fn init() {
let mut writer = {
2023-08-02 07:16:51 +00:00
let framebuffer = boot::framebuffer_arg();
2023-03-06 06:19:23 +00:00
let mut size = 0;
for i in aster_frame::mm::FRAMEBUFFER_REGIONS.get().unwrap().iter() {
2024-02-27 16:44:55 +00:00
size = i.len();
2023-03-06 06:19:23 +00:00
}
let page_size = size / PAGE_SIZE;
2023-08-02 07:16:51 +00:00
let start_paddr = framebuffer.address;
2023-11-04 08:41:30 +00:00
let io_mem = todo!("IoMem is private for components now, should fix it.");
2024-02-27 16:44:55 +00:00
let mut buffer: Vec<u8> = vec![0; size];
log::debug!("Found framebuffer:{:?}", framebuffer);
2024-02-27 16:44:55 +00:00
Writer {
io_mem,
x_pos: 0,
y_pos: 0,
bytes_per_pixel: (framebuffer.bpp / 8) as usize,
width: framebuffer.width as usize,
height: framebuffer.height as usize,
buffer: buffer.leak(),
2024-02-27 16:44:55 +00:00
}
2022-08-16 02:41:25 +00:00
};
writer.clear();
WRITER.call_once(|| SpinLock::new(writer));
2022-08-16 02:41:25 +00:00
}
2022-09-01 06:25:26 +00:00
pub(crate) struct Writer {
2023-07-23 10:40:41 +00:00
io_mem: IoMem,
2023-03-25 09:24:34 +00:00
/// FIXME: remove buffer. The meaning of buffer is to facilitate the various operations of framebuffer
buffer: &'static mut [u8],
2023-03-06 06:19:23 +00:00
bytes_per_pixel: usize,
width: usize,
height: usize,
2022-08-16 02:41:25 +00:00
x_pos: usize,
y_pos: usize,
}
impl Writer {
fn newline(&mut self) {
self.y_pos += 8;
self.carriage_return();
}
fn carriage_return(&mut self) {
self.x_pos = 0;
}
/// Erases all text on the screen
pub fn clear(&mut self) {
self.x_pos = 0;
self.y_pos = 0;
self.buffer.fill(0);
2023-07-23 10:40:41 +00:00
self.io_mem.write_bytes(0, self.buffer).unwrap();
2022-08-16 02:41:25 +00:00
}
2023-03-25 09:24:34 +00:00
/// Everything moves up one letter in size
2022-08-16 02:41:25 +00:00
fn shift_lines_up(&mut self) {
2023-03-06 06:19:23 +00:00
let offset = self.bytes_per_pixel * 8;
2022-08-16 02:41:25 +00:00
self.buffer.copy_within(offset.., 0);
2023-07-23 10:40:41 +00:00
self.io_mem.write_bytes(0, self.buffer).unwrap();
2022-08-16 02:41:25 +00:00
self.y_pos -= 8;
}
fn width(&self) -> usize {
2023-03-06 06:19:23 +00:00
self.width
2022-08-16 02:41:25 +00:00
}
fn height(&self) -> usize {
2023-03-06 06:19:23 +00:00
self.height
2022-08-16 02:41:25 +00:00
}
fn write_char(&mut self, c: char) {
match c {
'\n' => self.newline(),
'\r' => self.carriage_return(),
c => {
if self.x_pos >= self.width() {
self.newline();
}
while self.y_pos >= (self.height() - 8) {
self.shift_lines_up();
}
let rendered = font8x8::BASIC_FONTS
.get(c)
.expect("character not found in basic font");
self.write_rendered_char(rendered);
}
}
}
fn write_rendered_char(&mut self, rendered_char: [u8; 8]) {
for (y, byte) in rendered_char.iter().enumerate() {
for (x, bit) in (0..8).enumerate() {
let on = *byte & (1 << bit) != 0;
self.write_pixel(self.x_pos + x, self.y_pos + y, on);
}
}
self.x_pos += 8;
}
fn write_pixel(&mut self, x: usize, y: usize, on: bool) {
2023-03-25 09:24:34 +00:00
let pixel_offset = y * self.width + x;
2022-08-16 02:41:25 +00:00
let color = if on {
2023-03-06 06:19:23 +00:00
[0x33, 0xff, 0x66, 0]
2022-08-16 02:41:25 +00:00
} else {
[0, 0, 0, 0]
};
2023-03-06 06:19:23 +00:00
let bytes_per_pixel = self.bytes_per_pixel;
2022-08-16 02:41:25 +00:00
let byte_offset = pixel_offset * bytes_per_pixel;
self.buffer
.index_mut(byte_offset..(byte_offset + bytes_per_pixel))
.copy_from_slice(&color[..bytes_per_pixel]);
2023-07-23 10:40:41 +00:00
self.io_mem
2023-03-25 09:24:34 +00:00
.write_bytes(
byte_offset,
self.buffer
.index(byte_offset..(byte_offset + bytes_per_pixel)),
)
.unwrap();
2022-08-16 02:41:25 +00:00
}
/// Writes the given ASCII string to the buffer.
///
/// Wraps lines at `BUFFER_WIDTH`. Supports the `\n` newline character. Does **not**
/// support strings with non-ASCII characters, since they can't be printed in the VGA text
/// mode.
fn write_string(&mut self, s: &str) {
for char in s.chars() {
self.write_char(char);
}
}
}
impl fmt::Write for Writer {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.write_string(s);
Ok(())
}
}
/// Like the `print!` macro in the standard library, but prints to the VGA text buffer.
#[macro_export]
2023-03-25 09:24:34 +00:00
macro_rules! print {
($($arg:tt)*) => ($crate::_print(format_args!($($arg)*)));
2022-08-16 02:41:25 +00:00
}
/// Like the `println!` macro in the standard library, but prints to the VGA text buffer.
#[macro_export]
2023-03-25 09:24:34 +00:00
macro_rules! println {
() => ($crate::print!("\n"));
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
2022-08-16 02:41:25 +00:00
}
/// Prints the given formatted string to the VGA text buffer
/// through the global `WRITER` instance.
#[doc(hidden)]
pub fn _print(args: fmt::Arguments) {
use core::fmt::Write;
WRITER
.get()
.unwrap()
.lock_irq_disabled()
.write_fmt(args)
.unwrap();
2022-08-16 02:41:25 +00:00
}