uefi-rs icon indicating copy to clipboard operation
uefi-rs copied to clipboard

Add a method, to get Index on uefi::proto::console::gop::Mode

Open C0D3-M4513R opened this issue 3 years ago • 3 comments

I am currently writing my own kernel. I use the GOP to get a framebuffer. I look through all, and grab the one, that has the best properties.

The annoying part is, that I CAN iterate over all Modes and grab their respective ModeInfo. It is just, that there is no good way to know which mode I have the info of. That means it is impossible for me to modeset, because I don't know which index ModeInfo is from.

My current approach is the following. It doesn't feel very clean, but I don't think, that I can come up with a better approach.

let st = unsafe{uefi_services::system_table().as_mut()};

//todo: have a better way, to draw stuff
let mut gop = st.boot_services().locate_protocol::<uefi::proto::console::gop::GraphicsOutput>()?;
//SAFETY:
// FIXME: Cannot satisfy.
// This Application could have been started by another Application.
// If that Application also got the GOP, this is a violation.
let gop = unsafe{&mut *gop.get()};
let i = gop.modes();
the start, and gets set to Some(i.next())).
let i = i.enumerate().map(|(mn,m)|(mn,*m.info())).filter(|(_,m)|m.pixel_format()!=PixelFormat::BltOnly);

I feel like this could be written safer, if uefi allowed getting the Index of Mode.

C0D3-M4513R avatar Jul 03 '22 21:07 C0D3-M4513R

Alternatively you could allow us to know how many modes there are. Then we can iter over the modes using a for loop and query_modes.

AFAIK Currently only queriably by doing:

let i = gop.modes();
let max_modes=i.size_hint().0;

C0D3-M4513R avatar Jul 03 '22 21:07 C0D3-M4513R

Here's how you can do this with the existing API:

use uefi::proto::console::gop::{GraphicsOutput, PixelFormat};
use uefi::table::boot::{BootServices, OpenProtocolAttributes, OpenProtocolParams, SearchType};
use uefi::{Handle, Identify, Result};

pub fn gop_test(image: Handle, bt: &BootServices) -> Result {
    let gop_handle = *bt
        .locate_handle_buffer(SearchType::ByProtocol(&GraphicsOutput::GUID))?
        .handles()
        .first()
        .expect("no GOP handle found");

    let gop = bt.open_protocol::<GraphicsOutput>(
        OpenProtocolParams {
            handle: gop_handle,
            agent: image,
            controller: None,
        },
        OpenProtocolAttributes::Exclusive,
    )?;
    // SAFETY: the protocol was opened in exclusive mode so nothing else
    // can use it.
    let gop = unsafe { &mut *gop.interface.get() };

    let mode = gop
        .modes()
        .find(|mode| mode.info().pixel_format() != PixelFormat::BltOnly)
        .expect("no valid mode found");
    gop.set_mode(&mode)?;

    Ok(())
}

(Adapted from https://github.com/rust-osdev/uefi-rs/blob/main/uefi-test-runner/src/proto/console/gop.rs)

nicholasbishop avatar Jul 03 '22 23:07 nicholasbishop

Oops. I completely forgot to look at set_mode. The abstraction makes sense then. What doesn't make sense is that gop.query_mode is public. We don't know anything about indexes, and we cannot query anything from the current api. Either make a index getter, or query_mode private in my eyes.

Any reason why Mode is non-Copy, non-Clone and most of all non-debug? It is not like we can change something inside of Mode accidentally.

C0D3-M4513R avatar Jul 06 '22 10:07 C0D3-M4513R