mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-21 08:26:30 +00:00
Refactor project structure
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
bd878dd1c9
commit
e3c227ae06
17
kernel/comps/framebuffer/Cargo.toml
Normal file
17
kernel/comps/framebuffer/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "aster-framebuffer"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
aster-frame = { path = "../../../framework/aster-frame" }
|
||||
component = { path = "../../libs/comp-sys/component" }
|
||||
log = "0.4"
|
||||
spin = "0.9.4"
|
||||
font8x8 = { version = "0.2.5", default-features = false, features = [
|
||||
"unicode",
|
||||
] }
|
||||
|
||||
[features]
|
207
kernel/comps/framebuffer/src/lib.rs
Normal file
207
kernel/comps/framebuffer/src/lib.rs
Normal file
@ -0,0 +1,207 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! The framebuffer of Asterinas.
|
||||
#![no_std]
|
||||
#![forbid(unsafe_code)]
|
||||
#![feature(strict_provenance)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::{
|
||||
fmt,
|
||||
ops::{Index, IndexMut},
|
||||
};
|
||||
|
||||
use aster_frame::{boot, config::PAGE_SIZE, io_mem::IoMem, sync::SpinLock, vm::VmIo};
|
||||
use component::{init_component, ComponentInitError};
|
||||
use font8x8::UnicodeFonts;
|
||||
use spin::Once;
|
||||
|
||||
#[init_component]
|
||||
fn framebuffer_init() -> Result<(), ComponentInitError> {
|
||||
init();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) static WRITER: Once<SpinLock<Writer>> = Once::new();
|
||||
|
||||
pub(crate) fn init() {
|
||||
let mut writer = {
|
||||
let framebuffer = boot::framebuffer_arg();
|
||||
let mut writer = None;
|
||||
let mut size = 0;
|
||||
for i in aster_frame::vm::FRAMEBUFFER_REGIONS.get().unwrap().iter() {
|
||||
size = i.len() as usize;
|
||||
}
|
||||
|
||||
let page_size = size / PAGE_SIZE;
|
||||
|
||||
let start_paddr = framebuffer.address;
|
||||
let io_mem = todo!("IoMem is private for components now, should fix it.");
|
||||
|
||||
let mut buffer: Vec<u8> = Vec::with_capacity(size);
|
||||
for _ in 0..size {
|
||||
buffer.push(0);
|
||||
}
|
||||
log::debug!("Found framebuffer:{:?}", framebuffer);
|
||||
|
||||
writer = Some(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(),
|
||||
});
|
||||
|
||||
writer.unwrap()
|
||||
};
|
||||
writer.clear();
|
||||
|
||||
WRITER.call_once(|| SpinLock::new(writer));
|
||||
}
|
||||
|
||||
pub(crate) struct Writer {
|
||||
io_mem: IoMem,
|
||||
/// FIXME: remove buffer. The meaning of buffer is to facilitate the various operations of framebuffer
|
||||
buffer: &'static mut [u8],
|
||||
|
||||
bytes_per_pixel: usize,
|
||||
width: usize,
|
||||
height: usize,
|
||||
|
||||
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);
|
||||
self.io_mem.write_bytes(0, self.buffer).unwrap();
|
||||
}
|
||||
|
||||
/// Everything moves up one letter in size
|
||||
fn shift_lines_up(&mut self) {
|
||||
let offset = self.bytes_per_pixel * 8;
|
||||
self.buffer.copy_within(offset.., 0);
|
||||
self.io_mem.write_bytes(0, self.buffer).unwrap();
|
||||
self.y_pos -= 8;
|
||||
}
|
||||
|
||||
fn width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
fn height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
|
||||
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) {
|
||||
let pixel_offset = y * self.width + x;
|
||||
let color = if on {
|
||||
[0x33, 0xff, 0x66, 0]
|
||||
} else {
|
||||
[0, 0, 0, 0]
|
||||
};
|
||||
let bytes_per_pixel = self.bytes_per_pixel;
|
||||
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]);
|
||||
self.io_mem
|
||||
.write_bytes(
|
||||
byte_offset,
|
||||
self.buffer
|
||||
.index(byte_offset..(byte_offset + bytes_per_pixel)),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// 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]
|
||||
macro_rules! print {
|
||||
($($arg:tt)*) => ($crate::_print(format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
/// Like the `println!` macro in the standard library, but prints to the VGA text buffer.
|
||||
#[macro_export]
|
||||
macro_rules! println {
|
||||
() => ($crate::print!("\n"));
|
||||
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
/// 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();
|
||||
}
|
Reference in New Issue
Block a user