commit edf6174c4a931b956b7b5372bc6051b2c8ac10db Author: Elaina Claus Date: Tue Mar 14 09:41:14 2023 -0400 first commit diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100755 index 0000000..3376d76 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,6 @@ +[unstable] +build-std = ["core", "compiler_builtins", "alloc"] +build-std-features = ["compiler-builtins-mem"] + +[build] +target = "x86_64-unknown-uefi" \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/BOOT/EFI/BOOT/BOOTX64.EFI b/BOOT/EFI/BOOT/BOOTX64.EFI new file mode 100755 index 0000000..7b804ac Binary files /dev/null and b/BOOT/EFI/BOOT/BOOTX64.EFI differ diff --git a/Cargo.lock b/Cargo.lock new file mode 100755 index 0000000..02113f1 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,191 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "goblin" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6b4de4a8eb6c46a8c77e1d3be942cb9a8bf073c22374578e5ba4b08ed0ff68" +dependencies = [ + "log", + "plain", + "scroll", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "proc-macro2" +version = "1.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcada80daa06c42ed5f48c9a043865edea5dc44cbf9ac009fda3b89526e28607" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rlibc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe" + +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "stubby" +version = "0.1.0" +dependencies = [ + "arrayvec", + "goblin", + "log", + "rlibc", + "uefi", + "uefi-macros", + "uefi-services", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "ucs2" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad643914094137d475641b6bab89462505316ec2ce70907ad20102d28a79ab8" +dependencies = [ + "bit_field", +] + +[[package]] +name = "uefi" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5607fef843201070ed442fa257c7a944fae963fac7d4620612123192eb4d844" +dependencies = [ + "bitflags", + "log", + "ptr_meta", + "ucs2", + "uefi-macros", +] + +[[package]] +name = "uefi-macros" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8099684193f2d99f7f130951f4054a1591ff7da370e2b33d7a71f0434920499" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "uefi-services" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75daa44f951cc1d9dc68d98cabc06ddbccc221d7bd21222271be5d7ac526a9d" +dependencies = [ + "cfg-if", + "log", + "uefi", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0766f03 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "stubby" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rlibc = "1.0.0" + +uefi = { version = "0.19.1", features = ['logger', 'alloc', ] } +uefi-services = "0.16.0" +uefi-macros = "0.10.0" +log = { version = "0.4.17", default-features = false } +goblin = { version = "0.6.1", default-features = false, features = ['elf32', 'elf64', 'alloc', 'endian_fd'] } +arrayvec = { version = "0.7.2", default-features = false } diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..d463ed4 --- /dev/null +++ b/Makefile @@ -0,0 +1,46 @@ +ARCH ?= x86_64 +TARGET ?= $(ARCH)-unknown-uefi +PROJECT ?= stubby +OVMF_FW := OVMF_CODE.fd +OVMF_VARS = OVMF_VARS.fd +BOOT_DIR := BOOT + +qemu_args := -nodefaults -vga std -monitor vc:1440x900 -serial stdio -machine q35,accel=kvm:hvf -no-shutdown -no-reboot -m 256M +qemu_efi := -drive if=pflash,format=raw,readonly=on,file=$(OVMF_FW) +qemu_efi_vars := -drive if=pflash,format=raw,file=$(OVMF_VARS) +qemu_drive := -drive format=raw,file=fat:rw:$(BOOT_DIR) + +target_debug := target/$(TARGET)/debug/$(PROJECT).efi +target_release := target/$(TARGET)/release/$(PROJECT).efi + +.PHONY: all release debug clean run-debug run + +all: $(target_debug) $(target_release) +debug: $(target_debug) +release: $(target_release) + +clean: + rm -rv $(BOOT_DIR) + @RUST_TARGET_PATH=$(shell pwd) cargo clean --target $(TARGET) + +run-debug: $(target_debug) + @RUST_TARGET_PATH=$(shell pwd) cargo +nightly build -Z build-std --target $(TARGET) --verbose + mkdir -p $(BOOT_DIR)/EFI/BOOT/ + cp -v $(target_debug) $(BOOT_DIR)/EFI/BOOT/BOOTX64.EFI + @qemu-system-$(ARCH) $(qemu_args) $(qemu_efi) $(qemu_efi_vars) $(qemu_drive) + +run: $(target_release) + @RUST_TARGET_PATH=$(shell pwd) cargo +nightly build -Z build-std --target $(TARGET) --release + mkdir -p $(BOOT_DIR)/EFI/BOOT/ + cp -v $(target_release) $(BOOT_DIR)/EFI/BOOT/BOOTX64.EFI + @qemu-system-$(ARCH) $(qemu_args) $(qemu_efi) $(qemu_efi_vars) $(qemu_drive) + +$(target_debug): + @RUST_TARGET_PATH=$(shell pwd) cargo +nightly build -Z build-std --target $(TARGET) --verbose + mkdir -p $(BOOT_DIR)/EFI/BOOT/ + cp -v $(target_debug) $(BOOT_DIR)/EFI/BOOT/BOOTX64.EFI + +$(target_release): + @RUST_TARGET_PATH=$(shell pwd) cargo +nightly build -Z build-std --target $(TARGET) --release + mkdir -p $(BOOT_DIR)/EFI/BOOT/ + cp -v $(target_release) $(BOOT_DIR)/EFI/BOOT/BOOTX64.EFI diff --git a/OVMF_CODE.fd b/OVMF_CODE.fd new file mode 100644 index 0000000..bcdffdd Binary files /dev/null and b/OVMF_CODE.fd differ diff --git a/OVMF_VARS.fd b/OVMF_VARS.fd new file mode 100644 index 0000000..68c2132 Binary files /dev/null and b/OVMF_VARS.fd differ diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..87a8dbb --- /dev/null +++ b/src/main.rs @@ -0,0 +1,173 @@ +#![no_std] +#![no_main] +#![allow(unused)] + +#[macro_use] +extern crate log; +#[macro_use] +extern crate alloc; + +// Keep this line to ensure the `mem*` functions are linked in. +extern crate rlibc; + +extern crate goblin; + +extern crate uefi; +extern crate uefi_services; + +#[macro_use] +extern crate uefi_macros; + +use core::ffi::c_void; +use core::ptr; +use uefi::Handle; +use uefi::{prelude::*, Identify}; +use uefi::{ + proto::console::gop::{BltOp, BltPixel, FrameBuffer, GraphicsOutput, PixelFormat}, + table::boot::{ + AllocateType, BootServices, MemoryType, OpenProtocolAttributes, OpenProtocolParams, + }, +}; + +#[uefi_macros::entry] +pub fn efi_main(_image: Handle, mut st: SystemTable) -> Status { + // Initialize logging, memory allocation and uefi services + let mut bt = match uefi_services::init(&mut st) { + Ok(_) => { + + st.stdout().clear(); + st.stdout().set_color( + uefi::proto::console::text::Color::LightMagenta, + uefi::proto::console::text::Color::Black, + ); + + // output firmware-vendor (CStr16 to Rust string) + // max size of 32 characters + let mut buf = arrayvec::ArrayString::<32>::new(); + st.firmware_vendor().as_str_in_buf(&mut buf).unwrap(); + info!("Firmware Vendor: {}", buf.as_str()); + + let rev = st.uefi_revision(); + let (major, minor) = (rev.major(), rev.minor()); + let buf = format!("UEFI {}.{}", major, minor / 10); + info!("{}", buf); + + assert!(major >= 2, "Running on an old, unsupported version of UEFI"); + assert!( + minor >= 30, + "Old version of UEFI 2, some features might not be available." + ); + + st.boot_services() + } + Err(_) => { + panic!(); + } + }; + + + + + let handle = bt.get_handle_for_protocol::() + .expect("missing GraphicsOutput protocol"); + + + let mut gop = unsafe { + let mut gop_proto = st.boot_services().open_protocol::( + OpenProtocolParams { + handle, + agent: st.boot_services().image_handle(), + controller: None, + }, + // For this test, don't open in exclusive mode. That + // would break the connection between stdout and the + // video console. + OpenProtocolAttributes::GetProtocol, + ) + .expect("failed to open Graphics Output Protocol"); + + gop_proto + }; + + set_graphics_mode(&mut gop); + fill_color(&mut gop); + draw_fb(&mut gop); + info!("GOP Framebuffer test complete"); + + // Return success status + Status::SUCCESS +} + +// Set a larger graphics mode. +fn set_graphics_mode(gop: &mut GraphicsOutput) { + // We know for sure QEMU has a 1024x768 mode. + let mode = gop + .modes() + .find(|mode| { + let info = mode.info(); + info.resolution() == (1024, 768) + }) + .unwrap(); + + gop.set_mode(&mode).expect("Failed to set graphics mode"); +} + +// Fill the screen with color. +fn fill_color(gop: &mut GraphicsOutput) { + let op = BltOp::VideoFill { + // Cornflower blue. + color: BltPixel::new(100, 149, 237), + dest: (0, 0), + dims: (1024, 768), + }; + + gop.blt(op).expect("Failed to fill screen with color"); +} + +// Draw directly to the frame buffer. +fn draw_fb(gop: &mut GraphicsOutput) { + // The `virtio-gpu-pci` graphics device we use on aarch64 doesn't + // support `PixelFormat::BltOnly`. + if cfg!(target_arch = "aarch64") { + return; + } + + let mi = gop.current_mode_info(); + let stride = mi.stride(); + let (width, height) = mi.resolution(); + + let mut fb = gop.frame_buffer(); + + type PixelWriter = unsafe fn(&mut FrameBuffer, usize, [u8; 3]); + unsafe fn write_pixel_rgb(fb: &mut FrameBuffer, pixel_base: usize, rgb: [u8; 3]) { + fb.write_value(pixel_base, rgb); + } + unsafe fn write_pixel_bgr(fb: &mut FrameBuffer, pixel_base: usize, rgb: [u8; 3]) { + fb.write_value(pixel_base, [rgb[2], rgb[1], rgb[0]]); + } + let write_pixel: PixelWriter = match mi.pixel_format() { + PixelFormat::Rgb => write_pixel_rgb, + PixelFormat::Bgr => write_pixel_bgr, + _ => { + info!("This pixel format is not supported by the drawing demo"); + return; + } + }; + + let mut fill_rectangle = |(x1, y1), (x2, y2), color| { + assert!((x1 < width) && (x2 < width), "Bad X coordinate"); + assert!((y1 < height) && (y2 < height), "Bad Y coordinate"); + for row in y1..y2 { + for column in x1..x2 { + unsafe { + let pixel_index = (row * stride) + column; + let pixel_base = 4 * pixel_index; + write_pixel(&mut fb, pixel_base, color); + } + } + } + }; + + fill_rectangle((50, 30), (150, 600), [250, 128, 64]); + fill_rectangle((400, 120), (750, 450), [16, 128, 255]); +}