From 4acc215cf4546a464d3e44529ac35ecc7f88fde2 Mon Sep 17 00:00:00 2001 From: James Martin Date: Thu, 16 Jul 2020 01:17:45 -0700 Subject: [PATCH] Hacked together support for PC Screen Fonts and the UEFI GOP FB. * Added a Rust allocator using UEFI. * Fixed the logger macros. * Using the cozette font. * Other stuff. Idc about listing it honestly. --- Cargo.lock | 34 ++++++++- Cargo.toml | 6 +- run.sh | 2 +- src/allocator.rs | 43 +++++++++++ src/graphics.rs | 85 ++++++++++++++++++++++ src/graphics/font.rs | 79 ++++++++++++++++++++ src/graphics/font/cozette-attribution.txt | 1 + src/graphics/font/cozette.psf | Bin 0 -> 26884 bytes src/graphics/font/psf.rs | 60 +++++++++++++++ src/logger.rs | 20 ++--- src/main.rs | 26 ++++++- 11 files changed, 339 insertions(+), 17 deletions(-) create mode 100644 src/allocator.rs create mode 100644 src/graphics.rs create mode 100644 src/graphics/font.rs create mode 100644 src/graphics/font/cozette-attribution.txt create mode 100644 src/graphics/font/cozette.psf create mode 100644 src/graphics/font/psf.rs diff --git a/Cargo.lock b/Cargo.lock index 40073d8..50a91b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,11 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + [[package]] name = "bit_field" version = "0.9.0" @@ -23,6 +29,7 @@ name = "bootproof" version = "0.1.0" dependencies = [ "compiler_builtins", + "num-integer", "uefi", "x86_64", ] @@ -40,13 +47,32 @@ source = "git+https://github.com/rust-lang/compiler-builtins#f3846bc05da87b8a71c [[package]] name = "log" -version = "0.4.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ "cfg-if", ] +[[package]] +name = "num-integer" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" +dependencies = [ + "autocfg", +] + [[package]] name = "proc-macro2" version = "1.0.18" @@ -87,9 +113,9 @@ dependencies = [ [[package]] name = "uefi" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab1f1403ecbad37d25120161acc3db12066febf3446efcc40b7631d30678505d" +checksum = "08fcd8a8b1c2488ea5adb67f3840584557a7089150c6f209148567397f767e12" dependencies = [ "bitflags", "log", diff --git a/Cargo.toml b/Cargo.toml index d7d68b6..95fbee9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,5 +7,9 @@ license = "GPL-3.0+" [dependencies] compiler_builtins = { git = "https://github.com/rust-lang/compiler-builtins" } -uefi = "0.4.6" +uefi = "0.4.7" x86_64 = "0.11.1" + +[dependencies.num-integer] +version = "0.1.36" +default-features = false diff --git a/run.sh b/run.sh index 16b631e..9e02123 100755 --- a/run.sh +++ b/run.sh @@ -2,4 +2,4 @@ profile=${1:-"debug"} mkdir -p drive/EFI/Boot cp "target/x86_64-unknown-uefi/$profile/bootproof.efi" drive/EFI/Boot/BootX64.efi -qemu-system-x86_64 -nodefaults -machine "q35,accel=kvm:tcg" -smp 8 -m 128M -drive "if=pflash,format=raw,file=/usr/share/OVMF/OVMF_CODE.fd,readonly=on" -drive "if=pflash,format=raw,file=/usr/share/OVMF/OVMF_VARS.fd,readonly=on" -drive "format=raw,file=fat:rw:drive" -serial stdio -display none +qemu-system-x86_64 -nodefaults -cpu host -smp 8 -m 512M -machine "q35,accel=kvm:tcg" -drive "if=pflash,format=raw,file=/usr/share/OVMF/OVMF_CODE.fd,readonly=on" -drive "if=pflash,format=raw,file=/usr/share/OVMF/OVMF_VARS.fd,readonly=on" -drive "format=raw,file=fat:rw:drive" -display gtk,gl=on -vga virtio -serial stdio diff --git a/src/allocator.rs b/src/allocator.rs new file mode 100644 index 0000000..0d9b196 --- /dev/null +++ b/src/allocator.rs @@ -0,0 +1,43 @@ +use alloc::alloc::GlobalAlloc; +use core::alloc::Layout; +use uefi::table::boot::{AllocateType, MemoryDescriptor, MemoryType}; + +pub enum Allocator { + None, + Uefi(uefi::prelude::SystemTable) +} + +unsafe impl GlobalAlloc for Allocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + match self { + Allocator::Uefi(st) => { + crate::log!("Allocate {:?}", layout); + st.boot_services().allocate_pages(AllocateType::AnyPages, MemoryType::LOADER_DATA, layout.size()) + .expect("Failed to allocate memory!") + .expect("Failed to allocate memory! 2") + as *mut u8 + }, + Allocator::None => panic!("No allocator available!") + } + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + match self { + Allocator::Uefi(st) => { + crate::log!("Free {:?}", layout); + st.boot_services().free_pages(ptr as u64, layout.size()); + }, + Allocator::None => { + panic!("No allocator available!"); + } + } + } +} + +#[global_allocator] +pub static mut ALLOCATOR: Allocator = Allocator::None; + +#[alloc_error_handler] +fn handle_error(layout: Layout) -> ! { + panic!("Failed to allocate {:?}", layout); +} diff --git a/src/graphics.rs b/src/graphics.rs new file mode 100644 index 0000000..10b165b --- /dev/null +++ b/src/graphics.rs @@ -0,0 +1,85 @@ +mod font; + +use crate::println; +use uefi::proto::console::gop::*; + +fn px_index(stride: usize, x: usize, y: usize) -> usize { + 4 * (y * stride + x) +} + +fn make_px(r: u8, g: u8, b: u8) -> [u8; 4] { + [b, g, r, 0] +} + +unsafe fn draw_char(fb: &mut FrameBuffer, stride: usize, cx: usize, cy: usize, c: char) { + let font = font::font(); + let glyph = font.lookup(c).expect("Character missing from font."); + let color = make_px(255, 255, 255); + for dx in 0..num_integer::div_ceil(glyph.width(), 8) * 8 { + for dy in 0..glyph.height() { + if glyph.get(dx, dy) { + let scale = 2; + for sdx in 0..scale { + for sdy in 0..scale { + let px = cx + scale * dx as usize + sdx; + let py = cy + scale * dy as usize + sdy; + fb.write_value(px_index(stride, px, py), color); + } + } + } + } + } +} + +unsafe fn draw_str(fb: &mut FrameBuffer, stride: usize, mut cx: usize, cy: usize, text: &str) { + let width = font::font().width as usize * 2; + for c in text.chars() { + draw_char(fb, stride, cx, cy, c); + cx += width; + } +} + +fn draw(fb: &mut FrameBuffer, stride: usize, width: usize, height: usize) { + for x in 0..width { + for y in 0..height { + let i = px_index(stride, x, y); + let r = (x * 256 / width) as u8; + let g = (y * 256 / height) as u8; + let b = 255 - ((r as u16 + g as u16) / 2) as u8; + let px = make_px(r, g, b); + unsafe { + fb.write_value(i, px); + } + } + } + + let c_width = width / 8; + let c_height = height / 16; + unsafe { + draw_str(fb, stride, 8, 8, "✔ Hello, world! ♡"); + } +} + +pub fn do_graphics(st: &uefi::prelude::SystemTable) { + let gop = st.boot_services().locate_protocol::() + .unwrap() + .expect("UEFI Graphics Output Protocol (GOP) is not present."); + let mut gop = unsafe { &mut *gop.get() }; + let mut mode = None; + for gop_mode in gop.modes() { + let gop_mode = gop_mode.expect("Warning while accessing GOP mode."); + if let PixelFormat::BGR = gop_mode.info().pixel_format() { + mode = Some(gop_mode); + } else { + println!("Ignoring non-BGR pixel format."); + } + } + let mode = mode.expect("No usable pixel formats found."); + let (width, height) = mode.info().resolution(); + let stride = mode.info().stride(); + println!("Using mode: {}x{} {:?}", width, height, mode.info().pixel_format()); + gop.set_mode(&mode).unwrap().expect("Failed to set UEFI Graphics Output mode."); + let mut fb = gop.frame_buffer(); + + draw(&mut fb, stride, width, height); +} diff --git a/src/graphics/font.rs b/src/graphics/font.rs new file mode 100644 index 0000000..220949b --- /dev/null +++ b/src/graphics/font.rs @@ -0,0 +1,79 @@ +use alloc::sync::Arc; +use alloc::vec::Vec; +use psf::*; + +mod psf; + +static mut FONT: Option> = None; + +pub fn font() -> Arc { + unsafe { + FONT.clone().unwrap_or_else(|| { + let font = Arc::new(parse_font()); + FONT = Some(font.clone()); + font + }) + } +} + +fn pad(slice: &[u8]) -> [u8; 4] { + if slice.len() == 1 { + [slice[0], 0, 0, 0] + } else if slice.len() == 2 { + [slice[0], slice[1], 0, 0] + } else if slice.len() == 3 { + [slice[0], slice[1], slice[2], 0] + } else if slice.len() == 4 { + [slice[0], slice[1], slice[2], slice[3]] + } else { + crate::panic!("Bad character length {}", slice.len()) + } +} + +fn parse_font() -> PSF { + use core::convert::TryInto; + let font = core::include_bytes!("font/cozette.psf"); + let length = u32::from_le_bytes(font[16..20].try_into().unwrap()); + let charsize = u32::from_le_bytes(font[20..24].try_into().unwrap()); + let height = u32::from_le_bytes(font[24..28].try_into().unwrap()); + let width = u32::from_le_bytes(font[28..32].try_into().unwrap()); + crate::log!("{} {} {}", width, height, charsize); + + let glyphs_size = (length * charsize) as usize; + let mut glyphs = Vec::with_capacity(glyphs_size); + glyphs.extend_from_slice(&font[32..glyphs_size + 32]); + + let mut unicode_map = Vec::new(); + let mut unicode_info = &font[glyphs_size + 32..]; + let mut glyph = 0; + let mut i = 0; + while i < unicode_info.len() { + let mut nc = unicode_info[i]; + + while nc != 0xFE && nc != 0xFF { + let ch_bytes = nc.leading_ones().max(1) as usize; + let st = core::str::from_utf8(&unicode_info[i..i + ch_bytes as usize]).expect("Invalid character"); + let ch = st.chars().next().unwrap(); + unicode_map.push(UnicodeMap { c: ch, i: glyph }); + i += ch_bytes; + nc = unicode_info[i]; + } + + // Ignore multi-codepoint spellings of characters (for now). + while nc != 0xFF { + i += 1; + nc = unicode_info[i]; + } + + i += 1; + glyph += 1; + } + PSF { + width: width, + height: height, + length: length, + charsize: charsize, + glyphs: glyphs, + unicode: unicode_map, + } +} diff --git a/src/graphics/font/cozette-attribution.txt b/src/graphics/font/cozette-attribution.txt new file mode 100644 index 0000000..d01b1f2 --- /dev/null +++ b/src/graphics/font/cozette-attribution.txt @@ -0,0 +1 @@ +Cozette is an MIT-licensed font by Slavfox. Its source is available here: https://github.com/slavfox/Cozette diff --git a/src/graphics/font/cozette.psf b/src/graphics/font/cozette.psf new file mode 100644 index 0000000000000000000000000000000000000000..8229a065e42c9c8519ce9efa8c42978af783b96a GIT binary patch literal 26884 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 DeTMjW literal 0 HcmV?d00001 diff --git a/src/graphics/font/psf.rs b/src/graphics/font/psf.rs new file mode 100644 index 0000000..4a4de17 --- /dev/null +++ b/src/graphics/font/psf.rs @@ -0,0 +1,60 @@ +use alloc::vec::Vec; + +pub struct UnicodeMap { + pub c: char, + pub i: usize, +} + +pub struct PSF { + pub width: u32, + pub height: u32, + pub length: u32, + pub charsize: u32, + pub glyphs: Vec, + pub unicode: Vec, +} + +pub struct PSFGlyph<'a> { + width: u32, + height: u32, + bitmap: &'a [u8], +} + +impl PSF { + fn index_of(&self, c: char) -> Option { + for entry in &self.unicode { + if entry.c == c { + return Some(entry.i); + } + } + None + } + + fn get_bitmap<'a>(&'a self, index: usize) -> &'a [u8] { + let byte_index = self.charsize as usize * index; + &self.glyphs[byte_index..byte_index + self.charsize as usize] + } + + pub fn lookup<'a>(&'a self, c: char) -> Option> { + self.index_of(c).map(|i| PSFGlyph { + width: self.width, + height: self.height, + bitmap: self.get_bitmap(i) + }) + } +} + +impl PSFGlyph<'_> { + pub fn width(&self) -> u32 { self.width } + + pub fn height(&self) -> u32 { self.height } + + pub fn get(&self, x: u32, y: u32) -> bool { + let line_size = num_integer::div_ceil(self.width, 8); + let char_size = line_size * self.height; + let (line_byte_index, bit_index) = num_integer::div_rem(x, 8); + let mask = 0b10000000 >> bit_index; + let byte = self.bitmap[(y * line_size + line_byte_index) as usize]; + byte & mask > 0 + } +} diff --git a/src/logger.rs b/src/logger.rs index bd4dfa9..18f5866 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -1,5 +1,3 @@ -use crate::misc::halt; - use core::fmt::Write; pub enum LoggerBackend { @@ -45,7 +43,7 @@ impl Write for Logger<'_> { }; output.write_str(s) }, - _ => { + LoggerBackend::None => { // There's pretty much no way to recover from a missing logger. // What are we supposed to do-- log the error? Ok(()) @@ -61,7 +59,7 @@ macro_rules! log { ($( $arg:expr ),* ) => { unsafe { use core::fmt::Write; - core::writeln!(LOGGER_BACKEND.stderr(), $( $arg ),*).unwrap(); + core::writeln!(crate::logger::LOGGER_BACKEND.stderr(), $( $arg ),*).unwrap(); } } } @@ -71,7 +69,7 @@ macro_rules! print { ($( $arg:expr ),* ) => { unsafe { use core::fmt::Write; - core::write!(LOGGER_BACKEND.stdout(), $( $arg ),*).unwrap(); + core::write!(crate::logger::LOGGER_BACKEND.stdout(), $( $arg ),*).unwrap(); } } } @@ -81,7 +79,7 @@ macro_rules! println { ($( $arg:expr ),* ) => { unsafe { use core::fmt::Write; - core::writeln!(LOGGER_BACKEND.stdout(), $( $arg ),*).unwrap(); + core::writeln!(crate::logger::LOGGER_BACKEND.stdout(), $( $arg ),*).unwrap(); } } } @@ -89,13 +87,15 @@ macro_rules! println { #[macro_export] macro_rules! panic { ($( $arg:expr ),* ) => { - log!($( $arg ),*); - halt(); + { + use crate::misc::halt; + crate::log!($( $arg ),*); + halt() + } } } #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { - log!("{}", info); - halt(); + panic!("{}", info); } diff --git a/src/main.rs b/src/main.rs index 088b25c..0074517 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,17 @@ #![no_std] #![no_main] #![feature(abi_efiapi)] +#![feature(alloc)] +#![feature(alloc_error_handler)] #![feature(asm)] +extern crate alloc; +mod allocator; +mod graphics; mod logger; mod misc; +use crate::allocator::{Allocator, ALLOCATOR}; use crate::logger::{LoggerBackend, LOGGER_BACKEND}; use crate::misc::halt; @@ -18,10 +24,26 @@ fn setup(st: &SystemTable, _handle: Handle) { st.stdout().reset(false).expect_success("Failed to reset UEFI stdout."); println!("Booting..."); + + for entry in st.config_table() { + use uefi::table::cfg::*; + if entry.guid == ACPI2_GUID { + print!("ACPI2"); + } else if entry.guid == SMBIOS_GUID { + print!("SMBIOS"); + } else if entry.guid == SMBIOS3_GUID { + print!("SMBIOS3"); + } else { + print!("{}", entry.guid); + } + println!(": 0x{:016X}", entry.address as u64); + } + + graphics::do_graphics(st); } fn main(_st: SystemTable, _mmap: uefi::table::boot::MemoryMapIter) -> ! { - halt(); + halt() } #[entry] @@ -30,6 +52,7 @@ fn efi_main(handle: Handle, st_boot: SystemTable) -> Status { unsafe { LOGGER_BACKEND = LoggerBackend::UefiStdio(st_boot.unsafe_clone()); + ALLOCATOR = Allocator::Uefi(st_boot.unsafe_clone()); } setup(&st_boot, handle); @@ -55,6 +78,7 @@ fn efi_main(handle: Handle, st_boot: SystemTable) -> Status { // I do not currently have an adequate stdout for post-UEFI, but the UEFI one is now invalid. unsafe { LOGGER_BACKEND = LoggerBackend::None; + ALLOCATOR = Allocator::None; } main(st_runtime, mmap);