Skip to content

Commit b0c5b4e

Browse files
Separate the main logger functionality from the framebuffer section of the logger
1 parent fffa7ce commit b0c5b4e

File tree

3 files changed

+166
-160
lines changed

3 files changed

+166
-160
lines changed

common/src/framebuffer.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
use bootloader_api::info::{FrameBufferInfo, PixelFormat};
2+
use core::{
3+
fmt::self,
4+
ptr,
5+
};
6+
use font_constants::BACKUP_CHAR;
7+
use noto_sans_mono_bitmap::{
8+
get_raster, get_raster_width, FontWeight, RasterHeight, RasterizedChar,
9+
};
10+
11+
/// Additional vertical space between lines
12+
const LINE_SPACING: usize = 2;
13+
/// Additional horizontal space between characters.
14+
const LETTER_SPACING: usize = 0;
15+
16+
/// Padding from the border. Prevent that font is too close to border.
17+
const BORDER_PADDING: usize = 1;
18+
19+
/// Constants for the usage of the [`noto_sans_mono_bitmap`] crate.
20+
mod font_constants {
21+
use super::*;
22+
23+
/// Height of each char raster. The font size is ~0.84% of this. Thus, this is the line height that
24+
/// enables multiple characters to be side-by-side and appear optically in one line in a natural way.
25+
pub const CHAR_RASTER_HEIGHT: RasterHeight = RasterHeight::Size16;
26+
27+
/// The width of each single symbol of the mono space font.
28+
pub const CHAR_RASTER_WIDTH: usize = get_raster_width(FontWeight::Regular, CHAR_RASTER_HEIGHT);
29+
30+
/// Backup character if a desired symbol is not available by the font.
31+
/// The '�' character requires the feature "unicode-specials".
32+
pub const BACKUP_CHAR: char = '�';
33+
34+
pub const FONT_WEIGHT: FontWeight = FontWeight::Regular;
35+
}
36+
37+
/// Returns the raster of the given char or the raster of [`font_constants::BACKUP_CHAR`].
38+
fn get_char_raster(c: char) -> RasterizedChar {
39+
fn get(c: char) -> Option<RasterizedChar> {
40+
get_raster(
41+
c,
42+
font_constants::FONT_WEIGHT,
43+
font_constants::CHAR_RASTER_HEIGHT,
44+
)
45+
}
46+
get(c).unwrap_or_else(|| get(BACKUP_CHAR).expect("Should get raster of backup char."))
47+
}
48+
49+
/// Allows logging text to a pixel-based framebuffer.
50+
pub struct FrameBufferWriter {
51+
framebuffer: &'static mut [u8],
52+
info: FrameBufferInfo,
53+
x_pos: usize,
54+
y_pos: usize,
55+
}
56+
57+
impl FrameBufferWriter {
58+
/// Creates a new logger that uses the given framebuffer.
59+
pub fn new(framebuffer: &'static mut [u8], info: FrameBufferInfo) -> Self {
60+
let mut logger = Self {
61+
framebuffer,
62+
info,
63+
x_pos: 0,
64+
y_pos: 0,
65+
};
66+
logger.clear();
67+
logger
68+
}
69+
70+
fn newline(&mut self) {
71+
self.y_pos += font_constants::CHAR_RASTER_HEIGHT.val() + LINE_SPACING;
72+
self.carriage_return()
73+
}
74+
75+
fn carriage_return(&mut self) {
76+
self.x_pos = BORDER_PADDING;
77+
}
78+
79+
/// Erases all text on the screen. Resets `self.x_pos` and `self.y_pos`.
80+
pub fn clear(&mut self) {
81+
self.x_pos = BORDER_PADDING;
82+
self.y_pos = BORDER_PADDING;
83+
self.framebuffer.fill(0);
84+
}
85+
86+
fn width(&self) -> usize {
87+
self.info.width
88+
}
89+
90+
fn height(&self) -> usize {
91+
self.info.height
92+
}
93+
94+
/// Writes a single char to the framebuffer. Takes care of special control characters, such as
95+
/// newlines and carriage returns.
96+
fn write_char(&mut self, c: char) {
97+
match c {
98+
'\n' => self.newline(),
99+
'\r' => self.carriage_return(),
100+
c => {
101+
let new_xpos = self.x_pos + font_constants::CHAR_RASTER_WIDTH;
102+
if new_xpos >= self.width() {
103+
self.newline();
104+
}
105+
let new_ypos =
106+
self.y_pos + font_constants::CHAR_RASTER_HEIGHT.val() + BORDER_PADDING;
107+
if new_ypos >= self.height() {
108+
self.clear();
109+
}
110+
self.write_rendered_char(get_char_raster(c));
111+
}
112+
}
113+
}
114+
115+
/// Prints a rendered char into the framebuffer.
116+
/// Updates `self.x_pos`.
117+
fn write_rendered_char(&mut self, rendered_char: RasterizedChar) {
118+
for (y, row) in rendered_char.raster().iter().enumerate() {
119+
for (x, byte) in row.iter().enumerate() {
120+
self.write_pixel(self.x_pos + x, self.y_pos + y, *byte);
121+
}
122+
}
123+
self.x_pos += rendered_char.width() + LETTER_SPACING;
124+
}
125+
126+
fn write_pixel(&mut self, x: usize, y: usize, intensity: u8) {
127+
let pixel_offset = y * self.info.stride + x;
128+
let color = match self.info.pixel_format {
129+
PixelFormat::Rgb => [intensity, intensity, intensity / 2, 0],
130+
PixelFormat::Bgr => [intensity / 2, intensity, intensity, 0],
131+
PixelFormat::U8 => [if intensity > 200 { 0xf } else { 0 }, 0, 0, 0],
132+
other => {
133+
// set a supported (but invalid) pixel format before panicking to avoid a double
134+
// panic; it might not be readable though
135+
self.info.pixel_format = PixelFormat::Rgb;
136+
panic!("pixel format {:?} not supported in logger", other)
137+
}
138+
};
139+
let bytes_per_pixel = self.info.bytes_per_pixel;
140+
let byte_offset = pixel_offset * bytes_per_pixel;
141+
self.framebuffer[byte_offset..(byte_offset + bytes_per_pixel)]
142+
.copy_from_slice(&color[..bytes_per_pixel]);
143+
let _ = unsafe { ptr::read_volatile(&self.framebuffer[byte_offset]) };
144+
}
145+
}
146+
147+
unsafe impl Send for FrameBufferWriter {}
148+
unsafe impl Sync for FrameBufferWriter {}
149+
150+
impl fmt::Write for FrameBufferWriter {
151+
fn write_str(&mut self, s: &str) -> fmt::Result {
152+
for c in s.chars() {
153+
self.write_char(c);
154+
}
155+
Ok(())
156+
}
157+
}

common/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ pub mod legacy_memory_region;
2929
pub mod level_4_entries;
3030
/// Implements a loader for the kernel ELF binary.
3131
pub mod load_kernel;
32-
/// Provides a logger type that logs output as text to pixel-based framebuffers.
32+
/// Provides a type that logs output as text to pixel-based framebuffers.
33+
pub mod framebuffer;
34+
/// Provides a logger that logs output as text in various formats.
3335
pub mod logger;
3436

3537
const PAGE_SIZE: u64 = 4096;

common/src/logger.rs

Lines changed: 6 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,19 @@
1-
use bootloader_api::info::{FrameBufferInfo, PixelFormat};
1+
use crate::framebuffer::FrameBufferWriter;
2+
use bootloader_api::info::FrameBufferInfo;
3+
use core::fmt::Write;
24
use conquer_once::spin::OnceCell;
3-
use core::{
4-
fmt::{self, Write},
5-
ptr,
6-
};
7-
use font_constants::BACKUP_CHAR;
8-
use noto_sans_mono_bitmap::{
9-
get_raster, get_raster_width, FontWeight, RasterHeight, RasterizedChar,
10-
};
115
use spinning_top::Spinlock;
126

137
/// The global logger instance used for the `log` crate.
148
pub static LOGGER: OnceCell<LockedLogger> = OnceCell::uninit();
159

16-
/// A [`Logger`] instance protected by a spinlock.
17-
pub struct LockedLogger(Spinlock<Logger>);
18-
19-
/// Additional vertical space between lines
20-
const LINE_SPACING: usize = 2;
21-
/// Additional horizontal space between characters.
22-
const LETTER_SPACING: usize = 0;
23-
24-
/// Padding from the border. Prevent that font is too close to border.
25-
const BORDER_PADDING: usize = 1;
26-
27-
/// Constants for the usage of the [`noto_sans_mono_bitmap`] crate.
28-
mod font_constants {
29-
use super::*;
30-
31-
/// Height of each char raster. The font size is ~0.84% of this. Thus, this is the line height that
32-
/// enables multiple characters to be side-by-side and appear optically in one line in a natural way.
33-
pub const CHAR_RASTER_HEIGHT: RasterHeight = RasterHeight::Size16;
34-
35-
/// The width of each single symbol of the mono space font.
36-
pub const CHAR_RASTER_WIDTH: usize = get_raster_width(FontWeight::Regular, CHAR_RASTER_HEIGHT);
37-
38-
/// Backup character if a desired symbol is not available by the font.
39-
/// The '�' character requires the feature "unicode-specials".
40-
pub const BACKUP_CHAR: char = '�';
41-
42-
pub const FONT_WEIGHT: FontWeight = FontWeight::Regular;
43-
}
44-
45-
/// Returns the raster of the given char or the raster of [`font_constants::BACKUP_CHAR`].
46-
fn get_char_raster(c: char) -> RasterizedChar {
47-
fn get(c: char) -> Option<RasterizedChar> {
48-
get_raster(
49-
c,
50-
font_constants::FONT_WEIGHT,
51-
font_constants::CHAR_RASTER_HEIGHT,
52-
)
53-
}
54-
get(c).unwrap_or_else(|| get(BACKUP_CHAR).expect("Should get raster of backup char."))
55-
}
10+
/// A [`FrameBufferWriter`] instance protected by a spinlock.
11+
pub struct LockedLogger(Spinlock<FrameBufferWriter>);
5612

5713
impl LockedLogger {
5814
/// Create a new instance that logs to the given framebuffer.
5915
pub fn new(framebuffer: &'static mut [u8], info: FrameBufferInfo) -> Self {
60-
LockedLogger(Spinlock::new(Logger::new(framebuffer, info)))
16+
LockedLogger(Spinlock::new(FrameBufferWriter::new(framebuffer, info)))
6117
}
6218

6319
/// Force-unlocks the logger to prevent a deadlock.
@@ -82,112 +38,3 @@ impl log::Log for LockedLogger {
8238
fn flush(&self) {}
8339
}
8440

85-
/// Allows logging text to a pixel-based framebuffer.
86-
pub struct Logger {
87-
framebuffer: &'static mut [u8],
88-
info: FrameBufferInfo,
89-
x_pos: usize,
90-
y_pos: usize,
91-
}
92-
93-
impl Logger {
94-
/// Creates a new logger that uses the given framebuffer.
95-
pub fn new(framebuffer: &'static mut [u8], info: FrameBufferInfo) -> Self {
96-
let mut logger = Self {
97-
framebuffer,
98-
info,
99-
x_pos: 0,
100-
y_pos: 0,
101-
};
102-
logger.clear();
103-
logger
104-
}
105-
106-
fn newline(&mut self) {
107-
self.y_pos += font_constants::CHAR_RASTER_HEIGHT.val() + LINE_SPACING;
108-
self.carriage_return()
109-
}
110-
111-
fn carriage_return(&mut self) {
112-
self.x_pos = BORDER_PADDING;
113-
}
114-
115-
/// Erases all text on the screen. Resets `self.x_pos` and `self.y_pos`.
116-
pub fn clear(&mut self) {
117-
self.x_pos = BORDER_PADDING;
118-
self.y_pos = BORDER_PADDING;
119-
self.framebuffer.fill(0);
120-
}
121-
122-
fn width(&self) -> usize {
123-
self.info.width
124-
}
125-
126-
fn height(&self) -> usize {
127-
self.info.height
128-
}
129-
130-
/// Writes a single char to the framebuffer. Takes care of special control characters, such as
131-
/// newlines and carriage returns.
132-
fn write_char(&mut self, c: char) {
133-
match c {
134-
'\n' => self.newline(),
135-
'\r' => self.carriage_return(),
136-
c => {
137-
let new_xpos = self.x_pos + font_constants::CHAR_RASTER_WIDTH;
138-
if new_xpos >= self.width() {
139-
self.newline();
140-
}
141-
let new_ypos =
142-
self.y_pos + font_constants::CHAR_RASTER_HEIGHT.val() + BORDER_PADDING;
143-
if new_ypos >= self.height() {
144-
self.clear();
145-
}
146-
self.write_rendered_char(get_char_raster(c));
147-
}
148-
}
149-
}
150-
151-
/// Prints a rendered char into the framebuffer.
152-
/// Updates `self.x_pos`.
153-
fn write_rendered_char(&mut self, rendered_char: RasterizedChar) {
154-
for (y, row) in rendered_char.raster().iter().enumerate() {
155-
for (x, byte) in row.iter().enumerate() {
156-
self.write_pixel(self.x_pos + x, self.y_pos + y, *byte);
157-
}
158-
}
159-
self.x_pos += rendered_char.width() + LETTER_SPACING;
160-
}
161-
162-
fn write_pixel(&mut self, x: usize, y: usize, intensity: u8) {
163-
let pixel_offset = y * self.info.stride + x;
164-
let color = match self.info.pixel_format {
165-
PixelFormat::Rgb => [intensity, intensity, intensity / 2, 0],
166-
PixelFormat::Bgr => [intensity / 2, intensity, intensity, 0],
167-
PixelFormat::U8 => [if intensity > 200 { 0xf } else { 0 }, 0, 0, 0],
168-
other => {
169-
// set a supported (but invalid) pixel format before panicking to avoid a double
170-
// panic; it might not be readable though
171-
self.info.pixel_format = PixelFormat::Rgb;
172-
panic!("pixel format {:?} not supported in logger", other)
173-
}
174-
};
175-
let bytes_per_pixel = self.info.bytes_per_pixel;
176-
let byte_offset = pixel_offset * bytes_per_pixel;
177-
self.framebuffer[byte_offset..(byte_offset + bytes_per_pixel)]
178-
.copy_from_slice(&color[..bytes_per_pixel]);
179-
let _ = unsafe { ptr::read_volatile(&self.framebuffer[byte_offset]) };
180-
}
181-
}
182-
183-
unsafe impl Send for Logger {}
184-
unsafe impl Sync for Logger {}
185-
186-
impl fmt::Write for Logger {
187-
fn write_str(&mut self, s: &str) -> fmt::Result {
188-
for c in s.chars() {
189-
self.write_char(c);
190-
}
191-
Ok(())
192-
}
193-
}

0 commit comments

Comments
 (0)