Print userspace serial output to the screen
This commit is contained in:
parent
d4df5b53ff
commit
7ec14819c1
17
Cargo.lock
generated
17
Cargo.lock
generated
@ -109,6 +109,16 @@ version = "0.7.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b"
|
checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fontdue"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "efe23d02309319171d00d794c9ff48d4f903c0e481375b1b04b017470838af04"
|
||||||
|
dependencies = [
|
||||||
|
"hashbrown",
|
||||||
|
"ttf-parser",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.28.1"
|
version = "0.28.1"
|
||||||
@ -154,6 +164,7 @@ dependencies = [
|
|||||||
"crossbeam-queue",
|
"crossbeam-queue",
|
||||||
"derive-try-from-primitive",
|
"derive-try-from-primitive",
|
||||||
"elf",
|
"elf",
|
||||||
|
"fontdue",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
"humansize",
|
"humansize",
|
||||||
"intrusive-collections",
|
"intrusive-collections",
|
||||||
@ -365,6 +376,12 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ttf-parser"
|
||||||
|
version = "0.21.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uart_16550"
|
name = "uart_16550"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -28,3 +28,10 @@ saturating_cast = "0.1.0"
|
|||||||
humansize = "2.1.3"
|
humansize = "2.1.3"
|
||||||
cast = "0.3.0"
|
cast = "0.3.0"
|
||||||
az = "1.2.1"
|
az = "1.2.1"
|
||||||
|
fontdue = { version = "0.9.2", default-features = false, features = ["hashbrown"] }
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
strip = true
|
||||||
|
lto = true
|
||||||
|
# opt-level = "z"
|
||||||
|
codegen-units=1
|
||||||
|
BIN
FiraCode-Regular.ttf
Normal file
BIN
FiraCode-Regular.ttf
Normal file
Binary file not shown.
129
src/fbuffer.rs
Normal file
129
src/fbuffer.rs
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
use bootloader_api::info::FrameBufferInfo;
|
||||||
|
use fontdue::{layout::{CoordinateSystem, Layout, LayoutSettings, TextStyle}, Font, FontSettings};
|
||||||
|
use spin::{Lazy, Mutex};
|
||||||
|
use crate::{bootinfo::BOOTINFO, dbg};
|
||||||
|
use alloc::{string::String, vec::Vec, vec};
|
||||||
|
use core::slice;
|
||||||
|
|
||||||
|
|
||||||
|
struct Framebuffer<'a> {
|
||||||
|
info: FrameBufferInfo,
|
||||||
|
buffer: &'a mut [u8],
|
||||||
|
draw_buffer: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Framebuffer<'a> {
|
||||||
|
pub fn new(info: FrameBufferInfo, buffer: &'a mut [u8]) -> Self {
|
||||||
|
dbg!(&info);
|
||||||
|
let draw_buffer = vec![0; buffer.len()];
|
||||||
|
Self { info, buffer, draw_buffer }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_row_buf(&mut self, row: usize) -> &mut [u8] {
|
||||||
|
&mut self.draw_buffer[(self.info.stride * self.info.bytes_per_pixel * row)..]
|
||||||
|
[..(self.info.bytes_per_pixel * self.info.width)]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pixel_buf(&mut self, row: usize, col: usize) -> &mut [u8] {
|
||||||
|
let pbuf_start = col * self.info.bytes_per_pixel;
|
||||||
|
let pbuf_len = self.info.bytes_per_pixel;
|
||||||
|
&mut self.get_row_buf(row)[pbuf_start..][..pbuf_len]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_pixel(&mut self, row: usize, col: usize, value: u8) {
|
||||||
|
if row >= self.info.height || col >= self.info.width {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.get_pixel_buf(row, col).fill(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
for row in 0..self.info.height {
|
||||||
|
self.get_row_buf(row).fill(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_screen(&mut self) {
|
||||||
|
self.buffer.copy_from_slice(&self.draw_buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static FBUFFER: Lazy<Mutex<Framebuffer<'static>>> = Lazy::new(|| {
|
||||||
|
// Testing the framebuffer
|
||||||
|
let fbuf = BOOTINFO.framebuffer.as_ref().unwrap();
|
||||||
|
|
||||||
|
// No good way to get mutable buffer, so do this. No, its probably not safe. Too lazy to do it
|
||||||
|
// right.
|
||||||
|
let buf_start = fbuf.buffer().as_ptr();
|
||||||
|
let fbuf_buf = unsafe { slice::from_raw_parts_mut(buf_start as *mut u8, fbuf.buffer().len()) };
|
||||||
|
let fbuf_info = fbuf.info();
|
||||||
|
|
||||||
|
let mut fbuf = Framebuffer::new(fbuf_info, fbuf_buf);
|
||||||
|
fbuf.clear();
|
||||||
|
fbuf.update_screen();
|
||||||
|
Mutex::new(fbuf)
|
||||||
|
});
|
||||||
|
|
||||||
|
pub static OUT_STRING: Lazy<Mutex<String>> = Lazy::new(|| {
|
||||||
|
Mutex::new(String::new())
|
||||||
|
});
|
||||||
|
|
||||||
|
pub static FIRA_CODE: Lazy<Font> = Lazy::new(|| {
|
||||||
|
Font::from_bytes(include_bytes!("../FiraCode-Regular.ttf").as_slice(), FontSettings::default()).unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
pub fn write_str(s: &str) {
|
||||||
|
OUT_STRING.lock().push_str(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_char(c: char) {
|
||||||
|
OUT_STRING.lock().push(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_screen() {
|
||||||
|
let out_string = OUT_STRING.lock();
|
||||||
|
let mut fbuf = FBUFFER.lock();
|
||||||
|
fbuf.clear();
|
||||||
|
let mut layout = Layout::new(CoordinateSystem::PositiveYDown);
|
||||||
|
|
||||||
|
layout.reset(&LayoutSettings {
|
||||||
|
max_width: Some(fbuf.info.width as f32),
|
||||||
|
max_height: Some(fbuf.info.height as f32),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
layout.append(&[&*FIRA_CODE], &TextStyle::new(&out_string, 12.0, 0));
|
||||||
|
|
||||||
|
let height = layout.height();
|
||||||
|
let top_row = if height as usize > fbuf.info.height {
|
||||||
|
height as usize - fbuf.info.height
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
let glyphs = layout.glyphs();
|
||||||
|
|
||||||
|
let mut first_line_top_offset = None;
|
||||||
|
|
||||||
|
for line in layout.lines().unwrap() {
|
||||||
|
if ((line.baseline_y - line.max_ascent) as usize) < top_row {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if first_line_top_offset.is_none() {
|
||||||
|
first_line_top_offset = Some(((line.baseline_y - line.max_ascent) as usize) - top_row);
|
||||||
|
}
|
||||||
|
let first_line_top_offset = first_line_top_offset.unwrap();
|
||||||
|
for glyph_pos in &glyphs[line.glyph_start..=line.glyph_end] {
|
||||||
|
if glyph_pos.width == 0 || glyph_pos.height == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let (_, bitmap) = FIRA_CODE.rasterize_config(glyph_pos.key);
|
||||||
|
for (i, &pixel) in bitmap.iter().enumerate() {
|
||||||
|
let row = i / glyph_pos.width;
|
||||||
|
let col = i % glyph_pos.width;
|
||||||
|
fbuf.set_pixel(row + glyph_pos.y as usize - top_row - first_line_top_offset, col + glyph_pos.x as usize, pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fbuf.update_screen();
|
||||||
|
}
|
@ -6,7 +6,7 @@ use crate::{
|
|||||||
virtual_memory::{ASpaceMutex, AddressSpace, ACTIVE_SPACE, KERNEL_SPACE},
|
virtual_memory::{ASpaceMutex, AddressSpace, ACTIVE_SPACE, KERNEL_SPACE},
|
||||||
TASKING,
|
TASKING,
|
||||||
};
|
};
|
||||||
use alloc::{boxed::Box, vec::Vec};
|
use alloc::{boxed::Box, string::ToString, vec::Vec};
|
||||||
use az::WrappingCast;
|
use az::WrappingCast;
|
||||||
use cast::{u64, usize};
|
use cast::{u64, usize};
|
||||||
use core::{arch::asm, ffi::CStr, ptr, slice};
|
use core::{arch::asm, ffi::CStr, ptr, slice};
|
||||||
@ -251,7 +251,9 @@ extern "C" fn syscall_handler() {
|
|||||||
match regs.rax {
|
match regs.rax {
|
||||||
0 => {
|
0 => {
|
||||||
let rval = if let Some(chr) = char::from_u32(regs.rcx.wrapping_cast()) {
|
let rval = if let Some(chr) = char::from_u32(regs.rcx.wrapping_cast()) {
|
||||||
|
crate::fbuffer::write_char(chr);
|
||||||
if chr == '\n' {
|
if chr == '\n' {
|
||||||
|
crate::fbuffer::update_screen();
|
||||||
print!("\r\n");
|
print!("\r\n");
|
||||||
} else {
|
} else {
|
||||||
print!("{}", chr);
|
print!("{}", chr);
|
||||||
|
@ -84,6 +84,7 @@ mod serial;
|
|||||||
mod start;
|
mod start;
|
||||||
mod tasking;
|
mod tasking;
|
||||||
mod virtual_memory;
|
mod virtual_memory;
|
||||||
|
mod fbuffer;
|
||||||
|
|
||||||
use core::{ptr, slice};
|
use core::{ptr, slice};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user