diff options
Diffstat (limited to 'qemu/roms/sgabios')
-rw-r--r-- | qemu/roms/sgabios/COPYING | 202 | ||||
-rw-r--r-- | qemu/roms/sgabios/Makefile | 78 | ||||
-rw-r--r-- | qemu/roms/sgabios/csum8.c | 64 | ||||
-rw-r--r-- | qemu/roms/sgabios/design.txt | 296 | ||||
-rw-r--r-- | qemu/roms/sgabios/rom16.ld | 133 | ||||
-rw-r--r-- | qemu/roms/sgabios/sgabios.S | 2434 | ||||
-rw-r--r-- | qemu/roms/sgabios/sgabios.h | 76 |
7 files changed, 3283 insertions, 0 deletions
diff --git a/qemu/roms/sgabios/COPYING b/qemu/roms/sgabios/COPYING new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/qemu/roms/sgabios/COPYING @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/qemu/roms/sgabios/Makefile b/qemu/roms/sgabios/Makefile new file mode 100644 index 000000000..970b0ff37 --- /dev/null +++ b/qemu/roms/sgabios/Makefile @@ -0,0 +1,78 @@ +# Copyright 2010 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. +# +# $Id$ + +BUILD_DATE = \"$(shell date -u)\" +BUILD_SHORT_DATE = \"$(shell date -u +%D)\" +BUILD_HOST = \"$(shell hostname)\" +BUILD_USER = \"$(shell whoami)\" + +CFLAGS := -Wall -Os -m32 -nostdlib + +ASFLAGS := $(CFLAGS) +ASFLAGS += -DBUILD_DATE="$(BUILD_DATE)" +ASFLAGS += -DBUILD_SHORT_DATE="$(BUILD_SHORT_DATE)" +ASFLAGS += -DBUILD_HOST="$(BUILD_HOST)" +ASFLAGS += -DBUILD_USER="$(BUILD_USER)" + +LDSCRIPT := rom16.ld +LDFLAGS := -T $(LDSCRIPT) -nostdlib +OBJCOPY := objcopy + +ASRCS = sgabios.S + +CSRCS = + +SRCS = $(CSRCS) $(ASRCS) + +OBJS = ${CSRCS:.c=.o} ${ASRCS:.S=.o} +INCS = ${CSRCS:.c=.h} ${ASRCS:.S=.h} + +PROGS = sgabios.bin csum8 + +.SUFFIXES: .bin .elf +.PHONY: buildinfo + +all: $(PROGS) + +sgabios.bin: sgabios.elf + $(OBJCOPY) -O binary $< $@ + ./csum8 $@ + +sgabios.elf: .depend $(OBJS) $(LDSCRIPT) csum8 + $(LD) $(LDFLAGS) $(OBJS) -o $@ + +csum8: csum8.c + $(CC) -Wall -O2 -o $@ $< + +sgabios.o: buildinfo + + +buildinfo: + touch sgabios.S +clean: + $(RM) $(PROGS) $(OBJS) *.elf *.srec *.com version.h + +.depend:: $(INCS) $(SRCS) Makefile + $(RM) .depend + $(CPP) -M $(CFLAGS) $(SRCS) >.tmpdepend && mv .tmpdepend .depend + +ifeq (.depend, $(wildcard .depend)) +include .depend +else +# if no .depend file existed, add a make clean to the end of building .depend +.depend:: + $(MAKE) clean +endif diff --git a/qemu/roms/sgabios/csum8.c b/qemu/roms/sgabios/csum8.c new file mode 100644 index 000000000..69629139c --- /dev/null +++ b/qemu/roms/sgabios/csum8.c @@ -0,0 +1,64 @@ +/* + * Copyright 2010 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. + * + * compute rom checksum byte + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/types.h> + +#define MAX_SIZE 65536 +unsigned char buf[MAX_SIZE]; + +int main(int argc, char **argv) +{ + ssize_t fsize; + int i, sum, fd; + unsigned char csum; + + if (argc < 2) { + fprintf(stderr, "usage: %s filename\n", argv[0]); + exit(1); + } + if ((fd = open(argv[1], O_RDWR)) < 0) { + perror(argv[1]); + exit(1); + } + if ((fsize = read(fd, buf, MAX_SIZE)) < 0) { + perror(argv[1]); + exit(1); + } + if (fsize >= MAX_SIZE && read(fd, &buf[MAX_SIZE - 1], 1) > 0) { + fprintf(stderr, "FAIL: %s is larger than %d bytes\n", argv[1], MAX_SIZE); + exit(1); + } + i = fsize - 2048 * (fsize / 2048); + if (i != 2047) { + fprintf(stderr, "FAIL: %s is %zd bytes, need 2K pad-1\n", argv[1], fsize); + exit(1); + } + for (i = sum = 0; i < fsize; i++) { + sum += buf[i]; + } + sum &= 0xff; + csum = -sum & 0xff; + write(fd, &csum, 1); + close(fd); + fprintf(stderr, "%s: sum = 0x%02x, wrote byte 0x%02x\n", argv[1], sum, csum); + return 0; +} diff --git a/qemu/roms/sgabios/design.txt b/qemu/roms/sgabios/design.txt new file mode 100644 index 000000000..3af6b8285 --- /dev/null +++ b/qemu/roms/sgabios/design.txt @@ -0,0 +1,296 @@ +============================================= +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 <nil@google.com> +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$ diff --git a/qemu/roms/sgabios/rom16.ld b/qemu/roms/sgabios/rom16.ld new file mode 100644 index 000000000..4eaa12272 --- /dev/null +++ b/qemu/roms/sgabios/rom16.ld @@ -0,0 +1,133 @@ +/* + * Linker script for ROM16 binaries + */ + +/* Script for -z combreloc: combine and sort reloc sections */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", + "elf32-i386") +OUTPUT_ARCH(i386) +EXTERN(_start) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x0; + PROVIDE (__executable_start = .); + + .init : + { + KEEP (*(.init)) + } =0x90909090 + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x90909090 + .fini : + { + KEEP (*(.fini)) + } =0x90909090 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(4); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + PROVIDE (__ctors_start = .); + .ctors : + { + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + PROVIDE (__ctors_end = .); + PROVIDE (__dtors_start = .); + .dtors : + { + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + PROVIDE (__dtors_end = .); + + /* Adjust the address for the data segment. Avoid mixing code and + data within same 128-byte chunk. */ + . = ALIGN(128); + + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + } + .csum : + { + . = ALIGN(2048) - 5; + LONG(0xff4c494e); + /* BYTE(_rom_size_byte); */ + } =0xffffffff + _end = .; + PROVIDE (end = .); + PROVIDE(_rom_size_byte = (511 + end) / 512); + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/qemu/roms/sgabios/sgabios.S b/qemu/roms/sgabios/sgabios.S new file mode 100644 index 000000000..275d063ee --- /dev/null +++ b/qemu/roms/sgabios/sgabios.S @@ -0,0 +1,2434 @@ +/* + * Copyright 2010 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. + */ + +#include "sgabios.h" +#define BUILD_CL "$Id$" + +.code16 +.text + .section ".init","ax" + .globl _start + .type _start,@object +_start: + /* option rom header */ + .byte 0x55 + .byte 0xaa + .byte _rom_size_byte + .size _start, .-_start + + .globl legacy_entry + .type legacy_entry,@function +legacy_entry: + jmp sga_init + /* pnp entry here to avoid changing PnP table as code moves */ +pnp_init: + jmp pnp_sga_init + +/* + * do_old_int10h + * + * Patched at option rom init to be a far jump to old int 10h isr + * + */ +do_old_int10h: + .byte 0xea /* jmp absolute segment:offset */ +old_int10h: /* store what was at offset 0x40 */ + .word 0xf065 /* placeholder for chained ISR offset */ + /* if the chained segment is detected as 0xc000, use 80 cols only */ + /* since it's assumed that a vga card is attached and 80 cols max */ +old_int10h_seg: + .word 0xf000 /* placeholder for chained ISR segment */ +/* + * do_old_int16h + * + * Patched at option rom init to be a far jump to old int 16h isr + * + */ +do_old_int16h: + .byte 0xea /* jmp absolute segment:offset */ +old_int16h: /* store what was at offset 0x58 */ + .word 0xe82e /* placeholder for chained ISR offset */ + .word 0xf000 /* placeholder for chained ISR segment */ +.org 0x18 + .word 0 /* offset to PCI data, 0 = none */ + .word pnp_table /* offset to PnP expansion header */ +.org 0x20 +pnp_table: + /* FIXME: **** PnP header currently disabled by PoO **** */ + /* legacy entry only called once, PnP entry called multiple times */ + /* The code isn't yet written to deal with multiple inits properly */ + .ascii "$PoO" /* PnP expansion header signature */ + .byte 1 /* structure revision */ + .byte 2 /* length in 16-byte increments */ + .word 0 /* offset of next header, 0 if none */ + .byte 0 /* reserved */ + .byte 0x52 /* checksum - update manually! FIXME */ + .long 0 /* device identifier */ + .word mfg_string /* pointer to manufacturer string */ + .word prod_string /* pointer to product name string */ + .byte 3, 0x80, 0x80 /* device type code = other display */ + .byte 0xe3 /* device indicators, kbd/display dev */ + .word 0 /* boot connection vector, 0 if none */ + .word 0 /* disconnect vector, 0 if none */ + .word pnp_init /* bootstrap entry vector */ + .word 0 /* reserved */ + .word 0 /* static resource information vector */ + + /* WARNING: changing mfg_string / prod_string locations will */ + /* affect pnp table above -- recalculate checksum manually! */ +mfg_string: + .asciz "Google, Inc." +prod_string: + .ascii "Serial Graphics Adapter " +build_date: + .asciz BUILD_SHORT_DATE +long_version: + .ascii "SGABIOS " + .ascii BUILD_CL + .ascii " (" + .ascii BUILD_USER + .ascii "@" + .ascii BUILD_HOST + .ascii ") " + .asciz BUILD_DATE +term_cols: + .byte 80 /* overwritten at rom init with detected value */ +term_rows: + .byte 24 /* overwritten at rom init with detected value */ +term_init_string: /* terminal reply: \033[n;mR n=row, m=col */ + .asciz "\033[1;256r\033[256;256H\033[6n" + /* reset the scroll, move to col 256, row 256, ask current position */ + /* bios cursor positions >255 rows or cols can't be used anyway */ +term_info: + .asciz "Term: " +ebda_info: + .asciz "EBDA: " + +/* + * do_old_irq3 - exception 0x0b, int 0x0a + * + * Patched at option rom init to be a far jump to old irq 3 isr + * + */ +do_old_irq3: + .byte 0xea /* jmp absolute segment:offset */ +old_irq3: /* store what was at offset 0x28 */ + .word 0xeef3 /* placeholder for chained ISR offset */ + .word 0xf000 /* placeholder for chained ISR segment */ + +/* + * do_old_irq4 - exception 0x0c, int 0x0b + * + * Patched at option rom init to be a far jump to old irq 4 isr + * + */ +do_old_irq4: + .byte 0xea /* jmp absolute segment:offset */ +old_irq4: /* store what was at offset 0x2c */ + .word 0xeef3 /* placeholder for chained ISR offset */ + .word 0xf000 /* placeholder for chained ISR segment */ + +/* + * do_old_int14h + * + * Patched at option rom init to be a far jump to old int 14h isr + * + */ +do_old_int14h: + .byte 0xea /* jmp absolute segment:offset */ +old_int14h: /* store what was at offset 0x50 */ + .word 0xe739 /* placeholder for chained ISR offset */ + .word 0xf000 /* placeholder for chained ISR segment */ + +.align 16, 0xff /* aligning this table only makes hexdump prettier */ +/* ascii -> scancode, bit 7=shifted, char < 32 = +ctrl */ +/* except chars 8, 9, 13, 27 (bs, tab, enter, esc) */ +/* most int16h consumers will probably never use */ +ascii2scan: +/*00*/ .byte 0x00, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22 +/*08*/ .byte 0x0e, 0x17, 0x24, 0x25, 0x26, 0x1c, 0x31, 0x18 +/*10*/ .byte 0x19, 0x0f, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11 +/*18*/ .byte 0x2d, 0x15, 0x2c, 0x01, 0x2b, 0x1b, 0x87, 0x8c +/*20*/ .byte 0x39, 0x82, 0xa8, 0x84, 0x85, 0x86, 0x88, 0x28 +/*28*/ .byte 0x8a, 0x8b, 0x89, 0x8d, 0x33, 0x0c, 0x34, 0x35 +/*30*/ .byte 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 +/*38*/ .byte 0x09, 0x0a, 0xa7, 0x27, 0xb3, 0x0d, 0x34, 0xb5 +/*40*/ .byte 0x83, 0x9e, 0xb0, 0xae, 0xa0, 0x92, 0xa1, 0xa2 +/*48*/ .byte 0xa3, 0x97, 0xa4, 0xa5, 0xa6, 0xb2, 0xb1, 0x98 +/*50*/ .byte 0x99, 0x90, 0x93, 0x9f, 0x94, 0x96, 0xaf, 0x91 +/*58*/ .byte 0xad, 0x95, 0xac, 0x1a, 0x2b, 0x1b, 0x87, 0x8c +/*60*/ .byte 0x29, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22 +/*68*/ .byte 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18 +/*70*/ .byte 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11 +/*78*/ .byte 0x2d, 0x15, 0x2c, 0x9a, 0xab, 0x9b, 0xa9, 0x0e + +/* TABLES FOR NON-ASCII VGA CHARACTERS (CP437) TO ASCII */ +/* Unicode at: http://en.wikipedia.org/wiki/Code_page_437 */ + +ctrl2ascii: +/* translate vga (CP437) first 32 characters to ascii */ +/* for char 0, update the cursor position, but output nothing */ +/* lilo uses this "trick" for a background attribute update */ + .ascii "\0@@v***........*><|!PS-|^v><L-^v" +high2ascii: +/* translate vga (CP437) chars 0x80 to 0xff to ascii */ +/* these characters are mostly to visually approximate */ +/* line art characters will probably need tweaking */ +/*80*/ .ascii "CueaaaaceeeiiiAAEaAooouuyOUcLYPf" +/*a0*/ .ascii "aiounNao?--24!<>###||||++||+++++" +/*c0*/ .ascii "+--|-+||++--|-+----++++++++#-||-" +/*e0*/ .ascii "abgpesut00osiye^=+><||-=...vn2* " + +colortable: +/* vga text color is IRGB, ansi color is BGR */ +/* this table is effectively a nibble bit-reverse */ + .byte 0, 4, 2, 6, 1, 5, 3, 7 + +serial_port_base_address: + .word COM_BASE_ADDR + +/* in-memory console log + * + * It's expected that the EBDA contains a magic signature + * like 0xdeadbabe, followed by a byte of flags, followed + * by a 32-bit buffer pointer, followed by a 16-bit start + * index, followed by a 16-bit end index, followed by 16- + * bit logged character count, followed by an 8-bit flag. + */ + +#define MEMCONSOLE_BUFFER_SIZE 32768 +#define MEMCONSOLE_SIGNATURE 0xdeadbabe +#define MEMCONSOLE_ENDINDEX_OFF 0x0b +#define SGABIOS_EBDA_SIGNATURE 0x00414753 + +memconsole_buffer_start: /* pulled from ebda struct */ + .long 0x00000000 /* 0 = not found/no logging */ +memconsole_ebda_deadbabe_offset: /* bytes from start of ebda */ + .word 0x0000 /* 40:0e contains ebda seg */ +sgabios_ebda_logbuf_offset: /* bytes from start of ebda */ + .word 0x0000 /* 40:0e contains ebda seg */ + +/* + * setup_memconsole + * + * Initialize the option rom variables associated with logging + * of the legacy console output + * + * If these variables are left at zero, no logging will occur + * + * There are no parameters + * All registers except flags should be preserved + */ + +setup_memconsole: + pushaw + pushw %ds + pushw %es + pushw $BDA_SEG + popw %ds /* ds = 0x40 */ + pushw BDA_EBDA /* push word at 0x0e */ + popw %es /* es = EBDA_SEG */ + /* search for memconsole signature in ebda */ + movl $MEMCONSOLE_SIGNATURE, %eax + xorw %di, %di /* start at zero */ + movzbw %es:(%di), %cx /* cx = size of EBDA in KB */ + shlw $8, %cx /* cx = (cx * 1024) / 4 */ + cld + repnz + scasl /* search until sig found */ + subw $4, %di /* scasl always increments di, undo */ + cmpl %eax, %es:(%di) /* is signature here? */ + jnz setup_memconsole_end /* bail if so */ + movw %di, %cs:memconsole_ebda_deadbabe_offset /* save offset */ + movl %es:5(%di), %eax /* get 32-bit buffer base address */ + movl %eax, %cs:memconsole_buffer_start +setup_memconsole_end: + popw %es + popw %ds + popaw + ret + +/* + * memconsole_log_char + * + * Log the character passed in %al to the next available memory + * console log position, if any. + * + * If memconsole_buffer_start is zero, no logging will occur + * + * %al = character to be logged + * All registers except flags should be preserved + */ + +memconsole_log_char: + pushaw + pushw %ds + pushw %es + pushw %fs + pushw $BDA_SEG + popw %ds /* ds = 0x40 */ + pushw BDA_EBDA /* push word at 0x0e */ + popw %es /* es = EBDA_SEG */ + movw %ax, %si /* %si = %al = byte to write */ + movl %cs:memconsole_buffer_start, %ebp + movw %cs:memconsole_ebda_deadbabe_offset, %di + addw $MEMCONSOLE_ENDINDEX_OFF, %di /* %di points to char pos */ + orl %ebp, %ebp + jz memconsole_log_tail /* bufptr==0, no logging */ + movw %es:(%di), %bx /* bx = current position in buffer */ + cmpw $MEMCONSOLE_BUFFER_SIZE, %bx /* at end of buffer? */ + jnc memconsole_log_tail /* don't log any more if so */ + cmpb $0xd, %al /* is the char CR? */ + jz memconsole_log_tail /* if so, ignore it */ + cmpb $0x8, %al /* is the char backspace? */ + jnz memconsole_update_fsbase /* if not, log char as usual... */ + orw %bx, %bx /* make sure ptr isn't already zero */ + jz memconsole_log_tail /* if so, bail */ + decw %bx /* else point to previous character */ + jmp memconsole_update_end_ptr /* and go directly to save it */ +memconsole_update_fsbase: + movl $0xc0000100, %ecx /* ecx = IA32_FS_BASE (AMD64+) */ + rdmsr /* read what was there before */ + pushl %eax /* save away previous FS_BASE eax */ + pushl %edx /* save away previous FS_BASE edx */ + xorl %edx, %edx /* clear high 32 bits */ + movl %ebp, %eax /* eax = memconsole buffer start */ + wrmsr /* fs_base = memconsole buffer start */ + movw %si, %ax /* %ax = saved value on entry */ + movb %al, %fs:(%bx) /* log character */ + popl %edx /* restore previous FS_BASE edx */ + popl %eax /* restore previous FS_BASE eax */ + wrmsr /* write what was there before */ + incw %bx /* update character count */ +memconsole_update_end_ptr: + movw %bx, %es:(%di) /* save new end pointer */ + addw $2, %di /* numchars stored at next word */ + movw %bx, %es:(%di) /* save new numchar value */ +memconsole_log_tail: + popw %fs + popw %es + popw %ds + popaw + ret + +/* sgabioslog_setup_ebda + * + * SGABIOS makes its own 1KB EBDA allocation to save non- + * translated characters with associated cursor positions + * for the last 256 characters output. This is organized + * with 256 bytes reserved for houskeeping, 256 bytes for + * the raw character codes, and 512 bytes of 16bit cursor + * positions to record the associated position for each. + * + * The first 4 bytes contain "SGA\0" followed by a 16-bit + * size of the allocation in bytes, followed by a 16-bit + * index indicating the next spot to be overwritten. + * + * There are no parameters + * All registers should be preserved + */ + +sgabioslog_setup_ebda: + pushf + pushaw + pushw %ds + pushw %es + pushw $BDA_SEG + popw %ds /* ds = 0x40 */ + movw BDA_EBDA, %ax /* ax = old ebda segment from 0x0e */ + subw $SGABIOS_EBDA_DELTA, %ax + movw %ax, %es /* es = new EBDA segment start */ + cmpw $EBDA_MIN_SEG, %ax /* is there room for the allocation? */ + jc sgabioslog_setup_ebda_tail /* if not, don't change anything */ + cli /* paranoid in case irq uses EBDA */ + movw %ax, BDA_EBDA /* save new EBDA segment start */ + subw $SGABIOS_EBDA_KB, BDA_MEM_SIZE /* subtract extra allocation */ + movw %ax, %ds /* ds = new EBDA segment start */ + movw $SGABIOS_EBDA_BYTES, %si /* si = offset of first byte to move */ + movzbw (%si), %cx /* cx = number of KB in EBDA */ + addb $SGABIOS_EBDA_KB, (%si) /* update EBDA size in kb */ + shlw $10, %cx /* cx = KB * 1024 = bytes in EBDA */ + movw %cx, %cs:sgabios_ebda_logbuf_offset /* new ebda space */ + xorw %di, %di /* di = new EBDA start */ + cld + rep + movsb /* move ebda by SGABIOS_EBDA_BYTES */ + movw %cs:sgabios_ebda_logbuf_offset, %bx /* bx = new buffer */ + movl $SGABIOS_EBDA_SIGNATURE, (%bx) /* setup signature */ + movw $SGABIOS_EBDA_BYTES, 4(%bx) /* bytes in new ebda buffer */ + movw $0, 6(%bx) /* next log index, new ebda buffer */ +sgabioslog_setup_ebda_tail: + popw %es + popw %ds + popaw + popf + ret + +/* + * sgabioslog_save_char + * + * Like memconsole_log_char, except the original, untranslated + * character is expected to be given in the %al register. + * + * The original character and its corresponding cursor position + * are logged to the sgabios ebda memory allocation. + * + * %al = character to be logged + * All registers except flags should be preserved + */ + +sgabioslog_save_char: + pushaw + pushw %ds + pushw %es + pushw $BDA_SEG + popw %ds /* ds = 0x40 */ + pushw BDA_EBDA /* push word at 0x0e */ + popw %es /* es = EBDA_SEG */ + movw %cs:sgabios_ebda_logbuf_offset, %di + orw %di, %di /* is offset zero? */ + jz sgabioslog_save_tail /* if so, bail */ + cmpl $SGABIOS_EBDA_SIGNATURE, %es:(%di) + jnz sgabioslog_save_tail /* bail if magic not found */ + movw %es:6(%di), %bx /* bx = index of next char output */ + movb %al, %es:SGABIOS_EBDA_LOG_START(%bx,%di) /* store character */ + movzbw %bl, %ax /* %ax = next cursor buffer index */ + shlw $1, %ax /* %ax = offset to cursor storage */ + call get_current_cursor /* %dh = row, %dl = column */ + addw $SGABIOS_EBDA_POS_START, %di /* cursor storage */ + addw %ax, %di /* %di = next cursor storage offset */ + movw %dx, %es:(%di) /* save position for logged char */ + incw %bx /* point to next char to log */ + cmpw $SGABIOS_EBDA_LOG_SIZE, %bx + jnz sgabioslog_save_index + xorw %bx, %bx /* wrap around to start */ +sgabioslog_save_index: + movw %cs:sgabios_ebda_logbuf_offset, %di + movw %bx, %es:6(%di) /* save new index */ +sgabioslog_save_tail: + popw %es + popw %ds + popaw + ret + +/* + * sgabioslog_get_char + * + * Return the character at current cursor position, last recorded + * to sgabios ebda allocation, if available. + * + * If the current cursor postition contains one of the last 256 characters + * written to the ebda buffer, return that character, else return 0. + * + * If sgabios_ebdda_logbuf_offset is zero, %al will be 0 and zf set + * + * All registers except flags and %al should be preserved + */ + +sgabioslog_get_char: + pushaw + movw %sp, %bp + movb $0, 14(%bp) /* %al on stack = 0 */ + pushw %ds + pushw %es + pushw $BDA_SEG + popw %ds /* ds = 0x40 */ + pushw BDA_EBDA /* push word at 0x0e */ + popw %es /* es = EBDA_SEG */ + movw %cs:sgabios_ebda_logbuf_offset, %di + orw %di, %di + jz sgabioslog_get_tail /* offset==0, no logging */ + cmpl $SGABIOS_EBDA_SIGNATURE, %es:(%di) + jnz sgabioslog_get_tail /* bail if magic not found */ + call get_current_cursor /* dh = row, dl = col */ + std /* scan backwards in mem */ + movw %es:6(%di), %bx /* bx = index of next char output */ + decw %bx /* %bx = offset of last char in buf */ + jnc sgabioslog_got_pos + addw $SGABIOS_EBDA_LOG_SIZE, %bx /* bx position wrap around */ +sgabioslog_got_pos: + movw %bx, %ax /* %ax = last cursor pos written */ + shlw $1, %ax /* %ax = offset of last cursor pos */ + addw $SGABIOS_EBDA_POS_START, %di /* %di = first cursor position */ + addw %ax, %di /* %di = offset in ebda */ + movw %dx, %ax /* %ax = cursor pos to compare */ + movw %bx, %cx /* %cx = positions before wrap */ + jcxz sgabioslog_cmp_wrap /* if zero, try from end next */ + repnz + scasw /* search until position match */ + addw $2, %di /* scasd always decrements di, undo */ + cmpw %ax, %es:(%di) /* did it really match? */ + jz sgabioslog_cursor_match /* if so, do something */ +sgabioslog_cmp_wrap: + movw %cs:sgabios_ebda_logbuf_offset, %di + addw $SGABIOS_EBDA_POS_LAST, %di /* %di = last cursor storage */ + movw $SGABIOS_EBDA_LOG_SIZE, %cx /* %cx = compare all positions */ + repnz + scasw /* search until position match */ + addw $2, %di /* scasd always decrements di, undo */ + cmpw %ax, %es:(%di) /* did it really match? */ + jnz sgabioslog_get_tail /* if not, bail */ +sgabioslog_cursor_match: + /* %di contains the EBDA offset of the matching position */ + /* convert this into a memconsole offset */ + subw $512, %di /* take off the storage offset */ + subw %cs:sgabios_ebda_logbuf_offset, %di /* and ebda offset */ + shrw $1, %di /* %di = char position index */ + addw %cs:sgabios_ebda_logbuf_offset, %di /* add back ebda offset */ + addw $SGABIOS_EBDA_LOG_START, %di /* and add back log offset */ + movb %es:(%di), %al /* get related saved character */ + movb %al, 14(%bp) /* %al on stack = logged char */ +sgabioslog_get_tail: + popw %es + popw %ds + popaw + ret + +/* + * multibyteinput + * + * When an escape key is detected, the input routines will attempt to + * capture as many characters as arrive up until a timeout, or six, + * whichever is less. + * + * This table is intended to decide what the characters after the + * initial escape key translate to in terms of high and low bytes + * that go into the keyboard buffer the high byte is the scancode, + * the low byte is ascii, but for special keys this is usually 0xe0 + * or 0x00. + * + * This table is formatted so that the first word is a scancode + + * ascii pair (as returned by int 16h, ah = 10h or 11h). Immediately + * following is a nul-terminated ascii string to match in order to + * use the corresponding scancode+ascii word. + * + * The search through this table is terminated by a match or finding + * a 0 scancode+ascii word. + * + * FIXME: all the low bytes are now zero, get rid of them? + */ +multibyteinput: + .byte 0x3b /* F1 */ + .asciz "[[A" /* F1/screen */ + + .byte 0x3b /* F1 */ + .asciz "OP" /* F1/xterm/ansi */ + + .byte 0x3b /* F1 */ + .asciz "[11~" /* F1/vt400 */ + + .byte 0x3c /* F2 */ + .asciz "[[B" /* F2/screen */ + + .byte 0x3c /* F2 */ + .asciz "OQ" /* F2/xterm/ansi */ + + .byte 0x3c /* F2 */ + .asciz "[12~" /* F2/vt400 */ + + .byte 0x3d /* F3 */ + .asciz "[[C" /* F3/screen */ + + .byte 0x3d /* F3 */ + .asciz "OR" /* F3/xterm/ansi */ + + .byte 0x3d /* F3 */ + .asciz "[13~" /* F3/vt400 */ + + .byte 0x3e /* F4 */ + .asciz "[[D" /* F4/screen */ + + .byte 0x3e /* F4 */ + .asciz "OS" /* F4/xterm/ansi */ + + .byte 0x3e /* F4 */ + .asciz "[14~" /* F4/vt400 */ + + .byte 0x3f /* F5 */ + .asciz "[[E" /* F5/screen */ + + .byte 0x3f /* F5 */ + .asciz "[15~" /* F5/xterm */ + + .byte 0x3f /* F5 */ + .asciz "OT" /* F5/ansi */ + + .byte 0x40 /* F6 */ + .asciz "[17~" /* F6/screen/vt220/xterm/vt400 */ + + .byte 0x40 /* F6 */ + .asciz "OU" /* F6/ansi */ + + .byte 0x41 /* F7 */ + .asciz "[18~" /* F7/screen/vt220/xterm/vt400 */ + + .byte 0x41 /* F7 */ + .asciz "OV" /* F7/ansi */ + + .byte 0x42 /* F8 */ + .asciz "[19~" /* F8/screen/vt220/xterm/vt400 */ + + .byte 0x42 /* F8 */ + .asciz "OW" /* F8/ansi */ + + .byte 0x43 /* F9 */ + .asciz "[20~" /* F9/screen/vt220/xterm/vt400 */ + + .byte 0x43 /* F9 */ + .asciz "OX" /* F9/ansi */ + + .byte 0x44 /* F10 */ + .asciz "[21~" /* F10/screen/vt220/xterm/vt400 */ + + .byte 0x44 /* F10 */ + .asciz "OY" /* F10/ansi */ + + .byte 0x85 /* F11 */ + .asciz "[23~" /* F11/screen/xterm/vt400 */ + + .byte 0x85 /* F11 */ + .asciz "OZ" /* F11/ansi */ + + .byte 0x86 /* F12 */ + .asciz "[24~" /* F12/screen/xterm/vt400 */ + + .byte 0x52 /* Insert */ + .asciz "[2~" /* Insert/screen/vt102/xterm */ + + .byte 0x53 /* Delete */ + .asciz "[3~" /* Delete/screen/vt102/xterm */ + + .byte 0x4b /* Left */ + .asciz "OD" /* Left/screen/vt102 */ + + .byte 0x4b /* Left */ + .asciz "[D" /* Left/xterm */ + + .byte 0x47 /* Home */ + .asciz "[1~" /* Home/screen/vt102 */ + + .byte 0x47 /* Home */ + .asciz "[H" /* Home/xterm */ + + .byte 0x4f /* End */ + .asciz "[4~" /* End/screen/vt102 */ + + .byte 0x4f /* End */ + .asciz "[F" /* End/xterm */ + + .byte 0x48 /* Up */ + .asciz "OA" /* Up/screen/vt102 app */ + + .byte 0x48 /* Up */ + .asciz "[A" /* Up/xterm/vt102 ansi */ + + .byte 0x50 /* Down */ + .asciz "OB" /* Down/screen/vt102 app */ + + .byte 0x50 /* Down */ + .asciz "[B" /* Down/xterm/vt102 ansi */ + + .byte 0x49 /* PageUp */ + .asciz "[5~" /* PageUp/screen/vt102/xterm */ + + .byte 0x51 /* PageDown */ + .asciz "[6~" /* PageDown/screen/vt102/xterm */ + + .byte 0x4d /* Right */ + .asciz "OC" /* Right/screen/vt102 app */ + + .byte 0x4d /* Right */ + .asciz "[C" /* Right/xterm/vt102 ansi */ + + .byte 0 /* end of table marker */ + +/* init_serial_port + * + * Initialize serial port to 115200,8n1 + * Serial interrupts disabled + * + * All registers except flags preserved + */ + +init_serial_port: + pushw %ax + pushw %dx + pushw %bx + movw %cs:serial_port_base_address, %dx + addw $IER_OFFSET, %dx + xorb %al, %al + outb %al, %dx /* disable all serial interrupts */ + addw $(LCR_OFFSET - IER_OFFSET), %dx /* LCR */ + movb $(LCR_VALUE|LCR_DLAB), %al + outb %al, %dx /* enable divisor access */ + movw %cs:serial_port_base_address, %dx + movw $(PORT_DIVISOR/PORT_SPEED), %bx + movb %bl, %al /* al = lsb of divisor */ + outb %al, %dx /* set divisor latch lsb */ + movb %bh, %al /* al = msb of divisor */ + incw %dx + outb %al, %dx /* set divisor latch msb */ + movw %cs:serial_port_base_address, %dx + addw $LCR_OFFSET, %dx + movb $LCR_VALUE, %al + outb %al, %dx /* disable divisor access */ + addw $(MCR_OFFSET - LCR_OFFSET), %dx /* MCR */ + movb $MCR_DTRRTS, %al + outb %al, %dx /* enable DTR + RTS */ + movw %cs:serial_port_base_address, %dx + addw $FCR_OFFSET, %dx + movb $FCR_FIFO_ENABLE, %al + outb %al, %dx /* enable FIFOs */ + popw %bx + popw %dx + popw %ax + ret + + +/* get_serial_lsr + * + * return serial line status register in %al + * return offset to serial port line status register io port in %dx + * all other registers except flags unchanged + * + * if status == 0xff return ZF=1, else return ZF=0 + */ + +get_serial_lsr: + movw %cs:serial_port_base_address, %dx + addw $LSR_OFFSET, %dx + inb %dx, %al + cmpb $0xff, %al + ret + +/* + * get_byte + * + * get serial byte in %al, scancode in %ah [FIXME: EFI console input] + * + * all registers except %ax preserved + * + */ + +get_byte: + pushw %dx + pushw %bx +next_serial_char: + call get_serial_lsr /* get serial lsr in %al */ + jz get_byte_tail /* no port present... */ + testb $1, %al /* bit 0 of LSR = 1 = data available */ + jz get_byte_tail /* no input waiting */ + /* new character found on serial port */ + /* convert it to a scancode */ + movw %cs:serial_port_base_address, %dx + inb %dx, %al /* al = serial input char */ + testb $0x80, %al /* non-ascii char received? */ + jnz next_serial_char /* throw char away */ + movb %al, %dl /* dl = character read */ + pushw %ds + pushw %cs + popw %ds /* ds = cs */ + movw $ascii2scan, %bx /* table to translate ascii->scan */ + xlatb /* translate char to scancode */ + popw %ds + /* shift status is ignored at this point, may be used later */ + andb $0x7f, %al /* strip shift status from table */ + movb %al, %ah /* scancode goes in high byte */ + movb %dl, %al /* "translated" ascii in lower byte */ + cmpb $0x7f, %al /* Did the user transmit ascii DEL? */ + jnz get_byte_not_del /* if not, don't do anything to al */ + movb $0x08, %al /* else delete becomes backspace */ +get_byte_not_del: + testw %ax, %ax /* clear zero flag */ +get_byte_tail: + popw %bx + popw %dx + ret + +/* + * poll_byte + * + * get serial byte in %al, scancode in %ah [FIXME: EFI console input] + * retry up to 65536 times for an expected input byte + * + * all registers except %ax preserved + * + */ + +poll_byte: + pushw %cx + xorw %cx, %cx +poll_byte_retry: + inb $0xed, %al + call get_byte + loopz poll_byte_retry /* repeat while zf set or cx != 0 */ + popw %cx + ret + +/* + * get_multibyte + * + * after an escape character, poll for terminal keys that generate + * an escape code plus multiple bytes (up to four). + * + * if no byte is waiting, all registers preserved except flags + * if more bytes are waiting, all registers preserved except %ax and flags + * + */ +get_multibyte: + pushw %bp /* bp points to temp buffer on stack */ + pushw %bx /* bx points to multibyteinput table */ + pushw %cx /* cx will count chars */ + pushw %ax /* ax will receive chars */ + pushl $0 /* make space on stack for 4 chars */ + xorw %cx, %cx /* cx = 0 */ + movw %sp, %bp /* point bp at temp data */ + call poll_byte /* is a character waiting? */ + jz get_multibyte_tail /* if not, bail */ +get_multibyte_store: + movb %al, (%bp) /* store char received */ + incb %cl /* mark one char received */ + incw %bp /* point to next char */ + cmpb $4, %cl /* got enough chars? */ + jz got_multibyte /* no strings longer than 4 chars */ + call poll_byte /* is another char waiting? */ + jnz get_multibyte_store /* store a new one if it's there */ +got_multibyte: + movw $multibyteinput, %bx /* point to first scancode */ +got_multibyte_findkey: + movw %sp, %bp /* bp = start of buffer */ + movb %cs:(%bx), %ah /* ah = scancode */ + incw %bx /* bx = start of test string */ + orb %ah, %ah /* is it zero? */ + jz get_multibyte_tail /* if so, bail, key not found */ +got_multibyte_nextchar: + movb %cs:(%bx), %ch /* ch = test char to compare */ + incw %bx /* point to next char */ + orb %ch, %ch /* is char to compare NUL? */ + jz got_multibyte_key /* matched to end of a string! */ + cmpb %ch, (%bp) /* input tmp buf equal to test char? */ + jnz got_multibyte_try_next_key + /* note: expected that test string will be nul before input string */ + /* no attempt is made to ensure no more than 4 bytes stack read */ + incw %bp /* point to next input */ + jmp got_multibyte_nextchar +got_multibyte_try_next_key: /* align to next scancode/ascii pair */ + movb %cs:(%bx), %ch /* ch = test char to compare */ + incw %bx /* point to next char */ + orb %ch, %ch /* is char to compare NUL? */ + jnz got_multibyte_try_next_key + jmp got_multibyte_findkey +got_multibyte_key: + xorb %al, %al /* ascii value = 0 for special keys */ + movw %sp, %bp + movw %ax, 4(%bp) /* overwrite old %ax value with key */ +get_multibyte_tail: + addw $4, %sp /* pop temp space */ + popw %ax + popw %cx + popw %bx + popw %bp + ret + +/* + * send_byte + * + * send character in %al to serial port [FIXME: EFI console out] + * + * all registers preserved except flags + * + */ + +send_byte: + pushw %ax + pushw %dx + pushw %cx + testb $0x80, %al /* don't send non-ascii chars */ + jnz send_tail /* these should be translated earlier */ + movb %al, %ah /* save char to output in %ah */ + movw $0xFFF0, %cx /* only retry 65520 times */ +serial_ready_test: + call get_serial_lsr /* get serial lsr in %al */ + testb $TRANSMIT_READY_BIT, %al + loopz serial_ready_test /* if !tx ready, loop while cx!=0 */ + movb %ah, %al + movw %cs:serial_port_base_address, %dx + outb %al, %dx +send_tail: + popw %cx + popw %dx + popw %ax + ret + +/* + * translate_char + * + * translate vga character in %al to ascii + * + * returns: + * al = translated character + * + * all registers except %al preserved + * + */ + +translate_char: + pushw %bx + pushw %ds + pushw %cs + popw %ds /* ds = cs */ + testb $0x80, %al + jz translate_char_ctrl + andb $0x7f, %al + movw $high2ascii, %bx + xlatb +translate_char_ctrl: + cmpb $0x20, %al + jnc translate_char_tail + movw $ctrl2ascii, %bx + xlatb +translate_char_tail: + popw %ds + popw %bx + ret + +/* + * translate_char_tty + * + * translate vga character in %al to ascii + * unless %al == 7, 8, 10, or 13 (bell, bs, lf, cr) + * + * returns: + * al = translated character + * + * all registers except %al preserved + * + */ + +translate_char_tty: + cmpb $0x07, %al /* bell */ + jz translate_char_tty_tail + cmpb $0x08, %al /* backspace */ + jz translate_char_tty_tail + cmpb $0x0a, %al /* LF */ + jz translate_char_tty_tail + cmpb $0x0d, %al /* CR */ + jz translate_char_tty_tail + call translate_char +translate_char_tty_tail: + ret + +/* + * send_char + * + * send character 0 - 255 in %al out through serial port + * increment cursor position without control processing + * + * send_byte is used for data that isn't tracked + * + * send_char is used for text that should be tracked + * send_char outputs all characters as non-control chars + * + * returns: + * al = translated character + * + * all registers except %al preserved + * + */ + +send_char: + call sgabioslog_save_char /* save original char+pos */ + call translate_char + jmp send_char_tty_out + /* after ctrl translation, same as send_char_tty */ + +/* + * send_char_tty + * + * send character 0 - 255 in %al out through serial port + * increment cursor position *with* control processing + * for bell, linefeed, cr, and backspace (others all printable) + * + * send_byte is used for data that isn't tracked + * + * send_char_tty is used for text that should be tracked + * + * returns: + * al = translated character + * + * all registers except %al preserved + * + */ + + +/* send character 0 - 255 in %al out through serial port */ +/* increment cursor position with CR/LF/Backspace processing */ +send_char_tty: + call sgabioslog_save_char /* save original char+pos */ + call translate_char_tty +send_char_tty_out: + pushw %dx + call update_serial_cursor + call get_current_cursor /* vga cursor in %dx */ + cmpb $0x0d, %al /* CR */ + jnz send_char_tty_nul /* if not CR, check for NUL */ + orb %dl, %dl /* already at col 0? */ + jz send_char_tty_tail /* no need to re-send CR */ +send_char_tty_nul: + orb %al, %al /* %al == 0 ? (nul) */ + /* more than likely, we have NUL at this point because the caller */ + /* tried to read a char using int $0x10, %ah=8, and is trying */ + /* to re-output it with different attributes - for now send nothing */ + jz send_char_tty_tail +send_char_tty_write: + call memconsole_log_char /* log character sent */ + call send_byte + cmpb $0x07, %al /* bell */ + jz send_char_tty_tail /* no cursor update for bell */ + cmpb $0x08, %al /* backspace */ + jz send_char_tty_backspace + cmpb $0x0a, %al /* LF */ + jz send_char_tty_lf + cmpb $0x0d, %al /* CR */ + jz send_char_tty_cr + incb %dl + jmp send_char_tty_tail +send_char_tty_backspace: + orb %dl, %dl + jz send_char_tty_tail + decb %dl + jmp send_char_tty_tail +send_char_tty_lf: + incb %dh + jmp send_char_tty_tail +send_char_tty_cr: + xorb %dl, %dl +send_char_tty_tail: + cmpb %cs:term_cols, %dl + jc send_char_tty_check_rows + movb %cs:term_cols, %dl + decb %dl /* dl = cols - 1 */ +send_char_tty_check_rows: + cmpb %cs:term_rows, %dh + jc send_char_tty_save_cursor + movb %cs:term_rows, %dh + decb %dh /* dh = rows - 1 */ +send_char_tty_save_cursor: + call set_current_cursor + pushw %ds + pushw $BDA_SEG + popw %ds + /* save current position as the serial terminal position */ + /* since a character was just output at that position */ + movw %dx, BDA_SERIAL_POS + popw %ds + popw %dx + ret + +/* + * send_asciz_out + * + * send nul terminated string pointed to by %ds:%si + * to serial port without text tracking + * + * indended to be used for multi-byte send_byte + * + * all registers preserved except flags + */ + +send_asciz_out: + pushw %ax + pushw %si + cld +send_asciz_loop: + lodsb + test %al,%al + jz send_asciz_end + call send_byte + jmp send_asciz_loop +send_asciz_end: + popw %si + popw %ax + ret + +/* + * send_string + * + * send cx chars in string pointed to by %ds:%si + * to serial port with tty tracking + * + * indended to be used for multi-byte send_char_tty + * + * all registers preserved except flags + */ + +send_string: + pushw %ax + pushw %si + cld +send_string_loop: + lodsb + call send_char_tty + loop send_string_loop + popw %si + popw %ax + ret + +/* + * send_string + * + * send cx chars in string pointed to by %ds:%si + * with interleaved attribute data + * + * indended to be used for multi-byte send_char_tty + * with interleaved vga attribute updates + * + * all registers preserved except flags + */ + +send_attr_string: + pushw %ax + pushw %bx + pushw %si + cld +send_attr_string_loop: + lodsb + call send_char_tty + lodsb + movb %al, %bl + call send_attribute /* send attribute in %bl */ + loop send_attr_string_loop + popw %si + popw %bx + popw %ax + ret + +/* + * send_number + * + * send ascii version of number in %al to serial port + * + * intended for ansi cursor positions and attributes, + * so cursor position is not tracked/updated + * + * all registers preserved except flags + */ + +send_number: + pushw %ax + pushw %bx + aam /* ah = al/10, al = al mod 10 */ + movw %ax, %bx /* bh = al/10, bl = al mod 10 */ + movb %bh, %al + aam /* ah = bh/10, al = bh mod 10 */ + movb %al, %bh /* bh = 10s digit, bl = 1s digit */ + movb %ah, %al /* ah = al = 100s digit */ + testb %al, %al /* is there a 100s digit? */ + jz send_tens /* move to tens if not */ + orb $0x30, %al /* al = ascii value of digit */ + call send_byte +send_tens: + orb %bh, %ah /* bh = 10s, ah = 100s digits */ + jz send_ones /* non-zero = must send tens */ + movb %bh, %al /* al = bh = 10s digit */ + orb $0x30, %al /* al = ascii value of digit */ + call send_byte +send_ones: + movb %bl, %al /* al = bl = 1s digit */ + orb $0x30, %al /* al = ascii value of digit */ + call send_byte + popw %bx + popw %ax + ret + +/* + * send_crlf + * + * send CRLF to serial port + * + * FIXME: used at vga init and for scrolling terminal + * so position is not tracked. Callers of this routine + * predate the code that does smart tty/cursor output. + * + * Callers should probably be changed to use those + * routines or send_crlf changed to use them and + * terminal scrolling fixed to use linefeed only. + * + * all registers preserved except flags + */ + +send_crlf: + pushw %ax + movb $0x0d, %al + call send_byte + movb $0x0a, %al + call send_byte + popw %ax + ret +/* + * send_ansi_csi + * + * send ESCAPE [ to serial port + * + * output is not tracked since these are control sequences + * + * all registers preserved except flags + */ + +send_ansi_csi: /* transmit ESC [ */ + pushw %ax + movb $0x1b, %al /* escape */ + call send_byte + movb $0x5b, %al /* [ */ + call send_byte + popw %ax + ret +/* + * send_ansi_csi_2num + * + * send ESC [ %dh ; %dl to serial port + * + * since both position and attribute updates generally have + * two parameters, this function converts values in dx to + * two ascii numbers. It's expected that the caller will + * output the final trailing H or m or whatever is required. + * + * output is not tracked since these are control sequences + * + * all registers preserved except flags + */ + +send_ansi_csi_2num: +/* send ESC [ %dh ; %dl */ + pushw %ax + call send_ansi_csi /* esc [ */ + movb %dh, %al + call send_number + movb $0x3b, %al /* semicolon */ + call send_byte + movb %dl, %al + call send_number + popw %ax + ret + +/* + * send_ansi_cursor_pos + * + * send ESC [ %dh+1 ; %dl+1 to serial port to position + * cursor + * + * since both position and attribute updates generally have + * two parameters, this function converts values in dx to + * two ascii numbers, after adding 1 to both dh and dl. + * + * output is not tracked since this is a control sequence + * + * all registers preserved except flags + */ + +send_ansi_cursor_pos: + pushw %ax + pushw %dx + addw $0x0101, %dx /* dh += 1, dl += 1 */ + call send_ansi_csi_2num /* send esc [ %dh+1;%dl+1 */ + movb $0x48, %al /* H */ + call send_byte + popw %dx + popw %ax + ret + +/* + * send_attribute + * + * send ansi attribute change ESC [ 4x ; 3y ; (1|22)m + * if the attribute has changed since last sent (stored in bda) + * + * output is not tracked since this is a control sequence + * + * all registers preserved except flags + */ + +send_attribute: + andb $0x7f, %bl /* ansi has no bright bg */ + pushw %ds + pushw %es + pushw %ax + pushw %bx + pushw %dx + pushw $BDA_SEG + popw %es /* es = 0x40 */ + pushw %cs + popw %ds /* ds = cs */ + cmpb %es:BDA_COLOR_VAL, %bl + jz send_attribute_tail + cmpb $0x07, %bl /* is it white on black? */ + jnz send_attribute_color + /* for white on black, send esc [ m */ + call send_ansi_csi + jmp send_attribute_m /* send the m, return */ +send_attribute_color: + movb %bl, %ah /* ah = attribute */ + movw $colortable, %bx + movb %ah, %al + andb $7, %al /* al = fg attr */ + xlatb /* al = fg ansi num */ + movb %al, %dl /* dl = fg ansi num */ + movb %ah, %al + shrb $4, %al /* al = bg attr */ + xlatb /* al = bg ansi num */ + movb %al, %dh /* dh = bg ansi num */ + addw $0x281e, %dx /* 3x=setfg, 4x=setbg */ + call send_ansi_csi_2num + movb $0x3b, %al /* semicolon */ + call send_byte + shlb $4, %ah /* bright text? */ + sets %al /* if bit 7, al = 1 */ + js send_attribute_intensity + movb $22, %al /* 22 = normal intensity */ +send_attribute_intensity: + call send_number /* either 22 or 1 */ +send_attribute_m: + movb $0x6d, %al /* m */ + call send_byte +send_attribute_tail: + popw %dx + popw %bx + /* mark attribute in %bl the current one */ + movb %bl, %es:BDA_COLOR_VAL + popw %ax + popw %es + popw %ds + ret + +/* + * serial_get_input + * + * common code for both interrupt-driven and non-interrupt + * driven serial input. Called only when LSR bit 1 is set. + * + * No parameters, no return values + * + * Preserves all registers + */ + +serial_get_input: + pushf + /* be paranoid about int 9h happening during update */ + cli + pushaw + pushw %ds + /* next char input buffer is at 0x40:0x1c */ + pushw $BDA_SEG + popw %ds /* es = 0x40 */ + call get_byte /* next scancode/byte in %ax */ + cmpb $0x1b, %al /* look for escape */ + jnz serial_gotkey /* not escape, don't look for more bytes */ + call get_multibyte /* look for any chars after escape */ +serial_gotkey: + movw KBD_TAIL, %bx /* bx = keyboard tail pointer */ + movw %ax, (%bx) /* store key in buffer */ + addw $2, %bx /* point to next location */ + cmpw $KBD_BUF_END, %bx /* did the buffer wrap? */ + jb kbd_buf_no_wrap + movw $KBD_BUF_START, %bx +kbd_buf_no_wrap: + movw %bx, KBD_TAIL /* update tail pointer to show key */ + popw %ds + popaw + popf + ret + +/* + * irq3_isr + * + * entry point for irq 3 / int 0x0b / exception 11 + * + * Called when COM2 or COM4 have characters pending + * + * The segment not present exception should never happen + * in real mode 16-bit code like this, but just to be safe, + * if this interrupt is invoked and no characters are + * pending on the port found in serial_port_base_address, + * this routine will chain to the original handler. + * + * If characters are found pending, they will be processed + * and control returned via iret. + */ + +irq3_isr: +#if 0 + pushw %ax + pushw %dx + /* placeholder, this shouldn't ever happen */ + /* no interrupts are configured outside COM1 */ + call get_serial_lsr /* get serial lsr in %al */ + jz chain_irq3 /* no port present... */ + testb $1, %al /* bit 0 of LSR = 1 = data available */ + jz chain_irq3 /* no input waiting */ + call serial_get_input /* get input and stuff kbd buffer */ + movb $0x20, %al + outb %al, $0x20 /* send non-specific EOI */ + popw %dx + popw %ax + iret +chain_irq3: + popw %dx + popw %ax +#endif + jmp do_old_irq3 + +/* + * irq4_isr + * + * entry point for irq 4 / int 0x0c / exception 12 + * + * Called when COM1 or COM3 have characters pending + * + * The stack fault exception may occur if code attempts to + * read from sp:0xffff, so if this interrupt is invoked and + * no characters are pending on the port found in + * serial_port_base_address, this routine will chain to the + * original handler. + * + * If characters are found pending, they will be processed + * and control returned via iret. + */ + +irq4_isr: +#if 0 + pushw %ax + pushw %dx + call get_serial_lsr /* get serial lsr in %al */ + jz chain_irq4 /* no port present... */ + testb $1, %al /* bit 0 of LSR = 1 = data available */ + jz chain_irq4 /* no input waiting */ + call serial_get_input /* get input and stuff kbd buffer */ + movb $0x20, %al + outb %al, $0x20 /* send non-specific EOI */ + popw %dx + popw %ax + iret +chain_irq4: + popw %dx + popw %ax +#endif + jmp do_old_irq4 + +/* + * int14h_isr + * + * entry point for int 14h + * + */ +int14h_isr: + pushaw + movw %sp, %bp + addw $16, %bp /* bp points to return address */ + orb %ah, %ah /* fn 0x00, initialize port */ + jz int14h_init_port + cmpb $0x04, %ah /* fn 0x04, extended intialize */ + jnz chain_isr14h +int14h_init_port: + /* check for init port = current port */ + pushw %ds + pushw $BDA_SEG + popw %ds /* ds = 0x40 */ + movw %dx, %bx /* bx = port number */ + shlw $1, %bx /* bx = port number * 2 */ + andw $7, %bx /* bx = bda offset of serial io addr */ + movw (%bx), %cx /* cx = io address of port to init */ + popw %ds /* restore original ds */ + cmpw %cx, %cs:serial_port_base_address + jnz chain_isr14h /* if different, don't get in the way */ + /* init port == current port */ + pushw %ds + /* LILO 22.6 HACK STARTS HERE */ + movw (%bp), %bx /* return address for int 14h call */ + movw 2(%bp), %ds /* return segment for int 14h call */ + cmpl $0x4f4c494c, 0x06 /* does segment have lilo signature? */ + jnz int14h_init_tail /* not lilo, bail on hack */ + cmpw $0x0616, 0x0a /* does version match lilo 22.6? */ + jnz int14h_init_tail /* unknown lilo release, bail on hack */ + movb $0, 0x12 /* set lilo com port = 0 */ + movl $0x90c3585a, (%bx) /* return code= pop dx;pop ax;ret;nop */ + /* now lilo 22.6's own serial out is permanently disabled */ + /* this prevents double-character output from int10h + serial */ + /* this also prevents lilo from stealing serial input chars */ + /* END LILO 22.6 HACK */ +int14h_init_tail: + popw %ds + popaw + pushw %dx /* get_serial_lsr trashes %dx */ + call get_serial_lsr /* return serial status in %al */ + xorb %ah, %ah /* return serial status in %ax */ + popw %dx /* restore %dx */ + iret +chain_isr14h: + popaw + jmp do_old_int14h + +/* + * int16h_isr + * + * entry point for int 16h + * + * keyboard characters are usually retrieved by calling + * int 16h, generally placed in the keyboard buffer by + * irq 1 (int 9h). Poll serial port for new data before + * chaining to int 16h to fake irq 1 behavior + * + * all registers preserved except flags (later iret will restore) + * bda updated with a new keypress if available + * + * FIXME: handle multi-byte keypresses like cursor up/down + * to send proper scancodes for navigating lilo menus + */ + +int16h_isr: + pushw %ax + pushw %dx + /* each time int 16h is invoked, fake an int 9h */ + /* except read the serial input buffer */ + /* then chain to the original int 16h for processing */ + call get_serial_lsr + jz chain_isr16h /* no port present... */ + testb $1, %al /* bit 0 of LSR = 1 = data available */ + jz chain_isr16h /* no input waiting */ + call serial_get_input /* get input and stuff kbd buffer */ + /* for now, leave remaining chars pending in serial fifo */ + /* int 16h callers only get one char at a time anyway */ +chain_isr16h: + popw %dx + popw %ax + jmp do_old_int16h + +/* + * update serial_cursor + * + * figure out where the cursor was, and where it's going + * use the minimal amount of serial output to get it there + * input: vga cursor and serial cursor positions stored in BDA + * + * all registers preserved except flags + * bda updated with new position for serial console cursor + */ +update_serial_cursor: + pushw %ax + pushw %bx + pushw %dx + pushw %ds + pushw $BDA_SEG + popw %ds /* ds = 0x40 */ + call get_current_cursor /* dh = row, dl = col */ + movw BDA_SERIAL_POS, %bx /* bh = row, bl = col */ + subb %dl, %bl /* -col update */ + negb %bl /* col update */ + subb %dh, %bh /* -row update */ + negb %bh /* row update */ + /* handle a few special movement cases */ + /* cr, lf, bs, bs+bs, space, else send full ansi position */ + orb %dl, %dl /* column zero? */ + jnz update_serial_cursor_lf + movb $0x0d, %al /* CR */ + call send_byte + xorb %bl, %bl /* mark no diff in col */ +update_serial_cursor_lf: + cmpb $1, %bh /* +1 row? */ + jnz update_serial_cursor_bs + movb $0x0a, %al /* LF */ + call send_byte + xorb %bh, %bh /* mark no diff in row */ +update_serial_cursor_bs: + cmpb $-1, %bl /* one char back */ + jz update_serial_cursor_one_bs + cmpb $-2, %bl /* two chars back */ + jnz update_serial_cursor_space /* check for space */ + movb $0x08, %al /* BS */ + call send_byte +update_serial_cursor_one_bs: + movb $0x08, %al /* BS */ + call send_byte + xorb %bl, %bl /* mark no diff in col */ +update_serial_cursor_space: + cmpb $1, %bl /* one char forward */ + jnz update_serial_cursor_up + movb $0x20, %al /* space */ + call send_byte + xorb %bl, %bl /* mark no diff in col */ +update_serial_cursor_up: + cmpb $-1, %bh /* -1 row? */ + jnz update_serial_cursor_full /* do full ansi pos update */ + call send_ansi_csi /* send ESC [ A (cursor up) */ + movb $0x41, %al /* A */ + call send_byte + xorb %bh, %bh /* mark no diff in row */ +update_serial_cursor_full: + orw %bx, %bx /* diff = 0? */ + jz update_serial_cursor_done + call send_ansi_cursor_pos /* set cursor pos from dh,dl */ +update_serial_cursor_done: + movw %dx, BDA_SERIAL_POS + popw %ds + popw %dx + popw %bx + popw %ax + ret + +/* + * write_teletype + * + * handle int 10h, function 0eh + * + * ah = 0x0e write teletype character + * al = character ascii code + * bh = display page number + * + * all registers except %al preserved + * caller will restore all registers + */ + +write_teletype: + pushw %bx + movb $0x07, %bl /* black bg, white fg */ + call send_attribute + popw %bx + call send_char_tty + ret + +/* + * write_attr_char + * + * handle int 10h, function 09h + * + * ah = 0x09 write attribute/character at current cursor position + * al = character ascii code + * bh = display page number + * bl = character attribute + * cx = repetition count + * + * does not update cursor position + * all registers except %cx and %al preserved + * caller will restore all registers + */ + +write_attr_char: + call send_attribute /* send attribute in %bl */ + jmp write_char_common + +/* + * write_char + * + * handle int 10h, function 0ah + * + * ah = 0x0a write character at current cursor position + * al = character ascii code + * bh = display page number + * cx = repetition count + * + * does not update cursor position + * all registers except %cx and %al preserved + * caller will restore all registers + */ + +write_char: + pushw %bx + movb $0x07, %bl /* black bg, white fg */ + call send_attribute + popw %bx +write_char_common: + call get_current_cursor + call send_char + /* make cx=0 and cx=1 only output one char */ + cmpw $1, %cx + jbe write_char_tail + decw %cx + jmp write_char +write_char_tail: + /* put cursor back where it was on entry */ + call set_current_cursor + ret + +/* + * write_string + * + * handle int 10h, function 13h + * + * ah = 0x13 write character at current cursor position + * al = 0, data = char, ..., no cursor update + * al = 1, data = char, ..., cursor at end of string + * al = 2, data = char+attr, ..., no cursor update + * al = 3, data = char+attr, ..., cursor at end of string + * bh = display page number + * bl = character attribute for all chars (if al = 0 or 1) + * cx = characters in string (attributes don't count) + * dh = cursor row start + * dl = cursor column start + * es:bp = pointer to source text string in memory + * + * all registers preserved except flags + * caller will restore all registers + */ +write_string: + call set_cursor_position + pushw %ds + pushw %es + pushw %es + popw %ds /* ds = es */ + movw %bp, %si /* si = bp */ + testb $2, %al + jnz write_attr_string + call send_attribute /* send attribute in %bl */ + test %cx, %cx + jz write_string_empty + call send_string /* plaintext out */ +write_string_empty: + jmp write_string_update_cursor +write_attr_string: + call send_attr_string /* text+attrib out */ +write_string_update_cursor: + testb $1, %al /* cursor update? */ + jnz write_string_tail /* yes? already happened */ + /* restore entry cursor position if no update */ + call set_cursor_position +write_string_tail: + popw %es + popw %ds + ret + +/* + * set_cursor_position + * + * handle int 10h, function 02h + * + * ah = 0x02 set cursor position + * bh = display page number + * dh = cursor row + * dl = cursor column + * + * update bda cursor position with value in %dx + * serial console cursor only updated on text output + * this routine also called by set_current_cursor + * which won't bother setting ah = 2 + * + * all registers preserved except flags + */ + +set_cursor_position: + pushw %ax + pushw %ds + pushw $BDA_SEG + popw %ds /* ds = 0x40 */ + movzbw %bh, %ax /* ax = page number */ + andb $0x07, %al /* prevent invalid page number */ + shlb $1, %al /* calculate word offset */ + addb $BDA_CURSOR_BUF, %al /* ax = cursor save offset */ + movw %ax, %bx /* bx = cursor save offset */ + movw %dx, (%bx) /* save new cursor value */ + popw %ds + popw %ax + ret + +/* + * set_current_cursor + * + * get current display page number and call set_cursor_positon + * to store the row/column value in dx to the bda + * + * all registers preserved except flags + */ + +set_current_cursor: + pushw %ds + pushw %bx + pushw $BDA_SEG + popw %ds /* ds = 0x40 */ + movb BDA_ACTIVE_PAGE, %bh + call set_cursor_position + popw %bx + popw %ds + ret + +/* + * get_cursor_common + * + * read cursor position for page %bh from bda into %dx + * + * returns: + * dh = cursor row + * dl = cursor column + * ch = cursor start scanline + * cl = cursor end scanline + * + * all registers except %dx, %cx preserved + */ +get_cursor_common: + pushw %bx + pushw %ds + pushw $BDA_SEG + popw %ds /* ds = 0x40 */ + movzbw %bh, %bx /* dx = current page */ + andb $7, %bl + shlb $1, %bl + addb $BDA_CURSOR_BUF, %bl + movw (%bx), %dx /* get cursor pos */ + movw BDA_CURSOR_SCAN, %cx + popw %ds + popw %bx + ret + +/* + * get_current_cursor + * + * read cursor position for current page from bda into %dx + * + * returns: + * dh = cursor row + * dl = cursor column + * + * all registers except %dx preserved + */ + +get_current_cursor: + pushw %ds + pushw %bx + pushw %cx + pushw $BDA_SEG + popw %ds /* ds = 0x40 */ + movb BDA_ACTIVE_PAGE, %bh + call get_cursor_common + popw %cx + popw %bx + popw %ds + ret + +/* + * get_cursor_position + * + * handle int 10h, function 03h + * + * ah = 0x02 get cursor position + * bh = display page number + * + * returns: + * ax = 0 + * ch = cursor start scanline + * ch = cursor end scanline + * dh = cursor row + * dl = cursor column + * + * all registers except %ax, %cx, %dx preserved + */ + +get_cursor_position: + call bail_if_vga_attached /* does not return if vga attached */ + popw %ax /* not chaining, pop fake return address */ + popw %dx /* not chaining, pop saved cursor position */ + popaw /* not chaining to old int 10h, pop saved state */ + call get_cursor_common + xorw %ax, %ax + iret + +/* + * return_current_video_state + * + * handle int 10h, function 0fh + * + * ah = 0x0f return current video state + * + * returns: + * ah = number of columns on screen (from 40:4a) + * al = current video mode setting (from 40:49) + * bh = active display page number (from 40:62) + * + * all registers except %ax and %bh preserved + */ + +read_current_video_state: + call bail_if_vga_attached /* does not return if vga attached */ + popw %ax /* not chaining, pop fake return address */ + popw %dx /* not chaining, pop saved cursor position */ + popaw /* not chaining to old int 10h, pop saved state */ + pushw %ds + pushw $BDA_SEG + popw %ds /* ds = 0x40 */ + movb BDA_COLS, %ah + movb BDA_MODE_NUM, %al + movb BDA_ACTIVE_PAGE, %bh + popw %ds + iret + +/* + * read_attr_char + * + * handle int 10h, function 08h + * + * ah = 0x08 read character/attribute from screen + * + * returns: + * ah = attribute at current cursor position + * al = character read from current cursor position + * + * all registers preserved except %ax and flags + */ + +read_attr_char: + call bail_if_vga_attached /* does not return if vga attached */ + popw %ax /* not chaining, pop fake return address */ + popw %dx /* not chaining, pop saved cursor position */ + popaw /* not chaining to old int 10h, pop saved state */ + pushw %ds + pushw $BDA_SEG + popw %ds /* ds = 0x40 */ + movb BDA_COLOR_VAL, %ah /* return last color value */ + call sgabioslog_get_char + popw %ds + iret + +/* + * set_video_mode + * + * handle int 10h, function 00h + * + * ah = 0x00 set video mode + * al = video mode + * + * unless bit 7 of al = 1, setting mode clears screen + * + * all registers preserved except %bh, %dx, flags + */ + +set_video_mode: + testb $0x80, %al /* preserve screen flag? */ + jnz set_video_mode_tail + call send_ansi_csi + movb $0x32, %al /* 2 */ + call send_byte + movb $0x4a, %al /* J */ + call send_byte +set_video_mode_tail: + movb $0x07, %bl /* white on black text */ + call send_attribute /* send attribute in %bl */ + /* set cursor position to 0,0 */ + xorb %bh, %bh /* page 0 */ + xorw %dx, %dx + jmp set_cursor_position + +/* + * scroll_page_up + * + * handle int 10h, function 06h + * + * ah = 0x06 scroll current page up + * al = scroll distance in character rows (0 blanks entire area) + * bh = attribute to used on blanked lines + * ch = top row (upper left corner) of window + * cl = left-most column (upper left corner) of window + * dh = bottom row (lower right corner) of window + * dl = right-most column (lower right corner) of window + * + * all registers preserved except flags + */ + +scroll_page_up: + pushw %si + pushw %dx + call get_current_cursor /* save current cursor */ + movw %dx, %si /* si = vga cursor pos */ + popw %dx + cmpb $0, %al /* al = 0 = clear window */ + jz scroll_common_clear + pushw %ax + call send_ansi_csi /* CSI [ %al S */ + call send_number + movb $0x53, %al /* S */ + call send_byte + popw %dx + popw %si + ret + +/* + * scroll_common_clear + * + * common tail for up/down scrolls to clear window specified + * in %cx and %dx. + * + * stack should contain saved copy of si + * si = original vga cursor position on service entry + * + * bh = attribute to used on blanked lines + * ch = top row (upper left corner) of window + * cl = left-most column (upper left corner) of window + * dh = bottom row (lower right corner) of window + * dl = right-most column (lower right corner) of window + */ +scroll_common_clear: + pushw %ax + xchgb %bl, %bh /* bl = attribute, bh = old bl */ + call send_attribute /* send attribute in %bl */ + xchgb %bl, %bh /* restore bx */ + pushw %ds + pushw $BDA_SEG + popw %ds /* ds = 0x40 */ + /* check to see if region is full screen, and attribute default */ + orw %cx, %cx /* is top left 0,0? */ + jnz scroll_common_window /* no, handle window */ + cmpb $0x07, %bh /* is attribute white on black? */ + jnz scroll_common_window /* no, must write spaces */ +#ifdef LILO_CLEAR_WORKAROUND_NOT_REQUIRED + cmpb %cs:term_cols, %dl /* is right less than cols ? */ + jc scroll_common_window /* if so, handle window */ + cmpb %cs:term_rows, %dh /* is bottom less than rows ? */ + jc scroll_common_window /* if so, handle window */ +#endif + /* safe to send standard clear screen sequence */ + call send_ansi_csi /* send ESC [ */ + movb $0x32, %al /* 2 */ + call send_byte + movb $0x4a, %al /* J */ + call send_byte + jmp scroll_common_tail +scroll_common_window: + pushw %dx + movw %cx, %dx /* dx = upper right */ + call set_current_cursor + popw %dx + pushw %cx + /* setup cx with count of chars to clear per row */ + xorb %ch, %ch + negb %cl + addb %dl, %cl /* cl = dl - cl */ + incb %cl /* start = end col = clear 1 col */ + cmpb %cs:term_cols, %cl /* is count < cols? */ + jc scroll_common_row_ok /* if so then skip limit */ + movb %cs:term_cols, %cl /* limit count to cols */ +scroll_common_row_ok: + jz scroll_common_row_done /* count == 0 ? */ + movb $0x20, %al /* space */ +scroll_common_space_loop: + call send_char + loop scroll_common_space_loop /* send cx spaces */ +scroll_common_row_done: + popw %cx + incb %ch /* top left now next row */ + cmpb %dh, %ch + jbe scroll_common_window /* do next row */ +scroll_common_tail: + popw %ds + popw %ax + pushw %dx + movw %si, %dx /* dx = saved vga cursor pos */ + call set_current_cursor /* restore saved cursor */ + popw %dx + popw %si + ret + +/* + * scroll_page_down + * + * handle int 10h, function 07h + * + * ah = 0x07 scroll current page down + * al = scroll distance in character rows (0 blanks entire area) + * bh = attribute to used on blanked lines + * ch = top row (upper left corner) of window + * cl = left-most column (upper left corner) of window + * dh = bottom row (lower right corner) of window + * dl = right-most column (lower right corner) of window + * + * FIXME: this routine doesn't handle windowing, it currently + * only handles one line screen scrolls and erasing entire screen + * + * all registers preserved except flags + */ + +scroll_page_down: + pushw %si + pushw %dx + call get_current_cursor /* save current cursor */ + movw %dx, %si /* si = vga cursor pos */ + popw %dx + cmpb $0, %al /* al = 0 = clear window */ + jz scroll_common_clear + pushw %ax + call send_ansi_csi /* CSI [ %al T */ + call send_number + movb $0x54, %al /* T */ + call send_byte + popw %dx + popw %si + ret + +/* + * bail_if_vga_attached + * + * Check for vga installed, if not, return to caller. + * If so, pop return address, return to chain_isr_10h + * + * expected that routine calling this one has chain_isr_10h + * as the next item on the stack + * + * all registers except flags and sp preserved + */ + +bail_if_vga_attached: + cmpw $0xc000, %cs:old_int10h_seg /* vga attached? */ + jnz bail_tail /* if not, don't modify stack */ + addw $2, %sp /* else drop first return address */ +bail_tail: + ret /* return to caller or chain_isr_10h */ + +/* + * int10h_isr + * + * entry point for int 10h + * + * save all registers, force return to chain to previous int10h isr + * decide which function in ah needs to be dispatched + * + * ah = 0x00 set mode + * ah = 0x01 set cursor type + * ah = 0x02 set cursor position + * ah = 0x03 read cursor position + * ah = 0x04 read light pen position + * ah = 0x05 set active display page + * ah = 0x06 scroll active page up + * ah = 0x07 scroll active page down + * ah = 0x08 read attribute/character at cursor + * ah = 0x09 write attribute/character at cursor + * ah = 0x0a write character at cursor position + * ah = 0x0b set color palette + * ah = 0x0c write pixel + * ah = 0x0d read pixel + * ah = 0x0e write teletype + * ah = 0x0f read current video state + * ah = 0x10 set individual palette registers + * ah = 0x11 character generation (font control/info) + * ah = 0x12 alternate select (video control/info) + * ah = 0x13 write string + * ah = 0x1a read/write display combination code + * ah = 0x1b return functionality/state information + * ah = 0x1c save/restore video state + * ah = 0x4f vesa bios calls + * all registers preserved except flags (later iret will restore) + */ + +int10h_isr: + pushaw + call get_current_cursor + pushw %dx /* save current cursor */ + pushw %bp /* need bp for indexing off stack */ + movw %sp, %bp /* bp = sp */ + movw 14(%bp), %dx /* restore dx from earlier pushaw */ + popw %bp /* restore old bp */ + pushw $chain_isr10h /* force return to chain_isr10h */ + testb %ah, %ah + jnz int10h_02 + jmp set_video_mode +int10h_02: + cmpb $0x02, %ah + jnz int10h_03 + jmp set_cursor_position +int10h_03: + cmpb $0x03, %ah + jnz int10h_06 + jmp get_cursor_position +int10h_06: + cmpb $0x06, %ah + jnz int10h_07 + jmp scroll_page_up +int10h_07: + cmpb $0x07, %ah + jnz int10h_08 + jmp scroll_page_down +int10h_08: + cmpb $0x08, %ah + jnz int10h_09 + jmp read_attr_char +int10h_09: + cmpb $0x09, %ah + jnz int10h_0a + jmp write_attr_char +int10h_0a: + cmpb $0x0a, %ah + jnz int10h_0e + jmp write_char +int10h_0e: + cmpb $0x0e, %ah + jnz int10h_0f + jmp write_teletype +int10h_0f: + cmpb $0x0f, %ah + jnz int10h_13 + jmp read_current_video_state +int10h_13: + cmpb $0x13, %ah + jnz int10h_default + jmp write_string +int10h_default: + popw %ax /* pop chain_isr10h return address */ +chain_isr10h: + popw %dx /* pop saved cursor */ + cmpw $0xc000, %cs:old_int10h_seg /* vga attached? */ + jnz chain_post_cursor /* if not, don't restore the cursor */ + call set_current_cursor /* restore cursor if vga attached */ +chain_post_cursor: + popaw + jmp do_old_int10h + +/* + * pnp_sga_init + * + * handle PnP initialization of option rom + * + * es:di = pointer to PnP structure + * ax = indication as to which vectors should be hooked + * by specifying th type of boot device this has + * been selected as + * bit 7..3= reserved(0) + * bit 2 = 1 = connect as IPL (int 13h) + * bit 1 = 1 = connect as primary video (int 10h) + * bit 0 = 1 = connect as primary input (int 9h) + * bx = card select number (probably 0xffff) + * dx = read data port address (probably 0xffff) + * + * return: + * ax = initialization status + * bit 8 = 1 = IPL device supports int 13h block dev format + * bit 7 = 1 = Output device supports int 10h char output + * bit 6 = 1 = Input device supports int 9h char input + * bit 5..4 = 00 = no IPL device attached + * 01 = unknown whether or not IPL device attached + * 10 = IPL device attached (RPL devices have connection) + * 11 = reserved + * bit 3..2 = 00 = no display device attached + * 01 = unknown whether or not display device attached + * 10 = display device attached + * 11 = reserved + * bit 1..0 = 00 = no input device attached + * 01 = unknown whether or not input device attached + * 10 = input device attached + * 11 = reserved + * + * all registers preserved except %ax + */ + +pnp_sga_init: + /* FIXME: this is *wrong* -- init only what bios says to init */ + movw $0xca, %ax /* 0xca = attached int 10h, 9h display, input */ + +/* + * sga_init + * + * legacy option rom entry point + * + * all registers preserved + */ + +sga_init: + /* this is probably paranoid about register preservation */ + pushfw + cli /* more paranoia */ + pushaw + pushw %ds + pushw %es + pushw $0 + popw %es /* es = 0 */ + pushw %cs + popw %ds /* ds = cs */ + /* get original ISR */ + movl %es:0x28, %eax /* eax = old irq 3/int 0bh */ + movl %eax, old_irq3 /* save away old irq 4/int 0bh */ + movl %es:0x2c, %eax /* eax = old irq 4/int 0ch */ + movl %eax, old_irq4 /* save away old irq 4/int 0ch */ + movl %es:0x40, %eax /* eax = old int 10h */ + movl %eax, old_int10h /* save away old int 10h */ + movl %es:0x50, %eax /* eax = old int 14h */ + movl %eax, old_int14h /* save away old int 14h */ + movl %es:0x58, %eax /* eax = old int 16h */ + movl %eax, old_int16h /* save away old int 16h */ + movw $irq3_isr, %es:0x28 /* new irq 3 offset */ + movw %cs, %es:0x2a /* write new irq 3 seg */ + movw $irq4_isr, %es:0x2c /* new irq 4 offset */ + movw %cs, %es:0x2e /* write new irq 4 seg */ + movw $int10h_isr, %es:0x40 /* new int 10h offset */ + movw %cs, %es:0x42 /* write new int10h seg */ + movw $int14h_isr, %es:0x50 /* new int 14h offset */ + movw %cs, %es:0x52 /* write new int14h seg */ + movw $int16h_isr, %es:0x58 /* new int 16h offset */ + movw %cs, %es:0x5a /* write new int16h seg */ + /* empty input buffer to prepare for terminal sizing */ + call init_serial_port +input_clear_loop: + call get_byte + jnz input_clear_loop + movw $term_init_string, %si + call send_asciz_out + push $BDA_SEG + push $BDA_SEG + popw %ds /* ds = 0x40 */ + popw %es /* es = 0x40 */ + movw $BDA_CURSOR_BUF, %di +input_timeout_loop: + /* get input from terminal until timeout found */ + /* store input at 40:50 - 40:5e (cursor pos) */ + call poll_byte + jz input_timeout + stosb /* es:di */ + cmpw $0x5f, %di /* 14 characters max */ + jnz input_timeout_loop /* good for more data */ +input_timeout: + xorb %al, %al /* nul terminate input */ + stosb + cmpw $0x58, %di /* less than 8 chars? */ + jc resize_end /* too small to have valid data */ + movw $BDA_CURSOR_BUF, %si /* point to start */ + lodsw /* ax = first 2 chars */ + cmpw $0x5b1b, %ax /* was it "ESC[" ? */ + jnz resize_end /* reply starts ESC[row;colR */ + xorb %bl, %bl /* bl = ascii->int conversion */ +input_first_number: + lodsb /* al = next char */ + cmpb $0x30, %al + jc resize_end /* char < 0x30 invalid */ + cmpb $0x3a, %al /* is char < 0x3a */ + jnc input_semicolon + andb $0x0f, %al /* al = 0 - 9 */ + movb %bl, %ah /* ah = last conversion */ + aad /* ax = (al + ah * 10) & 0xff */ + movb %al, %bl /* bl = row ascii->int conversion */ + jmp input_first_number +input_semicolon: + /* at this point bl should contain rows, al = ; */ + /* sanity check, bail if invalid */ + cmpb $0x3b, %al + jnz resize_end /* invalid input found */ + cmpb $0x0a, %bl /* less than 10 rows? */ + jc suspect_loopback /* consider input invalid */ + xorb %bh, %bh /* bh = col ascii->int conversion */ +input_second_number: + lodsb /* al = next char */ + cmpb $0x30, %al + jc resize_end /* char < 0x30 invalid */ + cmpb $0x3a, %al /* is char < 0x3a */ + jnc input_final_r + andb $0x0f, %al /* al = 0 - 9 */ + movb %bh, %ah /* ah = last conversion */ + aad /* ax = (al + ah * 10) & 0xff */ + movb %al, %bh /* bh = ascii->int conversion */ + jmp input_second_number +input_final_r: + cmpb $0x52, %al /* is al = 'R' ? */ + jnz suspect_loopback /* invalid input found */ + movb %bl, %cs:term_rows /* save away bl rows value */ + cmpw $0xc000, %cs:old_int10h_seg /* vga attached? */ + jz resize_end /* if so, leave term_cols at 80 */ + movb %bh, %cs:term_cols /* save away bh cols value */ + jmp resize_end +suspect_loopback: + /* + * characters were received that look like what we sent out + * at this point, assume that a loopback device was plugged in + * and disable any future serial port reads or writes, by pointing + * output to port 0x2e8 (COM4) instead of 0x3f8 -- it's expected + * that this is safe since a real port responds correctly and a + * missing port will respond with 0xff which will terminate the + * loop that waits for the "right" status on the port. + */ + movw $0x2e8, %cs:serial_port_base_address +resize_end: + /* clear (hopefully) overwritten cursor position buffer */ + xorb %al, %al + movw $BDA_CURSOR_BUF, %di + movw $0x10, %cx + cld + rep + stosb /* fill 40:50 - 40:5f with 0 */ + pushw %cs + popw %ds /* ds = cs */ + call get_byte /* flush any remaining "wrong" input */ + jnz resize_end + call send_crlf /* place cursor on start of last line */ + movw $mfg_string, %si + call send_asciz_out + call send_crlf + movw $prod_string, %si + call send_asciz_out + call send_crlf + movw $long_version, %si + call send_asciz_out + call send_crlf + /* if vga attached, skip terminal message and bda setup... */ + cmpw $0xc000, %cs:old_int10h_seg /* vga attached? */ + jz post_bda_init_tail /* if so, don't modify BDA */ + /* show detected terminal size, or default if none detected */ + movw $term_info, %si + call send_asciz_out + pushw $BDA_SEG + popw %ds /* ds = 0x40 */ + movb %cs:term_cols, %al + movb %al, BDA_COLS /* 40:4a = number of character cols */ + movb $0, BDA_CURSOR_COL /* 40:51 = cursor0 col */ + call send_number + movb $0x78, %al /* x */ + call send_byte + movb %cs:term_rows, %al + movb %al, %ah + decb %ah /* ah = rows-1 */ + movb %ah, BDA_ROWS /* 40:84 = num character rows - 1 */ + movb %ah, BDA_CURSOR_ROW /* 40:50 = cursor0 row */ + call send_number + call send_crlf + movb $3, BDA_MODE_NUM + movb $0x29, BDA_MODE_SEL + movw $VGA_IO_BASE, BDA_6845_ADDR + movw $0x4000, BDA_PAGE_SIZE /* 16KB per video page */ + /* to avoid ansi colors every character, store last attribute */ + movb $0x07, BDA_COLOR_VAL /* 07 = black bg, white fg */ + movw %cs, %ax + movw $_start, BDA_ROM_OFF + movw %ax, BDA_ROM_SEG +post_bda_init_tail: + /* copy BDA rows/cols to sgabios location... */ + /* if vga card is installed, reuse those values... */ + /* if no vga card is installed, this shouldn't change anything */ + pushw $BDA_SEG + popw %ds /* ds = 0x40 */ + movb BDA_ROWS, %al + incb %al /* bda holds rows-1 */ + movb %al, %cs:term_rows /* sgabios rows */ + movb BDA_COLS, %ah + movb %ah, %cs:term_cols /* sgabios cols */ + /* setup in-memory logging of console if desired... */ + call setup_memconsole + /* setup logging of last 256 characters output, if ebda has room */ + call sgabioslog_setup_ebda + movw $ebda_info, %si + call send_asciz_out + movw %cs:sgabios_ebda_logbuf_offset, %ax + xchgb %ah, %al + call send_number + movb $0x20, %al + call send_byte + movb %ah, %al + call send_number + call send_crlf + popw %es + popw %ds + popaw + popf + lret + +_end_sgabios: diff --git a/qemu/roms/sgabios/sgabios.h b/qemu/roms/sgabios/sgabios.h new file mode 100644 index 000000000..51e829c92 --- /dev/null +++ b/qemu/roms/sgabios/sgabios.h @@ -0,0 +1,76 @@ +/* + * Copyright 2010 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. + */ + +/* don't allocate ebda if new value at 0x40e will be less than this */ +#define EBDA_MIN_SEG 0x9800 +#define SGABIOS_EBDA_KB 1 +/* note: no testing has yet been done logging other than 256 bytes */ +#define SGABIOS_EBDA_BYTES (SGABIOS_EBDA_KB*1024) +#define SGABIOS_EBDA_DELTA (SGABIOS_EBDA_BYTES/16) +#define SGABIOS_EBDA_LOG_START 256 +#define SGABIOS_EBDA_LOG_SIZE 256 +#define SGABIOS_EBDA_POS_START (SGABIOS_EBDA_LOG_START+SGABIOS_EBDA_LOG_SIZE) +#define SGABIOS_EBDA_POS_LAST (SGABIOS_EBDA_POS_START+(SGABIOS_EBDA_LOG_SIZE*2)-2) + +/* serial costants that may require modification */ +#define COM_BASE_ADDR 0x3f8 +#define PORT_SPEED 115200 +#define LCR_VALUE 0x13 /* 8n1 */ + +/* serial constants below shouldn't require modification */ +#define IER_OFFSET 0x01 +#define FCR_OFFSET 0x02 +#define LCR_OFFSET 0x03 +#define MCR_OFFSET 0x04 +#define LSR_OFFSET 0x05 +#define MSR_OFFSET 0x06 +#define SCR_OFFSET 0x07 +#define LCR_DLAB 0x80 +#define MCR_DTRRTS 0x03 +#define FCR_FIFO_ENABLE 0x01 +#define PORT_DIVISOR 115200 +#define TRANSMIT_READY_BIT 0x20 +#define BIOS_BUILD_VERSION "$Id: sgabios.S 7 2009-11-13 00:21:26Z smiles@google.com $" + +#define KBD_HEAD 0x1a +#define KBD_TAIL 0x1c +#define KBD_BUF_START 0x1e +#define KBD_BUF_END 0x3e + +#define VGA_IO_BASE 0x3d4 +#define BDA_SEG 0x40 +#define BDA_EBDA 0x0e +#define BDA_MEM_SIZE 0x13 +#define BDA_MODE_NUM 0x49 +#define BDA_COLS 0x4a +#define BDA_PAGE_SIZE 0x4c +/* BDA word 40:0c traditionally holds the LPT3 io port address... */ +/* Reuse it for tracking where the serial console cursor was left */ +/* Don't send ansi cursor pos update without text ready to output */ +/* Some operations don't update cursor position, but next int 10h */ +/* call is often one that might update to where cursor already is */ +#define BDA_SERIAL_POS 0x0c +#define BDA_CURSOR_BUF 0x50 +#define BDA_CURSOR_COL 0x50 +#define BDA_CURSOR_ROW 0x51 +#define BDA_CURSOR_SCAN 0x60 +#define BDA_ACTIVE_PAGE 0x62 +#define BDA_6845_ADDR 0x63 +#define BDA_MODE_SEL 0x65 +#define BDA_COLOR_VAL 0x66 +#define BDA_ROM_OFF 0x67 +#define BDA_ROM_SEG 0x69 +#define BDA_ROWS 0x84 |