You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When allocating memory for a UEFI application using BootServices with a custom memory type, the ExitBootServices call later freezes on a real machine, but it works fine in QEMU.
Everything works as expected on the real machine as well, if MemoryType::LOADER_DATA is used.
System Information:
Tested on: Lenovo V15 G3 IAP
CPU: 12th Gen Intel(R) Core(TM) i5-1235U
Rust Toolchain: nightly
Dependencies Used:
log = "0.4.22"uefi = { version = "0.31.0", features = ["logger", "alloc", "global_allocator", "panic_handler"] }
#![no_std]#![no_main]externcrate alloc;use alloc::format;use alloc::string::String;use log::info;use uefi::{
entry,Handle,Status, table::{Boot,SystemTable},};use uefi::prelude::BootServices;use uefi::proto::console::gop::{GraphicsOutput,PixelFormat};use uefi::table::boot::{AllocateType,MemoryType};usecrate::framebuffer::{Color,FrameBufferMetadata,RawFrameBuffer};mod framebuffer;constMY_MEMORY_TYPE:MemoryType = MemoryType::custom(0x80000001);#[entry]fnmain(_image_handle:Handle,system_table:SystemTable<Boot>) -> Status{
uefi::helpers::init().unwrap();info!("Hello, uefi world!");// some boilerplate to get a working framebuffer using Graphics Output Protocollet fb_meta = initialize_framebuffer(system_table.boot_services()).unwrap();let fb = RawFrameBuffer::from(fb_meta);// color white indicates framebuffer initialization was successful
fb.fill(Color::white());// allocate some memory using the custom memory typelet x = system_table.boot_services().allocate_pages(AllocateType::AnyPages,MY_MEMORY_TYPE,5).unwrap();// "use" the newly allocated memorylet _y = unsafe{*(x as*constu8)};// color blue indicates allocation was successful
fb.fill(Color::blue());// exit boot serviceslet(_, _) = unsafe{ system_table.exit_boot_services(MemoryType::LOADER_DATA)};// color green indicates exit was successful
fb.fill(Color::green());loop{}}/// Initialize framebuffer (GOP)fninitialize_framebuffer(boot_services:&BootServices,) -> Result<FrameBufferMetadata,String>{let gop_handle = boot_services
.get_handle_for_protocol::<GraphicsOutput>().map_err(|error| format!("Could not get handle for GOP: {error}."))?;letmut gop = boot_services
.open_protocol_exclusive::<GraphicsOutput>(gop_handle).map_err(|error| format!("Could not open GOP: {error}."))?;letmut raw_frame_buffer = gop.frame_buffer();let base = raw_frame_buffer.as_mut_ptr()asu64;let size = raw_frame_buffer.size();let info = gop.current_mode_info();let is_rgb = match info.pixel_format(){PixelFormat::Rgb => Ok(true),PixelFormat::Bgr => Ok(false),PixelFormat::Bitmask | PixelFormat::BltOnly => {Err("Not supported")}}?;let(width, height) = info.resolution();let stride = info.stride();Ok(FrameBufferMetadata{
base,
size,
width,
height,
stride,
is_rgb,})}
framebuffer.rs
use core::{
fmt,
fmt::{Debug,Formatter},};use core::ptr::write_volatile;pub(crate)constBPP:usize = 4;#[derive(Copy,Clone)]pub(crate)structFrameBufferMetadata{pub(crate)base:u64,pub(crate)size:usize,pub(crate)width:usize,pub(crate)height:usize,pub(crate)stride:usize,// pixels per scanlinepub(crate)is_rgb:bool,}implDebugforFrameBufferMetadata{fnfmt(&self,f:&mutFormatter<'_>) -> fmt::Result{
f.write_fmt(format_args!("FrameBufferMetadata {{\n\tbase: {:#x},\n\tsize: {:#x},\n\twidth: {},\n\theight: {},\n\tstride: {},\n}}",
self.base, self.size, self.width, self.height, self.stride
))}}#[derive(Copy,Clone,Debug,Default)]pub(crate)structColor{pub(crate)red:u8,pub(crate)green:u8,pub(crate)blue:u8,}macro_rules! color {($color:ident, $red:expr, $green:expr, $blue:expr) => {implColor{pub(crate)constfn $color() -> Color{Color{
red: $red,
green: $green,
blue: $blue,
}}}};}color!(green, 0x00, 0xFF, 0x00);color!(blue, 0x00, 0x00, 0xFF);color!(white, 0xFF, 0xFF, 0xFF);/// Directly accesses video memory in order to display graphics#[derive(Clone,Debug)]pub(crate)structRawFrameBuffer{pub(crate)meta_data:FrameBufferMetadata,}implRawFrameBuffer{/// Draws a pixel onto the screen at coordinates x,y and with the specified color. Returns, whether the action succeeds or the coordinates are invalid.pub(crate)fndraw_pixel(&self,x:usize,y:usize,color:Color,) -> Result<(),(usize,usize)>{if !self.in_bounds(x, y){returnErr((x, y));}let pitch = self.meta_data.stride*BPP;unsafe{let pixel = (self.meta_data.baseas*mutu8).add(pitch * y + BPP* x);ifself.meta_data.is_rgb{write_volatile(pixel, color.red);write_volatile(pixel.add(1), color.green);write_volatile(pixel.add(2), color.blue);}else{write_volatile(pixel, color.blue);write_volatile(pixel.add(1), color.green);write_volatile(pixel.add(2), color.red);}}Ok(())}/// Fills entire display with certain colorpub(crate)fnfill(&self,color:Color){for x in0..self.meta_data.width{for y in0..self.meta_data.height{self.draw_pixel(x, y, color).unwrap();}}}}implRawFrameBuffer{/// Whether a point is within the framebuffer vramfnin_bounds(&self,x:usize,y:usize) -> bool{
x < self.meta_data.width && y < self.meta_data.height}}implFrom<FrameBufferMetadata>forRawFrameBuffer{fnfrom(value:FrameBufferMetadata) -> Self{Self{meta_data: value }}}
Note: I'm relatively new to the UEFI and OSDev community so there might be an issue with my code itself. Please feel free to correct me if the mistake is mine.
The text was updated successfully, but these errors were encountered:
When allocating memory for a UEFI application using BootServices with a custom memory type, the ExitBootServices call later freezes on a real machine, but it works fine in QEMU.
Everything works as expected on the real machine as well, if
MemoryType::LOADER_DATA
is used.System Information:
Tested on: Lenovo V15 G3 IAP
CPU: 12th Gen Intel(R) Core(TM) i5-1235U
Rust Toolchain: nightly
Dependencies Used:
Source Code:
config.toml
main.rs
framebuffer.rs
Note: I'm relatively new to the UEFI and OSDev community so there might be an issue with my code itself. Please feel free to correct me if the mistake is mine.
The text was updated successfully, but these errors were encountered: