Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question on how to access to stdin, stdout (and stderr) since 0.32 #1400

Open
YtvwlD opened this issue Sep 13, 2024 · 4 comments
Open

Question on how to access to stdin, stdout (and stderr) since 0.32 #1400

YtvwlD opened this issue Sep 13, 2024 · 4 comments

Comments

@YtvwlD
Copy link
Contributor

YtvwlD commented Sep 13, 2024

Hi, I'm trying to display a menu. With older versions of uefi-rs, I'd have a function

pub fn choose<'a>(config: &'a Config, systab: &mut SystemTable<Boot>) -> &'a Entry

that accesses systab.stdin() and systab.stdout(). Since that is now deprecated, how would I change this?
The migration document doesn't mention stdin or stdout.

I've thought of this:

pub fn choose<'a>(config: &'a Config, stdin: &mut Input, stdout: &mut Output) -> &'a Entry

but I can't call it with:

let entry_to_boot = with_stdin(|stdin| with_stdout(
    |stdout| menu::choose(&config, stdin, stdout)
));

as this produces the following error:

error[E0596]: cannot borrow `*stdin` as mutable, as it is a captured variable in a `Fn` closure
   --> src/main.rs:117:40
    |
31  | fn efi_main(image: Handle, mut systab: SystemTable<Boot>) -> Status {
    |    --------                                                  ------ change this to return `FnMut` instead of `Fn`
...
117 |         |stdout| menu::choose(&config, stdin, stdout)
    |         -------- in this closure       ^^^^^ cannot borrow as mutable

Do I have to put the calls to with_stdin and with_stdout inside the function?

@phip1611
Copy link
Contributor

Good question, thanks for pointing that out. I don't have capacity to look into this in the next days, but perhaps @nicholasbishop can work on it?

@nicholasbishop
Copy link
Member

Good question indeed, the API here is not making what you want to do as easy as it should be.

I think the simplest way forward for now is to manually stash pointers. Here's an example that compiles:

#![no_std]
#![no_main]

use uefi::proto::console::text::{Output, Input};
use uefi::{Status, entry, system};
use core::ptr;

pub fn choose(_stdin: &mut Input, _stdout: &mut Output) {
    unimplemented!();
}

#[entry]
fn main() -> Status {
    let stdin: *mut Input = system::with_stdin(|stdin| ptr::from_mut(stdin));
    let stdout: *mut Output = system::with_stdout(|stdout| ptr::from_mut(stdout));

    // Safety: in the UEFI spec, section
    // EFI_BOOT_SERVICES.UninstallProtocolInterface(), it says that
    // console I/O protocols can never be removed. So these pointers are
    // always valid, and within this block there is no shared mutable
    // reference to stdin or stdout, so Rust's aliasing guarantees are
    // maintained.
    { 
        let stdin = unsafe { &mut *stdin };
        let stdout = unsafe { &mut *stdout };

        choose(stdin, stdout);
    }

    Status::SUCCESS
}

This is not ideal though, we should think about this API some more.

@YtvwlD
Copy link
Contributor Author

YtvwlD commented Sep 15, 2024

Can f be FnMut? Would that work?

(This also applies to with_config_table.)

@phip1611
Copy link
Contributor

How now system::with_std(|stdin, stdout|)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants