crossterm
crossterm copied to clipboard
Feature request: uefi support
Problem
This crate is great! It would be even grater, if it supported uefi. Rust nightly contains much of std already, see this example in the official docs.
In the end, I would love to use ratatui on Linux/Windows/UEFI with crossterm as a backend.
Solution
What we already have:
- std already supports printing to stdout (e.g. via
print!()
), but there is also raw access to the UEFI protocol via EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString() - the UEFI console supports a few control characters (LF, CR, BS, ...) and some ANSI escape codes
- the UEFI protocols provide an API for clearing the screen, querying for terminal size, setting the cursor position etc.
Open questions:
- I have not found features to enable alternate screen and raw mode (but I also lack deeper understanding of UEFI and what these modes do exactly)
- I have not had a closer look at input/events
I do not know if this feature request makes sense because I have not a full understanding of UEFI, crossterm, ratatui and terminals in general.
Development
If you quickly want to spin up a Rust application using stdout on UEFI (qemu):
sudo apt install ovmf # for qemu uefi image
rustup target add x86_64-unknown-uefi # install cross-compile toolchain
cargo init
cargo add r-efi
# copy this example into main.rs: https://github.com/rust-lang/rust/blob/master/src/doc/rustc/src/platform-support/unknown-uefi.md#example-hello-world-with-std
cargo build --target=x86_64-unknown-uefi
qemu-system-x86_64 -m 4G -cpu max -smp 4 -bios /usr/share/ovmf/OVMF.fd -nographic -no-reboot -nic none -drive file=fat:rw:./target/x86_64-unknown-uefi/debug,format=raw,media=disk
# type "<ESC>" to drop into shell
# type "fs0:" to change drive
# type "ls" to find your binary name: <...>.efi
# type "<...>.efi" to run application
PoC code for getting the terminal dimensions via query_mode
:
let mut columns: usize = 0;
let mut rows: usize = 0;
let r = unsafe {
let con_out: *mut simple_text_output::Protocol = (*system_table).con_out;
let query_mode: extern "efiapi" fn(
_: *mut simple_text_output::Protocol,
usize,
*mut usize,
*mut usize,
) -> efi::Status = (*con_out).query_mode;
let mode_number = 0;
query_mode(
con_out,
mode_number,
&mut columns as *mut _,
&mut rows as *mut _,
)
};
assert!(!r.is_error());