-
Notifications
You must be signed in to change notification settings - Fork 286
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
Feature request: uefi support #896
Comments
@joholl Short Version: The request does make sense but probably only at a lower level. Most of what you seek would likely be best handled by building out terminal functionality in the UEFI code. Long VersionWell, you asked for it. Specifically: "I have not a full understanding of UEFI, crossterm, ratatui and terminals in general." Allow me to fill in some of the blanks here. Apologies that this is so long, but terminals have quite a history and consider this to be a sort of crash course. I hope to provide enough context to place all of this within the bigger world of terminals, etc. Once you understand why all of these features are here, a lot of what you need to do to get this working should crystalize. What is a Terminal?Terminals, in the Crossterm / Unix sense, are hardware devices or software programs that speak some various flavors of protocol to your OS. This is complicated somewhat by a few things like...
On top of that, there's often issues of how you're talking to the terminal:
Terminals (Like Ogres) Have LayersAll of this meshes together such that you can expect the following layers:
Application LevelAt a high-level, most applications just want to print out text. Most everything you work with just knows to write strings to something (e.g. a file descriptor on Unix, a file handle on Windows, a protocol in UEFI). In the simplest model, those characters just get printed out. This isn't really very remarkable, but it's important to understand it when you are trying to sort out what's going on. At this level, you're concerned about things like character encodings (ASCII, Unicode, EBCDIC, etc.) And often you're only concerned about a small subset of characters in those encodings (Latin-1, Klingon, etc.). Most critically, this is where you'll send the control codes and sequences that other layers will intercept and interpret. Or, if things aren't right, they'll just display them wrong. Providing this layer is Crossterm's entire job—and to do that it (or your support code) needs to know a lot about those other layers. As a matter of history, printing itself has some cursor positioning that varies a bit for certain control codes. So even though this level isn't concerned with all forms of cursor positioning, it implicitly does some. For example, on old teletypes, backspace would move the carriage back one character. They actually supported underlines by printing the text, sending backspaces to back up to the beginning, and then printed underscores. They would also do bold the same way by backing up and printing it another time! There is even some ambiguity at this level. You know how Windows uses two characters (carriage return + linefeed) for line endings and Unix uses just one (only a linefeed)? This is because Windows preserved the old teletype interpretation of carriage return just positioning back at the first column and linefeed advancing the paper. Unix just decided to use only the linefeed. When this is set wrong, you can see things like "stair-stepping" in text. Terminal LevelWhen you read about ANSI codes, that is usually a terminal-level thing. Your application will need to know how to write these codes and the consuming software / hardware hopefully knows how to handle them. Alternate Screen-mode is at this level. Notably, raw mode is not. Clearing the screen and selecting colors is. The general gist of this layer is that you're telling the remote end how to do something more than just spit out characters. This will be things like colors, cursor positioning, etc. This may be implemented in hardware, in a(n) OS driver(s), or even an emulator program running on a GUI. Emulators will have codes for things like color palettes, handling cut-and-paste buffers, etc. OS LevelWhen you start hearing about things like cooked-mode, raw-mode, echoing mode, and break (i.e. For example, the original terminals were actually teletypes. That is, they were like a type-writer that the computer could also print back to. The "line buffering mode" settings actually emulate this and it's sort of the natural behavior for most Unix tools. Line buffering plus application-level text writing / reading gets you most of what you experience at the shell prompt. You'll also get stuff at this level like "process control". Display / Input LevelFinally, lowest-level physical aspects of presenting your text and getting input come into play. When you're dealing with a console driver, the OS has some subsystem that knows how to draw the characters. Some systems have hardware do this for them, whereas others manage their own graphics hardware and draw the text themselves. These systems might have escape codes for resizing the screen when it changes text modes or advanced codes for drawing graphics. They can even have codes for things like cursor shape / flash / flash rate or changing fonts. If you're dealing with a serial terminal, you have entirely different physical concerns. Here you may actually have functionality to set the baud rate and character encoding. Some serial systems actually use control characters for flow control. Others have "clear-to-send" / "data-terminal-ready" (CTS/DTR) bits. This may also be an entirely imaginary "physical" layer like you'll find in a Terminal Emulator program. Programs like xterm and konsole on Linux; iTerm or Terminal on Mac; whatever monstrosity Windows presents as a console; something even weirder under WSL; etc. Most of what they do will be at the "terminal level", but you'll still find things down here like window resizing, mouse events, and window titles. Why So Many Layers?Most all of the above exists because of the biggest annoyance in the field of computing—backwards compatibility. Some of this stuff has its root all the way back before WWI (in the 1920s and even a bit before)! So you're actually looking at about 100 years of backwards compatibility! Each of the above are layers are the end-result of series of often disconnected design decisions. From the ENIAC all the way to your Macbook—and every IBM Mainframe in between—decisions were piled on top of each other. There's more history here than I can easily recount, but I've attached a What's Your Stack?The easiest way to understand how you need to work with the above layers is to define your target environment. In modern parlance, what is your "stack"? The following are all common "stacks" these days:
In each of the above, every single layer (except a few marked in parenthesis) may interpret certain control codes or have external APIs to provide certain functionality. For example:
Where is Crossterm In All This?Most interestingly, Crossterm runs inside of the "Application" of these stacks. It's handling a dizzying array of control codes and features to handle everything you see there. And, in real programs, it often works in concert with other setup code to work with things like serial ports, It's honestly kind of crazy that Crossterm can find a subset of functionality that works across all of these things. In most use cases, it "stands on the shoulders of giants". The OS and emulators do most of the work for it. Your use case isn't much like that. Make It All Make Sense!Let's define your stack. You're probably going to be implementing one of these:
Notice what's missing above that was in every other stack? The OS. There's going to be no signal handling, buffering mode, "cooked" / "raw" handling, keyboard handling. For that matter, there's no Terminal Emulator or Hardware either. So that means no ANSI codes, limited control codes, etc. There's no terminal emulator or OS at boot time. That's good in that you don't have so much Considering the features / issues you've mentioned:
What Needs To Be Done, Then?
So... yeah. There's not a lot to be done here in Crossterm. You really need to build up the Rust UEFI support to provide:
To that end, a new Crossterm backend may help take out some of the other assumptions that most terminals meet but would be hard to implement. But you'll probably do better to keep as much as possible in the UEFI code. It would certainly be more widely useful. I hope that helps. And, if you do undertake this work, good luck. Appendix A: A (Not So) Brief (or Entirely Accurate) History of Text Processing EquipmentIn the beginning, $DIETY created people. And he saw that the people wanted to communicate much further than they could hear each other. And he created teletypes and it was good. And then he created computers. And he looked down and saw that computers had no mouth and could not speak, so he adapted teletypes into teleprinters. And he saw that computers could only speak in bits and that users could only speak in glyphs. And he said, "Let there be character encodings!" And there were character encodings. And it was good. And he saw that the characters were without formatting and the teletypes couldn't really print much more than a line of text. And he said, "Let there be control codes!" And control characters such as "Carriage Return" and "Line Feed" and "Tab" and "Form Feed" came into being. And they were simple characters, and now the teleprinters could print about freely. And they were happy for a time. And in these early times, IBM had to "Think Different" and they create some diabolical alternate encodings that they forced upon their customers. And these encodings were seen to be proprietary and unwieldy. In his anger, he consigned them to Corporate Hell, where they toil to this day, underpinning the government, financial, medical, and insurance systems. And the computers were confused, for the humans in their haste had made many typos because they couldn't see what they were typing. And they took pity on the humans and echoed back the characters they were typing. And thus echo mode was born. And it came to pass that humans humans realized that they had things to hide; and in their shame they created passwords. And computers gifted them with the ability to turn off echo mode, so their passwords weren't displayed. The computers tired of handling each character on their own, and they cried out to their creator, "Can we just get a whole line?" And the teletypes were taught to buffer, and line mode came to be. Soon the people had created great industries. They consumed entire forests, creating tractor-feed paper to feed to the hungry printers and teletypes. They looked upon the barren landscapes that had once been verdant jungles and despaired. They cried out, "We haven't invented recycling yet. What do we do with all of this paper?" And they made monitors and keyboards. They integrated them together, creating terminals. And they replaced the teleprinters with them. As punishment, the teleprinters were stripped of their keyboards and banished to the land of Hewlett-Packard, where they would have buggy drivers until the end of days. The terminals were taught to speak the same control codes that the printers had. And they had more added... so many more. But eventually, they exhausted their supply of bits, and could mint no more new characters. And they saw that it was wasteful, as some characters signified inputs that had no glyph to display (i.e. They cried out, "Let us escape from these bonds. Let us use multiple characters to signal new inputs and outputs." And escape they did, by creating escape codes. They could now print out the Escape character and define sequences of characters to control new functionality. And the monitors and the keyboards and the computers and the people were happy for a time. Even the printers rejoiced and hummed as they munched page after page of paper. And their ink flowed like wine, even when you weren't printing. And Hewlett-Packard became rich. But in time, the people became divided. And in this division they created new, incompatible, competing standards and codes. Some tribes of people strayed far from their computers as they had with the teletypes of old. They invented modems to sit in between the computer serial port and the terminal. Some left out the terminal altogether, integrating keyboards and monitors directly with computers. They retained vestigial aspects of the terminals that handled by video cards and the keyboard interface. Soon these devolved until some computers didn't even have a native text mode and drew their own characters. And $DIETY looked down on this and turned away in disgust. And he declared that the world of terminals was outside of his sight—and thus outside of his love. It came to pass that the fractious groups of humans had to fight among themselves to make this all work. And fight they did. Some created great families of terminals, each with their own dialect and capabilities. Some tried to unify the printers with the terminals again and created escape codes for remote printing. And computers tried their best to make use of all of this, providing APIs to control how they interfaces with serial ports and dialects of terminal and their own consoles. They even created interfaces to allow programs to talk to other programs, creating the In doing this, they also allowed entirely software terminals. Seeing the freedom from hardware limitations, they said "We will create a standard to replace these other N standards." And thus it came to pass that there were N+1 standards. Humans, in their desire to "just get work done" created vast libraries of data and code to try to sort all of this out. There were descriptions of terminal capabilities / codes like And in the ensuing years, there were oft recreated with specific focuses and varying qualities. Which leads us to the mess you're going to have to sort out to make all of this work. Appendix B: Some Useful LinksYou read all the way down here, eh? Here are some tasty links for your trouble.
|
Get this man a blog!!! :D (serious suggestion as this is a great write up and deserves to have a URL where people can point at permanently) Solving the underlying problem Ratatui apps in UEFI, I'd suggest solving this by sidestepping crossterm entirely.
|
@joshka Thanks for the kind words. I don't really maintain my blog anymore. I tend to put stuff like this in random GitHub comments because I have an inkling that they'll exist long after my blog will be gone. It seems like as good a place as any. I've added some resources and clarifications to the post. I hope it's useful to people who stumble across it in search engines and whatnot. I'm sure it'll be trained into some AI and memorialized forever... so I guess I've got that going for me. @joholl The above suggestion is a good one. You could skip Crossterm entirely and go straight to a That said, it's way more work to do that; so nobody (who matters) would blame you for going the expedient route. |
Oh wow... Thank you @jvantuyl for the very comprehensive (and no less entertaining) answer! @jvantuyl @joshka To be honest, I already kinda tried making More importantly, though, I think I'd rather have a non-interactive tool that works on most UEFI systems than an interactive tool that works on some of them, not quite on some others and not at all on the rest. It is hard for me to judge how fragmented the UEFI landscape is, right now. Adding UEFI support to crossterm might still be a worthwhile endeavor, perhaps. Feel free to close this issue if you feel like it is sufficiently unlikely (or unworthy of tracking). |
Problem
This crate is great! It would be even greater, 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:
print!()
), but there is also raw access to the UEFI protocol via EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString()Open questions:
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):
PoC code for getting the terminal dimensions via
query_mode
:The text was updated successfully, but these errors were encountered: