diff --git a/Cargo.lock b/Cargo.lock index d5badba..56775cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,6 +41,12 @@ 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]] name = "bindgen" version = "0.70.1" @@ -100,6 +106,12 @@ dependencies = [ "spin", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cexpr" version = "0.6.0" @@ -138,6 +150,38 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" +[[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]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + [[package]] name = "funty" version = "2.0.0" @@ -168,6 +212,7 @@ dependencies = [ "bitfield", "bitvec", "buddy_system_allocator", + "embedded-graphics", "kernel-common", "log", "spin", @@ -231,6 +276,12 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "micromath" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -247,6 +298,15 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "prettyplease" version = "0.2.25" @@ -324,9 +384,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", diff --git a/deny.toml b/deny.toml index 97a1eb4..053efa0 100644 --- a/deny.toml +++ b/deny.toml @@ -1,2 +1,6 @@ [licenses] -allow = ["Apache-2.0", "BSD-3-Clause", "BSD-3-Clause-acpica", "ISC", "MIT", "MPL-2.0", "Unicode-DFS-2016", "Unlicense"] +allow = ["Apache-2.0", "BSD-3-Clause", "ISC", "MIT", "MPL-2.0", "Unlicense"] +exceptions = [ + {allow = ["BSD-3-Clause-acpica"], crate = "acpica-rs"}, + {allow = ["Unicode-DFS-2016"], crate = "unicode-ident"} +] diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index a2ea46f..2ab6488 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -10,6 +10,7 @@ acpica-rs = {path = "../lib/acpica-rs"} bitfield = "0.17.0" bitvec = {version = "1.0.1", default-features = false, features = ["alloc", "atomic"]} buddy_system_allocator = "0.11.0" +embedded-graphics = "0.8.1" kernel-common = {path = "../lib/kernel-common"} log = "0.4.22" spin = "0.9.8" diff --git a/kernel/src/cpu/paging.rs b/kernel/src/cpu/paging.rs index 7274732..b7f7747 100644 --- a/kernel/src/cpu/paging.rs +++ b/kernel/src/cpu/paging.rs @@ -113,6 +113,7 @@ pub fn find_free_virt_range(mut start: u64, end: u64, size: u64) -> u64 { } fn map(pml4: &mut PageTable, virt: u64, phys: u64, user: bool, write: bool, exec: bool, cache_disable: bool) { assert!(virt >= 0x1000, "First page shouldn't be mapped"); + assert!(!write || !exec); { let mut frames_vec = PHYSICAL_FRAMES.lock(); let frame = phys as usize / 0x1000; diff --git a/kernel/src/main.rs b/kernel/src/main.rs index bf6a885..a873a83 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -17,13 +17,13 @@ use buddy_system_allocator::LockedHeap; use cpu::{gdt::setup_gdt, idt::setup_idt, paging::setup_paging}; use kernel_common::{ instructions::{cli, hlt}, - loader_struct::{LoaderStruct, LoaderStructMemoryRegion, LOADER_STRUCT_MAGIC}, + loader_struct::{FramebufferInfo, LoaderStruct, LoaderStructMemoryRegion, LOADER_STRUCT_MAGIC}, log::init_logger, paging::{KERNEL_HEAP_INITIAL_SIZE, KERNEL_HEAP_START}, }; use log::{error, info}; use spin::Mutex; -use sys::{acpica_osl::AE_OK, early_acpi::EarlyACPIHandler, hpet::setup_hpet, lapic::setup_lapic_timer, madt::parse_madt, pic::disable_pic, task::setup_multitasking}; +use sys::{acpica_osl::AE_OK, display::setup_display, early_acpi::EarlyACPIHandler, hpet::setup_hpet, lapic::setup_lapic_timer, madt::parse_madt, pic::disable_pic, task::setup_multitasking}; mod cpu; mod misc; @@ -39,6 +39,12 @@ static LOADER_STRUCT: Mutex = Mutex::new(LoaderStruct { rsdp_address: 0, available_memory: [LoaderStructMemoryRegion { initial_page: 0, page_count: 0 }; 1024], vm: 0, + framebuffer: FramebufferInfo { + address: 0, + width: 0, + height: 0, + stride: 0, + }, }); global_asm!(include_str!("cpu/boot.s"), options(att_syntax)); @@ -58,6 +64,7 @@ extern "C" fn early_main(temp_loader_struct: *const LoaderStruct) -> ! { setup_gdt(); setup_idt(); setup_paging(&loader_struct, loader_struct.phys_kernel_start, loader_struct.phys_heap_start); + setup_display(loader_struct.framebuffer); disable_pic(); RSDP_ADDRESS.store(loader_struct.rsdp_address, Ordering::SeqCst); let early_acpi_tables; diff --git a/kernel/src/misc/draw_target.rs b/kernel/src/misc/draw_target.rs new file mode 100644 index 0000000..9def6b3 --- /dev/null +++ b/kernel/src/misc/draw_target.rs @@ -0,0 +1,45 @@ +use core::convert::Infallible; + +use embedded_graphics::{ + pixelcolor::Bgr888, + prelude::{DrawTarget, OriginDimensions, RgbColor, Size}, + Pixel, +}; + +pub struct FramebufferTarget { + pub framebuffer: *mut u8, + pub width: usize, + pub height: usize, + pub stride: usize, +} + +impl DrawTarget for FramebufferTarget { + type Color = Bgr888; + + type Error = Infallible; + + fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> + where + I: IntoIterator>, + { + for i in pixels { + if i.0.x < 0 || i.0.x >= self.width as i32 || i.0.y < 0 || i.0.y >= self.height as i32 { + continue; + } + let offset = (i.0.y * self.stride as i32 + i.0.x) as isize * 4; + unsafe { + self.framebuffer.offset(offset).write_volatile(i.1.b()); + self.framebuffer.offset(offset + 1).write_volatile(i.1.g()); + self.framebuffer.offset(offset + 2).write_volatile(i.1.r()); + } + } + Ok(()) + } +} +impl OriginDimensions for FramebufferTarget { + fn size(&self) -> Size { + Size::new(self.width as u32, self.height as u32) + } +} +unsafe impl Send for FramebufferTarget {} +unsafe impl Sync for FramebufferTarget {} diff --git a/kernel/src/misc/mod.rs b/kernel/src/misc/mod.rs index c17f2d1..c2bf383 100644 --- a/kernel/src/misc/mod.rs +++ b/kernel/src/misc/mod.rs @@ -1 +1,2 @@ +pub mod draw_target; pub mod wrapped_alloc; diff --git a/kernel/src/sys/display.rs b/kernel/src/sys/display.rs new file mode 100644 index 0000000..8b73c8e --- /dev/null +++ b/kernel/src/sys/display.rs @@ -0,0 +1,23 @@ +use core::ptr::null_mut; + +use kernel_common::loader_struct::FramebufferInfo; +use spin::Mutex; + +use crate::{cpu::paging::map_physical, misc::draw_target::FramebufferTarget}; + +static FRAMEBUFFER: Mutex = Mutex::new(FramebufferTarget { + framebuffer: null_mut(), + width: 0, + height: 0, + stride: 0, +}); + +pub fn setup_display(info: FramebufferInfo) { + let addr = unsafe { map_physical(info.address, info.height * info.stride * 4) }; + *FRAMEBUFFER.lock() = FramebufferTarget { + framebuffer: addr as *mut u8, + width: info.width as usize, + height: info.height as usize, + stride: info.stride as usize, + }; +} diff --git a/kernel/src/sys/mod.rs b/kernel/src/sys/mod.rs index 9440a68..470d34e 100644 --- a/kernel/src/sys/mod.rs +++ b/kernel/src/sys/mod.rs @@ -1,4 +1,5 @@ pub mod acpica_osl; +pub mod display; pub mod early_acpi; pub mod hpet; mod ioapic; diff --git a/lib/kernel-common/src/loader_struct.rs b/lib/kernel-common/src/loader_struct.rs index 258449f..bbdae13 100644 --- a/lib/kernel-common/src/loader_struct.rs +++ b/lib/kernel-common/src/loader_struct.rs @@ -6,6 +6,14 @@ pub struct LoaderStructMemoryRegion { } #[repr(C)] #[derive(Clone, Copy)] +pub struct FramebufferInfo { + pub address: u64, + pub width: u64, + pub height: u64, + pub stride: u64, +} +#[repr(C)] +#[derive(Clone, Copy)] pub struct LoaderStruct { pub magic: u64, pub phys_kernel_start: u64, @@ -13,6 +21,7 @@ pub struct LoaderStruct { pub rsdp_address: u64, pub available_memory: [LoaderStructMemoryRegion; 1024], pub vm: u8, + pub framebuffer: FramebufferInfo, } pub const LOADER_STRUCT_MAGIC: u64 = 0x123456789abcdef0; diff --git a/loader/src/display.rs b/loader/src/display.rs new file mode 100644 index 0000000..cd924c6 --- /dev/null +++ b/loader/src/display.rs @@ -0,0 +1,35 @@ +use kernel_common::loader_struct::FramebufferInfo; +use uefi::{ + boot::{get_handle_for_protocol, open_protocol_exclusive, ScopedProtocol}, + proto::console::gop::{GraphicsOutput, PixelFormat}, +}; + +pub fn setup_display() -> FramebufferInfo { + let gop_handle = get_handle_for_protocol::().unwrap(); + let mut gop: ScopedProtocol = open_protocol_exclusive(gop_handle).unwrap(); + let modes = gop.modes(); + let mut best_mode = None; + let mut best_width = 0; + let mut best_height = 0; + for i in modes { + let info = i.info(); + if info.pixel_format() != PixelFormat::Bgr { + continue; + } + if info.resolution().0 > 1280 || info.resolution().1 > 720 { + continue; + } + if info.resolution().0 > best_width || info.resolution().1 > best_height { + best_width = info.resolution().0; + best_height = info.resolution().1; + best_mode = Some(i); + } + } + gop.set_mode(&best_mode.unwrap()).unwrap(); + FramebufferInfo { + address: gop.frame_buffer().as_mut_ptr() as u64, + width: best_width as u64, + height: best_height as u64, + stride: best_mode.unwrap().info().stride() as u64, + } +} diff --git a/loader/src/loader_struct.rs b/loader/src/loader_struct.rs index d6796db..f6bddf2 100644 --- a/loader/src/loader_struct.rs +++ b/loader/src/loader_struct.rs @@ -1,10 +1,10 @@ -use kernel_common::loader_struct::{LoaderStruct, LoaderStructMemoryRegion, LOADER_STRUCT_MAGIC}; +use kernel_common::loader_struct::{FramebufferInfo, LoaderStruct, LoaderStructMemoryRegion, LOADER_STRUCT_MAGIC}; use uefi::{ boot::MemoryType, mem::memory_map::{MemoryMap, MemoryMapOwned}, }; -pub fn generate_loader_struct(memory_map: &MemoryMapOwned, phys_start: u64, heap_start: u64, rsdp_address: u64, vm: bool) -> LoaderStruct { +pub fn generate_loader_struct(memory_map: &MemoryMapOwned, phys_start: u64, heap_start: u64, rsdp_address: u64, vm: bool, framebuffer: FramebufferInfo) -> LoaderStruct { let mut loader_struct = LoaderStruct { magic: LOADER_STRUCT_MAGIC, phys_kernel_start: phys_start, @@ -12,6 +12,7 @@ pub fn generate_loader_struct(memory_map: &MemoryMapOwned, phys_start: u64, heap rsdp_address, available_memory: [LoaderStructMemoryRegion { initial_page: 0, page_count: 0 }; 1024], vm: vm as u8, + framebuffer, }; let mut next_entry = 0; for i in memory_map.entries() { diff --git a/loader/src/main.rs b/loader/src/main.rs index 1e90936..c94296d 100644 --- a/loader/src/main.rs +++ b/loader/src/main.rs @@ -10,6 +10,7 @@ use core::{ sync::atomic::{AtomicU64, Ordering}, }; +use display::setup_display; use elf::{load_kernel, map_kernel}; use kernel_common::{ instructions::{cli, hlt}, @@ -30,6 +31,7 @@ use uefi::{ Status, }; +mod display; mod elf; mod loader_struct; mod paging; @@ -63,10 +65,11 @@ fn main() -> Status { } }); assert_ne!(rsdp.load(Ordering::SeqCst), 0, "RSDP not found"); + let framebuffer_info = setup_display(); let memory_map = unsafe { exit_boot_services(MemoryType::LOADER_DATA) }; let pml4 = setup_paging(&memory_map, heap_start); map_kernel(KERNEL, pml4, kernel_start); - let loader_struct = generate_loader_struct(&memory_map, kernel_start, heap_start, rsdp.load(Ordering::SeqCst), features.has_hypervisor()); + let loader_struct = generate_loader_struct(&memory_map, kernel_start, heap_start, rsdp.load(Ordering::SeqCst), features.has_hypervisor(), framebuffer_info); info!("Jumping to kernel..."); unsafe { (mem::transmute::<_, extern "C" fn(&LoaderStruct) -> !>(kernel_entry))(&loader_struct);