mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 14:27:49 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8b6293a72 | ||
|
|
15535d6217 | ||
|
|
521d4b2fd2 | ||
|
|
563c19731f | ||
|
|
79f47fda12 | ||
|
|
00fa82937a |
60
Cargo.lock
generated
60
Cargo.lock
generated
@@ -8,6 +8,18 @@ version = "1.0.77"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c9d19de80eff169429ac1e9f48fffb163916b448a44e8e046186232046d9e1f9"
|
checksum = "c9d19de80eff169429ac1e9f48fffb163916b448a44e8e046186232046d9e1f9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "az"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bincode"
|
name = "bincode"
|
||||||
version = "1.3.3"
|
version = "1.3.3"
|
||||||
@@ -108,6 +120,29 @@ version = "2.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-graphics"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0649998afacf6d575d126d83e68b78c0ab0e00ca2ac7e9b3db11b4cbe8274ef0"
|
||||||
|
dependencies = [
|
||||||
|
"az",
|
||||||
|
"byteorder",
|
||||||
|
"embedded-graphics-core",
|
||||||
|
"float-cmp",
|
||||||
|
"micromath",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-graphics-core"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba9ecd261f991856250d2207f6d8376946cd9f412a2165d3b75bc87a0bc7a044"
|
||||||
|
dependencies = [
|
||||||
|
"az",
|
||||||
|
"byteorder",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
@@ -135,6 +170,15 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "float-cmp"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "funty"
|
name = "funty"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@@ -175,6 +219,7 @@ name = "kernel"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bootloader_api",
|
"bootloader_api",
|
||||||
|
"embedded-graphics",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -214,6 +259,21 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "micromath"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ovmf-prebuilt"
|
name = "ovmf-prebuilt"
|
||||||
version = "0.1.0-alpha.1"
|
version = "0.1.0-alpha.1"
|
||||||
|
|||||||
@@ -10,3 +10,4 @@ bench = false
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bootloader_api = "0.11.0"
|
bootloader_api = "0.11.0"
|
||||||
|
embedded-graphics = "0.8.1"
|
||||||
|
|||||||
138
kernel/src/framebuffer.rs
Normal file
138
kernel/src/framebuffer.rs
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
use bootloader_api::info::{FrameBuffer, FrameBufferInfo, PixelFormat};
|
||||||
|
use embedded_graphics::{
|
||||||
|
draw_target::DrawTarget,
|
||||||
|
geometry::{self, Point},
|
||||||
|
pixelcolor::{Rgb888, RgbColor},
|
||||||
|
Pixel,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Display {
|
||||||
|
framebuffer: &'static mut [u8],
|
||||||
|
info: FrameBufferInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display {
|
||||||
|
pub fn new(framebuffer: &'static mut FrameBuffer) -> Display {
|
||||||
|
Self {
|
||||||
|
info: framebuffer.info(),
|
||||||
|
framebuffer: framebuffer.buffer_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_pixel(&mut self, coordinates: Point, color: Rgb888) {
|
||||||
|
// ignore any pixels that are out of bounds.
|
||||||
|
let position = match (coordinates.x.try_into(), coordinates.y.try_into()) {
|
||||||
|
(Ok(x), Ok(y)) if x < self.info.width && y < self.info.height => Position { x, y },
|
||||||
|
_ => return, // ignore out-of-bounds pixel
|
||||||
|
};
|
||||||
|
let color = Color {
|
||||||
|
red: color.r(),
|
||||||
|
green: color.g(),
|
||||||
|
blue: color.b(),
|
||||||
|
};
|
||||||
|
set_pixel_in(self.framebuffer, self.info, position, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn split_at_line(self, line_index: usize) -> (Self, Self) {
|
||||||
|
assert!(line_index < self.info.height);
|
||||||
|
|
||||||
|
let byte_offset = line_index * self.info.stride * self.info.bytes_per_pixel;
|
||||||
|
let (first_buffer, second_buffer) = self.framebuffer.split_at_mut(byte_offset);
|
||||||
|
|
||||||
|
let first = Self {
|
||||||
|
framebuffer: first_buffer,
|
||||||
|
info: FrameBufferInfo {
|
||||||
|
byte_len: byte_offset,
|
||||||
|
height: line_index,
|
||||||
|
..self.info
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let second = Self {
|
||||||
|
framebuffer: second_buffer,
|
||||||
|
info: FrameBufferInfo {
|
||||||
|
byte_len: self.info.byte_len - byte_offset,
|
||||||
|
height: self.info.height - line_index,
|
||||||
|
..self.info
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
(first, second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DrawTarget for Display {
|
||||||
|
type Color = Rgb888;
|
||||||
|
|
||||||
|
/// Drawing operations can never fail.
|
||||||
|
type Error = core::convert::Infallible;
|
||||||
|
|
||||||
|
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = Pixel<Self::Color>>,
|
||||||
|
{
|
||||||
|
for Pixel(coordinates, color) in pixels.into_iter() {
|
||||||
|
self.draw_pixel(coordinates, color);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl geometry::OriginDimensions for Display {
|
||||||
|
fn size(&self) -> geometry::Size {
|
||||||
|
geometry::Size::new(
|
||||||
|
self.info.width.try_into().unwrap(),
|
||||||
|
self.info.height.try_into().unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct Position {
|
||||||
|
pub x: usize,
|
||||||
|
pub y: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct Color {
|
||||||
|
pub red: u8,
|
||||||
|
pub green: u8,
|
||||||
|
pub blue: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_pixel_in(
|
||||||
|
framebuffer: &mut [u8],
|
||||||
|
info: FrameBufferInfo,
|
||||||
|
position: Position,
|
||||||
|
color: Color,
|
||||||
|
) {
|
||||||
|
// calculate offset to first byte of pixel
|
||||||
|
let byte_offset = {
|
||||||
|
// use stride to calculate pixel offset of target line
|
||||||
|
let line_offset = position.y * info.stride;
|
||||||
|
// add x position to get the absolute pixel offset in buffer
|
||||||
|
let pixel_offset = line_offset + position.x;
|
||||||
|
// convert to byte offset
|
||||||
|
pixel_offset * info.bytes_per_pixel
|
||||||
|
};
|
||||||
|
|
||||||
|
// set pixel based on color format
|
||||||
|
let pixel_bytes = &mut framebuffer[byte_offset..];
|
||||||
|
match info.pixel_format {
|
||||||
|
PixelFormat::Rgb => {
|
||||||
|
pixel_bytes[0] = color.red;
|
||||||
|
pixel_bytes[1] = color.green;
|
||||||
|
pixel_bytes[2] = color.blue;
|
||||||
|
}
|
||||||
|
PixelFormat::Bgr => {
|
||||||
|
pixel_bytes[0] = color.blue;
|
||||||
|
pixel_bytes[1] = color.green;
|
||||||
|
pixel_bytes[2] = color.red;
|
||||||
|
}
|
||||||
|
PixelFormat::U8 => {
|
||||||
|
// use a simple average-based grayscale transform
|
||||||
|
let gray = color.red / 3 + color.green / 3 + color.blue / 3;
|
||||||
|
pixel_bytes[0] = gray;
|
||||||
|
}
|
||||||
|
other => panic!("unknown pixel format {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,40 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use core::panic::PanicInfo;
|
use core::{convert::Infallible, panic::PanicInfo};
|
||||||
|
|
||||||
use bootloader_api::BootInfo;
|
use bootloader_api::BootInfo;
|
||||||
|
use embedded_graphics::{
|
||||||
|
draw_target::DrawTarget,
|
||||||
|
geometry::Point,
|
||||||
|
mono_font::{ascii::FONT_10X20, MonoTextStyle},
|
||||||
|
pixelcolor::{Rgb888, RgbColor},
|
||||||
|
primitives::{Circle, PrimitiveStyle, StyledDrawable},
|
||||||
|
text::Text,
|
||||||
|
Drawable,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod framebuffer;
|
||||||
|
|
||||||
bootloader_api::entry_point!(kernel_main);
|
bootloader_api::entry_point!(kernel_main);
|
||||||
|
|
||||||
fn kernel_main(boot_info: &'static mut BootInfo) -> ! {
|
fn kernel_main(boot_info: &'static mut BootInfo) -> ! {
|
||||||
if let Some(framebuffer) = boot_info.framebuffer.as_mut() {
|
if let Some(framebuffer) = boot_info.framebuffer.as_mut() {
|
||||||
for byte in framebuffer.buffer_mut() {
|
let height = framebuffer.info().height;
|
||||||
*byte = 0x90;
|
let display = framebuffer::Display::new(framebuffer);
|
||||||
}
|
let (mut upper, mut lower) = display.split_at_line(height / 2);
|
||||||
|
|
||||||
|
upper.clear(Rgb888::RED).unwrap_or_else(infallible);
|
||||||
|
lower.clear(Rgb888::BLUE).unwrap_or_else(infallible);
|
||||||
|
|
||||||
|
let style = PrimitiveStyle::with_fill(Rgb888::YELLOW);
|
||||||
|
Circle::new(Point::new(50, 50), 300)
|
||||||
|
.draw_styled(&style, &mut upper)
|
||||||
|
.unwrap_or_else(infallible);
|
||||||
|
|
||||||
|
let character_style = MonoTextStyle::new(&FONT_10X20, Rgb888::BLUE);
|
||||||
|
let text = Text::new("Hello, world!", Point::new(140, 210), character_style);
|
||||||
|
text.draw(&mut upper).unwrap_or_else(infallible);
|
||||||
}
|
}
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
@@ -21,3 +44,7 @@ fn kernel_main(boot_info: &'static mut BootInfo) -> ! {
|
|||||||
fn panic(_info: &PanicInfo) -> ! {
|
fn panic(_info: &PanicInfo) -> ! {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn infallible<T>(v: Infallible) -> T {
|
||||||
|
match v {}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user