diff --git a/Cargo.lock b/Cargo.lock index 8edf5a1..eadb0fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -134,6 +140,7 @@ checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" name = "efigife" version = "0.1.0" dependencies = [ + "aligned-vec", "embedded-graphics", "log", "tinygif", @@ -419,9 +426,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "spin" diff --git a/efi-bin/Cargo.toml b/efi-bin/Cargo.toml index 72c701a..de4f258 100644 --- a/efi-bin/Cargo.toml +++ b/efi-bin/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +aligned-vec = { version = "0.5.0", default-features = false } embedded-graphics.workspace = true log.workspace = true tinygif.workspace = true diff --git a/efi-bin/src/main.rs b/efi-bin/src/main.rs index c1189ae..cf114d5 100644 --- a/efi-bin/src/main.rs +++ b/efi-bin/src/main.rs @@ -3,26 +3,30 @@ extern crate alloc; +use aligned_vec::{AVec, ConstAlign}; +use alloc::vec::Vec; use core::time::Duration; -use uefi::prelude::*; +use uefi::{prelude::*, CStr16}; + use uefi::proto::console::gop::GraphicsOutput; use uefi::proto::loaded_image::LoadedImage; use uefi::proto::media::block::{BlockIO, Lba}; +use uefi::proto::media::file::{File, FileSystemVolumeLabel}; +use uefi::proto::media::fs::SimpleFileSystem; use uefi::proto::misc::Timestamp; use uefi::table::boot::{OpenProtocolAttributes, OpenProtocolParams}; use uefi_graphics2::embedded_graphics::{pixelcolor::Rgb888, prelude::*}; use uefi_graphics2::UefiDisplay; -const GIF_SIZE: usize = include_bytes!("bad-apple.gif").len(); +const GIF_SIZE: usize = ((include_bytes!("bad-apple.gif").len() + 511) / 512) * 512; +const VOLUME_LABEL: &CStr16 = cstr16!("EFIGIFEDEMO"); #[entry] fn main(_image_handle: Handle, mut boot_system_table: SystemTable) -> Status { uefi::helpers::init(&mut boot_system_table).expect("helper init"); - log::info!("hello!"); - // Disable the watchdog timer boot_system_table .boot_services() @@ -34,11 +38,34 @@ fn main(_image_handle: Handle, mut boot_system_table: SystemTable) -> Stat boot_services.stall(1_000_000); let img_handle = boot_services.image_handle(); - let loaded_image = boot_services - .open_protocol_exclusive::(img_handle) + let loaded_image_dev_path = boot_services + .open_protocol_exclusive::(img_handle) .expect("loaded image"); - let device_handle = loaded_image.device().expect("device handle"); + loaded_image_dev_path.get() + + let mut device_handle = loaded_image.device().expect("device handle"); + + /* + let handles = boot_services + .find_handles::() + .expect("sfs handle"); + for handle in handles { + let mut sfs = boot_services + .open_protocol_exclusive::(handle) + .expect("sfs proto"); + let mut root_dir = sfs.open_volume().expect("open volume"); + let vol_info = root_dir + .get_boxed_info::() + .expect("root dir label"); + if vol_info.volume_label() == VOLUME_LABEL { + assert_eq!(device_handle, handle); + } + } + */ + + // TODO boot_services.locate_device_path() + // FIXME we currently have the fat partition, need the parent disk let block_io = unsafe { boot_services.open_protocol::( @@ -52,11 +79,18 @@ fn main(_image_handle: Handle, mut boot_system_table: SystemTable) -> Stat } .expect("block io"); - let mut gif_buf = [0u8; GIF_SIZE]; + let mut gif_buf: AVec> = AVec::with_capacity(512, GIF_SIZE); + // for _ in 0..GIF_SIZE { + for _ in 0..512 { + gif_buf.push(0u8); + } + block_io .read_blocks(block_io.media().media_id(), Lba::from(0u64), &mut gif_buf) .expect("read blocks"); + panic!("{:x?}", &gif_buf[..32]); + let gif = tinygif::Gif::::from_slice(&gif_buf).expect("gif from slice"); // Get gop @@ -67,7 +101,6 @@ fn main(_image_handle: Handle, mut boot_system_table: SystemTable) -> Stat .open_protocol_exclusive::(gop_handle) .expect("graphics output open"); - use alloc::vec::Vec; // Create UefiDisplay for mode in gop.modes(&boot_services).collect::>() { let (w, h) = mode.info().resolution(); @@ -137,3 +170,166 @@ fn main(_image_handle: Handle, mut boot_system_table: SystemTable) -> Stat Status::SUCCESS } + +/* +// uefi-rs book example for reference: + +#![no_main] +#![no_std] + +extern crate alloc; + +use alloc::vec; +use alloc::vec::Vec; +use uefi::prelude::*; +use uefi::proto::console::gop::{BltOp, BltPixel, BltRegion, GraphicsOutput}; +use uefi::proto::loaded_image::LoadedImage; +use uefi::proto::media::block::{BlockIO, Lba}; +use uefi::table::boot::{OpenProtocolAttributes, OpenProtocolParams}; +use uefi::Result; + +const GIF_SIZE: usize = include_bytes!("bad-apple.gif").len(); + +#[derive(Clone, Copy)] +struct Point { + x: f32, + y: f32, +} + +impl Point { + fn new(x: f32, y: f32) -> Self { + Self { x, y } + } +} + +struct Buffer { + width: usize, + height: usize, + pixels: Vec, +} + +impl Buffer { + /// Create a new `Buffer`. + fn new(width: usize, height: usize) -> Self { + Buffer { + width, + height, + pixels: vec![BltPixel::new(0, 0, 0); width * height], + } + } + + /// Get a single pixel. + fn pixel(&mut self, x: usize, y: usize) -> Option<&mut BltPixel> { + self.pixels.get_mut(y * self.width + x) + } + + /// Blit the buffer to the framebuffer. + fn blit(&self, gop: &mut GraphicsOutput) -> Result { + gop.blt(BltOp::BufferToVideo { + buffer: &self.pixels, + src: BltRegion::Full, + dest: (0, 0), + dims: (self.width, self.height), + }) + } +} + +fn draw_sierpinski(bt: &BootServices) -> Result { + // Open graphics output protocol. + let gop_handle = bt + .get_handle_for_protocol::() + .expect("gop handle"); + let mut gop = bt + .open_protocol_exclusive::(gop_handle) + .expect("gop proto"); + + // Create a buffer to draw into. + let (width, height) = gop.current_mode_info().resolution(); + let mut buffer = Buffer::new(width, height); + + // Initialize the buffer with a simple gradient background. + for y in 0..height { + let r = ((y as f32) / ((height - 1) as f32)) * 255.0; + for x in 0..width { + let g = ((x as f32) / ((width - 1) as f32)) * 255.0; + let pixel = buffer.pixel(x, y).expect("gradient pixel"); + pixel.red = r as u8; + pixel.green = g as u8; + pixel.blue = 255; + } + } + + let size = Point::new(width as f32, height as f32); + + // Define the vertices of a big triangle. + let border = 20.0; + let triangle = [ + Point::new(size.x / 2.0, border), + Point::new(border, size.y - border), + Point::new(size.x - border, size.y - border), + ]; + + // `p` is the point to draw. Start at the center of the triangle. + let mut p = Point::new(size.x / 2.0, size.y / 2.0); + + // Loop forever, drawing the frame after each new point is changed. + loop { + // Choose one of the triangle's vertices at random. + let v = triangle[1]; // chosen by fair dice roll. + + // Move `p` halfway to the chosen vertex. + p.x = (p.x + v.x) * 0.5; + p.y = (p.y + v.y) * 0.5; + + // Set `p` to black. + let pixel = buffer + .pixel(p.x as usize, p.y as usize) + .expect("black pixel"); + pixel.red = 0; + pixel.green = 100; + pixel.blue = 0; + + // Draw the buffer to the screen. + buffer.blit(&mut gop).expect("blit"); + } +} + +#[entry] +fn main(_handle: Handle, mut system_table: SystemTable) -> Status { + uefi::helpers::init(&mut system_table).expect("table init"); + let boot_services = system_table.boot_services(); + + // Disable the watchdog timer + boot_services + .set_watchdog_timer(0, 0x10000, None) + .expect("disable watchdog timer"); + + let img_handle = boot_services.image_handle(); + let loaded_image = boot_services + .open_protocol_exclusive::(img_handle) + .expect("loaded image"); + + let device_handle = loaded_image.device().expect("device handle"); + + let block_io = unsafe { + boot_services.open_protocol::( + OpenProtocolParams { + handle: device_handle, + agent: img_handle, + controller: None, + }, + OpenProtocolAttributes::GetProtocol, + ) + } + .expect("block io"); + + let mut gif_buf = Vec::new(); + gif_buf.resize(GIF_SIZE, 0u8); + block_io + .read_blocks(block_io.media().media_id(), Lba::from(0u64), &mut gif_buf) + .expect("read blocks"); + + draw_sierpinski(boot_services).expect("sierpinski"); + Status::SUCCESS +} +*/ diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 8ae0535..aad4fff 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -11,6 +11,9 @@ use fatfs::{ }; use mbrs::{Mbr, PartInfo, PartType}; +const RELEASE: bool = false; +const VOLUME_LABEL: [u8; 11] = *b"EFIGIFEDEMO"; + #[derive(Copy, Clone)] enum Cpu { X86_64, @@ -33,9 +36,10 @@ fn main() { let cpu = match args .pop_front() .unwrap_or(std::env::consts::ARCH.to_string()) + .to_lowercase() .as_str() { - "aarch64" | "arm64" => Cpu::AArch64, + "aarch64" | "arm64" | "aa64" => Cpu::AArch64, "x86_64" | "x64" => Cpu::X86_64, x => unimplemented!("target cpu {:?}", x), }; @@ -101,28 +105,26 @@ impl FatWrite for MyStdIoWrapper { } fn do_build(cpu: Cpu, _args: VecDeque) { - let build = "debug"; - let build_success = Command::new(env!("CARGO")) + let mut cmd = Command::new(env!("CARGO")); + cmd.stdin(Stdio::inherit()) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) .arg("build") .arg("--bin") .arg("efigife") - //.arg("--release") .arg("--target") - .arg(format!("{}-unknown-uefi", cpu)) - .stdin(Stdio::inherit()) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()) - .output() - .unwrap() - .status - .success(); + .arg(format!("{}-unknown-uefi", cpu)); + if RELEASE { + cmd.arg("--release"); + } + let build_success = cmd.output().unwrap().status.success(); assert!(build_success); let efi_bin_path = format!( "{}/../target/{}-unknown-uefi/{}/efigife.efi", env!("CARGO_MANIFEST_DIR"), cpu, - build + if RELEASE { "release" } else { "debug" } ); let mut efi_bin_buf = Vec::new(); let mut efi_bin_file = File::open(efi_bin_path).unwrap(); @@ -135,7 +137,9 @@ fn do_build(cpu: Cpu, _args: VecDeque) { let mut fat_disk = MyStdIoWrapper(Cursor::new(&mut fat_disk_buf)); fatfs::format_volume( &mut fat_disk, - FormatVolumeOptions::new().fat_type(fatfs::FatType::Fat12), + FormatVolumeOptions::new() + .fat_type(fatfs::FatType::Fat12) + .volume_label(VOLUME_LABEL), ) .unwrap(); let fat_fs = FileSystem::new(fat_disk, FsOptions::new()).unwrap(); @@ -206,9 +210,13 @@ fn do_run(cpu: Cpu, args: VecDeque) { } else { cmd.arg("-M").arg("virt,pflash0=code,gic-version=3"); } - cmd.arg("-drive").arg( - "if=none,id=code,format=raw,file=/usr/share/qemu/edk2-aarch64-code.fd,readonly=on", - ); + cmd.arg("-drive") + .arg("if=none,id=code,format=raw,file=/usr/share/qemu/edk2-aarch64-code.fd,readonly=on") + .arg("-device") + .arg("qemu-xhci") + .arg("-usb") + .arg("-device") + .arg("usb-kbd"); } Cpu::X86_64 => { if kvm { @@ -222,9 +230,7 @@ fn do_run(cpu: Cpu, args: VecDeque) { cmd.arg("-global") .arg("ICH9-LPC.disable_s3=1") .arg("-drive") - .arg( - "if=pflash,format=raw,unit=0,file=/usr/share/edk2-ovmf/OVMF_CODE.fd,readonly=on", - ); + .arg("if=pflash,format=raw,unit=0,file=/usr/share/edk2-ovmf/OVMF_CODE.fd,readonly=on"); } } cmd.arg("-m")