============================================= Google Serial Graphics Adapter BIOS (SGABIOS) Copyright 2007 Google Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================================= Status: Implemented (as of 2007-08-08) Nathan Laredo Modified: 2008-02-14 13:45 PDT Objective --------- The Google Serial Graphics Adapter BIOS or SGABIOS provides a means for legacy pc software to communicate with an attached serial console as if a vga card is attached. Background ---------- The headless server problem When building a lot of systems for data center use, it makes no sense to install hardware that will rarely if ever be used. Graphics adapters are not very useful even if they are installed in a data center environment since often the person interested in seeing the output is separated from the device by tens to thousands of miles. While it's possible to use remote management hardware that provides a remotely accessible display and keyboard, this hardware is much more expensive than the hardware that it replaces, and often this hardware sends only images of the display rather than something suitable for logging. Since most systems already have a serial port, it's an obvious target as a replacement for the primary display and keyboard. The problem is that while an operating system like Linux can support this arrangement, all of the output that would normally appear on a graphics adapter before Linux boots is lost on modern x86 hardware without modifications to the system firmware. While some vendors provide firmware that enables the serial port to be used as the primary display, this is usually a "premium" option and isn't universally available for all x86 platforms. Often such services aren't implemented in a way that is friendly to saving logs of boot activity. One particularly ugly implementation might send the same text hundreds of times as it tries to refresh the entire display each timer tick. Others have ansi control sequences between every single character output which, while readable in a terminal, is almost unusable when referring to serial log files. Behavior like this slows down the serial output by up to fifteen times in some cases, using sometimes that many extra characters of control sequences for each character output. The need for detailed system logs None of the vendor-supplied serial redirection implementations include facilities for logging boot message for later capture by an operating system. Being able to refer to the boot messages after an operating system has loaded, or having a history of such messages can be a useful debug, analysis, and management feature. Even on systems with graphics adapters attached, once the display is scrolled or refreshed with enough new text, the old messages are only available in the user's own brain, which often isn't very good at accurately recalling more than two or three items that aren't grammatically meaningful in the user's native language. Overview --------- SGABIOS is designed to be inserted into a bios as an option rom to provide over a serial port the display and input capabilites normally handled by a VGA adapter and a keyboard, and additionally provide hooks for logging displayed characters for later collection after an operating system boots. It is designed to handle all text mode output sent to the legacy bios int 10h service routine. Int 10h is the most common method for displaying characters in 16-bit legacy x86 code. Occasionally some code may write directly to the vga memory in the interest of "speed," and this output will be missed, but it's rather uncommon for any code involved in booting a system to be concerned with the speed of display output. SGABIOS is not designed to handle these cases since those applications that make such assumptions generally write to an area of memory that typically already in use for system management mode and unusable outside of that mode. Paging tricks could be used to capture such output, but enabling paging requires protected mode to be enabled which instantly breaks all segment loads in legacy 16-bit real- mode code (which is the traditional boot environment). Detailed Design ---------------- VGA BIOS int 10h is hooked and chained to any existing handler or the default handler that the BIOS previously setup. During initialization, the option rom also probes the serial port for reply from an attached terminal. If the terminal replies to a specific sequence, the terminal size is recorded and used for all future display calculations. If a VGA card is attached at the same time, the width of the terminal is limited to 80 columns in order to have sensible output on both the VGA card and on the serial console. If no reply comes from the serial terminal within a very short timeout of about 8 milliseconds (or more accurately, 65536 reads of the serial status port), a default size of 80x24 is used. The detected size is displayed at the end of option rom init to the serial console. Because of the way the cursor is updated, if the cursor is never moved upwards or more than one line down by int 10h calls, output will still be appear completely appropriate for whatever sized terminal is attached but failed to get detected. Whenever int 10h is invoked, SGABIOS gets control first and decides whether to act based on register state. With the exception of functions for getting current mode info or the current cursor position, whether it acts or not, register state is ultimately restored to the state on entry and a far jump is made to the original handler. SGABIOS maintains two active cursor positions. One contains the traditional VGA cursor position at the traditional location in the BIOS Data Area, while the other maintains the position the serial console's cursor is located. The serial cursor position is located in a BDA location that traditionally contains the base io port address for LPT3, but since builtin printer ports are disappearing over time, this location is reused. These two values will often differ since serial terminal output will always move the cursor to the next position on the screen while many VGA operations don't update the cursor position at all, or some only at the start of the string, but leave the old value at the end. Keeping track of two active cursor positions means that SGABIOS can collapse a string of "set cursor" calls into perhaps a single one or none if the serial console cursor already happens to be at the target location. Cursor movements are further optimized by sending newline characters to move the cursor down one row, carriage return characters to move the cursor back to column 0, and backspace characters to send the cursor back one or two spaces. To avoid problems when a video card is connected, any Bios Data Area location that would be updated by a VGA card is left alone to be updated by the VGA card. SGABIOS will update the cursor position as usual, but just before chaining to an existing vga card's handler, it will restore the values to those on entry, and for those functions that return data, it will defer completely to the chained routines rather than taking those over as it does when no video card is detected. Cursor position updates to serial console are deferred until the next character of terminal output is available. This collapses the cases where the cursor is updated more than one time between each character output (this is surprisingly common). The goal of tracking the cursor so closely and minimizing the number of characters required to update the cursor position is to both to make the display of output as efficient and fast as possible and to allow one to grep a raw log of serial console output for text (which without such optimization may be impossible or extremely difficult with movement escape sequences between every character). In the same way cursor position is tracked, vga character attributes are tracked so that it's possible to minimize the number of times an attribute change escape sequence is sent to the serial console. A BIOS Data Area location traditionally used for storing the current palette value is used to store the last attribute sent to the serial console. As SGABIOS processes new calls, if the value is the same, after masking off bright background colors which aren't supported in ansi escape codes, then no attribute update is sent to the serial console, else an escape sequence is sent that gives the new background and foreground colors and whether the foreground is bold or not. Data communication Whenever the call is made to output text, SGABIOS first updates the serial terminal cursor to match the current position of the vga cursor (if necessary), outputs any attribute change if applicable to the particular int 10h call made, and finally sends the text character (or characters) out to the serial port, and then updates its own view of where the serial console cursor is located. After the text is sent, a logging routine is called to store that text in a private area of memory allocated at option rom init. For keyboard/terminal input, SGABIOS hooks bios int 16h which is typically called to poll for a keypress. Before passing the call along, SGABIOS looks for any pending input on the serial port and stuffs the keyboard buffer with any pending byte after translating it to a compatible keyboard scancode. If the character received is an escape, SGABIOS will continue to poll for up to four extra characters of input for several milliseconds in order to detect ANSI/VT100/xterm/etc cursor keys and function keys, looking up appropriate scancodes in a table of escape sequences for all known non-conflicting terminal types. SGABIOS also hooks the serial port interrupts, and on receiving an interrupt blocks out interrupts, calls the same polling routines as above, following the same processing of multi-byte input as well, stuffing the keyboard buffer as appropriate, and finally acknowledging the interrupt and returning from the handler. [ serial port interrupts are now DISABLED ] Optionally the serial port input/output can be replaced with a SMI trigger that calls into an EFI BIOS in order to tie into its own console input and output routines rather than directly hitting the serial port. In this particular case it's assumed that all logging is handled in the EFI module that will be called. BIOS int 15h, ax = 0d042h is used to trigger SMI. The parameters passed will need to be changed to be specific to the EFI or SMI handler put in place. In the example in SMBIOS, for output, ebx = 0xf00d0000 | (char << 8), and for input, ebx = 0xfeed0000, with the character, if any, returned in the eax register with ZF set and eax=0 if no character was available. Summary of new enhancements --------------------------- SGABIOS now keeps a log of the last 256 characters written to the screen and where they were written in the event an application like lilo asks for the current character under the cursor. These are currently stored in a 1KB EBDA allocation which can be expanded as needed. This method avoids having to store a 64KB buffer for the largest possible serial terminal supported (255x255). When lilo 22.6 is detected, SGABIOS now knows how to disable lilo's serial output in favor of its own. This avoids having double character output from both serial and VGABIOS interleaved. Possible future enhancements ---------------------------- Previous future ideas have now been implemented. Known Bugs ---------- With some versions of DOS, only the last character of every line is displayed once dos boots since DOS will use direct access to the VGA framebuffer until the end of line is reached, at which point it will start using int 10h. Dual cursor tracking might fix this issue by maintaining positions for dos that look like the end of line and another for internal use to know where to output next. Caveats ------- It may be possible for someone to construct a terminal reply for the terminal sizing code that is completely invalid and attempts to either setup variables to overrun buffers or else overruns the input buffer itself. This situation is currently handled by limiting the reply to between eight and fourteen characters and ignoring any values outside the range from ten to two hundred fifty-five for both the number of rows and the number of columns. In these situations a default size of 80x24 is used (unless a video card is present, in which case its size is used). If the resize code detects several unexpected characters during the terminal size detection, it currently assumes that someone has left a loopback device plugged into the serial port and redirects the serial input and output to the fourth serial port at 0x2e8. Security considerations ----------------------- None. This is already 16-bit real-mode x86 code. The entire system may be crashed or bent to do anyone's bidding at any time by any other running code outside of SGABIOS. Opensource Plan --------------- This source code was approved for release to the public for use under the Apache License, Version 2.0 on http://code.google.com/p/sgabios Document History ---------------- Date Author Description 2008-02-14 nil fix for release 2007-10-04 nil new features 2007-08-31 nil sga+vga fixes 2007-08-08 nil Initial version $Id$