From: Peter Dinda Date: Thu, 29 Nov 2007 20:26:38 +0000 (+0000) Subject: Initial revision X-Git-Tag: PDINDA0~1 X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=commitdiff_plain;h=626595465a2c6987606a6bc697df65130ad8c2d3;p=palacios.git Initial revision --- 626595465a2c6987606a6bc697df65130ad8c2d3 diff --git a/palacios/COPYING.geekos b/palacios/COPYING.geekos new file mode 100644 index 0000000..f07e852 --- /dev/null +++ b/palacios/COPYING.geekos @@ -0,0 +1,23 @@ +Copyright (c) 2001,2003,2004 David H. Hovemeyer +Copyright (c) 2003, Jeffrey K. Hollingsworth + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/palacios/LICENSE-klibc.geekos b/palacios/LICENSE-klibc.geekos new file mode 100644 index 0000000..b512ff9 --- /dev/null +++ b/palacios/LICENSE-klibc.geekos @@ -0,0 +1,73 @@ +This license applies to all files in directory and its subdirectories, +unless otherwise noted in individual files. + + +Some files are derived from files derived from the include/ directory +of the Linux kernel, and are licensed under the terms of the GNU +General Public License, version 2, as released by the Free Software +Foundation, Inc.; incorporated herein by reference. + + ----- + +Some files are derived from files copyrighted by the Regents of The +University of California, and are available under the following +license: + +Note: The advertising clause in the license appearing on BSD Unix +files was officially rescinded by the Director of the Office of +Technology Licensing of the University of California on July 22 +1999. He states that clause 3 is "hereby deleted in its entirety." + + * Copyright (c) + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + + ----- + +For all remaining files, the following license applies: + + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * Any copyright notice(s) and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/palacios/README b/palacios/README new file mode 100644 index 0000000..332be74 --- /dev/null +++ b/palacios/README @@ -0,0 +1,48 @@ +This is is a VMM that uses VT-x on 32 bit machines. + +It is based on GeekOS, VmxAssist, BOCHS BIOS/VGABIOS, and code +for playing around with VT and VT-X in the GeekOS context + +Peter Dinda + + +Here are some things you need to know: + + +Serial port I/O is used to communicate with the VMM. This means +you need a null modem connection between your test machine and your +dev machine. + +To configure serial on your dev machine: + +(as root, or other user who has access to the serial port): + + stty -F /dev/ttyS0 115200 (assume 8 bit, no parity already set) + +Then use kermit to communicate: + + kermit -l /dev/ttyS0 + set carrier-watch off + connect + +To access the ethernet power switch: + + + ifconfig eth0:1 up 192.168.0.4 (this is your address) + +Now you should be able to connect to http://192.168.0.100 + + +To build from scratch: + +cd build +make clean +make +make generate_sizes +make clean +make pxe + +This will copy the final image into /tftpboot so that if you have PXE +boot properly configured, the test machine will boot from it over the +network. + diff --git a/palacios/build/.bochsrc b/palacios/build/.bochsrc new file mode 100644 index 0000000..e95aa5a --- /dev/null +++ b/palacios/build/.bochsrc @@ -0,0 +1,751 @@ +# You may now use double quotes around pathnames, in case +# your pathname includes spaces. + +#======================================================================= +# CONFIG_INTERFACE +# +# The configuration interface is a series of menus or dialog boxes that +# allows you to change all the settings that control Bochs's behavior. +# There are two choices of configuration interface: a text mode version +# called "textconfig" and a graphical version called "wx". The text +# mode version uses stdin/stdout and is always compiled in. The graphical +# version is only available when you use "--with-wx" on the configure +# command. If you do not write a config_interface line, Bochs will +# choose a default for you. +# +# NOTE: if you use the "wx" configuration interface, you must also use +# the "wx" display library. +#======================================================================= +#config_interface: textconfig +#config_interface: wx + +#======================================================================= +# DISPLAY_LIBRARY +# +# The display library is the code that displays the Bochs VGA screen. Bochs +# has a selection of about 10 different display library implementations for +# different platforms. If you run configure with multiple --with-* options, +# the display_library command lets you choose which one you want to run with. +# If you do not write a display_library line, Bochs will choose a default for +# you. +# +# The choices are: +# x use X windows interface, cross platform +# win32 use native win32 libraries +# carbon use Carbon library (for MacOS X) +# beos use native BeOS libraries +# macintosh use MacOS pre-10 +# amigaos use native AmigaOS libraries +# sdl use SDL library, cross platform +# svga use SVGALIB library for Linux, allows graphics without X11 +# term text only, uses curses/ncurses library, cross platform +# rfb provides an interface to AT&T's VNC viewer, cross platform +# wx use wxWidgets library, cross platform +# nogui no display at all +# +# NOTE: if you use the "wx" configuration interface, you must also use +# the "wx" display library. +# +# Specific options: +# Some display libraries now support specific option to control their +# behaviour. See the examples below for currently supported options. +#======================================================================= +#display_library: amigaos +#display_library: beos +#display_library: carbon +#display_library: macintosh +#display_library: nogui +#display_library: rfb, options="timeout=60" # time to wait for client +#display_library: sdl, options="fullscreen" # startup in fullscreen mode +#display_library: term +#display_library: win32, options="legacyF12" # use F12 to toggle mouse +#display_library: wx +display_library: x + +#======================================================================= +# ROMIMAGE: +# The ROM BIOS controls what the PC does when it first powers on. +# Normally, you can use a precompiled BIOS in the source or binary +# distribution called BIOS-bochs-latest. The ROM BIOS is usually loaded +# starting at address 0xf0000, and it is exactly 64k long. +# You can also use the environment variable $BXSHARE to specify the +# location of the BIOS. +# The usage of external large BIOS images (up to 512k) at memory top is +# now supported, but we still recommend to use the BIOS distributed with +# Bochs. Now the start address can be calculated from image size. +#======================================================================= +romimage: file=$BXSHARE/BIOS-bochs-latest, address=0xf0000 +#romimage: file=mybios.bin, address=0xfff80000 # 512k at memory top +#romimage: file=mybios.bin # calculate start address from image size + +#======================================================================= +# CPU: +# This defines cpu-related parameters inside Bochs: +# +# COUNT: +# Set the number of processors:cores per processor:threads per core +# when Bochs is compiled for SMP emulation. +# Bochs currently supports up to 8 threads running simultaniosly. +# If Bochs is compiled without SMP support, it won't accept values +# different from 1. +# +# QUANTUM: +# Maximum amount of instructions allowed to execute by processor before +# returning control to another cpu. This option exists only in Bochs +# binary compiled with SMP support. +# +# RESET_ON_TRIPLE_FAULT: +# Reset the CPU when triple fault occur (highly recommended) rather than +# PANIC. Remember that if you trying to continue after triple fault the +# simulation will be completely bogus ! +# +# IPS: +# Emulated Instructions Per Second. This is the number of IPS that bochs +# is capable of running on your machine. You can recompile Bochs with +# --enable-show-ips option enabled, to find your workstation's capability. +# Measured IPS value will then be logged into your log file or status bar +# (if supported by the gui). +# +# IPS is used to calibrate many time-dependent events within the bochs +# simulation. For example, changing IPS affects the frequency of VGA +# updates, the duration of time before a key starts to autorepeat, and +# the measurement of BogoMips and other benchmarks. +# +# Examples: +# +# Bochs Machine/Compiler Mips +# ____________________________________________________________________ +# 2.2.6 2.6Ghz Intel Core 2 Duo with WinXP/g++ 3.4 21 to 25 Mips +# 2.2.6 2.1Ghz Athlon XP with Linux 2.6/g++ 3.4 12 to 15 Mips +# 2.0.1 1.6Ghz Intel P4 with Win2000/g++ 3.3 5 to 7 Mips +# 1.4 650Mhz Athlon K-7 with Linux 2.4.4/egcs-2.91.66 2 to 2.5 Mips +# 1.4 400Mhz Pentium II with Linux 2.0.36/egcs-1.0.3 1 to 1.8 Mips +#======================================================================= +cpu: count=1, ips=10000000, reset_on_triple_fault=1 + +#======================================================================= +# MEGS +# Set the number of Megabytes of physical memory you want to emulate. +# The default is 32MB, most OS's won't need more than that. +# The maximum amount of memory supported is 2048Mb. +#======================================================================= +#megs: 256 +#megs: 128 +#megs: 64 +megs: 256 +#megs: 16 +#megs: 8 + +#======================================================================= +# OPTROMIMAGE[1-4]: +# You may now load up to 4 optional ROM images. Be sure to use a +# read-only area, typically between C8000 and EFFFF. These optional +# ROM images should not overwrite the rombios (located at +# F0000-FFFFF) and the videobios (located at C0000-C7FFF). +# Those ROM images will be initialized by the bios if they contain +# the right signature (0x55AA) and a valid checksum. +# It can also be a convenient way to upload some arbitrary code/data +# in the simulation, that can be retrieved by the boot loader +#======================================================================= +#optromimage1: file=optionalrom.bin, address=0xd0000 +#optromimage2: file=optionalrom.bin, address=0xd1000 +#optromimage3: file=optionalrom.bin, address=0xd2000 +#optromimage4: file=optionalrom.bin, address=0xd3000 + +#optramimage1: file=/path/file1.img, address=0x0010000 +#optramimage2: file=/path/file2.img, address=0x0020000 +#optramimage3: file=/path/file3.img, address=0x0030000 +#optramimage4: file=/path/file4.img, address=0x0040000 + +#======================================================================= +# VGAROMIMAGE +# You now need to load a VGA ROM BIOS into C0000. +#======================================================================= +#vgaromimage: file=bios/VGABIOS-elpin-2.40 +vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest +#vgaromimage: file=bios/VGABIOS-lgpl-latest-cirrus + +#======================================================================= +# VGA: +# Here you can specify the display extension to be used. With the value +# 'none' you can use standard VGA with no extension. Other supported +# values are 'vbe' for Bochs VBE and 'cirrus' for Cirrus SVGA support. +#======================================================================= +#vga: extension=cirrus +#vga: extension=vbe +#vga: extension=none + +#======================================================================= +# FLOPPYA: +# Point this to pathname of floppy image file or device +# This should be of a bootable floppy(image/device) if you're +# booting from 'a' (or 'floppy'). +# +# You can set the initial status of the media to 'ejected' or 'inserted'. +# floppya: 2_88=path, status=ejected (2.88M 3.5" floppy) +# floppya: 1_44=path, status=inserted (1.44M 3.5" floppy) +# floppya: 1_2=path, status=ejected (1.2M 5.25" floppy) +# floppya: 720k=path, status=inserted (720K 3.5" floppy) +# floppya: 360k=path, status=inserted (360K 5.25" floppy) +# floppya: 320k=path, status=inserted (320K 5.25" floppy) +# floppya: 180k=path, status=inserted (180K 5.25" floppy) +# floppya: 160k=path, status=inserted (160K 5.25" floppy) +# floppya: image=path, status=inserted (guess type from image size) +# +# The path should be the name of a disk image file. On Unix, you can use a raw +# device name such as /dev/fd0 on Linux. On win32 platforms, use drive letters +# such as a: or b: as the path. The parameter 'image' works with image files +# only. In that case the size must match one of the supported types. +#======================================================================= +floppya: 1_44=./fd.img, status=inserted +#floppya: image=./fd.img, status=inserted +#floppya: 1_44=/dev/fd0H1440, status=inserted +#floppya: 1_2=../1_2, status=inserted +#floppya: 1_44=a:, status=inserted +#floppya: 1_44=a.img, status=inserted +#floppya: 1_44=/dev/rfd0a, status=inserted + +#======================================================================= +# FLOPPYB: +# See FLOPPYA above for syntax +#======================================================================= +#floppyb: 1_44=b:, status=inserted +#floppyb: 1_44=b.img, status=inserted + +#======================================================================= +# ATA0, ATA1, ATA2, ATA3 +# ATA controller for hard disks and cdroms +# +# ata[0-3]: enabled=[0|1], ioaddr1=addr, ioaddr2=addr, irq=number +# +# These options enables up to 4 ata channels. For each channel +# the two base io addresses and the irq must be specified. +# +# ata0 and ata1 are enabled by default with the values shown below +# +# Examples: +# ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 +# ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 +# ata2: enabled=1, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11 +# ata3: enabled=1, ioaddr1=0x168, ioaddr2=0x360, irq=9 +#======================================================================= +ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 +ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 +ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11 +ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9 + +#======================================================================= +# ATA[0-3]-MASTER, ATA[0-3]-SLAVE +# +# This defines the type and characteristics of all attached ata devices: +# type= type of attached device [disk|cdrom] +# mode= only valid for disks [flat|concat|external|dll|sparse|vmware3] +# mode= only valid for disks [undoable|growing|volatile] +# path= path of the image +# cylinders= only valid for disks +# heads= only valid for disks +# spt= only valid for disks +# status= only valid for cdroms [inserted|ejected] +# biosdetect= type of biosdetection [none|auto], only for disks on ata0 [cmos] +# translation=type of translation of the bios, only for disks [none|lba|large|rechs|auto] +# model= string returned by identify device command +# journal= optional filename of the redolog for undoable and volatile disks +# +# Point this at a hard disk image file, cdrom iso file, or physical cdrom +# device. To create a hard disk image, try running bximage. It will help you +# choose the size and then suggest a line that works with it. +# +# In UNIX it may be possible to use a raw device as a Bochs hard disk, +# but WE DON'T RECOMMEND IT. In Windows there is no easy way. +# +# In windows, the drive letter + colon notation should be used for cdroms. +# Depending on versions of windows and drivers, you may only be able to +# access the "first" cdrom in the system. On MacOSX, use path="drive" +# to access the physical drive. +# +# The path is always mandatory. Disk geometry autodetection works with images +# created by bximage if CHS is set to 0/0/0 (cylinders are calculated using +# heads=16 and spt=63). For other hard disk images and modes the cylinders, +# heads, and spt are mandatory. +# +# Default values are: +# mode=flat, biosdetect=auto, translation=auto, model="Generic 1234" +# +# The biosdetect option has currently no effect on the bios +# +# Examples: +# ata0-master: type=disk, mode=flat, path=10M.sample, cylinders=306, heads=4, spt=17 +# ata0-slave: type=disk, mode=flat, path=20M.sample, cylinders=615, heads=4, spt=17 +# ata1-master: type=disk, mode=flat, path=30M.sample, cylinders=615, heads=6, spt=17 +# ata1-slave: type=disk, mode=flat, path=46M.sample, cylinders=940, heads=6, spt=17 +# ata2-master: type=disk, mode=flat, path=62M.sample, cylinders=940, heads=8, spt=17 +# ata2-slave: type=disk, mode=flat, path=112M.sample, cylinders=900, heads=15, spt=17 +# ata3-master: type=disk, mode=flat, path=483M.sample, cylinders=1024, heads=15, spt=63 +# ata3-slave: type=cdrom, path=iso.sample, status=inserted +#======================================================================= +#ata0-master: type=disk, mode=flat, path="30M.sample", cylinders=615, heads=6, spt=17 +#ata0-master: type=disk, mode=flat, path="c.img", cylinders=0 # autodetect +#ata0-slave: type=cdrom, path=D:, status=inserted +#ata0-slave: type=cdrom, path=/dev/cdrom, status=inserted +#ata0-slave: type=cdrom, path="drive", status=inserted +#ata0-slave: type=cdrom, path=/dev/rcd0d, status=inserted + +#======================================================================= +# BOOT: +# This defines the boot sequence. Now you can specify up to 3 boot drives. +# You can either boot from 'floppy', 'disk' or 'cdrom' +# legacy 'a' and 'c' are also supported +# Examples: +# boot: floppy +# boot: disk +# boot: cdrom +# boot: c +# boot: a +# boot: cdrom, floppy, disk +#======================================================================= +boot: floppy +#boot: disk + +#======================================================================= +# CLOCK: +# This defines the parameters of the clock inside Bochs: +# +# SYNC: +# TO BE COMPLETED (see Greg explanation in feature request #536329) +# +# TIME0: +# Specifies the start (boot) time of the virtual machine. Use a time +# value as returned by the time(2) system call. If no time0 value is +# set or if time0 equal to 1 (special case) or if time0 equal 'local', +# the simulation will be started at the current local host time. +# If time0 equal to 2 (special case) or if time0 equal 'utc', +# the simulation will be started at the current utc time. +# +# Syntax: +# clock: sync=[none|slowdown|realtime|both], time0=[timeValue|local|utc] +# +# Example: +# clock: sync=none, time0=local # Now (localtime) +# clock: sync=slowdown, time0=315529200 # Tue Jan 1 00:00:00 1980 +# clock: sync=none, time0=631148400 # Mon Jan 1 00:00:00 1990 +# clock: sync=realtime, time0=938581955 # Wed Sep 29 07:12:35 1999 +# clock: sync=realtime, time0=946681200 # Sat Jan 1 00:00:00 2000 +# clock: sync=none, time0=1 # Now (localtime) +# clock: sync=none, time0=utc # Now (utc/gmt) +# +# Default value are sync=none, time0=local +#======================================================================= +#clock: sync=none, time0=local + + +#======================================================================= +# FLOPPY_BOOTSIG_CHECK: disabled=[0|1] +# Enables or disables the 0xaa55 signature check on boot floppies +# Defaults to disabled=0 +# Examples: +# floppy_bootsig_check: disabled=0 +# floppy_bootsig_check: disabled=1 +#======================================================================= +floppy_bootsig_check: disabled=0 + +#======================================================================= +# LOG: +# Give the path of the log file you'd like Bochs debug and misc. verbiage +# to be written to. If you don't use this option or set the filename to +# '-' the output is written to the console. If you really don't want it, +# make it "/dev/null" (Unix) or "nul" (win32). :^( +# +# Examples: +# log: ./bochs.out +# log: /dev/tty +#======================================================================= +#log: /dev/null +log: bochsout.txt + +#======================================================================= +# LOGPREFIX: +# This handles the format of the string prepended to each log line. +# You may use those special tokens : +# %t : 11 decimal digits timer tick +# %i : 8 hexadecimal digits of cpu current eip (ignored in SMP configuration) +# %e : 1 character event type ('i'nfo, 'd'ebug, 'p'anic, 'e'rror) +# %d : 5 characters string of the device, between brackets +# +# Default : %t%e%d +# Examples: +# logprefix: %t-%e-@%i-%d +# logprefix: %i%e%d +#======================================================================= +#logprefix: %t%e%d + +#======================================================================= +# LOG CONTROLS +# +# Bochs now has four severity levels for event logging. +# panic: cannot proceed. If you choose to continue after a panic, +# don't be surprised if you get strange behavior or crashes. +# error: something went wrong, but it is probably safe to continue the +# simulation. +# info: interesting or useful messages. +# debug: messages useful only when debugging the code. This may +# spit out thousands per second. +# +# For events of each level, you can choose to crash, report, or ignore. +# TODO: allow choice based on the facility: e.g. crash on panics from +# everything except the cdrom, and only report those. +# +# If you are experiencing many panics, it can be helpful to change +# the panic action to report instead of fatal. However, be aware +# that anything executed after a panic is uncharted territory and can +# cause bochs to become unstable. The panic is a "graceful exit," so +# if you disable it you may get a spectacular disaster instead. +#======================================================================= +panic: action=ask +error: action=report +info: action=report +debug: action=ignore +#pass: action=fatal + +#======================================================================= +# DEBUGGER_LOG: +# Give the path of the log file you'd like Bochs to log debugger output. +# If you really don't want it, make it /dev/null or '-'. :^( +# +# Examples: +# debugger_log: ./debugger.out +#======================================================================= +#debugger_log: /dev/null +#debugger_log: debugger.out +debugger_log: - + +#======================================================================= +# COM1, COM2, COM3, COM4: +# This defines a serial port (UART type 16550A). In the 'term' you can specify +# a device to use as com1. This can be a real serial line, or a pty. To use +# a pty (under X/Unix), create two windows (xterms, usually). One of them will +# run bochs, and the other will act as com1. Find out the tty the com1 +# window using the `tty' command, and use that as the `dev' parameter. +# Then do `sleep 1000000' in the com1 window to keep the shell from +# messing with things, and run bochs in the other window. Serial I/O to +# com1 (port 0x3f8) will all go to the other window. +# Other serial modes are 'null' (no input/output), 'file' (output to a file +# specified as the 'dev' parameter), 'raw' (use the real serial port - under +# construction for win32), 'mouse' (standard serial mouse - requires +# mouse option setting 'type=serial' or 'type=serial_wheel') and 'socket' +# (connect a networking socket). +# +# Examples: +# com1: enabled=1, mode=null +# com1: enabled=1, mode=mouse +# com2: enabled=1, mode=file, dev=serial.out +# com3: enabled=1, mode=raw, dev=com1 +# com3: enabled=1, mode=socket, dev=localhost:8888 +#======================================================================= +com1: enabled=1, mode=socket, dev=localhost:5001 + + +#======================================================================= +# PARPORT1, PARPORT2: +# This defines a parallel (printer) port. When turned on and an output file is +# defined the emulated printer port sends characters printed by the guest OS +# into the output file. On some platforms a device filename can be used to +# send the data to the real parallel port (e.g. "/dev/lp0" on Linux, "lpt1" on +# win32 platforms). +# +# Examples: +# parport1: enabled=1, file="parport.out" +# parport2: enabled=1, file="/dev/lp0" +# parport1: enabled=0 +#======================================================================= +parport1: enabled=1, file="parport.out" + +#======================================================================= +# SB16: +# This defines the SB16 sound emulation. It can have several of the +# following properties. +# All properties are in the format sb16: property=value +# midi: The filename is where the midi data is sent. This can be a +# device or just a file if you want to record the midi data. +# midimode: +# 0=no data +# 1=output to device (system dependent. midi denotes the device driver) +# 2=SMF file output, including headers +# 3=output the midi data stream to the file (no midi headers and no +# delta times, just command and data bytes) +# wave: This is the device/file where wave output is stored +# wavemode: +# 0=no data +# 1=output to device (system dependent. wave denotes the device driver) +# 2=VOC file output, incl. headers +# 3=output the raw wave stream to the file +# log: The file to write the sb16 emulator messages to. +# loglevel: +# 0=no log +# 1=resource changes, midi program and bank changes +# 2=severe errors +# 3=all errors +# 4=all errors plus all port accesses +# 5=all errors and port accesses plus a lot of extra info +# dmatimer: +# microseconds per second for a DMA cycle. Make it smaller to fix +# non-continuous sound. 750000 is usually a good value. This needs a +# reasonably correct setting for the IPS parameter of the CPU option. +# +# For an example look at the next line: +#======================================================================= + +#sb16: midimode=1, midi=/dev/midi00, wavemode=1, wave=/dev/dsp, loglevel=2, log=sb16.log, dmatimer=600000 + +#======================================================================= +# VGA_UPDATE_INTERVAL: +# Video memory is scanned for updates and screen updated every so many +# virtual seconds. The default is 40000, about 25Hz. Keep in mind that +# you must tweak the 'cpu: ips=N' directive to be as close to the number +# of emulated instructions-per-second your workstation can do, for this +# to be accurate. +# +# Examples: +# vga_update_interval: 250000 +#======================================================================= +vga_update_interval: 300000 + +# using for Winstone '98 tests +#vga_update_interval: 100000 + +#======================================================================= +# KEYBOARD_SERIAL_DELAY: +# Approximate time in microseconds that it takes one character to +# be transfered from the keyboard to controller over the serial path. +# Examples: +# keyboard_serial_delay: 200 +#======================================================================= +keyboard_serial_delay: 250 + +#======================================================================= +# KEYBOARD_PASTE_DELAY: +# Approximate time in microseconds between attempts to paste +# characters to the keyboard controller. This leaves time for the +# guest os to deal with the flow of characters. The ideal setting +# depends on how your operating system processes characters. The +# default of 100000 usec (.1 seconds) was chosen because it works +# consistently in Windows. +# +# If your OS is losing characters during a paste, increase the paste +# delay until it stops losing characters. +# +# Examples: +# keyboard_paste_delay: 100000 +#======================================================================= +keyboard_paste_delay: 100000 + +#======================================================================= +# MOUSE: +# This option prevents Bochs from creating mouse "events" unless a mouse +# is enabled. The hardware emulation itself is not disabled by this. +# You can turn the mouse on by setting enabled to 1, or turn it off by +# setting enabled to 0. Unless you have a particular reason for enabling +# the mouse by default, it is recommended that you leave it off. +# You can also toggle the mouse usage at runtime (control key + middle +# mouse button on X11, SDL, wxWidgets and Win32). +# With the mouse type option you can select the type of mouse to emulate. +# The default value is 'ps2'. The other choices are 'imps2' (wheel mouse +# on PS/2), 'serial', 'serial_wheel' (one com port requires setting +# 'mode=mouse') and 'usb' (3-button mouse - one of the USB ports must be +# connected with the 'mouse' device - requires PCI and USB support). +# +# Examples: +# mouse: enabled=1 +# mouse: enabled=1, type=imps2 +# mouse: enabled=1, type=serial +# mouse: enabled=0 +#======================================================================= +mouse: enabled=0 + +#======================================================================= +# private_colormap: Request that the GUI create and use it's own +# non-shared colormap. This colormap will be used +# when in the bochs window. If not enabled, a +# shared colormap scheme may be used. Not implemented +# on all GUI's. +# +# Examples: +# private_colormap: enabled=1 +# private_colormap: enabled=0 +#======================================================================= +private_colormap: enabled=0 + +#======================================================================= +# fullscreen: ONLY IMPLEMENTED ON AMIGA +# Request that Bochs occupy the entire screen instead of a +# window. +# +# Examples: +# fullscreen: enabled=0 +# fullscreen: enabled=1 +#======================================================================= +#fullscreen: enabled=0 +#screenmode: name="sample" + +#======================================================================= +# ne2k: NE2000 compatible ethernet adapter +# +# Examples: +# ne2k: ioaddr=IOADDR, irq=IRQ, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT +# +# ioaddr, irq: You probably won't need to change ioaddr and irq, unless there +# are IRQ conflicts. +# +# mac: The MAC address MUST NOT match the address of any machine on the net. +# Also, the first byte must be an even number (bit 0 set means a multicast +# address), and you cannot use ff:ff:ff:ff:ff:ff because that's the broadcast +# address. For the ethertap module, you must use fe:fd:00:00:00:01. There may +# be other restrictions too. To be safe, just use the b0:c4... address. +# +# ethdev: The ethdev value is the name of the network interface on your host +# platform. On UNIX machines, you can get the name by running ifconfig. On +# Windows machines, you must run niclist to get the name of the ethdev. +# Niclist source code is in misc/niclist.c and it is included in Windows +# binary releases. +# +# script: The script value is optional, and is the name of a script that +# is executed after bochs initialize the network interface. You can use +# this script to configure this network interface, or enable masquerading. +# This is mainly useful for the tun/tap devices that only exist during +# Bochs execution. The network interface name is supplied to the script +# as first parameter +# +# If you don't want to make connections to any physical networks, +# you can use the following 'ethmod's to simulate a virtual network. +# null: All packets are discarded, but logged to a few files. +# arpback: ARP is simulated. Disabled by default. +# vde: Virtual Distributed Ethernet +# vnet: ARP, ICMP-echo(ping), DHCP and read/write TFTP are simulated. +# The virtual host uses 192.168.10.1. +# DHCP assigns 192.168.10.2 to the guest. +# TFTP uses the ethdev value for the root directory and doesn't +# overwrite files. +# +#======================================================================= +# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=fbsd, ethdev=en0 #macosx +# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=fbsd, ethdev=xl0 +# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0 +# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=win32, ethdev=MYCARD +# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0 +# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun0, script=./tunconfig +# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=null, ethdev=eth0 +# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=vde, ethdev="/tmp/vde.ctl" +# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=vnet, ethdev="c:/temp" + +#======================================================================= +# KEYBOARD_MAPPING: +# This enables a remap of a physical localized keyboard to a +# virtualized us keyboard, as the PC architecture expects. +# If enabled, the keymap file must be specified. +# +# Examples: +# keyboard_mapping: enabled=1, map=gui/keymaps/x11-pc-de.map +#======================================================================= +keyboard_mapping: enabled=0, map= + +#======================================================================= +# KEYBOARD_TYPE: +# Type of keyboard return by a "identify keyboard" command to the +# keyboard controler. It must be one of "xt", "at" or "mf". +# Defaults to "mf". It should be ok for almost everybody. A known +# exception is french macs, that do have a "at"-like keyboard. +# +# Examples: +# keyboard_type: mf +#======================================================================= +#keyboard_type: mf + +#======================================================================= +# USER_SHORTCUT: +# This defines the keyboard shortcut to be sent when you press the "user" +# button in the headerbar. The shortcut string is a combination of maximum +# 3 key names (listed below) separated with a '-' character. The old-style +# syntax (without the '-') still works for the key combinations supported +# in Bochs 2.2.1. +# Valid key names: +# "alt", "bksl", "bksp", "ctrl", "del", "down", "end", "enter", "esc", +# "f1", ... "f12", "home", "ins", "left", "menu", "minus", "pgdwn", "pgup", +# "plus", "right", "shift", "space", "tab", "up", and "win". +# +# Example: +# user_shortcut: keys=ctrl-alt-del +#======================================================================= +#user_shortcut: keys=ctrl-alt-del + +#======================================================================= +# I440FXSUPPORT: +# This option controls the presence of the i440FX PCI chipset. You can +# also specify the devices connected to PCI slots. Up to 5 slots are +# available now. These devices are currently supported: ne2k, pcivga, +# pcidev and pcipnic. If Bochs is compiled with Cirrus SVGA support +# you'll have the additional choice 'cirrus'. +# +# Example: +# i440fxsupport: enabled=1, slot1=pcivga, slot2=ne2k +#======================================================================= +i440fxsupport: enabled=1 + +#======================================================================= +# USB1: +# This option controls the presence of the USB root hub which is a part +# of the i440FX PCI chipset. With the portX option you can connect devices +# to the hub (currently supported: 'mouse' and 'keypad'). If you connect +# the mouse to one of the ports and use the mouse option 'type=usb' you'll +# have a 3-button USB mouse. +# +# Example: +# usb1: enabled=1, port1=mouse, port2=keypad +#======================================================================= +#usb1: enabled=1 + +#======================================================================= +# CMOSIMAGE: +# This defines image file that can be loaded into the CMOS RAM at startup. +# The rtc_init parameter controls whether initialize the RTC with values stored +# in the image. By default the time0 argument given to the clock option is used. +# With 'rtc_init=image' the image is the source for the initial time. +# +# Example: +# cmosimage: file=cmos.img, rtc_init=image +#======================================================================= +#cmosimage: file=cmos.img, rtc_init=time0 + +#======================================================================= +# other stuff +#======================================================================= +#magic_break: enabled=1 +#load32bitOSImage: os=nullkernel, path=../kernel.img, iolog=../vga_io.log +#load32bitOSImage: os=linux, path=../linux.img, iolog=../vga_io.log, initrd=../initrd.img +#text_snapshot_check: enable + +#------------------------- +# PCI host device mapping +#------------------------- +#pcidev: vendor=0x1234, device=0x5678 + +#======================================================================= +# GDBSTUB: +# Enable GDB stub. See user documentation for details. +# Default value is enabled=0. +#======================================================================= +#gdbstub: enabled=0, port=1234, text_base=0, data_base=0, bss_base=0 + +#======================================================================= +# IPS: +# The IPS directive is DEPRECATED. Use the parameter IPS of the CPU +# directive instead. +#======================================================================= +#ips: 10000000 + +#======================================================================= +# for Macintosh, use the style of pathnames in the following +# examples. +# +# vgaromimage: :bios:VGABIOS-elpin-2.40 +# romimage: file=:bios:BIOS-bochs-latest, address=0xf0000 +# floppya: 1_44=[fd:], status=inserted +#======================================================================= diff --git a/palacios/build/Makefile b/palacios/build/Makefile new file mode 100644 index 0000000..941b8bd --- /dev/null +++ b/palacios/build/Makefile @@ -0,0 +1,396 @@ +# Makefile for GeekOS kernel, userspace, and tools +# Copyright (c) 2004,2005 David H. Hovemeyer +# $Revision: 1.1 $ + +# This is free software. You are permitted to use, +# redistribute, and modify it as specified in the file "COPYING". + +# Required software to build GeekOS: +# - GNU Make (http://www.gnu.org/software/make) +# - gcc 2.95.2 generating code for target (i386/ELF) and host platforms +# - nasm (http://nasm.sourceforge.net) +# - Perl5, AWK (any version), egrep +# +# Cygwin (http://cygwin.com) may be used to build GeekOS. +# Make sure that gcc, binutils, nasm, and perl are installed. + +# NOTES: +# - This makefile has been written carefully to work correctly +# with the -j (parallel make) option. I regularly use "make -j 2" +# to speed the build process on 2 processor systems. + + + +# THESE MUST MATCH WHAT IS DEFINED IN defs.h and defs.asm exactly +# MUST BE INTEGRAL NUMBER OF PAGES +TOP_OF_MEM := 0x40000000 +VM_SIZE := 0x20000000 +VM_START := 0x0 + +# +# THE KERNEL, SETUP, BOOTPACKAGE MUST BE SMALLER THAN THIS +# MUST BE INTEGRAL NUMBER OF PAGES +# define +MAX_VMM := 0x60000 + +# Base address of kernel +# +# Note: at top of memory minus three pages (GDT/TSS/IDT) +# minus maximum size +# +# +# Note that the code will initially load at 0x10000 +# +# The setup code needs to copy it up to this address and jump there +# +KERNEL_BASE_ADDR := $(shell perl -e 'print sprintf("0x%x",$(TOP_OF_MEM)-4096*3-$(MAX_VMM));') + +# Kernel entry point function +KERNEL_ENTRY = $(SYM_PFX)Main + + +PROJECT_ROOT := .. +VPATH := $(PROJECT_ROOT)/src + +#when -DNDEBUG is set the kassert functions are disabled +#JRLDEBUG=-DNDEBUG +JRLDEBUG= -DSERIAL_PRINT_DEBUG=1 -DSERIAL_PRINT_DEBUG_LEVEL=1000 -DSERIAL_PRINT=1 + +# +# +#Peter's compile flags +PADFLAGS = -DMAX_VMM=$(MAX_VMM) + +# Figure out if we're compiling with cygwin, http://cygwin.com +SYSTEM_NAME := $(shell uname -s) +ifeq ($(findstring CYGWIN,$(SYSTEM_NAME)),CYGWIN) +SYM_PFX := _ +EXTRA_C_OPTS := -DNEED_UNDERSCORE -DGNU_WIN32 +EXTRA_NASM_OPTS := -DNEED_UNDERSCORE +NON_ELF_SYSTEM := yes +EXTRA_CC_USER_OPTS := -Dmain=geekos_main +endif + +VMM_SIZES = ../include/geekos/vmm_sizes.h + + +# ---------------------------------------------------------------------- +# Configuration - +# Various options specifying how GeekOS should be built, +# what source files to build, which user programs to build, +# etc. This is generally the only section of the makefile +# that will need to be modified. +# ---------------------------------------------------------------------- + +# List of targets to build by default. +# These targets encompass everything needed to boot +# and run GeekOS. +ALL_TARGETS := fd.img rombios vgabios vmxassist + + +# Kernel source files +KERNEL_C_SRCS := idt.c int.c trap.c irq.c io.c \ + keyboard.c screen.c timer.c \ + mem.c crc32.c \ + gdt.c tss.c segment.c \ + bget.c malloc.c \ + synch.c kthread.c \ + serial.c reboot.c \ + paging.c vmx.c vmcs_gen.c vmcs.c\ + main.c + +# Kernel object files built from C source files +KERNEL_C_OBJS := $(KERNEL_C_SRCS:%.c=geekos/%.o) + +# Kernel assembly files +KERNEL_ASM_SRCS := lowlevel.asm vmx_lowlevel.asm + +KERNEL_GAS_SRCS := testvm.s + +# Kernel object files build from assembler source files +KERNEL_ASM_OBJS := $(KERNEL_ASM_SRCS:%.asm=geekos/%.o) + +KERNEL_GAS_OBJS := $(KERNEL_GAS_SRCS:%.s=geekos/%.o) + + +# All kernel object files +KERNEL_OBJS := $(KERNEL_C_OBJS) \ + $(KERNEL_ASM_OBJS) $(KERNEL_GAS_OBJS) + +# Common library source files. +# This library is linked into both the kernel and user programs. +# It provides string functions and generic printf()-style +# formatted output. +COMMON_C_SRCS := fmtout.c string.c memmove.c + +# Common library object files. +COMMON_C_OBJS := $(COMMON_C_SRCS:%.c=common/%.o) + + + + +# ---------------------------------------------------------------------- +# Tools - +# This section defines programs that are used to build GeekOS. +# ---------------------------------------------------------------------- + +# Uncomment if cross compiling +#TARGET_CC_PREFIX := i386-elf- + +# Target C compiler. gcc 2.95.2 or later should work. +TARGET_CC := $(TARGET_CC_PREFIX)gcc + +# Host C compiler. This is used to compile programs to execute on +# the host platform, not the target (x86) platform. On x86/ELF +# systems, such as Linux and FreeBSD, it can generally be the same +# as the target C compiler. +HOST_CC := gcc + +# Target linker. GNU ld is probably to only one that will work. +TARGET_LD := $(TARGET_CC_PREFIX)ld + +# Target archiver +TARGET_AR := $(TARGET_CC_PREFIX)ar + +# Target ranlib +TARGET_RANLIB := $(TARGET_CC_PREFIX)ranlib + +# Target nm +TARGET_NM := $(TARGET_CC_PREFIX)nm + +# Target objcopy +TARGET_OBJCOPY := $(TARGET_CC_PREFIX)objcopy + +# Nasm (http://nasm.sourceforge.net) +NASM := /usr/local/nasm-vmx/bin/nasm + +AS = as + +# Tool to build PFAT filesystem images. +BUILDFAT := tools/builtFat.exe + +# Perl5 or later +PERL := perl + +# Pad a file so its size is a multiple of some unit (i.e., sector size) +PAD := $(PERL) $(PROJECT_ROOT)/scripts/pad + +# Create a file filled with zeroes. +ZEROFILE := $(PERL) $(PROJECT_ROOT)/scripts/zerofile + +# Calculate size of file in sectors +NUMSECS := $(PERL) $(PROJECT_ROOT)/scripts/numsecs + + +# ---------------------------------------------------------------------- +# Definitions - +# Options passed to the tools. +# ---------------------------------------------------------------------- + +# Flags used for all C source files +GENERAL_OPTS := -O -Wall $(EXTRA_C_OPTS) $(JRLDEBUG) $(PADFLAGS) +CC_GENERAL_OPTS := $(GENERAL_OPTS) -Werror + +# Flags used for kernel C source files +CC_KERNEL_OPTS := -g -DGEEKOS -I$(PROJECT_ROOT)/include + +# Flags user for kernel assembly files +NASM_KERNEL_OPTS := -I$(PROJECT_ROOT)/src/geekos/ -f elf $(EXTRA_NASM_OPTS) + +# Flags used for common library and libc source files +CC_USER_OPTS := -I$(PROJECT_ROOT)/include -I$(PROJECT_ROOT)/include/libc \ + $(EXTRA_CC_USER_OPTS) + +# Flags passed to objcopy program (strip unnecessary sections from kernel.exe) +OBJCOPY_FLAGS := -R .dynamic -R .note -R .comment + +# ---------------------------------------------------------------------- +# Rules - +# Describes how to compile the source files. +# ---------------------------------------------------------------------- + +# Compilation of kernel C source files + +geekos/%.o : geekos/%.c + $(TARGET_CC) -c $(CC_GENERAL_OPTS) $(CC_KERNEL_OPTS) $< -o geekos/$*.o + + +# Compilation of kernel assembly source files +geekos/%.o : geekos/%.asm + $(NASM) $(NASM_KERNEL_OPTS) $< -o geekos/$*.o + +# Compilation of test VM +geekos/%.o : geekos/%.s + $(AS) $< -o geekos/$*.o + +geekos/%.o : geekos/%.S + $(TARGET_CC) -c $(CC_GENERAL_OPTS) $(CC_KERNEL_OPTS) $< -o geekos/$*.o + +# Compilation of common library C source files +common/%.o : common/%.c + $(TARGET_CC) -c $(CC_GENERAL_OPTS) $(CC_USER_OPTS) $< -o common/$*.o + +# ---------------------------------------------------------------------- +# Targets - +# Specifies files to be built +# ---------------------------------------------------------------------- + +# Default target - see definition of ALL_TARGETS in Configuration section +all : $(ALL_TARGETS) + + +geekos/vmx_lowlevel.o: $(PROJECT_ROOT)/src/geekos/vmx_lowlevel.asm + $(NASM) -O99 \ + -f elf \ + -I$(PROJECT_ROOT)/src/geekos/ \ + $(PROJECT_ROOT)/src/geekos/vmx_lowlevel.asm \ + -o $@ + + +geekos/test: geekos/test.o geekos/vmcs.o geekos/vmx_lowlevel.o + $(CC) geekos/test.o geekos/vmcs.o geekos/vmx_lowlevel.o -o geekos/test + +# Standard floppy image - just boots the kernel +fd.img : geekos/fd_boot.bin geekos/setup.bin geekos/kernel.bin rombios vgabios vmxassist + cat geekos/fd_boot.bin geekos/setup.bin geekos/kernel.bin > _temp + $(PAD) _temp 512 +# Note - second copy of rombios is intentional + cat _temp rombios vgabios vmxassist rombios > $@ + +# make ready to boot over PXE +pxe: fd.img + cp fd.img /tftpboot/geekos.img + $(PAD) /tftpboot/geekos.img 1474560 + + +pxe-discovery-pdinda: fd.img + cp fd.img geekos.img + $(PAD) geekos.img 1474560 + /usr/local/vmm-util/pxe_cp geekos.img + /usr/local/vmm-util/tty_perm pdinda + echo "Copied file to PXE boot area and set serial permissions for pdinda" + + +pxe-discovery-bjp600: fd.img + cp fd.img geekos.img + $(PAD) geekos.img 1474560 + /usr/local/vmm-util/pxe_cp geekos.img + /usr/local/vmm-util/tty_perm bjp600 + echo "Copied file to PXE boot area and set serial permissions for pdinda" + + +# Floppy boot sector (first stage boot loader). +geekos/fd_boot.bin : geekos/setup.bin geekos/kernel.bin $(PROJECT_ROOT)/src/geekos/fd_boot.asm rombios vgabios vmxassist + $(NASM) -f bin \ + -I$(PROJECT_ROOT)/src/geekos/ \ + -DNUM_SETUP_SECTORS=`$(NUMSECS) geekos/setup.bin` \ + -DNUM_KERN_SECTORS=`$(NUMSECS) geekos/kernel.bin` \ + -DNUM_BIOS_SECTORS=`$(NUMSECS) rombios` \ + -DNUM_VGA_BIOS_SECTORS=`$(NUMSECS) vgabios` \ + -DNUM_VMXASSIST_SECTORS=`$(NUMSECS) vmxassist` \ + $(PROJECT_ROOT)/src/geekos/fd_boot.asm \ + -o $@ + +# Setup program (second stage boot loader). +geekos/setup.bin : geekos/kernel.exe $(PROJECT_ROOT)/src/geekos/setup.asm + $(NASM) -f bin \ + -I$(PROJECT_ROOT)/src/geekos/ \ + -DENTRY_POINT=0x`egrep 'Main$$' geekos/kernel.syms |awk '{print $$1}'` \ + -DVMM_FINAL_ADDR=$(KERNEL_BASE_ADDR) \ + -DVMM_SIZE=$(MAX_VMM) \ + $(PROJECT_ROOT)/src/geekos/setup.asm \ + -o $@ + $(PAD) $@ 512 + +# Loadable (flat) kernel image. +geekos/kernel.bin : geekos/kernel.exe + $(TARGET_OBJCOPY) $(OBJCOPY_FLAGS) -S -O binary geekos/kernel.exe geekos/kernel.bin + $(PAD) $@ 512 + +# The kernel executable and symbol map. +geekos/kernel.exe : $(KERNEL_OBJS) $(COMMON_C_OBJS) + $(TARGET_LD) -o geekos/kernel.exe -Ttext $(KERNEL_BASE_ADDR) -e $(KERNEL_ENTRY) \ + $(KERNEL_OBJS) $(COMMON_C_OBJS) + $(TARGET_NM) geekos/kernel.exe > geekos/kernel.syms + + +generate_sizes: force + echo "#ifndef __vmm_sizes" > $(VMM_SIZES) + echo "#define __vmm_sizes" >> $(VMM_SIZES) + echo "#define KERNEL_LOAD_ADDRESS " $(KERNEL_BASE_ADDR) >> $(VMM_SIZES) + echo "#define KERNEL_SETUP_LENGTH (" `$(NUMSECS) geekos/setup.bin` "*512)" >> $(VMM_SIZES) + echo "#define KERNEL_CORE_LENGTH (" `$(NUMSECS) geekos/kernel.bin` "*512)" >> $(VMM_SIZES) + echo "#define KERNEL_START (KERNEL_LOAD_ADDRESS)" >> $(VMM_SIZES) + echo "#define KERNEL_END (KERNEL_LOAD_ADDRESS+KERNEL_CORE_LENGTH-1)" >> $(VMM_SIZES) + echo "#define BIOS_LENGTH (" `$(NUMSECS) rombios` "*512)" >> $(VMM_SIZES) + echo "#define VGA_BIOS_LENGTH (" `$(NUMSECS) vgabios` "*512)" >> $(VMM_SIZES) + echo "#define VMXASSIST_LENGTH (" `$(NUMSECS) vmxassist` "*512)" >> $(VMM_SIZES) + echo "#define BIOS_START (KERNEL_LOAD_ADDRESS+KERNEL_CORE_LENGTH)" >> $(VMM_SIZES) + echo "#define VGA_BIOS_START (BIOS_START+BIOS_LENGTH)" >> $(VMM_SIZES) + echo "#define VMXASSIST_START (VGA_BIOS_START+VGA_BIOS_LENGTH)" >> $(VMM_SIZES) + echo "//Note this is a second copy of the rom bios for debug" >> $(VMM_SIZES) + echo "#define BIOS2_START (VMXASSIST_START+VMXASSIST_LENGTH)" >> $(VMM_SIZES) + echo "#define VM_BOOT_PACKAGE_START (BIOS_START) " >> $(VMM_SIZES) + echo "#define VM_BOOT_PACKAGE_END (BIOS2_START+BIOS_LENGTH-1) " >> $(VMM_SIZES) + echo "#endif" >> $(VMM_SIZES) + +make_show_sizes: generate_sizes ../src/geekos/show_sizes.c + $(HOST_CC) -I../include/geekos ../src/geekos/show_sizes.c -o show_sizes + +show_sizes: make_show_sizes + ./show_sizes + + +get_kernel_size: make_show_sizes + ./show_sizes | grep + +force: + + +rombios: force + (cd ../src/vmboot/rombios; make) + cp ../src/vmboot/rombios/BIOS-bochs-latest rombios + $(PAD) rombios 512 + @echo "Rom bios lives at f000:0000 and is" `$(NUMSECS) rombios` "sectors long" + + +vgabios: force + (cd ../src/vmboot/vgabios; make) + cp ../src/vmboot/vgabios/vgabios.bin vgabios + $(PAD) vgabios 512 + @echo "Vga bios lives at c000:0000 and is" `$(NUMSECS) vgabios` "sectors long" + +vmxassist: force + (cd ../src/vmboot/vmxassist; make) + cp ../src/vmboot/vmxassist/vmxassist.bin vmxassist + $(PAD) vmxassist 512 + @echo "vmxassist lives at d000:0000 and is" `$(NUMSECS) vmxassist` "sectors long" + +# Clean build directories of generated files +clean : + rm -f rombios vgabios vmxassist + (cd ../src/vmboot/rombios; make clean) + (cd ../src/vmboot/vgabios; make clean) + (cd ../src/vmboot/vmxassist; make clean) + for d in geekos common libc user tools; do \ + (cd $$d && rm -f *); \ + done + + +# Build header file dependencies, so source files are recompiled when +# header files they depend on are modified. +depend : $(GENERATED_LIBC_SRCS) + $(TARGET_CC) -M $(CC_GENERAL_OPTS) $(CC_KERNEL_OPTS) \ + $(KERNEL_C_SRCS:%.c=$(PROJECT_ROOT)/src/geekos/%.c) \ + | $(PERL) -n -e 's,^(\S),geekos/$$1,;print' \ + > depend.mak + $(TARGET_CC) -M $(CC_GENERAL_OPTS) $(CC_USER_OPTS) \ + $(COMMON_C_SRCS:%.c=$(PROJECT_ROOT)/src/common/%.c) \ + | $(PERL) -n -e 's,^(\S),common/$$1,;print' \ + >> depend.mak + +# By default, there are no header file dependencies. +depend.mak : + touch $@ + +include depend.mak diff --git a/palacios/build/common/.ignore b/palacios/build/common/.ignore new file mode 100644 index 0000000..491aec8 --- /dev/null +++ b/palacios/build/common/.ignore @@ -0,0 +1 @@ +This file is just here to ensure that the directory exists. diff --git a/palacios/build/depend.mak b/palacios/build/depend.mak new file mode 100644 index 0000000..b7fa572 --- /dev/null +++ b/palacios/build/depend.mak @@ -0,0 +1,198 @@ +geekos/idt.o: ../src/geekos/idt.c ../include/geekos/kassert.h \ + ../include/geekos/screen.h ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/defs.h ../include/geekos/idt.h \ + ../include/geekos/int.h +geekos/int.o: ../src/geekos/int.c ../include/geekos/idt.h \ + ../include/geekos/int.h ../include/geekos/kassert.h \ + ../include/geekos/screen.h ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/defs.h ../include/geekos/serial.h \ + ../include/geekos/irq.h ../include/geekos/string.h \ + ../include/geekos/../libc/string.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stddef.h \ + ../include/geekos/io.h +geekos/trap.o: ../src/geekos/trap.c ../include/geekos/idt.h \ + ../include/geekos/int.h ../include/geekos/kassert.h \ + ../include/geekos/screen.h ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/defs.h ../include/geekos/kthread.h \ + ../include/geekos/list.h ../include/geekos/trap.h +geekos/irq.o: ../src/geekos/irq.c ../include/geekos/kassert.h \ + ../include/geekos/screen.h ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/idt.h ../include/geekos/int.h \ + ../include/geekos/defs.h ../include/geekos/io.h ../include/geekos/irq.h +geekos/io.o: ../src/geekos/io.c ../include/geekos/io.h \ + ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h +geekos/keyboard.o: ../src/geekos/keyboard.c ../include/geekos/kthread.h \ + ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/list.h ../include/geekos/kassert.h \ + ../include/geekos/screen.h ../include/geekos/irq.h \ + ../include/geekos/int.h ../include/geekos/defs.h ../include/geekos/io.h \ + ../include/geekos/keyboard.h +geekos/screen.o: ../src/geekos/screen.c \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdarg.h \ + ../include/geekos/kassert.h ../include/geekos/screen.h \ + ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/io.h ../include/geekos/int.h ../include/geekos/defs.h \ + ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h +geekos/timer.o: ../src/geekos/timer.c \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/limits.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/syslimits.h \ + /usr/include/limits.h /usr/include/features.h /usr/include/sys/cdefs.h \ + /usr/include/gnu/stubs.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/posix2_lim.h ../include/geekos/io.h \ + ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/int.h ../include/geekos/kassert.h \ + ../include/geekos/screen.h ../include/geekos/defs.h \ + ../include/geekos/irq.h ../include/geekos/kthread.h \ + ../include/geekos/list.h ../include/geekos/timer.h +geekos/mem.o: ../src/geekos/mem.c ../include/geekos/defs.h \ + ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/kassert.h ../include/geekos/screen.h \ + ../include/geekos/bootinfo.h ../include/geekos/gdt.h \ + ../include/geekos/int.h ../include/geekos/malloc.h \ + ../include/geekos/string.h ../include/geekos/../libc/string.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stddef.h \ + ../include/geekos/mem.h ../include/geekos/list.h \ + ../include/geekos/paging.h +geekos/crc32.o: ../src/geekos/crc32.c ../include/geekos/crc32.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stddef.h \ + ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/kassert.h ../include/geekos/screen.h +geekos/gdt.o: ../src/geekos/gdt.c ../include/geekos/kassert.h \ + ../include/geekos/screen.h ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/segment.h ../include/geekos/int.h \ + ../include/geekos/defs.h ../include/geekos/tss.h \ + ../include/geekos/gdt.h +geekos/tss.o: ../src/geekos/tss.c ../include/geekos/kassert.h \ + ../include/geekos/screen.h ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/defs.h ../include/geekos/gdt.h \ + ../include/geekos/segment.h ../include/geekos/string.h \ + ../include/geekos/../libc/string.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stddef.h \ + ../include/geekos/tss.h +geekos/segment.o: ../src/geekos/segment.c ../include/geekos/kassert.h \ + ../include/geekos/screen.h ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/string.h ../include/geekos/../libc/string.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stddef.h \ + ../include/geekos/tss.h ../include/geekos/segment.h +geekos/bget.o: ../src/geekos/bget.c ../include/geekos/string.h \ + ../include/geekos/../libc/string.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stddef.h \ + ../include/geekos/kassert.h ../include/geekos/screen.h \ + ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/bget.h +geekos/malloc.o: ../src/geekos/malloc.c ../include/geekos/screen.h \ + ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/int.h ../include/geekos/kassert.h \ + ../include/geekos/defs.h ../include/geekos/bget.h \ + ../include/geekos/malloc.h +geekos/synch.o: ../src/geekos/synch.c ../include/geekos/kthread.h \ + ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/list.h ../include/geekos/kassert.h \ + ../include/geekos/screen.h ../include/geekos/int.h \ + ../include/geekos/defs.h ../include/geekos/synch.h +geekos/kthread.o: ../src/geekos/kthread.c ../include/geekos/kassert.h \ + ../include/geekos/screen.h ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/defs.h ../include/geekos/int.h \ + ../include/geekos/mem.h ../include/geekos/list.h \ + ../include/geekos/paging.h ../include/geekos/bootinfo.h \ + ../include/geekos/symbol.h ../include/geekos/string.h \ + ../include/geekos/../libc/string.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stddef.h \ + ../include/geekos/kthread.h ../include/geekos/malloc.h +geekos/serial.o: ../src/geekos/serial.c ../include/geekos/serial.h \ + ../include/geekos/irq.h ../include/geekos/int.h \ + ../include/geekos/kassert.h ../include/geekos/screen.h \ + ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/defs.h ../include/geekos/string.h \ + ../include/geekos/../libc/string.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stddef.h \ + ../include/geekos/io.h ../include/geekos/reboot.h \ + ../include/geekos/gdt.h ../include/geekos/idt.h +geekos/reboot.o: ../src/geekos/reboot.c ../include/geekos/reboot.h \ + ../include/libc/string.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stddef.h +geekos/paging.o: ../src/geekos/paging.c ../include/geekos/string.h \ + ../include/geekos/../libc/string.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stddef.h \ + ../include/geekos/int.h ../include/geekos/kassert.h \ + ../include/geekos/screen.h ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/defs.h ../include/geekos/idt.h \ + ../include/geekos/kthread.h ../include/geekos/list.h \ + ../include/geekos/mem.h ../include/geekos/paging.h \ + ../include/geekos/bootinfo.h ../include/geekos/malloc.h \ + ../include/geekos/gdt.h ../include/geekos/segment.h \ + ../include/geekos/crc32.h ../include/geekos/serial.h \ + ../include/geekos/irq.h ../include/geekos/io.h +geekos/vmx.o: ../src/geekos/vmx.c ../include/geekos/vmx.h \ + ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/vmcs.h ../include/geekos/serial.h \ + ../include/geekos/irq.h ../include/geekos/int.h \ + ../include/geekos/kassert.h ../include/geekos/screen.h \ + ../include/geekos/defs.h ../include/geekos/string.h \ + ../include/geekos/../libc/string.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stddef.h \ + ../include/geekos/io.h ../include/geekos/vmcs_gen.h \ + ../include/geekos/mem.h ../include/geekos/list.h \ + ../include/geekos/paging.h ../include/geekos/bootinfo.h +geekos/vmcs_gen.o: ../src/geekos/vmcs_gen.c ../include/geekos/vmcs_gen.h \ + ../include/geekos/vmcs.h ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/serial.h ../include/geekos/irq.h \ + ../include/geekos/int.h ../include/geekos/kassert.h \ + ../include/geekos/screen.h ../include/geekos/defs.h \ + ../include/geekos/string.h ../include/geekos/../libc/string.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stddef.h \ + ../include/geekos/io.h +geekos/main.o: ../src/geekos/main.c ../include/geekos/bootinfo.h \ + ../include/geekos/string.h ../include/geekos/../libc/string.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stddef.h \ + ../include/geekos/screen.h ../include/geekos/ktypes.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdbool.h \ + ../include/geekos/mem.h ../include/geekos/defs.h \ + ../include/geekos/list.h ../include/geekos/kassert.h \ + ../include/geekos/paging.h ../include/geekos/crc32.h \ + ../include/geekos/tss.h ../include/geekos/int.h \ + ../include/geekos/kthread.h ../include/geekos/trap.h \ + ../include/geekos/timer.h ../include/geekos/keyboard.h \ + ../include/geekos/io.h ../include/geekos/serial.h \ + ../include/geekos/irq.h ../include/geekos/reboot.h \ + ../include/geekos/vmx.h ../include/geekos/vmcs.h \ + ../include/geekos/vmcs_gen.h +common/fmtout.o: ../src/common/fmtout.c \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdarg.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stddef.h \ + ../include/geekos/string.h ../include/geekos/../libc/string.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/limits.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/syslimits.h \ + /usr/include/limits.h /usr/include/features.h /usr/include/sys/cdefs.h \ + /usr/include/gnu/stubs.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/posix2_lim.h ../include/geekos/fmtout.h \ + ../include/geekos/../libc/fmtout.h +common/string.o: ../src/common/string.c ../include/libc/fmtout.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stdarg.h \ + ../include/libc/string.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stddef.h +common/memmove.o: ../src/common/memmove.c ../include/libc/string.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.6/include/stddef.h diff --git a/palacios/build/geekos/.ignore b/palacios/build/geekos/.ignore new file mode 100644 index 0000000..491aec8 --- /dev/null +++ b/palacios/build/geekos/.ignore @@ -0,0 +1 @@ +This file is just here to ensure that the directory exists. diff --git a/palacios/build/libc/.ignore b/palacios/build/libc/.ignore new file mode 100644 index 0000000..491aec8 --- /dev/null +++ b/palacios/build/libc/.ignore @@ -0,0 +1 @@ +This file is just here to ensure that the directory exists. diff --git a/palacios/build/noboot.img b/palacios/build/noboot.img new file mode 100644 index 0000000..6d4f193 Binary files /dev/null and b/palacios/build/noboot.img differ diff --git a/palacios/build/tools/.ignore b/palacios/build/tools/.ignore new file mode 100644 index 0000000..491aec8 --- /dev/null +++ b/palacios/build/tools/.ignore @@ -0,0 +1 @@ +This file is just here to ensure that the directory exists. diff --git a/palacios/build/user/.ignore b/palacios/build/user/.ignore new file mode 100644 index 0000000..491aec8 --- /dev/null +++ b/palacios/build/user/.ignore @@ -0,0 +1 @@ +This file is just here to ensure that the directory exists. diff --git a/palacios/include/geekos/argblock.h b/palacios/include/geekos/argblock.h new file mode 100644 index 0000000..54fac8b --- /dev/null +++ b/palacios/include/geekos/argblock.h @@ -0,0 +1,34 @@ +/* + * Create and extract the command line argument block for a process + * Copyright (c) 2003 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_ARGBLOCK_H +#define GEEKOS_ARGBLOCK_H + +/** + * Header struct for accessing argument block from user mode. + * Just cast the address of the argument block passed by + * the kernel to a pointer to this struct. + */ +struct Argument_Block { + int argc; + char **argv; +}; + +#ifdef GEEKOS + +/* + * Functions used by the kernel to create the argument block. + */ +void Get_Argument_Block_Size(const char *command, unsigned *numArgs, ulong_t *argBlockSize); +void Format_Argument_Block(char *argBlock, unsigned numArgs, ulong_t userAddress, + const char *command); + +#endif + +#endif /* GEEKOS_ARGBLOCK_H */ diff --git a/palacios/include/geekos/bget.h b/palacios/include/geekos/bget.h new file mode 100644 index 0000000..63a0857 --- /dev/null +++ b/palacios/include/geekos/bget.h @@ -0,0 +1,44 @@ +/* + + Interface definitions for bget.c, the memory management package. + +*/ + +#if defined (GEEKOS) + +// Adapted for geekos: http://www.cs.umd.edu/~daveho/geekos/ +// Original version of BGET downloaded from: http://www.fourmilab.ch/bget/ +// $Revision: 1.1 $ + +// GeekOS changes are (mostly) confined to #if defined (GEEKOS) +// sections. + +// Yes, we have prototypes :-) +#define PROTOTYPES + +#endif // defined (GEEKOS) + +#ifndef _ +#ifdef PROTOTYPES +#define _(x) x /* If compiler knows prototypes */ +#else +#define _(x) () /* It it doesn't */ +#endif /* PROTOTYPES */ +#endif + +typedef long bufsize; +void bpool _((void *buffer, bufsize len)); +void *bget _((bufsize size)); +void *bgetz _((bufsize size)); +void *bgetr _((void *buffer, bufsize newsize)); +void brel _((void *buf)); +void bectl _((int (*compact)(bufsize sizereq, int sequence), + void *(*acquire)(bufsize size), + void (*release)(void *buf), bufsize pool_incr)); +void bstats _((bufsize *curalloc, bufsize *totfree, bufsize *maxfree, + long *nget, long *nrel)); +void bstatse _((bufsize *pool_incr, long *npool, long *npget, + long *nprel, long *ndget, long *ndrel)); +void bufdump _((void *buf)); +void bpoold _((void *pool, int dumpalloc, int dumpfree)); +int bpoolv _((void *pool)); diff --git a/palacios/include/geekos/bootinfo.h b/palacios/include/geekos/bootinfo.h new file mode 100644 index 0000000..bb50de1 --- /dev/null +++ b/palacios/include/geekos/bootinfo.h @@ -0,0 +1,18 @@ +/* + * Boot information structure, passed to kernel Main() routine + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_BOOTINFO_H +#define GEEKOS_BOOTINFO_H + +struct Boot_Info { + int bootInfoSize; /* size of this struct; for versioning */ + int memSizeKB; /* number of KB, as reported by int 15h */ +}; + +#endif /* GEEKOS_BOOTINFO_H */ diff --git a/palacios/include/geekos/crc32.h b/palacios/include/geekos/crc32.h new file mode 100644 index 0000000..1628b77 --- /dev/null +++ b/palacios/include/geekos/crc32.h @@ -0,0 +1,10 @@ +#ifndef GEEKOS_CRC32_H +#define GEEKOS_CRC32_H + +#include +#include + +void Init_CRC32(void); +ulong_t crc32(ulong_t crc, char const *buf, size_t len); + +#endif /* GEEKOS_CRC32_H */ diff --git a/palacios/include/geekos/defs.h b/palacios/include/geekos/defs.h new file mode 100644 index 0000000..bc631c1 --- /dev/null +++ b/palacios/include/geekos/defs.h @@ -0,0 +1,146 @@ +/* + * Misc. kernel definitions + * Copyright (c) 2001,2004 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_DEFS_H +#define GEEKOS_DEFS_H + + + + +/* + * Kernel code and data segment selectors. + * Keep these up to date with defs.asm. + */ +#define KERNEL_CS (1<<3) +#define KERNEL_DS (2<<3) + + +/* + * Address where kernel is loaded INITIALLY + * we move it up in memory soon + */ +#define KERNEL_START_ADDR 0x10000 + +/* + * Kernel and user privilege levels + */ +#define KERNEL_PRIVILEGE 0 +#define USER_PRIVILEGE 3 + + +/* + * Software interrupt for syscalls + */ +#define SYSCALL_INT 0x90 + +/* + * The windows versions of gcc use slightly different + * names for the bss begin and end symbols than the Linux version. + */ +#if defined(GNU_WIN32) +# define BSS_START _bss_start__ +# define BSS_END _bss_end__ +#else +# define BSS_START __bss_start +# define BSS_END end +#endif + +/* + * x86 has 4096 byte pages + */ +#define PAGE_POWER 12 +#define PAGE_SIZE (1<IDT_LOCATION) +#error VMM_MAX is too small! +#endif + + +#define KERNEL_THREAD_OBJECT (START_OF_VM+VM_SIZE) +#define KERNEL_STACK (KERNEL_THREAD_OBJECT+KERNEL_THREAD_OBJECT_SIZE) +#define KERNEL_HEAP (KERNEL_STACK+KERNEL_STACK_SIZE) +#define KERNEL_PAGELIST (KERNEL_HEAP+KERNEL_HEAP_SIZE) + + +/* + * PC memory map + */ +#define ISA_HOLE_START 0x0A0000 +#define ISA_HOLE_END 0x100000 + + +#endif /* GEEKOS_DEFS_H */ diff --git a/palacios/include/geekos/errno.h b/palacios/include/geekos/errno.h new file mode 100644 index 0000000..3159eae --- /dev/null +++ b/palacios/include/geekos/errno.h @@ -0,0 +1,37 @@ +/* + * GeekOS error codes + * Copyright (c) 2003,2004 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_ERRNO_H +#define GEEKOS_ERRNO_H + +/* + * Error codes returned by kernel functions and + * system calls. These are meant to be returned to user + * code to describe system call failures. + */ +#define EUNSPECIFIED -1 /* Unspecified error */ +#define ENOTFOUND -2 /* No such file or directory */ +#define EUNSUPPORTED -3 /* Operation not supported */ +#define ENODEV -4 /* No such device */ +#define EIO -5 /* Input/output error */ +#define EBUSY -6 /* Resource in use */ +#define ENOMEM -7 /* Out of memory */ +#define ENOFILESYS -8 /* No such filesystem */ +#define ENAMETOOLONG -9 /* Name too long */ +#define EINVALIDFS -10 /* Invalid format for filesystem */ +#define EACCESS -11 /* Permission denied */ +#define EINVALID -12 /* Invalid argument */ +#define EMFILE -13 /* File descriptor table full */ +#define ENOTDIR -14 /* Not a directory */ +#define EEXIST -15 /* File or directory already exists */ +#define ENOSPACE -16 /* Out of space on device */ +#define EPIPE -17 /* Pipe has no reader */ +#define ENOEXEC -18 /* Invalid executable format */ + +#endif /* GEEKOS_ERRNO_H */ diff --git a/palacios/include/geekos/fmtout.h b/palacios/include/geekos/fmtout.h new file mode 100644 index 0000000..cb3f168 --- /dev/null +++ b/palacios/include/geekos/fmtout.h @@ -0,0 +1 @@ +#include "../libc/fmtout.h" diff --git a/palacios/include/geekos/gdt.h b/palacios/include/geekos/gdt.h new file mode 100644 index 0000000..3ae7b2b --- /dev/null +++ b/palacios/include/geekos/gdt.h @@ -0,0 +1,22 @@ +/* + * Initialize kernel GDT. + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_GDT_H +#define GEEKOS_GDT_H + +struct Segment_Descriptor; + +void DumpGDT(); +void Init_GDT(void); +struct Segment_Descriptor* Allocate_Segment_Descriptor(void); +void Free_Segment_Descriptor(struct Segment_Descriptor* desc); +int Get_Descriptor_Index(struct Segment_Descriptor* desc); + + +#endif /* GEEKOS_GDT_H */ diff --git a/palacios/include/geekos/idt.h b/palacios/include/geekos/idt.h new file mode 100644 index 0000000..b88cf28 --- /dev/null +++ b/palacios/include/geekos/idt.h @@ -0,0 +1,67 @@ +/* + * GeekOS IDT initialization code + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_IDT_H +#define GEEKOS_IDT_H + +#include + +/* + * We'll handle all possible interrupts. + */ +#define NUM_IDT_ENTRIES 256 + +/* + * Exceptions range from 0-17 + */ +#define FIRST_EXCEPTION 0 +#define NUM_EXCEPTIONS 18 + +/* + * External IRQs range from 32-47 + */ +#define FIRST_EXTERNAL_INT 32 +#define NUM_EXTERNAL_INTS 16 + +struct Interrupt_Gate { + ushort_t offsetLow; + ushort_t segmentSelector; + unsigned reserved : 5; + unsigned signature : 8; + unsigned dpl : 2; + unsigned present : 1; + ushort_t offsetHigh; +}; + +union IDT_Descriptor { + struct Interrupt_Gate ig; + /* + * In theory we could have members for trap gates + * and task gates if we wanted. + */ +}; + + + +void DumpIDT(); +void SerialDumpIDT(); + +void Init_IDT(void); +void Init_Interrupt_Gate(union IDT_Descriptor* desc, ulong_t addr, + int dpl); +void Install_Interrupt_Handler(int interrupt, Interrupt_Handler handler); + +/* + * This is defined in lowlevel.asm. + * The parameter should consist of 16 bit base, + * followed by 32 bit base address, describing the IDT. + */ +void Load_IDTR(ushort_t* limitAndBase); + +#endif /* GEEKOS_IDT_H */ diff --git a/palacios/include/geekos/int.h b/palacios/include/geekos/int.h new file mode 100644 index 0000000..a80d142 --- /dev/null +++ b/palacios/include/geekos/int.h @@ -0,0 +1,180 @@ +/* + * GeekOS interrupt handling data structures and functions + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +/* + * This module describes the C interface which must be implemented + * by interrupt handlers, and has the initialization function + * for the interrupt system as a whole. + */ + +#ifndef GEEKOS_INT_H +#define GEEKOS_INT_H + +#include +#include +#include + +/* + * This struct reflects the contents of the stack when + * a C interrupt handler function is called. + * It must be kept up to date with the code in "lowlevel.asm". + */ +struct Interrupt_State { + /* + * The register contents at the time of the exception. + * We save these explicitly. + */ + uint_t gs; + uint_t fs; + uint_t es; + uint_t ds; + uint_t ebp; + uint_t edi; + uint_t esi; + uint_t edx; + uint_t ecx; + uint_t ebx; + uint_t eax; + + /* + * We explicitly push the interrupt number. + * This makes it easy for the handler function to determine + * which interrupt occurred. + */ + uint_t intNum; + + /* + * This may be pushed by the processor; if not, we push + * a dummy error code, so the stack layout is the same + * for every type of interrupt. + */ + uint_t errorCode; + + /* These are always pushed on the stack by the processor. */ + uint_t eip; + uint_t cs; + uint_t eflags; +}; + +/* + * An interrupt that occurred in user mode. + * If Is_User_Interrupt(state) returns true, then the + * Interrupt_State object may be cast to this kind of struct. + */ +struct User_Interrupt_State { + struct Interrupt_State state; + uint_t espUser; + uint_t ssUser; +}; + +static __inline__ bool Is_User_Interrupt(struct Interrupt_State *state) +{ + return (state->cs & 3) == USER_PRIVILEGE; +} + + +/* + * The signature of an interrupt handler. + */ +typedef void (*Interrupt_Handler)(struct Interrupt_State* state); + +/* + * Perform all low- and high-level initialization of the + * interrupt system. + */ +void Init_Interrupts(void); + +/* + * Query whether or not interrupts are currently enabled. + */ +bool Interrupts_Enabled(void); + +/* + * Block interrupts. + */ +static __inline__ void __Disable_Interrupts(void) +{ + __asm__ __volatile__ ("cli"); +} +#define Disable_Interrupts() \ +do { \ + KASSERT(Interrupts_Enabled()); \ + __Disable_Interrupts(); \ +} while (0) + +/* + * Unblock interrupts. + */ +static __inline__ void __Enable_Interrupts(void) +{ + __asm__ __volatile__ ("sti"); +} +#define Enable_Interrupts() \ +do { \ + KASSERT(!Interrupts_Enabled()); \ + __Enable_Interrupts(); \ +} while (0) + +/* + * Dump interrupt state struct to screen + */ +void Dump_Interrupt_State(struct Interrupt_State* state); + +/** + * Start interrupt-atomic region. + * @return true if interrupts were enabled at beginning of call, + * false otherwise. + */ +static __inline__ bool Begin_Int_Atomic(void) +{ + bool enabled = Interrupts_Enabled(); + if (enabled) + Disable_Interrupts(); + return enabled; +} + +/** + * End interrupt-atomic region. + * @param iflag the value returned from the original Begin_Int_Atomic() call. + */ +static __inline__ void End_Int_Atomic(bool iflag) +{ + KASSERT(!Interrupts_Enabled()); + if (iflag) { + /* Interrupts were originally enabled, so turn them back on */ + Enable_Interrupts(); + } +} + +#define EXCEPTION_DE 0 // Divide by zero +#define EXCEPTION_DB 1 // reserved +#define EXCEPTION_NMI 2 // NMI +#define EXCEPTION_BP 3 // Breakpoint +#define EXCEPTION_OF 4 // Overflow +#define EXCEPTION_BR 5 // Bound range exceeded +#define EXCEPTION_UD 6 // Undefined opcode +#define EXCEPTION_NM 7 // Math coprocessor gone missing +#define EXCEPTION_DF 8 // Double fault +#define EXCEPTION_CO 9 // Coprocessor segment overrrun +#define EXCEPTION_TS 10 // Invalid TSS +#define EXCEPTION_NP 11 // Segment not present +#define EXCEPTION_SS 12 // Stack segment fault +#define EXCEPTION_GP 13 // General Protection fault +#define EXCEPTION_PF 14 // Page Fault +#define EXCEPTION_RES 15 // reserved +#define EXCEPTION_MF 16 // Math fault +#define EXCEPTION_AC 17 // Alignment check +#define EXCEPTION_MC 18 // Machine check +#define EXCEPTION_XF 19 // SIMD FP exception +// 20+ are reserved + + + + +#endif /* GEEKOS_INT_H */ diff --git a/palacios/include/geekos/io.h b/palacios/include/geekos/io.h new file mode 100644 index 0000000..bd23614 --- /dev/null +++ b/palacios/include/geekos/io.h @@ -0,0 +1,23 @@ +/* + * x86 port IO routines + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_IO_H +#define GEEKOS_IO_H + +#include + +void Out_Byte(ushort_t port, uchar_t value); +uchar_t In_Byte(ushort_t port); + +void Out_Word(ushort_t port, ushort_t value); +ushort_t In_Word(ushort_t port); + +void IO_Delay(void); + +#endif /* GEEKOS_IO_H */ diff --git a/palacios/include/geekos/io_devs.h b/palacios/include/geekos/io_devs.h new file mode 100644 index 0000000..6e6e24a --- /dev/null +++ b/palacios/include/geekos/io_devs.h @@ -0,0 +1,19 @@ +#ifndef _io_devs +#define _io_devs + + +// +// +// PIC: Programmable Interrupt Controller +// +#define PIC_MASTER_CMD_ISR_PORT 0x20 // Port where the master PIC command and status register is +#define PIC_MASTER_IMR_PORT 0x21 // Port where the master PIC interrupt mask register is +#define PIC_SLAVE_CMD_ISR_PORT 0xa0 // Port where the slave PIC command and status register is +#define PIC_SLAVE_IMR_PORT 0xa1 // Port where the slave PIC interrupt mask register is + + +#define BOOT_STATE_CARD_PORT 0x80 // hex codes sent here for display + + + +#endif diff --git a/palacios/include/geekos/irq.h b/palacios/include/geekos/irq.h new file mode 100644 index 0000000..3164170 --- /dev/null +++ b/palacios/include/geekos/irq.h @@ -0,0 +1,28 @@ +/* + * This is the device-driver interface to the interrupt system. + * Copyright (c) 2001,2003 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_IRQ_H +#define GEEKOS_IRQ_H + +#include + +void Install_IRQ(int irq, Interrupt_Handler handler); +ushort_t Get_IRQ_Mask(void); +void Set_IRQ_Mask(ushort_t mask); +void Enable_IRQ(int irq); +void Disable_IRQ(int irq); + +/* + * IRQ handlers should call these to begin and end the + * interrupt. + */ +void Begin_IRQ(struct Interrupt_State* state); +void End_IRQ(struct Interrupt_State* state); + +#endif /* GEEKOS_IRQ_H */ diff --git a/palacios/include/geekos/kassert.h b/palacios/include/geekos/kassert.h new file mode 100644 index 0000000..434a8a8 --- /dev/null +++ b/palacios/include/geekos/kassert.h @@ -0,0 +1,81 @@ +/* + * Definition of KASSERT() macro, and other useful debug macros + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_KASSERT_H +#define GEEKOS_KASSERT_H + +#include + +#ifndef NDEBUG + +struct Kernel_Thread; +extern struct Kernel_Thread* g_currentThread; + +#define KASSERT(cond) \ +do { \ + if (!(cond)) { \ + Set_Current_Attr(ATTRIB(RED, GRAY|BRIGHT)); \ + Print("Failed assertion in %s: %s at %s, line %d, RA=%lx, thread=%p\n",\ + __func__, #cond, __FILE__, __LINE__, \ + (ulong_t) __builtin_return_address(0), \ + g_currentThread); \ + while (1) \ + ; \ + } \ +} while (0) + +#define TODO(message) \ +do { \ + Set_Current_Attr(ATTRIB(BLUE, GRAY|BRIGHT)); \ + Print("Unimplemented feature: %s\n", (message)); \ + while (1) \ + ; \ +} while (0) + +/* + * Spin for some number of iterations. + * This is useful for slowing down things that go by too + * quickly. + */ +#define PAUSE(count) \ +do { \ + ulong_t i; \ + for (i = 0; i < (count); ++i) \ + ; \ +} while (0) + +#else + +/* + * The debug macros are no-ops when NDEBUG is defined. + */ +#define KASSERT(cond) +#define TODO(message) +#define PAUSE(count) + +#endif + +/* + * Stop dead. + * Its behavior does not depend on whether or not this + * is a debug build. + */ +#define STOP() while (1) + +/* + * Panic function. + */ +#define Panic(args...) \ +do { \ + Set_Current_Attr(ATTRIB(RED, GRAY|BRIGHT)); \ + Print(args); \ + while (1) ; \ +} while (0) + +#endif /* GEEKOS_KASSERT_H */ diff --git a/palacios/include/geekos/keyboard.h b/palacios/include/geekos/keyboard.h new file mode 100644 index 0000000..1ab5c42 --- /dev/null +++ b/palacios/include/geekos/keyboard.h @@ -0,0 +1,131 @@ +/* + * Keyboard driver + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_KEYBOARD_H +#define GEEKOS_KEYBOARD_H + +#include + +/* ---------------------------------------------------------------------- + * Hardware stuff + * ---------------------------------------------------------------------- */ + +#ifdef GEEKOS + +#define KB_IRQ 1 + +/* + * I/O ports + */ +#define KB_CMD 0x64 +#define KB_DATA 0x60 + +/* + * Bits in status port + */ +#define KB_OUTPUT_FULL 0x01 + +/* + * High bit in scan code is set when key is released + */ +#define KB_KEY_RELEASE 0x80 + +#endif /* GEEKOS */ + +/* ---------------------------------------------------------------------- + * Software keycodes + * ---------------------------------------------------------------------- */ + +/* + * Each keyboard event generates a 16 bit code. + * - The low 10 bits indicate which key was used. + * - If bit 8 (KEY_SPECIAL_FLAG) is 0, then the low 8 bits contain + * the ASCII code. + * - The flags indicate the shift/alt/control state, + * and whether the event was a make or release. + */ + +typedef ushort_t Keycode; + +/* + * Flags + */ +#define KEY_SPECIAL_FLAG 0x0100 +#define KEY_KEYPAD_FLAG 0x0200 +#define KEY_SHIFT_FLAG 0x1000 +#define KEY_ALT_FLAG 0x2000 +#define KEY_CTRL_FLAG 0x4000 +#define KEY_RELEASE_FLAG 0x8000 + +/* + * Special key codes + */ +#define _SPECIAL(num) (KEY_SPECIAL_FLAG | (num)) +#define KEY_UNKNOWN _SPECIAL(0) +#define KEY_F1 _SPECIAL(1) +#define KEY_F2 _SPECIAL(2) +#define KEY_F3 _SPECIAL(3) +#define KEY_F4 _SPECIAL(4) +#define KEY_F5 _SPECIAL(5) +#define KEY_F6 _SPECIAL(6) +#define KEY_F7 _SPECIAL(7) +#define KEY_F8 _SPECIAL(8) +#define KEY_F9 _SPECIAL(9) +#define KEY_F10 _SPECIAL(10) +#define KEY_F11 _SPECIAL(11) +#define KEY_F12 _SPECIAL(12) +#define KEY_LCTRL _SPECIAL(13) +#define KEY_RCTRL _SPECIAL(14) +#define KEY_LSHIFT _SPECIAL(15) +#define KEY_RSHIFT _SPECIAL(16) +#define KEY_LALT _SPECIAL(17) +#define KEY_RALT _SPECIAL(18) +#define KEY_PRINTSCRN _SPECIAL(19) +#define KEY_CAPSLOCK _SPECIAL(20) +#define KEY_NUMLOCK _SPECIAL(21) +#define KEY_SCRLOCK _SPECIAL(22) +#define KEY_SYSREQ _SPECIAL(23) + +/* + * Keypad keys + */ +#define KEYPAD_START 128 +#define _KEYPAD(num) (KEY_KEYPAD_FLAG | KEY_SPECIAL_FLAG | (num+KEYPAD_START)) +#define KEY_KPHOME _KEYPAD(0) +#define KEY_KPUP _KEYPAD(1) +#define KEY_KPPGUP _KEYPAD(2) +#define KEY_KPMINUS _KEYPAD(3) +#define KEY_KPLEFT _KEYPAD(4) +#define KEY_KPCENTER _KEYPAD(5) +#define KEY_KPRIGHT _KEYPAD(6) +#define KEY_KPPLUS _KEYPAD(7) +#define KEY_KPEND _KEYPAD(8) +#define KEY_KPDOWN _KEYPAD(9) +#define KEY_KPPGDN _KEYPAD(10) +#define KEY_KPINSERT _KEYPAD(11) +#define KEY_KPDEL _KEYPAD(12) + +/* + * ASCII codes for which there is no convenient C representation + */ +#define ASCII_ESC 0x1B +#define ASCII_BS 0x08 + +#ifdef GEEKOS + +/* + * Public functions + */ +void Init_Keyboard(void); +bool Read_Key(Keycode* keycode); +Keycode Wait_For_Key(void); + +#endif /* GEEKOS */ + +#endif /* GEEKOS_KEYBOARD_H */ diff --git a/palacios/include/geekos/kthread.h b/palacios/include/geekos/kthread.h new file mode 100644 index 0000000..f0ef23c --- /dev/null +++ b/palacios/include/geekos/kthread.h @@ -0,0 +1,158 @@ +/* + * Kernel threads + * Copyright (c) 2001,2003 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_KTHREAD_H +#define GEEKOS_KTHREAD_H + +#include +#include + +struct Kernel_Thread; +struct User_Context; +struct Interrupt_State; + +/* + * Queue of threads. + * This is used for the run queue(s), and also for + * thread synchronization and communication. + */ +DEFINE_LIST(Thread_Queue, Kernel_Thread); + +/* + * List which includes all threads. + */ +DEFINE_LIST(All_Thread_List, Kernel_Thread); + +/* + * Kernel thread context data structure. + * NOTE: there is assembly code in lowlevel.asm that depends + * on the offsets of the fields in this struct, so if you change + * the layout, make sure everything gets updated. + */ +struct Kernel_Thread { + ulong_t esp; /* offset 0 */ + volatile ulong_t numTicks; /* offset 4 */ + int priority; + DEFINE_LINK(Thread_Queue, Kernel_Thread); + void* stackPage; + struct User_Context* userContext; + struct Kernel_Thread* owner; + int refCount; + + /* These fields are used to implement the Join() function */ + bool alive; + struct Thread_Queue joinQueue; + int exitCode; + + /* The kernel thread id; also used as process id */ + int pid; + + /* Link fields for list of all threads in the system. */ + DEFINE_LINK(All_Thread_List, Kernel_Thread); + + /* Array of MAX_TLOCAL_KEYS pointers to thread-local data. */ +#define MAX_TLOCAL_KEYS 128 + const void* tlocalData[MAX_TLOCAL_KEYS]; + +}; + +/* + * Define Thread_Queue and All_Thread_List access and manipulation functions. + */ +IMPLEMENT_LIST(Thread_Queue, Kernel_Thread); +IMPLEMENT_LIST(All_Thread_List, Kernel_Thread); + +static __inline__ void Enqueue_Thread(struct Thread_Queue *queue, struct Kernel_Thread *kthread) { + Add_To_Back_Of_Thread_Queue(queue, kthread); +} + +static __inline__ void Remove_Thread(struct Thread_Queue *queue, struct Kernel_Thread *kthread) { + Remove_From_Thread_Queue(queue, kthread); +} + +/* + * Thread start functions should have this signature. + */ +typedef void (*Thread_Start_Func)(ulong_t arg); + +/* + * Thread priorities + */ +#define PRIORITY_IDLE 0 +#define PRIORITY_USER 1 +#define PRIORITY_LOW 2 +#define PRIORITY_NORMAL 5 +#define PRIORITY_HIGH 10 + + +/* + * Scheduler operations. + */ +void Init_Scheduler(void); +struct Kernel_Thread* Start_Kernel_Thread( + Thread_Start_Func startFunc, + ulong_t arg, + int priority, + bool detached +); +struct Kernel_Thread* Start_User_Thread(struct User_Context* userContext, bool detached); +void Make_Runnable(struct Kernel_Thread* kthread); +void Make_Runnable_Atomic(struct Kernel_Thread* kthread); +struct Kernel_Thread* Get_Current(void); +struct Kernel_Thread* Get_Next_Runnable(void); +void Schedule(void); +void Yield(void); +void Exit(int exitCode) __attribute__ ((noreturn)); +int Join(struct Kernel_Thread* kthread); +struct Kernel_Thread* Lookup_Thread(int pid); + +/* + * Thread context switch function, defined in lowlevel.asm + */ +void Switch_To_Thread(struct Kernel_Thread*); + +/* + * Wait queue functions. + */ +void Wait(struct Thread_Queue* waitQueue); +void Wake_Up(struct Thread_Queue* waitQueue); +void Wake_Up_One(struct Thread_Queue* waitQueue); + +/* + * Pointer to currently executing thread. + */ +extern struct Kernel_Thread* g_currentThread; + +/* + * Boolean flag indicating that we need to choose a new runnable thread. + */ +extern int g_needReschedule; + +/* + * Boolean flag indicating that preemption should be disabled. + */ +extern volatile int g_preemptionDisabled; + +/* + * Thread-local data information + */ +#define MIN_DESTRUCTOR_ITERATIONS 4 + +typedef void (*tlocal_destructor_t)(void *); +typedef unsigned int tlocal_key_t; + +extern int Tlocal_Create(tlocal_key_t *, tlocal_destructor_t); +extern void Tlocal_Put(tlocal_key_t, const void *); +extern void *Tlocal_Get(tlocal_key_t); + +/* Print list of all threads, for debugging. */ +extern void Dump_All_Thread_List(void); + + +#endif /* GEEKOS_KTHREAD_H */ diff --git a/palacios/include/geekos/ktypes.h b/palacios/include/geekos/ktypes.h new file mode 100644 index 0000000..7c72a3b --- /dev/null +++ b/palacios/include/geekos/ktypes.h @@ -0,0 +1,43 @@ +/* + * Kernel data types + * Copyright (c) 2001,2003 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_KTYPES_H +#define GEEKOS_KTYPES_H + +/* + * GeekOS uses the C99 bool type, with true and false + * constant values. + */ +#include + +/* + * Shorthand for commonly used integer types. + */ +typedef unsigned long ulong_t; +typedef unsigned int uint_t; +typedef unsigned short ushort_t; +typedef unsigned char uchar_t; +typedef unsigned long long ullong_t; + +/* + * MIN() and MAX() macros. + * By using gcc extensions, they are type-correct and + * evaulate their arguments only once. + */ +#define MIN(a,b) ({typeof (a) _a = (a); typeof (b) _b = (b); (_a < _b) ? _a : _b; }) +#define MAX(a,b) ({typeof (a) _a = (a); typeof (b) _b = (b); (_a < _b) ? _a : _b; }) + +/* + * Some ASCII character access and manipulation macros. + */ +#define ISDIGIT(c) ((c) >= '0' && (c) <= '9') +#define TOLOWER(c) (((c) >= 'A' && (c) <= 'Z') ? ((c) + ('a' - 'A')) : (c)) +#define TOUPPER(c) (((c) >= 'a' && (c) <= 'z') ? ((c) - ('a' - 'A')) : (c)) + +#endif /* GEEKOS_KTYPES_H */ diff --git a/palacios/include/geekos/list.h b/palacios/include/geekos/list.h new file mode 100644 index 0000000..96a7870 --- /dev/null +++ b/palacios/include/geekos/list.h @@ -0,0 +1,131 @@ +/* + * Generic list data type + * Copyright (c) 2001,2004 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_LIST_H +#define GEEKOS_LIST_H + +#include +#include + +/* + * Define a list type. + */ +#define DEFINE_LIST(listTypeName, nodeTypeName) \ +struct listTypeName { \ + struct nodeTypeName *head, *tail; \ +} + +/* + * Define members of a struct to be used as link fields for + * membership in given list type. + */ +#define DEFINE_LINK(listTypeName, nodeTypeName) \ + struct nodeTypeName * prev##listTypeName, * next##listTypeName + +/* + * Define inline list manipulation and access functions. + */ +#define IMPLEMENT_LIST(LType, NType) \ +static __inline__ void Clear_##LType(struct LType *listPtr) { \ + listPtr->head = listPtr->tail = 0; \ +} \ +static __inline__ bool Is_Member_Of_##LType(struct LType *listPtr, struct NType *nodePtr) { \ + struct NType *cur = listPtr->head; \ + while (cur != 0) { \ + if (cur == nodePtr) \ + return true; \ + cur = cur->next##LType; \ + } \ + return false; \ +} \ +static __inline__ struct NType * Get_Front_Of_##LType(struct LType *listPtr) { \ + return listPtr->head; \ +} \ +static __inline__ struct NType * Get_Back_Of_##LType(struct LType *listPtr) { \ + return listPtr->tail; \ +} \ +static __inline__ struct NType * Get_Next_In_##LType(struct NType *nodePtr) { \ + return nodePtr->next##LType; \ +} \ +static __inline__ void Set_Next_In_##LType(struct NType *nodePtr, struct NType *value) { \ + nodePtr->next##LType = value; \ +} \ +static __inline__ struct NType * Get_Prev_In_##LType(struct NType *nodePtr) { \ + return nodePtr->prev##LType; \ +} \ +static __inline__ void Set_Prev_In_##LType(struct NType *nodePtr, struct NType *value) { \ + nodePtr->prev##LType = value; \ +} \ +static __inline__ void Add_To_Front_Of_##LType(struct LType *listPtr, struct NType *nodePtr) { \ + KASSERT(!Is_Member_Of_##LType(listPtr, nodePtr)); \ + nodePtr->prev##LType = 0; \ + if (listPtr->head == 0) { \ + listPtr->head = listPtr->tail = nodePtr; \ + nodePtr->next##LType = 0; \ + } else { \ + listPtr->head->prev##LType = nodePtr; \ + nodePtr->next##LType = listPtr->head; \ + listPtr->head = nodePtr; \ + } \ +} \ +static __inline__ void Add_To_Back_Of_##LType(struct LType *listPtr, struct NType *nodePtr) { \ + /* KASSERT(!Is_Member_Of_##LType(listPtr, nodePtr)); */ \ + nodePtr->next##LType = 0; \ + if (listPtr->tail == 0) { \ + listPtr->head = listPtr->tail = nodePtr; \ + nodePtr->prev##LType = 0; \ + } \ + else { \ + listPtr->tail->next##LType = nodePtr; \ + nodePtr->prev##LType = listPtr->tail; \ + listPtr->tail = nodePtr; \ + } \ +} \ +static __inline__ void Append_##LType(struct LType *listToModify, struct LType *listToAppend) { \ + if (listToAppend->head != 0) { \ + if (listToModify->head == 0) { \ + listToModify->head = listToAppend->head; \ + listToModify->tail = listToAppend->tail; \ + } else { \ + KASSERT(listToAppend->head != 0); \ + KASSERT(listToModify->tail != 0); \ + listToAppend->head->prev##LType = listToModify->tail; \ + listToModify->tail->next##LType = listToAppend->head; \ + listToModify->tail = listToAppend->tail; \ + } \ + } \ + listToAppend->head = listToAppend->tail = 0; \ +} \ +static __inline__ struct NType * Remove_From_Front_Of_##LType(struct LType *listPtr) { \ + struct NType *nodePtr; \ + nodePtr = listPtr->head; \ + KASSERT(nodePtr != 0); \ + listPtr->head = listPtr->head->next##LType; \ + if (listPtr->head == 0) \ + listPtr->tail = 0; \ + else \ + listPtr->head->prev##LType = 0; \ + return nodePtr; \ +} \ +static __inline__ void Remove_From_##LType(struct LType *listPtr, struct NType *nodePtr) { \ + KASSERT(Is_Member_Of_##LType(listPtr, nodePtr)); \ + if (nodePtr->prev##LType != 0) \ + nodePtr->prev##LType->next##LType = nodePtr->next##LType; \ + else \ + listPtr->head = nodePtr->next##LType; \ + if (nodePtr->next##LType != 0) \ + nodePtr->next##LType->prev##LType = nodePtr->prev##LType; \ + else \ + listPtr->tail = nodePtr->prev##LType; \ +} \ +static __inline__ bool Is_##LType##_Empty(struct LType *listPtr) { \ + return listPtr->head == 0; \ +} + +#endif /* GEEKOS_LIST_H */ diff --git a/palacios/include/geekos/malloc.h b/palacios/include/geekos/malloc.h new file mode 100644 index 0000000..ba70e92 --- /dev/null +++ b/palacios/include/geekos/malloc.h @@ -0,0 +1,19 @@ +/* + * GeekOS memory allocation API + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_MALLOC_H +#define GEEKOS_MALLOC_H + +#include + +void Init_Heap(ulong_t start, ulong_t size); +void* Malloc(ulong_t size); +void Free(void* buf); + +#endif /* GEEKOS_MALLOC_H */ diff --git a/palacios/include/geekos/mem.h b/palacios/include/geekos/mem.h new file mode 100644 index 0000000..fdac1aa --- /dev/null +++ b/palacios/include/geekos/mem.h @@ -0,0 +1,119 @@ +/* + * Physical memory allocation + * Copyright (c) 2001,2003,2004 David H. Hovemeyer + * Copyright (c) 2003, Jeffrey K. Hollingsworth + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_MEM_H +#define GEEKOS_MEM_H + +#include +#include +#include +#include + +struct Boot_Info; + +/* + * Page flags + */ +#define PAGE_AVAIL 0x0000 /* page is on the freelist */ +#define PAGE_KERN 0x0001 /* page used by kernel code or data */ +#define PAGE_HW 0x0002 /* page used by hardware (e.g., ISA hole) */ +#define PAGE_ALLOCATED 0x0004 /* page is allocated */ +#define PAGE_UNUSED 0x0008 /* page is unused */ +#define PAGE_HEAP 0x0010 /* page is in kernel heap */ +#define PAGE_PAGEABLE 0x0020 /* page can be paged out */ +#define PAGE_LOCKED 0x0040 /* page is taken should not be freed */ +#define PAGE_VM 0x0080 /* page is used by the VM */ + + +struct Page; + +/* + * List datatype for doubly-linked list of Pages. + */ +DEFINE_LIST(Page_List, Page); + +/* + * Each page of physical memory has one of these structures + * associated with it, to do allocation and bookkeeping. + */ +struct Page { + unsigned flags; /* Flags indicating state of page */ + DEFINE_LINK(Page_List, Page); /* Link fields for Page_List */ + int clock; + ulong_t vaddr; /* User virtual address where page is mapped */ + pte_t *entry; /* Page table entry referring to the page */ +}; + +IMPLEMENT_LIST(Page_List, Page); + +void Init_Mem(struct Boot_Info* bootInfo); +void Init_BSS(void); +void* Alloc_Page(void); +void* Alloc_Pageable_Page(pte_t *entry, ulong_t vaddr); +void Free_Page(void* pageAddr); + +/* + * Determine if given address is a multiple of the page size. + */ +static __inline__ bool Is_Page_Multiple(ulong_t addr) +{ + return addr == (addr & ~(PAGE_MASK)); +} + +/* + * Round given address up to a multiple of the page size + */ +static __inline__ ulong_t Round_Up_To_Page(ulong_t addr) +{ + if ((addr & PAGE_MASK) != 0) { + addr &= ~(PAGE_MASK); + addr += PAGE_SIZE; + } + return addr; +} + +/* + * Round given address down to a multiple of the page size + */ +static __inline__ ulong_t Round_Down_To_Page(ulong_t addr) +{ + return addr & (~PAGE_MASK); +} + +/* + * Get the index of the page in memory. + */ +static __inline__ int Page_Index(ulong_t addr) +{ + return (int) (addr >> PAGE_POWER); +} + + +/* + * Get the Page struct associated with given address. + */ +static __inline__ struct Page *Get_Page(ulong_t addr) +{ + extern struct Page* g_pageList; + return &g_pageList[Page_Index(addr)]; + //return g_pageList + (sizeof(struct Page) * (int)(addr >> PAGE_POWER)); +} + +/* + * Get the physical address of the memory represented by given Page object. + */ +static __inline__ ulong_t Get_Page_Address(struct Page *page) +{ + extern struct Page* g_pageList; + ulong_t index = page - g_pageList; + return index << PAGE_POWER; +} + +#endif /* GEEKOS_MEM_H */ diff --git a/palacios/include/geekos/paging.h b/palacios/include/geekos/paging.h new file mode 100644 index 0000000..1810f0b --- /dev/null +++ b/palacios/include/geekos/paging.h @@ -0,0 +1,131 @@ +/* + * Paging (virtual memory) support + * Copyright (c) 2003, Jeffrey K. Hollingsworth + * Copyright (c) 2003,2004 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_PAGING_H +#define GEEKOS_PAGING_H + +#include +#include +#include +#include + +struct Page; +struct User_Context; + +#define NUM_PAGE_TABLE_ENTRIES 1024 +#define NUM_PAGE_DIR_ENTRIES 1024 + +#define PAGE_DIRECTORY_INDEX(x) ((((uint_t)x) >> 22) & 0x3ff) +#define PAGE_TABLE_INDEX(x) ((((uint_t)x) >> 12) & 0x3ff) +#define PAGE_OFFSET(x) ((((uint_t)x) & 0xfff)) + +#define PAGE_ALLIGNED_ADDR(x) (((uint_t) (x)) >> 12) +#define PAGE_ADDR(x) (PAGE_ALLIGNED_ADDR(x) << 12) + +/* + * Bits for flags field of pde_t and pte_t. + */ +#define VM_WRITE 1 /* Memory is writable */ +#define VM_USER 2 /* Memory is accessible to user code */ +#define VM_NOCACHE 8 /* Memory should not be cached */ +#define VM_READ 0 /* Memory can be read (ignored for x86) */ +#define VM_EXEC 0 /* Memory can be executed (ignored for x86) */ + + +/* + * Page directory entry datatype. + * If marked as present, it specifies the physical address + * and permissions of a page table. + */ +typedef struct { + uint_t present:1; + uint_t flags:4; + uint_t accessed:1; + uint_t reserved:1; + uint_t largePages:1; + uint_t globalPage:1; + uint_t kernelInfo:3; + uint_t pageTableBaseAddr:20; +} pde_t; + +/* + * Page table entry datatype. + * If marked as present, it specifies the physical address + * and permissions of a page of memory. + */ +typedef struct { + uint_t present:1; + uint_t flags:4; + uint_t accessed:1; + uint_t dirty:1; + uint_t pteAttribute:1; + uint_t globalPage:1; + uint_t kernelInfo:3; + uint_t pageBaseAddr:20; +} pte_t; + +/* + * Datatype representing the hardware error code + * pushed onto the stack by the processor on a page fault. + * The error code is stored in the "errorCode" field + * of the Interrupt_State struct. + */ +typedef struct { + uint_t protectionViolation:1; + uint_t writeFault:1; + uint_t userModeFault:1; + uint_t reservedBitFault:1; + uint_t reserved:28; +} faultcode_t; + +/* + * Bits used in the kernelInfo field of the PTE's: + */ +#define KINFO_PAGE_ON_DISK 0x4 /* Page not present; contents in paging file */ + +void Init_VM(struct Boot_Info *bootInfo); +void Init_Paging(void); + +extern void Flush_TLB(void); +extern void Set_PDBR(pde_t *pageDir); +extern pde_t *Get_PDBR(void); +extern void Enable_Paging(pde_t *pageDir); + +/* + * Return the address that caused a page fault. + */ +static __inline__ ulong_t Get_Page_Fault_Address(void) +{ + ulong_t faultAddress; + __asm__ __volatile__ ( + "mov %%cr2, %0" + : "=r" (faultAddress) + ); + return faultAddress; +} + +void SerialPrintPD(pde_t *pde); +void SerialPrintPT(void *starting_address, pte_t *pte); +void SerialPrintPDE(void *virtual_address, pde_t *pde); +void SerialPrintPTE(void *virtual_address,pte_t *pte); +void SerialDumpPageTables(pde_t *pde); + +pte_t *LookupPage(void *vaddr); + +pte_t *MapPage(void *vaddr, pte_t *pte, int alloc_pde); +pte_t *UnMapPage(void *vaddr); + +int Find_Space_On_Paging_File(void); +void Free_Space_On_Paging_File(int pagefileIndex); +void Write_To_Paging_File(void *paddr, ulong_t vaddr, int pagefileIndex); +void Read_From_Paging_File(void *paddr, ulong_t vaddr, int pagefileIndex); + + +#endif diff --git a/palacios/include/geekos/range.h b/palacios/include/geekos/range.h new file mode 100644 index 0000000..15bd023 --- /dev/null +++ b/palacios/include/geekos/range.h @@ -0,0 +1,55 @@ +/* + * Range checking + * Copyright (c) 2003, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_RANGE_H +#define GEEKOS_RANGE_H + +#include + +/* + * TODO: think about these, make sure they're correct + */ + +/** + * Check that given range is "proper". + * @param start the start of the range + * @param size the size of the range + * @return true if range is properly within the space + * 0(inclusive)..ULONG_MAX(inclusive) + */ +static __inline__ bool +Check_Range_Proper(ulong_t start, ulong_t size) +{ + /* + * Wrap around is only permitted if the sum is zero. + * E.g., start=ULONG_MAX, size==1 is a valid range. + */ + ulong_t sum = start + size; + return start <= sum || (sum == 0); +} + +/** + * Check that given range lies entirely under the + * maximum value specified (exclusive). + * @param start the start of the range + * @param size the size of the range + * @param max the lowest address NOT allowed to be in the range + * @return true if range falls entirely within the range + * 0(inclusive)..max(exclusive) + */ +static __inline__ bool +Check_Range_Under(ulong_t start, ulong_t size, ulong_t max) +{ + if (!Check_Range_Proper(start, size)) + return false; + + return start < max && (start + size) <= max; +} + +#endif /* GEEKOS_RANGE_H */ diff --git a/palacios/include/geekos/reboot.h b/palacios/include/geekos/reboot.h new file mode 100644 index 0000000..e954a2c --- /dev/null +++ b/palacios/include/geekos/reboot.h @@ -0,0 +1,7 @@ +#ifndef REBOOT_H +#define REBOOT_H + +void machine_real_restart(); + + +#endif diff --git a/palacios/include/geekos/screen.h b/palacios/include/geekos/screen.h new file mode 100644 index 0000000..241fc6f --- /dev/null +++ b/palacios/include/geekos/screen.h @@ -0,0 +1,57 @@ +/* + * GeekOS text screen output + * Copyright (c) 2001,2003 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_SCREEN_H +#define GEEKOS_SCREEN_H + +#include + +#define BLACK 0 +#define BLUE 1 +#define GREEN 2 +#define CYAN 3 +#define RED 4 +#define MAGENTA 5 +#define AMBER 6 +#define GRAY 7 +#define BRIGHT 8 +#define ATTRIB(bg,fg) ((fg)|((bg)<<4)) + +#define NUMCOLS 80 +#define NUMROWS 25 + +#define TABWIDTH 8 + +#ifdef GEEKOS + +/* + * VGA hardware stuff, for accessing the text display + * memory and controlling the cursor + */ +#define VIDMEM_ADDR 0xb8000 +#define VIDMEM ((uchar_t*) VIDMEM_ADDR) +#define CRT_ADDR_REG 0x3D4 +#define CRT_DATA_REG 0x3D5 +#define CRT_CURSOR_LOC_HIGH_REG 0x0E +#define CRT_CURSOR_LOC_LOW_REG 0x0F + +void Init_Screen(void); +void Clear_Screen(void); +void Get_Cursor(int* row, int* col); +bool Put_Cursor(int row, int col); +uchar_t Get_Current_Attr(void); +void Set_Current_Attr(uchar_t attrib); +void Put_Char(int c); +void Put_String(const char* s); +void Put_Buf(const char* buf, ulong_t length); +void Print(const char* fmt, ...) __attribute__ ((format (printf, 1, 2))); + +#endif /* GEEKOS */ + +#endif /* GEEKOS_SCREEN_H */ diff --git a/palacios/include/geekos/segment.h b/palacios/include/geekos/segment.h new file mode 100644 index 0000000..06f302a --- /dev/null +++ b/palacios/include/geekos/segment.h @@ -0,0 +1,90 @@ +/* + * General data structures and routines for segmentation + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +/* + * Source: _Protected Mode Software Architecture_ by Tom Shanley, + * ISBN 020155447X. + */ + +#ifndef GEEKOS_SEGMENT_H +#define GEEKOS_SEGMENT_H + +#include + +struct TSS; + +#if __TINYC__ +#define PACKED +#else +#define PACKED __attribute__((packed)) +#endif + +/* + * The general format of a segment descriptor. + */ +struct Segment_Descriptor { + ushort_t sizeLow PACKED ; + uint_t baseLow : 24 PACKED ; + uint_t type : 4 PACKED ; + uint_t system : 1 PACKED ; + uint_t dpl : 2 PACKED ; + uint_t present : 1 PACKED ; + uint_t sizeHigh : 4 PACKED ; + uint_t avail : 1 PACKED ; + uint_t reserved : 1 PACKED ; /* set to zero */ + uint_t dbBit : 1 PACKED ; + uint_t granularity : 1 PACKED ; + uchar_t baseHigh PACKED ; +}; + +/** + * Construct a segment selector. + * @param rpl requestor privilege level; should be KERNEL_PRIVILEGE + * for kernel segments and USER_PRIVILEGE for user segments + * @param segmentIsInGDT true if the referenced segment descriptor + * is defined in the GDT, false if it is defined in the LDT + * @param index index of the segment descriptor + * @return the segment selector + */ +static __inline__ ushort_t Selector(int rpl, bool segmentIsInGDT, int index) +{ + ushort_t selector = 0; + selector = (rpl & 0x3) | ((segmentIsInGDT ? 0 : 1) << 2) | ((index & 0x1FFF) << 3); + return selector; +} + +/* + * Routines to initialize segment descriptors. + * Code and data segments must start on a page-aligned address + * and are sized in pages. + */ + +void Init_Null_Segment_Descriptor(struct Segment_Descriptor* desc); + +void Init_Code_Segment_Descriptor( + struct Segment_Descriptor* desc, + ulong_t baseAddr, + ulong_t numPages, + int privilegeLevel +); +void Init_Data_Segment_Descriptor( + struct Segment_Descriptor* desc, + ulong_t baseAddr, + ulong_t numPages, + int privilegeLevel +); +void Init_TSS_Descriptor(struct Segment_Descriptor* desc, struct TSS* theTSS); + +void Init_LDT_Descriptor( + struct Segment_Descriptor* desc, + struct Segment_Descriptor theLDT[], + int numEntries +); + +#endif /* GEEKOS_SEGMENT_H */ diff --git a/palacios/include/geekos/serial.h b/palacios/include/geekos/serial.h new file mode 100644 index 0000000..4ebe0b0 --- /dev/null +++ b/palacios/include/geekos/serial.h @@ -0,0 +1,69 @@ +#ifndef SERIAL_H +#define SERIAL_H + +#include +#include +#include +#include + +#define COM1_IRQ 4 +#define DEFAULT_SERIAL_ADDR 0x3F8 + + +#ifndef SERIAL_PRINT +#define SERIAL_PRINT 1 +#endif +#ifndef SERIAL_PRINT_DEBUG +#define SERIAL_PRINT_DEBUG 1 +#endif +#ifndef SERIAL_PRINT_DEBUG_LEVEL +#define SERIAL_PRINT_DEBUG_LEVEL 10 +#endif + +#define SERIAL_PRINT_MAXBUF 256 + + +#if SERIAL_PRINT +#define SerialPrint(format, args...) \ +do { \ + char buf[SERIAL_PRINT_MAXBUF]; \ + snprintf( buf, SERIAL_PRINT_MAXBUF, format, ## args ) ; \ + SerialPutLineN(buf, SERIAL_PRINT_MAXBUF); \ +} while (0) +#else +#define SerialPrint(format, args...) do {} while (0) +#endif + + +#define PrintBoth(format, args...) \ +do { \ + Print(format, ## args); \ + SerialPrint(format, ##args); \ + } while (0) + + +#if SERIAL_PRINT_DEBUG +#define SerialPrintLevel(level, format, args...) \ +do { \ + char buf[SERIAL_PRINT_MAXBUF]; \ + if (level >= SERIAL_PRINT_DEBUG_LEVEL ) { \ + snprintf( buf, SERIAL_PRINT_MAXBUF, format, ## args ) ; \ + SerialPutLineN(buf, SERIAL_PRINT_MAXBUF); \ + } \ +} while (0) +#else +#define SerialPrintLevel(level, format, args...) do {} while (0) +#endif + + +void SerialPutLine(char * line); +void SerialPutLineN(char * line, int len); + + +void SerialPrintHex(unsigned char x); +void SerialMemDump(unsigned char *start, int n); + +void InitSerial(); +void InitSerialAddr(unsigned short io_addr); + +#endif diff --git a/palacios/include/geekos/string.h b/palacios/include/geekos/string.h new file mode 100644 index 0000000..661a148 --- /dev/null +++ b/palacios/include/geekos/string.h @@ -0,0 +1 @@ +#include "../libc/string.h" diff --git a/palacios/include/geekos/symbol.h b/palacios/include/geekos/symbol.h new file mode 100644 index 0000000..61e47bd --- /dev/null +++ b/palacios/include/geekos/symbol.h @@ -0,0 +1,20 @@ +/* + * Symbol mangling macros + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * The _S macro mangles a symbol name into whatever format is + * needed for external linkage. E.g., prepend an underscore + * for PECOFF. + */ + +#ifndef GEEKOS_SYMBOL_H +#define GEEKOS_SYMBOL_H + +#ifdef NEED_UNDERSCORE +# define _S(sym) "_" #sym +#else +# define _S(sym) #sym +#endif + +#endif /* GEEKOS_SYMBOL_H */ diff --git a/palacios/include/geekos/synch.h b/palacios/include/geekos/synch.h new file mode 100644 index 0000000..5cb95ef --- /dev/null +++ b/palacios/include/geekos/synch.h @@ -0,0 +1,44 @@ +/* + * Synchronization primitives + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_SYNCH_H +#define GEEKOS_SYNCH_H + +#include + +/* + * mutex states + */ +enum { MUTEX_UNLOCKED, MUTEX_LOCKED }; + +struct Mutex { + int state; + struct Kernel_Thread* owner; + struct Thread_Queue waitQueue; +}; + +#define MUTEX_INITIALIZER { MUTEX_UNLOCKED, 0, THREAD_QUEUE_INITIALIZER } + +struct Condition { + struct Thread_Queue waitQueue; +}; + +void Mutex_Init(struct Mutex* mutex); +void Mutex_Lock(struct Mutex* mutex); +void Mutex_Unlock(struct Mutex* mutex); + +void Cond_Init(struct Condition* cond); +void Cond_Wait(struct Condition* cond, struct Mutex* mutex); +void Cond_Signal(struct Condition* cond); +void Cond_Broadcast(struct Condition* cond); + +#define IS_HELD(mutex) \ + ((mutex)->state == MUTEX_LOCKED && (mutex)->owner == g_currentThread) + +#endif /* GEEKOS_SYNCH_H */ diff --git a/palacios/include/geekos/timer.h b/palacios/include/geekos/timer.h new file mode 100644 index 0000000..37dda14 --- /dev/null +++ b/palacios/include/geekos/timer.h @@ -0,0 +1,24 @@ +/* + * GeekOS timer interrupt support + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_TIMER_H +#define GEEKOS_TIMER_H + +#define TIMER_IRQ 0 + +extern volatile ulong_t g_numTicks; + +void Init_Timer(void); + +void Micro_Delay(int us); + + +void Micro_Delay(int us); + +#endif /* GEEKOS_TIMER_H */ diff --git a/palacios/include/geekos/trap.h b/palacios/include/geekos/trap.h new file mode 100644 index 0000000..73c28b8 --- /dev/null +++ b/palacios/include/geekos/trap.h @@ -0,0 +1,15 @@ +/* + * Trap handlers + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_TRAP_H +#define GEEKOS_TRAP_H + +void Init_Traps(void); + +#endif /* GEEKOS_TRAP_H */ diff --git a/palacios/include/geekos/tss.h b/palacios/include/geekos/tss.h new file mode 100644 index 0000000..66ea118 --- /dev/null +++ b/palacios/include/geekos/tss.h @@ -0,0 +1,89 @@ +/* + * x86 TSS data structure and routines + * Copyright (c) 2001,2004 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef GEEKOS_TSS_H +#define GEEKOS_TSS_H + +/* + * Source: _Protected Mode Software Architecture_ by Tom Shanley, + * ISBN 020155447X. + */ + +/* + * NOTE: all reserved fields must be set to zero. + */ + +struct TSS { + /* + * Link to nested task. For example, if an interrupt is handled + * by a task gate, the link field will contain the selector for + * the TSS of the interrupted task. + */ + ushort_t link; + ushort_t reserved1; + + /* Stacks for privilege levels. esp0/ss0 specifies the kernel stack. */ + ulong_t esp0; + ushort_t ss0; + ushort_t reserved2; + ulong_t esp1; + ushort_t ss1; + ushort_t reserved3; + ulong_t esp2; + ushort_t ss2; + ushort_t reserved4; + + /* Page directory register. */ + ulong_t cr3; + + /* General processor registers. */ + ulong_t eip; + ulong_t eflags; + ulong_t eax; + ulong_t ecx; + ulong_t edx; + ulong_t ebx; + ulong_t esp; + ulong_t ebp; + ulong_t esi; + ulong_t edi; + + /* Segment registers and padding. */ + ushort_t es; + ushort_t reserved5; + ushort_t cs; + ushort_t reserved6; + ushort_t ss; + ushort_t reserved7; + ushort_t ds; + ushort_t reserved8; + ushort_t fs; + ushort_t reserved9; + ushort_t gs; + ushort_t reserved10; + + /* GDT selector for the LDT descriptor. */ + ushort_t ldt; + ushort_t reserved11; + + /* + * The debug trap bit causes a debug exception upon a switch + * to the task specified by this TSS. + */ + uint_t debugTrap : 1; + uint_t reserved12 : 15; + + /* Offset in the TSS specifying where the io map is located. */ + ushort_t ioMapBase; +}; + +void Init_TSS(void); +void Set_Kernel_Stack_Pointer(ulong_t esp0); + +#endif /* GEEKOS_TSS_H */ diff --git a/palacios/include/geekos/vmcs.h b/palacios/include/geekos/vmcs.h new file mode 100644 index 0000000..30af389 --- /dev/null +++ b/palacios/include/geekos/vmcs.h @@ -0,0 +1,586 @@ +#ifndef __VMCS_H +#define __VMCS_H + +#include + + +/* 16 bit guest state */ +#define VMCS_GUEST_ES_SELECTOR 0x00000800 +#define VMCS_GUEST_CS_SELECTOR 0x00000802 +#define VMCS_GUEST_SS_SELECTOR 0x00000804 +#define VMCS_GUEST_DS_SELECTOR 0x00000806 +#define VMCS_GUEST_FS_SELECTOR 0x00000808 +#define VMCS_GUEST_GS_SELECTOR 0x0000080A +#define VMCS_GUEST_LDTR_SELECTOR 0x0000080C +#define VMCS_GUEST_TR_SELECTOR 0x0000080E + +/* 16 bit host state */ +#define VMCS_HOST_ES_SELECTOR 0x00000C00 +#define VMCS_HOST_CS_SELECTOR 0x00000C02 +#define VMCS_HOST_SS_SELECTOR 0x00000C04 +#define VMCS_HOST_DS_SELECTOR 0x00000C06 +#define VMCS_HOST_FS_SELECTOR 0x00000C08 +#define VMCS_HOST_GS_SELECTOR 0x00000C0A +#define VMCS_HOST_TR_SELECTOR 0x00000C0C + +/* 64 bit control fields */ +#define IO_BITMAP_A_ADDR 0x00002000 +#define IO_BITMAP_A_ADDR_HIGH 0x00002001 +#define IO_BITMAP_B_ADDR 0x00002002 +#define IO_BITMAP_B_ADDR_HIGH 0x00002003 +// Only with "Use MSR Bitmaps" enabled +#define MSR_BITMAPS 0x00002004 +#define MSR_BITMAPS_HIGH 0x00002005 +// +#define VM_EXIT_MSR_STORE_ADDR 0x00002006 +#define VM_EXIT_MSR_STORE_ADDR_HIGH 0x00002007 +#define VM_EXIT_MSR_LOAD_ADDR 0x00002008 +#define VM_EXIT_MSR_LOAD_ADDR_HIGH 0x00002009 +#define VM_ENTRY_MSR_LOAD_ADDR 0x0000200A +#define VM_ENTRY_MSR_LOAD_ADDR_HIGH 0x0000200B +#define VMCS_EXEC_PTR 0x0000200C +#define VMCS_EXEC_PTR_HIGH 0x0000200D +#define TSC_OFFSET 0x00002010 +#define TSC_OFFSET_HIGH 0x00002011 +// Only with "Use TPR Shadow" enabled +#define VIRT_APIC_PAGE_ADDR 0x00002012 +#define VIRT_APIC_PAGE_ADDR_HIGH 0x00002013 +// + + +/* 64 bit guest state fields */ +#define VMCS_LINK_PTR 0x00002800 +#define VMCS_LINK_PTR_HIGH 0x00002801 +#define GUEST_IA32_DEBUGCTL 0x00002802 +#define GUEST_IA32_DEBUGCTL_HIGH 0x00002803 + + +/* 32 bit control fields */ +#define PIN_VM_EXEC_CTRLS 0x00004000 +#define PROC_VM_EXEC_CTRLS 0x00004002 +#define EXCEPTION_BITMAP 0x00004004 +#define PAGE_FAULT_ERROR_MASK 0x00004006 +#define PAGE_FAULT_ERROR_MATCH 0x00004008 +#define CR3_TARGET_COUNT 0x0000400A +#define VM_EXIT_CTRLS 0x0000400C +#define VM_EXIT_MSR_STORE_COUNT 0x0000400E +#define VM_EXIT_MSR_LOAD_COUNT 0x00004010 +#define VM_ENTRY_CTRLS 0x00004012 +#define VM_ENTRY_MSR_LOAD_COUNT 0x00004014 +#define VM_ENTRY_INT_INFO_FIELD 0x00004016 +#define VM_ENTRY_EXCEPTION_ERROR 0x00004018 +#define VM_ENTRY_INSTR_LENGTH 0x0000401A +// Only with "Use TPR Shadow" Enabled +#define TPR_THRESHOLD 0x0000401C +// + + +/* 32 bit Read Only data fields */ +#define VM_INSTR_ERROR 0x00004400 +#define EXIT_REASON 0x00004402 +#define VM_EXIT_INT_INFO 0x00004404 +#define VM_EXIT_INT_ERROR 0x00004406 +#define IDT_VECTOR_INFO 0x00004408 +#define IDT_VECTOR_ERROR 0x0000440A +#define VM_EXIT_INSTR_LENGTH 0x0000440C +#define VMX_INSTR_INFO 0x0000440E + +/* 32 bit Guest state fields */ +#define GUEST_ES_LIMIT 0x00004800 +#define GUEST_CS_LIMIT 0x00004802 +#define GUEST_SS_LIMIT 0x00004804 +#define GUEST_DS_LIMIT 0x00004806 +#define GUEST_FS_LIMIT 0x00004808 +#define GUEST_GS_LIMIT 0x0000480A +#define GUEST_LDTR_LIMIT 0x0000480C +#define GUEST_TR_LIMIT 0x0000480E +#define GUEST_GDTR_LIMIT 0x00004810 +#define GUEST_IDTR_LIMIT 0x00004812 +#define GUEST_ES_ACCESS 0x00004814 +#define GUEST_CS_ACCESS 0x00004816 +#define GUEST_SS_ACCESS 0x00004818 +#define GUEST_DS_ACCESS 0x0000481A +#define GUEST_FS_ACCESS 0x0000481C +#define GUEST_GS_ACCESS 0x0000481E +#define GUEST_LDTR_ACCESS 0x00004820 +#define GUEST_TR_ACCESS 0x00004822 +#define GUEST_INT_STATE 0x00004824 +#define GUEST_ACTIVITY_STATE 0x00004826 +#define GUEST_SMBASE 0x00004828 +#define GUEST_IA32_SYSENTER_CS 0x0000482A + + +/* 32 bit host state field */ +#define HOST_IA32_SYSENTER_CS 0x00004C00 + +/* Natural Width Control Fields */ +#define CR0_GUEST_HOST_MASK 0x00006000 +#define CR4_GUEST_HOST_MASK 0x00006002 +#define CR0_READ_SHADOW 0x00006004 +#define CR4_READ_SHADOW 0x00006006 +#define CR3_TARGET_VALUE_0 0x00006008 +#define CR3_TARGET_VALUE_1 0x0000600A +#define CR3_TARGET_VALUE_2 0x0000600C +#define CR3_TARGET_VALUE_3 0x0000600E + + +/* Natural Width Read Only Fields */ +#define EXIT_QUALIFICATION 0x00006400 +#define IO_RCX 0x00006402 +#define IO_RSI 0x00006404 +#define IO_RDI 0x00006406 +#define IO_RIP 0x00006408 +#define GUEST_LINEAR_ADDR 0x0000640A + +/* Natural Width Guest State Fields */ +#define GUEST_CR0 0x00006800 +#define GUEST_CR3 0x00006802 +#define GUEST_CR4 0x00006804 +#define GUEST_ES_BASE 0x00006806 +#define GUEST_CS_BASE 0x00006808 +#define GUEST_SS_BASE 0x0000680A +#define GUEST_DS_BASE 0x0000680C +#define GUEST_FS_BASE 0x0000680E +#define GUEST_GS_BASE 0x00006810 +#define GUEST_LDTR_BASE 0x00006812 +#define GUEST_TR_BASE 0x00006814 +#define GUEST_GDTR_BASE 0x00006816 +#define GUEST_IDTR_BASE 0x00006818 +#define GUEST_DR7 0x0000681A +#define GUEST_RSP 0x0000681C +#define GUEST_RIP 0x0000681E +#define GUEST_RFLAGS 0x00006820 +#define GUEST_PENDING_DEBUG_EXCS 0x00006822 +#define GUEST_IA32_SYSENTER_ESP 0x00006824 +#define GUEST_IA32_SYSENTER_EIP 0x00006826 + + +/* Natural Width Host State Fields */ +#define HOST_CR0 0x00006C00 +#define HOST_CR3 0x00006C02 +#define HOST_CR4 0x00006C04 +#define HOST_FS_BASE 0x00006C06 +#define HOST_GS_BASE 0x00006C08 +#define HOST_TR_BASE 0x00006C0A +#define HOST_GDTR_BASE 0x00006C0C +#define HOST_IDTR_BASE 0x00006C0E +#define HOST_IA32_SYSENTER_ESP 0x00006C10 +#define HOST_IA32_SYSENTER_EIP 0x00006C12 +#define HOST_RSP 0x00006C14 +#define HOST_RIP 0x00006C16 + +/* Pin Based VM Execution Controls */ +/* INTEL MANUAL: 20-10 vol 3B */ +#define EXTERNAL_INTERRUPT_EXITING 0x00000001 +#define NMI_EXITING 0x00000008 +#define VIRTUAL_NMIS 0x00000020 + + +/* Processor Based VM Execution Controls */ +/* INTEL MANUAL: 20-11 vol. 3B */ +#define INTERRUPT_WINDOWS_EXIT 0x00000004 +#define USE_TSC_OFFSETTING 0x00000008 +#define HLT_EXITING 0x00000080 +#define INVLPG_EXITING 0x00000200 +#define MWAIT_EXITING 0x00000400 +#define RDPMC_EXITING 0x00000800 +#define RDTSC_EXITING 0x00001000 +#define CR8_LOAD_EXITING 0x00080000 +#define CR8_STORE_EXITING 0x00100000 +#define USE_TPR_SHADOW 0x00200000 +#define NMI_WINDOW_EXITING 0x00400000 +#define MOVDR_EXITING 0x00800000 +#define UNCONDITION_IO_EXITING 0x01000000 +#define USE_IO_BITMAPS 0x02000000 +#define USE_MSR_BITMAPS 0x10000000 +#define MONITOR_EXITING 0x20000000 +#define PAUSE_EXITING 0x40000000 + +/* VM-Exit Controls */ +/* INTEL MANUAL: 20-16 vol. 3B */ +#define HOST_ADDR_SPACE_SIZE 0x00000200 +#define ACK_IRQ_ON_EXIT 0x00008000 + +// Exit Reasons +#define VM_EXIT_REASON_INFO_EXCEPTION_OR_NMI 0 +#define VM_EXIT_REASON_EXTERNAL_INTR 1 +#define VM_EXIT_REASON_TRIPLE_FAULT 2 +#define VM_EXIT_REASON_INIT_SIGNAL 3 +#define VM_EXIT_REASON_STARTUP_IPI 4 +#define VM_EXIT_REASON_IO_SMI 5 +#define VM_EXIT_REASON_OTHER_SMI 6 +#define VM_EXIT_REASON_INTR_WINDOW 7 +#define VM_EXIT_REASON_NMI_WINDOW 8 +#define VM_EXIT_REASON_TASK_SWITCH 9 +#define VM_EXIT_REASON_CPUID 10 +#define VM_EXIT_REASON_HLT 12 +#define VM_EXIT_REASON_INVD 13 +#define VM_EXIT_REASON_INVLPG 14 +#define VM_EXIT_REASON_RDPMC 15 +#define VM_EXIT_REASON_RDTSC 16 +#define VM_EXIT_REASON_RSM 17 +#define VM_EXIT_REASON_VMCALL 18 +#define VM_EXIT_REASON_VMCLEAR 19 +#define VM_EXIT_REASON_VMLAUNCH 20 +#define VM_EXIT_REASON_VMPTRLD 21 +#define VM_EXIT_REASON_VMPTRST 22 +#define VM_EXIT_REASON_VMREAD 23 +#define VM_EXIT_REASON_VMRESUME 24 +#define VM_EXIT_REASON_VMWRITE 25 +#define VM_EXIT_REASON_VMXOFF 26 +#define VM_EXIT_REASON_VMXON 27 +#define VM_EXIT_REASON_CR_REG_ACCESSES 28 +#define VM_EXIT_REASON_MOV_DR 29 +#define VM_EXIT_REASON_IO_INSTR 30 +#define VM_EXIT_REASON_RDMSR 31 +#define VM_EXIT_REASON_WRMSR 32 +#define VM_EXIT_REASON_ENTRY_FAIL_INVALID_GUEST_STATE 33 +#define VM_EXIT_REASON_ENTRY_FAIL_MSR_LOAD 34 +#define VM_EXIT_REASON_MWAIT 36 +#define VM_EXIT_REASON_MONITOR 39 +#define VM_EXIT_REASON_PAUSE 40 +#define VM_EXIT_REASON_ENTRY_FAILURE_MACHINE_CHECK 41 +#define VM_EXIT_REASON_TPR_BELOW_THRESHOLD 43 + + +extern char *exception_names[]; +extern char *exception_type_names[]; + + + + +typedef void VMCS; + + +#if __TINYC__ +#define PACKED +#else +#define PACKED __attribute__((packed)) +#endif + + + +/* VMCS Exit QUALIFICATIONs */ +struct VMExitIOQual { + uint_t accessSize : 3 PACKED; // (0: 1 Byte ;; 1: 2 Bytes ;; 3: 4 Bytes) + uint_t dir : 1 PACKED; // (0: Out ;; 1: In) + uint_t string : 1 PACKED; // (0: not string ;; 1: string) + uint_t REP : 1 PACKED; // (0: not REP ;; 1: REP) + uint_t opEnc : 1 PACKED; // (0: DX ;; 1: immediate) + uint_t rsvd : 9 PACKED; // Set to 0 + uint_t port : 16 PACKED; // IO Port Number +}; + + + +struct VMExitDBGQual { + uint_t B0 : 1 PACKED; // Breakpoint 0 condition met + uint_t B1 : 1 PACKED; // Breakpoint 1 condition met + uint_t B2 : 1 PACKED; // Breakpoint 2 condition met + uint_t B3 : 1 PACKED; // Breakpoint 3 condition met + uint_t rsvd : 9 PACKED; // reserved to 0 + uint_t BD : 1 PACKED; // detected DBG reg access + uint_t BS : 1 PACKED; // cause either single instr or taken branch +}; + + +struct VMExitTSQual { + uint_t selector : 16 PACKED; // selector of destination TSS + uint_t rsvd : 14 PACKED; // reserved to 0 + uint_t src : 2 PACKED; // (0: CALL ; 1: IRET ; 2: JMP ; 3: Task gate in IDT) +}; + +struct VMExitCRQual { + uint_t crID : 4 PACKED; // cr number (0 for CLTS and LMSW) (bit 3 always 0, on 32bit) + uint_t accessType : 2 PACKED; // (0: MOV to CR ; 1: MOV from CR ; 2: CLTS ; 3: LMSW) + uint_t lmswOpType : 1 PACKED; // (0: register ; 1: memory) + uint_t rsvd1 : 1 PACKED; // reserved to 0 + uint_t gpr : 4 PACKED; // (0:RAX+[CLTS/LMSW], 1:RCX, 2:RDX, 3:RBX, 4:RSP, 5:RBP, 6:RSI, 6:RDI, 8-15:64bit regs) + uint_t rsvd2 : 4 PACKED; // reserved to 0 + uint_t lmswSrc : 16 PACKED; // src data for lmsw +}; + +struct VMExitMovDRQual { + uint_t regID : 3 PACKED; // debug register number + uint_t rsvd1 : 1 PACKED; // reserved to 0 + uint_t dir : 1 PACKED; // (0: MOV to DR , 1: MOV from DR) + uint_t rsvd2 : 3 PACKED; // reserved to 0 + uint_t gpr : 4 PACKED; // (0:RAX, 1:RCX, 2:RDX, 3:RBX, 4:RSP, 5:RBP, 6:RSI, 6:RDI, 8-15:64bit regs) +}; + +/* End Exit Qualifications */ + +/* Exit Vector Info */ +struct VMExitIntInfo { + uint_t nr : 8 PACKED; // IRQ number, exception vector, NMI = 2 + uint_t type : 3 PACKED; // (0: ext. IRQ , 2: NMI , 3: hw exception , 6: sw exception + uint_t errorCode : 1 PACKED; // 1: error Code present + uint_t iret : 1 PACKED; // something to do with NMIs and IRETs (Intel 3B, sec. 23.2.2) + uint_t rsvd : 18 PACKED; // always 0 + uint_t valid : 1 PACKED; // always 1 if valid +}; + + + + +/* End Exit Vector Info */ + + + + +/* Segment Selector Access Rights (32 bits) */ +/* INTEL Manual: 20-4 vol 3B */ +union SegAccess { + struct { + uchar_t type PACKED; + uint_t descType : 1 PACKED; + uint_t dpl : 2 PACKED; + uint_t present : 1 PACKED; + uchar_t rsvd1 PACKED; + uint_t avail : 1 PACKED ; + uint_t L : 1 PACKED ; // CS only (64 bit active), reserved otherwise + uint_t DB : 1 PACKED ; + uint_t granularity : 1 PACKED ; + uint_t unusable : 1 PACKED ; + uint_t rsvd2 : 15 PACKED ; + } as_fields; + uint_t as_dword; +}; + + +struct VMCSSegment { + ushort_t selector ; + uint_t baseAddr ; // should be 64 bits? + uint_t limit ; + union SegAccess access ; + +}; + + + +struct VMCSGuestStateArea { + /* (1) Guest State Area */ + /* (1.1) Guest Register State */ + uint_t cr0 ; // should be 64 bits? + uint_t cr3 ; // should be 64 bits? + uint_t cr4 ; // should be 64 bits? + uint_t dr7 ; // should be 64 bits? + uint_t rsp ; // should be 64 bits? + uint_t rip ; // should be 64 bits? + uint_t rflags ; // should be 64 bits? + + + struct VMCSSegment cs ; + struct VMCSSegment ss ; + struct VMCSSegment ds ; + struct VMCSSegment es ; + struct VMCSSegment fs ; + struct VMCSSegment gs ; + struct VMCSSegment ldtr ; + struct VMCSSegment tr ; + + struct VMCSSegment gdtr ; + struct VMCSSegment idtr ; + + // MSRs + ullong_t dbg_ctrl ; + uint_t sysenter_cs ; + ullong_t sysenter_esp ; // should be 64 bits? + ullong_t sysenter_eip ; // should be 64 bits? + + uint_t smbase ; + + /* (1.2) Guest Non-register State */ + uint_t activity ; /* (0=Active, 1=HLT, 2=Shutdown, 3=Wait-for-SIPI) + (listed in MSR: IA32_VMX_MISC) */ + + uint_t interrupt_state ; // see Table 20-3 (page 20-6) INTEL MANUAL 3B + + ullong_t pending_dbg_exceptions ; // should be 64 bits? + /* Table 20-4 page 20-8 INTEL MANUAL 3B */ + + ullong_t vmcs_link ; // should be set to 0xffffffff_ffffffff +}; + + +int CopyOutVMCSGuestStateArea(struct VMCSGuestStateArea *p); +int CopyInVMCSGuestStateArea(struct VMCSGuestStateArea *p); + + + +struct VMCSHostStateArea { + /* (2) Host State Area */ + ullong_t cr0 ; // Should be 64 bits? + ullong_t cr3 ; // should be 64 bits? + ullong_t cr4 ; // should be 64 bits? + ullong_t rsp ; // should be 64 bits? + ullong_t rip ; // should be 64 bits? + + ushort_t csSelector ; + ushort_t ssSelector ; + ushort_t dsSelector ; + ushort_t esSelector ; + ushort_t fsSelector ; + ushort_t gsSelector ; + ushort_t trSelector ; + + ullong_t fsBaseAddr ; // Should be 64 bits? + ullong_t gsBaseAddr ; // Should be 64 bits? + ullong_t trBaseAddr ; // Should be 64 bits? + ullong_t gdtrBaseAddr ; // Should be 64 bits? + ullong_t idtrBaseAddr ; // Should be 64 bits? + + + /* MSRs */ + uint_t sysenter_cs ; + ullong_t sysenter_esp ; // Should be 64 bits? + ullong_t sysenter_eip ; // Should be 64 bits? + +}; + +int CopyOutVMCSHostStateArea(struct VMCSHostStateArea *p); +int CopyInVMCSHostStateArea(struct VMCSHostStateArea *p); + + +struct VMCSExecCtrlFields { + uint_t pinCtrls ; // Table 20-5, Vol 3B. (pg. 20-10) + uint_t procCtrls ; // Table 20-6, Vol 3B. (pg. 20-11) + uint_t execBitmap ; + uint_t pageFaultErrorMask ; + uint_t pageFaultErrorMatch ; + uint_t ioBitmapA ; + uint_t ioBitmapB ; + ullong_t tscOffset ; + uint_t cr0GuestHostMask ; // Should be 64 bits? + uint_t cr0ReadShadow ; // Should be 64 bits? + uint_t cr4GuestHostMask ; // Should be 64 bits? + uint_t cr4ReadShadow ; // Should be 64 bits? + uint_t cr3TargetValue0 ; // should be 64 bits? + uint_t cr3TargetValue1 ; // should be 64 bits? + uint_t cr3TargetValue2 ; // should be 64 bits? + uint_t cr3TargetValue3 ; // should be 64 bits? + uint_t cr3TargetCount ; + + + + /* these fields enabled if "use TPR shadow"==1 */ + /* may not need them */ + ullong_t virtApicPageAddr ; + // uint_t virtApicPageAddrHigh + uint_t tprThreshold ; + /**/ + + ullong_t MSRBitmapsBaseAddr; + + + ullong_t vmcsExecPtr ; + +}; + +int CopyOutVMCSExecCtrlFields(struct VMCSExecCtrlFields *p); +int CopyInVMCSExecCtrlFields(struct VMCSExecCtrlFields *p); + + + + +struct VMCSExitCtrlFields { + uint_t exitCtrls ; // Table 20-7, Vol. 3B (pg. 20-16) + uint_t msrStoreCount ; + ullong_t msrStoreAddr ; + uint_t msrLoadCount ; + ullong_t msrLoadAddr ; +}; + +int CopyOutVMCSExitCtrlFields(struct VMCSExitCtrlFields *p); +int CopyInVMCSExitCtrlFields(struct VMCSExitCtrlFields *p); + + + +struct VMCSEntryCtrlFields { + uint_t entryCtrls ; // Table 20-9, Vol. 3B (pg. 20-18) + uint_t msrLoadCount ; + ullong_t msrLoadAddr ; + uint_t intInfo ; // Table 20-10, Vol. 3B (pg. 20-19) + uint_t exceptionErrorCode ; + uint_t instrLength ; +}; + + +int CopyOutVMCSEntryCtrlFields(struct VMCSEntryCtrlFields *p); +int CopyInVMCSEntryCtrlFields(struct VMCSEntryCtrlFields *p); + + +struct VMCSExitInfoFields { + uint_t reason; // Table 20-11, Vol. 3B (pg. 20-20) + uint_t qualification ; // Should be 64 bits? + uint_t intInfo ; + uint_t intErrorCode ; + uint_t idtVectorInfo ; + uint_t idtVectorErrorCode ; + uint_t instrLength ; + ullong_t guestLinearAddr ; // Should be 64 bits? + uint_t instrInfo ; + ullong_t ioRCX ; // Should be 64 bits? + ullong_t ioRSI ; // Should be 64 bits? + ullong_t ioRDI ; // Should be 64 bits? + ullong_t ioRIP ; // Should be 64 bits? + uint_t instrErrorField ; + +}; + + +int CopyOutVMCSExitInfoFields(struct VMCSExitInfoFields *p); + + + +struct VMCSData { + uint_t revision ; + uint_t abort ; + uint_t exitCtrlFlags; + struct VMCSGuestStateArea guestStateArea ; + struct VMCSHostStateArea hostStateArea ; + struct VMCSExecCtrlFields execCtrlFields ; + struct VMCSExitCtrlFields exitCtrlFields ; + struct VMCSEntryCtrlFields entryCtrlFields ; + struct VMCSExitInfoFields exitInfoFields ; +}; + + +int CopyOutVMCSData(struct VMCSData *p); +int CopyInVMCSData(struct VMCSData *p); + +struct VMXRegs { + uint_t edi; + uint_t esi; + uint_t ebp; + uint_t esp; + uint_t ebx; + uint_t edx; + uint_t ecx; + uint_t eax; +}; + +void SerialPrint_VMX_Regs(struct VMXRegs *regs); +void SerialPrint_VMCSData(struct VMCSData * vmcs); +void SerialPrint_VMCSGuestStateArea(struct VMCSGuestStateArea * guestState); +void SerialPrint_VMCSHostStateArea(struct VMCSHostStateArea * hostState); +void SerialPrint_VMCSExecCtrlFields(struct VMCSExecCtrlFields * execCtrls); +void SerialPrint_VMCSExitCtrlFields(struct VMCSExitCtrlFields * exitCtrls); +void SerialPrint_VMCSEntryCtrlFields(struct VMCSEntryCtrlFields * entryCtrls); +void SerialPrint_VMCSExitInfoFields(struct VMCSExitInfoFields * exitInfo); +void SerialPrint_VMCSSegment(char * segname, struct VMCSSegment * seg, int abbr); + +VMCS * CreateVMCS(); +extern uint_t VMCS_WRITE(); +extern uint_t VMCS_READ(); + +//uint_t VMCSRead(uint_t tag, void * val); + + + + + +#include +#include + +#endif diff --git a/palacios/include/geekos/vmcs_gen.h b/palacios/include/geekos/vmcs_gen.h new file mode 100644 index 0000000..4bdef7c --- /dev/null +++ b/palacios/include/geekos/vmcs_gen.h @@ -0,0 +1,779 @@ +#ifndef vmcs_gen +#define vmcs_gen +#include + +void Set_VMCS_GUEST_ES_SELECTOR(uint_t val); +uint_t Get_VMCS_GUEST_ES_SELECTOR(); + +void SerialPrint_VMCS_GUEST_ES_SELECTOR(); + + +void Set_VMCS_GUEST_CS_SELECTOR(uint_t val); +uint_t Get_VMCS_GUEST_CS_SELECTOR(); + +void SerialPrint_VMCS_GUEST_CS_SELECTOR(); + + +void Set_VMCS_GUEST_SS_SELECTOR(uint_t val); +uint_t Get_VMCS_GUEST_SS_SELECTOR(); + +void SerialPrint_VMCS_GUEST_SS_SELECTOR(); + + +void Set_VMCS_GUEST_DS_SELECTOR(uint_t val); +uint_t Get_VMCS_GUEST_DS_SELECTOR(); + +void SerialPrint_VMCS_GUEST_DS_SELECTOR(); + + +void Set_VMCS_GUEST_FS_SELECTOR(uint_t val); +uint_t Get_VMCS_GUEST_FS_SELECTOR(); + +void SerialPrint_VMCS_GUEST_FS_SELECTOR(); + + +void Set_VMCS_GUEST_GS_SELECTOR(uint_t val); +uint_t Get_VMCS_GUEST_GS_SELECTOR(); + +void SerialPrint_VMCS_GUEST_GS_SELECTOR(); + + +void Set_VMCS_GUEST_LDTR_SELECTOR(uint_t val); +uint_t Get_VMCS_GUEST_LDTR_SELECTOR(); + +void SerialPrint_VMCS_GUEST_LDTR_SELECTOR(); + + +void Set_VMCS_GUEST_TR_SELECTOR(uint_t val); +uint_t Get_VMCS_GUEST_TR_SELECTOR(); + +void SerialPrint_VMCS_GUEST_TR_SELECTOR(); + + +void Set_VMCS_HOST_ES_SELECTOR(uint_t val); +uint_t Get_VMCS_HOST_ES_SELECTOR(); + +void SerialPrint_VMCS_HOST_ES_SELECTOR(); + + +void Set_VMCS_HOST_CS_SELECTOR(uint_t val); +uint_t Get_VMCS_HOST_CS_SELECTOR(); + +void SerialPrint_VMCS_HOST_CS_SELECTOR(); + + +void Set_VMCS_HOST_SS_SELECTOR(uint_t val); +uint_t Get_VMCS_HOST_SS_SELECTOR(); + +void SerialPrint_VMCS_HOST_SS_SELECTOR(); + + +void Set_VMCS_HOST_DS_SELECTOR(uint_t val); +uint_t Get_VMCS_HOST_DS_SELECTOR(); + +void SerialPrint_VMCS_HOST_DS_SELECTOR(); + + +void Set_VMCS_HOST_FS_SELECTOR(uint_t val); +uint_t Get_VMCS_HOST_FS_SELECTOR(); + +void SerialPrint_VMCS_HOST_FS_SELECTOR(); + + +void Set_VMCS_HOST_GS_SELECTOR(uint_t val); +uint_t Get_VMCS_HOST_GS_SELECTOR(); + +void SerialPrint_VMCS_HOST_GS_SELECTOR(); + + +void Set_VMCS_HOST_TR_SELECTOR(uint_t val); +uint_t Get_VMCS_HOST_TR_SELECTOR(); + +void SerialPrint_VMCS_HOST_TR_SELECTOR(); + + +void Set_IO_BITMAP_A_ADDR(uint_t val); +uint_t Get_IO_BITMAP_A_ADDR(); + +void SerialPrint_IO_BITMAP_A_ADDR(); + + +void Set_IO_BITMAP_A_ADDR_HIGH(uint_t val); +uint_t Get_IO_BITMAP_A_ADDR_HIGH(); + +void SerialPrint_IO_BITMAP_A_ADDR_HIGH(); + + +void Set_IO_BITMAP_B_ADDR(uint_t val); +uint_t Get_IO_BITMAP_B_ADDR(); + +void SerialPrint_IO_BITMAP_B_ADDR(); + + +void Set_IO_BITMAP_B_ADDR_HIGH(uint_t val); +uint_t Get_IO_BITMAP_B_ADDR_HIGH(); + +void SerialPrint_IO_BITMAP_B_ADDR_HIGH(); + + +void Set_MSR_BITMAPS(uint_t val); +uint_t Get_MSR_BITMAPS(); + +void SerialPrint_MSR_BITMAPS(); + + +void Set_MSR_BITMAPS_HIGH(uint_t val); +uint_t Get_MSR_BITMAPS_HIGH(); + +void SerialPrint_MSR_BITMAPS_HIGH(); + + +void Set_VM_EXIT_MSR_STORE_ADDR(uint_t val); +uint_t Get_VM_EXIT_MSR_STORE_ADDR(); + +void SerialPrint_VM_EXIT_MSR_STORE_ADDR(); + + +void Set_VM_EXIT_MSR_STORE_ADDR_HIGH(uint_t val); +uint_t Get_VM_EXIT_MSR_STORE_ADDR_HIGH(); + +void SerialPrint_VM_EXIT_MSR_STORE_ADDR_HIGH(); + + +void Set_VM_EXIT_MSR_LOAD_ADDR(uint_t val); +uint_t Get_VM_EXIT_MSR_LOAD_ADDR(); + +void SerialPrint_VM_EXIT_MSR_LOAD_ADDR(); + + +void Set_VM_EXIT_MSR_LOAD_ADDR_HIGH(uint_t val); +uint_t Get_VM_EXIT_MSR_LOAD_ADDR_HIGH(); + +void SerialPrint_VM_EXIT_MSR_LOAD_ADDR_HIGH(); + + +void Set_VM_ENTRY_MSR_LOAD_ADDR(uint_t val); +uint_t Get_VM_ENTRY_MSR_LOAD_ADDR(); + +void SerialPrint_VM_ENTRY_MSR_LOAD_ADDR(); + + +void Set_VM_ENTRY_MSR_LOAD_ADDR_HIGH(uint_t val); +uint_t Get_VM_ENTRY_MSR_LOAD_ADDR_HIGH(); + +void SerialPrint_VM_ENTRY_MSR_LOAD_ADDR_HIGH(); + + +void Set_VMCS_EXEC_PTR(uint_t val); +uint_t Get_VMCS_EXEC_PTR(); + +void SerialPrint_VMCS_EXEC_PTR(); + + +void Set_VMCS_EXEC_PTR_HIGH(uint_t val); +uint_t Get_VMCS_EXEC_PTR_HIGH(); + +void SerialPrint_VMCS_EXEC_PTR_HIGH(); + + +void Set_TSC_OFFSET(uint_t val); +uint_t Get_TSC_OFFSET(); + +void SerialPrint_TSC_OFFSET(); + + +void Set_TSC_OFFSET_HIGH(uint_t val); +uint_t Get_TSC_OFFSET_HIGH(); + +void SerialPrint_TSC_OFFSET_HIGH(); + + +void Set_VIRT_APIC_PAGE_ADDR(uint_t val); +uint_t Get_VIRT_APIC_PAGE_ADDR(); + +void SerialPrint_VIRT_APIC_PAGE_ADDR(); + + +void Set_VIRT_APIC_PAGE_ADDR_HIGH(uint_t val); +uint_t Get_VIRT_APIC_PAGE_ADDR_HIGH(); + +void SerialPrint_VIRT_APIC_PAGE_ADDR_HIGH(); + + +void Set_VMCS_LINK_PTR(uint_t val); +uint_t Get_VMCS_LINK_PTR(); + +void SerialPrint_VMCS_LINK_PTR(); + + +void Set_VMCS_LINK_PTR_HIGH(uint_t val); +uint_t Get_VMCS_LINK_PTR_HIGH(); + +void SerialPrint_VMCS_LINK_PTR_HIGH(); + + +void Set_GUEST_IA32_DEBUGCTL(uint_t val); +uint_t Get_GUEST_IA32_DEBUGCTL(); + +void SerialPrint_GUEST_IA32_DEBUGCTL(); + + +void Set_GUEST_IA32_DEBUGCTL_HIGH(uint_t val); +uint_t Get_GUEST_IA32_DEBUGCTL_HIGH(); + +void SerialPrint_GUEST_IA32_DEBUGCTL_HIGH(); + + +void Set_PIN_VM_EXEC_CTRLS(uint_t val); +uint_t Get_PIN_VM_EXEC_CTRLS(); + +void SerialPrint_PIN_VM_EXEC_CTRLS(); + + +void Set_PROC_VM_EXEC_CTRLS(uint_t val); +uint_t Get_PROC_VM_EXEC_CTRLS(); + +void SerialPrint_PROC_VM_EXEC_CTRLS(); + + +void Set_EXCEPTION_BITMAP(uint_t val); +uint_t Get_EXCEPTION_BITMAP(); + +void SerialPrint_EXCEPTION_BITMAP(); + + +void Set_PAGE_FAULT_ERROR_MASK(uint_t val); +uint_t Get_PAGE_FAULT_ERROR_MASK(); + +void SerialPrint_PAGE_FAULT_ERROR_MASK(); + + +void Set_PAGE_FAULT_ERROR_MATCH(uint_t val); +uint_t Get_PAGE_FAULT_ERROR_MATCH(); + +void SerialPrint_PAGE_FAULT_ERROR_MATCH(); + + +void Set_CR3_TARGET_COUNT(uint_t val); +uint_t Get_CR3_TARGET_COUNT(); + +void SerialPrint_CR3_TARGET_COUNT(); + + +void Set_VM_EXIT_CTRLS(uint_t val); +uint_t Get_VM_EXIT_CTRLS(); + +void SerialPrint_VM_EXIT_CTRLS(); + + +void Set_VM_EXIT_MSR_STORE_COUNT(uint_t val); +uint_t Get_VM_EXIT_MSR_STORE_COUNT(); + +void SerialPrint_VM_EXIT_MSR_STORE_COUNT(); + + +void Set_VM_EXIT_MSR_LOAD_COUNT(uint_t val); +uint_t Get_VM_EXIT_MSR_LOAD_COUNT(); + +void SerialPrint_VM_EXIT_MSR_LOAD_COUNT(); + + +void Set_VM_ENTRY_CTRLS(uint_t val); +uint_t Get_VM_ENTRY_CTRLS(); + +void SerialPrint_VM_ENTRY_CTRLS(); + + +void Set_VM_ENTRY_MSR_LOAD_COUNT(uint_t val); +uint_t Get_VM_ENTRY_MSR_LOAD_COUNT(); + +void SerialPrint_VM_ENTRY_MSR_LOAD_COUNT(); + + +void Set_VM_ENTRY_INT_INFO_FIELD(uint_t val); +uint_t Get_VM_ENTRY_INT_INFO_FIELD(); + +void SerialPrint_VM_ENTRY_INT_INFO_FIELD(); + + +void Set_VM_ENTRY_EXCEPTION_ERROR(uint_t val); +uint_t Get_VM_ENTRY_EXCEPTION_ERROR(); + +void SerialPrint_VM_ENTRY_EXCEPTION_ERROR(); + + +void Set_VM_ENTRY_INSTR_LENGTH(uint_t val); +uint_t Get_VM_ENTRY_INSTR_LENGTH(); + +void SerialPrint_VM_ENTRY_INSTR_LENGTH(); + + +void Set_TPR_THRESHOLD(uint_t val); +uint_t Get_TPR_THRESHOLD(); + +void SerialPrint_TPR_THRESHOLD(); + + +void Set_VM_INSTR_ERROR(uint_t val); +uint_t Get_VM_INSTR_ERROR(); + +void SerialPrint_VM_INSTR_ERROR(); + + +void Set_EXIT_REASON(uint_t val); +uint_t Get_EXIT_REASON(); + +void SerialPrint_EXIT_REASON(); + + +void Set_VM_EXIT_INT_INFO(uint_t val); +uint_t Get_VM_EXIT_INT_INFO(); + +void SerialPrint_VM_EXIT_INT_INFO(); + + +void Set_VM_EXIT_INT_ERROR(uint_t val); +uint_t Get_VM_EXIT_INT_ERROR(); + +void SerialPrint_VM_EXIT_INT_ERROR(); + + +void Set_IDT_VECTOR_INFO(uint_t val); +uint_t Get_IDT_VECTOR_INFO(); + +void SerialPrint_IDT_VECTOR_INFO(); + + +void Set_IDT_VECTOR_ERROR(uint_t val); +uint_t Get_IDT_VECTOR_ERROR(); + +void SerialPrint_IDT_VECTOR_ERROR(); + + +void Set_VM_EXIT_INSTR_LENGTH(uint_t val); +uint_t Get_VM_EXIT_INSTR_LENGTH(); + +void SerialPrint_VM_EXIT_INSTR_LENGTH(); + + +void Set_VMX_INSTR_INFO(uint_t val); +uint_t Get_VMX_INSTR_INFO(); + +void SerialPrint_VMX_INSTR_INFO(); + + +void Set_GUEST_ES_LIMIT(uint_t val); +uint_t Get_GUEST_ES_LIMIT(); + +void SerialPrint_GUEST_ES_LIMIT(); + + +void Set_GUEST_CS_LIMIT(uint_t val); +uint_t Get_GUEST_CS_LIMIT(); + +void SerialPrint_GUEST_CS_LIMIT(); + + +void Set_GUEST_SS_LIMIT(uint_t val); +uint_t Get_GUEST_SS_LIMIT(); + +void SerialPrint_GUEST_SS_LIMIT(); + + +void Set_GUEST_DS_LIMIT(uint_t val); +uint_t Get_GUEST_DS_LIMIT(); + +void SerialPrint_GUEST_DS_LIMIT(); + + +void Set_GUEST_FS_LIMIT(uint_t val); +uint_t Get_GUEST_FS_LIMIT(); + +void SerialPrint_GUEST_FS_LIMIT(); + + +void Set_GUEST_GS_LIMIT(uint_t val); +uint_t Get_GUEST_GS_LIMIT(); + +void SerialPrint_GUEST_GS_LIMIT(); + + +void Set_GUEST_LDTR_LIMIT(uint_t val); +uint_t Get_GUEST_LDTR_LIMIT(); + +void SerialPrint_GUEST_LDTR_LIMIT(); + + +void Set_GUEST_TR_LIMIT(uint_t val); +uint_t Get_GUEST_TR_LIMIT(); + +void SerialPrint_GUEST_TR_LIMIT(); + + +void Set_GUEST_GDTR_LIMIT(uint_t val); +uint_t Get_GUEST_GDTR_LIMIT(); + +void SerialPrint_GUEST_GDTR_LIMIT(); + + +void Set_GUEST_IDTR_LIMIT(uint_t val); +uint_t Get_GUEST_IDTR_LIMIT(); + +void SerialPrint_GUEST_IDTR_LIMIT(); + + +void Set_GUEST_ES_ACCESS(uint_t val); +uint_t Get_GUEST_ES_ACCESS(); + +void SerialPrint_GUEST_ES_ACCESS(); + + +void Set_GUEST_CS_ACCESS(uint_t val); +uint_t Get_GUEST_CS_ACCESS(); + +void SerialPrint_GUEST_CS_ACCESS(); + + +void Set_GUEST_SS_ACCESS(uint_t val); +uint_t Get_GUEST_SS_ACCESS(); + +void SerialPrint_GUEST_SS_ACCESS(); + + +void Set_GUEST_DS_ACCESS(uint_t val); +uint_t Get_GUEST_DS_ACCESS(); + +void SerialPrint_GUEST_DS_ACCESS(); + + +void Set_GUEST_FS_ACCESS(uint_t val); +uint_t Get_GUEST_FS_ACCESS(); + +void SerialPrint_GUEST_FS_ACCESS(); + + +void Set_GUEST_GS_ACCESS(uint_t val); +uint_t Get_GUEST_GS_ACCESS(); + +void SerialPrint_GUEST_GS_ACCESS(); + + +void Set_GUEST_LDTR_ACCESS(uint_t val); +uint_t Get_GUEST_LDTR_ACCESS(); + +void SerialPrint_GUEST_LDTR_ACCESS(); + + +void Set_GUEST_TR_ACCESS(uint_t val); +uint_t Get_GUEST_TR_ACCESS(); + +void SerialPrint_GUEST_TR_ACCESS(); + + +void Set_GUEST_INT_STATE(uint_t val); +uint_t Get_GUEST_INT_STATE(); + +void SerialPrint_GUEST_INT_STATE(); + + +void Set_GUEST_ACTIVITY_STATE(uint_t val); +uint_t Get_GUEST_ACTIVITY_STATE(); + +void SerialPrint_GUEST_ACTIVITY_STATE(); + + +void Set_GUEST_SMBASE(uint_t val); +uint_t Get_GUEST_SMBASE(); + +void SerialPrint_GUEST_SMBASE(); + + +void Set_GUEST_IA32_SYSENTER_CS(uint_t val); +uint_t Get_GUEST_IA32_SYSENTER_CS(); + +void SerialPrint_GUEST_IA32_SYSENTER_CS(); + + +void Set_HOST_IA32_SYSENTER_CS(uint_t val); +uint_t Get_HOST_IA32_SYSENTER_CS(); + +void SerialPrint_HOST_IA32_SYSENTER_CS(); + + +void Set_CR0_GUEST_HOST_MASK(uint_t val); +uint_t Get_CR0_GUEST_HOST_MASK(); + +void SerialPrint_CR0_GUEST_HOST_MASK(); + + +void Set_CR4_GUEST_HOST_MASK(uint_t val); +uint_t Get_CR4_GUEST_HOST_MASK(); + +void SerialPrint_CR4_GUEST_HOST_MASK(); + + +void Set_CR0_READ_SHADOW(uint_t val); +uint_t Get_CR0_READ_SHADOW(); + +void SerialPrint_CR0_READ_SHADOW(); + + +void Set_CR4_READ_SHADOW(uint_t val); +uint_t Get_CR4_READ_SHADOW(); + +void SerialPrint_CR4_READ_SHADOW(); + + +void Set_CR3_TARGET_VALUE_0(uint_t val); +uint_t Get_CR3_TARGET_VALUE_0(); + +void SerialPrint_CR3_TARGET_VALUE_0(); + + +void Set_CR3_TARGET_VALUE_1(uint_t val); +uint_t Get_CR3_TARGET_VALUE_1(); + +void SerialPrint_CR3_TARGET_VALUE_1(); + + +void Set_CR3_TARGET_VALUE_2(uint_t val); +uint_t Get_CR3_TARGET_VALUE_2(); + +void SerialPrint_CR3_TARGET_VALUE_2(); + + +void Set_CR3_TARGET_VALUE_3(uint_t val); +uint_t Get_CR3_TARGET_VALUE_3(); + +void SerialPrint_CR3_TARGET_VALUE_3(); + + +void Set_EXIT_QUALIFICATION(uint_t val); +uint_t Get_EXIT_QUALIFICATION(); + +void SerialPrint_EXIT_QUALIFICATION(); + + +void Set_IO_RCX(uint_t val); +uint_t Get_IO_RCX(); + +void SerialPrint_IO_RCX(); + + +void Set_IO_RSI(uint_t val); +uint_t Get_IO_RSI(); + +void SerialPrint_IO_RSI(); + + +void Set_IO_RDI(uint_t val); +uint_t Get_IO_RDI(); + +void SerialPrint_IO_RDI(); + + +void Set_IO_RIP(uint_t val); +uint_t Get_IO_RIP(); + +void SerialPrint_IO_RIP(); + + +void Set_GUEST_LINEAR_ADDR(uint_t val); +uint_t Get_GUEST_LINEAR_ADDR(); + +void SerialPrint_GUEST_LINEAR_ADDR(); + + +void Set_GUEST_CR0(uint_t val); +uint_t Get_GUEST_CR0(); + +void SerialPrint_GUEST_CR0(); + + +void Set_GUEST_CR3(uint_t val); +uint_t Get_GUEST_CR3(); + +void SerialPrint_GUEST_CR3(); + + +void Set_GUEST_CR4(uint_t val); +uint_t Get_GUEST_CR4(); + +void SerialPrint_GUEST_CR4(); + + +void Set_GUEST_ES_BASE(uint_t val); +uint_t Get_GUEST_ES_BASE(); + +void SerialPrint_GUEST_ES_BASE(); + + +void Set_GUEST_CS_BASE(uint_t val); +uint_t Get_GUEST_CS_BASE(); + +void SerialPrint_GUEST_CS_BASE(); + + +void Set_GUEST_SS_BASE(uint_t val); +uint_t Get_GUEST_SS_BASE(); + +void SerialPrint_GUEST_SS_BASE(); + + +void Set_GUEST_DS_BASE(uint_t val); +uint_t Get_GUEST_DS_BASE(); + +void SerialPrint_GUEST_DS_BASE(); + + +void Set_GUEST_FS_BASE(uint_t val); +uint_t Get_GUEST_FS_BASE(); + +void SerialPrint_GUEST_FS_BASE(); + + +void Set_GUEST_GS_BASE(uint_t val); +uint_t Get_GUEST_GS_BASE(); + +void SerialPrint_GUEST_GS_BASE(); + + +void Set_GUEST_LDTR_BASE(uint_t val); +uint_t Get_GUEST_LDTR_BASE(); + +void SerialPrint_GUEST_LDTR_BASE(); + + +void Set_GUEST_TR_BASE(uint_t val); +uint_t Get_GUEST_TR_BASE(); + +void SerialPrint_GUEST_TR_BASE(); + + +void Set_GUEST_GDTR_BASE(uint_t val); +uint_t Get_GUEST_GDTR_BASE(); + +void SerialPrint_GUEST_GDTR_BASE(); + + +void Set_GUEST_IDTR_BASE(uint_t val); +uint_t Get_GUEST_IDTR_BASE(); + +void SerialPrint_GUEST_IDTR_BASE(); + + +void Set_GUEST_DR7(uint_t val); +uint_t Get_GUEST_DR7(); + +void SerialPrint_GUEST_DR7(); + + +void Set_GUEST_RSP(uint_t val); +uint_t Get_GUEST_RSP(); + +void SerialPrint_GUEST_RSP(); + + +void Set_GUEST_RIP(uint_t val); +uint_t Get_GUEST_RIP(); + +void SerialPrint_GUEST_RIP(); + + +void Set_GUEST_RFLAGS(uint_t val); +uint_t Get_GUEST_RFLAGS(); + +void SerialPrint_GUEST_RFLAGS(); + + +void Set_GUEST_PENDING_DEBUG_EXCS(uint_t val); +uint_t Get_GUEST_PENDING_DEBUG_EXCS(); + +void SerialPrint_GUEST_PENDING_DEBUG_EXCS(); + + +void Set_GUEST_IA32_SYSENTER_ESP(uint_t val); +uint_t Get_GUEST_IA32_SYSENTER_ESP(); + +void SerialPrint_GUEST_IA32_SYSENTER_ESP(); + + +void Set_GUEST_IA32_SYSENTER_EIP(uint_t val); +uint_t Get_GUEST_IA32_SYSENTER_EIP(); + +void SerialPrint_GUEST_IA32_SYSENTER_EIP(); + + +void Set_HOST_CR0(uint_t val); +uint_t Get_HOST_CR0(); + +void SerialPrint_HOST_CR0(); + + +void Set_HOST_CR3(uint_t val); +uint_t Get_HOST_CR3(); + +void SerialPrint_HOST_CR3(); + + +void Set_HOST_CR4(uint_t val); +uint_t Get_HOST_CR4(); + +void SerialPrint_HOST_CR4(); + + +void Set_HOST_FS_BASE(uint_t val); +uint_t Get_HOST_FS_BASE(); + +void SerialPrint_HOST_FS_BASE(); + + +void Set_HOST_GS_BASE(uint_t val); +uint_t Get_HOST_GS_BASE(); + +void SerialPrint_HOST_GS_BASE(); + + +void Set_HOST_TR_BASE(uint_t val); +uint_t Get_HOST_TR_BASE(); + +void SerialPrint_HOST_TR_BASE(); + + +void Set_HOST_GDTR_BASE(uint_t val); +uint_t Get_HOST_GDTR_BASE(); + +void SerialPrint_HOST_GDTR_BASE(); + + +void Set_HOST_IDTR_BASE(uint_t val); +uint_t Get_HOST_IDTR_BASE(); + +void SerialPrint_HOST_IDTR_BASE(); + + +void Set_HOST_IA32_SYSENTER_ESP(uint_t val); +uint_t Get_HOST_IA32_SYSENTER_ESP(); + +void SerialPrint_HOST_IA32_SYSENTER_ESP(); + + +void Set_HOST_IA32_SYSENTER_EIP(uint_t val); +uint_t Get_HOST_IA32_SYSENTER_EIP(); + +void SerialPrint_HOST_IA32_SYSENTER_EIP(); + + +void Set_HOST_RSP(uint_t val); +uint_t Get_HOST_RSP(); + +void SerialPrint_HOST_RSP(); + + +void Set_HOST_RIP(uint_t val); +uint_t Get_HOST_RIP(); + +void SerialPrint_HOST_RIP(); + +void SerialPrint_VMCS_ALL(); +#endif diff --git a/palacios/include/geekos/vmm_sizes.h b/palacios/include/geekos/vmm_sizes.h new file mode 100644 index 0000000..7d8d0bc --- /dev/null +++ b/palacios/include/geekos/vmm_sizes.h @@ -0,0 +1,18 @@ +#ifndef __vmm_sizes +#define __vmm_sizes +#define KERNEL_LOAD_ADDRESS 0x3ff9d000 +#define KERNEL_SETUP_LENGTH ( 1 *512) +#define KERNEL_CORE_LENGTH ( 189 *512) +#define KERNEL_START (KERNEL_LOAD_ADDRESS) +#define KERNEL_END (KERNEL_LOAD_ADDRESS+KERNEL_CORE_LENGTH-1) +#define BIOS_LENGTH ( 128 *512) +#define VGA_BIOS_LENGTH ( 55 *512) +#define VMXASSIST_LENGTH ( 38 *512) +#define BIOS_START (KERNEL_LOAD_ADDRESS+KERNEL_CORE_LENGTH) +#define VGA_BIOS_START (BIOS_START+BIOS_LENGTH) +#define VMXASSIST_START (VGA_BIOS_START+VGA_BIOS_LENGTH) +//Note this is a second copy of the rom bios for debug +#define BIOS2_START (VMXASSIST_START+VMXASSIST_LENGTH) +#define VM_BOOT_PACKAGE_START (BIOS_START) +#define VM_BOOT_PACKAGE_END (BIOS2_START+BIOS_LENGTH-1) +#endif diff --git a/palacios/include/geekos/vmx.h b/palacios/include/geekos/vmx.h new file mode 100644 index 0000000..62531a6 --- /dev/null +++ b/palacios/include/geekos/vmx.h @@ -0,0 +1,111 @@ +#ifndef __VMX_H +#define __VMX_H + +#include +#include + +#define IA32_FEATURE_CONTROL_MSR ((unsigned int)0x3a) +#define IA32_VMX_BASIC_MSR ((unsigned int)0x480) +#define IA32_VMX_PINBASED_CTLS_MSR ((unsigned int)0x481) +#define IA32_VMX_PROCBASED_CTLS_MSR ((unsigned int)0x482) +#define IA32_VMX_EXIT_CTLS_MSR ((unsigned int)0x483) +#define IA32_VMX_ENTRY_CTLS_MSR ((unsigned int)0x484) +#define IA32_VMX_MISC_MSR ((unsigned int)0x485) +#define IA32_VMX_CR0_FIXED0_MSR ((unsigned int)0x486) +#define IA32_VMX_CR0_FIXED1_MSR ((unsigned int)0x487) +#define IA32_VMX_CR4_FIXED0_MSR ((unsigned int)0x488) +#define IA32_VMX_CR4_FIXED1_MSR ((unsigned int)0x489) +#define IA32_VMX_VMCS_ENUM_MSR ((unsigned ing)0x48A) + +#define VMX_SUCCESS 0 +#define VMX_FAIL_INVALID 1 +#define VMX_FAIL_VALID 2 +#define VMM_ERROR 3 + +#define FEATURE_CONTROL_LOCK (1) +#define FEATURE_CONTROL_VMXON (1<<2) +#define FEATURE_CONTROL_VALID ( FEATURE_CONTROL_LOCK | FEATURE_CONTROL_VMXON) + + +#define CPUID_1_ECX_VTXFLAG (1<<5) + + + + + +typedef void VmxOnRegion; + +#if __TINYC__ +#define PACKED +#else +#define PACKED __attribute__((packed)) +#endif + + +struct MSR_REGS { + uint_t low PACKED; + uint_t high PACKED; +}; + +struct VMX_BASIC { + uint_t revision PACKED ; + uint_t regionSize : 13 PACKED ; + uint_t rsvd1 : 4 PACKED ; // Always 0 + uint_t physWidth : 1 PACKED ; + uint_t smm : 1 PACKED ; // Always 1 + uint_t memType : 4 PACKED ; + uint_t rsvd2 : 10 PACKED ; // Always 0 +}; + +union VMX_MSR { + struct MSR_REGS regs PACKED; + struct VMX_BASIC vmxBasic PACKED; +}; + + +struct VMDescriptor { + uint_t entry_ip; + uint_t exit_eip; + uint_t guest_esp; +} ; + + +enum VMState { VM_VMXASSIST_STARTUP, VM_VMXASSIST_V8086_BIOS, VM_VMXASSIST_V8086, VM_NORMAL }; + +struct VM { + enum VMState state; + struct VMXRegs registers; + struct VMDescriptor descriptor; + struct VMCSData vmcs; + struct VMCS *vmcsregion; + struct VmxOnRegion *vmxonregion; +}; + + +enum InstructionType { VM_UNKNOWN_INST, VM_MOV_TO_CR0 } ; + +struct Instruction { + enum InstructionType type; + uint_t address; + uint_t size; + uint_t input1; + uint_t input2; + uint_t output; +}; + + +void DecodeCurrentInstruction(struct VM *vm, struct Instruction *out); + + +VmxOnRegion * InitVMX(); +VmxOnRegion * CreateVmxOnRegion(); + +int VMLaunch(struct VMDescriptor *vm); + + +int Do_VMM(struct VMXRegs regs); + + + + +#endif diff --git a/palacios/include/libc/fmtout.h b/palacios/include/libc/fmtout.h new file mode 100644 index 0000000..429d7fd --- /dev/null +++ b/palacios/include/libc/fmtout.h @@ -0,0 +1,37 @@ +/* + * Generalized support for printf()-style formatted output + * Copyright (c) 2004, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef OUTPUT_H +#define OUTPUT_H + +#include + +/* + * An output sink for Format_Output(). + * Useful for emitting formatted output to a function + * or a buffer. + */ +struct Output_Sink { + /* + * Emit a single character of output. + * This is called for all output characters, + * in order. + */ + void (*Emit)(struct Output_Sink *o, int ch); + + /* + * Finish the formatted output. Called after all characters + * have been emitted. + */ + void (*Finish)(struct Output_Sink *o); +}; + +int Format_Output(struct Output_Sink *q, const char *format, va_list ap); + +#endif /* OUTPUT_H */ diff --git a/palacios/include/libc/string.h b/palacios/include/libc/string.h new file mode 100644 index 0000000..fb146c0 --- /dev/null +++ b/palacios/include/libc/string.h @@ -0,0 +1,37 @@ +/* + * String library + * Copyright (c) 2001,2004 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#ifndef STRING_H +#define STRING_H + +#include + +void* memset(void* s, int c, size_t n); +void* memcpy(void *dst, const void* src, size_t n); +void *memmove(void *dst, const void *src, size_t n); +int memcmp(const void *s1, const void *s2, size_t n); +size_t strlen(const char* s); +size_t strnlen(const char *s, size_t maxlen); +int strcmp(const char* s1, const char* s2); +int strncmp(const char* s1, const char* s2, size_t limit); +char *strcat(char *s1, const char *s2); +char *strcpy(char *dest, const char *src); +char *strncpy(char *dest, const char *src, size_t limit); +char *strdup(const char *s1); +int atoi(const char *buf); +char *strchr(const char *s, int c); +char *strrchr(const char *s, int c); +char *strpbrk(const char *s, const char *accept); + +/* Note: The ISO C standard puts this in , but we don't + * have that header in GeekOS (yet). */ +int snprintf(char *s, size_t size, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); + +#endif /* STRING_H */ diff --git a/palacios/scripts/eipToFunction b/palacios/scripts/eipToFunction new file mode 100755 index 0000000..98bffa6 --- /dev/null +++ b/palacios/scripts/eipToFunction @@ -0,0 +1,42 @@ +#! /usr/bin/perl + +# Find the function name from the value of the EIP (instruction pointer) +# register from a Bochs crash report. Uses the kernel symbol +# map (kernel.syms) produced by compiling the kernel. + +use strict qw(refs vars); +use FileHandle; + +if (scalar(@ARGV) != 2){ + print STDERR "Usage: eipToFunction kernel.syms \n"; + print STDERR " eip value should be in hex\n"; + exit 1; +} + +my $syms = shift @ARGV; +my $eip = hex(shift @ARGV); + +my @text = (); + +my $fh = new FileHandle("<$syms"); +(defined $fh) || die "Couldn't open $syms: $!\n"; +while (<$fh>) { + #print $_; + if (/^([0-9A-Fa-f]+)\s+[Tt]\s+(\S+)\s*$/) { + push @text, [hex($1), $2]; + } +} +$fh->close(); +#print scalar(@text),"\n"; + +@text = sort { $a->[0] <=> $b->[0] } @text; + +my $last = undef; + +foreach my $entry (@text) { + last if ($eip < $entry->[0]); + $last = $entry; +} +printf("%s\n",(defined $last) ? $last->[1] : "not found"); + +# vim:ts=4 diff --git a/palacios/scripts/findaddr b/palacios/scripts/findaddr new file mode 100755 index 0000000..7b9b877 --- /dev/null +++ b/palacios/scripts/findaddr @@ -0,0 +1,26 @@ +#! /usr/bin/perl + +# Find the address of a symbol in the storage map. + +use strict qw(refs vars); +use FileHandle; + +if ( scalar(@ARGV) != 2 ) { + print "Usage: findaddr \n"; + exit 1; +} + +my $storage = shift @ARGV; +my $symbol = shift @ARGV; + +my $fh = new FileHandle("<$storage"); +(defined $fh) || die "Couldn't open storage map: $!\n"; + +while ( <$fh> ) { + if ( /^\s*(0x([0-9]|[a-f]|[A-F])+)\s+\Q$symbol\E\s*$/ ) { + print $1, "\n"; + last; + } +} + +$fh->close(); diff --git a/palacios/scripts/generate_vmcs_serialization.pl b/palacios/scripts/generate_vmcs_serialization.pl new file mode 100755 index 0000000..ca1fdeb --- /dev/null +++ b/palacios/scripts/generate_vmcs_serialization.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl + +$#ARGV==0 or die "gimme a filename\n"; + +$file=shift; + +@list=(); + +open(HEADER,">$file.h"); +open(SOURCE,">$file.c"); + +print HEADER "#ifndef $file\n#define $file\n#include \n"; +print SOURCE "#include \n"; + +while () { + if (/\#define\s+(\S+)\s+/) { + push @list, $1; + GenSerUnserCode($1); + } +} + +GenPrintAllCode(@list); + +print HEADER "#endif\n"; + +sub GenSerUnserCode { + my $name=shift; + + print SOURCE <) { + if (m,^#define\s*(\S+)\s*(-\d+)\s*/\*\s*(.*\S)\s*\*/\s*$,) { + $errs[- $2] = $3; + $syms[- $2] = $1; + } +} + +print "const char *__strerrTable[] = {\n"; +for (my $i = 0; $i < scalar(@errs); $i++) { + print " \"", $errs[$i], "\", /* ", $syms[$i], " */\n"; +} +print "};\n"; +print "const int __strerrTableSize = sizeof(__strerrTable) / sizeof(const char *);\n"; + +# vim:ts=4 diff --git a/palacios/scripts/kerninfo b/palacios/scripts/kerninfo new file mode 100755 index 0000000..9241e3a --- /dev/null +++ b/palacios/scripts/kerninfo @@ -0,0 +1,38 @@ +#! /usr/bin/perl + +# A script to analyze the output of "objdump -h" on the +# kernel executable file. + +use strict qw(vars refs); +use FileHandle; + +my $kernfile = shift @ARGV; +(defined $kernfile) || die "usage: kernsize \n"; + +my $kern_fh = new FileHandle("<$kernfile"); +(defined $kern_fh) || die "can't open $kernfile: $!\n"; + +my $objdump_fh = new FileHandle("objdump -h $kernfile|"); +while ( <$objdump_fh> ) { + chop; + s/^\s+//; + my @fields = split(/\s+/, $_); + if ( $fields[0] =~ /^[0-9]$/ ) { +# print "text start is ", $fields[5], "\n" if $fields[0] eq '0'; + my $size = hex($fields[2]); + my $offset = hex($fields[5]); + + print $fields[0], " (", $fields[1], "): size=$size, offset=$offset\n"; + + printf("Word at beginning of section is %08x\n", ReadWord($kern_fh,$offset) ); + } +} +$objdump_fh->close(); + +sub ReadWord { + my ($fh, $offset) = @_; + seek $fh, $offset, SEEK_SET; + my $buf = 'X' x 4; + read $fh, $buf, 4; + return unpack('V',$buf); +} diff --git a/palacios/scripts/mkcdisk b/palacios/scripts/mkcdisk new file mode 100755 index 0000000..d3f4477 --- /dev/null +++ b/palacios/scripts/mkcdisk @@ -0,0 +1,25 @@ +#! /usr/bin/perl + +# Build a binary image containing a pseudo fat filesystem with the listed files + +# $Revision: 1.1 $ +use FileHandle; + +if ( scalar(@ARGV) < 2 ) { + print STDERR "usage: mkuprog \n"; + exit 1; +} + + +$filename = shift @ARGV; +$filecount = scalar ( @ARGV ); + +$fh = new FileHandle(">$filename"); + +write + +while (scalar(@ARGV)) { + $filename = shift @ARGV; + + print "got file ", $filename, "\n"; +} diff --git a/palacios/scripts/mkuprog b/palacios/scripts/mkuprog new file mode 100755 index 0000000..1581b4b --- /dev/null +++ b/palacios/scripts/mkuprog @@ -0,0 +1,55 @@ +#! /usr/bin/perl + +# From a binary image containing a user program, generate +# C code initializing a User_Program struct. + +# $Revision: 1.1 $ + +use strict qw(refs vars); +use FileHandle; + +if ( scalar(@ARGV) != 3 ) { + print STDERR "usage: mkuprog \n"; + exit 1; +} + +my $filename = shift @ARGV; +my $progname = shift @ARGV; +my $entryAddr = shift @ARGV; + +my $fh = new FileHandle("<$filename"); +(defined $fh) || die "Couldn't open $filename: $!\n"; +binmode $fh; + +my $dataArrayName = $progname . "Data"; +my $structName = $progname . "Prog"; +print "const unsigned char $dataArrayName"."[] = {\n"; + +my $LINEWIDTH = 10; + +my $buf = chr(0) x $LINEWIDTH; +my $n; +my $size = 0; +while ( ($n = read( $fh, $buf, $LINEWIDTH )) > 0 ) { + $size += $n; + my $i; + print " "; + for ( $i = 0; $i < $n; $i++ ) { + my $c = ord( substr($buf, $i, 1) ); + printf( "0x%x,", $c ); + } + print "\n"; +} + +print "};\n"; + +$fh->close(); + +print << "END"; +const struct User_Program $structName = { + "$progname", + $size, + $entryAddr, + $dataArrayName +}; +END diff --git a/palacios/scripts/numsecs b/palacios/scripts/numsecs new file mode 100755 index 0000000..708a893 --- /dev/null +++ b/palacios/scripts/numsecs @@ -0,0 +1,23 @@ +#! /usr/bin/perl + +# Find the number of 512-byte sectors needed to store +# given file. + +# $Revision: 1.1 $ + +use strict qw(refs vars); + +if ( scalar(@ARGV) != 1 ) { + print STDERR "Usage: numsecs \n"; + exit 1; +} + +my $filename = shift @ARGV; +my $size = (-s $filename ); +die "Couldn't get size of $filename: $!" if ( !defined $size ); + +my $result = int($size / 512); +my $remainder = $size % 512; +$result++ if ( $remainder > 0 ); + +print "$result\n"; diff --git a/palacios/scripts/pad b/palacios/scripts/pad new file mode 100755 index 0000000..c1c5329 --- /dev/null +++ b/palacios/scripts/pad @@ -0,0 +1,30 @@ +#! /usr/bin/perl + +# Pad a file with zero bytes to make its length +# an even multiple of some value. + +# $Revision: 1.1 $ + +use strict qw(refs vars); +use FileHandle; + +if ( scalar(@ARGV) != 2 ) { + print STDERR "usage: pad \n"; + exit 1; +} + +my $filename = shift @ARGV; +my $multiple = shift @ARGV; + +my $size = (-s $filename); +die "Couldn't get size of $filename: $!" if ( !defined $size ); + +my $num_pad = ($multiple - ($size % $multiple)) % $multiple; + +my $buf = chr(0) x $num_pad; + +my $fh = new FileHandle(">>$filename"); +die "Couldn't open $filename: $!" if ( !defined $fh ); +binmode $fh; +syswrite $fh, $buf, $num_pad, 0; +$fh->close(); diff --git a/palacios/scripts/pcat b/palacios/scripts/pcat new file mode 100755 index 0000000..d58f9fd --- /dev/null +++ b/palacios/scripts/pcat @@ -0,0 +1,23 @@ +#! /usr/bin/perl + +# A version of cat written in perl. + +use strict qw(refs vars); +use FileHandle; + +binmode STDOUT; + +my $buf = chr(0) x 1024; + +my $file; +while ( ($file = shift @ARGV) ) { + my $fh = new FileHandle("<$file"); + (defined $fh) || die "Couldn't open $file: $!\n"; + binmode $fh; + + my $n; + while ( ($n = sysread($fh, $buf, 1024)) > 0 ) { + syswrite( STDOUT, $buf, $n ); + } + $fh->close(); +} diff --git a/palacios/scripts/pw b/palacios/scripts/pw new file mode 100755 index 0000000..7edc728 --- /dev/null +++ b/palacios/scripts/pw @@ -0,0 +1,24 @@ +#! /usr/bin/perl + +# Inspect a 32 word at a specified offset in a file. +# $Revision: 1.1 $ + +use strict qw(refs vars); +use FileHandle; + +my $filename = shift @ARGV; +my $offset = shift @ARGV; + +((defined $filename) && (defined $offset)) + || die "Usage: pw \n"; + +my $fh = new FileHandle("<$filename"); +printf( "%08x\n", ReadWord($fh, $offset) ); + +sub ReadWord { + my ($fh, $offset) = @_; + seek $fh, $offset, SEEK_SET; + my $buf = 'X' x 4; + read $fh, $buf, 4; + return unpack('V',$buf); +} diff --git a/palacios/scripts/scan b/palacios/scripts/scan new file mode 100755 index 0000000..cbfe6dc --- /dev/null +++ b/palacios/scripts/scan @@ -0,0 +1,29 @@ +#! /usr/bin/perl + +# Scan a file for a 32-bit word with a particular value. +# $Revision: 1.1 $ + +use strict qw(refs vars); +use FileHandle; + +my $filename = shift @ARGV; +my $word_value = shift @ARGV; + +((defined $filename) && (defined $word_value)) + || die "Usage: scan \n"; + +my $fh = new FileHandle("<$filename"); +my $val = hex($word_value); + +my $buf = ' ' x 4; + +my $offset = 0; +while ( read( $fh, $buf, 4) == 4 ) { + my $out = unpack "V", $buf; + if ( $out == $val ) { + print "Found value $word_value at offset $offset\n"; + exit; + } + $offset += 4; +} +print "Didn't find value $word_value\n"; diff --git a/palacios/scripts/vmcs_entries_to_asm.pl b/palacios/scripts/vmcs_entries_to_asm.pl new file mode 100755 index 0000000..04bea4f --- /dev/null +++ b/palacios/scripts/vmcs_entries_to_asm.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl + + +$file = $ARGV[0]; +$ofile = $ARGV[1]; + +open(INFILE, "$file"); +@lines = ; +close INFILE; + +open(OUTFILE, ">$ofile"); + + +print OUTFILE "\%ifndef VMCS_FIELDS_ASM\n\%define VMCS_FIELDS_ASM\n\n"; + +foreach $line (@lines) { + + if ($line =~ /\#define\s+(\S+)\s+(\S+)*/) { + print OUTFILE $1 . " equ " . $2 . "\n"; + } + +} + + +print OUTFILE "\n\%endif\n\n"; + +close OUTFILE; + + diff --git a/palacios/scripts/zerofile b/palacios/scripts/zerofile new file mode 100755 index 0000000..52e744a --- /dev/null +++ b/palacios/scripts/zerofile @@ -0,0 +1,31 @@ +#! /usr/bin/perl + +# This script is used for creating a file full of zeroes, +# which we use to create the hard disk image used by bochs. + +use strict qw(refs vars); +use FileHandle; +use IO::Seekable; + +if ( scalar(@ARGV) != 2 ) { + print "Usage: zerofile \n"; + exit 1; +} + +my $outfile = shift @ARGV; +my $numsecs = shift @ARGV; + +my $buf = chr(0) x 1; + +my $fh = new FileHandle(">$outfile"); +(defined $fh) || die "Couldn't open $outfile: $!\n"; +binmode $fh; + +if ( !sysseek( $fh, ($numsecs * 512) - 1, SEEK_SET ) ) { + die "Couldn't seek in $outfile: $!\n"; +} +if ( !syswrite( $fh, $buf, 1 ) ) { + die "Couldn't write to $outfile: $!\n"; +} + +$fh->close(); diff --git a/palacios/src/common/fmtout.c b/palacios/src/common/fmtout.c new file mode 100644 index 0000000..c097eb4 --- /dev/null +++ b/palacios/src/common/fmtout.c @@ -0,0 +1,507 @@ +/* + * This code was originally part of klibc-0.103. + * It was adapted by David Hovemeyer + * for use in GeekOS (http://geekos.sourceforge.net). + * + * For information/source for klibc, visit + * http://www.kernel.org/pub/linux/libs/klibc/ + * http://www.zytor.com/mailman/listinfo/klibc/ + * http://www.zytor.com/cvsweb.cgi/klibc/ + * + * Modifications are marked with "DHH". + * Summary of modifications: + * + * 1. Use struct Output_Sink to emit formatted output, rather than a + * character buffer, to allow output polymorphism. + * + * 2. Buffer generated numbers so that all output is generated in order. + * + * 3. Don't use long long types: unsigned long is largest + * supported type. Arithmetic on 64 bit types requires runtime support + * (at least on x86). + * + * See the file LICENSE-klibc for license information. + */ + +/* + * vsnprintf.c + * + * vsnprintf(), from which the rest of the printf() + * family is built + */ + +#include +#include +#include +#include +#include /* DHH: for struct Output_Sink */ + +/* + * DHH: Hack, long long arithmetic requires runtime support. + * Use unsigned long as greatest unsigned integer supported. + */ +typedef long intmax_t; +typedef unsigned long uintmax_t; +typedef unsigned long uintptr_t; + +/* DHH */ +#define ASSERT(exp) \ +do { if (!(exp)) while(1); } while (0) + +enum flags { + FL_ZERO = 0x01, /* Zero modifier */ + FL_MINUS = 0x02, /* Minus modifier */ + FL_PLUS = 0x04, /* Plus modifier */ + FL_TICK = 0x08, /* ' modifier */ + FL_SPACE = 0x10, /* Space modifier */ + FL_HASH = 0x20, /* # modifier */ + FL_SIGNED = 0x40, /* Number is signed */ + FL_UPPER = 0x80 /* Upper case digits */ +}; + +/* These may have to be adjusted on certain implementations */ +enum ranks { + rank_char = -2, + rank_short = -1, + rank_int = 0, + rank_long = 1, +#if 0 + rank_longlong = 2, +#endif +}; + +#define MIN_RANK rank_char +#define MAX_RANK rank_long + +#define INTMAX_RANK rank_long +#define SIZE_T_RANK rank_long +#define PTRDIFF_T_RANK rank_long + +/* DHH */ +#define EMIT(x) do { (q)->Emit((q), (x)); } while (0) + +/* + * DHH - As a hack, we buffer this many digits when generating + * a number. Because this code originally was an implementation + * of vnsprintf(), it generated some digits backwards in a buffer. + * Obviously we can't do this when emitting output directly + * to the console or a file. So, we buffer the generated digits + * and then emit them in order. + * + * This value should be adequate to emit values up to 2^32-1 in + * bases 2 or greater, including tick marks. + */ +#define NDIGITS_MAX 43 + +static size_t +format_int(struct Output_Sink *q, uintmax_t val, enum flags flags, + int base, int width, int prec) +{ + char *qq; + size_t o = 0, oo; + static const char lcdigits[] = "0123456789abcdef"; + static const char ucdigits[] = "0123456789ABCDEF"; + const char *digits; + uintmax_t tmpval; + int minus = 0; + int ndigits = 0, nchars; + int tickskip, b4tick; + char digit_buffer[NDIGITS_MAX]; /* DHH */ + size_t ndigits_save; /* DHH */ + + /* Select type of digits */ + digits = (flags & FL_UPPER) ? ucdigits : lcdigits; + + /* If signed, separate out the minus */ + if ( flags & FL_SIGNED && (intmax_t)val < 0 ) { + minus = 1; + val = (uintmax_t)(-(intmax_t)val); + } + + /* Count the number of digits needed. This returns zero for 0. */ + tmpval = val; + while ( tmpval ) { + tmpval /= base; + ndigits++; + } + + /* Adjust ndigits for size of output */ + + if ( flags & FL_HASH && base == 8 ) { + if ( prec < ndigits+1 ) + prec = ndigits+1; + } + + if ( ndigits < prec ) { + ndigits = prec; /* Mandatory number padding */ + } else if ( val == 0 ) { + ndigits = 1; /* Zero still requires space */ + } + + /* For ', figure out what the skip should be */ + if ( flags & FL_TICK ) { + tickskip = (base == 16) ? 4 : 3; + } else { + tickskip = ndigits; /* No tick marks */ + } + + /* Tick marks aren't digits, but generated by the number converter */ + ndigits += (ndigits-1)/tickskip; + + /* Now compute the number of nondigits */ + nchars = ndigits; + + if ( minus || (flags & (FL_PLUS|FL_SPACE)) ) + nchars++; /* Need space for sign */ + if ( (flags & FL_HASH) && base == 16 ) { + nchars += 2; /* Add 0x for hex */ + } + + /* Emit early space padding */ + if ( !(flags & (FL_MINUS|FL_ZERO)) && width > nchars ) { + while ( width > nchars ) { + EMIT(' '); + width--; + } + } + + /* Emit nondigits */ + if ( minus ) + EMIT('-'); + else if ( flags & FL_PLUS ) + EMIT('+'); + else if ( flags & FL_SPACE ) + EMIT(' '); + + if ( (flags & FL_HASH) && base == 16 ) { + EMIT('0'); + EMIT((flags & FL_UPPER) ? 'X' : 'x'); + } + + /* Emit zero padding */ + if ( (flags & (FL_MINUS|FL_ZERO)) == FL_ZERO && width > ndigits ) { + while ( width > nchars ) { + EMIT('0'); + width--; + } + } + + /* Generate the number. This is done from right to left. */ + ASSERT(ndigits <= NDIGITS_MAX); /* DHH */ + ndigits_save = ndigits; + qq = digit_buffer + ndigits; + oo = o; + + /* Emit digits to temp buffer */ + b4tick = tickskip; + while ( ndigits > 0 ) { + if ( !b4tick-- ) { + qq--; oo--; ndigits--; + *qq = '_'; + b4tick = tickskip-1; + } + qq--; oo--; ndigits--; + *qq = digits[val%base]; + val /= base; + } + + /* Copy digits to Output_Sink */ + for (oo = 0; oo < ndigits_save; ++oo) + EMIT(digit_buffer[oo]); + + /* Emit late space padding */ + while ( (flags & FL_MINUS) && width > nchars ) { + EMIT(' '); + width--; + } + + return o; +} + +/* + * DHH - This function was originally vsnprintf(). + * I renamed it to Format_Output() and changed it to take + * a struct Output_Sink instead of a buffer. That way, it can + * be used for any kind of formatted output (string, console, + * file, etc.) + */ +int Format_Output(struct Output_Sink *q, const char *format, va_list ap) +{ + const char *p = format; + char ch; + size_t o = 0; /* Number of characters output */ + uintmax_t val = 0; + int rank = rank_int; /* Default rank */ + int width = 0; + int prec = -1; + int base; + size_t sz; + enum flags flags = 0; + enum { + st_normal, /* Ground state */ + st_flags, /* Special flags */ + st_width, /* Field width */ + st_prec, /* Field precision */ + st_modifiers /* Length or conversion modifiers */ + } state = st_normal; + const char *sarg; /* %s string argument */ + char carg; /* %c char argument */ + int slen; /* String length */ + + while ( (ch = *p++) ) { + switch ( state ) { + case st_normal: + if ( ch == '%' ) { + state = st_flags; + flags = 0; rank = rank_int; width = 0; prec = -1; + } else { + EMIT(ch); + } + break; + + case st_flags: + switch ( ch ) { + case '-': + flags |= FL_MINUS; + break; + case '+': + flags |= FL_PLUS; + break; + case '\'': + flags |= FL_TICK; + break; + case ' ': + flags |= FL_SPACE; + break; + case '#': + flags |= FL_HASH; + break; + case '0': + flags |= FL_ZERO; + break; + default: + state = st_width; + p--; /* Process this character again */ + break; + } + break; + + case st_width: + if ( ch >= '0' && ch <= '9' ) { + width = width*10+(ch-'0'); + } else if ( ch == '*' ) { + width = va_arg(ap, int); + if ( width < 0 ) { + width = -width; + flags |= FL_MINUS; + } + } else if ( ch == '.' ) { + prec = 0; /* Precision given */ + state = st_prec; + } else { + state = st_modifiers; + p--; /* Process this character again */ + } + break; + + case st_prec: + if ( ch >= '0' && ch <= '9' ) { + prec = prec*10+(ch-'0'); + } else if ( ch == '*' ) { + prec = va_arg(ap, int); + if ( prec < 0 ) + prec = -1; + } else { + state = st_modifiers; + p--; /* Process this character again */ + } + break; + + case st_modifiers: + switch ( ch ) { + /* Length modifiers - nonterminal sequences */ + case 'h': + rank--; /* Shorter rank */ + break; + case 'l': + rank++; /* Longer rank */ + break; + case 'j': + rank = INTMAX_RANK; + break; + case 'z': + rank = SIZE_T_RANK; + break; + case 't': + rank = PTRDIFF_T_RANK; + break; + case 'L': + case 'q': + rank += 2; + break; + default: + /* Output modifiers - terminal sequences */ + state = st_normal; /* Next state will be normal */ + if ( rank < MIN_RANK ) /* Canonicalize rank */ + rank = MIN_RANK; + else if ( rank > MAX_RANK ) + rank = MAX_RANK; + + switch ( ch ) { + case 'P': /* Upper case pointer */ + flags |= FL_UPPER; + /* fall through */ + case 'p': /* Pointer */ + base = 16; + prec = (CHAR_BIT*sizeof(void *)+3)/4; + flags |= FL_HASH; + val = (uintmax_t)(uintptr_t)va_arg(ap, void *); + goto is_integer; + + case 'd': /* Signed decimal output */ + case 'i': + base = 10; + flags |= FL_SIGNED; + switch (rank) { + case rank_char: + /* Yes, all these casts are needed... */ + val = (uintmax_t)(intmax_t)(signed char)va_arg(ap, signed int); + break; + case rank_short: + val = (uintmax_t)(intmax_t)(signed short)va_arg(ap, signed int); + break; + case rank_int: + val = (uintmax_t)(intmax_t)va_arg(ap, signed int); + break; + case rank_long: + val = (uintmax_t)(intmax_t)va_arg(ap, signed long); + break; +#if 0 + case rank_longlong: + val = (uintmax_t)(intmax_t)va_arg(ap, signed long long); + break; +#endif + } + goto is_integer; + case 'o': /* Octal */ + base = 8; + goto is_unsigned; + case 'u': /* Unsigned decimal */ + base = 10; + goto is_unsigned; + case 'X': /* Upper case hexadecimal */ + flags |= FL_UPPER; + /* fall through */ + case 'x': /* Hexadecimal */ + base = 16; + goto is_unsigned; + + is_unsigned: + switch (rank) { + case rank_char: + val = (uintmax_t)(unsigned char)va_arg(ap, unsigned int); + break; + case rank_short: + val = (uintmax_t)(unsigned short)va_arg(ap, unsigned int); + break; + case rank_int: + val = (uintmax_t)va_arg(ap, unsigned int); + break; + case rank_long: + val = (uintmax_t)va_arg(ap, unsigned long); + break; +#if 0 + case rank_longlong: + val = (uintmax_t)va_arg(ap, unsigned long long); + break; +#endif + } + /* fall through */ + + is_integer: + sz = format_int(q, val, flags, base, width, prec); + q += sz; o += sz; + break; + + case 'c': /* Character */ + carg = (char)va_arg(ap, int); + sarg = &carg; + slen = 1; + goto is_string; + case 's': /* String */ + sarg = va_arg(ap, const char *); + sarg = sarg ? sarg : "(null)"; + slen = strlen(sarg); + goto is_string; + + is_string: + { + char sch; + int i; + + if ( prec != -1 && slen > prec ) + slen = prec; + + if ( width > slen && !(flags & FL_MINUS) ) { + char pad = (flags & FL_ZERO) ? '0' : ' '; + while ( width > slen ) { + EMIT(pad); + width--; + } + } + for ( i = slen ; i ; i-- ) { + sch = *sarg++; + EMIT(sch); + } + if ( width > slen && (flags & FL_MINUS) ) { + while ( width > slen ) { + EMIT(' '); + width--; + } + } + } + break; + + case 'n': /* Output the number of characters written */ + { + switch (rank) { + case rank_char: + *va_arg(ap, signed char *) = o; + break; + case rank_short: + *va_arg(ap, signed short *) = o; + break; + case rank_int: + *va_arg(ap, signed int *) = o; + break; + case rank_long: + *va_arg(ap, signed long *) = o; + break; +#if 0 + case rank_longlong: + *va_arg(ap, signed long long *) = o; + break; +#endif + } + } + break; + + default: /* Anything else, including % */ + EMIT(ch); + break; + } + } + } + } + + /* Null-terminate the string */ +#if 0 + if ( o0 ) + buffer[n-1] = '\0'; /* Overflow - terminate at end of buffer */ +#endif + q->Finish(q); + + return o; +} diff --git a/palacios/src/common/memmove.c b/palacios/src/common/memmove.c new file mode 100644 index 0000000..27f04a5 --- /dev/null +++ b/palacios/src/common/memmove.c @@ -0,0 +1,57 @@ +/*********************************************************** +Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam, +The Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI or Corporation for National Research Initiatives or +CNRI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +While CWI is the initial source for this software, a modified version +is made available by the Corporation for National Research Initiatives +(CNRI) at the Internet address ftp://ftp.python.org. + +STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH +CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* A perhaps slow but I hope correct implementation of memmove */ + +#include + +void * +memmove(void *d, const void *s, size_t n) +{ + char *dst = (char*) d; + const char *src = (const char*) s; + char *realdst = dst; + if (n <= 0) + return dst; + if (src >= dst+n || dst >= src+n) + return memcpy(dst, src, n); + if (src > dst) { + while (--n >= 0) + *dst++ = *src++; + } + else if (src < dst) { + src += n; + dst += n; + while (--n >= 0) + *--dst = *--src; + } + return realdst; +} diff --git a/palacios/src/common/string.c b/palacios/src/common/string.c new file mode 100644 index 0000000..7db896c --- /dev/null +++ b/palacios/src/common/string.c @@ -0,0 +1,261 @@ +/* + * String library + * Copyright (c) 2001,2004 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +/* + * NOTE: + * These are slow and simple implementations of a subset of + * the standard C library string functions. + * We also have an implementation of snprintf(). + */ + +#include +#include + +extern void *Malloc(size_t size); + +void* memset(void* s, int c, size_t n) +{ + unsigned char* p = (unsigned char*) s; + + while (n > 0) { + *p++ = (unsigned char) c; + --n; + } + + return s; +} + +void* memcpy(void *dst, const void* src, size_t n) +{ + unsigned char* d = (unsigned char*) dst; + const unsigned char* s = (const unsigned char*) src; + + while (n > 0) { + *d++ = *s++; + --n; + } + + return dst; +} + +int memcmp(const void *s1_, const void *s2_, size_t n) +{ + const signed char *s1 = s1_, *s2 = s2_; + + while (n > 0) { + int cmp = *s1 - *s2; + if (cmp != 0) + return cmp; + ++s1; + ++s2; + } + + return 0; +} + +size_t strlen(const char* s) +{ + size_t len = 0; + while (*s++ != '\0') + ++len; + return len; +} + +/* + * This it a GNU extension. + * It is like strlen(), but it will check at most maxlen + * characters for the terminating nul character, + * returning maxlen if it doesn't find a nul. + * This is very useful for checking the length of untrusted + * strings (e.g., from user space). + */ +size_t strnlen(const char *s, size_t maxlen) +{ + size_t len = 0; + while (len < maxlen && *s++ != '\0') + ++len; + return len; +} + +int strcmp(const char* s1, const char* s2) +{ + while (1) { + int cmp = *s1 - *s2; + if (cmp != 0 || *s1 == '\0' || *s2 == '\0') + return cmp; + ++s1; + ++s2; + } +} + +int strncmp(const char* s1, const char* s2, size_t limit) +{ + size_t i = 0; + while (i < limit) { + int cmp = *s1 - *s2; + if (cmp != 0 || *s1 == '\0' || *s2 == '\0') + return cmp; + ++s1; + ++s2; + ++i; + } + + /* limit reached and equal */ + return 0; +} + +char *strcat(char *s1, const char *s2) +{ + char *t1; + + t1 = s1; + while (*s1) s1++; + while(*s2) *s1++ = *s2++; + *s1 = '\0'; + + return t1; +} + +char *strcpy(char *dest, const char *src) +{ + char *ret = dest; + + while (*src) { + *dest++ = *src++; + } + *dest = '\0'; + + return ret; +} + +char *strncpy(char *dest, const char *src, size_t limit) +{ + char *ret = dest; + + while (*src != '\0' && limit > 0) { + *dest++ = *src++; + --limit; + } + if (limit > 0) + *dest = '\0'; + + return ret; +} + +char *strdup(const char *s1) +{ + char *ret; + + ret = Malloc(strlen(s1) + 1); + strcpy(ret, s1); + + return ret; +} + +int atoi(const char *buf) +{ + int ret = 0; + + while (*buf >= '0' && *buf <= '9') { + ret *= 10; + ret += *buf - '0'; + buf++; + } + + return ret; +} + +char *strchr(const char *s, int c) +{ + while (*s != '\0') { + if (*s == c) + return (char *) s; + ++s; + } + return 0; +} + +char *strrchr(const char *s, int c) +{ + size_t len = strlen(s); + const char *p = s + len; + + while (p > s) { + --p; + if (*p == c) + return (char*) p; + } + return 0; +} + +char *strpbrk(const char *s, const char *accept) +{ + size_t setLen = strlen(accept); + + while (*s != '\0') { + size_t i; + for (i = 0; i < setLen; ++i) { + if (*s == accept[i]) + return (char *) s; + } + ++s; + } + + return 0; +} + +struct String_Output_Sink { + struct Output_Sink o; + char *s; + size_t n, size; +}; + +static void String_Emit(struct Output_Sink *o_, int ch) +{ + struct String_Output_Sink *o = (struct String_Output_Sink*) o_; + + if (o->n < o->size) + *(o->s)++ = ch; + ++(o->n); +} + +static void String_Finish(struct Output_Sink *o_) +{ + struct String_Output_Sink *o = (struct String_Output_Sink*) o_; + + if (o->n < o->size) + *(o->s) = '\0'; + else + /* + * Output was truncated; write terminator at end of buffer + * (we will have advanced one character too far) + */ + *(o->s - 1) = '\0'; +} + +int snprintf(char *s, size_t size, const char *fmt, ...) +{ + struct String_Output_Sink sink; + int rc; + va_list args; + + /* Prepare string output sink */ + sink.o.Emit = &String_Emit; + sink.o.Finish = &String_Finish; + sink.s = s; + sink.n = 0; + sink.size = size; + + /* Format the string */ + va_start(args, fmt); + rc = Format_Output(&sink.o, fmt, args); + va_end(args); + + return rc; +} diff --git a/palacios/src/geekos/README.txt b/palacios/src/geekos/README.txt new file mode 100644 index 0000000..52b6ec4 --- /dev/null +++ b/palacios/src/geekos/README.txt @@ -0,0 +1,5 @@ +GeekOS is a tiny operating system kernel for x86 PCs. Its main purpose +is to serve as a simple but realistic example of an OS kernel running +on real hardware. + +GeekOS is free software: see the file "COPYING" for details. diff --git a/palacios/src/geekos/bget.c b/palacios/src/geekos/bget.c new file mode 100644 index 0000000..cccbe16 --- /dev/null +++ b/palacios/src/geekos/bget.c @@ -0,0 +1,1610 @@ +// Adapted for geekos: http://www.cs.umd.edu/~daveho/geekos/ +// Original version of BGET downloaded from: http://www.fourmilab.ch/bget/ +// $Revision: 1.1 $ + +// GeekOS changes are (mostly) confined to #if defined (GEEKOS) +// sections. + +/* + + B G E T + + Buffer allocator + + Designed and implemented in April of 1972 by John Walker, based on the + Case Algol OPRO$ algorithm implemented in 1966. + + Reimplemented in 1975 by John Walker for the Interdata 70. + Reimplemented in 1977 by John Walker for the Marinchip 9900. + Reimplemented in 1982 by Duff Kurland for the Intel 8080. + + Portable C version implemented in September of 1990 by an older, wiser + instance of the original implementor. + + Souped up and/or weighed down slightly shortly thereafter by Greg + Lutz. + + AMIX edition, including the new compaction call-back option, prepared + by John Walker in July of 1992. + + Bug in built-in test program fixed, ANSI compiler warnings eradicated, + buffer pool validator implemented, and guaranteed repeatable test + added by John Walker in October of 1995. + + This program is in the public domain. + + 1. This is the book of the generations of Adam. In the day that God + created man, in the likeness of God made he him; + 2. Male and female created he them; and blessed them, and called + their name Adam, in the day when they were created. + 3. And Adam lived an hundred and thirty years, and begat a son in + his own likeness, and after his image; and called his name Seth: + 4. And the days of Adam after he had begotten Seth were eight + hundred years: and he begat sons and daughters: + 5. And all the days that Adam lived were nine hundred and thirty + years: and he died. + 6. And Seth lived an hundred and five years, and begat Enos: + 7. And Seth lived after he begat Enos eight hundred and seven years, + and begat sons and daughters: + 8. And all the days of Seth were nine hundred and twelve years: and + he died. + 9. And Enos lived ninety years, and begat Cainan: + 10. And Enos lived after he begat Cainan eight hundred and fifteen + years, and begat sons and daughters: + 11. And all the days of Enos were nine hundred and five years: and + he died. + 12. And Cainan lived seventy years and begat Mahalaleel: + 13. And Cainan lived after he begat Mahalaleel eight hundred and + forty years, and begat sons and daughters: + 14. And all the days of Cainan were nine hundred and ten years: and + he died. + 15. And Mahalaleel lived sixty and five years, and begat Jared: + 16. And Mahalaleel lived after he begat Jared eight hundred and + thirty years, and begat sons and daughters: + 17. And all the days of Mahalaleel were eight hundred ninety and + five years: and he died. + 18. And Jared lived an hundred sixty and two years, and he begat + Enoch: + 19. And Jared lived after he begat Enoch eight hundred years, and + begat sons and daughters: + 20. And all the days of Jared were nine hundred sixty and two years: + and he died. + 21. And Enoch lived sixty and five years, and begat Methuselah: + 22. And Enoch walked with God after he begat Methuselah three + hundred years, and begat sons and daughters: + 23. And all the days of Enoch were three hundred sixty and five + years: + 24. And Enoch walked with God: and he was not; for God took him. + 25. And Methuselah lived an hundred eighty and seven years, and + begat Lamech. + 26. And Methuselah lived after he begat Lamech seven hundred eighty + and two years, and begat sons and daughters: + 27. And all the days of Methuselah were nine hundred sixty and nine + years: and he died. + 28. And Lamech lived an hundred eighty and two years, and begat a + son: + 29. And he called his name Noah, saying, This same shall comfort us + concerning our work and toil of our hands, because of the ground + which the LORD hath cursed. + 30. And Lamech lived after he begat Noah five hundred ninety and + five years, and begat sons and daughters: + 31. And all the days of Lamech were seven hundred seventy and seven + years: and he died. + 32. And Noah was five hundred years old: and Noah begat Shem, Ham, + and Japheth. + + And buffers begat buffers, and links begat links, and buffer pools + begat links to chains of buffer pools containing buffers, and lo the + buffers and links and pools of buffers and pools of links to chains of + pools of buffers were fruitful and they multiplied and the Operating + System looked down upon them and said that it was Good. + + + INTRODUCTION + ============ + + BGET is a comprehensive memory allocation package which is easily + configured to the needs of an application. BGET is efficient in + both the time needed to allocate and release buffers and in the + memory overhead required for buffer pool management. It + automatically consolidates contiguous space to minimise + fragmentation. BGET is configured by compile-time definitions, + Major options include: + + * A built-in test program to exercise BGET and + demonstrate how the various functions are used. + + * Allocation by either the "first fit" or "best fit" + method. + + * Wiping buffers at release time to catch code which + references previously released storage. + + * Built-in routines to dump individual buffers or the + entire buffer pool. + + * Retrieval of allocation and pool size statistics. + + * Quantisation of buffer sizes to a power of two to + satisfy hardware alignment constraints. + + * Automatic pool compaction, growth, and shrinkage by + means of call-backs to user defined functions. + + Applications of BGET can range from storage management in + ROM-based embedded programs to providing the framework upon which + a multitasking system incorporating garbage collection is + constructed. BGET incorporates extensive internal consistency + checking using the mechanism; all these checks can be + turned off by compiling with NDEBUG defined, yielding a version of + BGET with minimal size and maximum speed. + + The basic algorithm underlying BGET has withstood the test of + time; more than 25 years have passed since the first + implementation of this code. And yet, it is substantially more + efficient than the native allocation schemes of many operating + systems: the Macintosh and Microsoft Windows to name two, on which + programs have obtained substantial speed-ups by layering BGET as + an application level memory manager atop the underlying system's. + + BGET has been implemented on the largest mainframes and the lowest + of microprocessors. It has served as the core for multitasking + operating systems, multi-thread applications, embedded software in + data network switching processors, and a host of C programs. And + while it has accreted flexibility and additional options over the + years, it remains fast, memory efficient, portable, and easy to + integrate into your program. + + + BGET IMPLEMENTATION ASSUMPTIONS + =============================== + + BGET is written in as portable a dialect of C as possible. The + only fundamental assumption about the underlying hardware + architecture is that memory is allocated is a linear array which + can be addressed as a vector of C "char" objects. On segmented + address space architectures, this generally means that BGET should + be used to allocate storage within a single segment (although some + compilers simulate linear address spaces on segmented + architectures). On segmented architectures, then, BGET buffer + pools may not be larger than a segment, but since BGET allows any + number of separate buffer pools, there is no limit on the total + storage which can be managed, only on the largest individual + object which can be allocated. Machines with a linear address + architecture, such as the VAX, 680x0, Sparc, MIPS, or the Intel + 80386 and above in native mode, may use BGET without restriction. + + + GETTING STARTED WITH BGET + ========================= + + Although BGET can be configured in a multitude of fashions, there + are three basic ways of working with BGET. The functions + mentioned below are documented in the following section. Please + excuse the forward references which are made in the interest of + providing a roadmap to guide you to the BGET functions you're + likely to need. + + Embedded Applications + --------------------- + + Embedded applications typically have a fixed area of memory + dedicated to buffer allocation (often in a separate RAM address + space distinct from the ROM that contains the executable code). + To use BGET in such an environment, simply call bpool() with the + start address and length of the buffer pool area in RAM, then + allocate buffers with bget() and release them with brel(). + Embedded applications with very limited RAM but abundant CPU speed + may benefit by configuring BGET for BestFit allocation (which is + usually not worth it in other environments). + + Malloc() Emulation + ------------------ + + If the C library malloc() function is too slow, not present in + your development environment (for example, an a native Windows or + Macintosh program), or otherwise unsuitable, you can replace it + with BGET. Initially define a buffer pool of an appropriate size + with bpool()--usually obtained by making a call to the operating + system's low-level memory allocator. Then allocate buffers with + bget(), bgetz(), and bgetr() (the last two permit the allocation + of buffers initialised to zero and [inefficient] re-allocation of + existing buffers for compatibility with C library functions). + Release buffers by calling brel(). If a buffer allocation request + fails, obtain more storage from the underlying operating system, + add it to the buffer pool by another call to bpool(), and continue + execution. + + Automatic Storage Management + ---------------------------- + + You can use BGET as your application's native memory manager and + implement automatic storage pool expansion, contraction, and + optionally application-specific memory compaction by compiling + BGET with the BECtl variable defined, then calling bectl() and + supplying functions for storage compaction, acquisition, and + release, as well as a standard pool expansion increment. All of + these functions are optional (although it doesn't make much sense + to provide a release function without an acquisition function, + does it?). Once the call-back functions have been defined with + bectl(), you simply use bget() and brel() to allocate and release + storage as before. You can supply an initial buffer pool with + bpool() or rely on automatic allocation to acquire the entire + pool. When a call on bget() cannot be satisfied, BGET first + checks if a compaction function has been supplied. If so, it is + called (with the space required to satisfy the allocation request + and a sequence number to allow the compaction routine to be called + successively without looping). If the compaction function is able + to free any storage (it needn't know whether the storage it freed + was adequate) it should return a nonzero value, whereupon BGET + will retry the allocation request and, if it fails again, call the + compaction function again with the next-higher sequence number. + + If the compaction function returns zero, indicating failure to + free space, or no compaction function is defined, BGET next tests + whether a non-NULL allocation function was supplied to bectl(). + If so, that function is called with an argument indicating how + many bytes of additional space are required. This will be the + standard pool expansion increment supplied in the call to bectl() + unless the original bget() call requested a buffer larger than + this; buffers larger than the standard pool block can be managed + "off the books" by BGET in this mode. If the allocation function + succeeds in obtaining the storage, it returns a pointer to the new + block and BGET expands the buffer pool; if it fails, the + allocation request fails and returns NULL to the caller. If a + non-NULL release function is supplied, expansion blocks which + become totally empty are released to the global free pool by + passing their addresses to the release function. + + Equipped with appropriate allocation, release, and compaction + functions, BGET can be used as part of very sophisticated memory + management strategies, including garbage collection. (Note, + however, that BGET is *not* a garbage collector by itself, and + that developing such a system requires much additional logic and + careful design of the application's memory allocation strategy.) + + + BGET FUNCTION DESCRIPTIONS + ========================== + + Functions implemented in this file (some are enabled by certain of + the optional settings below): + + void bpool(void *buffer, bufsize len); + + Create a buffer pool of bytes, using the storage starting at + . You can call bpool() subsequently to contribute + additional storage to the overall buffer pool. + + void *bget(bufsize size); + + Allocate a buffer of bytes. The address of the buffer is + returned, or NULL if insufficient memory was available to allocate + the buffer. + + void *bgetz(bufsize size); + + Allocate a buffer of bytes and clear it to all zeroes. The + address of the buffer is returned, or NULL if insufficient memory + was available to allocate the buffer. + + void *bgetr(void *buffer, bufsize newsize); + + Reallocate a buffer previously allocated by bget(), changing its + size to and preserving all existing data. NULL is + returned if insufficient memory is available to reallocate the + buffer, in which case the original buffer remains intact. + + void brel(void *buf); + + Return the buffer , previously allocated by bget(), to the + free space pool. + + void bectl(int (*compact)(bufsize sizereq, int sequence), + void *(*acquire)(bufsize size), + void (*release)(void *buf), + bufsize pool_incr); + + Expansion control: specify functions through which the package may + compact storage (or take other appropriate action) when an + allocation request fails, and optionally automatically acquire + storage for expansion blocks when necessary, and release such + blocks when they become empty. If is non-NULL, whenever + a buffer allocation request fails, the function will be + called with arguments specifying the number of bytes (total buffer + size, including header overhead) required to satisfy the + allocation request, and a sequence number indicating the number of + consecutive calls on attempting to satisfy this + allocation request. The sequence number is 1 for the first call + on for a given allocation request, and increments on + subsequent calls, permitting the function to take + increasingly dire measures in an attempt to free up storage. If + the function returns a nonzero value, the allocation + attempt is re-tried. If returns 0 (as it must if it + isn't able to release any space or add storage to the buffer + pool), the allocation request fails, which can trigger automatic + pool expansion if the argument is non-NULL. At the time + the function is called, the state of the buffer + allocator is identical to that at the moment the allocation + request was made; consequently, the function may call + brel(), bpool(), bstats(), and/or directly manipulate the buffer + pool in any manner which would be valid were the application in + control. This does not, however, relieve the function + of the need to ensure that whatever actions it takes do not change + things underneath the application that made the allocation + request. For example, a function that released a buffer + in the process of being reallocated with bgetr() would lead to + disaster. Implementing a safe and effective mechanism + requires careful design of an application's memory architecture, + and cannot generally be easily retrofitted into existing code. + + If is non-NULL, that function will be called whenever an + allocation request fails. If the function succeeds in + allocating the requested space and returns a pointer to the new + area, allocation will proceed using the expanded buffer pool. If + cannot obtain the requested space, it should return NULL + and the entire allocation process will fail. + specifies the normal expansion block size. Providing an + function will cause subsequent bget() requests for buffers too + large to be managed in the linked-block scheme (in other words, + larger than minus the buffer overhead) to be satisfied + directly by calls to the function. Automatic release of + empty pool blocks will occur only if all pool blocks in the system + are the size given by . + + void bstats(bufsize *curalloc, bufsize *totfree, + bufsize *maxfree, long *nget, long *nrel); + + The amount of space currently allocated is stored into the + variable pointed to by . The total free space (sum of + all free blocks in the pool) is stored into the variable pointed + to by , and the size of the largest single block in the + free space pool is stored into the variable pointed to by + . The variables pointed to by and are + filled, respectively, with the number of successful (non-NULL + return) bget() calls and the number of brel() calls. + + void bstatse(bufsize *pool_incr, long *npool, + long *npget, long *nprel, + long *ndget, long *ndrel); + + Extended statistics: The expansion block size will be stored into + the variable pointed to by , or the negative thereof if + automatic expansion block releases are disabled. The number of + currently active pool blocks will be stored into the variable + pointed to by . The variables pointed to by and + will be filled with, respectively, the number of expansion + block acquisitions and releases which have occurred. The + variables pointed to by and will be filled with + the number of bget() and brel() calls, respectively, managed + through blocks directly allocated by the acquisition and release + functions. + + void bufdump(void *buf); + + The buffer pointed to by is dumped on standard output. + + void bpoold(void *pool, int dumpalloc, int dumpfree); + + All buffers in the buffer pool , previously initialised by a + call on bpool(), are listed in ascending memory address order. If + is nonzero, the contents of allocated buffers are + dumped; if is nonzero, the contents of free blocks are + dumped. + + int bpoolv(void *pool); + + The named buffer pool, previously initialised by a call on + bpool(), is validated for bad pointers, overwritten data, etc. If + compiled with NDEBUG not defined, any error generates an assertion + failure. Otherwise 1 is returned if the pool is valid, 0 if an + error is found. + + + BGET CONFIGURATION + ================== +*/ + +/*#define TestProg 20000*/ /* Generate built-in test program + if defined. The value specifies + how many buffer allocation attempts + the test program should make. */ + +#define SizeQuant 4 /* Buffer allocation size quantum: + all buffers allocated are a + multiple of this size. This + MUST be a power of two. */ + +/*#define BufDump 1*/ /* Define this symbol to enable the + bpoold() function which dumps the + buffers in a buffer pool. */ + +/*#define BufValid 1*/ /* Define this symbol to enable the + bpoolv() function for validating + a buffer pool. */ + +/*#define DumpData 1*/ /* Define this symbol to enable the + bufdump() function which allows + dumping the contents of an allocated + or free buffer. */ + +/*#define BufStats 1*/ /* Define this symbol to enable the + bstats() function which calculates + the total free space in the buffer + pool, the largest available + buffer, and the total space + currently allocated. */ + +/*#define FreeWipe 1*/ /* Wipe free buffers to a guaranteed + pattern of garbage to trip up + miscreants who attempt to use + pointers into released buffers. */ + +#define BestFit 1 /* Use a best fit algorithm when + searching for space for an + allocation request. This uses + memory more efficiently, but + allocation will be much slower. */ + +/*#define BECtl 1*/ /* Define this symbol to enable the + bectl() function for automatic + pool space control. */ + +#if defined (GEEKOS) + +#include // for memset() + +// Provide an assert() macro +#include +#define assert(exp) KASSERT(exp) + +#else // define (GEEKOS) + +#include + +#ifdef lint +#define NDEBUG /* Exits in asserts confuse lint */ +/* LINTLIBRARY */ /* Don't complain about def, no ref */ +extern char *sprintf(); /* Sun includes don't define sprintf */ +#endif + +#include +#include + +#endif // defined (GEEKOS) + +#ifdef BufDump /* BufDump implies DumpData */ +#ifndef DumpData +#define DumpData 1 +#endif +#endif + +#ifdef DumpData +#include +#endif + +/* Declare the interface, including the requested buffer size type, + bufsize. */ + +#include + +#define MemSize int /* Type for size arguments to memxxx() + functions such as memcmp(). */ + +/* Queue links */ + +struct qlinks { + struct bfhead *flink; /* Forward link */ + struct bfhead *blink; /* Backward link */ +}; + +/* Header in allocated and free buffers */ + +struct bhead { + bufsize prevfree; /* Relative link back to previous + free buffer in memory or 0 if + previous buffer is allocated. */ + bufsize bsize; /* Buffer size: positive if free, + negative if allocated. */ +}; +#define BH(p) ((struct bhead *) (p)) + +/* Header in directly allocated buffers (by acqfcn) */ + +struct bdhead { + bufsize tsize; /* Total size, including overhead */ + struct bhead bh; /* Common header */ +}; +#define BDH(p) ((struct bdhead *) (p)) + +/* Header in free buffers */ + +struct bfhead { + struct bhead bh; /* Common allocated/free header */ + struct qlinks ql; /* Links on free list */ +}; +#define BFH(p) ((struct bfhead *) (p)) + +static struct bfhead freelist = { /* List of free buffers */ + {0, 0}, + {&freelist, &freelist} +}; + + +#ifdef BufStats +static bufsize totalloc = 0; /* Total space currently allocated */ +static long numget = 0, numrel = 0; /* Number of bget() and brel() calls */ +#ifdef BECtl +static long numpblk = 0; /* Number of pool blocks */ +static long numpget = 0, numprel = 0; /* Number of block gets and rels */ +static long numdget = 0, numdrel = 0; /* Number of direct gets and rels */ +#endif /* BECtl */ +#endif /* BufStats */ + +#ifdef BECtl + +/* Automatic expansion block management functions */ + +static int (*compfcn) _((bufsize sizereq, int sequence)) = NULL; +static void *(*acqfcn) _((bufsize size)) = NULL; +static void (*relfcn) _((void *buf)) = NULL; + +static bufsize exp_incr = 0; /* Expansion block size */ +static bufsize pool_len = 0; /* 0: no bpool calls have been made + -1: not all pool blocks are + the same size + >0: (common) block size for all + bpool calls made so far + */ +#endif + +/* Minimum allocation quantum: */ + +#define QLSize (sizeof(struct qlinks)) +#define SizeQ ((SizeQuant > QLSize) ? SizeQuant : QLSize) + +#define V (void) /* To denote unwanted returned values */ + +/* End sentinel: value placed in bsize field of dummy block delimiting + end of pool block. The most negative number which will fit in a + bufsize, defined in a way that the compiler will accept. */ + +#define ESent ((bufsize) (-(((1L << (sizeof(bufsize) * 8 - 2)) - 1) * 2) - 2)) + +/* BGET -- Allocate a buffer. */ + +void *bget(requested_size) + bufsize requested_size; +{ + bufsize size = requested_size; + struct bfhead *b; +#ifdef BestFit + struct bfhead *best; +#endif + void *buf; +#ifdef BECtl + int compactseq = 0; +#endif + + assert(size > 0); + + if (size < SizeQ) { /* Need at least room for the */ + size = SizeQ; /* queue links. */ + } +#ifdef SizeQuant +#if SizeQuant > 1 + size = (size + (SizeQuant - 1)) & (~(SizeQuant - 1)); +#endif +#endif + + size += sizeof(struct bhead); /* Add overhead in allocated buffer + to size required. */ + +#ifdef BECtl + /* If a compact function was provided in the call to bectl(), wrap + a loop around the allocation process to allow compaction to + intervene in case we don't find a suitable buffer in the chain. */ + + while (1) { +#endif + b = freelist.ql.flink; +#ifdef BestFit + best = &freelist; +#endif + + + /* Scan the free list searching for the first buffer big enough + to hold the requested size buffer. */ + +#ifdef BestFit + while (b != &freelist) { + if (b->bh.bsize >= size) { + if ((best == &freelist) || (b->bh.bsize < best->bh.bsize)) { + best = b; + } + } + b = b->ql.flink; /* Link to next buffer */ + } + b = best; +#endif /* BestFit */ + + while (b != &freelist) { + if ((bufsize) b->bh.bsize >= size) { + + /* Buffer is big enough to satisfy the request. Allocate it + to the caller. We must decide whether the buffer is large + enough to split into the part given to the caller and a + free buffer that remains on the free list, or whether the + entire buffer should be removed from the free list and + given to the caller in its entirety. We only split the + buffer if enough room remains for a header plus the minimum + quantum of allocation. */ + + if ((b->bh.bsize - size) > (SizeQ + (sizeof(struct bhead)))) { + struct bhead *ba, *bn; + + ba = BH(((char *) b) + (b->bh.bsize - size)); + bn = BH(((char *) ba) + size); + assert(bn->prevfree == b->bh.bsize); + /* Subtract size from length of free block. */ + b->bh.bsize -= size; + /* Link allocated buffer to the previous free buffer. */ + ba->prevfree = b->bh.bsize; + /* Plug negative size into user buffer. */ + ba->bsize = -(bufsize) size; + /* Mark buffer after this one not preceded by free block. */ + bn->prevfree = 0; + +#ifdef BufStats + totalloc += size; + numget++; /* Increment number of bget() calls */ +#endif + buf = (void *) ((((char *) ba) + sizeof(struct bhead))); + return buf; + } else { + struct bhead *ba; + + ba = BH(((char *) b) + b->bh.bsize); + assert(ba->prevfree == b->bh.bsize); + + /* The buffer isn't big enough to split. Give the whole + shebang to the caller and remove it from the free list. */ + + assert(b->ql.blink->ql.flink == b); + assert(b->ql.flink->ql.blink == b); + b->ql.blink->ql.flink = b->ql.flink; + b->ql.flink->ql.blink = b->ql.blink; + +#ifdef BufStats + totalloc += b->bh.bsize; + numget++; /* Increment number of bget() calls */ +#endif + /* Negate size to mark buffer allocated. */ + b->bh.bsize = -(b->bh.bsize); + + /* Zero the back pointer in the next buffer in memory + to indicate that this buffer is allocated. */ + ba->prevfree = 0; + + /* Give user buffer starting at queue links. */ + buf = (void *) &(b->ql); + return buf; + } + } + b = b->ql.flink; /* Link to next buffer */ + } +#ifdef BECtl + + /* We failed to find a buffer. If there's a compact function + defined, notify it of the size requested. If it returns + true, try the allocation again. */ + + if ((compfcn == NULL) || (!(*compfcn)(size, ++compactseq))) { + break; + } + } + + /* No buffer available with requested size free. */ + + /* Don't give up yet -- look in the reserve supply. */ + + if (acqfcn != NULL) { + if (size > exp_incr - sizeof(struct bhead)) { + + /* Request is too large to fit in a single expansion + block. Try to satisy it by a direct buffer acquisition. */ + + struct bdhead *bdh; + + size += sizeof(struct bdhead) - sizeof(struct bhead); + if ((bdh = BDH((*acqfcn)((bufsize) size))) != NULL) { + + /* Mark the buffer special by setting the size field + of its header to zero. */ + bdh->bh.bsize = 0; + bdh->bh.prevfree = 0; + bdh->tsize = size; +#ifdef BufStats + totalloc += size; + numget++; /* Increment number of bget() calls */ + numdget++; /* Direct bget() call count */ +#endif + buf = (void *) (bdh + 1); + return buf; + } + + } else { + + /* Try to obtain a new expansion block */ + + void *newpool; + + if ((newpool = (*acqfcn)((bufsize) exp_incr)) != NULL) { + bpool(newpool, exp_incr); + buf = bget(requested_size); /* This can't, I say, can't + get into a loop. */ + return buf; + } + } + } + + /* Still no buffer available */ + +#endif /* BECtl */ + + return NULL; +} + +/* BGETZ -- Allocate a buffer and clear its contents to zero. We clear + the entire contents of the buffer to zero, not just the + region requested by the caller. */ + +void *bgetz(size) + bufsize size; +{ + char *buf = (char *) bget(size); + + if (buf != NULL) { + struct bhead *b; + bufsize rsize; + + b = BH(buf - sizeof(struct bhead)); + rsize = -(b->bsize); + if (rsize == 0) { + struct bdhead *bd; + + bd = BDH(buf - sizeof(struct bdhead)); + rsize = bd->tsize - sizeof(struct bdhead); + } else { + rsize -= sizeof(struct bhead); + } + assert(rsize >= size); + V memset(buf, 0, (MemSize) rsize); + } + return ((void *) buf); +} + +/* BGETR -- Reallocate a buffer. This is a minimal implementation, + simply in terms of brel() and bget(). It could be + enhanced to allow the buffer to grow into adjacent free + blocks and to avoid moving data unnecessarily. */ + +void *bgetr(buf, size) + void *buf; + bufsize size; +{ + void *nbuf; + bufsize osize; /* Old size of buffer */ + struct bhead *b; + + if ((nbuf = bget(size)) == NULL) { /* Acquire new buffer */ + return NULL; + } + if (buf == NULL) { + return nbuf; + } + b = BH(((char *) buf) - sizeof(struct bhead)); + osize = -b->bsize; +#ifdef BECtl + if (osize == 0) { + /* Buffer acquired directly through acqfcn. */ + struct bdhead *bd; + + bd = BDH(((char *) buf) - sizeof(struct bdhead)); + osize = bd->tsize - sizeof(struct bdhead); + } else +#endif + osize -= sizeof(struct bhead); + assert(osize > 0); + V memcpy((char *) nbuf, (char *) buf, /* Copy the data */ + (MemSize) ((size < osize) ? size : osize)); + brel(buf); + return nbuf; +} + +/* BREL -- Release a buffer. */ + +void brel(buf) + void *buf; +{ + struct bfhead *b, *bn; + + b = BFH(((char *) buf) - sizeof(struct bhead)); +#ifdef BufStats + numrel++; /* Increment number of brel() calls */ +#endif + assert(buf != NULL); + +#ifdef BECtl + if (b->bh.bsize == 0) { /* Directly-acquired buffer? */ + struct bdhead *bdh; + + bdh = BDH(((char *) buf) - sizeof(struct bdhead)); + assert(b->bh.prevfree == 0); +#ifdef BufStats + totalloc -= bdh->tsize; + assert(totalloc >= 0); + numdrel++; /* Number of direct releases */ +#endif /* BufStats */ +#ifdef FreeWipe + V memset((char *) buf, 0x55, + (MemSize) (bdh->tsize - sizeof(struct bdhead))); +#endif /* FreeWipe */ + assert(relfcn != NULL); + (*relfcn)((void *) bdh); /* Release it directly. */ + return; + } +#endif /* BECtl */ + + /* Buffer size must be negative, indicating that the buffer is + allocated. */ + + if (b->bh.bsize >= 0) { + bn = NULL; + } + assert(b->bh.bsize < 0); + + /* Back pointer in next buffer must be zero, indicating the + same thing: */ + + assert(BH((char *) b - b->bh.bsize)->prevfree == 0); + +#ifdef BufStats + totalloc += b->bh.bsize; + assert(totalloc >= 0); +#endif + + /* If the back link is nonzero, the previous buffer is free. */ + + if (b->bh.prevfree != 0) { + + /* The previous buffer is free. Consolidate this buffer with it + by adding the length of this buffer to the previous free + buffer. Note that we subtract the size in the buffer being + released, since it's negative to indicate that the buffer is + allocated. */ + + register bufsize size = b->bh.bsize; + + /* Make the previous buffer the one we're working on. */ + assert(BH((char *) b - b->bh.prevfree)->bsize == b->bh.prevfree); + b = BFH(((char *) b) - b->bh.prevfree); + b->bh.bsize -= size; + } else { + + /* The previous buffer isn't allocated. Insert this buffer + on the free list as an isolated free block. */ + + assert(freelist.ql.blink->ql.flink == &freelist); + assert(freelist.ql.flink->ql.blink == &freelist); + b->ql.flink = &freelist; + b->ql.blink = freelist.ql.blink; + freelist.ql.blink = b; + b->ql.blink->ql.flink = b; + b->bh.bsize = -b->bh.bsize; + } + + /* Now we look at the next buffer in memory, located by advancing from + the start of this buffer by its size, to see if that buffer is + free. If it is, we combine this buffer with the next one in + memory, dechaining the second buffer from the free list. */ + + bn = BFH(((char *) b) + b->bh.bsize); + if (bn->bh.bsize > 0) { + + /* The buffer is free. Remove it from the free list and add + its size to that of our buffer. */ + + assert(BH((char *) bn + bn->bh.bsize)->prevfree == bn->bh.bsize); + assert(bn->ql.blink->ql.flink == bn); + assert(bn->ql.flink->ql.blink == bn); + bn->ql.blink->ql.flink = bn->ql.flink; + bn->ql.flink->ql.blink = bn->ql.blink; + b->bh.bsize += bn->bh.bsize; + + /* Finally, advance to the buffer that follows the newly + consolidated free block. We must set its backpointer to the + head of the consolidated free block. We know the next block + must be an allocated block because the process of recombination + guarantees that two free blocks will never be contiguous in + memory. */ + + bn = BFH(((char *) b) + b->bh.bsize); + } +#ifdef FreeWipe + V memset(((char *) b) + sizeof(struct bfhead), 0x55, + (MemSize) (b->bh.bsize - sizeof(struct bfhead))); +#endif + assert(bn->bh.bsize < 0); + + /* The next buffer is allocated. Set the backpointer in it to point + to this buffer; the previous free buffer in memory. */ + + bn->bh.prevfree = b->bh.bsize; + +#ifdef BECtl + + /* If a block-release function is defined, and this free buffer + constitutes the entire block, release it. Note that pool_len + is defined in such a way that the test will fail unless all + pool blocks are the same size. */ + + if (relfcn != NULL && + ((bufsize) b->bh.bsize) == (pool_len - sizeof(struct bhead))) { + + assert(b->bh.prevfree == 0); + assert(BH((char *) b + b->bh.bsize)->bsize == ESent); + assert(BH((char *) b + b->bh.bsize)->prevfree == b->bh.bsize); + /* Unlink the buffer from the free list */ + b->ql.blink->ql.flink = b->ql.flink; + b->ql.flink->ql.blink = b->ql.blink; + + (*relfcn)(b); +#ifdef BufStats + numprel++; /* Nr of expansion block releases */ + numpblk--; /* Total number of blocks */ + assert(numpblk == numpget - numprel); +#endif /* BufStats */ + } +#endif /* BECtl */ +} + +#ifdef BECtl + +/* BECTL -- Establish automatic pool expansion control */ + +void bectl(compact, acquire, release, pool_incr) + int (*compact) _((bufsize sizereq, int sequence)); + void *(*acquire) _((bufsize size)); + void (*release) _((void *buf)); + bufsize pool_incr; +{ + compfcn = compact; + acqfcn = acquire; + relfcn = release; + exp_incr = pool_incr; +} +#endif + +/* BPOOL -- Add a region of memory to the buffer pool. */ + +void bpool(buf, len) + void *buf; + bufsize len; +{ + struct bfhead *b = BFH(buf); + struct bhead *bn; + +#ifdef SizeQuant + len &= ~(SizeQuant - 1); +#endif +#ifdef BECtl + if (pool_len == 0) { + pool_len = len; + } else if (len != pool_len) { + pool_len = -1; + } +#ifdef BufStats + numpget++; /* Number of block acquisitions */ + numpblk++; /* Number of blocks total */ + assert(numpblk == numpget - numprel); +#endif /* BufStats */ +#endif /* BECtl */ + + /* Since the block is initially occupied by a single free buffer, + it had better not be (much) larger than the largest buffer + whose size we can store in bhead.bsize. */ + + assert(len - sizeof(struct bhead) <= -((bufsize) ESent + 1)); + + /* Clear the backpointer at the start of the block to indicate that + there is no free block prior to this one. That blocks + recombination when the first block in memory is released. */ + + b->bh.prevfree = 0; + + /* Chain the new block to the free list. */ + + assert(freelist.ql.blink->ql.flink == &freelist); + assert(freelist.ql.flink->ql.blink == &freelist); + b->ql.flink = &freelist; + b->ql.blink = freelist.ql.blink; + freelist.ql.blink = b; + b->ql.blink->ql.flink = b; + + /* Create a dummy allocated buffer at the end of the pool. This dummy + buffer is seen when a buffer at the end of the pool is released and + blocks recombination of the last buffer with the dummy buffer at + the end. The length in the dummy buffer is set to the largest + negative number to denote the end of the pool for diagnostic + routines (this specific value is not counted on by the actual + allocation and release functions). */ + + len -= sizeof(struct bhead); + b->bh.bsize = (bufsize) len; +#ifdef FreeWipe + V memset(((char *) b) + sizeof(struct bfhead), 0x55, + (MemSize) (len - sizeof(struct bfhead))); +#endif + bn = BH(((char *) b) + len); + bn->prevfree = (bufsize) len; + /* Definition of ESent assumes two's complement! */ + assert((~0) == -1); + bn->bsize = ESent; +} + +#ifdef BufStats + +/* BSTATS -- Return buffer allocation free space statistics. */ + +void bstats(curalloc, totfree, maxfree, nget, nrel) + bufsize *curalloc, *totfree, *maxfree; + long *nget, *nrel; +{ + struct bfhead *b = freelist.ql.flink; + + *nget = numget; + *nrel = numrel; + *curalloc = totalloc; + *totfree = 0; + *maxfree = -1; + while (b != &freelist) { + assert(b->bh.bsize > 0); + *totfree += b->bh.bsize; + if (b->bh.bsize > *maxfree) { + *maxfree = b->bh.bsize; + } + b = b->ql.flink; /* Link to next buffer */ + } +} + +#ifdef BECtl + +/* BSTATSE -- Return extended statistics */ + +void bstatse(pool_incr, npool, npget, nprel, ndget, ndrel) + bufsize *pool_incr; + long *npool, *npget, *nprel, *ndget, *ndrel; +{ + *pool_incr = (pool_len < 0) ? -exp_incr : exp_incr; + *npool = numpblk; + *npget = numpget; + *nprel = numprel; + *ndget = numdget; + *ndrel = numdrel; +} +#endif /* BECtl */ +#endif /* BufStats */ + +#ifdef DumpData + +/* BUFDUMP -- Dump the data in a buffer. This is called with the user + data pointer, and backs up to the buffer header. It will + dump either a free block or an allocated one. */ + +void bufdump(buf) + void *buf; +{ + struct bfhead *b; + uchar_t *bdump; + bufsize bdlen; + + b = BFH(((char *) buf) - sizeof(struct bhead)); + assert(b->bh.bsize != 0); + if (b->bh.bsize < 0) { + bdump = (uchar_t *) buf; + bdlen = (-b->bh.bsize) - sizeof(struct bhead); + } else { + bdump = (uchar_t *) (((char *) b) + sizeof(struct bfhead)); + bdlen = b->bh.bsize - sizeof(struct bfhead); + } + + while (bdlen > 0) { + int i, dupes = 0; + bufsize l = bdlen; + char bhex[50], bascii[20]; + + if (l > 16) { + l = 16; + } + + for (i = 0; i < l; i++) { + V sprintf(bhex + i * 3, "%02X ", bdump[i]); + bascii[i] = isprint(bdump[i]) ? bdump[i] : ' '; + } + bascii[i] = 0; + V printf("%-48s %s\n", bhex, bascii); + bdump += l; + bdlen -= l; + while ((bdlen > 16) && (memcmp((char *) (bdump - 16), + (char *) bdump, 16) == 0)) { + dupes++; + bdump += 16; + bdlen -= 16; + } + if (dupes > 1) { + V printf( + " (%d lines [%d bytes] identical to above line skipped)\n", + dupes, dupes * 16); + } else if (dupes == 1) { + bdump -= 16; + bdlen += 16; + } + } +} +#endif + +#ifdef BufDump + +/* BPOOLD -- Dump a buffer pool. The buffer headers are always listed. + If DUMPALLOC is nonzero, the contents of allocated buffers + are dumped. If DUMPFREE is nonzero, free blocks are + dumped as well. If FreeWipe checking is enabled, free + blocks which have been clobbered will always be dumped. */ + +void bpoold(buf, dumpalloc, dumpfree) + void *buf; + int dumpalloc, dumpfree; +{ + struct bfhead *b = BFH(buf); + + while (b->bh.bsize != ESent) { + bufsize bs = b->bh.bsize; + + if (bs < 0) { + bs = -bs; + V printf("Allocated buffer: size %6ld bytes.\n", (long) bs); + if (dumpalloc) { + bufdump((void *) (((char *) b) + sizeof(struct bhead))); + } + } else { + char *lerr = ""; + + assert(bs > 0); + if ((b->ql.blink->ql.flink != b) || + (b->ql.flink->ql.blink != b)) { + lerr = " (Bad free list links)"; + } + V printf("Free block: size %6ld bytes.%s\n", + (long) bs, lerr); +#ifdef FreeWipe + lerr = ((char *) b) + sizeof(struct bfhead); + if ((bs > sizeof(struct bfhead)) && ((*lerr != 0x55) || + (memcmp(lerr, lerr + 1, + (MemSize) (bs - (sizeof(struct bfhead) + 1))) != 0))) { + V printf( + "(Contents of above free block have been overstored.)\n"); + bufdump((void *) (((char *) b) + sizeof(struct bhead))); + } else +#endif + if (dumpfree) { + bufdump((void *) (((char *) b) + sizeof(struct bhead))); + } + } + b = BFH(((char *) b) + bs); + } +} +#endif /* BufDump */ + +#ifdef BufValid + +/* BPOOLV -- Validate a buffer pool. If NDEBUG isn't defined, + any error generates an assertion failure. */ + +int bpoolv(buf) + void *buf; +{ + struct bfhead *b = BFH(buf); + + while (b->bh.bsize != ESent) { + bufsize bs = b->bh.bsize; + + if (bs < 0) { + bs = -bs; + } else { + char *lerr = ""; + + assert(bs > 0); + if (bs <= 0) { + return 0; + } + if ((b->ql.blink->ql.flink != b) || + (b->ql.flink->ql.blink != b)) { + V printf("Free block: size %6ld bytes. (Bad free list links)\n", + (long) bs); + assert(0); + return 0; + } +#ifdef FreeWipe + lerr = ((char *) b) + sizeof(struct bfhead); + if ((bs > sizeof(struct bfhead)) && ((*lerr != 0x55) || + (memcmp(lerr, lerr + 1, + (MemSize) (bs - (sizeof(struct bfhead) + 1))) != 0))) { + V printf( + "(Contents of above free block have been overstored.)\n"); + bufdump((void *) (((char *) b) + sizeof(struct bhead))); + assert(0); + return 0; + } +#endif + } + b = BFH(((char *) b) + bs); + } + return 1; +} +#endif /* BufValid */ + + /***********************\ + * * + * Built-in test program * + * * + \***********************/ + +#ifdef TestProg + +#define Repeatable 1 /* Repeatable pseudorandom sequence */ + /* If Repeatable is not defined, a + time-seeded pseudorandom sequence + is generated, exercising BGET with + a different pattern of calls on each + run. */ +#define OUR_RAND /* Use our own built-in version of + rand() to guarantee the test is + 100% repeatable. */ + +#ifdef BECtl +#define PoolSize 300000 /* Test buffer pool size */ +#else +#define PoolSize 50000 /* Test buffer pool size */ +#endif +#define ExpIncr 32768 /* Test expansion block size */ +#define CompactTries 10 /* Maximum tries at compacting */ + +#define dumpAlloc 0 /* Dump allocated buffers ? */ +#define dumpFree 0 /* Dump free buffers ? */ + +#ifndef Repeatable +extern long time(); +#endif + +extern char *malloc(); +extern int free _((char *)); + +static char *bchain = NULL; /* Our private buffer chain */ +static char *bp = NULL; /* Our initial buffer pool */ + +#include + +#ifdef OUR_RAND + +static ulong_t int next = 1; + +/* Return next random integer */ + +int rand() +{ + next = next * 1103515245L + 12345; + return (uint_t) (next / 65536L) % 32768L; +} + +/* Set seed for random generator */ + +void srand(seed) + uint_t seed; +{ + next = seed; +} +#endif + +/* STATS -- Edit statistics returned by bstats() or bstatse(). */ + +static void stats(when) + char *when; +{ + bufsize cural, totfree, maxfree; + long nget, nfree; +#ifdef BECtl + bufsize pincr; + long totblocks, npget, nprel, ndget, ndrel; +#endif + + bstats(&cural, &totfree, &maxfree, &nget, &nfree); + V printf( + "%s: %ld gets, %ld releases. %ld in use, %ld free, largest = %ld\n", + when, nget, nfree, (long) cural, (long) totfree, (long) maxfree); +#ifdef BECtl + bstatse(&pincr, &totblocks, &npget, &nprel, &ndget, &ndrel); + V printf( + " Blocks: size = %ld, %ld (%ld bytes) in use, %ld gets, %ld frees\n", + (long)pincr, totblocks, pincr * totblocks, npget, nprel); + V printf(" %ld direct gets, %ld direct frees\n", ndget, ndrel); +#endif /* BECtl */ +} + +#ifdef BECtl +static int protect = 0; /* Disable compaction during bgetr() */ + +/* BCOMPACT -- Compaction call-back function. */ + +static int bcompact(bsize, seq) + bufsize bsize; + int seq; +{ +#ifdef CompactTries + char *bc = bchain; + int i = rand() & 0x3; + +#ifdef COMPACTRACE + V printf("Compaction requested. %ld bytes needed, sequence %d.\n", + (long) bsize, seq); +#endif + + if (protect || (seq > CompactTries)) { +#ifdef COMPACTRACE + V printf("Compaction gave up.\n"); +#endif + return 0; + } + + /* Based on a random cast, release a random buffer in the list + of allocated buffers. */ + + while (i > 0 && bc != NULL) { + bc = *((char **) bc); + i--; + } + if (bc != NULL) { + char *fb; + + fb = *((char **) bc); + if (fb != NULL) { + *((char **) bc) = *((char **) fb); + brel((void *) fb); + return 1; + } + } + +#ifdef COMPACTRACE + V printf("Compaction bailed out.\n"); +#endif +#endif /* CompactTries */ + return 0; +} + +/* BEXPAND -- Expand pool call-back function. */ + +static void *bexpand(size) + bufsize size; +{ + void *np = NULL; + bufsize cural, totfree, maxfree; + long nget, nfree; + + /* Don't expand beyond the total allocated size given by PoolSize. */ + + bstats(&cural, &totfree, &maxfree, &nget, &nfree); + + if (cural < PoolSize) { + np = (void *) malloc((unsigned) size); + } +#ifdef EXPTRACE + V printf("Expand pool by %ld -- %s.\n", (long) size, + np == NULL ? "failed" : "succeeded"); +#endif + return np; +} + +/* BSHRINK -- Shrink buffer pool call-back function. */ + +static void bshrink(buf) + void *buf; +{ + if (((char *) buf) == bp) { +#ifdef EXPTRACE + V printf("Initial pool released.\n"); +#endif + bp = NULL; + } +#ifdef EXPTRACE + V printf("Shrink pool.\n"); +#endif + free((char *) buf); +} + +#endif /* BECtl */ + +/* Restrict buffer requests to those large enough to contain our pointer and + small enough for the CPU architecture. */ + +static bufsize blimit(bs) + bufsize bs; +{ + if (bs < sizeof(char *)) { + bs = sizeof(char *); + } + + /* This is written out in this ugly fashion because the + cool expression in sizeof(int) that auto-configured + to any length int befuddled some compilers. */ + + if (sizeof(int) == 2) { + if (bs > 32767) { + bs = 32767; + } + } else { + if (bs > 200000) { + bs = 200000; + } + } + return bs; +} + +int main() +{ + int i; + double x; + + /* Seed the random number generator. If Repeatable is defined, we + always use the same seed. Otherwise, we seed from the clock to + shake things up from run to run. */ + +#ifdef Repeatable + V srand(1234); +#else + V srand((int) time((long *) NULL)); +#endif + + /* Compute x such that pow(x, p) ranges between 1 and 4*ExpIncr as + p ranges from 0 to ExpIncr-1, with a concentration in the lower + numbers. */ + + x = 4.0 * ExpIncr; + x = log(x); + x = exp(log(4.0 * ExpIncr) / (ExpIncr - 1.0)); + +#ifdef BECtl + bectl(bcompact, bexpand, bshrink, (bufsize) ExpIncr); + bp = malloc(ExpIncr); + assert(bp != NULL); + bpool((void *) bp, (bufsize) ExpIncr); +#else + bp = malloc(PoolSize); + assert(bp != NULL); + bpool((void *) bp, (bufsize) PoolSize); +#endif + + stats("Create pool"); + V bpoolv((void *) bp); + bpoold((void *) bp, dumpAlloc, dumpFree); + + for (i = 0; i < TestProg; i++) { + char *cb; + bufsize bs = pow(x, (double) (rand() & (ExpIncr - 1))); + + assert(bs <= (((bufsize) 4) * ExpIncr)); + bs = blimit(bs); + if (rand() & 0x400) { + cb = (char *) bgetz(bs); + } else { + cb = (char *) bget(bs); + } + if (cb == NULL) { +#ifdef EasyOut + break; +#else + char *bc = bchain; + + if (bc != NULL) { + char *fb; + + fb = *((char **) bc); + if (fb != NULL) { + *((char **) bc) = *((char **) fb); + brel((void *) fb); + } + continue; + } +#endif + } + *((char **) cb) = (char *) bchain; + bchain = cb; + + /* Based on a random cast, release a random buffer in the list + of allocated buffers. */ + + if ((rand() & 0x10) == 0) { + char *bc = bchain; + int i = rand() & 0x3; + + while (i > 0 && bc != NULL) { + bc = *((char **) bc); + i--; + } + if (bc != NULL) { + char *fb; + + fb = *((char **) bc); + if (fb != NULL) { + *((char **) bc) = *((char **) fb); + brel((void *) fb); + } + } + } + + /* Based on a random cast, reallocate a random buffer in the list + to a random size */ + + if ((rand() & 0x20) == 0) { + char *bc = bchain; + int i = rand() & 0x3; + + while (i > 0 && bc != NULL) { + bc = *((char **) bc); + i--; + } + if (bc != NULL) { + char *fb; + + fb = *((char **) bc); + if (fb != NULL) { + char *newb; + + bs = pow(x, (double) (rand() & (ExpIncr - 1))); + bs = blimit(bs); +#ifdef BECtl + protect = 1; /* Protect against compaction */ +#endif + newb = (char *) bgetr((void *) fb, bs); +#ifdef BECtl + protect = 0; +#endif + if (newb != NULL) { + *((char **) bc) = newb; + } + } + } + } + } + stats("\nAfter allocation"); + if (bp != NULL) { + V bpoolv((void *) bp); + bpoold((void *) bp, dumpAlloc, dumpFree); + } + + while (bchain != NULL) { + char *buf = bchain; + + bchain = *((char **) buf); + brel((void *) buf); + } + stats("\nAfter release"); +#ifndef BECtl + if (bp != NULL) { + V bpoolv((void *) bp); + bpoold((void *) bp, dumpAlloc, dumpFree); + } +#endif + + return 0; +} +#endif diff --git a/palacios/src/geekos/bootsect.asm b/palacios/src/geekos/bootsect.asm new file mode 100644 index 0000000..9986818 --- /dev/null +++ b/palacios/src/geekos/bootsect.asm @@ -0,0 +1,247 @@ +; Boot sector for GeekOS +; Copyright (c) 2001, David H. Hovemeyer +; $Revision: 1.1 $ + +; This is free software. You are permitted to use, +; redistribute, and modify it as specified in the file "COPYING". + +; Loads setup code and a program image from sectors 1..n of a floppy +; and executes the setup code (which will in turn execute +; the program image). + +; Some of this code is adapted from Kernel Toolkit 0.2 +; and Linux version 2.2.x, so the following copyrights apply: + +; Copyright (C) 1991, 1992 Linus Torvalds +; modified by Drew Eckhardt +; modified by Bruce Evans (bde) +; adapted for Kernel Toolkit by Luigi Sgro + +%include "defs.asm" + +; This macro is used to calculate padding needed +; to ensure that the boot sector is exactly 512 bytes +; in size. The argument is the desired offset to be +; padded to. +%macro PadFromStart 1 + times (%1 - ($ - BeginText)) db 0 +%endmacro + +KERN_START_SEC equ (NUM_SETUP_SECTORS + 1) + +BIOS_SIGNATURE_OFFSET equ 510 + +; ---------------------------------------------------------------------- +; The actual code +; ---------------------------------------------------------------------- + +[BITS 16] +[ORG 0x0] + +BeginText: ; needed to calculate padding bytes to fill the sector + + ; Copy the boot sector into INITSEG. + mov ax, BOOTSEG + mov ds, ax ; source segment for string copy + xor si, si ; source index for string copy + mov ax, INITSEG + mov es, ax ; destination segment for string copy + xor di, di ; destination index for string copy + cld ; clear direction flag + mov cx, 256 ; number of words to copy + rep movsw ; copy 512 bytes + + jmp INITSEG:after_move + +after_move: + ; Now we're executing in INITSEG + + ; We want the data segment to refer to INITSEG + ; (since we've defined variables in the same place as the code) + mov ds, ax ; ax still contains INITSEG + + ; Put the stack in the place where we were originally loaded. + ; By definition, there is nothing important there now. + mov ax, 0 + mov ss, ax + mov sp, (BOOTSEG << 4) + 512 - 2 + +load_setup: + ; Load the setup code. + mov word [sec_count], 1 +.again: + mov ax, [sec_count] + push ax ; 1st param to ReadSector (log sec num) + push word SETUPSEG ; 2nd param to ReadSector (seg base) + dec ax ; convert to 0-indexed + shl ax, 9 ; multiply by 512 + push ax ; ...to get 3rd param (byte offset) + + ; read the sector from the floppy + call ReadSector + add sp, 6 ; clear 3 word params + + ; on to next sector + inc word [sec_count] + + ; are we done? + cmp word [sec_count], NUM_SETUP_SECTORS + jle .again + +load_kernel: + ; Load the kernel image from sectors KERN_START_SEC..n of the + ; floppy into memory at KERNSEG. Note that there are 128 sectors + ; per 64K segment. So, when figuring out which segment to + ; load the sector into, we shift right by 7 bits (which is + ; equivalent to dividing by 128). + mov word [sec_count], KERN_START_SEC +.again: + mov ax, [sec_count] ; logical sector on the floppy + push ax ; 1st param to ReadSector (log sec num) + sub ax, KERN_START_SEC ; convert to 0-indexed + mov cx, ax ; save in cx + shr ax, 7 ; divide by 128 + shl ax, 12 ; ...and multiply by 0x1000 + add ax, KERNSEG ; ...to get base relative to KERNSEG + push ax ; 2nd param to ReadSector (seg base) + and cx, 0x7f ; mod sector by 128 + shl cx, 9 ; ...and multiply by 512 + push cx ; to get offset in segment (3rd parm) + + ; read the sector from the floppy + call ReadSector + add sp, 6 ; clear 3 word params + + ; on to next sector + inc word [sec_count] + + ; have we loaded all of the sectors? + cmp word [sec_count], KERN_START_SEC+NUM_KERN_SECTORS + jl .again + + ; Now we've loaded the setup code and the kernel image. + ; Jump to setup code. + jmp SETUPSEG:0 + +; Read a sector from the floppy drive. +; This code (and the rest of this boot sector) will have to +; be re-written at some point so it reads more than one +; sector at a time. +; +; Parameters: +; - "logical" sector number [bp+8] +; - destination segment [bp+6] +; - destination offset [bp+4] +ReadSector: + push bp ; set up stack frame + mov bp, sp ; " + pusha ; save all registers + +%if 0 +; debug params + mov dx, [bp+8] + call PrintHex + call PrintNL + mov dx, [bp+6] + call PrintHex + call PrintNL + mov dx, [bp+4] + call PrintHex + call PrintNL +%endif + + ; Sector = log_sec % SECTORS_PER_TRACK + ; Head = (log_sec / SECTORS_PER_TRACK) % HEADS + mov ax, [bp+8] ; get logical sector number from stack + xor dx, dx ; dx is high part of dividend (== 0) + mov bx, SECTORS_PER_TRACK ; divisor + div bx ; do the division + mov [sec], dx ; sector is the remainder + and ax, 1 ; same as mod by HEADS==2 (slight hack) + mov [head], ax + + ; Track = log_sec / (SECTORS_PER_TRACK*HEADS) + mov ax, [bp+8] ; get logical sector number again + xor dx, dx ; dx is high part of dividend + mov bx, SECTORS_PER_TRACK*2 ; divisor + div bx ; do the division + mov [track], ax ; track is quotient + +%if 0 +; debugging code + mov dx, [sec] + call PrintHex + call PrintNL + mov dx, [head] + call PrintHex + call PrintNL + mov dx, [track] + call PrintHex + call PrintNL +%endif + + ; Now, try to actually read the sector from the floppy, + ; retrying up to 3 times. + + mov [num_retries], byte 0 + +.again: + mov ax, [bp+6] ; dest segment... + mov es, ax ; goes in es + mov ax, (0x02 << 8) | 1 ; function = 02h in ah, + ; # secs = 1 in al + mov bx, [track] ; track number... + mov ch, bl ; goes in ch + mov bx, [sec] ; sector number... + mov cl, bl ; goes in cl... + inc cl ; but it must be 1-based, not 0-based + mov bx, [head] ; head number... + mov dh, bl ; goes in dh + xor dl, dl ; hard code drive=0 + mov bx, [bp+4] ; offset goes in bx + ; (es:bx points to buffer) + + ; Call the BIOS Read Diskette Sectors service + int 0x13 + + ; If the carry flag is NOT set, then there was no error + ; and we're done. + jnc .done + + ; Error - code stored in ah + mov dx, ax + call PrintHex + inc byte [num_retries] + cmp byte [num_retries], 3 + jne .again + + ; If we got here, we failed thrice, so we give up + mov dx, 0xdead + call PrintHex +.here: jmp .here + +.done: + popa ; restore all regisiters + pop bp ; leave stack frame + ret + +; Include utility routines +%include "util.asm" + +; ---------------------------------------------------------------------- +; Variables +; ---------------------------------------------------------------------- + +; These are used by ReadSector +head: dw 0 +track: dw 0 +sec: dw 0 +num_retries: db 0 + + +; Used for loops reading sectors from floppy +sec_count: dw 0 + + +PadFromStart BIOS_SIGNATURE_OFFSET +Signature dw 0xAA55 ; BIOS controls this to ensure this is a boot sector diff --git a/palacios/src/geekos/crc32.c b/palacios/src/geekos/crc32.c new file mode 100644 index 0000000..0165c3b --- /dev/null +++ b/palacios/src/geekos/crc32.c @@ -0,0 +1,52 @@ +/* Copyright abandoned; this code is in the public domain. */ +/* Provided to GNUnet by peter@horizon.com */ + +/* + * Adapted for GeekOS by David Hovemeyer + * Code downloaded from OVM (http://www.ovmj.org) + */ + +#include +#include +#include + +#define POLYNOMIAL (ulong_t)0xedb88320 +static ulong_t crc_table[256]; + +/* + * This routine writes each crc_table entry exactly once, + * with the correct final value. Thus, it is safe to call + * even on a table that someone else is using concurrently. + */ +void Init_CRC32(void) { + unsigned int i, j; + ulong_t h = 1; + PrintBoth("Initializing CRC32\n"); + crc_table[0] = 0; + for (i = 128; i; i >>= 1) { + h = (h >> 1) ^ ((h & 1) ? POLYNOMIAL : 0); + /* h is now crc_table[i] */ + for (j = 0; j < 256; j += 2*i) + crc_table[i+j] = crc_table[j] ^ h; + } +} + +/* + * This computes the standard preset and inverted CRC, as used + * by most networking standards. Start by passing in an initial + * chaining value of 0, and then pass in the return value from the + * previous crc32() call. The final return value is the CRC. + * Note that this is a little-endian CRC, which is best used with + * data transmitted lsbit-first, and it should, itself, be appended + * to data in little-endian byte and bit order to preserve the + * property of detecting all burst errors of length 32 bits or less. + */ +ulong_t crc32(ulong_t crc, char const *buf, size_t len) { + KASSERT(crc_table[255] != 0); + crc ^= 0xffffffff; + while (len--) + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + return crc ^ 0xffffffff; +} + +/* end of crc32.c */ diff --git a/palacios/src/geekos/defs.asm b/palacios/src/geekos/defs.asm new file mode 100644 index 0000000..362fc83 --- /dev/null +++ b/palacios/src/geekos/defs.asm @@ -0,0 +1,88 @@ +; Definitions for use in GeekOS boot code +; Copyright (c) 2001, David H. Hovemeyer +; $Revision: 1.1 $ + +; This is free software. You are permitted to use, +; redistribute, and modify it as specified in the file "COPYING". + +; A lot of this code is adapted from Kernel Toolkit 0.2 +; and Linux version 2.2.x, so the following copyrights apply: + +; Copyright (C) 1991, 1992 Linus Torvalds +; modified by Drew Eckhardt +; modified by Bruce Evans (bde) +; adapted for Kernel Toolkit by Luigi Sgro + +%ifndef DEFS_ASM +%define DEFS_ASM + +TOP_OF_MEM equ 0x40000000 +VM_SIZE equ 0x20000000 +START_OF_VM equ 0x0 + +; BIOS loads the boot sector at offset 0 in this segment +BOOTSEG equ 0x07C0 + +; We'll move the boot sector up to higher memory. +; Note that the "ISA hole" begins at segment 0xA000 == 640K. +INITSEG equ 0x9000 + +; Put the setup code here, just after the boot sector. +SETUPSEG equ 0x9020 + +; Load our "Kernel" at this segment, which starts at 64K. +; The number of sectors in the kernel, NUM_KERN_SECTORS, +; will be passed on the command line. +KERNSEG equ 0x1000 + +; Size of PFAT boot record. +; Keep up to date with . +PFAT_BOOT_RECORD_SIZE equ 28 + +; Offset of BIOS signature word in boot sector. +BIOS_SIGNATURE_OFFSET equ 510 + +; Offset of PFAT boot record in boot sector. +PFAT_BOOT_RECORD_OFFSET equ BIOS_SIGNATURE_OFFSET - PFAT_BOOT_RECORD_SIZE + +; Video memory segment +VIDSEG equ 0xb800 + +; The following information is correct for a 1.44M floppy. +; Yes, I'm hard coding this. +SECTORS_PER_TRACK equ 18 +HEADS equ 2 +CYLINDERS equ 80 + +; 8259A PIC initialization codes. +; Source: Linux bootsect.S, and Intel 8259A datasheet + +; The most important reason why we reprogram the PICs is to +; route the hardware interrupts through vectors *above* +; those reserved by Intel. The BIOS (for historical reasons :-) +; routes them such that they conflict with internal processor-generated +; interrupts. + +ICW1 equ 0x11 ; ICW1 - ICW4 needed, cascade mode, interval=8, + ; edge triggered. (I think interval is irrelevant + ; for x86.) +ICW2_MASTER equ 0x20 ; put IRQs 0-7 at 0x20 (above Intel reserved ints) +ICW2_SLAVE equ 0x28 ; put IRQs 8-15 at 0x28 +ICW3_MASTER equ 0x04 ; IR2 connected to slave +ICW3_SLAVE equ 0x02 ; slave has id 2 +ICW4 equ 0x01 ; 8086 mode, no auto-EOI, non-buffered mode, + ; not special fully nested mode + +; Kernel code and data segment selectors. +; Keep these up to date with defs.h. +KERNEL_CS equ 1<<3 ; kernel code segment is GDT entry 1 +KERNEL_DS equ 2<<3 ; kernel data segment is GDT entry 2 + +; Pages for context object and stack for initial kernel thread - +; the one we construct for Main(). Keep these up to date with defs.h. +; We put them at 1MB, for no particular reason. + ;; Moved to just after where the VM will go +KERN_THREAD_OBJ equ (START_OF_VM+VM_SIZE) +KERN_STACK equ KERN_THREAD_OBJ + 4096 + +%endif diff --git a/palacios/src/geekos/depend.mak b/palacios/src/geekos/depend.mak new file mode 100644 index 0000000..6e60675 --- /dev/null +++ b/palacios/src/geekos/depend.mak @@ -0,0 +1 @@ +dummy: diff --git a/palacios/src/geekos/fd_boot.asm b/palacios/src/geekos/fd_boot.asm new file mode 100644 index 0000000..e541a9c --- /dev/null +++ b/palacios/src/geekos/fd_boot.asm @@ -0,0 +1,295 @@ +; Boot sector for GeekOS +; Copyright (c) 2001,2004 David H. Hovemeyer +; Copyright (c) 2003, Jeffrey K. Hollingsworth +; $Revision: 1.1 $ + +; This is free software. You are permitted to use, +; redistribute, and modify it as specified in the file "COPYING". + +; Loads setup code and a program image from sectors 1..n of a floppy +; and executes the setup code (which will in turn execute +; the program image). + +; Some of this code is adapted from Kernel Toolkit 0.2 +; and Linux version 2.2.x, so the following copyrights apply: + +; Copyright (C) 1991, 1992 Linus Torvalds +; modified by Drew Eckhardt +; modified by Bruce Evans (bde) +; adapted for Kernel Toolkit by Luigi Sgro + +%include "defs.asm" + +; Pad to desired offset from start symbol. +; Usage: Pad_From_Symbol offset, symbol +%macro Pad_From_Symbol 2 + times (%1 - ($ - %2)) db 0 +%endmacro + +; ---------------------------------------------------------------------- +; The actual code +; ---------------------------------------------------------------------- + +[BITS 16] +[ORG 0x0] + +BeginText: ; needed to calculate padding bytes to fill the sector + + ; Copy the boot sector into INITSEG. + mov ax, BOOTSEG + mov ds, ax ; source segment for string copy + xor si, si ; source index for string copy + mov ax, INITSEG + mov es, ax ; destination segment for string copy + xor di, di ; destination index for string copy + cld ; clear direction flag + mov cx, 256 ; number of words to copy + rep movsw ; copy 512 bytes + + jmp INITSEG:after_move + +after_move: + ; Now we're executing in INITSEG + + ; We want the data segment to refer to INITSEG + ; (since we've defined variables in the same place as the code) + mov ds, ax ; ax still contains INITSEG + + ; Put the stack in the place where we were originally loaded. + ; By definition, there is nothing important there now. + mov ax, 0 + mov ss, ax + mov sp, (BOOTSEG << 4) + 512 - 2 + +load_setup: + ; Load the setup code. + mov ax, word [setupStart] + mov word [sec_count], ax + add ax, [setupSize] + mov word [max_sector], ax +.again: + mov ax, [sec_count] + push ax ; 1st param to ReadSector (log sec num) + push word SETUPSEG ; 2nd param to ReadSector (seg base) + sub ax, [setupStart] ; convert to 0-indexed + shl ax, 9 ; multiply by 512 + push ax ; ...to get 3rd param (byte offset) + + ; read the sector from the floppy + call ReadSector + add sp, 6 ; clear 3 word params + + ; on to next sector + inc word [sec_count] + + ; are we done? + mov bx, word [max_sector] + cmp word [sec_count], bx + jl .again + +load_kernel: + ; Load the kernel image from sectors KERN_START_SEC..n of the + ; floppy into memory at KERNSEG. Note that there are 128 sectors + ; per 64K segment. So, when figuring out which segment to + ; load the sector into, we shift right by 7 bits (which is + ; equivalent to dividing by 128). + + ; Figure out start sector and max sector + mov ax, word [kernelStart] + mov word [sec_count], ax + add ax, word [kernelSize] + mov word [max_sector], ax +.again: + mov ax, [sec_count] ; logical sector on the floppy + push ax ; 1st param to ReadSector (log sec num) + sub ax, [kernelStart] ; convert to 0-indexed + mov cx, ax ; save in cx + shr ax, 7 ; divide by 128 + shl ax, 12 ; ...and multiply by 0x1000 + add ax, KERNSEG ; ...to get base relative to KERNSEG + push ax ; 2nd param to ReadSector (seg base) + and cx, 0x7f ; mod sector by 128 + shl cx, 9 ; ...and multiply by 512 + push cx ; to get offset in segment (3rd parm) + + ; read the sector from the floppy + call ReadSector + add sp, 6 ; clear 3 word params + + ; on to next sector + inc word [sec_count] + + ; have we loaded all of the sectors? + mov bx, word [max_sector] + cmp word [sec_count], bx + jl .again + + ; Now we've loaded the setup code and the kernel image. + ; Jump to setup code. + jmp SETUPSEG:0 + +; Read a sector from the floppy drive. +; This code (and the rest of this boot sector) will have to +; be re-written at some point so it reads more than one +; sector at a time. +; +; Parameters: +; - "logical" sector number [bp+8] +; - destination segment [bp+6] +; - destination offset [bp+4] +ReadSector: + push bp ; set up stack frame + mov bp, sp ; " + pusha ; save all registers + +%if 0 +; debug params + mov dx, [bp+8] + call PrintHex + call PrintNL + mov dx, [bp+6] + call PrintHex + call PrintNL + mov dx, [bp+4] + call PrintHex + call PrintNL +%endif + + ; Sector = log_sec % SECTORS_PER_TRACK + ; Head = (log_sec / SECTORS_PER_TRACK) % HEADS + mov ax, [bp+8] ; get logical sector number from stack + xor dx, dx ; dx is high part of dividend (== 0) + mov bx, SECTORS_PER_TRACK ; divisor + div bx ; do the division + mov [sec], dx ; sector is the remainder + and ax, 1 ; same as mod by HEADS==2 (slight hack) + mov [head], ax + + ; Track = log_sec / (SECTORS_PER_TRACK*HEADS) + mov ax, [bp+8] ; get logical sector number again + xor dx, dx ; dx is high part of dividend + mov bx, SECTORS_PER_TRACK*2 ; divisor + div bx ; do the division + mov [track], ax ; track is quotient + +%if 0 +; debugging code + mov dx, [sec] + call PrintHex + call PrintNL + mov dx, [head] + call PrintHex + call PrintNL + mov dx, [track] + call PrintHex + call PrintNL +%endif + + ; Now, try to actually read the sector from the floppy, + ; retrying up to 3 times. + + mov [num_retries], byte 0 + +.again: + mov ax, [bp+6] ; dest segment... + mov es, ax ; goes in es + mov ax, (0x02 << 8) | 1 ; function = 02h in ah, + ; # secs = 1 in al + mov bx, [track] ; track number... + mov ch, bl ; goes in ch + mov bx, [sec] ; sector number... + mov cl, bl ; goes in cl... + inc cl ; but it must be 1-based, not 0-based + mov bx, [head] ; head number... + mov dh, bl ; goes in dh + xor dl, dl ; hard code drive=0 + mov bx, [bp+4] ; offset goes in bx + ; (es:bx points to buffer) + + ; Call the BIOS Read Diskette Sectors service + int 0x13 + + ; If the carry flag is NOT set, then there was no error + ; and we're done. + jnc .done + + ; Error - code stored in ah + mov dx, ax + call PrintHex + inc byte [num_retries] + cmp byte [num_retries], 3 + jne .again + + ; If we got here, we failed thrice, so we give up + mov dx, 0xdead + call PrintHex +.here: jmp .here + +.done: + popa ; restore all regisiters + pop bp ; leave stack frame + ret + +; Include utility routines +%include "util.asm" + +; ---------------------------------------------------------------------- +; Variables +; ---------------------------------------------------------------------- + +; These are used by ReadSector +head: dw 0 +track: dw 0 +sec: dw 0 +num_retries: db 0 + +; Used for loops reading sectors from floppy +sec_count: dw 0 +max_sector: dw 0 + +; Padding to make the PFAT Boot Record sit just before the BIOS signature. +Pad_From_Symbol PFAT_BOOT_RECORD_OFFSET, BeginText + +; PFAT boot record +; Describes how to load the setup program and kernel. +; The default values are appropriate for creating a boot +; floppy by concatenating the boot sector, setup program, +; and kernel image. The buildFat program will change +; these values if the boot floppy is formatted as a PFAT +; filesystem. + dw 0 + dw 0 + + dw 0 + dw 0 + + dw 0 + dw 0 + + dw 0 + dw 0 + + dw 0 + dw 0 + +;; part of pfat boot record +setupStart: + dw 1 ; by default, setup is at first sector + +;; part of pfat boot record +setupSize: + dw NUM_SETUP_SECTORS ; number of sectors in setup + +;; part of pfat boot record +kernelStart: + dw 1+NUM_SETUP_SECTORS ; default start sector for kernel + +;; part of pfat boot record +kernelSize: + dw NUM_KERN_SECTORS+2*NUM_BIOS_SECTORS+NUM_VGA_BIOS_SECTORS+NUM_VMXASSIST_SECTORS + + +; Finish by writing the BIOS signature to mark this as +; a valid boot sector. +Pad_From_Symbol BIOS_SIGNATURE_OFFSET, BeginText +Signature dw 0xAA55 ; BIOS controls this to ensure this is a boot sector diff --git a/palacios/src/geekos/gdt.c b/palacios/src/geekos/gdt.c new file mode 100644 index 0000000..dd0ca5b --- /dev/null +++ b/palacios/src/geekos/gdt.c @@ -0,0 +1,178 @@ +/* + * Initialize kernel GDT. + * Copyright (c) 2001,2004 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#include +#include +#include +#include +#include +#include + + +/* + * This is defined in lowlevel.asm. + */ +extern void Load_GDTR(ushort_t* limitAndBase); + +/* ---------------------------------------------------------------------- + * Data + * ---------------------------------------------------------------------- */ + +/* + * Number of entries in the kernel GDT. + */ +#define NUM_GDT_ENTRIES 16 + +/* + * This is the kernel's global descriptor table. + */ +struct Segment_Descriptor *s_GDT=(struct Segment_Descriptor *)GDT_LOCATION; + +/* + * Number of allocated GDT entries. + */ +static int s_numAllocated = 0; + + + + + +void DumpGDT() +{ + int i; + Print("GDT Contents:\n"); + + for (i=0;iavail) { + ++s_numAllocated; + desc->avail = 0; + result = desc; + break; + } + } + + End_Int_Atomic(iflag); + + return result; +} + +/* + * Free a segment descriptor. + */ +void Free_Segment_Descriptor(struct Segment_Descriptor* desc) +{ + bool iflag = Begin_Int_Atomic(); + + KASSERT(!desc->avail); + + Init_Null_Segment_Descriptor(desc); + desc->avail = 1; + --s_numAllocated; + + End_Int_Atomic(iflag); +} + +/* + * Get the index (int the GDT) of given segment descriptor. + */ +int Get_Descriptor_Index(struct Segment_Descriptor* desc) +{ + return (int) (desc - s_GDT); +} + +/* + * Initialize the kernel's GDT. + */ +void Init_GDT(void) +{ + ushort_t limitAndBase[3]; + ulong_t gdtBaseAddr = (ulong_t) s_GDT; + struct Segment_Descriptor* desc; + int i; + + Print("GDT Placed at %x, %d entries\n",GDT_LOCATION,NUM_GDT_ENTRIES); + + KASSERT(sizeof(struct Segment_Descriptor) == 8); + + /* Clear out entries. */ + for (i = 0; i < NUM_GDT_ENTRIES; ++i) { + desc = &s_GDT[ i ]; + Init_Null_Segment_Descriptor(desc); + desc->avail = 1; + } + + /* Kernel code segment. */ + desc = Allocate_Segment_Descriptor(); + Init_Code_Segment_Descriptor( + desc, + 0, /* base address */ + 0x100000, /* num pages (== 2^20) */ + 0 /* privilege level (0 == kernel) */ + ); + KASSERT(Get_Descriptor_Index(desc) == (KERNEL_CS >> 3)); + + /* Kernel data segment. */ + desc = Allocate_Segment_Descriptor(); + Init_Data_Segment_Descriptor( + desc, + 0, /* base address */ + 0x100000, /* num pages (== 2^20) */ + 0 /* privilege level (0 == kernel) */ + ); + KASSERT(Get_Descriptor_Index(desc) == (KERNEL_DS >> 3)); + + /* Activate the kernel GDT. */ + limitAndBase[0] = sizeof(struct Segment_Descriptor) * NUM_GDT_ENTRIES; + limitAndBase[1] = gdtBaseAddr & 0xffff; + limitAndBase[2] = gdtBaseAddr >> 16; + Load_GDTR(limitAndBase); +} diff --git a/palacios/src/geekos/idt.c b/palacios/src/geekos/idt.c new file mode 100644 index 0000000..37c7fd0 --- /dev/null +++ b/palacios/src/geekos/idt.c @@ -0,0 +1,171 @@ +/* + * GeekOS IDT initialization code + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#include +#include +#include +#include + +/* ---------------------------------------------------------------------- + * Private data and functions + * ---------------------------------------------------------------------- */ + +/* + * Allocated + */ +//static union IDT_Descriptor s_IDT[ NUM_IDT_ENTRIES ]; +static union IDT_Descriptor *s_IDT = (union IDT_Descriptor *)IDT_LOCATION; + + +/* + * These symbols are defined in lowlevel.asm, and define the + * size of the interrupt entry point table and the sizes + * of the individual entry points. This gives us sufficient + * information to build the IDT. + */ +extern char g_entryPointTableStart, g_entryPointTableEnd; +extern int g_handlerSizeNoErr, g_handlerSizeErr; + +/* + * Table of C interrupt handler functions. + * Note that this is public only because it is used + * in lowlevel.asm. Other code should not refer to it. + */ +Interrupt_Handler g_interruptTable[ NUM_IDT_ENTRIES ]; + + + +void DumpIDT() +{ + int i; + Print("IDT Contents:\n"); + + for (i=0;i> 16; + + /* Install the new table in the IDTR. */ + Load_IDTR(limitAndBase); +} + +/* + * Initialize an interrupt gate with given handler address + * and descriptor privilege level. + */ +void Init_Interrupt_Gate(union IDT_Descriptor* desc, ulong_t addr, + int dpl) +{ + desc->ig.offsetLow = addr & 0xffff; + desc->ig.segmentSelector = KERNEL_CS; + desc->ig.reserved = 0; + desc->ig.signature = 0x70; /* == 01110000b */ + desc->ig.dpl = dpl; + desc->ig.present = 1; + desc->ig.offsetHigh = addr >> 16; +} + +/* + * Install a C handler function for given interrupt. + * This is a lower-level notion than an "IRQ", which specifically + * means an interrupt triggered by external hardware. + * This function can install a handler for ANY interrupt. + */ +void Install_Interrupt_Handler(int interrupt, Interrupt_Handler handler) +{ + KASSERT(interrupt >= 0 && interrupt < NUM_IDT_ENTRIES); + g_interruptTable[interrupt] = handler; +} diff --git a/palacios/src/geekos/int.c b/palacios/src/geekos/int.c new file mode 100644 index 0000000..319017b --- /dev/null +++ b/palacios/src/geekos/int.c @@ -0,0 +1,125 @@ +/* + * GeekOS interrupt handling data structures and functions + * Copyright (c) 2001,2003 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#include /* x86-specific int handling stuff */ +#include +#include +#include +#include +#include + +#include + +/* + * Defined in lowlevel.asm. + */ +ulong_t Get_Current_EFLAGS(void); + +/* ---------------------------------------------------------------------- + * Private functions and data + * ---------------------------------------------------------------------- */ + +/* + * A dummy interrupt handler function. + * Ensures that the low-level interrupt code always + * has a handler to call. + */ +static void Dummy_Interrupt_Handler(struct Interrupt_State* state) +{ + Begin_IRQ(state); + + Print("Unexpected Interrupt! Ignoring!\n"); + SerialPrint("*** Unexpected interrupt! *** Ignoring!\n"); + Dump_Interrupt_State(state); + SerialPrint_VMCS_ALL(); + + End_IRQ(state); + + // STOP(); +} + +#if 0 +static void Print_Selector(const char* regName, uint_t value) +{ + Print("%s: index=%d, ti=%d, rpl=%d\n", + regName, value >> 3, (value >> 2) & 1, value & 3); +} +#endif + +static void SerialPrint_Selector(const char* regName, uint_t value) +{ + SerialPrint("%s: index=%d, ti=%d, rpl=%d\n", + regName, value >> 3, (value >> 2) & 1, value & 3); +} + +/* ---------------------------------------------------------------------- + * Public functions + * ---------------------------------------------------------------------- */ + +/* + * Initialize the interrupt system. + */ +void Init_Interrupts(void) +{ + int i; + + PrintBoth("Initializing Interrupts\n"); + + /* Low-level initialization. Build and initialize the IDT. */ + Init_IDT(); + + /* + * Initialize all entries of the handler table with a dummy handler. + * This will ensure that we always have a handler function to call. + */ + for (i = 0; i < NUM_IDT_ENTRIES; ++i) { + Install_Interrupt_Handler(i, Dummy_Interrupt_Handler); + } + + /* Re-enable interrupts */ + Enable_Interrupts(); +} + +/* + * Query whether or not interrupts are currently enabled. + */ +bool Interrupts_Enabled(void) +{ + ulong_t eflags = Get_Current_EFLAGS(); + return (eflags & EFLAGS_IF) != 0; +} + +/* + * Dump interrupt state struct to screen + */ +void Dump_Interrupt_State(struct Interrupt_State* state) +{ + uint_t errorCode = state->errorCode; + + SerialPrint("eax=%08x ebx=%08x ecx=%08x edx=%08x\n" + "esi=%08x edi=%08x ebp=%08x\n" + "eip=%08x cs=%08x eflags=%08x\n" + "Interrupt number=%d (%s), error code=%d\n" + "index=%d, TI=%d, IDT=%d, EXT=%d\n", + state->eax, state->ebx, state->ecx, state->edx, + state->esi, state->edi, state->ebp, + state->eip, state->cs, state->eflags, + state->intNum, exception_names[state->intNum], errorCode, + errorCode >> 3, (errorCode >> 2) & 1, (errorCode >> 1) & 1, errorCode & 1 + ); + if (Is_User_Interrupt(state)) { + struct User_Interrupt_State *ustate = (struct User_Interrupt_State*) state; + SerialPrint("user esp=%08x, user ss=%08x\n", ustate->espUser, ustate->ssUser); + } + SerialPrint_Selector("cs", state->cs); + SerialPrint_Selector("ds", state->ds); + SerialPrint_Selector("es", state->es); + SerialPrint_Selector("fs", state->fs); + SerialPrint_Selector("gs", state->gs); +} diff --git a/palacios/src/geekos/io.c b/palacios/src/geekos/io.c new file mode 100644 index 0000000..3132733 --- /dev/null +++ b/palacios/src/geekos/io.c @@ -0,0 +1,80 @@ +/* + * x86 port IO routines + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#include + +/* + * Write a byte to an I/O port. + */ +void Out_Byte(ushort_t port, uchar_t value) +{ + __asm__ __volatile__ ( + "outb %b0, %w1" + : + : "a" (value), "Nd" (port) + ); +} + +/* + * Read a byte from an I/O port. + */ +uchar_t In_Byte(ushort_t port) +{ + uchar_t value; + + __asm__ __volatile__ ( + "inb %w1, %b0" + : "=a" (value) + : "Nd" (port) + ); + + return value; +} + +/* + * Write a word to an I/O port. + */ +void Out_Word(ushort_t port, ushort_t value) +{ + __asm__ __volatile__ ( + "outw %w0, %w1" + : + : "a" (value), "Nd" (port) + ); +} + +/* + * Read a byte from an I/O port. + */ +ushort_t In_Word(ushort_t port) +{ + ushort_t value; + + __asm__ __volatile__ ( + "inw %w1, %w0" + : "=a" (value) + : "Nd" (port) + ); + + return value; +} + +/* + * Short delay. May be needed when talking to some + * (slow) I/O devices. + */ +void IO_Delay(void) +{ + uchar_t value = 0; + __asm__ __volatile__ ( + "outb %0, $0x80" + : + : "a" (value) + ); +} diff --git a/palacios/src/geekos/irq.c b/palacios/src/geekos/irq.c new file mode 100644 index 0000000..24c5104 --- /dev/null +++ b/palacios/src/geekos/irq.c @@ -0,0 +1,133 @@ +/* + * This is the device-driver interface to the interrupt system. + * Copyright (c) 2001,2003 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#include +#include +#include +#include + +/* ---------------------------------------------------------------------- + * Private functions and data + * ---------------------------------------------------------------------- */ + +/* + * Current IRQ mask. + * This should be kept up to date with setup.asm + * (which does the initial programming of the PICs). + */ +static ushort_t s_irqMask = 0xfffb; + +/* + * Get the master and slave parts of an IRQ mask. + */ +#define MASTER(mask) ((mask) & 0xff) +#define SLAVE(mask) (((mask)>>8) & 0xff) + + +/* ---------------------------------------------------------------------- + * Public functions + * ---------------------------------------------------------------------- */ + +/* + * Install a handler for given IRQ. + * Note that we don't unmask the IRQ. + */ +void Install_IRQ(int irq, Interrupt_Handler handler) +{ + Install_Interrupt_Handler(irq + FIRST_EXTERNAL_INT, handler); +} + +/* + * Get current IRQ mask. Each bit position represents + * one of the 16 IRQ lines. + */ +ushort_t Get_IRQ_Mask(void) +{ + return s_irqMask; +} + +/* + * Set the IRQ mask. + */ +void Set_IRQ_Mask(ushort_t mask) +{ + uchar_t oldMask, newMask; + + oldMask = MASTER(s_irqMask); + newMask = MASTER(mask); + if (newMask != oldMask) { + Out_Byte(0x21, newMask); + } + + oldMask = SLAVE(s_irqMask); + newMask = SLAVE(mask); + if (newMask != oldMask) { + Out_Byte(0xA1, newMask); + } + + s_irqMask = mask; +} + +/* + * Enable given IRQ. + */ +void Enable_IRQ(int irq) +{ + bool iflag = Begin_Int_Atomic(); + + KASSERT(irq >= 0 && irq < 16); + ushort_t mask = Get_IRQ_Mask(); + mask &= ~(1 << irq); + Set_IRQ_Mask(mask); + + End_Int_Atomic(iflag); +} + +/* + * Disable given IRQ. + */ +void Disable_IRQ(int irq) +{ + bool iflag = Begin_Int_Atomic(); + + KASSERT(irq >= 0 && irq < 16); + ushort_t mask = Get_IRQ_Mask(); + mask |= (1 << irq); + Set_IRQ_Mask(mask); + + End_Int_Atomic(iflag); +} + +/* + * Called by an IRQ handler to begin the interrupt. + * Currently a no-op. + */ +void Begin_IRQ(struct Interrupt_State* state) +{ +} + +/* + * Called by an IRQ handler to end the interrupt. + * Sends an EOI command to the appropriate PIC(s). + */ +void End_IRQ(struct Interrupt_State* state) +{ + int irq = state->intNum - FIRST_EXTERNAL_INT; + uchar_t command = 0x60 | (irq & 0x7); + + if (irq < 8) { + /* Specific EOI to master PIC */ + Out_Byte(0x20, command); + } + else { + /* Specific EOI to slave PIC, then to master (cascade line) */ + Out_Byte(0xA0, command); + Out_Byte(0x20, 0x62); + } +} diff --git a/palacios/src/geekos/keyboard.c b/palacios/src/geekos/keyboard.c new file mode 100644 index 0000000..409d9a4 --- /dev/null +++ b/palacios/src/geekos/keyboard.c @@ -0,0 +1,329 @@ +/* + * Keyboard driver + * Copyright (c) 2001,2004 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +/* + * Information sources: + * - Chapter 8 of _The Undocumented PC_, 2nd ed, by Frank van Gilluwe, + * ISBN 0-201-47950-8. + * - Pages 400-409 of _The Programmers PC Sourcebook_, by Thom Hogan, + * ISBN 1-55615-118-7. + */ + +/* + * Credits: + * - Peter Gnodde added support for + * the CTRL and ALT modifiers + */ + +/* + * TODO list: + * - Right now we're assuming an 83-key keyboard. + * Should add support for 101+ keyboards. + * - Should toggle keyboard LEDs. + */ + +#include +#include +#include +#include +#include +#include + +/* ---------------------------------------------------------------------- + * Private data and functions + * ---------------------------------------------------------------------- */ + +/* + * Current shift state. + */ +#define LEFT_SHIFT 0x01 +#define RIGHT_SHIFT 0x02 +#define LEFT_CTRL 0x04 +#define RIGHT_CTRL 0x08 +#define LEFT_ALT 0x10 +#define RIGHT_ALT 0x20 +#define SHIFT_MASK (LEFT_SHIFT | RIGHT_SHIFT) +#define CTRL_MASK (LEFT_CTRL | RIGHT_CTRL) +#define ALT_MASK (LEFT_ALT | RIGHT_ALT) +static unsigned s_shiftState = 0; + +/* + * Queue for keycodes, in case they arrive faster than consumer + * can deal with them. + */ +#define QUEUE_SIZE 256 +#define QUEUE_MASK 0xff +#define NEXT(index) (((index) + 1) & QUEUE_MASK) +static Keycode s_queue[QUEUE_SIZE]; +static int s_queueHead, s_queueTail; + +/* + * Wait queue for thread(s) waiting for keyboard events. + */ +static struct Thread_Queue s_waitQueue; + +/* + * Translate from scan code to key code, when shift is not pressed. + */ +static const Keycode s_scanTableNoShift[] = { + KEY_UNKNOWN, ASCII_ESC, '1', '2', /* 0x00 - 0x03 */ + '3', '4', '5', '6', /* 0x04 - 0x07 */ + '7', '8', '9', '0', /* 0x08 - 0x0B */ + '-', '=', ASCII_BS, '\t', /* 0x0C - 0x0F */ + 'q', 'w', 'e', 'r', /* 0x10 - 0x13 */ + 't', 'y', 'u', 'i', /* 0x14 - 0x17 */ + 'o', 'p', '[', ']', /* 0x18 - 0x1B */ + '\r', KEY_LCTRL, 'a', 's', /* 0x1C - 0x1F */ + 'd', 'f', 'g', 'h', /* 0x20 - 0x23 */ + 'j', 'k', 'l', ';', /* 0x24 - 0x27 */ + '\'', '`', KEY_LSHIFT, '\\', /* 0x28 - 0x2B */ + 'z', 'x', 'c', 'v', /* 0x2C - 0x2F */ + 'b', 'n', 'm', ',', /* 0x30 - 0x33 */ + '.', '/', KEY_RSHIFT, KEY_PRINTSCRN, /* 0x34 - 0x37 */ + KEY_LALT, ' ', KEY_CAPSLOCK, KEY_F1, /* 0x38 - 0x3B */ + KEY_F2, KEY_F3, KEY_F4, KEY_F5, /* 0x3C - 0x3F */ + KEY_F6, KEY_F7, KEY_F8, KEY_F9, /* 0x40 - 0x43 */ + KEY_F10, KEY_NUMLOCK, KEY_SCRLOCK, KEY_KPHOME, /* 0x44 - 0x47 */ + KEY_KPUP, KEY_KPPGUP, KEY_KPMINUS, KEY_KPLEFT, /* 0x48 - 0x4B */ + KEY_KPCENTER, KEY_KPRIGHT, KEY_KPPLUS, KEY_KPEND, /* 0x4C - 0x4F */ + KEY_KPDOWN, KEY_KPPGDN, KEY_KPINSERT, KEY_KPDEL, /* 0x50 - 0x53 */ + KEY_SYSREQ, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, /* 0x54 - 0x57 */ +}; +#define SCAN_TABLE_SIZE (sizeof(s_scanTableNoShift) / sizeof(Keycode)) + +/* + * Translate from scan code to key code, when shift *is* pressed. + * Keep this in sync with the unshifted table above! + * They must be the same size. + */ +static const Keycode s_scanTableWithShift[] = { + KEY_UNKNOWN, ASCII_ESC, '!', '@', /* 0x00 - 0x03 */ + '#', '$', '%', '^', /* 0x04 - 0x07 */ + '&', '*', '(', ')', /* 0x08 - 0x0B */ + '_', '+', ASCII_BS, '\t', /* 0x0C - 0x0F */ + 'Q', 'W', 'E', 'R', /* 0x10 - 0x13 */ + 'T', 'Y', 'U', 'I', /* 0x14 - 0x17 */ + 'O', 'P', '{', '}', /* 0x18 - 0x1B */ + '\r', KEY_LCTRL, 'A', 'S', /* 0x1C - 0x1F */ + 'D', 'F', 'G', 'H', /* 0x20 - 0x23 */ + 'J', 'K', 'L', ':', /* 0x24 - 0x27 */ + '"', '~', KEY_LSHIFT, '|', /* 0x28 - 0x2B */ + 'Z', 'X', 'C', 'V', /* 0x2C - 0x2F */ + 'B', 'N', 'M', '<', /* 0x30 - 0x33 */ + '>', '?', KEY_RSHIFT, KEY_PRINTSCRN, /* 0x34 - 0x37 */ + KEY_LALT, ' ', KEY_CAPSLOCK, KEY_F1, /* 0x38 - 0x3B */ + KEY_F2, KEY_F3, KEY_F4, KEY_F5, /* 0x3C - 0x3F */ + KEY_F6, KEY_F7, KEY_F8, KEY_F9, /* 0x40 - 0x43 */ + KEY_F10, KEY_NUMLOCK, KEY_SCRLOCK, KEY_KPHOME, /* 0x44 - 0x47 */ + KEY_KPUP, KEY_KPPGUP, KEY_KPMINUS, KEY_KPLEFT, /* 0x48 - 0x4B */ + KEY_KPCENTER, KEY_KPRIGHT, KEY_KPPLUS, KEY_KPEND, /* 0x4C - 0x4F */ + KEY_KPDOWN, KEY_KPPGDN, KEY_KPINSERT, KEY_KPDEL, /* 0x50 - 0x53 */ + KEY_SYSREQ, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, /* 0x54 - 0x57 */ +}; + +static __inline__ bool Is_Queue_Empty(void) +{ + return s_queueHead == s_queueTail; +} + +static __inline__ bool Is_Queue_Full(void) +{ + return NEXT(s_queueTail) == s_queueHead; +} + +static __inline__ void Enqueue_Keycode(Keycode keycode) +{ + if (!Is_Queue_Full()) { + s_queue[ s_queueTail ] = keycode; + s_queueTail = NEXT(s_queueTail); + } +} + +static __inline__ Keycode Dequeue_Keycode(void) +{ + Keycode result; + KASSERT(!Is_Queue_Empty()); + result = s_queue[ s_queueHead ]; + s_queueHead = NEXT(s_queueHead); + return result; +} + +/* + * Handler for keyboard interrupts. + */ +static void Keyboard_Interrupt_Handler(struct Interrupt_State* state) +{ + uchar_t status, scanCode; + unsigned flag = 0; + bool release = false, shift; + Keycode keycode; + + Begin_IRQ(state); + + status = In_Byte(KB_CMD); + IO_Delay(); + + if ((status & KB_OUTPUT_FULL) != 0) { + /* There is a byte available */ + scanCode = In_Byte(KB_DATA); + IO_Delay(); +/* + * Print("code=%x%s\n", scanCode, (scanCode&0x80) ? " [release]" : ""); + */ + + if (scanCode & KB_KEY_RELEASE) { + release = true; + scanCode &= ~(KB_KEY_RELEASE); + } + + if (scanCode >= SCAN_TABLE_SIZE) { + Print("Unknown scan code: %x\n", scanCode); + goto done; + } + + /* Process the key */ + shift = ((s_shiftState & SHIFT_MASK) != 0); + keycode = shift ? s_scanTableWithShift[scanCode] : s_scanTableNoShift[scanCode]; + + /* Update shift, control and alt state */ + switch (keycode) { + case KEY_LSHIFT: + flag = LEFT_SHIFT; + break; + case KEY_RSHIFT: + flag = RIGHT_SHIFT; + break; + case KEY_LCTRL: + flag = LEFT_CTRL; + break; + case KEY_RCTRL: + flag = RIGHT_CTRL; + break; + case KEY_LALT: + flag = LEFT_ALT; + break; + case KEY_RALT: + flag = RIGHT_ALT; + break; + default: + goto noflagchange; + } + + if (release) + s_shiftState &= ~(flag); + else + s_shiftState |= flag; + + /* + * Shift, control and alt keys don't have to be + * queued, flags will be set! + */ + goto done; + +noflagchange: + /* Format the new keycode */ + if (shift) + keycode |= KEY_SHIFT_FLAG; + if ((s_shiftState & CTRL_MASK) != 0) + keycode |= KEY_CTRL_FLAG; + if ((s_shiftState & ALT_MASK) != 0) + keycode |= KEY_ALT_FLAG; + if (release) + keycode |= KEY_RELEASE_FLAG; + + /* Put the keycode in the buffer */ + Enqueue_Keycode(keycode); + + /* Wake up event consumers */ + Wake_Up(&s_waitQueue); + + /* + * Pick a new thread upon return from interrupt + * (hopefully the one waiting for the keyboard event) + */ + g_needReschedule = true; + } + +done: + End_IRQ(state); +} + +/* ---------------------------------------------------------------------- + * Public functions + * ---------------------------------------------------------------------- */ + +void Init_Keyboard(void) +{ + ushort_t irqMask; + + Print("Initializing keyboard...\n"); + + /* Start out with no shift keys enabled. */ + s_shiftState = 0; + + /* Buffer is initially empty. */ + s_queueHead = s_queueTail = 0; + + /* Install interrupt handler */ + Install_IRQ(KB_IRQ, Keyboard_Interrupt_Handler); + + /* Enable IRQ1 (keyboard) */ + irqMask = Get_IRQ_Mask(); + irqMask &= ~(1 << KB_IRQ); + Set_IRQ_Mask(irqMask); +} + +/* + * Poll for a key event. + * Returns true if a key is available, + * false if not. If a key event is available, + * it will be stored in the location pointed to + * by keycode. + */ +bool Read_Key(Keycode* keycode) +{ + bool result, iflag; + + iflag = Begin_Int_Atomic(); + + result = !Is_Queue_Empty(); + if (result) { + *keycode = Dequeue_Keycode(); + } + + End_Int_Atomic(iflag); + + return result; +} + +/* + * Wait for a keycode to arrive. + * Uses the keyboard wait queue to sleep until + * a keycode arrives. + */ +Keycode Wait_For_Key(void) +{ + bool gotKey, iflag; + Keycode keycode = KEY_UNKNOWN; + + iflag = Begin_Int_Atomic(); + + do { + gotKey = !Is_Queue_Empty(); + if (gotKey) + keycode = Dequeue_Keycode(); + else + Wait(&s_waitQueue); + } + while (!gotKey); + + End_Int_Atomic(iflag); + + return keycode; +} diff --git a/palacios/src/geekos/kthread.c b/palacios/src/geekos/kthread.c new file mode 100644 index 0000000..e2a6df2 --- /dev/null +++ b/palacios/src/geekos/kthread.c @@ -0,0 +1,818 @@ +/* + * Kernel threads + * Copyright (c) 2001,2003 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* ---------------------------------------------------------------------- + * Private data + * ---------------------------------------------------------------------- */ + +/* + * List of all threads in the system. + */ +static struct All_Thread_List s_allThreadList; + +/* + * Queue of runnable threads. + */ +static struct Thread_Queue s_runQueue; + +/* + * Current thread. + */ +struct Kernel_Thread* g_currentThread; + +/* + * Boolean flag indicating that we need to choose a new runnable thread. + * It is checked by the interrupt return code (Handle_Interrupt, + * in lowlevel.asm) before returning from an interrupt. + */ +int g_needReschedule; + +/* + * Boolean flag indicating that preemption is disabled. + * When set, external interrupts (such as the timer tick) + * will not cause a new thread to be selected. + */ +volatile int g_preemptionDisabled; + +/* + * Queue of finished threads needing disposal, + * and a wait queue used for communication between exited threads + * and the reaper thread. + */ +static struct Thread_Queue s_graveyardQueue; +static struct Thread_Queue s_reaperWaitQueue; + +/* + * Counter for keys that access thread-local data, and an array + * of destructors for freeing that data when the thread dies. This is + * based on POSIX threads' thread-specific data functionality. + */ +static unsigned int s_tlocalKeyCounter = 0; +static tlocal_destructor_t s_tlocalDestructors[MAX_TLOCAL_KEYS]; + +/* ---------------------------------------------------------------------- + * Private functions + * ---------------------------------------------------------------------- */ + +/* + * Initialize a new Kernel_Thread. + */ +static void Init_Thread(struct Kernel_Thread* kthread, void* stackPage, + int priority, bool detached) +{ + static int nextFreePid = 1; + + struct Kernel_Thread* owner = detached ? (struct Kernel_Thread*)0 : g_currentThread; + + memset(kthread, '\0', sizeof(*kthread)); + kthread->stackPage = stackPage; + kthread->esp = ((ulong_t) kthread->stackPage) + PAGE_SIZE; + kthread->numTicks = 0; + kthread->priority = priority; + kthread->userContext = 0; + kthread->owner = owner; + + /* + * The thread has an implicit self-reference. + * If the thread is not detached, then its owner + * also has a reference to it. + */ + kthread->refCount = detached ? 1 : 2; + + kthread->alive = true; + Clear_Thread_Queue(&kthread->joinQueue); + kthread->pid = nextFreePid++; + +} + +/* + * Create a new raw thread object. + * Returns a null pointer if there isn't enough memory. + */ +static struct Kernel_Thread* Create_Thread(int priority, bool detached) +{ + struct Kernel_Thread* kthread; + void* stackPage = 0; + + /* + * For now, just allocate one page each for the thread context + * object and the thread's stack. + */ + kthread = Alloc_Page(); + if (kthread != 0) + stackPage = Alloc_Page(); + + /* Make sure that the memory allocations succeeded. */ + if (kthread == 0) + return 0; + if (stackPage == 0) { + Free_Page(kthread); + return 0; + } + + /*Print("New thread @ %x, stack @ %x\n", kthread, stackPage); */ + + /* + * Initialize the stack pointer of the new thread + * and accounting info + */ + Init_Thread(kthread, stackPage, priority, detached); + + /* Add to the list of all threads in the system. */ + Add_To_Back_Of_All_Thread_List(&s_allThreadList, kthread); + + return kthread; +} + +/* + * Push a dword value on the stack of given thread. + * We use this to set up some context for the thread before + * we make it runnable. + */ +static __inline__ void Push(struct Kernel_Thread* kthread, ulong_t value) +{ + kthread->esp -= 4; + *((ulong_t *) kthread->esp) = value; +} + +/* + * Destroy given thread. + * This function should perform all cleanup needed to + * reclaim the resources used by a thread. + * Called with interrupts enabled. + */ +static void Destroy_Thread(struct Kernel_Thread* kthread) +{ + + /* Dispose of the thread's memory. */ + Disable_Interrupts(); + Free_Page(kthread->stackPage); + Free_Page(kthread); + + /* Remove from list of all threads */ + Remove_From_All_Thread_List(&s_allThreadList, kthread); + + Enable_Interrupts(); + +} + +/* + * Hand given thread to the reaper for destruction. + * Must be called with interrupts disabled! + */ +static void Reap_Thread(struct Kernel_Thread* kthread) +{ + KASSERT(!Interrupts_Enabled()); + Enqueue_Thread(&s_graveyardQueue, kthread); + Wake_Up(&s_reaperWaitQueue); +} + +/* + * Called when a reference to the thread is broken. + */ +static void Detach_Thread(struct Kernel_Thread* kthread) +{ + KASSERT(!Interrupts_Enabled()); + KASSERT(kthread->refCount > 0); + + --kthread->refCount; + if (kthread->refCount == 0) { + Reap_Thread(kthread); + } +} + +/* + * This function performs any needed initialization before + * a thread start function is executed. Currently we just use + * it to enable interrupts (since Schedule() always activates + * a thread with interrupts disabled). + */ +static void Launch_Thread(void) +{ + Enable_Interrupts(); +} + +/* + * Push initial values for general purpose registers. + */ +static void Push_General_Registers(struct Kernel_Thread* kthread) +{ + /* + * Push initial values for saved general-purpose registers. + * (The actual values are not important.) + */ + Push(kthread, 0); /* eax */ + Push(kthread, 0); /* ebx */ + Push(kthread, 0); /* edx */ + Push(kthread, 0); /* edx */ + Push(kthread, 0); /* esi */ + Push(kthread, 0); /* edi */ + Push(kthread, 0); /* ebp */ +} + +/* + * Shutdown a kernel thread. + * This is called if a kernel thread exits by falling off + * the end of its start function. + */ +static void Shutdown_Thread(void) +{ + Exit(0); +} + +/* + * Set up the initial context for a kernel-mode-only thread. + */ +static void Setup_Kernel_Thread( + struct Kernel_Thread* kthread, + Thread_Start_Func startFunc, + ulong_t arg) +{ + /* + * Push the argument to the thread start function, and the + * return address (the Shutdown_Thread function, so the thread will + * go away cleanly when the start function returns). + */ + Push(kthread, arg); + Push(kthread, (ulong_t) &Shutdown_Thread); + + /* Push the address of the start function. */ + Push(kthread, (ulong_t) startFunc); + + /* + * To make the thread schedulable, we need to make it look + * like it was suspended by an interrupt. This means pushing + * an "eflags, cs, eip" sequence onto the stack, + * as well as int num, error code, saved registers, etc. + */ + + /* + * The EFLAGS register will have all bits clear. + * The important constraint is that we want to have the IF + * bit clear, so that interrupts are disabled when the + * thread starts. + */ + Push(kthread, 0UL); /* EFLAGS */ + + /* + * As the "return address" specifying where the new thread will + * start executing, use the Launch_Thread() function. + */ + Push(kthread, KERNEL_CS); + Push(kthread, (ulong_t) &Launch_Thread); + + /* Push fake error code and interrupt number. */ + Push(kthread, 0); + Push(kthread, 0); + + /* Push initial values for general-purpose registers. */ + Push_General_Registers(kthread); + + /* + * Push values for saved segment registers. + * Only the ds and es registers will contain valid selectors. + * The fs and gs registers are not used by any instruction + * generated by gcc. + */ + Push(kthread, KERNEL_DS); /* ds */ + Push(kthread, KERNEL_DS); /* es */ + Push(kthread, 0); /* fs */ + Push(kthread, 0); /* gs */ +} + + + +/* + * This is the body of the idle thread. Its job is to preserve + * the invariant that a runnable thread always exists, + * i.e., the run queue is never empty. + */ +static void Idle(ulong_t arg) +{ + while (true) + Yield(); +} + +/* + * The reaper thread. Its job is to de-allocate memory + * used by threads which have finished. + */ +static void Reaper(ulong_t arg) +{ + struct Kernel_Thread *kthread; + + Disable_Interrupts(); + + while (true) { + /* See if there are any threads needing disposal. */ + if ((kthread = s_graveyardQueue.head) == 0) { + /* Graveyard is empty, so wait for a thread to die. */ + Wait(&s_reaperWaitQueue); + } + else { + /* Make the graveyard queue empty. */ + Clear_Thread_Queue(&s_graveyardQueue); + + /* + * Now we can re-enable interrupts, since we + * have removed all the threads needing disposal. + */ + Enable_Interrupts(); + Yield(); /* allow other threads to run? */ + + /* Dispose of the dead threads. */ + while (kthread != 0) { + struct Kernel_Thread* next = Get_Next_In_Thread_Queue(kthread); +#if 0 + Print("Reaper: disposing of thread @ %x, stack @ %x\n", + kthread, kthread->stackPage); +#endif + Destroy_Thread(kthread); + kthread = next; + } + + /* + * Disable interrupts again, since we're going to + * do another iteration. + */ + Disable_Interrupts(); + } + } +} + +/* + * Find the best (highest priority) thread in given + * thread queue. Returns null if queue is empty. + */ +static __inline__ struct Kernel_Thread* Find_Best(struct Thread_Queue* queue) +{ + /* Pick the highest priority thread */ + struct Kernel_Thread *kthread = queue->head, *best = 0; + while (kthread != 0) { + if (best == 0 || kthread->priority > best->priority) + best = kthread; + kthread = Get_Next_In_Thread_Queue(kthread); + } + return best; +} + +/* + * Acquires pointer to thread-local data from the current thread + * indexed by the given key. Assumes interrupts are off. + */ +static __inline__ const void** Get_Tlocal_Pointer(tlocal_key_t k) +{ + struct Kernel_Thread* current = g_currentThread; + + KASSERT(k < MAX_TLOCAL_KEYS); + + return ¤t->tlocalData[k]; +} + +/* + * Clean up any thread-local data upon thread exit. Assumes + * this is called with interrupts disabled. We follow the POSIX style + * of possibly invoking a destructor more than once, because a + * destructor to some thread-local data might cause other thread-local + * data to become alive once again. If everything is NULL by the end + * of an iteration, we are done. + */ +static void Tlocal_Exit(struct Kernel_Thread* curr) { + int i, j, called = 0; + + KASSERT(!Interrupts_Enabled()); + + for (j = 0; jtlocalData[i]; + if (x != NULL && s_tlocalDestructors[i] != NULL) { + + curr->tlocalData[i] = NULL; + called = 1; + + Enable_Interrupts(); + s_tlocalDestructors[i](x); + Disable_Interrupts(); + } + } + if (!called) break; + } +} + + +/* ---------------------------------------------------------------------- + * Public functions + * ---------------------------------------------------------------------- */ + +void Init_Scheduler(void) +{ + struct Kernel_Thread* mainThread = (struct Kernel_Thread *) KERNEL_THREAD_OBJECT; + + PrintBoth("Initializing Scheduler\n"); + + /* + * Create initial kernel thread context object and stack, + * and make them current. + */ + Init_Thread(mainThread, (void *) KERNEL_STACK, PRIORITY_NORMAL, true); + g_currentThread = mainThread; + Add_To_Back_Of_All_Thread_List(&s_allThreadList, mainThread); + + /* + * Create the idle thread. + */ + /*Print("starting idle thread\n");*/ + Start_Kernel_Thread(Idle, 0, PRIORITY_IDLE, true); + + /* + * Create the reaper thread. + */ + /*Print("starting reaper thread\n");*/ + Start_Kernel_Thread(Reaper, 0, PRIORITY_NORMAL, true); +} + +/* + * Start a kernel-mode-only thread, using given function as its body + * and passing given argument as its parameter. Returns pointer + * to the new thread if successful, null otherwise. + * + * startFunc - is the function to be called by the new thread + * arg - is a paramter to pass to the new function + * priority - the priority of this thread (use PRIORITY_NORMAL) for + * most things + * detached - use false for kernel threads + */ +struct Kernel_Thread* Start_Kernel_Thread( + Thread_Start_Func startFunc, + ulong_t arg, + int priority, + bool detached +) +{ + struct Kernel_Thread* kthread = Create_Thread(priority, detached); + if (kthread != 0) { + /* + * Create the initial context for the thread to make + * it schedulable. + */ + Setup_Kernel_Thread(kthread, startFunc, arg); + + + /* Atomically put the thread on the run queue. */ + Make_Runnable_Atomic(kthread); + } + + return kthread; +} + +/* + * Add given thread to the run queue, so that it + * may be scheduled. Must be called with interrupts disabled! + */ +void Make_Runnable(struct Kernel_Thread* kthread) +{ + KASSERT(!Interrupts_Enabled()); + + Enqueue_Thread(&s_runQueue, kthread); +} + +/* + * Atomically make a thread runnable. + * Assumes interrupts are currently enabled. + */ +void Make_Runnable_Atomic(struct Kernel_Thread* kthread) +{ + Disable_Interrupts(); + Make_Runnable(kthread); + Enable_Interrupts(); +} + +/* + * Get the thread that currently has the CPU. + */ +struct Kernel_Thread* Get_Current(void) +{ + return g_currentThread; +} + +/* + * Get the next runnable thread from the run queue. + * This is the scheduler. + */ +struct Kernel_Thread* Get_Next_Runnable(void) +{ + struct Kernel_Thread* best = 0; + + best = Find_Best(&s_runQueue); + KASSERT(best != 0); + Remove_Thread(&s_runQueue, best); + +/* + * Print("Scheduling %x\n", best); + */ + return best; +} + +/* + * Schedule a thread that is waiting to run. + * Must be called with interrupts off! + * The current thread should already have been placed + * on whatever queue is appropriate (i.e., either the + * run queue if it is still runnable, or a wait queue + * if it is waiting for an event to occur). + */ +void Schedule(void) +{ + struct Kernel_Thread* runnable; + + /* Make sure interrupts really are disabled */ + KASSERT(!Interrupts_Enabled()); + + /* Preemption should not be disabled. */ + KASSERT(!g_preemptionDisabled); + + /* Get next thread to run from the run queue */ + runnable = Get_Next_Runnable(); + + /* + * Activate the new thread, saving the context of the current thread. + * Eventually, this thread will get re-activated and Switch_To_Thread() + * will "return", and then Schedule() will return to wherever + * it was called from. + */ + Switch_To_Thread(runnable); +} + +/* + * Voluntarily give up the CPU to another thread. + * Does nothing if no other threads are ready to run. + */ +void Yield(void) +{ + Disable_Interrupts(); + Make_Runnable(g_currentThread); + Schedule(); + Enable_Interrupts(); +} + +/* + * Exit the current thread. + * Calling this function initiates a context switch. + */ +void Exit(int exitCode) +{ + struct Kernel_Thread* current = g_currentThread; + + if (Interrupts_Enabled()) + Disable_Interrupts(); + + /* Thread is dead */ + current->exitCode = exitCode; + current->alive = false; + + /* Clean up any thread-local memory */ + Tlocal_Exit(g_currentThread); + + /* Notify the thread's owner, if any */ + Wake_Up(¤t->joinQueue); + + /* Remove the thread's implicit reference to itself. */ + Detach_Thread(g_currentThread); + + /* + * Schedule a new thread. + * Since the old thread wasn't placed on any + * thread queue, it won't get scheduled again. + */ + Schedule(); + + /* Shouldn't get here */ + KASSERT(false); + // the build dies on a warning for a 'noreturn' violation + // This ensures that this function never returns + while(1); +} + +/* + * Wait for given thread to die. + * Interrupts must be enabled. + * Returns the thread exit code. + */ +int Join(struct Kernel_Thread* kthread) +{ + int exitCode; + + KASSERT(Interrupts_Enabled()); + + /* It is only legal for the owner to join */ + KASSERT(kthread->owner == g_currentThread); + + Disable_Interrupts(); + + /* Wait for it to die */ + while (kthread->alive) { + Wait(&kthread->joinQueue); + } + + /* Get thread exit code. */ + exitCode = kthread->exitCode; + + /* Release our reference to the thread */ + Detach_Thread(kthread); + + Enable_Interrupts(); + + return exitCode; +} + +/* + * Look up a thread by its process id. + * The caller must be the thread's owner. + */ +struct Kernel_Thread* Lookup_Thread(int pid) +{ + struct Kernel_Thread *result = 0; + + bool iflag = Begin_Int_Atomic(); + + /* + * TODO: we could remove the requirement that the caller + * needs to be the thread's owner by specifying that another + * reference is added to the thread before it is returned. + */ + + result = Get_Front_Of_All_Thread_List(&s_allThreadList); + while (result != 0) { + if (result->pid == pid) { + if (g_currentThread != result->owner) + result = 0; + break; + } + result = Get_Next_In_All_Thread_List(result); + } + + End_Int_Atomic(iflag); + + return result; +} + + +/* + * Wait on given wait queue. + * Must be called with interrupts disabled! + * Note that the function will return with interrupts + * disabled. This is desirable, because it allows us to + * atomically test a condition that can be affected by an interrupt + * and wait for it to be satisfied (if necessary). + * See the Wait_For_Key() function in keyboard.c + * for an example. + */ +void Wait(struct Thread_Queue* waitQueue) +{ + struct Kernel_Thread* current = g_currentThread; + + KASSERT(!Interrupts_Enabled()); + + /* Add the thread to the wait queue. */ + Enqueue_Thread(waitQueue, current); + + /* Find another thread to run. */ + Schedule(); +} + +/* + * Wake up all threads waiting on given wait queue. + * Must be called with interrupts disabled! + * See Keyboard_Interrupt_Handler() function in keyboard.c + * for an example. + */ +void Wake_Up(struct Thread_Queue* waitQueue) +{ + struct Kernel_Thread *kthread = waitQueue->head, *next; + + KASSERT(!Interrupts_Enabled()); + + /* + * Walk throught the list of threads in the wait queue, + * transferring each one to the run queue. + */ + while (kthread != 0) { + next = Get_Next_In_Thread_Queue(kthread); + Make_Runnable(kthread); + kthread = next; + } + + /* The wait queue is now empty. */ + Clear_Thread_Queue(waitQueue); +} + +/* + * Wake up a single thread waiting on given wait queue + * (if there are any threads waiting). Chooses the highest priority thread. + * Interrupts must be disabled! + */ +void Wake_Up_One(struct Thread_Queue* waitQueue) +{ + struct Kernel_Thread* best; + + KASSERT(!Interrupts_Enabled()); + + best = Find_Best(waitQueue); + + if (best != 0) { + Remove_Thread(waitQueue, best); + Make_Runnable(best); + /*Print("Wake_Up_One: waking up %x from %x\n", best, g_currentThread); */ + } +} + +/* + * Allocate a key for accessing thread-local data. + */ +int Tlocal_Create(tlocal_key_t *key, tlocal_destructor_t destructor) +{ + KASSERT(key); + + bool iflag = Begin_Int_Atomic(); + + if (s_tlocalKeyCounter == MAX_TLOCAL_KEYS) return -1; + s_tlocalDestructors[s_tlocalKeyCounter] = destructor; + *key = s_tlocalKeyCounter++; + + End_Int_Atomic(iflag); + + return 0; +} + +/* + * Store a value for a thread-local item + */ +void Tlocal_Put(tlocal_key_t k, const void *v) +{ + const void **pv; + + KASSERT(k < s_tlocalKeyCounter); + + pv = Get_Tlocal_Pointer(k); + *pv = v; +} + +/* + * Acquire a thread-local value + */ +void *Tlocal_Get(tlocal_key_t k) +{ + const void **pv; + + KASSERT(k < s_tlocalKeyCounter); + + pv = Get_Tlocal_Pointer(k); + return (void *)*pv; +} + +/* + * Print list of all threads in system. + * For debugging. + */ +void Dump_All_Thread_List(void) +{ + struct Kernel_Thread *kthread; + int count = 0; + bool iflag = Begin_Int_Atomic(); + + kthread = Get_Front_Of_All_Thread_List(&s_allThreadList); + + Print("["); + while (kthread != 0) { + ++count; + Print("<%lx,%lx,%lx>", + (ulong_t) Get_Prev_In_All_Thread_List(kthread), + (ulong_t) kthread, + (ulong_t) Get_Next_In_All_Thread_List(kthread)); + KASSERT(kthread != Get_Next_In_All_Thread_List(kthread)); + kthread = Get_Next_In_All_Thread_List(kthread); + } + Print("]\n"); + Print("%d threads are running\n", count); + + End_Int_Atomic(iflag); +} diff --git a/palacios/src/geekos/lowlevel.asm b/palacios/src/geekos/lowlevel.asm new file mode 100644 index 0000000..63f93c2 --- /dev/null +++ b/palacios/src/geekos/lowlevel.asm @@ -0,0 +1,576 @@ +; -*- fundamental -*- +; Low level interrupt/thread handling code for GeekOS. +; Copyright (c) 2001,2003,2004 David H. Hovemeyer +; Copyright (c) 2003, Jeffrey K. Hollingsworth +; $Revision: 1.1 $ + +; This is free software. You are permitted to use, +; redistribute, and modify it as specified in the file "COPYING". + +; This is 32 bit code to be linked into the kernel. +; It defines low level interrupt handler entry points that we'll use +; to populate the IDT. It also contains the interrupt handling +; and thread context switch code. + +%include "defs.asm" +%include "symbol.asm" +%include "util.asm" + + +[BITS 32] + +; ---------------------------------------------------------------------- +; Definitions +; ---------------------------------------------------------------------- + +; This is the size of the Interrupt_State struct in int.h +INTERRUPT_STATE_SIZE equ 64 + +; Save registers prior to calling a handler function. +; This must be kept up to date with: +; - Interrupt_State struct in int.h +; - Setup_Initial_Thread_Context() in kthread.c +%macro Save_Registers 0 + push eax + push ebx + push ecx + push edx + push esi + push edi + push ebp + push ds + push es + push fs + push gs +%endmacro + +; Restore registers and clean up the stack after calling a handler function +; (i.e., just before we return from the interrupt via an iret instruction). +%macro Restore_Registers 0 + pop gs + pop fs + pop es + pop ds + pop ebp + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + add esp, 8 ; skip int num and error code +%endmacro + +; Code to activate a new user context (if necessary), before returning +; to executing a thread. Should be called just before restoring +; registers (because the interrupt context is used). +%macro Activate_User_Context 0 + ; If the new thread has a user context which is not the current + ; one, activate it. + push esp ; Interrupt_State pointer + push dword [g_currentThread] ; Kernel_Thread pointer +; call Switch_To_User_Context + add esp, 8 ; clear 2 arguments +%endmacro + +; Number of bytes between the top of the stack and +; the interrupt number after the general-purpose and segment +; registers have been saved. +REG_SKIP equ (11*4) + +; Template for entry point code for interrupts that have +; an explicit processor-generated error code. +; The argument is the interrupt number. +%macro Int_With_Err 1 +align 8 + push dword %1 ; push interrupt number + jmp Handle_Interrupt ; jump to common handler +%endmacro + +; Template for entry point code for interrupts that do not +; generate an explicit error code. We push a dummy error +; code on the stack, so the stack layout is the same +; for all interrupts. +%macro Int_No_Err 1 +align 8 + push dword 0 ; fake error code + push dword %1 ; push interrupt number + jmp Handle_Interrupt ; jump to common handler +%endmacro + + +; ---------------------------------------------------------------------- +; Symbol imports and exports +; ---------------------------------------------------------------------- + +; This symbol is defined in idt.c, and is a table of addresses +; of C handler functions for interrupts. +IMPORT g_interruptTable + +; Global variable pointing to context struct for current thread. +IMPORT g_currentThread + +; Set to non-zero when we need to choose a new thread +; in the interrupt return code. +IMPORT g_needReschedule + +; Set to non-zero when preemption is disabled. +IMPORT g_preemptionDisabled + +; This is the function that returns the next runnable thread. +IMPORT Get_Next_Runnable + +; Function to put a thread on the run queue. +IMPORT Make_Runnable + +; Function to activate a new user context (if needed). +IMPORT Switch_To_User_Context + +; Sizes of interrupt handler entry points for interrupts with +; and without error codes. The code in idt.c uses this +; information to infer the layout of the table of interrupt +; handler entry points, without needing a separate linker +; symbol for each one (which is quite tedious to type :-) +EXPORT g_handlerSizeNoErr +EXPORT g_handlerSizeErr + +; Simple functions to load the IDTR, GDTR, and LDTR. +EXPORT Load_IDTR +EXPORT Load_GDTR +EXPORT Load_LDTR + +; Beginning and end of the table of interrupt entry points. +EXPORT g_entryPointTableStart +EXPORT g_entryPointTableEnd + +; Thread context switch function. +EXPORT Switch_To_Thread + +; Return current value of eflags register. +EXPORT Get_Current_EFLAGS + +; Return the return address +EXPORT Get_EIP +; ESP +EXPORT Get_ESP +; EBP +EXPORT Get_EBP + +; Virtual memory support. +EXPORT Enable_Paging +EXPORT Set_PDBR +EXPORT Get_PDBR +EXPORT Flush_TLB + +; CPUID functions +EXPORT cpuid_ecx +EXPORT cpuid_eax + +; Utility Functions +EXPORT Set_MSR +EXPORT Get_MSR + +EXPORT Get_CR2 + + +EXPORT Proc_test + +; ---------------------------------------------------------------------- +; Code +; ---------------------------------------------------------------------- + +[SECTION .text] + +; Load IDTR with 6-byte pointer whose address is passed as +; the parameter. +align 8 +Load_IDTR: + mov eax, [esp+4] + lidt [eax] + ret + +; Load the GDTR with 6-byte pointer whose address is +; passed as the parameter. Assumes that interrupts +; are disabled. +align 8 +Load_GDTR: + mov eax, [esp+4] + lgdt [eax] + ; Reload segment registers + mov ax, KERNEL_DS + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + jmp KERNEL_CS:.here +.here: + ret + +; Load the LDT whose selector is passed as a parameter. +align 8 +Load_LDTR: + mov eax, [esp+4] + lldt ax + ret + +; +; Start paging +; load crt3 with the passed page directory pointer +; enable paging bit in cr2 +align 8 +Enable_Paging: + push ebp + mov ebp, esp + push eax + push ebx + mov eax, [ebp+8] + mov cr3, eax + mov eax, cr3 + mov cr3, eax + mov ebx, cr0 + or ebx, 0x80000000 + mov cr0, ebx + pop ebx + pop eax + pop ebp + ret + + + + + +; +; Change PDBR +; load cr3 with the passed page directory pointer +align 8 +Set_PDBR: + mov eax, [esp+4] + mov cr3, eax + ret + +; +; Get the current PDBR. +; This is useful for lazily switching address spaces; +; only switch if the new thread has a different address space. +; +align 8 +Get_PDBR: + mov eax, cr3 + ret + +; +; Flush TLB - just need to re-load cr3 to force this to happen +; +align 8 +Flush_TLB: + mov eax, cr3 + mov cr3, eax + ret + + +; +; cpuid_ecx - return the ecx register from cpuid +; +align 8 +cpuid_ecx: + push ebp + mov ebp, esp + push ecx + mov eax, [ebp + 8] + cpuid + mov eax, ecx + pop ecx + pop ebp + ret + +; +; cpuid_eax - return the eax register from cpuid +; +align 8 +cpuid_eax: + mov eax, [esp+4] + cpuid + ret + +; +; Set_MSR - Set the value of a given MSR +; +align 8 +Set_MSR: + push ebp + mov ebp, esp + pusha + mov eax, [ebp+16] + mov edx, [ebp+12] + mov ecx, [ebp+8] + wrmsr + popa + pop ebp + ret + + + +; +; Get_MSR - Get the value of a given MSR +; void Get_MSR(int MSR, void * high_byte, void * low_byte); +; +align 8 +Get_MSR: + push ebp + mov ebp, esp + pusha + mov ecx, [ebp+8] + rdmsr + mov ebx, [ebp+12] + mov [ebx], edx + mov ebx, [ebp+16] + mov [ebx], eax + popa + pop ebp + ret + + + +align 8 +Get_CR2: + mov eax, cr2 + ret + + +align 8 +Proc_test: + push ebp + mov ebp, esp + push ebx + mov ebx, [ebp + 8] + mov eax, [ebp + 12] + + add eax, ebx + pop ebx + pop ebp + ret + + +; Common interrupt handling code. +; Save registers, call C handler function, +; possibly choose a new thread to run, restore +; registers, return from the interrupt. +align 8 +Handle_Interrupt: + ; Save registers (general purpose and segment) + Save_Registers + + ; Ensure that we're using the kernel data segment + mov ax, KERNEL_DS + mov ds, ax + mov es, ax + + ; Get the address of the C handler function from the + ; table of handler functions. + mov eax, g_interruptTable ; get address of handler table + mov esi, [esp+REG_SKIP] ; get interrupt number + mov ebx, [eax+esi*4] ; get address of handler function + + ; Call the handler. + ; The argument passed is a pointer to an Interrupt_State struct, + ; which describes the stack layout for all interrupts. + push esp + call ebx + add esp, 4 ; clear 1 argument + + ; If preemption is disabled, then the current thread + ; keeps running. + cmp [g_preemptionDisabled], dword 0 + jne .restore + + ; See if we need to choose a new thread to run. + cmp [g_needReschedule], dword 0 + je .restore + + ; Put current thread back on the run queue + push dword [g_currentThread] + call Make_Runnable + add esp, 4 ; clear 1 argument + + ; Save stack pointer in current thread context, and + ; clear numTicks field. + mov eax, [g_currentThread] + mov [eax+0], esp ; esp field + mov [eax+4], dword 0 ; numTicks field + + ; Pick a new thread to run, and switch to its stack + call Get_Next_Runnable + mov [g_currentThread], eax + mov esp, [eax+0] ; esp field + + ; Clear "need reschedule" flag + mov [g_needReschedule], dword 0 + +.restore: + ; Activate the user context, if necessary. + Activate_User_Context + + ; Restore registers + Restore_Registers + + ; Return from the interrupt. + iret + +; ---------------------------------------------------------------------- +; Switch_To_Thread() +; Save context of currently executing thread, and activate +; the thread whose context object is passed as a parameter. +; +; Parameter: +; - ptr to Kernel_Thread whose state should be restored and made active +; +; Notes: +; Called with interrupts disabled. +; This must be kept up to date with definition of Kernel_Thread +; struct, in kthread.h. +; ---------------------------------------------------------------------- +align 16 +Switch_To_Thread: + ; Modify the stack to allow a later return via an iret instruction. + ; We start with a stack that looks like this: + ; + ; thread_ptr + ; esp --> return addr + ; + ; We change it to look like this: + ; + ; thread_ptr + ; eflags + ; cs + ; esp --> return addr + + push eax ; save eax + mov eax, [esp+4] ; get return address + mov [esp-4], eax ; move return addr down 8 bytes from orig loc + add esp, 8 ; move stack ptr up + pushfd ; put eflags where return address was + mov eax, [esp-4] ; restore saved value of eax + push dword KERNEL_CS ; push cs selector + sub esp, 4 ; point stack ptr at return address + + ; Push fake error code and interrupt number + push dword 0 + push dword 0 + + ; Save general purpose registers. + Save_Registers + + ; Save stack pointer in the thread context struct (at offset 0). + mov eax, [g_currentThread] + mov [eax+0], esp + + ; Clear numTicks field in thread context, since this + ; thread is being suspended. + mov [eax+4], dword 0 + + ; Load the pointer to the new thread context into eax. + ; We skip over the Interrupt_State struct on the stack to + ; get the parameter. + mov eax, [esp+INTERRUPT_STATE_SIZE] + + ; Make the new thread current, and switch to its stack. + mov [g_currentThread], eax + mov esp, [eax+0] + + ; Activate the user context, if necessary. + Activate_User_Context + + ; Restore general purpose and segment registers, and clear interrupt + ; number and error code. + Restore_Registers + + ; We'll return to the place where the thread was + ; executing last. + iret + +; Return current contents of eflags register. +align 16 +Get_Current_EFLAGS: + pushfd ; push eflags + pop eax ; pop contents into eax + ret + + + +; Return the eip of the next instruction after the caller +align 16 +Get_EIP: + mov eax, [esp] + ret + +; Return the current esp in the procedure +align 16 +Get_ESP: + mov eax, esp + ret + +; Return the current ebp in the procedure +align 16 +Get_EBP: + mov eax, ebp + ret + + + +; ---------------------------------------------------------------------- +; Generate interrupt-specific entry points for all interrupts. +; We also define symbols to indicate the extend of the table +; of entry points, and the size of individual entry points. +; ---------------------------------------------------------------------- +align 8 +g_entryPointTableStart: + +; Handlers for processor-generated exceptions, as defined by +; Intel 486 manual. +Int_No_Err 0 +align 8 +Before_No_Err: +Int_No_Err 1 +align 8 +After_No_Err: +Int_No_Err 2 ; FIXME: not described in 486 manual +Int_No_Err 3 +Int_No_Err 4 +Int_No_Err 5 +Int_No_Err 6 +Int_No_Err 7 +align 8 +Before_Err: +Int_With_Err 8 +align 8 +After_Err: +Int_No_Err 9 ; FIXME: not described in 486 manual +Int_With_Err 10 +Int_With_Err 11 +Int_With_Err 12 +Int_With_Err 13 +Int_With_Err 14 +Int_No_Err 15 ; FIXME: not described in 486 manual +Int_No_Err 16 +Int_With_Err 17 + +; The remaining interrupts (18 - 255) do not have error codes. +; We can generate them all in one go with nasm's %rep construct. +%assign intNum 18 +%rep (256 - 18) +Int_No_Err intNum +%assign intNum intNum+1 +%endrep + +align 8 +g_entryPointTableEnd: + +[SECTION .data] + +; Exported symbols defining the size of handler entry points +; (both with and without error codes). +align 4 +g_handlerSizeNoErr: dd (After_No_Err - Before_No_Err) +align 4 +g_handlerSizeErr: dd (After_Err - Before_Err) diff --git a/palacios/src/geekos/main.c b/palacios/src/geekos/main.c new file mode 100644 index 0000000..2da73ac --- /dev/null +++ b/palacios/src/geekos/main.c @@ -0,0 +1,434 @@ +/* + * GeekOS C code entry point + * Copyright (c) 2001,2003,2004 David H. Hovemeyer + * Copyright (c) 2003, Jeffrey K. Hollingsworth + * Copyright (c) 2004, Iulian Neamtiu + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +/* + static inline unsigned int cpuid_ecx(unsigned int op) + { + unsigned int eax, ecx; + + __asm__("cpuid" + : "=a" (eax), "=c" (ecx) + : "0" (op) + : "bx", "dx" ); + + return ecx; + } +*/ + + + +extern void Get_MSR(ulong_t msr, unsigned int *val1, unsigned int *val2); +extern void Set_MSR(ulong_t msr, ulong_t val1, ulong_t val2); +extern uint_t Get_EIP(); +extern uint_t Get_ESP(); +extern uint_t Get_EBP(); + + +int foo=42; + +#define SPEAKER_PORT 0x61 + + +void Buzz(unsigned delay, unsigned num) +{ + volatile int x; + int i,j; + unsigned char init; + + init=In_Byte(SPEAKER_PORT); + + for (i=0;ientry_ip, vm->exit_eip, vm->guest_esp); + + SerialPrintLevel(100,"VM_Thread: You should see nothing further from me\n"); + + + ret = VMLaunch(vm); + + + SerialPrintLevel(100,"VM_Thread: uh oh..."); + + switch (ret) { + case VMX_SUCCESS: + SerialPrintLevel(100,"Normal VMExit Occurred\n"); + break; + case VMX_FAIL_INVALID: + SerialPrintLevel(100,"Possibile invalid VMCS (%.8x)\n", ret); + break; + case VMX_FAIL_VALID: + SerialPrintLevel(100,"Valid VMCS, errorcode recorded in VMCS\n"); + break; + case VMM_ERROR: + SerialPrintLevel(100,"VMM Error\n"); + break; + default: + SerialPrintLevel(100,"VMLaunch returned unknown error (%.8x)\n", ret); + break; + } + + SerialPrintLevel(100,"VM_Thread: Spinning\n"); + while (1) {} + +} + + +int AllocateAndMapPagesForRange(uint_t start, uint_t length, pte_t template_pte) +{ + uint_t address; + + for (address=start;address"); + + + SerialPrintLevel(100,"Initializing VMX\n"); + PrintBoth("Initializing VMX\n"); + VmxOnRegion * vmxRegion = InitVMX(); + + if (vmxRegion==NULL) { + PrintBoth("VMX Cannot be turned on. Halted.\n"); + while (1) {} + } + + + + SerialPrintLevel(1000,"Launching Noisemaker and keyboard listener threads\n"); + + key_thread = Start_Kernel_Thread(Keyboard_Listener, (ulong_t)&doIBuzz, PRIORITY_NORMAL, false); + spkr_thread = Start_Kernel_Thread(Buzzer, (ulong_t)&doIBuzz, PRIORITY_NORMAL, false); + + +// Enable this to run the simple buzzer VM +#if 0 + + // Put the entry around 0x10000, where the geekos kernel used to live + vm.entry_ip=(uint_t)0x10000; + vm.exit_eip=0; + // Put the stack as the last thing in the VM partition + vm.guest_esp=(uint_t)START_OF_VM+VM_SIZE-1; + + + memcpy(vm.entry_ip,MYBUZZVM_START,MYBUZZVM_LEN); + + SerialPrintLevel(1000,"VM-Launching MyBuzzVM after copy to 0x10000\n"); + + vm_thread = Start_Kernel_Thread(VM_Thread, (ulong_t)&vm,PRIORITY_NORMAL,false); + +#else + +#if 0 + + // write the hello VM down to where we would usually put + // vmxassist, and see if it can talk to us + vm.entry_ip=(uint_t)START_OF_VM+0xd000000; + vm.exit_eip=0; + // Put the stack as the last thing in the VM partition + vm.guest_esp=(uint_t)START_OF_VM+VM_SIZE-1; + + + memcpy((void*)(vm.entry_ip),Hello,200); // 200 should be plenty + + SerialPrintLevel(1000,"VM-Launching HelloVM after copy to 0xd000000\n"); + + vm_thread = Start_Kernel_Thread(VM_Thread, (ulong_t)&vm,PRIORITY_NORMAL,false); + +#else + // Try to launch a real VM + + // First we will copy down VMXAssist, then we'll launch that + // and see if it can handle the system bios + + // We now map pages of physical memory into where we are going + // to slap the vmxassist, bios, and vgabios code + pte_t template_pte; + + template_pte.present=1; + template_pte.flags=VM_WRITE|VM_READ|VM_USER|VM_EXEC; + template_pte.accessed=0; + template_pte.dirty=0; + template_pte.pteAttribute=0; + template_pte.globalPage=0; + template_pte.kernelInfo=0; + + SerialPrintLevel(1000,"Allocating Pages for VMXASSIST, BIOS, and VGA BIOS\n"); + +#define SEGLEN (1024*64) + + AllocateAndMapPagesForRange(START_OF_VM+0xd0000, SEGLEN, template_pte); + AllocateAndMapPagesForRange(START_OF_VM+0xf0000, SEGLEN, template_pte); + AllocateAndMapPagesForRange(START_OF_VM+0xc0000, SEGLEN, template_pte); + + // Now we should be copying into actual memory + + SerialPrintLevel(1000,"Copying VMXASSIST code from %x to %x (%d bytes)\n", VMXASSIST_START, START_OF_VM+0xd0000,VMXASSIST_LENGTH); + memcpy((char*)(START_OF_VM+0xd0000),(char*)VMXASSIST_START,VMXASSIST_LENGTH); + SerialPrintLevel(1000,"Copying BIOS (2nd copy) code from %x to %x (%d bytes)\n", BIOS2_START, START_OF_VM+0xf0000,BIOS_LENGTH); + memcpy((char*)(START_OF_VM+0xf0000),(char*)BIOS2_START,BIOS_LENGTH); + SerialPrintLevel(1000,"Copying VGA BIOS code from %x to %x (%d bytes)\n", VGA_BIOS_START, START_OF_VM+0xc0000,VGA_BIOS_LENGTH); + memcpy((char *)(START_OF_VM+0xc0000),(char*)VGA_BIOS_START,VGA_BIOS_LENGTH); + + // jump into vmxassist + vm.entry_ip=(uint_t)0xd0000; + vm.exit_eip=0; + // Put the stack at 512K + vm.guest_esp=(uint_t)START_OF_VM+1024*512; + + SerialPrintLevel(1000,"VM-Launching to vmxassist for boot\n"); + + vm_thread = Start_Kernel_Thread(VM_Thread, (ulong_t)&vm,PRIORITY_NORMAL,false); + + + SerialPrintLevel(1000,"Next: setup GDT\n"); + +#endif +#endif + + + TODO("Write a Virtual Machine Monitor"); + + + /* Now this thread is done. */ + Exit(0); +} + + diff --git a/palacios/src/geekos/malloc.c b/palacios/src/geekos/malloc.c new file mode 100644 index 0000000..ea76959 --- /dev/null +++ b/palacios/src/geekos/malloc.c @@ -0,0 +1,55 @@ +/* + * GeekOS memory allocation API + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#include +#include +#include +#include +#include + +/* + * Initialize the heap starting at given address and occupying + * specified number of bytes. + */ +void Init_Heap(ulong_t start, ulong_t size) +{ + /*Print("Creating kernel heap: start=%lx, size=%ld\n", start, size);*/ + bpool((void*) start, size); +} + +/* + * Dynamically allocate a buffer of given size. + * Returns null if there is not enough memory to satisfy the + * allocation. + */ +void* Malloc(ulong_t size) +{ + void *result; + bool iflag; + + KASSERT(size > 0); + + iflag = Begin_Int_Atomic(); + result = bget(size); + End_Int_Atomic(iflag); + + return result; +} + +/* + * Free a buffer allocated with Malloc() or Malloc(). + */ +void Free(void* buf) +{ + bool iflag; + + iflag = Begin_Int_Atomic(); + brel(buf); + End_Int_Atomic(iflag); +} diff --git a/palacios/src/geekos/mem.c b/palacios/src/geekos/mem.c new file mode 100644 index 0000000..2fbc0f5 --- /dev/null +++ b/palacios/src/geekos/mem.c @@ -0,0 +1,346 @@ +/* + * Physical memory allocation + * Copyright (c) 2001,2003,2004 David H. Hovemeyer + * Copyright (c) 2003, Jeffrey K. Hollingsworth + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* ---------------------------------------------------------------------- + * Global data + * ---------------------------------------------------------------------- */ + +/* + * List of Page structures representing each page of physical memory. + */ +struct Page* g_pageList; + +/* + * Number of pages currently available on the freelist. + */ +uint_t g_freePageCount = 0; + +/* ---------------------------------------------------------------------- + * Private data and functions + * ---------------------------------------------------------------------- */ + +/* + * Defined in paging.c + */ +extern int debugFaults; +#define Debug(args...) if (debugFaults) Print(args) + +/* + * List of pages available for allocation. + */ +static struct Page_List s_freeList; + +/* + * Total number of physical pages. + */ +int unsigned s_numPages; + +/* + * Add a range of pages to the inventory of physical memory. + */ +static void Add_Page_Range(ulong_t start, ulong_t end, int flags) +{ + ulong_t addr; + + //Print("Start: %u, End: %u\n", (unsigned int)start, (unsigned int)end); + + KASSERT(Is_Page_Multiple(start)); + KASSERT(Is_Page_Multiple(end)); + KASSERT(start < end); + + //Print("Adding %lu pages\n", (end - start) / PAGE_SIZE); + + for (addr = start; addr < end; addr += PAGE_SIZE) { + // Print("Adding Page at %u\n", (unsigned int)addr); + struct Page *page = Get_Page(addr); + + page->flags = flags; + + if (flags == PAGE_AVAIL) { + /* Add the page to the freelist */ + Add_To_Back_Of_Page_List(&s_freeList, page); + + /* Update free page count */ + ++g_freePageCount; + } else { + Set_Next_In_Page_List(page, 0); + Set_Prev_In_Page_List(page, 0); + } + + } + // Print("%d pages now in freelist\n", g_freePageCount); + +} + +/* ---------------------------------------------------------------------- + * Public functions + * ---------------------------------------------------------------------- */ + +/* + * The linker defines this symbol to indicate the end of + * the executable image. + */ +extern char end; + +/* + * Initialize memory management data structures. + * Enables the use of Alloc_Page() and Free_Page() functions. + */ +void Init_Mem(struct Boot_Info* bootInfo) +{ + ulong_t numPages = bootInfo->memSizeKB >> 2; + // ulong_t endOfMem = numPages * PAGE_SIZE; + unsigned numPageListBytes = sizeof(struct Page) * numPages; + ulong_t pageListAddr; + ulong_t pageListEnd; + ulong_t kernEnd; + + KASSERT(bootInfo->memSizeKB > 0); + + if (bootInfo->memSizeKB != TOP_OF_MEM/1024) { + PrintBoth("Kernel compiled for %d KB machine, but machine claims %d KB\n",TOP_OF_MEM/1024,bootInfo->memSizeKB); + if (bootInfo->memSizeKB < TOP_OF_MEM/1024) { + PrintBoth("Kernel compiled for more memory than machine has. Panicking\n"); + KASSERT(0); + } + } + + if (0) { + // if there is not enough memory between START_OF_VM+VM_SIZE and TOP_OF_MEM + // to store the kernel and kernel structures, we need to panick + PrintBoth("Kernel is not compiled with sufficient memory above the VM to support the memory\n"); + KASSERT(0); + } + + + bootInfo->memSizeKB = TOP_OF_MEM / 1024; + + /* + * Before we do anything, switch from setup.asm's temporary GDT + * to the kernel's permanent GDT. + */ + Init_GDT(); + + /* + * We'll put the list of Page objects right after the end + * of the kernel, and mark it as "kernel". This will bootstrap + * us sufficiently that we can start allocating pages and + * keeping track of them. + */ + + // JRL: This is stupid... + // with large mem sizes the page list overruns into the ISA + // hole. By blind luck this causes an unrelated assertion failure, otherwise + // I might never have caught it... + // We fix it by moving the page list after the kernel heap... + // For now we'll make our own stupid assumption that the mem size + // is large enough to accomodate the list in high mem. + + PrintBoth("Total Memory Size: %u MBytes\n", bootInfo->memSizeKB/1024); + PrintBoth("VM Start: %x\n",START_OF_VM); + PrintBoth("VM End: %x\n",START_OF_VM+VM_SIZE-1); + + + PrintBoth("Page struct size: %u bytes\n", sizeof(struct Page)); + PrintBoth("Page List Size: %u bytes\n", numPageListBytes); + + + //pageListAddr = Round_Up_To_Page((ulong_t) &end); + //pageListAddr = Round_Up_To_Page(HIGHMEM_START + KERNEL_HEAP_SIZE); + + // Note that this is now moved to be just above the kernel heap + // see defs.h for layout + pageListAddr=Round_Up_To_Page(KERNEL_PAGELIST); + + pageListEnd = Round_Up_To_Page(pageListAddr + numPageListBytes); + + g_pageList = (struct Page*) pageListAddr; + // kernEnd = Round_Up_To_Page(pageListAddr + numPageListBytes); + // + // PAD - Note: I am changing this so that everything through the end of + // the VM boot package (bioses/vmxassist) is off limits + //kernEnd = Round_Up_To_Page((ulong_t) &end); + kernEnd = Round_Up_To_Page(VM_BOOT_PACKAGE_END); + s_numPages = numPages; + + PrintBoth("Pagelist addr: %p\n", g_pageList); + PrintBoth("index: %p\n", &g_pageList[3]); + PrintBoth("direct offset: %p\n", g_pageList + (sizeof(struct Page) * 2)); + PrintBoth("Kernel Size=%lx\n", (kernEnd - KERNEL_START_ADDR)); + PrintBoth("Kernel Start=%x\n", KERNEL_START_ADDR); + PrintBoth("Kernel End=%lx\n", kernEnd); + PrintBoth("VM Boot Package Start=%x\n", VM_BOOT_PACKAGE_START); + PrintBoth("VM Boot Package End=%x\n", VM_BOOT_PACKAGE_END); + + /* + * The initial kernel thread and its stack are placed + * just beyond the ISA hole. + */ + // This is no longer true + // KASSERT(ISA_HOLE_END == KERN_THREAD_OBJ); + // instead, + //KASSERT(KERN_THREAD_OBJ==(START_OF_VM+VM_SIZE)); + //KASSERT(KERN_STACK == KERN_THREAD_OBJ + PAGE_SIZE); + + /* + * Memory looks like this: + * 0 - start: available (might want to preserve BIOS data area) + * start - end: kernel + * end - ISA_HOLE_START: available + * ISA_HOLE_START - ISA_HOLE_END: used by hardware (and ROM BIOS?) + * ISA_HOLE_END - HIGHMEM_START: used by initial kernel thread + * HIGHMEM_START - end of memory: available + * (the kernel heap is located at HIGHMEM_START; any unused memory + * beyond that is added to the freelist) + */ + + // The VM region... 0 .. VM size is out of bounds + KASSERT(START_OF_VM==0); + Add_Page_Range(START_OF_VM, START_OF_VM+VM_SIZE, PAGE_VM); + // The kernel is still in low memory at this point, in the VM region + // Thus we will mark it as kernel use + // Add_Page_Range(KERNEL_START_ADDR, kernEnd, PAGE_KERN); + + + //Add_Page_Range(kernEnd, ISA_HOLE_START, PAGE_AVAIL); + // ISA hole remains closed (no actual memory) + // Add_Page_Range(ISA_HOLE_START, ISA_HOLE_END, PAGE_HW); + + //Add_Page_Range(ISA_HOLE_END, HIGHMEM_START, PAGE_ALLOCATED); + // Add_Page_Range(HIGHMEM_START, HIGHMEM_START + KERNEL_HEAP_SIZE, PAGE_HEAP); + //Add_Page_Range(HIGHMEM_START + KERNEL_HEAP_SIZE, endOfMem, PAGE_AVAIL); + /* JRL: move page list after kernel heap */ + + //Now, above the VM region... + + // Kernel thread object + Add_Page_Range(KERNEL_THREAD_OBJECT,KERNEL_THREAD_OBJECT+KERNEL_THREAD_OBJECT_SIZE,PAGE_ALLOCATED); + // Kernel stack + Add_Page_Range(KERNEL_STACK,KERNEL_STACK+KERNEL_STACK_SIZE,PAGE_ALLOCATED); + // Kernel heap + Add_Page_Range(KERNEL_HEAP,KERNEL_HEAP+KERNEL_HEAP_SIZE,PAGE_HEAP); + // Kernel page list + Add_Page_Range(pageListAddr, pageListEnd, PAGE_KERN); + // Free space + Add_Page_Range(pageListEnd,Round_Down_To_Page(FINAL_KERNEL_START), PAGE_AVAIL); + // The kernel + Add_Page_Range(Round_Down_To_Page(FINAL_KERNEL_START),Round_Up_To_Page(FINAL_VMBOOTEND+1),PAGE_KERN); + // The vmbootpackage + // IDT (this should be one page) + Add_Page_Range(IDT_LOCATION,TSS_LOCATION,PAGE_KERN); + // TSS (this should be one page) + Add_Page_Range(TSS_LOCATION,GDT_LOCATION, PAGE_KERN); + // GDT (this should be one page) + Add_Page_Range(GDT_LOCATION,TOP_OF_MEM, PAGE_KERN); + + /* Initialize the kernel heap */ + Init_Heap(KERNEL_HEAP, KERNEL_HEAP_SIZE); + + PrintBoth("%uKB memory detected, %u pages in freelist, %d bytes in kernel heap\n", + bootInfo->memSizeKB, g_freePageCount, KERNEL_HEAP_SIZE); + + PrintBoth("Memory Layout:\n"); + PrintBoth("%x to %x - VM\n",START_OF_VM,START_OF_VM+VM_SIZE-1); + PrintBoth("%x to %x - INITIAL THREAD\n",KERNEL_THREAD_OBJECT,KERNEL_THREAD_OBJECT+KERNEL_THREAD_OBJECT_SIZE-1); + PrintBoth("%x to %x - KERNEL STACK\n",KERNEL_STACK,KERNEL_STACK+KERNEL_STACK_SIZE-1); + PrintBoth("%x to %x - KERNEL HEAP\n",KERNEL_HEAP,KERNEL_HEAP+KERNEL_HEAP_SIZE-1); + PrintBoth("%lx to %lx - PAGE LIST\n",pageListAddr,pageListEnd-1); + PrintBoth("%lx to %x - FREE\n",pageListEnd,FINAL_KERNEL_START-1); + PrintBoth("%x to %x - KERNEL CODE\n",FINAL_KERNEL_START,FINAL_KERNEL_END); + PrintBoth("%x to %x - BIOS\n",FINAL_BIOS_START,FINAL_BIOS_END); + PrintBoth("%x to %x - VGABIOS\n",FINAL_VGA_BIOS_START,FINAL_VGA_BIOS_END); + PrintBoth("%x to %x - VMXASSIST\n",FINAL_VMXASSIST_START,FINAL_VMXASSIST_END); + PrintBoth("%x to %x - BIOS (2nd copy)\n",FINAL_BIOS2_START,FINAL_BIOS2_END); + PrintBoth("%x to %x - IDT\n",IDT_LOCATION,TSS_LOCATION-1); + PrintBoth("%x to %x - TSS\n",TSS_LOCATION,GDT_LOCATION-1); + PrintBoth("%x to %x - GDT\n",GDT_LOCATION,TOP_OF_MEM-1); + +} + +/* + * Initialize the .bss section of the kernel executable image. + */ +void Init_BSS(void) +{ + extern char BSS_START, BSS_END; + + /* Fill .bss with zeroes */ + memset(&BSS_START, '\0', &BSS_END - &BSS_START); + PrintBoth("BSS Inited, BSS_START=%x, BSS_END=%x\n",BSS_START,BSS_END); +} + +/* + * Allocate a page of physical memory. + */ +void* Alloc_Page(void) +{ + struct Page* page; + void *result = 0; + + bool iflag = Begin_Int_Atomic(); + + /* See if we have a free page */ + if (!Is_Page_List_Empty(&s_freeList)) { + /* Remove the first page on the freelist. */ + page = Get_Front_Of_Page_List(&s_freeList); + KASSERT((page->flags & PAGE_ALLOCATED) == 0); + Remove_From_Front_Of_Page_List(&s_freeList); + + /* Mark page as having been allocated. */ + page->flags |= PAGE_ALLOCATED; + g_freePageCount--; + result = (void*) Get_Page_Address(page); + } + + End_Int_Atomic(iflag); + + return result; +} + +/* + * Free a page of physical memory. + */ +void Free_Page(void* pageAddr) +{ + ulong_t addr = (ulong_t) pageAddr; + struct Page* page; + bool iflag; + + iflag = Begin_Int_Atomic(); + + KASSERT(Is_Page_Multiple(addr)); + + /* Get the Page object for this page */ + page = Get_Page(addr); + KASSERT((page->flags & PAGE_ALLOCATED) != 0); + + /* Clear the allocation bit */ + page->flags &= ~(PAGE_ALLOCATED); + + /* Put the page back on the freelist */ + Add_To_Back_Of_Page_List(&s_freeList, page); + g_freePageCount++; + + End_Int_Atomic(iflag); +} diff --git a/palacios/src/geekos/paging.c b/palacios/src/geekos/paging.c new file mode 100644 index 0000000..bb19af3 --- /dev/null +++ b/palacios/src/geekos/paging.c @@ -0,0 +1,431 @@ +/* + * Paging (virtual memory) support + * Copyright (c) 2003, Jeffrey K. Hollingsworth + * Copyright (c) 2003,2004 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include +#include +#include +#include +#include + +/* ---------------------------------------------------------------------- + * Public data + * ---------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + * Private functions/data + * ---------------------------------------------------------------------- */ + +#define SECTORS_PER_PAGE (PAGE_SIZE / SECTOR_SIZE) + +/* + * flag to indicate if debugging paging code + */ +int debugFaults = 0; +#define Debug(args...) if (debugFaults) Print(args) + + + +void SerialPrintPD(pde_t *pde) +{ + int i; + + SerialPrint("Page Directory at %p:\n",pde); + for (i=0;i %p : present=%x, flags=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n", + virtual_address, + (void*) (pde->pageTableBaseAddr << PAGE_POWER), + pde->present, + pde->flags, + pde->accessed, + pde->reserved, + pde->largePages, + pde->globalPage, + pde->kernelInfo); +} + +void SerialPrintPTE(void *virtual_address, pte_t *pte) +{ + SerialPrint("PTE %p -> %p : present=%x, flags=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, kernelInfo=%x\n", + virtual_address, + (void*)(pte->pageBaseAddr << PAGE_POWER), + pte->present, + pte->flags, + pte->accessed, + pte->dirty, + pte->pteAttribute, + pte->globalPage, + pte->kernelInfo); +} + + +void SerialDumpPageTables(pde_t *pde) +{ + int i; + + SerialPrint("Dumping the pages starting with the pde page at %p\n",pde); + + for (i=0;ipid, address, g_freePageCount); + if (faultCode.protectionViolation) + SerialPrintLevel(100," Protection Violation, "); + else + SerialPrintLevel(100," Non-present page, "); + if (faultCode.writeFault) + SerialPrintLevel(100,"Write Fault, "); + else + SerialPrintLevel(100,"Read Fault, "); + if (faultCode.userModeFault) + SerialPrintLevel(100,"in User Mode\n"); + else + SerialPrintLevel(100,"in Supervisor Mode\n"); +} + +/* + * Handler for page faults. + * You should call the Install_Interrupt_Handler() function to + * register this function as the handler for interrupt 14. + */ +/*static*/ void Page_Fault_Handler(struct Interrupt_State* state) +{ + ulong_t address; + faultcode_t faultCode; + + KASSERT(!Interrupts_Enabled()); + + /* Get the address that caused the page fault */ + address = Get_Page_Fault_Address(); + Debug("Page fault @%lx\n", address); + + /* Get the fault code */ + faultCode = *((faultcode_t *) &(state->errorCode)); + + /* rest of your handling code here */ + SerialPrintLevel(100,"Unexpected Page Fault received\n"); + Print_Fault_Info(address, faultCode); + Dump_Interrupt_State(state); + SerialPrint_VMCS_ALL(); + /* user faults just kill the process */ + if (!faultCode.userModeFault) KASSERT(0); + + /* For now, just kill the thread/process. */ + Exit(-1); +} + +/* ---------------------------------------------------------------------- + * Public functions + * ---------------------------------------------------------------------- */ + + + +/* + * Initialize virtual memory by building page tables + * for the kernel and physical memory. + */ +void Init_VM(struct Boot_Info *bootInfo) +{ + int numpages; + int numpagetables; + int i,j; + + pde_t *pd; + pte_t *pt; + + PrintBoth("Intitialing Virtual Memory\n"); + + if (checkPaging()) { + SerialPrintLevel(100,"Paging is currently ON\n"); + return ; + } + + SerialPrintLevel(100,"Paging is currently OFF - initializing the pages for a 1-1 map\n"); + + numpages=bootInfo->memSizeKB / (PAGE_SIZE/1024); + numpagetables = numpages / NUM_PAGE_TABLE_ENTRIES + ((numpages % NUM_PAGE_TABLE_ENTRIES) != 0 ); + + SerialPrintLevel(100,"We need %d pages, and thus %d page tables, and one page directory\n",numpages, numpagetables); + + pd = (pde_t*)Alloc_Page(); + + if (!pd) { + SerialPrintLevel(100,"We are giving up since we can't allocate a page directory!\n"); + return; + } else { + SerialPrintLevel(100,"Our PDE is at physical address %p\n",pd); + } + + for (i=0;i=numpagetables) { + pd[i].present=0; + pd[i].flags=0; + pd[i].accessed=0; + pd[i].reserved=0; + pd[i].largePages=0; + pd[i].globalPage=0; + pd[i].kernelInfo=0; + pd[i].pageTableBaseAddr=0; + } else { + pt = (pte_t*)Alloc_Page(); + if (!pt) { + SerialPrintLevel(100,"We are giving up since we can't allocate page table %d\n",i); + } else { + //SerialPrintLevel(100,"Page Table %d is at physical address %p\n",i,pt); + } + pd[i].present=1; + pd[i].flags= VM_READ | VM_WRITE | VM_EXEC | VM_USER; + pd[i].accessed=0; + pd[i].reserved=0; + pd[i].largePages=0; + pd[i].globalPage=0; + pd[i].kernelInfo=0; + pd[i].pageTableBaseAddr = PAGE_ALLIGNED_ADDR(pt); + + for (j=0;j= numpages) { + pt[j].present=0; + pt[j].flags=0; + pt[j].accessed=0; + pt[j].dirty=0; + pt[j].pteAttribute=0; + pt[j].globalPage=0; + pt[j].kernelInfo=0; + pt[j].pageBaseAddr=0; + } else { + pt[j].present=1; + pt[j].flags=VM_READ | VM_WRITE | VM_EXEC | VM_USER; + pt[j].accessed=0; + pt[j].dirty=0; + pt[j].pteAttribute=0; + pt[j].globalPage=0; + pt[j].kernelInfo=0; + pt[j].pageBaseAddr=(i*NUM_PAGE_TABLE_ENTRIES + j); + } + } + } + } + SerialPrintLevel(100,"Done creating 1<->1 initial page tables\n"); + SerialPrintLevel(100,"Now installing page fault handler\n"); + // SerialDumpPageTables(pd); + Install_Interrupt_Handler(14,Page_Fault_Handler); + SerialPrintLevel(100,"Now turning on the paging bit!\n"); + Enable_Paging(pd); + SerialPrintLevel(100,"We are still alive after paging turned on!\n"); + SerialPrintLevel(100,"checkPaging returns %d\n",checkPaging()); +} + + +// +pte_t *LookupPage(void *vaddr) +{ + uint_t pde_offset = ((uint_t)vaddr) >> 22; + uint_t pte_offset = (((uint_t)vaddr) >> 12) & 0x3ff; + pte_t *pte; + pde_t *pde = Get_PDBR(); + + KASSERT(pde); + + pde+=pde_offset; + + if (!(pde->present)) { + return 0; + } + + pte = (pte_t *)((pde->pageTableBaseAddr)<<12); + + pte+=pte_offset; + + return pte; +} + + +pte_t *CreateAndAddPageTable(void *vaddr, uint_t flags) +{ + int i; + + KASSERT(!(PAGE_OFFSET(vaddr))); + + pte_t *pt = Alloc_Page(); + + KASSERT(pt); + + for (i=0;ipresent)); + + pde->present=1; + pde->flags=flags; + pde->accessed=0; + pde->reserved=0; + pde->largePages=0; + pde->globalPage=0; + pde->kernelInfo=0; + pde->pageTableBaseAddr = PAGE_ALLIGNED_ADDR(pt); + + return pt; +} + +pte_t *MapPage(void *vaddr, pte_t *pte, int alloc_pde) +{ + pte_t *oldpte = LookupPage(vaddr); + + if (!pte) { + if (alloc_pde) { + CreateAndAddPageTable(vaddr,pte->flags); + oldpte = LookupPage(vaddr); + KASSERT(pte); + } else { + return 0; + } + } + + *oldpte = *pte; + + return oldpte; +} + +pte_t *UnMapPage(void *vaddr) +{ + pte_t *oldpte = LookupPage(vaddr); + + if (!oldpte) { + return 0; + } + oldpte->present=0; + + return oldpte; +} + + + +/** + * Initialize paging file data structures. + * All filesystems should be mounted before this function + * is called, to ensure that the paging file is available. + */ +void Init_Paging(void) +{ + PrintBoth("Initializing Paging\n"); +} + +/** + * Find a free bit of disk on the paging file for this page. + * Interrupts must be disabled. + * @return index of free page sized chunk of disk space in + * the paging file, or -1 if the paging file is full + */ +int Find_Space_On_Paging_File(void) +{ + KASSERT(!Interrupts_Enabled()); + TODO("Find free page in paging file"); +} + +/** + * Free a page-sized chunk of disk space in the paging file. + * Interrupts must be disabled. + * @param pagefileIndex index of the chunk of disk space + */ +void Free_Space_On_Paging_File(int pagefileIndex) +{ + KASSERT(!Interrupts_Enabled()); + TODO("Free page in paging file"); +} + +/** + * Write the contents of given page to the indicated block + * of space in the paging file. + * @param paddr a pointer to the physical memory of the page + * @param vaddr virtual address where page is mapped in user memory + * @param pagefileIndex the index of the page sized chunk of space + * in the paging file + */ +void Write_To_Paging_File(void *paddr, ulong_t vaddr, int pagefileIndex) +{ + struct Page *page = Get_Page((ulong_t) paddr); + KASSERT(!(page->flags & PAGE_PAGEABLE)); /* Page must be locked! */ + TODO("Write page data to paging file"); +} + +/** + * Read the contents of the indicated block + * of space in the paging file into the given page. + * @param paddr a pointer to the physical memory of the page + * @param vaddr virtual address where page will be re-mapped in + * user memory + * @param pagefileIndex the index of the page sized chunk of space + * in the paging file + */ +void Read_From_Paging_File(void *paddr, ulong_t vaddr, int pagefileIndex) +{ + struct Page *page = Get_Page((ulong_t) paddr); + KASSERT(!(page->flags & PAGE_PAGEABLE)); /* Page must be locked! */ + TODO("Read page data from paging file"); +} + diff --git a/palacios/src/geekos/reboot.c b/palacios/src/geekos/reboot.c new file mode 100644 index 0000000..08f307d --- /dev/null +++ b/palacios/src/geekos/reboot.c @@ -0,0 +1,161 @@ +#include +#include +// from linux... + + +#define RTC_PORT(x) (0x70 + (x)) + +/* The following code and data reboots the machine by switching to real + mode and jumping to the BIOS reset entry point, as if the CPU has + really been reset. The previous version asked the keyboard + controller to pulse the CPU reset line, which is more thorough, but + doesn't work with at least one type of 486 motherboard. It is easy + to stop this code working; hence the copious comments. */ + +static unsigned long long +real_mode_gdt_entries [3] = +{ + 0x0000000000000000ULL, /* Null descriptor */ + 0x00009a000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ + 0x000092000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ +}; + +static struct +{ + unsigned short size __attribute__ ((packed)); + unsigned long long * base __attribute__ ((packed)); +} +real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries }, + real_mode_idt = { 0x3ff, 0 }; +//no_idt = { 0, 0 }; + + + +static unsigned char real_mode_switch [] = +{ + 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ + 0x66, 0x83, 0xe0, 0x11, /* andl $0x00000011,%eax */ + 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60, /* orl $0x60000000,%eax */ + 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */ + 0x66, 0x0f, 0x22, 0xd8, /* movl %eax,%cr3 */ + 0x66, 0x0f, 0x20, 0xc3, /* movl %cr0,%ebx */ + 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /* andl $0x60000000,%ebx */ + 0x74, 0x02, /* jz f */ + 0x0f, 0x09, /* wbinvd */ + 0x24, 0x10, /* f: andb $0x10,al */ + 0x66, 0x0f, 0x22, 0xc0 /* movl %eax,%cr0 */ +}; +static unsigned char jump_to_bios [] = +{ + 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */ +}; + + +/* + * Switch to real mode and then execute the code + * specified by the code and length parameters. + * We assume that length will aways be less that 100! + */ +void machine_real_restart() { + // unsigned long flags; + + unsigned short rtp1, rtp2; + unsigned char val1, val2; + + //JRL// local_irq_disable(); + + /* Write zero to CMOS register number 0x0f, which the BIOS POST + routine will recognize as telling it to do a proper reboot. (Well + that's what this book in front of me says -- it may only apply to + the Phoenix BIOS though, it's not clear). At the same time, + disable NMIs by setting the top bit in the CMOS address register, + as we're about to do peculiar things to the CPU. I'm not sure if + `outb_p' is needed instead of just `outb'. Use it to be on the + safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) + */ + +//JRL// spin_lock_irqsave(&rtc_lock, flags); +//JRL// CMOS_WRITE(0x00, 0x8f); + val1 = 0x8f; + val2 = 0x00; + rtp1 = RTC_PORT(0); + rtp2 = RTC_PORT(1); + + // outb_p(0x8f, RTC_PORT(0)); + // outb_p(0x00, RTC_PORT(1)); + + __asm__ __volatile__ ( + "outb %b0, %w1" + : + : "a" (val1), "Nd" (rtp1) + ); + + __asm__ __volatile__ ( + "outb %b0, %w1" + : + : "a" (val2), "Nd" (rtp2) + ); + +//JRL// spin_unlock_irqrestore(&rtc_lock, flags); + + /* Remap the kernel at virtual address zero, as well as offset zero + from the kernel segment. This assumes the kernel segment starts at + virtual address PAGE_OFFSET. */ + +//JRL// memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, +//JRL// sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS); + + /* + * Use `swapper_pg_dir' as our page directory. + */ +//JRL// load_cr3(swapper_pg_dir); + + /* Write 0x1234 to absolute memory location 0x472. The BIOS reads + this on booting to tell it to "Bypass memory test (also warm + boot)". This seems like a fairly standard thing that gets set by + REBOOT.COM programs, and the previous reset routine did this + too. */ + + *((unsigned short *)0x472) = 0x1234; + + /* For the switch to real mode, copy some code to low memory. It has + to be in the first 64k because it is running in 16-bit mode, and it + has to have the same physical and virtual address, because it turns + off paging. Copy it near the end of the first page, out of the way + of BIOS variables. */ + + memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100), + real_mode_switch, sizeof (real_mode_switch)); + memcpy ((void *) (0x1000 - 100), jump_to_bios, sizeof(jump_to_bios)); + + /* Set up the IDT for real mode. */ + + __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt)); + + /* Set up a GDT from which we can load segment descriptors for real + mode. The GDT is not used in real mode; it is just needed here to + prepare the descriptors. */ + + __asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt)); + + /* Load the data segment registers, and thus the descriptors ready for + real mode. The base address of each segment is 0x100, 16 times the + selector value being loaded here. This is so that the segment + registers don't have to be reloaded after switching to real mode: + the values are consistent for real mode operation already. */ + + __asm__ __volatile__ ("movl $0x0010,%%eax\n" + "\tmovl %%eax,%%ds\n" + "\tmovl %%eax,%%es\n" + "\tmovl %%eax,%%fs\n" + "\tmovl %%eax,%%gs\n" + "\tmovl %%eax,%%ss" : : : "eax"); + + /* Jump to the 16-bit code that we copied earlier. It disables paging + and the cache, switches to real mode, and jumps to the BIOS reset + entry point. */ + + __asm__ __volatile__ ("ljmp $0x0008,%0" + : + : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); +} diff --git a/palacios/src/geekos/screen.c b/palacios/src/geekos/screen.c new file mode 100644 index 0000000..9c78dde --- /dev/null +++ b/palacios/src/geekos/screen.c @@ -0,0 +1,533 @@ +/* + * GeekOS text screen output + * Copyright (c) 2001,2003,2004 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Information sources for VT100 and ANSI escape sequences: + * - http://www.lns.cornell.edu/~pvhp/dcl/vt100.html + * - http://en.wikipedia.org/wiki/ANSI_escape_code + */ + +/* ---------------------------------------------------------------------- + * Private functions and data + * ---------------------------------------------------------------------- */ + +#define ESC ((char) 0x1B) +#define DEFAULT_ATTRIBUTE ATTRIB(BLACK, GRAY) + +enum State { + S_NORMAL, /* Normal state - output is echoed verbatim */ + S_ESC, /* Saw ESC character - begin output escape sequence */ + S_ESC2, /* Saw '[' character - continue output escape sequence */ + S_ARG, /* Scanning a numeric argument */ + S_CMD, /* Command */ +}; + +#define MAXARGS 8 /* Max args that can be passed to esc sequence */ + +struct Console_State { + /* Current state information */ + int row, col; + int saveRow, saveCol; + uchar_t currentAttr; + + /* Working variables for processing escape sequences. */ + enum State state; + int argList[MAXARGS]; + int numArgs; +}; + +static struct Console_State s_cons; + +#define NUM_SCREEN_DWORDS ((NUMROWS * NUMCOLS * 2) / 4) +#define NUM_SCROLL_DWORDS (((NUMROWS-1) * NUMCOLS * 2) / 4) +#define NUM_DWORDS_PER_LINE ((NUMCOLS*2)/4) +#define FILL_DWORD (0x00200020 | (s_cons.currentAttr<<24) | (s_cons.currentAttr<<8)) + +/* + * Scroll the display one line. + * We speed things up by copying 4 bytes at a time. + */ +static void Scroll(void) +{ + uint_t* v; + int i, n = NUM_SCROLL_DWORDS; + uint_t fill = FILL_DWORD; + + /* Move lines 1..NUMROWS-1 up one position. */ + for (v = (uint_t*)VIDMEM, i = 0; i < n; ++i) { + *v = *(v + NUM_DWORDS_PER_LINE); + ++v; + } + + /* Clear out last line. */ + for (v = (uint_t*)VIDMEM + n, i = 0; i < NUM_DWORDS_PER_LINE; ++i) + *v++ = fill; +} + +/* + * Clear current cursor position to end of line using + * current attribute. + */ +static void Clear_To_EOL(void) +{ + int n = (NUMCOLS - s_cons.col); + uchar_t* v = VIDMEM + s_cons.row*(NUMCOLS*2) + s_cons.col*2; + while (n-- > 0) { + *v++ = ' '; + *v++ = s_cons.currentAttr; + } +} + +/* + * Move to the beginning of the next line, scrolling + * if necessary. + */ +static void Newline(void) +{ + ++s_cons.row; + s_cons.col = 0; + if (s_cons.row == NUMROWS) { + Scroll(); + s_cons.row = NUMROWS - 1; + } +} + +/* + * Write the graphic representation of given character to the screen + * at current position, with current attribute, scrolling if + * necessary. + */ +static void Put_Graphic_Char(int c) +{ + uchar_t* v = VIDMEM + s_cons.row*(NUMCOLS*2) + s_cons.col*2; + + /* Put character at current position */ + *v++ = (uchar_t) c; + *v = s_cons.currentAttr; + + if (s_cons.col < NUMCOLS - 1) + ++s_cons.col; + else + Newline(); +} + +/* + * Put one character to the screen using the current cursor position + * and attribute, scrolling if needed. The caller should update + * the cursor position once all characters have been written. + */ +static void Output_Literal_Character(int c) +{ + int numSpaces; + + switch (c) { + case '\n': + Clear_To_EOL(); + Newline(); + break; + + case '\t': + numSpaces = TABWIDTH - (s_cons.col % TABWIDTH); + while (numSpaces-- > 0) + Put_Graphic_Char(' '); + break; + + default: + Put_Graphic_Char(c); + break; + } + +#ifndef NDEBUG + /* + * When compiled with --enable-port-e9-hack, Bochs will send writes + * to port E9 to the console. This helps tremendously with debugging, + * because it allows debug Print() statements to be visible after + * Bochs has exited. + */ + Out_Byte(0xE9, c); +#endif +} + +/* + * Move the cursor to a new position, stopping at the screen borders. + */ +static void Move_Cursor(int row, int col) +{ + if (row < 0) + row = 0; + else if (row >= NUMROWS) + row = NUMROWS - 1; + + if (col < 0) + col = 0; + else if (col >= NUMCOLS) + col = NUMCOLS - 1; + + s_cons.row = row; + s_cons.col = col; +} + +/* + * Table mapping ANSI colors to VGA text mode colors. + */ +static const uchar_t s_ansiToVgaColor[] = { + BLACK,RED,GREEN,AMBER,BLUE,MAGENTA,CYAN,GRAY +}; + +/* + * Update the attributes specified by the arguments + * of the escape sequence. + */ +static void Update_Attributes(void) +{ + int i; + int attr = s_cons.currentAttr & ~(BRIGHT); + + for (i = 0; i < s_cons.numArgs; ++i) { + int value = s_cons.argList[i]; + if (value == 0) + attr = DEFAULT_ATTRIBUTE; + else if (value == 1) + attr |= BRIGHT; + else if (value >= 30 && value <= 37) + attr = (attr & ~0x7) | s_ansiToVgaColor[value - 30]; + else if (value >= 40 && value <= 47) + attr = (attr & ~(0x7 << 4)) | (s_ansiToVgaColor[value - 40] << 4); + } + s_cons.currentAttr = attr; +} + +/* Reset to cancel or finish processing an escape sequence. */ +static void Reset(void) +{ + s_cons.state = S_NORMAL; + s_cons.numArgs = 0; +} + +/* Start an escape sequence. */ +static void Start_Escape(void) +{ + s_cons.state = S_ESC; + s_cons.numArgs = 0; +} + +/* Start a numeric argument to an escape sequence. */ +static void Start_Arg(int argNum) +{ + KASSERT(s_cons.numArgs == argNum); + s_cons.numArgs++; + s_cons.state = S_ARG; + if (argNum < MAXARGS) + s_cons.argList[argNum] = 0; +} + +/* Save current cursor position. */ +static void Save_Cursor(void) +{ + s_cons.saveRow = s_cons.row; + s_cons.saveCol = s_cons.col; +} + +/* Restore saved cursor position. */ +static void Restore_Cursor(void) +{ + s_cons.row = s_cons.saveRow; + s_cons.col = s_cons.saveCol; +} + +/* Add a digit to current numeric argument. */ +static void Add_Digit(int c) +{ + KASSERT(ISDIGIT(c)); + if (s_cons.numArgs < MAXARGS) { + int argNum = s_cons.numArgs - 1; + s_cons.argList[argNum] *= 10; + s_cons.argList[argNum] += (c - '0'); + } +} + +/* + * Get a numeric argument. + * Returns zero if that argument was not actually specified. + */ +static int Get_Arg(int argNum) +{ + return argNum < s_cons.numArgs ? s_cons.argList[argNum] : 0; +} + +/* + * The workhorse output function. + * Depending on the current console output state, + * does literal character output or processes part of + * an escape sequence. + */ +static void Put_Char_Imp(int c) +{ +again: + switch (s_cons.state) { + case S_NORMAL: + if (c == ESC) + Start_Escape(); + else + Output_Literal_Character(c); + break; + + case S_ESC: + if (c == '[') + s_cons.state = S_ESC2; + else + Reset(); + break; + + case S_ESC2: + if (ISDIGIT(c)) { + Start_Arg(0); + goto again; + } else if (c == ';') { + /* Special case: for "n;m" commands, "n" is implicitly 1 if omitted */ + Start_Arg(0); + Add_Digit('1'); + Start_Arg(1); + } else { + s_cons.state = S_CMD; + goto again; + } + break; + + case S_ARG: + if (ISDIGIT(c)) + Add_Digit(c); + else if (c == ';') + Start_Arg(s_cons.numArgs); + else { + s_cons.state = S_CMD; + goto again; + } + break; + + case S_CMD: + switch (c) { + case 'K': Clear_To_EOL(); break; + case 's': Save_Cursor(); break; + case 'u': Restore_Cursor(); break; + case 'A': Move_Cursor(s_cons.row - Get_Arg(0), s_cons.col); break; + case 'B': Move_Cursor(s_cons.row + Get_Arg(0), s_cons.col); break; + case 'C': Move_Cursor(s_cons.row, s_cons.col + Get_Arg(0)); break; + case 'D': Move_Cursor(s_cons.row, s_cons.col - Get_Arg(0)); break; + case 'm': Update_Attributes(); break; + case 'f': case 'H': + if (s_cons.numArgs == 2) Move_Cursor(Get_Arg(0)-1, Get_Arg(1)-1); break; + case 'J': + if (s_cons.numArgs == 1 && Get_Arg(0) == 2) { + Clear_Screen(); + Put_Cursor(0, 0); + } + break; + default: break; + } + Reset(); + break; + + default: + KASSERT(false); + } +} + +/* + * Update the location of the hardware cursor. + */ +static void Update_Cursor(void) +{ + /* + * The cursor location is a character offset from the beginning + * of page memory (I think). + */ + uint_t characterPos = (s_cons.row * NUMCOLS) + s_cons.col; + uchar_t origAddr; + + /* + * Save original contents of CRT address register. + * It is considered good programming practice to restore + * it to its original value after modifying it. + */ + origAddr = In_Byte(CRT_ADDR_REG); + IO_Delay(); + + /* Set the high cursor location byte */ + Out_Byte(CRT_ADDR_REG, CRT_CURSOR_LOC_HIGH_REG); + IO_Delay(); + Out_Byte(CRT_DATA_REG, (characterPos>>8) & 0xff); + IO_Delay(); + + /* Set the low cursor location byte */ + Out_Byte(CRT_ADDR_REG, CRT_CURSOR_LOC_LOW_REG); + IO_Delay(); + Out_Byte(CRT_DATA_REG, characterPos & 0xff); + IO_Delay(); + + /* Restore contents of the CRT address register */ + Out_Byte(CRT_ADDR_REG, origAddr); +} + +/* ---------------------------------------------------------------------- + * Public functions + * ---------------------------------------------------------------------- */ + +/* + * Initialize the screen module. + */ +void Init_Screen(void) +{ + bool iflag = Begin_Int_Atomic(); + + s_cons.row = s_cons.col = 0; + s_cons.currentAttr = DEFAULT_ATTRIBUTE; + Clear_Screen(); + + End_Int_Atomic(iflag); + Print("Screen Inited\n"); +} + +/* + * Clear the screen using the current attribute. + */ +void Clear_Screen(void) +{ + uint_t* v = (uint_t*)VIDMEM; + int i; + uint_t fill = FILL_DWORD; + + bool iflag = Begin_Int_Atomic(); + + for (i = 0; i < NUM_SCREEN_DWORDS; ++i) + *v++ = fill; + + End_Int_Atomic(iflag); +} + +/* + * Get current cursor position. + */ +void Get_Cursor(int* row, int* col) +{ + bool iflag = Begin_Int_Atomic(); + *row = s_cons.row; + *col = s_cons.col; + End_Int_Atomic(iflag); +} + +/* + * Set the current cursor position. + * Return true if successful, or false if the specified + * cursor position is invalid. + */ +bool Put_Cursor(int row, int col) +{ + bool iflag; + + if (row < 0 || row >= NUMROWS || col < 0 || col >= NUMCOLS) + return false; + + iflag = Begin_Int_Atomic(); + s_cons.row = row; + s_cons.col = col; + Update_Cursor(); + End_Int_Atomic(iflag); + + return true; +} + +/* + * Get the current character attribute. + */ +uchar_t Get_Current_Attr(void) +{ + return s_cons.currentAttr; +} + +/* + * Set the current character attribute. + */ +void Set_Current_Attr(uchar_t attrib) +{ + bool iflag = Begin_Int_Atomic(); + s_cons.currentAttr = attrib; + End_Int_Atomic(iflag); +} + +/* + * Write a single character to the screen at current position + * using current attribute, handling scrolling, special characters, etc. + */ +void Put_Char(int c) +{ + bool iflag = Begin_Int_Atomic(); + Put_Char_Imp(c); + Update_Cursor(); + End_Int_Atomic(iflag); +} + +/* + * Write a string of characters to the screen at current cursor + * position using current attribute. + */ +void Put_String(const char* s) +{ + bool iflag = Begin_Int_Atomic(); + while (*s != '\0') + Put_Char_Imp(*s++); + Update_Cursor(); + End_Int_Atomic(iflag); +} + +/* + * Write a buffer of characters at current cursor position + * using current attribute. + */ +void Put_Buf(const char* buf, ulong_t length) +{ + bool iflag = Begin_Int_Atomic(); + while (length > 0) { + Put_Char_Imp(*buf++); + --length; + } + Update_Cursor(); + End_Int_Atomic(iflag); +} + +/* Support for Print(). */ +static void Print_Emit(struct Output_Sink *o, int ch) { Put_Char_Imp(ch); } +static void Print_Finish(struct Output_Sink *o) { Update_Cursor(); } +static struct Output_Sink s_outputSink = { &Print_Emit, &Print_Finish }; + +/* + * Print to console using printf()-style formatting. + * Calls into Format_Output in common library. + */ +void Print(const char *fmt, ...) +{ + va_list args; + + bool iflag = Begin_Int_Atomic(); + + va_start(args, fmt); + Format_Output(&s_outputSink, fmt, args); + va_end(args); + + End_Int_Atomic(iflag); +} + diff --git a/palacios/src/geekos/segment.c b/palacios/src/geekos/segment.c new file mode 100644 index 0000000..4e83db0 --- /dev/null +++ b/palacios/src/geekos/segment.c @@ -0,0 +1,138 @@ +/* + * General data structures and routines for segmentation + * Copyright (c) 2001, David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +/* + * Source: _Protected Mode Software Architecture_ by Tom Shanley, + * ISBN 020155447X. + */ + +#include +#include +#include +#include + +static __inline__ void Set_Size_And_Base_Pages( + struct Segment_Descriptor* desc, + ulong_t baseAddr, + ulong_t numPages +) +{ + /* + * There are 20 bits in the size fields of a segment descriptor. + * The maximum possible value is thus 0xFFFFF, which in terms of + * pages is one page less than 4GB. So, I conclude that the + * number of pages in the segment is one greater than the + * value specified in the descriptor. + */ + KASSERT(numPages > 0); + numPages -= 1; + + desc->sizeLow = numPages & 0xFFFF; + desc->sizeHigh = (numPages >> 16) & 0x0F; + desc->baseLow = baseAddr & 0xFFFFFF; + desc->baseHigh = (baseAddr >> 24) & 0xFF; + desc->granularity = 1; /* size in pages */ +} + +static __inline__ void Set_Size_And_Base_Bytes( + struct Segment_Descriptor* desc, + ulong_t baseAddr, + ulong_t numBytes +) +{ + desc->sizeLow = numBytes & 0xFFFF; + desc->sizeHigh = (numBytes >> 16) & 0x0F; + desc->baseLow = baseAddr & 0xFFFFFF; + desc->baseHigh = (baseAddr >> 24) & 0xFF; + desc->granularity = 0; /* size in bytes */ +} + +/* + * Initialize an unused segment descriptor. + */ +void Init_Null_Segment_Descriptor(struct Segment_Descriptor* desc) +{ + memset(desc, '\0', sizeof(*desc)); +} + +/* + * Initialize a code segment descriptor. + */ +void Init_Code_Segment_Descriptor( + struct Segment_Descriptor* desc, + ulong_t baseAddr, + ulong_t numPages, + int privilegeLevel +) +{ + KASSERT(privilegeLevel >= 0 && privilegeLevel <= 3); + + Set_Size_And_Base_Pages(desc, baseAddr, numPages); + desc->type = 0x0A; /* 1010b: code, !conforming, readable, !accessed */ + desc->system = 1; + desc->dpl = privilegeLevel; + desc->present = 1; + desc->reserved = 0; + desc->dbBit = 1; /* 32 bit code segment */ +} + +/* + * Initialize a data segment descriptor. + */ +void Init_Data_Segment_Descriptor( + struct Segment_Descriptor* desc, + ulong_t baseAddr, + ulong_t numPages, + int privilegeLevel +) +{ + KASSERT(privilegeLevel >= 0 && privilegeLevel <= 3); + + Set_Size_And_Base_Pages(desc, baseAddr, numPages); + desc->type = 0x02; /* 0010b: data, expand-up, writable, !accessed */ + desc->system = 1; + desc->dpl = privilegeLevel; + desc->present = 1; + desc->reserved = 0; + desc->dbBit = 1; /* 32 bit operands */ +} + +/* + * Initialize a TSS descriptor. + */ +void Init_TSS_Descriptor(struct Segment_Descriptor* desc, struct TSS* theTSS) +{ + Set_Size_And_Base_Bytes(desc, (ulong_t) theTSS, sizeof(struct TSS)); + desc->type = 0x09; /* 1001b: 32 bit, !busy */ + desc->system = 0; + desc->dpl = 0; + desc->present = 1; + desc->reserved = 0; + desc->dbBit = 0; /* must be 0 in TSS */ +} + +/* + * Initialize an LDT (Local Descriptor Table) descriptor. + */ +void Init_LDT_Descriptor( + struct Segment_Descriptor* desc, + struct Segment_Descriptor theLDT[], + int numEntries +) +{ + Set_Size_And_Base_Bytes( + desc, (ulong_t) theLDT, sizeof(struct Segment_Descriptor) * numEntries); + + desc->type = 0x02; /* 0010b */ + desc->system = 0; + desc->dpl = 0; + desc->present = 1; + desc->reserved = 0; + desc->dbBit = 0; +} diff --git a/palacios/src/geekos/serial.c b/palacios/src/geekos/serial.c new file mode 100644 index 0000000..68ef275 --- /dev/null +++ b/palacios/src/geekos/serial.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include + + + + +unsigned short serial_io_addr = 0; + + +static void Serial_Interrupt_Handler(struct Interrupt_State * state) { + char rcv_byte; + char irq_id; + + Begin_IRQ(state); + + irq_id = In_Byte(serial_io_addr + 2); + + + if ((irq_id & 0x04) != 0) { + rcv_byte = In_Byte(serial_io_addr + 0); + + if (rcv_byte == 'k') { + SerialPrint("Restarting Machine\r\n"); + machine_real_restart(); + } else if (rcv_byte=='d') { + SerialPrint("Dumping Machine State\n"); + Dump_Interrupt_State(state); + DumpIDT(); + DumpGDT(); + } + +#if 0 + SerialPrint("Unreserved serial byte: %d (%c)\r\n", rcv_byte, rcv_byte); +#endif + } + End_IRQ(state); +} + +void InitSerial() { + Print("Initialzing Serial\n"); + Install_IRQ(COM1_IRQ, Serial_Interrupt_Handler); + Enable_IRQ(COM1_IRQ); + InitSerialAddr(DEFAULT_SERIAL_ADDR); +} + +void InitSerialAddr(unsigned short io_addr) { + serial_io_addr = io_addr; + + Print("Initializing Polled Serial Output on COM1 - 115200 N81 noflow\n"); + // io_adr = 0x3F8; /* 3F8=COM1, 2F8=COM2, 3E8=COM3, 2E8=COM4 */ + Out_Byte(io_addr + 3, 0x80); + // 115200 /* 115200 / 12 = 9600 baud */ + Out_Byte(io_addr + 0, 1); + Out_Byte(io_addr + 1, 0); + /* 8N1 */ + Out_Byte(io_addr + 3, 0x03); + /* all interrupts disabled */ + // Out_Byte(io_addr + 1, 0); + Out_Byte(io_addr + 1, 0x01); + /* turn off FIFO, if any */ + Out_Byte(io_addr + 2, 0); + /* loopback off, interrupts (Out2) off, Out1/RTS/DTR off */ + // Out_Byte(io_addr + 4, 0); + // enable interrupts (bit 3) + Out_Byte(io_addr + 4, 0x08); +} + + +inline static void SerialPutChar(unsigned char c) { + + // static unsigned short io_adr; + if (serial_io_addr==0) { + return; + } + + + if (c=='\n') { + /* wait for transmitter ready */ + while((In_Byte(serial_io_addr + 5) & 0x40) == 0) { + } + /* send char */ + Out_Byte(serial_io_addr + 0, '\r'); + /* wait for transmitter ready */ + } + while((In_Byte(serial_io_addr + 5) & 0x40) == 0) { + } + /* send char */ + Out_Byte(serial_io_addr + 0, c); +} + + + +void SerialPutLineN(char * line, int len) { + int i; + for (i = 0; i < len && line[i] != 0; i++) { + SerialPutChar(line[i]); + } +} + + +void SerialPutLine(char * line) { + int i; + for (i = 0; line[i]!= 0; i++) { + SerialPutChar(line[i]); + } +} + + +void SerialPrintHex(unsigned char x) +{ + unsigned char z; + + z = (x>>4) & 0xf ; + SerialPrint("%x", z); + z = x & 0xf; + SerialPrint("%x", z); +} + +void SerialMemDump(unsigned char *start, int n) +{ + int i, j; + + for (i=0;i=32) && (start[j]<=126)) ? start[j] : '.'); + } + SerialPrint("\n"); + } +} diff --git a/palacios/src/geekos/setup.asm b/palacios/src/geekos/setup.asm new file mode 100644 index 0000000..56c9938 --- /dev/null +++ b/palacios/src/geekos/setup.asm @@ -0,0 +1,247 @@ +; -*- fundamental -*- +; GeekOS setup code +; Copyright (c) 2001,2004 David H. Hovemeyer +; $Revision: 1.1 $ + +; This is free software. You are permitted to use, +; redistribute, and modify it as specified in the file "COPYING". + +; A lot of this code is adapted from Kernel Toolkit 0.2 +; and Linux version 2.2.x, so the following copyrights apply: + +; Copyright (C) 1991, 1992 Linus Torvalds +; modified by Drew Eckhardt +; modified by Bruce Evans (bde) +; adapted for Kernel Toolkit by Luigi Sgro + +%include "defs.asm" + +[BITS 16] +[ORG 0x0] + +start_setup: + + ; Redefine the data segment so we can access variables + ; declared in this file. + mov ax, SETUPSEG + mov ds, ax + + ; Use int 15h to find out size of extended memory in KB. + ; Extended memory is the memory above 1MB. So by + ; adding 1MB to this amount, we get the total amount + ; of system memory. We can only detect 64MB this way, + ; but that's OK for now. + ;mov ah, 0x88 + ;int 0x15 + ;add ax, 1024 ; 1024 KB == 1 MB + mov ax, 0xe801 + int 0x15 + add ax, 1024 ; 1024 KB == 1 MB + mov [mem_size_kbytes], ax + mov [mem_size_eblocks], bx + + ; Kill the floppy motor. + call Kill_Motor + + ; Block interrupts, since we can't meaningfully handle them yet + ; and we no longer need BIOS services. + cli + + ; Set up IDT and GDT registers + lidt [IDT_Pointer] + lgdt [GDT_Pointer] + + ; Initialize the interrupt controllers, and enable the + ; A20 address line + call Init_PIC + call Enable_A20 + + ; Switch to protected mode! + mov ax, 0x01 + lmsw ax + + ; Jump to 32 bit code. + jmp dword KERNEL_CS:(SETUPSEG << 4) + setup_32 + +[BITS 32] +setup_32: + + ; set up data segment registers + mov ax, KERNEL_DS + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + + ; Create the stack for the initial kernel thread. + mov esp, KERN_STACK + 4096 + + ; Build Boot_Info struct on stack. + ; Note that we push the fields on in reverse order, + ; since the stack grows downwards. + xor eax, eax + mov ax, [(SETUPSEG<<4)+mem_size_kbytes] + xor ebx, ebx + mov bx, [(SETUPSEG<<4)+mem_size_eblocks] + shl ebx, 6 + add eax, ebx + push eax ; memSizeKB + push dword 8 ; bootInfoSize + + ; Pass pointer to Boot_Info struct as argument to kernel + ; entry point. + push esp + + ; Push return address to make this look like a call + ; XXX - untested + push dword (SETUPSEG<<4)+.returnAddr + + + ; Copy VMM kernel and VMM Boot Package to final location + call copy_vmm + + ; Far jump into kernel + jmp KERNEL_CS:ENTRY_POINT + +.returnAddr: + ; We shouldn't return here. +.here: jmp .here + + +copy_vmm: + pusha + + mov ebx, KERNSEG<<4 + mov ecx, VMM_FINAL_ADDR + mov edx, VMM_SIZE +repeat: + mov eax, [ebx] + mov [ecx], eax + add ebx, $4 + add ecx, $4 + sub edx, $4 + jnz repeat + + popa + + ret + + + +[BITS 16] + +; Kill the floppy motor. +; This code was shamelessly stolen from Linux. +Kill_Motor: + mov dx, 0x3f2 + xor al, al + out dx, al + ret + +Init_PIC: + ; Initialize master and slave PIC! + mov al, ICW1 + out 0x20, al ; ICW1 to master + call Delay + out 0xA0, al ; ICW1 to slave + call Delay + mov al, ICW2_MASTER + out 0x21, al ; ICW2 to master + call Delay + mov al, ICW2_SLAVE + out 0xA1, al ; ICW2 to slave + call Delay + mov al, ICW3_MASTER + out 0x21, al ; ICW3 to master + call Delay + mov al, ICW3_SLAVE + out 0xA1, al ; ICW3 to slave + call Delay + mov al, ICW4 + out 0x21, al ; ICW4 to master + call Delay + out 0xA1, al ; ICW4 to slave + call Delay + mov al, 0xff ; mask all ints in slave + out 0xA1, al ; OCW1 to slave + call Delay + mov al, 0xfb ; mask all ints but 2 in master + out 0x21, al ; OCW1 to master + call Delay + ret + +; Linux uses this code. +; The idea is that some systems issue port I/O instructions +; faster than the device hardware can deal with them. +Delay: + jmp .done +.done: ret + +; Enable the A20 address line, so we can correctly address +; memory above 1MB. +Enable_A20: + mov al, 0xD1 + out 0x64, al + call Delay + mov al, 0xDF + out 0x60, al + call Delay + ret + + +; ---------------------------------------------------------------------- +; Setup data +; ---------------------------------------------------------------------- + +mem_size_kbytes: dw 0 +mem_size_eblocks: dw 0 + +; ---------------------------------------------------------------------- +; The GDT. Creates flat 32-bit address space for the kernel +; code, data, and stack. Note that this GDT is just used +; to create an environment where we can start running 32 bit +; code. The kernel will create and manage its own GDT. +; ---------------------------------------------------------------------- + +; GDT initialization stuff +NUM_GDT_ENTRIES equ 3 ; number of entries in GDT +GDT_ENTRY_SZ equ 8 ; size of a single GDT entry + +align 8, db 0 +GDT: + ; Descriptor 0 is not used + dw 0 + dw 0 + dw 0 + dw 0 + + ; Descriptor 1: kernel code segment + dw 0xFFFF ; bytes 0 and 1 of segment size + dw 0x0000 ; bytes 0 and 1 of segment base address + db 0x00 ; byte 2 of segment base address + db 0x9A ; present, DPL=0, non-system, code, non-conforming, + ; readable, not accessed + db 0xCF ; granularity=page, 32 bit code, upper nibble of size + db 0x00 ; byte 3 of segment base address + + ; Descriptor 2: kernel data and stack segment + ; NOTE: what Intel calls an "expand-up" segment + ; actually means that the stack will grow DOWN, + ; towards lower memory. So, we can use this descriptor + ; for both data and stack references. + dw 0xFFFF ; bytes 0 and 1 of segment size + dw 0x0000 ; bytes 0 and 1 of segment base address + db 0x00 ; byte 2 of segment base address + db 0x92 ; present, DPL=0, non-system, data, expand-up, + ; writable, not accessed + db 0xCF ; granularity=page, big, upper nibble of size + db 0x00 ; byte 3 of segment base address + +GDT_Pointer: + dw NUM_GDT_ENTRIES*GDT_ENTRY_SZ ; limit + dd (SETUPSEG<<4) + GDT ; base address + +IDT_Pointer: + dw 0 + dd 00 diff --git a/palacios/src/geekos/show_sizes.c b/palacios/src/geekos/show_sizes.c new file mode 100644 index 0000000..c75d119 --- /dev/null +++ b/palacios/src/geekos/show_sizes.c @@ -0,0 +1,25 @@ +#include +#include "vmm_sizes.h" + +int main() +{ + printf("KERNEL_LOAD_ADDRESS = 0x%x\n", KERNEL_LOAD_ADDRESS); + printf("KERNEL_SETUP_LENGTH = 0x%x\n", KERNEL_SETUP_LENGTH); + printf("KERNEL_CORE_LENGTH = 0x%x\n", KERNEL_CORE_LENGTH); + printf("BIOS_START = 0x%x\n", BIOS_START); + printf("BIOS_LENGTH = 0x%x\n", BIOS_LENGTH); + printf("BIOS2_START = 0x%x\n", BIOS2_START); + printf("VGA_BIOS_START = 0x%x\n", VGA_BIOS_START); + printf("VGA_BIOS_LENGTH = 0x%x\n", VGA_BIOS_LENGTH); + printf("VMXASSIST_START = 0x%x\n", VMXASSIST_START); + printf("VMXASSIST_LENGTH = 0x%x\n", VMXASSIST_LENGTH); + printf("\n"); + printf("KERNEL_START = 0x%x\n", KERNEL_START); + printf("KERNEL_END = 0x%x\n", KERNEL_END); + printf("VM_BOOT_PACKAGE_START = 0x%x\n", VM_BOOT_PACKAGE_START); + printf("VM_BOOT_PACKAGE_END = 0x%x\n", VM_BOOT_PACKAGE_END); + + + return 0; + +} diff --git a/palacios/src/geekos/symbol.asm b/palacios/src/geekos/symbol.asm new file mode 100644 index 0000000..0bb1584 --- /dev/null +++ b/palacios/src/geekos/symbol.asm @@ -0,0 +1,43 @@ +; Symbol mangling macros +; Copyright (c) 2001, David H. Hovemeyer +; $Revision: 1.1 $ + +; This file defines macros for dealing with externally-visible +; symbols that must be mangled for some object file formats. +; For example, PECOFF requires a leading underscore, while +; ELF does not. + +; EXPORT defines a symbol as global +; IMPORT references a symbol defined in another module + +; Thanks to Christopher Giese for providing the NASM macros +; (thus saving me hours of frustration). + +%ifndef SYMBOL_ASM +%define SYMBOL_ASM + +%ifdef NEED_UNDERSCORE + +%macro EXPORT 1 +[GLOBAL _%1] +%define %1 _%1 +%endmacro + +%macro IMPORT 1 +[EXTERN _%1] +%define %1 _%1 +%endmacro + +%else + +%macro EXPORT 1 +[GLOBAL %1] +%endmacro + +%macro IMPORT 1 +[EXTERN %1] +%endmacro + +%endif + +%endif diff --git a/palacios/src/geekos/synch.c b/palacios/src/geekos/synch.c new file mode 100644 index 0000000..86e7191 --- /dev/null +++ b/palacios/src/geekos/synch.c @@ -0,0 +1,206 @@ +/* + * Synchronization primitives + * Copyright (c) 2001,2004 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#include +#include +#include +#include +#include + +/* + * NOTES: + * - The GeekOS mutex and condition variable APIs are based on those + * in pthreads. + * - Unlike disabling interrupts, mutexes offer NO protection against + * concurrent execution of interrupt handlers. Mutexes and + * condition variables should only be used from kernel threads, + * with interrupts enabled. + */ + +/* ---------------------------------------------------------------------- + * Private functions + * ---------------------------------------------------------------------- */ + +/* + * The mutex is currently locked. + * Atomically reenable preemption and wait in the + * mutex's wait queue. + */ +static void Mutex_Wait(struct Mutex *mutex) +{ + KASSERT(mutex->state == MUTEX_LOCKED); + KASSERT(g_preemptionDisabled); + + Disable_Interrupts(); + g_preemptionDisabled = false; + Wait(&mutex->waitQueue); + g_preemptionDisabled = true; + Enable_Interrupts(); +} + +/* + * Lock given mutex. + * Preemption must be disabled. + */ +static __inline__ void Mutex_Lock_Imp(struct Mutex* mutex) +{ + KASSERT(g_preemptionDisabled); + + /* Make sure we're not already holding the mutex */ + KASSERT(!IS_HELD(mutex)); + + /* Wait until the mutex is in an unlocked state */ + while (mutex->state == MUTEX_LOCKED) { + Mutex_Wait(mutex); + } + + /* Now it's ours! */ + mutex->state = MUTEX_LOCKED; + mutex->owner = g_currentThread; +} + +/* + * Unlock given mutex. + * Preemption must be disabled. + */ +static __inline__ void Mutex_Unlock_Imp(struct Mutex* mutex) +{ + KASSERT(g_preemptionDisabled); + + /* Make sure mutex was actually acquired by this thread. */ + KASSERT(IS_HELD(mutex)); + + /* Unlock the mutex. */ + mutex->state = MUTEX_UNLOCKED; + mutex->owner = 0; + + /* + * If there are threads waiting to acquire the mutex, + * wake one of them up. Note that it is legal to inspect + * the queue with interrupts enabled because preemption + * is disabled, and therefore we know that no thread can + * concurrently add itself to the queue. + */ + if (!Is_Thread_Queue_Empty(&mutex->waitQueue)) { + Disable_Interrupts(); + Wake_Up_One(&mutex->waitQueue); + Enable_Interrupts(); + } +} + +/* ---------------------------------------------------------------------- + * Public functions + * ---------------------------------------------------------------------- */ + +/* + * Initialize given mutex. + */ +void Mutex_Init(struct Mutex* mutex) +{ + mutex->state = MUTEX_UNLOCKED; + mutex->owner = 0; + Clear_Thread_Queue(&mutex->waitQueue); +} + +/* + * Lock given mutex. + */ +void Mutex_Lock(struct Mutex* mutex) +{ + KASSERT(Interrupts_Enabled()); + + g_preemptionDisabled = true; + Mutex_Lock_Imp(mutex); + g_preemptionDisabled = false; +} + +/* + * Unlock given mutex. + */ +void Mutex_Unlock(struct Mutex* mutex) +{ + KASSERT(Interrupts_Enabled()); + + g_preemptionDisabled = true; + Mutex_Unlock_Imp(mutex); + g_preemptionDisabled = false; +} + +/* + * Initialize given condition. + */ +void Cond_Init(struct Condition* cond) +{ + Clear_Thread_Queue(&cond->waitQueue); +} + +/* + * Wait on given condition (protected by given mutex). + */ +void Cond_Wait(struct Condition* cond, struct Mutex* mutex) +{ + KASSERT(Interrupts_Enabled()); + + /* Ensure mutex is held. */ + KASSERT(IS_HELD(mutex)); + + /* Turn off scheduling. */ + g_preemptionDisabled = true; + + /* + * Release the mutex, but leave preemption disabled. + * No other threads will be able to run before this thread + * is able to wait. Therefore, this thread will not + * miss the eventual notification on the condition. + */ + Mutex_Unlock_Imp(mutex); + + /* + * Atomically reenable preemption and wait in the condition wait queue. + * Other threads can run while this thread is waiting, + * and eventually one of them will call Cond_Signal() or Cond_Broadcast() + * to wake up this thread. + * On wakeup, disable preemption again. + */ + Disable_Interrupts(); + g_preemptionDisabled = false; + Wait(&cond->waitQueue); + g_preemptionDisabled = true; + Enable_Interrupts(); + + /* Reacquire the mutex. */ + Mutex_Lock_Imp(mutex); + + /* Turn scheduling back on. */ + g_preemptionDisabled = false; +} + +/* + * Wake up one thread waiting on the given condition. + * The mutex guarding the condition should be held! + */ +void Cond_Signal(struct Condition* cond) +{ + KASSERT(Interrupts_Enabled()); + Disable_Interrupts(); /* prevent scheduling */ + Wake_Up_One(&cond->waitQueue); + Enable_Interrupts(); /* resume scheduling */ +} + +/* + * Wake up all threads waiting on the given condition. + * The mutex guarding the condition should be held! + */ +void Cond_Broadcast(struct Condition* cond) +{ + KASSERT(Interrupts_Enabled()); + Disable_Interrupts(); /* prevent scheduling */ + Wake_Up(&cond->waitQueue); + Enable_Interrupts(); /* resume scheduling */ +} diff --git a/palacios/src/geekos/testvm.s b/palacios/src/geekos/testvm.s new file mode 100644 index 0000000..1ab713e --- /dev/null +++ b/palacios/src/geekos/testvm.s @@ -0,0 +1,43 @@ +# -*- fundamental -*- + +.global MyBuzzVM +MyBuzzVM: + pushl %ebp + movl %esp, %ebp + pushl %esi + pushl %ebx + inb $97, %al + movl $97, %ecx + movb %al, %bl + orl $2, %ebx + movl %eax, %esi +.L24: + movb %bl, %al + movl %ecx, %edx + outb %al, %dx + movl $0, %edx +.L30: + incl %edx + cmpl $999999, %edx + jle .L30 + movl %esi, %eax + movl %ecx, %edx + outb %al, %dx + movl $0, %edx +.L35: + incl %edx + cmpl $999999, %edx + jle .L35 + jmp .L24 + + + + + + + + + + + + diff --git a/palacios/src/geekos/timer.c b/palacios/src/geekos/timer.c new file mode 100644 index 0000000..cd89f86 --- /dev/null +++ b/palacios/src/geekos/timer.c @@ -0,0 +1,221 @@ +/* + * GeekOS timer interrupt support + * Copyright (c) 2001,2003 David H. Hovemeyer + * Copyright (c) 2003, Jeffrey K. Hollingsworth + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define HZ 100 + + +/* + * Global tick counter + */ +volatile ulong_t g_numTicks; + +/* + * Number of times the spin loop can execute during one timer tick + */ +static int s_spinCountPerTick; + +/* + * Number of ticks to wait before calibrating the delay loop. + */ +#define CALIBRATE_NUM_TICKS 3 + +/* + * The default quantum; maximum number of ticks a thread can use before + * we suspend it and choose another. + */ +#define DEFAULT_MAX_TICKS 4 + +/* + * Settable quantum. + */ +int g_Quantum = DEFAULT_MAX_TICKS; + +/* + * Ticks per second. + * FIXME: should set this to something more reasonable, like 100. + */ +#define TICKS_PER_SEC 18 + +/*#define DEBUG_TIMER */ +#ifdef DEBUG_TIMER +# define Debug(args...) Print(args) +#else +# define Debug(args...) +#endif + +/* ---------------------------------------------------------------------- + * Private functions + * ---------------------------------------------------------------------- */ + +static void Timer_Interrupt_Handler(struct Interrupt_State* state) +{ + struct Kernel_Thread* current = g_currentThread; + + Begin_IRQ(state); + + SerialPrintLevel(10,"Host Timer Interrupt Handler Running\n"); + + /* Update global and per-thread number of ticks */ + ++g_numTicks; + ++current->numTicks; + + + /* + * If thread has been running for an entire quantum, + * inform the interrupt return code that we want + * to choose a new thread. + */ + if (current->numTicks >= g_Quantum) { + g_needReschedule = true; + } + + + End_IRQ(state); +} + +/* + * Temporary timer interrupt handler used to calibrate + * the delay loop. + */ +static void Timer_Calibrate(struct Interrupt_State* state) +{ + Begin_IRQ(state); + if (g_numTicks < CALIBRATE_NUM_TICKS) + ++g_numTicks; + else { + /* + * Now we can look at EAX, which reflects how many times + * the loop has executed + */ + /*Print("Timer_Calibrate: eax==%d\n", state->eax);*/ + s_spinCountPerTick = INT_MAX - state->eax; + state->eax = 0; /* make the loop terminate */ + } + End_IRQ(state); +} + +/* + * Delay loop; spins for given number of iterations. + */ +static void Spin(int count) +{ + /* + * The assembly code is the logical equivalent of + * while (count-- > 0) { // waste some time } + * We rely on EAX being used as the counter + * variable. + */ + + int result; + __asm__ __volatile__ ( + "1: decl %%eax\n\t" + "cmpl $0, %%eax\n\t" + "nop; nop; nop; nop; nop; nop\n\t" + "nop; nop; nop; nop; nop; nop\n\t" + "jg 1b" + : "=a" (result) + : "a" (count) + ); +} + +/* + * Calibrate the delay loop. + * This will initialize s_spinCountPerTick, which indicates + * how many iterations of the loop are executed per timer tick. + */ +static void Calibrate_Delay(void) +{ + Disable_Interrupts(); + + /* Install temporarily interrupt handler */ + Install_IRQ(TIMER_IRQ, &Timer_Calibrate); + Enable_IRQ(TIMER_IRQ); + + Enable_Interrupts(); + + /* Wait a few ticks */ + while (g_numTicks < CALIBRATE_NUM_TICKS) + ; + + /* + * Execute the spin loop. + * The temporary interrupt handler will overwrite the + * loop counter when the next tick occurs. + */ + Spin(INT_MAX); + + Disable_Interrupts(); + + /* + * Mask out the timer IRQ again, + * since we will be installing a real timer interrupt handler. + */ + Disable_IRQ(TIMER_IRQ); + Enable_Interrupts(); +} + +/* ---------------------------------------------------------------------- + * Public functions + * ---------------------------------------------------------------------- */ + +void Init_Timer(void) +{ + ushort_t foo = 1193182L / HZ; + + PrintBoth("Initializing timer and setting to %d Hz...\n",HZ); + + /* Calibrate for delay loop */ + Calibrate_Delay(); + PrintBoth("Delay loop: %d iterations per tick\n", s_spinCountPerTick); + + // Set Timer to HZ + + Out_Byte(0x43,0x36); // channel 0, LSB/MSB, mode 3, binary + Out_Byte(0x40, foo & 0xff); // LSB + Out_Byte(0x40, foo >>8); // MSB + + /* Install an interrupt handler for the timer IRQ */ + + Install_IRQ(TIMER_IRQ, &Timer_Interrupt_Handler); + Enable_IRQ(TIMER_IRQ); +} + + +#define US_PER_TICK (TICKS_PER_SEC * 1000000) + +/* + * Spin for at least given number of microseconds. + * FIXME: I'm sure this implementation leaves a lot to + * be desired. + */ +void Micro_Delay(int us) +{ + int num = us * s_spinCountPerTick; + int denom = US_PER_TICK; + + int numSpins = num / denom; + int rem = num % denom; + + if (rem > 0) + ++numSpins; + + Debug("Micro_Delay(): num=%d, denom=%d, spin count = %d\n", num, denom, numSpins); + + Spin(numSpins); +} diff --git a/palacios/src/geekos/trap.c b/palacios/src/geekos/trap.c new file mode 100644 index 0000000..2085a99 --- /dev/null +++ b/palacios/src/geekos/trap.c @@ -0,0 +1,45 @@ +/* + * Trap handlers + * Copyright (c) 2001,2003,2004 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +#include +#include +#include +#include +#include + +/* + * TODO: need to add handlers for other exceptions (such as bounds + * check, debug, etc.) + */ + +/* + * Handler for general protection faults and other bad errors. + * Kill the current thread (which caused the fault). + */ +static void GPF_Handler(struct Interrupt_State* state) +{ + /* Send the thread to the reaper... */ + SerialPrintLevel(1000,"Exception %d received, killing thread %p\n",state->intNum, g_currentThread); + Dump_Interrupt_State(state); + + Exit(-1); + + /* We will never get here */ + KASSERT(false); +} + +/* + * Initialize handlers for processor traps. + */ +void Init_Traps(void) +{ + PrintBoth("Initializing Traps\n"); + Install_Interrupt_Handler(12, &GPF_Handler); /* stack exception */ + Install_Interrupt_Handler(13, &GPF_Handler); /* general protection fault */ +} diff --git a/palacios/src/geekos/tss.c b/palacios/src/geekos/tss.c new file mode 100644 index 0000000..a94bc52 --- /dev/null +++ b/palacios/src/geekos/tss.c @@ -0,0 +1,82 @@ +/* + * x86 TSS data structure and routines + * Copyright (c) 2001,2004 David H. Hovemeyer + * $Revision: 1.1 $ + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "COPYING". + */ + +/* + * Source: _Protected Mode Software Architecture_ by Tom Shanley, + * ISBN 020155447X. + */ + +#include +#include +#include +#include +#include +#include + +#include + +/* + * We use one TSS in GeekOS. + */ +//static struct TSS s_theTSS; +static struct TSS *s_theTSS = (struct TSS *) TSS_LOCATION; +static struct Segment_Descriptor *s_tssDesc; +static ushort_t s_tssSelector; + +static void __inline__ Load_Task_Register(void) +{ + /* Critical: TSS must be marked as not busy */ + s_tssDesc->type = 0x09; + + /* Load the task register */ + __asm__ __volatile__ ( + "ltr %0" + : + : "a" (s_tssSelector) + ); +} + +/* + * Initialize the kernel TSS. This must be done after the memory and + * GDT initialization, but before the scheduler is started. + */ +void Init_TSS(void) +{ + PrintBoth("Initializing TSS\n"); + + s_tssDesc = Allocate_Segment_Descriptor(); + KASSERT(s_tssDesc != 0); + + memset(s_theTSS, '\0', sizeof(struct TSS)); + Init_TSS_Descriptor(s_tssDesc, s_theTSS); + + s_tssSelector = Selector(0, true, Get_Descriptor_Index(s_tssDesc)); + + Load_Task_Register(); +} + +/* + * Set kernel stack pointer. + * This should be called before switching to a new + * user process, so that interrupts occurring while executing + * in user mode will be delivered on the correct stack. + */ +void Set_Kernel_Stack_Pointer(ulong_t esp0) +{ + s_theTSS->ss0 = KERNEL_DS; + s_theTSS->esp0 = esp0; + + /* + * NOTE: I read on alt.os.development that it is necessary to + * reload the task register after modifying a TSS. + * I haven't verified this in the IA32 documentation, + * but there is certainly no harm in being paranoid. + */ + Load_Task_Register(); +} diff --git a/palacios/src/geekos/util.asm b/palacios/src/geekos/util.asm new file mode 100644 index 0000000..86a019b --- /dev/null +++ b/palacios/src/geekos/util.asm @@ -0,0 +1,52 @@ +; This code is adapted from Kernel Toolkit 0.2 +; and Linux version 2.2.x, so the following copyrights apply: + +; Copyright (C) 1991, 1992 Linus Torvalds +; modified by Drew Eckhardt +; modified by Bruce Evans (bde) +; adapted for Kernel Toolkit by Luigi Sgro + +%ifndef UTIL_ASM +%define UTIL_ASM +%include "defs.asm" +%include "symbol.asm" + +[BITS 32] + +; The following were copied from ktk-0.2 bootsect.asm, and were presumably +; from the Linux bootsect code. I changed them a little so they +; don't clobber the caller's registers. + +EXPORT PrintHex + +[SECTION .text] +; Print the word contained in the dx register to the screen. +align 8 +PrintHex: + pusha + mov cx, 4 ; 4 hex digits +.PrintDigit: + rol dx, 4 ; rotate so that lowest 4 bits are used + mov ax, 0E0Fh ; ah = request, al = mask for nybble + and al, dl + add al, 90h ; convert al to ascii hex (four instructions) + daa ; I've spent 1 hour to understand how it works.. + adc al, 40h + daa + int 10h + loop .PrintDigit + popa + ret + +; Print a newline. +align 8 +PrintNL: ; print CR and NL + push ax + mov ax, 0E0Dh ; CR + int 10h + mov al, 0Ah ; LF + int 10h + pop ax + ret + +%endif diff --git a/palacios/src/geekos/vmcs.c b/palacios/src/geekos/vmcs.c new file mode 100644 index 0000000..5f9de3a --- /dev/null +++ b/palacios/src/geekos/vmcs.c @@ -0,0 +1,789 @@ +#include +#include + + + + +char *exception_names[] = { + "#DE (Divide Error)", + "#DB (Reserved)", + "NMI", + "#BP (Breakpoint)", + "#OF (Overflow)", + "#BR (BOUND Range Exceeded)", + "#UD (Invalid Opcode)", + "#NM (No Math Coprocessor)", + "#DF (Double Fault)", + "Coprocessor Segment Overrun", + "#TS (Invalid TSS)", + "#NP (Segment Not Present)", + "#SS (Stack Segment Fault)", + "#GP (General Protection Fault)", + "#PF (Page Fault)", + "(Reserved - 15)", + "#MF (Math Fault x87)", + "#AC (Alignment Check)", + "#MC (Machine Check)", + "#XF (SIMD FP Exception)", + "(Reserved - 20)", + "(Reserved - 21)", + "(Reserved - 22)", + "(Reserved - 23)", + "(Reserved - 24)", + "(Reserved - 25)", + "(Reserved - 26)", + "(Reserved - 27)", + "(Reserved - 28)", + "(Reserved - 29)", + "(Reserved - 30)", + "(Reserved - 31)", + "USER 32", + "USER 33", + "USER 34", + "USER 35", + "USER 36", + "USER 37", + "USER 38", + "USER 39", + "USER 40", + "USER 41", + "USER 42", + "USER 43", + "USER 44", + "USER 45", + "USER 46", + "USER 47", + "USER 48", + "USER 49", + "USER 50", + "USER 51", + "USER 52", + "USER 53", + "USER 54", + "USER 55", + "USER 56", + "USER 57", + "USER 58", + "USER 59", + "USER 60", + "USER 61", + "USER 62", + "USER 63", + "USER 64", + "USER 65", + "USER 66", + "USER 67", + "USER 68", + "USER 69", + "USER 70", + "USER 71", + "USER 72", + "USER 73", + "USER 74", + "USER 75", + "USER 76", + "USER 77", + "USER 78", + "USER 79", + "USER 80", + "USER 81", + "USER 82", + "USER 83", + "USER 84", + "USER 85", + "USER 86", + "USER 87", + "USER 88", + "USER 89", + "USER 90", + "USER 91", + "USER 92", + "USER 93", + "USER 94", + "USER 95", + "USER 96", + "USER 97", + "USER 98", + "USER 99", + "USER 100", + "USER 101", + "USER 102", + "USER 103", + "USER 104", + "USER 105", + "USER 106", + "USER 107", + "USER 108", + "USER 109", + "USER 110", + "USER 111", + "USER 112", + "USER 113", + "USER 114", + "USER 115", + "USER 116", + "USER 117", + "USER 118", + "USER 119", + "USER 120", + "USER 121", + "USER 122", + "USER 123", + "USER 124", + "USER 125", + "USER 126", + "USER 127", + "USER 128", + "USER 129", + "USER 130", + "USER 131", + "USER 132", + "USER 133", + "USER 134", + "USER 135", + "USER 136", + "USER 137", + "USER 138", + "USER 139", + "USER 140", + "USER 141", + "USER 142", + "USER 143", + "USER 144", + "USER 145", + "USER 146", + "USER 147", + "USER 148", + "USER 149", + "USER 150", + "USER 151", + "USER 152", + "USER 153", + "USER 154", + "USER 155", + "USER 156", + "USER 157", + "USER 158", + "USER 159", + "USER 160", + "USER 161", + "USER 162", + "USER 163", + "USER 164", + "USER 165", + "USER 166", + "USER 167", + "USER 168", + "USER 169", + "USER 170", + "USER 171", + "USER 172", + "USER 173", + "USER 174", + "USER 175", + "USER 176", + "USER 177", + "USER 178", + "USER 179", + "USER 180", + "USER 181", + "USER 182", + "USER 183", + "USER 184", + "USER 185", + "USER 186", + "USER 187", + "USER 188", + "USER 189", + "USER 190", + "USER 191", + "USER 192", + "USER 193", + "USER 194", + "USER 195", + "USER 196", + "USER 197", + "USER 198", + "USER 199", + "USER 200", + "USER 201", + "USER 202", + "USER 203", + "USER 204", + "USER 205", + "USER 206", + "USER 207", + "USER 208", + "USER 209", + "USER 210", + "USER 211", + "USER 212", + "USER 213", + "USER 214", + "USER 215", + "USER 216", + "USER 217", + "USER 218", + "USER 219", + "USER 220", + "USER 221", + "USER 222", + "USER 223", + "USER 224", + "USER 225", + "USER 226", + "USER 227", + "USER 228", + "USER 229", + "USER 230", + "USER 231", + "USER 232", + "USER 233", + "USER 234", + "USER 235", + "USER 236", + "USER 237", + "USER 238", + "USER 239", + "USER 240", + "USER 241", + "USER 242", + "USER 243", + "USER 244", + "USER 245", + "USER 246", + "USER 247", + "USER 248", + "USER 249", + "USER 250", + "USER 251", + "USER 252", + "USER 253", + "USER 254", + "USER 255", +}; + +char *exception_type_names[] = { + "External Interrupt", + "NOT USED", + "NMI", + "Hardware Exception", + "NOT USED", + "NOT USED", + "Software Exception", + "NOT USED" +}; + +// +// Ignores "HIGH" addresses - 32 bit only for now +// + + +#define CHK_VMCS_READ(tag, val) {if (VMCS_READ(tag, val) != 0) return -1;} +#define CHK_VMCS_WRITE(tag, val) {if (VMCS_WRITE(tag, val) != 0) return -1;} + + + +int CopyOutVMCSGuestStateArea(struct VMCSGuestStateArea *p) { + CHK_VMCS_READ(GUEST_CR0, &(p->cr0)); + CHK_VMCS_READ(GUEST_CR3, &(p->cr3)); + CHK_VMCS_READ(GUEST_CR4, &(p->cr4)); + CHK_VMCS_READ(GUEST_DR7, &(p->dr7)); + CHK_VMCS_READ(GUEST_RSP, &(p->rsp)); + CHK_VMCS_READ(GUEST_RIP, &(p->rip)); + CHK_VMCS_READ(GUEST_RFLAGS, &(p->rflags)); + CHK_VMCS_READ(VMCS_GUEST_CS_SELECTOR, &(p->cs.selector)); + CHK_VMCS_READ(VMCS_GUEST_SS_SELECTOR, &(p->ss.selector)); + CHK_VMCS_READ(VMCS_GUEST_DS_SELECTOR, &(p->ds.selector)); + CHK_VMCS_READ(VMCS_GUEST_ES_SELECTOR, &(p->es.selector)); + CHK_VMCS_READ(VMCS_GUEST_FS_SELECTOR, &(p->fs.selector)); + CHK_VMCS_READ(VMCS_GUEST_GS_SELECTOR, &(p->gs.selector)); + CHK_VMCS_READ(VMCS_GUEST_LDTR_SELECTOR, &(p->ldtr.selector)); + CHK_VMCS_READ(VMCS_GUEST_TR_SELECTOR, &(p->tr.selector)); + CHK_VMCS_READ(GUEST_CS_BASE, &(p->cs.baseAddr)); + CHK_VMCS_READ(GUEST_SS_BASE, &(p->ss.baseAddr)); + CHK_VMCS_READ(GUEST_DS_BASE, &(p->ds.baseAddr)); + CHK_VMCS_READ(GUEST_ES_BASE, &(p->es.baseAddr)); + CHK_VMCS_READ(GUEST_FS_BASE, &(p->fs.baseAddr)); + CHK_VMCS_READ(GUEST_GS_BASE, &(p->gs.baseAddr)); + CHK_VMCS_READ(GUEST_LDTR_BASE, &(p->ldtr.baseAddr)); + CHK_VMCS_READ(GUEST_TR_BASE, &(p->tr.baseAddr)); + CHK_VMCS_READ(GUEST_CS_LIMIT, &(p->cs.limit)); + CHK_VMCS_READ(GUEST_SS_LIMIT, &(p->ss.limit)); + CHK_VMCS_READ(GUEST_DS_LIMIT, &(p->ds.limit)); + CHK_VMCS_READ(GUEST_ES_LIMIT, &(p->es.limit)); + CHK_VMCS_READ(GUEST_FS_LIMIT, &(p->fs.limit)); + CHK_VMCS_READ(GUEST_GS_LIMIT, &(p->gs.limit)); + CHK_VMCS_READ(GUEST_LDTR_LIMIT, &(p->ldtr.limit)); + CHK_VMCS_READ(GUEST_TR_LIMIT, &(p->tr.limit)); + CHK_VMCS_READ(GUEST_CS_ACCESS, &(p->cs.access)); + CHK_VMCS_READ(GUEST_SS_ACCESS, &(p->ss.access)); + CHK_VMCS_READ(GUEST_DS_ACCESS, &(p->ds.access)); + CHK_VMCS_READ(GUEST_ES_ACCESS, &(p->es.access)); + CHK_VMCS_READ(GUEST_FS_ACCESS, &(p->fs.access)); + CHK_VMCS_READ(GUEST_GS_ACCESS, &(p->gs.access)); + CHK_VMCS_READ(GUEST_LDTR_ACCESS, &(p->ldtr.access)); + CHK_VMCS_READ(GUEST_TR_ACCESS, &(p->tr.access)); + CHK_VMCS_READ(GUEST_GDTR_BASE, &(p->gdtr.baseAddr)); + CHK_VMCS_READ(GUEST_IDTR_BASE, &(p->idtr.baseAddr)); + CHK_VMCS_READ(GUEST_GDTR_LIMIT, &(p->gdtr.limit)); + CHK_VMCS_READ(GUEST_IDTR_LIMIT, &(p->idtr.limit)); + CHK_VMCS_READ(GUEST_IA32_DEBUGCTL, &(p->dbg_ctrl)); + CHK_VMCS_READ(GUEST_IA32_DEBUGCTL_HIGH, ((char *)&(p->dbg_ctrl)) + 4); + CHK_VMCS_READ(GUEST_IA32_SYSENTER_CS, &(p->sysenter_cs)); + CHK_VMCS_READ(GUEST_IA32_SYSENTER_ESP, &(p->sysenter_esp)); + CHK_VMCS_READ(GUEST_IA32_SYSENTER_EIP, &(p->sysenter_eip)); + CHK_VMCS_READ(GUEST_SMBASE, &(p->smbase)); + + CHK_VMCS_READ(GUEST_ACTIVITY_STATE, &(p->activity)); + CHK_VMCS_READ(GUEST_INT_STATE, &(p->interrupt_state)); + CHK_VMCS_READ(GUEST_PENDING_DEBUG_EXCS, &(p->pending_dbg_exceptions)); + CHK_VMCS_READ(VMCS_LINK_PTR, &(p->vmcs_link)); + CHK_VMCS_READ(VMCS_LINK_PTR_HIGH, ((char *)&(p->vmcs_link)) + 4); + return 0; +} + + +int CopyInVMCSGuestStateArea(struct VMCSGuestStateArea *p) { + CHK_VMCS_WRITE(GUEST_CR0, &(p->cr0)); + CHK_VMCS_WRITE(GUEST_CR3, &(p->cr3)); + CHK_VMCS_WRITE(GUEST_CR4, &(p->cr4)); + CHK_VMCS_WRITE(GUEST_DR7, &(p->dr7)); + CHK_VMCS_WRITE(GUEST_RSP, &(p->rsp)); + CHK_VMCS_WRITE(GUEST_RIP, &(p->rip)); + CHK_VMCS_WRITE(GUEST_RFLAGS, &(p->rflags)); + CHK_VMCS_WRITE(VMCS_GUEST_CS_SELECTOR, &(p->cs.selector)); + CHK_VMCS_WRITE(VMCS_GUEST_SS_SELECTOR, &(p->ss.selector)); + CHK_VMCS_WRITE(VMCS_GUEST_DS_SELECTOR, &(p->ds.selector)); + CHK_VMCS_WRITE(VMCS_GUEST_ES_SELECTOR, &(p->es.selector)); + CHK_VMCS_WRITE(VMCS_GUEST_FS_SELECTOR, &(p->fs.selector)); + CHK_VMCS_WRITE(VMCS_GUEST_GS_SELECTOR, &(p->gs.selector)); + CHK_VMCS_WRITE(VMCS_GUEST_LDTR_SELECTOR, &(p->ldtr.selector)); + CHK_VMCS_WRITE(VMCS_GUEST_TR_SELECTOR, &(p->tr.selector)); + CHK_VMCS_WRITE(GUEST_CS_BASE, &(p->cs.baseAddr)); + CHK_VMCS_WRITE(GUEST_SS_BASE, &(p->ss.baseAddr)); + CHK_VMCS_WRITE(GUEST_DS_BASE, &(p->ds.baseAddr)); + CHK_VMCS_WRITE(GUEST_ES_BASE, &(p->es.baseAddr)); + CHK_VMCS_WRITE(GUEST_FS_BASE, &(p->fs.baseAddr)); + CHK_VMCS_WRITE(GUEST_GS_BASE, &(p->gs.baseAddr)); + CHK_VMCS_WRITE(GUEST_LDTR_BASE, &(p->ldtr.baseAddr)); + CHK_VMCS_WRITE(GUEST_TR_BASE, &(p->tr.baseAddr)); + CHK_VMCS_WRITE(GUEST_CS_LIMIT, &(p->cs.limit)); + CHK_VMCS_WRITE(GUEST_SS_LIMIT, &(p->ss.limit)); + CHK_VMCS_WRITE(GUEST_DS_LIMIT, &(p->ds.limit)); + CHK_VMCS_WRITE(GUEST_ES_LIMIT, &(p->es.limit)); + CHK_VMCS_WRITE(GUEST_FS_LIMIT, &(p->fs.limit)); + CHK_VMCS_WRITE(GUEST_GS_LIMIT, &(p->gs.limit)); + CHK_VMCS_WRITE(GUEST_LDTR_LIMIT, &(p->ldtr.limit)); + CHK_VMCS_WRITE(GUEST_TR_LIMIT, &(p->tr.limit)); + CHK_VMCS_WRITE(GUEST_CS_ACCESS, &(p->cs.access)); + CHK_VMCS_WRITE(GUEST_SS_ACCESS, &(p->ss.access)); + CHK_VMCS_WRITE(GUEST_DS_ACCESS, &(p->ds.access)); + CHK_VMCS_WRITE(GUEST_ES_ACCESS, &(p->es.access)); + CHK_VMCS_WRITE(GUEST_FS_ACCESS, &(p->fs.access)); + CHK_VMCS_WRITE(GUEST_GS_ACCESS, &(p->gs.access)); + CHK_VMCS_WRITE(GUEST_LDTR_ACCESS, &(p->ldtr.access)); + CHK_VMCS_WRITE(GUEST_TR_ACCESS, &(p->tr.access)); + CHK_VMCS_WRITE(GUEST_GDTR_BASE, &(p->gdtr.baseAddr)); + CHK_VMCS_WRITE(GUEST_IDTR_BASE, &(p->idtr.baseAddr)); + CHK_VMCS_WRITE(GUEST_GDTR_LIMIT, &(p->gdtr.limit)); + CHK_VMCS_WRITE(GUEST_IDTR_LIMIT, &(p->idtr.limit)); + CHK_VMCS_WRITE(GUEST_IA32_DEBUGCTL, &(p->dbg_ctrl)); + CHK_VMCS_WRITE(GUEST_IA32_DEBUGCTL_HIGH, ((char *)&(p->dbg_ctrl)) + 4); + CHK_VMCS_WRITE(GUEST_IA32_SYSENTER_CS, &(p->sysenter_cs)); + CHK_VMCS_WRITE(GUEST_IA32_SYSENTER_ESP, &(p->sysenter_esp)); + CHK_VMCS_WRITE(GUEST_IA32_SYSENTER_EIP, &(p->sysenter_eip)); + CHK_VMCS_WRITE(GUEST_SMBASE, &(p->smbase)); + + CHK_VMCS_WRITE(GUEST_ACTIVITY_STATE, &(p->activity)); + CHK_VMCS_WRITE(GUEST_INT_STATE, &(p->interrupt_state)); + CHK_VMCS_WRITE(GUEST_PENDING_DEBUG_EXCS, &(p->pending_dbg_exceptions)); + CHK_VMCS_WRITE(VMCS_LINK_PTR, &(p->vmcs_link)); + CHK_VMCS_WRITE(VMCS_LINK_PTR_HIGH, ((char *)&(p->vmcs_link)) + 4); + return 0; +} + + + +int CopyOutVMCSHostStateArea(struct VMCSHostStateArea *p) { + CHK_VMCS_READ(HOST_CR0, &(p->cr0)); + CHK_VMCS_READ(HOST_CR3, &(p->cr3)); + CHK_VMCS_READ(HOST_CR4, &(p->cr4)); + CHK_VMCS_READ(HOST_RSP, &(p->rsp)); + CHK_VMCS_READ(HOST_RIP, &(p->rip)); + CHK_VMCS_READ(VMCS_HOST_CS_SELECTOR, &(p->csSelector)); + CHK_VMCS_READ(VMCS_HOST_SS_SELECTOR, &(p->ssSelector)); + CHK_VMCS_READ(VMCS_HOST_DS_SELECTOR, &(p->dsSelector)); + CHK_VMCS_READ(VMCS_HOST_ES_SELECTOR, &(p->esSelector)); + CHK_VMCS_READ(VMCS_HOST_FS_SELECTOR, &(p->fsSelector)); + CHK_VMCS_READ(VMCS_HOST_GS_SELECTOR, &(p->gsSelector)); + CHK_VMCS_READ(VMCS_HOST_TR_SELECTOR, &(p->trSelector)); + CHK_VMCS_READ(HOST_FS_BASE, &(p->fsBaseAddr)); + CHK_VMCS_READ(HOST_GS_BASE, &(p->gsBaseAddr)); + CHK_VMCS_READ(HOST_TR_BASE, &(p->trBaseAddr)); + CHK_VMCS_READ(HOST_GDTR_BASE, &(p->gdtrBaseAddr)); + CHK_VMCS_READ(HOST_IDTR_BASE, &(p->idtrBaseAddr)); + CHK_VMCS_READ(HOST_IA32_SYSENTER_CS, &(p->sysenter_cs)); + CHK_VMCS_READ(HOST_IA32_SYSENTER_ESP, &(p->sysenter_esp)); + CHK_VMCS_READ(HOST_IA32_SYSENTER_EIP, &(p->sysenter_eip)); + return 0; +} + + + +int CopyInVMCSHostStateArea(struct VMCSHostStateArea *p) { + CHK_VMCS_WRITE(HOST_CR0, &(p->cr0)); + CHK_VMCS_WRITE(HOST_CR3, &(p->cr3)); + CHK_VMCS_WRITE(HOST_CR4, &(p->cr4)); + CHK_VMCS_WRITE(HOST_RSP, &(p->rsp)); + CHK_VMCS_WRITE(HOST_RIP, &(p->rip)); + CHK_VMCS_WRITE(VMCS_HOST_CS_SELECTOR, &(p->csSelector)); + CHK_VMCS_WRITE(VMCS_HOST_SS_SELECTOR, &(p->ssSelector)); + CHK_VMCS_WRITE(VMCS_HOST_DS_SELECTOR, &(p->dsSelector)); + CHK_VMCS_WRITE(VMCS_HOST_ES_SELECTOR, &(p->esSelector)); + CHK_VMCS_WRITE(VMCS_HOST_FS_SELECTOR, &(p->fsSelector)); + CHK_VMCS_WRITE(VMCS_HOST_GS_SELECTOR, &(p->gsSelector)); + CHK_VMCS_WRITE(VMCS_HOST_TR_SELECTOR, &(p->trSelector)); + CHK_VMCS_WRITE(HOST_FS_BASE, &(p->fsBaseAddr)); + CHK_VMCS_WRITE(HOST_GS_BASE, &(p->gsBaseAddr)); + CHK_VMCS_WRITE(HOST_TR_BASE, &(p->trBaseAddr)); + CHK_VMCS_WRITE(HOST_GDTR_BASE, &(p->gdtrBaseAddr)); + CHK_VMCS_WRITE(HOST_IDTR_BASE, &(p->idtrBaseAddr)); + CHK_VMCS_WRITE(HOST_IA32_SYSENTER_CS, &(p->sysenter_cs)); + CHK_VMCS_WRITE(HOST_IA32_SYSENTER_ESP, &(p->sysenter_esp)); + CHK_VMCS_WRITE(HOST_IA32_SYSENTER_EIP, &(p->sysenter_eip)); + return 0; +} + + +int CopyOutVMCSExitCtrlFields(struct VMCSExitCtrlFields *p) +{ + CHK_VMCS_READ(VM_EXIT_CTRLS,&(p->exitCtrls)); + CHK_VMCS_READ(VM_EXIT_MSR_STORE_COUNT,&(p->msrStoreCount)); + CHK_VMCS_READ(VM_EXIT_MSR_STORE_ADDR,&(p->msrStoreAddr)); + CHK_VMCS_READ(VM_EXIT_MSR_LOAD_COUNT,&(p->msrLoadCount)); + CHK_VMCS_READ(VM_EXIT_MSR_LOAD_ADDR,&(p->msrLoadAddr)); + return 0; +} + +int CopyInVMCSExitCtrlFields(struct VMCSExitCtrlFields *p) +{ + CHK_VMCS_WRITE(VM_EXIT_CTRLS,&(p->exitCtrls)); + CHK_VMCS_WRITE(VM_EXIT_MSR_STORE_COUNT,&(p->msrStoreCount)); + CHK_VMCS_WRITE(VM_EXIT_MSR_STORE_ADDR,&(p->msrStoreAddr)); + CHK_VMCS_WRITE(VM_EXIT_MSR_LOAD_COUNT,&(p->msrLoadCount)); + CHK_VMCS_WRITE(VM_EXIT_MSR_LOAD_ADDR,&(p->msrLoadAddr)); + return 0; +} + + +int CopyOutVMCSEntryCtrlFields(struct VMCSEntryCtrlFields *p) +{ + CHK_VMCS_READ(VM_ENTRY_CTRLS,&(p->entryCtrls)); + CHK_VMCS_READ(VM_ENTRY_MSR_LOAD_COUNT,&(p->msrLoadCount)); + CHK_VMCS_READ(VM_ENTRY_MSR_LOAD_ADDR,&(p->msrLoadAddr)); + CHK_VMCS_READ(VM_ENTRY_INT_INFO_FIELD,&(p->intInfo)); + CHK_VMCS_READ(VM_ENTRY_EXCEPTION_ERROR,&(p->exceptionErrorCode)); + CHK_VMCS_READ(VM_ENTRY_INSTR_LENGTH,&(p->instrLength)); + return 0; +} + +int CopyInVMCSEntryCtrlFields(struct VMCSEntryCtrlFields *p) +{ + CHK_VMCS_WRITE(VM_ENTRY_CTRLS,&(p->entryCtrls)); + CHK_VMCS_WRITE(VM_ENTRY_MSR_LOAD_COUNT,&(p->msrLoadCount)); + CHK_VMCS_WRITE(VM_ENTRY_MSR_LOAD_ADDR,&(p->msrLoadAddr)); + CHK_VMCS_WRITE(VM_ENTRY_INT_INFO_FIELD,&(p->intInfo)); + CHK_VMCS_WRITE(VM_ENTRY_EXCEPTION_ERROR,&(p->exceptionErrorCode)); + CHK_VMCS_WRITE(VM_ENTRY_INSTR_LENGTH,&(p->instrLength)); + return 0; +} + +int CopyOutVMCSExitInfoFields(struct VMCSExitInfoFields *p) { + CHK_VMCS_READ(EXIT_REASON,&(p->reason)); + CHK_VMCS_READ(EXIT_QUALIFICATION,&(p->qualification)); + CHK_VMCS_READ(VM_EXIT_INT_INFO,&(p->intInfo)); + CHK_VMCS_READ(VM_EXIT_INT_ERROR,&(p->intErrorCode)); + CHK_VMCS_READ(IDT_VECTOR_INFO,&(p->idtVectorInfo)); + CHK_VMCS_READ(IDT_VECTOR_ERROR,&(p->idtVectorErrorCode)); + CHK_VMCS_READ(VM_EXIT_INSTR_LENGTH,&(p->instrLength)); + CHK_VMCS_READ(GUEST_LINEAR_ADDR,&(p->guestLinearAddr)); + CHK_VMCS_READ(VMX_INSTR_INFO,&(p->instrInfo)); + CHK_VMCS_READ(IO_RCX,&(p->ioRCX)); + CHK_VMCS_READ(IO_RSI,&(p->ioRSI)); + CHK_VMCS_READ(IO_RDI,&(p->ioRDI)); + CHK_VMCS_READ(IO_RIP,&(p->ioRIP)); + CHK_VMCS_READ(VM_INSTR_ERROR,&(p->instrErrorField)); + return 0; +} + + +int CopyOutVMCSExecCtrlFields(struct VMCSExecCtrlFields *p) +{ + CHK_VMCS_READ(PIN_VM_EXEC_CTRLS,&(p->pinCtrls)); + CHK_VMCS_READ(PROC_VM_EXEC_CTRLS,&(p->procCtrls)); + CHK_VMCS_READ(EXCEPTION_BITMAP,&(p->execBitmap)); + CHK_VMCS_READ(PAGE_FAULT_ERROR_MASK,&(p->pageFaultErrorMask)); + CHK_VMCS_READ(PAGE_FAULT_ERROR_MATCH,&(p->pageFaultErrorMatch)); + CHK_VMCS_READ(IO_BITMAP_A_ADDR,&(p->ioBitmapA)); + CHK_VMCS_READ(IO_BITMAP_B_ADDR,&(p->ioBitmapB)); + CHK_VMCS_READ(TSC_OFFSET,&(p->tscOffset)); + CHK_VMCS_READ(CR0_GUEST_HOST_MASK,&(p->cr0GuestHostMask)); + CHK_VMCS_READ(CR0_READ_SHADOW,&(p->cr0ReadShadow)); + CHK_VMCS_READ(CR4_GUEST_HOST_MASK,&(p->cr4GuestHostMask)); + CHK_VMCS_READ(CR4_READ_SHADOW,&(p->cr4ReadShadow)); + CHK_VMCS_READ(CR3_TARGET_COUNT, &(p->cr3TargetCount)); + CHK_VMCS_READ(CR3_TARGET_VALUE_0, &(p->cr3TargetValue0)); + CHK_VMCS_READ(CR3_TARGET_VALUE_1, &(p->cr3TargetValue1)); + CHK_VMCS_READ(CR3_TARGET_VALUE_2, &(p->cr3TargetValue2)); + CHK_VMCS_READ(CR3_TARGET_VALUE_3, &(p->cr3TargetValue3)); + CHK_VMCS_READ(VIRT_APIC_PAGE_ADDR, &(p->virtApicPageAddr)); + CHK_VMCS_READ(TPR_THRESHOLD, &(p->tprThreshold)); + CHK_VMCS_READ(MSR_BITMAPS, &(p->MSRBitmapsBaseAddr)); + CHK_VMCS_READ(VMCS_EXEC_PTR,&(p->vmcsExecPtr)); + return 0; +} + + +int CopyInVMCSExecCtrlFields(struct VMCSExecCtrlFields *p) +{ + CHK_VMCS_WRITE(PIN_VM_EXEC_CTRLS,&(p->pinCtrls)); + CHK_VMCS_WRITE(PROC_VM_EXEC_CTRLS,&(p->procCtrls)); + CHK_VMCS_WRITE(EXCEPTION_BITMAP,&(p->execBitmap)); + CHK_VMCS_WRITE(PAGE_FAULT_ERROR_MASK,&(p->pageFaultErrorMask)); + CHK_VMCS_WRITE(PAGE_FAULT_ERROR_MATCH,&(p->pageFaultErrorMatch)); + CHK_VMCS_WRITE(IO_BITMAP_A_ADDR,&(p->ioBitmapA)); + CHK_VMCS_WRITE(IO_BITMAP_B_ADDR,&(p->ioBitmapB)); + CHK_VMCS_WRITE(TSC_OFFSET,&(p->tscOffset)); + CHK_VMCS_WRITE(CR0_GUEST_HOST_MASK,&(p->cr0GuestHostMask)); + CHK_VMCS_WRITE(CR0_READ_SHADOW,&(p->cr0ReadShadow)); + CHK_VMCS_WRITE(CR4_GUEST_HOST_MASK,&(p->cr4GuestHostMask)); + CHK_VMCS_WRITE(CR4_READ_SHADOW,&(p->cr4ReadShadow)); + CHK_VMCS_WRITE(CR3_TARGET_COUNT, &(p->cr3TargetCount)); + CHK_VMCS_WRITE(CR3_TARGET_VALUE_0, &(p->cr3TargetValue0)); + CHK_VMCS_WRITE(CR3_TARGET_VALUE_1, &(p->cr3TargetValue1)); + CHK_VMCS_WRITE(CR3_TARGET_VALUE_2, &(p->cr3TargetValue2)); + CHK_VMCS_WRITE(CR3_TARGET_VALUE_3, &(p->cr3TargetValue3)); + CHK_VMCS_WRITE(VIRT_APIC_PAGE_ADDR, &(p->virtApicPageAddr)); + CHK_VMCS_WRITE(TPR_THRESHOLD, &(p->tprThreshold)); + CHK_VMCS_WRITE(MSR_BITMAPS, &(p->MSRBitmapsBaseAddr)); + CHK_VMCS_WRITE(VMCS_EXEC_PTR,&(p->vmcsExecPtr)); + return 0; +} + + +int CopyOutVMCSData(struct VMCSData *p) { + if (CopyOutVMCSGuestStateArea(&(p->guestStateArea)) != 0) { + return -1; + } + if (CopyOutVMCSHostStateArea(&(p->hostStateArea)) != 0) { + return -1; + } + if (CopyOutVMCSExecCtrlFields(&(p->execCtrlFields)) != 0) { + return -1; + } + if (CopyOutVMCSExitCtrlFields(&(p->exitCtrlFields)) != 0) { + return -1; + } + if (CopyOutVMCSEntryCtrlFields(&(p->entryCtrlFields)) != 0) { + return -1; + } + if (CopyOutVMCSExitInfoFields(&(p->exitInfoFields)) != 0) { + return -1; + } + return 0; +} + + +int CopyInVMCSData(struct VMCSData *p) { + if (CopyInVMCSGuestStateArea(&(p->guestStateArea)) != 0) { + return -1; + } + if (CopyInVMCSHostStateArea(&(p->hostStateArea)) != 0) { + return -1; + } + if (CopyInVMCSExecCtrlFields(&(p->execCtrlFields)) != 0) { + return -1; + } + if (CopyInVMCSExitCtrlFields(&(p->exitCtrlFields)) != 0) { + return -1; + } + if (CopyInVMCSEntryCtrlFields(&(p->entryCtrlFields)) != 0) { + return -1; + } + return 0; +} + + +void SerialPrint_VMX_Regs(struct VMXRegs * regs) { + SerialPrint("==>VMX Register values:\n"); + SerialPrint("EAX: %x\n", regs->eax); + SerialPrint("ECX: %x\n", regs->ecx); + SerialPrint("EDX: %x\n", regs->edx); + SerialPrint("EBX: %x\n", regs->ebx); + SerialPrint("ESP: %x\n", regs->esp); + SerialPrint("EBP: %x\n", regs->ebp); + SerialPrint("ESI: %x\n", regs->esi); + SerialPrint("EDI: %x\n", regs->edi); + SerialPrint("\n"); +} + + +void SerialPrint_VMCSSegment(char * segname, struct VMCSSegment * seg, int abbr) { + SerialPrint("Segment: %s\n", segname); + if (abbr == 0) { + SerialPrint("\tSelector: %x\n", (uint_t)seg->selector); + SerialPrint("\tAccess: %x\n", *(uint_t*)&(seg->access)); + } + SerialPrint("\tBase Addr: %x\n", (uint_t)seg->baseAddr); + SerialPrint("\tLimit: %x\n", (uint_t)seg->limit); + +} + + +void SerialPrint_VMCSGuestStateArea(struct VMCSGuestStateArea * guestState) { + SerialPrint("==>Guest State Area\n"); + SerialPrint("==>==> Guest Register State\n"); + SerialPrint("GUEST_CR0: %x\n",(uint_t) guestState->cr0); + SerialPrint("GUEST_CR3: %x\n",(uint_t)guestState->cr3); + SerialPrint("GUEST_CR4: %x\n",(uint_t)guestState->cr4); + SerialPrint("GUEST_DR7: %x\n",(uint_t)guestState->dr7); + SerialPrint("GUEST_RSP: %x\n",(uint_t)guestState->rsp); + SerialPrint("GUEST_RIP: %x\n",(uint_t)guestState->rip); + SerialPrint("GUEST_RFLAGS: %x\n",(uint_t)guestState->rflags); + + SerialPrint_VMCSSegment("Guest CS", &(guestState->cs), 0); + SerialPrint_VMCSSegment("Guest SS", &(guestState->ss), 0); + SerialPrint_VMCSSegment("Guest DS",&(guestState->ds), 0); + SerialPrint_VMCSSegment("Guest ES", &(guestState->es), 0); + SerialPrint_VMCSSegment("Guest FS", &(guestState->fs), 0); + SerialPrint_VMCSSegment("Guest GS", &(guestState->gs), 0); + SerialPrint_VMCSSegment("Guest LDTR", &(guestState->ldtr), 0); + SerialPrint_VMCSSegment("Guest TR", &(guestState->tr), 0); + SerialPrint_VMCSSegment("Guest GDTR", &(guestState->gdtr), 1); + SerialPrint_VMCSSegment("Guest IDTR", &(guestState->idtr), 1); + + + SerialPrint("GUEST_IA32_DEBUGCTL: %x\n",(uint_t)(guestState->dbg_ctrl & 0xffffffff)); + SerialPrint("GUEST_IA32_DEBUGCTL_HIGH: %x\n",(uint_t)(guestState->dbg_ctrl >> 32) & 0xffffffff); + SerialPrint("GUEST_IA32_SYSENTER_CS: %x\n",guestState->sysenter_cs); + SerialPrint("GUEST_IA32_SYSENTER_ESP: %x\n",(uint_t)guestState->sysenter_esp); + SerialPrint("GUEST_IA32_SYSENTER_EIP: %x\n",(uint_t)guestState->sysenter_eip); + SerialPrint("GUEST_SMBASE: %x\n", (uint_t)guestState->smbase); + + SerialPrint("==>==> Guest Non-Register State\n"); + SerialPrint("GUEST_ACTIVITY_STATE: %x\n", (uint_t)guestState->activity); + SerialPrint("GUEST_INT_STATE: %x\n", (uint_t)guestState->interrupt_state); + SerialPrint("GUEST_PENDING_DEBUG_EXCS: %x\n", (uint_t)guestState->pending_dbg_exceptions); + SerialPrint("VMCS_LINK_PTR: %x\n", (uint_t)guestState->vmcs_link & 0xffffffff); + SerialPrint("VMCS_LINK_PTR_HIGH: %x\n", (uint_t)(guestState->vmcs_link >> 32) & 0xffffffff); +} + + +void SerialPrint_VMCSHostStateArea(struct VMCSHostStateArea * hostState) { + SerialPrint("\n==> Host State Area\n"); + SerialPrint("HOST_CR0: %x\n", (uint_t)hostState->cr0); + SerialPrint("HOST_CR3: %x\n", (uint_t)hostState->cr3); + SerialPrint("HOST_CR4: %x\n", (uint_t)hostState->cr4); + SerialPrint("HOST_RSP: %x\n", (uint_t)hostState->rsp); + SerialPrint("HOST_RIP: %x\n", (uint_t)hostState->rip); + SerialPrint("VMCS_HOST_CS_SELECTOR: %x\n", (uint_t)hostState->csSelector); + SerialPrint("VMCS_HOST_SS_SELECTOR: %x\n", (uint_t)hostState->ssSelector); + SerialPrint("VMCS_HOST_DS_SELECTOR: %x\n", (uint_t)hostState->dsSelector); + SerialPrint("VMCS_HOST_ES_SELECTOR: %x\n", (uint_t)hostState->esSelector); + SerialPrint("VMCS_HOST_FS_SELECTOR: %x\n", (uint_t)hostState->fsSelector); + SerialPrint("VMCS_HOST_GS_SELECTOR: %x\n", (uint_t)hostState->gsSelector); + SerialPrint("VMCS_HOST_TR_SELECTOR: %x\n", (uint_t)hostState->trSelector); + SerialPrint("HOST_FS_BASE: %x\n", (uint_t)hostState->fsBaseAddr); + SerialPrint("HOST_GS_BASE: %x\n", (uint_t)hostState->gsBaseAddr); + SerialPrint("HOST_TR_BASE: %x\n", (uint_t)hostState->trBaseAddr); + SerialPrint("HOST_GDTR_BASE: %x\n", (uint_t)hostState->gdtrBaseAddr); + SerialPrint("HOST_IDTR_BASE: %x\n", (uint_t)hostState->idtrBaseAddr); + SerialPrint("HOST_IA32_SYSENTER_CS: %x\n", (uint_t)hostState->sysenter_cs); + SerialPrint("HOST_IA32_SYSENTER_ESP: %x\n", (uint_t)hostState->sysenter_esp); + SerialPrint("HOST_IA32_SYSENTER_EIP: %x\n", (uint_t)hostState->sysenter_eip); +} + +void SerialPrint_VMCSExecCtrlFields(struct VMCSExecCtrlFields * execCtrls) { + SerialPrint("\n==> VM-Execution Controls:\n"); + SerialPrint("PIN_VM_EXEC_CTRLS: %x\n", (uint_t) execCtrls->pinCtrls); + SerialPrint("PROC_VM_EXEC_CTRLS: %x\n", (uint_t) execCtrls->procCtrls); + SerialPrint("EXCEPTION_BITMAP: %x\n", (uint_t) execCtrls->execBitmap); + SerialPrint("PAGE_FAULT_ERROR_MASK: %x\n", (uint_t) execCtrls->pageFaultErrorMask); + SerialPrint("PAGE_FAULT_ERROR_MATCH: %x\n", (uint_t) execCtrls->pageFaultErrorMatch); + SerialPrint("IO_BITMAP_A_ADDR: %x\n", (uint_t) execCtrls->ioBitmapA); + // SerialPrint("IO_BITMAP_A_ADDR_HIGH: %x\n", (uint_t) execCtrls->); + SerialPrint("IO_BITMAP_B_ADDR: %x\n", (uint_t) execCtrls->ioBitmapB); + // SerialPrint("IO_BITMAP_B_ADDR_HIGH: %x\n", (uint_t) execCtrls->); + SerialPrint("TSC_OFFSET: %x\n", (uint_t) execCtrls->tscOffset & 0xffffffff); + SerialPrint("TSC_OFFSET_HIGH: %x\n", (uint_t) (execCtrls->tscOffset >> 32) & 0xffffffff); + SerialPrint("CR0_GUEST_HOST_MASK: %x\n", (uint_t) execCtrls->cr0GuestHostMask); + SerialPrint("CR0_READ_SHADOW: %x\n", (uint_t) execCtrls->cr0ReadShadow); + SerialPrint("CR4_GUEST_HOST_MASK: %x\n", (uint_t) execCtrls->cr4GuestHostMask); + SerialPrint("CR4_READ_SHADOW: %x\n", (uint_t) execCtrls->cr4ReadShadow); + SerialPrint("CR3_TARGET_COUNT: %x\n", (uint_t) execCtrls->cr3TargetCount); + SerialPrint("CR3_TARGET_VALUE_0: %x\n", (uint_t) execCtrls->cr3TargetValue0); + SerialPrint("CR3_TARGET_VALUE_1: %x\n", (uint_t) execCtrls->cr3TargetValue1); + SerialPrint("CR3_TARGET_VALUE_2: %x\n", (uint_t) execCtrls->cr3TargetValue2); + SerialPrint("CR3_TARGET_VALUE_3: %x\n", (uint_t) execCtrls->cr3TargetValue3); + SerialPrint("VIRT_APIC_PAGE_ADDR: %x\n", (uint_t) execCtrls->virtApicPageAddr & 0xffffffff); + SerialPrint("VIRT_APIC_PAGE_ADDR_HIGH: %x\n", (uint_t) (execCtrls->virtApicPageAddr >> 32) & 0xffffffff); + SerialPrint("TPR_THRESHOLD: %x\n", (uint_t) execCtrls->tprThreshold); + SerialPrint("MSR_BITMAPS: %x\n", (uint_t) execCtrls->MSRBitmapsBaseAddr & 0xffffffff); + SerialPrint("MSR_BITMAPS_HIGH: %x\n", (uint_t) (execCtrls->MSRBitmapsBaseAddr >> 32) & 0xffffffff); + SerialPrint("VMCS_EXEC_PTR: %x\n", (uint_t) execCtrls->vmcsExecPtr & 0xffffffff); + SerialPrint("VMCS_EXEC_PTR_HIGH: %x\n", (uint_t) (execCtrls->vmcsExecPtr >> 32) & 0xffffffff); +} + +void SerialPrint_VMCSExitCtrlFields(struct VMCSExitCtrlFields * exitCtrls) { + SerialPrint("\n==> VM Exit Controls\n"); + SerialPrint("VM_EXIT_CTRLS: %x\n", (uint_t) exitCtrls->exitCtrls); + SerialPrint("VM_EXIT_MSR_STORE_COUNT: %x\n", (uint_t) exitCtrls->msrStoreCount); + SerialPrint("VM_EXIT_MSR_STORE_ADDR: %x\n", (uint_t) exitCtrls->msrStoreAddr & 0xffffffff); + SerialPrint("VM_EXIT_MSR_STORE_ADDR_HIGH: %x\n", (uint_t) (exitCtrls->msrStoreAddr >> 32) & 0xffffffff); + SerialPrint("VM_EXIT_MSR_LOAD_COUNT: %x\n", (uint_t) exitCtrls->msrLoadCount); + SerialPrint("VM_EXIT_MSR_LOAD_ADDR: %x\n", (uint_t) exitCtrls->msrLoadAddr & 0xffffffff); + SerialPrint("VM_EXIT_MSR_LOAD_ADDR_HIGH: %x\n", (uint_t) (exitCtrls->msrLoadAddr >> 32) & 0xffffffff); +} + +void SerialPrint_VMCSEntryCtrlFields(struct VMCSEntryCtrlFields * entryCtrls) { + SerialPrint("\n==> VM Entry Controls\n"); + SerialPrint("VM_ENTRY_CTRLS: %x\n", (uint_t) entryCtrls->entryCtrls); + SerialPrint("VM_ENTRY_MSR_LOAD_COUNT: %x\n", (uint_t) entryCtrls->msrLoadCount); + SerialPrint("VM_ENTRY_MSR_LOAD_ADDR: %x\n", (uint_t) entryCtrls->msrLoadAddr & 0xffffffff); + SerialPrint("VM_ENTRY_MSR_LOAD_ADDR_HIGH: %x\n", (uint_t) (entryCtrls->msrLoadAddr >> 32) & 0xffffffff); + SerialPrint("VM_ENTRY_INT_INFO_FIELD: %x\n", (uint_t) entryCtrls->intInfo); + SerialPrint("VM_ENTRY_EXCEPTION_ERROR: %x\n", (uint_t) entryCtrls->exceptionErrorCode); + SerialPrint("VM_ENTRY_INSTR_LENGTH: %x\n", (uint_t) entryCtrls->instrLength); +} + +void SerialPrint_VMCSExitInfoFields(struct VMCSExitInfoFields * exitInfo) { + SerialPrint("\n==> VM Exit Info\n"); + SerialPrint("EXIT_REASON: %x\n", (uint_t) exitInfo->reason); + SerialPrint("EXIT_QUALIFICATION: %x\n", (uint_t) exitInfo->qualification); + SerialPrint("VM_EXIT_INT_INFO: %x\n", (uint_t) exitInfo->intInfo); + SerialPrint("VM_EXIT_INT_ERROR: %x\n", (uint_t) exitInfo->intErrorCode); + SerialPrint("IDT_VECTOR_INFO: %x\n", (uint_t) exitInfo->idtVectorInfo); + SerialPrint("IDT_VECTOR_ERROR: %x\n", (uint_t) exitInfo->idtVectorErrorCode); + SerialPrint("VM_EXIT_INSTR_LENGTH: %x\n", (uint_t) exitInfo->instrLength); + SerialPrint("GUEST_LINEAR_ADDR: %x\n", (uint_t) exitInfo->guestLinearAddr); + SerialPrint("VMX_INSTR_INFO: %x\n", (uint_t) exitInfo->instrInfo); + SerialPrint("IO_RCX: %x\n", (uint_t) exitInfo->ioRCX); + SerialPrint("IO_RSI: %x\n", (uint_t) exitInfo->ioRSI); + SerialPrint("IO_RDI: %x\n", (uint_t) exitInfo->ioRDI); + SerialPrint("IO_RIP: %x\n", (uint_t) exitInfo->ioRIP); + SerialPrint("VM_INSTR_ERROR: %x\n", (uint_t) exitInfo->instrErrorField); +} + + +void SerialPrint_VMCSData(struct VMCSData * vmcs) { + SerialPrint("VMCSData Structure\n"); + + SerialPrint_VMCSGuestStateArea(&(vmcs->guestStateArea)); + SerialPrint_VMCSHostStateArea(&(vmcs->hostStateArea)); + SerialPrint_VMCSExecCtrlFields(&(vmcs->execCtrlFields)); + SerialPrint_VMCSExitCtrlFields(&(vmcs->exitCtrlFields)); + SerialPrint_VMCSEntryCtrlFields(&(vmcs->entryCtrlFields)); + SerialPrint_VMCSExitInfoFields(&(vmcs->exitInfoFields)); + SerialPrint("\n"); +} diff --git a/palacios/src/geekos/vmcs_fields.asm b/palacios/src/geekos/vmcs_fields.asm new file mode 100644 index 0000000..f354cf1 --- /dev/null +++ b/palacios/src/geekos/vmcs_fields.asm @@ -0,0 +1,135 @@ +%ifndef VMCS_FIELDS_ASM +%define VMCS_FIELDS_ASM + +VMCS_GUEST_ES_SELECTOR equ 0x00000800 +VMCS_GUEST_CS_SELECTOR equ 0x00000802 +VMCS_GUEST_SS_SELECTOR equ 0x00000804 +VMCS_GUEST_DS_SELECTOR equ 0x00000806 +VMCS_GUEST_FS_SELECTOR equ 0x00000808 +VMCS_GUEST_GS_SELECTOR equ 0x0000080A +VMCS_GUEST_LDTR_SELECTOR equ 0x0000080C +VMCS_GUEST_TR_SELECTOR equ 0x0000080E +VMCS_HOST_ES_SELECTOR equ 0x00000C00 +VMCS_HOST_CS_SELECTOR equ 0x00000C02 +VMCS_HOST_SS_SELECTOR equ 0x00000C04 +VMCS_HOST_DS_SELECTOR equ 0x00000C06 +VMCS_HOST_FS_SELECTOR equ 0x00000C08 +VMCS_HOST_GS_SELECTOR equ 0x00000C0A +VMCS_HOST_TR_SELECTOR equ 0x00000C0C +IO_BITMAP_A_ADDR equ 0x00002000 +IO_BITMAP_A_ADDR_HIGH equ 0x00002001 +IO_BITMAP_B_ADDR equ 0x00002002 +IO_BITMAP_B_ADDR_HIGH equ 0x00002003 +MSR_BITMAPS equ 0x00002004 +MSR_BITMAPS_HIGH equ 0x00002005 +VM_EXIT_MSR_STORE_ADDR equ 0x00002006 +VM_EXIT_MSR_STORE_ADDR_HIGH equ 0x00002007 +VM_EXIT_MSR_LOAD_ADDR equ 0x00002008 +VM_EXIT_MSR_LOAD_ADDR_HIGH equ 0x00002009 +VM_ENTRY_MSR_LOAD_ADDR equ 0x0000200A +VM_ENTRY_MSR_LOAD_ADDR_HIGH equ 0x0000200B +VMCS_EXEC_PTR equ 0x0000200C +VMCS_EXEC_PTR_HIGH equ 0x0000200D +TSC_OFFSET equ 0x00002010 +TSC_OFFSET_HIGH equ 0x00002011 +VIRT_APIC_PAGE_ADDR equ 0x00002012 +VIRT_APIC_PAGE_ADDR_HIGH equ 0x00002013 +VMCS_LINK_PTR equ 0x00002800 +VMCS_LINK_PTR_HIGH equ 0x00002801 +GUEST_IA32_DEBUGCTL equ 0x00002802 +GUEST_IA32_DEBUGCTL_HIGH equ 0x00002803 +PIN_VM_EXEC_CTRLS equ 0x00004000 +PROC_VM_EXEC_CTRLS equ 0x00004002 +EXCEPTION_BITMAP equ 0x00004004 +PAGE_FAULT_ERROR_MASK equ 0x00004006 +PAGE_FAULT_ERROR_MATCH equ 0x00004008 +CR3_TARGET_COUNT equ 0x0000400A +VM_EXIT_CTRLS equ 0x0000400C +VM_EXIT_MSR_STORE_COUNT equ 0x0000400E +VM_EXIT_MSR_LOAD_COUNT equ 0x00004010 +VM_ENTRY_CTRLS equ 0x00004012 +VM_ENTRY_MSR_LOAD_COUNT equ 0x00004014 +VM_ENTRY_INT_INFO_FIELD equ 0x00004016 +VM_ENTRY_EXCEPTION_ERROR equ 0x00004018 +VM_ENTRY_INSTR_LENGTH equ 0x0000401A +TPR_THRESHOLD equ 0x0000401C +VM_INSTR_ERROR equ 0x00004400 +EXIT_REASON equ 0x00004402 +VM_EXIT_INT_INFO equ 0x00004404 +VM_EXIT_INT_ERROR equ 0x00004406 +IDT_VECTOR_INFO equ 0x00004408 +IDT_VECTOR_ERROR equ 0x0000440A +VM_EXIT_INSTR_LENGTH equ 0x0000440C +VMX_INSTR_INFO equ 0x0000440E +GUEST_ES_LIMIT equ 0x00004800 +GUEST_CS_LIMIT equ 0x00004802 +GUEST_SS_LIMIT equ 0x00004804 +GUEST_DS_LIMIT equ 0x00004806 +GUEST_FS_LIMIT equ 0x00004808 +GUEST_GS_LIMIT equ 0x0000480A +GUEST_LDTR_LIMIT equ 0x0000480C +GUEST_TR_LIMIT equ 0x0000480E +GUEST_GDTR_LIMIT equ 0x00004810 +GUEST_IDTR_LIMIT equ 0x00004812 +GUEST_ES_ACCESS equ 0x00004814 +GUEST_CS_ACCESS equ 0x00004816 +GUEST_SS_ACCESS equ 0x00004818 +GUEST_DS_ACCESS equ 0x0000481A +GUEST_FS_ACCESS equ 0x0000481C +GUEST_GS_ACCESS equ 0x0000481E +GUEST_LDTR_ACCESS equ 0x00004820 +GUEST_TR_ACCESS equ 0x00004822 +GUEST_INT_STATE equ 0x00004824 +GUEST_ACTIVITY_STATE equ 0x00004826 +GUEST_SMBASE equ 0x00004828 +GUEST_IA32_SYSENTER_CS equ 0x0000482A +HOST_IA32_SYSENTER_CS equ 0x00004C00 +CR0_GUEST_HOST_MASK equ 0x00006000 +CR4_GUEST_HOST_MASK equ 0x00006002 +CR0_READ_SHADOW equ 0x00006004 +CR4_READ_SHADOW equ 0x00006006 +CR3_TARGET_VALUE_0 equ 0x00006008 +CR3_TARGET_VALUE_1 equ 0x0000600A +CR3_TARGET_VALUE_2 equ 0x0000600C +CR3_TARGET_VALUE_3 equ 0x0000600E +EXIT_QUALIFICATION equ 0x00006400 +IO_RCX equ 0x00006402 +IO_RSI equ 0x00006404 +IO_RDI equ 0x00006406 +IO_RIP equ 0x00006408 +GUEST_LINEAR_ADDR equ 0x0000640A +GUEST_CR0 equ 0x00006800 +GUEST_CR3 equ 0x00006802 +GUEST_CR4 equ 0x00006804 +GUEST_ES_BASE equ 0x00006806 +GUEST_CS_BASE equ 0x00006808 +GUEST_SS_BASE equ 0x0000680A +GUEST_DS_BASE equ 0x0000680C +GUEST_FS_BASE equ 0x0000680E +GUEST_GS_BASE equ 0x00006810 +GUEST_LDTR_BASE equ 0x00006812 +GUEST_TR_BASE equ 0x00006814 +GUEST_GDTR_BASE equ 0x00006816 +GUEST_IDTR_BASE equ 0x00006818 +GUEST_DR7 equ 0x0000681A +GUEST_RSP equ 0x0000681C +GUEST_RIP equ 0x0000681E +GUEST_RFLAGS equ 0x00006820 +GUEST_PENDING_DEBUG_EXCS equ 0x00006822 +GUEST_IA32_SYSENTER_ESP equ 0x00006824 +GUEST_IA32_SYSENTER_EIP equ 0x00006826 +HOST_CR0 equ 0x00006C00 +HOST_CR3 equ 0x00006C02 +HOST_CR4 equ 0x00006C04 +HOST_FS_BASE equ 0x00006C06 +HOST_GS_BASE equ 0x00006C08 +HOST_TR_BASE equ 0x00006C0A +HOST_GDTR_BASE equ 0x00006C0C +HOST_IDTR_BASE equ 0x00006C0E +HOST_IA32_SYSENTER_ESP equ 0x00006C10 +HOST_IA32_SYSENTER_EIP equ 0x00006C12 +HOST_RSP equ 0x00006C14 +HOST_RIP equ 0x00006C16 + +%endif + diff --git a/palacios/src/geekos/vmcs_gen.c b/palacios/src/geekos/vmcs_gen.c new file mode 100644 index 0000000..c96127e --- /dev/null +++ b/palacios/src/geekos/vmcs_gen.c @@ -0,0 +1,926 @@ +#include + + + + +void Set_VMCS_GUEST_ES_SELECTOR(uint_t val) { VMCS_WRITE(VMCS_GUEST_ES_SELECTOR,val); } +uint_t Get_VMCS_GUEST_ES_SELECTOR() { uint_t rc; VMCS_READ(VMCS_GUEST_ES_SELECTOR,&rc); return rc; } + +void SerialPrint_VMCS_GUEST_ES_SELECTOR() { SerialPrint("VMCS_GUEST_ES_SELECTOR = %x\n", Get_VMCS_GUEST_ES_SELECTOR()); } + + +void Set_VMCS_GUEST_CS_SELECTOR(uint_t val) { VMCS_WRITE(VMCS_GUEST_CS_SELECTOR,val); } +uint_t Get_VMCS_GUEST_CS_SELECTOR() { uint_t rc; VMCS_READ(VMCS_GUEST_CS_SELECTOR,&rc); return rc; } + +void SerialPrint_VMCS_GUEST_CS_SELECTOR() { SerialPrint("VMCS_GUEST_CS_SELECTOR = %x\n", Get_VMCS_GUEST_CS_SELECTOR()); } + + +void Set_VMCS_GUEST_SS_SELECTOR(uint_t val) { VMCS_WRITE(VMCS_GUEST_SS_SELECTOR,val); } +uint_t Get_VMCS_GUEST_SS_SELECTOR() { uint_t rc; VMCS_READ(VMCS_GUEST_SS_SELECTOR,&rc); return rc; } + +void SerialPrint_VMCS_GUEST_SS_SELECTOR() { SerialPrint("VMCS_GUEST_SS_SELECTOR = %x\n", Get_VMCS_GUEST_SS_SELECTOR()); } + + +void Set_VMCS_GUEST_DS_SELECTOR(uint_t val) { VMCS_WRITE(VMCS_GUEST_DS_SELECTOR,val); } +uint_t Get_VMCS_GUEST_DS_SELECTOR() { uint_t rc; VMCS_READ(VMCS_GUEST_DS_SELECTOR,&rc); return rc; } + +void SerialPrint_VMCS_GUEST_DS_SELECTOR() { SerialPrint("VMCS_GUEST_DS_SELECTOR = %x\n", Get_VMCS_GUEST_DS_SELECTOR()); } + + +void Set_VMCS_GUEST_FS_SELECTOR(uint_t val) { VMCS_WRITE(VMCS_GUEST_FS_SELECTOR,val); } +uint_t Get_VMCS_GUEST_FS_SELECTOR() { uint_t rc; VMCS_READ(VMCS_GUEST_FS_SELECTOR,&rc); return rc; } + +void SerialPrint_VMCS_GUEST_FS_SELECTOR() { SerialPrint("VMCS_GUEST_FS_SELECTOR = %x\n", Get_VMCS_GUEST_FS_SELECTOR()); } + + +void Set_VMCS_GUEST_GS_SELECTOR(uint_t val) { VMCS_WRITE(VMCS_GUEST_GS_SELECTOR,val); } +uint_t Get_VMCS_GUEST_GS_SELECTOR() { uint_t rc; VMCS_READ(VMCS_GUEST_GS_SELECTOR,&rc); return rc; } + +void SerialPrint_VMCS_GUEST_GS_SELECTOR() { SerialPrint("VMCS_GUEST_GS_SELECTOR = %x\n", Get_VMCS_GUEST_GS_SELECTOR()); } + + +void Set_VMCS_GUEST_LDTR_SELECTOR(uint_t val) { VMCS_WRITE(VMCS_GUEST_LDTR_SELECTOR,val); } +uint_t Get_VMCS_GUEST_LDTR_SELECTOR() { uint_t rc; VMCS_READ(VMCS_GUEST_LDTR_SELECTOR,&rc); return rc; } + +void SerialPrint_VMCS_GUEST_LDTR_SELECTOR() { SerialPrint("VMCS_GUEST_LDTR_SELECTOR = %x\n", Get_VMCS_GUEST_LDTR_SELECTOR()); } + + +void Set_VMCS_GUEST_TR_SELECTOR(uint_t val) { VMCS_WRITE(VMCS_GUEST_TR_SELECTOR,val); } +uint_t Get_VMCS_GUEST_TR_SELECTOR() { uint_t rc; VMCS_READ(VMCS_GUEST_TR_SELECTOR,&rc); return rc; } + +void SerialPrint_VMCS_GUEST_TR_SELECTOR() { SerialPrint("VMCS_GUEST_TR_SELECTOR = %x\n", Get_VMCS_GUEST_TR_SELECTOR()); } + + +void Set_VMCS_HOST_ES_SELECTOR(uint_t val) { VMCS_WRITE(VMCS_HOST_ES_SELECTOR,val); } +uint_t Get_VMCS_HOST_ES_SELECTOR() { uint_t rc; VMCS_READ(VMCS_HOST_ES_SELECTOR,&rc); return rc; } + +void SerialPrint_VMCS_HOST_ES_SELECTOR() { SerialPrint("VMCS_HOST_ES_SELECTOR = %x\n", Get_VMCS_HOST_ES_SELECTOR()); } + + +void Set_VMCS_HOST_CS_SELECTOR(uint_t val) { VMCS_WRITE(VMCS_HOST_CS_SELECTOR,val); } +uint_t Get_VMCS_HOST_CS_SELECTOR() { uint_t rc; VMCS_READ(VMCS_HOST_CS_SELECTOR,&rc); return rc; } + +void SerialPrint_VMCS_HOST_CS_SELECTOR() { SerialPrint("VMCS_HOST_CS_SELECTOR = %x\n", Get_VMCS_HOST_CS_SELECTOR()); } + + +void Set_VMCS_HOST_SS_SELECTOR(uint_t val) { VMCS_WRITE(VMCS_HOST_SS_SELECTOR,val); } +uint_t Get_VMCS_HOST_SS_SELECTOR() { uint_t rc; VMCS_READ(VMCS_HOST_SS_SELECTOR,&rc); return rc; } + +void SerialPrint_VMCS_HOST_SS_SELECTOR() { SerialPrint("VMCS_HOST_SS_SELECTOR = %x\n", Get_VMCS_HOST_SS_SELECTOR()); } + + +void Set_VMCS_HOST_DS_SELECTOR(uint_t val) { VMCS_WRITE(VMCS_HOST_DS_SELECTOR,val); } +uint_t Get_VMCS_HOST_DS_SELECTOR() { uint_t rc; VMCS_READ(VMCS_HOST_DS_SELECTOR,&rc); return rc; } + +void SerialPrint_VMCS_HOST_DS_SELECTOR() { SerialPrint("VMCS_HOST_DS_SELECTOR = %x\n", Get_VMCS_HOST_DS_SELECTOR()); } + + +void Set_VMCS_HOST_FS_SELECTOR(uint_t val) { VMCS_WRITE(VMCS_HOST_FS_SELECTOR,val); } +uint_t Get_VMCS_HOST_FS_SELECTOR() { uint_t rc; VMCS_READ(VMCS_HOST_FS_SELECTOR,&rc); return rc; } + +void SerialPrint_VMCS_HOST_FS_SELECTOR() { SerialPrint("VMCS_HOST_FS_SELECTOR = %x\n", Get_VMCS_HOST_FS_SELECTOR()); } + + +void Set_VMCS_HOST_GS_SELECTOR(uint_t val) { VMCS_WRITE(VMCS_HOST_GS_SELECTOR,val); } +uint_t Get_VMCS_HOST_GS_SELECTOR() { uint_t rc; VMCS_READ(VMCS_HOST_GS_SELECTOR,&rc); return rc; } + +void SerialPrint_VMCS_HOST_GS_SELECTOR() { SerialPrint("VMCS_HOST_GS_SELECTOR = %x\n", Get_VMCS_HOST_GS_SELECTOR()); } + + +void Set_VMCS_HOST_TR_SELECTOR(uint_t val) { VMCS_WRITE(VMCS_HOST_TR_SELECTOR,val); } +uint_t Get_VMCS_HOST_TR_SELECTOR() { uint_t rc; VMCS_READ(VMCS_HOST_TR_SELECTOR,&rc); return rc; } + +void SerialPrint_VMCS_HOST_TR_SELECTOR() { SerialPrint("VMCS_HOST_TR_SELECTOR = %x\n", Get_VMCS_HOST_TR_SELECTOR()); } + + +void Set_IO_BITMAP_A_ADDR(uint_t val) { VMCS_WRITE(IO_BITMAP_A_ADDR,val); } +uint_t Get_IO_BITMAP_A_ADDR() { uint_t rc; VMCS_READ(IO_BITMAP_A_ADDR,&rc); return rc; } + +void SerialPrint_IO_BITMAP_A_ADDR() { SerialPrint("IO_BITMAP_A_ADDR = %x\n", Get_IO_BITMAP_A_ADDR()); } + + +void Set_IO_BITMAP_A_ADDR_HIGH(uint_t val) { VMCS_WRITE(IO_BITMAP_A_ADDR_HIGH,val); } +uint_t Get_IO_BITMAP_A_ADDR_HIGH() { uint_t rc; VMCS_READ(IO_BITMAP_A_ADDR_HIGH,&rc); return rc; } + +void SerialPrint_IO_BITMAP_A_ADDR_HIGH() { SerialPrint("IO_BITMAP_A_ADDR_HIGH = %x\n", Get_IO_BITMAP_A_ADDR_HIGH()); } + + +void Set_IO_BITMAP_B_ADDR(uint_t val) { VMCS_WRITE(IO_BITMAP_B_ADDR,val); } +uint_t Get_IO_BITMAP_B_ADDR() { uint_t rc; VMCS_READ(IO_BITMAP_B_ADDR,&rc); return rc; } + +void SerialPrint_IO_BITMAP_B_ADDR() { SerialPrint("IO_BITMAP_B_ADDR = %x\n", Get_IO_BITMAP_B_ADDR()); } + + +void Set_IO_BITMAP_B_ADDR_HIGH(uint_t val) { VMCS_WRITE(IO_BITMAP_B_ADDR_HIGH,val); } +uint_t Get_IO_BITMAP_B_ADDR_HIGH() { uint_t rc; VMCS_READ(IO_BITMAP_B_ADDR_HIGH,&rc); return rc; } + +void SerialPrint_IO_BITMAP_B_ADDR_HIGH() { SerialPrint("IO_BITMAP_B_ADDR_HIGH = %x\n", Get_IO_BITMAP_B_ADDR_HIGH()); } + + +void Set_MSR_BITMAPS(uint_t val) { VMCS_WRITE(MSR_BITMAPS,val); } +uint_t Get_MSR_BITMAPS() { uint_t rc; VMCS_READ(MSR_BITMAPS,&rc); return rc; } + +void SerialPrint_MSR_BITMAPS() { SerialPrint("MSR_BITMAPS = %x\n", Get_MSR_BITMAPS()); } + + +void Set_MSR_BITMAPS_HIGH(uint_t val) { VMCS_WRITE(MSR_BITMAPS_HIGH,val); } +uint_t Get_MSR_BITMAPS_HIGH() { uint_t rc; VMCS_READ(MSR_BITMAPS_HIGH,&rc); return rc; } + +void SerialPrint_MSR_BITMAPS_HIGH() { SerialPrint("MSR_BITMAPS_HIGH = %x\n", Get_MSR_BITMAPS_HIGH()); } + + +void Set_VM_EXIT_MSR_STORE_ADDR(uint_t val) { VMCS_WRITE(VM_EXIT_MSR_STORE_ADDR,val); } +uint_t Get_VM_EXIT_MSR_STORE_ADDR() { uint_t rc; VMCS_READ(VM_EXIT_MSR_STORE_ADDR,&rc); return rc; } + +void SerialPrint_VM_EXIT_MSR_STORE_ADDR() { SerialPrint("VM_EXIT_MSR_STORE_ADDR = %x\n", Get_VM_EXIT_MSR_STORE_ADDR()); } + + +void Set_VM_EXIT_MSR_STORE_ADDR_HIGH(uint_t val) { VMCS_WRITE(VM_EXIT_MSR_STORE_ADDR_HIGH,val); } +uint_t Get_VM_EXIT_MSR_STORE_ADDR_HIGH() { uint_t rc; VMCS_READ(VM_EXIT_MSR_STORE_ADDR_HIGH,&rc); return rc; } + +void SerialPrint_VM_EXIT_MSR_STORE_ADDR_HIGH() { SerialPrint("VM_EXIT_MSR_STORE_ADDR_HIGH = %x\n", Get_VM_EXIT_MSR_STORE_ADDR_HIGH()); } + + +void Set_VM_EXIT_MSR_LOAD_ADDR(uint_t val) { VMCS_WRITE(VM_EXIT_MSR_LOAD_ADDR,val); } +uint_t Get_VM_EXIT_MSR_LOAD_ADDR() { uint_t rc; VMCS_READ(VM_EXIT_MSR_LOAD_ADDR,&rc); return rc; } + +void SerialPrint_VM_EXIT_MSR_LOAD_ADDR() { SerialPrint("VM_EXIT_MSR_LOAD_ADDR = %x\n", Get_VM_EXIT_MSR_LOAD_ADDR()); } + + +void Set_VM_EXIT_MSR_LOAD_ADDR_HIGH(uint_t val) { VMCS_WRITE(VM_EXIT_MSR_LOAD_ADDR_HIGH,val); } +uint_t Get_VM_EXIT_MSR_LOAD_ADDR_HIGH() { uint_t rc; VMCS_READ(VM_EXIT_MSR_LOAD_ADDR_HIGH,&rc); return rc; } + +void SerialPrint_VM_EXIT_MSR_LOAD_ADDR_HIGH() { SerialPrint("VM_EXIT_MSR_LOAD_ADDR_HIGH = %x\n", Get_VM_EXIT_MSR_LOAD_ADDR_HIGH()); } + + +void Set_VM_ENTRY_MSR_LOAD_ADDR(uint_t val) { VMCS_WRITE(VM_ENTRY_MSR_LOAD_ADDR,val); } +uint_t Get_VM_ENTRY_MSR_LOAD_ADDR() { uint_t rc; VMCS_READ(VM_ENTRY_MSR_LOAD_ADDR,&rc); return rc; } + +void SerialPrint_VM_ENTRY_MSR_LOAD_ADDR() { SerialPrint("VM_ENTRY_MSR_LOAD_ADDR = %x\n", Get_VM_ENTRY_MSR_LOAD_ADDR()); } + + +void Set_VM_ENTRY_MSR_LOAD_ADDR_HIGH(uint_t val) { VMCS_WRITE(VM_ENTRY_MSR_LOAD_ADDR_HIGH,val); } +uint_t Get_VM_ENTRY_MSR_LOAD_ADDR_HIGH() { uint_t rc; VMCS_READ(VM_ENTRY_MSR_LOAD_ADDR_HIGH,&rc); return rc; } + +void SerialPrint_VM_ENTRY_MSR_LOAD_ADDR_HIGH() { SerialPrint("VM_ENTRY_MSR_LOAD_ADDR_HIGH = %x\n", Get_VM_ENTRY_MSR_LOAD_ADDR_HIGH()); } + + +void Set_VMCS_EXEC_PTR(uint_t val) { VMCS_WRITE(VMCS_EXEC_PTR,val); } +uint_t Get_VMCS_EXEC_PTR() { uint_t rc; VMCS_READ(VMCS_EXEC_PTR,&rc); return rc; } + +void SerialPrint_VMCS_EXEC_PTR() { SerialPrint("VMCS_EXEC_PTR = %x\n", Get_VMCS_EXEC_PTR()); } + + +void Set_VMCS_EXEC_PTR_HIGH(uint_t val) { VMCS_WRITE(VMCS_EXEC_PTR_HIGH,val); } +uint_t Get_VMCS_EXEC_PTR_HIGH() { uint_t rc; VMCS_READ(VMCS_EXEC_PTR_HIGH,&rc); return rc; } + +void SerialPrint_VMCS_EXEC_PTR_HIGH() { SerialPrint("VMCS_EXEC_PTR_HIGH = %x\n", Get_VMCS_EXEC_PTR_HIGH()); } + + +void Set_TSC_OFFSET(uint_t val) { VMCS_WRITE(TSC_OFFSET,val); } +uint_t Get_TSC_OFFSET() { uint_t rc; VMCS_READ(TSC_OFFSET,&rc); return rc; } + +void SerialPrint_TSC_OFFSET() { SerialPrint("TSC_OFFSET = %x\n", Get_TSC_OFFSET()); } + + +void Set_TSC_OFFSET_HIGH(uint_t val) { VMCS_WRITE(TSC_OFFSET_HIGH,val); } +uint_t Get_TSC_OFFSET_HIGH() { uint_t rc; VMCS_READ(TSC_OFFSET_HIGH,&rc); return rc; } + +void SerialPrint_TSC_OFFSET_HIGH() { SerialPrint("TSC_OFFSET_HIGH = %x\n", Get_TSC_OFFSET_HIGH()); } + + +void Set_VIRT_APIC_PAGE_ADDR(uint_t val) { VMCS_WRITE(VIRT_APIC_PAGE_ADDR,val); } +uint_t Get_VIRT_APIC_PAGE_ADDR() { uint_t rc; VMCS_READ(VIRT_APIC_PAGE_ADDR,&rc); return rc; } + +void SerialPrint_VIRT_APIC_PAGE_ADDR() { SerialPrint("VIRT_APIC_PAGE_ADDR = %x\n", Get_VIRT_APIC_PAGE_ADDR()); } + + +void Set_VIRT_APIC_PAGE_ADDR_HIGH(uint_t val) { VMCS_WRITE(VIRT_APIC_PAGE_ADDR_HIGH,val); } +uint_t Get_VIRT_APIC_PAGE_ADDR_HIGH() { uint_t rc; VMCS_READ(VIRT_APIC_PAGE_ADDR_HIGH,&rc); return rc; } + +void SerialPrint_VIRT_APIC_PAGE_ADDR_HIGH() { SerialPrint("VIRT_APIC_PAGE_ADDR_HIGH = %x\n", Get_VIRT_APIC_PAGE_ADDR_HIGH()); } + + +void Set_VMCS_LINK_PTR(uint_t val) { VMCS_WRITE(VMCS_LINK_PTR,val); } +uint_t Get_VMCS_LINK_PTR() { uint_t rc; VMCS_READ(VMCS_LINK_PTR,&rc); return rc; } + +void SerialPrint_VMCS_LINK_PTR() { SerialPrint("VMCS_LINK_PTR = %x\n", Get_VMCS_LINK_PTR()); } + + +void Set_VMCS_LINK_PTR_HIGH(uint_t val) { VMCS_WRITE(VMCS_LINK_PTR_HIGH,val); } +uint_t Get_VMCS_LINK_PTR_HIGH() { uint_t rc; VMCS_READ(VMCS_LINK_PTR_HIGH,&rc); return rc; } + +void SerialPrint_VMCS_LINK_PTR_HIGH() { SerialPrint("VMCS_LINK_PTR_HIGH = %x\n", Get_VMCS_LINK_PTR_HIGH()); } + + +void Set_GUEST_IA32_DEBUGCTL(uint_t val) { VMCS_WRITE(GUEST_IA32_DEBUGCTL,val); } +uint_t Get_GUEST_IA32_DEBUGCTL() { uint_t rc; VMCS_READ(GUEST_IA32_DEBUGCTL,&rc); return rc; } + +void SerialPrint_GUEST_IA32_DEBUGCTL() { SerialPrint("GUEST_IA32_DEBUGCTL = %x\n", Get_GUEST_IA32_DEBUGCTL()); } + + +void Set_GUEST_IA32_DEBUGCTL_HIGH(uint_t val) { VMCS_WRITE(GUEST_IA32_DEBUGCTL_HIGH,val); } +uint_t Get_GUEST_IA32_DEBUGCTL_HIGH() { uint_t rc; VMCS_READ(GUEST_IA32_DEBUGCTL_HIGH,&rc); return rc; } + +void SerialPrint_GUEST_IA32_DEBUGCTL_HIGH() { SerialPrint("GUEST_IA32_DEBUGCTL_HIGH = %x\n", Get_GUEST_IA32_DEBUGCTL_HIGH()); } + + +void Set_PIN_VM_EXEC_CTRLS(uint_t val) { VMCS_WRITE(PIN_VM_EXEC_CTRLS,val); } +uint_t Get_PIN_VM_EXEC_CTRLS() { uint_t rc; VMCS_READ(PIN_VM_EXEC_CTRLS,&rc); return rc; } + +void SerialPrint_PIN_VM_EXEC_CTRLS() { SerialPrint("PIN_VM_EXEC_CTRLS = %x\n", Get_PIN_VM_EXEC_CTRLS()); } + + +void Set_PROC_VM_EXEC_CTRLS(uint_t val) { VMCS_WRITE(PROC_VM_EXEC_CTRLS,val); } +uint_t Get_PROC_VM_EXEC_CTRLS() { uint_t rc; VMCS_READ(PROC_VM_EXEC_CTRLS,&rc); return rc; } + +void SerialPrint_PROC_VM_EXEC_CTRLS() { SerialPrint("PROC_VM_EXEC_CTRLS = %x\n", Get_PROC_VM_EXEC_CTRLS()); } + + +void Set_EXCEPTION_BITMAP(uint_t val) { VMCS_WRITE(EXCEPTION_BITMAP,val); } +uint_t Get_EXCEPTION_BITMAP() { uint_t rc; VMCS_READ(EXCEPTION_BITMAP,&rc); return rc; } + +void SerialPrint_EXCEPTION_BITMAP() { SerialPrint("EXCEPTION_BITMAP = %x\n", Get_EXCEPTION_BITMAP()); } + + +void Set_PAGE_FAULT_ERROR_MASK(uint_t val) { VMCS_WRITE(PAGE_FAULT_ERROR_MASK,val); } +uint_t Get_PAGE_FAULT_ERROR_MASK() { uint_t rc; VMCS_READ(PAGE_FAULT_ERROR_MASK,&rc); return rc; } + +void SerialPrint_PAGE_FAULT_ERROR_MASK() { SerialPrint("PAGE_FAULT_ERROR_MASK = %x\n", Get_PAGE_FAULT_ERROR_MASK()); } + + +void Set_PAGE_FAULT_ERROR_MATCH(uint_t val) { VMCS_WRITE(PAGE_FAULT_ERROR_MATCH,val); } +uint_t Get_PAGE_FAULT_ERROR_MATCH() { uint_t rc; VMCS_READ(PAGE_FAULT_ERROR_MATCH,&rc); return rc; } + +void SerialPrint_PAGE_FAULT_ERROR_MATCH() { SerialPrint("PAGE_FAULT_ERROR_MATCH = %x\n", Get_PAGE_FAULT_ERROR_MATCH()); } + + +void Set_CR3_TARGET_COUNT(uint_t val) { VMCS_WRITE(CR3_TARGET_COUNT,val); } +uint_t Get_CR3_TARGET_COUNT() { uint_t rc; VMCS_READ(CR3_TARGET_COUNT,&rc); return rc; } + +void SerialPrint_CR3_TARGET_COUNT() { SerialPrint("CR3_TARGET_COUNT = %x\n", Get_CR3_TARGET_COUNT()); } + + +void Set_VM_EXIT_CTRLS(uint_t val) { VMCS_WRITE(VM_EXIT_CTRLS,val); } +uint_t Get_VM_EXIT_CTRLS() { uint_t rc; VMCS_READ(VM_EXIT_CTRLS,&rc); return rc; } + +void SerialPrint_VM_EXIT_CTRLS() { SerialPrint("VM_EXIT_CTRLS = %x\n", Get_VM_EXIT_CTRLS()); } + + +void Set_VM_EXIT_MSR_STORE_COUNT(uint_t val) { VMCS_WRITE(VM_EXIT_MSR_STORE_COUNT,val); } +uint_t Get_VM_EXIT_MSR_STORE_COUNT() { uint_t rc; VMCS_READ(VM_EXIT_MSR_STORE_COUNT,&rc); return rc; } + +void SerialPrint_VM_EXIT_MSR_STORE_COUNT() { SerialPrint("VM_EXIT_MSR_STORE_COUNT = %x\n", Get_VM_EXIT_MSR_STORE_COUNT()); } + + +void Set_VM_EXIT_MSR_LOAD_COUNT(uint_t val) { VMCS_WRITE(VM_EXIT_MSR_LOAD_COUNT,val); } +uint_t Get_VM_EXIT_MSR_LOAD_COUNT() { uint_t rc; VMCS_READ(VM_EXIT_MSR_LOAD_COUNT,&rc); return rc; } + +void SerialPrint_VM_EXIT_MSR_LOAD_COUNT() { SerialPrint("VM_EXIT_MSR_LOAD_COUNT = %x\n", Get_VM_EXIT_MSR_LOAD_COUNT()); } + + +void Set_VM_ENTRY_CTRLS(uint_t val) { VMCS_WRITE(VM_ENTRY_CTRLS,val); } +uint_t Get_VM_ENTRY_CTRLS() { uint_t rc; VMCS_READ(VM_ENTRY_CTRLS,&rc); return rc; } + +void SerialPrint_VM_ENTRY_CTRLS() { SerialPrint("VM_ENTRY_CTRLS = %x\n", Get_VM_ENTRY_CTRLS()); } + + +void Set_VM_ENTRY_MSR_LOAD_COUNT(uint_t val) { VMCS_WRITE(VM_ENTRY_MSR_LOAD_COUNT,val); } +uint_t Get_VM_ENTRY_MSR_LOAD_COUNT() { uint_t rc; VMCS_READ(VM_ENTRY_MSR_LOAD_COUNT,&rc); return rc; } + +void SerialPrint_VM_ENTRY_MSR_LOAD_COUNT() { SerialPrint("VM_ENTRY_MSR_LOAD_COUNT = %x\n", Get_VM_ENTRY_MSR_LOAD_COUNT()); } + + +void Set_VM_ENTRY_INT_INFO_FIELD(uint_t val) { VMCS_WRITE(VM_ENTRY_INT_INFO_FIELD,val); } +uint_t Get_VM_ENTRY_INT_INFO_FIELD() { uint_t rc; VMCS_READ(VM_ENTRY_INT_INFO_FIELD,&rc); return rc; } + +void SerialPrint_VM_ENTRY_INT_INFO_FIELD() { SerialPrint("VM_ENTRY_INT_INFO_FIELD = %x\n", Get_VM_ENTRY_INT_INFO_FIELD()); } + + +void Set_VM_ENTRY_EXCEPTION_ERROR(uint_t val) { VMCS_WRITE(VM_ENTRY_EXCEPTION_ERROR,val); } +uint_t Get_VM_ENTRY_EXCEPTION_ERROR() { uint_t rc; VMCS_READ(VM_ENTRY_EXCEPTION_ERROR,&rc); return rc; } + +void SerialPrint_VM_ENTRY_EXCEPTION_ERROR() { SerialPrint("VM_ENTRY_EXCEPTION_ERROR = %x\n", Get_VM_ENTRY_EXCEPTION_ERROR()); } + + +void Set_VM_ENTRY_INSTR_LENGTH(uint_t val) { VMCS_WRITE(VM_ENTRY_INSTR_LENGTH,val); } +uint_t Get_VM_ENTRY_INSTR_LENGTH() { uint_t rc; VMCS_READ(VM_ENTRY_INSTR_LENGTH,&rc); return rc; } + +void SerialPrint_VM_ENTRY_INSTR_LENGTH() { SerialPrint("VM_ENTRY_INSTR_LENGTH = %x\n", Get_VM_ENTRY_INSTR_LENGTH()); } + + +void Set_TPR_THRESHOLD(uint_t val) { VMCS_WRITE(TPR_THRESHOLD,val); } +uint_t Get_TPR_THRESHOLD() { uint_t rc; VMCS_READ(TPR_THRESHOLD,&rc); return rc; } + +void SerialPrint_TPR_THRESHOLD() { SerialPrint("TPR_THRESHOLD = %x\n", Get_TPR_THRESHOLD()); } + + +void Set_VM_INSTR_ERROR(uint_t val) { VMCS_WRITE(VM_INSTR_ERROR,val); } +uint_t Get_VM_INSTR_ERROR() { uint_t rc; VMCS_READ(VM_INSTR_ERROR,&rc); return rc; } + +void SerialPrint_VM_INSTR_ERROR() { SerialPrint("VM_INSTR_ERROR = %x\n", Get_VM_INSTR_ERROR()); } + + +void Set_EXIT_REASON(uint_t val) { VMCS_WRITE(EXIT_REASON,val); } +uint_t Get_EXIT_REASON() { uint_t rc; VMCS_READ(EXIT_REASON,&rc); return rc; } + +void SerialPrint_EXIT_REASON() { SerialPrint("EXIT_REASON = %x\n", Get_EXIT_REASON()); } + + +void Set_VM_EXIT_INT_INFO(uint_t val) { VMCS_WRITE(VM_EXIT_INT_INFO,val); } +uint_t Get_VM_EXIT_INT_INFO() { uint_t rc; VMCS_READ(VM_EXIT_INT_INFO,&rc); return rc; } + +void SerialPrint_VM_EXIT_INT_INFO() { SerialPrint("VM_EXIT_INT_INFO = %x\n", Get_VM_EXIT_INT_INFO()); } + + +void Set_VM_EXIT_INT_ERROR(uint_t val) { VMCS_WRITE(VM_EXIT_INT_ERROR,val); } +uint_t Get_VM_EXIT_INT_ERROR() { uint_t rc; VMCS_READ(VM_EXIT_INT_ERROR,&rc); return rc; } + +void SerialPrint_VM_EXIT_INT_ERROR() { SerialPrint("VM_EXIT_INT_ERROR = %x\n", Get_VM_EXIT_INT_ERROR()); } + + +void Set_IDT_VECTOR_INFO(uint_t val) { VMCS_WRITE(IDT_VECTOR_INFO,val); } +uint_t Get_IDT_VECTOR_INFO() { uint_t rc; VMCS_READ(IDT_VECTOR_INFO,&rc); return rc; } + +void SerialPrint_IDT_VECTOR_INFO() { SerialPrint("IDT_VECTOR_INFO = %x\n", Get_IDT_VECTOR_INFO()); } + + +void Set_IDT_VECTOR_ERROR(uint_t val) { VMCS_WRITE(IDT_VECTOR_ERROR,val); } +uint_t Get_IDT_VECTOR_ERROR() { uint_t rc; VMCS_READ(IDT_VECTOR_ERROR,&rc); return rc; } + +void SerialPrint_IDT_VECTOR_ERROR() { SerialPrint("IDT_VECTOR_ERROR = %x\n", Get_IDT_VECTOR_ERROR()); } + + +void Set_VM_EXIT_INSTR_LENGTH(uint_t val) { VMCS_WRITE(VM_EXIT_INSTR_LENGTH,val); } +uint_t Get_VM_EXIT_INSTR_LENGTH() { uint_t rc; VMCS_READ(VM_EXIT_INSTR_LENGTH,&rc); return rc; } + +void SerialPrint_VM_EXIT_INSTR_LENGTH() { SerialPrint("VM_EXIT_INSTR_LENGTH = %x\n", Get_VM_EXIT_INSTR_LENGTH()); } + + +void Set_VMX_INSTR_INFO(uint_t val) { VMCS_WRITE(VMX_INSTR_INFO,val); } +uint_t Get_VMX_INSTR_INFO() { uint_t rc; VMCS_READ(VMX_INSTR_INFO,&rc); return rc; } + +void SerialPrint_VMX_INSTR_INFO() { SerialPrint("VMX_INSTR_INFO = %x\n", Get_VMX_INSTR_INFO()); } + + +void Set_GUEST_ES_LIMIT(uint_t val) { VMCS_WRITE(GUEST_ES_LIMIT,val); } +uint_t Get_GUEST_ES_LIMIT() { uint_t rc; VMCS_READ(GUEST_ES_LIMIT,&rc); return rc; } + +void SerialPrint_GUEST_ES_LIMIT() { SerialPrint("GUEST_ES_LIMIT = %x\n", Get_GUEST_ES_LIMIT()); } + + +void Set_GUEST_CS_LIMIT(uint_t val) { VMCS_WRITE(GUEST_CS_LIMIT,val); } +uint_t Get_GUEST_CS_LIMIT() { uint_t rc; VMCS_READ(GUEST_CS_LIMIT,&rc); return rc; } + +void SerialPrint_GUEST_CS_LIMIT() { SerialPrint("GUEST_CS_LIMIT = %x\n", Get_GUEST_CS_LIMIT()); } + + +void Set_GUEST_SS_LIMIT(uint_t val) { VMCS_WRITE(GUEST_SS_LIMIT,val); } +uint_t Get_GUEST_SS_LIMIT() { uint_t rc; VMCS_READ(GUEST_SS_LIMIT,&rc); return rc; } + +void SerialPrint_GUEST_SS_LIMIT() { SerialPrint("GUEST_SS_LIMIT = %x\n", Get_GUEST_SS_LIMIT()); } + + +void Set_GUEST_DS_LIMIT(uint_t val) { VMCS_WRITE(GUEST_DS_LIMIT,val); } +uint_t Get_GUEST_DS_LIMIT() { uint_t rc; VMCS_READ(GUEST_DS_LIMIT,&rc); return rc; } + +void SerialPrint_GUEST_DS_LIMIT() { SerialPrint("GUEST_DS_LIMIT = %x\n", Get_GUEST_DS_LIMIT()); } + + +void Set_GUEST_FS_LIMIT(uint_t val) { VMCS_WRITE(GUEST_FS_LIMIT,val); } +uint_t Get_GUEST_FS_LIMIT() { uint_t rc; VMCS_READ(GUEST_FS_LIMIT,&rc); return rc; } + +void SerialPrint_GUEST_FS_LIMIT() { SerialPrint("GUEST_FS_LIMIT = %x\n", Get_GUEST_FS_LIMIT()); } + + +void Set_GUEST_GS_LIMIT(uint_t val) { VMCS_WRITE(GUEST_GS_LIMIT,val); } +uint_t Get_GUEST_GS_LIMIT() { uint_t rc; VMCS_READ(GUEST_GS_LIMIT,&rc); return rc; } + +void SerialPrint_GUEST_GS_LIMIT() { SerialPrint("GUEST_GS_LIMIT = %x\n", Get_GUEST_GS_LIMIT()); } + + +void Set_GUEST_LDTR_LIMIT(uint_t val) { VMCS_WRITE(GUEST_LDTR_LIMIT,val); } +uint_t Get_GUEST_LDTR_LIMIT() { uint_t rc; VMCS_READ(GUEST_LDTR_LIMIT,&rc); return rc; } + +void SerialPrint_GUEST_LDTR_LIMIT() { SerialPrint("GUEST_LDTR_LIMIT = %x\n", Get_GUEST_LDTR_LIMIT()); } + + +void Set_GUEST_TR_LIMIT(uint_t val) { VMCS_WRITE(GUEST_TR_LIMIT,val); } +uint_t Get_GUEST_TR_LIMIT() { uint_t rc; VMCS_READ(GUEST_TR_LIMIT,&rc); return rc; } + +void SerialPrint_GUEST_TR_LIMIT() { SerialPrint("GUEST_TR_LIMIT = %x\n", Get_GUEST_TR_LIMIT()); } + + +void Set_GUEST_GDTR_LIMIT(uint_t val) { VMCS_WRITE(GUEST_GDTR_LIMIT,val); } +uint_t Get_GUEST_GDTR_LIMIT() { uint_t rc; VMCS_READ(GUEST_GDTR_LIMIT,&rc); return rc; } + +void SerialPrint_GUEST_GDTR_LIMIT() { SerialPrint("GUEST_GDTR_LIMIT = %x\n", Get_GUEST_GDTR_LIMIT()); } + + +void Set_GUEST_IDTR_LIMIT(uint_t val) { VMCS_WRITE(GUEST_IDTR_LIMIT,val); } +uint_t Get_GUEST_IDTR_LIMIT() { uint_t rc; VMCS_READ(GUEST_IDTR_LIMIT,&rc); return rc; } + +void SerialPrint_GUEST_IDTR_LIMIT() { SerialPrint("GUEST_IDTR_LIMIT = %x\n", Get_GUEST_IDTR_LIMIT()); } + + +void Set_GUEST_ES_ACCESS(uint_t val) { VMCS_WRITE(GUEST_ES_ACCESS,val); } +uint_t Get_GUEST_ES_ACCESS() { uint_t rc; VMCS_READ(GUEST_ES_ACCESS,&rc); return rc; } + +void SerialPrint_GUEST_ES_ACCESS() { SerialPrint("GUEST_ES_ACCESS = %x\n", Get_GUEST_ES_ACCESS()); } + + +void Set_GUEST_CS_ACCESS(uint_t val) { VMCS_WRITE(GUEST_CS_ACCESS,val); } +uint_t Get_GUEST_CS_ACCESS() { uint_t rc; VMCS_READ(GUEST_CS_ACCESS,&rc); return rc; } + +void SerialPrint_GUEST_CS_ACCESS() { SerialPrint("GUEST_CS_ACCESS = %x\n", Get_GUEST_CS_ACCESS()); } + + +void Set_GUEST_SS_ACCESS(uint_t val) { VMCS_WRITE(GUEST_SS_ACCESS,val); } +uint_t Get_GUEST_SS_ACCESS() { uint_t rc; VMCS_READ(GUEST_SS_ACCESS,&rc); return rc; } + +void SerialPrint_GUEST_SS_ACCESS() { SerialPrint("GUEST_SS_ACCESS = %x\n", Get_GUEST_SS_ACCESS()); } + + +void Set_GUEST_DS_ACCESS(uint_t val) { VMCS_WRITE(GUEST_DS_ACCESS,val); } +uint_t Get_GUEST_DS_ACCESS() { uint_t rc; VMCS_READ(GUEST_DS_ACCESS,&rc); return rc; } + +void SerialPrint_GUEST_DS_ACCESS() { SerialPrint("GUEST_DS_ACCESS = %x\n", Get_GUEST_DS_ACCESS()); } + + +void Set_GUEST_FS_ACCESS(uint_t val) { VMCS_WRITE(GUEST_FS_ACCESS,val); } +uint_t Get_GUEST_FS_ACCESS() { uint_t rc; VMCS_READ(GUEST_FS_ACCESS,&rc); return rc; } + +void SerialPrint_GUEST_FS_ACCESS() { SerialPrint("GUEST_FS_ACCESS = %x\n", Get_GUEST_FS_ACCESS()); } + + +void Set_GUEST_GS_ACCESS(uint_t val) { VMCS_WRITE(GUEST_GS_ACCESS,val); } +uint_t Get_GUEST_GS_ACCESS() { uint_t rc; VMCS_READ(GUEST_GS_ACCESS,&rc); return rc; } + +void SerialPrint_GUEST_GS_ACCESS() { SerialPrint("GUEST_GS_ACCESS = %x\n", Get_GUEST_GS_ACCESS()); } + + +void Set_GUEST_LDTR_ACCESS(uint_t val) { VMCS_WRITE(GUEST_LDTR_ACCESS,val); } +uint_t Get_GUEST_LDTR_ACCESS() { uint_t rc; VMCS_READ(GUEST_LDTR_ACCESS,&rc); return rc; } + +void SerialPrint_GUEST_LDTR_ACCESS() { SerialPrint("GUEST_LDTR_ACCESS = %x\n", Get_GUEST_LDTR_ACCESS()); } + + +void Set_GUEST_TR_ACCESS(uint_t val) { VMCS_WRITE(GUEST_TR_ACCESS,val); } +uint_t Get_GUEST_TR_ACCESS() { uint_t rc; VMCS_READ(GUEST_TR_ACCESS,&rc); return rc; } + +void SerialPrint_GUEST_TR_ACCESS() { SerialPrint("GUEST_TR_ACCESS = %x\n", Get_GUEST_TR_ACCESS()); } + + +void Set_GUEST_INT_STATE(uint_t val) { VMCS_WRITE(GUEST_INT_STATE,val); } +uint_t Get_GUEST_INT_STATE() { uint_t rc; VMCS_READ(GUEST_INT_STATE,&rc); return rc; } + +void SerialPrint_GUEST_INT_STATE() { SerialPrint("GUEST_INT_STATE = %x\n", Get_GUEST_INT_STATE()); } + + +void Set_GUEST_ACTIVITY_STATE(uint_t val) { VMCS_WRITE(GUEST_ACTIVITY_STATE,val); } +uint_t Get_GUEST_ACTIVITY_STATE() { uint_t rc; VMCS_READ(GUEST_ACTIVITY_STATE,&rc); return rc; } + +void SerialPrint_GUEST_ACTIVITY_STATE() { SerialPrint("GUEST_ACTIVITY_STATE = %x\n", Get_GUEST_ACTIVITY_STATE()); } + + +void Set_GUEST_SMBASE(uint_t val) { VMCS_WRITE(GUEST_SMBASE,val); } +uint_t Get_GUEST_SMBASE() { uint_t rc; VMCS_READ(GUEST_SMBASE,&rc); return rc; } + +void SerialPrint_GUEST_SMBASE() { SerialPrint("GUEST_SMBASE = %x\n", Get_GUEST_SMBASE()); } + + +void Set_GUEST_IA32_SYSENTER_CS(uint_t val) { VMCS_WRITE(GUEST_IA32_SYSENTER_CS,val); } +uint_t Get_GUEST_IA32_SYSENTER_CS() { uint_t rc; VMCS_READ(GUEST_IA32_SYSENTER_CS,&rc); return rc; } + +void SerialPrint_GUEST_IA32_SYSENTER_CS() { SerialPrint("GUEST_IA32_SYSENTER_CS = %x\n", Get_GUEST_IA32_SYSENTER_CS()); } + + +void Set_HOST_IA32_SYSENTER_CS(uint_t val) { VMCS_WRITE(HOST_IA32_SYSENTER_CS,val); } +uint_t Get_HOST_IA32_SYSENTER_CS() { uint_t rc; VMCS_READ(HOST_IA32_SYSENTER_CS,&rc); return rc; } + +void SerialPrint_HOST_IA32_SYSENTER_CS() { SerialPrint("HOST_IA32_SYSENTER_CS = %x\n", Get_HOST_IA32_SYSENTER_CS()); } + + +void Set_CR0_GUEST_HOST_MASK(uint_t val) { VMCS_WRITE(CR0_GUEST_HOST_MASK,val); } +uint_t Get_CR0_GUEST_HOST_MASK() { uint_t rc; VMCS_READ(CR0_GUEST_HOST_MASK,&rc); return rc; } + +void SerialPrint_CR0_GUEST_HOST_MASK() { SerialPrint("CR0_GUEST_HOST_MASK = %x\n", Get_CR0_GUEST_HOST_MASK()); } + + +void Set_CR4_GUEST_HOST_MASK(uint_t val) { VMCS_WRITE(CR4_GUEST_HOST_MASK,val); } +uint_t Get_CR4_GUEST_HOST_MASK() { uint_t rc; VMCS_READ(CR4_GUEST_HOST_MASK,&rc); return rc; } + +void SerialPrint_CR4_GUEST_HOST_MASK() { SerialPrint("CR4_GUEST_HOST_MASK = %x\n", Get_CR4_GUEST_HOST_MASK()); } + + +void Set_CR0_READ_SHADOW(uint_t val) { VMCS_WRITE(CR0_READ_SHADOW,val); } +uint_t Get_CR0_READ_SHADOW() { uint_t rc; VMCS_READ(CR0_READ_SHADOW,&rc); return rc; } + +void SerialPrint_CR0_READ_SHADOW() { SerialPrint("CR0_READ_SHADOW = %x\n", Get_CR0_READ_SHADOW()); } + + +void Set_CR4_READ_SHADOW(uint_t val) { VMCS_WRITE(CR4_READ_SHADOW,val); } +uint_t Get_CR4_READ_SHADOW() { uint_t rc; VMCS_READ(CR4_READ_SHADOW,&rc); return rc; } + +void SerialPrint_CR4_READ_SHADOW() { SerialPrint("CR4_READ_SHADOW = %x\n", Get_CR4_READ_SHADOW()); } + + +void Set_CR3_TARGET_VALUE_0(uint_t val) { VMCS_WRITE(CR3_TARGET_VALUE_0,val); } +uint_t Get_CR3_TARGET_VALUE_0() { uint_t rc; VMCS_READ(CR3_TARGET_VALUE_0,&rc); return rc; } + +void SerialPrint_CR3_TARGET_VALUE_0() { SerialPrint("CR3_TARGET_VALUE_0 = %x\n", Get_CR3_TARGET_VALUE_0()); } + + +void Set_CR3_TARGET_VALUE_1(uint_t val) { VMCS_WRITE(CR3_TARGET_VALUE_1,val); } +uint_t Get_CR3_TARGET_VALUE_1() { uint_t rc; VMCS_READ(CR3_TARGET_VALUE_1,&rc); return rc; } + +void SerialPrint_CR3_TARGET_VALUE_1() { SerialPrint("CR3_TARGET_VALUE_1 = %x\n", Get_CR3_TARGET_VALUE_1()); } + + +void Set_CR3_TARGET_VALUE_2(uint_t val) { VMCS_WRITE(CR3_TARGET_VALUE_2,val); } +uint_t Get_CR3_TARGET_VALUE_2() { uint_t rc; VMCS_READ(CR3_TARGET_VALUE_2,&rc); return rc; } + +void SerialPrint_CR3_TARGET_VALUE_2() { SerialPrint("CR3_TARGET_VALUE_2 = %x\n", Get_CR3_TARGET_VALUE_2()); } + + +void Set_CR3_TARGET_VALUE_3(uint_t val) { VMCS_WRITE(CR3_TARGET_VALUE_3,val); } +uint_t Get_CR3_TARGET_VALUE_3() { uint_t rc; VMCS_READ(CR3_TARGET_VALUE_3,&rc); return rc; } + +void SerialPrint_CR3_TARGET_VALUE_3() { SerialPrint("CR3_TARGET_VALUE_3 = %x\n", Get_CR3_TARGET_VALUE_3()); } + + +void Set_EXIT_QUALIFICATION(uint_t val) { VMCS_WRITE(EXIT_QUALIFICATION,val); } +uint_t Get_EXIT_QUALIFICATION() { uint_t rc; VMCS_READ(EXIT_QUALIFICATION,&rc); return rc; } + +void SerialPrint_EXIT_QUALIFICATION() { SerialPrint("EXIT_QUALIFICATION = %x\n", Get_EXIT_QUALIFICATION()); } + + +void Set_IO_RCX(uint_t val) { VMCS_WRITE(IO_RCX,val); } +uint_t Get_IO_RCX() { uint_t rc; VMCS_READ(IO_RCX,&rc); return rc; } + +void SerialPrint_IO_RCX() { SerialPrint("IO_RCX = %x\n", Get_IO_RCX()); } + + +void Set_IO_RSI(uint_t val) { VMCS_WRITE(IO_RSI,val); } +uint_t Get_IO_RSI() { uint_t rc; VMCS_READ(IO_RSI,&rc); return rc; } + +void SerialPrint_IO_RSI() { SerialPrint("IO_RSI = %x\n", Get_IO_RSI()); } + + +void Set_IO_RDI(uint_t val) { VMCS_WRITE(IO_RDI,val); } +uint_t Get_IO_RDI() { uint_t rc; VMCS_READ(IO_RDI,&rc); return rc; } + +void SerialPrint_IO_RDI() { SerialPrint("IO_RDI = %x\n", Get_IO_RDI()); } + + +void Set_IO_RIP(uint_t val) { VMCS_WRITE(IO_RIP,val); } +uint_t Get_IO_RIP() { uint_t rc; VMCS_READ(IO_RIP,&rc); return rc; } + +void SerialPrint_IO_RIP() { SerialPrint("IO_RIP = %x\n", Get_IO_RIP()); } + + +void Set_GUEST_LINEAR_ADDR(uint_t val) { VMCS_WRITE(GUEST_LINEAR_ADDR,val); } +uint_t Get_GUEST_LINEAR_ADDR() { uint_t rc; VMCS_READ(GUEST_LINEAR_ADDR,&rc); return rc; } + +void SerialPrint_GUEST_LINEAR_ADDR() { SerialPrint("GUEST_LINEAR_ADDR = %x\n", Get_GUEST_LINEAR_ADDR()); } + + +void Set_GUEST_CR0(uint_t val) { VMCS_WRITE(GUEST_CR0,val); } +uint_t Get_GUEST_CR0() { uint_t rc; VMCS_READ(GUEST_CR0,&rc); return rc; } + +void SerialPrint_GUEST_CR0() { SerialPrint("GUEST_CR0 = %x\n", Get_GUEST_CR0()); } + + +void Set_GUEST_CR3(uint_t val) { VMCS_WRITE(GUEST_CR3,val); } +uint_t Get_GUEST_CR3() { uint_t rc; VMCS_READ(GUEST_CR3,&rc); return rc; } + +void SerialPrint_GUEST_CR3() { SerialPrint("GUEST_CR3 = %x\n", Get_GUEST_CR3()); } + + +void Set_GUEST_CR4(uint_t val) { VMCS_WRITE(GUEST_CR4,val); } +uint_t Get_GUEST_CR4() { uint_t rc; VMCS_READ(GUEST_CR4,&rc); return rc; } + +void SerialPrint_GUEST_CR4() { SerialPrint("GUEST_CR4 = %x\n", Get_GUEST_CR4()); } + + +void Set_GUEST_ES_BASE(uint_t val) { VMCS_WRITE(GUEST_ES_BASE,val); } +uint_t Get_GUEST_ES_BASE() { uint_t rc; VMCS_READ(GUEST_ES_BASE,&rc); return rc; } + +void SerialPrint_GUEST_ES_BASE() { SerialPrint("GUEST_ES_BASE = %x\n", Get_GUEST_ES_BASE()); } + + +void Set_GUEST_CS_BASE(uint_t val) { VMCS_WRITE(GUEST_CS_BASE,val); } +uint_t Get_GUEST_CS_BASE() { uint_t rc; VMCS_READ(GUEST_CS_BASE,&rc); return rc; } + +void SerialPrint_GUEST_CS_BASE() { SerialPrint("GUEST_CS_BASE = %x\n", Get_GUEST_CS_BASE()); } + + +void Set_GUEST_SS_BASE(uint_t val) { VMCS_WRITE(GUEST_SS_BASE,val); } +uint_t Get_GUEST_SS_BASE() { uint_t rc; VMCS_READ(GUEST_SS_BASE,&rc); return rc; } + +void SerialPrint_GUEST_SS_BASE() { SerialPrint("GUEST_SS_BASE = %x\n", Get_GUEST_SS_BASE()); } + + +void Set_GUEST_DS_BASE(uint_t val) { VMCS_WRITE(GUEST_DS_BASE,val); } +uint_t Get_GUEST_DS_BASE() { uint_t rc; VMCS_READ(GUEST_DS_BASE,&rc); return rc; } + +void SerialPrint_GUEST_DS_BASE() { SerialPrint("GUEST_DS_BASE = %x\n", Get_GUEST_DS_BASE()); } + + +void Set_GUEST_FS_BASE(uint_t val) { VMCS_WRITE(GUEST_FS_BASE,val); } +uint_t Get_GUEST_FS_BASE() { uint_t rc; VMCS_READ(GUEST_FS_BASE,&rc); return rc; } + +void SerialPrint_GUEST_FS_BASE() { SerialPrint("GUEST_FS_BASE = %x\n", Get_GUEST_FS_BASE()); } + + +void Set_GUEST_GS_BASE(uint_t val) { VMCS_WRITE(GUEST_GS_BASE,val); } +uint_t Get_GUEST_GS_BASE() { uint_t rc; VMCS_READ(GUEST_GS_BASE,&rc); return rc; } + +void SerialPrint_GUEST_GS_BASE() { SerialPrint("GUEST_GS_BASE = %x\n", Get_GUEST_GS_BASE()); } + + +void Set_GUEST_LDTR_BASE(uint_t val) { VMCS_WRITE(GUEST_LDTR_BASE,val); } +uint_t Get_GUEST_LDTR_BASE() { uint_t rc; VMCS_READ(GUEST_LDTR_BASE,&rc); return rc; } + +void SerialPrint_GUEST_LDTR_BASE() { SerialPrint("GUEST_LDTR_BASE = %x\n", Get_GUEST_LDTR_BASE()); } + + +void Set_GUEST_TR_BASE(uint_t val) { VMCS_WRITE(GUEST_TR_BASE,val); } +uint_t Get_GUEST_TR_BASE() { uint_t rc; VMCS_READ(GUEST_TR_BASE,&rc); return rc; } + +void SerialPrint_GUEST_TR_BASE() { SerialPrint("GUEST_TR_BASE = %x\n", Get_GUEST_TR_BASE()); } + + +void Set_GUEST_GDTR_BASE(uint_t val) { VMCS_WRITE(GUEST_GDTR_BASE,val); } +uint_t Get_GUEST_GDTR_BASE() { uint_t rc; VMCS_READ(GUEST_GDTR_BASE,&rc); return rc; } + +void SerialPrint_GUEST_GDTR_BASE() { SerialPrint("GUEST_GDTR_BASE = %x\n", Get_GUEST_GDTR_BASE()); } + + +void Set_GUEST_IDTR_BASE(uint_t val) { VMCS_WRITE(GUEST_IDTR_BASE,val); } +uint_t Get_GUEST_IDTR_BASE() { uint_t rc; VMCS_READ(GUEST_IDTR_BASE,&rc); return rc; } + +void SerialPrint_GUEST_IDTR_BASE() { SerialPrint("GUEST_IDTR_BASE = %x\n", Get_GUEST_IDTR_BASE()); } + + +void Set_GUEST_DR7(uint_t val) { VMCS_WRITE(GUEST_DR7,val); } +uint_t Get_GUEST_DR7() { uint_t rc; VMCS_READ(GUEST_DR7,&rc); return rc; } + +void SerialPrint_GUEST_DR7() { SerialPrint("GUEST_DR7 = %x\n", Get_GUEST_DR7()); } + + +void Set_GUEST_RSP(uint_t val) { VMCS_WRITE(GUEST_RSP,val); } +uint_t Get_GUEST_RSP() { uint_t rc; VMCS_READ(GUEST_RSP,&rc); return rc; } + +void SerialPrint_GUEST_RSP() { SerialPrint("GUEST_RSP = %x\n", Get_GUEST_RSP()); } + + +void Set_GUEST_RIP(uint_t val) { VMCS_WRITE(GUEST_RIP,val); } +uint_t Get_GUEST_RIP() { uint_t rc; VMCS_READ(GUEST_RIP,&rc); return rc; } + +void SerialPrint_GUEST_RIP() { SerialPrint("GUEST_RIP = %x\n", Get_GUEST_RIP()); } + + +void Set_GUEST_RFLAGS(uint_t val) { VMCS_WRITE(GUEST_RFLAGS,val); } +uint_t Get_GUEST_RFLAGS() { uint_t rc; VMCS_READ(GUEST_RFLAGS,&rc); return rc; } + +void SerialPrint_GUEST_RFLAGS() { SerialPrint("GUEST_RFLAGS = %x\n", Get_GUEST_RFLAGS()); } + + +void Set_GUEST_PENDING_DEBUG_EXCS(uint_t val) { VMCS_WRITE(GUEST_PENDING_DEBUG_EXCS,val); } +uint_t Get_GUEST_PENDING_DEBUG_EXCS() { uint_t rc; VMCS_READ(GUEST_PENDING_DEBUG_EXCS,&rc); return rc; } + +void SerialPrint_GUEST_PENDING_DEBUG_EXCS() { SerialPrint("GUEST_PENDING_DEBUG_EXCS = %x\n", Get_GUEST_PENDING_DEBUG_EXCS()); } + + +void Set_GUEST_IA32_SYSENTER_ESP(uint_t val) { VMCS_WRITE(GUEST_IA32_SYSENTER_ESP,val); } +uint_t Get_GUEST_IA32_SYSENTER_ESP() { uint_t rc; VMCS_READ(GUEST_IA32_SYSENTER_ESP,&rc); return rc; } + +void SerialPrint_GUEST_IA32_SYSENTER_ESP() { SerialPrint("GUEST_IA32_SYSENTER_ESP = %x\n", Get_GUEST_IA32_SYSENTER_ESP()); } + + +void Set_GUEST_IA32_SYSENTER_EIP(uint_t val) { VMCS_WRITE(GUEST_IA32_SYSENTER_EIP,val); } +uint_t Get_GUEST_IA32_SYSENTER_EIP() { uint_t rc; VMCS_READ(GUEST_IA32_SYSENTER_EIP,&rc); return rc; } + +void SerialPrint_GUEST_IA32_SYSENTER_EIP() { SerialPrint("GUEST_IA32_SYSENTER_EIP = %x\n", Get_GUEST_IA32_SYSENTER_EIP()); } + + +void Set_HOST_CR0(uint_t val) { VMCS_WRITE(HOST_CR0,val); } +uint_t Get_HOST_CR0() { uint_t rc; VMCS_READ(HOST_CR0,&rc); return rc; } + +void SerialPrint_HOST_CR0() { SerialPrint("HOST_CR0 = %x\n", Get_HOST_CR0()); } + + +void Set_HOST_CR3(uint_t val) { VMCS_WRITE(HOST_CR3,val); } +uint_t Get_HOST_CR3() { uint_t rc; VMCS_READ(HOST_CR3,&rc); return rc; } + +void SerialPrint_HOST_CR3() { SerialPrint("HOST_CR3 = %x\n", Get_HOST_CR3()); } + + +void Set_HOST_CR4(uint_t val) { VMCS_WRITE(HOST_CR4,val); } +uint_t Get_HOST_CR4() { uint_t rc; VMCS_READ(HOST_CR4,&rc); return rc; } + +void SerialPrint_HOST_CR4() { SerialPrint("HOST_CR4 = %x\n", Get_HOST_CR4()); } + + +void Set_HOST_FS_BASE(uint_t val) { VMCS_WRITE(HOST_FS_BASE,val); } +uint_t Get_HOST_FS_BASE() { uint_t rc; VMCS_READ(HOST_FS_BASE,&rc); return rc; } + +void SerialPrint_HOST_FS_BASE() { SerialPrint("HOST_FS_BASE = %x\n", Get_HOST_FS_BASE()); } + + +void Set_HOST_GS_BASE(uint_t val) { VMCS_WRITE(HOST_GS_BASE,val); } +uint_t Get_HOST_GS_BASE() { uint_t rc; VMCS_READ(HOST_GS_BASE,&rc); return rc; } + +void SerialPrint_HOST_GS_BASE() { SerialPrint("HOST_GS_BASE = %x\n", Get_HOST_GS_BASE()); } + + +void Set_HOST_TR_BASE(uint_t val) { VMCS_WRITE(HOST_TR_BASE,val); } +uint_t Get_HOST_TR_BASE() { uint_t rc; VMCS_READ(HOST_TR_BASE,&rc); return rc; } + +void SerialPrint_HOST_TR_BASE() { SerialPrint("HOST_TR_BASE = %x\n", Get_HOST_TR_BASE()); } + + +void Set_HOST_GDTR_BASE(uint_t val) { VMCS_WRITE(HOST_GDTR_BASE,val); } +uint_t Get_HOST_GDTR_BASE() { uint_t rc; VMCS_READ(HOST_GDTR_BASE,&rc); return rc; } + +void SerialPrint_HOST_GDTR_BASE() { SerialPrint("HOST_GDTR_BASE = %x\n", Get_HOST_GDTR_BASE()); } + + +void Set_HOST_IDTR_BASE(uint_t val) { VMCS_WRITE(HOST_IDTR_BASE,val); } +uint_t Get_HOST_IDTR_BASE() { uint_t rc; VMCS_READ(HOST_IDTR_BASE,&rc); return rc; } + +void SerialPrint_HOST_IDTR_BASE() { SerialPrint("HOST_IDTR_BASE = %x\n", Get_HOST_IDTR_BASE()); } + + +void Set_HOST_IA32_SYSENTER_ESP(uint_t val) { VMCS_WRITE(HOST_IA32_SYSENTER_ESP,val); } +uint_t Get_HOST_IA32_SYSENTER_ESP() { uint_t rc; VMCS_READ(HOST_IA32_SYSENTER_ESP,&rc); return rc; } + +void SerialPrint_HOST_IA32_SYSENTER_ESP() { SerialPrint("HOST_IA32_SYSENTER_ESP = %x\n", Get_HOST_IA32_SYSENTER_ESP()); } + + +void Set_HOST_IA32_SYSENTER_EIP(uint_t val) { VMCS_WRITE(HOST_IA32_SYSENTER_EIP,val); } +uint_t Get_HOST_IA32_SYSENTER_EIP() { uint_t rc; VMCS_READ(HOST_IA32_SYSENTER_EIP,&rc); return rc; } + +void SerialPrint_HOST_IA32_SYSENTER_EIP() { SerialPrint("HOST_IA32_SYSENTER_EIP = %x\n", Get_HOST_IA32_SYSENTER_EIP()); } + + +void Set_HOST_RSP(uint_t val) { VMCS_WRITE(HOST_RSP,val); } +uint_t Get_HOST_RSP() { uint_t rc; VMCS_READ(HOST_RSP,&rc); return rc; } + +void SerialPrint_HOST_RSP() { SerialPrint("HOST_RSP = %x\n", Get_HOST_RSP()); } + + +void Set_HOST_RIP(uint_t val) { VMCS_WRITE(HOST_RIP,val); } +uint_t Get_HOST_RIP() { uint_t rc; VMCS_READ(HOST_RIP,&rc); return rc; } + +void SerialPrint_HOST_RIP() { SerialPrint("HOST_RIP = %x\n", Get_HOST_RIP()); } + +void SerialPrint_VMCS_ALL() { + + SerialPrint("==>Guest State Area\n"); + SerialPrint("==>==> Guest Register State\n"); + SerialPrint_GUEST_CR0(); + SerialPrint_GUEST_CR3(); + SerialPrint_GUEST_CR4(); + SerialPrint_GUEST_DR7(); + SerialPrint_GUEST_RSP(); + SerialPrint_GUEST_RIP(); + SerialPrint_GUEST_RFLAGS(); + SerialPrint_VMCS_GUEST_CS_SELECTOR(); + SerialPrint_VMCS_GUEST_SS_SELECTOR(); + SerialPrint_VMCS_GUEST_DS_SELECTOR(); + SerialPrint_VMCS_GUEST_ES_SELECTOR(); + SerialPrint_VMCS_GUEST_FS_SELECTOR(); + SerialPrint_VMCS_GUEST_GS_SELECTOR(); + SerialPrint_VMCS_GUEST_LDTR_SELECTOR(); + SerialPrint_VMCS_GUEST_TR_SELECTOR(); + SerialPrint_GUEST_CS_BASE(); + SerialPrint_GUEST_SS_BASE(); + SerialPrint_GUEST_DS_BASE(); + SerialPrint_GUEST_ES_BASE(); + SerialPrint_GUEST_FS_BASE(); + SerialPrint_GUEST_GS_BASE(); + SerialPrint_GUEST_LDTR_BASE(); + SerialPrint_GUEST_TR_BASE(); + SerialPrint_GUEST_CS_LIMIT(); + SerialPrint_GUEST_SS_LIMIT(); + SerialPrint_GUEST_DS_LIMIT(); + SerialPrint_GUEST_ES_LIMIT(); + SerialPrint_GUEST_FS_LIMIT(); + SerialPrint_GUEST_GS_LIMIT(); + SerialPrint_GUEST_LDTR_LIMIT(); + SerialPrint_GUEST_TR_LIMIT(); + SerialPrint_GUEST_ES_ACCESS(); + SerialPrint_GUEST_CS_ACCESS(); + SerialPrint_GUEST_SS_ACCESS(); + SerialPrint_GUEST_DS_ACCESS(); + SerialPrint_GUEST_FS_ACCESS(); + SerialPrint_GUEST_GS_ACCESS(); + SerialPrint_GUEST_LDTR_ACCESS(); + SerialPrint_GUEST_TR_ACCESS(); + SerialPrint_GUEST_GDTR_BASE(); + SerialPrint_GUEST_IDTR_BASE(); + SerialPrint_GUEST_GDTR_LIMIT(); + SerialPrint_GUEST_IDTR_LIMIT(); + SerialPrint_GUEST_IA32_DEBUGCTL(); + SerialPrint_GUEST_IA32_DEBUGCTL_HIGH(); + SerialPrint_GUEST_IA32_SYSENTER_CS(); + SerialPrint_GUEST_IA32_SYSENTER_ESP(); + SerialPrint_GUEST_IA32_SYSENTER_EIP(); + SerialPrint_GUEST_SMBASE(); + + SerialPrint("==>==> Guest Non-Register State\n"); + SerialPrint_GUEST_ACTIVITY_STATE(); + SerialPrint_GUEST_INT_STATE(); + SerialPrint_GUEST_PENDING_DEBUG_EXCS(); + SerialPrint_VMCS_LINK_PTR(); + SerialPrint_VMCS_LINK_PTR_HIGH(); + + SerialPrint("\n==> Host State Area\n"); + SerialPrint_HOST_CR0(); + SerialPrint_HOST_CR3(); + SerialPrint_HOST_CR4(); + SerialPrint_HOST_RSP(); + SerialPrint_HOST_RIP(); + SerialPrint_VMCS_HOST_CS_SELECTOR(); + SerialPrint_VMCS_HOST_SS_SELECTOR(); + SerialPrint_VMCS_HOST_DS_SELECTOR(); + SerialPrint_VMCS_HOST_ES_SELECTOR(); + SerialPrint_VMCS_HOST_FS_SELECTOR(); + SerialPrint_VMCS_HOST_GS_SELECTOR(); + SerialPrint_VMCS_HOST_TR_SELECTOR(); + SerialPrint_HOST_FS_BASE(); + SerialPrint_HOST_GS_BASE(); + SerialPrint_HOST_TR_BASE(); + SerialPrint_HOST_GDTR_BASE(); + SerialPrint_HOST_IDTR_BASE(); + SerialPrint_HOST_IA32_SYSENTER_CS(); + SerialPrint_HOST_IA32_SYSENTER_ESP(); + SerialPrint_HOST_IA32_SYSENTER_EIP(); + + + SerialPrint("\n==> VM-Execution Controls:\n"); + SerialPrint_PIN_VM_EXEC_CTRLS(); + SerialPrint_PROC_VM_EXEC_CTRLS(); + SerialPrint_EXCEPTION_BITMAP(); + SerialPrint_PAGE_FAULT_ERROR_MASK(); + SerialPrint_PAGE_FAULT_ERROR_MATCH(); + SerialPrint_IO_BITMAP_A_ADDR(); + SerialPrint_IO_BITMAP_A_ADDR_HIGH(); + SerialPrint_IO_BITMAP_B_ADDR(); + SerialPrint_IO_BITMAP_B_ADDR_HIGH(); + SerialPrint_TSC_OFFSET(); + SerialPrint_TSC_OFFSET_HIGH(); + SerialPrint_CR0_GUEST_HOST_MASK(); + SerialPrint_CR0_READ_SHADOW(); + SerialPrint_CR4_GUEST_HOST_MASK(); + SerialPrint_CR4_READ_SHADOW(); + SerialPrint_CR3_TARGET_COUNT(); + SerialPrint_CR3_TARGET_VALUE_0(); + SerialPrint_CR3_TARGET_VALUE_1(); + SerialPrint_CR3_TARGET_VALUE_2(); + SerialPrint_CR3_TARGET_VALUE_3(); + SerialPrint_VIRT_APIC_PAGE_ADDR(); + SerialPrint_VIRT_APIC_PAGE_ADDR_HIGH(); + SerialPrint_TPR_THRESHOLD(); + SerialPrint_MSR_BITMAPS(); + SerialPrint_MSR_BITMAPS_HIGH(); + SerialPrint_VMCS_EXEC_PTR(); + SerialPrint_VMCS_EXEC_PTR_HIGH(); + + SerialPrint("\n==> VM Exit Controls\n"); + SerialPrint_VM_EXIT_CTRLS(); + SerialPrint_VM_EXIT_MSR_STORE_COUNT(); + SerialPrint_VM_EXIT_MSR_STORE_ADDR(); + SerialPrint_VM_EXIT_MSR_STORE_ADDR_HIGH(); + SerialPrint_VM_EXIT_MSR_LOAD_COUNT(); + SerialPrint_VM_EXIT_MSR_LOAD_ADDR(); + SerialPrint_VM_EXIT_MSR_LOAD_ADDR_HIGH(); + + SerialPrint("\n==> VM Entry Controls\n"); + SerialPrint_VM_ENTRY_CTRLS(); + SerialPrint_VM_ENTRY_MSR_LOAD_COUNT(); + SerialPrint_VM_ENTRY_MSR_LOAD_ADDR(); + SerialPrint_VM_ENTRY_MSR_LOAD_ADDR_HIGH(); + SerialPrint_VM_ENTRY_INT_INFO_FIELD(); + SerialPrint_VM_ENTRY_EXCEPTION_ERROR(); + SerialPrint_VM_ENTRY_INSTR_LENGTH(); + + SerialPrint("\n==> VM Exit Info\n"); + SerialPrint_EXIT_REASON(); + SerialPrint_EXIT_QUALIFICATION(); + SerialPrint_VM_EXIT_INT_INFO(); + SerialPrint_VM_EXIT_INT_ERROR(); + SerialPrint_IDT_VECTOR_INFO(); + SerialPrint_IDT_VECTOR_ERROR(); + SerialPrint_VM_EXIT_INSTR_LENGTH(); + SerialPrint_GUEST_LINEAR_ADDR(); + SerialPrint_VMX_INSTR_INFO(); + SerialPrint_IO_RCX(); + SerialPrint_IO_RSI(); + SerialPrint_IO_RDI(); + SerialPrint_IO_RIP(); + SerialPrint_VM_INSTR_ERROR(); + SerialPrint("\n"); +} diff --git a/palacios/src/geekos/vmx.c b/palacios/src/geekos/vmx.c new file mode 100644 index 0000000..4ce96e0 --- /dev/null +++ b/palacios/src/geekos/vmx.c @@ -0,0 +1,894 @@ +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + + +extern void Get_MSR(unsigned int msr, uint_t * high, uint_t * low); +extern void Set_MSR(unsigned int msr, uint_t high, uint_t low); +extern int Enable_VMX(ullong_t regionPtr); +extern int cpuid_ecx(unsigned int op); +extern int Launch_VM(ullong_t vmcsPtr, uint_t eip); + +#define NUMPORTS 65536 + + +#define VMXASSIST_INFO_PORT 0x0e9 +#define ROMBIOS_PANIC_PORT 0x400 +#define ROMBIOS_PANIC_PORT2 0x401 +#define ROMBIOS_INFO_PORT 0x402 +#define ROMBIOS_DEBUG_PORT 0x403 + + + +static struct VM theVM; + +static uint_t GetLinearIP(struct VM *vm) +{ + if (vm->state==VM_VMXASSIST_V8086_BIOS || vm->state==VM_VMXASSIST_V8086) { + return vm->vmcs.guestStateArea.cs.baseAddr + vm->vmcs.guestStateArea.rip; + } else { + return vm->vmcs.guestStateArea.rip; + } +} + + +static void VMXPanic() +{ + while (1) {} +} + + +#define MAX_CODE 512 +#define INSTR_OFFSET_START 17 +#define NOP_SEQ_LEN 10 +#define INSTR_OFFSET_END (INSTR_OFFSET_START+NOP_SEQ_LEN-1) +#define TEMPLATE_CODE_LEN 35 + +uint_t oldesp=0; +uint_t myregs=0; + +// simply execute the instruction that is faulting and return +static int ExecFaultingInstructionInVMM(struct VM *vm) +{ + uint_t address = GetLinearIP(vm); + myregs = (uint_t)&(vm->registers); + + + SerialPrintLevel(1000,"About the execute faulting instruction!\n"); + SerialPrintLevel(1000,"Instruction is:\n"); + SerialMemDump((void*)(address),vm->vmcs.exitInfoFields.instrLength); + + + SerialPrintLevel(1000,"The template code is:\n"); + SerialMemDump(&&template_code,TEMPLATE_CODE_LEN); + + // clone the template code + //memcpy(&&template_code,code,MAX_CODE); + + // clean up the nop field + memset(&&template_code+INSTR_OFFSET_START,*((uchar_t *)(&&template_code+0)),NOP_SEQ_LEN); + // overwrite the nops with the faulting instruction + memcpy(&&template_code+INSTR_OFFSET_START, (void*)(address),vm->vmcs.exitInfoFields.instrLength); + + SerialPrintLevel(1000,"Finished modifying the template code, which now is:\n"); + SerialMemDump(&&template_code,TEMPLATE_CODE_LEN); + + SerialPrintLevel(1000,"Now entering modified template code\n"); + + + template_code: + // Template code stores current registers, + // restores registers, has a landing pad of noops + // that will be modified, restores current regs, and then returns + // + // Note that this currently ignores cr0, cr3, cr4, dr7, rsp, rip, and rflags + // it also blythly assumes it can exec the instruction in protected mode + // + __asm__ __volatile__ ("nop\n" // for cloning purposes (1 byte) + "pusha\n" // push our current regs onto the current stack (1 byte) + "movl %0, %%eax\n" // Get oldesp location (5 bytes) + "movl %%esp, (%%eax)\n" // store the current stack pointer in oldesp (2 bytes) + "movl %1, %%eax\n" // Get regs location (5 bytes) + "movl (%%eax), %%esp\n" // point esp at regs (2 bytes) + "popa\n" // now we have the VM registers restored (1 byte) + "nop\n" // now we execute the actual instruction (1 byte x 10) + "nop\n" // now we execute the actual instruction + "nop\n" // now we execute the actual instruction + "nop\n" // now we execute the actual instruction + "nop\n" // now we execute the actual instruction + "nop\n" // now we execute the actual instruction + "nop\n" // now we execute the actual instruction + "nop\n" // now we execute the actual instruction + "nop\n" // now we execute the actual instruction + "nop\n" // now we execute the actual instruction + // need to copy back to the VM registers! + "movl %0, %%eax\n" // recapture oldesp location (5 bytes) + "movl (%%eax), %%esp\n" // now we'll get our esp back from oldesp (2 bytes) + "popa\n" // and restore our GP regs and we're done (1 byte) + : "=m"(oldesp) + : "m"(myregs) + ); + + SerialPrintLevel(1000,"Survived executing the faulting instruction and returning.\n"); + + vm->vmcs.guestStateArea.rip += vm->vmcs.exitInfoFields.instrLength; + + return 0; + +} + + +VmxOnRegion * InitVMX() { + VmxOnRegion * region = NULL; + + unsigned int ret; + union VMX_MSR featureMSR; + + ret = cpuid_ecx(1); + if (ret & CPUID_1_ECX_VTXFLAG) { + Get_MSR(IA32_FEATURE_CONTROL_MSR, &featureMSR.regs.high, &featureMSR.regs.low); + + SerialPrintLevel(100,"MSRREGlow: 0x%.8x\n", featureMSR.regs.low); + if ((featureMSR.regs.low & FEATURE_CONTROL_VALID) != FEATURE_CONTROL_VALID) { + PrintBoth("VMX is locked -- enable in the BIOS\n"); + return NULL; + } + } else { + PrintBoth("VMX not supported on this cpu\n"); + return NULL; + } + + region = CreateVmxOnRegion(); + + + ret = Enable_VMX((ullong_t)((uint_t)region)); + if (ret == 0) { + PrintBoth("VMX Enabled\n"); + } else { + PrintBoth("VMX failure (ret = %d)\n", ret); + } + + theVM.vmxonregion = region; + + return region; +} + +extern uint_t VMCS_CLEAR(); +extern uint_t VMCS_LOAD(); +extern uint_t VMCS_STORE(); +extern uint_t VMCS_LAUNCH(); +extern uint_t VMCS_RESUME(); +extern uint_t Init_VMCS_HostState(); +extern uint_t Init_VMCS_GuestState(); + +void SetCtrlBitsCorrectly(int msrno, int vmcsno) +{ + uint_t reserved =0; + union VMX_MSR msr; + + SerialPrintLevel(100,"SetCtrlBitsCorrectly(%x,%x)\n",msrno,vmcsno); + Get_MSR(msrno, &msr.regs.high, &msr.regs.low); + SerialPrintLevel(100,"MSR %x = %x : %x \n", msrno, msr.regs.high, msr.regs.low); + reserved = msr.regs.low; + reserved &= msr.regs.high; + VMCS_WRITE(vmcsno, &reserved); +} + + +void SetCRBitsCorrectly(int msr0no, int msr1no, int vmcsno) +{ + uint_t reserved =0; + union VMX_MSR msr0, msr1; + + SerialPrintLevel(100,"SetCRBitsCorrectly(%x,%x,%x)\n",msr0no,msr1no,vmcsno); + Get_MSR(msr0no, &msr0.regs.high, &msr0.regs.low); + Get_MSR(msr1no, &msr1.regs.high, &msr1.regs.low); + SerialPrintLevel(100,"MSR %x = %x, %x = %x \n", msr0no, msr0.regs.low, msr1no, msr1.regs.low); + reserved = msr0.regs.low; + reserved &= msr1.regs.low; + VMCS_WRITE(vmcsno, &reserved); +} + + +extern int Get_CR2(); +extern int vmRunning; + + +static int PanicUnhandledVMExit(struct VM *vm) +{ + Print("Panicking due to VMExit with reason %u\n",vm->vmcs.exitInfoFields.reason); + SerialPrint("Panicking due to VMExit with reason %u\n",vm->vmcs.exitInfoFields.reason); + SerialPrint_VMCS_ALL(); + SerialPrint_VMX_Regs(&(vm->registers)); + VMXPanic(); + return 0; +} + + +static int HandleVMPrintsAndPanics(struct VM *vm, uint_t port, uint_t data) +{ + if (port==VMXASSIST_INFO_PORT && + (vm->state == VM_VMXASSIST_STARTUP || + vm->state == VM_VMXASSIST_V8086_BIOS || + vm->state == VM_VMXASSIST_V8086)) { + // Communication channel from VMXAssist + SerialPrintLevel(1000,"VMXASSIST Output Port\n"); + PrintBoth("%c",data&0xff); + return 1; + } + + if ((port==ROMBIOS_PANIC_PORT || + port==ROMBIOS_PANIC_PORT2 || + port==ROMBIOS_DEBUG_PORT || + port==ROMBIOS_INFO_PORT) && + (vm->state==VM_VMXASSIST_V8086_BIOS)) { + // rombios is communicating + SerialPrintLevel(1000,"ROMBIOS Output Port\n"); + // PrintBoth("%c",data&0xff); + return 1; + } + + if (port==BOOT_STATE_CARD_PORT && vm->state==VM_VMXASSIST_V8086_BIOS) { + // rombios is sending something to the display card + SerialPrintLevel(1000,"Hex Display: 0x%x\n",data&0xff); + return 1; + } + return 0; +} + +static int HandleInOutExit(struct VM *vm) +{ + uint_t address; + + struct VMCSExitInfoFields *exitinfo = &(vm->vmcs.exitInfoFields); + struct VMExitIOQual * qual = (struct VMExitIOQual *)&(vm->vmcs.exitInfoFields.qualification); + struct VMXRegs *regs = &(vm->registers); + + address=GetLinearIP(vm); + + SerialPrintLevel(1000,"Handling Input/Output Instruction Exit\n"); + if (SERIAL_PRINT_DEBUG && 1000>=SERIAL_PRINT_DEBUG_LEVEL) { + SerialPrint_VMX_Regs(regs); + } + SerialPrintLevel(1000,"Qualifications=0x%x\n",exitinfo->qualification); + SerialPrintLevel(1000,"Reason=0x%x\n",exitinfo->reason); + SerialPrintLevel(1000,"IO Port: 0x%x (%d)\n", qual->port, qual->port); + SerialPrintLevel(1000,"Instruction Info=%x\n",exitinfo->instrInfo); + SerialPrintLevel(1000,"%x : %s %s %s instruction of length %d for %d bytes from/to port 0x%x\n", + address, + qual->dir == 0 ? "output" : "input", + qual->string ==0 ? "nonstring" : "STRING", + qual->REP == 0 ? "with no rep" : "WITH REP", + exitinfo->instrLength, + qual->accessSize==0 ? 1 : qual->accessSize==1 ? 2 : 4, + qual->port); + + if (qual->port==PIC_MASTER_CMD_ISR_PORT || + qual->port==PIC_MASTER_IMR_PORT || + qual->port==PIC_SLAVE_CMD_ISR_PORT || + qual->port==PIC_SLAVE_IMR_PORT) { + SerialPrintLevel(1000, "PIC Access\n"); + } + + + if (qual->dir==1 && qual->REP==0 && qual->string==0) { + char byte = In_Byte(qual->port); + + vm->vmcs.guestStateArea.rip += exitinfo->instrLength; + regs->eax = (regs->eax & 0xffffff00) | byte; + SerialPrintLevel(1000,"Returning 0x%x in eax\n",(regs->eax)); + } + + if (qual->dir==0 && qual->REP==0 && qual->string==0) { + // See if we need to handle the outb as a signal or + // print from the VM + if (HandleVMPrintsAndPanics(vm,qual->port,regs->eax)) { + } else { + // If not, just go ahead and do the outb + Out_Byte(qual->port,regs->eax); + SerialPrintLevel(1000,"Wrote 0x%x to port\n",(regs->eax)); + } + vm->vmcs.guestStateArea.rip += exitinfo->instrLength; + } + + return 0; +} + + +static int HandleExternalIRQExit(struct VM *vm) +{ + struct VMCSExitInfoFields * exitinfo = &(vm->vmcs.exitInfoFields); + struct VMExitIntInfo * intInfo = (struct VMExitIntInfo *)&(vm->vmcs.exitInfoFields.intInfo); + + SerialPrintLevel(1000,"External Interrupt captured\n"); + SerialPrintLevel(100,"IntInfo: %x\n", exitinfo->intInfo); + + + if (!intInfo->valid) { + // interrupts are off, but this interrupt is not acknoledged (still pending) + // so we turn on interrupts to deliver appropriately in the + // host + SerialPrintLevel(100,"External Interrupt is invald. Turning Interrupts back on\n"); + asm("sti"); + return 0; + } + + // At this point, interrupts are off and the interrupt has been + // acknowledged. We will now handle the interrupt ourselves + // and turn interrupts back on in the host + + SerialPrintLevel(100,"type: %d\n", intInfo->type); + SerialPrintLevel(100,"number: %d\n", intInfo->nr); + + SerialPrint("Interrupt %d occuring now and handled by HandleExternalIRQExit\n",intInfo->nr); + + switch (intInfo->type) { + case 0: { // ext. IRQ + // In the following, we construct an "int x" instruction + // where x is the specific interrupt number that is raised + // then we execute that instruciton + // because we are in host context, that means it is delivered as normal + // through the host IDT + + ((char*)(&&ext_int_seq_start))[1] = intInfo->nr; + + SerialPrintLevel(100,"Interrupt instruction setup done %x\n", *((ushort_t *)(&&ext_int_seq_start))); + +ext_int_seq_start: + asm("int $0"); + } + + break; + case 2: // NMI + SerialPrintLevel(100,"Type: NMI\n"); + break; + case 3: // hw exception + SerialPrintLevel(100,"Type: HW Exception\n"); + break; + case 4: // sw exception + SerialPrintLevel(100,"Type: SW Exception\n"); + break; + default: + SerialPrintLevel(100,"Invalid Interrupt Type\n"); + return -1; + } + + if (intInfo->valid && intInfo->errorCode) { + SerialPrintLevel(100,"IntError: %x\n", exitinfo->intErrorCode); + } + + + return 0; + +} + + + +void DecodeCurrentInstruction(struct VM *vm, struct Instruction *inst) +{ + // this is a gruesome hack + uint_t address = GetLinearIP(vm); + uint_t length = vm->vmcs.exitInfoFields.instrLength; + unsigned char *t = (unsigned char *) address; + + + + SerialPrintLevel(100,"DecodeCurrentInstruction: instruction is\n"); + SerialMemDump(t,length); + + if (length==3 && t[0]==0x0f && t[1]==0x22 && t[2]==0xc0) { + // mov from eax to cr0 + // usually used to signal + inst->type=VM_MOV_TO_CR0; + inst->address=address; + inst->size=length; + inst->input1=vm->registers.eax; + inst->input2=vm->vmcs.guestStateArea.cr0; + inst->output=vm->registers.eax; + SerialPrintLevel(100,"MOV FROM EAX TO CR0\n"); + } else { + inst->type=VM_UNKNOWN_INST; + } +} + + +static void V8086ModeSegmentRegisterFixup(struct VM *vm) +{ + vm->vmcs.guestStateArea.cs.baseAddr=vm->vmcs.guestStateArea.cs.selector<<4; + vm->vmcs.guestStateArea.es.baseAddr=vm->vmcs.guestStateArea.es.selector<<4; + vm->vmcs.guestStateArea.ss.baseAddr=vm->vmcs.guestStateArea.ss.selector<<4; + vm->vmcs.guestStateArea.ds.baseAddr=vm->vmcs.guestStateArea.ds.selector<<4; + vm->vmcs.guestStateArea.fs.baseAddr=vm->vmcs.guestStateArea.fs.selector<<4; + vm->vmcs.guestStateArea.gs.baseAddr=vm->vmcs.guestStateArea.gs.selector<<4; +} + +static void SetupV8086ModeForBoot(struct VM *vm) +{ + vm->state = VM_VMXASSIST_V8086_BIOS; + + // Put guest into V8086 mode on return + vm->vmcs.guestStateArea.rflags |= EFLAGS_VM | EFLAGS_IOPL_HI | EFLAGS_IOPL_LO ; + + // We will start at f000:fff0 on return + // + // We want this to look as much as possible as a processor + // reset + vm->vmcs.guestStateArea.rip = 0xfff0; // note, 16 bit rip + vm->vmcs.guestStateArea.cs.selector = 0xf000; + vm->vmcs.guestStateArea.cs.limit=0xffff; + vm->vmcs.guestStateArea.cs.access.as_dword = 0xf3; + + vm->vmcs.guestStateArea.ss.selector = 0x0000; + vm->vmcs.guestStateArea.ss.limit=0xffff; + vm->vmcs.guestStateArea.ss.access.as_dword = 0xf3; + + vm->vmcs.guestStateArea.ds.selector = 0x0000; + vm->vmcs.guestStateArea.ds.limit=0xffff; + vm->vmcs.guestStateArea.ds.access.as_dword = 0xf3; + + vm->vmcs.guestStateArea.es.selector = 0x0000; + vm->vmcs.guestStateArea.es.limit=0xffff; + vm->vmcs.guestStateArea.es.access.as_dword = 0xf3; + + vm->vmcs.guestStateArea.fs.selector = 0x0000; + vm->vmcs.guestStateArea.fs.limit=0xffff; + vm->vmcs.guestStateArea.fs.access.as_dword = 0xf3; + + vm->vmcs.guestStateArea.gs.selector = 0x0000; + vm->vmcs.guestStateArea.gs.limit=0xffff; + vm->vmcs.guestStateArea.gs.access.as_dword = 0xf3; + + V8086ModeSegmentRegisterFixup(vm); + + SerialPrint_VMCSData(&(vm->vmcs)); + +} + + + +static int HandleExceptionOrNMI(struct VM *vm) +{ + struct Instruction inst; + uint_t num; + uint_t type; + uint_t errorvalid; + uint_t error; + uint_t ext=0; + uint_t idt=0; + uint_t ti=0; + uint_t selectorindex=0; + + SerialPrintLevel(1000,"Exception or NMI occurred\n"); + + num=vm->vmcs.exitInfoFields.intInfo & 0xff; + type=(vm->vmcs.exitInfoFields.intInfo & 0x700)>>8; + errorvalid=(vm->vmcs.exitInfoFields.intInfo & 0x800)>>11; + if (errorvalid) { + error=vm->vmcs.exitInfoFields.intErrorCode; + ext=error&0x1; + idt=(error&0x2)>>1; + ti=(error&0x4)>>2; + selectorindex=(error>>3)&0xffff; + } + + SerialPrint("Exception %d now - handled by HandleExceptionOrNMI\n",num); + + SerialPrintLevel(1000,"Exception Number %u : %s\n", num, exception_names[num]); + SerialPrintLevel(1000,"Exception Type %u : %s\n", type, exception_type_names[type]); + if (errorvalid) { + if (ext) { + SerialPrintLevel(1000,"External\n"); + } else { + SerialPrintLevel(1000,"%s - Selector Index is %u\n", idt ? "IDT" : ti ? "LDT" : "GDT", selectorindex); + } + } + + DecodeCurrentInstruction(vm,&inst); + + if (inst.type==VM_MOV_TO_CR0) { + SerialPrintLevel(1000,"MOV TO CR0, oldvalue=0x%x, newvalue=0x%x\n",inst.input2, inst.input1); + if ((inst.input2 & CR0_PE) && !(inst.input1 & CR0_PE) && vm->state==VM_VMXASSIST_STARTUP) { + // This is VMXAssist signalling for us to turn on V8086 mode and + // jump into the bios + SerialPrintLevel(1000,"VMXAssist is signaling us for switch to V8086 mode and jump to 0xf000:fff0\n"); + SetupV8086ModeForBoot(vm); + goto leave; + } else { + SerialPrintLevel(1000,"Instruction is a write to CR0, but we don't understand it so we'll just exec it\n"); + } + } + + + SerialPrintLevel(1000,"Trying to execute the faulting instruction in VMM context now\n"); + ExecFaultingInstructionInVMM(vm); + + leave: + // + //PanicUnhandledVMExit(vmcs,regs); + //VMXPanic(); + return 0; +} + + +static struct VM *FindVM() +{ + return &theVM; +} + + +int Do_VMM(struct VMXRegs regs) +{ + + ullong_t vmcs_ptr = 0; + uint_t vmcs_ptr_low = 0; + int ret = 0; + uint_t vmx_abort = 0; + + + + SerialPrintLevel(100,"Vm Exit\n"); + ret = VMCS_STORE(&vmcs_ptr); + vmcs_ptr &= 0xffffffff; + vmcs_ptr_low += vmcs_ptr; + + + SerialPrintLevel(100,"ret=%d\n", ret); + SerialPrintLevel(100,"Revision: %x\n", *(uint_t *)(vmcs_ptr_low)); + vmx_abort = *(uint_t*)(((char *)vmcs_ptr_low)+4); + + struct VM *vm = FindVM(); + + if (vmx_abort != 0) { + SerialPrintLevel(1000,"VM ABORTED w/ code: %x\n", vmx_abort); + return -1; + } + + vm->registers = regs; + + if (CopyOutVMCSData(&(vm->vmcs)) != 0) { + SerialPrintLevel(1000,"Could not copy out VMCS\n"); + return -1; + } + + SerialPrintLevel(100,"VM Exit for reason: %d (%x)\n", + vm->vmcs.exitInfoFields.reason & 0x00000fff, + vm->vmcs.exitInfoFields.reason); + + if (vm->vmcs.exitInfoFields.reason & (0x1<<29) ) { + SerialPrintLevel(1000,"VM Exit is from VMX root operation. Panicking\n"); + VMXPanic(); + } + + if (vm->vmcs.exitInfoFields.reason & (0x1<<31) ) { + SerialPrintLevel(1000,"VM Exit is due to a VM entry failure. Shouldn't happen here. Panicking\n"); + SerialPrint_VMCSData(&(vm->vmcs)); + VMXPanic(); + } + + switch (vm->vmcs.exitInfoFields.reason) { + case VM_EXIT_REASON_INFO_EXCEPTION_OR_NMI: + ret = HandleExceptionOrNMI(vm); + break; + case VM_EXIT_REASON_EXTERNAL_INTR: + ret = HandleExternalIRQExit(vm); + break; + case VM_EXIT_REASON_TRIPLE_FAULT: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_INIT_SIGNAL: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_STARTUP_IPI: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_IO_SMI: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_OTHER_SMI: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_INTR_WINDOW: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_NMI_WINDOW: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_TASK_SWITCH: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_CPUID: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_INVD: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_INVLPG: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_RDPMC: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_RDTSC: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_RSM: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_VMCALL: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_VMCLEAR: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_VMLAUNCH: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_VMPTRLD: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_VMPTRST: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_VMREAD: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_VMRESUME: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_VMWRITE: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_VMXOFF: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_VMXON: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_CR_REG_ACCESSES: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_MOV_DR: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_IO_INSTR: + ret = HandleInOutExit(vm); + break; + case VM_EXIT_REASON_RDMSR: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_WRMSR: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_ENTRY_FAIL_INVALID_GUEST_STATE: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_ENTRY_FAIL_MSR_LOAD: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_MWAIT: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_MONITOR: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_PAUSE: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_ENTRY_FAILURE_MACHINE_CHECK: + ret = PanicUnhandledVMExit(vm); + break; + case VM_EXIT_REASON_TPR_BELOW_THRESHOLD: + ret = PanicUnhandledVMExit(vm); + break; + default: + ret = PanicUnhandledVMExit(vm); + break; + } + + + regs = vm->registers; + CopyInVMCSData(&(vm->vmcs)); + + /* + { + VMCS_CLEAR(vmcs_ptr); + } + */ + + SerialPrintLevel(100,"Returning from Do_VMM: %d\n", ret); + + return ret; +} + + +static void ConfigureExits(struct VM *vm) +{ + CopyOutVMCSExecCtrlFields(&(vm->vmcs.execCtrlFields)); + + vm->vmcs.execCtrlFields.pinCtrls |= 0 + // EXTERNAL_INTERRUPT_EXITING + | NMI_EXITING; + vm->vmcs.execCtrlFields.procCtrls |= 0 + // INTERRUPT_WINDOWS_EXIT + | USE_TSC_OFFSETTING + | HLT_EXITING + |INVLPG_EXITING + |MWAIT_EXITING + |RDPMC_EXITING + |RDTSC_EXITING + |MOVDR_EXITING + |UNCONDITION_IO_EXITING + |MONITOR_EXITING + |PAUSE_EXITING ; + + CopyInVMCSExecCtrlFields(&(vm->vmcs.execCtrlFields)); + + CopyOutVMCSExitCtrlFields(&(vm->vmcs.exitCtrlFields)); + + vm->vmcs.exitCtrlFields.exitCtrls |= ACK_IRQ_ON_EXIT; + + CopyInVMCSExitCtrlFields(&(vm->vmcs.exitCtrlFields)); + + +/* VMCS_READ(VM_EXIT_CTRLS, &flags); */ +/* flags |= ACK_IRQ_ON_EXIT; */ +/* VMCS_WRITE(VM_EXIT_CTRLS, &flags); */ +} + + +extern int RunVMM(); +extern int SAFE_VM_LAUNCH(); + +int MyLaunch(struct VM *vm) +{ + ullong_t vmcs = (ullong_t)((uint_t) (vm->vmcsregion)); + uint_t entry_eip = vm->descriptor.entry_ip; + uint_t exit_eip = vm->descriptor.exit_eip; + uint_t guest_esp = vm->descriptor.guest_esp; + uint_t f = 0xffffffff; + uint_t tmpReg = 0; + int ret; + int vmm_ret = 0; + + exit_eip=(uint_t)RunVMM; + + SerialPrintLevel(100,"Clear\n"); + VMCS_CLEAR(vmcs); + SerialPrintLevel(100,"Load\n"); + VMCS_LOAD(vmcs); + + + SerialPrintLevel(100,"VMCS_LINK_PTR\n"); + VMCS_WRITE(VMCS_LINK_PTR, &f); + SerialPrintLevel(100,"VMCS_LINK_PTR_HIGH\n"); + VMCS_WRITE(VMCS_LINK_PTR_HIGH, &f); + + + SetCtrlBitsCorrectly(IA32_VMX_PINBASED_CTLS_MSR, PIN_VM_EXEC_CTRLS); + SetCtrlBitsCorrectly(IA32_VMX_PROCBASED_CTLS_MSR, PROC_VM_EXEC_CTRLS); + SetCtrlBitsCorrectly(IA32_VMX_EXIT_CTLS_MSR, VM_EXIT_CTRLS); + SetCtrlBitsCorrectly(IA32_VMX_ENTRY_CTLS_MSR, VM_ENTRY_CTRLS); + + // + // + //SetCtrlBitsCorrectly(IA32_something,GUEST_IA32_DEBUGCTL); + //SetCtrlBitsCorrectly(IA32_something,GUEST_IA32_DEBUGCTL_HIGH); + + + /* Host state */ + SerialPrintLevel(100,"Setting up host state\n"); + SetCRBitsCorrectly(IA32_VMX_CR0_FIXED0_MSR, IA32_VMX_CR0_FIXED1_MSR, HOST_CR0); + SetCRBitsCorrectly(IA32_VMX_CR4_FIXED0_MSR, IA32_VMX_CR4_FIXED1_MSR, HOST_CR4); + ret = Init_VMCS_HostState(); + + if (ret != VMX_SUCCESS) { + if (ret == VMX_FAIL_VALID) { + SerialPrintLevel(100,"Init Host state: VMCS FAILED WITH ERROR\n"); + } else { + SerialPrintLevel(100,"Init Host state: Invalid VMCS\n"); + } + return ret; + } + + // SerialPrintLevel(100,"HOST_RIP: %x (%u)\n", exit_eip, exit_eip); + VMCS_WRITE(HOST_RIP, &exit_eip); + + /* Guest state */ + SerialPrintLevel(100,"Setting up guest state\n"); + SerialPrintLevel(100,"GUEST_RIP: %x (%u)\n", entry_eip, entry_eip); + VMCS_WRITE(GUEST_RIP,&entry_eip); + + SetCRBitsCorrectly(IA32_VMX_CR0_FIXED0_MSR, IA32_VMX_CR0_FIXED1_MSR, GUEST_CR0); + SetCRBitsCorrectly(IA32_VMX_CR4_FIXED0_MSR, IA32_VMX_CR4_FIXED1_MSR, GUEST_CR4); + ret = Init_VMCS_GuestState(); + + SerialPrintLevel(100,"InitGuestState returned\n"); + if (ret != VMX_SUCCESS) { + if (ret == VMX_FAIL_VALID) { + SerialPrintLevel(100,"Init Guest state: VMCS FAILED WITH ERROR\n"); + } else { + SerialPrintLevel(100,"Init Guest state: Invalid VMCS\n"); + } + return ret; + } + SerialPrintLevel(100,"GUEST_RSP: %x (%u)\n", guest_esp, (uint_t)guest_esp); + VMCS_WRITE(GUEST_RSP,&guest_esp); + + // tmpReg = 0x4100; + tmpReg = 0xffffffff; + if (VMCS_WRITE(EXCEPTION_BITMAP,&tmpReg ) != VMX_SUCCESS) { + Print("Bitmap error\n"); + } + + ConfigureExits(vm); + + SerialPrintLevel(100,"VMCS_LAUNCH\n"); + + vm->state=VM_VMXASSIST_STARTUP; + + vmm_ret = SAFE_VM_LAUNCH(); + + SerialPrintLevel(100,"VMM error %d\n", vmm_ret); + + return vmm_ret; +} + + + + +int VMLaunch(struct VMDescriptor *vm) +{ + VMCS * vmcs = CreateVMCS(); + int rc; + + ullong_t vmcs_ptr = (ullong_t)((uint_t)vmcs); + uint_t top = (vmcs_ptr>>32)&0xffffffff; + uint_t bottom = (vmcs_ptr)&0xffffffff; + + theVM.vmcsregion = vmcs; + theVM.descriptor = *vm; + + SerialPrintLevel(100,"vmcs_ptr_top=%x vmcs_ptr_bottom=%x, eip=%x\n", top, bottom, vm->entry_ip); + rc=MyLaunch(&theVM); // vmcs_ptr, vm->entry_ip, vm->exit_eip, vm->guest_esp); + SerialPrintLevel(100,"Returned from MyLaunch();\n"); + return rc; +} + + +VmxOnRegion * CreateVmxOnRegion() { + union VMX_MSR basicMSR; + VmxOnRegion * region = (VmxOnRegion *)Alloc_Page(); + + Get_MSR(IA32_VMX_BASIC_MSR, &basicMSR.regs.high, &basicMSR.regs.low); + // memcpy(region, &basicMSR.vmxBasic.revision, sizeof(uint_t)); + + *(ulong_t*)region = basicMSR.vmxBasic.revision; + + Print("VMX revision: 0x%lu\n", *(ulong_t *)region); + + return region; +} + +VMCS * CreateVMCS() { + union VMX_MSR basicMSR; + VMCS * vmcs = (VMCS *)Alloc_Page(); + + Get_MSR(IA32_VMX_BASIC_MSR, &basicMSR.regs.high, &basicMSR.regs.low); + *(ulong_t *)vmcs = basicMSR.vmxBasic.revision; + *(ulong_t *)((char*)vmcs + 4) = 0; + + SerialPrintLevel(100,"VMCS Region size: %u\n", basicMSR.vmxBasic.regionSize); + SerialPrintLevel(100,"VMCS Abort: %x\n",*(uint_t *)(((char*)vmcs)+4)); + + return vmcs; +} + + diff --git a/palacios/src/geekos/vmx_lowlevel.asm b/palacios/src/geekos/vmx_lowlevel.asm new file mode 100644 index 0000000..05257c9 --- /dev/null +++ b/palacios/src/geekos/vmx_lowlevel.asm @@ -0,0 +1,936 @@ +; -*- fundamental -*- + +%ifndef VMX_ASM +%define VMX_ASM + + +%include "defs.asm" +%include "symbol.asm" + + +%include "vmcs_fields.asm" + +VMX_SUCCESS equ 0x00000000 +VMX_FAIL_INVALID equ 0x00000001 +VMX_FAIL_VALID equ 0x00000002 +VMM_ERROR equ 0x00000003 + +[BITS 32] + +IMPORT Do_VMM + + +; VMX Functions +EXPORT VMCS_READ +EXPORT VMCS_WRITE +EXPORT VMCS_CLEAR +EXPORT VMCS_LOAD +EXPORT VMCS_STORE +EXPORT Enable_VMX +EXPORT Disable_VMX +EXPORT Launch_VM +EXPORT VMCS_LAUNCH +EXPORT VMCS_RESUME +EXPORT RunVMM +EXPORT SAFE_VM_LAUNCH +EXPORT Init_VMCS_HostState +EXPORT Init_VMCS_GuestState + +; +; Enable_VMX - Turn on VMX +; +align 8 +Enable_VMX: + push ebp + mov ebp, esp + push ebx + mov ebx, cr4 + or ebx, dword 0x00002000 + mov cr4, ebx + mov ebx, cr0 + or ebx, dword 0x80000021 + mov cr0, ebx + vmxon [ebp+8] + pop ebx + pop ebp + mov eax, VMX_SUCCESS + jnc .return + mov eax, VMX_FAIL_INVALID +.return + ret + + +; +; VMREAD - read a value from a VMCS +; +align 8 +VMCS_READ: + push ebp + mov ebp, esp + push ecx + push ebx + + mov ecx, [ebp + 8] + mov ebx,[ebp + 12] +; lea ebx, ebp + vmread [ebx], ecx + + pop ebx + pop ecx + pop ebp + jz .error_code + jc .error + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + ret + +; +; VMWRITE - write a value to a VMCS +align 8 +VMCS_WRITE: + push ebp + mov ebp, esp + push ebx + + mov eax, [ebp + 8] + mov ebx, [ebp + 12] + vmwrite eax, [ebx] + + pop ebx + pop ebp + jz .error_code + jc .error + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + ret + +; +; VMCLEAR - Initializes a VMCS +; +align 8 +VMCS_CLEAR: + vmclear [esp+4] + jz .error_code + jc .error + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + ret + + + +; +; VMCS_LOAD - load a VMCS +; +align 8 +VMCS_LOAD: + vmptrld [esp+4] + jz .error_code + jc .error + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + ret + + + +; +; VMCS_STORE - Store a VMCS +; +align 8 +VMCS_STORE: + mov eax, [esp+4] + vmptrst [eax] + jz .error_code + jc .error + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + ret + + +; +; VMCS_LAUNCH +; +align 8 +VMCS_LAUNCH: + vmlaunch + jz .error_code + jc .error + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + ret + + + +; +; VMCS_RESUME +; +align 8 +VMCS_RESUME: + vmresume + jz .error_code + jc .error + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + ret + +align 8 +SAFE_VM_LAUNCH: + pushf + pusha + mov eax, HOST_RSP + vmwrite eax, esp + jz .esp_err + jc .esp_err + jmp .vm_cont + +.esp_err + popa + jz .error_code + jc .error +.vm_cont + vmlaunch + popa + jz .error_code + jc .error + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + popf + ret + + +; +; RunVMM +; +align 8 +RunVMM: + pusha + call Do_VMM + and eax, eax + jnz .vmm_error + jmp .vm_cont + +.vmm_error + popa + popa + mov eax, VMM_ERROR + jmp .return + +.vm_cont + popa + vmresume + popa ; we only get here if there is an error in the vmresume + ; we restore the host state and return an error code + + jz .error_code + jc .error + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + popf + ret + + + + +; +; Setup_VMCS_GuestState +; Copy all of the Guest registers into the guest state of a vmcs +; + +align 8 +InitGuestSelectors: + push ebp + mov ebp, esp + push ebx + push ebx + + mov ebx, VMCS_GUEST_ES_SELECTOR + mov eax, es + vmwrite ebx, eax + jz .error_code + jc .error + + mov ebx, VMCS_GUEST_CS_SELECTOR + mov eax, cs + vmwrite ebx, eax + jz .error_code + jc .error + + mov ebx, VMCS_GUEST_SS_SELECTOR + mov eax, ss + vmwrite ebx, eax + jz .error_code + jc .error + + mov ebx, VMCS_GUEST_DS_SELECTOR + mov eax, ds + vmwrite ebx, eax + jz .error_code + jc .error + + mov ebx, VMCS_GUEST_FS_SELECTOR + mov eax, fs + vmwrite ebx, eax + jz .error_code + jc .error + + mov ebx, VMCS_GUEST_GS_SELECTOR + mov eax, gs + vmwrite ebx, eax + jz .error_code + jc .error + + str [esp] + mov eax, [esp] + mov ebx, VMCS_GUEST_TR_SELECTOR + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + pop ebx + pop ebx + pop ebp + ret +ret + +align 8 +InitGuestDescRegs: + push ebp + mov ebp, esp + push ebx + sub esp, 6 + + + sgdt [esp] + mov eax, [esp] + and eax, 0xffff + mov ebx, GUEST_GDTR_LIMIT + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, [esp+2] + mov ebx, GUEST_GDTR_BASE + vmwrite ebx, eax + jz .error_code + jc .error + + + sidt [esp] + mov eax, [esp] + and eax, 0xffff + mov ebx, GUEST_IDTR_LIMIT + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, [esp+2] + mov ebx, GUEST_IDTR_BASE + vmwrite ebx, eax + jz .error_code + jc .error + + + sldt [esp] + mov eax, [esp] + mov ebx, GUEST_LDTR_BASE + vmwrite ebx, eax + jz .error_code + jc .error + + + mov eax, 0x00000000 + mov ebx, GUEST_LDTR_LIMIT + vmwrite ebx, eax + jz .error_code + jc .error + + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + + add esp, 6 + pop ebx + pop ebp + ret + + + + + +align 8 +InitGuestSegBases: + push ebp + mov ebp, esp + push ebx + + + mov eax, dword 0 + mov ebx, GUEST_ES_BASE + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, dword 0 + mov ebx, GUEST_CS_BASE + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, dword 0 + mov ebx, GUEST_SS_BASE + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, dword 0 + mov ebx, GUEST_DS_BASE + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, dword 0 + mov ebx, GUEST_FS_BASE + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, dword 0 + mov ebx, GUEST_GS_BASE + vmwrite ebx, eax + jz .error_code + jc .error + +; mov eax, dword 0 + mov eax, 0x000220a0 + mov ebx, GUEST_TR_BASE + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + + pop ebx + pop ebp + ret + +align 8 +InitGuestSegsAccess: + push ebp + mov ebp, esp + push ebx + + mov eax, 1100000010010011b + mov ebx, GUEST_ES_ACCESS + vmwrite ebx, eax + jz .error_code + jc .error + + + + mov eax, 1100000010011001b +; mov eax, 0x0000c099 + mov ebx, GUEST_CS_ACCESS + vmwrite ebx, eax + jz .error_code + jc .error + +; mov eax, 1100000010010111b + mov eax, 1100000010010011b + mov ebx, GUEST_SS_ACCESS + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, 1100000010010011b + mov ebx, GUEST_DS_ACCESS + vmwrite ebx, eax + jz .error_code + jc .error + + + mov eax, 1100000010010011b + mov ebx, GUEST_FS_ACCESS + vmwrite ebx, eax + jz .error_code + jc .error + + + mov eax, 1100000010010011b + mov ebx, GUEST_GS_ACCESS + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, 0x10000 + mov ebx, GUEST_LDTR_ACCESS + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, 01000000010001011b + mov ebx, GUEST_TR_ACCESS + vmwrite ebx, eax + jz .error_code + jc .error + +; + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + pop ebx + pop ebp + ret + +;; Do seg limit +align 8 +InitGuestSegsLimits: + push ebp + mov ebp, esp + push ebx + + +; mov eax, 0xffffffff + mov eax, 0xffffffff + mov ebx, GUEST_ES_LIMIT + vmwrite ebx, eax + jz .error_code + jc .error + +; mov eax, 0xffffffff + mov eax, 0xffffffff + mov ebx, GUEST_CS_LIMIT + vmwrite ebx, eax + jz .error_code + jc .error + +; mov eax, 0xffffffff + mov eax, 0xffffffff + mov ebx, GUEST_SS_LIMIT + vmwrite ebx, eax + jz .error_code + jc .error + +; mov eax, 0xffffffff + mov eax, 0xffffffff + mov ebx, GUEST_DS_LIMIT + vmwrite ebx, eax + jz .error_code + jc .error + +; mov eax, 0xffffffff + mov eax, 0xffffffff + mov ebx, GUEST_FS_LIMIT + vmwrite ebx, eax + jz .error_code + jc .error + +; mov eax, 0xffffffff + mov eax, 0xffffffff + mov ebx, GUEST_GS_LIMIT + vmwrite ebx, eax + jz .error_code + jc .error + +; mov eax, 0xffffffff + mov eax, 0x68fff + mov ebx, GUEST_TR_LIMIT + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + pop ebx + pop ebp + ret + + +align 8 +Init_VMCS_GuestState: + push ebp + mov ebp, esp + push ebx + + mov ebx, GUEST_CR3 + mov eax, cr3 + vmwrite ebx, eax + jz .error_code + jc .error + + call InitGuestSelectors + and eax, 0xffffffff + jz .selDone + jmp .return +.selDone + + call InitGuestDescRegs + and eax, 0xffffffff + jz .descRegsDone + jmp .return +.descRegsDone + + call InitGuestSegBases + and eax, 0xffffffff + jz .descSegBasesDone + jmp .return +.descSegBasesDone + + + call InitGuestSegsLimits + and eax, 0xffffffff + jz .segsLimitsDone + jmp .return +.segsLimitsDone + + call InitGuestSegsAccess + and eax, 0xffffffff + jz .segsAccessDone + jmp .return +.segsAccessDone + + mov ebx, GUEST_RSP + mov eax, esp + vmwrite ebx, eax + jz .error_code + jc .error + + mov ebx, GUEST_RFLAGS + mov eax, dword 0x00000002 + vmwrite ebx, eax + jz .error_code + jc .error + + mov ebx, GUEST_DR7 + mov eax, dword 0x00000400 + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + pop ebx + pop ebp + ret + +; +; Setup_VMCS_HostState +; Copy all of the host registers into the host state of a vmcs +; + +align 8 +InitHostSelectors: + push ebp + mov ebp, esp + push ebx + push ebx + + mov ebx, VMCS_HOST_ES_SELECTOR + mov eax, es + vmwrite ebx, eax + jz .error_code + jc .error + + mov ebx, VMCS_HOST_CS_SELECTOR + mov eax, cs + vmwrite ebx, eax + jz .error_code + jc .error + + mov ebx, VMCS_HOST_SS_SELECTOR + mov eax, ss + vmwrite ebx, eax + jz .error_code + jc .error + + mov ebx, VMCS_HOST_DS_SELECTOR + mov eax, ds + vmwrite ebx, eax + jz .error_code + jc .error + + mov ebx, VMCS_HOST_FS_SELECTOR + mov eax, fs + vmwrite ebx, eax + jz .error_code + jc .error + + mov ebx, VMCS_HOST_GS_SELECTOR + mov eax, gs + vmwrite ebx, eax + jz .error_code + jc .error + + str [esp] + mov eax, [esp] + mov ebx, VMCS_HOST_TR_SELECTOR + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + pop ebx + pop ebx + pop ebp + ret +ret + + + + + +align 8 +InitHostBaseRegs: + push ebp + mov ebp, esp + push ebx + sub esp, 6 + + sgdt [esp] + mov eax, [esp+2] + mov ebx, HOST_GDTR_BASE + vmwrite ebx, eax + jz .error_code + jc .error + + sidt [esp] + mov eax, [esp+2] + mov ebx, HOST_IDTR_BASE + vmwrite ebx, eax + jz .error_code + jc .error + + + mov eax, dword 0 + mov ebx, HOST_FS_BASE + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, dword 0 + mov ebx, HOST_GS_BASE + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, dword 0 + mov ebx, HOST_TR_BASE + vmwrite ebx, eax + jz .error_code + jc .error + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + + add esp, 6 + pop ebx + pop ebp + ret + + +align 8 +Init_VMCS_HostState: + push ebp + mov ebp, esp + push ebx + + mov ebx, HOST_CR3 + mov eax, cr3 + vmwrite ebx, eax + jz .error_code + jc .error + + + mov ebx, HOST_RSP + mov eax, esp + vmwrite ebx, eax + jz .error_code + jc .error + +; push esp + call InitHostSelectors + and eax, 0xffffffff + jz .selDone + jmp .return +.selDone +; push esp + call InitHostBaseRegs + and eax, 0xffffffff + jz .baseRegsDone + jmp .return +.baseRegsDone + + + mov eax, VMX_SUCCESS + jmp .return +.error + mov eax, VMX_FAIL_INVALID + jmp .return +.error_code + mov eax, VMX_FAIL_VALID +.return + pop ebx + pop ebp + ret + +; +; Launch_VM - inits a vmcs with an ip and launches it +; [eip = ebp + 8], [vmcs = ebp + 12] +; int Launch_VM(ullont_t VMCS, uint_t eip); +; +align 8 +Launch_VM: + push ebp + mov ebp, esp + push ebx + mov ebx, dword 0 + vmclear [ebp+8] + jz .error_code + jc .error + add ebx, dword 1 + vmptrld [ebp+8] + jz .error_code + jc .error + mov eax, dword 0x0000681E + add ebx, dword 1 + vmwrite eax, [ebp+16] + jz .error_code + jc .error + add ebx, dword 1 + vmlaunch + jz .error_code + jc .error + mov eax, VMX_SUCCESS + jmp .return +.error + shl ebx, 4 + mov eax, VMX_FAIL_INVALID + or eax, ebx + jmp .return +.error_code + shl ebx, 4 + mov eax, VMX_FAIL_VALID + or eax, ebx + mov ebx, dword 0x00004400 + vmread eax, ebx +.return + pop ebx + pop ebp + + ret + + +%endif diff --git a/palacios/src/libc/compat.c b/palacios/src/libc/compat.c new file mode 100644 index 0000000..995a03b --- /dev/null +++ b/palacios/src/libc/compat.c @@ -0,0 +1,8 @@ +#include +#include + +void *Malloc(size_t n) +{ + Print("Malloc not implemented in user mode\n"); + return 0; +} diff --git a/palacios/src/vmboot/rombios/Makefile b/palacios/src/vmboot/rombios/Makefile new file mode 100644 index 0000000..1d16fb2 --- /dev/null +++ b/palacios/src/vmboot/rombios/Makefile @@ -0,0 +1,27 @@ + +.PHONY: all +all: bios + +.PHONY: bios +bios: biossums BIOS-bochs-latest + +.PHONY: clean +clean: + rm -f *.o *.a *.s rombios.bin _rombios*_.c + rm -f as86-sym.txt ld86-sym.txt + rm -f rombios*.txt rombios*.sym usage biossums + rm -f BIOS-bochs-* + +BIOS-bochs-latest: rombios.c biossums + gcc -DBX_SMP_PROCESSORS=1 -E -P $< > _rombios_.c + bcc -o rombios.s -C-c -D__i86__ -0 -S _rombios_.c + sed -e 's/^\.text//' -e 's/^\.data//' rombios.s > _rombios_.s + as86 _rombios_.s -b tmp.bin -u- -w- -g -0 -j -O -l rombios.txt + -perl makesym.perl < rombios.txt > rombios.sym + mv tmp.bin BIOS-bochs-latest + ./biossums BIOS-bochs-latest + rm -f _rombios_.s + +biossums: biossums.c + gcc -o biossums biossums.c + diff --git a/palacios/src/vmboot/rombios/apmbios.S b/palacios/src/vmboot/rombios/apmbios.S new file mode 100644 index 0000000..a010949 --- /dev/null +++ b/palacios/src/vmboot/rombios/apmbios.S @@ -0,0 +1,367 @@ +// APM BIOS support for the Bochs BIOS +// Copyright (C) 2004 Fabrice Bellard +// +// Debugging extensions, 16-bit interface and extended power options +// Copyright (C) 2005 Struan Bartlett +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +#if defined(APM_REAL) +#define APMSYM(s) apmreal_ ## s +#elif defined(APM_PROT16) +#define APMSYM(s) apm16_ ## s +#elif defined(APM_PROT32) +#define APMSYM(s) apm32_ ## s +#else +#error unsupported APM mode +#endif + +APMSYM(out_str): + push eax + push ebx + mov ebx, eax +APMSYM(out_str1): + SEG CS + mov al, byte ptr [bx] + cmp al, #0 + je APMSYM(out_str2) + outb dx, al + inc ebx + jmp APMSYM(out_str1) +APMSYM(out_str2): + pop ebx + pop eax + ret + +APMSYM(07_poweroff_str): + .ascii "Shutdown" + db 0 +APMSYM(07_suspend_str): + .ascii "Suspend" + db 0 +APMSYM(07_standby_str): + .ascii "Standby" + db 0 + +#if DEBUG_APM +APMSYM(put_str): + push edx + mov dx, #INFO_PORT + call APMSYM(out_str) + pop edx + ret + +; print the hex number in eax +APMSYM(put_num): + push eax + push ebx + push ecx + push edx + mov ecx, eax + mov bx, #8 + mov dx, #INFO_PORT +APMSYM(put_num1): + mov eax, ecx + shr eax, #28 + add al, #0x30 + cmp al, #0x39 + jbe APMSYM(put_num2) + add al, #0x27 +APMSYM(put_num2): + outb dx, al + shl ecx, #4 + dec bx + jne APMSYM(put_num1) + pop edx + pop ecx + pop ebx + pop eax + ret + +APMSYM(put_reg): + outb dx, al + shr eax, #8 + outb dx, al + shr eax, #8 + outb dx, al + shr eax, #8 + outb dx, al + + mov eax,ebx + call APMSYM(put_num) + + mov al, #0x3b + outb dx,al + mov al, #0x20 + outb dx,al + ret + +APMSYM(put_regs): + push eax + push edx + push ebx + mov dx, #INFO_PORT + + mov ebx, eax + mov eax, #0x3d584145 // 'EAX=' + call APMSYM(put_reg) + pop ebx + push ebx + mov eax, #0x3d584245 // 'EBX=' + call APMSYM(put_reg) + mov ebx, ecx + mov eax, #0x3d584345 // 'ECX=' + call APMSYM(put_reg) + mov ebx, edx + mov eax, #0x3d584445 // 'EDX=' + call APMSYM(put_reg) + mov ebx, esi + mov eax, #0x3d495345 // 'ESI=' + call APMSYM(put_reg) + mov ebx, edi + mov eax, #0x3d494445 // 'EDI=' + call APMSYM(put_reg) + + mov al, #0x0a + outb dx, al + pop ebx + pop edx + pop eax + ret +#endif + +#if defined(APM_PROT32) +_apm32_entry: +#endif +#if defined(APM_PROT16) +_apm16_entry: +#endif + pushf + +#if defined(APM_REAL) +_apmreal_entry: +#endif + +#if DEBUG_APM + call APMSYM(put_regs) +#endif + +#if defined(APM_REAL) +;----------------- +; APM installation check +APMSYM(00): + cmp al, #0x00 + jne APMSYM(01) + + mov ah, #1 // APM major version + mov al, #2 // APM minor version + + mov bh, #0x50 // 'P' + mov bl, #0x4d // 'M' + + // bit 0 : 16 bit interface supported + // bit 1 : 32 bit interface supported + mov cx, #0x3 + jmp APMSYM(ok) + +;----------------- +; APM real mode interface connect +APMSYM(01): + cmp al, #0x01 + jne APMSYM(02) + jmp APMSYM(ok) + +;----------------- +; APM 16 bit protected mode interface connect +APMSYM(02): + cmp al, #0x02 + jne APMSYM(03) + + mov bx, #_apm16_entry + + mov ax, #0xf000 // 16 bit code segment base + mov si, #0xfff0 // 16 bit code segment size + mov cx, #0xf000 // data segment address + mov di, #0xfff0 // data segment length + jmp APMSYM(ok) + +;----------------- +; APM 32 bit protected mode interface connect +APMSYM(03): + cmp al, #0x03 + jne APMSYM(04) + mov ax, #0xf000 // 32 bit code segment base + mov ebx, #_apm32_entry + mov cx, #0xf000 // 16 bit code segment base + // 32 bit code segment size (low 16 bits) + // 16 bit code segment size (high 16 bits) + mov esi, #0xfff0fff0 + mov dx, #0xf000 // data segment address + mov di, #0xfff0 // data segment length + jmp APMSYM(ok) +#endif + +;----------------- +; APM interface disconnect +APMSYM(04): + cmp al, #0x04 + jne APMSYM(05) + jmp APMSYM(ok) + +;----------------- +; APM cpu idle +APMSYM(05): + cmp al, #0x05 + jne APMSYM(07) + pushf ; XEN + sti ; XEN: OS calls us with ints disabled -- better re-enable here! + hlt + popf ; XEN + jmp APMSYM(ok) + +;----------------- +; APM Set Power State +APMSYM(07): + cmp al, #0x07 + jne APMSYM(08) + + cmp bx, #1 + jne APMSYM(ok) + + cmp cx, #3 + je APMSYM(07_poweroff) + + cmp cx, #2 + je APMSYM(07_suspend) + + cmp cx, #1 + je APMSYM(07_standby) + + jne APMSYM(ok) + +APMSYM(07_poweroff): + // send power off event to emulator + cli + mov dx, #0x8900 + mov ax, #APMSYM(07_poweroff_str) + call APMSYM(out_str) + +APMSYM(07_1): + hlt + jmp APMSYM(07_1) + +APMSYM(07_suspend): + push edx + mov dx, #0x8900 + mov ax, #APMSYM(07_suspend_str) + call APMSYM(out_str) + pop edx + jmp APMSYM(ok) + +APMSYM(07_standby): + push edx + mov dx, #0x8900 + mov ax, #APMSYM(07_standby_str) + call APMSYM(out_str) + pop edx + jmp APMSYM(ok) + +;----------------- +; APM Enable / Disable +APMSYM(08): + cmp al, #0x08 + jne APMSYM(0a) + + jmp APMSYM(ok) + +;----------------- +; Get Power Status +APMSYM(0a): + cmp al, #0x0a + jne APMSYM(0b) + mov bh, #0x01 // on line + // mov bh, #0x02 // battery + mov bl, #0xff // unknown battery status + // mov bl, #0x03 // charging + mov ch, #0x80 // no system battery + // mov ch, #0x8 // charging + mov cl, #0xff // unknown remaining time + // mov cl, #50 + mov dx, #0xffff // unknown remaining time + mov si, #0 // zero battery + // mov si, #1 // one battery + jmp APMSYM(ok) + +;----------------- +; Get PM Event +APMSYM(0b): + cmp al, #0x0b + jne APMSYM(0e) + mov ah, #0x80 // no event pending + jmp APMSYM(error) + +;----------------- +; APM Driver Version +APMSYM(0e): + cmp al, #0x0e + jne APMSYM(0f) + + mov ah, #1 + mov al, #2 + + jmp APMSYM(ok) + +;----------------- +; APM Engage / Disengage +APMSYM(0f): + cmp al, #0x0f + jne APMSYM(10) + + jmp APMSYM(ok) + +;----------------- +; APM Get Capabilities +APMSYM(10): + cmp al, #0x10 + jne APMSYM(unimplemented) + + mov bl, #0 + mov cx, #0 + + jmp APMSYM(ok) + +;----------------- +APMSYM(ok): + popf + clc +#if defined(APM_REAL) + jmp iret_modify_cf +#else + retf +#endif +APMSYM(unimplemented): +APMSYM(error): + popf + stc +#if defined(APM_REAL) + jmp iret_modify_cf +#else + retf +#endif + +#undef APM_PROT32 +#undef APM_PROT16 +#undef APM_REAL +#undef APMSYM diff --git a/palacios/src/vmboot/rombios/biossums.c b/palacios/src/vmboot/rombios/biossums.c new file mode 100644 index 0000000..be12e49 --- /dev/null +++ b/palacios/src/vmboot/rombios/biossums.c @@ -0,0 +1,478 @@ +/* biossums.c --- written by Eike W. */ + +#include +#include + +typedef unsigned char byte; + +void check( int value, char* message ); + +#define LEN_BIOS_DATA 0x10000 +#define MAX_OFFSET (LEN_BIOS_DATA - 1) + + +#define BIOS_OFFSET 0xFFFF + +long chksum_bios_get_offset( byte* data, long offset ); +byte chksum_bios_calc_value( byte* data, long offset ); +byte chksum_bios_get_value( byte* data, long offset ); +void chksum_bios_set_value( byte* data, long offset, byte value ); + + +#define _32__LEN 9 +#define _32__CHKSUM 10 + +#define _32__MINHDR 16 + +long chksum__32__get_offset( byte* data, long offset ); +byte chksum__32__calc_value( byte* data, long offset ); +byte chksum__32__get_value( byte* data, long offset ); +void chksum__32__set_value( byte* data, long offset, byte value ); + + +#define _MP__LEN 8 +#define _MP__CHKSUM 10 + +#define _MP__MINHDR 16 + +long chksum__mp__get_offset( byte* data, long offset ); +byte chksum__mp__calc_value( byte* data, long offset ); +byte chksum__mp__get_value( byte* data, long offset ); +void chksum__mp__set_value( byte* data, long offset, byte value ); + + +#define PCMP_BASELEN 4 +#define PCMP_CHKSUM 7 +#define PCMP_EXT_LEN 40 +#define PCMP_EXT_CHKSUM 42 + +#define PCMP_MINHDR 42 + +long chksum_pcmp_get_offset( byte* data, long offset ); +byte chksum_pcmp_calc_value( byte* data, long offset ); +byte chksum_pcmp_get_value( byte* data, long offset ); +void chksum_pcmp_set_value( byte* data, long offset, byte value ); + + +#define _PIR_LEN 6 +#define _PIR_CHKSUM 31 + +#define _PIR_MINHDR 32 + +long chksum__pir_get_offset( byte *data, long offset ); +byte chksum__pir_calc_value( byte* data, long offset ); +byte chksum__pir_get_value( byte* data, long offset ); +void chksum__pir_set_value( byte* data, long offset, byte value ); + + +byte bios_data[LEN_BIOS_DATA]; + + +int main( int argc, char* argv[] ) { + + FILE* stream; + long offset, tmp_offset; + byte cur_val = 0, new_val = 0; + int hits; + + + if( argc != 2 ) { + printf( "Error. Need a file-name as an argument.\n" ); + exit( EXIT_FAILURE ); + } + + if(( stream = fopen( argv[1], "rb" )) == NULL ) { + printf( "Error opening %s for reading.\n", argv[1] ); + exit( EXIT_FAILURE ); + } + if( fread( bios_data, 1, LEN_BIOS_DATA, stream ) < LEN_BIOS_DATA ) { + printf( "Error reading 64KBytes from %s.\n", argv[1] ); + fclose( stream ); + exit( EXIT_FAILURE ); + } + fclose( stream ); + + hits = 0; + offset = 0L; + while( (tmp_offset = chksum__32__get_offset( bios_data, offset )) != -1L ) { + offset = tmp_offset; + cur_val = chksum__32__get_value( bios_data, offset ); + new_val = chksum__32__calc_value( bios_data, offset ); + printf( "\n\nPCI-Bios header at: 0x%4lX\n", offset ); + printf( "Current checksum: 0x%02X\n", cur_val ); + printf( "Calculated checksum: 0x%02X ", new_val ); + hits++; + } + if( hits == 1 && cur_val != new_val ) { + printf( "Setting checksum." ); + chksum__32__set_value( bios_data, offset, new_val ); + } + if( hits >= 2 ) { + printf( "Multiple PCI headers! No checksum set." ); + } + if( hits ) { + printf( "\n" ); + } + + + hits = 0; + offset = 0L; + while( (tmp_offset = chksum__mp__get_offset( bios_data, offset )) != -1L ) { + offset = tmp_offset; + cur_val = chksum__mp__get_value( bios_data, offset ); + new_val = chksum__mp__calc_value( bios_data, offset ); + printf( "\n\nMP header at: 0x%4lX\n", offset ); + printf( "Current checksum: 0x%02X\n", cur_val ); + printf( "Calculated checksum: 0x%02X ", new_val ); + hits++; + } + if( hits == 1 && cur_val != new_val ) { + printf( "Setting checksum." ); + chksum__mp__set_value( bios_data, offset, new_val ); + } + if( hits >= 2 ) { + printf( "Warning! Multiple MP headers. No checksum set." ); + } + if( hits ) { + printf( "\n" ); + } + + + hits = 0; + offset = 0L; + while( (tmp_offset = chksum_pcmp_get_offset( bios_data, offset )) != -1L ) { + offset = tmp_offset; + cur_val = chksum_pcmp_get_value( bios_data, offset ); + new_val = chksum_pcmp_calc_value( bios_data, offset ); + printf( "\n\nPCMP header at: 0x%4lX\n", offset ); + printf( "Current checksum: 0x%02X\n", cur_val ); + printf( "Calculated checksum: 0x%02X ", new_val ); + hits++; + } + if( hits == 1 && cur_val != new_val ) { + printf( "Setting checksum." ); + chksum_pcmp_set_value( bios_data, offset, new_val ); + } + if( hits >= 2 ) { + printf( "Warning! Multiple PCMP headers. No checksum set." ); + } + if( hits ) { + printf( "\n" ); + } + + + hits = 0; + offset = 0L; + while( (tmp_offset = chksum__pir_get_offset( bios_data, offset )) != -1L ) { + offset = tmp_offset; + cur_val = chksum__pir_get_value( bios_data, offset ); + new_val = chksum__pir_calc_value( bios_data, offset ); + printf( "\n\n$PIR header at: 0x%4lX\n", offset ); + printf( "Current checksum: 0x%02X\n", cur_val ); + printf( "Calculated checksum: 0x%02X\n ", new_val ); + hits++; + } + if( hits == 1 && cur_val != new_val ) { + printf( "Setting checksum." ); + chksum__pir_set_value( bios_data, offset, new_val ); + } + if( hits >= 2 ) { + printf( "Warning! Multiple $PIR headers. No checksum set." ); + } + if( hits ) { + printf( "\n" ); + } + + + offset = 0L; + offset = chksum_bios_get_offset( bios_data, offset ); + cur_val = chksum_bios_get_value( bios_data, offset ); + new_val = chksum_bios_calc_value( bios_data, offset ); + printf( "\n\nBios checksum at: 0x%4lX\n", offset ); + printf( "Current checksum: 0x%02X\n", cur_val ); + printf( "Calculated checksum: 0x%02X ", new_val ); + if( cur_val != new_val ) { + printf( "Setting checksum." ); + chksum_bios_set_value( bios_data, offset, new_val ); + } + printf( "\n" ); + + + if(( stream = fopen( argv[1], "wb" )) == NULL ) { + printf( "Error opening %s for writing.\n", argv[1] ); + exit( EXIT_FAILURE ); + } + if( fwrite( bios_data, 1, LEN_BIOS_DATA, stream ) < LEN_BIOS_DATA ) { + printf( "Error writing 64KBytes to %s.\n", argv[1] ); + fclose( stream ); + exit( EXIT_FAILURE ); + } + fclose( stream ); + + return( EXIT_SUCCESS ); +} + + +void check( int okay, char* message ) { + + if( !okay ) { + printf( "\n\nError. %s.\n", message ); + exit( EXIT_FAILURE ); + } +} + + +long chksum_bios_get_offset( byte* data, long offset ) { + + return( BIOS_OFFSET ); +} + + +byte chksum_bios_calc_value( byte* data, long offset ) { + + int i; + byte sum; + + sum = 0; + for( i = 0; i < MAX_OFFSET; i++ ) { + sum = sum + *( data + i ); + } + sum = -sum; /* iso ensures -s + s == 0 on unsigned types */ + return( sum ); +} + + +byte chksum_bios_get_value( byte* data, long offset ) { + + return( *( data + BIOS_OFFSET ) ); +} + + +void chksum_bios_set_value( byte* data, long offset, byte value ) { + + *( data + BIOS_OFFSET ) = value; +} + + +byte chksum__32__calc_value( byte* data, long offset ) { + + int i; + int len; + byte sum; + + check( offset + _32__MINHDR <= MAX_OFFSET, "_32_ header out of bounds" ); + len = *( data + offset + _32__LEN ) << 4; + check( offset + len <= MAX_OFFSET, "_32_ header-length out of bounds" ); + sum = 0; + for( i = 0; i < len; i++ ) { + if( i != _32__CHKSUM ) { + sum = sum + *( data + offset + i ); + } + } + sum = -sum; + return( sum ); +} + + +long chksum__32__get_offset( byte* data, long offset ) { + + long result = -1L; + + offset = offset + 0x0F; + offset = offset & ~( 0x0F ); + while( offset + 16 < MAX_OFFSET ) { + offset = offset + 16; + if( *( data + offset + 0 ) == '_' && \ + *( data + offset + 1 ) == '3' && \ + *( data + offset + 2 ) == '2' && \ + *( data + offset + 3 ) == '_' ) { + result = offset; + break; + } + } + return( result ); +} + + +byte chksum__32__get_value( byte* data, long offset ) { + + check( offset + _32__CHKSUM <= MAX_OFFSET, "PCI-Bios checksum out of bounds" ); + return( *( data + offset + _32__CHKSUM ) ); +} + + +void chksum__32__set_value( byte* data, long offset, byte value ) { + + check( offset + _32__CHKSUM <= MAX_OFFSET, "PCI-Bios checksum out of bounds" ); + *( data + offset + _32__CHKSUM ) = value; +} + + +byte chksum__mp__calc_value( byte* data, long offset ) { + + int i; + int len; + byte sum; + + check( offset + _MP__MINHDR <= MAX_OFFSET, "_MP_ header out of bounds" ); + len = *( data + offset + _MP__LEN ) << 4; + check( offset + len <= MAX_OFFSET, "_MP_ header-length out of bounds" ); + sum = 0; + for( i = 0; i < len; i++ ) { + if( i != _MP__CHKSUM ) { + sum = sum + *( data + offset + i ); + } + } + sum = -sum; + return( sum ); +} + + +long chksum__mp__get_offset( byte* data, long offset ) { + + long result = -1L; + + offset = offset + 0x0F; + offset = offset & ~( 0x0F ); + while( offset + 16 < MAX_OFFSET ) { + offset = offset + 16; + if( *( data + offset + 0 ) == '_' && \ + *( data + offset + 1 ) == 'M' && \ + *( data + offset + 2 ) == 'P' && \ + *( data + offset + 3 ) == '_' ) { + result = offset; + break; + } + } + return( result ); +} + + +byte chksum__mp__get_value( byte* data, long offset ) { + + check( offset + _MP__CHKSUM <= MAX_OFFSET, "MP checksum out of bounds" ); + return( *( data + offset + _MP__CHKSUM ) ); +} + + +void chksum__mp__set_value( byte* data, long offset, byte value ) { + + check( offset + _MP__CHKSUM <= MAX_OFFSET, "MP checksum out of bounds" ); + *( data + offset + _MP__CHKSUM ) = value; +} + + +byte chksum_pcmp_calc_value( byte* data, long offset ) { + + int i; + int len; + byte sum; + + check( offset + PCMP_MINHDR <= MAX_OFFSET, "PCMP header out of bounds" ); + len = *( data + offset + PCMP_BASELEN ) + \ + ( *( data + offset + PCMP_BASELEN + 1 ) << 8 ); + check( offset + len <= MAX_OFFSET, "PCMP header-length out of bounds" ); + if( *( data + offset + PCMP_EXT_LEN ) | \ + *( data + offset + PCMP_EXT_LEN + 1 ) | \ + *( data + offset + PCMP_EXT_CHKSUM ) ) { + check( 0, "PCMP header indicates extended tables (unsupported)" ); + } + sum = 0; + for( i = 0; i < len; i++ ) { + if( i != PCMP_CHKSUM ) { + sum = sum + *( data + offset + i ); + } + } + sum = -sum; + return( sum ); +} + + +long chksum_pcmp_get_offset( byte* data, long offset ) { + + long result = -1L; + + offset = offset + 0x0F; + offset = offset & ~( 0x0F ); + while( offset + 16 < MAX_OFFSET ) { + offset = offset + 16; + if( *( data + offset + 0 ) == 'P' && \ + *( data + offset + 1 ) == 'C' && \ + *( data + offset + 2 ) == 'M' && \ + *( data + offset + 3 ) == 'P' ) { + result = offset; + break; + } + } + return( result ); +} + + +byte chksum_pcmp_get_value( byte* data, long offset ) { + + check( offset + PCMP_CHKSUM <= MAX_OFFSET, "PCMP checksum out of bounds" ); + return( *( data + offset + PCMP_CHKSUM ) ); +} + + +void chksum_pcmp_set_value( byte* data, long offset, byte value ) { + + check( offset + PCMP_CHKSUM <= MAX_OFFSET, "PCMP checksum out of bounds" ); + *( data + offset + PCMP_CHKSUM ) = value; +} + + +byte chksum__pir_calc_value( byte* data, long offset ) { + + int i; + int len; + byte sum; + + check( offset + _PIR_MINHDR <= MAX_OFFSET, "$PIR header out of bounds" ); + len = *( data + offset + _PIR_LEN ) + \ + ( *( data + offset + _PIR_LEN + 1 ) << 8 ); + check( offset + len <= MAX_OFFSET, "$PIR header-length out of bounds" ); + sum = 0; + for( i = 0; i < len; i++ ) { + if( i != _PIR_CHKSUM ) { + sum = sum + *( data + offset + i ); + } + } + sum = -sum; + return( sum ); +} + + +long chksum__pir_get_offset( byte* data, long offset ) { + + long result = -1L; + + offset = offset + 0x0F; + offset = offset & ~( 0x0F ); + while( offset + 16 < MAX_OFFSET ) { + offset = offset + 16; + if( *( data + offset + 0 ) == '$' && \ + *( data + offset + 1 ) == 'P' && \ + *( data + offset + 2 ) == 'I' && \ + *( data + offset + 3 ) == 'R' ) { + result = offset; + break; + } + } + return( result ); +} + + +byte chksum__pir_get_value( byte* data, long offset ) { + + check( offset + _PIR_CHKSUM <= MAX_OFFSET, "$PIR checksum out of bounds" ); + return( *( data + offset + _PIR_CHKSUM ) ); +} + + +void chksum__pir_set_value( byte* data, long offset, byte value ) { + + check( offset + _PIR_CHKSUM <= MAX_OFFSET, "$PIR checksum out of bounds" ); + *( data + offset + _PIR_CHKSUM ) = value; +} + diff --git a/palacios/src/vmboot/rombios/makesym.perl b/palacios/src/vmboot/rombios/makesym.perl new file mode 100755 index 0000000..a3c7705 --- /dev/null +++ b/palacios/src/vmboot/rombios/makesym.perl @@ -0,0 +1,31 @@ +#!/usr/bin/perl +# +# $Id: makesym.perl,v 1.1 2007/11/29 20:26:38 pdinda Exp $ +# +# Read output file from as86 (e.g. rombios.txt) and write out a symbol +# table suitable for the Bochs debugger. +# + +$WHERE_BEFORE_SYM_TABLE = 0; +$WHERE_IN_SYM_TABLE = 1; +$WHERE_AFTER_SYM_TABLE = 2; + +$where = $WHERE_BEFORE_SYM_TABLE; +while () { + chop; + if ($where == WHERE_BEFORE_SYM_TABLE && /^Symbols:/) { + $where = $WHERE_IN_SYM_TABLE; + } elsif ($where == $WHERE_IN_SYM_TABLE && /^$/) { + $where = $WHERE_AFTER_SYM_TABLE; + } + if ($where == $WHERE_IN_SYM_TABLE) { + @F = split (/\s+/); + ($name[0], $junk, $addr[0], $junk, $name[1], $junk, $addr[1]) = @F; + foreach $col (0,1) { + next if length $addr[$col] < 1; + $addr[$col] =~ tr/A-Z/a-z/; + $addr[$col] = "000f" . $addr[$col]; + print "$addr[$col] $name[$col]\n"; + } + } +} diff --git a/palacios/src/vmboot/rombios/rombios.c b/palacios/src/vmboot/rombios/rombios.c new file mode 100644 index 0000000..b8322d0 --- /dev/null +++ b/palacios/src/vmboot/rombios/rombios.c @@ -0,0 +1,10930 @@ +///////////////////////////////////////////////////////////////////////// +// $Id: rombios.c,v 1.1 2007/11/29 20:26:38 pdinda Exp $ +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2002 MandrakeSoft S.A. +// +// MandrakeSoft S.A. +// 43, rue d'Aboukir +// 75002 Paris - France +// http://www.linux-mandrake.com/ +// http://www.mandrakesoft.com/ +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +// ROM BIOS for use with Bochs/Plex x86 emulation environment + +#define HVMASSIST +#undef HVMTEST + +// Xen full virtualization does not handle unaligned IO with page crossing. +// Disable 32-bit PIO as a workaround. +#undef NO_PIO32 + + +// ROM BIOS compatability entry points: +// =================================== +// $e05b ; POST Entry Point +// $e2c3 ; NMI Handler Entry Point +// $e3fe ; INT 13h Fixed Disk Services Entry Point +// $e401 ; Fixed Disk Parameter Table +// $e6f2 ; INT 19h Boot Load Service Entry Point +// $e6f5 ; Configuration Data Table +// $e729 ; Baud Rate Generator Table +// $e739 ; INT 14h Serial Communications Service Entry Point +// $e82e ; INT 16h Keyboard Service Entry Point +// $e987 ; INT 09h Keyboard Service Entry Point +// $ec59 ; INT 13h Diskette Service Entry Point +// $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point +// $efc7 ; Diskette Controller Parameter Table +// $efd2 ; INT 17h Printer Service Entry Point +// $f045 ; INT 10 Functions 0-Fh Entry Point +// $f065 ; INT 10h Video Support Service Entry Point +// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh) +// $f841 ; INT 12h Memory Size Service Entry Point +// $f84d ; INT 11h Equipment List Service Entry Point +// $f859 ; INT 15h System Services Entry Point +// $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters) +// $fe6e ; INT 1Ah Time-of-day Service Entry Point +// $fea5 ; INT 08h System Timer ISR Entry Point +// $fef3 ; Initial Interrupt Vector Offsets Loaded by POST +// $ff53 ; IRET Instruction for Dummy Interrupt Handler +// $ff54 ; INT 05h Print Screen Service Entry Point +// $fff0 ; Power-up Entry Point +// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY +// $fffe ; System Model ID + +// NOTES for ATA/ATAPI driver (cbbochs@free.fr) +// Features +// - supports up to 4 ATA interfaces +// - device/geometry detection +// - 16bits/32bits device access +// - pchs/lba access +// - datain/dataout/packet command support +// +// NOTES for El-Torito Boot (cbbochs@free.fr) +// - CD-ROM booting is only available if ATA/ATAPI Driver is available +// - Current code is only able to boot mono-session cds +// - Current code can not boot and emulate a hard-disk +// the bios will panic otherwise +// - Current code also use memory in EBDA segement. +// - I used cmos byte 0x3D to store extended information on boot-device +// - Code has to be modified modified to handle multiple cdrom drives +// - Here are the cdrom boot failure codes: +// 1 : no atapi device found +// 2 : no atapi cdrom found +// 3 : can not read cd - BRVD +// 4 : cd is not eltorito (BRVD) +// 5 : cd is not eltorito (ISO TAG) +// 6 : cd is not eltorito (ELTORITO TAG) +// 7 : can not read cd - boot catalog +// 8 : boot catalog : bad header +// 9 : boot catalog : bad platform +// 10 : boot catalog : bad signature +// 11 : boot catalog : bootable flag not set +// 12 : can not read cd - boot image +// +// ATA driver +// - EBDA segment. +// I used memory starting at 0x121 in the segment +// - the translation policy is defined in cmos regs 0x39 & 0x3a +// +// TODO : +// +// int74 +// - needs to be reworked. Uses direct [bp] offsets. (?) +// +// int13: +// - f04 (verify sectors) isn't complete (?) +// - f02/03/04 should set current cyl,etc in BDA (?) +// - rewrite int13_relocated & clean up int13 entry code +// +// NOTES: +// - NMI access (bit7 of addr written to 70h) +// +// ATA driver +// - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c) +// - could send the multiple-sector read/write commands +// +// El-Torito +// - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk" +// - Implement remaining int13_cdemu functions (as defined by El-Torito specs) +// - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded" +// - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13. +// This is ok. But DL should be reincremented afterwards. +// - Fix all "FIXME ElTorito Various" +// - should be able to boot any cdrom instead of the first one +// +// BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7) + +#define DEBUG_ROMBIOS 0 + +#define DEBUG_ATA 0 +#define DEBUG_INT13_HD 0 +#define DEBUG_INT13_CD 0 +#define DEBUG_INT13_ET 0 +#define DEBUG_INT13_FL 0 +#define DEBUG_INT15 0 +#define DEBUG_INT16 0 +#define DEBUG_INT1A 0 +#define DEBUG_INT74 0 +#define DEBUG_APM 0 + +#define BX_CPU 3 +#define BX_USE_PS2_MOUSE 1 +#define BX_CALL_INT15_4F 1 +#define BX_USE_EBDA 1 +#define BX_SUPPORT_FLOPPY 1 +#define BX_FLOPPY_ON_CNT 37 /* 2 seconds */ +#define BX_PCIBIOS 1 +#define BX_APM 1 + +#define BX_USE_ATADRV 1 +#define BX_ELTORITO_BOOT 1 + +#define BX_MAX_ATA_INTERFACES 4 +#define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2) + +#define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */ +#define BX_DEBUG_SERIAL 0 /* output to COM1 */ + + /* model byte 0xFC = AT */ +#define SYS_MODEL_ID 0xFC +#define SYS_SUBMODEL_ID 0x00 +#define BIOS_REVISION 1 +#define BIOS_CONFIG_TABLE 0xe6f5 + +#ifndef BIOS_BUILD_DATE +# define BIOS_BUILD_DATE "06/23/99" +#endif + + // 1K of base memory used for Extended Bios Data Area (EBDA) + // EBDA is used for PS/2 mouse support, and IDE BIOS, etc. +#define EBDA_SEG 0x9FC0 +#define EBDA_SIZE 1 // In KiB +#define BASE_MEM_IN_K (640 - EBDA_SIZE) + + // Define the application NAME +#ifdef HVMASSIST +# define BX_APPNAME "HVMAssist" +#elif PLEX86 +# define BX_APPNAME "Plex86" +#else +# define BX_APPNAME "Bochs" +#endif + + // Sanity Checks +#if BX_USE_ATADRV && BX_CPU<3 +# error The ATA/ATAPI Driver can only to be used with a 386+ cpu +#endif +#if BX_USE_ATADRV && !BX_USE_EBDA +# error ATA/ATAPI Driver can only be used if EBDA is available +#endif +#if BX_ELTORITO_BOOT && !BX_USE_ATADRV +# error El-Torito Boot can only be use if ATA/ATAPI Driver is available +#endif +#if BX_PCIBIOS && BX_CPU<3 +# error PCI BIOS can only be used with 386+ cpu +#endif +#if BX_APM && BX_CPU<3 +# error APM BIOS can only be used with 386+ cpu +#endif + +#ifndef BX_SMP_PROCESSORS +#define BX_SMP_PROCESSORS 1 +# warning BX_SMP_PROCESSORS not defined, defaulting to 1 +#endif + +#define PANIC_PORT 0x400 +#define PANIC_PORT2 0x401 +#define INFO_PORT 0x402 +#define DEBUG_PORT 0x403 + +// #20 is dec 20 +// #$20 is hex 20 = 32 +// #0x20 is hex 20 = 32 +// LDA #$20 +// JSR $E820 +// LDD .i,S +// JSR $C682 +// mov al, #$20 + +// all hex literals should be prefixed with '0x' +// grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c +// no mov SEG-REG, #value, must mov register into seg-reg +// grep -i "mov[ ]*.s" rombios.c + +// This is for compiling with gcc2 and gcc3 +#define ASM_START #asm +#define ASM_END #endasm + +ASM_START +.rom + +.org 0x0000 + +#if BX_CPU >= 3 +use16 386 +#else +use16 286 +#endif + +MACRO HALT + ;; the HALT macro is called with the line number of the HALT call. + ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex + ;; to print a BX_PANIC message. This will normally halt the simulation + ;; with a message such as "BIOS panic at rombios.c, line 4091". + ;; However, users can choose to make panics non-fatal and continue. +#if BX_VIRTUAL_PORTS + mov dx,#PANIC_PORT + mov ax,#?1 + out dx,ax +#else + mov dx,#0x80 + mov ax,#?1 + out dx,al +#endif +MEND + +MACRO JMP_AP + db 0xea + dw ?2 + dw ?1 +MEND + +MACRO SET_INT_VECTOR + mov ax, ?3 + mov ?1*4, ax + mov ax, ?2 + mov ?1*4+2, ax +MEND + +ASM_END + +typedef unsigned char Bit8u; +typedef unsigned short Bit16u; +typedef unsigned short bx_bool; +typedef unsigned long Bit32u; + +#if BX_USE_ATADRV + + void memsetb(seg,offset,value,count); + void memcpyb(dseg,doffset,sseg,soffset,count); + void memcpyd(dseg,doffset,sseg,soffset,count); + + // memset of count bytes + void + memsetb(seg,offset,value,count) + Bit16u seg; + Bit16u offset; + Bit16u value; + Bit16u count; + { + ASM_START + push bp + mov bp, sp + + push ax + push cx + push es + push di + + mov cx, 10[bp] ; count + cmp cx, #0x00 + je memsetb_end + mov ax, 4[bp] ; segment + mov es, ax + mov ax, 6[bp] ; offset + mov di, ax + mov al, 8[bp] ; value + cld + rep + stosb + + memsetb_end: + pop di + pop es + pop cx + pop ax + + pop bp + ASM_END + } + + // memcpy of count bytes + void + memcpyb(dseg,doffset,sseg,soffset,count) + Bit16u dseg; + Bit16u doffset; + Bit16u sseg; + Bit16u soffset; + Bit16u count; + { + ASM_START + push bp + mov bp, sp + + push ax + push cx + push es + push di + push ds + push si + + mov cx, 12[bp] ; count + cmp cx, #0x0000 + je memcpyb_end + mov ax, 4[bp] ; dsegment + mov es, ax + mov ax, 6[bp] ; doffset + mov di, ax + mov ax, 8[bp] ; ssegment + mov ds, ax + mov ax, 10[bp] ; soffset + mov si, ax + cld + rep + movsb + + memcpyb_end: + pop si + pop ds + pop di + pop es + pop cx + pop ax + + pop bp + ASM_END + } + +#if 0 + // memcpy of count dword + void + memcpyd(dseg,doffset,sseg,soffset,count) + Bit16u dseg; + Bit16u doffset; + Bit16u sseg; + Bit16u soffset; + Bit16u count; + { + ASM_START + push bp + mov bp, sp + + push ax + push cx + push es + push di + push ds + push si + + mov cx, 12[bp] ; count + cmp cx, #0x0000 + je memcpyd_end + mov ax, 4[bp] ; dsegment + mov es, ax + mov ax, 6[bp] ; doffset + mov di, ax + mov ax, 8[bp] ; ssegment + mov ds, ax + mov ax, 10[bp] ; soffset + mov si, ax + cld + rep + movsd + + memcpyd_end: + pop si + pop ds + pop di + pop es + pop cx + pop ax + + pop bp + ASM_END + } +#endif +#endif //BX_USE_ATADRV + + // read_dword and write_dword functions + static Bit32u read_dword(); + static void write_dword(); + + Bit32u + read_dword(seg, offset) + Bit16u seg; + Bit16u offset; + { + ASM_START + push bp + mov bp, sp + + push bx + push ds + mov ax, 4[bp] ; segment + mov ds, ax + mov bx, 6[bp] ; offset + mov ax, [bx] + inc bx + inc bx + mov dx, [bx] + ;; ax = return value (word) + ;; dx = return value (word) + pop ds + pop bx + + pop bp + ASM_END + } + + void + write_dword(seg, offset, data) + Bit16u seg; + Bit16u offset; + Bit32u data; + { + ASM_START + push bp + mov bp, sp + + push ax + push bx + push ds + mov ax, 4[bp] ; segment + mov ds, ax + mov bx, 6[bp] ; offset + mov ax, 8[bp] ; data word + mov [bx], ax ; write data word + inc bx + inc bx + mov ax, 10[bp] ; data word + mov [bx], ax ; write data word + pop ds + pop bx + pop ax + + pop bp + ASM_END + } + + // Bit32u (unsigned long) and long helper functions + ASM_START + + ;; and function + landl: + landul: + SEG SS + and ax,[di] + SEG SS + and bx,2[di] + ret + + ;; add function + laddl: + laddul: + SEG SS + add ax,[di] + SEG SS + adc bx,2[di] + ret + + ;; cmp function + lcmpl: + lcmpul: + and eax, #0x0000FFFF + shl ebx, #16 + add eax, ebx + shr ebx, #16 + SEG SS + cmp eax, dword ptr [di] + ret + + ;; sub function + lsubl: + lsubul: + SEG SS + sub ax,[di] + SEG SS + sbb bx,2[di] + ret + + ;; mul function + lmull: + lmulul: + and eax, #0x0000FFFF + shl ebx, #16 + add eax, ebx + SEG SS + mul eax, dword ptr [di] + mov ebx, eax + shr ebx, #16 + ret + + ;; dec function + ldecl: + ldecul: + SEG SS + dec dword ptr [bx] + ret + + ;; or function + lorl: + lorul: + SEG SS + or ax,[di] + SEG SS + or bx,2[di] + ret + + ;; inc function + lincl: + lincul: + SEG SS + inc dword ptr [bx] + ret + + ;; tst function + ltstl: + ltstul: + and eax, #0x0000FFFF + shl ebx, #16 + add eax, ebx + shr ebx, #16 + test eax, eax + ret + + ;; sr function + lsrul: + mov cx,di + jcxz lsr_exit + and eax, #0x0000FFFF + shl ebx, #16 + add eax, ebx + lsr_loop: + shr eax, #1 + loop lsr_loop + mov ebx, eax + shr ebx, #16 + lsr_exit: + ret + + ;; sl function + lsll: + lslul: + mov cx,di + jcxz lsl_exit + and eax, #0x0000FFFF + shl ebx, #16 + add eax, ebx + lsl_loop: + shl eax, #1 + loop lsl_loop + mov ebx, eax + shr ebx, #16 + lsl_exit: + ret + + idiv_: + cwd + idiv bx + ret + + idiv_u: + xor dx,dx + div bx + ret + + ldivul: + and eax, #0x0000FFFF + shl ebx, #16 + add eax, ebx + xor edx, edx + SEG SS + mov bx, 2[di] + shl ebx, #16 + SEG SS + mov bx, [di] + div ebx + mov ebx, eax + shr ebx, #16 + ret + + ASM_END + +// for access to RAM area which is used by interrupt vectors +// and BIOS Data Area + +typedef struct { + unsigned char filler1[0x400]; + unsigned char filler2[0x6c]; + Bit16u ticks_low; + Bit16u ticks_high; + Bit8u midnight_flag; + } bios_data_t; + +#define BiosData ((bios_data_t *) 0) + +#if BX_USE_ATADRV + typedef struct { + Bit16u heads; // # heads + Bit16u cylinders; // # cylinders + Bit16u spt; // # sectors / track + } chs_t; + + // DPTE definition + typedef struct { + Bit16u iobase1; + Bit16u iobase2; + Bit8u prefix; + Bit8u unused; + Bit8u irq; + Bit8u blkcount; + Bit8u dma; + Bit8u pio; + Bit16u options; + Bit16u reserved; + Bit8u revision; + Bit8u checksum; + } dpte_t; + + typedef struct { + Bit8u iface; // ISA or PCI + Bit16u iobase1; // IO Base 1 + Bit16u iobase2; // IO Base 2 + Bit8u irq; // IRQ + } ata_channel_t; + + typedef struct { + Bit8u type; // Detected type of ata (ata/atapi/none/unknown) + Bit8u device; // Detected type of attached devices (hd/cd/none) + Bit8u removable; // Removable device flag + Bit8u lock; // Locks for removable devices + // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices + Bit8u mode; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA + Bit16u blksize; // block size + + Bit8u translation; // type of translation + chs_t lchs; // Logical CHS + chs_t pchs; // Physical CHS + + Bit32u sectors; // Total sectors count + } ata_device_t; + + typedef struct { + // ATA channels info + ata_channel_t channels[BX_MAX_ATA_INTERFACES]; + + // ATA devices info + ata_device_t devices[BX_MAX_ATA_DEVICES]; + // + // map between (bios hd id - 0x80) and ata channels + Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES]; + + // map between (bios cd id - 0xE0) and ata channels + Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES]; + + // Buffer for DPTE table + dpte_t dpte; + + // Count of transferred sectors and bytes + Bit16u trsfsectors; + Bit32u trsfbytes; + + } ata_t; + +#if BX_ELTORITO_BOOT + // ElTorito Device Emulation data + typedef struct { + Bit8u active; + Bit8u media; + Bit8u emulated_drive; + Bit8u controller_index; + Bit16u device_spec; + Bit32u ilba; + Bit16u buffer_segment; + Bit16u load_segment; + Bit16u sector_count; + + // Virtual device + chs_t vdevice; + } cdemu_t; +#endif // BX_ELTORITO_BOOT + + // for access to EBDA area + // The EBDA structure should conform to + // http://www.cybertrails.com/~fys/rombios.htm document + // I made the ata and cdemu structs begin at 0x121 in the EBDA seg + typedef struct { + unsigned char filler1[0x3D]; + + // FDPT - Can be splitted in data members if needed + unsigned char fdpt0[0x10]; + unsigned char fdpt1[0x10]; + + unsigned char filler2[0xC4]; + + // ATA Driver data + ata_t ata; + +#if BX_ELTORITO_BOOT + // El Torito Emulation data + cdemu_t cdemu; +#endif // BX_ELTORITO_BOOT + + } ebda_data_t; + + #define EbdaData ((ebda_data_t *) 0) + + // for access to the int13ext structure + typedef struct { + Bit8u size; + Bit8u reserved; + Bit16u count; + Bit16u offset; + Bit16u segment; + Bit32u lba1; + Bit32u lba2; + } int13ext_t; + + #define Int13Ext ((int13ext_t *) 0) + + // Disk Physical Table definition + typedef struct { + Bit16u size; + Bit16u infos; + Bit32u cylinders; + Bit32u heads; + Bit32u spt; + Bit32u sector_count1; + Bit32u sector_count2; + Bit16u blksize; + Bit16u dpte_segment; + Bit16u dpte_offset; + Bit16u key; + Bit8u dpi_length; + Bit8u reserved1; + Bit16u reserved2; + Bit8u host_bus[4]; + Bit8u iface_type[8]; + Bit8u iface_path[8]; + Bit8u device_path[8]; + Bit8u reserved3; + Bit8u checksum; + } dpt_t; + + #define Int13DPT ((dpt_t *) 0) + +#endif // BX_USE_ATADRV + +typedef struct { + union { + struct { + Bit16u di, si, bp, sp; + Bit16u bx, dx, cx, ax; + } r16; + struct { + Bit16u filler[4]; + Bit8u bl, bh, dl, dh, cl, ch, al, ah; + } r8; + } u; + } pusha_regs_t; + +typedef struct { + union { + struct { + Bit32u edi, esi, ebp, esp; + Bit32u ebx, edx, ecx, eax; + } r32; + struct { + Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4; + Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8; + } r16; + struct { + Bit32u filler[4]; + Bit8u bl, bh; + Bit16u filler1; + Bit8u dl, dh; + Bit16u filler2; + Bit8u cl, ch; + Bit16u filler3; + Bit8u al, ah; + Bit16u filler4; + } r8; + } u; +} pushad_regs_t; + +typedef struct { + union { + struct { + Bit16u flags; + } r16; + struct { + Bit8u flagsl; + Bit8u flagsh; + } r8; + } u; + } flags_t; + +#define SetCF(x) x.u.r8.flagsl |= 0x01 +#define SetZF(x) x.u.r8.flagsl |= 0x40 +#define ClearCF(x) x.u.r8.flagsl &= 0xfe +#define ClearZF(x) x.u.r8.flagsl &= 0xbf +#define GetCF(x) (x.u.r8.flagsl & 0x01) + +typedef struct { + Bit16u ip; + Bit16u cs; + flags_t flags; + } iret_addr_t; + + + +static Bit8u inb(); +static Bit8u inb_cmos(); +static void outb(); +static void outb_cmos(); +static Bit16u inw(); +static void outw(); +static void init_rtc(); +static bx_bool rtc_updating(); + +static Bit8u read_byte(); +static Bit16u read_word(); +static void write_byte(); +static void write_word(); +static void bios_printf(); +static void copy_e820_table(); + +static Bit8u inhibit_mouse_int_and_events(); +static void enable_mouse_int_and_events(); +static Bit8u send_to_mouse_ctrl(); +static Bit8u get_mouse_data(); +static void set_kbd_command_byte(); + +static void int09_function(); +static void int13_harddisk(); +static void int13_cdrom(); +static void int13_cdemu(); +static void int13_eltorito(); +static void int13_diskette_function(); +static void int14_function(); +static void int15_function(); +static void int16_function(); +static void int17_function(); +static Bit32u int19_function(); +static void int1a_function(); +static void int70_function(); +static void int74_function(); +static Bit16u get_CS(); +//static Bit16u get_DS(); +//static void set_DS(); +static Bit16u get_SS(); +static unsigned int enqueue_key(); +static unsigned int dequeue_key(); +static void get_hd_geometry(); +static void set_diskette_ret_status(); +static void set_diskette_current_cyl(); +static void determine_floppy_media(); +static bx_bool floppy_drive_exists(); +static bx_bool floppy_drive_recal(); +static bx_bool floppy_media_known(); +static bx_bool floppy_media_sense(); +static bx_bool set_enable_a20(); +static void debugger_on(); +static void debugger_off(); +static void keyboard_init(); +static void keyboard_panic(); +static void shutdown_status_panic(); +static void nmi_handler_msg(); + +static void print_bios_banner(); +static void print_boot_device(); +static void print_boot_failure(); +static void print_cdromboot_failure(); + +# if BX_USE_ATADRV + +// ATA / ATAPI driver +void ata_init(); +void ata_detect(); +void ata_reset(); + +Bit16u ata_cmd_non_data(); +Bit16u ata_cmd_data_in(); +Bit16u ata_cmd_data_out(); +Bit16u ata_cmd_packet(); + +Bit16u atapi_get_sense(); +Bit16u atapi_is_ready(); +Bit16u atapi_is_cdrom(); + +#endif // BX_USE_ATADRV + +#if BX_ELTORITO_BOOT + +void cdemu_init(); +Bit8u cdemu_isactive(); +Bit8u cdemu_emulated_drive(); + +Bit16u cdrom_boot(); + +#endif // BX_ELTORITO_BOOT + +static char bios_cvs_version_string[] = "$Revision: 1.1 $"; +static char bios_date_string[] = "$Date: 2007/11/29 20:26:38 $"; + +static char CVSID[] = "$Id: rombios.c,v 1.1 2007/11/29 20:26:38 pdinda Exp $"; + +/* Offset to skip the CVS $Id: prefix */ +#define bios_version_string (CVSID + 4) + +#define BIOS_PRINTF_HALT 1 +#define BIOS_PRINTF_SCREEN 2 +#define BIOS_PRINTF_INFO 4 +#define BIOS_PRINTF_DEBUG 8 +#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO) +#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT) + +#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p) + +// Defines the output macros. +// BX_DEBUG goes to INFO port until we can easily choose debug info on a +// per-device basis. Debug info are sent only in debug mode +#if DEBUG_ROMBIOS +# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p) +#else +# define BX_DEBUG(format, p...) +#endif +#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p) +#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p) + +#if DEBUG_ATA +# define BX_DEBUG_ATA(a...) BX_DEBUG(a) +#else +# define BX_DEBUG_ATA(a...) +#endif +#if DEBUG_INT13_HD +# define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a) +#else +# define BX_DEBUG_INT13_HD(a...) +#endif +#if DEBUG_INT13_CD +# define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a) +#else +# define BX_DEBUG_INT13_CD(a...) +#endif +#if DEBUG_INT13_ET +# define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a) +#else +# define BX_DEBUG_INT13_ET(a...) +#endif +#if DEBUG_INT13_FL +# define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a) +#else +# define BX_DEBUG_INT13_FL(a...) +#endif +#if DEBUG_INT15 +# define BX_DEBUG_INT15(a...) BX_DEBUG(a) +#else +# define BX_DEBUG_INT15(a...) +#endif +#if DEBUG_INT16 +# define BX_DEBUG_INT16(a...) BX_DEBUG(a) +#else +# define BX_DEBUG_INT16(a...) +#endif +#if DEBUG_INT1A +# define BX_DEBUG_INT1A(a...) BX_DEBUG(a) +#else +# define BX_DEBUG_INT1A(a...) +#endif +#if DEBUG_INT74 +# define BX_DEBUG_INT74(a...) BX_DEBUG(a) +#else +# define BX_DEBUG_INT74(a...) +#endif + +#define SET_AL(val8) AX = ((AX & 0xff00) | (val8)) +#define SET_BL(val8) BX = ((BX & 0xff00) | (val8)) +#define SET_CL(val8) CX = ((CX & 0xff00) | (val8)) +#define SET_DL(val8) DX = ((DX & 0xff00) | (val8)) +#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8)) +#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8)) +#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8)) +#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8)) + +#define GET_AL() ( AX & 0x00ff ) +#define GET_BL() ( BX & 0x00ff ) +#define GET_CL() ( CX & 0x00ff ) +#define GET_DL() ( DX & 0x00ff ) +#define GET_AH() ( AX >> 8 ) +#define GET_BH() ( BX >> 8 ) +#define GET_CH() ( CX >> 8 ) +#define GET_DH() ( DX >> 8 ) + +#define GET_ELDL() ( ELDX & 0x00ff ) +#define GET_ELDH() ( ELDX >> 8 ) + +#define SET_CF() FLAGS |= 0x0001 +#define CLEAR_CF() FLAGS &= 0xfffe +#define GET_CF() (FLAGS & 0x0001) + +#define SET_ZF() FLAGS |= 0x0040 +#define CLEAR_ZF() FLAGS &= 0xffbf +#define GET_ZF() (FLAGS & 0x0040) + +#define UNSUPPORTED_FUNCTION 0x86 + +#define none 0 +#define MAX_SCAN_CODE 0x53 + +static struct { + Bit16u normal; + Bit16u shift; + Bit16u control; + Bit16u alt; + Bit8u lock_flags; + } scan_to_scanascii[MAX_SCAN_CODE + 1] = { + { none, none, none, none, none }, + { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */ + { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */ + { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */ + { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */ + { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */ + { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */ + { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */ + { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */ + { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */ + { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */ + { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */ + { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */ + { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */ + { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */ + { 0x0f09, 0x0f00, none, none, none }, /* tab */ + { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */ + { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */ + { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */ + { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */ + { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */ + { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */ + { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */ + { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */ + { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */ + { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */ + { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */ + { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */ + { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */ + { none, none, none, none, none }, /* L Ctrl */ + { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */ + { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */ + { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */ + { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */ + { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */ + { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */ + { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */ + { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */ + { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */ + { 0x273b, 0x273a, none, none, none }, /* ;: */ + { 0x2827, 0x2822, none, none, none }, /* '" */ + { 0x2960, 0x297e, none, none, none }, /* `~ */ + { none, none, none, none, none }, /* L shift */ + { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */ + { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */ + { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */ + { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */ + { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */ + { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */ + { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */ + { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */ + { 0x332c, 0x333c, none, none, none }, /* ,< */ + { 0x342e, 0x343e, none, none, none }, /* .> */ + { 0x352f, 0x353f, none, none, none }, /* /? */ + { none, none, none, none, none }, /* R Shift */ + { 0x372a, 0x372a, none, none, none }, /* * */ + { none, none, none, none, none }, /* L Alt */ + { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */ + { none, none, none, none, none }, /* caps lock */ + { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */ + { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */ + { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */ + { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */ + { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */ + { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */ + { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */ + { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */ + { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */ + { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */ + { none, none, none, none, none }, /* Num Lock */ + { none, none, none, none, none }, /* Scroll Lock */ + { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */ + { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */ + { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */ + { 0x4a2d, 0x4a2d, none, none, none }, /* - */ + { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */ + { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */ + { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */ + { 0x4e2b, 0x4e2b, none, none, none }, /* + */ + { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */ + { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */ + { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */ + { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */ + { 0x5300, 0x532e, none, none, 0x20 } /* Del */ + }; + + Bit8u +inb(port) + Bit16u port; +{ +ASM_START + push bp + mov bp, sp + + push dx + mov dx, 4[bp] + in al, dx + pop dx + + pop bp +ASM_END +} + +#if BX_USE_ATADRV + Bit16u +inw(port) + Bit16u port; +{ +ASM_START + push bp + mov bp, sp + + push dx + mov dx, 4[bp] + in ax, dx + pop dx + + pop bp +ASM_END +} +#endif + + void +outb(port, val) + Bit16u port; + Bit8u val; +{ +ASM_START + push bp + mov bp, sp + + push ax + push dx + mov dx, 4[bp] + mov al, 6[bp] + out dx, al + pop dx + pop ax + + pop bp +ASM_END +} + +#if BX_USE_ATADRV + void +outw(port, val) + Bit16u port; + Bit16u val; +{ +ASM_START + push bp + mov bp, sp + + push ax + push dx + mov dx, 4[bp] + mov ax, 6[bp] + out dx, ax + pop dx + pop ax + + pop bp +ASM_END +} +#endif + + void +outb_cmos(cmos_reg, val) + Bit8u cmos_reg; + Bit8u val; +{ +ASM_START + push bp + mov bp, sp + + mov al, 4[bp] ;; cmos_reg + out 0x70, al + mov al, 6[bp] ;; val + out 0x71, al + + pop bp +ASM_END +} + + Bit8u +inb_cmos(cmos_reg) + Bit8u cmos_reg; +{ +ASM_START + push bp + mov bp, sp + + mov al, 4[bp] ;; cmos_reg + out 0x70, al + in al, 0x71 + + pop bp +ASM_END +} + + void +init_rtc() +{ + printf("rombios: init_rtc()\n"); + outb_cmos(0x0a, 0x26); + outb_cmos(0x0b, 0x02); + inb_cmos(0x0c); + inb_cmos(0x0d); +} + + bx_bool +rtc_updating() +{ + // This function checks to see if the update-in-progress bit + // is set in CMOS Status Register A. If not, it returns 0. + // If it is set, it tries to wait until there is a transition + // to 0, and will return 0 if such a transition occurs. A 1 + // is returned only after timing out. The maximum period + // that this bit should be set is constrained to 244useconds. + // The count I use below guarantees coverage or more than + // this time, with any reasonable IPS setting. + + Bit16u count; + + count = 25000; + while (--count != 0) { + if ( (inb_cmos(0x0a) & 0x80) == 0 ) + return(0); + } + return(1); // update-in-progress never transitioned to 0 +} + + + Bit8u +read_byte(seg, offset) + Bit16u seg; + Bit16u offset; +{ +ASM_START + push bp + mov bp, sp + + push bx + push ds + mov ax, 4[bp] ; segment + mov ds, ax + mov bx, 6[bp] ; offset + mov al, [bx] + ;; al = return value (byte) + pop ds + pop bx + + pop bp +ASM_END +} + + Bit16u +read_word(seg, offset) + Bit16u seg; + Bit16u offset; +{ +ASM_START + push bp + mov bp, sp + + push bx + push ds + mov ax, 4[bp] ; segment + mov ds, ax + mov bx, 6[bp] ; offset + mov ax, [bx] + ;; ax = return value (word) + pop ds + pop bx + + pop bp +ASM_END +} + + void +write_byte(seg, offset, data) + Bit16u seg; + Bit16u offset; + Bit8u data; +{ +ASM_START + push bp + mov bp, sp + + push ax + push bx + push ds + mov ax, 4[bp] ; segment + mov ds, ax + mov bx, 6[bp] ; offset + mov al, 8[bp] ; data byte + mov [bx], al ; write data byte + pop ds + pop bx + pop ax + + pop bp +ASM_END +} + + void +write_word(seg, offset, data) + Bit16u seg; + Bit16u offset; + Bit16u data; +{ +ASM_START + push bp + mov bp, sp + + push ax + push bx + push ds + mov ax, 4[bp] ; segment + mov ds, ax + mov bx, 6[bp] ; offset + mov ax, 8[bp] ; data word + mov [bx], ax ; write data word + pop ds + pop bx + pop ax + + pop bp +ASM_END +} + + Bit16u +get_CS() +{ +ASM_START + mov ax, cs +ASM_END +} + +// Bit16u +//get_DS() +//{ +//ASM_START +// mov ax, ds +//ASM_END +//} +// +// void +//set_DS(ds_selector) +// Bit16u ds_selector; +//{ +//ASM_START +// push bp +// mov bp, sp +// +// push ax +// mov ax, 4[bp] ; ds_selector +// mov ds, ax +// pop ax +// +// pop bp +//ASM_END +//} + + Bit16u +get_SS() +{ +ASM_START + mov ax, ss +ASM_END +} + +#ifdef HVMASSIST +void +copy_e820_table() +{ + Bit8u nr_entries = read_byte(0x9000, 0x1e8); + if (nr_entries > 32) + nr_entries = 32; + write_word(0xe000, 0x8, nr_entries); + memcpyb(0xe000, 0x10, 0x9000, 0x2d0, nr_entries * 0x14); +} +#endif /* HVMASSIST */ + +#if BX_DEBUG_SERIAL +/* serial debug port*/ +#define BX_DEBUG_PORT 0x03f8 + +/* data */ +#define UART_RBR 0x00 +#define UART_THR 0x00 + +/* control */ +#define UART_IER 0x01 +#define UART_IIR 0x02 +#define UART_FCR 0x02 +#define UART_LCR 0x03 +#define UART_MCR 0x04 +#define UART_DLL 0x00 +#define UART_DLM 0x01 + +/* status */ +#define UART_LSR 0x05 +#define UART_MSR 0x06 +#define UART_SCR 0x07 + +int uart_can_tx_byte(base_port) + Bit16u base_port; +{ + return inb(base_port + UART_LSR) & 0x20; +} + +void uart_wait_to_tx_byte(base_port) + Bit16u base_port; +{ + while (!uart_can_tx_byte(base_port)); +} + +void uart_wait_until_sent(base_port) + Bit16u base_port; +{ + while (!(inb(base_port + UART_LSR) & 0x40)); +} + +void uart_tx_byte(base_port, data) + Bit16u base_port; + Bit8u data; +{ + uart_wait_to_tx_byte(base_port); + outb(base_port + UART_THR, data); + uart_wait_until_sent(base_port); +} +#endif + + void +wrch(c) + Bit8u c; +{ + ASM_START + push bp + mov bp, sp + + push bx + mov ah, #0x0e + mov al, 4[bp] + xor bx,bx + int #0x10 + pop bx + + pop bp + ASM_END +} + + void +send(action, c) + Bit16u action; + Bit8u c; +{ +#if BX_DEBUG_SERIAL + if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r'); + uart_tx_byte(BX_DEBUG_PORT, c); +#endif +#ifdef HVMASSIST + outb(0xE9, c); +#endif +#if BX_VIRTUAL_PORTS + if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c); + if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c); +#endif + if (action & BIOS_PRINTF_SCREEN) { + if (c == '\n') wrch('\r'); + wrch(c); + } +} + + void +put_int(action, val, width, neg) + Bit16u action; + short val, width; + bx_bool neg; +{ + short nval = val / 10; + if (nval) + put_int(action, nval, width - 1, neg); + else { + while (--width > 0) send(action, ' '); + if (neg) send(action, '-'); + } + send(action, val - (nval * 10) + '0'); +} + + void +put_uint(action, val, width, neg) + Bit16u action; + unsigned short val; + short width; + bx_bool neg; +{ + unsigned short nval = val / 10; + if (nval) + put_uint(action, nval, width - 1, neg); + else { + while (--width > 0) send(action, ' '); + if (neg) send(action, '-'); + } + send(action, val - (nval * 10) + '0'); +} + +//-------------------------------------------------------------------------- +// bios_printf() +// A compact variable argument printf function which prints its output via +// an I/O port so that it can be logged by Bochs/Plex. +// Currently, only %x is supported (or %02x, %04x, etc). +// +// Supports %[format_width][format] +// where format can be d,x,c,s +//-------------------------------------------------------------------------- + void +bios_printf(action, s) + Bit16u action; + Bit8u *s; +{ + Bit8u c, format_char; + bx_bool in_format; + short i; + Bit16u *arg_ptr; + Bit16u arg_seg, arg, nibble, shift_count, format_width; + + arg_ptr = &s; + arg_seg = get_SS(); + + in_format = 0; + format_width = 0; + + if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) { +#if BX_VIRTUAL_PORTS + outb(PANIC_PORT2, 0x00); +#endif + bios_printf (BIOS_PRINTF_SCREEN, "FATAL: "); + } + + while (c = read_byte(get_CS(), s)) { + if ( c == '%' ) { + in_format = 1; + format_width = 0; + } + else if (in_format) { + if ( (c>='0') && (c<='9') ) { + format_width = (format_width * 10) + (c - '0'); + } + else { + arg_ptr++; // increment to next arg + arg = read_word(arg_seg, arg_ptr); + if (c == 'x') { + if (format_width == 0) + format_width = 4; + for (i=format_width-1; i>=0; i--) { + nibble = (arg >> (4 * i)) & 0x000f; + send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A')); + } + } + else if (c == 'u') { + put_uint(action, arg, format_width, 0); + } + else if (c == 'd') { + if (arg & 0x8000) + put_int(action, -arg, format_width - 1, 1); + else + put_int(action, arg, format_width, 0); + } + else if (c == 's') { + bios_printf(action & (~BIOS_PRINTF_HALT), arg); + } + else if (c == 'c') { + send(action, arg); + } + else + BX_PANIC("bios_printf: unknown format\n"); + in_format = 0; + } + } + else { + send(action, c); + } + s ++; + } + + if (action & BIOS_PRINTF_HALT) { + // freeze in a busy loop. +ASM_START + cli + halt2_loop: + hlt + jmp halt2_loop +ASM_END + } +} + +//-------------------------------------------------------------------------- +// keyboard_init +//-------------------------------------------------------------------------- +// this file is based on LinuxBIOS implementation of keyboard.c +// could convert to #asm to gain space + void +keyboard_init() +{ + Bit16u max; + int rc; + + printf("rombios: keyboard_init\n"); + + /* printf("Assuming keyboard already inited and returning\n"); + return; */ + + /* ------------------- Flush buffers ------------------------*/ + /* Wait until buffer is empty */ + max=0xffff; + while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00); + + /* flush incoming keys */ + max=0x2000; + while (--max > 0) { + outb(0x80, 0x00); + if (inb(0x64) & 0x01) { + inb(0x60); + max = 0x2000; + } + } + + // Due to timer issues, and if the IPS setting is > 15000000, + // the incoming keys might not be flushed here. That will + // cause a panic a few lines below. See sourceforge bug report : + // [ 642031 ] FATAL: Keyboard RESET error:993 + + /* ------------------- controller side ----------------------*/ + /* send cmd = 0xAA, self test 8042 */ + outb(0x64, 0xaa); + + /* Wait until buffer is empty */ + max=0xffff; + while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00); + if (max==0x0) keyboard_panic(00); + + /* Wait for data */ + max=0xffff; + while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01); + if (max==0x0) keyboard_panic(01); + + /* read self-test result, 0x55 should be returned from 0x60 */ + if ((inb(0x60) != 0x55)){ + keyboard_panic(991); + } + + /* send cmd = 0xAB, keyboard interface test */ + outb(0x64,0xab); + + /* Wait until buffer is empty */ + max=0xffff; + while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10); + if (max==0x0) keyboard_panic(10); + + /* Wait for data */ + max=0xffff; + while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11); + if (max==0x0) keyboard_panic(11); + + /* read keyboard interface test result, */ + /* 0x00 should be returned form 0x60 */ + if ((inb(0x60) != 0x00)) { + keyboard_panic(992); + } + + /* Enable Keyboard clock */ + outb(0x64,0xae); + outb(0x64,0xa8); + + /* ------------------- keyboard side ------------------------*/ + /* reset kerboard and self test (keyboard side) */ + outb(0x60, 0xff); + + /* Wait until buffer is empty */ + max=0xffff; + while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20); + if (max==0x0) keyboard_panic(20); + + /* Wait for data */ + max=0xffff; + while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21); + if (max==0x0) keyboard_panic(21); + + /* keyboard should return ACK */ + if ((inb(0x60) != 0xfa)) { + keyboard_panic(993); + } + + /* Wait for data */ + max=0xffff; + while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31); + if (max==0x0) keyboard_panic(31); + + if ((inb(0x60) != 0xaa)) { + keyboard_panic(994); + } + + /* Disable keyboard */ + outb(0x60, 0xf5); + + /* Wait until buffer is empty */ + max=0xffff; + while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40); + if (max==0x0) keyboard_panic(40); + + /* Wait for data */ + max=0xffff; + while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41); + if (max==0x0) keyboard_panic(41); + + /* keyboard should return ACK */ + rc=inb(0x60); + if (rc != 0xfa) { + printf("rc=0x%x\n",rc); + keyboard_panic(995); + } + + /* Write Keyboard Mode */ + outb(0x64, 0x60); + + /* Wait until buffer is empty */ + max=0xffff; + while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50); + if (max==0x0) keyboard_panic(50); + + /* send cmd: scan code convert, disable mouse, enable IRQ 1 */ + outb(0x60, 0x61); + + /* Wait until buffer is empty */ + max=0xffff; + while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60); + if (max==0x0) keyboard_panic(60); + + /* Enable keyboard */ + outb(0x60, 0xf4); + + /* Wait until buffer is empty */ + max=0xffff; + while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70); + if (max==0x0) keyboard_panic(70); + + /* Wait for data */ + max=0xffff; + while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71); + if (max==0x0) keyboard_panic(70); + + /* keyboard should return ACK */ + if ((inb(0x60) != 0xfa)) { + keyboard_panic(996); + } + + outb(0x80, 0x77); + printf("keyboard init done.\n"); +} + +//-------------------------------------------------------------------------- +// keyboard_panic +//-------------------------------------------------------------------------- + void +keyboard_panic(status) + Bit16u status; +{ + // If you're getting a 993 keyboard panic here, + // please see the comment in keyboard_init + printf("Keyboard error:%u CONTINUING\n",status); return; + BX_PANIC("Keyboard error:%u\n",status); +} + +//-------------------------------------------------------------------------- +// shutdown_status_panic +// called when the shutdown statsu is not implemented, displays the status +//-------------------------------------------------------------------------- + void +shutdown_status_panic(status) + Bit16u status; +{ + BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status); +} + +//-------------------------------------------------------------------------- +// print_bios_banner +// displays a the bios version +//-------------------------------------------------------------------------- +void +print_bios_banner() +{ + printf("Hi from peter's modified bios\n"); + printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":""); + printf("%s %s\n", bios_cvs_version_string, bios_date_string); + printf("\n"); +} + +//-------------------------------------------------------------------------- +// print_boot_device +// displays the boot device +//-------------------------------------------------------------------------- + +static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"}; + +void +print_boot_device(cdboot, drive) + Bit8u cdboot; Bit16u drive; +{ + Bit8u i; + + // cdboot contains 0 if floppy/harddisk, 1 otherwise + // drive contains real/emulated boot drive + + if(cdboot)i=2; // CD-Rom + else if((drive&0x0080)==0x00)i=0; // Floppy + else if((drive&0x0080)==0x80)i=1; // Hard drive + else return; + + printf("Booting from %s...\n",drivetypes[i]); +} + +//-------------------------------------------------------------------------- +// print_boot_failure +// displays the reason why boot failed +//-------------------------------------------------------------------------- + void +print_boot_failure(cdboot, drive, reason, lastdrive) + Bit8u cdboot; Bit8u drive; Bit8u lastdrive; +{ + Bit16u drivenum = drive&0x7f; + + // cdboot: 1 if boot from cd, 0 otherwise + // drive : drive number + // reason: 0 signature check failed, 1 read error + // lastdrive: 1 boot drive is the last one in boot sequence + + if (cdboot) + bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]); + else if (drive & 0x80) + bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum); + else + bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum); + + if (lastdrive==1) { + if (reason==0) + BX_PANIC("Not a bootable disk\n"); + else + BX_PANIC("Could not read the boot disk\n"); + } +} + +//-------------------------------------------------------------------------- +// print_cdromboot_failure +// displays the reason why boot failed +//-------------------------------------------------------------------------- + void +print_cdromboot_failure( code ) + Bit16u code; +{ + bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code); + + return; +} + +void +nmi_handler_msg() +{ + BX_PANIC("NMI Handler called\n"); +} + +void +int18_panic_msg() +{ + BX_PANIC("INT18: BOOT FAILURE\n"); +} + +void +log_bios_start() +{ +#if BX_DEBUG_SERIAL + outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */ +#endif + BX_INFO("%s\n", bios_version_string); +} + + bx_bool +set_enable_a20(val) + bx_bool val; +{ + Bit8u oldval; + + // Use PS2 System Control port A to set A20 enable + + // get current setting first + oldval = inb(0x92); + + // change A20 status + if (val) + outb(0x92, oldval | 0x02); + else + outb(0x92, oldval & 0xfd); + + return((oldval & 0x02) != 0); +} + + void +debugger_on() +{ + outb(0xfedc, 0x01); +} + + void +debugger_off() +{ + outb(0xfedc, 0x00); +} + +#if BX_USE_ATADRV + +// --------------------------------------------------------------------------- +// Start of ATA/ATAPI Driver +// --------------------------------------------------------------------------- + +// Global defines -- ATA register and register bits. +// command block & control block regs +#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0 +#define ATA_CB_ERR 1 // error in pio_base_addr1+1 +#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1 +#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2 +#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3 +#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4 +#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5 +#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6 +#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7 +#define ATA_CB_CMD 7 // command out pio_base_addr1+7 +#define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6 +#define ATA_CB_DC 6 // device control out pio_base_addr2+6 +#define ATA_CB_DA 7 // device address in pio_base_addr2+7 + +#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC +#define ATA_CB_ER_BBK 0x80 // ATA bad block +#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error +#define ATA_CB_ER_MC 0x20 // ATA media change +#define ATA_CB_ER_IDNF 0x10 // ATA id not found +#define ATA_CB_ER_MCR 0x08 // ATA media change request +#define ATA_CB_ER_ABRT 0x04 // ATA command aborted +#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found +#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found + +#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask) +#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request +#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort +#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media +#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication + +// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC) +#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask) +#define ATA_CB_SC_P_REL 0x04 // ATAPI release +#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O +#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D + +// bits 7-4 of the device/head (CB_DH) reg +#define ATA_CB_DH_DEV0 0xa0 // select device 0 +#define ATA_CB_DH_DEV1 0xb0 // select device 1 + +// status reg (CB_STAT and CB_ASTAT) bits +#define ATA_CB_STAT_BSY 0x80 // busy +#define ATA_CB_STAT_RDY 0x40 // ready +#define ATA_CB_STAT_DF 0x20 // device fault +#define ATA_CB_STAT_WFT 0x20 // write fault (old name) +#define ATA_CB_STAT_SKC 0x10 // seek complete +#define ATA_CB_STAT_SERV 0x10 // service +#define ATA_CB_STAT_DRQ 0x08 // data request +#define ATA_CB_STAT_CORR 0x04 // corrected +#define ATA_CB_STAT_IDX 0x02 // index +#define ATA_CB_STAT_ERR 0x01 // error (ATA) +#define ATA_CB_STAT_CHK 0x01 // check (ATAPI) + +// device control reg (CB_DC) bits +#define ATA_CB_DC_HD15 0x08 // bit should always be set to one +#define ATA_CB_DC_SRST 0x04 // soft reset +#define ATA_CB_DC_NIEN 0x02 // disable interrupts + +// Most mandtory and optional ATA commands (from ATA-3), +#define ATA_CMD_CFA_ERASE_SECTORS 0xC0 +#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03 +#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87 +#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD +#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38 +#define ATA_CMD_CHECK_POWER_MODE1 0xE5 +#define ATA_CMD_CHECK_POWER_MODE2 0x98 +#define ATA_CMD_DEVICE_RESET 0x08 +#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90 +#define ATA_CMD_FLUSH_CACHE 0xE7 +#define ATA_CMD_FORMAT_TRACK 0x50 +#define ATA_CMD_IDENTIFY_DEVICE 0xEC +#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1 +#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1 +#define ATA_CMD_IDLE1 0xE3 +#define ATA_CMD_IDLE2 0x97 +#define ATA_CMD_IDLE_IMMEDIATE1 0xE1 +#define ATA_CMD_IDLE_IMMEDIATE2 0x95 +#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91 +#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91 +#define ATA_CMD_NOP 0x00 +#define ATA_CMD_PACKET 0xA0 +#define ATA_CMD_READ_BUFFER 0xE4 +#define ATA_CMD_READ_DMA 0xC8 +#define ATA_CMD_READ_DMA_QUEUED 0xC7 +#define ATA_CMD_READ_MULTIPLE 0xC4 +#define ATA_CMD_READ_SECTORS 0x20 +#define ATA_CMD_READ_VERIFY_SECTORS 0x40 +#define ATA_CMD_RECALIBRATE 0x10 +#define ATA_CMD_SEEK 0x70 +#define ATA_CMD_SET_FEATURES 0xEF +#define ATA_CMD_SET_MULTIPLE_MODE 0xC6 +#define ATA_CMD_SLEEP1 0xE6 +#define ATA_CMD_SLEEP2 0x99 +#define ATA_CMD_STANDBY1 0xE2 +#define ATA_CMD_STANDBY2 0x96 +#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0 +#define ATA_CMD_STANDBY_IMMEDIATE2 0x94 +#define ATA_CMD_WRITE_BUFFER 0xE8 +#define ATA_CMD_WRITE_DMA 0xCA +#define ATA_CMD_WRITE_DMA_QUEUED 0xCC +#define ATA_CMD_WRITE_MULTIPLE 0xC5 +#define ATA_CMD_WRITE_SECTORS 0x30 +#define ATA_CMD_WRITE_VERIFY 0x3C + +#define ATA_IFACE_NONE 0x00 +#define ATA_IFACE_ISA 0x00 +#define ATA_IFACE_PCI 0x01 + +#define ATA_TYPE_NONE 0x00 +#define ATA_TYPE_UNKNOWN 0x01 +#define ATA_TYPE_ATA 0x02 +#define ATA_TYPE_ATAPI 0x03 + +#define ATA_DEVICE_NONE 0x00 +#define ATA_DEVICE_HD 0xFF +#define ATA_DEVICE_CDROM 0x05 + +#define ATA_MODE_NONE 0x00 +#define ATA_MODE_PIO16 0x00 +#define ATA_MODE_PIO32 0x01 +#define ATA_MODE_ISADMA 0x02 +#define ATA_MODE_PCIDMA 0x03 +#define ATA_MODE_USEIRQ 0x10 + +#define ATA_TRANSLATION_NONE 0 +#define ATA_TRANSLATION_LBA 1 +#define ATA_TRANSLATION_LARGE 2 +#define ATA_TRANSLATION_RECHS 3 + +#define ATA_DATA_NO 0x00 +#define ATA_DATA_IN 0x01 +#define ATA_DATA_OUT 0x02 + +// --------------------------------------------------------------------------- +// ATA/ATAPI driver : initialization +// --------------------------------------------------------------------------- +void ata_init( ) +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + Bit8u channel, device; + + printf("rom_bios: ata_init\n"); + + // Channels info init. + for (channel=0; channelata.channels[channel].iface,ATA_IFACE_NONE); + write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0); + write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0); + write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0); + } + + // Devices info init. + for (device=0; deviceata.devices[device].type,ATA_TYPE_NONE); + write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE); + write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0); + write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0); + write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE); + write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0); + write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE); + write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0); + write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0); + write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0); + write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0); + write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0); + write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0); + + write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L); + } + + // hdidmap and cdidmap init. + for (device=0; deviceata.hdidmap[device],BX_MAX_ATA_DEVICES); + write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES); + } + + write_byte(ebda_seg,&EbdaData->ata.hdcount,0); + write_byte(ebda_seg,&EbdaData->ata.cdcount,0); +} + +// --------------------------------------------------------------------------- +// ATA/ATAPI driver : device detection +// --------------------------------------------------------------------------- + +void ata_detect( ) +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + Bit8u hdcount, cdcount, device, type; + Bit8u buffer[0x0200]; + +#if BX_MAX_ATA_INTERFACES > 0 + write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA); + write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0); + write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0); + write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14); +#endif +#if BX_MAX_ATA_INTERFACES > 1 + write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA); + write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170); + write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370); + write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15); +#endif +#if BX_MAX_ATA_INTERFACES > 2 + write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA); + write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8); + write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0); + write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12); +#endif +#if BX_MAX_ATA_INTERFACES > 3 + write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA); + write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168); + write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360); + write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11); +#endif +#if BX_MAX_ATA_INTERFACES > 4 +#error Please fill the ATA interface informations +#endif + + // Device detection + hdcount=cdcount=0; + + for(device=0; deviceata.channels[channel].iobase1); + iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2); + + // Disable interrupts + outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN); + + // Look for device + outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0); + outb(iobase1+ATA_CB_SC, 0x55); + outb(iobase1+ATA_CB_SN, 0xaa); + outb(iobase1+ATA_CB_SC, 0xaa); + outb(iobase1+ATA_CB_SN, 0x55); + outb(iobase1+ATA_CB_SC, 0x55); + outb(iobase1+ATA_CB_SN, 0xaa); + + // If we found something + sc = inb(iobase1+ATA_CB_SC); + sn = inb(iobase1+ATA_CB_SN); + + if ( (sc == 0x55) && (sn == 0xaa) ) { + write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN); + + // reset the channel + ata_reset (device); + + // check for ATA or ATAPI + outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0); + sc = inb(iobase1+ATA_CB_SC); + sn = inb(iobase1+ATA_CB_SN); + if ( (sc==0x01) && (sn==0x01) ) { + cl = inb(iobase1+ATA_CB_CL); + ch = inb(iobase1+ATA_CB_CH); + st = inb(iobase1+ATA_CB_STAT); + + if ( (cl==0x14) && (ch==0xeb) ) { + write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI); + } + else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) { + write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA); + } + } + } + + type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type); + + // Now we send a IDENTIFY command to ATA device + if(type == ATA_TYPE_ATA) { + Bit32u sectors; + Bit16u cylinders, heads, spt, blksize; + Bit8u translation, removable, mode; + + // default mode to PIO16 + mode = ATA_MODE_PIO16; + + //Temporary values to do the transfer + write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD); + write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16); + + if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 ) + BX_PANIC("ata-detect: Failed to detect ATA device\n"); + + removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0; +#ifndef NO_PIO32 + mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16; +#endif + + blksize = read_word(get_SS(),buffer+10); + + cylinders = read_word(get_SS(),buffer+(1*2)); // word 1 + heads = read_word(get_SS(),buffer+(3*2)); // word 3 + spt = read_word(get_SS(),buffer+(6*2)); // word 6 + + sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61 + + write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD); + write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable); + write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode); + write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize); + write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads); + write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders); + write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt); + write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors); + BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt); + + translation = inb_cmos(0x39 + channel/2); + for (shift=device%4; shift>0; shift--) translation >>= 2; + translation &= 0x03; + + write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation); + + switch (translation) { + case ATA_TRANSLATION_NONE: + BX_INFO("none"); + break; + case ATA_TRANSLATION_LBA: + BX_INFO("lba"); + break; + case ATA_TRANSLATION_LARGE: + BX_INFO("large"); + break; + case ATA_TRANSLATION_RECHS: + BX_INFO("r-echs"); + break; + } + switch (translation) { + case ATA_TRANSLATION_NONE: + break; + case ATA_TRANSLATION_LBA: + spt = 63; + sectors /= 63; + heads = sectors / 1024; + if (heads>128) heads = 255; + else if (heads>64) heads = 128; + else if (heads>32) heads = 64; + else if (heads>16) heads = 32; + else heads=16; + cylinders = sectors / heads; + break; + case ATA_TRANSLATION_RECHS: + // Take care not to overflow + if (heads==16) { + if(cylinders>61439) cylinders=61439; + heads=15; + cylinders = (Bit16u)((Bit32u)(cylinders)*16/15); + } + // then go through the large bitshift process + case ATA_TRANSLATION_LARGE: + while(cylinders > 1024) { + cylinders >>= 1; + heads <<= 1; + + // If we max out the head count + if (heads > 127) break; + } + break; + } + // clip to 1024 cylinders in lchs + if (cylinders > 1024) cylinders=1024; + BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt); + + write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads); + write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders); + write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt); + + // fill hdidmap + write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device); + hdcount++; + } + + // Now we send a IDENTIFY command to ATAPI device + if(type == ATA_TYPE_ATAPI) { + + Bit8u type, removable, mode; + Bit16u blksize; + + // default mode to PIO16 + mode = ATA_MODE_PIO16; + + //Temporary values to do the transfer + write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM); + write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16); + + if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0) + BX_PANIC("ata-detect: Failed to detect ATAPI device\n"); + + type = read_byte(get_SS(),buffer+1) & 0x1f; + removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0; +#ifndef NO_PIO32 + mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16; +#endif + blksize = 2048; + + write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type); + write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable); + write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode); + write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize); + + // fill cdidmap + write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device); + cdcount++; + } + + { + Bit32u sizeinmb; + Bit16u ataversion; + Bit8u c, i, version, model[41]; + + switch (type) { + case ATA_TYPE_ATA: + sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors); + sizeinmb >>= 11; + case ATA_TYPE_ATAPI: + // Read ATA/ATAPI version + ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160); + for(version=15;version>0;version--) { + if((ataversion&(1<0;i--){ + if(read_byte(get_SS(),model+i)==0x20) + write_byte(get_SS(),model+i,0x00); + else break; + } + break; + } + + switch (type) { + case ATA_TYPE_ATA: + printf("ata%d %s: ",channel,slave?" slave":"master"); + i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c); + printf(" ATA-%d Hard-Disk (%d MBytes)\n",version,(Bit16u)sizeinmb); + break; + case ATA_TYPE_ATAPI: + printf("ata%d %s: ",channel,slave?" slave":"master"); + i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c); + if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM) + printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version); + else + printf(" ATAPI-%d Device\n",version); + break; + case ATA_TYPE_UNKNOWN: + printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master"); + break; + } + } + } + + // Store the devices counts + write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount); + write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount); + write_byte(0x40,0x75, hdcount); + + printf("\n"); + + // FIXME : should use bios=cmos|auto|disable bits + // FIXME : should know about translation bits + // FIXME : move hard_drive_post here + +} + +// --------------------------------------------------------------------------- +// ATA/ATAPI driver : software reset +// --------------------------------------------------------------------------- +// ATA-3 +// 8.2.1 Software reset - Device 0 + +void ata_reset(device) +Bit16u device; +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + Bit16u iobase1, iobase2; + Bit8u channel, slave, sn, sc; + Bit16u max; + + channel = device / 2; + slave = device % 2; + + iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1); + iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2); + + // Reset + +// 8.2.1 (a) -- set SRST in DC + outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST); + +// 8.2.1 (b) -- wait for BSY + max=0xff; + while(--max>0) { + Bit8u status = inb(iobase1+ATA_CB_STAT); + if ((status & ATA_CB_STAT_BSY) != 0) break; + } + +// 8.2.1 (f) -- clear SRST + outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN); + + if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) { + +// 8.2.1 (g) -- check for sc==sn==0x01 + // select device + outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0); + sc = inb(iobase1+ATA_CB_SC); + sn = inb(iobase1+ATA_CB_SN); + + if ( (sc==0x01) && (sn==0x01) ) { + +// 8.2.1 (h) -- wait for not BSY + max=0xff; + while(--max>0) { + Bit8u status = inb(iobase1+ATA_CB_STAT); + if ((status & ATA_CB_STAT_BSY) == 0) break; + } + } + } + +// 8.2.1 (i) -- wait for DRDY + max=0xfff; + while(--max>0) { + Bit8u status = inb(iobase1+ATA_CB_STAT); + if ((status & ATA_CB_STAT_RDY) != 0) break; + } + + // Enable interrupts + outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15); +} + +// --------------------------------------------------------------------------- +// ATA/ATAPI driver : execute a non data command +// --------------------------------------------------------------------------- + +Bit16u ata_cmd_non_data() +{return 0;} + +// --------------------------------------------------------------------------- +// ATA/ATAPI driver : execute a data-in command +// --------------------------------------------------------------------------- + // returns + // 0 : no error + // 1 : BUSY bit set + // 2 : read error + // 3 : expected DRQ=1 + // 4 : no sectors left to read/verify + // 5 : more sectors to read/verify + // 6 : no sectors left to write + // 7 : more sectors to write +Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset) +Bit16u device, command, count, cylinder, head, sector, segment, offset; +Bit32u lba; +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + Bit16u iobase1, iobase2, blksize; + Bit8u channel, slave; + Bit8u status, current, mode; + + channel = device / 2; + slave = device % 2; + + iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1); + iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2); + mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode); + blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize); + if (mode == ATA_MODE_PIO32) blksize>>=2; + else blksize>>=1; + + // sector will be 0 only on lba access. Convert to lba-chs + if (sector == 0) { + sector = (Bit16u) (lba & 0x000000ffL); + lba >>= 8; + cylinder = (Bit16u) (lba & 0x0000ffffL); + lba >>= 16; + head = ((Bit16u) (lba & 0x0000000fL)) | 0x40; + } + + // Reset count of transferred data + write_word(ebda_seg, &EbdaData->ata.trsfsectors,0); + write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L); + current = 0; + + status = inb(iobase1 + ATA_CB_STAT); + if (status & ATA_CB_STAT_BSY) return 1; + + outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN); + outb(iobase1 + ATA_CB_FR, 0x00); + outb(iobase1 + ATA_CB_SC, count); + outb(iobase1 + ATA_CB_SN, sector); + outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff); + outb(iobase1 + ATA_CB_CH, cylinder >> 8); + outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head ); + outb(iobase1 + ATA_CB_CMD, command); + + while (1) { + status = inb(iobase1 + ATA_CB_STAT); + if ( !(status & ATA_CB_STAT_BSY) ) break; + } + + if (status & ATA_CB_STAT_ERR) { + BX_DEBUG_ATA("ata_cmd_data_in : read error\n"); + return 2; + } else if ( !(status & ATA_CB_STAT_DRQ) ) { + BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status); + return 3; + } + + // FIXME : move seg/off translation here + +ASM_START + sti ;; enable higher priority interrupts +ASM_END + + while (1) { + +ASM_START + push bp + mov bp, sp + mov di, _ata_cmd_data_in.offset + 2[bp] + mov ax, _ata_cmd_data_in.segment + 2[bp] + mov cx, _ata_cmd_data_in.blksize + 2[bp] + + ;; adjust if there will be an overrun. 2K max sector size + cmp di, #0xf800 ;; + jbe ata_in_no_adjust + +ata_in_adjust: + sub di, #0x0800 ;; sub 2 kbytes from offset + add ax, #0x0080 ;; add 2 Kbytes to segment + +ata_in_no_adjust: + mov es, ax ;; segment in es + + mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port + + mov ah, _ata_cmd_data_in.mode + 2[bp] + cmp ah, #ATA_MODE_PIO32 + je ata_in_32 + +ata_in_16: + rep + insw ;; CX words transfered from port(DX) to ES:[DI] + jmp ata_in_done + +ata_in_32: + rep + insd ;; CX dwords transfered from port(DX) to ES:[DI] + +ata_in_done: + mov _ata_cmd_data_in.offset + 2[bp], di + mov _ata_cmd_data_in.segment + 2[bp], es + pop bp +ASM_END + + current++; + write_word(ebda_seg, &EbdaData->ata.trsfsectors,current); + count--; + status = inb(iobase1 + ATA_CB_STAT); + if (count == 0) { + if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) + != ATA_CB_STAT_RDY ) { + BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status); + return 4; + } + break; + } + else { + if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) + != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) { + BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status); + return 5; + } + continue; + } + } + // Enable interrupts + outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15); + return 0; +} + +// --------------------------------------------------------------------------- +// ATA/ATAPI driver : execute a data-out command +// --------------------------------------------------------------------------- + // returns + // 0 : no error + // 1 : BUSY bit set + // 2 : read error + // 3 : expected DRQ=1 + // 4 : no sectors left to read/verify + // 5 : more sectors to read/verify + // 6 : no sectors left to write + // 7 : more sectors to write +Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset) +Bit16u device, command, count, cylinder, head, sector, segment, offset; +Bit32u lba; +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + Bit16u iobase1, iobase2, blksize; + Bit8u channel, slave; + Bit8u status, current, mode; + + channel = device / 2; + slave = device % 2; + + iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1); + iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2); + mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode); + blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize); + if (mode == ATA_MODE_PIO32) blksize>>=2; + else blksize>>=1; + + // sector will be 0 only on lba access. Convert to lba-chs + if (sector == 0) { + sector = (Bit16u) (lba & 0x000000ffL); + lba >>= 8; + cylinder = (Bit16u) (lba & 0x0000ffffL); + lba >>= 16; + head = ((Bit16u) (lba & 0x0000000fL)) | 0x40; + } + + // Reset count of transferred data + write_word(ebda_seg, &EbdaData->ata.trsfsectors,0); + write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L); + current = 0; + + status = inb(iobase1 + ATA_CB_STAT); + if (status & ATA_CB_STAT_BSY) return 1; + + outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN); + outb(iobase1 + ATA_CB_FR, 0x00); + outb(iobase1 + ATA_CB_SC, count); + outb(iobase1 + ATA_CB_SN, sector); + outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff); + outb(iobase1 + ATA_CB_CH, cylinder >> 8); + outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head ); + outb(iobase1 + ATA_CB_CMD, command); + + while (1) { + status = inb(iobase1 + ATA_CB_STAT); + if ( !(status & ATA_CB_STAT_BSY) ) break; + } + + if (status & ATA_CB_STAT_ERR) { + BX_DEBUG_ATA("ata_cmd_data_out : read error\n"); + return 2; + } else if ( !(status & ATA_CB_STAT_DRQ) ) { + BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status); + return 3; + } + + // FIXME : move seg/off translation here + +ASM_START + sti ;; enable higher priority interrupts +ASM_END + + while (1) { + +ASM_START + push bp + mov bp, sp + mov si, _ata_cmd_data_out.offset + 2[bp] + mov ax, _ata_cmd_data_out.segment + 2[bp] + mov cx, _ata_cmd_data_out.blksize + 2[bp] + + ;; adjust if there will be an overrun. 2K max sector size + cmp si, #0xf800 ;; + jbe ata_out_no_adjust + +ata_out_adjust: + sub si, #0x0800 ;; sub 2 kbytes from offset + add ax, #0x0080 ;; add 2 Kbytes to segment + +ata_out_no_adjust: + mov es, ax ;; segment in es + + mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port + + mov ah, _ata_cmd_data_out.mode + 2[bp] + cmp ah, #ATA_MODE_PIO32 + je ata_out_32 + +ata_out_16: + seg ES + rep + outsw ;; CX words transfered from port(DX) to ES:[SI] + jmp ata_out_done + +ata_out_32: + seg ES + rep + outsd ;; CX dwords transfered from port(DX) to ES:[SI] + +ata_out_done: + mov _ata_cmd_data_out.offset + 2[bp], si + mov _ata_cmd_data_out.segment + 2[bp], es + pop bp +ASM_END + + current++; + write_word(ebda_seg, &EbdaData->ata.trsfsectors,current); + count--; + status = inb(iobase1 + ATA_CB_STAT); + if (count == 0) { + if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) + != ATA_CB_STAT_RDY ) { + BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status); + return 6; + } + break; + } + else { + if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) + != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) { + BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status); + return 7; + } + continue; + } + } + // Enable interrupts + outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15); + return 0; +} + +// --------------------------------------------------------------------------- +// ATA/ATAPI driver : execute a packet command +// --------------------------------------------------------------------------- + // returns + // 0 : no error + // 1 : error in parameters + // 2 : BUSY bit set + // 3 : error + // 4 : not ready +Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff) +Bit8u cmdlen,inout; +Bit16u device,cmdseg, cmdoff, bufseg, bufoff; +Bit16u header; +Bit32u length; +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + Bit16u iobase1, iobase2; + Bit16u lcount, lbefore, lafter, count; + Bit8u channel, slave; + Bit8u status, mode, lmode; + Bit32u total, transfer; + + channel = device / 2; + slave = device % 2; + + // Data out is not supported yet + if (inout == ATA_DATA_OUT) { + BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n"); + return 1; + } + + // The header length must be even + if (header & 1) { + BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header); + return 1; + } + + iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1); + iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2); + mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode); + transfer= 0L; + + if (cmdlen < 12) cmdlen=12; + if (cmdlen > 12) cmdlen=16; + cmdlen>>=1; + + // Reset count of transferred data + write_word(ebda_seg, &EbdaData->ata.trsfsectors,0); + write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L); + + status = inb(iobase1 + ATA_CB_STAT); + if (status & ATA_CB_STAT_BSY) return 2; + + outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN); + // outb(iobase1 + ATA_CB_FR, 0x00); + // outb(iobase1 + ATA_CB_SC, 0x00); + // outb(iobase1 + ATA_CB_SN, 0x00); + outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff); + outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8); + outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0); + outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET); + + // Device should ok to receive command + while (1) { + status = inb(iobase1 + ATA_CB_STAT); + if ( !(status & ATA_CB_STAT_BSY) ) break; + } + + if (status & ATA_CB_STAT_ERR) { + BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status); + return 3; + } else if ( !(status & ATA_CB_STAT_DRQ) ) { + BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status); + return 4; + } + + // Normalize address + cmdseg += (cmdoff / 16); + cmdoff %= 16; + + // Send command to device +ASM_START + sti ;; enable higher priority interrupts + + push bp + mov bp, sp + + mov si, _ata_cmd_packet.cmdoff + 2[bp] + mov ax, _ata_cmd_packet.cmdseg + 2[bp] + mov cx, _ata_cmd_packet.cmdlen + 2[bp] + mov es, ax ;; segment in es + + mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port + + seg ES + rep + outsw ;; CX words transfered from port(DX) to ES:[SI] + + pop bp +ASM_END + + if (inout == ATA_DATA_NO) { + status = inb(iobase1 + ATA_CB_STAT); + } + else { + while (1) { + + status = inb(iobase1 + ATA_CB_STAT); + + // Check if command completed + if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break; + + if (status & ATA_CB_STAT_ERR) { + BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status); + return 3; + } + + // Device must be ready to send data + if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) + != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) { + BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status); + return 4; + } + + // Normalize address + bufseg += (bufoff / 16); + bufoff %= 16; + + // Get the byte count + lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL); + + // adjust to read what we want + if(header>lcount) { + lbefore=lcount; + header-=lcount; + lcount=0; + } + else { + lbefore=header; + header=0; + lcount-=lbefore; + } + + if(lcount>length) { + lafter=lcount-length; + lcount=length; + length=0; + } + else { + lafter=0; + length-=lcount; + } + + // Save byte count + count = lcount; + + BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter); + BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff); + + // If counts not dividable by 4, use 16bits mode + lmode = mode; + if (lbefore & 0x03) lmode=ATA_MODE_PIO16; + if (lcount & 0x03) lmode=ATA_MODE_PIO16; + if (lafter & 0x03) lmode=ATA_MODE_PIO16; + + // adds an extra byte if count are odd. before is always even + if (lcount & 0x01) { + lcount+=1; + if ((lafter > 0) && (lafter & 0x01)) { + lafter-=1; + } + } + + if (lmode == ATA_MODE_PIO32) { + lcount>>=2; lbefore>>=2; lafter>>=2; + } + else { + lcount>>=1; lbefore>>=1; lafter>>=1; + } + + ; // FIXME bcc bug + +ASM_START + push bp + mov bp, sp + + mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port + + mov cx, _ata_cmd_packet.lbefore + 2[bp] + jcxz ata_packet_no_before + + mov ah, _ata_cmd_packet.lmode + 2[bp] + cmp ah, #ATA_MODE_PIO32 + je ata_packet_in_before_32 + +ata_packet_in_before_16: + in ax, dx + loop ata_packet_in_before_16 + jmp ata_packet_no_before + +ata_packet_in_before_32: + push eax +ata_packet_in_before_32_loop: + in eax, dx + loop ata_packet_in_before_32_loop + pop eax + +ata_packet_no_before: + mov cx, _ata_cmd_packet.lcount + 2[bp] + jcxz ata_packet_after + + mov di, _ata_cmd_packet.bufoff + 2[bp] + mov ax, _ata_cmd_packet.bufseg + 2[bp] + mov es, ax + + mov ah, _ata_cmd_packet.lmode + 2[bp] + cmp ah, #ATA_MODE_PIO32 + je ata_packet_in_32 + +ata_packet_in_16: + rep + insw ;; CX words transfered tp port(DX) to ES:[DI] + jmp ata_packet_after + +ata_packet_in_32: + rep + insd ;; CX dwords transfered to port(DX) to ES:[DI] + +ata_packet_after: + mov cx, _ata_cmd_packet.lafter + 2[bp] + jcxz ata_packet_done + + mov ah, _ata_cmd_packet.lmode + 2[bp] + cmp ah, #ATA_MODE_PIO32 + je ata_packet_in_after_32 + +ata_packet_in_after_16: + in ax, dx + loop ata_packet_in_after_16 + jmp ata_packet_done + +ata_packet_in_after_32: + push eax +ata_packet_in_after_32_loop: + in eax, dx + loop ata_packet_in_after_32_loop + pop eax + +ata_packet_done: + pop bp +ASM_END + + // Compute new buffer address + bufoff += count; + + // Save transferred bytes count + transfer += count; + write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer); + } + } + + // Final check, device must be ready + if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) + != ATA_CB_STAT_RDY ) { + BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status); + return 4; + } + + // Enable interrupts + outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15); + return 0; +} + +// --------------------------------------------------------------------------- +// End of ATA/ATAPI Driver +// --------------------------------------------------------------------------- + +// --------------------------------------------------------------------------- +// Start of ATA/ATAPI generic functions +// --------------------------------------------------------------------------- + + Bit16u +atapi_get_sense(device) + Bit16u device; +{ + Bit8u atacmd[12]; + Bit8u buffer[16]; + Bit8u i; + + memsetb(get_SS(),atacmd,0,12); + + // Request SENSE + atacmd[0]=0x03; + atacmd[4]=0x20; + if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0) + return 0x0002; + + if ((buffer[0] & 0x7e) == 0x70) { + return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12]; + } + + return 0; +} + + Bit16u +atapi_is_ready(device) + Bit16u device; +{ + Bit8u atacmd[12]; + Bit8u buffer[]; + + memsetb(get_SS(),atacmd,0,12); + + // Test Unit Ready + if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0) + return 0x000f; + + if (atapi_get_sense(device) !=0 ) { + memsetb(get_SS(),atacmd,0,12); + + // try to send Test Unit Ready again + if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0) + return 0x000f; + + return atapi_get_sense(device); + } + return 0; +} + + Bit16u +atapi_is_cdrom(device) + Bit8u device; +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + + if (device >= BX_MAX_ATA_DEVICES) + return 0; + + if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI) + return 0; + + if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM) + return 0; + + return 1; +} + +// --------------------------------------------------------------------------- +// End of ATA/ATAPI generic functions +// --------------------------------------------------------------------------- + +#endif // BX_USE_ATADRV + +#if BX_ELTORITO_BOOT + +// --------------------------------------------------------------------------- +// Start of El-Torito boot functions +// --------------------------------------------------------------------------- + + void +cdemu_init() +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + + printf("rombios: cdemu_init\n"); + + // the only important data is this one for now + write_byte(ebda_seg,&EbdaData->cdemu.active,0x00); +} + + Bit8u +cdemu_isactive() +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + + return(read_byte(ebda_seg,&EbdaData->cdemu.active)); +} + + Bit8u +cdemu_emulated_drive() +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + + return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)); +} + +static char isotag[6]="CD001"; +static char eltorito[24]="EL TORITO SPECIFICATION"; +// +// Returns ah: emulated drive, al: error code +// + Bit16u +cdrom_boot() +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + Bit8u atacmd[12], buffer[2048]; + Bit32u lba; + Bit16u boot_segment, nbsectors, i, error; + Bit8u device; + + // Find out the first cdrom + for (device=0; device= BX_MAX_ATA_DEVICES) return 2; + + // Read the Boot Record Volume Descriptor + memsetb(get_SS(),atacmd,0,12); + atacmd[0]=0x28; // READ command + atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors + atacmd[8]=(0x01 & 0x00ff); // Sectors + atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA + atacmd[3]=(0x11 & 0x00ff0000) >> 16; + atacmd[4]=(0x11 & 0x0000ff00) >> 8; + atacmd[5]=(0x11 & 0x000000ff); + if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0) + return 3; + + // Validity checks + if(buffer[0]!=0)return 4; + for(i=0;i<5;i++){ + if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5; + } + for(i=0;i<23;i++) + if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6; + + // ok, now we calculate the Boot catalog address + lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47]; + + // And we read the Boot Catalog + memsetb(get_SS(),atacmd,0,12); + atacmd[0]=0x28; // READ command + atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors + atacmd[8]=(0x01 & 0x00ff); // Sectors + atacmd[2]=(lba & 0xff000000) >> 24; // LBA + atacmd[3]=(lba & 0x00ff0000) >> 16; + atacmd[4]=(lba & 0x0000ff00) >> 8; + atacmd[5]=(lba & 0x000000ff); + if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0) + return 7; + + // Validation entry + if(buffer[0x00]!=0x01)return 8; // Header + if(buffer[0x01]!=0x00)return 9; // Platform + if(buffer[0x1E]!=0x55)return 10; // key 1 + if(buffer[0x1F]!=0xAA)return 10; // key 2 + + // Initial/Default Entry + if(buffer[0x20]!=0x88)return 11; // Bootable + + write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]); + if(buffer[0x21]==0){ + // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0. + // Win2000 cd boot needs to know it booted from cd + write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0); + } + else if(buffer[0x21]<4) + write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00); + else + write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80); + + write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2); + write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2); + + boot_segment=buffer[0x23]*0x100+buffer[0x22]; + if(boot_segment==0x0000)boot_segment=0x07C0; + + write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment); + write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000); + + nbsectors=buffer[0x27]*0x100+buffer[0x26]; + write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors); + + lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28]; + write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba); + + // And we read the image in memory + memsetb(get_SS(),atacmd,0,12); + atacmd[0]=0x28; // READ command + atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors + atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors + atacmd[2]=(lba & 0xff000000) >> 24; // LBA + atacmd[3]=(lba & 0x00ff0000) >> 16; + atacmd[4]=(lba & 0x0000ff00) >> 8; + atacmd[5]=(lba & 0x000000ff); + if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0) + return 12; + + // Remember the media type + switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) { + case 0x01: // 1.2M floppy + write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15); + write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80); + write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2); + break; + case 0x02: // 1.44M floppy + write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18); + write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80); + write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2); + break; + case 0x03: // 2.88M floppy + write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36); + write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80); + write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2); + break; + case 0x04: // Harddrive + write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f); + write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders, + (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1); + write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1); + break; + } + + if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) { + // Increase bios installed hardware number of devices + if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00) + write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41); + else + write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1); + } + + + // everything is ok, so from now on, the emulation is active + if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) + write_byte(ebda_seg,&EbdaData->cdemu.active,0x01); + + // return the boot drive + no error + return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0; +} + +// --------------------------------------------------------------------------- +// End of El-Torito boot functions +// --------------------------------------------------------------------------- +#endif // BX_ELTORITO_BOOT + + void +int14_function(regs, ds, iret_addr) + pusha_regs_t regs; // regs pushed from PUSHA instruction + Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper + iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call +{ + Bit16u addr,timer,val16; + Bit8u timeout; + + ASM_START + sti + ASM_END + + addr = read_word(0x0040, (regs.u.r16.dx << 1)); + timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx); + if ((regs.u.r16.dx < 4) && (addr > 0)) { + switch (regs.u.r8.ah) { + case 0: + outb(addr+3, inb(addr+3) | 0x80); + if (regs.u.r8.al & 0xE0 == 0) { + outb(addr, 0x17); + outb(addr+1, 0x04); + } else { + val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5); + outb(addr, val16 & 0xFF); + outb(addr+1, val16 >> 8); + } + outb(addr+3, regs.u.r8.al & 0x1F); + regs.u.r8.ah = inb(addr+5); + regs.u.r8.al = inb(addr+6); + ClearCF(iret_addr.flags); + break; + case 1: + timer = read_word(0x0040, 0x006C); + while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) { + val16 = read_word(0x0040, 0x006C); + if (val16 != timer) { + timer = val16; + timeout--; + } + } + if (timeout) outb(addr, regs.u.r8.al); + regs.u.r8.ah = inb(addr+5); + if (!timeout) regs.u.r8.ah |= 0x80; + ClearCF(iret_addr.flags); + break; + case 2: + timer = read_word(0x0040, 0x006C); + while (((inb(addr+5) & 0x01) == 0) && (timeout)) { + val16 = read_word(0x0040, 0x006C); + if (val16 != timer) { + timer = val16; + timeout--; + } + } + if (timeout) { + regs.u.r8.ah = 0; + regs.u.r8.al = inb(addr); + } else { + regs.u.r8.ah = inb(addr+5); + } + ClearCF(iret_addr.flags); + break; + case 3: + regs.u.r8.ah = inb(addr+5); + regs.u.r8.al = inb(addr+6); + ClearCF(iret_addr.flags); + break; + default: + SetCF(iret_addr.flags); // Unsupported + } + } else { + SetCF(iret_addr.flags); // Unsupported + } +} + + void +int15_function(regs, ES, DS, FLAGS) + pusha_regs_t regs; // REGS pushed via pusha + Bit16u ES, DS, FLAGS; +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + bx_bool prev_a20_enable; + Bit16u base15_00; + Bit8u base23_16; + Bit16u ss; + Bit16u CX,DX; + + Bit16u bRegister; + Bit8u irqDisable; + +BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax); + + switch (regs.u.r8.ah) { + case 0x24: /* A20 Control */ + switch (regs.u.r8.al) { + case 0x00: + set_enable_a20(0); + CLEAR_CF(); + regs.u.r8.ah = 0; + break; + case 0x01: + set_enable_a20(1); + CLEAR_CF(); + regs.u.r8.ah = 0; + break; + case 0x02: + regs.u.r8.al = (inb(0x92) >> 1) & 0x01; + CLEAR_CF(); + regs.u.r8.ah = 0; + break; + case 0x03: + CLEAR_CF(); + regs.u.r8.ah = 0; + regs.u.r16.bx = 3; + break; + default: + BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al); + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + } + break; + + case 0x41: + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + break; + + case 0x4f: + /* keyboard intercept */ +#if BX_CPU < 2 + regs.u.r8.ah = UNSUPPORTED_FUNCTION; +#else + // nop +#endif + SET_CF(); + break; + + case 0x52: // removable media eject + CLEAR_CF(); + regs.u.r8.ah = 0; // "ok ejection may proceed" + break; + + case 0x83: { + if( regs.u.r8.al == 0 ) { + // Set Interval requested. + if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) { + // Interval not already set. + write_byte( 0x40, 0xA0, 1 ); // Set status byte. + write_word( 0x40, 0x98, ES ); // Byte location, segment + write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset + write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay + write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay. + CLEAR_CF( ); + irqDisable = inb( 0xA1 ); + outb( 0xA1, irqDisable & 0xFE ); + bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through. + outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer + } else { + // Interval already set. + BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" ); + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + } + } else if( regs.u.r8.al == 1 ) { + // Clear Interval requested + write_byte( 0x40, 0xA0, 0 ); // Clear status byte + CLEAR_CF( ); + bRegister = inb_cmos( 0xB ); + outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer + } else { + BX_DEBUG_INT15("int15: Func 83h, failed.\n" ); + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + regs.u.r8.al--; + } + + break; + } + + case 0x87: +#if BX_CPU < 3 +# error "Int15 function 87h not supported on < 80386" +#endif + // +++ should probably have descriptor checks + // +++ should have exception handlers + + // turn off interrupts +ASM_START + cli +ASM_END + + prev_a20_enable = set_enable_a20(1); // enable A20 line + + // 128K max of transfer on 386+ ??? + // source == destination ??? + + // ES:SI points to descriptor table + // offset use initially comments + // ============================================== + // 00..07 Unused zeros Null descriptor + // 08..0f GDT zeros filled in by BIOS + // 10..17 source ssssssss source of data + // 18..1f dest dddddddd destination of data + // 20..27 CS zeros filled in by BIOS + // 28..2f SS zeros filled in by BIOS + + //es:si + //eeee0 + //0ssss + //----- + +// check for access rights of source & dest here + + // Initialize GDT descriptor + base15_00 = (ES << 4) + regs.u.r16.si; + base23_16 = ES >> 12; + if (base15_00 < (ES<<4)) + base23_16++; + write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor + write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00 + write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16 + write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access + write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16 + + // Initialize CS descriptor + write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit + write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00 + write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16 + write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access + write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16 + + // Initialize SS descriptor + ss = get_SS(); + base15_00 = ss << 4; + base23_16 = ss >> 12; + write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit + write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00 + write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16 + write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access + write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16 + + CX = regs.u.r16.cx; +ASM_START + // Compile generates locals offset info relative to SP. + // Get CX (word count) from stack. + mov bx, sp + SEG SS + mov cx, _int15_function.CX [bx] + + // since we need to set SS:SP, save them to the BDA + // for future restore + push eax + xor eax, eax + mov ds, ax + mov 0x0469, ss + mov 0x0467, sp + + SEG ES + lgdt [si + 0x08] + SEG CS + lidt [pmode_IDT_info] + ;; perhaps do something with IDT here + + ;; set PE bit in CR0 + mov eax, cr0 + or al, #0x01 + mov cr0, eax + ;; far jump to flush CPU queue after transition to protected mode + JMP_AP(0x0020, protected_mode) + +protected_mode: + ;; GDT points to valid descriptor table, now load SS, DS, ES + mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00 + mov ss, ax + mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00 + mov ds, ax + mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00 + mov es, ax + xor si, si + xor di, di + cld + rep + movsw ;; move CX words from DS:SI to ES:DI + + ;; make sure DS and ES limits are 64KB + mov ax, #0x28 + mov ds, ax + mov es, ax + + ;; reset PG bit in CR0 ??? + mov eax, cr0 + and al, #0xFE + mov cr0, eax + + ;; far jump to flush CPU queue after transition to real mode + JMP_AP(0xf000, real_mode) + +real_mode: + ;; restore IDT to normal real-mode defaults + SEG CS + lidt [rmode_IDT_info] + + // restore SS:SP from the BDA + xor ax, ax + mov ds, ax + mov ss, 0x0469 + mov sp, 0x0467 + pop eax +ASM_END + + set_enable_a20(prev_a20_enable); + + // turn back on interrupts +ASM_START + sti +ASM_END + + regs.u.r8.ah = 0; + CLEAR_CF(); + break; + + + case 0x88: + // Get the amount of extended memory (above 1M) +#if BX_CPU < 2 + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + SET_CF(); +#else + regs.u.r8.al = inb_cmos(0x30); + regs.u.r8.ah = inb_cmos(0x31); + + // limit to 15M + if(regs.u.r16.ax > 0x3c00) + regs.u.r16.ax = 0x3c00; + + CLEAR_CF(); +#endif + break; + + case 0x90: + /* Device busy interrupt. Called by Int 16h when no key available */ + break; + + case 0x91: + /* Interrupt complete. Called by Int 16h when key becomes available */ + break; + + case 0xbf: + BX_INFO("*** int 15h function AH=bf not yet supported!\n"); + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + break; + + case 0xC0: +#if 0 + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + break; +#endif + CLEAR_CF(); + regs.u.r8.ah = 0; + regs.u.r16.bx = BIOS_CONFIG_TABLE; + ES = 0xF000; + break; + + case 0xc1: + ES = ebda_seg; + CLEAR_CF(); + break; + + case 0xd8: + bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n"); + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + break; + + default: + BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n", + (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx); + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + break; + } +} + +#if BX_USE_PS2_MOUSE + void +int15_function_mouse(regs, ES, DS, FLAGS) + pusha_regs_t regs; // REGS pushed via pusha + Bit16u ES, DS, FLAGS; +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + Bit8u mouse_flags_1, mouse_flags_2; + Bit16u mouse_driver_seg; + Bit16u mouse_driver_offset; + Bit8u comm_byte, prev_command_byte; + Bit8u ret, mouse_data1, mouse_data2, mouse_data3; + +BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax); + + switch (regs.u.r8.ah) { + case 0xC2: + // Return Codes status in AH + // ========================= + // 00: success + // 01: invalid subfunction (AL > 7) + // 02: invalid input value (out of allowable range) + // 03: interface error + // 04: resend command received from mouse controller, + // device driver should attempt command again + // 05: cannot enable mouse, since no far call has been installed + // 80/86: mouse service not implemented + + switch (regs.u.r8.al) { + case 0: // Disable/Enable Mouse +BX_DEBUG_INT15("case 0:\n"); + switch (regs.u.r8.bh) { + case 0: // Disable Mouse +BX_DEBUG_INT15("case 0: disable mouse\n"); + inhibit_mouse_int_and_events(); // disable IRQ12 and packets + ret = send_to_mouse_ctrl(0xF5); // disable mouse command + if (ret == 0) { + ret = get_mouse_data(&mouse_data1); + if ( (ret == 0) || (mouse_data1 == 0xFA) ) { + CLEAR_CF(); + regs.u.r8.ah = 0; + return; + } + } + + // error + SET_CF(); + regs.u.r8.ah = ret; + return; + break; + + case 1: // Enable Mouse +BX_DEBUG_INT15("case 1: enable mouse\n"); + mouse_flags_2 = read_byte(ebda_seg, 0x0027); + if ( (mouse_flags_2 & 0x80) == 0 ) { + BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n"); + SET_CF(); // error + regs.u.r8.ah = 5; // no far call installed + return; + } + inhibit_mouse_int_and_events(); // disable IRQ12 and packets + ret = send_to_mouse_ctrl(0xF4); // enable mouse command + if (ret == 0) { + ret = get_mouse_data(&mouse_data1); + if ( (ret == 0) && (mouse_data1 == 0xFA) ) { + enable_mouse_int_and_events(); // turn IRQ12 and packet generation on + CLEAR_CF(); + regs.u.r8.ah = 0; + return; + } + } + SET_CF(); + regs.u.r8.ah = ret; + return; + + default: // invalid subfunction + BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh); + SET_CF(); // error + regs.u.r8.ah = 1; // invalid subfunction + return; + } + break; + + case 1: // Reset Mouse + case 5: // Initialize Mouse +BX_DEBUG_INT15("case 1 or 5:\n"); + if (regs.u.r8.al == 5) { + if (regs.u.r8.bh != 3) { + SET_CF(); + regs.u.r8.ah = 0x02; // invalid input + return; + } + mouse_flags_2 = read_byte(ebda_seg, 0x0027); + mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh; + mouse_flags_1 = 0x00; + write_byte(ebda_seg, 0x0026, mouse_flags_1); + write_byte(ebda_seg, 0x0027, mouse_flags_2); + } + + inhibit_mouse_int_and_events(); // disable IRQ12 and packets + ret = send_to_mouse_ctrl(0xFF); // reset mouse command + if (ret == 0) { + ret = get_mouse_data(&mouse_data3); + // if no mouse attached, it will return RESEND + if (mouse_data3 == 0xfe) { + SET_CF(); + return; + } + if (mouse_data3 != 0xfa) + BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3); + if ( ret == 0 ) { + ret = get_mouse_data(&mouse_data1); + if ( ret == 0 ) { + ret = get_mouse_data(&mouse_data2); + if ( ret == 0 ) { + // turn IRQ12 and packet generation on + enable_mouse_int_and_events(); + CLEAR_CF(); + regs.u.r8.ah = 0; + regs.u.r8.bl = mouse_data1; + regs.u.r8.bh = mouse_data2; + return; + } + } + } + } + + // error + SET_CF(); + regs.u.r8.ah = ret; + return; + + case 2: // Set Sample Rate +BX_DEBUG_INT15("case 2:\n"); + switch (regs.u.r8.bh) { + case 0: mouse_data1 = 10; break; // 10 reports/sec + case 1: mouse_data1 = 20; break; // 20 reports/sec + case 2: mouse_data1 = 40; break; // 40 reports/sec + case 3: mouse_data1 = 60; break; // 60 reports/sec + case 4: mouse_data1 = 80; break; // 80 reports/sec + case 5: mouse_data1 = 100; break; // 100 reports/sec (default) + case 6: mouse_data1 = 200; break; // 200 reports/sec + default: mouse_data1 = 0; + } + if (mouse_data1 > 0) { + ret = send_to_mouse_ctrl(0xF3); // set sample rate command + if (ret == 0) { + ret = get_mouse_data(&mouse_data2); + ret = send_to_mouse_ctrl(mouse_data1); + ret = get_mouse_data(&mouse_data2); + CLEAR_CF(); + regs.u.r8.ah = 0; + } else { + // error + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + } + } else { + // error + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + } + break; + + case 3: // Set Resolution +BX_DEBUG_INT15("case 3:\n"); + // BX: + // 0 = 25 dpi, 1 count per millimeter + // 1 = 50 dpi, 2 counts per millimeter + // 2 = 100 dpi, 4 counts per millimeter + // 3 = 200 dpi, 8 counts per millimeter + CLEAR_CF(); + regs.u.r8.ah = 0; + break; + + case 4: // Get Device ID +BX_DEBUG_INT15("case 4:\n"); + inhibit_mouse_int_and_events(); // disable IRQ12 and packets + ret = send_to_mouse_ctrl(0xF2); // get mouse ID command + if (ret == 0) { + ret = get_mouse_data(&mouse_data1); + ret = get_mouse_data(&mouse_data2); + CLEAR_CF(); + regs.u.r8.ah = 0; + regs.u.r8.bh = mouse_data2; + } else { + // error + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + } + break; + + case 6: // Return Status & Set Scaling Factor... +BX_DEBUG_INT15("case 6:\n"); + switch (regs.u.r8.bh) { + case 0: // Return Status + comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets + ret = send_to_mouse_ctrl(0xE9); // get mouse info command + if (ret == 0) { + ret = get_mouse_data(&mouse_data1); + if (mouse_data1 != 0xfa) + BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1); + if (ret == 0) { + ret = get_mouse_data(&mouse_data1); + if ( ret == 0 ) { + ret = get_mouse_data(&mouse_data2); + if ( ret == 0 ) { + ret = get_mouse_data(&mouse_data3); + if ( ret == 0 ) { + CLEAR_CF(); + regs.u.r8.ah = 0; + regs.u.r8.bl = mouse_data1; + regs.u.r8.cl = mouse_data2; + regs.u.r8.dl = mouse_data3; + set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable + return; + } + } + } + } + } + + // error + SET_CF(); + regs.u.r8.ah = ret; + set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable + return; + + case 1: // Set Scaling Factor to 1:1 + case 2: // Set Scaling Factor to 2:1 + comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets + if (regs.u.r8.bh == 1) { + ret = send_to_mouse_ctrl(0xE6); + } else { + ret = send_to_mouse_ctrl(0xE7); + } + if (ret == 0) { + get_mouse_data(&mouse_data1); + ret = (mouse_data1 != 0xFA); + } + if (ret == 0) { + CLEAR_CF(); + regs.u.r8.ah = 0; + } else { + // error + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + } + set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable + break; + + default: + BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh); + } + break; + + case 7: // Set Mouse Handler Address +BX_DEBUG_INT15("case 7:\n"); + mouse_driver_seg = ES; + mouse_driver_offset = regs.u.r16.bx; + write_word(ebda_seg, 0x0022, mouse_driver_offset); + write_word(ebda_seg, 0x0024, mouse_driver_seg); + mouse_flags_2 = read_byte(ebda_seg, 0x0027); + if (mouse_driver_offset == 0 && mouse_driver_seg == 0) { + /* remove handler */ + if ( (mouse_flags_2 & 0x80) != 0 ) { + mouse_flags_2 &= ~0x80; + inhibit_mouse_int_and_events(); // disable IRQ12 and packets + } + } + else { + /* install handler */ + mouse_flags_2 |= 0x80; + } + write_byte(ebda_seg, 0x0027, mouse_flags_2); + CLEAR_CF(); + regs.u.r8.ah = 0; + break; + + default: +BX_DEBUG_INT15("case default:\n"); + regs.u.r8.ah = 1; // invalid function + SET_CF(); + } + break; + + default: + BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n", + (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx); + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + break; + } +} +#endif + + void +int15_function32(regs, ES, DS, FLAGS) + pushad_regs_t regs; // REGS pushed via pushad + Bit16u ES, DS, FLAGS; +{ + Bit32u extended_memory_size=0; // 64bits long + Bit16u CX,DX; + +BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax); + + switch (regs.u.r8.ah) { + case 0x86: + // Wait for CX:DX microseconds. currently using the + // refresh request port 0x61 bit4, toggling every 15usec + + CX = regs.u.r16.cx; + DX = regs.u.r16.dx; + +ASM_START + sti + + ;; Get the count in eax + mov bx, sp + SEG SS + mov ax, _int15_function.CX [bx] + shl eax, #16 + SEG SS + mov ax, _int15_function.DX [bx] + + ;; convert to numbers of 15usec ticks + mov ebx, #15 + xor edx, edx + div eax, ebx + mov ecx, eax + + ;; wait for ecx number of refresh requests + in al, #0x61 + and al,#0x10 + mov ah, al + + or ecx, ecx + je int1586_tick_end +int1586_tick: + in al, #0x61 + and al,#0x10 + cmp al, ah + je int1586_tick + mov ah, al + dec ecx + jnz int1586_tick +int1586_tick_end: +ASM_END + + break; + + case 0xe8: + switch(regs.u.r8.al) + { + case 0x20: // coded by osmaker aka K.J. + if(regs.u.r32.edx == 0x534D4150) /* SMAP */ + { +#ifdef HVMASSIST + if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) { + Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14; + + if (regs.u.r16.bx + 0x14 <= e820_table_size) { + memcpyb(ES, regs.u.r16.di, + 0xe000, 0x10 + regs.u.r16.bx, 0x14); + } + regs.u.r32.ebx += 0x14; + if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size) + regs.u.r32.ebx = 0; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + } else if (regs.u.r16.bx == 1) { + extended_memory_size = inb_cmos(0x35); + extended_memory_size <<= 8; + extended_memory_size |= inb_cmos(0x34); + extended_memory_size *= 64; + if (extended_memory_size > 0x3bc000) // greater than EFF00000??? + { + extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000 + } + extended_memory_size *= 1024; + extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off + + if (extended_memory_size <= 15728640) + { + extended_memory_size = inb_cmos(0x31); + extended_memory_size <<= 8; + extended_memory_size |= inb_cmos(0x30); + extended_memory_size *= 1024; + } + + write_word(ES, regs.u.r16.di, 0x0000); + write_word(ES, regs.u.r16.di+2, 0x0010); + write_word(ES, regs.u.r16.di+4, 0x0000); + write_word(ES, regs.u.r16.di+6, 0x0000); + + write_word(ES, regs.u.r16.di+8, extended_memory_size); + extended_memory_size >>= 16; + write_word(ES, regs.u.r16.di+10, extended_memory_size); + extended_memory_size >>= 16; + write_word(ES, regs.u.r16.di+12, extended_memory_size); + extended_memory_size >>= 16; + write_word(ES, regs.u.r16.di+14, extended_memory_size); + + write_word(ES, regs.u.r16.di+16, 0x1); + write_word(ES, regs.u.r16.di+18, 0x0); + + regs.u.r32.ebx = 0; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + } else { /* AX=E820, DX=534D4150, BX unrecognized */ + goto int15_unimplemented; + } +#else + switch(regs.u.r16.bx) + { + case 0: + write_word(ES, regs.u.r16.di, 0x00); + write_word(ES, regs.u.r16.di+2, 0x00); + write_word(ES, regs.u.r16.di+4, 0x00); + write_word(ES, regs.u.r16.di+6, 0x00); + + write_word(ES, regs.u.r16.di+8, 0xFC00); + write_word(ES, regs.u.r16.di+10, 0x0009); + write_word(ES, regs.u.r16.di+12, 0x0000); + write_word(ES, regs.u.r16.di+14, 0x0000); + + write_word(ES, regs.u.r16.di+16, 0x1); + write_word(ES, regs.u.r16.di+18, 0x0); + + regs.u.r32.ebx = 1; + + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + break; + case 1: + extended_memory_size = inb_cmos(0x35); + extended_memory_size <<= 8; + extended_memory_size |= inb_cmos(0x34); + extended_memory_size *= 64; + if(extended_memory_size > 0x3bc000) // greater than EFF00000??? + { + extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000 + } + extended_memory_size *= 1024; + extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off + + if(extended_memory_size <= 15728640) + { + extended_memory_size = inb_cmos(0x31); + extended_memory_size <<= 8; + extended_memory_size |= inb_cmos(0x30); + extended_memory_size *= 1024; + } + + write_word(ES, regs.u.r16.di, 0x0000); + write_word(ES, regs.u.r16.di+2, 0x0010); + write_word(ES, regs.u.r16.di+4, 0x0000); + write_word(ES, regs.u.r16.di+6, 0x0000); + + write_word(ES, regs.u.r16.di+8, extended_memory_size); + extended_memory_size >>= 16; + write_word(ES, regs.u.r16.di+10, extended_memory_size); + extended_memory_size >>= 16; + write_word(ES, regs.u.r16.di+12, extended_memory_size); + extended_memory_size >>= 16; + write_word(ES, regs.u.r16.di+14, extended_memory_size); + + write_word(ES, regs.u.r16.di+16, 0x1); + write_word(ES, regs.u.r16.di+18, 0x0); + + regs.u.r32.ebx = 0; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + break; + default: /* AX=E820, DX=534D4150, BX unrecognized */ + goto int15_unimplemented; + break; + } +#endif + } else { + // if DX != 0x534D4150) + goto int15_unimplemented; + } + break; + + case 0x01: + // do we have any reason to fail here ? + CLEAR_CF(); + + // my real system sets ax and bx to 0 + // this is confirmed by Ralph Brown list + // but syslinux v1.48 is known to behave + // strangely if ax is set to 0 + // regs.u.r16.ax = 0; + // regs.u.r16.bx = 0; + + // Get the amount of extended memory (above 1M) + regs.u.r8.cl = inb_cmos(0x30); + regs.u.r8.ch = inb_cmos(0x31); + + // limit to 15M + if(regs.u.r16.cx > 0x3c00) + { + regs.u.r16.cx = 0x3c00; + } + + // Get the amount of extended memory above 16M in 64k blocs + regs.u.r8.dl = inb_cmos(0x34); + regs.u.r8.dh = inb_cmos(0x35); + + // Set configured memory equal to extended memory + regs.u.r16.ax = regs.u.r16.cx; + regs.u.r16.bx = regs.u.r16.dx; + break; + default: /* AH=0xE8?? but not implemented */ + goto int15_unimplemented; + } + break; + int15_unimplemented: + // fall into the default + default: + BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n", + (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx); + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + break; + } +} + + void +int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS) + Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS; +{ + Bit8u scan_code, ascii_code, shift_flags, count; + Bit16u kbd_code, max; + + BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX); + + switch (GET_AH()) { + case 0x00: /* read keyboard input */ + + if ( !dequeue_key(&scan_code, &ascii_code, 1) ) { + BX_PANIC("KBD: int16h: out of keyboard input\n"); + } + if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0; + else if (ascii_code == 0xE0) ascii_code = 0; + AX = (scan_code << 8) | ascii_code; + break; + + case 0x01: /* check keyboard status */ + if ( !dequeue_key(&scan_code, &ascii_code, 0) ) { + SET_ZF(); + return; + } + if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0; + else if (ascii_code == 0xE0) ascii_code = 0; + AX = (scan_code << 8) | ascii_code; + CLEAR_ZF(); + break; + + case 0x02: /* get shift flag status */ + shift_flags = read_byte(0x0040, 0x17); + SET_AL(shift_flags); + break; + + case 0x05: /* store key-stroke into buffer */ + if ( !enqueue_key(GET_CH(), GET_CL()) ) { + SET_AL(1); + } + else { + SET_AL(0); + } + break; + + case 0x09: /* GET KEYBOARD FUNCTIONALITY */ + // bit Bochs Description + // 7 0 reserved + // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support) + // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support) + // 4 1 INT 16/AH=0Ah supported + // 3 0 INT 16/AX=0306h supported + // 2 0 INT 16/AX=0305h supported + // 1 0 INT 16/AX=0304h supported + // 0 0 INT 16/AX=0300h supported + // + SET_AL(0x30); + break; + + case 0x0A: /* GET KEYBOARD ID */ + count = 2; + kbd_code = 0x0; + outb(0x60, 0xf2); + /* Wait for data */ + max=0xffff; + while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00); + if (max>0x0) { + if ((inb(0x60) == 0xfa)) { + do { + max=0xffff; + while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00); + if (max>0x0) { + kbd_code >>= 8; + kbd_code |= (inb(0x60) << 8); + } + } while (--count>0); + } + } + BX=kbd_code; + break; + + case 0x10: /* read MF-II keyboard input */ + + if ( !dequeue_key(&scan_code, &ascii_code, 1) ) { + BX_PANIC("KBD: int16h: out of keyboard input\n"); + } + if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0; + AX = (scan_code << 8) | ascii_code; + break; + + case 0x11: /* check MF-II keyboard status */ + if ( !dequeue_key(&scan_code, &ascii_code, 0) ) { + SET_ZF(); + return; + } + if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0; + AX = (scan_code << 8) | ascii_code; + CLEAR_ZF(); + break; + + case 0x12: /* get extended keyboard status */ + shift_flags = read_byte(0x0040, 0x17); + SET_AL(shift_flags); + shift_flags = read_byte(0x0040, 0x18); + SET_AH(shift_flags); + BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX); + break; + + case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */ + SET_AH(0x80); // function int16 ah=0x10-0x12 supported + break; + + case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */ + // don't change AH : function int16 ah=0x20-0x22 NOT supported + break; + + case 0x6F: + if (GET_AL() == 0x08) + SET_AH(0x02); // unsupported, aka normal keyboard + + default: + BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH()); + } +} + + unsigned int +dequeue_key(scan_code, ascii_code, incr) + Bit8u *scan_code; + Bit8u *ascii_code; + unsigned int incr; +{ + Bit16u buffer_start, buffer_end, buffer_head, buffer_tail; + Bit16u ss; + Bit8u acode, scode; + +#if BX_CPU < 2 + buffer_start = 0x001E; + buffer_end = 0x003E; +#else + buffer_start = read_word(0x0040, 0x0080); + buffer_end = read_word(0x0040, 0x0082); +#endif + + buffer_head = read_word(0x0040, 0x001a); + buffer_tail = read_word(0x0040, 0x001c); + + if (buffer_head != buffer_tail) { + ss = get_SS(); + acode = read_byte(0x0040, buffer_head); + scode = read_byte(0x0040, buffer_head+1); + write_byte(ss, ascii_code, acode); + write_byte(ss, scan_code, scode); + + if (incr) { + buffer_head += 2; + if (buffer_head >= buffer_end) + buffer_head = buffer_start; + write_word(0x0040, 0x001a, buffer_head); + } + return(1); + } + else { + return(0); + } +} + +static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n"; + + Bit8u +inhibit_mouse_int_and_events() +{ + Bit8u command_byte, prev_command_byte; + + // Turn off IRQ generation and aux data line + if ( inb(0x64) & 0x02 ) + BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse"); + outb(0x64, 0x20); // get command byte + while ( (inb(0x64) & 0x01) != 0x01 ); + prev_command_byte = inb(0x60); + command_byte = prev_command_byte; + //while ( (inb(0x64) & 0x02) ); + if ( inb(0x64) & 0x02 ) + BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse"); + command_byte &= 0xfd; // turn off IRQ 12 generation + command_byte |= 0x20; // disable mouse serial clock line + outb(0x64, 0x60); // write command byte + outb(0x60, command_byte); + return(prev_command_byte); +} + + void +enable_mouse_int_and_events() +{ + Bit8u command_byte; + + // Turn on IRQ generation and aux data line + if ( inb(0x64) & 0x02 ) + BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse"); + outb(0x64, 0x20); // get command byte + while ( (inb(0x64) & 0x01) != 0x01 ); + command_byte = inb(0x60); + //while ( (inb(0x64) & 0x02) ); + if ( inb(0x64) & 0x02 ) + BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse"); + command_byte |= 0x02; // turn on IRQ 12 generation + command_byte &= 0xdf; // enable mouse serial clock line + outb(0x64, 0x60); // write command byte + outb(0x60, command_byte); +} + + Bit8u +send_to_mouse_ctrl(sendbyte) + Bit8u sendbyte; +{ + Bit8u response; + + // wait for chance to write to ctrl + if ( inb(0x64) & 0x02 ) + BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse"); + outb(0x64, 0xD4); + outb(0x60, sendbyte); + return(0); +} + + + Bit8u +get_mouse_data(data) + Bit8u *data; +{ + Bit8u response; + Bit16u ss; + + while ( (inb(0x64) & 0x21) != 0x21 ) { + } + + response = inb(0x60); + + ss = get_SS(); + write_byte(ss, data, response); + return(0); +} + + void +set_kbd_command_byte(command_byte) + Bit8u command_byte; +{ + if ( inb(0x64) & 0x02 ) + BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm"); + outb(0x64, 0xD4); + + outb(0x64, 0x60); // write command byte + outb(0x60, command_byte); +} + + void +int09_function(DI, SI, BP, SP, BX, DX, CX, AX) + Bit16u DI, SI, BP, SP, BX, DX, CX, AX; +{ + Bit8u scancode, asciicode, shift_flags; + Bit8u mf2_flags, mf2_state, led_flags; + + // + // DS has been set to F000 before call + // + + + scancode = GET_AL(); + + if (scancode == 0) { + BX_INFO("KBD: int09 handler: AL=0\n"); + return; + } + + + shift_flags = read_byte(0x0040, 0x17); + mf2_flags = read_byte(0x0040, 0x18); + mf2_state = read_byte(0x0040, 0x96); + led_flags = read_byte(0x0040, 0x97); + asciicode = 0; + + switch (scancode) { + case 0x3a: /* Caps Lock press */ + shift_flags ^= 0x40; + write_byte(0x0040, 0x17, shift_flags); + mf2_flags |= 0x40; + write_byte(0x0040, 0x18, mf2_flags); + led_flags ^= 0x04; + write_byte(0x0040, 0x97, led_flags); + break; + case 0xba: /* Caps Lock release */ + mf2_flags &= ~0x40; + write_byte(0x0040, 0x18, mf2_flags); + break; + + case 0x2a: /* L Shift press */ + /*shift_flags &= ~0x40;*/ + shift_flags |= 0x02; + write_byte(0x0040, 0x17, shift_flags); + led_flags &= ~0x04; + write_byte(0x0040, 0x97, led_flags); + break; + case 0xaa: /* L Shift release */ + shift_flags &= ~0x02; + write_byte(0x0040, 0x17, shift_flags); + break; + + case 0x36: /* R Shift press */ + /*shift_flags &= ~0x40;*/ + shift_flags |= 0x01; + write_byte(0x0040, 0x17, shift_flags); + led_flags &= ~0x04; + write_byte(0x0040, 0x97, led_flags); + break; + case 0xb6: /* R Shift release */ + shift_flags &= ~0x01; + write_byte(0x0040, 0x17, shift_flags); + break; + + case 0x1d: /* Ctrl press */ + shift_flags |= 0x04; + write_byte(0x0040, 0x17, shift_flags); + if (mf2_state & 0x01) { + mf2_flags |= 0x04; + } else { + mf2_flags |= 0x01; + } + write_byte(0x0040, 0x18, mf2_flags); + break; + case 0x9d: /* Ctrl release */ + shift_flags &= ~0x04; + write_byte(0x0040, 0x17, shift_flags); + if (mf2_state & 0x01) { + mf2_flags &= ~0x04; + } else { + mf2_flags &= ~0x01; + } + write_byte(0x0040, 0x18, mf2_flags); + break; + + case 0x38: /* Alt press */ + shift_flags |= 0x08; + write_byte(0x0040, 0x17, shift_flags); + if (mf2_state & 0x01) { + mf2_flags |= 0x08; + } else { + mf2_flags |= 0x02; + } + write_byte(0x0040, 0x18, mf2_flags); + break; + case 0xb8: /* Alt release */ + shift_flags &= ~0x08; + write_byte(0x0040, 0x17, shift_flags); + if (mf2_state & 0x01) { + mf2_flags &= ~0x08; + } else { + mf2_flags &= ~0x02; + } + write_byte(0x0040, 0x18, mf2_flags); + break; + + case 0x45: /* Num Lock press */ + if ((mf2_state & 0x01) == 0) { + mf2_flags |= 0x20; + write_byte(0x0040, 0x18, mf2_flags); + shift_flags ^= 0x20; + led_flags ^= 0x02; + write_byte(0x0040, 0x17, shift_flags); + write_byte(0x0040, 0x97, led_flags); + } + break; + case 0xc5: /* Num Lock release */ + if ((mf2_state & 0x01) == 0) { + mf2_flags &= ~0x20; + write_byte(0x0040, 0x18, mf2_flags); + } + break; + + case 0x46: /* Scroll Lock press */ + mf2_flags |= 0x10; + write_byte(0x0040, 0x18, mf2_flags); + shift_flags ^= 0x10; + led_flags ^= 0x01; + write_byte(0x0040, 0x17, shift_flags); + write_byte(0x0040, 0x97, led_flags); + break; + + case 0xc6: /* Scroll Lock release */ + mf2_flags &= ~0x10; + write_byte(0x0040, 0x18, mf2_flags); + break; + + default: + if (scancode & 0x80) return; /* toss key releases ... */ + if (scancode > MAX_SCAN_CODE) { + BX_INFO("KBD: int09h_handler(): unknown scancode read!\n"); + return; + } + if (shift_flags & 0x08) { /* ALT */ + asciicode = scan_to_scanascii[scancode].alt; + scancode = scan_to_scanascii[scancode].alt >> 8; + } + else if (shift_flags & 0x04) { /* CONTROL */ + asciicode = scan_to_scanascii[scancode].control; + scancode = scan_to_scanascii[scancode].control >> 8; + } + else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */ + /* check if lock state should be ignored + * because a SHIFT key are pressed */ + + if (shift_flags & scan_to_scanascii[scancode].lock_flags) { + asciicode = scan_to_scanascii[scancode].normal; + scancode = scan_to_scanascii[scancode].normal >> 8; + } + else { + asciicode = scan_to_scanascii[scancode].shift; + scancode = scan_to_scanascii[scancode].shift >> 8; + } + } + else { + /* check if lock is on */ + if (shift_flags & scan_to_scanascii[scancode].lock_flags) { + asciicode = scan_to_scanascii[scancode].shift; + scancode = scan_to_scanascii[scancode].shift >> 8; + } + else { + asciicode = scan_to_scanascii[scancode].normal; + scancode = scan_to_scanascii[scancode].normal >> 8; + } + } + if (scancode==0 && asciicode==0) { + BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n"); + } + enqueue_key(scancode, asciicode); + break; + } + mf2_state &= ~0x01; +} + + unsigned int +enqueue_key(scan_code, ascii_code) + Bit8u scan_code, ascii_code; +{ + Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail; + + //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n", + // scan_code, ascii_code); + +#if BX_CPU < 2 + buffer_start = 0x001E; + buffer_end = 0x003E; +#else + buffer_start = read_word(0x0040, 0x0080); + buffer_end = read_word(0x0040, 0x0082); +#endif + + buffer_head = read_word(0x0040, 0x001A); + buffer_tail = read_word(0x0040, 0x001C); + + temp_tail = buffer_tail; + buffer_tail += 2; + if (buffer_tail >= buffer_end) + buffer_tail = buffer_start; + + if (buffer_tail == buffer_head) { + return(0); + } + + write_byte(0x0040, temp_tail, ascii_code); + write_byte(0x0040, temp_tail+1, scan_code); + write_word(0x0040, 0x001C, buffer_tail); + return(1); +} + + + void +int74_function(make_farcall, Z, Y, X, status) + Bit16u make_farcall, Z, Y, X, status; +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + Bit8u in_byte, index, package_count; + Bit8u mouse_flags_1, mouse_flags_2; + +BX_DEBUG_INT74("entering int74_function\n"); + make_farcall = 0; + + in_byte = inb(0x64); + if ( (in_byte & 0x21) != 0x21 ) { + return; + } + in_byte = inb(0x60); +BX_DEBUG_INT74("int74: read byte %02x\n", in_byte); + + mouse_flags_1 = read_byte(ebda_seg, 0x0026); + mouse_flags_2 = read_byte(ebda_seg, 0x0027); + + if ( (mouse_flags_2 & 0x80) != 0x80 ) { + // BX_PANIC("int74_function:\n"); + return; + } + + package_count = mouse_flags_2 & 0x07; + index = mouse_flags_1 & 0x07; + write_byte(ebda_seg, 0x28 + index, in_byte); + + if ( (index+1) >= package_count ) { +BX_DEBUG_INT74("int74_function: make_farcall=1\n"); + status = read_byte(ebda_seg, 0x0028 + 0); + X = read_byte(ebda_seg, 0x0028 + 1); + Y = read_byte(ebda_seg, 0x0028 + 2); + Z = 0; + mouse_flags_1 = 0; + // check if far call handler installed + if (mouse_flags_2 & 0x80) + make_farcall = 1; + } + else { + mouse_flags_1++; + } + write_byte(ebda_seg, 0x0026, mouse_flags_1); +} + +#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status) + +#if BX_USE_ATADRV + + void +int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) + Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; +{ + Bit32u lba; + Bit16u ebda_seg=read_word(0x0040,0x000E); + Bit16u cylinder, head, sector; + Bit16u segment, offset; + Bit16u npc, nph, npspt, nlc, nlh, nlspt; + Bit16u size, count; + Bit8u device, status; + + BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES); + + write_byte(0x0040, 0x008e, 0); // clear completion flag + + // basic check : device has to be defined + if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) { + BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL()); + goto int13_fail; + } + + // Get the ata channel + device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]); + + // basic check : device has to be valid + if (device >= BX_MAX_ATA_DEVICES) { + BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL()); + goto int13_fail; + } + + switch (GET_AH()) { + + case 0x00: /* disk controller reset */ + ata_reset (device); + goto int13_success; + break; + + case 0x01: /* read disk status */ + status = read_byte(0x0040, 0x0074); + SET_AH(status); + SET_DISK_RET_STATUS(0); + /* set CF if error status read */ + if (status) goto int13_fail_nostatus; + else goto int13_success_noah; + break; + + case 0x02: // read disk sectors + case 0x03: // write disk sectors + case 0x04: // verify disk sectors + + count = GET_AL(); + cylinder = GET_CH(); + cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300; + sector = (GET_CL() & 0x3f); + head = GET_DH(); + + segment = ES; + offset = BX; + + if ( (count > 128) || (count == 0) ) { + BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH()); + goto int13_fail; + } + + nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders); + nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads); + nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt); + + // sanity check on cyl heads, sec + if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) { + BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector); + goto int13_fail; + } + + // FIXME verify + if ( GET_AH() == 0x04 ) goto int13_success; + + nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads); + npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt); + + // if needed, translate lchs to lba, and execute command + if ( (nph != nlh) || (npspt != nlspt)) { + lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1; + sector = 0; // this forces the command to be lba + } + + if ( GET_AH() == 0x02 ) + status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset); + else + status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset); + + // Set nb of sector transferred + SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors)); + + if (status != 0) { + BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status); + SET_AH(0x0c); + goto int13_fail_noah; + } + + goto int13_success; + break; + + case 0x05: /* format disk track */ + BX_INFO("format disk track called\n"); + goto int13_success; + return; + break; + + case 0x08: /* read disk drive parameters */ + + // Get logical geometry from table + nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders); + nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads); + nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt); + count = read_byte(ebda_seg, &EbdaData->ata.hdcount); + + nlc = nlc - 2; /* 0 based , last sector not used */ + SET_AL(0); + SET_CH(nlc & 0xff); + SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f)); + SET_DH(nlh - 1); + SET_DL(count); /* FIXME returns 0, 1, or n hard drives */ + + // FIXME should set ES & DI + + goto int13_success; + break; + + case 0x10: /* check drive ready */ + // should look at 40:8E also??? + + // Read the status from controller + status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT); + if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) { + goto int13_success; + } + else { + SET_AH(0xAA); + goto int13_fail_noah; + } + break; + + case 0x15: /* read disk drive size */ + + // Get physical geometry from table + npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders); + nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads); + npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt); + + // Compute sector count seen by int13 + lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt; + CX = lba >> 16; + DX = lba & 0xffff; + + SET_AH(3); // hard disk accessible + goto int13_success_noah; + break; + + case 0x41: // IBM/MS installation check + BX=0xaa55; // install check + SET_AH(0x30); // EDD 3.0 + CX=0x0007; // ext disk access and edd, removable supported + goto int13_success_noah; + break; + + case 0x42: // IBM/MS extended read + case 0x43: // IBM/MS extended write + case 0x44: // IBM/MS verify + case 0x47: // IBM/MS extended seek + + count=read_word(DS, SI+(Bit16u)&Int13Ext->count); + segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment); + offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset); + + // Can't use 64 bits lba + lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2); + if (lba != 0L) { + BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH()); + goto int13_fail; + } + + // Get 32 bits lba and check + lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1); + if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) { + BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH()); + goto int13_fail; + } + + // If verify or seek + if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 )) + goto int13_success; + + // Execute the command + if ( GET_AH() == 0x42 ) + status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset); + else + status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset); + + count=read_word(ebda_seg, &EbdaData->ata.trsfsectors); + write_word(DS, SI+(Bit16u)&Int13Ext->count, count); + + if (status != 0) { + BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status); + SET_AH(0x0c); + goto int13_fail_noah; + } + + goto int13_success; + break; + + case 0x45: // IBM/MS lock/unlock drive + case 0x49: // IBM/MS extended media change + goto int13_success; // Always success for HD + break; + + case 0x46: // IBM/MS eject media + SET_AH(0xb2); // Volume Not Removable + goto int13_fail_noah; // Always fail for HD + break; + + case 0x48: // IBM/MS get drive parameters + size=read_word(DS,SI+(Bit16u)&Int13DPT->size); + + // Buffer is too small + if(size < 0x1a) + goto int13_fail; + + // EDD 1.x + if(size >= 0x1a) { + Bit16u blksize; + + npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders); + nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads); + npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt); + lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors); + blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize); + + write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a); + write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid + write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc); + write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph); + write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt); + write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64 + write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L); + write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize); + } + + // EDD 2.x + if(size >= 0x1e) { + Bit8u channel, dev, irq, mode, checksum, i, translation; + Bit16u iobase1, iobase2, options; + + write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e); + + write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg); + write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte); + + // Fill in dpte + channel = device / 2; + iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1); + iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2); + irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq); + mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode); + translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation); + + options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation + options |= (1<<4); // lba translation + options |= (mode==ATA_MODE_PIO32?1:0<<7); + options |= (translation==ATA_TRANSLATION_LBA?1:0<<9); + options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9); + + write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1); + write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2); + write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 ); + write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb ); + write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq ); + write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 ); + write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 ); + write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 ); + write_word(ebda_seg, &EbdaData->ata.dpte.options, options); + write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0); + write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11); + + checksum=0; + for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i); + checksum = ~checksum; + write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum); + } + + // EDD 3.x + if(size >= 0x42) { + Bit8u channel, iface, checksum, i; + Bit16u iobase1; + + channel = device / 2; + iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface); + iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1); + + write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42); + write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd); + write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24); + write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0); + write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0); + + if (iface==ATA_IFACE_ISA) { + write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I'); + write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S'); + write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A'); + write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0); + } + else { + // FIXME PCI + } + write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A'); + write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T'); + write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A'); + write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0); + + if (iface==ATA_IFACE_ISA) { + write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1); + write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0); + write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L); + } + else { + // FIXME PCI + } + write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2); + write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0); + write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0); + write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L); + + checksum=0; + for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i); + checksum = ~checksum; + write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum); + } + + goto int13_success; + break; + + case 0x4e: // // IBM/MS set hardware configuration + // DMA, prefetch, PIO maximum not supported + switch (GET_AL()) { + case 0x01: + case 0x03: + case 0x04: + case 0x06: + goto int13_success; + break; + default : + goto int13_fail; + } + break; + + case 0x09: /* initialize drive parameters */ + case 0x0c: /* seek to specified cylinder */ + case 0x0d: /* alternate disk reset */ + case 0x11: /* recalibrate */ + case 0x14: /* controller internal diagnostic */ + BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH()); + goto int13_success; + break; + + case 0x0a: /* read disk sectors with ECC */ + case 0x0b: /* write disk sectors with ECC */ + case 0x18: // set media type for format + case 0x50: // IBM/MS send packet command + default: + BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH()); + goto int13_fail; + break; + } + +int13_fail: + SET_AH(0x01); // defaults to invalid function in AH or invalid parameter +int13_fail_noah: + SET_DISK_RET_STATUS(GET_AH()); +int13_fail_nostatus: + SET_CF(); // error occurred + return; + +int13_success: + SET_AH(0x00); // no error +int13_success_noah: + SET_DISK_RET_STATUS(0x00); + CLEAR_CF(); // no error + return; +} + +// --------------------------------------------------------------------------- +// Start of int13 for cdrom +// --------------------------------------------------------------------------- + + void +int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) + Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + Bit8u device, status, locks; + Bit8u atacmd[12]; + Bit32u lba; + Bit16u count, segment, offset, i, size; + + BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES); + // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI); + + SET_DISK_RET_STATUS(0x00); + + /* basic check : device should be 0xE0+ */ + if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) { + BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL()); + goto int13_fail; + } + + // Get the ata channel + device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]); + + /* basic check : device has to be valid */ + if (device >= BX_MAX_ATA_DEVICES) { + BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL()); + goto int13_fail; + } + + switch (GET_AH()) { + + // all those functions return SUCCESS + case 0x00: /* disk controller reset */ + case 0x09: /* initialize drive parameters */ + case 0x0c: /* seek to specified cylinder */ + case 0x0d: /* alternate disk reset */ + case 0x10: /* check drive ready */ + case 0x11: /* recalibrate */ + case 0x14: /* controller internal diagnostic */ + case 0x16: /* detect disk change */ + goto int13_success; + break; + + // all those functions return disk write-protected + case 0x03: /* write disk sectors */ + case 0x05: /* format disk track */ + case 0x43: // IBM/MS extended write + SET_AH(0x03); + goto int13_fail_noah; + break; + + case 0x01: /* read disk status */ + status = read_byte(0x0040, 0x0074); + SET_AH(status); + SET_DISK_RET_STATUS(0); + + /* set CF if error status read */ + if (status) goto int13_fail_nostatus; + else goto int13_success_noah; + break; + + case 0x15: /* read disk drive size */ + SET_AH(0x02); + goto int13_fail_noah; + break; + + case 0x41: // IBM/MS installation check + BX=0xaa55; // install check + SET_AH(0x30); // EDD 2.1 + CX=0x0007; // ext disk access, removable and edd + goto int13_success_noah; + break; + + case 0x42: // IBM/MS extended read + case 0x44: // IBM/MS verify sectors + case 0x47: // IBM/MS extended seek + + count=read_word(DS, SI+(Bit16u)&Int13Ext->count); + segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment); + offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset); + + // Can't use 64 bits lba + lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2); + if (lba != 0L) { + BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH()); + goto int13_fail; + } + + // Get 32 bits lba + lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1); + + // If verify or seek + if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 )) + goto int13_success; + + memsetb(get_SS(),atacmd,0,12); + atacmd[0]=0x28; // READ command + atacmd[7]=(count & 0xff00) >> 8; // Sectors + atacmd[8]=(count & 0x00ff); // Sectors + atacmd[2]=(lba & 0xff000000) >> 24; // LBA + atacmd[3]=(lba & 0x00ff0000) >> 16; + atacmd[4]=(lba & 0x0000ff00) >> 8; + atacmd[5]=(lba & 0x000000ff); + status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset); + + count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11); + write_word(DS, SI+(Bit16u)&Int13Ext->count, count); + + if (status != 0) { + BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status); + SET_AH(0x0c); + goto int13_fail_noah; + } + + goto int13_success; + break; + + case 0x45: // IBM/MS lock/unlock drive + if (GET_AL() > 2) goto int13_fail; + + locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock); + + switch (GET_AL()) { + case 0 : // lock + if (locks == 0xff) { + SET_AH(0xb4); + SET_AL(1); + goto int13_fail_noah; + } + write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks); + SET_AL(1); + break; + case 1 : // unlock + if (locks == 0x00) { + SET_AH(0xb0); + SET_AL(0); + goto int13_fail_noah; + } + write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks); + SET_AL(locks==0?0:1); + break; + case 2 : // status + SET_AL(locks==0?0:1); + break; + } + goto int13_success; + break; + + case 0x46: // IBM/MS eject media + locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock); + + if (locks != 0) { + SET_AH(0xb1); // media locked + goto int13_fail_noah; + } + // FIXME should handle 0x31 no media in device + // FIXME should handle 0xb5 valid request failed + + // Call removable media eject + ASM_START + push bp + mov bp, sp + + mov ah, #0x52 + int 15 + mov _int13_cdrom.status + 2[bp], ah + jnc int13_cdrom_rme_end + mov _int13_cdrom.status, #1 +int13_cdrom_rme_end: + pop bp + ASM_END + + if (status != 0) { + SET_AH(0xb1); // media locked + goto int13_fail_noah; + } + + goto int13_success; + break; + + case 0x48: // IBM/MS get drive parameters + size = read_word(DS,SI+(Bit16u)&Int13Ext->size); + + // Buffer is too small + if(size < 0x1a) + goto int13_fail; + + // EDD 1.x + if(size >= 0x1a) { + Bit16u cylinders, heads, spt, blksize; + + blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize); + + write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a); + write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values + write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff); + write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff); + write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff); + write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64 + write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff); + write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize); + } + + // EDD 2.x + if(size >= 0x1e) { + Bit8u channel, dev, irq, mode, checksum, i; + Bit16u iobase1, iobase2, options; + + write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e); + + write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg); + write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte); + + // Fill in dpte + channel = device / 2; + iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1); + iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2); + irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq); + mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode); + + // FIXME atapi device + options = (1<<4); // lba translation + options |= (1<<5); // removable device + options |= (1<<6); // atapi device + options |= (mode==ATA_MODE_PIO32?1:0<<7); + + write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1); + write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2); + write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 ); + write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb ); + write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq ); + write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 ); + write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 ); + write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 ); + write_word(ebda_seg, &EbdaData->ata.dpte.options, options); + write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0); + write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11); + + checksum=0; + for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i); + checksum = ~checksum; + write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum); + } + + // EDD 3.x + if(size >= 0x42) { + Bit8u channel, iface, checksum, i; + Bit16u iobase1; + + channel = device / 2; + iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface); + iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1); + + write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42); + write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd); + write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24); + write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0); + write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0); + + if (iface==ATA_IFACE_ISA) { + write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I'); + write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S'); + write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A'); + write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0); + } + else { + // FIXME PCI + } + write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A'); + write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T'); + write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A'); + write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0); + + if (iface==ATA_IFACE_ISA) { + write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1); + write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0); + write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L); + } + else { + // FIXME PCI + } + write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2); + write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0); + write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0); + write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L); + + checksum=0; + for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i); + checksum = ~checksum; + write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum); + } + + goto int13_success; + break; + + case 0x49: // IBM/MS extended media change + // always send changed ?? + SET_AH(06); + goto int13_fail_nostatus; + break; + + case 0x4e: // // IBM/MS set hardware configuration + // DMA, prefetch, PIO maximum not supported + switch (GET_AL()) { + case 0x01: + case 0x03: + case 0x04: + case 0x06: + goto int13_success; + break; + default : + goto int13_fail; + } + break; + + // all those functions return unimplemented + case 0x02: /* read sectors */ + case 0x04: /* verify sectors */ + case 0x08: /* read disk drive parameters */ + case 0x0a: /* read disk sectors with ECC */ + case 0x0b: /* write disk sectors with ECC */ + case 0x18: /* set media type for format */ + case 0x50: // ? - send packet command + default: + BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH()); + goto int13_fail; + break; + } + +int13_fail: + SET_AH(0x01); // defaults to invalid function in AH or invalid parameter +int13_fail_noah: + SET_DISK_RET_STATUS(GET_AH()); +int13_fail_nostatus: + SET_CF(); // error occurred + return; + +int13_success: + SET_AH(0x00); // no error +int13_success_noah: + SET_DISK_RET_STATUS(0x00); + CLEAR_CF(); // no error + return; +} + +// --------------------------------------------------------------------------- +// End of int13 for cdrom +// --------------------------------------------------------------------------- + +#if BX_ELTORITO_BOOT +// --------------------------------------------------------------------------- +// Start of int13 for eltorito functions +// --------------------------------------------------------------------------- + + void +int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS) + Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS; +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + + BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES); + // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI); + + switch (GET_AH()) { + + // FIXME ElTorito Various. Should be implemented + case 0x4a: // ElTorito - Initiate disk emu + case 0x4c: // ElTorito - Initiate disk emu and boot + case 0x4d: // ElTorito - Return Boot catalog + BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX); + goto int13_fail; + break; + + case 0x4b: // ElTorito - Terminate disk emu + // FIXME ElTorito Hardcoded + write_byte(DS,SI+0x00,0x13); + write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media)); + write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)); + write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index)); + write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba)); + write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec)); + write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment)); + write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment)); + write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count)); + write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders)); + write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt)); + write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads)); + + // If we have to terminate emulation + if(GET_AL() == 0x00) { + // FIXME ElTorito Various. Should be handled accordingly to spec + write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye + } + + goto int13_success; + break; + + default: + BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH()); + goto int13_fail; + break; + } + +int13_fail: + SET_AH(0x01); // defaults to invalid function in AH or invalid parameter + SET_DISK_RET_STATUS(GET_AH()); + SET_CF(); // error occurred + return; + +int13_success: + SET_AH(0x00); // no error + SET_DISK_RET_STATUS(0x00); + CLEAR_CF(); // no error + return; +} + +// --------------------------------------------------------------------------- +// End of int13 for eltorito functions +// --------------------------------------------------------------------------- + +// --------------------------------------------------------------------------- +// Start of int13 when emulating a device from the cd +// --------------------------------------------------------------------------- + + void +int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS) + Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS; +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + Bit8u device, status; + Bit16u vheads, vspt, vcylinders; + Bit16u head, sector, cylinder, nbsectors; + Bit32u vlba, ilba, slba, elba; + Bit16u before, segment, offset; + Bit8u atacmd[12]; + + BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES); + //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI); + + /* at this point, we are emulating a floppy/harddisk */ + + // Recompute the device number + device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2; + device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec); + + SET_DISK_RET_STATUS(0x00); + + /* basic checks : emulation should be active, dl should equal the emulated drive */ + if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 ) + || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) { + BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL()); + goto int13_fail; + } + + switch (GET_AH()) { + + // all those functions return SUCCESS + case 0x00: /* disk controller reset */ + case 0x09: /* initialize drive parameters */ + case 0x0c: /* seek to specified cylinder */ + case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ? + case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ? + case 0x11: /* recalibrate */ + case 0x14: /* controller internal diagnostic */ + case 0x16: /* detect disk change */ + goto int13_success; + break; + + // all those functions return disk write-protected + case 0x03: /* write disk sectors */ + case 0x05: /* format disk track */ + SET_AH(0x03); + goto int13_fail_noah; + break; + + case 0x01: /* read disk status */ + status=read_byte(0x0040, 0x0074); + SET_AH(status); + SET_DISK_RET_STATUS(0); + + /* set CF if error status read */ + if (status) goto int13_fail_nostatus; + else goto int13_success_noah; + break; + + case 0x02: // read disk sectors + case 0x04: // verify disk sectors + vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt); + vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders); + vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads); + + ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba); + + sector = GET_CL() & 0x003f; + cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH(); + head = GET_DH(); + nbsectors = GET_AL(); + segment = ES; + offset = BX; + + // no sector to read ? + if(nbsectors==0) goto int13_success; + + // sanity checks sco openserver needs this! + if ((sector > vspt) + || (cylinder >= vcylinders) + || (head >= vheads)) { + goto int13_fail; + } + + // After controls, verify do nothing + if (GET_AH() == 0x04) goto int13_success; + + segment = ES+(BX / 16); + offset = BX % 16; + + // calculate the virtual lba inside the image + vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1)); + + // In advance so we don't loose the count + SET_AL(nbsectors); + + // start lba on cd + slba = (Bit32u)vlba/4; + before= (Bit16u)vlba%4; + + // end lba on cd + elba = (Bit32u)(vlba+nbsectors-1)/4; + + memsetb(get_SS(),atacmd,0,12); + atacmd[0]=0x28; // READ command + atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors + atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors + atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA + atacmd[3]=(ilba+slba & 0x00ff0000) >> 16; + atacmd[4]=(ilba+slba & 0x0000ff00) >> 8; + atacmd[5]=(ilba+slba & 0x000000ff); + if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) { + BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status); + SET_AH(0x02); + SET_AL(0); + goto int13_fail_noah; + } + + goto int13_success; + break; + + case 0x08: /* read disk drive parameters */ + vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt); + vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1; + vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1; + + SET_AL( 0x00 ); + SET_BL( 0x00 ); + SET_CH( vcylinders & 0xff ); + SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f )); + SET_DH( vheads ); + SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2 + // FIXME ElTorito Harddisk. should send the HD count + + switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) { + case 0x01: SET_BL( 0x02 ); break; + case 0x02: SET_BL( 0x04 ); break; + case 0x03: SET_BL( 0x06 ); break; + } + +ASM_START + push bp + mov bp, sp + mov ax, #diskette_param_table2 + mov _int13_cdemu.DI+2[bp], ax + mov _int13_cdemu.ES+2[bp], cs + pop bp +ASM_END + goto int13_success; + break; + + case 0x15: /* read disk drive size */ + // FIXME ElTorito Harddisk. What geometry to send ? + SET_AH(0x03); + goto int13_success_noah; + break; + + // all those functions return unimplemented + case 0x0a: /* read disk sectors with ECC */ + case 0x0b: /* write disk sectors with ECC */ + case 0x18: /* set media type for format */ + case 0x41: // IBM/MS installation check + // FIXME ElTorito Harddisk. Darwin would like to use EDD + case 0x42: // IBM/MS extended read + case 0x43: // IBM/MS extended write + case 0x44: // IBM/MS verify sectors + case 0x45: // IBM/MS lock/unlock drive + case 0x46: // IBM/MS eject media + case 0x47: // IBM/MS extended seek + case 0x48: // IBM/MS get drive parameters + case 0x49: // IBM/MS extended media change + case 0x4e: // ? - set hardware configuration + case 0x50: // ? - send packet command + default: + BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH()); + goto int13_fail; + break; + } + +int13_fail: + SET_AH(0x01); // defaults to invalid function in AH or invalid parameter +int13_fail_noah: + SET_DISK_RET_STATUS(GET_AH()); +int13_fail_nostatus: + SET_CF(); // error occurred + return; + +int13_success: + SET_AH(0x00); // no error +int13_success_noah: + SET_DISK_RET_STATUS(0x00); + CLEAR_CF(); // no error + return; +} + +// --------------------------------------------------------------------------- +// End of int13 when emulating a device from the cd +// --------------------------------------------------------------------------- + +#endif // BX_ELTORITO_BOOT + +#else //BX_USE_ATADRV + + void +outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl) + Bit16u cylinder; + Bit16u hd_heads; + Bit16u head; + Bit16u hd_sectors; + Bit16u sector; + Bit16u dl; +{ +ASM_START + push bp + mov bp, sp + push eax + push ebx + push edx + xor eax,eax + mov ax,4[bp] // cylinder + xor ebx,ebx + mov bl,6[bp] // hd_heads + imul ebx + + mov bl,8[bp] // head + add eax,ebx + mov bl,10[bp] // hd_sectors + imul ebx + mov bl,12[bp] // sector + add eax,ebx + + dec eax + mov dx,#0x1f3 + out dx,al + mov dx,#0x1f4 + mov al,ah + out dx,al + shr eax,#16 + mov dx,#0x1f5 + out dx,al + and ah,#0xf + mov bl,14[bp] // dl + and bl,#1 + shl bl,#4 + or ah,bl + or ah,#0xe0 + mov al,ah + mov dx,#0x01f6 + out dx,al + pop edx + pop ebx + pop eax + pop bp +ASM_END +} + + void +int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) + Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; +{ + Bit8u drive, num_sectors, sector, head, status, mod; + Bit8u drive_map; + Bit8u n_drives; + Bit16u cyl_mod, ax; + Bit16u max_cylinder, cylinder, total_sectors; + Bit16u hd_cylinders; + Bit8u hd_heads, hd_sectors; + Bit16u val16; + Bit8u sector_count; + unsigned int i; + Bit16u tempbx; + Bit16u dpsize; + + Bit16u count, segment, offset; + Bit32u lba; + Bit16u error; + + BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES); + + write_byte(0x0040, 0x008e, 0); // clear completion flag + + /* at this point, DL is >= 0x80 to be passed from the floppy int13h + handler code */ + /* check how many disks first (cmos reg 0x12), return an error if + drive not present */ + drive_map = inb_cmos(0x12); + drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) | + (((drive_map & 0x0f)==0) ? 0 : 2); + n_drives = (drive_map==0) ? 0 : + ((drive_map==3) ? 2 : 1); + + if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */ + SET_AH(0x01); + SET_DISK_RET_STATUS(0x01); + SET_CF(); /* error occurred */ + return; + } + + switch (GET_AH()) { + + case 0x00: /* disk controller reset */ +BX_DEBUG_INT13_HD("int13_f00\n"); + + SET_AH(0); + SET_DISK_RET_STATUS(0); + set_diskette_ret_status(0); + set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */ + set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */ + CLEAR_CF(); /* successful */ + return; + break; + + case 0x01: /* read disk status */ +BX_DEBUG_INT13_HD("int13_f01\n"); + status = read_byte(0x0040, 0x0074); + SET_AH(status); + SET_DISK_RET_STATUS(0); + /* set CF if error status read */ + if (status) SET_CF(); + else CLEAR_CF(); + return; + break; + + case 0x04: // verify disk sectors + case 0x02: // read disk sectors + drive = GET_ELDL(); + get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors); + + num_sectors = GET_AL(); + cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH(); + sector = (GET_CL() & 0x3f); + head = GET_DH(); + + + if (hd_cylinders > 1024) { + if (hd_cylinders <= 2048) { + cylinder <<= 1; + } + else if (hd_cylinders <= 4096) { + cylinder <<= 2; + } + else if (hd_cylinders <= 8192) { + cylinder <<= 3; + } + else { // hd_cylinders <= 16384 + cylinder <<= 4; + } + + ax = head / hd_heads; + cyl_mod = ax & 0xff; + head = ax >> 8; + cylinder |= cyl_mod; + } + + if ( (cylinder >= hd_cylinders) || + (sector > hd_sectors) || + (head >= hd_heads) ) { + SET_AH(1); + SET_DISK_RET_STATUS(1); + SET_CF(); /* error occurred */ + return; + } + + if ( (num_sectors > 128) || (num_sectors == 0) ) + BX_PANIC("int13_harddisk(): num_sectors out of range!\n"); + + if (head > 15) + BX_PANIC("hard drive BIOS:(read/verify) head > 15\n"); + + if ( GET_AH() == 0x04 ) { + SET_AH(0); + SET_DISK_RET_STATUS(0); + CLEAR_CF(); + return; + } + + status = inb(0x1f7); + if (status & 0x80) { + BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n"); + } + outb(0x01f2, num_sectors); + /* activate LBA? (tomv) */ + if (hd_heads > 16) { +BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector); + outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive); + } + else { + outb(0x01f3, sector); + outb(0x01f4, cylinder & 0x00ff); + outb(0x01f5, cylinder >> 8); + outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f)); + } + outb(0x01f7, 0x20); + + while (1) { + status = inb(0x1f7); + if ( !(status & 0x80) ) break; + } + + if (status & 0x01) { + BX_PANIC("hard drive BIOS:(read/verify) read error\n"); + } else if ( !(status & 0x08) ) { + BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status); + BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n"); + } + + sector_count = 0; + tempbx = BX; + +ASM_START + sti ;; enable higher priority interrupts +ASM_END + + while (1) { +ASM_START + ;; store temp bx in real DI register + push bp + mov bp, sp + mov di, _int13_harddisk.tempbx + 2 [bp] + pop bp + + ;; adjust if there will be an overrun + cmp di, #0xfe00 + jbe i13_f02_no_adjust +i13_f02_adjust: + sub di, #0x0200 ; sub 512 bytes from offset + mov ax, es + add ax, #0x0020 ; add 512 to segment + mov es, ax + +i13_f02_no_adjust: + mov cx, #0x0100 ;; counter (256 words = 512b) + mov dx, #0x01f0 ;; AT data read port + + rep + insw ;; CX words transfered from port(DX) to ES:[DI] + +i13_f02_done: + ;; store real DI register back to temp bx + push bp + mov bp, sp + mov _int13_harddisk.tempbx + 2 [bp], di + pop bp +ASM_END + + sector_count++; + num_sectors--; + if (num_sectors == 0) { + status = inb(0x1f7); + if ( (status & 0xc9) != 0x40 ) + BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status); + break; + } + else { + status = inb(0x1f7); + if ( (status & 0xc9) != 0x48 ) + BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status); + continue; + } + } + + SET_AH(0); + SET_DISK_RET_STATUS(0); + SET_AL(sector_count); + CLEAR_CF(); /* successful */ + return; + break; + + + case 0x03: /* write disk sectors */ +BX_DEBUG_INT13_HD("int13_f03\n"); + drive = GET_ELDL (); + get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors); + + num_sectors = GET_AL(); + cylinder = GET_CH(); + cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300; + sector = (GET_CL() & 0x3f); + head = GET_DH(); + + if (hd_cylinders > 1024) { + if (hd_cylinders <= 2048) { + cylinder <<= 1; + } + else if (hd_cylinders <= 4096) { + cylinder <<= 2; + } + else if (hd_cylinders <= 8192) { + cylinder <<= 3; + } + else { // hd_cylinders <= 16384 + cylinder <<= 4; + } + + ax = head / hd_heads; + cyl_mod = ax & 0xff; + head = ax >> 8; + cylinder |= cyl_mod; + } + + if ( (cylinder >= hd_cylinders) || + (sector > hd_sectors) || + (head >= hd_heads) ) { + SET_AH( 1); + SET_DISK_RET_STATUS(1); + SET_CF(); /* error occurred */ + return; + } + + if ( (num_sectors > 128) || (num_sectors == 0) ) + BX_PANIC("int13_harddisk(): num_sectors out of range!\n"); + + if (head > 15) + BX_PANIC("hard drive BIOS:(read) head > 15\n"); + + status = inb(0x1f7); + if (status & 0x80) { + BX_PANIC("hard drive BIOS:(read) BUSY bit set\n"); + } +// should check for Drive Ready Bit also in status reg + outb(0x01f2, num_sectors); + + /* activate LBA? (tomv) */ + if (hd_heads > 16) { +BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector); + outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL()); + } + else { + outb(0x01f3, sector); + outb(0x01f4, cylinder & 0x00ff); + outb(0x01f5, cylinder >> 8); + outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f)); + } + outb(0x01f7, 0x30); + + // wait for busy bit to turn off after seeking + while (1) { + status = inb(0x1f7); + if ( !(status & 0x80) ) break; + } + + if ( !(status & 0x08) ) { + BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status); + BX_PANIC("hard drive BIOS:(write) data-request bit not set\n"); + } + + sector_count = 0; + tempbx = BX; + +ASM_START + sti ;; enable higher priority interrupts +ASM_END + + while (1) { +ASM_START + ;; store temp bx in real SI register + push bp + mov bp, sp + mov si, _int13_harddisk.tempbx + 2 [bp] + pop bp + + ;; adjust if there will be an overrun + cmp si, #0xfe00 + jbe i13_f03_no_adjust +i13_f03_adjust: + sub si, #0x0200 ; sub 512 bytes from offset + mov ax, es + add ax, #0x0020 ; add 512 to segment + mov es, ax + +i13_f03_no_adjust: + mov cx, #0x0100 ;; counter (256 words = 512b) + mov dx, #0x01f0 ;; AT data read port + + seg ES + rep + outsw ;; CX words tranfered from ES:[SI] to port(DX) + + ;; store real SI register back to temp bx + push bp + mov bp, sp + mov _int13_harddisk.tempbx + 2 [bp], si + pop bp +ASM_END + + sector_count++; + num_sectors--; + if (num_sectors == 0) { + status = inb(0x1f7); + if ( (status & 0xe9) != 0x40 ) + BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status); + break; + } + else { + status = inb(0x1f7); + if ( (status & 0xc9) != 0x48 ) + BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status); + continue; + } + } + + SET_AH(0); + SET_DISK_RET_STATUS(0); + SET_AL(sector_count); + CLEAR_CF(); /* successful */ + return; + break; + + case 0x05: /* format disk track */ +BX_DEBUG_INT13_HD("int13_f05\n"); + BX_PANIC("format disk track called\n"); + /* nop */ + SET_AH(0); + SET_DISK_RET_STATUS(0); + CLEAR_CF(); /* successful */ + return; + break; + + case 0x08: /* read disk drive parameters */ +BX_DEBUG_INT13_HD("int13_f08\n"); + + drive = GET_ELDL (); + get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors); + + // translate CHS + // + if (hd_cylinders <= 1024) { + // hd_cylinders >>= 0; + // hd_heads <<= 0; + } + else if (hd_cylinders <= 2048) { + hd_cylinders >>= 1; + hd_heads <<= 1; + } + else if (hd_cylinders <= 4096) { + hd_cylinders >>= 2; + hd_heads <<= 2; + } + else if (hd_cylinders <= 8192) { + hd_cylinders >>= 3; + hd_heads <<= 3; + } + else { // hd_cylinders <= 16384 + hd_cylinders >>= 4; + hd_heads <<= 4; + } + + max_cylinder = hd_cylinders - 2; /* 0 based */ + SET_AL(0); + SET_CH(max_cylinder & 0xff); + SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f)); + SET_DH(hd_heads - 1); + SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */ + SET_AH(0); + SET_DISK_RET_STATUS(0); + CLEAR_CF(); /* successful */ + + return; + break; + + case 0x09: /* initialize drive parameters */ +BX_DEBUG_INT13_HD("int13_f09\n"); + SET_AH(0); + SET_DISK_RET_STATUS(0); + CLEAR_CF(); /* successful */ + return; + break; + + case 0x0a: /* read disk sectors with ECC */ +BX_DEBUG_INT13_HD("int13_f0a\n"); + case 0x0b: /* write disk sectors with ECC */ +BX_DEBUG_INT13_HD("int13_f0b\n"); + BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n"); + return; + break; + + case 0x0c: /* seek to specified cylinder */ +BX_DEBUG_INT13_HD("int13_f0c\n"); + BX_INFO("int13h function 0ch (seek) not implemented!\n"); + SET_AH(0); + SET_DISK_RET_STATUS(0); + CLEAR_CF(); /* successful */ + return; + break; + + case 0x0d: /* alternate disk reset */ +BX_DEBUG_INT13_HD("int13_f0d\n"); + SET_AH(0); + SET_DISK_RET_STATUS(0); + CLEAR_CF(); /* successful */ + return; + break; + + case 0x10: /* check drive ready */ +BX_DEBUG_INT13_HD("int13_f10\n"); + //SET_AH(0); + //SET_DISK_RET_STATUS(0); + //CLEAR_CF(); /* successful */ + //return; + //break; + + // should look at 40:8E also??? + status = inb(0x01f7); + if ( (status & 0xc0) == 0x40 ) { + SET_AH(0); + SET_DISK_RET_STATUS(0); + CLEAR_CF(); // drive ready + return; + } + else { + SET_AH(0xAA); + SET_DISK_RET_STATUS(0xAA); + SET_CF(); // not ready + return; + } + break; + + case 0x11: /* recalibrate */ +BX_DEBUG_INT13_HD("int13_f11\n"); + SET_AH(0); + SET_DISK_RET_STATUS(0); + CLEAR_CF(); /* successful */ + return; + break; + + case 0x14: /* controller internal diagnostic */ +BX_DEBUG_INT13_HD("int13_f14\n"); + SET_AH(0); + SET_DISK_RET_STATUS(0); + CLEAR_CF(); /* successful */ + SET_AL(0); + return; + break; + + case 0x15: /* read disk drive size */ + drive = GET_ELDL(); + get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors); +ASM_START + push bp + mov bp, sp + mov al, _int13_harddisk.hd_heads + 2 [bp] + mov ah, _int13_harddisk.hd_sectors + 2 [bp] + mul al, ah ;; ax = heads * sectors + mov bx, _int13_harddisk.hd_cylinders + 2 [bp] + dec bx ;; use (cylinders - 1) ??? + mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors) + ;; now we need to move the 32bit result dx:ax to what the + ;; BIOS wants which is cx:dx. + ;; and then into CX:DX on the stack + mov _int13_harddisk.CX + 2 [bp], dx + mov _int13_harddisk.DX + 2 [bp], ax + pop bp +ASM_END + SET_AH(3); // hard disk accessible + SET_DISK_RET_STATUS(0); // ??? should this be 0 + CLEAR_CF(); // successful + return; + break; + + case 0x18: // set media type for format + case 0x41: // IBM/MS + case 0x42: // IBM/MS + case 0x43: // IBM/MS + case 0x44: // IBM/MS + case 0x45: // IBM/MS lock/unlock drive + case 0x46: // IBM/MS eject media + case 0x47: // IBM/MS extended seek + case 0x49: // IBM/MS extended media change + case 0x50: // IBM/MS send packet command + default: + BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH()); + + SET_AH(1); // code=invalid function in AH or invalid parameter + SET_DISK_RET_STATUS(1); + SET_CF(); /* unsuccessful */ + return; + break; + } +} + +static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n"; +static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n"; + + void +get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors) + Bit8u drive; + Bit16u *hd_cylinders; + Bit8u *hd_heads; + Bit8u *hd_sectors; +{ + Bit8u hd_type; + Bit16u ss; + Bit16u cylinders; + Bit8u iobase; + + ss = get_SS(); + if (drive == 0x80) { + hd_type = inb_cmos(0x12) & 0xf0; + if (hd_type != 0xf0) + BX_INFO(panic_msg_reg12h,0); + hd_type = inb_cmos(0x19); // HD0: extended type + if (hd_type != 47) + BX_INFO(panic_msg_reg19h,0,0x19); + iobase = 0x1b; + } else { + hd_type = inb_cmos(0x12) & 0x0f; + if (hd_type != 0x0f) + BX_INFO(panic_msg_reg12h,1); + hd_type = inb_cmos(0x1a); // HD0: extended type + if (hd_type != 47) + BX_INFO(panic_msg_reg19h,0,0x1a); + iobase = 0x24; + } + + // cylinders + cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8); + write_word(ss, hd_cylinders, cylinders); + + // heads + write_byte(ss, hd_heads, inb_cmos(iobase+2)); + + // sectors per track + write_byte(ss, hd_sectors, inb_cmos(iobase+8)); +} + +#endif //else BX_USE_ATADRV + + +////////////////////// +// FLOPPY functions // +////////////////////// + + bx_bool +floppy_media_known(drive) + Bit16u drive; +{ + Bit8u val8; + Bit16u media_state_offset; + + val8 = read_byte(0x0040, 0x003e); // diskette recal status + if (drive) + val8 >>= 1; + val8 &= 0x01; + if (val8 == 0) + return(0); + + media_state_offset = 0x0090; + if (drive) + media_state_offset += 1; + + val8 = read_byte(0x0040, media_state_offset); + val8 = (val8 >> 4) & 0x01; + if (val8 == 0) + return(0); + + // check pass, return KNOWN + return(1); +} + + bx_bool +floppy_media_sense(drive) + Bit16u drive; +{ + bx_bool retval; + Bit16u media_state_offset; + Bit8u drive_type, config_data, media_state; + + if (floppy_drive_recal(drive) == 0) { + return(0); + } + + // for now cheat and get drive type from CMOS, + // assume media is same as drive type + + // ** config_data ** + // Bitfields for diskette media control: + // Bit(s) Description (Table M0028) + // 7-6 last data rate set by controller + // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps + // 5-4 last diskette drive step rate selected + // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah + // 3-2 {data rate at start of operation} + // 1-0 reserved + + // ** media_state ** + // Bitfields for diskette drive media state: + // Bit(s) Description (Table M0030) + // 7-6 data rate + // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps + // 5 double stepping required (e.g. 360kB in 1.2MB) + // 4 media type established + // 3 drive capable of supporting 4MB media + // 2-0 on exit from BIOS, contains + // 000 trying 360kB in 360kB + // 001 trying 360kB in 1.2MB + // 010 trying 1.2MB in 1.2MB + // 011 360kB in 360kB established + // 100 360kB in 1.2MB established + // 101 1.2MB in 1.2MB established + // 110 reserved + // 111 all other formats/drives + + drive_type = inb_cmos(0x10); + if (drive == 0) + drive_type >>= 4; + else + drive_type &= 0x0f; + if ( drive_type == 1 ) { + // 360K 5.25" drive + config_data = 0x00; // 0000 0000 + media_state = 0x25; // 0010 0101 + retval = 1; + } + else if ( drive_type == 2 ) { + // 1.2 MB 5.25" drive + config_data = 0x00; // 0000 0000 + media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5) + retval = 1; + } + else if ( drive_type == 3 ) { + // 720K 3.5" drive + config_data = 0x00; // 0000 0000 ??? + media_state = 0x17; // 0001 0111 + retval = 1; + } + else if ( drive_type == 4 ) { + // 1.44 MB 3.5" drive + config_data = 0x00; // 0000 0000 + media_state = 0x17; // 0001 0111 + retval = 1; + } + else if ( drive_type == 5 ) { + // 2.88 MB 3.5" drive + config_data = 0xCC; // 1100 1100 + media_state = 0xD7; // 1101 0111 + retval = 1; + } + // + // Extended floppy size uses special cmos setting + else if ( drive_type == 6 ) { + // 160k 5.25" drive + config_data = 0x00; // 0000 0000 + media_state = 0x27; // 0010 0111 + retval = 1; + } + else if ( drive_type == 7 ) { + // 180k 5.25" drive + config_data = 0x00; // 0000 0000 + media_state = 0x27; // 0010 0111 + retval = 1; + } + else if ( drive_type == 8 ) { + // 320k 5.25" drive + config_data = 0x00; // 0000 0000 + media_state = 0x27; // 0010 0111 + retval = 1; + } + + else { + // not recognized + config_data = 0x00; // 0000 0000 + media_state = 0x00; // 0000 0000 + retval = 0; + } + + if (drive == 0) + media_state_offset = 0x90; + else + media_state_offset = 0x91; + write_byte(0x0040, 0x008B, config_data); + write_byte(0x0040, media_state_offset, media_state); + + return(retval); +} + + bx_bool +floppy_drive_recal(drive) + Bit16u drive; +{ + Bit8u val8, dor; + Bit16u curr_cyl_offset; + + // set 40:3e bit 7 to 0 + val8 = read_byte(0x0000, 0x043e); + val8 &= 0x7f; + write_byte(0x0000, 0x043e, val8); + + // turn on motor of selected drive, DMA & int enabled, normal operation + if (drive) + dor = 0x20; + else + dor = 0x10; + dor |= 0x0c; + dor |= drive; + outb(0x03f2, dor); + + // reset the disk motor timeout value of INT 08 + write_byte(0x40,0x40, BX_FLOPPY_ON_CNT); + + // check port 3f4 for drive readiness + val8 = inb(0x3f4); + if ( (val8 & 0xf0) != 0x80 ) + BX_PANIC("floppy recal:f07: ctrl not ready\n"); + + // send Recalibrate command (2 bytes) to controller + outb(0x03f5, 0x07); // 07: Recalibrate + outb(0x03f5, drive); // 0=drive0, 1=drive1 + + // turn on interrupts +ASM_START + sti +ASM_END + + // wait on 40:3e bit 7 to become 1 + val8 = (read_byte(0x0000, 0x043e) & 0x80); + while ( val8 == 0 ) { + val8 = (read_byte(0x0000, 0x043e) & 0x80); + } + + val8 = 0; // separate asm from while() loop + // turn off interrupts +ASM_START + cli +ASM_END + + // set 40:3e bit 7 to 0, and calibrated bit + val8 = read_byte(0x0000, 0x043e); + val8 &= 0x7f; + if (drive) { + val8 |= 0x02; // Drive 1 calibrated + curr_cyl_offset = 0x0095; + } + else { + val8 |= 0x01; // Drive 0 calibrated + curr_cyl_offset = 0x0094; + } + write_byte(0x0040, 0x003e, val8); + write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0 + + return(1); +} + + + + bx_bool +floppy_drive_exists(drive) + Bit16u drive; +{ + Bit8u drive_type; + + // check CMOS to see if drive exists + drive_type = inb_cmos(0x10); + if (drive == 0) + drive_type >>= 4; + else + drive_type &= 0x0f; + if ( drive_type == 0 ) + return(0); + else + return(1); +} + +#if BX_SUPPORT_FLOPPY + void +int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) + Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; +{ + Bit8u drive, num_sectors, track, sector, head, status; + Bit16u base_address, base_count, base_es; + Bit8u page, mode_register, val8, dor; + Bit8u return_status[7]; + Bit8u drive_type, num_floppies, ah; + Bit16u es, last_addr; + + BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES); + // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI); + + ah = GET_AH(); + + switch ( ah ) { + case 0x00: // diskette controller reset +BX_DEBUG_INT13_FL("floppy f00\n"); + drive = GET_ELDL(); + if (drive > 1) { + SET_AH(1); // invalid param + set_diskette_ret_status(1); + SET_CF(); + return; + } + drive_type = inb_cmos(0x10); + + if (drive == 0) + drive_type >>= 4; + else + drive_type &= 0x0f; + if (drive_type == 0) { + SET_AH(0x80); // drive not responding + set_diskette_ret_status(0x80); + SET_CF(); + return; + } + SET_AH(0); + set_diskette_ret_status(0); + CLEAR_CF(); // successful + set_diskette_current_cyl(drive, 0); // current cylinder + return; + + case 0x01: // Read Diskette Status + CLEAR_CF(); + val8 = read_byte(0x0000, 0x0441); + SET_AH(val8); + if (val8) { + SET_CF(); + } + return; + + case 0x02: // Read Diskette Sectors + case 0x03: // Write Diskette Sectors + case 0x04: // Verify Diskette Sectors + num_sectors = GET_AL(); + track = GET_CH(); + sector = GET_CL(); + head = GET_DH(); + drive = GET_ELDL(); + + if ( (drive > 1) || (head > 1) || + (num_sectors == 0) || (num_sectors > 72) ) { +BX_INFO("floppy: drive>1 || head>1 ...\n"); + SET_AH(1); + set_diskette_ret_status(1); + SET_AL(0); // no sectors read + SET_CF(); // error occurred + return; + } + + // see if drive exists + if (floppy_drive_exists(drive) == 0) { + SET_AH(0x80); // not responding + set_diskette_ret_status(0x80); + SET_AL(0); // no sectors read + SET_CF(); // error occurred + return; + } + + // see if media in drive, and type is known + if (floppy_media_known(drive) == 0) { + if (floppy_media_sense(drive) == 0) { + SET_AH(0x0C); // Media type not found + set_diskette_ret_status(0x0C); + SET_AL(0); // no sectors read + SET_CF(); // error occurred + return; + } + } + + if (ah == 0x02) { + // Read Diskette Sectors + + //----------------------------------- + // set up DMA controller for transfer + //----------------------------------- + + // es:bx = pointer to where to place information from diskette + // port 04: DMA-1 base and current address, channel 2 + // port 05: DMA-1 base and current count, channel 2 + page = (ES >> 12); // upper 4 bits + base_es = (ES << 4); // lower 16bits contributed by ES + base_address = base_es + BX; // lower 16 bits of address + // contributed by ES:BX + if ( base_address < base_es ) { + // in case of carry, adjust page by 1 + page++; + } + base_count = (num_sectors * 512) - 1; + + // check for 64K boundary overrun + last_addr = base_address + base_count; + if (last_addr < base_address) { + SET_AH(0x09); + set_diskette_ret_status(0x09); + SET_AL(0); // no sectors read + SET_CF(); // error occurred + return; + } + + BX_DEBUG_INT13_FL("masking DMA-1 c2\n"); + outb(0x000a, 0x06); + + BX_DEBUG_INT13_FL("clear flip-flop\n"); + outb(0x000c, 0x00); // clear flip-flop + outb(0x0004, base_address); + outb(0x0004, base_address>>8); + BX_DEBUG_INT13_FL("clear flip-flop\n"); + outb(0x000c, 0x00); // clear flip-flop + outb(0x0005, base_count); + outb(0x0005, base_count>>8); + + // port 0b: DMA-1 Mode Register + mode_register = 0x46; // single mode, increment, autoinit disable, + // transfer type=write, channel 2 + BX_DEBUG_INT13_FL("setting mode register\n"); + outb(0x000b, mode_register); + + BX_DEBUG_INT13_FL("setting page register\n"); + // port 81: DMA-1 Page Register, channel 2 + outb(0x0081, page); + + BX_DEBUG_INT13_FL("unmask chan 2\n"); + outb(0x000a, 0x02); // unmask channel 2 + + BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n"); + outb(0x000a, 0x02); + + //-------------------------------------- + // set up floppy controller for transfer + //-------------------------------------- + + // set 40:3e bit 7 to 0 + val8 = read_byte(0x0000, 0x043e); + val8 &= 0x7f; + write_byte(0x0000, 0x043e, val8); + + // turn on motor of selected drive, DMA & int enabled, normal operation + if (drive) + dor = 0x20; + else + dor = 0x10; + dor |= 0x0c; + dor |= drive; + outb(0x03f2, dor); + + // reset the disk motor timeout value of INT 08 + write_byte(0x40,0x40, BX_FLOPPY_ON_CNT); + + // check port 3f4 for drive readiness + val8 = inb(0x3f4); + if ( (val8 & 0xf0) != 0x80 ) + BX_PANIC("int13_diskette:f02: ctrl not ready\n"); + + // send read-normal-data command (9 bytes) to controller + outb(0x03f5, 0xe6); // e6: read normal data + outb(0x03f5, (head << 2) | drive); // HD DR1 DR2 + outb(0x03f5, track); + outb(0x03f5, head); + outb(0x03f5, sector); + outb(0x03f5, 2); // 512 byte sector size + outb(0x03f5, 0); // last sector number possible on track + outb(0x03f5, 0); // Gap length + outb(0x03f5, 0xff); // Gap length + + // turn on interrupts + ASM_START + sti + ASM_END + + // wait on 40:3e bit 7 to become 1 + val8 = (read_byte(0x0000, 0x043e) & 0x80); + while ( val8 == 0 ) { + val8 = (read_byte(0x0000, 0x043e) & 0x80); + } + + val8 = 0; // separate asm from while() loop + // turn off interrupts + ASM_START + cli + ASM_END + + // set 40:3e bit 7 to 0 + val8 = read_byte(0x0000, 0x043e); + val8 &= 0x7f; + write_byte(0x0000, 0x043e, val8); + + // check port 3f4 for accessibility to status bytes + val8 = inb(0x3f4); + if ( (val8 & 0xc0) != 0xc0 ) + BX_PANIC("int13_diskette: ctrl not ready\n"); + + // read 7 return status bytes from controller + // using loop index broken, have to unroll... + return_status[0] = inb(0x3f5); + return_status[1] = inb(0x3f5); + return_status[2] = inb(0x3f5); + return_status[3] = inb(0x3f5); + return_status[4] = inb(0x3f5); + return_status[5] = inb(0x3f5); + return_status[6] = inb(0x3f5); + // record in BIOS Data Area + write_byte(0x0040, 0x0042, return_status[0]); + write_byte(0x0040, 0x0043, return_status[1]); + write_byte(0x0040, 0x0044, return_status[2]); + write_byte(0x0040, 0x0045, return_status[3]); + write_byte(0x0040, 0x0046, return_status[4]); + write_byte(0x0040, 0x0047, return_status[5]); + write_byte(0x0040, 0x0048, return_status[6]); + + if ( (return_status[0] & 0xc0) != 0 ) { + SET_AH(0x20); + set_diskette_ret_status(0x20); + SET_AL(0); // no sectors read + SET_CF(); // error occurred + return; + } + + // ??? should track be new val from return_status[3] ? + set_diskette_current_cyl(drive, track); + // AL = number of sectors read (same value as passed) + SET_AH(0x00); // success + CLEAR_CF(); // success + return; + } + else if (ah == 0x03) { + // Write Diskette Sectors + + //----------------------------------- + // set up DMA controller for transfer + //----------------------------------- + + // es:bx = pointer to where to place information from diskette + // port 04: DMA-1 base and current address, channel 2 + // port 05: DMA-1 base and current count, channel 2 + page = (ES >> 12); // upper 4 bits + base_es = (ES << 4); // lower 16bits contributed by ES + base_address = base_es + BX; // lower 16 bits of address + // contributed by ES:BX + if ( base_address < base_es ) { + // in case of carry, adjust page by 1 + page++; + } + base_count = (num_sectors * 512) - 1; + + // check for 64K boundary overrun + last_addr = base_address + base_count; + if (last_addr < base_address) { + SET_AH(0x09); + set_diskette_ret_status(0x09); + SET_AL(0); // no sectors read + SET_CF(); // error occurred + return; + } + + BX_DEBUG_INT13_FL("masking DMA-1 c2\n"); + outb(0x000a, 0x06); + + outb(0x000c, 0x00); // clear flip-flop + outb(0x0004, base_address); + outb(0x0004, base_address>>8); + outb(0x000c, 0x00); // clear flip-flop + outb(0x0005, base_count); + outb(0x0005, base_count>>8); + + // port 0b: DMA-1 Mode Register + mode_register = 0x4a; // single mode, increment, autoinit disable, + // transfer type=read, channel 2 + outb(0x000b, mode_register); + + // port 81: DMA-1 Page Register, channel 2 + outb(0x0081, page); + + BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n"); + outb(0x000a, 0x02); + + //-------------------------------------- + // set up floppy controller for transfer + //-------------------------------------- + + // set 40:3e bit 7 to 0 + val8 = read_byte(0x0000, 0x043e); + val8 &= 0x7f; + write_byte(0x0000, 0x043e, val8); + + // turn on motor of selected drive, DMA & int enabled, normal operation + if (drive) + dor = 0x20; + else + dor = 0x10; + dor |= 0x0c; + dor |= drive; + outb(0x03f2, dor); + + // reset the disk motor timeout value of INT 08 + write_byte(0x40,0x40, BX_FLOPPY_ON_CNT); + + // check port 3f4 for drive readiness + val8 = inb(0x3f4); + if ( (val8 & 0xf0) != 0x80 ) + BX_PANIC("int13_diskette:f03: ctrl not ready\n"); + + // send read-normal-data command (9 bytes) to controller + outb(0x03f5, 0xc5); // c5: write normal data + outb(0x03f5, (head << 2) | drive); // HD DR1 DR2 + outb(0x03f5, track); + outb(0x03f5, head); + outb(0x03f5, sector); + outb(0x03f5, 2); // 512 byte sector size + outb(0x03f5, 0); // last sector number possible on track + outb(0x03f5, 0); // Gap length + outb(0x03f5, 0xff); // Gap length + + // turn on interrupts + ASM_START + sti + ASM_END + + // wait on 40:3e bit 7 to become 1 + val8 = (read_byte(0x0000, 0x043e) & 0x80); + while ( val8 == 0 ) { + val8 = (read_byte(0x0000, 0x043e) & 0x80); + } + + val8 = 0; // separate asm from while() loop + // turn off interrupts + ASM_START + cli + ASM_END + + // set 40:3e bit 7 to 0 + val8 = read_byte(0x0000, 0x043e); + val8 &= 0x7f; + write_byte(0x0000, 0x043e, val8); + + // check port 3f4 for accessibility to status bytes + val8 = inb(0x3f4); + if ( (val8 & 0xc0) != 0xc0 ) + BX_PANIC("int13_diskette: ctrl not ready\n"); + + // read 7 return status bytes from controller + // using loop index broken, have to unroll... + return_status[0] = inb(0x3f5); + return_status[1] = inb(0x3f5); + return_status[2] = inb(0x3f5); + return_status[3] = inb(0x3f5); + return_status[4] = inb(0x3f5); + return_status[5] = inb(0x3f5); + return_status[6] = inb(0x3f5); + // record in BIOS Data Area + write_byte(0x0040, 0x0042, return_status[0]); + write_byte(0x0040, 0x0043, return_status[1]); + write_byte(0x0040, 0x0044, return_status[2]); + write_byte(0x0040, 0x0045, return_status[3]); + write_byte(0x0040, 0x0046, return_status[4]); + write_byte(0x0040, 0x0047, return_status[5]); + write_byte(0x0040, 0x0048, return_status[6]); + + if ( (return_status[0] & 0xc0) != 0 ) { + if ( (return_status[1] & 0x02) != 0 ) { + // diskette not writable. + // AH=status code=0x03 (tried to write on write-protected disk) + // AL=number of sectors written=0 + AX = 0x0300; + SET_CF(); + return; + } else { + BX_PANIC("int13_diskette_function: read error\n"); + } + } + + // ??? should track be new val from return_status[3] ? + set_diskette_current_cyl(drive, track); + // AL = number of sectors read (same value as passed) + SET_AH(0x00); // success + CLEAR_CF(); // success + return; + } + else { // if (ah == 0x04) + // Verify Diskette Sectors + + // ??? should track be new val from return_status[3] ? + set_diskette_current_cyl(drive, track); + // AL = number of sectors verified (same value as passed) + CLEAR_CF(); // success + SET_AH(0x00); // success + return; + } + + + case 0x05: // format diskette track +BX_DEBUG_INT13_FL("floppy f05\n"); + + num_sectors = GET_AL(); + track = GET_CH(); + head = GET_DH(); + drive = GET_ELDL(); + + if ((drive > 1) || (head > 1) || (track > 79) || + (num_sectors == 0) || (num_sectors > 18)) { + SET_AH(1); + set_diskette_ret_status(1); + SET_CF(); // error occurred + } + + // see if drive exists + if (floppy_drive_exists(drive) == 0) { + SET_AH(0x80); // drive not responding + set_diskette_ret_status(0x80); + SET_CF(); // error occurred + return; + } + + // see if media in drive, and type is known + if (floppy_media_known(drive) == 0) { + if (floppy_media_sense(drive) == 0) { + SET_AH(0x0C); // Media type not found + set_diskette_ret_status(0x0C); + SET_AL(0); // no sectors read + SET_CF(); // error occurred + return; + } + } + + // set up DMA controller for transfer + page = (ES >> 12); // upper 4 bits + base_es = (ES << 4); // lower 16bits contributed by ES + base_address = base_es + BX; // lower 16 bits of address + // contributed by ES:BX + if ( base_address < base_es ) { + // in case of carry, adjust page by 1 + page++; + } + base_count = (num_sectors * 4) - 1; + + // check for 64K boundary overrun + last_addr = base_address + base_count; + if (last_addr < base_address) { + SET_AH(0x09); + set_diskette_ret_status(0x09); + SET_AL(0); // no sectors read + SET_CF(); // error occurred + return; + } + + outb(0x000a, 0x06); + outb(0x000c, 0x00); // clear flip-flop + outb(0x0004, base_address); + outb(0x0004, base_address>>8); + outb(0x000c, 0x00); // clear flip-flop + outb(0x0005, base_count); + outb(0x0005, base_count>>8); + mode_register = 0x4a; // single mode, increment, autoinit disable, + // transfer type=read, channel 2 + outb(0x000b, mode_register); + // port 81: DMA-1 Page Register, channel 2 + outb(0x0081, page); + outb(0x000a, 0x02); + + // set up floppy controller for transfer + val8 = read_byte(0x0000, 0x043e); + val8 &= 0x7f; + write_byte(0x0000, 0x043e, val8); + // turn on motor of selected drive, DMA & int enabled, normal operation + if (drive) + dor = 0x20; + else + dor = 0x10; + dor |= 0x0c; + dor |= drive; + outb(0x03f2, dor); + + // reset the disk motor timeout value of INT 08 + write_byte(0x40,0x40, BX_FLOPPY_ON_CNT); + + // check port 3f4 for drive readiness + val8 = inb(0x3f4); + if ( (val8 & 0xf0) != 0x80 ) + BX_PANIC("int13_diskette:f05: ctrl not ready\n"); + + // send read-normal-data command (6 bytes) to controller + outb(0x03f5, 0x4d); // 4d: format track + outb(0x03f5, (head << 2) | drive); // HD DR1 DR2 + outb(0x03f5, 2); // 512 byte sector size + outb(0x03f5, num_sectors); // number of sectors per track + outb(0x03f5, 0); // Gap length + outb(0x03f5, 0xf6); // Fill byte + // turn on interrupts + ASM_START + sti + ASM_END + // wait on 40:3e bit 7 to become 1 + val8 = (read_byte(0x0000, 0x043e) & 0x80); + while ( val8 == 0 ) { + val8 = (read_byte(0x0000, 0x043e) & 0x80); + } + val8 = 0; // separate asm from while() loop + // turn off interrupts + ASM_START + cli + ASM_END + // set 40:3e bit 7 to 0 + val8 = read_byte(0x0000, 0x043e); + val8 &= 0x7f; + write_byte(0x0000, 0x043e, val8); + // check port 3f4 for accessibility to status bytes + val8 = inb(0x3f4); + if ( (val8 & 0xc0) != 0xc0 ) + BX_PANIC("int13_diskette: ctrl not ready\n"); + + // read 7 return status bytes from controller + // using loop index broken, have to unroll... + return_status[0] = inb(0x3f5); + return_status[1] = inb(0x3f5); + return_status[2] = inb(0x3f5); + return_status[3] = inb(0x3f5); + return_status[4] = inb(0x3f5); + return_status[5] = inb(0x3f5); + return_status[6] = inb(0x3f5); + // record in BIOS Data Area + write_byte(0x0040, 0x0042, return_status[0]); + write_byte(0x0040, 0x0043, return_status[1]); + write_byte(0x0040, 0x0044, return_status[2]); + write_byte(0x0040, 0x0045, return_status[3]); + write_byte(0x0040, 0x0046, return_status[4]); + write_byte(0x0040, 0x0047, return_status[5]); + write_byte(0x0040, 0x0048, return_status[6]); + + if ( (return_status[0] & 0xc0) != 0 ) { + if ( (return_status[1] & 0x02) != 0 ) { + // diskette not writable. + // AH=status code=0x03 (tried to write on write-protected disk) + // AL=number of sectors written=0 + AX = 0x0300; + SET_CF(); + return; + } else { + BX_PANIC("int13_diskette_function: write error\n"); + } + } + + SET_AH(0); + set_diskette_ret_status(0); + set_diskette_current_cyl(drive, 0); + CLEAR_CF(); // successful + return; + + + case 0x08: // read diskette drive parameters +BX_DEBUG_INT13_FL("floppy f08\n"); + drive = GET_ELDL(); + + if (drive > 1) { + AX = 0; + BX = 0; + CX = 0; + DX = 0; + ES = 0; + DI = 0; + SET_DL(num_floppies); + SET_CF(); + return; + } + + drive_type = inb_cmos(0x10); + num_floppies = 0; + if (drive_type & 0xf0) + num_floppies++; + if (drive_type & 0x0f) + num_floppies++; + + if (drive == 0) + drive_type >>= 4; + else + drive_type &= 0x0f; + + SET_BH(0); + SET_BL(drive_type); + SET_AH(0); + SET_AL(0); + SET_DL(num_floppies); + + switch (drive_type) { + case 0: // none + CX = 0; + SET_DH(0); // max head # + break; + + case 1: // 360KB, 5.25" + CX = 0x2709; // 40 tracks, 9 sectors + SET_DH(1); // max head # + break; + + case 2: // 1.2MB, 5.25" + CX = 0x4f0f; // 80 tracks, 15 sectors + SET_DH(1); // max head # + break; + + case 3: // 720KB, 3.5" + CX = 0x4f09; // 80 tracks, 9 sectors + SET_DH(1); // max head # + break; + + case 4: // 1.44MB, 3.5" + CX = 0x4f12; // 80 tracks, 18 sectors + SET_DH(1); // max head # + break; + + case 5: // 2.88MB, 3.5" + CX = 0x4f24; // 80 tracks, 36 sectors + SET_DH(1); // max head # + break; + + case 6: // 160k, 5.25" + CX = 0x2708; // 40 tracks, 8 sectors + SET_DH(0); // max head # + break; + + case 7: // 180k, 5.25" + CX = 0x2709; // 40 tracks, 9 sectors + SET_DH(0); // max head # + break; + + case 8: // 320k, 5.25" + CX = 0x2708; // 40 tracks, 8 sectors + SET_DH(1); // max head # + break; + + default: // ? + BX_PANIC("floppy: int13: bad floppy type\n"); + } + + /* set es & di to point to 11 byte diskette param table in ROM */ +ASM_START + push bp + mov bp, sp + mov ax, #diskette_param_table2 + mov _int13_diskette_function.DI+2[bp], ax + mov _int13_diskette_function.ES+2[bp], cs + pop bp +ASM_END + CLEAR_CF(); // success + /* disk status not changed upon success */ + return; + + + case 0x15: // read diskette drive type +BX_DEBUG_INT13_FL("floppy f15\n"); + drive = GET_ELDL(); + if (drive > 1) { + SET_AH(0); // only 2 drives supported + // set_diskette_ret_status here ??? + SET_CF(); + return; + } + drive_type = inb_cmos(0x10); + + if (drive == 0) + drive_type >>= 4; + else + drive_type &= 0x0f; + CLEAR_CF(); // successful, not present + if (drive_type==0) { + SET_AH(0); // drive not present + } + else { + SET_AH(1); // drive present, does not support change line + } + + return; + + case 0x16: // get diskette change line status +BX_DEBUG_INT13_FL("floppy f16\n"); + drive = GET_ELDL(); + if (drive > 1) { + SET_AH(0x01); // invalid drive + set_diskette_ret_status(0x01); + SET_CF(); + return; + } + + SET_AH(0x06); // change line not supported + set_diskette_ret_status(0x06); + SET_CF(); + return; + + case 0x17: // set diskette type for format(old) +BX_DEBUG_INT13_FL("floppy f17\n"); + /* not used for 1.44M floppies */ + SET_AH(0x01); // not supported + set_diskette_ret_status(1); /* not supported */ + SET_CF(); + return; + + case 0x18: // set diskette type for format(new) +BX_DEBUG_INT13_FL("floppy f18\n"); + SET_AH(0x01); // do later + set_diskette_ret_status(1); + SET_CF(); + return; + + default: + BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH()); + + // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) { + SET_AH(0x01); // ??? + set_diskette_ret_status(1); + SET_CF(); + return; + // } + } +} +#else // #if BX_SUPPORT_FLOPPY + void +int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) + Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; +{ + Bit8u val8; + + switch ( GET_AH() ) { + + case 0x01: // Read Diskette Status + CLEAR_CF(); + val8 = read_byte(0x0000, 0x0441); + SET_AH(val8); + if (val8) { + SET_CF(); + } + return; + + default: + SET_CF(); + write_byte(0x0000, 0x0441, 0x01); + SET_AH(0x01); + } +} +#endif // #if BX_SUPPORT_FLOPPY + + void +set_diskette_ret_status(value) + Bit8u value; +{ + write_byte(0x0040, 0x0041, value); +} + + void +set_diskette_current_cyl(drive, cyl) + Bit8u drive; + Bit8u cyl; +{ + if (drive > 1) + BX_PANIC("set_diskette_current_cyl(): drive > 1\n"); + write_byte(0x0040, 0x0094+drive, cyl); +} + + void +determine_floppy_media(drive) + Bit16u drive; +{ +#if 0 + Bit8u val8, DOR, ctrl_info; + + ctrl_info = read_byte(0x0040, 0x008F); + if (drive==1) + ctrl_info >>= 4; + else + ctrl_info &= 0x0f; + +#if 0 + if (drive == 0) { + DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0 + } + else { + DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1 + } +#endif + + if ( (ctrl_info & 0x04) != 0x04 ) { + // Drive not determined means no drive exists, done. + return; + } + +#if 0 + // check Main Status Register for readiness + val8 = inb(0x03f4) & 0x80; // Main Status Register + if (val8 != 0x80) + BX_PANIC("d_f_m: MRQ bit not set\n"); + + // change line + + // existing BDA values + + // turn on drive motor + outb(0x03f2, DOR); // Digital Output Register + // +#endif + BX_PANIC("d_f_m: OK so far\n"); +#endif +} + + void +int17_function(regs, ds, iret_addr) + pusha_regs_t regs; // regs pushed from PUSHA instruction + Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper + iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call +{ + Bit16u addr,timeout; + Bit8u val8; + + ASM_START + sti + ASM_END + + addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8); + if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) { + timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8; + if (regs.u.r8.ah == 0) { + outb(addr, regs.u.r8.al); + val8 = inb(addr+2); + outb(addr+2, val8 | 0x01); // send strobe + ASM_START + nop + ASM_END + outb(addr+2, val8 & ~0x01); + while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) { + timeout--; + } + } + if (regs.u.r8.ah == 1) { + val8 = inb(addr+2); + outb(addr+2, val8 & ~0x04); // send init + ASM_START + nop + ASM_END + outb(addr+2, val8 | 0x04); + } + val8 = inb(addr+1); + regs.u.r8.ah = (val8 ^ 0x48); + if (!timeout) regs.u.r8.ah |= 0x01; + ClearCF(iret_addr.flags); + } else { + SetCF(iret_addr.flags); // Unsupported + } +} + +// returns bootsegment in ax, drive in bl + Bit32u +int19_function(bseqnr) +Bit8u bseqnr; +{ + Bit16u ebda_seg=read_word(0x0040,0x000E); + Bit16u bootseq; + Bit8u bootdrv; + Bit8u bootcd; + Bit8u bootchk; + Bit16u bootseg; + Bit16u status; + Bit8u lastdrive=0; + + // if BX_ELTORITO_BOOT is not defined, old behavior + // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL + // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:) + // 0: system boot sequence, first drive C: then A: + // 1: system boot sequence, first drive A: then C: + // else BX_ELTORITO_BOOT is defined + // CMOS regs 0x3D and 0x38 contain the boot sequence: + // CMOS reg 0x3D & 0x0f : 1st boot device + // CMOS reg 0x3D & 0xf0 : 2nd boot device + // CMOS reg 0x38 & 0xf0 : 3rd boot device + // boot device codes: + // 0x00 : not defined + // 0x01 : first floppy + // 0x02 : first harddrive + // 0x03 : first cdrom + // else : boot failure + + // Get the boot sequence +#if BX_ELTORITO_BOOT + bootseq=inb_cmos(0x3d); + bootseq|=((inb_cmos(0x38) & 0xf0) << 4); + + if (bseqnr==2) bootseq >>= 4; + if (bseqnr==3) bootseq >>= 8; + if (bootseq<0x10) lastdrive = 1; + bootdrv=0x00; bootcd=0; + switch(bootseq & 0x0f) { + case 0x01: bootdrv=0x00; bootcd=0; break; + case 0x02: bootdrv=0x80; bootcd=0; break; + case 0x03: bootdrv=0x00; bootcd=1; break; + default: return 0x00000000; + } +#else + bootseq=inb_cmos(0x2d); + + if (bseqnr==2) { + bootseq ^= 0x20; + lastdrive = 1; + } + bootdrv=0x00; bootcd=0; + if((bootseq&0x20)==0) bootdrv=0x80; +#endif // BX_ELTORITO_BOOT + +#if BX_ELTORITO_BOOT + // We have to boot from cd + if (bootcd != 0) { + status = cdrom_boot(); + + // If failure + if ( (status & 0x00ff) !=0 ) { + print_cdromboot_failure(status); + print_boot_failure(bootcd, bootdrv, 1, lastdrive); + return 0x00000000; + } + + bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment); + bootdrv = (Bit8u)(status>>8); + } + +#endif // BX_ELTORITO_BOOT + + // We have to boot from harddisk or floppy + if (bootcd == 0) { + bootseg=0x07c0; + +ASM_START + push bp + mov bp, sp + + mov ax, #0x0000 + mov _int19_function.status + 2[bp], ax + mov dl, _int19_function.bootdrv + 2[bp] + mov ax, _int19_function.bootseg + 2[bp] + mov es, ax ;; segment + mov bx, #0x0000 ;; offset + mov ah, #0x02 ;; function 2, read diskette sector + mov al, #0x01 ;; read 1 sector + mov ch, #0x00 ;; track 0 + mov cl, #0x01 ;; sector 1 + mov dh, #0x00 ;; head 0 + int #0x13 ;; read sector + jnc int19_load_done + mov ax, #0x0001 + mov _int19_function.status + 2[bp], ax + +int19_load_done: + pop bp +ASM_END + + if (status != 0) { + print_boot_failure(bootcd, bootdrv, 1, lastdrive); + return 0x00000000; + } + } + + // check signature if instructed by cmos reg 0x38, only for floppy + // bootchk = 1 : signature check disabled + // bootchk = 0 : signature check enabled + if (bootdrv != 0) bootchk = 0; + else bootchk = inb_cmos(0x38) & 0x01; + +#if BX_ELTORITO_BOOT + // if boot from cd, no signature check + if (bootcd != 0) + bootchk = 1; +#endif // BX_ELTORITO_BOOT + + if (bootchk == 0) { + if (read_word(bootseg,0x1fe) != 0xaa55) { + print_boot_failure(bootcd, bootdrv, 0, lastdrive); + return 0x00000000; + } + } + +#if BX_ELTORITO_BOOT + // Print out the boot string + print_boot_device(bootcd, bootdrv); +#else // BX_ELTORITO_BOOT + print_boot_device(0, bootdrv); +#endif // BX_ELTORITO_BOOT + + // return the boot segment + return (((Bit32u)bootdrv) << 16) + bootseg; +} + + void +int1a_function(regs, ds, iret_addr) + pusha_regs_t regs; // regs pushed from PUSHA instruction + Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper + iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call +{ + Bit8u val8; + + BX_DEBUG_INT1A("int1a: AX=%04x BX=%04x CX=%04x DX=%04x DS=%04x\n", regs.u.r16.ax, regs.u.r16.bx, regs.u.r16.cx, regs.u.r16.dx, ds); + + ASM_START + sti + ASM_END + + switch (regs.u.r8.ah) { + case 0: // get current clock count + ASM_START + cli + ASM_END + regs.u.r16.cx = BiosData->ticks_high; + regs.u.r16.dx = BiosData->ticks_low; + regs.u.r8.al = BiosData->midnight_flag; + BiosData->midnight_flag = 0; // reset flag + ASM_START + sti + ASM_END + // AH already 0 + ClearCF(iret_addr.flags); // OK + break; + + case 1: // Set Current Clock Count + ASM_START + cli + ASM_END + BiosData->ticks_high = regs.u.r16.cx; + BiosData->ticks_low = regs.u.r16.dx; + BiosData->midnight_flag = 0; // reset flag + ASM_START + sti + ASM_END + regs.u.r8.ah = 0; + ClearCF(iret_addr.flags); // OK + break; + + + case 2: // Read CMOS Time + if (rtc_updating()) { + SetCF(iret_addr.flags); + break; + } + + regs.u.r8.dh = inb_cmos(0x00); // Seconds + regs.u.r8.cl = inb_cmos(0x02); // Minutes + regs.u.r8.ch = inb_cmos(0x04); // Hours + regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B + regs.u.r8.ah = 0; + regs.u.r8.al = regs.u.r8.ch; + ClearCF(iret_addr.flags); // OK + break; + + case 3: // Set CMOS Time + // Using a debugger, I notice the following masking/setting + // of bits in Status Register B, by setting Reg B to + // a few values and getting its value after INT 1A was called. + // + // try#1 try#2 try#3 + // before 1111 1101 0111 1101 0000 0000 + // after 0110 0010 0110 0010 0000 0010 + // + // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1 + // My assumption: RegB = ((RegB & 01100000b) | 00000010b) + if (rtc_updating()) { + init_rtc(); + // fall through as if an update were not in progress + } + outb_cmos(0x00, regs.u.r8.dh); // Seconds + outb_cmos(0x02, regs.u.r8.cl); // Minutes + outb_cmos(0x04, regs.u.r8.ch); // Hours + // Set Daylight Savings time enabled bit to requested value + val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01); + // (reg B already selected) + outb_cmos(0x0b, val8); + regs.u.r8.ah = 0; + regs.u.r8.al = val8; // val last written to Reg B + ClearCF(iret_addr.flags); // OK + break; + + case 4: // Read CMOS Date + regs.u.r8.ah = 0; + if (rtc_updating()) { + SetCF(iret_addr.flags); + break; + } + regs.u.r8.cl = inb_cmos(0x09); // Year + regs.u.r8.dh = inb_cmos(0x08); // Month + regs.u.r8.dl = inb_cmos(0x07); // Day of Month + regs.u.r8.ch = inb_cmos(0x32); // Century + regs.u.r8.al = regs.u.r8.ch; + ClearCF(iret_addr.flags); // OK + break; + + case 5: // Set CMOS Date + // Using a debugger, I notice the following masking/setting + // of bits in Status Register B, by setting Reg B to + // a few values and getting its value after INT 1A was called. + // + // try#1 try#2 try#3 try#4 + // before 1111 1101 0111 1101 0000 0010 0000 0000 + // after 0110 1101 0111 1101 0000 0010 0000 0000 + // + // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1 + // My assumption: RegB = (RegB & 01111111b) + if (rtc_updating()) { + init_rtc(); + SetCF(iret_addr.flags); + break; + } + outb_cmos(0x09, regs.u.r8.cl); // Year + outb_cmos(0x08, regs.u.r8.dh); // Month + outb_cmos(0x07, regs.u.r8.dl); // Day of Month + outb_cmos(0x32, regs.u.r8.ch); // Century + val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit + outb_cmos(0x0b, val8); + regs.u.r8.ah = 0; + regs.u.r8.al = val8; // AL = val last written to Reg B + ClearCF(iret_addr.flags); // OK + break; + + case 6: // Set Alarm Time in CMOS + // Using a debugger, I notice the following masking/setting + // of bits in Status Register B, by setting Reg B to + // a few values and getting its value after INT 1A was called. + // + // try#1 try#2 try#3 + // before 1101 1111 0101 1111 0000 0000 + // after 0110 1111 0111 1111 0010 0000 + // + // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1 + // My assumption: RegB = ((RegB & 01111111b) | 00100000b) + val8 = inb_cmos(0x0b); // Get Status Reg B + regs.u.r16.ax = 0; + if (val8 & 0x20) { + // Alarm interrupt enabled already + SetCF(iret_addr.flags); // Error: alarm in use + break; + } + if (rtc_updating()) { + init_rtc(); + // fall through as if an update were not in progress + } + outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm + outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm + outb_cmos(0x05, regs.u.r8.ch); // Hours alarm + outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8 + // enable Status Reg B alarm bit, clear halt clock bit + outb_cmos(0x0b, (val8 & 0x7f) | 0x20); + ClearCF(iret_addr.flags); // OK + break; + + case 7: // Turn off Alarm + // Using a debugger, I notice the following masking/setting + // of bits in Status Register B, by setting Reg B to + // a few values and getting its value after INT 1A was called. + // + // try#1 try#2 try#3 try#4 + // before 1111 1101 0111 1101 0010 0000 0010 0010 + // after 0100 0101 0101 0101 0000 0000 0000 0010 + // + // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1 + // My assumption: RegB = (RegB & 01010111b) + val8 = inb_cmos(0x0b); // Get Status Reg B + // clear clock-halt bit, disable alarm bit + outb_cmos(0x0b, val8 & 0x57); // disable alarm bit + regs.u.r8.ah = 0; + regs.u.r8.al = val8; // val last written to Reg B + ClearCF(iret_addr.flags); // OK + break; +#if BX_PCIBIOS + case 0xb1: + // real mode PCI BIOS functions now handled in assembler code + // this C code handles the error code for information only + if (regs.u.r8.bl == 0xff) { + BX_INFO("PCI BIOS: PCI not present\n"); + } else if (regs.u.r8.bl == 0x81) { + BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al); + } else if (regs.u.r8.bl == 0x83) { + BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx); + } else if (regs.u.r8.bl == 0x86) { + BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx); + } + regs.u.r8.ah = regs.u.r8.bl; + SetCF(iret_addr.flags); + break; +#endif + + default: + SetCF(iret_addr.flags); // Unsupported + } +} + + void +int70_function(regs, ds, iret_addr) + pusha_regs_t regs; // regs pushed from PUSHA instruction + Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper + iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call +{ + // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes + Bit8u registerB = 0, registerC = 0; + + // Check which modes are enabled and have occurred. + registerB = inb_cmos( 0xB ); + registerC = inb_cmos( 0xC ); + + if( ( registerB & 0x60 ) != 0 ) { + if( ( registerC & 0x20 ) != 0 ) { + // Handle Alarm Interrupt. +ASM_START + sti + int #0x4a + cli +ASM_END + } + if( ( registerC & 0x40 ) != 0 ) { + // Handle Periodic Interrupt. + + if( read_byte( 0x40, 0xA0 ) != 0 ) { + // Wait Interval (Int 15, AH=83) active. + Bit32u time, toggle; + + time = read_dword( 0x40, 0x9C ); // Time left in microseconds. + if( time < 0x3D1 ) { + // Done waiting. + Bit16u segment, offset; + + offset = read_word( 0x40, 0x98 ); + segment = read_word( 0x40, 0x9A ); + write_byte( 0x40, 0xA0, 0 ); // Turn of status byte. + outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt. + write_byte( segment, offset, 0x80 ); // Write to specified flag byte. + } else { + // Continue waiting. + time -= 0x3D1; + write_dword( 0x40, 0x9C, time ); + } + } + } + } + +ASM_START + call eoi_both_pics +ASM_END +} + + +ASM_START +;------------------------------------------ +;- INT74h : PS/2 mouse hardware interrupt - +;------------------------------------------ +int74_handler: + sti + pusha + push ds ;; save DS + push #0x00 ;; placeholder for status + push #0x00 ;; placeholder for X + push #0x00 ;; placeholder for Y + push #0x00 ;; placeholder for Z + push #0x00 ;; placeholder for make_far_call boolean + call _int74_function + pop cx ;; remove make_far_call from stack + jcxz int74_done + + ;; make far call to EBDA:0022 + push #0x00 + pop ds + push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04) + pop ds + //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00) + call far ptr[0x22] +int74_done: + cli + call eoi_both_pics + add sp, #8 ;; pop status, x, y, z + + pop ds ;; restore DS + popa + iret + + +;; This will perform an IRET, but will retain value of current CF +;; by altering flags on stack. Better than RETF #02. +iret_modify_cf: + jc carry_set + push bp + mov bp, sp + and BYTE [bp + 0x06], #0xfe + pop bp + iret +carry_set: + push bp + mov bp, sp + or BYTE [bp + 0x06], #0x01 + pop bp + iret + + +;---------------------- +;- INT13h (relocated) - +;---------------------- +; +; int13_relocated is a little bit messed up since I played with it +; I have to rewrite it: +; - call a function that detect which function to call +; - make all called C function get the same parameters list +; +int13_relocated: + +#if BX_ELTORITO_BOOT + ;; check for an eltorito function + cmp ah,#0x4a + jb int13_not_eltorito + cmp ah,#0x4d + ja int13_not_eltorito + + pusha + push es + push ds + push ss + pop ds + + push #int13_out + jmp _int13_eltorito ;; ELDX not used + +int13_not_eltorito: + push ax + push bx + push cx + push dx + + ;; check if emulation active + call _cdemu_isactive + cmp al,#0x00 + je int13_cdemu_inactive + + ;; check if access to the emulated drive + call _cdemu_emulated_drive + pop dx + push dx + cmp al,dl ;; int13 on emulated drive + jne int13_nocdemu + + pop dx + pop cx + pop bx + pop ax + + pusha + push es + push ds + push ss + pop ds + + push #int13_out + jmp _int13_cdemu ;; ELDX not used + +int13_nocdemu: + and dl,#0xE0 ;; mask to get device class, including cdroms + cmp al,dl ;; al is 0x00 or 0x80 + jne int13_cdemu_inactive ;; inactive for device class + + pop dx + pop cx + pop bx + pop ax + + push ax + push cx + push dx + push bx + + dec dl ;; real drive is dl - 1 + jmp int13_legacy + +int13_cdemu_inactive: + pop dx + pop cx + pop bx + pop ax + +#endif // BX_ELTORITO_BOOT + +int13_noeltorito: + + push ax + push cx + push dx + push bx + +int13_legacy: + + push dx ;; push eltorito value of dx instead of sp + + push bp + push si + push di + + push es + push ds + push ss + pop ds + + ;; now the 16-bit registers can be restored with: + ;; pop ds; pop es; popa; iret + ;; arguments passed to functions should be + ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS + + test dl, #0x80 + jnz int13_notfloppy + + push #int13_out + jmp _int13_diskette_function + +int13_notfloppy: + +#if BX_USE_ATADRV + + cmp dl, #0xE0 + jb int13_notcdrom + + // ebx is modified: BSD 5.2.1 boot loader problem + // someone should figure out which 32 bit register that actually are used + + shr ebx, #16 + push bx + + call _int13_cdrom + + pop bx + shl ebx, #16 + + jmp int13_out + +int13_notcdrom: + +#endif + +int13_disk: + call _int13_harddisk + +int13_out: + pop ds + pop es + popa + iret + + +;---------- +;- INT18h - +;---------- +int18_handler: ;; Boot Failure routing + call _int18_panic_msg + hlt + iret + +;---------- +;- INT19h - +;---------- +int19_relocated: ;; Boot function, relocated + + ;; int19 was beginning to be really complex, so now it + ;; just calls an C function, that does the work + ;; it returns in BL the boot drive, and in AX the boot segment + ;; the boot segment will be 0x0000 if something has failed + + push bp + mov bp, sp + + ;; drop ds + xor ax, ax + mov ds, ax + + ;; 1st boot device + mov ax, #0x0001 + push ax + call _int19_function + inc sp + inc sp + ;; bl contains the boot drive + ;; ax contains the boot segment or 0 if failure + + test ax, ax ;; if ax is 0 try next boot device + jnz boot_setup + + ;; 2nd boot device + mov ax, #0x0002 + push ax + call _int19_function + inc sp + inc sp + test ax, ax ;; if ax is 0 try next boot device + jnz boot_setup + + ;; 3rd boot device + mov ax, #0x0003 + push ax + call _int19_function + inc sp + inc sp + test ax, ax ;; if ax is 0 call int18 + jz int18_handler + +boot_setup: + mov dl, bl ;; set drive so guest os find it + shl eax, #0x04 ;; convert seg to ip + mov 2[bp], ax ;; set ip + + shr eax, #0x04 ;; get cs back + and ax, #0xF000 ;; remove what went in ip + mov 4[bp], ax ;; set cs + xor ax, ax + mov es, ax ;; set es to zero fixes [ 549815 ] + mov [bp], ax ;; set bp to zero + mov ax, #0xaa55 ;; set ok flag + + pop bp + iret ;; Beam me up Scotty + +;---------- +;- INT1Ch - +;---------- +int1c_handler: ;; User Timer Tick + iret + + +;---------------------- +;- POST: Floppy Drive - +;---------------------- +floppy_drive_post: + mov ax, #0x0000 + mov ds, ax + + mov al, #0x00 + mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred + + mov 0x043f, al ;; diskette motor status: read op, drive0, motors off + + mov 0x0440, al ;; diskette motor timeout counter: not active + mov 0x0441, al ;; diskette controller status return code + + mov 0x0442, al ;; disk & diskette controller status register 0 + mov 0x0443, al ;; diskette controller status register 1 + mov 0x0444, al ;; diskette controller status register 2 + mov 0x0445, al ;; diskette controller cylinder number + mov 0x0446, al ;; diskette controller head number + mov 0x0447, al ;; diskette controller sector number + mov 0x0448, al ;; diskette controller bytes written + + mov 0x048b, al ;; diskette configuration data + + ;; ----------------------------------------------------------------- + ;; (048F) diskette controller information + ;; + mov al, #0x10 ;; get CMOS diskette drive type + out 0x70, AL + in AL, 0x71 + mov ah, al ;; save byte to AH + +look_drive0: + shr al, #4 ;; look at top 4 bits for drive 0 + jz f0_missing ;; jump if no drive0 + mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line + jmp look_drive1 +f0_missing: + mov bl, #0x00 ;; no drive0 + +look_drive1: + mov al, ah ;; restore from AH + and al, #0x0f ;; look at bottom 4 bits for drive 1 + jz f1_missing ;; jump if no drive1 + or bl, #0x70 ;; drive1 determined, multi-rate, has changed line +f1_missing: + ;; leave high bits in BL zerod + mov 0x048f, bl ;; put new val in BDA (diskette controller information) + ;; ----------------------------------------------------------------- + + mov al, #0x00 + mov 0x0490, al ;; diskette 0 media state + mov 0x0491, al ;; diskette 1 media state + + ;; diskette 0,1 operational starting state + ;; drive type has not been determined, + ;; has no changed detection line + mov 0x0492, al + mov 0x0493, al + + mov 0x0494, al ;; diskette 0 current cylinder + mov 0x0495, al ;; diskette 1 current cylinder + + mov al, #0x02 + out #0x0a, al ;; clear DMA-1 channel 2 mask bit + + SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2) + SET_INT_VECTOR(0x40, #0xF000, #int13_diskette) + SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6 + + ret + + +;-------------------- +;- POST: HARD DRIVE - +;-------------------- +; relocated here because the primary POST area isnt big enough. +hard_drive_post: + // IRQ 14 = INT 76h + // INT 76h calls INT 15h function ax=9100 + + mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14 + mov dx, #0x03f6 + out dx, al + + mov ax, #0x0000 + mov ds, ax + mov 0x0474, al /* hard disk status of last operation */ + mov 0x0477, al /* hard disk port offset (XT only ???) */ + mov 0x048c, al /* hard disk status register */ + mov 0x048d, al /* hard disk error register */ + mov 0x048e, al /* hard disk task complete flag */ + mov al, #0x01 + mov 0x0475, al /* hard disk number attached */ + mov al, #0xc0 + mov 0x0476, al /* hard disk control byte */ + SET_INT_VECTOR(0x13, #0xF000, #int13_handler) + SET_INT_VECTOR(0x76, #0xF000, #int76_handler) + ;; INT 41h: hard disk 0 configuration pointer + ;; INT 46h: hard disk 1 configuration pointer + SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D) + SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D) + + ;; move disk geometry data from CMOS to EBDA disk parameter table(s) + mov al, #0x12 + out #0x70, al + in al, #0x71 + and al, #0xf0 + cmp al, #0xf0 + je post_d0_extended + jmp check_for_hd1 +post_d0_extended: + mov al, #0x19 + out #0x70, al + in al, #0x71 + cmp al, #47 ;; decimal 47 - user definable + je post_d0_type47 + HALT(__LINE__) +post_d0_type47: + ;; CMOS purpose param table offset + ;; 1b cylinders low 0 + ;; 1c cylinders high 1 + ;; 1d heads 2 + ;; 1e write pre-comp low 5 + ;; 1f write pre-comp high 6 + ;; 20 retries/bad map/heads>8 8 + ;; 21 landing zone low C + ;; 22 landing zone high D + ;; 23 sectors/track E + + mov ax, #EBDA_SEG + mov ds, ax + + ;;; Filling EBDA table for hard disk 0. + mov al, #0x1f + out #0x70, al + in al, #0x71 + mov ah, al + mov al, #0x1e + out #0x70, al + in al, #0x71 + mov (0x003d + 0x05), ax ;; write precomp word + + mov al, #0x20 + out #0x70, al + in al, #0x71 + mov (0x003d + 0x08), al ;; drive control byte + + mov al, #0x22 + out #0x70, al + in al, #0x71 + mov ah, al + mov al, #0x21 + out #0x70, al + in al, #0x71 + mov (0x003d + 0x0C), ax ;; landing zone word + + mov al, #0x1c ;; get cylinders word in AX + out #0x70, al + in al, #0x71 ;; high byte + mov ah, al + mov al, #0x1b + out #0x70, al + in al, #0x71 ;; low byte + mov bx, ax ;; BX = cylinders + + mov al, #0x1d + out #0x70, al + in al, #0x71 + mov cl, al ;; CL = heads + + mov al, #0x23 + out #0x70, al + in al, #0x71 + mov dl, al ;; DL = sectors + + cmp bx, #1024 + jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS + +hd0_post_physical_chs: + ;; no logical CHS mapping used, just physical CHS + ;; use Standard Fixed Disk Parameter Table (FDPT) + mov (0x003d + 0x00), bx ;; number of physical cylinders + mov (0x003d + 0x02), cl ;; number of physical heads + mov (0x003d + 0x0E), dl ;; number of physical sectors + jmp check_for_hd1 + +hd0_post_logical_chs: + ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT) + mov (0x003d + 0x09), bx ;; number of physical cylinders + mov (0x003d + 0x0b), cl ;; number of physical heads + mov (0x003d + 0x04), dl ;; number of physical sectors + mov (0x003d + 0x0e), dl ;; number of logical sectors (same) + mov al, #0xa0 + mov (0x003d + 0x03), al ;; A0h signature, indicates translated table + + cmp bx, #2048 + jnbe hd0_post_above_2048 + ;; 1024 < c <= 2048 cylinders + shr bx, #0x01 + shl cl, #0x01 + jmp hd0_post_store_logical + +hd0_post_above_2048: + cmp bx, #4096 + jnbe hd0_post_above_4096 + ;; 2048 < c <= 4096 cylinders + shr bx, #0x02 + shl cl, #0x02 + jmp hd0_post_store_logical + +hd0_post_above_4096: + cmp bx, #8192 + jnbe hd0_post_above_8192 + ;; 4096 < c <= 8192 cylinders + shr bx, #0x03 + shl cl, #0x03 + jmp hd0_post_store_logical + +hd0_post_above_8192: + ;; 8192 < c <= 16384 cylinders + shr bx, #0x04 + shl cl, #0x04 + +hd0_post_store_logical: + mov (0x003d + 0x00), bx ;; number of physical cylinders + mov (0x003d + 0x02), cl ;; number of physical heads + ;; checksum + mov cl, #0x0f ;; repeat count + mov si, #0x003d ;; offset to disk0 FDPT + mov al, #0x00 ;; sum +hd0_post_checksum_loop: + add al, [si] + inc si + dec cl + jnz hd0_post_checksum_loop + not al ;; now take 2s complement + inc al + mov [si], al +;;; Done filling EBDA table for hard disk 0. + + +check_for_hd1: + ;; is there really a second hard disk? if not, return now + mov al, #0x12 + out #0x70, al + in al, #0x71 + and al, #0x0f + jnz post_d1_exists + ret +post_d1_exists: + ;; check that the hd type is really 0x0f. + cmp al, #0x0f + jz post_d1_extended + HALT(__LINE__) +post_d1_extended: + ;; check that the extended type is 47 - user definable + mov al, #0x1a + out #0x70, al + in al, #0x71 + cmp al, #47 ;; decimal 47 - user definable + je post_d1_type47 + HALT(__LINE__) +post_d1_type47: + ;; Table for disk1. + ;; CMOS purpose param table offset + ;; 0x24 cylinders low 0 + ;; 0x25 cylinders high 1 + ;; 0x26 heads 2 + ;; 0x27 write pre-comp low 5 + ;; 0x28 write pre-comp high 6 + ;; 0x29 heads>8 8 + ;; 0x2a landing zone low C + ;; 0x2b landing zone high D + ;; 0x2c sectors/track E +;;; Fill EBDA table for hard disk 1. + mov ax, #EBDA_SEG + mov ds, ax + mov al, #0x28 + out #0x70, al + in al, #0x71 + mov ah, al + mov al, #0x27 + out #0x70, al + in al, #0x71 + mov (0x004d + 0x05), ax ;; write precomp word + + mov al, #0x29 + out #0x70, al + in al, #0x71 + mov (0x004d + 0x08), al ;; drive control byte + + mov al, #0x2b + out #0x70, al + in al, #0x71 + mov ah, al + mov al, #0x2a + out #0x70, al + in al, #0x71 + mov (0x004d + 0x0C), ax ;; landing zone word + + mov al, #0x25 ;; get cylinders word in AX + out #0x70, al + in al, #0x71 ;; high byte + mov ah, al + mov al, #0x24 + out #0x70, al + in al, #0x71 ;; low byte + mov bx, ax ;; BX = cylinders + + mov al, #0x26 + out #0x70, al + in al, #0x71 + mov cl, al ;; CL = heads + + mov al, #0x2c + out #0x70, al + in al, #0x71 + mov dl, al ;; DL = sectors + + cmp bx, #1024 + jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS + +hd1_post_physical_chs: + ;; no logical CHS mapping used, just physical CHS + ;; use Standard Fixed Disk Parameter Table (FDPT) + mov (0x004d + 0x00), bx ;; number of physical cylinders + mov (0x004d + 0x02), cl ;; number of physical heads + mov (0x004d + 0x0E), dl ;; number of physical sectors + ret + +hd1_post_logical_chs: + ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT) + mov (0x004d + 0x09), bx ;; number of physical cylinders + mov (0x004d + 0x0b), cl ;; number of physical heads + mov (0x004d + 0x04), dl ;; number of physical sectors + mov (0x004d + 0x0e), dl ;; number of logical sectors (same) + mov al, #0xa0 + mov (0x004d + 0x03), al ;; A0h signature, indicates translated table + + cmp bx, #2048 + jnbe hd1_post_above_2048 + ;; 1024 < c <= 2048 cylinders + shr bx, #0x01 + shl cl, #0x01 + jmp hd1_post_store_logical + +hd1_post_above_2048: + cmp bx, #4096 + jnbe hd1_post_above_4096 + ;; 2048 < c <= 4096 cylinders + shr bx, #0x02 + shl cl, #0x02 + jmp hd1_post_store_logical + +hd1_post_above_4096: + cmp bx, #8192 + jnbe hd1_post_above_8192 + ;; 4096 < c <= 8192 cylinders + shr bx, #0x03 + shl cl, #0x03 + jmp hd1_post_store_logical + +hd1_post_above_8192: + ;; 8192 < c <= 16384 cylinders + shr bx, #0x04 + shl cl, #0x04 + +hd1_post_store_logical: + mov (0x004d + 0x00), bx ;; number of physical cylinders + mov (0x004d + 0x02), cl ;; number of physical heads + ;; checksum + mov cl, #0x0f ;; repeat count + mov si, #0x004d ;; offset to disk0 FDPT + mov al, #0x00 ;; sum +hd1_post_checksum_loop: + add al, [si] + inc si + dec cl + jnz hd1_post_checksum_loop + not al ;; now take 2s complement + inc al + mov [si], al +;;; Done filling EBDA table for hard disk 1. + + ret + +;-------------------- +;- POST: EBDA segment +;-------------------- +; relocated here because the primary POST area isnt big enough. +ebda_post: +#if BX_USE_EBDA + mov ax, #EBDA_SEG + mov ds, ax + mov byte ptr [0x0], #EBDA_SIZE +#endif + xor ax, ax ; mov EBDA seg into 40E + mov ds, ax + mov word ptr [0x40E], #EBDA_SEG + ret;; + +;-------------------- +;- POST: EOI + jmp via [0x40:67) +;-------------------- +; relocated here because the primary POST area isnt big enough. +eoi_jmp_post: + call eoi_both_pics + + xor ax, ax + mov ds, ax + + jmp far ptr [0x467] + + +;-------------------- +eoi_both_pics: + mov al, #0x20 + out #0xA0, al ;; slave PIC EOI +eoi_master_pic: + mov al, #0x20 + out #0x20, al ;; master PIC EOI + ret + +;-------------------- +BcdToBin: + ;; in: AL in BCD format + ;; out: AL in binary format, AH will always be 0 + ;; trashes BX + mov bl, al + and bl, #0x0f ;; bl has low digit + shr al, #4 ;; al has high digit + mov bh, #10 + mul al, bh ;; multiply high digit by 10 (result in AX) + add al, bl ;; then add low digit + ret + +;-------------------- +timer_tick_post: + ;; Setup the Timer Ticks Count (0x46C:dword) and + ;; Timer Ticks Roller Flag (0x470:byte) + ;; The Timer Ticks Count needs to be set according to + ;; the current CMOS time, as if ticks have been occurring + ;; at 18.2hz since midnight up to this point. Calculating + ;; this is a little complicated. Here are the factors I gather + ;; regarding this. 14,318,180 hz was the original clock speed, + ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU + ;; at the time, or 4 to drive the CGA video adapter. The div3 + ;; source was divided again by 4 to feed a 1.193Mhz signal to + ;; the timer. With a maximum 16bit timer count, this is again + ;; divided down by 65536 to 18.2hz. + ;; + ;; 14,318,180 Hz clock + ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU + ;; /4 = 1,193,181 Hz fed to timer + ;; /65536 (maximum timer count) = 18.20650736 ticks/second + ;; 1 second = 18.20650736 ticks + ;; 1 minute = 1092.390442 ticks + ;; 1 hour = 65543.42651 ticks + ;; + ;; Given the values in the CMOS clock, one could calculate + ;; the number of ticks by the following: + ;; ticks = (BcdToBin(seconds) * 18.206507) + + ;; (BcdToBin(minutes) * 1092.3904) + ;; (BcdToBin(hours) * 65543.427) + ;; To get a little more accuracy, since Im using integer + ;; arithmatic, I use: + ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 + + ;; (BcdToBin(minutes) * 10923904) / 10000 + + ;; (BcdToBin(hours) * 65543427) / 1000 + + ;; assuming DS=0000 + + ;; get CMOS seconds + xor eax, eax ;; clear EAX + mov al, #0x00 + out #0x70, al + in al, #0x71 ;; AL has CMOS seconds in BCD + call BcdToBin ;; EAX now has seconds in binary + mov edx, #18206507 + mul eax, edx + mov ebx, #1000000 + xor edx, edx + div eax, ebx + mov ecx, eax ;; ECX will accumulate total ticks + + ;; get CMOS minutes + xor eax, eax ;; clear EAX + mov al, #0x02 + out #0x70, al + in al, #0x71 ;; AL has CMOS minutes in BCD + call BcdToBin ;; EAX now has minutes in binary + mov edx, #10923904 + mul eax, edx + mov ebx, #10000 + xor edx, edx + div eax, ebx + add ecx, eax ;; add to total ticks + + ;; get CMOS hours + xor eax, eax ;; clear EAX + mov al, #0x04 + out #0x70, al + in al, #0x71 ;; AL has CMOS hours in BCD + call BcdToBin ;; EAX now has hours in binary + mov edx, #65543427 + mul eax, edx + mov ebx, #1000 + xor edx, edx + div eax, ebx + add ecx, eax ;; add to total ticks + + mov 0x46C, ecx ;; Timer Ticks Count + xor al, al + mov 0x470, al ;; Timer Ticks Rollover Flag + ret + +;-------------------- +int76_handler: + ;; record completion in BIOS task complete flag + push ax + push ds + mov ax, #0x0040 + mov ds, ax + mov 0x008E, #0xff + call eoi_both_pics + pop ds + pop ax + iret + + +;-------------------- +#if BX_APM + +use32 386 +#define APM_PROT32 +#include "apmbios.S" + +use16 386 +#define APM_PROT16 +#include "apmbios.S" + +#define APM_REAL +#include "apmbios.S" + +#endif + +;-------------------- +#if BX_PCIBIOS +use32 386 +.align 16 +bios32_structure: + db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature + dw bios32_entry_point, 0xf ;; 32 bit physical address + db 0 ;; revision level + ;; length in paragraphs and checksum stored in a word to prevent errors + dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \ + & 0xff) << 8) + 0x01 + db 0,0,0,0,0 ;; reserved + +.align 16 +bios32_entry_point: + pushf + cmp eax, #0x49435024 + jne unknown_service + mov eax, #0x80000000 + mov dx, #0x0cf8 + out dx, eax + mov dx, #0x0cfc + in eax, dx + cmp eax, #0x12378086 + jne unknown_service + mov ebx, #0x000f0000 + mov ecx, #0 + mov edx, #pcibios_protected + xor al, al + jmp bios32_end +unknown_service: + mov al, #0x80 +bios32_end: + popf + retf + +.align 16 +pcibios_protected: + pushf + cli + push esi + push edi + cmp al, #0x01 ;; installation check + jne pci_pro_f02 + mov bx, #0x0210 + mov cx, #0 + mov edx, #0x20494350 + mov al, #0x01 + jmp pci_pro_ok +pci_pro_f02: ;; find pci device + cmp al, #0x02 + jne pci_pro_f08 + shl ecx, #16 + mov cx, dx + mov bx, #0x0000 + mov di, #0x00 +pci_pro_devloop: + call pci_pro_select_reg + mov dx, #0x0cfc + in eax, dx + cmp eax, ecx + jne pci_pro_nextdev + cmp si, #0 + je pci_pro_ok + dec si +pci_pro_nextdev: + inc bx + cmp bx, #0x0100 + jne pci_pro_devloop + mov ah, #0x86 + jmp pci_pro_fail +pci_pro_f08: ;; read configuration byte + cmp al, #0x08 + jne pci_pro_f09 + call pci_pro_select_reg + push edx + mov dx, di + and dx, #0x03 + add dx, #0x0cfc + in al, dx + pop edx + mov cl, al + jmp pci_pro_ok +pci_pro_f09: ;; read configuration word + cmp al, #0x09 + jne pci_pro_f0a + call pci_pro_select_reg + push edx + mov dx, di + and dx, #0x02 + add dx, #0x0cfc + in ax, dx + pop edx + mov cx, ax + jmp pci_pro_ok +pci_pro_f0a: ;; read configuration dword + cmp al, #0x0a + jne pci_pro_f0b + call pci_pro_select_reg + push edx + mov dx, #0x0cfc + in eax, dx + pop edx + mov ecx, eax + jmp pci_pro_ok +pci_pro_f0b: ;; write configuration byte + cmp al, #0x0b + jne pci_pro_f0c + call pci_pro_select_reg + push edx + mov dx, di + and dx, #0x03 + add dx, #0x0cfc + mov al, cl + out dx, al + pop edx + jmp pci_pro_ok +pci_pro_f0c: ;; write configuration word + cmp al, #0x0c + jne pci_pro_f0d + call pci_pro_select_reg + push edx + mov dx, di + and dx, #0x02 + add dx, #0x0cfc + mov ax, cx + out dx, ax + pop edx + jmp pci_pro_ok +pci_pro_f0d: ;; write configuration dword + cmp al, #0x0d + jne pci_pro_unknown + call pci_pro_select_reg + push edx + mov dx, #0x0cfc + mov eax, ecx + out dx, eax + pop edx + jmp pci_pro_ok +pci_pro_unknown: + mov ah, #0x81 +pci_pro_fail: + pop edi + pop esi + sti + popf + stc + retf +pci_pro_ok: + xor ah, ah + pop edi + pop esi + sti + popf + clc + retf + +pci_pro_select_reg: + push edx + mov eax, #0x800000 + mov ax, bx + shl eax, #8 + and di, #0xff + or ax, di + and al, #0xfc + mov dx, #0x0cf8 + out dx, eax + pop edx + ret + +use16 386 + +pcibios_real: + push eax + push dx + mov eax, #0x80000000 + mov dx, #0x0cf8 + out dx, eax + mov dx, #0x0cfc + in eax, dx + cmp eax, #0x12378086 + je pci_present + pop dx + pop eax + mov ah, #0xff + stc + ret +pci_present: + pop dx + pop eax + cmp al, #0x01 ;; installation check + jne pci_real_f02 + mov ax, #0x0001 + mov bx, #0x0210 + mov cx, #0 + mov edx, #0x20494350 + mov edi, #0xf0000 + mov di, #pcibios_protected + clc + ret +pci_real_f02: ;; find pci device + push esi + push edi + cmp al, #0x02 + jne pci_real_f08 + shl ecx, #16 + mov cx, dx + mov bx, #0x0000 + mov di, #0x00 +pci_real_devloop: + call pci_real_select_reg + mov dx, #0x0cfc + in eax, dx + cmp eax, ecx + jne pci_real_nextdev + cmp si, #0 + je pci_real_ok + dec si +pci_real_nextdev: + inc bx + cmp bx, #0x0100 + jne pci_real_devloop + mov dx, cx + shr ecx, #16 + mov ah, #0x86 + jmp pci_real_fail +pci_real_f08: ;; read configuration byte + cmp al, #0x08 + jne pci_real_f09 + call pci_real_select_reg + push dx + mov dx, di + and dx, #0x03 + add dx, #0x0cfc + in al, dx + pop dx + mov cl, al + jmp pci_real_ok +pci_real_f09: ;; read configuration word + cmp al, #0x09 + jne pci_real_f0a + call pci_real_select_reg + push dx + mov dx, di + and dx, #0x02 + add dx, #0x0cfc + in ax, dx + pop dx + mov cx, ax + jmp pci_real_ok +pci_real_f0a: ;; read configuration dword + cmp al, #0x0a + jne pci_real_f0b + call pci_real_select_reg + push dx + mov dx, #0x0cfc + in eax, dx + pop dx + mov ecx, eax + jmp pci_real_ok +pci_real_f0b: ;; write configuration byte + cmp al, #0x0b + jne pci_real_f0c + call pci_real_select_reg + push dx + mov dx, di + and dx, #0x03 + add dx, #0x0cfc + mov al, cl + out dx, al + pop dx + jmp pci_real_ok +pci_real_f0c: ;; write configuration word + cmp al, #0x0c + jne pci_real_f0d + call pci_real_select_reg + push dx + mov dx, di + and dx, #0x02 + add dx, #0x0cfc + mov ax, cx + out dx, ax + pop dx + jmp pci_real_ok +pci_real_f0d: ;; write configuration dword + cmp al, #0x0d + jne pci_real_unknown + call pci_real_select_reg + push dx + mov dx, #0x0cfc + mov eax, ecx + out dx, eax + pop dx + jmp pci_real_ok +pci_real_unknown: + mov ah, #0x81 +pci_real_fail: + pop edi + pop esi + stc + ret +pci_real_ok: + xor ah, ah + pop edi + pop esi + clc + ret + +pci_real_select_reg: + push dx + mov eax, #0x800000 + mov ax, bx + shl eax, #8 + and di, #0xff + or ax, di + and al, #0xfc + mov dx, #0x0cf8 + out dx, eax + pop dx + ret + +.align 16 +pci_routing_table_structure: + db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature + db 0, 1 ;; version + dw 32 + (6 * 16) ;; table size + db 0 ;; PCI interrupt router bus + db 0x08 ;; PCI interrupt router DevFunc + dw 0x0000 ;; PCI exclusive IRQs + dw 0x8086 ;; compatible PCI interrupt router vendor ID + dw 0x7000 ;; compatible PCI interrupt router device ID + dw 0,0 ;; Miniport data + db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved + db 0x07 ;; checksum + ;; first slot entry PCI-to-ISA (embedded) + db 0 ;; pci bus number + db 0x08 ;; pci device number (bit 7-3) + db 0x60 ;; link value INTA#: pointer into PCI2ISA config space + dw 0xdef8 ;; IRQ bitmap INTA# + db 0x61 ;; link value INTB# + dw 0xdef8 ;; IRQ bitmap INTB# + db 0x62 ;; link value INTC# + dw 0xdef8 ;; IRQ bitmap INTC# + db 0x63 ;; link value INTD# + dw 0xdef8 ;; IRQ bitmap INTD# + db 0 ;; physical slot (0 = embedded) + db 0 ;; reserved + ;; second slot entry: 1st PCI slot + db 0 ;; pci bus number + db 0x10 ;; pci device number (bit 7-3) + db 0x61 ;; link value INTA# + dw 0xdef8 ;; IRQ bitmap INTA# + db 0x62 ;; link value INTB# + dw 0xdef8 ;; IRQ bitmap INTB# + db 0x63 ;; link value INTC# + dw 0xdef8 ;; IRQ bitmap INTC# + db 0x60 ;; link value INTD# + dw 0xdef8 ;; IRQ bitmap INTD# + db 1 ;; physical slot (0 = embedded) + db 0 ;; reserved + ;; third slot entry: 2nd PCI slot + db 0 ;; pci bus number + db 0x18 ;; pci device number (bit 7-3) + db 0x62 ;; link value INTA# + dw 0xdef8 ;; IRQ bitmap INTA# + db 0x63 ;; link value INTB# + dw 0xdef8 ;; IRQ bitmap INTB# + db 0x60 ;; link value INTC# + dw 0xdef8 ;; IRQ bitmap INTC# + db 0x61 ;; link value INTD# + dw 0xdef8 ;; IRQ bitmap INTD# + db 2 ;; physical slot (0 = embedded) + db 0 ;; reserved + ;; 4th slot entry: 3rd PCI slot + db 0 ;; pci bus number + db 0x20 ;; pci device number (bit 7-3) + db 0x63 ;; link value INTA# + dw 0xdef8 ;; IRQ bitmap INTA# + db 0x60 ;; link value INTB# + dw 0xdef8 ;; IRQ bitmap INTB# + db 0x61 ;; link value INTC# + dw 0xdef8 ;; IRQ bitmap INTC# + db 0x62 ;; link value INTD# + dw 0xdef8 ;; IRQ bitmap INTD# + db 3 ;; physical slot (0 = embedded) + db 0 ;; reserved + ;; 5th slot entry: 4rd PCI slot + db 0 ;; pci bus number + db 0x28 ;; pci device number (bit 7-3) + db 0x60 ;; link value INTA# + dw 0xdef8 ;; IRQ bitmap INTA# + db 0x61 ;; link value INTB# + dw 0xdef8 ;; IRQ bitmap INTB# + db 0x62 ;; link value INTC# + dw 0xdef8 ;; IRQ bitmap INTC# + db 0x63 ;; link value INTD# + dw 0xdef8 ;; IRQ bitmap INTD# + db 4 ;; physical slot (0 = embedded) + db 0 ;; reserved + ;; 6th slot entry: 5rd PCI slot + db 0 ;; pci bus number + db 0x30 ;; pci device number (bit 7-3) + db 0x61 ;; link value INTA# + dw 0xdef8 ;; IRQ bitmap INTA# + db 0x62 ;; link value INTB# + dw 0xdef8 ;; IRQ bitmap INTB# + db 0x63 ;; link value INTC# + dw 0xdef8 ;; IRQ bitmap INTC# + db 0x60 ;; link value INTD# + dw 0xdef8 ;; IRQ bitmap INTD# + db 5 ;; physical slot (0 = embedded) + db 0 ;; reserved + +pci_irq_list: + db 11, 10, 9, 5; + +pcibios_init_sel_reg: + push eax + mov eax, #0x800000 + mov ax, bx + shl eax, #8 + and dl, #0xfc + or al, dl + mov dx, #0x0cf8 + out dx, eax + pop eax + ret + +pcibios_init_set_elcr: + push ax + push cx + mov dx, #0x04d0 + test al, #0x08 + jz is_master_pic + inc dx + and al, #0x07 +is_master_pic: + mov cl, al + mov bl, #0x01 + shl bl, cl + in al, dx + or al, bl + out dx, al + pop cx + pop ax + ret + +pcibios_init: + push ds + push bp + mov ax, #0xf000 + mov ds, ax + mov dx, #0x04d0 ;; reset ELCR1 + ELCR2 + mov al, #0x00 + out dx, al + inc dx + out dx, al + mov si, #pci_routing_table_structure + mov bh, [si+8] + mov bl, [si+9] + mov dl, #0x00 + call pcibios_init_sel_reg + mov dx, #0x0cfc + in eax, dx + cmp eax, [si+12] ;; check irq router + jne pci_init_end + mov dl, [si+34] + call pcibios_init_sel_reg + push bx ;; save irq router bus + devfunc + mov dx, #0x0cfc + mov ax, #0x8080 + out dx, ax ;; reset PIRQ route control + inc dx + inc dx + out dx, ax + mov ax, [si+6] + sub ax, #0x20 + shr ax, #4 + mov cx, ax + add si, #0x20 ;; set pointer to 1st entry + mov bp, sp + mov ax, #pci_irq_list + push ax + xor ax, ax + push ax +pci_init_loop1: + mov bh, [si] + mov bl, [si+1] +pci_init_loop2: + mov dl, #0x00 + call pcibios_init_sel_reg + mov dx, #0x0cfc + in ax, dx + cmp ax, #0xffff + jnz pci_test_int_pin + test bl, #0x07 + jz next_pir_entry + jmp next_pci_func +pci_test_int_pin: + mov dl, #0x3c + call pcibios_init_sel_reg + mov dx, #0x0cfd + in al, dx + and al, #0x07 + jz next_pci_func + dec al ;; determine pirq reg + mov dl, #0x03 + mul al, dl + add al, #0x02 + xor ah, ah + mov bx, ax + mov al, [si+bx] + mov dl, al + mov bx, [bp] + call pcibios_init_sel_reg + mov dx, #0x0cfc + and al, #0x03 + add dl, al + in al, dx + cmp al, #0x80 + jb pirq_found + mov bx, [bp-2] ;; pci irq list pointer + mov al, [bx] + out dx, al + inc bx + mov [bp-2], bx + call pcibios_init_set_elcr +pirq_found: + mov bh, [si] + mov bl, [si+1] + add bl, [bp-3] ;; pci function number + mov dl, #0x3c + call pcibios_init_sel_reg + mov dx, #0x0cfc + out dx, al +next_pci_func: + inc byte ptr[bp-3] + inc bl + test bl, #0x07 + jnz pci_init_loop2 +next_pir_entry: + add si, #0x10 + mov byte ptr[bp-3], #0x00 + loop pci_init_loop1 + mov sp, bp + pop bx +pci_init_end: + pop bp + pop ds + ret +#endif // BX_PCIBIOS + +; parallel port detection: base address in DX, index in BX, timeout in CL +detect_parport: + push dx + add dx, #2 + in al, dx + and al, #0xdf ; clear input mode + out dx, al + pop dx + mov al, #0xaa + out dx, al + in al, dx + cmp al, #0xaa + jne no_parport + push bx + shl bx, #1 + mov [bx+0x408], dx ; Parallel I/O address + pop bx + mov [bx+0x478], cl ; Parallel printer timeout + inc bx +no_parport: + ret + +; serial port detection: base address in DX, index in BX, timeout in CL +detect_serial: +; no serial port in the VM -PAD + ret + + push dx + inc dx + mov al, #0x02 + out dx, al + in al, dx + cmp al, #0x02 + jne no_serial + inc dx + in al, dx + cmp al, #0x02 + jne no_serial + dec dx + xor al, al + out dx, al + pop dx + push bx + shl bx, #1 + mov [bx+0x400], dx ; Serial I/O address + pop bx + mov [bx+0x47c], cl ; Serial timeout + inc bx + ret +no_serial: + pop dx + ret + +rom_checksum: + push ax + push bx + push cx + xor ax, ax + xor bx, bx + xor cx, cx + mov ch, [2] + shl cx, #1 +checksum_loop: + add al, [bx] + inc bx + loop checksum_loop + and al, #0xff + pop cx + pop bx + pop ax + ret + +rom_scan: + ;; Scan for existence of valid expansion ROMS. + ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments + ;; General ROM: from 0xC8000..0xDFFFF in 2k increments + ;; System ROM: only 0xE0000 + ;; + ;; Header: + ;; Offset Value + ;; 0 0x55 + ;; 1 0xAA + ;; 2 ROM length in 512-byte blocks + ;; 3 ROM initialization entry point (FAR CALL) + + mov cx, #0xc000 +rom_scan_loop: + mov ds, cx + mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k + cmp [0], #0xAA55 ;; look for signature + jne rom_scan_increment + call rom_checksum + jnz rom_scan_increment + mov al, [2] ;; change increment to ROM length in 512-byte blocks + + ;; We want our increment in 512-byte quantities, rounded to + ;; the nearest 2k quantity, since we only scan at 2k intervals. + test al, #0x03 + jz block_count_rounded + and al, #0xfc ;; needs rounding up + add al, #0x04 +block_count_rounded: + + xor bx, bx ;; Restore DS back to 0000: + mov ds, bx + push ax ;; Save AX + ;; Push addr of ROM entry point + push cx ;; Push seg + push #0x0003 ;; Push offset + mov bp, sp ;; Call ROM init routine using seg:off on stack + db 0xff ;; call_far ss:[bp+0] + db 0x5e + db 0 + cli ;; In case expansion ROM BIOS turns IF on + add sp, #2 ;; Pop offset value + pop cx ;; Pop seg value (restore CX) + pop ax ;; Restore AX +rom_scan_increment: + shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments + ;; because the segment selector is shifted left 4 bits. + add cx, ax + cmp cx, #0xe000 + jbe rom_scan_loop + + xor ax, ax ;; Restore DS back to 0000: + mov ds, ax + ret + +#ifdef HVMASSIST + +; Copy the SMBIOS entry point over from 0x9f000, where hvmloader left it. +; The entry point must be somewhere in 0xf0000-0xfffff on a 16-byte boundary, +; but the tables themeselves can be elsewhere. +smbios_init: + push ax + push cx + push es + push ds + push di + push si + + mov cx, #0x001f ; 0x1f bytes to copy + mov ax, #0xf000 + mov es, ax ; destination segment is 0xf0000 + mov di, #smbios_entry_point ; destination offset + mov ax, #0x9f00 + mov ds, ax ; source segment is 0x9f000 + mov si, #0x0000 ; source offset is 0 + cld + rep + movsb + + pop si + pop di + pop ds + pop es + pop cx + pop ax + + ret + +#endif + + + +;; for 'C' strings and other data, insert them here with +;; a the following hack: +;; DATA_SEG_DEFS_HERE + + +;-------- +;- POST - +;-------- +.org 0xe05b ; POST Entry Point +post: + + xor ax, ax + + ;; first reset the DMA controllers + out 0x0d,al + out 0xda,al + + ;; then initialize the DMA controllers + mov al, #0xC0 + out 0xD6, al ; cascade mode of channel 4 enabled + mov al, #0x00 + out 0xD4, al ; unmask channel 4 + + ;; Examine CMOS shutdown status. + mov AL, #0x0f + out 0x70, AL + in AL, 0x71 + + ;; backup status + mov bl, al + + ;; Reset CMOS shutdown status. + mov AL, #0x0f + out 0x70, AL ; select CMOS register Fh + mov AL, #0x00 + out 0x71, AL ; set shutdown action to normal + + ;; Examine CMOS shutdown status. + mov al, bl + + ;; 0x00, 0x09, 0x0D+ = normal startup + cmp AL, #0x00 + jz normal_post + cmp AL, #0x0d + jae normal_post + cmp AL, #0x09 + je normal_post + + ;; 0x05 = eoi + jmp via [0x40:0x67] jump + cmp al, #0x05 + je eoi_jmp_post + + ;; Examine CMOS shutdown status. + ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status. + push bx + call _shutdown_status_panic + +#if 0 + HALT(__LINE__) + ; + ;#if 0 + ; 0xb0, 0x20, /* mov al, #0x20 */ + ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */ + ;#endif + ; + pop es + pop ds + popa + iret +#endif + +normal_post: + ; case 0: normal startup + + cli + mov ax, #0xfffe + mov sp, ax + mov ax, #0x0000 + mov ds, ax + mov ss, ax + + ;; zero out BIOS data area (40:00..40:ff) + mov es, ax + mov cx, #0x0080 ;; 128 words + mov di, #0x0400 + cld + rep + stosw + + call _log_bios_start + + ;; set all interrupts to default handler + mov bx, #0x0000 ;; offset index + mov cx, #0x0100 ;; counter (256 interrupts) + mov ax, #dummy_iret_handler + mov dx, #0xF000 + +post_default_ints: + mov [bx], ax + inc bx + inc bx + mov [bx], dx + inc bx + inc bx + loop post_default_ints + + ;; set vector 0x79 to zero + ;; this is used by 'gardian angel' protection system + SET_INT_VECTOR(0x79, #0, #0) + + ;; base memory in K 40:13 (word) + mov ax, #BASE_MEM_IN_K + mov 0x0413, ax + + + ;; Manufacturing Test 40:12 + ;; zerod out above + + ;; Warm Boot Flag 0040:0072 + ;; value of 1234h = skip memory checks + ;; zerod out above + + + ;; Printer Services vector + SET_INT_VECTOR(0x17, #0xF000, #int17_handler) + + ;; Bootstrap failure vector + SET_INT_VECTOR(0x18, #0xF000, #int18_handler) + + ;; Bootstrap Loader vector + SET_INT_VECTOR(0x19, #0xF000, #int19_handler) + + ;; User Timer Tick vector + SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler) + + ;; Memory Size Check vector + SET_INT_VECTOR(0x12, #0xF000, #int12_handler) + + ;; Equipment Configuration Check vector + SET_INT_VECTOR(0x11, #0xF000, #int11_handler) + + ;; System Services + SET_INT_VECTOR(0x15, #0xF000, #int15_handler) + + ;; EBDA setup + call ebda_post + + ;; PIT setup + SET_INT_VECTOR(0x08, #0xF000, #int08_handler) + ;; int 1C already points at dummy_iret_handler (above) + mov al, #0x34 ; timer0: binary count, 16bit count, mode 2 + out 0x43, al +#ifdef HVMASSIST + mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support) + out 0x40, al ; lsb + mov al, #0xe9 + out 0x40, al ; msb +#else + mov al, #0x00 ; maximum count of 0000H = 18.2Hz + out 0x40, al + out 0x40, al +#endif + + ;; Keyboard + SET_INT_VECTOR(0x09, #0xF000, #int09_handler) + SET_INT_VECTOR(0x16, #0xF000, #int16_handler) + + xor ax, ax + mov ds, ax + mov 0x0417, al /* keyboard shift flags, set 1 */ + mov 0x0418, al /* keyboard shift flags, set 2 */ + mov 0x0419, al /* keyboard alt-numpad work area */ + mov 0x0471, al /* keyboard ctrl-break flag */ + mov 0x0497, al /* keyboard status flags 4 */ + mov al, #0x10 + mov 0x0496, al /* keyboard status flags 3 */ + + + /* keyboard head of buffer pointer */ + mov bx, #0x001E + mov 0x041A, bx + + /* keyboard end of buffer pointer */ + mov 0x041C, bx + + /* keyboard pointer to start of buffer */ + mov bx, #0x001E + mov 0x0480, bx + + /* keyboard pointer to end of buffer */ + mov bx, #0x003E + mov 0x0482, bx + + /* init the keyboard */ + call _keyboard_init + + ;; mov CMOS Equipment Byte to BDA Equipment Word + mov ax, 0x0410 + mov al, #0x14 + out 0x70, al + in al, 0x71 + mov 0x0410, ax + + + ;; Parallel setup + SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler) + xor ax, ax + mov ds, ax + xor bx, bx + mov cl, #0x14 ; timeout value + mov dx, #0x378 ; Parallel I/O address, port 1 + call detect_parport + mov dx, #0x278 ; Parallel I/O address, port 2 + call detect_parport + shl bx, #0x0e + mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports + and ax, #0x3fff + or ax, bx ; set number of parallel ports + mov 0x410, ax + + ;; Serial setup + SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler) + SET_INT_VECTOR(0x14, #0xF000, #int14_handler) + xor bx, bx + mov cl, #0x0a ; timeout value + mov dx, #0x03f8 ; Serial I/O address, port 1 + call detect_serial + mov dx, #0x02f8 ; Serial I/O address, port 2 + call detect_serial + mov dx, #0x03e8 ; Serial I/O address, port 3 + call detect_serial + mov dx, #0x02e8 ; Serial I/O address, port 4 + call detect_serial + shl bx, #0x09 + mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports + and ax, #0xf1ff + or ax, bx ; set number of serial port + mov 0x410, ax + + ;; CMOS RTC + SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler) + SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler) + SET_INT_VECTOR(0x70, #0xF000, #int70_handler) + ;; BIOS DATA AREA 0x4CE ??? + call timer_tick_post + + ;; PS/2 mouse setup + SET_INT_VECTOR(0x74, #0xF000, #int74_handler) + + ;; IRQ13 (FPU exception) setup + SET_INT_VECTOR(0x75, #0xF000, #int75_handler) + + ;; Video setup + SET_INT_VECTOR(0x10, #0xF000, #int10_handler) + + ;; PIC + mov al, #0x11 ; send initialisation commands + out 0x20, al + out 0xa0, al + mov al, #0x08 + out 0x21, al + mov al, #0x70 + out 0xa1, al + mov al, #0x04 + out 0x21, al + mov al, #0x02 + out 0xa1, al + mov al, #0x01 + out 0x21, al + out 0xa1, al + mov al, #0xb8 + out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6 +#if BX_USE_PS2_MOUSE + mov al, #0x8f +#else + mov al, #0x9f +#endif + out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14 + +#ifdef HVMASSIST + call _copy_e820_table + call smbios_init +#endif + + call rom_scan + + call _print_bios_banner + + ;; + ;; Floppy setup + ;; + call floppy_drive_post + +#if BX_USE_ATADRV + + ;; + ;; Hard Drive setup + ;; + call hard_drive_post + + ;; + ;; ATA/ATAPI driver setup + ;; + call _ata_init + call _ata_detect + ;; +#else // BX_USE_ATADRV + + ;; + ;; Hard Drive setup + ;; + call hard_drive_post + +#endif // BX_USE_ATADRV + +#if BX_ELTORITO_BOOT + ;; + ;; eltorito floppy/harddisk emulation from cd + ;; + call _cdemu_init + ;; +#endif // BX_ELTORITO_BOOT + + int #0x19 + //JMP_EP(0x0064) ; INT 19h location + + +.org 0xe2c3 ; NMI Handler Entry Point +nmi: + ;; FIXME the NMI handler should not panic + ;; but iret when called from int75 (fpu exception) + call _nmi_handler_msg + iret + +int75_handler: + out 0xf0, al // clear irq13 + call eoi_both_pics // clear interrupt + int 2 // legacy nmi call + iret + +;------------------------------------------- +;- INT 13h Fixed Disk Services Entry Point - +;------------------------------------------- +.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point +int13_handler: + //JMPL(int13_relocated) + jmp int13_relocated + +.org 0xe401 ; Fixed Disk Parameter Table + +;---------- +;- INT19h - +;---------- +.org 0xe6f2 ; INT 19h Boot Load Service Entry Point +int19_handler: + + jmp int19_relocated +;------------------------------------------- +;- System BIOS Configuration Data Table +;------------------------------------------- +.org BIOS_CONFIG_TABLE +db 0x08 ; Table size (bytes) -Lo +db 0x00 ; Table size (bytes) -Hi +db SYS_MODEL_ID +db SYS_SUBMODEL_ID +db BIOS_REVISION +; Feature byte 1 +; b7: 1=DMA channel 3 used by hard disk +; b6: 1=2 interrupt controllers present +; b5: 1=RTC present +; b4: 1=BIOS calls int 15h/4Fh every key +; b3: 1=wait for extern event supported (Int 15h/41h) +; b2: 1=extended BIOS data area used +; b1: 0=AT or ESDI bus, 1=MicroChannel +; b0: 1=Dual bus (MicroChannel + ISA) +db (0 << 7) | \ + (1 << 6) | \ + (1 << 5) | \ + (BX_CALL_INT15_4F << 4) | \ + (0 << 3) | \ + (BX_USE_EBDA << 2) | \ + (0 << 1) | \ + (0 << 0) +; Feature byte 2 +; b7: 1=32-bit DMA supported +; b6: 1=int16h, function 9 supported +; b5: 1=int15h/C6h (get POS data) supported +; b4: 1=int15h/C7h (get mem map info) supported +; b3: 1=int15h/C8h (en/dis CPU) supported +; b2: 1=non-8042 kb controller +; b1: 1=data streaming supported +; b0: reserved +db (0 << 7) | \ + (1 << 6) | \ + (0 << 5) | \ + (0 << 4) | \ + (0 << 3) | \ + (0 << 2) | \ + (0 << 1) | \ + (0 << 0) +; Feature byte 3 +; b7: not used +; b6: reserved +; b5: reserved +; b4: POST supports ROM-to-RAM enable/disable +; b3: SCSI on system board +; b2: info panel installed +; b1: Initial Machine Load (IML) system - BIOS on disk +; b0: SCSI supported in IML +db 0x00 +; Feature byte 4 +; b7: IBM private +; b6: EEPROM present +; b5-3: ABIOS presence (011 = not supported) +; b2: private +; b1: memory split above 16Mb supported +; b0: POSTEXT directly supported by POST +db 0x00 +; Feature byte 5 (IBM) +; b1: enhanced mouse +; b0: flash EPROM +db 0x00 + + + +.org 0xe729 ; Baud Rate Generator Table + +;---------- +;- INT14h - +;---------- +.org 0xe739 ; INT 14h Serial Communications Service Entry Point +int14_handler: + push ds + pusha + mov ax, #0x0000 + mov ds, ax + call _int14_function + popa + pop ds + iret + + +;---------------------------------------- +;- INT 16h Keyboard Service Entry Point - +;---------------------------------------- +.org 0xe82e +int16_handler: + + sti + push ds + pushf + pusha + + cmp ah, #0x00 + je int16_F00 + cmp ah, #0x10 + je int16_F00 + + mov bx, #0xf000 + mov ds, bx + call _int16_function + popa + popf + pop ds + jz int16_zero_set + +int16_zero_clear: + push bp + mov bp, sp + //SEG SS + and BYTE [bp + 0x06], #0xbf + pop bp + iret + +int16_zero_set: + push bp + mov bp, sp + //SEG SS + or BYTE [bp + 0x06], #0x40 + pop bp + iret + +int16_F00: + mov bx, #0x0040 + mov ds, bx + +int16_wait_for_key: + cli + mov bx, 0x001a + cmp bx, 0x001c + jne int16_key_found + sti + nop +#if 0 + /* no key yet, call int 15h, function AX=9002 */ + 0x50, /* push AX */ + 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */ + 0xcd, 0x15, /* int 15h */ + 0x58, /* pop AX */ + 0xeb, 0xea, /* jmp WAIT_FOR_KEY */ +#endif + jmp int16_wait_for_key + +int16_key_found: + mov bx, #0xf000 + mov ds, bx + call _int16_function + popa + popf + pop ds +#if 0 + /* notify int16 complete w/ int 15h, function AX=9102 */ + 0x50, /* push AX */ + 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */ + 0xcd, 0x15, /* int 15h */ + 0x58, /* pop AX */ +#endif + iret + + + +;------------------------------------------------- +;- INT09h : Keyboard Hardware Service Entry Point - +;------------------------------------------------- +.org 0xe987 +int09_handler: + cli + push ax + + mov al, #0xAD ;;disable keyboard + out #0x64, al + + mov al, #0x0B + out #0x20, al + in al, #0x20 + and al, #0x02 + jz int09_finish + + in al, #0x60 ;;read key from keyboard controller + //test al, #0x80 ;;look for key release + //jnz int09_process_key ;; dont pass releases to intercept? + + ;; check for extended key + cmp al, #0xe0 + jne int09_call_int15_4f + + push ds + xor ax, ax + mov ds, ax + mov al, BYTE [0x496] ;; mf2_state |= 0x01 + or al, #0x01 + mov BYTE [0x496], al + pop ds + + in al, #0x60 ;;read another key from keyboard controller + + sti + +int09_call_int15_4f: + push ds + pusha +#ifdef BX_CALL_INT15_4F + mov ah, #0x4f ;; allow for keyboard intercept + stc + int #0x15 + jnc int09_done +#endif + + +//int09_process_key: + mov bx, #0xf000 + mov ds, bx + call _int09_function + +int09_done: + popa + pop ds + cli + call eoi_master_pic + +int09_finish: + mov al, #0xAE ;;enable keyboard + out #0x64, al + pop ax + iret + + + + +;---------------------------------------- +;- INT 13h Diskette Service Entry Point - +;---------------------------------------- +.org 0xec59 +int13_diskette: + jmp int13_noeltorito + +;--------------------------------------------- +;- INT 0Eh Diskette Hardware ISR Entry Point - +;--------------------------------------------- +.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point +int0e_handler: + push ax + push dx + mov dx, #0x03f4 + in al, dx + and al, #0xc0 + cmp al, #0xc0 + je int0e_normal + mov dx, #0x03f5 + mov al, #0x08 ; sense interrupt status + out dx, al +int0e_loop1: + mov dx, #0x03f4 + in al, dx + and al, #0xc0 + cmp al, #0xc0 + jne int0e_loop1 +int0e_loop2: + mov dx, #0x03f5 + in al, dx + mov dx, #0x03f4 + in al, dx + and al, #0xc0 + cmp al, #0xc0 + je int0e_loop2 +int0e_normal: + push ds + mov ax, #0x0000 ;; segment 0000 + mov ds, ax + call eoi_master_pic + mov al, 0x043e + or al, #0x80 ;; diskette interrupt has occurred + mov 0x043e, al + pop ds + pop dx + pop ax + iret + + +.org 0xefc7 ; Diskette Controller Parameter Table +diskette_param_table: +;; Since no provisions are made for multiple drive types, most +;; values in this table are ignored. I set parameters for 1.44M +;; floppy here +db 0xAF +db 0x02 ;; head load time 0000001, DMA used +db 0x25 +db 0x02 +db 18 +db 0x1B +db 0xFF +db 0x6C +db 0xF6 +db 0x0F +db 0x08 + + +;---------------------------------------- +;- INT17h : Printer Service Entry Point - +;---------------------------------------- +.org 0xefd2 +int17_handler: + push ds + pusha + mov ax, #0x0000 + mov ds, ax + call _int17_function + popa + pop ds + iret + +diskette_param_table2: +;; New diskette parameter table adding 3 parameters from IBM +;; Since no provisions are made for multiple drive types, most +;; values in this table are ignored. I set parameters for 1.44M +;; floppy here +db 0xAF +db 0x02 ;; head load time 0000001, DMA used +db 0x25 +db 0x02 +db 18 +db 0x1B +db 0xFF +db 0x6C +db 0xF6 +db 0x0F +db 0x08 +db 79 ;; maximum track +db 0 ;; data transfer rate +db 4 ;; drive type in cmos + +.org 0xf045 ; INT 10 Functions 0-Fh Entry Point + HALT(__LINE__) + iret + +;---------- +;- INT10h - +;---------- +.org 0xf065 ; INT 10h Video Support Service Entry Point +int10_handler: + ;; dont do anything, since the VGA BIOS handles int10h requests + iret + +.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh) + +;---------- +;- INT12h - +;---------- +.org 0xf841 ; INT 12h Memory Size Service Entry Point +; ??? different for Pentium (machine check)? +int12_handler: + push ds + mov ax, #0x0040 + mov ds, ax + mov ax, 0x0013 + pop ds + iret + +;---------- +;- INT11h - +;---------- +.org 0xf84d ; INT 11h Equipment List Service Entry Point +int11_handler: + push ds + mov ax, #0x0040 + mov ds, ax + mov ax, 0x0010 + pop ds + iret + +;---------- +;- INT15h - +;---------- +.org 0xf859 ; INT 15h System Services Entry Point +int15_handler: + pushf +#if BX_APM + cmp ah, #0x53 + je apm_call +#endif + push ds + push es + cmp ah, #0x86 + je int15_handler32 + cmp ah, #0xE8 + je int15_handler32 + pusha +#if BX_USE_PS2_MOUSE + cmp ah, #0xC2 + je int15_handler_mouse +#endif + call _int15_function +int15_handler_mouse_ret: + popa +int15_handler32_ret: + pop es + pop ds + popf + jmp iret_modify_cf +#if BX_APM +apm_call: + jmp _apmreal_entry +#endif + +#if BX_USE_PS2_MOUSE +int15_handler_mouse: + call _int15_function_mouse + jmp int15_handler_mouse_ret +#endif + +int15_handler32: + pushad + call _int15_function32 + popad + jmp int15_handler32_ret + +;; Protected mode IDT descriptor +;; +;; I just make the limit 0, so the machine will shutdown +;; if an exception occurs during protected mode memory +;; transfers. +;; +;; Set base to f0000 to correspond to beginning of BIOS, +;; in case I actually define an IDT later +;; Set limit to 0 + +pmode_IDT_info: +dw 0x0000 ;; limit 15:00 +dw 0x0000 ;; base 15:00 +db 0x0f ;; base 23:16 + +;; Real mode IDT descriptor +;; +;; Set to typical real-mode values. +;; base = 000000 +;; limit = 03ff + +rmode_IDT_info: +dw 0x03ff ;; limit 15:00 +dw 0x0000 ;; base 15:00 +db 0x00 ;; base 23:16 + + +;---------- +;- INT1Ah - +;---------- +.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point +int1a_handler: +#if BX_PCIBIOS + cmp ah, #0xb1 + jne int1a_normal + call pcibios_real + jc pcibios_error + retf 2 +pcibios_error: + mov bl, ah + mov ah, #0xb1 + push ds + pusha + mov ax, ss ; set readable descriptor to ds, for calling pcibios + mov ds, ax ; on 16bit protected mode. + jmp int1a_callfunction +int1a_normal: +#endif + push ds + pusha + xor ax, ax + mov ds, ax +int1a_callfunction: + call _int1a_function + popa + pop ds + iret + +;; +;; int70h: IRQ8 - CMOS RTC +;; +int70_handler: + push ds + pusha + xor ax, ax + mov ds, ax + call _int70_function + popa + pop ds + iret + +;--------- +;- INT08 - +;--------- +.org 0xfea5 ; INT 08h System Timer ISR Entry Point +int08_handler: + sti + push eax + push ds + xor ax, ax + mov ds, ax + + ;; time to turn off drive(s)? + mov al,0x0440 + or al,al + jz int08_floppy_off + dec al + mov 0x0440,al + jnz int08_floppy_off + ;; turn motor(s) off + push dx + mov dx,#0x03f2 + in al,dx + and al,#0xcf + out dx,al + pop dx +int08_floppy_off: + + mov eax, 0x046c ;; get ticks dword + inc eax + + ;; compare eax to one days worth of timer ticks at 18.2 hz + cmp eax, #0x001800B0 + jb int08_store_ticks + ;; there has been a midnight rollover at this point + xor eax, eax ;; zero out counter + inc BYTE 0x0470 ;; increment rollover flag + +int08_store_ticks: + mov 0x046c, eax ;; store new ticks dword + ;; chain to user timer tick INT #0x1c + //pushf + //;; call_ep [ds:loc] + //CALL_EP( 0x1c << 2 ) + int #0x1c + cli + call eoi_master_pic + pop ds + pop eax + iret + +.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST + + +.org 0xff00 +.ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team." + +;------------------------------------------------ +;- IRET Instruction for Dummy Interrupt Handler - +;------------------------------------------------ +.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler +dummy_iret_handler: + iret + +.org 0xff54 ; INT 05h Print Screen Service Entry Point + HALT(__LINE__) + iret + +#ifdef HVMTEST +.org 0xffe0 + jmp 0xf000:post; +#endif + +.org 0xfff0 ; Power-up Entry Point +#ifdef HVMTEST + jmp 0xd000:0x0003; +#else + jmp 0xf000:post +#endif + +.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY +.ascii BIOS_BUILD_DATE + +.org 0xfffe ; System Model ID +db SYS_MODEL_ID +db 0x00 ; filler + +.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters) +ASM_END +/* + * This font comes from the fntcol16.zip package (c) by Joseph Gil + * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip + * This font is public domain + */ +static Bit8u vgafont8[128*8]= +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, + 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, + 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, + 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, + 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c, + 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c, + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, + 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, + 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, + 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, + 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78, + 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, + 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0, + 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0, + 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99, + 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, + 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00, + 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, + 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00, + 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, + 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff, + 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, + 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, + 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, + 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, + 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00, + 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, + 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00, + 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00, + 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00, + 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, + 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, + 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, + 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, + 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, + 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, + 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00, + 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00, + 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00, + 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00, + 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, + 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00, + 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00, + 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00, + 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00, + 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00, + 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, + 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60, + 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00, + 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, + 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00, + 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, + 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00, + 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, + 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, + 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, + 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00, + 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00, + 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, + 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, + 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, + 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00, + 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, + 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, + 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00, + 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00, + 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, + 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00, + 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, + 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00, + 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, + 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, + 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, + 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00, + 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00, + 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, + 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, + 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, + 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, + 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, + 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, + 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00, + 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, + 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, + 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, + 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00, + 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, + 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00, + 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, + 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, + 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00, + 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, + 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00, + 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, +}; + +#ifdef HVMASSIST +// +// MP Tables +// just carve out some blank space for HVMLOADER to write the MP tables to +// +// NOTE: There should be enough space for a 32 processor entry MP table +// +ASM_START +.org 0xcc00 +db 0x5F, 0x5F, 0x5F, 0x48, 0x56, 0x4D, 0x4D, 0x50 ;; ___HVMMP +dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 64 bytes +dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 128 bytes +dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 192 bytes +dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 256 bytes +dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 320 bytes +dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 384 bytes +dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 448 bytes +dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 512 bytes +dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 576 bytes +dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 640 bytes +dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 704 bytes +dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 768 bytes +dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 832 bytes +dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 896 bytes + +.align 16 +smbios_entry_point: +db 0,0,0,0,0,0,0,0 ; 8 bytes +db 0,0,0,0,0,0,0,0 ; 16 bytes +db 0,0,0,0,0,0,0,0 ; 24 bytes +db 0,0,0,0,0,0,0 ; 31 bytes +ASM_END + +#else // !HVMASSIST + +ASM_START +.org 0xcc00 +// bcc-generated data will be placed here + +// For documentation of this config structure, look on developer.intel.com and +// search for multiprocessor specification. Note that when you change anything +// you must update the checksum (a pain!). It would be better to construct this +// with C structures, or at least fill in the checksum automatically. +// +// Maybe this structs could be moved elsewhere than d000 + +#if (BX_SMP_PROCESSORS==1) + // no structure necessary. +#elif (BX_SMP_PROCESSORS==2) +// define the Intel MP Configuration Structure for 2 processors at +// APIC ID 0,1. I/O APIC at ID=2. +.align 16 +mp_config_table: + db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature + dw (mp_config_end-mp_config_table) ;; table length + db 4 ;; spec rev + db 0x65 ;; checksum + .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU" + db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 " + db 0x20, 0x20, 0x20, 0x20 + db 0x20, 0x20, 0x20, 0x20 + dw 0,0 ;; oem table ptr + dw 0 ;; oem table size + dw 20 ;; entry count + dw 0x0000, 0xfee0 ;; memory mapped address of local APIC + dw 0 ;; extended table length + db 0 ;; extended table checksum + db 0 ;; reserved +mp_config_proc0: + db 0 ;; entry type=processor + db 0 ;; local APIC id + db 0x11 ;; local APIC version number + db 3 ;; cpu flags: enabled, bootstrap processor + db 0,6,0,0 ;; cpu signature + dw 0x201,0 ;; feature flags + dw 0,0 ;; reserved + dw 0,0 ;; reserved +mp_config_proc1: + db 0 ;; entry type=processor + db 1 ;; local APIC id + db 0x11 ;; local APIC version number + db 1 ;; cpu flags: enabled + db 0,6,0,0 ;; cpu signature + dw 0x201,0 ;; feature flags + dw 0,0 ;; reserved + dw 0,0 ;; reserved +mp_config_isa_bus: + db 1 ;; entry type=bus + db 0 ;; bus ID + db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA " +mp_config_ioapic: + db 2 ;; entry type=I/O APIC + db 2 ;; apic id=2. linux will set. + db 0x11 ;; I/O APIC version number + db 1 ;; flags=1=enabled + dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC +mp_config_irqs: + db 3 ;; entry type=I/O interrupt + db 0 ;; interrupt type=vectored interrupt + db 0,0 ;; flags po=0, el=0 (linux uses as default) + db 0 ;; source bus ID is ISA + db 0 ;; source bus IRQ + db 2 ;; destination I/O APIC ID + db 0 ;; destination I/O APIC interrrupt in + ;; repeat pattern for interrupts 0-15 + db 3,0,0,0,0,1,2,1 + db 3,0,0,0,0,2,2,2 + db 3,0,0,0,0,3,2,3 + db 3,0,0,0,0,4,2,4 + db 3,0,0,0,0,5,2,5 + db 3,0,0,0,0,6,2,6 + db 3,0,0,0,0,7,2,7 + db 3,0,0,0,0,8,2,8 + db 3,0,0,0,0,9,2,9 + db 3,0,0,0,0,10,2,10 + db 3,0,0,0,0,11,2,11 + db 3,0,0,0,0,12,2,12 + db 3,0,0,0,0,13,2,13 + db 3,0,0,0,0,14,2,14 + db 3,0,0,0,0,15,2,15 +#elif (BX_SMP_PROCESSORS==4) +// define the Intel MP Configuration Structure for 4 processors at +// APIC ID 0,1,2,3. I/O APIC at ID=4. +.align 16 +mp_config_table: + db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature + dw (mp_config_end-mp_config_table) ;; table length + db 4 ;; spec rev + db 0xdd ;; checksum + .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU" + db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 " + db 0x20, 0x20, 0x20, 0x20 + db 0x20, 0x20, 0x20, 0x20 + dw 0,0 ;; oem table ptr + dw 0 ;; oem table size + dw 22 ;; entry count + dw 0x0000, 0xfee0 ;; memory mapped address of local APIC + dw 0 ;; extended table length + db 0 ;; extended table checksum + db 0 ;; reserved +mp_config_proc0: + db 0 ;; entry type=processor + db 0 ;; local APIC id + db 0x11 ;; local APIC version number + db 3 ;; cpu flags: enabled, bootstrap processor + db 0,6,0,0 ;; cpu signature + dw 0x201,0 ;; feature flags + dw 0,0 ;; reserved + dw 0,0 ;; reserved +mp_config_proc1: + db 0 ;; entry type=processor + db 1 ;; local APIC id + db 0x11 ;; local APIC version number + db 1 ;; cpu flags: enabled + db 0,6,0,0 ;; cpu signature + dw 0x201,0 ;; feature flags + dw 0,0 ;; reserved + dw 0,0 ;; reserved +mp_config_proc2: + db 0 ;; entry type=processor + db 2 ;; local APIC id + db 0x11 ;; local APIC version number + db 1 ;; cpu flags: enabled + db 0,6,0,0 ;; cpu signature + dw 0x201,0 ;; feature flags + dw 0,0 ;; reserved + dw 0,0 ;; reserved +mp_config_proc3: + db 0 ;; entry type=processor + db 3 ;; local APIC id + db 0x11 ;; local APIC version number + db 1 ;; cpu flags: enabled + db 0,6,0,0 ;; cpu signature + dw 0x201,0 ;; feature flags + dw 0,0 ;; reserved + dw 0,0 ;; reserved +mp_config_isa_bus: + db 1 ;; entry type=bus + db 0 ;; bus ID + db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA " +mp_config_ioapic: + db 2 ;; entry type=I/O APIC + db 4 ;; apic id=4. linux will set. + db 0x11 ;; I/O APIC version number + db 1 ;; flags=1=enabled + dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC +mp_config_irqs: + db 3 ;; entry type=I/O interrupt + db 0 ;; interrupt type=vectored interrupt + db 0,0 ;; flags po=0, el=0 (linux uses as default) + db 0 ;; source bus ID is ISA + db 0 ;; source bus IRQ + db 4 ;; destination I/O APIC ID + db 0 ;; destination I/O APIC interrrupt in + ;; repeat pattern for interrupts 0-15 + db 3,0,0,0,0,1,4,1 + db 3,0,0,0,0,2,4,2 + db 3,0,0,0,0,3,4,3 + db 3,0,0,0,0,4,4,4 + db 3,0,0,0,0,5,4,5 + db 3,0,0,0,0,6,4,6 + db 3,0,0,0,0,7,4,7 + db 3,0,0,0,0,8,4,8 + db 3,0,0,0,0,9,4,9 + db 3,0,0,0,0,10,4,10 + db 3,0,0,0,0,11,4,11 + db 3,0,0,0,0,12,4,12 + db 3,0,0,0,0,13,4,13 + db 3,0,0,0,0,14,4,14 + db 3,0,0,0,0,15,4,15 +#elif (BX_SMP_PROCESSORS==8) +// define the Intel MP Configuration Structure for 8 processors at +// APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8. +.align 16 +mp_config_table: + db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature + dw (mp_config_end-mp_config_table) ;; table length + db 4 ;; spec rev + db 0xc3 ;; checksum + .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU" + db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 " + db 0x20, 0x20, 0x20, 0x20 + db 0x20, 0x20, 0x20, 0x20 + dw 0,0 ;; oem table ptr + dw 0 ;; oem table size + dw 26 ;; entry count + dw 0x0000, 0xfee0 ;; memory mapped address of local APIC + dw 0 ;; extended table length + db 0 ;; extended table checksum + db 0 ;; reserved +mp_config_proc0: + db 0 ;; entry type=processor + db 0 ;; local APIC id + db 0x11 ;; local APIC version number + db 3 ;; cpu flags: enabled, bootstrap processor + db 0,6,0,0 ;; cpu signature + dw 0x201,0 ;; feature flags + dw 0,0 ;; reserved + dw 0,0 ;; reserved +mp_config_proc1: + db 0 ;; entry type=processor + db 1 ;; local APIC id + db 0x11 ;; local APIC version number + db 1 ;; cpu flags: enabled + db 0,6,0,0 ;; cpu signature + dw 0x201,0 ;; feature flags + dw 0,0 ;; reserved + dw 0,0 ;; reserved +mp_config_proc2: + db 0 ;; entry type=processor + db 2 ;; local APIC id + db 0x11 ;; local APIC version number + db 1 ;; cpu flags: enabled + db 0,6,0,0 ;; cpu signature + dw 0x201,0 ;; feature flags + dw 0,0 ;; reserved + dw 0,0 ;; reserved +mp_config_proc3: + db 0 ;; entry type=processor + db 3 ;; local APIC id + db 0x11 ;; local APIC version number + db 1 ;; cpu flags: enabled + db 0,6,0,0 ;; cpu signature + dw 0x201,0 ;; feature flags + dw 0,0 ;; reserved + dw 0,0 ;; reserved +mp_config_proc4: + db 0 ;; entry type=processor + db 4 ;; local APIC id + db 0x11 ;; local APIC version number + db 1 ;; cpu flags: enabled + db 0,6,0,0 ;; cpu signature + dw 0x201,0 ;; feature flags + dw 0,0 ;; reserved + dw 0,0 ;; reserved +mp_config_proc5: + db 0 ;; entry type=processor + db 5 ;; local APIC id + db 0x11 ;; local APIC version number + db 1 ;; cpu flags: enabled + db 0,6,0,0 ;; cpu signature + dw 0x201,0 ;; feature flags + dw 0,0 ;; reserved + dw 0,0 ;; reserved +mp_config_proc6: + db 0 ;; entry type=processor + db 6 ;; local APIC id + db 0x11 ;; local APIC version number + db 1 ;; cpu flags: enabled + db 0,6,0,0 ;; cpu signature + dw 0x201,0 ;; feature flags + dw 0,0 ;; reserved + dw 0,0 ;; reserved +mp_config_proc7: + db 0 ;; entry type=processor + db 7 ;; local APIC id + db 0x11 ;; local APIC version number + db 1 ;; cpu flags: enabled + db 0,6,0,0 ;; cpu signature + dw 0x201,0 ;; feature flags + dw 0,0 ;; reserved + dw 0,0 ;; reserved +mp_config_isa_bus: + db 1 ;; entry type=bus + db 0 ;; bus ID + db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA " +mp_config_ioapic: + db 2 ;; entry type=I/O APIC + db 8 ;; apic id=8 + db 0x11 ;; I/O APIC version number + db 1 ;; flags=1=enabled + dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC +mp_config_irqs: + db 3 ;; entry type=I/O interrupt + db 0 ;; interrupt type=vectored interrupt + db 0,0 ;; flags po=0, el=0 (linux uses as default) + db 0 ;; source bus ID is ISA + db 0 ;; source bus IRQ + db 8 ;; destination I/O APIC ID + db 0 ;; destination I/O APIC interrrupt in + ;; repeat pattern for interrupts 0-15 + db 3,0,0,0,0,1,8,1 + db 3,0,0,0,0,2,8,2 + db 3,0,0,0,0,3,8,3 + db 3,0,0,0,0,4,8,4 + db 3,0,0,0,0,5,8,5 + db 3,0,0,0,0,6,8,6 + db 3,0,0,0,0,7,8,7 + db 3,0,0,0,0,8,8,8 + db 3,0,0,0,0,9,8,9 + db 3,0,0,0,0,10,8,10 + db 3,0,0,0,0,11,8,11 + db 3,0,0,0,0,12,8,12 + db 3,0,0,0,0,13,8,13 + db 3,0,0,0,0,14,8,14 + db 3,0,0,0,0,15,8,15 +#else +# error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors. +#endif // if (BX_SMP_PROCESSORS==...) + +mp_config_end: // this label used to find length of mp structure + db 0 + +#if (BX_SMP_PROCESSORS>1) +.align 16 +mp_floating_pointer_structure: +db 0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature +dw mp_config_table, 0xf ;; pointer to MP configuration table +db 1 ;; length of this struct in 16-bit byte chunks +db 4 ;; MP spec revision +db 0xc1 ;; checksum +db 0 ;; MP feature byte 1. value 0 means look at the config table +db 0,0,0,0 ;; MP feature bytes 2-5. +#endif + +ASM_END + +#endif // HVMASSIST diff --git a/palacios/src/vmboot/vgabios/BUGS b/palacios/src/vmboot/vgabios/BUGS new file mode 100644 index 0000000..2bf3b06 --- /dev/null +++ b/palacios/src/vmboot/vgabios/BUGS @@ -0,0 +1,3 @@ +Not all the functions have been implemented yet. + +Please report any bugs to diff --git a/palacios/src/vmboot/vgabios/COPYING b/palacios/src/vmboot/vgabios/COPYING new file mode 100644 index 0000000..223ede7 --- /dev/null +++ b/palacios/src/vmboot/vgabios/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/palacios/src/vmboot/vgabios/ChangeLog b/palacios/src/vmboot/vgabios/ChangeLog new file mode 100644 index 0000000..08711f0 --- /dev/null +++ b/palacios/src/vmboot/vgabios/ChangeLog @@ -0,0 +1,1060 @@ +2005-05-24 16:50 vruppert + + * vbe.c (1.47), vgabios.c (1.61): + + - output to the vgabios info port can be disabled now. It is still enabled by + default and always possible in debug mode. (based on a patch from Alex Beregszaszi) + +2005-05-20 16:06 vruppert + + * vbe.c (1.46), vgabios.c (1.60): + + - fixed return value for the default case in the VBE section (non-debug mode) + - removed unused macros HALT and PANIC_PORT + +2005-03-07 20:39 vruppert + + * README (1.9): + + - updates for 0.5a release + +2005-03-06 13:06 vruppert + + * Makefile (1.17): + + - vgabios files with cirrus support added to release target + +2005-03-06 12:24 vruppert + + * Makefile (1.16): + + - cross compilation support added (patch from Alex Beregszaszi) + +2005-03-05 13:03 vruppert + + * BUGS (1.3), README (1.8), TODO (1.11): + + - documentation updates + +2004-12-04 15:26 vruppert + + * VGABIOS-lgpl-latest.bin (1.61), VGABIOS-lgpl-latest.cirrus.bin + (1.13), VGABIOS-lgpl-latest.cirrus.debug.bin (1.13), + VGABIOS-lgpl-latest.debug.bin (1.61), clext.c (1.9): + + - Cirrus extension: support for 1280x1024x15 and 1280x1024x16 modes added (patch + from Fabrice Bellard) + +2004-08-08 16:53 vruppert + + * VGABIOS-lgpl-latest.bin (1.60), VGABIOS-lgpl-latest.cirrus.bin (1.12), + VGABIOS-lgpl-latest.cirrus.debug.bin (1.12), + VGABIOS-lgpl-latest.debug.bin (1.60), clext.c (1.8): + + - use single bank mode for VBE + - enable 16k granularity for VBE only + +2004-07-30 19:33 vruppert + + * VGABIOS-lgpl-latest.bin (1.59), VGABIOS-lgpl-latest.cirrus.bin (1.11), + VGABIOS-lgpl-latest.cirrus.debug.bin (1.11), + VGABIOS-lgpl-latest.debug.bin (1.59), clext.c (1.7): + + - cirrus init: set standard vga mode and reset bitblt + +2004-07-22 18:38 vruppert + + * VGABIOS-lgpl-latest.bin (1.58), VGABIOS-lgpl-latest.cirrus.bin (1.10), + VGABIOS-lgpl-latest.cirrus.debug.bin (1.10), + VGABIOS-lgpl-latest.debug.bin (1.58), clext.c (1.6), vbe.c (1.45), + vbetables.h (1.24): + + - cirrus extension: tables for mode 1280x1024x8 added + - vbe: dispi_set_xres() and dispi_set_virt_width() now modify vga compatible + registers + - vbe: mode list entry for mode 800x600x4 fixed + +2004-07-18 20:23 vruppert + + * VGABIOS-lgpl-latest.bin (1.57), VGABIOS-lgpl-latest.cirrus.bin (1.9), + VGABIOS-lgpl-latest.cirrus.debug.bin (1.9), + VGABIOS-lgpl-latest.debug.bin (1.57), vgabios.c (1.59), vgatables.h (1.8): + + - disable CRTC write protection before setting new values + - CRTC line for mode 0x6a fixed + +2004-07-07 16:08 vruppert + + * Makefile (1.15), VGABIOS-lgpl-latest.bin (1.56), + VGABIOS-lgpl-latest.cirrus.bin (1.8), VGABIOS-lgpl-latest.cirrus.debug.bin (1.8), + VGABIOS-lgpl-latest.debug.bin (1.56), biossums.c (1.1), clext.c (1.5): + + - biossums utility for the Bochs BIOS adapted for the LGPL'd VGABIOS + - VESA3 PMINFO checksum calculated in the source + - 24 bpp mode entries fixed (patch from Fabrice Bellard) + +2004-06-25 18:28 vruppert + + * VGABIOS-lgpl-latest.cirrus.bin (1.7), VGABIOS-lgpl-latest.cirrus.debug.bin (1.7), + clext.c (1.4): + + - 4MB memory probe added (patch from Fabrice Bellard) + +2004-06-25 17:31 vruppert + + * VGABIOS-lgpl-latest.bin (1.55), VGABIOS-lgpl-latest.cirrus.bin (1.6), + VGABIOS-lgpl-latest.cirrus.debug.bin (1.6), + VGABIOS-lgpl-latest.debug.bin (1.55), clext.c (1.3): + + - fixed value of sequencer reset register in cirrus mode table + - fixed possible overflow error if cirrus start address is >256k + +2004-06-23 21:11 vruppert + + * VGABIOS-lgpl-latest.bin (1.54), VGABIOS-lgpl-latest.cirrus.bin (1.5), + VGABIOS-lgpl-latest.cirrus.debug.bin (1.5), + VGABIOS-lgpl-latest.debug.bin (1.54), clext.c (1.2): + + - applied new patch for the cirrus extension from suzu + * enable VESA LFB support if a Cirrus PCI adapter is detected + * prepared VBE3 protected mode info block (test case required) + - added VBE functions 4F06h and 4F07h + - some bugfixes + +2004-06-17 18:57 vruppert + + * Makefile (1.14), VGABIOS-lgpl-latest.bin (1.53), + VGABIOS-lgpl-latest.cirrus.bin (1.2), VGABIOS-lgpl-latest.cirrus.debug.bin (1.2), + VGABIOS-lgpl-latest.debug.bin (1.53): + + - fixed makefile targets for the binaries with cirrus extension + +2004-06-16 21:11 vruppert + + * Makefile (1.13), VGABIOS-lgpl-latest.bin (1.52), + VGABIOS-lgpl-latest.cirrus.bin (1.1), VGABIOS-lgpl-latest.cirrus.debug.bin (1.1), + VGABIOS-lgpl-latest.debug.bin (1.52), clext.c (1.1), vgabios.c (1.58): + + - applied suzu's cirrus extension patch. Cirrus SVGA detection, most of the + cirrus-specific modes and some basic VBE features are present now. + +2004-05-31 21:15 vruppert + + * VGABIOS-lgpl-latest.bin (1.51), VGABIOS-lgpl-latest.debug.bin (1.51), + vgabios.c (1.57): + + - write character in planar graphics modes: sequencer map mask must be 0x0f and + bit operation must be 'replace' if bit 7 of attribute is clear + - read/write pixel in planar graphics modes: bit mask setup simplified + +2004-05-11 18:08 vruppert + + * VGABIOS-lgpl-latest.bin (1.50), VGABIOS-lgpl-latest.debug.bin (1.50), + vgabios.c (1.56): + + - biosfn_select_vert_res rewritten in assembler + - scroll text in planar graphics modes: attribute for blank line fixed + - write character in planar graphics modes: graphics controller values fixed + +2004-05-09 20:32 vruppert + + * VGABIOS-lgpl-latest.bin (1.49), VGABIOS-lgpl-latest.debug.bin (1.49), + vbe.c (1.44), vbe.h (1.24), vgabios.c (1.55): + + - VBE init code and some dispi ioport functions rewritten in assembler + - text scroll functions for CGA graphics modes added + - scroll text in graphics modes: attribute for blank line fixed + +2004-05-08 16:06 vruppert + + * BUGS (1.2), README (1.7), TODO (1.10), VGABIOS-lgpl-latest.bin (1.48), + VGABIOS-lgpl-latest.debug.bin (1.48), vbe.c (1.43), vbe.h (1.23), + vbe_display_api.txt (1.11), vgabios.c (1.54): + + - VBE internal functions dispi_set_enable and dispi_set_bank now called both from C + and asm code + - VBE function 0x03 rewritten in assembler + - VBE function 0x08 cleaned up + - text output and scroll functions for graphics modes rewritten using case + structures + - documentation and comments updated + +2004-05-06 21:18 vruppert + + * VGABIOS-lgpl-latest.bin (1.47), VGABIOS-lgpl-latest.debug.bin (1.47), + vbe.c (1.42), vbe.h (1.22), vgabios.c (1.53): + + - VBE functions 0x05, 0x06, 0x07 and some dispi ioport functions rewritten in + assembler + - VBE functions 0x06 and 0x07: get functions now supported, 15 bpp bug fixed + +2004-05-05 19:24 vruppert + + * VGABIOS-lgpl-latest.bin (1.46), VGABIOS-lgpl-latest.debug.bin (1.46), + vbe.c (1.41), vbe.h (1.21), vbe_display_api.txt (1.10), vgabios.c (1.52): + + - 8 bit DAC capability flag set + - vbe_biosfn_set_get_dac_palette_format implemented + - VBE api description updated + - C definitions from header files now used assembler code + +2004-05-02 17:27 vruppert + + * VGABIOS-lgpl-latest.bin (1.45), VGABIOS-lgpl-latest.debug.bin (1.45), + vgabios.c (1.51): + + - text scroll functions for PLANAR1/PLANAR4 graphics modes added + - function biosfn_get_ega_info rewritten in assembler + - read/write graphics pixel functions rewritten using a case structure + +2004-05-01 16:03 vruppert + + * VGABIOS-lgpl-latest.bin (1.44), VGABIOS-lgpl-latest.debug.bin (1.44), + vgabios.c (1.50): + + - biosfn_enable_cursor_emulation rewritten in assembler + - remap of the cursor shape depends on modeset control bit 0 + - text output in PLANAR4 modes now supports attribute bit 7 (XOR with background) + +2004-04-25 20:13 vruppert + + * VGABIOS-lgpl-latest.bin (1.43), VGABIOS-lgpl-latest.debug.bin (1.43), + vgabios.c (1.49), vgatables.h (1.7): + + - table entries for vga mode 0x0f fixed (PLANAR2 exists on EGA only) + - function release_font_access now supports the monochrome text mode + - PLANAR1 modes now supported in text output functions and read/write pixel + - function AH=0x12/BL=0x32 rewritten in assembler + +2004-04-25 08:45 vruppert + + * VGABIOS-lgpl-latest.bin (1.42), VGABIOS-lgpl-latest.debug.bin (1.42), + vgabios.c (1.48): + + - block address calculation in font functions fixed + - functions AX=0x1103, AH=0x12/BL=0x31 and AH=0x12/BL=0x33 rewritten in assembler + +2004-04-24 09:59 vruppert + + * VGABIOS-lgpl-latest.bin (1.41), VGABIOS-lgpl-latest.debug.bin (1.41), + vgabios.c (1.47): + + - read/write graphics pixel for PLANAR4 modes added + - CGA specific functions (group AH = 0x0B) implemented + +2004-04-23 14:34 vruppert + + * VGABIOS-lgpl-latest.bin (1.40), VGABIOS-lgpl-latest.debug.bin (1.40), + vgabios.c (1.46): + + - remaining palette and dac read/write functions (except gray scale summing) + rewritten in assembler + +2004-04-18 13:43 vruppert + + * VGABIOS-lgpl-latest.bin (1.39), VGABIOS-lgpl-latest.debug.bin (1.39), + vgabios.c (1.45): + + - some palette and dac read/write functions rewritten in assembler + - main int10 debug message now works with assembler functions, too + +2004-04-18 09:15 japj + + * vbe.c (1.40): + + updated my email address + put vgabios url in the bios copyright string + (instead of my old email address) + +2004-04-17 07:18 vruppert + + * VGABIOS-lgpl-latest.bin (1.38), VGABIOS-lgpl-latest.debug.bin (1.38), + vgabios.c (1.44): + + - biosfn_set_video_mode: don't load DAC registers if default palette loading is + disabled. Perform gray scale summing if enabled. + - biosfn_perform_gray_scale_summing: switch between DAC read and write mode is + required to make this function work. Maximum DAC value always set to 0x3f. + +2004-04-08 17:50 vruppert + + * VGABIOS-lgpl-latest.bin (1.37), VGABIOS-lgpl-latest.debug.bin (1.37), + vgabios.c (1.43): + + - write character function for the LINEAR8 mode + - get_font_access() and release_font_access() rewritten in assembler + - fixed wrong variable name in the init code + +2004-04-06 19:31 vruppert + + * VGABIOS-lgpl-latest.bin (1.36), VGABIOS-lgpl-latest.debug.bin (1.36), + vgabios.c (1.42): + + - init functions rewitten in assembler + - function biosfn_set_display_code rewritten in assembler + +2004-04-05 19:40 vruppert + + * VGABIOS-lgpl-latest.bin (1.35), VGABIOS-lgpl-latest.debug.bin (1.35), + vgabios.c (1.41): + + - functions biosfn_get_video_mode() and biosfn_read_display_code() rewritten + in assembler + +2004-04-04 18:20 vruppert + + * VGABIOS-lgpl-latest.bin (1.34), VGABIOS-lgpl-latest.debug.bin (1.34), + vgabios.c (1.40): + + - write character function for CGA modes added + - read/write graphics pixel for CGA and LINEAR8 modes added + +2004-02-23 21:08 vruppert + + * VGABIOS-lgpl-latest.bin (1.33), VGABIOS-lgpl-latest.debug.bin (1.33), + vbe.c (1.39): + + - dispi_get_max_bpp(): restore the original value of the vbe enable register + +2004-02-22 14:17 vruppert + + * README (1.6), vbe.c (1.38), vbe.h (1.20), vbe_display_api.txt (1.9), + VGABIOS-lgpl-latest.bin (1.32), VGABIOS-lgpl-latest.debug.bin (1.32): + + - new function dispi_get_max_bpp() returns the bpp capabilities of the Bochs gui + - create the mode list depending on the supported bpp capability + - unused stuff removed + - documentation updated + +2004-02-21 18:20 vruppert + + * vbe.c (1.37), vbe.h (1.19), vbetables.h (1.23), + VGABIOS-lgpl-latest.bin (1.31), VGABIOS-lgpl-latest.debug.bin (1.31): + + - dynamicly genarated vbe mode_info list works now + +2003-11-17 21:04 vruppert + + * vbe.c (1.36), vbetables.h (1.22), vgabios.c (1.39), vgatables.h (1.6), + VGABIOS-lgpl-latest.bin (1.30), VGABIOS-lgpl-latest.debug.bin (1.30): + + - new VBE presence flag stored at unused BDA address 0xB9 + - VBE init code rewritten + - added BIOS TTY flag for VBE mode 0x0102 (TODO: scrolling) + - vgabios_init_func: load and activate text font already done by set_video_mode + - function biosfn_get_all_palette_reg() fixed + +2003-11-06 00:26 cbothamy + + * README (1.5): + + - add changes for 0.4c release + +2003-11-06 00:22 cbothamy + + * VGABIOS-lgpl-latest.bin (1.29), VGABIOS-lgpl-latest.debug.bin + (1.29): + + - compile vgabios.c rev1.38 + +2003-11-06 00:21 cbothamy + + * vgabios.c (1.38): + + - activate char table after loading it when setting a text video + mode + +2003-11-06 00:19 cbothamy + + * Makefile (1.12): + + - when making a release, remove unwanted files first, and exclude + CVS from the tarball + +2003-11-04 22:50 cbothamy + + * ChangeLog (1.20, v0_4b): + + - update ChangeLog for 0.4b release + +2003-11-04 22:49 cbothamy + + * README (1.4, v0_4b): + + - update Changes for 0.4b release + +2003-11-04 20:26 vruppert + + * vgabios.c (1.37), VGABIOS-lgpl-latest.bin (1.28), + VGABIOS-lgpl-latest.debug.bin (1.28) (utags: v0_4b): + + - biosfn_get_font_info(): character height must be returned in CX + +2003-11-03 21:57 vruppert + + * vbe.c (1.35, v0_4b), vgabios.c (1.36), VGABIOS-lgpl-latest.bin + (1.27), VGABIOS-lgpl-latest.debug.bin (1.27): + + - the 'noclearmem' flag is not stored in the 'current video mode' + register (0040h:0049h) - VBE also stores the 'noclear' flag in + the 'video control' register (0040h:0087h) + +2003-10-05 10:06 vruppert + + * vbe.h (1.18, v0_4b), vbe_display_api.txt (1.8, v0_4b), + VGABIOS-lgpl-latest.bin (1.26), VGABIOS-lgpl-latest.debug.bin + (1.26): + + - changed VBE i/o registers to 0x01CE/CF (suggestion from Daniel + Gimpelevich) + +2003-08-18 18:38 vruppert + + * VGABIOS-lgpl-latest.bin (1.25), VGABIOS-lgpl-latest.debug.bin + (1.25), vgabios.c (1.35): + + - wrong offsets to the character tables (INT 0x1F/0x43) fixed + (underscore added) - functions accessing the CRT controller + optimized using a local variable 'crtc_addr' + +2003-08-17 15:46 cbothamy + + * ChangeLog (1.19, v0_4a): + + - ChangeLog is now automatically generated by running "cvs2cl -r + -t -P -S" - update ChangeLog for 0.4a release + +2003-08-17 15:44 cbothamy + + * README (1.3, v0_4a): + + - added the old ChangeLog in the HOSTORY section of the README + file - update History for 0.4a release, with a summary of Changes + +2003-08-17 15:24 cbothamy + + * Makefile (1.11, v0_4b, v0_4a): + + - fix Makefile for "release" target + +2003-08-16 01:49 cbothamy + + * Makefile (1.10), README (1.2), VGABIOS-lgpl-latest.bin (1.24, + v0_4a), VGABIOS-lgpl-latest.debug.bin (1.24, v0_4a), vgabios.c + (1.34, v0_4a): + + - update the Makefile for releases - remove references to old + plex86 website - update the Makefile so it build + VGABIOS-lgpl-latest.bin and VGABIOS-lgpl-latest.debug.bin + +2003-08-07 18:17 vruppert + + * VGABIOS-lgpl-latest.bin (1.23), VGABIOS-lgpl-latest.debug.bin + (1.23): + + - current VBE mode now stored in BDA (unused address 0xBA) + +2003-08-07 17:54 vruppert + + * vbe.c (1.34), vgatables.h (1.5, v0_4b) (utags: v0_4a): + + - current VBE mode now stored in BDA (unused address 0xBA) + +2003-07-20 18:05 vruppert + + * vgabios.c (1.33), VGABIOS-lgpl-latest.bin (1.22), + VGABIOS-lgpl-latest.debug.bin (1.22): + + - fixed a few functions accessing the attribute controller + +2003-07-19 09:33 vruppert + + * vgabios.c (1.32), VGABIOS-lgpl-latest.bin (1.21), + VGABIOS-lgpl-latest.debug.bin (1.21): + + - re-enable video after programming the attribute controller - + biosfn_set_all_palette_reg(): number of palette registers fixed + +2003-07-16 22:32 vruppert + + * ChangeLog (1.18), vbe.c (1.33), vbe.h (1.17, v0_4a), + vbe_display_api.txt (1.7, v0_4a), vgabios.c (1.31), + VGABIOS-lgpl-latest.bin (1.20), VGABIOS-lgpl-latest.debug.bin + (1.20): + + - LFB flag now stored in the register VBE_DISPI_INDEX_ENABLE - + release date in Changelog fixed - release date of VBE BIOS 0.6 + was the same as VGA BIOS 0.3b - year changed in copyright + messages + +2003-07-15 12:40 vruppert + + * VGABIOS-lgpl-latest.bin (1.19), VGABIOS-lgpl-latest.debug.bin + (1.19): + + - new function dispi_get_bpp() - function + vbe_biosfn_set_get_logical_scan_line_length() fixed for >8bpp - + number of image pages of all VBE modes fixed + +2003-07-15 12:35 vruppert + + * vbe.c (1.32), vbetables.h (1.21, v0_4b, v0_4a): + + - new function dispi_get_bpp() - function + vbe_biosfn_set_get_logical_scan_line_length() fixed for >8bpp - + number of image pages of all VBE modes fixed + +2003-07-14 19:45 vruppert + + * vbe_display_api.txt (1.6): + + - description of VBE_DISPI_ interface 0xb0c2 added + +2003-07-10 19:07 vruppert + + * vbe.c (1.31), vbetables.h (1.20), VGABIOS-lgpl-latest.bin (1.18), + VGABIOS-lgpl-latest.debug.bin (1.18): + + - 15 bpp VBE modes added - "Bochs own" mode 0x142 (640x480x32bpp) + added + +2003-07-01 19:00 vruppert + + * vbe.c (1.30), vbe.h (1.16), vbetables.h (1.19), + VGABIOS-lgpl-latest.bin (1.17), VGABIOS-lgpl-latest.debug.bin + (1.17): + + - VBE preserve display memory feature implemented - VBE mode + entries 0x117 and 0x118 added + +2003-06-30 21:27 vruppert + + * vbe.c (1.29), vbe.h (1.15), vbetables.h (1.18), + VGABIOS-lgpl-latest.bin (1.16), VGABIOS-lgpl-latest.debug.bin + (1.16): + + - VBE mode info blocks of modes with >8bpp enabled - VBE modes + with 24 bpp: bytes per scanline fixed - vbe_biosfn_set_mode() now + supports >8bpp - VBE will be enabled with new VBE_DISPI_ID2 + (0xB0C2) + +2003-06-29 12:53 vruppert + + * vbetables.h (1.17), VGABIOS-lgpl-latest.bin (1.15), + VGABIOS-lgpl-latest.debug.bin (1.15): + + - duplicate lines with VBE_MODE_ATTRIBUTE_GRAPHICS_MODE removed - + VBE mode info items of currently unsupported modes fixed + +2003-06-15 21:19 vruppert + + * vgabios.c (1.30), VGABIOS-lgpl-latest.bin (1.14), + VGABIOS-lgpl-latest.debug.bin (1.14): + + - function write_gfx_char() rewritten + +2003-04-26 09:27 vruppert + + * VGABIOS-lgpl-latest.debug.bin (1.13): + + - added missing VBE function dispi_get_bank() - added missing + return codes for VBE function 4F05h - memory size is always + reported in VBE function 4F00h - fixed scan line length for VBE + mode 0102h - fixed function set_active_page() for graphics modes + - fixed the page sizes of some VGA modes + +2003-04-26 09:22 vruppert + + * vbe.c (1.28), vbetables.h (1.16), vgabios.c (1.29), vgatables.h + (1.4), VGABIOS-lgpl-latest.bin (1.13): + + - added missing VBE function dispi_get_bank() - added missing + return codes for VBE function 4F05h - memory size is always + reported in VBE function 4F00h - fixed scan line length for VBE + mode 0102h - fixed function set_active_page() for graphics modes + - fixed the page sizes of some VGA modes + +2003-04-20 09:51 vruppert + + * vgabios.c (1.28), vgatables.h (1.3), VGABIOS-lgpl-latest.bin + (1.12), VGABIOS-lgpl-latest.debug.bin (1.12): + + - function write_gfx_char() now supports different font sizes - + some entries of the static functionality table fixed + +2003-04-18 09:23 vruppert + + * vbe.c (1.27), vbe.h (1.14), vbetables.h (1.15): + + - applied patch #1331 * new function dispi_set_bank_farcall() + * VBE mode info item WinFuncPtr points to the new function if the + flag VBE_WINDOW_ATTRIBUTE_RELOCATABLE is set * flag + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE added + +2003-02-11 20:17 vruppert + + * VGABIOS-lgpl-latest.bin (1.11), VGABIOS-lgpl-latest.debug.bin + (1.11), vbe.c (1.26), vbetables.h (1.14): + + - VBE mode search rewritten * improved function + mode_info_find_mode() is now used by the VBE functions 0x4F01 + and 0x4F02 * removed all mode list entries with the LFB bit + set. LFB detection is now present in the function + mode_info_find_mode() + +2003-02-09 20:59 vruppert + + * VGABIOS-lgpl-latest.bin (1.10), VGABIOS-lgpl-latest.debug.bin + (1.10), vgabios.c (1.27): + + - function write_gfx_char(): memory address now calculated in + this function; background color is always black - function + biosfn_write_char_attr(): the count parameter is now used in + graphics modes too - function biosfn_write_char_only() works + the same way as function biosfn_write_char_attr() in graphics + mode - copying charmap data optimized using memcpyb() + +2003-02-09 11:36 vruppert + + * VGABIOS-lgpl-latest.bin (1.9), VGABIOS-lgpl-latest.debug.bin + (1.9): + + - VESA mode 0x102 added (uses existing SVGA mode 0x6a) - all VESA + modes with the LFB flag set removed from the list (Linux doesn't + like mode numbers > 0x07ff) + +2003-02-09 11:02 vruppert + + * vbe.c (1.25), vbe.h (1.13), vbetables.h (1.13): + + - VESA mode 0x102 added (uses existing SVGA mode 0x6a) - all VESA + modes with the LFB flag set removed from the list (Linux doesn't + like mode numbers > 0x07ff) + +2003-02-08 13:04 vruppert + + * vbe.c (1.24), vgabios.c (1.26): + + - vbe_biosfn_return_current_mode() now returns the active + standard VGA mode TODO: return VESA mode if enabled - + biosfn_set_video_mode() now clears the screen in CGA mode + correctly - write character functions are now working in all + PLANAR4 graphics modes - added stubs for unimplemented features + in graphics modes + +2003-02-04 22:19 vruppert + + * VGABIOS-lgpl-latest.bin (1.8), VGABIOS-lgpl-latest.debug.bin + (1.8): + + - set video mode: clear vga memory in graphics mode - set video + mode: load default font in text mode - write character + implemented for graphics mode 0x12 + +2003-02-04 22:06 vruppert + + * vgabios.c (1.25): + + - set video mode: clear vga memory in graphics mode - set video + mode: load default font in text mode - write character + implemented for graphics mode 0x12 + +2003-01-21 19:30 vruppert + + * vgabios.c (1.24): + + - remap the cursor size if the char height is > 8 and the new + values are < 8 + +2003-01-20 18:24 cbothamy + + * Makefile (1.9): + + - fix so make -j2 does not overwrite temp files + +2003-01-19 12:35 vruppert + + * vgabios.c (1.23): + + - function set_scan_lines() recalculates the number of rows and + the page size - new values for char height, text rows and page + size are stored in the BIOS data segment - asm helper function + idiv_u added + +2003-01-15 18:49 cbothamy + + * VGABIOS-lgpl-latest.bin (1.7), VGABIOS-lgpl-latest.debug.bin + (1.7): + + - compile vgabios rev 1.22 + +2003-01-15 18:49 cbothamy + + * vgabios.c (1.22): + + - fix bug found by ams : a 8bits index value was compared to + 0x100 in some cases in biosfn_set_all_dac_reg, + biosfn_read_all_dac_reg, biosfn_perform_gray_scale_summing + +2003-01-15 17:34 cbothamy + + * Makefile (1.8): + + - fix symbol table file names, discovered by ams + +2003-01-04 21:20 vruppert + + * VGABIOS-lgpl-latest.bin (1.6), VGABIOS-lgpl-latest.debug.bin + (1.6), vgabios.c (1.21): + + - biosfn_set_video_mode(): reset attribute controller flip-flop + before setting up the controller's registers (bug found with + amidiag) + +2003-01-04 09:50 vruppert + + * vbe.c (1.23): + + - VBE function 0x00 returns VBE 1.x compatible information if no + VBE signature is present + +2003-01-01 12:44 vruppert + + * VGABIOS-lgpl-latest.bin (1.5), VGABIOS-lgpl-latest.debug.bin + (1.5): + + - SVGA mode 0x6A (800x600x4) added to the list of graphics modes + +2002-12-31 18:07 vruppert + + * vgatables.h (1.2): + + - SVGA mode 0x6A (800x600x4) added to the list of graphics modes + +2002-11-23 10:38 cbothamy + + * ChangeLog (1.17, v0_3b): + + - fix changelog for 0.3b release + +2002-10-20 17:12 vruppert + + * VGABIOS-lgpl-latest.bin (1.4), VGABIOS-lgpl-latest.debug.bin + (1.4), vgabios.c (1.20) (utags: v0_3b): + + - new function set_scan_lines() for the font size change (patch + from Hartmut Birr) - cursor shape start and end must be updated + in set_scan_lines() - set_scan_lines() is called by the functions + 0x1110, 0x1111, 0x1112 and 0x1114 after copying the font data + +2002-10-04 08:20 vruppert + + * VGABIOS-lgpl-latest.bin (1.3), VGABIOS-lgpl-latest.debug.bin + (1.3), vgabios.c (1.19): + + - biosfn_set_single_dac_reg(): the red value is stored in DH + +2002-09-19 19:05 cbothamy + + * VGABIOS-lgpl-latest.bin (1.2), VGABIOS-lgpl-latest.debug.bin + (1.2): + + - updated with latest changes + +2002-09-19 19:03 cbothamy + + * ChangeLog (1.16), Makefile (1.7, v0_3b), vbe.c (1.22, v0_3b), + vgabios.c (1.18), vgabios.h (1.3, v0_4b, v0_4a, v0_3b): + + - updated the Makefile - removed display of copyrights. - + changed the Copyright string to "LGPL VGABios developers" + +2002-09-08 21:14 vruppert + + * vgabios.c (1.17): + + - set the cursor shape depending on the current font height - + clear BL before calling int 0x10 function 0x1103 in + vgabios_init_func + +2002-08-23 22:58 cbothamy + + * vbe.c (1.21), vbetables.h (1.12, v0_3b): + + - added lfb-mode numbers (patch from mathis) + +2002-07-21 21:57 japj + + * vbe.c (1.20), vgabios.c (1.16): + + gcc2/3 preprocessing fix + +2002-05-18 16:55 cbothamy + + * vgabios.c (1.15): + + - include patch from Volker that adds some text font functions + +2002-05-01 23:13 japj + + * VGABIOS-lgpl-latest.bin (1.1), VGABIOS-lgpl-latest.debug.bin + (1.1): + + adding latest bin & debug bin of the vgabios + +2002-04-29 14:50 japj + + * ChangeLog (1.15), vbe.c (1.19), vbe.h (1.12, v0_3b), vbetables.h + (1.11), vgabios.c (1.14): + + - applying hw scrolling/multibuffering patch + +2002-04-25 21:59 japj + + * Makefile (1.6), vbe.c (1.18), vgabios.c (1.13): + + - reverting #asm/##asm & endasm patch (does not work with with + cygwin) + +2002-04-19 19:38 japj + + * Makefile (1.5), vbe.c (1.17), vgabios.c (1.12): + + - fixing preprocessing of vgabios with latest gcc (from Mandrake + 8.2) + +2002-04-08 23:44 japj + + * ChangeLog (1.14), vbe_display_api.txt (1.5, v0_3b): + + - preparing docs for new DISPI interface (for hardware scrolling) + +2002-04-03 19:06 japj + + * ChangeLog (1.13), TODO (1.9, v0_4b, v0_4a, v0_3b), vbe.c (1.16): + + - defaulting LFB on + updated changelog & todo + +2002-04-03 00:38 cbothamy + + * vbe.c (1.15), vgabios.c (1.11): + + - changed the logging ports to 0x500 -> 0x502 + +2002-03-14 17:54 japj + + * vbe.c (1.14): + + - vbetables.h is dependant upon some defines (VBE_HAVE_LFB), so + put the include *after* the define + +2002-03-13 21:47 japj + + * ChangeLog (1.12), TODO (1.8), vbe.c (1.13), vbetables.h (1.10), + vgabios.c (1.10): + + - made LFB dependant upon define - not implement vbe functions + return failure - updated todo & docs for things after bochs 1.4 + +2002-03-13 19:46 japj + + * vbe.h (1.11), vbe_display_api.txt (1.4): + + - added max video memory + documented what is in the 0xb0c0 + interface + +2002-03-12 02:33 cbothamy + + * ChangeLog (1.11), Makefile (1.4): + + - updated for 0.3a. Merged vgabios.bin and vbebios.bin + +2002-03-10 21:36 japj + + * ChangeLog (1.10), vbetables.h (1.9): + + - added LFB modes for testing with vbe-lfb patch in Bochs + +2002-03-10 17:42 japj + + * vbe.c (1.12, v0_3a): + + - show people when they do NOT have VBE support available + +2002-03-10 17:36 japj + + * TODO (1.7, v0_3a), vbe.c (1.11), vbe.h (1.10, v0_3a), vgabios.c + (1.9, v0_3a): + + - cleanup of vbe internal functions (set 8bpp mode is now + dependant on ModeInfo content instead of hardcoded functions) + +2002-03-10 17:20 cbothamy + + * ChangeLog (1.9, v0_3a), TODO (1.6): + + - updated for 0.3a + +2002-03-10 17:19 cbothamy + + * vbe.c (1.10), vbe.h (1.9): + + - added vbe_has_vbe_display function that detects an attached vbe + display + +2002-03-10 17:12 cbothamy + + * vgabios.c (1.8): + + - vbe calls are done only if a vbe display is detected + +2002-03-10 11:25 japj + + * vbe.h (1.8), vbe_display_api.txt (1.3, v0_3a): + + - preparing for LFB support + +2002-03-09 14:25 japj + + * vgabios.c (1.7): + + - fixing initial cursor shape to _ instead of - + +2002-03-08 23:08 japj + + * ChangeLog (1.8), TODO (1.5), vbe.c (1.9), vbe.h (1.7), vgabios.c + (1.6): + + - updating vbe code to new API + +2002-03-08 21:48 japj + + * vbe.c (1.8), vbe.h (1.6), vbetables.h (1.8, v0_3a): + + - updating vbe code with #defines from API + +2002-03-08 21:31 japj + + * vbe_display_api.txt (1.2): + + - adding some text about how banks work + +2002-03-08 21:09 japj + + * ChangeLog (1.7), vbe_display_api.txt (1.1): + + - adding vbe_display_api documentation + +2002-03-07 21:36 japj + + * ChangeLog (1.6), vbe.c (1.7), vbetables.h (1.7): + + - added 1024x768xbpp support - some more cleanups/comments + +2002-03-06 21:55 japj + + * ChangeLog (1.5), TODO (1.4), vbe.c (1.6), vbetables.h (1.6), + vgabios.c (1.5): + + - updated changelog with new modi - added 640x480x8 (Mandrake + Installer can use this!) - added pre VBE2 compatible 'detection' + - fixed problem when normal vga set mode wouldn't disable vbe + mode + +2002-03-06 20:59 japj + + * TODO (1.3), vbe.c (1.5), vbe.h (1.5), vbetables.h (1.5), + vgabios.c (1.4): + + - adding 640x400x8 and 800x600x8 vbe support (this depends + HEAVILY on my bochs vga code patch - japj) + +2002-03-06 18:00 japj + + * vbe.c (1.4), vbe.h (1.4), vbetables.h (1.4): + + - implemented banked & lfb support for 320x200x8bpp (some fixes + for vbetest program not displaying anything) + +2002-03-05 20:25 japj + + * Makefile (1.3, v0_3a): + + for vbe debug bios: - print debugging information in assembly + output - print source code in assembly output + +2002-03-01 19:39 japj + + * ChangeLog (1.4), TODO (1.2), vbe.c (1.3), vbe.h (1.3), + vbetables.h (1.3): + + - added vbe support for 320x200x8 using the standard vgamode + (0x13) + +2002-02-19 00:29 japj + + * ChangeLog (1.3): + + - updating ChangeLog with lfbprof + +2002-02-18 23:26 japj + + * tests/lfbprof/: lfbprof.c (1.2), lfbprof.h (1.2) (utags: v0_3a, + v0_3b, v0_4a, v0_4b): + + - fixed unsigned short for mode list (-1 != 0xffff otherwise) - + fixed LfbMapRealPointer macro mask problem (some modes were + skipped) - added some extra 'debugging' printf's + +2002-02-18 23:07 japj + + * tests/lfbprof/: Makefile (1.1, v0_4b, v0_4a, v0_3b, v0_3a), + lfbprof.c (1.1), lfbprof.h (1.1): + + - Adding lfbprof testprogram (for vbe testing purposes) It + needs to be compiled with the Watcom C Compiler + +2002-02-18 18:48 japj + + * vbe.c (1.2), vbe.h (1.2): + + - cosmetic updates to vbe.c/h + added bunch of FIXMEs for work + that needs to be done + +2002-02-18 18:34 japj + + * vbetables.h (1.2): + + - cosmetic updates in vbetables.h + +2002-02-18 18:32 japj + + * ChangeLog (1.2): + + updated changelog with merge of vbebios 0.2 + +2002-02-18 18:07 japj + + * vgabios.c (1.3): + + - small cosmetic cleanup in vgabios vbe code + added FIXMEs + +2002-02-18 17:55 japj + + * Makefile (1.2), dataseghack (1.2, v0_4b, v0_4a, v0_3b, v0_3a), + vbe.c (1.1), vbe.h (1.1), vbetables.h (1.1), vgabios.c (1.2), + vgabios.h (1.2, v0_3a): + + - merging with vbebios 0.2 release + +2002-02-18 11:31 cbothamy + + * BUGS (1.1, v0_4b, v0_4a, v0_3b, v0_3a), COPYING (1.1, v0_4b, + v0_4a, v0_3b, v0_3a), ChangeLog (1.1), Makefile (1.1), Notes + (1.1, v0_4b, v0_4a, v0_3b, v0_3a), README (1.1, v0_3b, v0_3a), + TODO (1.1), dataseghack (1.1), vgabios.c (1.1), vgabios.h (1.1), + vgafonts.h (1.1, v0_4b, v0_4a, v0_3b, v0_3a), vgatables.h (1.1, + v0_3b, v0_3a), tests/testbios.c (1.1, v0_4b, v0_4a, v0_3b, + v0_3a): + + - initial import + diff --git a/palacios/src/vmboot/vgabios/Makefile b/palacios/src/vmboot/vgabios/Makefile new file mode 100644 index 0000000..b5482ea --- /dev/null +++ b/palacios/src/vmboot/vgabios/Makefile @@ -0,0 +1,80 @@ +CC = gcc + +GCC = gcc +BCC = bcc +AS86 = as86 + +RELEASE = `pwd | sed "s-.*/--"` +RELDATE = `date '+%d %b %Y'` +RELVERS = `pwd | sed "s-.*/--" | sed "s/vgabios//" | sed "s/-//"` + +VGABIOS_DATE = "-DVGABIOS_DATE=\"$(RELDATE)\"" + +.PHONY: all +all: bios cirrus-bios + +.PHONY: bios +bios: biossums vgabios.bin vgabios.debug.bin + +.PHONY: cirrus-bios +cirrus-bios: vgabios-cirrus.bin vgabios-cirrus.debug.bin + +.PHONY: clean +clean: + rm -f biossums *.o *.s *.ld86 \ + temp.awk.* vgabios*.orig _vgabios_* _vgabios-debug_* core vgabios*.bin vgabios*.txt $(RELEASE).bin *.bak + rm -f VGABIOS-lgpl-latest*.bin + +.PHONY: release +release: + VGABIOS_VERS=\"-DVGABIOS_VERS=\\\"$(RELVERS)\\\"\" make bios cirrus-bios + /bin/rm -f *.o *.s *.ld86 \ + temp.awk.* vgabios.*.orig _vgabios_.*.c core *.bak .#* + cp VGABIOS-lgpl-latest.bin ../$(RELEASE).bin + cp VGABIOS-lgpl-latest.debug.bin ../$(RELEASE).debug.bin + cp VGABIOS-lgpl-latest.cirrus.bin ../$(RELEASE).cirrus.bin + cp VGABIOS-lgpl-latest.cirrus.debug.bin ../$(RELEASE).cirrus.debug.bin + tar czvf ../$(RELEASE).tgz --exclude CVS -C .. $(RELEASE)/ + +vgabios.bin: biossums vgabios.c vgabios.h vgafonts.h vgatables.h vbe.h vbe.c vbetables.h + $(GCC) -E -P vgabios.c $(VGABIOS_VERS) $(VGABIOS_DATE) > _vgabios_.c + $(BCC) -o vgabios.s -C-c -D__i86__ -S -0 _vgabios_.c + sed -e 's/^\.text//' -e 's/^\.data//' vgabios.s > _vgabios_.s + $(AS86) _vgabios_.s -b vgabios.bin -u -w- -g -0 -j -O -l vgabios.txt + rm -f _vgabios_.s _vgabios_.c vgabios.s + cp vgabios.bin VGABIOS-lgpl-latest.bin + ./biossums VGABIOS-lgpl-latest.bin + ls -l VGABIOS-lgpl-latest.bin + +vgabios.debug.bin: biossums vgabios.c vgabios.h vgafonts.h vgatables.h vbe.h vbe.c vbetables.h + $(GCC) -E -P vgabios.c $(VGABIOS_VERS) -DDEBUG $(VGABIOS_DATE) > _vgabios-debug_.c + $(BCC) -o vgabios-debug.s -C-c -D__i86__ -S -0 _vgabios-debug_.c + sed -e 's/^\.text//' -e 's/^\.data//' vgabios-debug.s > _vgabios-debug_.s + $(AS86) _vgabios-debug_.s -b vgabios.debug.bin -u -w- -g -0 -j -O -l vgabios.debug.txt + rm -f _vgabios-debug_.s _vgabios-debug_.c vgabios-debug.s + cp vgabios.debug.bin VGABIOS-lgpl-latest.debug.bin + ./biossums VGABIOS-lgpl-latest.debug.bin + ls -l VGABIOS-lgpl-latest.debug.bin + +vgabios-cirrus.bin: biossums vgabios.c vgabios.h vgafonts.h vgatables.h clext.c + $(GCC) -E -P vgabios.c $(VGABIOS_VERS) -DCIRRUS $(VGABIOS_DATE) > _vgabios-cirrus_.c + $(BCC) -o vgabios-cirrus.s -C-c -D__i86__ -S -0 _vgabios-cirrus_.c + sed -e 's/^\.text//' -e 's/^\.data//' vgabios-cirrus.s > _vgabios-cirrus_.s + $(AS86) _vgabios-cirrus_.s -b vgabios-cirrus.bin -u -w- -g -0 -j -O -l vgabios-cirrus.txt + rm -f _vgabios-cirrus_.s _vgabios-cirrus_.c vgabios-cirrus.s + cp vgabios-cirrus.bin VGABIOS-lgpl-latest.cirrus.bin + ./biossums VGABIOS-lgpl-latest.cirrus.bin + ls -l VGABIOS-lgpl-latest.cirrus.bin + +vgabios-cirrus.debug.bin: biossums vgabios.c vgabios.h vgafonts.h vgatables.h clext.c + $(GCC) -E -P vgabios.c $(VGABIOS_VERS) -DCIRRUS -DCIRRUS_DEBUG $(VGABIOS_DATE) > _vgabios-cirrus-debug_.c + $(BCC) -o vgabios-cirrus-debug.s -C-c -D__i86__ -S -0 _vgabios-cirrus-debug_.c + sed -e 's/^\.text//' -e 's/^\.data//' vgabios-cirrus-debug.s > _vgabios-cirrus-debug_.s + $(AS86) _vgabios-cirrus-debug_.s -b vgabios-cirrus.debug.bin -u -w- -g -0 -j -O -l vgabios-cirrus.debug.txt + rm -f _vgabios-cirrus-debug_.s _vgabios-cirrus-debug_.c vgabios-cirrus-debug.s + cp vgabios-cirrus.debug.bin VGABIOS-lgpl-latest.cirrus.debug.bin + ./biossums VGABIOS-lgpl-latest.cirrus.debug.bin + ls -l VGABIOS-lgpl-latest.cirrus.debug.bin + +biossums: biossums.c + $(CC) -o biossums biossums.c diff --git a/palacios/src/vmboot/vgabios/Notes b/palacios/src/vmboot/vgabios/Notes new file mode 100644 index 0000000..d5b708d --- /dev/null +++ b/palacios/src/vmboot/vgabios/Notes @@ -0,0 +1,11 @@ +Development notes +----------------- + +- need to split video init function + 1. set bios variables + 2. do the real init with io based on bios variables + +- characters format switching will set the bios + variables and call function #2 above + +- need to rework the tables as explained in Interrupt list diff --git a/palacios/src/vmboot/vgabios/README b/palacios/src/vmboot/vgabios/README new file mode 100644 index 0000000..69462d9 --- /dev/null +++ b/palacios/src/vmboot/vgabios/README @@ -0,0 +1,191 @@ +Plex86/Bochs VGABios +-------------------- + +The goal of this project is to have a LGPL'd Video Bios in plex86, +Bochs and qemu. +This VGA Bios is very specific to the emulated VGA card. +It is NOT meant to drive a physical vga card. + + +Cirrus SVGA extension +--------------------- + +The Cirrus SVGA extension is designed for the Cirrus emulation in Bochs and +qemu. The initial patch for the Cirrus extension has been written by Makoto +Suzuki (suzu). + + +Install +------- +To compile the VGA Bios you will need : +- gcc +- bcc +- as86 +- ld86 + +Untar the archive, and type make. You should get a "VGABIOS-lgpl-latest.bin" +file. Alternatively, you can use the binary file "VGABIOS-lgpl-latest.bin", +i have compiled for you. + +Edit your plex86/bochs conf file, and modify the load-rom command in the +VGA BIOS section, to point to the new vgabios image file. + + +Debugging +--------- +You can get a very basic debugging system: messages printed by the vgabios. +You have to register the "unmapped" device driver in plex86 or bochs, and make +sure it grabs port 0xfff0. + +Comment the #undef DEBUG at the beginning of vgabios.c. +You can then use the "printf" function in the bios. + + +Testing +------- +Look at the "testvga.c" file in the archive. This is a minimal Turbo C 2.0 +source file that calls a few int10 functions. Feel free to modify it to suit +your needs. + + +Copyright and License +--------------------- +This program has been written by Christophe Bothamy +It is protected by the GNU Lesser Public License, which you should +have received a copy of along with this package. + + +Reverse Engineering +------------------- +The VGA Bios has been written without reverse-engineering any existing Bios. + + +Acknowledgment +-------------- +The source code contains code ripped from rombios.c of plex86, written +by Kevin Lawton + +The source code contains fonts from fntcol16.zip (c) by Joseph Gil avalable at : +ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip +These fonts are public domain + +The source code is based on information taken from : +- Kevin Lawton's vga card emulation for bochs/plex86 +- Ralf Brown's interrupts list avalaible at + http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html +- Finn Thogersons' VGADOC4b available at http://home.worldonline.dk/~finth/ +- Michael Abrash's Graphics Programming Black Book +- Francois Gervais' book "programmation des cartes graphiques cga-ega-vga" + edited by sybex +- DOSEMU 1.0.1 source code for several tables values and formulas + + +Feedback +-------- +Please report any bugs, comments, patches for this VGA Bios to info@vruppert.de +You can find the latest release at : http://www.nongnu.org/vgabios/ +For any information on bochs, visit the website http://bochs.sourceforge.net/ +For any information on qemu, visit the website http://fabrice.bellard.free.fr/qemu/ + + +History +------- +vgabios-0.5b : May 24 2005 + - Volker + . fixed return value for the default case in the VBE section (non-debug mode) + . removed unused stuff + +vgabios-0.5a : Mar 07 2005 + - Volker + . Cirrus SVGA extension (initial patches from Makoto Suzuki, improvements + from Fabrice Bellard) + . vgabios image size is now exactly 32k with a checksum + . a lot of vgabios and vbe functions rewritten in assembler + . dynamicly generated VBE mode info list + . write character function for CGA and LINEAR8 modes + . read/write graphics pixel for some graphics modes + . text scroll feature for some graphics modes + . VBE 8-bit DAC support + +vgabios-0.4c : Nov 06 2003 + - Christophe + . fix font problem on initial screen of NT4 Loader + +vgabios-0.4b : Nov 04 2003 + - Volker + . fix offset of character tables + . optimizations of CRT controller accesses + . VBE i/o registers changed to 0x01CE/CF + (suggestion from Daniel Gimpelevich) + . "noclear" flag stored in BIOS area + . fix character height returned by get_font_info function + +vgabios-0.4a : Aug 17 2003 + - Volker + . VBE mode search rewritten (VBE modes with LFB bit removed) + . many bugfixes and optimizations + . write character function implemented for graphics modes + . support for 15bpp, 16bpp, 24bpp and 32bpp VBE modes added + . SVGA mode 0x6A added + . VBE modes 0x102, 0x117, 0x118 and 0x142 (Bochs specific) + +vgabios-0.3b : Nov 23 2002 + - Christophe + . added lfb-mode numbers (patch from mathis) + . updated the Makefile + . removed display of copyrights. + . changed the Copyright string to "LGPL VGABios developers" + - Volker + . set the cursor shape depending on the current font height + . clear BL before calling int 0x10 function 0x1103 in vgabios_init_func + . added some text font functions + - Jeroen + . Forced to new DISPI (0xb0c1) interface (requires latest bochs vbe code) + . Added multibuffering support + . Added new DISPI interface for: virt width, height, x offset, y offset + . Added LFB modes (to be used with the vbe-lfb patch in bochs) + see VBE_HAVE_LFB in vbe.c (currently default enabled) + . updated TODO & docs for changes after bochs 1.4 + +vgabios-0.3a : Mar 10 2002 + - Christophe + . Fixed bug in function ah=13 + - Jeroen + . updated vbebios implementation to new api + . added vbe_display_api documentation + . added 640x400x8, 640x480x8, 800x600x8, 1024x768 + (>640x480 needs a special bochs patch atm) + . added 320x200x8 vbe support (uses the standard 320x200x8 vga mode to + display, this allows for testing & having something on screen as well, + at least until bochs host side display is up & running) + . adding lfbprof (vbe) testprogram (+some small fixes to it) + . merging with vbebios 0.2 + +vgabios-0.2b : Nov 19 2001 + - Christophe + . Fixed bug in function ah=13 + +vgabios-0.2a : Nov 09 2001 + - Christophe + . Included bugfix from techt@pikeonline.net about grayscale summing + . Added the "IBM" string at org 0x1e as Bart Oldeman suggested + . Fixed DS and ES that where inverted in the int10 parameters list! + . The following have been implemented : + - function ax=1a00, ax=1a01, ah=1b + - function ax=1130 + . Added debug messages for unimplemented/unknown functions + Must be compiled with DEBUG defined. The output is trapped + by the unknown-ioport driver of plex/bochs (port 0xfff0 is used) + +vgabios-0.1a : May 8 2001 + - Christophe + . First release. The work has been focused only on text mode. + . The following have been implemented : + - inits + - int 10 handler + - functions ah=00, ah=01, ah=02, ah=03, ah=05, ah=06, ah=07, ah=08 + ah=09, ah=0a, ah=0e, ah=0f, ax=1000, ax=1001, ax=1002, ax=1003 + ax=1007, ax=1008, ax=1009, ax=1010, ax=1012, ax=1013, ax=1015 + ax=1017, ax=1018, ax=1019, ax=101a, ax=101b, ah=12 bl=10, + ah=12 bl=30, ah=12 bl=31, ah=12 bl=32, ah=12 bl=33, ah=12 bl=34 + ah=13 diff --git a/palacios/src/vmboot/vgabios/TODO b/palacios/src/vmboot/vgabios/TODO new file mode 100644 index 0000000..0b83ed0 --- /dev/null +++ b/palacios/src/vmboot/vgabios/TODO @@ -0,0 +1,28 @@ +Short term : +------------ + +General + - Fix init mode (ah=00). Should use more BIOS variables + - Add new functionalities and modify static functionality table + - Performance : 16 bits IO + +v0.6 + - Reimplement the tables so it is compatible with the video save pointer table + - Implement the remaining functions (don't know if all are needed): + - chargen ax=1120, ax=1121, ax=1122, ax=1123, ax=1124 + - display switch interface ah=12 bl=35 + - video refresh control ah=12 bl=36 + - save/restore state ah=1c + - Graphic modes + +v1.0 + - Bugfixes + + +================================================================================================= +VBE: +---- +Long term: +- have plex86 host side display interface +- have text io functions in vbe mode + diff --git a/palacios/src/vmboot/vgabios/biossums.c b/palacios/src/vmboot/vgabios/biossums.c new file mode 100644 index 0000000..bb1d0ad --- /dev/null +++ b/palacios/src/vmboot/vgabios/biossums.c @@ -0,0 +1,200 @@ +/* biossums.c --- written by Eike W. for the Bochs BIOS */ +/* adapted for the LGPL'd VGABIOS by vruppert */ + +#include +#include + +typedef unsigned char byte; + +void check( int value, char* message ); + +#define LEN_BIOS_DATA 0x8000 +#define MAX_OFFSET (LEN_BIOS_DATA - 1) + + +#define BIOS_OFFSET 0x7FFF + +long chksum_bios_get_offset( byte* data, long offset ); +byte chksum_bios_calc_value( byte* data, long offset ); +byte chksum_bios_get_value( byte* data, long offset ); +void chksum_bios_set_value( byte* data, long offset, byte value ); + + +#define PMID_LEN 20 +#define PMID_CHKSUM 19 + +long chksum_pmid_get_offset( byte* data, long offset ); +byte chksum_pmid_calc_value( byte* data, long offset ); +byte chksum_pmid_get_value( byte* data, long offset ); +void chksum_pmid_set_value( byte* data, long offset, byte value ); + + +byte bios_data[LEN_BIOS_DATA]; + + +int main( int argc, char* argv[] ) { + + FILE* stream; + long offset, tmp_offset; + byte cur_val = 0, new_val = 0; + int hits; + + + if( argc != 2 ) { + printf( "Error. Need a file-name as an argument.\n" ); + exit( EXIT_FAILURE ); + } + + if(( stream = fopen( argv[1], "rb" )) == NULL ) { + printf( "Error opening %s for reading.\n", argv[1] ); + exit( EXIT_FAILURE ); + } + if( fread( bios_data, 1, LEN_BIOS_DATA, stream ) >= LEN_BIOS_DATA ) { + printf( "Error reading max. 32767 Bytes from %s.\n", argv[1] ); + fclose( stream ); + exit( EXIT_FAILURE ); + } + fclose( stream ); + + hits = 0; + offset = 0L; + while( (tmp_offset = chksum_pmid_get_offset( bios_data, offset )) != -1L ) { + offset = tmp_offset; + cur_val = chksum_pmid_get_value( bios_data, offset ); + new_val = chksum_pmid_calc_value( bios_data, offset ); + printf( "\nPMID entry at: 0x%4lX\n", offset ); + printf( "Current checksum: 0x%02X\n", cur_val ); + printf( "Calculated checksum: 0x%02X ", new_val ); + hits++; + } + if( hits == 1 && cur_val != new_val ) { + printf( "Setting checksum." ); + chksum_pmid_set_value( bios_data, offset, new_val ); + } + if( hits >= 2 ) { + printf( "Multiple PMID entries! No checksum set." ); + } + if( hits ) { + printf( "\n" ); + } + + + offset = 0L; + offset = chksum_bios_get_offset( bios_data, offset ); + cur_val = chksum_bios_get_value( bios_data, offset ); + new_val = chksum_bios_calc_value( bios_data, offset ); + printf( "\nBios checksum at: 0x%4lX\n", offset ); + printf( "Current checksum: 0x%02X\n", cur_val ); + printf( "Calculated checksum: 0x%02X ", new_val ); + if( cur_val != new_val ) { + printf( "Setting checksum." ); + chksum_bios_set_value( bios_data, offset, new_val ); + } + printf( "\n" ); + + + if(( stream = fopen( argv[1], "wb" )) == NULL ) { + printf( "Error opening %s for writing.\n", argv[1] ); + exit( EXIT_FAILURE ); + } + if( fwrite( bios_data, 1, LEN_BIOS_DATA, stream ) < LEN_BIOS_DATA ) { + printf( "Error writing 32KBytes to %s.\n", argv[1] ); + fclose( stream ); + exit( EXIT_FAILURE ); + } + fclose( stream ); + + return( EXIT_SUCCESS ); +} + + +void check( int okay, char* message ) { + + if( !okay ) { + printf( "\n\nError. %s.\n", message ); + exit( EXIT_FAILURE ); + } +} + + +long chksum_bios_get_offset( byte* data, long offset ) { + + return( BIOS_OFFSET ); +} + + +byte chksum_bios_calc_value( byte* data, long offset ) { + + int i; + byte sum; + + sum = 0; + for( i = 0; i < MAX_OFFSET; i++ ) { + sum = sum + *( data + i ); + } + sum = -sum; /* iso ensures -s + s == 0 on unsigned types */ + return( sum ); +} + + +byte chksum_bios_get_value( byte* data, long offset ) { + + return( *( data + BIOS_OFFSET ) ); +} + + +void chksum_bios_set_value( byte* data, long offset, byte value ) { + + *( data + BIOS_OFFSET ) = value; +} + + +byte chksum_pmid_calc_value( byte* data, long offset ) { + + int i; + int len; + byte sum; + + len = PMID_LEN; + check( offset + len <= MAX_OFFSET, "PMID entry length out of bounds" ); + sum = 0; + for( i = 0; i < len; i++ ) { + if( i != PMID_CHKSUM ) { + sum = sum + *( data + offset + i ); + } + } + sum = -sum; + return( sum ); +} + + +long chksum_pmid_get_offset( byte* data, long offset ) { + + long result = -1L; + + while( offset + PMID_LEN < MAX_OFFSET ) { + offset = offset + 1; + if( *( data + offset + 0 ) == 'P' && \ + *( data + offset + 1 ) == 'M' && \ + *( data + offset + 2 ) == 'I' && \ + *( data + offset + 3 ) == 'D' ) { + result = offset; + break; + } + } + return( result ); +} + + +byte chksum_pmid_get_value( byte* data, long offset ) { + + check( offset + PMID_CHKSUM <= MAX_OFFSET, "PMID checksum out of bounds" ); + return( *( data + offset + PMID_CHKSUM ) ); +} + + +void chksum_pmid_set_value( byte* data, long offset, byte value ) { + + check( offset + PMID_CHKSUM <= MAX_OFFSET, "PMID checksum out of bounds" ); + *( data + offset + PMID_CHKSUM ) = value; +} diff --git a/palacios/src/vmboot/vgabios/clext.c b/palacios/src/vmboot/vgabios/clext.c new file mode 100644 index 0000000..1eb3c69 --- /dev/null +++ b/palacios/src/vmboot/vgabios/clext.c @@ -0,0 +1,1633 @@ +// +// QEMU Cirrus CLGD 54xx VGABIOS Extension. +// +// Copyright (c) 2004 Makoto Suzuki (suzu) +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +//#define CIRRUS_VESA3_PMINFO +#ifdef VBE +#undef CIRRUS_VESA3_PMINFO +#endif + +#define PM_BIOSMEM_CURRENT_MODE 0x449 +#define PM_BIOSMEM_CRTC_ADDRESS 0x463 +#define PM_BIOSMEM_VBE_MODE 0x4BA + +typedef struct +{ + /* + 0 */ + unsigned short mode; + unsigned short width; + unsigned short height; + unsigned short depth; + /* + 8 */ + unsigned short hidden_dac; /* 0x3c6 */ + unsigned short *seq; /* 0x3c4 */ + unsigned short *graph; /* 0x3ce */ + unsigned short *crtc; /* 0x3d4 */ + /* +16 */ + unsigned char bitsperpixel; + unsigned char vesacolortype; + unsigned char vesaredmask; + unsigned char vesaredpos; + unsigned char vesagreenmask; + unsigned char vesagreenpos; + unsigned char vesabluemask; + unsigned char vesabluepos; + /* +24 */ + unsigned char vesareservedmask; + unsigned char vesareservedpos; +} cirrus_mode_t; +#define CIRRUS_MODE_SIZE 26 + + +/* For VESA BIOS 3.0 */ +#define CIRRUS_PM16INFO_SIZE 20 + +/* VGA */ +unsigned short cseq_vga[] = {0x0007,0xffff}; +unsigned short cgraph_vga[] = {0x0009,0x000a,0x000b,0xffff}; +unsigned short ccrtc_vga[] = {0x001a,0x001b,0x001d,0xffff}; + +/* extensions */ +unsigned short cgraph_svgacolor[] = { +0x0000,0x0001,0x0002,0x0003,0x0004,0x4005,0x0506,0x0f07,0xff08, +0x0009,0x000a,0x000b, +0xffff +}; +/* 640x480x8 */ +unsigned short cseq_640x480x8[] = { +0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107, +0x580b,0x580c,0x580d,0x580e, +0x0412,0x0013,0x2017, +0x331b,0x331c,0x331d,0x331e, +0xffff +}; +unsigned short ccrtc_640x480x8[] = { +0x2c11, +0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07, +0x4009,0x000c,0x000d, +0xea10,0xdf12,0x5013,0x4014,0xdf15,0x0b16,0xc317,0xff18, +0x001a,0x221b,0x001d, +0xffff +}; +/* 640x480x16 */ +unsigned short cseq_640x480x16[] = { +0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707, +0x580b,0x580c,0x580d,0x580e, +0x0412,0x0013,0x2017, +0x331b,0x331c,0x331d,0x331e, +0xffff +}; +unsigned short ccrtc_640x480x16[] = { +0x2c11, +0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07, +0x4009,0x000c,0x000d, +0xea10,0xdf12,0xa013,0x4014,0xdf15,0x0b16,0xc317,0xff18, +0x001a,0x221b,0x001d, +0xffff +}; +/* 640x480x24 */ +unsigned short cseq_640x480x24[] = { +0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507, +0x580b,0x580c,0x580d,0x580e, +0x0412,0x0013,0x2017, +0x331b,0x331c,0x331d,0x331e, +0xffff +}; +unsigned short ccrtc_640x480x24[] = { +0x2c11, +0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07, +0x4009,0x000c,0x000d, +0xea10,0xdf12,0x0013,0x4014,0xdf15,0x0b16,0xc317,0xff18, +0x001a,0x321b,0x001d, +0xffff +}; +/* 800x600x8 */ +unsigned short cseq_800x600x8[] = { +0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107, +0x230b,0x230c,0x230d,0x230e, +0x0412,0x0013,0x2017, +0x141b,0x141c,0x141d,0x141e, +0xffff +}; +unsigned short ccrtc_800x600x8[] = { +0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007, +0x6009,0x000c,0x000d, +0x7d10,0x5712,0x6413,0x4014,0x5715,0x9816,0xc317,0xff18, +0x001a,0x221b,0x001d, +0xffff +}; +/* 800x600x16 */ +unsigned short cseq_800x600x16[] = { +0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707, +0x230b,0x230c,0x230d,0x230e, +0x0412,0x0013,0x2017, +0x141b,0x141c,0x141d,0x141e, +0xffff +}; +unsigned short ccrtc_800x600x16[] = { +0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007, +0x6009,0x000c,0x000d, +0x7d10,0x5712,0xc813,0x4014,0x5715,0x9816,0xc317,0xff18, +0x001a,0x221b,0x001d, +0xffff +}; +/* 800x600x24 */ +unsigned short cseq_800x600x24[] = { +0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507, +0x230b,0x230c,0x230d,0x230e, +0x0412,0x0013,0x2017, +0x141b,0x141c,0x141d,0x141e, +0xffff +}; +unsigned short ccrtc_800x600x24[] = { +0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007, +0x6009,0x000c,0x000d, +0x7d10,0x5712,0x2c13,0x4014,0x5715,0x9816,0xc317,0xff18, +0x001a,0x321b,0x001d, +0xffff +}; +/* 1024x768x8 */ +unsigned short cseq_1024x768x8[] = { +0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107, +0x760b,0x760c,0x760d,0x760e, +0x0412,0x0013,0x2017, +0x341b,0x341c,0x341d,0x341e, +0xffff +}; +unsigned short ccrtc_1024x768x8[] = { +0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507, +0x6009,0x000c,0x000d, +0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18, +0x001a,0x221b,0x001d, +0xffff +}; +/* 1024x768x16 */ +unsigned short cseq_1024x768x16[] = { +0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707, +0x760b,0x760c,0x760d,0x760e, +0x0412,0x0013,0x2017, +0x341b,0x341c,0x341d,0x341e, +0xffff +}; +unsigned short ccrtc_1024x768x16[] = { +0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507, +0x6009,0x000c,0x000d, +0x0310,0xff12,0x0013,0x4014,0xff15,0x2416,0xc317,0xff18, +0x001a,0x321b,0x001d, +0xffff +}; +/* 1024x768x24 */ +unsigned short cseq_1024x768x24[] = { +0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507, +0x760b,0x760c,0x760d,0x760e, +0x0412,0x0013,0x2017, +0x341b,0x341c,0x341d,0x341e, +0xffff +}; +unsigned short ccrtc_1024x768x24[] = { +0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507, +0x6009,0x000c,0x000d, +0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18, +0x001a,0x321b,0x001d, +0xffff +}; +/* 1280x1024x8 */ +unsigned short cseq_1280x1024x8[] = { +0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107, +0x760b,0x760c,0x760d,0x760e, +0x0412,0x0013,0x2017, +0x341b,0x341c,0x341d,0x341e, +0xffff +}; +unsigned short ccrtc_1280x1024x8[] = { +0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707, +0x6009,0x000c,0x000d, +0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18, +0x001a,0x221b,0x001d, +0xffff +}; +/* 1280x1024x16 */ +unsigned short cseq_1280x1024x16[] = { +0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707, +0x760b,0x760c,0x760d,0x760e, +0x0412,0x0013,0x2017, +0x341b,0x341c,0x341d,0x341e, +0xffff +}; +unsigned short ccrtc_1280x1024x16[] = { +0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707, +0x6009,0x000c,0x000d, +0x0310,0xff12,0x4013,0x4014,0xff15,0x2416,0xc317,0xff18, +0x001a,0x321b,0x001d, +0xffff +}; + + +cirrus_mode_t cirrus_modes[] = +{ + {0x5f,640,480,8,0x00, + cseq_640x480x8,cgraph_svgacolor,ccrtc_640x480x8,8, + 4,0,0,0,0,0,0,0,0}, + {0x64,640,480,16,0xe1, + cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16, + 6,5,11,6,5,5,0,0,0}, + {0x66,640,480,15,0xf0, + cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16, + 6,5,10,5,5,5,0,1,15}, + {0x71,640,480,24,0xe5, + cseq_640x480x24,cgraph_svgacolor,ccrtc_640x480x24,24, + 6,8,16,8,8,8,0,0,0}, + + {0x5c,800,600,8,0x00, + cseq_800x600x8,cgraph_svgacolor,ccrtc_800x600x8,8, + 4,0,0,0,0,0,0,0,0}, + {0x65,800,600,16,0xe1, + cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16, + 6,5,11,6,5,5,0,0,0}, + {0x67,800,600,15,0xf0, + cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16, + 6,5,10,5,5,5,0,1,15}, + + {0x60,1024,768,8,0x00, + cseq_1024x768x8,cgraph_svgacolor,ccrtc_1024x768x8,8, + 4,0,0,0,0,0,0,0,0}, + {0x74,1024,768,16,0xe1, + cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16, + 6,5,11,6,5,5,0,0,0}, + {0x68,1024,768,15,0xf0, + cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16, + 6,5,10,5,5,5,0,1,15}, + + {0x78,800,600,24,0xe5, + cseq_800x600x24,cgraph_svgacolor,ccrtc_800x600x24,24, + 6,8,16,8,8,8,0,0,0}, + {0x79,1024,768,24,0xe5, + cseq_1024x768x24,cgraph_svgacolor,ccrtc_1024x768x24,24, + 6,8,16,8,8,8,0,0,0}, + + {0x6d,1280,1024,8,0x00, + cseq_1280x1024x8,cgraph_svgacolor,ccrtc_1280x1024x8,8, + 4,0,0,0,0,0,0,0,0}, + {0x69,1280,1024,15,0xf0, + cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16, + 6,5,10,5,5,5,0,1,15}, + {0x75,1280,1024,16,0xe1, + cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16, + 6,5,11,6,5,5,0,0,0}, + + {0xfe,0,0,0,0,cseq_vga,cgraph_vga,ccrtc_vga,0, + 0xff,0,0,0,0,0,0,0,0}, + {0xff,0,0,0,0,0,0,0,0, + 0xff,0,0,0,0,0,0,0,0}, +}; + +unsigned char cirrus_id_table[] = { + // 5430 + 0xA0, 0x32, + // 5446 + 0xB8, 0x39, + + 0xff, 0xff +}; + + +unsigned short cirrus_vesa_modelist[] = { +// 640x480x8 + 0x101, 0x5f, +// 640x480x15 + 0x110, 0x66, +// 640x480x16 + 0x111, 0x64, +// 640x480x24 + 0x112, 0x71, +// 800x600x8 + 0x103, 0x5c, +// 800x600x15 + 0x113, 0x67, +// 800x600x16 + 0x114, 0x65, +// 800x600x24 + 0x115, 0x78, +// 1024x768x8 + 0x105, 0x60, +// 1024x768x15 + 0x116, 0x68, +// 1024x768x16 + 0x117, 0x74, +// 1024x768x24 + 0x118, 0x79, +// 1280x1024x8 + 0x107, 0x6d, +// 1280x1024x15 + 0x119, 0x69, +// 1280x1024x16 + 0x11a, 0x75, +// invalid + 0xffff,0xffff +}; + + +ASM_START + +cirrus_installed: +.ascii "cirrus-compatible VGA is detected" +.byte 0x0d,0x0a +.byte 0x0d,0x0a,0x00 + +cirrus_not_installed: +.ascii "cirrus-compatible VGA is not detected" +.byte 0x0d,0x0a +.byte 0x0d,0x0a,0x00 + +cirrus_vesa_vendorname: +cirrus_vesa_productname: +cirrus_vesa_oemname: +.ascii "VGABIOS Cirrus extension" +.byte 0 +cirrus_vesa_productrevision: +.ascii "1.0" +.byte 0 + +cirrus_init: + call cirrus_check + jnz no_cirrus + SET_INT_VECTOR(0x10, #0xC000, #cirrus_int10_handler) + mov al, #0x0f ; memory setup + mov dx, #0x3C4 + out dx, al + inc dx + in al, dx + and al, #0x18 + mov ah, al + mov al, #0x0a + dec dx + out dx, ax + mov ax, #0x0007 ; set vga mode + out dx, ax + mov ax, #0x0431 ; reset bitblt + mov dx, #0x3CE + out dx, ax + mov ax, #0x0031 + out dx, ax +no_cirrus: + ret + +cirrus_display_info: + push ds + push si + push cs + pop ds + call cirrus_check + mov si, #cirrus_not_installed + jnz cirrus_msgnotinstalled + mov si, #cirrus_installed + +cirrus_msgnotinstalled: + call _display_string + pop si + pop ds + ret + +cirrus_check: + push ax + push dx + mov ax, #0x9206 + mov dx, #0x3C4 + out dx, ax + inc dx + in al, dx + cmp al, #0x12 + pop dx + pop ax + ret + + +cirrus_int10_handler: + pushf + push bp + cmp ah, #0x00 ;; set video mode + jz cirrus_set_video_mode + cmp ah, #0x12 ;; cirrus extension + jz cirrus_extbios + cmp ah, #0x4F ;; VESA extension + jz cirrus_vesa + +cirrus_unhandled: + pop bp + popf + jmp vgabios_int10_handler + +cirrus_return: +#ifdef CIRRUS_DEBUG + call cirrus_debug_dump +#endif + pop bp + popf + iret + +cirrus_set_video_mode: +#ifdef CIRRUS_DEBUG + call cirrus_debug_dump +#endif + push si + push ax + push bx + push ds +#ifdef CIRRUS_VESA3_PMINFO + db 0x2e ;; cs: + mov si, [cirrus_vesa_sel0000_data] +#else + xor si, si +#endif + mov ds, si + xor bx, bx + mov [PM_BIOSMEM_VBE_MODE], bx + pop ds + pop bx + call cirrus_get_modeentry + jnc cirrus_set_video_mode_extended + mov al, #0xfe + call cirrus_get_modeentry_nomask + call cirrus_switch_mode + pop ax + pop si + jmp cirrus_unhandled + +cirrus_extbios: +#ifdef CIRRUS_DEBUG + call cirrus_debug_dump +#endif + cmp bl, #0x80 + jb cirrus_unhandled + cmp bl, #0xAF + ja cirrus_unhandled + push bx + and bx, #0x7F + shl bx, 1 + db 0x2e ;; cs: + mov bp, cirrus_extbios_handlers[bx] + pop bx + push #cirrus_return + push bp + ret + +cirrus_vesa: +#ifdef CIRRUS_DEBUG + call cirrus_debug_dump +#endif + cmp al, #0x0F + ja cirrus_vesa_not_handled + push bx + xor bx, bx + mov bl, al + shl bx, 1 + db 0x2e ;; cs: + mov bp, cirrus_vesa_handlers[bx] + pop bx + push #cirrus_return + push bp + ret + +cirrus_vesa_not_handled: + mov ax, #0x014F ;; not implemented + jmp cirrus_return + +#ifdef CIRRUS_DEBUG +cirrus_debug_dump: + push es + push ds + pusha + push cs + pop ds + call _cirrus_debugmsg + popa + pop ds + pop es + ret +#endif + +cirrus_set_video_mode_extended: + call cirrus_switch_mode + pop ax ;; mode + test al, #0x80 + jnz cirrus_set_video_mode_extended_1 + push ax + mov ax, #0xffff ; set to 0xff to keep win 2K happy + call cirrus_clear_vram + pop ax +cirrus_set_video_mode_extended_1: + and al, #0x7f + + push ds +#ifdef CIRRUS_VESA3_PMINFO + db 0x2e ;; cs: + mov si, [cirrus_vesa_sel0000_data] +#else + xor si, si +#endif + mov ds, si + mov [PM_BIOSMEM_CURRENT_MODE], al + pop ds + + mov al, #0x20 + + pop si + jmp cirrus_return + +cirrus_vesa_pmbios_init: + retf +cirrus_vesa_pmbios_entry: + pushf + push bp + cmp ah, #0x4F + jnz cirrus_vesa_pmbios_unimplemented + cmp al, #0x0F + ja cirrus_vesa_pmbios_unimplemented + push bx + xor bx, bx + mov bl, al + shl bx, 1 + db 0x2e ;; cs: + mov bp, cirrus_vesa_handlers[bx] + pop bx + push #cirrus_vesa_pmbios_return + push bp + ret +cirrus_vesa_pmbios_unimplemented: + mov ax, #0x014F +cirrus_vesa_pmbios_return: + pop bp + popf + retf + +; in si:mode table +cirrus_switch_mode: + push ds + push bx + push dx + push cs + pop ds + + mov bx, [si+10] ;; seq + mov dx, #0x3c4 + mov ax, #0x1206 + out dx, ax ;; Unlock cirrus special + call cirrus_switch_mode_setregs + + mov bx, [si+12] ;; graph + mov dx, #0x3ce + call cirrus_switch_mode_setregs + + mov bx, [si+14] ;; crtc + call cirrus_get_crtc + call cirrus_switch_mode_setregs + + mov dx, #0x3c6 + mov al, #0x00 + out dx, al + in al, dx + in al, dx + in al, dx + in al, dx + mov al, [si+8] ;; hidden dac + out dx, al + mov al, #0xff + out dx, al + + mov al, #0x00 + mov bl, [si+17] ;; memory model + or bl, bl + jz is_text_mode + mov al, #0x01 + cmp bl, #0x03 + jnz is_text_mode + or al, #0x40 +is_text_mode: + mov bl, #0x10 + call biosfn_get_single_palette_reg + and bh, #0xfe + or bh, al + call biosfn_set_single_palette_reg + + pop dx + pop bx + pop ds + ret + +cirrus_enable_16k_granularity: + push ax + push dx + mov dx, #0x3ce + mov al, #0x0b + out dx, al + inc dx + in al, dx + or al, #0x20 ;; enable 16k + out dx, al + pop dx + pop ax + ret + +cirrus_switch_mode_setregs: +csms_1: + mov ax, [bx] + cmp ax, #0xffff + jz csms_2 + out dx, ax + add bx, #0x2 + jmp csms_1 +csms_2: + ret + +cirrus_extbios_80h: + push dx + call cirrus_get_crtc + mov al, #0x27 + out dx, al + inc dx + in al, dx + mov bx, #_cirrus_id_table +c80h_1: + db 0x2e ;; cs: + mov ah, [bx] + cmp ah, al + jz c80h_2 + cmp ah, #0xff + jz c80h_2 + inc bx + inc bx + jmp c80h_1 +c80h_2: + db 0x2e ;; cs: + mov al, 0x1[bx] + pop dx + mov ah, #0x00 + xor bx, bx + ret + +cirrus_extbios_81h: + mov ax, #0x100 ;; XXX + ret +cirrus_extbios_82h: + push dx + call cirrus_get_crtc + xor ax, ax + mov al, #0x27 + out dx, al + inc dx + in al, dx + and al, #0x03 + mov ah, #0xAF + pop dx + ret + +cirrus_extbios_85h: + push cx + push dx + mov dx, #0x3C4 + mov al, #0x0f ;; get DRAM band width + out dx, al + inc dx + in al, dx + ;; al = 4 << bandwidth + mov cl, al + shr cl, #0x03 + and cl, #0x03 + cmp cl, #0x03 + je c85h2 + mov al, #0x04 + shl al, cl + jmp c85h3 +c85h2: +;; 4MB or 2MB + and al, #0x80 + mov al, #0x20 ;; 2 MB + je c85h3 + mov al, #0x40 ;; 4 MB +c85h3: + pop dx + pop cx + ret + +cirrus_extbios_9Ah: + mov ax, #0x4060 + mov cx, #0x1132 + ret + +cirrus_extbios_A0h: + call cirrus_get_modeentry + mov ah, #0x01 + sbb ah, #0x00 + mov bx, cirrus_extbios_A0h_callback + mov si, #0xffff + mov di, bx + mov ds, bx + mov es, bx + ret + +cirrus_extbios_A0h_callback: + ;; fatal: not implemented yet + cli + hlt + retf + +cirrus_extbios_A1h: + mov bx, #0x0E00 ;; IBM 8512/8513, color + ret + +cirrus_extbios_A2h: + mov al, #0x07 ;; HSync 31.5 - 64.0 kHz + ret + +cirrus_extbios_AEh: + mov al, #0x01 ;; High Refresh 75Hz + ret + +cirrus_extbios_unimplemented: + ret + +cirrus_vesa_00h: + push ds + push si + mov bp, di + push es + pop ds + cld + mov ax, [di] + cmp ax, #0x4256 ;; VB + jnz cv00_1 + mov ax, [di+2] + cmp ax, #0x3245 ;; E2 + jnz cv00_1 + ;; VBE2 + lea di, 0x14[bp] + mov ax, #0x0100 ;; soft ver. + stosw + mov ax, # cirrus_vesa_vendorname + stosw + mov ax, cs + stosw + mov ax, # cirrus_vesa_productname + stosw + mov ax, cs + stosw + mov ax, # cirrus_vesa_productrevision + stosw + mov ax, cs + stosw +cv00_1: + mov di, bp + mov ax, #0x4556 ;; VE + stosw + mov ax, #0x4153 ;; SA + stosw + mov ax, #0x0200 ;; v2.00 + stosw + mov ax, # cirrus_vesa_oemname + stosw + mov ax, cs + stosw + xor ax, ax ;; caps + stosw + stosw + lea ax, 0x40[bp] + stosw + mov ax, es + stosw + call cirrus_extbios_85h ;; vram in 64k + mov ah, #0x00 + stosw + + push cs + pop ds + lea di, 0x40[bp] + mov si, #_cirrus_vesa_modelist +cv00_2: + lodsw + stosw + add si, #2 + cmp ax, #0xffff + jnz cv00_2 + + mov ax, #0x004F + mov di, bp + pop si + pop ds + ret + +cirrus_vesa_01h: + mov ax, cx + and ax, #0x3fff + call cirrus_vesamode_to_mode + cmp ax, #0xffff + jnz cirrus_vesa_01h_1 + jmp cirrus_vesa_unimplemented +cirrus_vesa_01h_1: + push ds + push si + push cx + push dx + push bx + mov bp, di + cld + push cs + pop ds + call cirrus_get_modeentry_nomask + + push di + xor ax, ax + mov cx, #0x80 + rep + stosw ;; clear buffer + pop di + + mov ax, #0x003b ;; mode + stosw + mov ax, #0x0007 ;; attr + stosw + mov ax, #0x0010 ;; granularity =16K + stosw + mov ax, #0x0040 ;; size =64K + stosw + mov ax, #0xA000 ;; segment A + stosw + xor ax, ax ;; no segment B + stosw + mov ax, #cirrus_vesa_05h_farentry + stosw + mov ax, cs + stosw + call cirrus_get_line_offset_entry + stosw ;; bytes per scan line + mov ax, [si+2] ;; width + stosw + mov ax, [si+4] ;; height + stosw + mov ax, #0x08 + stosb + mov ax, #0x10 + stosb + mov al, #1 ;; count of planes + stosb + mov al, [si+6] ;; bpp + stosb + mov al, #0x1 ;; XXX number of banks + stosb + mov al, [si+17] + stosb ;; memory model + mov al, #0x0 ;; XXX size of bank in K + stosb + call cirrus_get_line_offset_entry + mov bx, [si+4] + mul bx ;; dx:ax=vramdisp + or ax, ax + jz cirrus_vesa_01h_3 + inc dx +cirrus_vesa_01h_3: + call cirrus_extbios_85h ;; al=vram in 64k + mov ah, #0x00 + mov cx, dx + xor dx, dx + div cx + dec ax + stosb ;; number of image pages = vramtotal/vramdisp-1 + mov al, #0x00 + stosb + + ;; v1.2+ stuffs + push si + add si, #18 + movsw + movsw + movsw + movsw + pop si + + mov ah, [si+16] + mov al, #0x0 + sub ah, #9 + rcl al, #1 ; bit 0=palette flag + stosb ;; direct screen mode info + + ;; v2.0+ stuffs + ;; 32-bit LFB address + xor ax, ax + stosw + call cirrus_get_lfb_addr + stosw + or ax, ax + jz cirrus_vesa_01h_4 + push di + mov di, bp + db 0x26 ;; es: + mov ax, [di] + or ax, #0x0080 ;; mode bit 7:LFB + stosw + pop di +cirrus_vesa_01h_4: + + xor ax, ax + stosw ; reserved + stosw ; reserved + stosw ; reserved + + mov ax, #0x004F + mov di, bp + pop bx + pop dx + pop cx + pop si + pop ds + + test cx, #0x4000 ;; LFB flag + jz cirrus_vesa_01h_5 + push cx + db 0x26 ;; es: + mov cx, [di] + cmp cx, #0x0080 ;; is LFB supported? + jnz cirrus_vesa_01h_6 + mov ax, #0x014F ;; error - no LFB +cirrus_vesa_01h_6: + pop cx +cirrus_vesa_01h_5: + ret + +cirrus_vesa_02h: + ;; XXX support CRTC registers + test bx, #0x3e00 + jnz cirrus_vesa_02h_2 ;; unknown flags + mov ax, bx + and ax, #0x1ff ;; bit 8-0 mode + cmp ax, #0x100 ;; legacy VGA mode + jb cirrus_vesa_02h_legacy + call cirrus_vesamode_to_mode + cmp ax, #0xffff + jnz cirrus_vesa_02h_1 +cirrus_vesa_02h_2: + jmp cirrus_vesa_unimplemented +cirrus_vesa_02h_legacy: +#ifdef CIRRUS_VESA3_PMINFO + db 0x2e ;; cs: + cmp byte ptr [cirrus_vesa_is_protected_mode], #0 + jnz cirrus_vesa_02h_2 +#endif // CIRRUS_VESA3_PMINFO + int #0x10 + mov ax, #0x004F + ret +cirrus_vesa_02h_1: + push si + push ax + call cirrus_get_modeentry_nomask + call cirrus_switch_mode + test bx, #0x4000 ;; LFB + jnz cirrus_vesa_02h_3 + call cirrus_enable_16k_granularity +cirrus_vesa_02h_3: + test bx, #0x8000 ;; no clear + jnz cirrus_vesa_02h_4 + push ax + xor ax,ax + call cirrus_clear_vram + pop ax +cirrus_vesa_02h_4: + pop ax + push ds +#ifdef CIRRUS_VESA3_PMINFO + db 0x2e ;; cs: + mov si, [cirrus_vesa_sel0000_data] +#else + xor si, si +#endif + mov ds, si + mov [PM_BIOSMEM_CURRENT_MODE], al + mov [PM_BIOSMEM_VBE_MODE], bx + pop ds + pop si + mov ax, #0x004F + ret + +cirrus_vesa_03h: + push ds +#ifdef CIRRUS_VESA3_PMINFO + db 0x2e ;; cs: + mov ax, [cirrus_vesa_sel0000_data] +#else + xor ax, ax +#endif + mov ds, ax + mov bx, # PM_BIOSMEM_VBE_MODE + mov ax, [bx] + mov bx, ax + test bx, bx + jnz cirrus_vesa_03h_1 + mov bx, # PM_BIOSMEM_CURRENT_MODE + mov al, [bx] + mov bl, al + xor bh, bh +cirrus_vesa_03h_1: + mov ax, #0x004f + pop ds + ret + +cirrus_vesa_05h_farentry: + call cirrus_vesa_05h + retf + +cirrus_vesa_05h: + cmp bl, #0x01 + ja cirrus_vesa_05h_1 + cmp bh, #0x00 + jz cirrus_vesa_05h_setmempage + cmp bh, #0x01 + jz cirrus_vesa_05h_getmempage +cirrus_vesa_05h_1: + jmp cirrus_vesa_unimplemented +cirrus_vesa_05h_setmempage: + or dh, dh ; address must be < 0x100 + jnz cirrus_vesa_05h_1 + push dx + mov al, bl ;; bl=bank number + add al, #0x09 + mov ah, dl ;; dx=window address in granularity + mov dx, #0x3ce + out dx, ax + pop dx + mov ax, #0x004F + ret +cirrus_vesa_05h_getmempage: + mov al, bl ;; bl=bank number + add al, #0x09 + mov dx, #0x3ce + out dx, al + inc dx + in al, dx + xor dx, dx + mov dl, al ;; dx=window address in granularity + mov ax, #0x004F + ret + +cirrus_vesa_06h: + mov ax, cx + cmp bl, #0x01 + je cirrus_vesa_06h_3 + cmp bl, #0x02 + je cirrus_vesa_06h_2 + jb cirrus_vesa_06h_1 + mov ax, #0x0100 + ret +cirrus_vesa_06h_1: + call cirrus_get_bpp_bytes + mov bl, al + xor bh, bh + mov ax, cx + mul bx +cirrus_vesa_06h_2: + call cirrus_set_line_offset +cirrus_vesa_06h_3: + call cirrus_get_bpp_bytes + mov bl, al + xor bh, bh + xor dx, dx + call cirrus_get_line_offset + push ax + div bx + mov cx, ax + pop bx + call cirrus_extbios_85h ;; al=vram in 64k + xor dx, dx + mov dl, al + xor ax, ax + div bx + mov dx, ax + mov ax, #0x004f + ret + +cirrus_vesa_07h: + cmp bl, #0x80 + je cirrus_vesa_07h_1 + cmp bl, #0x01 + je cirrus_vesa_07h_2 + jb cirrus_vesa_07h_1 + mov ax, #0x0100 + ret +cirrus_vesa_07h_1: + push dx + call cirrus_get_bpp_bytes + mov bl, al + xor bh, bh + mov ax, cx + mul bx + pop bx + push ax + call cirrus_get_line_offset + mul bx + pop bx + add ax, bx + jnc cirrus_vesa_07h_3 + inc dx +cirrus_vesa_07h_3: + push dx + and dx, #0x0003 + mov bx, #0x04 + div bx + pop dx + shr dx, #2 + call cirrus_set_start_addr + mov ax, #0x004f + ret +cirrus_vesa_07h_2: + call cirrus_get_start_addr + shl dx, #2 + push dx + mov bx, #0x04 + mul bx + pop bx + or dx, bx + push ax + call cirrus_get_line_offset + mov bx, ax + pop ax + div bx + push ax + push dx + call cirrus_get_bpp_bytes + mov bl, al + xor bh, bh + pop ax + xor dx, dx + div bx + mov cx, ax + pop dx + mov ax, #0x004f + ret + +cirrus_vesa_unimplemented: + mov ax, #0x014F ;; not implemented + ret + + +;; in ax:vesamode, out ax:cirrusmode +cirrus_vesamode_to_mode: + push ds + push cx + push si + push cs + pop ds + mov cx, #0xffff + mov si, #_cirrus_vesa_modelist +cvtm_1: + cmp [si],ax + jz cvtm_2 + cmp [si],cx + jz cvtm_2 + add si, #4 + jmp cvtm_1 +cvtm_2: + mov ax,[si+2] + pop si + pop cx + pop ds + ret + + ; cirrus_get_crtc + ;; NOTE - may be called in protected mode +cirrus_get_crtc: + push ds + push ax + mov dx, #0x3cc + in al, dx + and al, #0x01 + shl al, #5 + mov dx, #0x3b4 + add dl, al + pop ax + pop ds + ret + +;; in - al:mode, out - cflag:result, si:table, ax:destroyed +cirrus_get_modeentry: + and al, #0x7f +cirrus_get_modeentry_nomask: + mov si, #_cirrus_modes +cgm_1: + db 0x2e ;; cs: + mov ah, [si] + cmp al, ah + jz cgm_2 + cmp ah, #0xff + jz cgm_4 + add si, # CIRRUS_MODE_SIZE + jmp cgm_1 +cgm_4: + xor si, si + stc ;; video mode is not supported + jmp cgm_3 +cgm_2: + clc ;; video mode is supported +cgm_3: + ret + + ; get LFB address + ; out - ax:LFB address (high 16 bit) + ;; NOTE - may be called in protected mode +cirrus_get_lfb_addr: + push cx + push dx + push eax + xor cx, cx + mov dl, #0x00 + call cirrus_pci_read + cmp ax, #0xffff + jz cirrus_get_lfb_addr_5 + cirrus_get_lfb_addr_3: + mov dl, #0x00 + call cirrus_pci_read + cmp ax, #0x1013 ;; cirrus + jz cirrus_get_lfb_addr_4 + add cx, #0x8 + cmp cx, #0x200 ;; search bus #0 and #1 + jb cirrus_get_lfb_addr_3 + cirrus_get_lfb_addr_5: + xor dx, dx ;; no LFB + jmp cirrus_get_lfb_addr_6 + cirrus_get_lfb_addr_4: + mov dl, #0x10 ;; I/O space #0 + call cirrus_pci_read + test ax, #0xfff1 + jnz cirrus_get_lfb_addr_5 + shr eax, #16 + mov dx, ax ;; LFB address + cirrus_get_lfb_addr_6: + pop eax + mov ax, dx + pop dx + pop cx + ret + +cirrus_pci_read: + mov eax, #0x00800000 + mov ax, cx + shl eax, #8 + mov al, dl + mov dx, #0xcf8 + out dx, eax + add dl, #4 + in eax, dx + ret + +;; out - al:bytes per pixel +cirrus_get_bpp_bytes: + push dx + mov dx, #0x03c4 + mov al, #0x07 + out dx, al + inc dx + in al, dx + and al, #0x0e + cmp al, #0x06 + jne cirrus_get_bpp_bytes_1 + and al, #0x02 +cirrus_get_bpp_bytes_1: + shr al, #1 + cmp al, #0x04 + je cirrus_get_bpp_bytes_2 + inc al +cirrus_get_bpp_bytes_2: + pop dx + ret + +;; in - ax: new line offset +cirrus_set_line_offset: + shr ax, #3 + push ax + call cirrus_get_crtc + mov al, #0x13 + out dx, al + inc dx + pop ax + out dx, al + dec dx + mov al, #0x1b + out dx, al + inc dx + shl ah, #4 + in al, dx + and al, #ef + or al, ah + out dx, al + ret + +;; out - ax: active line offset +cirrus_get_line_offset: + push dx + push bx + call cirrus_get_crtc + mov al, #0x13 + out dx, al + inc dx + in al, dx + mov bl, al + dec dx + mov al, #0x1b + out dx, al + inc dx + in al, dx + mov ah, al + shr ah, #4 + and ah, #0x01 + mov al, bl + shl ax, #3 + pop bx + pop dx + ret + +;; in - si: table +;; out - ax: line offset for mode +cirrus_get_line_offset_entry: + push bx + mov bx, [si+14] ;; crtc table + push bx +offset_loop1: + mov ax, [bx] + cmp al, #0x13 + je offset_found1 + inc bx + inc bx + jnz offset_loop1 +offset_found1: + xor al, al + shr ax, #5 + pop bx + push ax +offset_loop2: + mov ax, [bx] + cmp al, #0x1b + je offset_found2 + inc bx + inc bx + jnz offset_loop2 +offset_found2: + pop bx + and ax, #0x1000 + shr ax, #1 + or ax, bx + pop bx + ret + +;; in - new address in DX:AX +cirrus_set_start_addr: + push bx + push dx + push ax + call cirrus_get_crtc + mov al, #0x0d + out dx, al + inc dx + pop ax + out dx, al + dec dx + mov al, #0x0c + out dx, al + inc dx + mov al, ah + out dx, al + dec dx + mov al, #0x1d + out dx, al + inc dx + in al, dx + and al, #0x7f + pop bx + mov ah, bl + shl bl, #4 + and bl, #0x80 + or al, bl + out dx, al + dec dx + mov bl, ah + and ah, #0x01 + shl bl, #1 + and bl, #0x0c + or ah, bl + mov al, #0x1b + out dx, al + inc dx + in al, dx + and al, #0xf2 + or al, ah + out dx, al + pop bx + ret + +;; out - current address in DX:AX +cirrus_get_start_addr: + push bx + call cirrus_get_crtc + mov al, #0x0c + out dx, al + inc dx + in al, dx + mov ah, al + dec dx + mov al, #0x0d + out dx, al + inc dx + in al, dx + push ax + dec dx + mov al, #0x1b + out dx, al + inc dx + in al, dx + dec dx + mov bl, al + and al, #0x01 + and bl, #0x0c + shr bl, #1 + or bl, al + mov al, #0x1d + out dx, al + inc dx + in al, dx + and al, #0x80 + shr al, #4 + or bl, al + mov dl, bl + xor dh, dh + pop ax + pop bx + ret + +cirrus_clear_vram: + pusha + push es + mov si, ax + + call cirrus_enable_16k_granularity + call cirrus_extbios_85h + shl al, #2 + mov bl, al + xor ah,ah +cirrus_clear_vram_1: + mov al, #0x09 + mov dx, #0x3ce + out dx, ax + push ax + mov cx, #0xa000 + mov es, cx + xor di, di + mov ax, si + mov cx, #8192 + cld + rep + stosw + pop ax + inc ah + cmp ah, bl + jne cirrus_clear_vram_1 + + pop es + popa + ret + +cirrus_extbios_handlers: + ;; 80h + dw cirrus_extbios_80h + dw cirrus_extbios_81h + dw cirrus_extbios_82h + dw cirrus_extbios_unimplemented + ;; 84h + dw cirrus_extbios_unimplemented + dw cirrus_extbios_85h + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + ;; 88h + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + ;; 8Ch + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + ;; 90h + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + ;; 94h + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + ;; 98h + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + dw cirrus_extbios_9Ah + dw cirrus_extbios_unimplemented + ;; 9Ch + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + ;; A0h + dw cirrus_extbios_A0h + dw cirrus_extbios_A1h + dw cirrus_extbios_A2h + dw cirrus_extbios_unimplemented + ;; A4h + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + ;; A8h + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + ;; ACh + dw cirrus_extbios_unimplemented + dw cirrus_extbios_unimplemented + dw cirrus_extbios_AEh + dw cirrus_extbios_unimplemented + +cirrus_vesa_handlers: + ;; 00h + dw cirrus_vesa_00h + dw cirrus_vesa_01h + dw cirrus_vesa_02h + dw cirrus_vesa_03h + ;; 04h + dw cirrus_vesa_unimplemented + dw cirrus_vesa_05h + dw cirrus_vesa_06h + dw cirrus_vesa_07h + ;; 08h + dw cirrus_vesa_unimplemented + dw cirrus_vesa_unimplemented + dw cirrus_vesa_unimplemented + dw cirrus_vesa_unimplemented + ;; 0Ch + dw cirrus_vesa_unimplemented + dw cirrus_vesa_unimplemented + dw cirrus_vesa_unimplemented + dw cirrus_vesa_unimplemented + + + +ASM_END + +#ifdef CIRRUS_VESA3_PMINFO +ASM_START +cirrus_vesa_pminfo: + /* + 0 */ + .byte 0x50,0x4d,0x49,0x44 ;; signature[4] + /* + 4 */ + dw cirrus_vesa_pmbios_entry ;; entry_bios + dw cirrus_vesa_pmbios_init ;; entry_init + /* + 8 */ +cirrus_vesa_sel0000_data: + dw 0x0000 ;; sel_00000 +cirrus_vesa_selA000_data: + dw 0xA000 ;; sel_A0000 + /* +12 */ +cirrus_vesa_selB000_data: + dw 0xB000 ;; sel_B0000 +cirrus_vesa_selB800_data: + dw 0xB800 ;; sel_B8000 + /* +16 */ +cirrus_vesa_selC000_data: + dw 0xC000 ;; sel_C0000 +cirrus_vesa_is_protected_mode: + ;; protected mode flag and checksum + dw (~((0xf2 + (cirrus_vesa_pmbios_entry >> 8) + (cirrus_vesa_pmbios_entry) \ + + (cirrus_vesa_pmbios_init >> 8) + (cirrus_vesa_pmbios_init)) & 0xff) << 8) + 0x01 +ASM_END +#endif // CIRRUS_VESA3_PMINFO + + +#ifdef CIRRUS_DEBUG +static void cirrus_debugmsg(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS) + Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS; +{ + if((GET_AH()!=0x0E)&&(GET_AH()!=0x02)&&(GET_AH()!=0x09)&&(AX!=0x4F05)) + printf("vgabios call ah%02x al%02x bx%04x cx%04x dx%04x\n",GET_AH(),GET_AL(),BX,CX,DX); +} +#endif diff --git a/palacios/src/vmboot/vgabios/dataseghack b/palacios/src/vmboot/vgabios/dataseghack new file mode 100755 index 0000000..02a2d4c --- /dev/null +++ b/palacios/src/vmboot/vgabios/dataseghack @@ -0,0 +1,23 @@ +#!/bin/bash + +awk \ + 'BEGIN { }\ + /^\.text/,/DATA_SEG_DEFS_HERE/ { print }\ + END { }'\ + $1 > temp.awk.1 + +awk \ + 'BEGIN { i = 0; last = "hello" }\ + /BLOCK_STRINGS_BEGIN/,/^\.bss/ { if ( i > 1 ) { print last } last = $0; i = i + 1 }\ + END { }'\ + $1 > temp.awk.2 + +awk \ + 'BEGIN { }\ + /DATA_SEG_DEFS_HERE/,/BLOCK_STRINGS_BEGIN/ { print }\ + END { }'\ + $1 > temp.awk.3 + +cp $1 $1.orig +cat temp.awk.1 temp.awk.2 temp.awk.3 | sed -e 's/^\.data//' -e 's/^\.bss//' -e 's/^\.text//' > $1 +/bin/rm -f temp.awk.1 temp.awk.2 temp.awk.3 $1.orig diff --git a/palacios/src/vmboot/vgabios/vbe.c b/palacios/src/vmboot/vgabios/vbe.c new file mode 100644 index 0000000..8c06473 --- /dev/null +++ b/palacios/src/vmboot/vgabios/vbe.c @@ -0,0 +1,1068 @@ +// ============================================================================================ +// +// Copyright (C) 2002 Jeroen Janssen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// ============================================================================================ +// +// This VBE is part of the VGA Bios specific to the plex86/bochs Emulated VGA card. +// You can NOT drive any physical vga card with it. +// +// ============================================================================================ +// +// This VBE Bios is based on information taken from : +// - VESA BIOS EXTENSION (VBE) Core Functions Standard Version 3.0 located at www.vesa.org +// +// ============================================================================================ + + +// defines available +// enable LFB support +#define VBE_HAVE_LFB + +// disable VESA/VBE2 check in vbe info +//#define VBE2_NO_VESA_CHECK + +// dynamicly generate a mode_info list +#define DYN_LIST + + +#include "vbe.h" +#include "vbetables.h" + + +// The current OEM Software Revision of this VBE Bios +#define VBE_OEM_SOFTWARE_REV 0x0002; + +extern char vbebios_copyright; +extern char vbebios_vendor_name; +extern char vbebios_product_name; +extern char vbebios_product_revision; + +#ifndef DYN_LIST +extern Bit16u vbebios_mode_list; +#endif + +ASM_START +// FIXME: 'merge' these (c) etc strings with the vgabios.c strings? +_vbebios_copyright: +.ascii "Bochs/Plex86 VBE(C) 2003 http://savannah.nongnu.org/projects/vgabios/" +.byte 0x00 + +_vbebios_vendor_name: +.ascii "Bochs/Plex86 Developers" +.byte 0x00 + +_vbebios_product_name: +.ascii "Bochs/Plex86 VBE Adapter" +.byte 0x00 + +_vbebios_product_revision: +.ascii "$Id: vbe.c,v 1.1 2007/11/29 20:26:38 pdinda Exp $" +.byte 0x00 + +_vbebios_info_string: +.ascii "Bochs VBE Display Adapter enabled" +.byte 0x0a,0x0d +.byte 0x0a,0x0d +.byte 0x00 + +_no_vbebios_info_string: +.ascii "NO Bochs VBE Support available!" +.byte 0x0a,0x0d +.byte 0x0a,0x0d +.byte 0x00 + +#if defined(USE_BX_INFO) || defined(DEBUG) +msg_vbe_init: +.ascii "VBE Bios $Id: vbe.c,v 1.1 2007/11/29 20:26:38 pdinda Exp $" +.byte 0x0a,0x0d, 0x00 +#endif + +#ifndef DYN_LIST +// FIXME: for each new mode add a statement here +// at least until dynamic list creation is working +_vbebios_mode_list: + +.word VBE_VESA_MODE_640X400X8 +.word VBE_VESA_MODE_640X480X8 +.word VBE_VESA_MODE_800X600X4 +.word VBE_VESA_MODE_800X600X8 +.word VBE_VESA_MODE_1024X768X8 +.word VBE_VESA_MODE_640X480X1555 +.word VBE_VESA_MODE_640X480X565 +.word VBE_VESA_MODE_640X480X888 +.word VBE_VESA_MODE_800X600X1555 +.word VBE_VESA_MODE_800X600X565 +.word VBE_VESA_MODE_800X600X888 +.word VBE_VESA_MODE_1024X768X1555 +.word VBE_VESA_MODE_1024X768X565 +.word VBE_VESA_MODE_1024X768X888 +.word VBE_OWN_MODE_640X480X8888 +.word VBE_OWN_MODE_800X600X8888 +.word VBE_OWN_MODE_1024X768X8888 +.word VBE_OWN_MODE_320X200X8 +.word VBE_VESA_MODE_END_OF_LIST +#endif + +; DISPI ioport functions + +dispi_get_id: + push dx + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_ID + out dx, ax + mov dx, # VBE_DISPI_IOPORT_DATA + in ax, dx + pop dx + ret + +dispi_set_id: + push dx + push ax + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_ID + out dx, ax + pop ax + mov dx, # VBE_DISPI_IOPORT_DATA + out dx, ax + pop dx + ret +ASM_END + +static void dispi_set_xres(xres) + Bit16u xres; +{ +ASM_START + push bp + mov bp, sp + push ax + push dx + + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_XRES + out dx, ax + mov dx, # VBE_DISPI_IOPORT_DATA + mov ax, 4[bp] ; xres + out dx, ax + push ax + mov dx, #0x03d4 + mov ax, #0x0011 + out dx, ax + mov dx, #0x03d4 + pop ax + push ax + shr ax, #3 + dec ax + mov ah, al + mov al, #0x01 + out dx, ax + pop ax + call vga_set_virt_width + + pop dx + pop ax + pop bp +ASM_END +} + +static void dispi_set_yres(yres) + Bit16u yres; +{ + outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_YRES); + outw(VBE_DISPI_IOPORT_DATA,yres); +} + +static void dispi_set_bpp(bpp) + Bit16u bpp; +{ + outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_BPP); + outw(VBE_DISPI_IOPORT_DATA,bpp); +} + +ASM_START +; AL = bits per pixel / AH = bytes per pixel +dispi_get_bpp: + push dx + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_BPP + out dx, ax + mov dx, # VBE_DISPI_IOPORT_DATA + in ax, dx + mov ah, al + shr ah, 3 + test al, #0x07 + jz get_bpp_noinc + inc ah +get_bpp_noinc: + pop dx + ret + +_dispi_get_max_bpp: + push dx + push bx + call dispi_get_enable + mov bx, ax + or ax, # VBE_DISPI_GETCAPS + call _dispi_set_enable + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_BPP + out dx, ax + mov dx, # VBE_DISPI_IOPORT_DATA + in ax, dx + push ax + mov ax, bx + call _dispi_set_enable + pop ax + pop bx + pop dx + ret + +_dispi_set_enable: + push dx + push ax + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_ENABLE + out dx, ax + pop ax + mov dx, # VBE_DISPI_IOPORT_DATA + out dx, ax + pop dx + ret + +dispi_get_enable: + push dx + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_ENABLE + out dx, ax + mov dx, # VBE_DISPI_IOPORT_DATA + in ax, dx + pop dx + ret + +_dispi_set_bank: + push dx + push ax + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_BANK + out dx, ax + pop ax + mov dx, # VBE_DISPI_IOPORT_DATA + out dx, ax + pop dx + ret + +dispi_get_bank: + push dx + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_BANK + out dx, ax + mov dx, # VBE_DISPI_IOPORT_DATA + in ax, dx + pop dx + ret +ASM_END + +static void dispi_set_bank_farcall() +{ +ASM_START + cmp bx,#0x0100 + je dispi_set_bank_farcall_get + or bx,bx + jnz dispi_set_bank_farcall_error + push dx + mov ax,# VBE_DISPI_INDEX_BANK + mov dx,# VBE_DISPI_IOPORT_INDEX + out dx,ax + pop ax + mov dx,# VBE_DISPI_IOPORT_DATA + out dx,ax + retf +dispi_set_bank_farcall_get: + mov ax,# VBE_DISPI_INDEX_BANK + mov dx,# VBE_DISPI_IOPORT_INDEX + out dx,ax + mov dx,# VBE_DISPI_IOPORT_DATA + in ax,dx + mov dx,ax + retf +dispi_set_bank_farcall_error: + mov ax,#0x014F + retf +ASM_END +} + +ASM_START +dispi_set_x_offset: + push dx + push ax + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_X_OFFSET + out dx, ax + pop ax + mov dx, # VBE_DISPI_IOPORT_DATA + out dx, ax + pop dx + ret + +dispi_get_x_offset: + push dx + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_X_OFFSET + out dx, ax + mov dx, # VBE_DISPI_IOPORT_DATA + in ax, dx + pop dx + ret + +dispi_set_y_offset: + push dx + push ax + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_Y_OFFSET + out dx, ax + pop ax + mov dx, # VBE_DISPI_IOPORT_DATA + out dx, ax + pop dx + ret + +dispi_get_y_offset: + push dx + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_Y_OFFSET + out dx, ax + mov dx, # VBE_DISPI_IOPORT_DATA + in ax, dx + pop dx + ret + +vga_set_virt_width: + push ax + push bx + push dx + mov bx, ax + call dispi_get_bpp + cmp al, #0x04 + ja set_width_svga + shr bx, #2 +set_width_svga: + shr bx, #2 + mov dx, #0x03d4 + mov ah, bl + mov al, #0x13 + out dx, ax + pop dx + pop bx + pop ax + ret + +dispi_set_virt_width: + call vga_set_virt_width + push dx + push ax + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_VIRT_WIDTH + out dx, ax + pop ax + mov dx, # VBE_DISPI_IOPORT_DATA + out dx, ax + pop dx + ret + +dispi_get_virt_width: + push dx + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_VIRT_WIDTH + out dx, ax + mov dx, # VBE_DISPI_IOPORT_DATA + in ax, dx + pop dx + ret + +dispi_get_virt_height: + push dx + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_VIRT_HEIGHT + out dx, ax + mov dx, # VBE_DISPI_IOPORT_DATA + in ax, dx + pop dx + ret +ASM_END + + +// ModeInfo helper function +static ModeInfoListItem* mode_info_find_mode(mode, using_lfb) + Bit16u mode; Boolean using_lfb; +{ + ModeInfoListItem *cur_info=&mode_info_list; + + while (cur_info->mode != VBE_VESA_MODE_END_OF_LIST) + { + if (cur_info->mode == mode) + { + if (!using_lfb) + { + return cur_info; + } + else if (cur_info->info.ModeAttributes & VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE) + { + return cur_info; + } + else + { + cur_info++; + } + } + else + { + cur_info++; + } + } + + return 0; +} + +ASM_START + +; Has VBE display - Returns true if VBE display detected + +_vbe_has_vbe_display: + push ds + push bx + mov ax, # BIOSMEM_SEG + mov ds, ax + mov bx, # BIOSMEM_VBE_FLAG + mov al, [bx] + and al, #0x01 + xor ah, ah + pop bx + pop ds + ret + +; VBE Init - Initialise the Vesa Bios Extension Code +; This function does a sanity check on the host side display code interface. + +vbe_init: + mov ax, # VBE_DISPI_ID0 + call dispi_set_id + call dispi_get_id + cmp ax, # VBE_DISPI_ID0 + jne no_vbe_interface + push ds + push bx + mov ax, # BIOSMEM_SEG + mov ds, ax + mov bx, # BIOSMEM_VBE_FLAG + mov al, #0x01 + mov [bx], al + pop bx + pop ds + mov ax, # VBE_DISPI_ID3 + call dispi_set_id +no_vbe_interface: +#if defined(USE_BX_INFO) || defined(DEBUG) + mov bx, #msg_vbe_init + push bx + call _printf + inc sp + inc sp +#endif + ret + +; VBE Display Info - Display information on screen about the VBE + +vbe_display_info: + call _vbe_has_vbe_display + test ax, ax + jz no_vbe_flag + mov ax, #0xc000 + mov ds, ax + mov si, #_vbebios_info_string + jmp _display_string +no_vbe_flag: + mov ax, #0xc000 + mov ds, ax + mov si, #_no_vbebios_info_string + jmp _display_string +ASM_END + +/** Function 00h - Return VBE Controller Information + * + * Input: + * AX = 4F00h + * ES:DI = Pointer to buffer in which to place VbeInfoBlock structure + * (VbeSignature should be VBE2 when VBE 2.0 information is desired and + * the info block is 512 bytes in size) + * Output: + * AX = VBE Return Status + * + */ +void vbe_biosfn_return_controller_information(AX, ES, DI) +Bit16u *AX;Bit16u ES;Bit16u DI; +{ + Bit16u ss=get_SS(); + VbeInfoBlock vbe_info_block; + Bit16u status; + Bit16u result; + Bit16u vbe2_info; + Bit16u cur_mode=0; + Bit16u cur_ptr=34; + ModeInfoListItem *cur_info=&mode_info_list; + + status = read_word(ss, AX); + +#ifdef DEBUG + printf("VBE vbe_biosfn_return_vbe_info ES%x DI%x AX%x\n",ES,DI,status); +#endif + + vbe2_info = 0; +#ifdef VBE2_NO_VESA_CHECK +#else + // get vbe_info_block into local variable + memcpyb(ss, &vbe_info_block, ES, DI, sizeof(vbe_info_block)); + + // check for VBE2 signature + if (((vbe_info_block.VbeSignature[0] == 'V') && + (vbe_info_block.VbeSignature[1] == 'B') && + (vbe_info_block.VbeSignature[2] == 'E') && + (vbe_info_block.VbeSignature[3] == '2')) || + + ((vbe_info_block.VbeSignature[0] == 'V') && + (vbe_info_block.VbeSignature[1] == 'E') && + (vbe_info_block.VbeSignature[2] == 'S') && + (vbe_info_block.VbeSignature[3] == 'A')) ) + { + vbe2_info = 1; +#ifdef DEBUG + printf("VBE correct VESA/VBE2 signature found\n"); +#endif + } +#endif + + // VBE Signature + vbe_info_block.VbeSignature[0] = 'V'; + vbe_info_block.VbeSignature[1] = 'E'; + vbe_info_block.VbeSignature[2] = 'S'; + vbe_info_block.VbeSignature[3] = 'A'; + + // VBE Version supported + vbe_info_block.VbeVersion = 0x0200; + + // OEM String + vbe_info_block.OemStringPtr_Seg = 0xc000; + vbe_info_block.OemStringPtr_Off = &vbebios_copyright; + + // Capabilities + vbe_info_block.Capabilities[0] = VBE_CAPABILITY_8BIT_DAC; + vbe_info_block.Capabilities[1] = 0; + vbe_info_block.Capabilities[2] = 0; + vbe_info_block.Capabilities[3] = 0; + +#ifdef DYN_LIST + // VBE Video Mode Pointer (dynamicly generated from the mode_info_list) + vbe_info_block.VideoModePtr_Seg= ES ; + vbe_info_block.VideoModePtr_Off= DI + 34; +#else + // VBE Video Mode Pointer (staticly in rom) + vbe_info_block.VideoModePtr_Seg = 0xc000; + vbe_info_block.VideoModePtr_Off = &vbebios_mode_list; +#endif + + // VBE Total Memory (in 64b blocks) + vbe_info_block.TotalMemory = VBE_TOTAL_VIDEO_MEMORY_DIV_64K; + + if (vbe2_info) + { + // OEM Stuff + vbe_info_block.OemSoftwareRev = VBE_OEM_SOFTWARE_REV; + vbe_info_block.OemVendorNamePtr_Seg = 0xc000; + vbe_info_block.OemVendorNamePtr_Off = &vbebios_vendor_name; + vbe_info_block.OemProductNamePtr_Seg = 0xc000; + vbe_info_block.OemProductNamePtr_Off = &vbebios_product_name; + vbe_info_block.OemProductRevPtr_Seg = 0xc000; + vbe_info_block.OemProductRevPtr_Off = &vbebios_product_revision; + + // copy updates in vbe_info_block back + memcpyb(ES, DI, ss, &vbe_info_block, sizeof(vbe_info_block)); + } + else + { + // copy updates in vbe_info_block back (VBE 1.x compatibility) + memcpyb(ES, DI, ss, &vbe_info_block, 256); + } + +#ifdef DYN_LIST + do + { + if (cur_info->info.BitsPerPixel <= dispi_get_max_bpp()) { +#ifdef DEBUG + printf("VBE found mode %x => %x\n", cur_info->mode,cur_mode); +#endif + write_word(ES, DI + cur_ptr, cur_info->mode); + cur_mode++; + cur_ptr+=2; + } + cur_info++; + } while (cur_info->mode != VBE_VESA_MODE_END_OF_LIST); + + // Add vesa mode list terminator + write_word(ES, DI + cur_ptr, cur_info->mode); +#endif + + result = 0x4f; + + write_word(ss, AX, result); +} + + +/** Function 01h - Return VBE Mode Information + * + * Input: + * AX = 4F01h + * CX = Mode Number + * ES:DI = Pointer to buffer in which to place ModeInfoBlock structure + * Output: + * AX = VBE Return Status + * + */ +void vbe_biosfn_return_mode_information(AX, CX, ES, DI) +Bit16u *AX;Bit16u CX; Bit16u ES;Bit16u DI; +{ + Bit16u result=0x0100; + Bit16u ss=get_SS(); + ModeInfoBlock info; + ModeInfoListItem *cur_info; + Boolean using_lfb; + +#ifdef DEBUG + printf("VBE vbe_biosfn_return_mode_information ES%x DI%x CX%x\n",ES,DI,CX); +#endif + + using_lfb=((CX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER); + + CX = (CX & 0x1ff); + + cur_info = mode_info_find_mode(CX, using_lfb, &cur_info); + + if (cur_info != 0) + { +#ifdef DEBUG + printf("VBE found mode %x\n",CX); +#endif + memsetb(ss, &info, 0, sizeof(ModeInfoBlock)); + memcpyb(ss, &info, 0xc000, &(cur_info->info), sizeof(ModeInfoBlockCompact)); + if (info.WinAAttributes & VBE_WINDOW_ATTRIBUTE_RELOCATABLE) { + info.WinFuncPtr = 0xC0000000UL; + *(Bit16u *)&(info.WinFuncPtr) = (Bit16u)(dispi_set_bank_farcall); + } + + result = 0x4f; + } + else + { +#ifdef DEBUG + printf("VBE *NOT* found mode %x\n",CX); +#endif + result = 0x100; + } + + if (result == 0x4f) + { + // copy updates in mode_info_block back + memcpyb(ES, DI, ss, &info, sizeof(info)); + } + + write_word(ss, AX, result); +} + +/** Function 02h - Set VBE Mode + * + * Input: + * AX = 4F02h + * BX = Desired Mode to set + * ES:DI = Pointer to CRTCInfoBlock structure + * Output: + * AX = VBE Return Status + * + */ +void vbe_biosfn_set_mode(AX, BX, ES, DI) +Bit16u *AX;Bit16u BX; Bit16u ES;Bit16u DI; +{ + Bit16u ss = get_SS(); + Bit16u result; + ModeInfoListItem *cur_info; + Boolean using_lfb; + Bit8u no_clear; + Bit8u lfb_flag; + + using_lfb=((BX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER); + lfb_flag=using_lfb?VBE_DISPI_LFB_ENABLED:0; + no_clear=((BX & VBE_MODE_PRESERVE_DISPLAY_MEMORY) == VBE_MODE_PRESERVE_DISPLAY_MEMORY)?VBE_DISPI_NOCLEARMEM:0; + + BX = (BX & 0x1ff); + + //result=read_word(ss,AX); + + // check for non vesa mode + if (BXinfo.XResolution, + cur_info->info.YResolution, + cur_info->info.BitsPerPixel); +#endif + + // first disable current mode (when switching between vesa modi) + dispi_set_enable(VBE_DISPI_DISABLED); + + if (cur_info->mode == VBE_VESA_MODE_800X600X4) + { + biosfn_set_video_mode(0x6a); + } + + dispi_set_bpp(cur_info->info.BitsPerPixel); + dispi_set_xres(cur_info->info.XResolution); + dispi_set_yres(cur_info->info.YResolution); + dispi_set_bank(0); + dispi_set_enable(VBE_DISPI_ENABLED | no_clear | lfb_flag); + + write_word(BIOSMEM_SEG,BIOSMEM_VBE_MODE,BX); + write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60 | no_clear)); + + result = 0x4f; + } + else + { +#ifdef DEBUG + printf("VBE *NOT* found mode %x\n" , BX); +#endif + result = 0x100; + + // FIXME: redirect non VBE modi to normal VGA bios operation + // (switch back to VGA mode + if (BX == 3) + result = 0x4f; + } + + write_word(ss, AX, result); +} + +/** Function 03h - Return Current VBE Mode + * + * Input: + * AX = 4F03h + * Output: + * AX = VBE Return Status + * BX = Current VBE Mode + * + */ +ASM_START +vbe_biosfn_return_current_mode: + push ds + mov ax, # BIOSMEM_SEG + mov ds, ax + call dispi_get_enable + and ax, # VBE_DISPI_ENABLED + jz no_vbe_mode + mov bx, # BIOSMEM_VBE_MODE + mov ax, [bx] + mov bx, ax + jnz vbe_03_ok +no_vbe_mode: + mov bx, # BIOSMEM_CURRENT_MODE + mov al, [bx] + mov bl, al + xor bh, bh +vbe_03_ok: + mov ax, #0x004f + pop ds + ret +ASM_END + + +/** Function 04h - Save/Restore State + * + * Input: + * AX = 4F04h + * DL = 00h Return Save/Restore State buffer size + * 01h Save State + * 02h Restore State + * CX = Requested states + * ES:BX = Pointer to buffer (if DL <> 00h) + * Output: + * AX = VBE Return Status + * BX = Number of 64-byte blocks to hold the state buffer (if DL=00h) + * + */ +void vbe_biosfn_save_restore_state(AX, DL, CX, ES, BX) +{ +} + + +/** Function 05h - Display Window Control + * + * Input: + * AX = 4F05h + * (16-bit) BH = 00h Set memory window + * = 01h Get memory window + * BL = Window number + * = 00h Window A + * = 01h Window B + * DX = Window number in video memory in window + * granularity units (Set Memory Window only) + * Note: + * If this function is called while in a linear frame buffer mode, + * this function must fail with completion code AH=03h + * + * Output: + * AX = VBE Return Status + * DX = Window number in window granularity units + * (Get Memory Window only) + */ +ASM_START +vbe_biosfn_display_window_control: + cmp bl, #0x00 + jne vbe_05_failed + cmp bh, #0x01 + je get_display_window + jb set_display_window + mov ax, #0x0100 + ret +set_display_window: + mov ax, dx + call _dispi_set_bank + call dispi_get_bank + cmp ax, dx + jne vbe_05_failed + mov ax, #0x004f + ret +get_display_window: + call dispi_get_bank + mov dx, ax + mov ax, #0x004f + ret +vbe_05_failed: + mov ax, #0x014f + ret +ASM_END + + +/** Function 06h - Set/Get Logical Scan Line Length + * + * Input: + * AX = 4F06h + * BL = 00h Set Scan Line Length in Pixels + * = 01h Get Scan Line Length + * = 02h Set Scan Line Length in Bytes + * = 03h Get Maximum Scan Line Length + * CX = If BL=00h Desired Width in Pixels + * If BL=02h Desired Width in Bytes + * (Ignored for Get Functions) + * + * Output: + * AX = VBE Return Status + * BX = Bytes Per Scan Line + * CX = Actual Pixels Per Scan Line + * (truncated to nearest complete pixel) + * DX = Maximum Number of Scan Lines + */ +ASM_START +vbe_biosfn_set_get_logical_scan_line_length: + mov ax, cx + cmp bl, #0x01 + je get_logical_scan_line_length + cmp bl, #0x02 + je set_logical_scan_line_bytes + jb set_logical_scan_line_pixels + mov ax, #0x0100 + ret +set_logical_scan_line_bytes: + push ax + call dispi_get_bpp + xor bh, bh + mov bl, ah + xor dx, dx + pop ax + div bx +set_logical_scan_line_pixels: + call dispi_set_virt_width +get_logical_scan_line_length: + call dispi_get_bpp + xor bh, bh + mov bl, ah + call dispi_get_virt_width + mov cx, ax + mul bx + mov bx, ax + call dispi_get_virt_height + mov dx, ax + mov ax, #0x004f + ret +ASM_END + + +/** Function 07h - Set/Get Display Start + * + * Input(16-bit): + * AX = 4F07h + * BH = 00h Reserved and must be 00h + * BL = 00h Set Display Start + * = 01h Get Display Start + * = 02h Schedule Display Start (Alternate) + * = 03h Schedule Stereoscopic Display Start + * = 04h Get Scheduled Display Start Status + * = 05h Enable Stereoscopic Mode + * = 06h Disable Stereoscopic Mode + * = 80h Set Display Start during Vertical Retrace + * = 82h Set Display Start during Vertical Retrace (Alternate) + * = 83h Set Stereoscopic Display Start during Vertical Retrace + * ECX = If BL=02h/82h Display Start Address in bytes + * If BL=03h/83h Left Image Start Address in bytes + * EDX = If BL=03h/83h Right Image Start Address in bytes + * CX = If BL=00h/80h First Displayed Pixel In Scan Line + * DX = If BL=00h/80h First Displayed Scan Line + * + * Output: + * AX = VBE Return Status + * BH = If BL=01h Reserved and will be 0 + * CX = If BL=01h First Displayed Pixel In Scan Line + * If BL=04h 0 if flip has not occurred, not 0 if it has + * DX = If BL=01h First Displayed Scan Line + * + * Input(32-bit): + * BH = 00h Reserved and must be 00h + * BL = 00h Set Display Start + * = 80h Set Display Start during Vertical Retrace + * CX = Bits 0-15 of display start address + * DX = Bits 16-31 of display start address + * ES = Selector for memory mapped registers + */ +ASM_START +vbe_biosfn_set_get_display_start: + cmp bl, #0x80 + je set_display_start + cmp bl, #0x01 + je get_display_start + jb set_display_start + mov ax, #0x0100 + ret +set_display_start: + mov ax, cx + call dispi_set_x_offset + mov ax, dx + call dispi_set_y_offset + mov ax, #0x004f + ret +get_display_start: + call dispi_get_x_offset + mov cx, ax + call dispi_get_y_offset + mov dx, ax + xor bh, bh + mov ax, #0x004f + ret +ASM_END + + +/** Function 08h - Set/Get Dac Palette Format + * + * Input: + * AX = 4F08h + * BL = 00h set DAC palette width + * = 01h get DAC palette width + * BH = If BL=00h: desired number of bits per primary color + * Output: + * AX = VBE Return Status + * BH = current number of bits per primary color (06h = standard VGA) + */ +ASM_START +vbe_biosfn_set_get_dac_palette_format: + cmp bl, #0x01 + je get_dac_palette_format + jb set_dac_palette_format + mov ax, #0x0100 + ret +set_dac_palette_format: + call dispi_get_enable + cmp bh, #0x06 + je set_normal_dac + cmp bh, #0x08 + jne vbe_08_unsupported + or ax, # VBE_DISPI_8BIT_DAC + jnz set_dac_mode +set_normal_dac: + and ax, #~ VBE_DISPI_8BIT_DAC +set_dac_mode: + call _dispi_set_enable +get_dac_palette_format: + mov bh, #0x06 + call dispi_get_enable + and ax, # VBE_DISPI_8BIT_DAC + jz vbe_08_ok + mov bh, #0x08 +vbe_08_ok: + mov ax, #0x004f + ret +vbe_08_unsupported: + mov ax, #0x014f + ret +ASM_END + + +/** Function 09h - Set/Get Palette Data + * + * Input: + * AX = 4F09h + * Output: + * AX = VBE Return Status + * + * FIXME: incomplete API description, Input & Output + */ +void vbe_biosfn_set_get_palette_data(AX) +{ +} + +/** Function 0Ah - Return VBE Protected Mode Interface + * + * Input: + * AX = 4F0Ah + * Output: + * AX = VBE Return Status + * + * FIXME: incomplete API description, Input & Output + */ +void vbe_biosfn_return_protected_mode_interface(AX) +{ +} diff --git a/palacios/src/vmboot/vgabios/vbe.h b/palacios/src/vmboot/vgabios/vbe.h new file mode 100644 index 0000000..621048a --- /dev/null +++ b/palacios/src/vmboot/vgabios/vbe.h @@ -0,0 +1,302 @@ +#ifndef vbe_h_included +#define vbe_h_included + +#include "vgabios.h" + +// DISPI helper function +void dispi_set_enable(enable); + +/** VBE int10 API + * + * See the function descriptions in vbe.c for more information + */ +Boolean vbe_has_vbe_display(); +void vbe_biosfn_return_controller_information(AX, ES, DI); +void vbe_biosfn_return_mode_information(AX, CX, ES, DI); +void vbe_biosfn_set_mode(AX, BX, ES, DI); +void vbe_biosfn_save_restore_state(AX, DL, CX, ES, BX); +void vbe_biosfn_set_get_palette_data(AX); +void vbe_biosfn_return_protected_mode_interface(AX); + +// The official VBE Information Block +typedef struct VbeInfoBlock +{ + Bit8u VbeSignature[4]; + Bit16u VbeVersion; + Bit16u OemStringPtr_Off; + Bit16u OemStringPtr_Seg; + Bit8u Capabilities[4]; + Bit16u VideoModePtr_Off; + Bit16u VideoModePtr_Seg; + Bit16u TotalMemory; + Bit16u OemSoftwareRev; + Bit16u OemVendorNamePtr_Off; + Bit16u OemVendorNamePtr_Seg; + Bit16u OemProductNamePtr_Off; + Bit16u OemProductNamePtr_Seg; + Bit16u OemProductRevPtr_Off; + Bit16u OemProductRevPtr_Seg; + Bit16u Reserved[111]; // used for dynamicly generated mode list + Bit8u OemData[256]; +} VbeInfoBlock; + + +// This one is for compactly storing a static list of mode info blocks +// this saves us 189 bytes per block +typedef struct ModeInfoBlockCompact +{ +// Mandatory information for all VBE revisions + Bit16u ModeAttributes; + Bit8u WinAAttributes; + Bit8u WinBAttributes; + Bit16u WinGranularity; + Bit16u WinSize; + Bit16u WinASegment; + Bit16u WinBSegment; + Bit32u WinFuncPtr; + Bit16u BytesPerScanLine; +// Mandatory information for VBE 1.2 and above + Bit16u XResolution; + Bit16u YResolution; + Bit8u XCharSize; + Bit8u YCharSize; + Bit8u NumberOfPlanes; + Bit8u BitsPerPixel; + Bit8u NumberOfBanks; + Bit8u MemoryModel; + Bit8u BankSize; + Bit8u NumberOfImagePages; + Bit8u Reserved_page; +// Direct Color fields (required for direct/6 and YUV/7 memory models) + Bit8u RedMaskSize; + Bit8u RedFieldPosition; + Bit8u GreenMaskSize; + Bit8u GreenFieldPosition; + Bit8u BlueMaskSize; + Bit8u BlueFieldPosition; + Bit8u RsvdMaskSize; + Bit8u RsvdFieldPosition; + Bit8u DirectColorModeInfo; +// Mandatory information for VBE 2.0 and above + Bit32u PhysBasePtr; + Bit32u OffScreenMemOffset; + Bit16u OffScreenMemSize; +// Mandatory information for VBE 3.0 and above + Bit16u LinBytesPerScanLine; + Bit8u BnkNumberOfPages; + Bit8u LinNumberOfPages; + Bit8u LinRedMaskSize; + Bit8u LinRedFieldPosition; + Bit8u LinGreenMaskSize; + Bit8u LinGreenFieldPosition; + Bit8u LinBlueMaskSize; + Bit8u LinBlueFieldPosition; + Bit8u LinRsvdMaskSize; + Bit8u LinRsvdFieldPosition; + Bit32u MaxPixelClock; +// Bit8u Reserved[189]; // DO NOT PUT THIS IN HERE because of Compact Mode Info storage in bios +} ModeInfoBlockCompact; + +typedef struct ModeInfoBlock +{ +// Mandatory information for all VBE revisions + Bit16u ModeAttributes; + Bit8u WinAAttributes; + Bit8u WinBAttributes; + Bit16u WinGranularity; + Bit16u WinSize; + Bit16u WinASegment; + Bit16u WinBSegment; + Bit32u WinFuncPtr; + Bit16u BytesPerScanLine; +// Mandatory information for VBE 1.2 and above + Bit16u XResolution; + Bit16u YResolution; + Bit8u XCharSize; + Bit8u YCharSize; + Bit8u NumberOfPlanes; + Bit8u BitsPerPixel; + Bit8u NumberOfBanks; + Bit8u MemoryModel; + Bit8u BankSize; + Bit8u NumberOfImagePages; + Bit8u Reserved_page; +// Direct Color fields (required for direct/6 and YUV/7 memory models) + Bit8u RedMaskSize; + Bit8u RedFieldPosition; + Bit8u GreenMaskSize; + Bit8u GreenFieldPosition; + Bit8u BlueMaskSize; + Bit8u BlueFieldPosition; + Bit8u RsvdMaskSize; + Bit8u RsvdFieldPosition; + Bit8u DirectColorModeInfo; +// Mandatory information for VBE 2.0 and above + Bit32u PhysBasePtr; + Bit32u OffScreenMemOffset; + Bit16u OffScreenMemSize; +// Mandatory information for VBE 3.0 and above + Bit16u LinBytesPerScanLine; + Bit8u BnkNumberOfPages; + Bit8u LinNumberOfPages; + Bit8u LinRedMaskSize; + Bit8u LinRedFieldPosition; + Bit8u LinGreenMaskSize; + Bit8u LinGreenFieldPosition; + Bit8u LinBlueMaskSize; + Bit8u LinBlueFieldPosition; + Bit8u LinRsvdMaskSize; + Bit8u LinRsvdFieldPosition; + Bit32u MaxPixelClock; + Bit8u Reserved[189]; +} ModeInfoBlock; + +// VBE Return Status Info +// AL +#define VBE_RETURN_STATUS_SUPPORTED 0x4F +#define VBE_RETURN_STATUS_UNSUPPORTED 0x00 +// AH +#define VBE_RETURN_STATUS_SUCCESSFULL 0x00 +#define VBE_RETURN_STATUS_FAILED 0x01 +#define VBE_RETURN_STATUS_NOT_SUPPORTED 0x02 +#define VBE_RETURN_STATUS_INVALID 0x03 + +// VBE Mode Numbers + +#define VBE_MODE_VESA_DEFINED 0x0100 +#define VBE_MODE_REFRESH_RATE_USE_CRTC 0x0800 +#define VBE_MODE_LINEAR_FRAME_BUFFER 0x4000 +#define VBE_MODE_PRESERVE_DISPLAY_MEMORY 0x8000 + +// VBE GFX Mode Number + +#define VBE_VESA_MODE_640X400X8 0x100 +#define VBE_VESA_MODE_640X480X8 0x101 +#define VBE_VESA_MODE_800X600X4 0x102 +#define VBE_VESA_MODE_800X600X8 0x103 +#define VBE_VESA_MODE_1024X768X4 0x104 +#define VBE_VESA_MODE_1024X768X8 0x105 +#define VBE_VESA_MODE_1280X1024X4 0x106 +#define VBE_VESA_MODE_1280X1024X8 0x107 +#define VBE_VESA_MODE_320X200X1555 0x10D +#define VBE_VESA_MODE_320X200X565 0x10E +#define VBE_VESA_MODE_320X200X888 0x10F +#define VBE_VESA_MODE_640X480X1555 0x110 +#define VBE_VESA_MODE_640X480X565 0x111 +#define VBE_VESA_MODE_640X480X888 0x112 +#define VBE_VESA_MODE_800X600X1555 0x113 +#define VBE_VESA_MODE_800X600X565 0x114 +#define VBE_VESA_MODE_800X600X888 0x115 +#define VBE_VESA_MODE_1024X768X1555 0x116 +#define VBE_VESA_MODE_1024X768X565 0x117 +#define VBE_VESA_MODE_1024X768X888 0x118 +#define VBE_VESA_MODE_1280X1024X1555 0x119 +#define VBE_VESA_MODE_1280X1024X565 0x11A +#define VBE_VESA_MODE_1280X1024X888 0x11B + +// BOCHS/PLEX86 'own' mode numbers +#define VBE_OWN_MODE_320X200X8888 0x140 +#define VBE_OWN_MODE_640X400X8888 0x141 +#define VBE_OWN_MODE_640X480X8888 0x142 +#define VBE_OWN_MODE_800X600X8888 0x143 +#define VBE_OWN_MODE_1024X768X8888 0x144 +#define VBE_OWN_MODE_1280X1024X8888 0x145 +#define VBE_OWN_MODE_320X200X8 0x146 + +#define VBE_VESA_MODE_END_OF_LIST 0xFFFF + +// Capabilities + +#define VBE_CAPABILITY_8BIT_DAC 0x0001 +#define VBE_CAPABILITY_NOT_VGA_COMPATIBLE 0x0002 +#define VBE_CAPABILITY_RAMDAC_USE_BLANK_BIT 0x0004 +#define VBE_CAPABILITY_STEREOSCOPIC_SUPPORT 0x0008 +#define VBE_CAPABILITY_STEREO_VIA_VESA_EVC 0x0010 + +// Mode Attributes + +#define VBE_MODE_ATTRIBUTE_SUPPORTED 0x0001 +#define VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE 0x0002 +#define VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT 0x0004 +#define VBE_MODE_ATTRIBUTE_COLOR_MODE 0x0008 +#define VBE_MODE_ATTRIBUTE_GRAPHICS_MODE 0x0010 +#define VBE_MODE_ATTRIBUTE_NOT_VGA_COMPATIBLE 0x0020 +#define VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW 0x0040 +#define VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE 0x0080 +#define VBE_MODE_ATTRIBUTE_DOUBLE_SCAN_MODE 0x0100 +#define VBE_MODE_ATTRIBUTE_INTERLACE_MODE 0x0200 +#define VBE_MODE_ATTRIBUTE_HARDWARE_TRIPLE_BUFFER 0x0400 +#define VBE_MODE_ATTRIBUTE_HARDWARE_STEREOSCOPIC_DISPLAY 0x0800 +#define VBE_MODE_ATTRIBUTE_DUAL_DISPLAY_START_ADDRESS 0x1000 + +#define VBE_MODE_ATTTRIBUTE_LFB_ONLY ( VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE ) + +// Window attributes + +#define VBE_WINDOW_ATTRIBUTE_RELOCATABLE 0x01 +#define VBE_WINDOW_ATTRIBUTE_READABLE 0x02 +#define VBE_WINDOW_ATTRIBUTE_WRITEABLE 0x04 + +// Memory model + +#define VBE_MEMORYMODEL_TEXT_MODE 0x00 +#define VBE_MEMORYMODEL_CGA_GRAPHICS 0x01 +#define VBE_MEMORYMODEL_HERCULES_GRAPHICS 0x02 +#define VBE_MEMORYMODEL_PLANAR 0x03 +#define VBE_MEMORYMODEL_PACKED_PIXEL 0x04 +#define VBE_MEMORYMODEL_NON_CHAIN_4_256 0x05 +#define VBE_MEMORYMODEL_DIRECT_COLOR 0x06 +#define VBE_MEMORYMODEL_YUV 0x07 + +// DirectColorModeInfo + +#define VBE_DIRECTCOLOR_COLOR_RAMP_PROGRAMMABLE 0x01 +#define VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE 0x02 + +// GUEST <-> HOST Communication API + +// FIXME: either dynamicly ask host for this or put somewhere high in physical memory +// like 0xE0000000 + + + #define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 4 + + #define VBE_DISPI_BANK_ADDRESS 0xA0000 + #define VBE_DISPI_BANK_SIZE_KB 64 + + #define VBE_DISPI_MAX_XRES 1024 + #define VBE_DISPI_MAX_YRES 768 + + #define VBE_DISPI_IOPORT_INDEX 0x01CE + #define VBE_DISPI_IOPORT_DATA 0x01CF + + #define VBE_DISPI_INDEX_ID 0x0 + #define VBE_DISPI_INDEX_XRES 0x1 + #define VBE_DISPI_INDEX_YRES 0x2 + #define VBE_DISPI_INDEX_BPP 0x3 + #define VBE_DISPI_INDEX_ENABLE 0x4 + #define VBE_DISPI_INDEX_BANK 0x5 + #define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 + #define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 + #define VBE_DISPI_INDEX_X_OFFSET 0x8 + #define VBE_DISPI_INDEX_Y_OFFSET 0x9 + + #define VBE_DISPI_ID0 0xB0C0 + #define VBE_DISPI_ID1 0xB0C1 + #define VBE_DISPI_ID2 0xB0C2 + #define VBE_DISPI_ID3 0xB0C3 + + #define VBE_DISPI_DISABLED 0x00 + #define VBE_DISPI_ENABLED 0x01 + #define VBE_DISPI_GETCAPS 0x02 + #define VBE_DISPI_8BIT_DAC 0x20 + #define VBE_DISPI_LFB_ENABLED 0x40 + #define VBE_DISPI_NOCLEARMEM 0x80 + + #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000 + + +#define VBE_TOTAL_VIDEO_MEMORY_DIV_64K (VBE_DISPI_TOTAL_VIDEO_MEMORY_MB*1024/64) + + +#endif diff --git a/palacios/src/vmboot/vgabios/vbe_display_api.txt b/palacios/src/vmboot/vgabios/vbe_display_api.txt new file mode 100644 index 0000000..788e17a --- /dev/null +++ b/palacios/src/vmboot/vgabios/vbe_display_api.txt @@ -0,0 +1,227 @@ +VBE Display API +------------------------------------------------------------------------------------------------------------- + This document is part of the Bochs/VBEBios documentation, + it specifies the bochs host <-> vbebios client communication. + + That means, the display code implementation and the vbebios code depend + very heavily on each other. As such, this documents needs be synchronised + between bochs CVS and the vgabios CVS. + + This document does not describe how the VBEBios implements the VBE2/3 spec. + This document does not describe how the Bochs display code will display gfx based upon this spec. + + +API History +----------- +0xb0c0 supports the following VBE_DISPI_ interfaces (present in Bochs 1.4): + VBE_DISPI_INDEX_ID + VBE_DISPI_INDEX_XRES + VBE_DISPI_INDEX_YRES + VBE_DISPI_INDEX_BPP + VBE_DISPI_INDEX_ENABLE + VBE_DISPI_INDEX_BANK + + Bpp format supported is: + VBE_DISPI_BPP_8 + +0xb0c1 supports 0xb0c0 VBE_DISPI_ interfaces, additional interfaces (present in Bochs 2.0): + VBE_DISPI_INDEX_VIRT_WIDTH + VBE_DISPI_INDEX_VIRT_HEIGHT + VBE_DISPI_INDEX_X_OFFSET + VBE_DISPI_INDEX_Y_OFFSET + +0xb0c2 supports 0xb0c1 VBE_DISPI_ interfaces, interfaces updated for + additional features (present in Bochs 2.1): + VBE_DISPI_INDEX_BPP supports >8bpp color depth (value = bits) + VBE_DISPI_INDEX_ENABLE supports new flags VBE_DISPI_NOCLEARMEM and VBE_DISPI_LFB_ENABLED + VBE i/o registers changed from 0xFF80/81 to 0x01CE/CF + +0xb0c3 supports 0xb0c2 VBE_DISPI_ interfaces, interfaces updated for + additional features: + VBE_DISPI_INDEX_ENABLE supports new flags VBE_DISPI_GETCAPS and VBE_DISPI_8BIT_DAC + + +History +------- + Version 0.6 2002 Nov 23 Jeroen Janssen + - Added LFB support + - Added Virt width, height and x,y offset + + Version 0.5 2002 March 08 Jeroen Janssen + - Added documentation about panic behaviour / current limits of the data values. + - Changed BPP API (in order to include future (A)RGB formats) + - Initial version (based upon extended display text of the vbe bochs display patch) + + +Todo +---- + Version 0.6+ [random order] + - Add lots of different (A)RGB formats + +References +---------- + [VBE3] VBE 3 Specification at + http://www.vesa.org/vbe3.pdf + + [BOCHS] Bochs Open Source IA-32 Emulator at + http://bochs.sourceforge.net + + [VBEBIOS] VBE Bios for Bochs at + http://savannah.gnu.org/projects/vgabios/ + + [Screenshots] Screenshots of programs using the VBE Bios at + http://japj.org/projects/bochs_plex86/screenshots.html + +Abbreviations +------------- + VBE Vesa Bios Extension + DISPI (Bochs) Display Interface + BPP Bits Per Pixel + LFB Linear Frame Buffer + + +#defines +-------- + #define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 4 + #define VBE_DISPI_BANK_ADDRESS 0xA0000 + #define VBE_DISPI_BANK_SIZE_KB 64 + + #define VBE_DISPI_MAX_XRES 1024 + #define VBE_DISPI_MAX_YRES 768 + + #define VBE_DISPI_IOPORT_INDEX 0x01CE + #define VBE_DISPI_IOPORT_DATA 0x01CF + + #define VBE_DISPI_INDEX_ID 0x0 + #define VBE_DISPI_INDEX_XRES 0x1 + #define VBE_DISPI_INDEX_YRES 0x2 + #define VBE_DISPI_INDEX_BPP 0x3 + #define VBE_DISPI_INDEX_ENABLE 0x4 + #define VBE_DISPI_INDEX_BANK 0x5 + #define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 + #define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 + #define VBE_DISPI_INDEX_X_OFFSET 0x8 + #define VBE_DISPI_INDEX_Y_OFFSET 0x9 + + #define VBE_DISPI_ID0 0xB0C0 + #define VBE_DISPI_ID1 0xB0C1 + #define VBE_DISPI_ID2 0xB0C2 + + #define VBE_DISPI_DISABLED 0x00 + #define VBE_DISPI_ENABLED 0x01 + #define VBE_DISPI_VBE_ENABLED 0x40 + #define VBE_DISPI_NOCLEARMEM 0x80 + + #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000 + +API +--- + The display api works by using a index (VBE_DISPI_IOPORT_INDEX) and + data (VBE_DISPI_IOPORT_DATA) ioport. One writes the index of the parameter to the index port. + Next, the parameter value can be read or written. + +[0xb0c0] + * VBE_DISPI_INDEX_ID : WORD {R,W} + This parameter can be used to detect the current display API (both bochs & vbebios). + The bios writes VBE_DISPI_ID0 to the dataport and reads it back again. + This way, the display code knows the vbebios 'ID' and the vbebios can check if the correct + display code is present. + As a result, a PANIC can be generated if an incompatible vbebios/display code combination is detected. + This panic can be generated from the bochs display code (NOT the bios, see Notes). + + Example values: VBE_DISPI_ID0 + + * VBE_DISPI_INDEX_XRES : WORD {R,W} + This parameter can be used to read/write the vbe display X resolution (in pixels). + It's illegal to set the XRES when the VBE is enabled (display code should generate PANIC). + + If the value written exceeds VBE_DISPI_MAX_XRES, the display code needs to generate a PANIC. + + Example values: 320,640,800,1024 + + * VBE_DISPI_INDEX_YRES : WORD {R,W} + This parameter can be used to read/write the vbe display Y resolution (in pixels). + It's illegal to set the YRES when the VBE is enabled (display code should generate PANIC). + + If the value written exceeds VBE_DISPI_MAX_YRES, the display code needs to generate a PANIC. + + Example values: 200,400,480,600,768 + + * VBE_DISPI_INDEX_BPP : WORD {R,W} + This parameter can be used to read/write the vbe display BPP. + It's illegal to set the BPP when the VBE is enabled (display code should generate PANIC). + + If the value written is an incompatible BPP, the display code needs to generate a PANIC. + + Example values: VBE_DISPI_BPP_8 + + * VBE_DISPI_INDEX_ENABLE : WORD {R,W} + This parameter can be used to read/write the vbe ENABLED state. + If the bios writes VBE_DISPI_ENABLED then the display code will setup a hostside display mode + with the current XRES, YRES and BPP settings. + If the bios write VBE_DISPI_DISABLED then the display code will switch back to normal vga mode behaviour. + + Example values: VBE_DISPI_ENABLED, VBE_DISPI_DISABLED + + * VBE_DISPI_INDEX_BANK : WORD {R,W} + This parameter can be used to read/write the current selected BANK (at 0xA0000). + This can be used for switching banks in banked mode. + +[0xb0c1] + * VBE_DISPI_INDEX_VIRT_WIDTH : WORD {R,W} + This parameter can be used to read/write the current virtual width. + Upon enabling a mode, this will be set to the current xres + Setting this field during enabled mode will result in the virtual width to be changed. + Value will be adjusted if current setting is not possible. + + * VBE_DISPI_INDEX_VIRT_HEIGHT : WORD {R} + This parameter can be read in order to obtain the current virtual height. + This setting will be adjusted after setting a virtual width in order to stay within limit of video memory. + + * VBE_DISPI_INDEX_X_OFFSET : WORD {R,W} + The current X offset (in pixels!) of the visible screen part. + Writing a new offset will also result in a complete screen refresh. + + * VBE_DISPI_INDEX_Y_OFFSET : WORD {R,W} + The current Y offset (in pixels!) of the visible screen part. + Writing a new offset will also result in a complete screen refresh. + + +[0xb0c2] + * VBE_DISPI_INDEX_BPP : WORD {R,W} + The value written is now the number of bits per pixel. A value of 0 is treated + the same as 8 for backward compatibilty. These values are supported: 8, 15, + 16, 24 and 32. The value of 4 is not yet handled in the VBE code. + * VBE_DISPI_INDEX_ENABLE : WORD {R,W} + The new flag VBE_DISPI_NOCLEARMEM allows to preserve the VBE video memory. + The new flag VBE_DISPI_LFB_ENABLED indicates the usage of the LFB. + +[0xb0c3] + * VBE_DISPI_INDEX_ENABLE : WORD {R,W} + If the new flag VBE_DISPI_GETCAPS is enabled, the xres, yres and bpp registers + return the gui capabilities. + The new flag VBE_DISPI_8BIT_DAC switches the DAC to 8 bit mode. + +Displaying GFX (banked mode) +-------------- + What happens is that the total screen is devided in banks of 'VBE_DISPI_BANK_SIZE_KB' KiloByte in size. + If you want to set a pixel you can calculate its bank by doing: + + offset = pixel_x + pixel_y * resolution_x; + bank = offset / 64 Kb (rounded 1.9999 -> 1) + + bank_pixel_pos = offset - bank * 64Kb + + Now you can set the current bank and put the pixel at VBE_DISPI_BANK_ADDRESS + bank_pixel_pos + +Displaying GFX (linear frame buffer mode) +-------------- + NOT WRITTEN YET + +Notes +----- + * Since the XRES/YRES/BPP may not be written when VBE is enabled, if you want to switch from one VBE mode + to another, you will need to disable VBE first. + + * Note when the bios doesn't find a valid DISPI_ID, it can disable the VBE functions. This allows people to + use the same bios for both vbe enabled and disabled bochs executables. diff --git a/palacios/src/vmboot/vgabios/vbetables.h b/palacios/src/vmboot/vgabios/vbetables.h new file mode 100644 index 0000000..a742ac7 --- /dev/null +++ b/palacios/src/vmboot/vgabios/vbetables.h @@ -0,0 +1,1282 @@ +#ifndef vbetables_h_included +#define vbetables_h_included + +/* vbetables.h + + This file contains a static mode information list containing all + bochs/plex86 "supported" VBE modi and their 'settings'. + +*/ + +typedef struct ModeInfoListItem +{ + Bit16u mode; + ModeInfoBlockCompact info; +} ModeInfoListItem; + +// FIXME: check all member variables to be correct for the different modi +// FIXME: add more modi +static ModeInfoListItem mode_info_list[]= +{ + { + VBE_VESA_MODE_640X400X8, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 640, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 640, + /*Bit16u YResolution*/ 400, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 8, + /*Bit8u NumberOfBanks*/ 4, // 640x400/64kb == 4 + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 15, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 0, + /*Bit8u RedFieldPosition*/ 0, + /*Bit8u GreenMaskSize*/ 0, + /*Bit8u GreenFieldPosition*/ 0, + /*Bit8u BlueMaskSize*/ 0, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 640, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 0, + /*Bit8u LinRedFieldPosition*/ 0, + /*Bit8u LinGreenMaskSize*/ 0, + /*Bit8u LinGreenFieldPosition*/ 0, + /*Bit8u LinBlueMaskSize*/ 0, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_VESA_MODE_640X480X8, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 640, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 640, + /*Bit16u YResolution*/ 480, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 8, + /*Bit8u NumberOfBanks*/ 5, // 640x480/64kb == 5 + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 11, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 0, + /*Bit8u RedFieldPosition*/ 0, + /*Bit8u GreenMaskSize*/ 0, + /*Bit8u GreenFieldPosition*/ 0, + /*Bit8u BlueMaskSize*/ 0, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 640, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 0, + /*Bit8u LinRedFieldPosition*/ 0, + /*Bit8u LinGreenMaskSize*/ 0, + /*Bit8u LinGreenFieldPosition*/ 0, + /*Bit8u LinBlueMaskSize*/ 0, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_VESA_MODE_800X600X4, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT | + VBE_MODE_ATTRIBUTE_COLOR_MODE | + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 100, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 800, + /*Bit16u YResolution*/ 600, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 4, + /*Bit8u BitsPerPixel*/ 4, + /*Bit8u NumberOfBanks*/ 16, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PLANAR, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 15, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 0, + /*Bit8u RedFieldPosition*/ 0, + /*Bit8u GreenMaskSize*/ 0, + /*Bit8u GreenFieldPosition*/ 0, + /*Bit8u BlueMaskSize*/ 0, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +// Mandatory information for VBE 2.0 and above + /*Bit32u PhysBasePtr*/ 0, + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 100, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 0, + /*Bit8u LinRedFieldPosition*/ 0, + /*Bit8u LinGreenMaskSize*/ 0, + /*Bit8u LinGreenFieldPosition*/ 0, + /*Bit8u LinBlueMaskSize*/ 0, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_VESA_MODE_800X600X8, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 800, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 800, + /*Bit16u YResolution*/ 600, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 8, + /*Bit8u NumberOfBanks*/ 8, // 800x600/64kb == 8 + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 7, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 0, + /*Bit8u RedFieldPosition*/ 0, + /*Bit8u GreenMaskSize*/ 0, + /*Bit8u GreenFieldPosition*/ 0, + /*Bit8u BlueMaskSize*/ 0, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 800, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 0, + /*Bit8u LinRedFieldPosition*/ 0, + /*Bit8u LinGreenMaskSize*/ 0, + /*Bit8u LinGreenFieldPosition*/ 0, + /*Bit8u LinBlueMaskSize*/ 0, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_VESA_MODE_1024X768X8, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 1024, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 1024, + /*Bit16u YResolution*/ 768, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 8, + /*Bit8u NumberOfBanks*/ 12, // 1024x768/64kb == 12 + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 3, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 0, + /*Bit8u RedFieldPosition*/ 0, + /*Bit8u GreenMaskSize*/ 0, + /*Bit8u GreenFieldPosition*/ 0, + /*Bit8u BlueMaskSize*/ 0, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 1024, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 0, + /*Bit8u LinRedFieldPosition*/ 0, + /*Bit8u LinGreenMaskSize*/ 0, + /*Bit8u LinGreenFieldPosition*/ 0, + /*Bit8u LinBlueMaskSize*/ 0, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_VESA_MODE_640X480X1555, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 640*2, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 640, + /*Bit16u YResolution*/ 480, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 15, + /*Bit8u NumberOfBanks*/ 1, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 5, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 5, + /*Bit8u RedFieldPosition*/ 10, + /*Bit8u GreenMaskSize*/ 5, + /*Bit8u GreenFieldPosition*/ 5, + /*Bit8u BlueMaskSize*/ 5, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 1, + /*Bit8u RsvdFieldPosition*/ 15, + /*Bit8u DirectColorModeInfo*/ 0, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 640*2, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 5, + /*Bit8u LinRedFieldPosition*/ 10, + /*Bit8u LinGreenMaskSize*/ 0, + /*Bit8u LinGreenFieldPosition*/ 5, + /*Bit8u LinBlueMaskSize*/ 5, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 1, + /*Bit8u LinRsvdFieldPosition*/ 15, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_VESA_MODE_800X600X1555, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 800*2, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 800, + /*Bit16u YResolution*/ 600, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 15, + /*Bit8u NumberOfBanks*/ 1, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 3, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 5, + /*Bit8u RedFieldPosition*/ 10, + /*Bit8u GreenMaskSize*/ 5, + /*Bit8u GreenFieldPosition*/ 5, + /*Bit8u BlueMaskSize*/ 5, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 1, + /*Bit8u RsvdFieldPosition*/ 15, + /*Bit8u DirectColorModeInfo*/ 0, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 800*2, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 5, + /*Bit8u LinRedFieldPosition*/ 10, + /*Bit8u LinGreenMaskSize*/ 5, + /*Bit8u LinGreenFieldPosition*/ 5, + /*Bit8u LinBlueMaskSize*/ 5, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 1, + /*Bit8u LinRsvdFieldPosition*/ 15, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_VESA_MODE_1024X768X1555, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 1024*2, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 1024, + /*Bit16u YResolution*/ 768, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 15, + /*Bit8u NumberOfBanks*/ 1, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 1, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 5, + /*Bit8u RedFieldPosition*/ 10, + /*Bit8u GreenMaskSize*/ 5, + /*Bit8u GreenFieldPosition*/ 5, + /*Bit8u BlueMaskSize*/ 5, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 1, + /*Bit8u RsvdFieldPosition*/ 15, + /*Bit8u DirectColorModeInfo*/ 0, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 1024*2, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 5, + /*Bit8u LinRedFieldPosition*/ 10, + /*Bit8u LinGreenMaskSize*/ 5, + /*Bit8u LinGreenFieldPosition*/ 5, + /*Bit8u LinBlueMaskSize*/ 5, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 1, + /*Bit8u LinRsvdFieldPosition*/ 15, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_VESA_MODE_640X480X565, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 640*2, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 640, + /*Bit16u YResolution*/ 480, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 16, + /*Bit8u NumberOfBanks*/ 1, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 5, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 5, + /*Bit8u RedFieldPosition*/ 11, + /*Bit8u GreenMaskSize*/ 6, + /*Bit8u GreenFieldPosition*/ 5, + /*Bit8u BlueMaskSize*/ 5, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 640*2, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 5, + /*Bit8u LinRedFieldPosition*/ 11, + /*Bit8u LinGreenMaskSize*/ 6, + /*Bit8u LinGreenFieldPosition*/ 5, + /*Bit8u LinBlueMaskSize*/ 5, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_VESA_MODE_800X600X565, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 800*2, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 800, + /*Bit16u YResolution*/ 600, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 16, + /*Bit8u NumberOfBanks*/ 1, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 3, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 5, + /*Bit8u RedFieldPosition*/ 11, + /*Bit8u GreenMaskSize*/ 6, + /*Bit8u GreenFieldPosition*/ 5, + /*Bit8u BlueMaskSize*/ 5, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 800*2, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 5, + /*Bit8u LinRedFieldPosition*/ 11, + /*Bit8u LinGreenMaskSize*/ 6, + /*Bit8u LinGreenFieldPosition*/ 5, + /*Bit8u LinBlueMaskSize*/ 5, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_VESA_MODE_1024X768X565, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 1024*2, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 1024, + /*Bit16u YResolution*/ 768, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 16, + /*Bit8u NumberOfBanks*/ 1, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 1, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 5, + /*Bit8u RedFieldPosition*/ 11, + /*Bit8u GreenMaskSize*/ 6, + /*Bit8u GreenFieldPosition*/ 5, + /*Bit8u BlueMaskSize*/ 5, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 1024*2, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 5, + /*Bit8u LinRedFieldPosition*/ 11, + /*Bit8u LinGreenMaskSize*/ 6, + /*Bit8u LinGreenFieldPosition*/ 5, + /*Bit8u LinBlueMaskSize*/ 5, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_VESA_MODE_640X480X888, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 640*3, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 640, + /*Bit16u YResolution*/ 480, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 24, + /*Bit8u NumberOfBanks*/ 1, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 3, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 8, + /*Bit8u RedFieldPosition*/ 16, + /*Bit8u GreenMaskSize*/ 8, + /*Bit8u GreenFieldPosition*/ 8, + /*Bit8u BlueMaskSize*/ 8, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 640*3, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 8, + /*Bit8u LinRedFieldPosition*/ 16, + /*Bit8u LinGreenMaskSize*/ 8, + /*Bit8u LinGreenFieldPosition*/ 8, + /*Bit8u LinBlueMaskSize*/ 8, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_VESA_MODE_800X600X888, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 800*3, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 800, + /*Bit16u YResolution*/ 600, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 24, + /*Bit8u NumberOfBanks*/ 1, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 1, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 8, + /*Bit8u RedFieldPosition*/ 16, + /*Bit8u GreenMaskSize*/ 8, + /*Bit8u GreenFieldPosition*/ 8, + /*Bit8u BlueMaskSize*/ 8, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 800*3, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 8, + /*Bit8u LinRedFieldPosition*/ 16, + /*Bit8u LinGreenMaskSize*/ 8, + /*Bit8u LinGreenFieldPosition*/ 8, + /*Bit8u LinBlueMaskSize*/ 8, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_VESA_MODE_1024X768X888, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 1024*3, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 1024, + /*Bit16u YResolution*/ 768, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 24, + /*Bit8u NumberOfBanks*/ 1, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 8, + /*Bit8u RedFieldPosition*/ 16, + /*Bit8u GreenMaskSize*/ 8, + /*Bit8u GreenFieldPosition*/ 8, + /*Bit8u BlueMaskSize*/ 8, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 1024*3, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 8, + /*Bit8u LinRedFieldPosition*/ 16, + /*Bit8u LinGreenMaskSize*/ 8, + /*Bit8u LinGreenFieldPosition*/ 8, + /*Bit8u LinBlueMaskSize*/ 8, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_OWN_MODE_640X480X8888, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 640*4, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 640, + /*Bit16u YResolution*/ 480, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 32, + /*Bit8u NumberOfBanks*/ 1, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 1, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 8, + /*Bit8u RedFieldPosition*/ 16, + /*Bit8u GreenMaskSize*/ 8, + /*Bit8u GreenFieldPosition*/ 8, + /*Bit8u BlueMaskSize*/ 8, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 8, + /*Bit8u RsvdFieldPosition*/ 24, + /*Bit8u DirectColorModeInfo*/ VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 640*4, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 8, + /*Bit8u LinRedFieldPosition*/ 16, + /*Bit8u LinGreenMaskSize*/ 8, + /*Bit8u LinGreenFieldPosition*/ 8, + /*Bit8u LinBlueMaskSize*/ 8, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 8, + /*Bit8u LinRsvdFieldPosition*/ 24, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_OWN_MODE_800X600X8888, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 800*4, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 800, + /*Bit16u YResolution*/ 600, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 32, + /*Bit8u NumberOfBanks*/ 1, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 1, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 8, + /*Bit8u RedFieldPosition*/ 16, + /*Bit8u GreenMaskSize*/ 8, + /*Bit8u GreenFieldPosition*/ 8, + /*Bit8u BlueMaskSize*/ 8, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 8, + /*Bit8u RsvdFieldPosition*/ 24, + /*Bit8u DirectColorModeInfo*/ VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 800*4, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 8, + /*Bit8u LinRedFieldPosition*/ 16, + /*Bit8u LinGreenMaskSize*/ 8, + /*Bit8u LinGreenFieldPosition*/ 8, + /*Bit8u LinBlueMaskSize*/ 8, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 8, + /*Bit8u LinRsvdFieldPosition*/ 24, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_OWN_MODE_1024X768X8888, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 1024*4, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 1024, + /*Bit16u YResolution*/ 768, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 32, + /*Bit8u NumberOfBanks*/ 1, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 1, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 8, + /*Bit8u RedFieldPosition*/ 16, + /*Bit8u GreenMaskSize*/ 8, + /*Bit8u GreenFieldPosition*/ 8, + /*Bit8u BlueMaskSize*/ 8, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 8, + /*Bit8u RsvdFieldPosition*/ 24, + /*Bit8u DirectColorModeInfo*/ VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 1024*4, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 8, + /*Bit8u LinRedFieldPosition*/ 16, + /*Bit8u LinGreenMaskSize*/ 8, + /*Bit8u LinGreenFieldPosition*/ 8, + /*Bit8u LinBlueMaskSize*/ 8, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 8, + /*Bit8u LinRsvdFieldPosition*/ 24, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + + { + VBE_OWN_MODE_320X200X8, + { +/*typedef struct ModeInfoBlock +{*/ +// Mandatory information for all VBE revisions + /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | +#ifdef VBE_HAVE_LFB + VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +#endif + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, + /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, + /*Bit16u WinBSegment*/ 0, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 320, +// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 320, + /*Bit16u YResolution*/ 200, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 8, + /*Bit8u NumberOfBanks*/ 1, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 3, + /*Bit8u Reserved_page*/ 0, +// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 0, + /*Bit8u RedFieldPosition*/ 0, + /*Bit8u GreenMaskSize*/ 0, + /*Bit8u GreenFieldPosition*/ 0, + /*Bit8u BlueMaskSize*/ 0, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +// Mandatory information for VBE 2.0 and above +#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +#else + /*Bit32u PhysBasePtr*/ 0, +#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 320, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 0, + /*Bit8u LinRedFieldPosition*/ 0, + /*Bit8u LinGreenMaskSize*/ 0, + /*Bit8u LinGreenFieldPosition*/ 0, + /*Bit8u LinBlueMaskSize*/ 0, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +/*} ModeInfoBlock;*/ + } + }, + +/** END OF THE LIST **/ + { + VBE_VESA_MODE_END_OF_LIST, + { + 0, + } + } +}; + +#endif diff --git a/palacios/src/vmboot/vgabios/vgabios.c b/palacios/src/vmboot/vgabios/vgabios.c new file mode 100644 index 0000000..6afa337 --- /dev/null +++ b/palacios/src/vmboot/vgabios/vgabios.c @@ -0,0 +1,3608 @@ +// ============================================================================================ +/* + * vgabios.c + */ +// ============================================================================================ +// +// Copyright (C) 2001,2002 the LGPL VGABios developers Team +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// ============================================================================================ +// +// This VGA Bios is specific to the plex86/bochs Emulated VGA card. +// You can NOT drive any physical vga card with it. +// +// ============================================================================================ +// +// This file contains code ripped from : +// - rombios.c of plex86 +// +// This VGA Bios contains fonts from : +// - fntcol16.zip (c) by Joseph Gil avalable at : +// ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip +// These fonts are public domain +// +// This VGA Bios is based on information taken from : +// - Kevin Lawton's vga card emulation for bochs/plex86 +// - Ralf Brown's interrupts list available at http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html +// - Finn Thogersons' VGADOC4b available at http://home.worldonline.dk/~finth/ +// - Michael Abrash's Graphics Programming Black Book +// - Francois Gervais' book "programmation des cartes graphiques cga-ega-vga" edited by sybex +// - DOSEMU 1.0.1 source code for several tables values and formulas +// +// Thanks for patches, comments and ideas to : +// - techt@pikeonline.net +// +// ============================================================================================ + +#include "vgabios.h" + +#ifdef VBE +#include "vbe.h" +#endif + +#undef DEBUG +#define USE_BX_INFO + +/* Declares */ +static Bit8u read_byte(); +static Bit16u read_word(); +static void write_byte(); +static void write_word(); +static Bit8u inb(); +static Bit16u inw(); +static void outb(); +static void outw(); + +static Bit16u get_SS(); + +// Output +static void printf(); +static void unimplemented(); +static void unknown(); + +static Bit8u find_vga_entry(); + +static void memsetb(); +static void memsetw(); +static void memcpyb(); +static void memcpyw(); + +static void biosfn_set_video_mode(); +static void biosfn_set_cursor_shape(); +static void biosfn_set_cursor_pos(); +static void biosfn_get_cursor_pos(); +static void biosfn_set_active_page(); +static void biosfn_scroll(); +static void biosfn_read_char_attr(); +static void biosfn_write_char_attr(); +static void biosfn_write_char_only(); +static void biosfn_write_pixel(); +static void biosfn_read_pixel(); +static void biosfn_write_teletype(); +static void biosfn_perform_gray_scale_summing(); +static void biosfn_load_text_user_pat(); +static void biosfn_load_text_8_14_pat(); +static void biosfn_load_text_8_8_pat(); +static void biosfn_load_text_8_16_pat(); +static void biosfn_load_gfx_8_8_chars(); +static void biosfn_load_gfx_user_chars(); +static void biosfn_load_gfx_8_14_chars(); +static void biosfn_load_gfx_8_8_dd_chars(); +static void biosfn_load_gfx_8_16_chars(); +static void biosfn_get_font_info(); +static void biosfn_alternate_prtsc(); +static void biosfn_switch_video_interface(); +static void biosfn_enable_video_refresh_control(); +static void biosfn_write_string(); +static void biosfn_read_state_info(); +static void biosfn_read_video_state_size(); +static void biosfn_save_video_state(); +static void biosfn_restore_video_state(); + +// This is for compiling with gcc2 and gcc3 +#define ASM_START #asm +#define ASM_END #endasm + +ASM_START + +MACRO SET_INT_VECTOR + push ds + xor ax, ax + mov ds, ax + mov ax, ?3 + mov ?1*4, ax + mov ax, ?2 + mov ?1*4+2, ax + pop ds +MEND + +ASM_END + +ASM_START +.text +.rom +.org 0 + +use16 386 + +vgabios_start: +.byte 0x55, 0xaa /* BIOS signature, required for BIOS extensions */ + +.byte 0x40 /* BIOS extension length in units of 512 bytes */ + + +vgabios_entry_point: + + jmp vgabios_init_func + +vgabios_name: +.ascii "Plex86/Bochs VGABios" +.ascii " " +.byte 0x00 + +// Info from Bart Oldeman +.org 0x1e +.ascii "IBM" +.byte 0x00 + +vgabios_version: +#ifndef VGABIOS_VERS +.ascii "current-cvs" +#else +.ascii VGABIOS_VERS +#endif +.ascii " " + +vgabios_date: +.ascii VGABIOS_DATE +.byte 0x0a,0x0d +.byte 0x00 + +vgabios_copyright: +.ascii "(C) 2003 the LGPL VGABios developers Team" +.byte 0x0a,0x0d +.byte 0x00 + +vgabios_license: +.ascii "This VGA/VBE Bios is released under the GNU LGPL" +.byte 0x0a,0x0d +.byte 0x0a,0x0d +.byte 0x00 + +vgabios_website: +.ascii "Please visit :" +.byte 0x0a,0x0d +;;.ascii " . http://www.plex86.org" +;;.byte 0x0a,0x0d +.ascii " . http://bochs.sourceforge.net" +.byte 0x0a,0x0d +.ascii " . http://www.nongnu.org/vgabios" +.byte 0x0a,0x0d +.byte 0x0a,0x0d +.byte 0x00 + + +;; ============================================================================================ +;; +;; Init Entry point +;; +;; ============================================================================================ +vgabios_init_func: + +;; init vga card + call init_vga_card + +;; init basic bios vars + call init_bios_area + +#ifdef VBE +;; init vbe functions + call vbe_init +#endif + +;; set int10 vect + SET_INT_VECTOR(0x10, #0xC000, #vgabios_int10_handler) + +#ifdef CIRRUS + call cirrus_init +#endif + +;; display splash screen + call _display_splash_screen + +;; init video mode and clear the screen + mov ax,#0x0003 + int #0x10 + +;; show info + call _display_info + +#ifdef VBE +;; show vbe info + call vbe_display_info +#endif + +#ifdef CIRRUS +;; show cirrus info + call cirrus_display_info +#endif + + retf +ASM_END + +/* + * int10 handled here + */ +ASM_START +vgabios_int10_handler: + pushf +#ifdef DEBUG + push es + push ds + pusha + mov bx, #0xc000 + mov ds, bx + call _int10_debugmsg + popa + pop ds + pop es +#endif + cmp ah, #0x0f + jne int10_test_1A + call biosfn_get_video_mode + jmp int10_end +int10_test_1A: + cmp ah, #0x1a + jne int10_test_0B + call biosfn_group_1A + jmp int10_end +int10_test_0B: + cmp ah, #0x0b + jne int10_test_1103 + call biosfn_group_0B + jmp int10_end +int10_test_1103: + cmp ax, #0x1103 + jne int10_test_12 + call biosfn_set_text_block_specifier + jmp int10_end +int10_test_12: + cmp ah, #0x12 + jne int10_test_101B + cmp bl, #0x10 + jne int10_test_BL30 + call biosfn_get_ega_info + jmp int10_end +int10_test_BL30: + cmp bl, #0x30 + jne int10_test_BL31 + call biosfn_select_vert_res + jmp int10_end +int10_test_BL31: + cmp bl, #0x31 + jne int10_test_BL32 + call biosfn_enable_default_palette_loading + jmp int10_end +int10_test_BL32: + cmp bl, #0x32 + jne int10_test_BL33 + call biosfn_enable_video_addressing + jmp int10_end +int10_test_BL33: + cmp bl, #0x33 + jne int10_test_BL34 + call biosfn_enable_grayscale_summing + jmp int10_end +int10_test_BL34: + cmp bl, #0x34 + jne int10_normal + call biosfn_enable_cursor_emulation + jmp int10_end +int10_test_101B: + cmp ax, #0x101b + je int10_normal + cmp ah, #0x10 +#ifndef VBE + jne int10_normal +#else + jne int10_test_4F +#endif + call biosfn_group_10 + jmp int10_end +#ifdef VBE +int10_test_4F: + cmp ah, #0x4f + jne int10_normal + cmp al, #0x03 + jne int10_test_vbe_05 + call vbe_biosfn_return_current_mode + jmp int10_end +int10_test_vbe_05: + cmp al, #0x05 + jne int10_test_vbe_06 + call vbe_biosfn_display_window_control + jmp int10_end +int10_test_vbe_06: + cmp al, #0x06 + jne int10_test_vbe_07 + call vbe_biosfn_set_get_logical_scan_line_length + jmp int10_end +int10_test_vbe_07: + cmp al, #0x07 + jne int10_test_vbe_08 + call vbe_biosfn_set_get_display_start + jmp int10_end +int10_test_vbe_08: + cmp al, #0x08 + jne int10_normal + call vbe_biosfn_set_get_dac_palette_format + jmp int10_end +#endif + +int10_normal: + push es + push ds + pusha + +;; We have to set ds to access the right data segment + mov bx, #0xc000 + mov ds, bx + call _int10_func + + popa + pop ds + pop es +int10_end: + popf + iret +ASM_END + +#include "vgatables.h" +#include "vgafonts.h" + +/* + * Boot time harware inits + */ +ASM_START +init_vga_card: +;; switch to color mode and enable CPU access 480 lines + mov dx, #0x3C2 + mov al, #0xC3 + outb dx,al + +;; more than 64k 3C4/04 + mov dx, #0x3C4 + mov al, #0x04 + outb dx,al + mov dx, #0x3C5 + mov al, #0x02 + outb dx,al + +#if defined(USE_BX_INFO) || defined(DEBUG) + mov bx, #msg_vga_init + push bx + call _printf +#endif + inc sp + inc sp + ret + +#if defined(USE_BX_INFO) || defined(DEBUG) +msg_vga_init: +.ascii "VGABios $Id: vgabios.c,v 1.1 2007/11/29 20:26:38 pdinda Exp $" +.byte 0x0d,0x0a,0x00 +#endif +ASM_END + +// -------------------------------------------------------------------------------------------- +/* + * Boot time bios area inits + */ +ASM_START +init_bios_area: + push ds + mov ax, # BIOSMEM_SEG + mov ds, ax + +;; init detected hardware BIOS Area + mov bx, # BIOSMEM_INITIAL_MODE + mov ax, [bx] + and ax, #0xffcf + mov [bx], ax + +;; Just for the first int10 find its children + +;; the default char height + mov bx, # BIOSMEM_CHAR_HEIGHT + mov al, #0x10 + mov [bx], al + +;; Clear the screen + mov bx, # BIOSMEM_VIDEO_CTL + mov al, #0x60 + mov [bx], al + +;; Set the basic screen we have + mov bx, # BIOSMEM_SWITCHES + mov al, #0xf9 + mov [bx], al + +;; Set the basic modeset options + mov bx, # BIOSMEM_MODESET_CTL + mov al, #0x51 + mov [bx], al + +;; Set the default MSR + mov bx, # BIOSMEM_CURRENT_MSR + mov al, #0x09 + mov [bx], al + + pop ds + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +/* + * Boot time Splash screen + */ +static void display_splash_screen() +{ +} + +// -------------------------------------------------------------------------------------------- +/* + * Tell who we are + */ + +static void display_info() +{ +ASM_START + mov ax,#0xc000 + mov ds,ax + mov si,#vgabios_name + call _display_string + mov si,#vgabios_version + call _display_string + + ;;mov si,#vgabios_copyright + ;;call _display_string + ;;mov si,#crlf + ;;call _display_string + + mov si,#vgabios_license + call _display_string + mov si,#vgabios_website + call _display_string +ASM_END +} + +static void display_string() +{ + // Get length of string +ASM_START + mov ax,ds + mov es,ax + mov di,si + xor cx,cx + not cx + xor al,al + cld + repne + scasb + not cx + dec cx + push cx + + mov ax,#0x0300 + mov bx,#0x0000 + int #0x10 + + pop cx + mov ax,#0x1301 + mov bx,#0x000b + mov bp,si + int #0x10 +ASM_END +} + +// -------------------------------------------------------------------------------------------- +#ifdef DEBUG +static void int10_debugmsg(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS) + Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS; +{ + // 0E is write char... + if(GET_AH()!=0x0E) + printf("vgabios call ah%02x al%02x bx%04x cx%04x dx%04x\n",GET_AH(),GET_AL(),BX,CX,DX); +} +#endif + +// -------------------------------------------------------------------------------------------- +/* + * int10 main dispatcher + */ +static void int10_func(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS) + Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS; +{ + + // BIOS functions + switch(GET_AH()) + { + case 0x00: + biosfn_set_video_mode(GET_AL()); + switch(GET_AL()&0x7F) + {case 6: + SET_AL(0x3F); + break; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 7: + SET_AL(0x30); + break; + default: + SET_AL(0x20); + } + break; + case 0x01: + biosfn_set_cursor_shape(GET_CH(),GET_CL()); + break; + case 0x02: + biosfn_set_cursor_pos(GET_BH(),DX); + break; + case 0x03: + biosfn_get_cursor_pos(GET_BH(),&CX,&DX); + break; + case 0x04: + // Read light pen pos (unimplemented) +#ifdef DEBUG + unimplemented(); +#endif + AX=0x00; + BX=0x00; + CX=0x00; + DX=0x00; + break; + case 0x05: + biosfn_set_active_page(GET_AL()); + break; + case 0x06: + biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_UP); + break; + case 0x07: + biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_DOWN); + break; + case 0x08: + biosfn_read_char_attr(GET_BH(),&AX); + break; + case 0x09: + biosfn_write_char_attr(GET_AL(),GET_BH(),GET_BL(),CX); + break; + case 0x0A: + biosfn_write_char_only(GET_AL(),GET_BH(),GET_BL(),CX); + break; + case 0x0C: + biosfn_write_pixel(GET_BH(),GET_AL(),CX,DX); + break; + case 0x0D: + biosfn_read_pixel(GET_BH(),CX,DX,&AX); + break; + case 0x0E: + // Ralf Brown Interrupt list is WRONG on bh(page) + // We do output only on the current page ! + biosfn_write_teletype(GET_AL(),0xff,GET_BL(),NO_ATTR); + break; + case 0x10: + // All other functions of group AH=0x10 rewritten in assembler + biosfn_perform_gray_scale_summing(BX,CX); + break; + case 0x11: + switch(GET_AL()) + { + case 0x00: + case 0x10: + biosfn_load_text_user_pat(GET_AL(),ES,BP,CX,DX,GET_BL(),GET_BH()); + break; + case 0x01: + case 0x11: + biosfn_load_text_8_14_pat(GET_AL(),GET_BL()); + break; + case 0x02: + case 0x12: + biosfn_load_text_8_8_pat(GET_AL(),GET_BL()); + break; + case 0x04: + case 0x14: + biosfn_load_text_8_16_pat(GET_AL(),GET_BL()); + break; + case 0x20: + biosfn_load_gfx_8_8_chars(ES,BP); + break; + case 0x21: + biosfn_load_gfx_user_chars(ES,BP,CX,GET_BL(),GET_DL()); + break; + case 0x22: + biosfn_load_gfx_8_14_chars(GET_BL()); + break; + case 0x23: + biosfn_load_gfx_8_8_dd_chars(GET_BL()); + break; + case 0x24: + biosfn_load_gfx_8_16_chars(GET_BL()); + break; + case 0x30: + biosfn_get_font_info(GET_BH(),&ES,&BP,&CX,&DX); + break; +#ifdef DEBUG + default: + unknown(); +#endif + } + + break; + case 0x12: + switch(GET_BL()) + { + case 0x20: + biosfn_alternate_prtsc(); + break; + case 0x35: + biosfn_switch_video_interface(GET_AL(),ES,DX); + SET_AL(0x12); + break; + case 0x36: + biosfn_enable_video_refresh_control(GET_AL()); + SET_AL(0x12); + break; +#ifdef DEBUG + default: + unknown(); +#endif + } + break; + case 0x13: + biosfn_write_string(GET_AL(),GET_BH(),GET_BL(),CX,GET_DH(),GET_DL(),ES,BP); + break; + case 0x1B: + biosfn_read_state_info(BX,ES,DI); + SET_AL(0x1B); + break; + case 0x1C: + switch(GET_AL()) + { + case 0x00: + biosfn_read_video_state_size(CX,&BX); + break; + case 0x01: + biosfn_save_video_state(CX,ES,BX); + break; + case 0x02: + biosfn_restore_video_state(CX,ES,BX); + break; +#ifdef DEBUG + default: + unknown(); +#endif + } + SET_AL(0x1C); + break; + +#ifdef VBE + case 0x4f: + if (vbe_has_vbe_display()) { + switch(GET_AL()) + { + case 0x00: + vbe_biosfn_return_controller_information(&AX,ES,DI); + break; + case 0x01: + vbe_biosfn_return_mode_information(&AX,CX,ES,DI); + break; + case 0x02: + vbe_biosfn_set_mode(&AX,BX,ES,DI); + break; + case 0x04: + //FIXME +#ifdef DEBUG + unimplemented(); +#endif + // function failed + AX=0x100; + break; + case 0x09: + //FIXME +#ifdef DEBUG + unimplemented(); +#endif + // function failed + AX=0x100; + break; + case 0x0A: + //FIXME +#ifdef DEBUG + unimplemented(); +#endif + // function failed + AX=0x100; + break; + default: +#ifdef DEBUG + unknown(); +#endif + // function failed + AX=0x100; + } + } + else { + // No VBE display + AX=0x0100; + } + break; +#endif + +#ifdef DEBUG + default: + unknown(); +#endif + } +} + +// ============================================================================================ +// +// BIOS functions +// +// ============================================================================================ + +static void biosfn_set_video_mode(mode) Bit8u mode; +{// mode: Bit 7 is 1 if no clear screen + + // Should we clear the screen ? + Bit8u noclearmem=mode&0x80; + Bit8u line,mmask,*palette; + Bit16u i,twidth,theight,cheight; + Bit8u modeset_ctl,video_ctl,vga_switches; + Bit16u crtc_addr; + +#ifdef VBE + if (vbe_has_vbe_display()) { + dispi_set_enable(VBE_DISPI_DISABLED); + } +#endif // def VBE + + // The real mode + mode=mode&0x7f; + + // find the entry in the video modes + line=find_vga_entry(mode); + +#ifdef DEBUG + printf("mode search %02x found line %02x\n",mode,line); +#endif + + if(line==0xFF) + return; + + twidth=vga_modes[line].twidth; + theight=vga_modes[line].theight; + cheight=vga_modes[line].cheight; + + // Read the bios vga control + video_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL); + + // Read the bios vga switches + vga_switches=read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES); + + // Read the bios mode set control + modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL); + + // Then we know the number of lines +// FIXME + + // if palette loading (bit 3 of modeset ctl = 0) + if((modeset_ctl&0x08)==0) + {// Set the PEL mask + outb(VGAREG_PEL_MASK,vga_modes[line].pelmask); + + // Set the whole dac always, from 0 + outb(VGAREG_DAC_WRITE_ADDRESS,0x00); + + // From which palette + switch(vga_modes[line].dacmodel) + {case 0: + palette=&palette0; + break; + case 1: + palette=&palette1; + break; + case 2: + palette=&palette2; + break; + case 3: + palette=&palette3; + break; + } + + // Always 256*3 values + for(i=0;i<0x0100;i++) + { + if(i<=dac_regs[vga_modes[line].dacmodel]) + {outb(VGAREG_DAC_DATA,palette[(i*3)+0]); + outb(VGAREG_DAC_DATA,palette[(i*3)+1]); + outb(VGAREG_DAC_DATA,palette[(i*3)+2]); + } + else + {outb(VGAREG_DAC_DATA,0); + outb(VGAREG_DAC_DATA,0); + outb(VGAREG_DAC_DATA,0); + } + } + if((modeset_ctl&0x02)==0x02) + { + biosfn_perform_gray_scale_summing(0x00, 0x100); + } + } + + // Reset Attribute Ctl flip-flop + inb(VGAREG_ACTL_RESET); + + // Set Attribute Ctl + for(i=0;i<=ACTL_MAX_REG;i++) + {outb(VGAREG_ACTL_ADDRESS,i); + outb(VGAREG_ACTL_WRITE_DATA,actl_regs[vga_modes[line].actlmodel][i]); + } + + // Set Sequencer Ctl + for(i=0;i<=SEQU_MAX_REG;i++) + {outb(VGAREG_SEQU_ADDRESS,i); + outb(VGAREG_SEQU_DATA,sequ_regs[vga_modes[line].sequmodel][i]); + } + + // Set Grafx Ctl + for(i=0;i<=GRDC_MAX_REG;i++) + {outb(VGAREG_GRDC_ADDRESS,i); + outb(VGAREG_GRDC_DATA,grdc_regs[vga_modes[line].grdcmodel][i]); + } + + // Set CRTC address VGA or MDA + crtc_addr=vga_modes[line].memmodel==MTEXT?VGAREG_MDA_CRTC_ADDRESS:VGAREG_VGA_CRTC_ADDRESS; + + // Disable CRTC write protection + outw(crtc_addr,0x0011); + // Set CRTC regs + for(i=0;i<=CRTC_MAX_REG;i++) + {outb(crtc_addr,i); + outb(crtc_addr+1,crtc_regs[vga_modes[line].crtcmodel][i]); + } + + // Set the misc register + outb(VGAREG_WRITE_MISC_OUTPUT,vga_modes[line].miscreg); + + // Enable video + outb(VGAREG_ACTL_ADDRESS,0x20); + inb(VGAREG_ACTL_RESET); + + if(noclearmem==0x00) + { + if(vga_modes[line].class==TEXT) + { + memsetw(vga_modes[line].sstart,0,0x0720,0x4000); // 32k + } + else + { + if(mode<0x0d) + { + memsetw(vga_modes[line].sstart,0,0x0000,0x4000); // 32k + } + else + { + outb( VGAREG_SEQU_ADDRESS, 0x02 ); + mmask = inb( VGAREG_SEQU_DATA ); + outb( VGAREG_SEQU_DATA, 0x0f ); // all planes + memsetw(vga_modes[line].sstart,0,0x0000,0x8000); // 64k + outb( VGAREG_SEQU_DATA, mmask ); + } + } + } + + // Set the BIOS mem + write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,mode); + write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS,twidth); + write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,vga_modes[line].slength); + write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,crtc_addr); + write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theight-1); + write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,cheight); + write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|noclearmem)); + write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9); + write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x7f); + + // FIXME We nearly have the good tables. to be reworked + write_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,0x08); // 8 is VGA should be ok for now + write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER,0x00); + write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER+2,0x00); + + // FIXME + write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x00); // Unavailable on vanilla vga, but... + write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,0x00); // Unavailable on vanilla vga, but... + + // Set cursor shape + if(vga_modes[line].class==TEXT) + { + biosfn_set_cursor_shape(0x06,0x07); + } + + // Set cursor pos for page 0..7 + for(i=0;i<8;i++) + biosfn_set_cursor_pos(i,0x0000); + + // Set active page 0 + biosfn_set_active_page(0x00); + + // Write the fonts in memory + if(vga_modes[line].class==TEXT) + { +ASM_START + ;; copy and activate 8x16 font + mov ax, #0x1104 + mov bl, #0x00 + int #0x10 + mov ax, #0x1103 + mov bl, #0x00 + int #0x10 +ASM_END + } + + // Set the ints 0x1F and 0x43 +ASM_START + SET_INT_VECTOR(0x1f, #0xC000, #_vgafont8+128*8) +ASM_END + + switch(cheight) + {case 8: +ASM_START + SET_INT_VECTOR(0x43, #0xC000, #_vgafont8) +ASM_END + break; + case 14: +ASM_START + SET_INT_VECTOR(0x43, #0xC000, #_vgafont14) +ASM_END + break; + case 16: +ASM_START + SET_INT_VECTOR(0x43, #0xC000, #_vgafont16) +ASM_END + break; + } +} + +// -------------------------------------------------------------------------------------------- +static void biosfn_set_cursor_shape (CH,CL) +Bit8u CH;Bit8u CL; +{Bit16u cheight,curs,crtc_addr; + Bit8u modeset_ctl; + + CH&=0x3f; + CL&=0x1f; + + curs=(CH<<8)+CL; + write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE,curs); + + modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL); + cheight = read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); + if((modeset_ctl&0x01) && (cheight>8) && (CL<8) && (CH<0x20)) + { + if(CL!=(CH+1)) + { + CH = ((CH+1) * cheight / 8) -1; + } + else + { + CH = ((CL+1) * cheight / 8) - 2; + } + CL = ((CL+1) * cheight / 8) - 1; + } + + // CTRC regs 0x0a and 0x0b + crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS); + outb(crtc_addr,0x0a); + outb(crtc_addr+1,CH); + outb(crtc_addr,0x0b); + outb(crtc_addr+1,CL); +} + +// -------------------------------------------------------------------------------------------- +static void biosfn_set_cursor_pos (page, cursor) +Bit8u page;Bit16u cursor; +{ + Bit8u xcurs,ycurs,current; + Bit16u nbcols,nbrows,address,crtc_addr; + + // Should not happen... + if(page>7)return; + + // Bios cursor pos + write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*page, cursor); + + // Set the hardware cursor + current=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); + if(page==current) + { + // Get the dimensions + nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS); + nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1; + + xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8; + + // Calculate the address knowing nbcols nbrows and page num + address=SCREEN_IO_START(nbcols,nbrows,page)+xcurs+ycurs*nbcols; + + // CRTC regs 0x0e and 0x0f + crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS); + outb(crtc_addr,0x0e); + outb(crtc_addr+1,(address&0xff00)>>8); + outb(crtc_addr,0x0f); + outb(crtc_addr+1,address&0x00ff); + } +} + +// -------------------------------------------------------------------------------------------- +static void biosfn_get_cursor_pos (page,shape, pos) +Bit8u page;Bit16u *shape;Bit16u *pos; +{ + Bit16u ss=get_SS(); + + // Default + write_word(ss, shape, 0); + write_word(ss, pos, 0); + + if(page>7)return; + // FIXME should handle VGA 14/16 lines + write_word(ss,shape,read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE)); + write_word(ss,pos,read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_POS+page*2)); +} + +// -------------------------------------------------------------------------------------------- +static void biosfn_set_active_page (page) +Bit8u page; +{ + Bit16u cursor,dummy,crtc_addr; + Bit16u nbcols,nbrows,address; + Bit8u mode,line; + + if(page>7)return; + + // Get the mode + mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE); + line=find_vga_entry(mode); + if(line==0xFF)return; + + // Get pos curs pos for the right page + biosfn_get_cursor_pos(page,&dummy,&cursor); + + if(vga_modes[line].class==TEXT) + { + // Get the dimensions + nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS); + nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1; + + // Calculate the address knowing nbcols nbrows and page num + address=SCREEN_MEM_START(nbcols,nbrows,page); + write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START,address); + + // Start address + address=SCREEN_IO_START(nbcols,nbrows,page); + } + else + { + address = page*vga_modes[line].slength; + } + + // CRTC regs 0x0c and 0x0d + crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS); + outb(crtc_addr,0x0c); + outb(crtc_addr+1,(address&0xff00)>>8); + outb(crtc_addr,0x0d); + outb(crtc_addr+1,address&0x00ff); + + // And change the BIOS page + write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE,page); + +#ifdef DEBUG + printf("Set active page %02x address %04x\n",page,address); +#endif + + // Display the cursor, now the page is active + biosfn_set_cursor_pos(page,cursor); +} + +// -------------------------------------------------------------------------------------------- +static void vgamem_copy_pl4(xstart,ysrc,ydest,cols,nbcols,cheight) +Bit8u xstart;Bit8u ysrc;Bit8u ydest;Bit8u cols;Bit8u nbcols;Bit8u cheight; +{ + Bit16u src,dest; + Bit8u i; + + src=ysrc*cheight*nbcols+xstart; + dest=ydest*cheight*nbcols+xstart; + outw(VGAREG_GRDC_ADDRESS, 0x0105); + for(i=0;i>1)+xstart; + dest=((ydest*cheight*nbcols)>>1)+xstart; + for(i=0;i>1)*nbcols,0xb800,0x2000+src+(i>>1)*nbcols,cols); + else + memcpyb(0xb800,dest+(i>>1)*nbcols,0xb800,src+(i>>1)*nbcols,cols); + } +} + +// -------------------------------------------------------------------------------------------- +static void vgamem_fill_cga(xstart,ystart,cols,nbcols,cheight,attr) +Bit8u xstart;Bit8u ystart;Bit8u cols;Bit8u nbcols;Bit8u cheight;Bit8u attr; +{ + Bit16u dest; + Bit8u i; + + dest=((ystart*cheight*nbcols)>>1)+xstart; + for(i=0;i>1)*nbcols,attr,cols); + else + memsetb(0xb800,dest+(i>>1)*nbcols,attr,cols); + } +} + +// -------------------------------------------------------------------------------------------- +static void biosfn_scroll (nblines,attr,rul,cul,rlr,clr,page,dir) +Bit8u nblines;Bit8u attr;Bit8u rul;Bit8u cul;Bit8u rlr;Bit8u clr;Bit8u page;Bit8u dir; +{ + // page == 0xFF if current + + Bit8u mode,line,cheight,bpp,cols; + Bit16u nbcols,nbrows,i; + Bit16u address; + + if(rul>rlr)return; + if(cul>clr)return; + + // Get the mode + mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE); + line=find_vga_entry(mode); + if(line==0xFF)return; + + // Get the dimensions + nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1; + nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS); + + // Get the current page + if(page==0xFF) + page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); + + if(rlr>=nbrows)rlr=nbrows-1; + if(clr>=nbcols)clr=nbcols-1; + if(nblines>nbrows)nblines=0; + cols=clr-cul+1; + + if(vga_modes[line].class==TEXT) + { + // Compute the address + address=SCREEN_MEM_START(nbcols,nbrows,page); +#ifdef DEBUG + printf("Scroll, address %04x (%04x %04x %02x)\n",address,nbrows,nbcols,page); +#endif + + if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1) + { + memsetw(vga_modes[line].sstart,address,(Bit16u)attr*0x100+' ',nbrows*nbcols); + } + else + {// if Scroll up + if(dir==SCROLL_UP) + {for(i=rul;i<=rlr;i++) + { + if((i+nblines>rlr)||(nblines==0)) + memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(Bit16u)attr*0x100+' ',cols); + else + memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i+nblines)*nbcols+cul)*2,cols); + } + } + else + {for(i=rlr;i>=rul;i--) + { + if((irlr)||(nblines==0)) + vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr); + else + vgamem_copy_pl4(cul,i+nblines,i,cols,nbcols,cheight); + } + } + else + {for(i=rlr;i>=rul;i--) + { + if((irlr)||(nblines==0)) + vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr); + else + vgamem_copy_cga(cul,i+nblines,i,cols,nbcols,cheight); + } + } + else + {for(i=rlr;i>=rul;i--) + { + if((i>8; + + // Get the dimensions + nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1; + nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS); + + if(vga_modes[line].class==TEXT) + { + // Compute the address + address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2; + + write_word(ss,car,read_word(vga_modes[line].sstart,address)); + } + else + { + // FIXME gfx mode +#ifdef DEBUG + unimplemented(); +#endif + } +} + +// -------------------------------------------------------------------------------------------- +static void write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight) +Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;Bit8u cheight; +{ + Bit8u i,j,mask; + Bit8u *fdata; + Bit16u addr,dest,src; + + switch(cheight) + {case 14: + fdata = &vgafont14; + break; + case 16: + fdata = &vgafont16; + break; + default: + fdata = &vgafont8; + } + addr=xcurs+ycurs*cheight*nbcols; + src = car * cheight; + outw(VGAREG_SEQU_ADDRESS, 0x0f02); + outw(VGAREG_GRDC_ADDRESS, 0x0205); + if(attr&0x80) + { + outw(VGAREG_GRDC_ADDRESS, 0x1803); + } + else + { + outw(VGAREG_GRDC_ADDRESS, 0x0003); + } + for(i=0;i>j; + outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08); + read_byte(0xa000,dest); + if(fdata[src+i]&mask) + { + write_byte(0xa000,dest,attr&0x0f); + } + else + { + write_byte(0xa000,dest,0x00); + } + } + } +ASM_START + mov dx, # VGAREG_GRDC_ADDRESS + mov ax, #0xff08 + out dx, ax + mov ax, #0x0005 + out dx, ax + mov ax, #0x0003 + out dx, ax +ASM_END +} + +// -------------------------------------------------------------------------------------------- +static void write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp) +Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;Bit8u bpp; +{ + Bit8u i,j,mask,data; + Bit8u *fdata; + Bit16u addr,dest,src; + + fdata = &vgafont8; + addr=(xcurs*bpp)+ycurs*320; + src = car * 8; + for(i=0;i<8;i++) + { + dest=addr+(i>>1)*80; + if (i & 1) dest += 0x2000; + mask = 0x80; + if (bpp == 1) + { + if (attr & 0x80) + { + data = read_byte(0xb800,dest); + } + else + { + data = 0x00; + } + for(j=0;j<8;j++) + { + if (fdata[src+i] & mask) + { + if (attr & 0x80) + { + data ^= (attr & 0x01) << (7-j); + } + else + { + data |= (attr & 0x01) << (7-j); + } + } + mask >>= 1; + } + write_byte(0xb800,dest,data); + } + else + { + while (mask > 0) + { + if (attr & 0x80) + { + data = read_byte(0xb800,dest); + } + else + { + data = 0x00; + } + for(j=0;j<4;j++) + { + if (fdata[src+i] & mask) + { + if (attr & 0x80) + { + data ^= (attr & 0x03) << ((3-j)*2); + } + else + { + data |= (attr & 0x03) << ((3-j)*2); + } + } + mask >>= 1; + } + write_byte(0xb800,dest,data); + dest += 1; + } + } + } +} + +// -------------------------------------------------------------------------------------------- +static void write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols) +Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols; +{ + Bit8u i,j,mask,data; + Bit8u *fdata; + Bit16u addr,dest,src; + + fdata = &vgafont8; + addr=xcurs*8+ycurs*nbcols*64; + src = car * 8; + for(i=0;i<8;i++) + { + dest=addr+i*nbcols*8; + mask = 0x80; + for(j=0;j<8;j++) + { + data = 0x00; + if (fdata[src+i] & mask) + { + data = attr; + } + write_byte(0xa000,dest+j,data); + mask >>= 1; + } + } +} + +// -------------------------------------------------------------------------------------------- +static void biosfn_write_char_attr (car,page,attr,count) +Bit8u car;Bit8u page;Bit8u attr;Bit16u count; +{ + Bit8u cheight,xcurs,ycurs,mode,line,bpp; + Bit16u nbcols,nbrows,address; + Bit16u cursor,dummy; + + // Get the mode + mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE); + line=find_vga_entry(mode); + if(line==0xFF)return; + + // Get the cursor pos for the page + biosfn_get_cursor_pos(page,&dummy,&cursor); + xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8; + + // Get the dimensions + nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1; + nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS); + + if(vga_modes[line].class==TEXT) + { + // Compute the address + address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2; + + dummy=((Bit16u)attr<<8)+car; +/* +printf("sstart=%x\n", vga_modes[line].sstart); +printf("address=%x\n", address); +printf("dummy=%x\n", dummy); +printf("count=%x\n", count); +*/ + memsetw(vga_modes[line].sstart,address,dummy,count); + } + else + { + // FIXME gfx mode not complete + cheight=vga_modes[line].cheight; + bpp=vga_modes[line].pixbits; + while((count-->0) && (xcurs>8; + + // Get the dimensions + nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1; + nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS); + + if(vga_modes[line].class==TEXT) + { + // Compute the address + address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2; + + while(count-->0) + {write_byte(vga_modes[line].sstart,address,car); + address+=2; + } + } + else + { + // FIXME gfx mode not complete + cheight=vga_modes[line].cheight; + bpp=vga_modes[line].pixbits; + while((count-->0) && (xcurs> (CX & 0x07); + outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08); + outw(VGAREG_GRDC_ADDRESS, 0x0205); + data = read_byte(0xa000,addr); + if (AL & 0x80) + { + outw(VGAREG_GRDC_ADDRESS, 0x1803); + } + write_byte(0xa000,addr,AL); +ASM_START + mov dx, # VGAREG_GRDC_ADDRESS + mov ax, #0xff08 + out dx, ax + mov ax, #0x0005 + out dx, ax + mov ax, #0x0003 + out dx, ax +ASM_END + break; + case CGA: + if(vga_modes[line].pixbits==2) + { + addr=(CX>>2)+(DX>>1)*80; + } + else + { + addr=(CX>>3)+(DX>>1)*80; + } + if (DX & 1) addr += 0x2000; + data = read_byte(0xb800,addr); + if(vga_modes[line].pixbits==2) + { + attr = (AL & 0x03) << ((3 - (CX & 0x03)) * 2); + mask = 0x03 << ((3 - (CX & 0x03)) * 2); + } + else + { + attr = (AL & 0x01) << (7 - (CX & 0x07)); + mask = 0x01 << (7 - (CX & 0x07)); + } + if (AL & 0x80) + { + data ^= attr; + } + else + { + data &= ~mask; + data |= attr; + } + write_byte(0xb800,addr,data); + break; + case LINEAR8: + addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8); + write_byte(0xa000,addr,AL); + break; +#ifdef DEBUG + default: + unimplemented(); +#endif + } +} + +// -------------------------------------------------------------------------------------------- +static void biosfn_read_pixel (BH,CX,DX,AX) Bit8u BH;Bit16u CX;Bit16u DX;Bit16u *AX; +{ + Bit8u mode,line,mask,attr,data,i; + Bit16u addr; + Bit16u ss=get_SS(); + + // Get the mode + mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE); + line=find_vga_entry(mode); + if(line==0xFF)return; + if(vga_modes[line].class==TEXT)return; + + switch(vga_modes[line].memmodel) + { + case PLANAR4: + case PLANAR1: + addr = CX/8+DX*read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS); + mask = 0x80 >> (CX & 0x07); + attr = 0x00; + for(i=0;i<4;i++) + { + outw(VGAREG_GRDC_ADDRESS, (i << 8) | 0x04); + data = read_byte(0xa000,addr) & mask; + if (data > 0) attr |= (0x01 << i); + } + break; + case CGA: + addr=(CX>>2)+(DX>>1)*80; + if (DX & 1) addr += 0x2000; + data = read_byte(0xb800,addr); + if(vga_modes[line].pixbits==2) + { + attr = (data >> ((3 - (CX & 0x03)) * 2)) & 0x03; + } + else + { + attr = (data >> (7 - (CX & 0x07))) & 0x01; + } + break; + case LINEAR8: + addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8); + attr=read_byte(0xa000,addr); + break; + default: +#ifdef DEBUG + unimplemented(); +#endif + attr = 0; + } + write_word(ss,AX,(read_word(ss,AX) & 0xff00) | attr); +} + +// -------------------------------------------------------------------------------------------- +static void biosfn_write_teletype (car, page, attr, flag) +Bit8u car;Bit8u page;Bit8u attr;Bit8u flag; +{// flag = WITH_ATTR / NO_ATTR + + Bit8u cheight,xcurs,ycurs,mode,line,bpp; + Bit16u nbcols,nbrows,address; + Bit16u cursor,dummy; + + // special case if page is 0xff, use current page + if(page==0xff) + page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); + + // Get the mode + mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE); + line=find_vga_entry(mode); + if(line==0xFF)return; + + // Get the cursor pos for the page + biosfn_get_cursor_pos(page,&dummy,&cursor); + xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8; + + // Get the dimensions + nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1; + nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS); + + switch(car) + { + case 7: + //FIXME should beep + break; + + case 8: + if(xcurs>0)xcurs--; + break; + + case '\r': + xcurs=0; + break; + + case '\n': + xcurs=0; + ycurs++; + break; + + case '\t': + do + { + biosfn_write_teletype(' ',page,attr,flag); + biosfn_get_cursor_pos(page,&dummy,&cursor); + xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8; + }while(xcurs%8==0); + break; + + default: + + if(vga_modes[line].class==TEXT) + { + // Compute the address + address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2; + + // Write the char + write_byte(vga_modes[line].sstart,address,car); + + if(flag==WITH_ATTR) + write_byte(vga_modes[line].sstart,address+1,attr); + } + else + { + // FIXME gfx mode not complete + cheight=vga_modes[line].cheight; + bpp=vga_modes[line].pixbits; + switch(vga_modes[line].memmodel) + { + case PLANAR4: + case PLANAR1: + write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight); + break; + case CGA: + write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp); + break; + case LINEAR8: + write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols); + break; +#ifdef DEBUG + default: + unimplemented(); +#endif + } + } + xcurs++; + } + + // Do we need to wrap ? + if(xcurs==nbcols) + {xcurs=0; + ycurs++; + } + + // Do we need to scroll ? + if(ycurs==nbrows) + { + if(vga_modes[line].class==TEXT) + { + biosfn_scroll(0x01,0x07,0,0,nbrows-1,nbcols-1,page,SCROLL_UP); + } + else + { + biosfn_scroll(0x01,0x00,0,0,nbrows-1,nbcols-1,page,SCROLL_UP); + } + ycurs-=1; + } + + // Set the cursor for the page + cursor=ycurs; cursor<<=8; cursor+=xcurs; + biosfn_set_cursor_pos(page,cursor); +} + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_get_video_mode: + push ds + mov ax, # BIOSMEM_SEG + mov ds, ax + push bx + mov bx, # BIOSMEM_CURRENT_PAGE + mov al, [bx] + pop bx + mov bh, al + push bx + mov bx, # BIOSMEM_VIDEO_CTL + mov ah, [bx] + and ah, #0x80 + mov bx, # BIOSMEM_CURRENT_MODE + mov al, [bx] + or al, ah + mov bx, # BIOSMEM_NB_COLS + mov ah, [bx] + pop bx + pop ds + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_group_10: + cmp al, #0x00 + jne int10_test_1001 + jmp biosfn_set_single_palette_reg +int10_test_1001: + cmp al, #0x01 + jne int10_test_1002 + jmp biosfn_set_overscan_border_color +int10_test_1002: + cmp al, #0x02 + jne int10_test_1003 + jmp biosfn_set_all_palette_reg +int10_test_1003: + cmp al, #0x03 + jne int10_test_1007 + jmp biosfn_toggle_intensity +int10_test_1007: + cmp al, #0x07 + jne int10_test_1008 + jmp biosfn_get_single_palette_reg +int10_test_1008: + cmp al, #0x08 + jne int10_test_1009 + jmp biosfn_read_overscan_border_color +int10_test_1009: + cmp al, #0x09 + jne int10_test_1010 + jmp biosfn_get_all_palette_reg +int10_test_1010: + cmp al, #0x10 + jne int10_test_1012 + jmp biosfn_set_single_dac_reg +int10_test_1012: + cmp al, #0x12 + jne int10_test_1013 + jmp biosfn_set_all_dac_reg +int10_test_1013: + cmp al, #0x13 + jne int10_test_1015 + jmp biosfn_select_video_dac_color_page +int10_test_1015: + cmp al, #0x15 + jne int10_test_1017 + jmp biosfn_read_single_dac_reg +int10_test_1017: + cmp al, #0x17 + jne int10_test_1018 + jmp biosfn_read_all_dac_reg +int10_test_1018: + cmp al, #0x18 + jne int10_test_1019 + jmp biosfn_set_pel_mask +int10_test_1019: + cmp al, #0x19 + jne int10_test_101A + jmp biosfn_read_pel_mask +int10_test_101A: + cmp al, #0x1a + jne int10_group_10_unknown + jmp biosfn_read_video_dac_state +int10_group_10_unknown: +#ifdef DEBUG + call _unknown +#endif + ret + +biosfn_set_single_palette_reg: + cmp bl, #0x14 + ja no_actl_reg1 + push ax + push dx + mov dx, # VGAREG_ACTL_RESET + in al, dx + mov dx, # VGAREG_ACTL_ADDRESS + mov al, bl + out dx, al + mov al, bh + out dx, al + mov al, #0x20 + out dx, al + pop dx + pop ax +no_actl_reg1: + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_set_overscan_border_color: + push bx + mov bl, #0x11 + call biosfn_set_single_palette_reg + pop bx + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_set_all_palette_reg: + push ax + push bx + push cx + push dx + mov bx, dx + mov dx, # VGAREG_ACTL_RESET + in al, dx + mov cl, #0x00 + mov dx, # VGAREG_ACTL_ADDRESS +set_palette_loop: + mov al, cl + out dx, al + seg es + mov al, [bx] + out dx, al + inc bx + inc cl + cmp cl, #0x10 + jne set_palette_loop + mov al, #0x11 + out dx, al + seg es + mov al, [bx] + out dx, al + mov al, #0x20 + out dx, al + pop dx + pop cx + pop bx + pop ax + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_toggle_intensity: + push ax + push bx + push dx + mov dx, # VGAREG_ACTL_RESET + in al, dx + mov dx, # VGAREG_ACTL_ADDRESS + mov al, #0x10 + out dx, al + mov dx, # VGAREG_ACTL_READ_DATA + in al, dx + and al, #0xf7 + and bl, #0x01 + shl bl, 3 + or al, bl + mov dx, # VGAREG_ACTL_ADDRESS + out dx, al + mov al, #0x20 + out dx, al + pop dx + pop bx + pop ax + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_get_single_palette_reg: + cmp bl, #0x14 + ja no_actl_reg2 + push ax + push dx + mov dx, # VGAREG_ACTL_RESET + in al, dx + mov dx, # VGAREG_ACTL_ADDRESS + mov al, bl + out dx, al + mov dx, # VGAREG_ACTL_READ_DATA + in al, dx + mov bh, al + mov dx, # VGAREG_ACTL_RESET + in al, dx + mov dx, # VGAREG_ACTL_ADDRESS + mov al, #0x20 + out dx, al + pop dx + pop ax +no_actl_reg2: + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_read_overscan_border_color: + push ax + push bx + mov bl, #0x11 + call biosfn_get_single_palette_reg + mov al, bh + pop bx + mov bh, al + pop ax + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_get_all_palette_reg: + push ax + push bx + push cx + push dx + mov bx, dx + mov cl, #0x00 +get_palette_loop: + mov dx, # VGAREG_ACTL_RESET + in al, dx + mov dx, # VGAREG_ACTL_ADDRESS + mov al, cl + out dx, al + mov dx, # VGAREG_ACTL_READ_DATA + in al, dx + seg es + mov [bx], al + inc bx + inc cl + cmp cl, #0x10 + jne get_palette_loop + mov dx, # VGAREG_ACTL_RESET + in al, dx + mov dx, # VGAREG_ACTL_ADDRESS + mov al, #0x11 + out dx, al + mov dx, # VGAREG_ACTL_READ_DATA + in al, dx + seg es + mov [bx], al + mov dx, # VGAREG_ACTL_RESET + in al, dx + mov dx, # VGAREG_ACTL_ADDRESS + mov al, #0x20 + out dx, al + pop dx + pop cx + pop bx + pop ax + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_set_single_dac_reg: + push ax + push dx + mov dx, # VGAREG_DAC_WRITE_ADDRESS + mov al, bl + out dx, al + mov dx, # VGAREG_DAC_DATA + pop ax + push ax + mov al, ah + out dx, al + mov al, ch + out dx, al + mov al, cl + out dx, al + pop dx + pop ax + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_set_all_dac_reg: + push ax + push bx + push cx + push dx + mov dx, # VGAREG_DAC_WRITE_ADDRESS + mov al, bl + out dx, al + pop dx + push dx + mov bx, dx + mov dx, # VGAREG_DAC_DATA +set_dac_loop: + seg es + mov al, [bx] + out dx, al + inc bx + seg es + mov al, [bx] + out dx, al + inc bx + seg es + mov al, [bx] + out dx, al + inc bx + dec cx + jnz set_dac_loop + pop dx + pop cx + pop bx + pop ax + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_select_video_dac_color_page: + push ax + push bx + push dx + mov dx, # VGAREG_ACTL_RESET + in al, dx + mov dx, # VGAREG_ACTL_ADDRESS + mov al, #0x10 + out dx, al + mov dx, # VGAREG_ACTL_READ_DATA + in al, dx + and bl, #0x01 + jnz set_dac_page + and al, #0x7f + shl bh, 7 + or al, bh + mov dx, # VGAREG_ACTL_ADDRESS + out dx, al + jmp set_actl_normal +set_dac_page: + push ax + mov dx, # VGAREG_ACTL_RESET + in al, dx + mov dx, # VGAREG_ACTL_ADDRESS + mov al, #0x14 + out dx, al + pop ax + and al, #0x80 + jnz set_dac_16_page + shl bh, 2 +set_dac_16_page: + and bh, #0x0f + mov al, bh + out dx, al +set_actl_normal: + mov al, #0x20 + out dx, al + pop dx + pop bx + pop ax + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_read_single_dac_reg: + push ax + push dx + mov dx, # VGAREG_DAC_READ_ADDRESS + mov al, bl + out dx, al + pop ax + mov ah, al + mov dx, # VGAREG_DAC_DATA + in al, dx + xchg al, ah + push ax + in al, dx + mov ch, al + in al, dx + mov cl, al + pop dx + pop ax + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_read_all_dac_reg: + push ax + push bx + push cx + push dx + mov dx, # VGAREG_DAC_READ_ADDRESS + mov al, bl + out dx, al + pop dx + push dx + mov bx, dx + mov dx, # VGAREG_DAC_DATA +read_dac_loop: + in al, dx + seg es + mov [bx], al + inc bx + in al, dx + seg es + mov [bx], al + inc bx + in al, dx + seg es + mov [bx], al + inc bx + dec cx + jnz read_dac_loop + pop dx + pop cx + pop bx + pop ax + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_set_pel_mask: + push ax + push dx + mov dx, # VGAREG_PEL_MASK + mov al, bl + out dx, al + pop dx + pop ax + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_read_pel_mask: + push ax + push dx + mov dx, # VGAREG_PEL_MASK + in al, dx + mov bl, al + pop dx + pop ax + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_read_video_dac_state: + push ax + push dx + mov dx, # VGAREG_ACTL_RESET + in al, dx + mov dx, # VGAREG_ACTL_ADDRESS + mov al, #0x10 + out dx, al + mov dx, # VGAREG_ACTL_READ_DATA + in al, dx + mov bl, al + shr bl, 7 + mov dx, # VGAREG_ACTL_RESET + in al, dx + mov dx, # VGAREG_ACTL_ADDRESS + mov al, #0x14 + out dx, al + mov dx, # VGAREG_ACTL_READ_DATA + in al, dx + mov bh, al + and bh, #0x0f + test bl, #0x01 + jnz get_dac_16_page + shr bh, 2 +get_dac_16_page: + mov dx, # VGAREG_ACTL_RESET + in al, dx + mov dx, # VGAREG_ACTL_ADDRESS + mov al, #0x20 + out dx, al + pop dx + pop ax + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +static void biosfn_perform_gray_scale_summing (start,count) +Bit16u start;Bit16u count; +{Bit8u r,g,b; + Bit16u i; + Bit16u index; + + inb(VGAREG_ACTL_RESET); + outb(VGAREG_ACTL_ADDRESS,0x00); + + for( index = 0; index < count; index++ ) + { + // set read address and switch to read mode + outb(VGAREG_DAC_READ_ADDRESS,start); + // get 6-bit wide RGB data values + r=inb( VGAREG_DAC_DATA ); + g=inb( VGAREG_DAC_DATA ); + b=inb( VGAREG_DAC_DATA ); + + // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue ) + i = ( ( 77*r + 151*g + 28*b ) + 0x80 ) >> 8; + + if(i>0x3f)i=0x3f; + + // set write address and switch to write mode + outb(VGAREG_DAC_WRITE_ADDRESS,start); + // write new intensity value + outb( VGAREG_DAC_DATA, i&0xff ); + outb( VGAREG_DAC_DATA, i&0xff ); + outb( VGAREG_DAC_DATA, i&0xff ); + start++; + } + inb(VGAREG_ACTL_RESET); + outb(VGAREG_ACTL_ADDRESS,0x20); +} + +// -------------------------------------------------------------------------------------------- +static void get_font_access() +{ +ASM_START + mov dx, # VGAREG_SEQU_ADDRESS + mov ax, #0x0100 + out dx, ax + mov ax, #0x0402 + out dx, ax + mov ax, #0x0704 + out dx, ax + mov ax, #0x0300 + out dx, ax + mov dx, # VGAREG_GRDC_ADDRESS + mov ax, #0x0204 + out dx, ax + mov ax, #0x0005 + out dx, ax + mov ax, #0x0406 + out dx, ax +ASM_END +} + +static void release_font_access() +{ +ASM_START + mov dx, # VGAREG_SEQU_ADDRESS + mov ax, #0x0100 + out dx, ax + mov ax, #0x0302 + out dx, ax + mov ax, #0x0304 + out dx, ax + mov ax, #0x0300 + out dx, ax + mov dx, # VGAREG_READ_MISC_OUTPUT + in al, dx + and al, #0x01 + shl al, 2 + or al, #0x0a + mov ah, al + mov al, #0x06 + mov dx, # VGAREG_GRDC_ADDRESS + out dx, ax + mov ax, #0x0004 + out dx, ax + mov ax, #0x1005 + out dx, ax +ASM_END +} + +ASM_START +idiv_u: + xor dx,dx + div bx + ret +ASM_END + +static void set_scan_lines(lines) Bit8u lines; +{ + Bit16u crtc_addr,cols,page,vde; + Bit8u crtc_r9,ovl,rows; + + crtc_addr = read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS); + outb(crtc_addr, 0x09); + crtc_r9 = inb(crtc_addr+1); + crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1); + outb(crtc_addr+1, crtc_r9); + if(lines==8) + { + biosfn_set_cursor_shape(0x06,0x07); + } + else + { + biosfn_set_cursor_shape(lines-4,lines-3); + } + write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, lines); + outb(crtc_addr, 0x12); + vde = inb(crtc_addr+1); + outb(crtc_addr, 0x07); + ovl = inb(crtc_addr+1); + vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1); + rows = vde / lines; + write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, rows-1); + cols = read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS); + write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, rows * cols * 2); +} + +static void biosfn_load_text_user_pat (AL,ES,BP,CX,DX,BL,BH) Bit8u AL;Bit16u ES;Bit16u BP;Bit16u CX;Bit16u DX;Bit8u BL;Bit8u BH; +{ + Bit16u blockaddr,dest,i,src; + + get_font_access(); + blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11); + for(i=0;i=0x10) + { + set_scan_lines(BH); + } +} + +static void biosfn_load_text_8_14_pat (AL,BL) Bit8u AL;Bit8u BL; +{ + Bit16u blockaddr,dest,i,src; + + get_font_access(); + blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11); + for(i=0;i<0x100;i++) + { + src = i * 14; + dest = blockaddr + i * 32; + memcpyb(0xA000, dest, 0xC000, vgafont14+src, 14); + } + release_font_access(); + if(AL>=0x10) + { + set_scan_lines(14); + } +} + +static void biosfn_load_text_8_8_pat (AL,BL) Bit8u AL;Bit8u BL; +{ + Bit16u blockaddr,dest,i,src; + + get_font_access(); + blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11); + for(i=0;i<0x100;i++) + { + src = i * 8; + dest = blockaddr + i * 32; + memcpyb(0xA000, dest, 0xC000, vgafont8+src, 8); + } + release_font_access(); + if(AL>=0x10) + { + set_scan_lines(8); + } +} + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_set_text_block_specifier: + push ax + push dx + mov dx, # VGAREG_SEQU_ADDRESS + mov ah, bl + mov al, #0x03 + out dx, ax + pop dx + pop ax + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +static void biosfn_load_text_8_16_pat (AL,BL) Bit8u AL;Bit8u BL; +{ + Bit16u blockaddr,dest,i,src; + + get_font_access(); + blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11); + for(i=0;i<0x100;i++) + { + src = i * 16; + dest = blockaddr + i * 32; + memcpyb(0xA000, dest, 0xC000, vgafont16+src, 16); + } + release_font_access(); + if(AL>=0x10) + { + set_scan_lines(16); + } +} + +static void biosfn_load_gfx_8_8_chars (ES,BP) Bit16u ES;Bit16u BP; +{ +#ifdef DEBUG + unimplemented(); +#endif +} +static void biosfn_load_gfx_user_chars (ES,BP,CX,BL,DL) Bit16u ES;Bit16u BP;Bit16u CX;Bit8u BL;Bit8u DL; +{ +#ifdef DEBUG + unimplemented(); +#endif +} +static void biosfn_load_gfx_8_14_chars (BL) Bit8u BL; +{ +#ifdef DEBUG + unimplemented(); +#endif +} +static void biosfn_load_gfx_8_8_dd_chars (BL) Bit8u BL; +{ +#ifdef DEBUG + unimplemented(); +#endif +} +static void biosfn_load_gfx_8_16_chars (BL) Bit8u BL; +{ +#ifdef DEBUG + unimplemented(); +#endif +} +// -------------------------------------------------------------------------------------------- +static void biosfn_get_font_info (BH,ES,BP,CX,DX) +Bit8u BH;Bit16u *ES;Bit16u *BP;Bit16u *CX;Bit16u *DX; +{Bit16u ss=get_SS(); + + switch(BH) + {case 0x00: + write_word(ss,ES,read_word(0x00,0x1f*4)); + write_word(ss,BP,read_word(0x00,(0x1f*4)+2)); + break; + case 0x01: + write_word(ss,ES,read_word(0x00,0x43*4)); + write_word(ss,BP,read_word(0x00,(0x43*4)+2)); + break; + case 0x02: + write_word(ss,ES,0xC000); + write_word(ss,BP,vgafont14); + break; + case 0x03: + write_word(ss,ES,0xC000); + write_word(ss,BP,vgafont8); + break; + case 0x04: + write_word(ss,ES,0xC000); + write_word(ss,BP,vgafont8+128*8); + break; + case 0x05: + write_word(ss,ES,0xC000); + write_word(ss,BP,vgafont14alt); + break; + case 0x06: + write_word(ss,ES,0xC000); + write_word(ss,BP,vgafont16); + break; + case 0x07: + write_word(ss,ES,0xC000); + write_word(ss,BP,vgafont16alt); + break; + default: + #ifdef DEBUG + printf("Get font info BH(%02x) was discarded\n",BH); + #endif + return; + } + // Set byte/char of on screen font + write_word(ss,CX,(Bit16u)read_byte(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)); + + // Set Highest char row + write_word(ss,DX,(Bit16u)read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)); +} + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_get_ega_info: + push ds + push ax + mov ax, # BIOSMEM_SEG + mov ds, ax + xor ch, ch + mov bx, # BIOSMEM_SWITCHES + mov cl, [bx] + and cl, #0x0f + mov bx, # BIOSMEM_CRTC_ADDRESS + mov ax, [bx] + mov bx, #0x0003 + cmp ax, # VGAREG_MDA_CRTC_ADDRESS + jne mode_ega_color + mov bh, #0x01 +mode_ega_color: + pop ax + pop ds + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +static void biosfn_alternate_prtsc() +{ +#ifdef DEBUG + unimplemented(); +#endif +} + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_select_vert_res: + +; res : 00 200 lines, 01 350 lines, 02 400 lines + + push ds + push bx + push dx + mov dl, al + mov ax, # BIOSMEM_SEG + mov ds, ax + mov bx, # BIOSMEM_MODESET_CTL + mov al, [bx] + mov bx, # BIOSMEM_SWITCHES + mov ah, [bx] + cmp dl, #0x01 + je vert_res_350 + jb vert_res_200 + cmp dl, #0x02 + je vert_res_400 +#ifdef DEBUG + mov al, dl + xor ah, ah + push ax + mov bx, #msg_vert_res + push bx + call _printf + add sp, #4 +#endif + jmp set_retcode +vert_res_400: + + ; reset modeset ctl bit 7 and set bit 4 + ; set switches bit 3-0 to 0x09 + + and al, #0x7f + or al, #0x10 + and ah, #0xf0 + or ah, #0x09 + jnz set_vert_res +vert_res_350: + + ; reset modeset ctl bit 7 and bit 4 + ; set switches bit 3-0 to 0x09 + + and al, #0x6f + and ah, #0xf0 + or ah, #0x09 + jnz set_vert_res +vert_res_200: + + ; set modeset ctl bit 7 and reset bit 4 + ; set switches bit 3-0 to 0x08 + + and al, #0xef + or al, #0x80 + and ah, #0xf0 + or ah, #0x08 +set_vert_res: + mov bx, # BIOSMEM_MODESET_CTL + mov [bx], al + mov bx, # BIOSMEM_SWITCHES + mov [bx], ah +set_retcode: + mov ax, #0x1212 + pop dx + pop bx + pop ds + ret + +#ifdef DEBUG +msg_vert_res: +.ascii "Select vert res (%02x) was discarded" +.byte 0x0d,0x0a,0x00 +#endif + + +biosfn_enable_default_palette_loading: + push ds + push bx + push dx + mov dl, al + and dl, #0x01 + shl dl, 3 + mov ax, # BIOSMEM_SEG + mov ds, ax + mov bx, # BIOSMEM_MODESET_CTL + mov al, [bx] + and al, #0xf7 + or al, dl + mov [bx], al + mov ax, #0x1212 + pop dx + pop bx + pop ds + ret + + +biosfn_enable_video_addressing: + push bx + push dx + mov bl, al + and bl, #0x01 + xor bl, #0x01 + shl bl, 1 + mov dx, # VGAREG_READ_MISC_OUTPUT + in al, dx + and al, #0xfd + or al, bl + mov dx, # VGAREG_WRITE_MISC_OUTPUT + out dx, al + mov ax, #0x1212 + pop dx + pop bx + ret + + +biosfn_enable_grayscale_summing: + push ds + push bx + push dx + mov dl, al + and dl, #0x01 + xor dl, #0x01 + shl dl, 1 + mov ax, # BIOSMEM_SEG + mov ds, ax + mov bx, # BIOSMEM_MODESET_CTL + mov al, [bx] + and al, #0xfd + or al, dl + mov [bx], al + mov ax, #0x1212 + pop dx + pop bx + pop ds + ret + + +biosfn_enable_cursor_emulation: + push ds + push bx + push dx + mov dl, al + and dl, #0x01 + xor dl, #0x01 + mov ax, # BIOSMEM_SEG + mov ds, ax + mov bx, # BIOSMEM_MODESET_CTL + mov al, [bx] + and al, #0xfe + or al, dl + mov [bx], al + mov ax, #0x1212 + pop dx + pop bx + pop ds + ret +ASM_END + +// -------------------------------------------------------------------------------------------- +static void biosfn_switch_video_interface (AL,ES,DX) Bit8u AL;Bit16u ES;Bit16u DX; +{ +#ifdef DEBUG + unimplemented(); +#endif +} +static void biosfn_enable_video_refresh_control (AL) Bit8u AL; +{ +#ifdef DEBUG + unimplemented(); +#endif +} + +// -------------------------------------------------------------------------------------------- +static void biosfn_write_string (flag,page,attr,count,row,col,seg,offset) +Bit8u flag;Bit8u page;Bit8u attr;Bit16u count;Bit8u row;Bit8u col;Bit16u seg;Bit16u offset; +{ + Bit16u newcurs,oldcurs,dummy; + Bit8u car,carattr; + + // Read curs info for the page + biosfn_get_cursor_pos(page,&dummy,&oldcurs); + + // if row=0xff special case : use current cursor position + if(row==0xff) + {col=oldcurs&0x00ff; + row=(oldcurs&0xff00)>>8; + } + + newcurs=row; newcurs<<=8; newcurs+=col; + biosfn_set_cursor_pos(page,newcurs); + + while(count--!=0) + { + car=read_byte(seg,offset++); + if((flag&0x02)!=0) + attr=read_byte(seg,offset++); + + biosfn_write_teletype(car,page,attr,WITH_ATTR); + } + + // Set back curs pos + if((flag&0x01)==0) + biosfn_set_cursor_pos(page,oldcurs); +} + +// -------------------------------------------------------------------------------------------- +ASM_START +biosfn_group_1A: + cmp al, #0x00 + je biosfn_read_display_code + cmp al, #0x01 + je biosfn_set_display_code +#ifdef DEBUG + call _unknown +#endif + ret +biosfn_read_display_code: + push ds + push ax + mov ax, # BIOSMEM_SEG + mov ds, ax + mov bx, # BIOSMEM_DCC_INDEX + mov al, [bx] + mov bl, al + xor bh, bh + pop ax + mov al, ah + pop ds + ret +biosfn_set_display_code: + push ds + push ax + push bx + mov ax, # BIOSMEM_SEG + mov ds, ax + mov ax, bx + mov bx, # BIOSMEM_DCC_INDEX + mov [bx], al +#ifdef DEBUG + mov al, ah + xor ah, ah + push ax + mov bx, #msg_alt_dcc + push bx + call _printf + add sp, #4 +#endif + pop bx + pop ax + mov al, ah + pop ds + ret + +#ifdef DEBUG +msg_alt_dcc: +.ascii "Alternate Display code (%02x) was discarded" +.byte 0x0d,0x0a,0x00 +#endif +ASM_END + +// -------------------------------------------------------------------------------------------- +static void biosfn_read_state_info (BX,ES,DI) +Bit16u BX;Bit16u ES;Bit16u DI; +{ + // Address of static functionality table + write_word(ES,DI+0x00,&static_functionality); + write_word(ES,DI+0x02,0xC000); + + // Hard coded copy from BIOS area. Should it be cleaner ? + memcpyb(ES,DI+0x04,BIOSMEM_SEG,0x49,30); + memcpyb(ES,DI+0x22,BIOSMEM_SEG,0x84,3); + + write_byte(ES,DI+0x25,read_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX)); + write_byte(ES,DI+0x26,0); + write_byte(ES,DI+0x27,16); + write_byte(ES,DI+0x28,0); + write_byte(ES,DI+0x29,8); + write_byte(ES,DI+0x2a,2); + write_byte(ES,DI+0x2b,0); + write_byte(ES,DI+0x2c,0); + write_byte(ES,DI+0x31,3); + write_byte(ES,DI+0x32,0); + + memsetb(ES,DI+0x33,0,13); +} + +// -------------------------------------------------------------------------------------------- +static void biosfn_read_video_state_size (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX; +{ +#ifdef DEBUG + unimplemented(); +#endif +} +static void biosfn_save_video_state (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX; +{ +#ifdef DEBUG + unimplemented(); +#endif +} +static void biosfn_restore_video_state (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX; +{ +#ifdef DEBUG + unimplemented(); +#endif +} + +// ============================================================================================ +// +// Video Utils +// +// ============================================================================================ + +// -------------------------------------------------------------------------------------------- +static Bit8u find_vga_entry(mode) +Bit8u mode; +{ + Bit8u i,line=0xFF; + for(i=0;i<=MODE_MAX;i++) + if(vga_modes[i].svgamode==mode) + {line=i; + break; + } + return line; +} + +/* =========================================================== */ +/* + * Misc Utils +*/ +/* =========================================================== */ + +// -------------------------------------------------------------------------------------------- +static void memsetb(seg,offset,value,count) + Bit16u seg; + Bit16u offset; + Bit16u value; + Bit16u count; +{ +ASM_START + push bp + mov bp, sp + + push ax + push cx + push es + push di + + mov cx, 10[bp] ; count + cmp cx, #0x00 + je memsetb_end + mov ax, 4[bp] ; segment + mov es, ax + mov ax, 6[bp] ; offset + mov di, ax + mov al, 8[bp] ; value + cld + rep + stosb + +memsetb_end: + pop di + pop es + pop cx + pop ax + + pop bp +ASM_END +} + +// -------------------------------------------------------------------------------------------- +static void memsetw(seg,offset,value,count) + Bit16u seg; + Bit16u offset; + Bit16u value; + Bit16u count; +{ +ASM_START + push bp + mov bp, sp + + push ax + push cx + push es + push di + + mov cx, 10[bp] ; count + cmp cx, #0x00 + je memsetw_end + mov ax, 4[bp] ; segment + mov es, ax + mov ax, 6[bp] ; offset + mov di, ax + mov ax, 8[bp] ; value + cld + rep + stosw + +memsetw_end: + pop di + pop es + pop cx + pop ax + + pop bp +ASM_END +} + +// -------------------------------------------------------------------------------------------- +static void memcpyb(dseg,doffset,sseg,soffset,count) + Bit16u dseg; + Bit16u doffset; + Bit16u sseg; + Bit16u soffset; + Bit16u count; +{ +ASM_START + push bp + mov bp, sp + + push ax + push cx + push es + push di + push ds + push si + + mov cx, 12[bp] ; count + cmp cx, #0x0000 + je memcpyb_end + mov ax, 4[bp] ; dsegment + mov es, ax + mov ax, 6[bp] ; doffset + mov di, ax + mov ax, 8[bp] ; ssegment + mov ds, ax + mov ax, 10[bp] ; soffset + mov si, ax + cld + rep + movsb + +memcpyb_end: + pop si + pop ds + pop di + pop es + pop cx + pop ax + + pop bp +ASM_END +} + +// -------------------------------------------------------------------------------------------- +static void memcpyw(dseg,doffset,sseg,soffset,count) + Bit16u dseg; + Bit16u doffset; + Bit16u sseg; + Bit16u soffset; + Bit16u count; +{ +ASM_START + push bp + mov bp, sp + + push ax + push cx + push es + push di + push ds + push si + + mov cx, 12[bp] ; count + cmp cx, #0x0000 + je memcpyw_end + mov ax, 4[bp] ; dsegment + mov es, ax + mov ax, 6[bp] ; doffset + mov di, ax + mov ax, 8[bp] ; ssegment + mov ds, ax + mov ax, 10[bp] ; soffset + mov si, ax + cld + rep + movsw + +memcpyw_end: + pop si + pop ds + pop di + pop es + pop cx + pop ax + + pop bp +ASM_END +} + +/* =========================================================== */ +/* + * These functions where ripped from Kevin's rombios.c +*/ +/* =========================================================== */ + +// -------------------------------------------------------------------------------------------- +static Bit8u +read_byte(seg, offset) + Bit16u seg; + Bit16u offset; +{ +ASM_START + push bp + mov bp, sp + + push bx + push ds + mov ax, 4[bp] ; segment + mov ds, ax + mov bx, 6[bp] ; offset + mov al, [bx] + ;; al = return value (byte) + pop ds + pop bx + + pop bp +ASM_END +} + +// -------------------------------------------------------------------------------------------- +static Bit16u +read_word(seg, offset) + Bit16u seg; + Bit16u offset; +{ +ASM_START + push bp + mov bp, sp + + push bx + push ds + mov ax, 4[bp] ; segment + mov ds, ax + mov bx, 6[bp] ; offset + mov ax, [bx] + ;; ax = return value (word) + pop ds + pop bx + + pop bp +ASM_END +} + +// -------------------------------------------------------------------------------------------- +static void +write_byte(seg, offset, data) + Bit16u seg; + Bit16u offset; + Bit8u data; +{ +ASM_START + push bp + mov bp, sp + + push ax + push bx + push ds + mov ax, 4[bp] ; segment + mov ds, ax + mov bx, 6[bp] ; offset + mov al, 8[bp] ; data byte + mov [bx], al ; write data byte + pop ds + pop bx + pop ax + + pop bp +ASM_END +} + +// -------------------------------------------------------------------------------------------- +static void +write_word(seg, offset, data) + Bit16u seg; + Bit16u offset; + Bit16u data; +{ +ASM_START + push bp + mov bp, sp + + push ax + push bx + push ds + mov ax, 4[bp] ; segment + mov ds, ax + mov bx, 6[bp] ; offset + mov ax, 8[bp] ; data word + mov [bx], ax ; write data word + pop ds + pop bx + pop ax + + pop bp +ASM_END +} + +// -------------------------------------------------------------------------------------------- + Bit8u +inb(port) + Bit16u port; +{ +ASM_START + push bp + mov bp, sp + + push dx + mov dx, 4[bp] + in al, dx + pop dx + + pop bp +ASM_END +} + + Bit16u +inw(port) + Bit16u port; +{ +ASM_START + push bp + mov bp, sp + + push dx + mov dx, 4[bp] + in ax, dx + pop dx + + pop bp +ASM_END +} + +// -------------------------------------------------------------------------------------------- + void +outb(port, val) + Bit16u port; + Bit8u val; +{ +ASM_START + push bp + mov bp, sp + + push ax + push dx + mov dx, 4[bp] + mov al, 6[bp] + out dx, al + pop dx + pop ax + + pop bp +ASM_END +} + +// -------------------------------------------------------------------------------------------- + void +outw(port, val) + Bit16u port; + Bit16u val; +{ +ASM_START + push bp + mov bp, sp + + push ax + push dx + mov dx, 4[bp] + mov ax, 6[bp] + out dx, ax + pop dx + pop ax + + pop bp +ASM_END +} + +Bit16u get_SS() +{ +ASM_START + mov ax, ss +ASM_END +} + +#ifdef DEBUG +void unimplemented() +{ + printf("--> Unimplemented\n"); +} + +void unknown() +{ + printf("--> Unknown int10\n"); +} +#endif + +// -------------------------------------------------------------------------------------------- +#if defined(USE_BX_INFO) || defined(DEBUG) || defined(CIRRUS_DEBUG) +void printf(s) + Bit8u *s; +{ + Bit8u c, format_char; + Boolean in_format; + unsigned format_width, i; + Bit16u *arg_ptr; + Bit16u arg_seg, arg, digit, nibble, shift_count; + + arg_ptr = &s; + arg_seg = get_SS(); + + in_format = 0; + format_width = 0; + + while (c = read_byte(0xc000, s)) { + if ( c == '%' ) { + in_format = 1; + format_width = 0; + } + else if (in_format) { + if ( (c>='0') && (c<='9') ) { + format_width = (format_width * 10) + (c - '0'); + } + else if (c == 'x') { + arg_ptr++; // increment to next arg + arg = read_word(arg_seg, arg_ptr); + if (format_width == 0) + format_width = 4; + i = 0; + digit = format_width - 1; + for (i=0; i> (4 * digit)) & 0x000f; + if (nibble <= 9) + outb(0xE9, nibble + '0'); + else + outb(0xE9, (nibble - 10) + 'A'); + digit--; + } + in_format = 0; + } + //else if (c == 'd') { + // in_format = 0; + // } + } + else { + outb(0xE9, c); + } + s ++; + } +} +#endif + +#ifdef VBE +#include "vbe.c" +#endif + +#ifdef CIRRUS +#include "clext.c" +#endif + +// -------------------------------------------------------------------------------------------- + +ASM_START +;; DATA_SEG_DEFS_HERE +ASM_END + +ASM_START +.ascii "vgabios ends here" +.byte 0x00 +vgabios_end: +.byte 0xCB +;; BLOCK_STRINGS_BEGIN +ASM_END diff --git a/palacios/src/vmboot/vgabios/vgabios.h b/palacios/src/vmboot/vgabios/vgabios.h new file mode 100644 index 0000000..3ad4bae --- /dev/null +++ b/palacios/src/vmboot/vgabios/vgabios.h @@ -0,0 +1,47 @@ +#ifndef vgabios_h_included +#define vgabios_h_included + +/* Types */ +typedef unsigned char Bit8u; +typedef unsigned short Bit16u; +typedef unsigned long Bit32u; +typedef unsigned short Boolean; + +/* Defines */ + +#define SET_AL(val8) AX = ((AX & 0xff00) | (val8)) +#define SET_BL(val8) BX = ((BX & 0xff00) | (val8)) +#define SET_CL(val8) CX = ((CX & 0xff00) | (val8)) +#define SET_DL(val8) DX = ((DX & 0xff00) | (val8)) +#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8)) +#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8)) +#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8)) +#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8)) + +#define GET_AL() ( AX & 0x00ff ) +#define GET_BL() ( BX & 0x00ff ) +#define GET_CL() ( CX & 0x00ff ) +#define GET_DL() ( DX & 0x00ff ) +#define GET_AH() ( AX >> 8 ) +#define GET_BH() ( BX >> 8 ) +#define GET_CH() ( CX >> 8 ) +#define GET_DH() ( DX >> 8 ) + +#define SET_CF() FLAGS |= 0x0001 +#define CLEAR_CF() FLAGS &= 0xfffe +#define GET_CF() (FLAGS & 0x0001) + +#define SET_ZF() FLAGS |= 0x0040 +#define CLEAR_ZF() FLAGS &= 0xffbf +#define GET_ZF() (FLAGS & 0x0040) + +#define SCROLL_DOWN 0 +#define SCROLL_UP 1 +#define NO_ATTR 2 +#define WITH_ATTR 3 + +#define SCREEN_SIZE(x,y) (((x*y*2)|0x00ff)+1) +#define SCREEN_MEM_START(x,y,p) ((((x*y*2)|0x00ff)+1)*p) +#define SCREEN_IO_START(x,y,p) ((((x*y)|0x00ff)+1)*p) + +#endif diff --git a/palacios/src/vmboot/vgabios/vgafonts.h b/palacios/src/vmboot/vgabios/vgafonts.h new file mode 100644 index 0000000..0c213e6 --- /dev/null +++ b/palacios/src/vmboot/vgabios/vgafonts.h @@ -0,0 +1,784 @@ +/* + * These fonts come from ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip + * The package is (c) by Joseph Gil + * The individual fonts are public domain + */ +static Bit8u vgafont8[256*8]= +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, + 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, + 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, + 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, + 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c, + 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c, + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, + 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, + 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, + 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, + 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78, + 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, + 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0, + 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0, + 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99, + 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, + 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00, + 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, + 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00, + 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, + 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff, + 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, + 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, + 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, + 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, + 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00, + 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, + 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00, + 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00, + 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00, + 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, + 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, + 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, + 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, + 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, + 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, + 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00, + 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00, + 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00, + 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00, + 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, + 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00, + 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00, + 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00, + 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00, + 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00, + 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, + 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60, + 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00, + 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, + 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00, + 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, + 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00, + 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, + 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, + 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, + 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00, + 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00, + 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, + 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, + 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, + 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00, + 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, + 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, + 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00, + 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00, + 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, + 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00, + 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, + 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00, + 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, + 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, + 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, + 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00, + 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00, + 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, + 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, + 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, + 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, + 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, + 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, + 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00, + 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, + 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, + 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, + 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00, + 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, + 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00, + 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, + 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, + 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00, + 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, + 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00, + 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, + 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78, + 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, + 0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, + 0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00, + 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, + 0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, + 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, + 0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38, + 0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, + 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, + 0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, + 0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, + 0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00, + 0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00, + 0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00, + 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00, + 0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, + 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, + 0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, + 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, + 0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00, + 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, + 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18, + 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00, + 0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30, + 0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7, + 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70, + 0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, + 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, + 0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00, + 0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00, + 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, + 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, + 0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, + 0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f, + 0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03, + 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00, + 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00, + 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, + 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, + 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, + 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, + 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, + 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, + 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, + 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00, + 0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0, + 0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, + 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, + 0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00, + 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0, + 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00, + 0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc, + 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00, + 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00, + 0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, + 0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0, + 0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00, + 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, + 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00, + 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00, + 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00, + 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00, + 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, + 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00, + 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, + 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c, + 0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, + 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static Bit8u vgafont14[256*14]= +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x06, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x66, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe6, 0x66, 0x6c, 0x6c, 0x78, 0x6c, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x7c, 0x6c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0x8c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x70, 0x1c, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x66, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0xc6, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xcc, 0x76, 0x36, 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, + 0x00, 0xc6, 0xc6, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xcc, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, + 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00, + 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, + 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, + 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0x40, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static Bit8u vgafont16[256*16]= +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, + 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00, + 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, + 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, + 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static Bit8u vgafont14alt[1]={0x00}; +static Bit8u vgafont16alt[1]={0x00}; diff --git a/palacios/src/vmboot/vgabios/vgatables.h b/palacios/src/vmboot/vgabios/vgatables.h new file mode 100644 index 0000000..e5eca1e --- /dev/null +++ b/palacios/src/vmboot/vgabios/vgatables.h @@ -0,0 +1,318 @@ +/* + * + * BIOS Memory + * + */ +#define BIOSMEM_SEG 0x40 + +#define BIOSMEM_INITIAL_MODE 0x10 +#define BIOSMEM_CURRENT_MODE 0x49 +#define BIOSMEM_NB_COLS 0x4A +#define BIOSMEM_PAGE_SIZE 0x4C +#define BIOSMEM_CURRENT_START 0x4E +#define BIOSMEM_CURSOR_POS 0x50 +#define BIOSMEM_CURSOR_TYPE 0x60 +#define BIOSMEM_CURRENT_PAGE 0x62 +#define BIOSMEM_CRTC_ADDRESS 0x63 +#define BIOSMEM_CURRENT_MSR 0x65 +#define BIOSMEM_CURRENT_PAL 0x66 +#define BIOSMEM_NB_ROWS 0x84 +#define BIOSMEM_CHAR_HEIGHT 0x85 +#define BIOSMEM_VIDEO_CTL 0x87 +#define BIOSMEM_SWITCHES 0x88 +#define BIOSMEM_MODESET_CTL 0x89 +#define BIOSMEM_DCC_INDEX 0x8A +#define BIOSMEM_VS_POINTER 0xA8 +#define BIOSMEM_VBE_FLAG 0xB9 +#define BIOSMEM_VBE_MODE 0xBA + + +/* + * + * VGA registers + * + */ +#define VGAREG_ACTL_ADDRESS 0x3c0 +#define VGAREG_ACTL_WRITE_DATA 0x3c0 +#define VGAREG_ACTL_READ_DATA 0x3c1 + +#define VGAREG_INPUT_STATUS 0x3c2 +#define VGAREG_WRITE_MISC_OUTPUT 0x3c2 +#define VGAREG_VIDEO_ENABLE 0x3c3 +#define VGAREG_SEQU_ADDRESS 0x3c4 +#define VGAREG_SEQU_DATA 0x3c5 + +#define VGAREG_PEL_MASK 0x3c6 +#define VGAREG_DAC_STATE 0x3c7 +#define VGAREG_DAC_READ_ADDRESS 0x3c7 +#define VGAREG_DAC_WRITE_ADDRESS 0x3c8 +#define VGAREG_DAC_DATA 0x3c9 + +#define VGAREG_READ_FEATURE_CTL 0x3ca +#define VGAREG_READ_MISC_OUTPUT 0x3cc + +#define VGAREG_GRDC_ADDRESS 0x3ce +#define VGAREG_GRDC_DATA 0x3cf + +#define VGAREG_MDA_CRTC_ADDRESS 0x3b4 +#define VGAREG_MDA_CRTC_DATA 0x3b5 +#define VGAREG_VGA_CRTC_ADDRESS 0x3d4 +#define VGAREG_VGA_CRTC_DATA 0x3d5 + +#define VGAREG_MDA_WRITE_FEATURE_CTL 0x3ba +#define VGAREG_VGA_WRITE_FEATURE_CTL 0x3da +#define VGAREG_ACTL_RESET 0x3da + +#define VGAREG_MDA_MODECTL 0x3b8 +#define VGAREG_CGA_MODECTL 0x3d8 +#define VGAREG_CGA_PALETTE 0x3d9 + +/* Video memory */ +#define VGAMEM_GRAPH 0xA000 +#define VGAMEM_CTEXT 0xB800 +#define VGAMEM_MTEXT 0xB000 + +/* + * + * Tables of default values for each mode + * + */ +#define MODE_MAX 0x14 +#define TEXT 0x00 +#define GRAPH 0x01 + +#define CTEXT 0x00 +#define MTEXT 0x01 +#define CGA 0x02 +#define PLANAR1 0x03 +#define PLANAR4 0x04 +#define LINEAR8 0x05 + +// for SVGA +#define LINEAR15 0x10 +#define LINEAR16 0x11 +#define LINEAR24 0x12 +#define LINEAR32 0x13 + +typedef struct +{Bit8u svgamode; + Bit16u vesamode; + Bit8u class; /* TEXT, GRAPH */ + Bit8u memmodel; /* CTEXT,MTEXT,CGA,PL1,PL2,PL4,P8,P15,P16,P24,P32 */ + Bit8u nbpages; + Bit8u pixbits; + Bit16u swidth, sheight; + Bit16u twidth, theight; + Bit16u cwidth, cheight; + Bit16u sstart; + Bit16u slength; + Bit8u miscreg; + Bit8u pelmask; + Bit8u crtcmodel; + Bit8u actlmodel; + Bit8u grdcmodel; + Bit8u sequmodel; + Bit8u dacmodel; /* 0 1 2 3 */ +} VGAMODES; + +static VGAMODES vga_modes[MODE_MAX+1]= +{//mode vesa class model pg bits sw sh tw th cw ch sstart slength misc pelm crtc actl gdc sequ dac + {0x00, 0xFFFF, TEXT, CTEXT, 8, 4, 360, 400, 40, 25, 9, 16, 0xB800, 0x0800, 0x67, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02}, + {0x01, 0xFFFF, TEXT, CTEXT, 8, 4, 360, 400, 40, 25, 9, 16, 0xB800, 0x0800, 0x67, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02}, + {0x02, 0xFFFF, TEXT, CTEXT, 4, 4, 720, 400, 80, 25, 9, 16, 0xB800, 0x1000, 0x67, 0xFF, 0x01, 0x00, 0x00, 0x01, 0x02}, + {0x03, 0xFFFF, TEXT, CTEXT, 4, 4, 720, 400, 80, 25, 9, 16, 0xB800, 0x1000, 0x67, 0xFF, 0x01, 0x00, 0x00, 0x01, 0x02}, + {0x04, 0xFFFF, GRAPH, CGA, 4, 2, 320, 200, 40, 25, 8, 8, 0xB800, 0x0800, 0x63, 0xFF, 0x02, 0x01, 0x01, 0x02, 0x01}, + {0x05, 0xFFFF, GRAPH, CGA, 1, 2, 320, 200, 40, 25, 8, 8, 0xB800, 0x0800, 0x63, 0xFF, 0x02, 0x01, 0x01, 0x02, 0x01}, + {0x06, 0xFFFF, GRAPH, CGA, 1, 1, 640, 200, 80, 25, 8, 8, 0xB800, 0x1000, 0x63, 0xFF, 0x03, 0x02, 0x02, 0x03, 0x01}, + {0x07, 0xFFFF, TEXT, MTEXT, 4, 4, 720, 400, 80, 25, 9, 16, 0xB000, 0x1000, 0x66, 0xFF, 0x04, 0x03, 0x03, 0x01, 0x00}, + {0x0D, 0xFFFF, GRAPH, PLANAR4, 8, 4, 320, 200, 40, 25, 8, 8, 0xA000, 0x2000, 0x63, 0xFF, 0x05, 0x04, 0x04, 0x04, 0x01}, + {0x0E, 0xFFFF, GRAPH, PLANAR4, 4, 4, 640, 200, 80, 25, 8, 8, 0xA000, 0x4000, 0x63, 0xFF, 0x06, 0x04, 0x04, 0x05, 0x01}, + {0x0F, 0xFFFF, GRAPH, PLANAR1, 2, 1, 640, 350, 80, 25, 8, 14, 0xA000, 0x8000, 0xa3, 0xFF, 0x07, 0x05, 0x04, 0x05, 0x00}, + {0x10, 0xFFFF, GRAPH, PLANAR4, 2, 4, 640, 350, 80, 25, 8, 14, 0xA000, 0x8000, 0xa3, 0xFF, 0x07, 0x06, 0x04, 0x05, 0x02}, + {0x11, 0xFFFF, GRAPH, PLANAR1, 1, 1, 640, 480, 80, 30, 8, 16, 0xA000, 0x0000, 0xe3, 0xFF, 0x08, 0x07, 0x04, 0x05, 0x02}, + {0x12, 0xFFFF, GRAPH, PLANAR4, 1, 4, 640, 480, 80, 30, 8, 16, 0xA000, 0x0000, 0xe3, 0xFF, 0x08, 0x06, 0x04, 0x05, 0x02}, + {0x13, 0xFFFF, GRAPH, LINEAR8, 1, 8, 320, 200, 40, 25, 8, 8, 0xA000, 0x0000, 0x63, 0xFF, 0x09, 0x08, 0x05, 0x06, 0x03}, + {0x6A, 0xFFFF, GRAPH, PLANAR4, 1, 4, 800, 600,100, 37, 8, 16, 0xA000, 0x0000, 0xe3, 0xFF, 0x0A, 0x06, 0x04, 0x05, 0x02} +}; + +/* CRTC */ +#define CRTC_MAX_REG 0x18 +#define CRTC_MAX_MODEL 0x0A +static Bit8u crtc_access[CRTC_MAX_REG+1]= +{ /* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; +static Bit8u crtc_regs[CRTC_MAX_MODEL+1][CRTC_MAX_REG+1]= +{/* Model 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 */ + /* 00 */ 0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,0xff, + /* 01 */ 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,0xff, + /* 02 */ 0x2d,0x27,0x28,0x90,0x2b,0x80,0xbf,0x1f,0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,0xff, + /* 03 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xc2,0xff, + /* 04 */ 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x0f,0x96,0xb9,0xa3,0xff, + /* 05 */ 0x2d,0x27,0x28,0x90,0x2b,0x80,0xbf,0x1f,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xe3,0xff, + /* 06 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xe3,0xff, + /* 07 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x85,0x5d,0x28,0x0f,0x63,0xba,0xe3,0xff, + /* 08 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0xea,0x8c,0xdf,0x28,0x00,0xe7,0x04,0xe3,0xff, + /* 09 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x40,0x96,0xb9,0xa3,0xff, + /* 0A */ 0x7f,0x63,0x63,0x83,0x6b,0x1b,0x72,0xf0,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x8d,0x57,0x32,0x00,0x57,0x73,0xe3,0xff +}; + +/* Attribute Controler 0x3c0 */ +#define ACTL_MAX_REG 0x14 +#define ACTL_MAX_MODEL 0x08 + +static Bit8u actl_access[ACTL_MAX_REG+1]= +{/* 00 01 02 03 04 05 06 07 08 09 0A 0B OC OD OE OF 10 11 12 13 14 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; + +static Bit8u actl_regs[ACTL_MAX_MODEL+1][ACTL_MAX_REG+1]= +{/* Model 00 01 02 03 04 05 06 07 08 09 0A 0B OC OD OE OF 10 11 12 13 14 */ + /* 00 */ 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x0c,0x00,0x0f,0x08,0x00, + /* 01 */ 0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x01,0x00,0x03,0x00,0x00, + /* 02 */ 0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x01,0x00,0x01,0x00,0x00, + /* 03 */ 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0e,0x00,0x0f,0x08,0x00, + /* 04 */ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x01,0x00,0x0f,0x00,0x00, + /* 05 */ 0x00,0x08,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,0x01,0x00,0x01,0x00,0x00, + /* 06 */ 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x01,0x00,0x0f,0x00,0x00, + /* 07 */ 0x00,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x01,0x00,0x01,0x00,0x00, + /* 08 */ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x41,0x00,0x0f,0x00,0x00 +}; + +/* Sequencer 0x3c4 */ +#define SEQU_MAX_REG 0x04 +#define SEQU_MAX_MODEL 0x06 + +static Bit8u sequ_access[SEQU_MAX_REG+1]= +{ /* 00 01 02 03 04 */ + 0x00,0x00,0x00,0x00,0x00 +}; + +static Bit8u sequ_regs[SEQU_MAX_MODEL+1][SEQU_MAX_REG+1]= +{/* Model 00 01 02 03 04 */ + /* 00 */ 0x03,0x08,0x03,0x00,0x02, + /* 01 */ 0x03,0x00,0x03,0x00,0x02, + /* 02 */ 0x03,0x09,0x03,0x00,0x02, + /* 03 */ 0x03,0x01,0x01,0x00,0x06, + /* 04 */ 0x03,0x09,0x0f,0x00,0x06, + /* 05 */ 0x03,0x01,0x0f,0x00,0x06, + /* 06 */ 0x03,0x01,0x0f,0x00,0x0e +}; + +/* Graphic ctl 0x3ce */ +#define GRDC_MAX_REG 0x08 +#define GRDC_MAX_MODEL 0x05 + +static Bit8u grdc_access[GRDC_MAX_REG+1]= +{ /* 00 01 02 03 04 05 06 07 08 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; + +static Bit8u grdc_regs[GRDC_MAX_MODEL+1][GRDC_MAX_REG+1]= +{/* Model 00 01 02 03 04 05 06 07 08 */ + /* 00 */ 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x0f,0xff, + /* 01 */ 0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x0f,0xff, + /* 02 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x0f,0xff, + /* 03 */ 0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x0f,0xff, + /* 04 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,0xff, + /* 05 */ 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,0xff +}; + +/* Default Palette */ +#define DAC_MAX_MODEL 3 + +static Bit8u dac_regs[DAC_MAX_MODEL+1]= +{0x3f,0x3f,0x3f,0xff}; + +/* Mono */ +static Bit8u palette0[63+1][3]= +{ + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, + 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, + 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, + 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, + 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f +}; + +static Bit8u palette1[63+1][3]= +{ + 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a, + 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a, + 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f, + 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f, + 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a, + 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a, + 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f, + 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f +}; + +static Bit8u palette2[63+1][3]= +{ + 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x2a,0x00, 0x2a,0x2a,0x2a, + 0x00,0x00,0x15, 0x00,0x00,0x3f, 0x00,0x2a,0x15, 0x00,0x2a,0x3f, 0x2a,0x00,0x15, 0x2a,0x00,0x3f, 0x2a,0x2a,0x15, 0x2a,0x2a,0x3f, + 0x00,0x15,0x00, 0x00,0x15,0x2a, 0x00,0x3f,0x00, 0x00,0x3f,0x2a, 0x2a,0x15,0x00, 0x2a,0x15,0x2a, 0x2a,0x3f,0x00, 0x2a,0x3f,0x2a, + 0x00,0x15,0x15, 0x00,0x15,0x3f, 0x00,0x3f,0x15, 0x00,0x3f,0x3f, 0x2a,0x15,0x15, 0x2a,0x15,0x3f, 0x2a,0x3f,0x15, 0x2a,0x3f,0x3f, + 0x15,0x00,0x00, 0x15,0x00,0x2a, 0x15,0x2a,0x00, 0x15,0x2a,0x2a, 0x3f,0x00,0x00, 0x3f,0x00,0x2a, 0x3f,0x2a,0x00, 0x3f,0x2a,0x2a, + 0x15,0x00,0x15, 0x15,0x00,0x3f, 0x15,0x2a,0x15, 0x15,0x2a,0x3f, 0x3f,0x00,0x15, 0x3f,0x00,0x3f, 0x3f,0x2a,0x15, 0x3f,0x2a,0x3f, + 0x15,0x15,0x00, 0x15,0x15,0x2a, 0x15,0x3f,0x00, 0x15,0x3f,0x2a, 0x3f,0x15,0x00, 0x3f,0x15,0x2a, 0x3f,0x3f,0x00, 0x3f,0x3f,0x2a, + 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f +}; + +static Bit8u palette3[256][3]= +{ + 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a, + 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f, + 0x00,0x00,0x00, 0x05,0x05,0x05, 0x08,0x08,0x08, 0x0b,0x0b,0x0b, 0x0e,0x0e,0x0e, 0x11,0x11,0x11, 0x14,0x14,0x14, 0x18,0x18,0x18, + 0x1c,0x1c,0x1c, 0x20,0x20,0x20, 0x24,0x24,0x24, 0x28,0x28,0x28, 0x2d,0x2d,0x2d, 0x32,0x32,0x32, 0x38,0x38,0x38, 0x3f,0x3f,0x3f, + 0x00,0x00,0x3f, 0x10,0x00,0x3f, 0x1f,0x00,0x3f, 0x2f,0x00,0x3f, 0x3f,0x00,0x3f, 0x3f,0x00,0x2f, 0x3f,0x00,0x1f, 0x3f,0x00,0x10, + 0x3f,0x00,0x00, 0x3f,0x10,0x00, 0x3f,0x1f,0x00, 0x3f,0x2f,0x00, 0x3f,0x3f,0x00, 0x2f,0x3f,0x00, 0x1f,0x3f,0x00, 0x10,0x3f,0x00, + 0x00,0x3f,0x00, 0x00,0x3f,0x10, 0x00,0x3f,0x1f, 0x00,0x3f,0x2f, 0x00,0x3f,0x3f, 0x00,0x2f,0x3f, 0x00,0x1f,0x3f, 0x00,0x10,0x3f, + 0x1f,0x1f,0x3f, 0x27,0x1f,0x3f, 0x2f,0x1f,0x3f, 0x37,0x1f,0x3f, 0x3f,0x1f,0x3f, 0x3f,0x1f,0x37, 0x3f,0x1f,0x2f, 0x3f,0x1f,0x27, + + 0x3f,0x1f,0x1f, 0x3f,0x27,0x1f, 0x3f,0x2f,0x1f, 0x3f,0x37,0x1f, 0x3f,0x3f,0x1f, 0x37,0x3f,0x1f, 0x2f,0x3f,0x1f, 0x27,0x3f,0x1f, + 0x1f,0x3f,0x1f, 0x1f,0x3f,0x27, 0x1f,0x3f,0x2f, 0x1f,0x3f,0x37, 0x1f,0x3f,0x3f, 0x1f,0x37,0x3f, 0x1f,0x2f,0x3f, 0x1f,0x27,0x3f, + 0x2d,0x2d,0x3f, 0x31,0x2d,0x3f, 0x36,0x2d,0x3f, 0x3a,0x2d,0x3f, 0x3f,0x2d,0x3f, 0x3f,0x2d,0x3a, 0x3f,0x2d,0x36, 0x3f,0x2d,0x31, + 0x3f,0x2d,0x2d, 0x3f,0x31,0x2d, 0x3f,0x36,0x2d, 0x3f,0x3a,0x2d, 0x3f,0x3f,0x2d, 0x3a,0x3f,0x2d, 0x36,0x3f,0x2d, 0x31,0x3f,0x2d, + 0x2d,0x3f,0x2d, 0x2d,0x3f,0x31, 0x2d,0x3f,0x36, 0x2d,0x3f,0x3a, 0x2d,0x3f,0x3f, 0x2d,0x3a,0x3f, 0x2d,0x36,0x3f, 0x2d,0x31,0x3f, + 0x00,0x00,0x1c, 0x07,0x00,0x1c, 0x0e,0x00,0x1c, 0x15,0x00,0x1c, 0x1c,0x00,0x1c, 0x1c,0x00,0x15, 0x1c,0x00,0x0e, 0x1c,0x00,0x07, + 0x1c,0x00,0x00, 0x1c,0x07,0x00, 0x1c,0x0e,0x00, 0x1c,0x15,0x00, 0x1c,0x1c,0x00, 0x15,0x1c,0x00, 0x0e,0x1c,0x00, 0x07,0x1c,0x00, + 0x00,0x1c,0x00, 0x00,0x1c,0x07, 0x00,0x1c,0x0e, 0x00,0x1c,0x15, 0x00,0x1c,0x1c, 0x00,0x15,0x1c, 0x00,0x0e,0x1c, 0x00,0x07,0x1c, + + 0x0e,0x0e,0x1c, 0x11,0x0e,0x1c, 0x15,0x0e,0x1c, 0x18,0x0e,0x1c, 0x1c,0x0e,0x1c, 0x1c,0x0e,0x18, 0x1c,0x0e,0x15, 0x1c,0x0e,0x11, + 0x1c,0x0e,0x0e, 0x1c,0x11,0x0e, 0x1c,0x15,0x0e, 0x1c,0x18,0x0e, 0x1c,0x1c,0x0e, 0x18,0x1c,0x0e, 0x15,0x1c,0x0e, 0x11,0x1c,0x0e, + 0x0e,0x1c,0x0e, 0x0e,0x1c,0x11, 0x0e,0x1c,0x15, 0x0e,0x1c,0x18, 0x0e,0x1c,0x1c, 0x0e,0x18,0x1c, 0x0e,0x15,0x1c, 0x0e,0x11,0x1c, + 0x14,0x14,0x1c, 0x16,0x14,0x1c, 0x18,0x14,0x1c, 0x1a,0x14,0x1c, 0x1c,0x14,0x1c, 0x1c,0x14,0x1a, 0x1c,0x14,0x18, 0x1c,0x14,0x16, + 0x1c,0x14,0x14, 0x1c,0x16,0x14, 0x1c,0x18,0x14, 0x1c,0x1a,0x14, 0x1c,0x1c,0x14, 0x1a,0x1c,0x14, 0x18,0x1c,0x14, 0x16,0x1c,0x14, + 0x14,0x1c,0x14, 0x14,0x1c,0x16, 0x14,0x1c,0x18, 0x14,0x1c,0x1a, 0x14,0x1c,0x1c, 0x14,0x1a,0x1c, 0x14,0x18,0x1c, 0x14,0x16,0x1c, + 0x00,0x00,0x10, 0x04,0x00,0x10, 0x08,0x00,0x10, 0x0c,0x00,0x10, 0x10,0x00,0x10, 0x10,0x00,0x0c, 0x10,0x00,0x08, 0x10,0x00,0x04, + 0x10,0x00,0x00, 0x10,0x04,0x00, 0x10,0x08,0x00, 0x10,0x0c,0x00, 0x10,0x10,0x00, 0x0c,0x10,0x00, 0x08,0x10,0x00, 0x04,0x10,0x00, + + 0x00,0x10,0x00, 0x00,0x10,0x04, 0x00,0x10,0x08, 0x00,0x10,0x0c, 0x00,0x10,0x10, 0x00,0x0c,0x10, 0x00,0x08,0x10, 0x00,0x04,0x10, + 0x08,0x08,0x10, 0x0a,0x08,0x10, 0x0c,0x08,0x10, 0x0e,0x08,0x10, 0x10,0x08,0x10, 0x10,0x08,0x0e, 0x10,0x08,0x0c, 0x10,0x08,0x0a, + 0x10,0x08,0x08, 0x10,0x0a,0x08, 0x10,0x0c,0x08, 0x10,0x0e,0x08, 0x10,0x10,0x08, 0x0e,0x10,0x08, 0x0c,0x10,0x08, 0x0a,0x10,0x08, + 0x08,0x10,0x08, 0x08,0x10,0x0a, 0x08,0x10,0x0c, 0x08,0x10,0x0e, 0x08,0x10,0x10, 0x08,0x0e,0x10, 0x08,0x0c,0x10, 0x08,0x0a,0x10, + 0x0b,0x0b,0x10, 0x0c,0x0b,0x10, 0x0d,0x0b,0x10, 0x0f,0x0b,0x10, 0x10,0x0b,0x10, 0x10,0x0b,0x0f, 0x10,0x0b,0x0d, 0x10,0x0b,0x0c, + 0x10,0x0b,0x0b, 0x10,0x0c,0x0b, 0x10,0x0d,0x0b, 0x10,0x0f,0x0b, 0x10,0x10,0x0b, 0x0f,0x10,0x0b, 0x0d,0x10,0x0b, 0x0c,0x10,0x0b, + 0x0b,0x10,0x0b, 0x0b,0x10,0x0c, 0x0b,0x10,0x0d, 0x0b,0x10,0x0f, 0x0b,0x10,0x10, 0x0b,0x0f,0x10, 0x0b,0x0d,0x10, 0x0b,0x0c,0x10, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00 +}; + +static Bit8u static_functionality[0x10]= +{ + /* 0 */ 0xff, // All modes supported #1 + /* 1 */ 0xe0, // All modes supported #2 + /* 2 */ 0x0f, // All modes supported #3 + /* 3 */ 0x00, 0x00, 0x00, 0x00, // reserved + /* 7 */ 0x07, // 200, 350, 400 scan lines + /* 8 */ 0x02, // mamimum number of visible charsets in text mode + /* 9 */ 0x08, // total number of charset blocks in text mode + /* a */ 0xe7, // Change to add new functions + /* b */ 0x0c, // Change to add new functions + /* c */ 0x00, // reserved + /* d */ 0x00, // reserved + /* e */ 0x00, // Change to add new functions + /* f */ 0x00 // reserved +}; diff --git a/palacios/src/vmboot/vmxassist/Makefile b/palacios/src/vmboot/vmxassist/Makefile new file mode 100644 index 0000000..116692d --- /dev/null +++ b/palacios/src/vmboot/vmxassist/Makefile @@ -0,0 +1,79 @@ +# +# Makefile +# +# Leendert van Doorn, leendert@watson.ibm.com +# Copyright (c) 2005, International Business Machines Corporation. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., 59 Temple +# Place - Suite 330, Boston, MA 02111-1307 USA. +# + +# External CFLAGS can do more harm than good. +CFLAGS := + + +# The emulator code lives in ROM space +TEXTADDR=0x000D0000 + +DEFINES=-DDEBUG -DTEXTADDR=$(TEXTADDR) + +# Disable PIE/SSP if GCC supports them. They can break us. +CFLAGS += $(call test-gcc-flag,$(CC),-nopie) +CFLAGS += $(call test-gcc-flag,$(CC),-fno-stack-protector) +CFLAGS += $(call test-gcc-flag,$(CC),-fno-stack-protector-all) + +CPP = cpp -P +OBJCOPY = objcopy -p -O binary -R .note -R .comment -R .bss -S --gap-fill=0 +CFLAGS += $(DEFINES) -I. -fno-builtin -O2 -msoft-float +LDFLAGS = -m elf_i386 + +OBJECTS = head.o trap.o vm86.o setup.o util.o + +.PHONY: all +all: vmxassist.bin + +vmxassist.bin: vmxassist.ld $(OBJECTS) + $(CPP) $(DEFINES) vmxassist.ld > vmxassist.tmp + $(LD) -o vmxassist $(LDFLAGS) -nostdlib --fatal-warnings -N -T vmxassist.tmp $(OBJECTS) + nm -n vmxassist > vmxassist.sym + $(OBJCOPY) vmxassist vmxassist.tmp + dd if=vmxassist.tmp of=vmxassist.bin ibs=512 conv=sync + rm -f vmxassist.tmp + +head.o: machine.h vm86.h head.S + $(CC) $(CFLAGS) -D__ASSEMBLY__ $(DEFINES) -c head.S + +trap.o: machine.h vm86.h offsets.h trap.S + $(CC) $(CFLAGS) -D__ASSEMBLY__ $(DEFINES) -c trap.S + +vm86.o: machine.h vm86.h vm86.c + $(CC) $(CFLAGS) -c vm86.c + +setup.o: machine.h vm86.h setup.c + $(CC) $(CFLAGS) -c setup.c + +util.o: machine.h vm86.h util.c + $(CC) $(CFLAGS) -c util.c + +offsets.h: gen + ./gen > offsets.h + +gen: vm86.h gen.c + $(CC) $(CFLAGS) -I. -o gen gen.c + +.PHONY: clean +clean: + rm -f vmxassist vmxassist.tmp vmxassist.bin vmxassist.run vmxassist.sym head.s + rm -f $(OBJECTS) + rm -f gen gen.o offsets.h + diff --git a/palacios/src/vmboot/vmxassist/e820.h b/palacios/src/vmboot/vmxassist/e820.h new file mode 100644 index 0000000..8190c76 --- /dev/null +++ b/palacios/src/vmboot/vmxassist/e820.h @@ -0,0 +1,32 @@ +#ifndef __XEN_PUBLIC_HVM_E820_H__ +#define __XEN_PUBLIC_HVM_E820_H__ + +/* PC BIOS standard E820 types. */ +#define E820_RAM 1 +#define E820_RESERVED 2 +#define E820_ACPI 3 +#define E820_NVS 4 + +/* Xen HVM extended E820 types. */ +#define E820_IO 16 +#define E820_SHARED_PAGE 17 +#define E820_XENSTORE 18 +#define E820_BUFFERED_IO 19 + +/* E820 location in HVM virtual address space. */ +#define E820_MAP_PAGE 0x00090000 +#define E820_MAP_NR_OFFSET 0x000001E8 +#define E820_MAP_OFFSET 0x000002D0 + +struct e820entry { + uint64_t addr; + uint64_t size; + uint32_t type; +} __attribute__((packed)); + +#define HVM_BELOW_4G_RAM_END 0xF0000000 + +#define HVM_BELOW_4G_MMIO_START HVM_BELOW_4G_RAM_END +#define HVM_BELOW_4G_MMIO_LENGTH ((1ULL << 32) - HVM_BELOW_4G_MMIO_START) + +#endif /* __XEN_PUBLIC_HVM_E820_H__ */ diff --git a/palacios/src/vmboot/vmxassist/gen.c b/palacios/src/vmboot/vmxassist/gen.c new file mode 100644 index 0000000..2dcb229 --- /dev/null +++ b/palacios/src/vmboot/vmxassist/gen.c @@ -0,0 +1,52 @@ +/* + * gen.c: Generate assembler symbols. + * + * Leendert van Doorn, leendert@watson.ibm.com + * Copyright (c) 2005, International Business Machines Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ +#include +#include +#include +#include + +int +main(void) +{ + printf("/* MACHINE GENERATED; DO NOT EDIT */\n"); + printf("#define VMX_ASSIST_CTX_GS_SEL 0x%x\n", + (unsigned int)offsetof(struct vmx_assist_context, gs_sel)); + printf("#define VMX_ASSIST_CTX_FS_SEL 0x%x\n", + (unsigned int)offsetof(struct vmx_assist_context, fs_sel)); + printf("#define VMX_ASSIST_CTX_DS_SEL 0x%x\n", + (unsigned int)offsetof(struct vmx_assist_context, ds_sel)); + printf("#define VMX_ASSIST_CTX_ES_SEL 0x%x\n", + (unsigned int)offsetof(struct vmx_assist_context, es_sel)); + printf("#define VMX_ASSIST_CTX_SS_SEL 0x%x\n", + (unsigned int)offsetof(struct vmx_assist_context, ss_sel)); + printf("#define VMX_ASSIST_CTX_ESP 0x%x\n", + (unsigned int)offsetof(struct vmx_assist_context, esp)); + printf("#define VMX_ASSIST_CTX_EFLAGS 0x%x\n", + (unsigned int)offsetof(struct vmx_assist_context, eflags)); + printf("#define VMX_ASSIST_CTX_CS_SEL 0x%x\n", + (unsigned int)offsetof(struct vmx_assist_context, cs_sel)); + printf("#define VMX_ASSIST_CTX_EIP 0x%x\n", + (unsigned int)offsetof(struct vmx_assist_context, eip)); + + printf("#define VMX_ASSIST_CTX_CR0 0x%x\n", + (unsigned int)offsetof(struct vmx_assist_context, cr0)); + + return 0; +} diff --git a/palacios/src/vmboot/vmxassist/head.S b/palacios/src/vmboot/vmxassist/head.S new file mode 100644 index 0000000..b183fac --- /dev/null +++ b/palacios/src/vmboot/vmxassist/head.S @@ -0,0 +1,170 @@ +/* + * head.S: VMXAssist runtime start off. + * + * Leendert van Doorn, leendert@watson.ibm.com + * Copyright (c) 2005, International Business Machines Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ +#include "vm86.h" +#include "machine.h" + +/* + * When a partition tries to mask off the CR0_PE bit a world + * switch happens to the environment below. The magic indicates + * that this is a valid context. + */ +#ifdef TEST + .byte 0x55, 0xaa + .byte 0x80 + .code16 + jmp _start16 +#else + jmp _start +#endif + + .align 8 + .long VMXASSIST_MAGIC + .long newctx /* new context */ + .long oldctx /* old context */ + +#ifdef TEST +/* + * We are running in 16-bit. Get into the protected mode as soon as + * possible. We use our own (minimal) GDT to get started. + * + * ROM is a misnomer as this code isn't really rommable (although it + * only requires a few changes) but it does live in a BIOS ROM segment. + * This code allows me to debug vmxassists under (a modified version of) + * Bochs and load it as a "optromimage1". + */ + .code16 + .globl _start16 +_start16: + cli + + /* load our own global descriptor table */ + data32 addr32 lgdt %cs:(rom_gdtr - TEXTADDR) + + /* go to protected mode */ + movl %cr0, %eax + orl $CR0_PE, %eax + movl %eax, %cr0 + data32 ljmp $0x08, $1f + + .align 32 + .globl rom_gdt +rom_gdt: + .word 0, 0 /* 0x00: reserved */ + .byte 0, 0, 0, 0 + + .word 0xFFFF, 0 /* 0x08: CS 32-bit */ + .byte 0, 0x9A, 0xCF, 0 + + .word 0xFFFF, 0 /* 0x10: CS 32-bit */ + .byte 0, 0x92, 0xCF, 0 +rom_gdt_end: + + .align 4 + .globl rom_gdtr +rom_gdtr: + .word rom_gdt_end - rom_gdt - 1 + .long rom_gdt + + .code32 +1: + /* welcome to the 32-bit world */ + movw $0x10, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw %ax, %fs + movw %ax, %gs + + /* enable Bochs debug facilities */ + movw $0x8A00, %dx + movw $0x8A00, %ax + outw %ax, (%dx) + + jmp _start +#endif /* TEST */ + +/* + * This is the real start. Control was transfered to this point + * with CR0_PE set and executing in some 32-bit segment. We call + * main and setup our own environment. + */ + .globl _start + .code32 +_start: + cli + + /* save register parameters to C land */ +#ifdef TEST + xorl %edx, %edx +#endif + + /* clear bss */ + cld + xorb %al, %al + movl $_bbss, %edi + movl $_ebss, %ecx + subl %edi, %ecx + rep stosb + + movl %edx, booting_cpu + movl %ebx, booting_vector + + /* make sure we are in a sane world */ + clts + + /* setup my own stack */ + movl $stack_top - 4*4, %esp + movl %esp, %ebp + + /* go ... */ + call main + jmp halt + +/* + * Something bad happened, print invoking %eip and loop forever + */ + .align 4 + .globl halt +halt: + push $halt_msg + call printf +#ifdef TEST + movw $0x8A00, %dx + movw $0x8AE0, %ax + outw %ax, (%dx) +#endif + cli + jmp . + + .data +halt_msg: + .asciz "Halt called from %%eip 0x%x\n" + + +/* + * Our stack + */ + .bss + .align 8 + .globl stack, stack_top +stack: + .skip STACK_SIZE +stack_top: + diff --git a/palacios/src/vmboot/vmxassist/machine.h b/palacios/src/vmboot/vmxassist/machine.h new file mode 100644 index 0000000..0ea2adf --- /dev/null +++ b/palacios/src/vmboot/vmxassist/machine.h @@ -0,0 +1,209 @@ +/* + * machine.h: Intel CPU specific definitions + * + * Leendert van Doorn, leendert@watson.ibm.com + * Copyright (c) 2005, International Business Machines Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __MACHINE_H__ +#define __MACHINE_H__ + +/* the size of our stack (4KB) */ +#define STACK_SIZE 8192 + +#define TSS_SELECTOR 0x08 +#define CODE_SELECTOR 0x10 +#define DATA_SELECTOR 0x18 + +#define CR0_PE (1 << 0) +#define CR0_EM (1 << 2) +#define CR0_TS (1 << 3) +#define CR0_NE (1 << 5) +#define CR0_PG (1 << 31) + +#define CR4_VME (1 << 0) +#define CR4_PVI (1 << 1) +#define CR4_PSE (1 << 4) +#define CR4_PAE (1 << 5) + +#define EFLAGS_ZF (1 << 6) +#define EFLAGS_TF (1 << 8) +#define EFLAGS_IF (1 << 9) +#define EFLAGS_DF (1 << 10) +#define EFLAGS_IOPL (3 << 12) +#define EFLAGS_VM ((1 << 17) | EFLAGS_IOPL) +#define EFLAGS_VIF (1 << 19) +#define EFLAGS_VIP (1 << 20) + +#define LOG_PGSIZE 12 /* log2(page size) */ +#define LOG_PDSIZE 22 /* log2(page directory size) */ + +/* Derived constants */ +#define PGSIZE (1 << LOG_PGSIZE) /* page size */ +#define PGMASK (~(PGSIZE - 1)) /* page mask */ +#define LPGSIZE (1 << LOG_PDSIZE) /* large page size */ +#define LPGMASK (~(LPGSIZE - 1)) /* large page mask */ + +#ifdef TEST +#define PTE_P (1 << 0) /* Present */ +#define PTE_RW (1 << 1) /* Read/Write */ +#define PTE_US (1 << 2) /* User/Supervisor */ +#define PTE_PS (1 << 7) /* Page Size */ +#endif + +/* Programmable Interrupt Contoller (PIC) defines */ +#define PIC_MASTER 0x20 +#define PIC_SLAVE 0xA0 + +#define PIC_CMD 0 /* command */ +#define PIC_ISR 0 /* interrupt status */ +#define PIC_IMR 1 /* interrupt mask */ + + +#ifndef __ASSEMBLY__ + +struct dtr { + unsigned short size; + unsigned long base __attribute__ ((packed)); +}; + +struct tss { + unsigned short prev_link; + unsigned short _1; + unsigned long esp0; + unsigned short ss0; + unsigned short _2; + unsigned long esp1; + unsigned short ss1; + unsigned short _3; + unsigned long esp2; + unsigned short ss2; + unsigned short _4; + unsigned long cr3; + unsigned long eip; + unsigned long eflags; + unsigned long eax; + unsigned long ecx; + unsigned long edx; + unsigned long ebx; + unsigned long esi; + unsigned long edi; + unsigned long esp; + unsigned long ebp; + unsigned long es; + unsigned long cs; + unsigned long ss; + unsigned long ds; + unsigned long fs; + unsigned long gs; + unsigned short ldt_segment; + unsigned short _5; + unsigned short _6; + unsigned short iomap_base; +#ifdef ENABLE_VME + unsigned long int_redir[8]; +#endif + unsigned char iomap[8192]; +}; + +static inline void +outw(unsigned short addr, unsigned short val) +{ + __asm__ __volatile__ ("outw %%ax, %%dx" :: "d"(addr), "a"(val)); +} + +static inline void +outb(unsigned short addr, unsigned char val) +{ + __asm__ __volatile__ ("outb %%al, %%dx" :: "d"(addr), "a"(val)); +} + +static inline unsigned char +inb(unsigned short addr) +{ + unsigned char val; + + __asm__ __volatile__ ("inb %w1,%0" : "=a" (val) : "Nd" (addr)); + return val; +} + +static inline unsigned +get_cmos(int reg) +{ + outb(0x70, reg); + return inb(0x71); +} + +static inline unsigned +get_cr0(void) +{ + unsigned rv; + __asm__ __volatile__("movl %%cr0, %0" : "=r"(rv)); + return rv; +} + +static inline void +set_cr0(unsigned value) +{ + __asm__ __volatile__( + "movl %0, %%cr0\n" + "jmp 1f\n" + "1: nop\n" + : /* no outputs */ + : "r"(value) + ); +} + +static inline unsigned +get_cr2(void) +{ + unsigned rv; + + __asm__ __volatile__("movl %%cr2, %0" : "=r"(rv)); + return rv; +} + +static inline unsigned +get_cr4(void) +{ + unsigned rv; + __asm__ __volatile__("movl %%cr4, %0" : "=r"(rv)); + return rv; +} + +static inline void +set_cr3(unsigned addr) +{ + __asm__ __volatile__("movl %0, %%cr3" : /* no outputs */ : "r"(addr)); +} + +static inline void +set_cr4(unsigned value) +{ + __asm__ __volatile__("movl %0, %%cr4" : /* no outputs */ : "r"(value)); +} + +#ifdef TEST +static inline void +breakpoint(void) +{ + outw(0x8A00, 0x8AE0); +} +#endif /* TEST */ + +#endif /* __ASSEMBLY__ */ + +#endif /* __MACHINE_H__ */ + diff --git a/palacios/src/vmboot/vmxassist/offsets.h b/palacios/src/vmboot/vmxassist/offsets.h new file mode 100644 index 0000000..8049f8c --- /dev/null +++ b/palacios/src/vmboot/vmxassist/offsets.h @@ -0,0 +1,11 @@ +/* MACHINE GENERATED; DO NOT EDIT */ +#define VMX_ASSIST_CTX_GS_SEL 0x78 +#define VMX_ASSIST_CTX_FS_SEL 0x68 +#define VMX_ASSIST_CTX_DS_SEL 0x38 +#define VMX_ASSIST_CTX_ES_SEL 0x48 +#define VMX_ASSIST_CTX_SS_SEL 0x58 +#define VMX_ASSIST_CTX_ESP 0x4 +#define VMX_ASSIST_CTX_EFLAGS 0x8 +#define VMX_ASSIST_CTX_CS_SEL 0x28 +#define VMX_ASSIST_CTX_EIP 0x0 +#define VMX_ASSIST_CTX_CR0 0xc diff --git a/palacios/src/vmboot/vmxassist/setup.c b/palacios/src/vmboot/vmxassist/setup.c new file mode 100644 index 0000000..0576900 --- /dev/null +++ b/palacios/src/vmboot/vmxassist/setup.c @@ -0,0 +1,396 @@ +/* + * setup.c: Setup the world for vmxassist. + * + * Leendert van Doorn, leendert@watson.ibm.com + * Copyright (c) 2005, International Business Machines Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ +#include "vm86.h" +#include "util.h" +#include "machine.h" + +#if (VMXASSIST_BASE != TEXTADDR) +#error VMXAssist base mismatch +#endif + +#define NR_PGD (PGSIZE / sizeof(unsigned)) + +#define min(a, b) ((a) > (b) ? (b) : (a)) + +/* Which CPU are we booting, and what is the initial CS segment? */ +int booting_cpu, booting_vector; + +unsigned long long gdt[] __attribute__ ((aligned(32))) = { + 0x0000000000000000ULL, /* 0x00: reserved */ + 0x0000890000000000ULL, /* 0x08: 32-bit TSS */ + 0x00CF9A000000FFFFULL, /* 0x10: CS 32-bit */ + 0x00CF92000000FFFFULL, /* 0x18: DS 32-bit */ +}; + +struct dtr gdtr = { sizeof(gdt)-1, (unsigned long) &gdt }; + +struct tss tss __attribute__ ((aligned(4))); + +unsigned long long idt[NR_TRAPS] __attribute__ ((aligned(32))); + +struct dtr idtr = { sizeof(idt)-1, (unsigned long) &idt }; + +#ifdef TEST +unsigned pgd[NR_PGD] __attribute__ ((aligned(PGSIZE))) = { 0 }; + +struct e820entry e820map[] = { + { 0x0000000000000000ULL, 0x000000000009F800ULL, E820_RAM }, + { 0x000000000009F800ULL, 0x0000000000000800ULL, E820_RESERVED }, + { 0x00000000000A0000ULL, 0x0000000000020000ULL, E820_IO }, + { 0x00000000000C0000ULL, 0x0000000000040000ULL, E820_RESERVED }, + { 0x0000000000100000ULL, 0x0000000000000000ULL, E820_RAM }, + { 0x0000000000000000ULL, 0x0000000000001000ULL, E820_SHARED_PAGE }, + { 0x0000000000000000ULL, 0x0000000000003000ULL, E820_NVS }, + { 0x0000000000003000ULL, 0x000000000000A000ULL, E820_ACPI }, + { 0x00000000FEC00000ULL, 0x0000000001400000ULL, E820_IO }, +}; +#endif /* TEST */ + +struct vmx_assist_context oldctx; +struct vmx_assist_context newctx; + +unsigned long memory_size; +int initialize_real_mode; + +extern char stack[], stack_top[]; +extern unsigned trap_handlers[]; + +void +banner(void) +{ + printf("VMXAssist (%s)\n", __DATE__); + + /* Bochs its way to convey memory size */ + memory_size = ((get_cmos(0x35) << 8) | get_cmos(0x34)) << 6; + if (memory_size > 0x3bc000) + memory_size = 0x3bc000; + memory_size = (memory_size << 10) + 0xF00000; + if (memory_size <= 0xF00000) + memory_size = + (((get_cmos(0x31) << 8) | get_cmos(0x30)) + 0x400) << 10; + memory_size += 0x400 << 10; /* + 1MB */ + +#ifdef TEST + /* Create an SMAP for our debug environment */ + e820map[4].size = memory_size - e820map[4].addr - PGSIZE; + e820map[5].addr = memory_size - PGSIZE; + e820map[6].addr = memory_size; + e820map[7].addr += memory_size; + + *E820_MAP_NR = sizeof(e820map)/sizeof(e820map[0]); + memcpy(E820_MAP, e820map, sizeof(e820map)); +#endif + + printf("Memory size %ld MB\n", memory_size >> 20); + printf("E820 map:\n"); + print_e820_map(E820_MAP, *E820_MAP_NR); + printf("\n"); +} + +#ifdef TEST +void +setup_paging(void) +{ + unsigned long i; + + if (((unsigned)pgd & ~PGMASK) != 0) + panic("PGD not page aligned"); + set_cr4(get_cr4() | CR4_PSE); + for (i = 0; i < NR_PGD; i++) + pgd[i] = (i * LPGSIZE)| PTE_PS | PTE_US | PTE_RW | PTE_P; + set_cr3((unsigned) pgd); + set_cr0(get_cr0() | (CR0_PE|CR0_PG)); +} +#endif /* TEST */ + +void +setup_gdt(void) +{ + unsigned long long addr = (unsigned long long) &tss; + + /* setup task state segment */ + memset(&tss, 0, sizeof(tss)); + tss.ss0 = DATA_SELECTOR; + tss.esp0 = (unsigned) stack_top - 4*4; + tss.iomap_base = offsetof(struct tss, iomap); + + /* initialize gdt's tss selector */ + gdt[TSS_SELECTOR / sizeof(gdt[0])] |= + ((addr & 0xFF000000) << (56-24)) | + ((addr & 0x00FF0000) << (32-16)) | + ((addr & 0x0000FFFF) << (16)) | + (sizeof(tss) - 1); + + /* switch to our own gdt and set current tss */ + __asm__ __volatile__ ("lgdt %0" : : "m" (gdtr)); + __asm__ __volatile__ ("movl %%eax,%%ds;" + "movl %%eax,%%es;" + "movl %%eax,%%fs;" + "movl %%eax,%%gs;" + "movl %%eax,%%ss" : : "a" (DATA_SELECTOR)); + + __asm__ __volatile__ ("ljmp %0,$1f; 1:" : : "i" (CODE_SELECTOR)); + + __asm__ __volatile__ ("ltr %%ax" : : "a" (TSS_SELECTOR)); +} + +void +set_intr_gate(int i, unsigned handler) +{ + unsigned long long addr = handler; + + idt[i] = ((addr & 0xFFFF0000ULL) << 32) | (0x8E00ULL << 32) | + (addr & 0xFFFFULL) | (CODE_SELECTOR << 16); +} + +void +setup_idt(void) +{ + int i; + + for (i = 0; i < NR_TRAPS; i++) + set_intr_gate(i, trap_handlers[i]); + __asm__ __volatile__ ("lidt %0" : : "m" (idtr)); +} + +void +setup_pic(void) +{ + /* mask all interrupts */ + outb(PIC_MASTER + PIC_IMR, 0xFF); + outb(PIC_SLAVE + PIC_IMR, 0xFF); + + /* setup master PIC */ + outb(PIC_MASTER + PIC_CMD, 0x11); /* edge triggered, cascade, ICW4 */ + outb(PIC_MASTER + PIC_IMR, NR_EXCEPTION_HANDLER); + outb(PIC_MASTER + PIC_IMR, 1 << 2); /* slave on channel 2 */ + outb(PIC_MASTER + PIC_IMR, 0x01); + + /* setup slave PIC */ + outb(PIC_SLAVE + PIC_CMD, 0x11); /* edge triggered, cascade, ICW4 */ + outb(PIC_SLAVE + PIC_IMR, NR_EXCEPTION_HANDLER + 8); + outb(PIC_SLAVE + PIC_IMR, 0x02); /* slave identity is 2 */ + outb(PIC_SLAVE + PIC_IMR, 0x01); + + /* enable all interrupts */ + outb(PIC_MASTER + PIC_IMR, 0); + outb(PIC_SLAVE + PIC_IMR, 0); +} + +void +setiomap(int port) +{ + tss.iomap[port >> 3] |= 1 << (port & 7); +} + +void +enter_real_mode(struct regs *regs) +{ + /* mask off TSS busy bit */ + gdt[TSS_SELECTOR / sizeof(gdt[0])] &= ~0x0000020000000000ULL; + + /* start 8086 emulation of BIOS */ + if (initialize_real_mode) { + initialize_real_mode = 0; + regs->eflags |= EFLAGS_VM | 0x02; + regs->ves = regs->vds = regs->vfs = regs->vgs = 0xF000; + if (booting_cpu == 0) { + regs->cs = 0xF000; /* ROM BIOS POST entry point */ +#ifdef TEST + regs->eip = 0xFFE0; +#else + regs->eip = 0xFFF0; +#endif + } else { + regs->cs = booting_vector << 8; /* AP entry point */ + regs->eip = 0; + } + regs->uesp = 0; + regs->uss = 0; + + /* intercept accesses to the PIC */ + setiomap(PIC_MASTER+PIC_CMD); + setiomap(PIC_MASTER+PIC_IMR); + setiomap(PIC_SLAVE+PIC_CMD); + setiomap(PIC_SLAVE+PIC_IMR); + + printf("Starting emulated 16-bit real-mode: ip=%04x:%04x\n", + regs->cs, regs->eip); + + mode = VM86_REAL; /* becomes previous mode */ + set_mode(regs, VM86_REAL); + + /* this should get us into 16-bit mode */ + return; + } else { + /* go from protected to real mode */ + regs->eflags |= EFLAGS_VM; + + set_mode(regs, VM86_PROTECTED_TO_REAL); + + emulate(regs); + } +} + +/* + * Setup the environment for VMX assist. + * This environment consists of flat segments (code and data), + * its own gdt, idt, and tr. + */ +void +setup_ctx(void) +{ + struct vmx_assist_context *c = &newctx; + + memset(c, 0, sizeof(*c)); + c->eip = (unsigned long) switch_to_real_mode; + c->esp = (unsigned) stack_top - 4*4; + c->eflags = 0x2; /* no interrupts, please */ + + /* + * Obviously, vmx assist is not running with CR0_PE disabled. + * The reason why the vmx assist cr0 has CR0.PE disabled is + * that a transtion to CR0.PE causes a world switch. It seems + * more natural to enable CR0.PE to cause a world switch to + * protected mode rather than disabling it. + */ +#ifdef TEST + c->cr0 = (get_cr0() | CR0_NE | CR0_PG) & ~CR0_PE; + c->cr3 = (unsigned long) pgd; +#else + c->cr0 = (get_cr0() | CR0_NE) & ~CR0_PE; + c->cr3 = 0; +#endif + c->cr4 = get_cr4(); + + c->idtr_limit = sizeof(idt)-1; + c->idtr_base = (unsigned long) &idt; + + c->gdtr_limit = sizeof(gdt)-1; + c->gdtr_base = (unsigned long) &gdt; + + c->cs_sel = CODE_SELECTOR; + c->cs_limit = 0xFFFFFFFF; + c->cs_base = 0; + c->cs_arbytes.fields.seg_type = 0xb; + c->cs_arbytes.fields.s = 1; + c->cs_arbytes.fields.dpl = 0; + c->cs_arbytes.fields.p = 1; + c->cs_arbytes.fields.avl = 0; + c->cs_arbytes.fields.default_ops_size = 1; + c->cs_arbytes.fields.g = 1; + + c->ds_sel = DATA_SELECTOR; + c->ds_limit = 0xFFFFFFFF; + c->ds_base = 0; + c->ds_arbytes = c->cs_arbytes; + c->ds_arbytes.fields.seg_type = 0x3; + + c->es_sel = DATA_SELECTOR; + c->es_limit = 0xFFFFFFFF; + c->es_base = 0; + c->es_arbytes = c->ds_arbytes; + + c->ss_sel = DATA_SELECTOR; + c->ss_limit = 0xFFFFFFFF; + c->ss_base = 0; + c->ss_arbytes = c->ds_arbytes; + + c->fs_sel = DATA_SELECTOR; + c->fs_limit = 0xFFFFFFFF; + c->fs_base = 0; + c->fs_arbytes = c->ds_arbytes; + + c->gs_sel = DATA_SELECTOR; + c->gs_limit = 0xFFFFFFFF; + c->gs_base = 0; + c->gs_arbytes = c->ds_arbytes; + + c->tr_sel = TSS_SELECTOR; + c->tr_limit = sizeof(tss) - 1; + c->tr_base = (unsigned long) &tss; + c->tr_arbytes.fields.seg_type = 0xb; /* 0x9 | 0x2 (busy) */ + c->tr_arbytes.fields.s = 0; + c->tr_arbytes.fields.dpl = 0; + c->tr_arbytes.fields.p = 1; + c->tr_arbytes.fields.avl = 0; + c->tr_arbytes.fields.default_ops_size = 0; + c->tr_arbytes.fields.g = 0; + + c->ldtr_sel = 0; + c->ldtr_limit = 0; + c->ldtr_base = 0; + c->ldtr_arbytes = c->ds_arbytes; + c->ldtr_arbytes.fields.seg_type = 0x2; + c->ldtr_arbytes.fields.s = 0; + c->ldtr_arbytes.fields.dpl = 0; + c->ldtr_arbytes.fields.p = 1; + c->ldtr_arbytes.fields.avl = 0; + c->ldtr_arbytes.fields.default_ops_size = 0; + c->ldtr_arbytes.fields.g = 0; +} + +/* + * Start BIOS by causing a world switch to vmxassist, which causes + * VM8086 to be enabled and control is transfered to F000:FFF0. + */ +void +start_bios(void) +{ + if (booting_cpu == 0) + printf("Start BIOS ...\n"); + else + printf("Start AP %d from %08x ...\n", + booting_cpu, booting_vector << 12); + + initialize_real_mode = 1; + set_cr0(get_cr0() & ~CR0_PE); + panic("vmxassist returned"); /* "cannot happen" */ +} + +int +main(void) +{ + + printf("Hello from VMXAssist\n"); + + if (booting_cpu == 0) + banner(); + +#ifdef TEST + setup_paging(); +#endif + + setup_gdt(); + setup_idt(); + +#ifndef TEST + set_cr4(get_cr4() | CR4_VME); +#endif + + setup_ctx(); + + if (booting_cpu == 0) + setup_pic(); + + start_bios(); + + return 0; +} diff --git a/palacios/src/vmboot/vmxassist/trap.S b/palacios/src/vmboot/vmxassist/trap.S new file mode 100644 index 0000000..468da0a --- /dev/null +++ b/palacios/src/vmboot/vmxassist/trap.S @@ -0,0 +1,191 @@ +/* + * trap.S: Trap and world switch handlers + * + * Leendert van Doorn, leendert@watson.ibm.com + * Copyright (c) 2005, International Business Machines Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ +#include "machine.h" +#include "vm86.h" +#include "offsets.h" + +/* + * All processor exception/faults/interrupts end up here. + * + * On an exception/fault, the processor pushes CS:EIP, SS, ESP and an + * optional error code onto the stack. The common_trap routine + * below saves the processor context and transfers control to trap() + * whose job it is to virtualize and pass on the trap. + */ + .macro TRAP_HANDLER trapno error + .text + .align 16 +1: .if \error == 0 + pushl $0 /* dummy error code */ + .endif + pushl $\trapno + jmp common_trap + .section .rodata + .long 1b + .text + .endm + + .section .rodata + .code32 + .align 4 + .global trap_handlers +trap_handlers: + TRAP_HANDLER 0, 0 /* divide error */ + TRAP_HANDLER 1, 0 /* debug */ + TRAP_HANDLER 2, 0 /* NMI interrupt */ + TRAP_HANDLER 3, 0 /* breakpoint */ + TRAP_HANDLER 4, 0 /* overflow */ + TRAP_HANDLER 5, 0 /* BOUND range exceeded */ + TRAP_HANDLER 6, 0 /* invalid opcode */ + TRAP_HANDLER 7, 0 /* device not available */ + TRAP_HANDLER 8, 1 /* double fault */ + TRAP_HANDLER 9, 0 /* coprocessor segment overrun */ + TRAP_HANDLER 10, 1 /* invalid TSS */ + TRAP_HANDLER 11, 1 /* segment not present */ + TRAP_HANDLER 12, 1 /* stack-segment fault */ + TRAP_HANDLER 13, 1 /* general protection */ + TRAP_HANDLER 14, 1 /* page fault */ + TRAP_HANDLER 15, 0 /* reserved */ + TRAP_HANDLER 16, 0 /* FPU floating-point error */ + TRAP_HANDLER 17, 1 /* alignment check */ + TRAP_HANDLER 18, 0 /* machine check */ + TRAP_HANDLER 19, 0 /* SIMD floating-point error */ + TRAP_HANDLER 20, 0 /* reserved */ + TRAP_HANDLER 21, 0 /* reserved */ + TRAP_HANDLER 22, 0 /* reserved */ + TRAP_HANDLER 23, 0 /* reserved */ + TRAP_HANDLER 24, 0 /* reserved */ + TRAP_HANDLER 25, 0 /* reserved */ + TRAP_HANDLER 26, 0 /* reserved */ + TRAP_HANDLER 27, 0 /* reserved */ + TRAP_HANDLER 28, 0 /* reserved */ + TRAP_HANDLER 29, 0 /* reserved */ + TRAP_HANDLER 30, 0 /* reserved */ + TRAP_HANDLER 31, 0 /* reserved */ + TRAP_HANDLER 32, 0 /* irq 0 */ + TRAP_HANDLER 33, 0 /* irq 1 */ + TRAP_HANDLER 34, 0 /* irq 2 */ + TRAP_HANDLER 35, 0 /* irq 3 */ + TRAP_HANDLER 36, 0 /* irq 4 */ + TRAP_HANDLER 37, 0 /* irq 5 */ + TRAP_HANDLER 38, 0 /* irq 6 */ + TRAP_HANDLER 39, 0 /* irq 7 */ + TRAP_HANDLER 40, 0 /* irq 8 */ + TRAP_HANDLER 41, 0 /* irq 9 */ + TRAP_HANDLER 42, 0 /* irq 10 */ + TRAP_HANDLER 43, 0 /* irq 11 */ + TRAP_HANDLER 44, 0 /* irq 12 */ + TRAP_HANDLER 45, 0 /* irq 13 */ + TRAP_HANDLER 46, 0 /* irq 14 */ + TRAP_HANDLER 47, 0 /* irq 15 */ + + .text + .code32 + .align 16 +common_trap: /* common trap handler */ + pushl %gs + pushl %fs + pushl %ds + pushl %es + pushal + + movl $DATA_SELECTOR, %eax /* make sure these are sane */ + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %esp, %ebp + + pushl %ebp + pushl 52(%ebp) + pushl 48(%ebp) + call trap /* trap(trapno, errno, regs) */ + addl $12, %esp + +trap_return: + popal + popl %es + popl %ds + popl %fs + popl %gs + addl $8, %esp /* skip trapno, errno */ + iret + /* NOT REACHED */ + + +/* + * A world switch to real mode occured. The hypervisor saved the + * executing context into "oldctx" and instantiated "newctx", which + * gets us here. Here we push a stack frame that is compatible with + * a trap frame (see above) so that we can handle this event as a + * regular trap. + */ + .text + .align 16 + .globl switch_to_real_mode +switch_to_real_mode: + pushl oldctx+VMX_ASSIST_CTX_GS_SEL /* 16 to 32-bit transition */ + pushl oldctx+VMX_ASSIST_CTX_FS_SEL + pushl oldctx+VMX_ASSIST_CTX_DS_SEL + pushl oldctx+VMX_ASSIST_CTX_ES_SEL + pushl oldctx+VMX_ASSIST_CTX_SS_SEL + pushl oldctx+VMX_ASSIST_CTX_ESP + pushl oldctx+VMX_ASSIST_CTX_EFLAGS + pushl oldctx+VMX_ASSIST_CTX_CS_SEL + pushl oldctx+VMX_ASSIST_CTX_EIP + pushl $-1 /* trapno, errno */ + pushl $-1 + pushl %gs + pushl %fs + pushl %ds + pushl %es + pushal + + movl %esp, %ebp + pushl %ebp + call enter_real_mode + addl $4, %esp + + jmp trap_return + /* NOT REACHED */ + + +/* + * Switch to protected mode. At this point all the registers have + * been reloaded by trap_return and all we have to do is cause a + * world switch by turning on CR0.PE. + */ + .text + .align 16 + .globl switch_to_protected_mode +switch_to_protected_mode: + movl oldctx+VMX_ASSIST_CTX_CR0, %esp + movl %esp, %cr0 /* actual world switch ! */ + + /* NOT REACHED */ + pushl $switch_failed + call panic + jmp . + + .data + .align 4 +switch_failed: + .asciz "World switch to protected mode failed\n" + diff --git a/palacios/src/vmboot/vmxassist/util.c b/palacios/src/vmboot/vmxassist/util.c new file mode 100644 index 0000000..0181fe7 --- /dev/null +++ b/palacios/src/vmboot/vmxassist/util.c @@ -0,0 +1,406 @@ +/* + * util.c: Commonly used utility functions. + * + * Leendert van Doorn, leendert@watson.ibm.com + * Copyright (c) 2005, International Business Machines Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ +#include + +#include "util.h" +#include "machine.h" + +#define isdigit(c) ((c) >= '0' && (c) <= '9') +#define min(a, b) ((a) < (b) ? (a) : (b)) + +static void putchar(int); +static char *printnum(char *, unsigned long, int); +static void _doprint(void (*)(int), char const *, va_list); + + +void +dump_regs(struct regs *regs) +{ + printf("eax %8x ecx %8x edx %8x ebx %8x\n", + regs->eax, regs->ecx, regs->edx, regs->ebx); + printf("esp %8x ebp %8x esi %8x edi %8x\n", + regs->esp, regs->ebp, regs->esi, regs->edi); + printf("eip %8x eflags %8x cs %8x ds %8x\n", + regs->eip, regs->eflags, regs->cs, regs->ds); + printf("es %8x fs %8x uss %8x uesp %8x\n", + regs->es, regs->fs, regs->uss, regs->uesp); + printf("ves %8x vds %8x vfs %8x vgs %8x\n", + regs->ves, regs->vds, regs->vfs, regs->vgs); + if (regs->trapno != -1 || regs->errno != -1) + printf("trapno %8x errno %8x\n", regs->trapno, regs->errno); + + printf("cr0 %8lx cr2 %8x cr3 %8lx cr4 %8lx\n", + (long)oldctx.cr0, get_cr2(), + (long)oldctx.cr3, (long)oldctx.cr4); +} + +#ifdef DEBUG +void +hexdump(unsigned char *data, int sz) +{ + unsigned char *d; + int i; + + for (d = data; sz > 0; d += 16, sz -= 16) { + int n = sz > 16 ? 16 : sz; + + printf("%08x: ", (unsigned)d); + for (i = 0; i < n; i++) + printf("%02x%c", d[i], i == 7 ? '-' : ' '); + for (; i < 16; i++) + printf(" %c", i == 7 ? '-' : ' '); + printf(" "); + for (i = 0; i < n; i++) + printf("%c", d[i] >= ' ' && d[i] <= '~' ? d[i] : '.'); + printf("\n"); + } +} + +void +print_e820_map(struct e820entry *map, int entries) +{ + struct e820entry *m; + + if (entries > 32) + entries = 32; + + for (m = map; m < &map[entries]; m++) { + printf("%08lx%08lx - %08lx%08lx ", + (unsigned long) (m->addr >> 32), + (unsigned long) (m->addr), + (unsigned long) ((m->addr+m->size) >> 32), + (unsigned long) ((m->addr+m->size))); + + switch (m->type) { + case E820_RAM: + printf("(RAM)\n"); break; + case E820_RESERVED: + printf("(Reserved)\n"); break; + case E820_ACPI: + printf("(ACPI Data)\n"); break; + case E820_NVS: + printf("(ACPI NVS)\n"); break; + default: + printf("(Type %ld)\n", m->type); break; + } + } +} + +void +dump_dtr(unsigned long addr, unsigned long size) +{ + unsigned long long entry; + unsigned long base, limit; + int i; + + for (i = 0; i < size; i += 8) { + entry = ((unsigned long long *) addr)[i >> 3]; + base = (((entry >> (56-24)) & 0xFF000000) | + ((entry >> (32-16)) & 0x00FF0000) | + ((entry >> ( 16)) & 0x0000FFFF)); + limit = (((entry >> (48-16)) & 0x000F0000) | + ((entry ) & 0x0000FFFF)); + if (entry & (1ULL << (23+32))) /* G */ + limit = (limit << 12) | 0xFFF; + + printf("[0x%x] = 0x%08x%08x, base 0x%lx, limit 0x%lx\n", i, + (unsigned)(entry >> 32), (unsigned)(entry), + base, limit); + } +} + +void +dump_vmx_context(struct vmx_assist_context *c) +{ + printf("eip 0x%lx, esp 0x%lx, eflags 0x%lx\n", + (long) c->eip, (long) c->esp, (long) c->eflags); + + printf("cr0 0x%lx, cr3 0x%lx, cr4 0x%lx\n", + (long)c->cr0, (long)c->cr3, (long)c->cr4); + + printf("idtr: limit 0x%lx, base 0x%lx\n", + (long)c->idtr_limit, (long)c->idtr_base); + + printf("gdtr: limit 0x%lx, base 0x%lx\n", + (long)c->gdtr_limit, (long)c->gdtr_base); + + printf("cs: sel 0x%lx, limit 0x%lx, base 0x%lx\n", + (long)c->cs_sel, (long)c->cs_limit, (long)c->cs_base); + printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n", + c->cs_arbytes.fields.seg_type, + c->cs_arbytes.fields.s, + c->cs_arbytes.fields.dpl, + c->cs_arbytes.fields.p, + c->cs_arbytes.fields.avl, + c->cs_arbytes.fields.default_ops_size, + c->cs_arbytes.fields.g, + c->cs_arbytes.fields.null_bit); + + printf("ds: sel 0x%lx, limit 0x%lx, base 0x%lx\n", + (long)c->ds_sel, (long)c->ds_limit, (long)c->ds_base); + printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n", + c->ds_arbytes.fields.seg_type, + c->ds_arbytes.fields.s, + c->ds_arbytes.fields.dpl, + c->ds_arbytes.fields.p, + c->ds_arbytes.fields.avl, + c->ds_arbytes.fields.default_ops_size, + c->ds_arbytes.fields.g, + c->ds_arbytes.fields.null_bit); + + printf("es: sel 0x%lx, limit 0x%lx, base 0x%lx\n", + (long)c->es_sel, (long)c->es_limit, (long)c->es_base); + printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n", + c->es_arbytes.fields.seg_type, + c->es_arbytes.fields.s, + c->es_arbytes.fields.dpl, + c->es_arbytes.fields.p, + c->es_arbytes.fields.avl, + c->es_arbytes.fields.default_ops_size, + c->es_arbytes.fields.g, + c->es_arbytes.fields.null_bit); + + printf("ss: sel 0x%lx, limit 0x%lx, base 0x%lx\n", + (long)c->ss_sel, (long)c->ss_limit, (long)c->ss_base); + printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n", + c->ss_arbytes.fields.seg_type, + c->ss_arbytes.fields.s, + c->ss_arbytes.fields.dpl, + c->ss_arbytes.fields.p, + c->ss_arbytes.fields.avl, + c->ss_arbytes.fields.default_ops_size, + c->ss_arbytes.fields.g, + c->ss_arbytes.fields.null_bit); + + printf("fs: sel 0x%lx, limit 0x%lx, base 0x%lx\n", + (long)c->fs_sel, (long)c->fs_limit, (long)c->fs_base); + printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n", + c->fs_arbytes.fields.seg_type, + c->fs_arbytes.fields.s, + c->fs_arbytes.fields.dpl, + c->fs_arbytes.fields.p, + c->fs_arbytes.fields.avl, + c->fs_arbytes.fields.default_ops_size, + c->fs_arbytes.fields.g, + c->fs_arbytes.fields.null_bit); + + printf("gs: sel 0x%lx, limit 0x%lx, base 0x%lx\n", + (long)c->gs_sel, (long)c->gs_limit, (long)c->gs_base); + printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n", + c->gs_arbytes.fields.seg_type, + c->gs_arbytes.fields.s, + c->gs_arbytes.fields.dpl, + c->gs_arbytes.fields.p, + c->gs_arbytes.fields.avl, + c->gs_arbytes.fields.default_ops_size, + c->gs_arbytes.fields.g, + c->gs_arbytes.fields.null_bit); + + printf("tr: sel 0x%lx, limit 0x%lx, base 0x%lx\n", + (long)c->tr_sel, (long)c->tr_limit, (long)c->tr_base); + printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n", + c->tr_arbytes.fields.seg_type, + c->tr_arbytes.fields.s, + c->tr_arbytes.fields.dpl, + c->tr_arbytes.fields.p, + c->tr_arbytes.fields.avl, + c->tr_arbytes.fields.default_ops_size, + c->tr_arbytes.fields.g, + c->tr_arbytes.fields.null_bit); + + printf("ldtr: sel 0x%lx, limit 0x%lx, base 0x%lx\n", + (long)c->ldtr_sel, (long)c->ldtr_limit, (long)c->ldtr_base); + printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n", + c->ldtr_arbytes.fields.seg_type, + c->ldtr_arbytes.fields.s, + c->ldtr_arbytes.fields.dpl, + c->ldtr_arbytes.fields.p, + c->ldtr_arbytes.fields.avl, + c->ldtr_arbytes.fields.default_ops_size, + c->ldtr_arbytes.fields.g, + c->ldtr_arbytes.fields.null_bit); + + printf("GDTR <0x%lx,0x%lx>:\n", + (long)c->gdtr_base, (long)c->gdtr_limit); + dump_dtr(c->gdtr_base, c->gdtr_limit); +} +#endif /* DEBUG */ + +/* + * Lightweight printf that doesn't drag in everything under the sun. + */ +int +printf(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _doprint(putchar, fmt, ap); + va_end(ap); + return 0; /* for gcc compat */ +} + +int +vprintf(const char *fmt, va_list ap) +{ + _doprint(putchar, fmt, ap); + return 0; /* for gcc compat */ +} + +void +panic(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _doprint(putchar, fmt, ap); + putchar('\n'); + va_end(ap); + halt(); +} + +unsigned +strlen(const char *s) +{ + const char *q = s; + + while (*s++) + /* void */; + return s - q - 1; +} + +static void +putchar(int ch) +{ + outb(0xE9, ch); +} + +/* + * A stripped down version of doprint, + * but still powerful enough for most tasks. + */ +static void +_doprint(void (*put)(int), char const *fmt, va_list ap) +{ + register char *str, c; + int lflag, zflag, nflag; + char buffer[17]; + unsigned value; + int i, slen, pad; + + for ( ; *fmt != '\0'; fmt++) { + pad = zflag = nflag = lflag = 0; + if (*fmt == '%') { + c = *++fmt; + if (c == '-' || isdigit(c)) { + if (c == '-') { + nflag = 1; + c = *++fmt; + } + zflag = c == '0'; + for (pad = 0; isdigit(c); c = *++fmt) + pad = (pad * 10) + c - '0'; + } + if (c == 'l') { /* long extension */ + lflag = 1; + c = *++fmt; + } + if (c == 'd' || c == 'u' || c == 'o' || c == 'x') { + if (lflag) + value = va_arg(ap, unsigned); + else + value = (unsigned) va_arg(ap, unsigned int); + str = buffer; + printnum(str, value, + c == 'o' ? 8 : (c == 'x' ? 16 : 10)); + goto printn; + } else if (c == 'O' || c == 'D' || c == 'X') { + value = va_arg(ap, unsigned); + str = buffer; + printnum(str, value, + c == 'O' ? 8 : (c == 'X' ? 16 : 10)); + printn: + slen = strlen(str); + for (i = pad - slen; i > 0; i--) + put(zflag ? '0' : ' '); + while (*str) put(*str++); + } else if (c == 's') { + str = va_arg(ap, char *); + slen = strlen(str); + if (nflag == 0) + for (i = pad - slen; i > 0; i--) put(' '); + while (*str) put(*str++); + if (nflag) + for (i = pad - slen; i > 0; i--) put(' '); + } else if (c == 'c') + put(va_arg(ap, int)); + else + put(*fmt); + } else + put(*fmt); + } +} + +static char * +printnum(char *p, unsigned long num, int base) +{ + unsigned long n; + + if ((n = num/base) > 0) + p = printnum(p, n, base); + *p++ = "0123456789ABCDEF"[(int)(num % base)]; + *p = '\0'; + return p; +} + +void * +memset(void *s, int c, unsigned n) +{ + int t0, t1; + + __asm__ __volatile__ ("cld; rep; stosb" + : "=&c" (t0), "=&D" (t1) + : "a" (c), "1" (s), "0" (n) + : "memory"); + return s; +} + +void * +memcpy(void *dest, const void *src, unsigned n) +{ + int t0, t1, t2; + + __asm__ __volatile__( + "cld\n" + "rep; movsl\n" + "testb $2,%b4\n" + "je 1f\n" + "movsw\n" + "1: testb $1,%b4\n" + "je 2f\n" + "movsb\n" + "2:" + : "=&c" (t0), "=&D" (t1), "=&S" (t2) + : "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src) + : "memory" + ); + return dest; +} + diff --git a/palacios/src/vmboot/vmxassist/util.h b/palacios/src/vmboot/vmxassist/util.h new file mode 100644 index 0000000..9c2982f --- /dev/null +++ b/palacios/src/vmboot/vmxassist/util.h @@ -0,0 +1,46 @@ +/* + * util.h: Useful utility functions. + * + * Leendert van Doorn, leendert@watson.ibm.com + * Copyright (c) 2005, International Business Machines Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __UTIL_H__ +#define __UTIL_H__ + +#include +#include + +#include +#define E820_MAP_NR ((unsigned char *)E820_MAP_PAGE + E820_MAP_NR_OFFSET) +#define E820_MAP ((struct e820entry *)(E820_MAP_PAGE + E820_MAP_OFFSET)) + +#define offsetof(type, member) ((unsigned) &((type *)0)->member) + +struct vmx_assist_context; + +extern void hexdump(unsigned char *, int); +extern void dump_regs(struct regs *); +extern void dump_vmx_context(struct vmx_assist_context *); +extern void print_e820_map(struct e820entry *, int); +extern void dump_dtr(unsigned long, unsigned long); +extern void *memcpy(void *, const void *, unsigned); +extern void *memset(void *, int, unsigned); +extern int printf(const char *fmt, ...); +extern int vprintf(const char *fmt, va_list ap); +extern void panic(const char *format, ...); +extern void halt(void); + +#endif /* __UTIL_H__ */ diff --git a/palacios/src/vmboot/vmxassist/vm86.c b/palacios/src/vmboot/vmxassist/vm86.c new file mode 100644 index 0000000..8c620a4 --- /dev/null +++ b/palacios/src/vmboot/vmxassist/vm86.c @@ -0,0 +1,1650 @@ +/* + * vm86.c: A vm86 emulator. The main purpose of this emulator is to do as + * little work as possible. + * + * Leendert van Doorn, leendert@watson.ibm.com + * Copyright (c) 2005-2006, International Business Machines Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ +#include "vm86.h" +#include "util.h" +#include "machine.h" + +#define HIGHMEM (1 << 20) /* 1MB */ +#define MASK16(v) ((v) & 0xFFFF) + +#define DATA32 0x0001 +#define ADDR32 0x0002 +#define SEG_CS 0x0004 +#define SEG_DS 0x0008 +#define SEG_ES 0x0010 +#define SEG_SS 0x0020 +#define SEG_FS 0x0040 +#define SEG_GS 0x0080 + +static unsigned prev_eip = 0; +enum vm86_mode mode = 0; + +static struct regs saved_rm_regs; + +#ifdef DEBUG +int traceset = 0; + +char *states[] = { + "", + "", + "", + "" +}; + +static char *rnames[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }; +#endif /* DEBUG */ + +#define PDE_PS (1 << 7) +#define PT_ENTRY_PRESENT 0x1 + +/* We only support access to <=4G physical memory due to 1:1 mapping */ +static unsigned +guest_linear_to_real(uint32_t base) +{ + uint32_t gcr3 = oldctx.cr3; + uint64_t l2_mfn; + uint64_t l1_mfn; + uint64_t l0_mfn; + + if (!(oldctx.cr0 & CR0_PG)) + return base; + + if (!(oldctx.cr4 & CR4_PAE)) { + l1_mfn = ((uint32_t *)(long)gcr3)[(base >> 22) & 0x3ff]; + if (!(l1_mfn & PT_ENTRY_PRESENT)) + panic("l2 entry not present\n"); + + if ((oldctx.cr4 & CR4_PSE) && (l1_mfn & PDE_PS)) { + l0_mfn = l1_mfn & 0xffc00000; + return l0_mfn + (base & 0x3fffff); + } + + l1_mfn &= 0xfffff000; + + l0_mfn = ((uint32_t *)(long)l1_mfn)[(base >> 12) & 0x3ff]; + if (!(l0_mfn & PT_ENTRY_PRESENT)) + panic("l1 entry not present\n"); + l0_mfn &= 0xfffff000; + + return l0_mfn + (base & 0xfff); + } else { + l2_mfn = ((uint64_t *)(long)gcr3)[(base >> 30) & 0x3]; + if (!(l2_mfn & PT_ENTRY_PRESENT)) + panic("l3 entry not present\n"); + l2_mfn &= 0x3fffff000ULL; + + l1_mfn = ((uint64_t *)(long)l2_mfn)[(base >> 21) & 0x1ff]; + if (!(l1_mfn & PT_ENTRY_PRESENT)) + panic("l2 entry not present\n"); + + if (l1_mfn & PDE_PS) { /* CR4.PSE is ignored in PAE mode */ + l0_mfn = l1_mfn & 0x3ffe00000ULL; + return l0_mfn + (base & 0x1fffff); + } + + l1_mfn &= 0x3fffff000ULL; + + l0_mfn = ((uint64_t *)(long)l1_mfn)[(base >> 12) & 0x1ff]; + if (!(l0_mfn & PT_ENTRY_PRESENT)) + panic("l1 entry not present\n"); + l0_mfn &= 0x3fffff000ULL; + + return l0_mfn + (base & 0xfff); + } +} + +static unsigned +address(struct regs *regs, unsigned seg, unsigned off) +{ + unsigned long long entry; + unsigned seg_base, seg_limit; + unsigned entry_low, entry_high; + + if (seg == 0) { + if (mode == VM86_REAL || mode == VM86_REAL_TO_PROTECTED) + return off; + else + panic("segment is zero, but not in real mode!\n"); + } + + if (mode == VM86_REAL || seg > oldctx.gdtr_limit || + (mode == VM86_REAL_TO_PROTECTED && regs->cs == seg)) + return ((seg & 0xFFFF) << 4) + off; + + entry = ((unsigned long long *) + guest_linear_to_real(oldctx.gdtr_base))[seg >> 3]; + entry_high = entry >> 32; + entry_low = entry & 0xFFFFFFFF; + + seg_base = (entry_high & 0xFF000000) | ((entry >> 16) & 0xFFFFFF); + seg_limit = (entry_high & 0xF0000) | (entry_low & 0xFFFF); + + if (entry_high & 0x8000 && + ((entry_high & 0x800000 && off >> 12 <= seg_limit) || + (!(entry_high & 0x800000) && off <= seg_limit))) + return seg_base + off; + + panic("should never reach here in function address():\n\t" + "entry=0x%08x%08x, mode=%d, seg=0x%08x, offset=0x%08x\n", + entry_high, entry_low, mode, seg, off); + + return 0; +} + +#ifdef DEBUG +void +trace(struct regs *regs, int adjust, char *fmt, ...) +{ + unsigned off = regs->eip - adjust; + va_list ap; + + if ((traceset & (1 << mode)) && + (mode == VM86_REAL_TO_PROTECTED || mode == VM86_REAL)) { + /* 16-bit, seg:off addressing */ + unsigned addr = address(regs, regs->cs, off); + printf("0x%08x: 0x%x:0x%04x ", addr, regs->cs, off); + printf("(%d) ", mode); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf("\n"); + } + if ((traceset & (1 << mode)) && + (mode == VM86_PROTECTED_TO_REAL || mode == VM86_PROTECTED)) { + /* 16-bit, gdt addressing */ + unsigned addr = address(regs, regs->cs, off); + printf("0x%08x: 0x%x:0x%08x ", addr, regs->cs, off); + printf("(%d) ", mode); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf("\n"); + } +} +#endif /* DEBUG */ + +static inline unsigned +read32(unsigned addr) +{ + return *(unsigned long *) addr; +} + +static inline unsigned +read16(unsigned addr) +{ + return *(unsigned short *) addr; +} + +static inline unsigned +read8(unsigned addr) +{ + return *(unsigned char *) addr; +} + +static inline void +write32(unsigned addr, unsigned value) +{ + *(unsigned long *) addr = value; +} + +static inline void +write16(unsigned addr, unsigned value) +{ + *(unsigned short *) addr = value; +} + +static inline void +write8(unsigned addr, unsigned value) +{ + *(unsigned char *) addr = value; +} + +static inline void +push32(struct regs *regs, unsigned value) +{ + regs->uesp -= 4; + write32(address(regs, regs->uss, MASK16(regs->uesp)), value); +} + +static inline void +push16(struct regs *regs, unsigned value) +{ + regs->uesp -= 2; + write16(address(regs, regs->uss, MASK16(regs->uesp)), value); +} + +static inline unsigned +pop32(struct regs *regs) +{ + unsigned value = read32(address(regs, regs->uss, MASK16(regs->uesp))); + regs->uesp += 4; + return value; +} + +static inline unsigned +pop16(struct regs *regs) +{ + unsigned value = read16(address(regs, regs->uss, MASK16(regs->uesp))); + regs->uesp += 2; + return value; +} + +static inline unsigned +fetch32(struct regs *regs) +{ + unsigned addr = address(regs, regs->cs, MASK16(regs->eip)); + + regs->eip += 4; + return read32(addr); +} + +static inline unsigned +fetch16(struct regs *regs) +{ + unsigned addr = address(regs, regs->cs, MASK16(regs->eip)); + + regs->eip += 2; + return read16(addr); +} + +static inline unsigned +fetch8(struct regs *regs) +{ + unsigned addr = address(regs, regs->cs, MASK16(regs->eip)); + + regs->eip++; + return read8(addr); +} + +static unsigned +getreg32(struct regs *regs, int r) +{ + switch (r & 7) { + case 0: return regs->eax; + case 1: return regs->ecx; + case 2: return regs->edx; + case 3: return regs->ebx; + case 4: return regs->esp; + case 5: return regs->ebp; + case 6: return regs->esi; + case 7: return regs->edi; + } + return ~0; +} + +static unsigned +getreg16(struct regs *regs, int r) +{ + return MASK16(getreg32(regs, r)); +} + +static unsigned +getreg8(struct regs *regs, int r) +{ + switch (r & 7) { + case 0: return regs->eax & 0xFF; /* al */ + case 1: return regs->ecx & 0xFF; /* cl */ + case 2: return regs->edx & 0xFF; /* dl */ + case 3: return regs->ebx & 0xFF; /* bl */ + case 4: return (regs->esp >> 8) & 0xFF; /* ah */ + case 5: return (regs->ebp >> 8) & 0xFF; /* ch */ + case 6: return (regs->esi >> 8) & 0xFF; /* dh */ + case 7: return (regs->edi >> 8) & 0xFF; /* bh */ + } + return ~0; +} + +static void +setreg32(struct regs *regs, int r, unsigned v) +{ + switch (r & 7) { + case 0: regs->eax = v; break; + case 1: regs->ecx = v; break; + case 2: regs->edx = v; break; + case 3: regs->ebx = v; break; + case 4: regs->esp = v; break; + case 5: regs->ebp = v; break; + case 6: regs->esi = v; break; + case 7: regs->edi = v; break; + } +} + +static void +setreg16(struct regs *regs, int r, unsigned v) +{ + setreg32(regs, r, (getreg32(regs, r) & ~0xFFFF) | MASK16(v)); +} + +static void +setreg8(struct regs *regs, int r, unsigned v) +{ + v &= 0xFF; + switch (r & 7) { + case 0: regs->eax = (regs->eax & ~0xFF) | v; break; + case 1: regs->ecx = (regs->ecx & ~0xFF) | v; break; + case 2: regs->edx = (regs->edx & ~0xFF) | v; break; + case 3: regs->ebx = (regs->ebx & ~0xFF) | v; break; + case 4: regs->esp = (regs->esp & ~0xFF00) | (v << 8); break; + case 5: regs->ebp = (regs->ebp & ~0xFF00) | (v << 8); break; + case 6: regs->esi = (regs->esi & ~0xFF00) | (v << 8); break; + case 7: regs->edi = (regs->edi & ~0xFF00) | (v << 8); break; + } +} + +static unsigned +segment(unsigned prefix, struct regs *regs, unsigned seg) +{ + if (prefix & SEG_ES) + seg = regs->ves; + if (prefix & SEG_DS) + seg = regs->vds; + if (prefix & SEG_CS) + seg = regs->cs; + if (prefix & SEG_SS) + seg = regs->uss; + if (prefix & SEG_FS) + seg = regs->fs; + if (prefix & SEG_GS) + seg = regs->gs; + return seg; +} + +static unsigned +sib(struct regs *regs, int mod, unsigned byte) +{ + unsigned scale = (byte >> 6) & 3; + int index = (byte >> 3) & 7; + int base = byte & 7; + unsigned addr = 0; + + switch (mod) { + case 0: + if (base == 5) + addr = fetch32(regs); + else + addr = getreg32(regs, base); + break; + case 1: + addr = getreg32(regs, base) + (char) fetch8(regs); + break; + case 2: + addr = getreg32(regs, base) + fetch32(regs); + break; + } + + if (index != 4) + addr += getreg32(regs, index) << scale; + + return addr; +} + +/* + * Operand (modrm) decode + */ +static unsigned +operand(unsigned prefix, struct regs *regs, unsigned modrm) +{ + int mod, disp = 0, seg; + + seg = segment(prefix, regs, regs->vds); + + if (prefix & ADDR32) { /* 32-bit addressing */ + switch ((mod = (modrm >> 6) & 3)) { + case 0: + switch (modrm & 7) { + case 0: return address(regs, seg, regs->eax); + case 1: return address(regs, seg, regs->ecx); + case 2: return address(regs, seg, regs->edx); + case 3: return address(regs, seg, regs->ebx); + case 4: return address(regs, seg, + sib(regs, mod, fetch8(regs))); + case 5: return address(regs, seg, fetch32(regs)); + case 6: return address(regs, seg, regs->esi); + case 7: return address(regs, seg, regs->edi); + } + break; + case 1: + case 2: + if ((modrm & 7) != 4) { + if (mod == 1) + disp = (char) fetch8(regs); + else + disp = (int) fetch32(regs); + } + switch (modrm & 7) { + case 0: return address(regs, seg, regs->eax + disp); + case 1: return address(regs, seg, regs->ecx + disp); + case 2: return address(regs, seg, regs->edx + disp); + case 3: return address(regs, seg, regs->ebx + disp); + case 4: return address(regs, seg, + sib(regs, mod, fetch8(regs))); + case 5: return address(regs, seg, regs->ebp + disp); + case 6: return address(regs, seg, regs->esi + disp); + case 7: return address(regs, seg, regs->edi + disp); + } + break; + case 3: + return getreg32(regs, modrm); + } + } else { /* 16-bit addressing */ + switch ((mod = (modrm >> 6) & 3)) { + case 0: + switch (modrm & 7) { + case 0: return address(regs, seg, MASK16(regs->ebx) + + MASK16(regs->esi)); + case 1: return address(regs, seg, MASK16(regs->ebx) + + MASK16(regs->edi)); + case 2: return address(regs, seg, MASK16(regs->ebp) + + MASK16(regs->esi)); + case 3: return address(regs, seg, MASK16(regs->ebp) + + MASK16(regs->edi)); + case 4: return address(regs, seg, MASK16(regs->esi)); + case 5: return address(regs, seg, MASK16(regs->edi)); + case 6: return address(regs, seg, fetch16(regs)); + case 7: return address(regs, seg, MASK16(regs->ebx)); + } + break; + case 1: + case 2: + if (mod == 1) + disp = (char) fetch8(regs); + else + disp = (int) fetch16(regs); + switch (modrm & 7) { + case 0: return address(regs, seg, MASK16(regs->ebx) + + MASK16(regs->esi) + disp); + case 1: return address(regs, seg, MASK16(regs->ebx) + + MASK16(regs->edi) + disp); + case 2: return address(regs, seg, MASK16(regs->ebp) + + MASK16(regs->esi) + disp); + case 3: return address(regs, seg, MASK16(regs->ebp) + + MASK16(regs->edi) + disp); + case 4: return address(regs, seg, + MASK16(regs->esi) + disp); + case 5: return address(regs, seg, + MASK16(regs->edi) + disp); + case 6: return address(regs, seg, + MASK16(regs->ebp) + disp); + case 7: return address(regs, seg, + MASK16(regs->ebx) + disp); + } + break; + case 3: + return getreg16(regs, modrm); + } + } + + return 0; +} + +/* + * Load new IDT + */ +static int +lidt(struct regs *regs, unsigned prefix, unsigned modrm) +{ + unsigned eip = regs->eip - 3; + unsigned addr = operand(prefix, regs, modrm); + + oldctx.idtr_limit = ((struct dtr *) addr)->size; + if ((prefix & DATA32) == 0) + oldctx.idtr_base = ((struct dtr *) addr)->base & 0xFFFFFF; + else + oldctx.idtr_base = ((struct dtr *) addr)->base; + TRACE((regs, regs->eip - eip, "lidt 0x%x <%d, 0x%x>", + addr, oldctx.idtr_limit, oldctx.idtr_base)); + + return 1; +} + +/* + * Load new GDT + */ +static int +lgdt(struct regs *regs, unsigned prefix, unsigned modrm) +{ + unsigned eip = regs->eip - 3; + unsigned addr = operand(prefix, regs, modrm); + + oldctx.gdtr_limit = ((struct dtr *) addr)->size; + if ((prefix & DATA32) == 0) + oldctx.gdtr_base = ((struct dtr *) addr)->base & 0xFFFFFF; + else + oldctx.gdtr_base = ((struct dtr *) addr)->base; + TRACE((regs, regs->eip - eip, "lgdt 0x%x <%d, 0x%x>", + addr, oldctx.gdtr_limit, oldctx.gdtr_base)); + + return 1; +} + +/* + * Modify CR0 either through an lmsw instruction. + */ +static int +lmsw(struct regs *regs, unsigned prefix, unsigned modrm) +{ + unsigned eip = regs->eip - 3; + unsigned ax = operand(prefix, regs, modrm) & 0xF; + unsigned cr0 = (oldctx.cr0 & 0xFFFFFFF0) | ax; + + TRACE((regs, regs->eip - eip, "lmsw 0x%x", ax)); +#ifndef TEST + oldctx.cr0 = cr0 | CR0_PE | CR0_NE; +#else + oldctx.cr0 = cr0 | CR0_PE | CR0_NE | CR0_PG; +#endif + if (cr0 & CR0_PE) + set_mode(regs, VM86_REAL_TO_PROTECTED); + + return 1; +} + +/* + * We need to handle moves that address memory beyond the 64KB segment + * limit that VM8086 mode enforces. + */ +static int +movr(struct regs *regs, unsigned prefix, unsigned opc) +{ + unsigned eip = regs->eip - 1; + unsigned modrm = fetch8(regs); + unsigned addr = operand(prefix, regs, modrm); + unsigned val, r = (modrm >> 3) & 7; + + if ((modrm & 0xC0) == 0xC0) /* no registers */ + return 0; + + switch (opc) { + case 0x88: /* addr32 mov r8, r/m8 */ + val = getreg8(regs, r); + TRACE((regs, regs->eip - eip, + "movb %%e%s, *0x%x", rnames[r], addr)); + write8(addr, val); + break; + + case 0x8A: /* addr32 mov r/m8, r8 */ + TRACE((regs, regs->eip - eip, + "movb *0x%x, %%%s", addr, rnames[r])); + setreg8(regs, r, read8(addr)); + break; + + case 0x89: /* addr32 mov r16, r/m16 */ + val = getreg32(regs, r); + if (prefix & DATA32) { + TRACE((regs, regs->eip - eip, + "movl %%e%s, *0x%x", rnames[r], addr)); + write32(addr, val); + } else { + TRACE((regs, regs->eip - eip, + "movw %%%s, *0x%x", rnames[r], addr)); + write16(addr, MASK16(val)); + } + break; + + case 0x8B: /* addr32 mov r/m16, r16 */ + if (prefix & DATA32) { + TRACE((regs, regs->eip - eip, + "movl *0x%x, %%e%s", addr, rnames[r])); + setreg32(regs, r, read32(addr)); + } else { + TRACE((regs, regs->eip - eip, + "movw *0x%x, %%%s", addr, rnames[r])); + setreg16(regs, r, read16(addr)); + } + break; + + case 0xC6: /* addr32 movb $imm, r/m8 */ + if ((modrm >> 3) & 7) + return 0; + val = fetch8(regs); + write8(addr, val); + TRACE((regs, regs->eip - eip, "movb $0x%x, *0x%x", + val, addr)); + break; + } + return 1; +} + +/* + * Move to and from a control register. + */ +static int +movcr(struct regs *regs, unsigned prefix, unsigned opc) +{ + unsigned eip = regs->eip - 2; + unsigned modrm = fetch8(regs); + unsigned cr = (modrm >> 3) & 7; + + if ((modrm & 0xC0) != 0xC0) /* only registers */ + return 0; + + switch (opc) { + case 0x20: /* mov Rd, Cd */ + TRACE((regs, regs->eip - eip, "movl %%cr%d, %%eax", cr)); + switch (cr) { + case 0: +#ifndef TEST + setreg32(regs, modrm, + oldctx.cr0 & ~(CR0_PE | CR0_NE)); +#else + setreg32(regs, modrm, + oldctx.cr0 & ~(CR0_PE | CR0_NE | CR0_PG)); +#endif + break; + case 2: + setreg32(regs, modrm, get_cr2()); + break; + case 3: + setreg32(regs, modrm, oldctx.cr3); + break; + case 4: + setreg32(regs, modrm, oldctx.cr4); + break; + } + break; + case 0x22: /* mov Cd, Rd */ + TRACE((regs, regs->eip - eip, "movl %%eax, %%cr%d", cr)); + switch (cr) { + case 0: + oldctx.cr0 = getreg32(regs, modrm) | (CR0_PE | CR0_NE); +#ifdef TEST + oldctx.cr0 |= CR0_PG; +#endif + if (getreg32(regs, modrm) & CR0_PE) + set_mode(regs, VM86_REAL_TO_PROTECTED); + else + set_mode(regs, VM86_REAL); + break; + case 3: + oldctx.cr3 = getreg32(regs, modrm); + break; + case 4: + oldctx.cr4 = getreg32(regs, modrm); + break; + } + break; + } + + return 1; +} + +static inline void set_eflags_ZF(unsigned mask, unsigned v1, struct regs *regs) +{ + if ((v1 & mask) == 0) + regs->eflags |= EFLAGS_ZF; + else + regs->eflags &= ~EFLAGS_ZF; +} + +/* + * We need to handle cmp opcodes that address memory beyond the 64KB + * segment limit that VM8086 mode enforces. + */ +static int +cmp(struct regs *regs, unsigned prefix, unsigned opc) +{ + unsigned eip = regs->eip - 1; + unsigned modrm = fetch8(regs); + unsigned addr = operand(prefix, regs, modrm); + unsigned diff, val, r = (modrm >> 3) & 7; + + if ((modrm & 0xC0) == 0xC0) /* no registers */ + return 0; + + switch (opc) { + case 0x39: /* addr32 cmp r16, r/m16 */ + val = getreg32(regs, r); + if (prefix & DATA32) { + diff = read32(addr) - val; + set_eflags_ZF(~0, diff, regs); + + TRACE((regs, regs->eip - eip, + "cmp %%e%s, *0x%x (0x%x)", + rnames[r], addr, diff)); + } else { + diff = read16(addr) - val; + set_eflags_ZF(0xFFFF, diff, regs); + + TRACE((regs, regs->eip - eip, + "cmp %%%s, *0x%x (0x%x)", + rnames[r], addr, diff)); + } + break; + + /* other cmp opcodes ... */ + } + return 1; +} + +/* + * We need to handle test opcodes that address memory beyond the 64KB + * segment limit that VM8086 mode enforces. + */ +static int +test(struct regs *regs, unsigned prefix, unsigned opc) +{ + unsigned eip = regs->eip - 1; + unsigned modrm = fetch8(regs); + unsigned addr = operand(prefix, regs, modrm); + unsigned val, diff; + + if ((modrm & 0xC0) == 0xC0) /* no registers */ + return 0; + + switch (opc) { + case 0xF6: /* testb $imm, r/m8 */ + if ((modrm >> 3) & 7) + return 0; + val = fetch8(regs); + diff = read8(addr) & val; + set_eflags_ZF(0xFF, diff, regs); + + TRACE((regs, regs->eip - eip, "testb $0x%x, *0x%x (0x%x)", + val, addr, diff)); + break; + + /* other test opcodes ... */ + } + + return 1; +} + +/* + * We need to handle pop opcodes that address memory beyond the 64KB + * segment limit that VM8086 mode enforces. + */ +static int +pop(struct regs *regs, unsigned prefix, unsigned opc) +{ + unsigned eip = regs->eip - 1; + unsigned modrm = fetch8(regs); + unsigned addr = operand(prefix, regs, modrm); + + if ((modrm & 0xC0) == 0xC0) /* no registers */ + return 0; + + switch (opc) { + case 0x8F: /* pop r/m16 */ + if ((modrm >> 3) & 7) + return 0; + if (prefix & DATA32) + write32(addr, pop32(regs)); + else + write16(addr, pop16(regs)); + TRACE((regs, regs->eip - eip, "pop *0x%x", addr)); + break; + + /* other pop opcodes ... */ + } + + return 1; +} + +/* + * Emulate a segment load in protected mode + */ +static int +load_seg(unsigned long sel, uint32_t *base, uint32_t *limit, union vmcs_arbytes *arbytes) +{ + unsigned long long entry; + + /* protected mode: use seg as index into gdt */ + if (sel > oldctx.gdtr_limit) + return 0; + + if (sel == 0) { + arbytes->fields.null_bit = 1; + return 1; + } + + entry = ((unsigned long long *) + guest_linear_to_real(oldctx.gdtr_base))[sel >> 3]; + + /* Check the P bit first */ + if (!((entry >> (15+32)) & 0x1) && sel != 0) + return 0; + + *base = (((entry >> (56-24)) & 0xFF000000) | + ((entry >> (32-16)) & 0x00FF0000) | + ((entry >> ( 16)) & 0x0000FFFF)); + *limit = (((entry >> (48-16)) & 0x000F0000) | + ((entry ) & 0x0000FFFF)); + + arbytes->bytes = 0; + arbytes->fields.seg_type = (entry >> (8+32)) & 0xF; /* TYPE */ + arbytes->fields.s = (entry >> (12+32)) & 0x1; /* S */ + if (arbytes->fields.s) + arbytes->fields.seg_type |= 1; /* accessed */ + arbytes->fields.dpl = (entry >> (13+32)) & 0x3; /* DPL */ + arbytes->fields.p = (entry >> (15+32)) & 0x1; /* P */ + arbytes->fields.avl = (entry >> (20+32)) & 0x1; /* AVL */ + arbytes->fields.default_ops_size = (entry >> (22+32)) & 0x1; /* D */ + + if (entry & (1ULL << (23+32))) { /* G */ + arbytes->fields.g = 1; + *limit = (*limit << 12) | 0xFFF; + } + + return 1; +} + +/* + * Transition to protected mode + */ +static void +protected_mode(struct regs *regs) +{ + regs->eflags &= ~(EFLAGS_TF|EFLAGS_VM); + + oldctx.eip = regs->eip; + oldctx.esp = regs->uesp; + oldctx.eflags = regs->eflags; + + memset(&saved_rm_regs, 0, sizeof(struct regs)); + + /* reload all segment registers */ + if (!load_seg(regs->cs, &oldctx.cs_base, + &oldctx.cs_limit, &oldctx.cs_arbytes)) + panic("Invalid %%cs=0x%x for protected mode\n", regs->cs); + oldctx.cs_sel = regs->cs; + + if (load_seg(regs->ves, &oldctx.es_base, + &oldctx.es_limit, &oldctx.es_arbytes)) + oldctx.es_sel = regs->ves; + else { + load_seg(0, &oldctx.es_base, + &oldctx.es_limit, &oldctx.es_arbytes); + oldctx.es_sel = 0; + saved_rm_regs.ves = regs->ves; + } + + if (load_seg(regs->uss, &oldctx.ss_base, + &oldctx.ss_limit, &oldctx.ss_arbytes)) + oldctx.ss_sel = regs->uss; + else { + load_seg(0, &oldctx.ss_base, + &oldctx.ss_limit, &oldctx.ss_arbytes); + oldctx.ss_sel = 0; + saved_rm_regs.uss = regs->uss; + } + + if (load_seg(regs->vds, &oldctx.ds_base, + &oldctx.ds_limit, &oldctx.ds_arbytes)) + oldctx.ds_sel = regs->vds; + else { + load_seg(0, &oldctx.ds_base, + &oldctx.ds_limit, &oldctx.ds_arbytes); + oldctx.ds_sel = 0; + saved_rm_regs.vds = regs->vds; + } + + if (load_seg(regs->vfs, &oldctx.fs_base, + &oldctx.fs_limit, &oldctx.fs_arbytes)) + oldctx.fs_sel = regs->vfs; + else { + load_seg(0, &oldctx.fs_base, + &oldctx.fs_limit, &oldctx.fs_arbytes); + oldctx.fs_sel = 0; + saved_rm_regs.vfs = regs->vfs; + } + + if (load_seg(regs->vgs, &oldctx.gs_base, + &oldctx.gs_limit, &oldctx.gs_arbytes)) + oldctx.gs_sel = regs->vgs; + else { + load_seg(0, &oldctx.gs_base, + &oldctx.gs_limit, &oldctx.gs_arbytes); + oldctx.gs_sel = 0; + saved_rm_regs.vgs = regs->vgs; + } + + /* initialize jump environment to warp back to protected mode */ + regs->cs = CODE_SELECTOR; + regs->ds = DATA_SELECTOR; + regs->es = DATA_SELECTOR; + regs->fs = DATA_SELECTOR; + regs->gs = DATA_SELECTOR; + regs->eip = (unsigned) &switch_to_protected_mode; + + /* this should get us into 32-bit mode */ +} + +/* + * Start real-mode emulation + */ +static void +real_mode(struct regs *regs) +{ + regs->eflags |= EFLAGS_VM | 0x02; + regs->ds = DATA_SELECTOR; + regs->es = DATA_SELECTOR; + regs->fs = DATA_SELECTOR; + regs->gs = DATA_SELECTOR; + + /* + * When we transition from protected to real-mode and we + * have not reloaded the segment descriptors yet, they are + * interpreted as if they were in protect mode. + * We emulate this behavior by assuming that these memory + * reference are below 1MB and set %ss, %ds, %es accordingly. + */ + if (regs->uss != 0) { + if (regs->uss >= HIGHMEM) + panic("%%ss 0x%lx higher than 1MB", regs->uss); + regs->uss = address(regs, regs->uss, 0) >> 4; + } else { + regs->uss = saved_rm_regs.uss; + } + if (regs->vds != 0) { + if (regs->vds >= HIGHMEM) + panic("%%ds 0x%lx higher than 1MB", regs->vds); + regs->vds = address(regs, regs->vds, 0) >> 4; + } else { + regs->vds = saved_rm_regs.vds; + } + if (regs->ves != 0) { + if (regs->ves >= HIGHMEM) + panic("%%es 0x%lx higher than 1MB", regs->ves); + regs->ves = address(regs, regs->ves, 0) >> 4; + } else { + regs->ves = saved_rm_regs.ves; + } + + /* this should get us into 16-bit mode */ +} + +/* + * This is the smarts of the emulator and handles the mode transitions. The + * emulator handles 4 different modes. 1) VM86_REAL: emulated real-mode, + * Just handle those instructions that are not supported under VM8086. + * 2) VM86_REAL_TO_PROTECTED: going from real-mode to protected mode. In + * this we single step through the instructions until we reload the + * new %cs (some OSes do a lot of computations before reloading %cs). 2) + * VM86_PROTECTED_TO_REAL when we are going from protected to real mode. In + * this case we emulate the instructions by hand. Finally, 4) VM86_PROTECTED + * when we transitioned to protected mode and we should abandon the + * emulator. No instructions are emulated when in VM86_PROTECTED mode. + */ +void +set_mode(struct regs *regs, enum vm86_mode newmode) +{ + switch (newmode) { + case VM86_REAL: + if ((mode == VM86_PROTECTED_TO_REAL) || + (mode == VM86_REAL_TO_PROTECTED)) { + regs->eflags &= ~EFLAGS_TF; + real_mode(regs); + break; + } else if (mode == VM86_REAL) { + break; + } else + panic("unexpected real mode transition"); + break; + + case VM86_REAL_TO_PROTECTED: + if (mode == VM86_REAL) { + regs->eflags |= EFLAGS_TF; + break; + } else if (mode == VM86_REAL_TO_PROTECTED) { + break; + } else + panic("unexpected real-to-protected mode transition"); + break; + + case VM86_PROTECTED_TO_REAL: + if (mode == VM86_PROTECTED) { + break; + } else + panic("unexpected protected-to-real mode transition"); + break; + + case VM86_PROTECTED: + if (mode == VM86_REAL_TO_PROTECTED) { + protected_mode(regs); +// printf("\n"); + mode = newmode; + return; + } else + panic("unexpected protected mode transition"); + break; + } + + mode = newmode; + TRACE((regs, 0, states[mode])); +} + +static void +jmpl(struct regs *regs, int prefix) +{ + unsigned n = regs->eip; + unsigned cs, eip; + + if (mode == VM86_REAL_TO_PROTECTED) { /* jump to protected mode */ + eip = (prefix & DATA32) ? fetch32(regs) : fetch16(regs); + cs = fetch16(regs); + + TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip)); + + regs->cs = cs; + regs->eip = eip; + set_mode(regs, VM86_PROTECTED); + } else if (mode == VM86_PROTECTED_TO_REAL) { /* jump to real mode */ + eip = (prefix & DATA32) ? fetch32(regs) : fetch16(regs); + cs = fetch16(regs); + + TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip)); + + regs->cs = cs; + regs->eip = eip; + set_mode(regs, VM86_REAL); + } else + panic("jmpl"); +} + +static void +jmpl_indirect(struct regs *regs, int prefix, unsigned modrm) +{ + unsigned n = regs->eip; + unsigned cs, eip; + unsigned addr; + + addr = operand(prefix, regs, modrm); + + if (mode == VM86_REAL_TO_PROTECTED) { /* jump to protected mode */ + eip = (prefix & DATA32) ? read32(addr) : read16(addr); + addr += (prefix & DATA32) ? 4 : 2; + cs = read16(addr); + + TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip)); + + regs->cs = cs; + regs->eip = eip; + set_mode(regs, VM86_PROTECTED); + } else if (mode == VM86_PROTECTED_TO_REAL) { /* jump to real mode */ + eip = (prefix & DATA32) ? read32(addr) : read16(addr); + addr += (prefix & DATA32) ? 4 : 2; + cs = read16(addr); + + TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip)); + + regs->cs = cs; + regs->eip = eip; + set_mode(regs, VM86_REAL); + } else + panic("jmpl"); +} + +static void +retl(struct regs *regs, int prefix) +{ + unsigned cs, eip; + + if (prefix & DATA32) { + eip = pop32(regs); + cs = MASK16(pop32(regs)); + } else { + eip = pop16(regs); + cs = pop16(regs); + } + + TRACE((regs, 1, "retl (to 0x%x:0x%x)", cs, eip)); + + if (mode == VM86_REAL_TO_PROTECTED) { /* jump to protected mode */ + regs->cs = cs; + regs->eip = eip; + set_mode(regs, VM86_PROTECTED); + } else if (mode == VM86_PROTECTED_TO_REAL) { /* jump to real mode */ + regs->cs = cs; + regs->eip = eip; + set_mode(regs, VM86_REAL); + } else + panic("retl"); +} + +static void +interrupt(struct regs *regs, int n) +{ + TRACE((regs, 0, "external interrupt %d", n)); + push16(regs, regs->eflags); + push16(regs, regs->cs); + push16(regs, regs->eip); + regs->eflags &= ~EFLAGS_IF; + regs->eip = read16(address(regs, 0, n * 4)); + regs->cs = read16(address(regs, 0, n * 4 + 2)); +} + +/* + * Most port I/O operations are passed unmodified. We do have to be + * careful and make sure the emulated program isn't remapping the + * interrupt vectors. The following simple state machine catches + * these attempts and rewrites them. + */ +static int +outbyte(struct regs *regs, unsigned prefix, unsigned opc) +{ + static char icw2[2] = { 0 }; + int al, port; + + switch (opc) { + case 0xE6: /* outb port, al */ + port = fetch8(regs); + break; + case 0xEE: /* outb (%dx), al */ + port = MASK16(regs->edx); + break; + default: + return 0; + } + + al = regs->eax & 0xFF; + + switch (port) { + case PIC_MASTER + PIC_CMD: + if (al & (1 << 4)) /* A0=0,D4=1 -> ICW1 */ + icw2[0] = 1; + break; + case PIC_MASTER + PIC_IMR: + if (icw2[0]) { + icw2[0] = 0; + printf("Remapping master: ICW2 0x%x -> 0x%x\n", + al, NR_EXCEPTION_HANDLER); + al = NR_EXCEPTION_HANDLER; + } + break; + + case PIC_SLAVE + PIC_CMD: + if (al & (1 << 4)) /* A0=0,D4=1 -> ICW1 */ + icw2[1] = 1; + break; + case PIC_SLAVE + PIC_IMR: + if (icw2[1]) { + icw2[1] = 0; + printf("Remapping slave: ICW2 0x%x -> 0x%x\n", + al, NR_EXCEPTION_HANDLER+8); + al = NR_EXCEPTION_HANDLER+8; + } + break; + } + + outb(port, al); + return 1; +} + +static int +inbyte(struct regs *regs, unsigned prefix, unsigned opc) +{ + int port; + + switch (opc) { + case 0xE4: /* inb al, port */ + port = fetch8(regs); + break; + case 0xEC: /* inb al, (%dx) */ + port = MASK16(regs->edx); + break; + default: + return 0; + } + + regs->eax = (regs->eax & ~0xFF) | inb(port); + return 1; +} + +static void +pushrm(struct regs *regs, int prefix, unsigned modrm) +{ + unsigned n = regs->eip; + unsigned addr; + unsigned data; + + addr = operand(prefix, regs, modrm); + + if (prefix & DATA32) { + data = read32(addr); + push32(regs, data); + } else { + data = read16(addr); + push16(regs, data); + } + + TRACE((regs, (regs->eip - n) + 1, "push *0x%x", addr)); +} + +enum { OPC_INVALID, OPC_EMULATED }; + +#define rdmsr(msr,val1,val2) \ + __asm__ __volatile__( \ + "rdmsr" \ + : "=a" (val1), "=d" (val2) \ + : "c" (msr)) + +#define wrmsr(msr,val1,val2) \ + __asm__ __volatile__( \ + "wrmsr" \ + : /* no outputs */ \ + : "c" (msr), "a" (val1), "d" (val2)) + +/* + * Emulate a single instruction, including all its prefixes. We only implement + * a small subset of the opcodes, and not all opcodes are implemented for each + * of the four modes we can operate in. + */ +static int +opcode(struct regs *regs) +{ + unsigned eip = regs->eip; + unsigned opc, modrm, disp; + unsigned prefix = 0; + + for (;;) { + switch ((opc = fetch8(regs))) { + case 0x07: + if (prefix & DATA32) + regs->ves = pop32(regs); + else + regs->ves = pop16(regs); + TRACE((regs, regs->eip - eip, "pop %%es")); + return OPC_EMULATED; + + case 0x0F: /* two byte opcode */ + if (mode == VM86_PROTECTED) + goto invalid; + switch ((opc = fetch8(regs))) { + case 0x01: + switch (((modrm = fetch8(regs)) >> 3) & 7) { + case 0: /* sgdt */ + case 1: /* sidt */ + goto invalid; + case 2: /* lgdt */ + if (!lgdt(regs, prefix, modrm)) + goto invalid; + return OPC_EMULATED; + case 3: /* lidt */ + if (!lidt(regs, prefix, modrm)) + goto invalid; + return OPC_EMULATED; + case 4: /* smsw */ + goto invalid; + case 5: + goto invalid; + case 6: /* lmsw */ + if (!lmsw(regs, prefix, modrm)) + goto invalid; + return OPC_EMULATED; + case 7: /* invlpg */ + goto invalid; + } + break; + case 0x09: /* wbinvd */ + return OPC_EMULATED; + case 0x20: /* mov Rd, Cd (1h) */ + case 0x22: + if (!movcr(regs, prefix, opc)) + goto invalid; + return OPC_EMULATED; + case 0x30: /* WRMSR */ + wrmsr(regs->ecx, regs->eax, regs->edx); + return OPC_EMULATED; + case 0x32: /* RDMSR */ + rdmsr(regs->ecx, regs->eax, regs->edx); + return OPC_EMULATED; + default: + goto invalid; + } + goto invalid; + + case 0x26: + TRACE((regs, regs->eip - eip, "%%es:")); + prefix |= SEG_ES; + continue; + + case 0x2E: + TRACE((regs, regs->eip - eip, "%%cs:")); + prefix |= SEG_CS; + continue; + + case 0x36: + TRACE((regs, regs->eip - eip, "%%ss:")); + prefix |= SEG_SS; + continue; + + case 0x39: /* addr32 cmp r16, r/m16 */ + case 0x3B: /* addr32 cmp r/m16, r16 */ + if (mode != VM86_REAL && mode != VM86_REAL_TO_PROTECTED) + goto invalid; + if ((prefix & ADDR32) == 0) + goto invalid; + if (!cmp(regs, prefix, opc)) + goto invalid; + return OPC_EMULATED; + + case 0x3E: + TRACE((regs, regs->eip - eip, "%%ds:")); + prefix |= SEG_DS; + continue; + + case 0x64: + TRACE((regs, regs->eip - eip, "%%fs:")); + prefix |= SEG_FS; + continue; + + case 0x65: + TRACE((regs, regs->eip - eip, "%%gs:")); + prefix |= SEG_GS; + continue; + + case 0x66: + TRACE((regs, regs->eip - eip, "data32")); + prefix |= DATA32; + continue; + + case 0x67: + TRACE((regs, regs->eip - eip, "addr32")); + prefix |= ADDR32; + continue; + + case 0x88: /* addr32 mov r8, r/m8 */ + case 0x8A: /* addr32 mov r/m8, r8 */ + if (mode != VM86_REAL && mode != VM86_REAL_TO_PROTECTED) + goto invalid; + if ((prefix & ADDR32) == 0) + goto invalid; + if (!movr(regs, prefix, opc)) + goto invalid; + return OPC_EMULATED; + + case 0x89: /* addr32 mov r16, r/m16 */ + if (mode == VM86_PROTECTED_TO_REAL) { + unsigned modrm = fetch8(regs); + unsigned addr = operand(prefix, regs, modrm); + unsigned val, r = (modrm >> 3) & 7; + + if (prefix & DATA32) { + val = getreg16(regs, r); + write32(addr, val); + } else { + val = getreg32(regs, r); + write16(addr, MASK16(val)); + } + TRACE((regs, regs->eip - eip, + "mov %%%s, *0x%x", rnames[r], addr)); + return OPC_EMULATED; + } + case 0x8B: /* addr32 mov r/m16, r16 */ + if (mode != VM86_REAL && mode != VM86_REAL_TO_PROTECTED) + goto invalid; + if ((prefix & ADDR32) == 0) + goto invalid; + if (!movr(regs, prefix, opc)) + goto invalid; + return OPC_EMULATED; + + case 0x8F: /* addr32 pop r/m16 */ + if ((prefix & ADDR32) == 0) + goto invalid; + if (!pop(regs, prefix, opc)) + goto invalid; + return OPC_EMULATED; + + case 0x90: /* nop */ + TRACE((regs, regs->eip - eip, "nop")); + return OPC_EMULATED; + + case 0x9C: /* pushf */ + TRACE((regs, regs->eip - eip, "pushf")); + if (prefix & DATA32) + push32(regs, regs->eflags & ~EFLAGS_VM); + else + push16(regs, regs->eflags & ~EFLAGS_VM); + return OPC_EMULATED; + + case 0x9D: /* popf */ + TRACE((regs, regs->eip - eip, "popf")); + if (prefix & DATA32) + regs->eflags = pop32(regs); + else + regs->eflags = (regs->eflags & 0xFFFF0000L) | + pop16(regs); + regs->eflags |= EFLAGS_VM; + return OPC_EMULATED; + + case 0xA1: /* mov ax, r/m16 */ + { + int addr, data; + int seg = segment(prefix, regs, regs->vds); + int offset = prefix & ADDR32? fetch32(regs) : fetch16(regs); + + if (prefix & DATA32) { + addr = address(regs, seg, offset); + data = read32(addr); + setreg32(regs, 0, data); + } else { + addr = address(regs, seg, offset); + data = read16(addr); + setreg16(regs, 0, data); + } + TRACE((regs, regs->eip - eip, "mov *0x%x, %%ax", addr)); + } + return OPC_EMULATED; + + case 0xBB: /* mov bx, imm16 */ + { + int data; + if (prefix & DATA32) { + data = fetch32(regs); + setreg32(regs, 3, data); + } else { + data = fetch16(regs); + setreg16(regs, 3, data); + } + TRACE((regs, regs->eip - eip, "mov $0x%x, %%bx", data)); + } + return OPC_EMULATED; + + case 0xC6: /* addr32 movb $imm, r/m8 */ + if ((prefix & ADDR32) == 0) + goto invalid; + if (!movr(regs, prefix, opc)) + goto invalid; + return OPC_EMULATED; + + case 0xCB: /* retl */ + if ((mode == VM86_REAL_TO_PROTECTED) || + (mode == VM86_PROTECTED_TO_REAL)) { + retl(regs, prefix); + return OPC_INVALID; + } + goto invalid; + + case 0xCD: /* int $n */ + TRACE((regs, regs->eip - eip, "int")); + interrupt(regs, fetch8(regs)); + return OPC_EMULATED; + + case 0xCF: /* iret */ + if (prefix & DATA32) { + TRACE((regs, regs->eip - eip, "data32 iretd")); + regs->eip = pop32(regs); + regs->cs = pop32(regs); + regs->eflags = pop32(regs); + } else { + TRACE((regs, regs->eip - eip, "iret")); + regs->eip = pop16(regs); + regs->cs = pop16(regs); + regs->eflags = (regs->eflags & 0xFFFF0000L) | + pop16(regs); + } + return OPC_EMULATED; + + case 0xE4: /* inb al, port */ + if (!inbyte(regs, prefix, opc)) + goto invalid; + return OPC_EMULATED; + + case 0xE6: /* outb port, al */ + if (!outbyte(regs, prefix, opc)) + goto invalid; + return OPC_EMULATED; + + case 0xEA: /* jmpl */ + if ((mode == VM86_REAL_TO_PROTECTED) || + (mode == VM86_PROTECTED_TO_REAL)) { + jmpl(regs, prefix); + return OPC_INVALID; + } + goto invalid; + + case 0xFF: /* jmpl (indirect) */ + { + unsigned modrm = fetch8(regs); + switch((modrm >> 3) & 7) { + case 5: /* jmpl (indirect) */ + if ((mode == VM86_REAL_TO_PROTECTED) || + (mode == VM86_PROTECTED_TO_REAL)) { + jmpl_indirect(regs, prefix, modrm); + return OPC_INVALID; + } + goto invalid; + + case 6: /* push r/m16 */ + pushrm(regs, prefix, modrm); + return OPC_EMULATED; + + default: + goto invalid; + } + } + + case 0xEB: /* short jump */ + if ((mode == VM86_REAL_TO_PROTECTED) || + (mode == VM86_PROTECTED_TO_REAL)) { + disp = (char) fetch8(regs); + TRACE((regs, 2, "jmp 0x%x", regs->eip + disp)); + regs->eip += disp; + return OPC_EMULATED; + } + goto invalid; + + case 0xEC: /* inb al, (%dx) */ + if (!inbyte(regs, prefix, opc)) + goto invalid; + return OPC_EMULATED; + + case 0xEE: /* outb (%dx), al */ + if (!outbyte(regs, prefix, opc)) + goto invalid; + return OPC_EMULATED; + + case 0xF0: /* lock */ + TRACE((regs, regs->eip - eip, "lock")); + continue; + + case 0xF6: /* addr32 testb $imm, r/m8 */ + if ((prefix & ADDR32) == 0) + goto invalid; + if (!test(regs, prefix, opc)) + goto invalid; + return OPC_EMULATED; + + case 0xFA: /* cli */ + TRACE((regs, regs->eip - eip, "cli")); + regs->eflags &= ~EFLAGS_IF; + return OPC_EMULATED; + + case 0xFB: /* sti */ + TRACE((regs, regs->eip - eip, "sti")); + regs->eflags |= EFLAGS_IF; + return OPC_EMULATED; + + default: + goto invalid; + } + } + +invalid: + regs->eip = eip; + TRACE((regs, regs->eip - eip, "opc 0x%x", opc)); + return OPC_INVALID; +} + +void +emulate(struct regs *regs) +{ + unsigned flteip; + int nemul = 0; + + /* emulate as many instructions as possible */ + while (opcode(regs) != OPC_INVALID) + nemul++; + + /* detect the case where we are not making progress */ + if (nemul == 0 && prev_eip == regs->eip) { + flteip = address(regs, MASK16(regs->cs), regs->eip); + panic("Unknown opcode at %04x:%04x=0x%x", + MASK16(regs->cs), regs->eip, flteip); + } else + prev_eip = regs->eip; +} + +void +trap(int trapno, int errno, struct regs *regs) +{ + /* emulate device interrupts */ + if (trapno >= NR_EXCEPTION_HANDLER) { + int irq = trapno - NR_EXCEPTION_HANDLER; + if (irq < 8) + interrupt(regs, irq + 8); + else + interrupt(regs, 0x70 + (irq - 8)); + return; + } + + switch (trapno) { + case 1: /* Debug */ + if (regs->eflags & EFLAGS_VM) { + /* emulate any 8086 instructions */ + if (mode != VM86_REAL_TO_PROTECTED) + panic("not in real-to-protected mode"); + emulate(regs); + return; + } + goto invalid; + + case 13: /* GPF */ + if (regs->eflags & EFLAGS_VM) { + /* emulate any 8086 instructions */ + if (mode == VM86_PROTECTED) + panic("unexpected protected mode"); + emulate(regs); + return; + } + goto invalid; + + default: + invalid: + printf("Trap (0x%x) while in %s mode\n", + trapno, regs->eflags & EFLAGS_VM ? "real" : "protected"); + if (trapno == 14) + printf("Page fault address 0x%x\n", get_cr2()); + dump_regs(regs); + halt(); + } +} diff --git a/palacios/src/vmboot/vmxassist/vm86.h b/palacios/src/vmboot/vmxassist/vm86.h new file mode 100644 index 0000000..e0997e4 --- /dev/null +++ b/palacios/src/vmboot/vmxassist/vm86.h @@ -0,0 +1,70 @@ +/* + * vm86.h: vm86 emulator definitions. + * + * Leendert van Doorn, leendert@watson.ibm.com + * Copyright (c) 2005, International Business Machines Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __VM86_H__ +#define __VM86_H__ + +#ifndef __ASSEMBLY__ +#include +#endif + +#include "vmx_assist.h" + +#define NR_EXCEPTION_HANDLER 32 +#define NR_INTERRUPT_HANDLERS 16 +#define NR_TRAPS (NR_EXCEPTION_HANDLER+NR_INTERRUPT_HANDLERS) + +#ifndef __ASSEMBLY__ + +struct regs { + unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax; + unsigned ds, es, fs, gs; + unsigned trapno, errno; + unsigned eip, cs, eflags, uesp, uss; + unsigned ves, vds, vfs, vgs; +}; + +enum vm86_mode { + VM86_REAL = 0, + VM86_REAL_TO_PROTECTED, + VM86_PROTECTED_TO_REAL, + VM86_PROTECTED +}; + +#ifdef DEBUG +#define TRACE(a) trace a +#else +#define TRACE(a) +#endif + +extern enum vm86_mode prevmode, mode; +extern struct vmx_assist_context oldctx; +extern struct vmx_assist_context newctx; + +extern void emulate(struct regs *); +extern void dump_regs(struct regs *); +extern void trace(struct regs *, int, char *, ...); + +extern void set_mode(struct regs *, enum vm86_mode); +extern void switch_to_real_mode(void); +extern void switch_to_protected_mode(void); + +#endif /* __ASSEMBLY__ */ + +#endif /* __VM86_H__ */ diff --git a/palacios/src/vmboot/vmxassist/vmx_assist.h b/palacios/src/vmboot/vmxassist/vmx_assist.h new file mode 100644 index 0000000..f987b0f --- /dev/null +++ b/palacios/src/vmboot/vmxassist/vmx_assist.h @@ -0,0 +1,98 @@ +/* + * vmx_assist.h: Context definitions for the VMXASSIST world switch. + * + * Leendert van Doorn, leendert@watson.ibm.com + * Copyright (c) 2005, International Business Machines Corporation. + */ + +#ifndef _VMX_ASSIST_H_ +#define _VMX_ASSIST_H_ + +#define VMXASSIST_BASE 0xD0000 +#define VMXASSIST_MAGIC 0x17101966 +#define VMXASSIST_MAGIC_OFFSET (VMXASSIST_BASE+8) + +#define VMXASSIST_NEW_CONTEXT (VMXASSIST_BASE + 12) +#define VMXASSIST_OLD_CONTEXT (VMXASSIST_NEW_CONTEXT + 4) + +#ifndef __ASSEMBLY__ + +union vmcs_arbytes { + struct arbyte_fields { + unsigned int seg_type : 4, + s : 1, + dpl : 2, + p : 1, + reserved0 : 4, + avl : 1, + reserved1 : 1, + default_ops_size: 1, + g : 1, + null_bit : 1, + reserved2 : 15; + } fields; + unsigned int bytes; +}; + +/* + * World switch state + */ +struct vmx_assist_context { + uint32_t eip; /* execution pointer */ + uint32_t esp; /* stack pointer */ + uint32_t eflags; /* flags register */ + uint32_t cr0; + uint32_t cr3; /* page table directory */ + uint32_t cr4; + uint32_t idtr_limit; /* idt */ + uint32_t idtr_base; + uint32_t gdtr_limit; /* gdt */ + uint32_t gdtr_base; + uint32_t cs_sel; /* cs selector */ + uint32_t cs_limit; + uint32_t cs_base; + union vmcs_arbytes cs_arbytes; + uint32_t ds_sel; /* ds selector */ + uint32_t ds_limit; + uint32_t ds_base; + union vmcs_arbytes ds_arbytes; + uint32_t es_sel; /* es selector */ + uint32_t es_limit; + uint32_t es_base; + union vmcs_arbytes es_arbytes; + uint32_t ss_sel; /* ss selector */ + uint32_t ss_limit; + uint32_t ss_base; + union vmcs_arbytes ss_arbytes; + uint32_t fs_sel; /* fs selector */ + uint32_t fs_limit; + uint32_t fs_base; + union vmcs_arbytes fs_arbytes; + uint32_t gs_sel; /* gs selector */ + uint32_t gs_limit; + uint32_t gs_base; + union vmcs_arbytes gs_arbytes; + uint32_t tr_sel; /* task selector */ + uint32_t tr_limit; + uint32_t tr_base; + union vmcs_arbytes tr_arbytes; + uint32_t ldtr_sel; /* ldtr selector */ + uint32_t ldtr_limit; + uint32_t ldtr_base; + union vmcs_arbytes ldtr_arbytes; +}; +typedef struct vmx_assist_context vmx_assist_context_t; + +#endif /* __ASSEMBLY__ */ + +#endif /* _VMX_ASSIST_H_ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/palacios/src/vmboot/vmxassist/vmxassist.ld b/palacios/src/vmboot/vmxassist/vmxassist.ld new file mode 100644 index 0000000..088519b --- /dev/null +++ b/palacios/src/vmboot/vmxassist/vmxassist.ld @@ -0,0 +1,32 @@ +/* + * vmxassist.ld + */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +ENTRY(_start) + +SECTIONS +{ + _btext = .; + .text TEXTADDR : + { + *(.text) + *(.rodata) + *(.rodata.*) + } + _etext = .; + + _bdata = .; + .data : + { + *(.data) + } + _edata = .; + + _bbss = .; + .bss : + { + *(.bss) + } + _ebss = .; +} + diff --git a/utils/binutils-2.16.91.0.7.tar.gz b/utils/binutils-2.16.91.0.7.tar.gz new file mode 100644 index 0000000..32209e2 Binary files /dev/null and b/utils/binutils-2.16.91.0.7.tar.gz differ diff --git a/utils/nasm-0.98.39.tar.gz b/utils/nasm-0.98.39.tar.gz new file mode 100644 index 0000000..303daa8 Binary files /dev/null and b/utils/nasm-0.98.39.tar.gz differ diff --git a/utils/vmx.patch b/utils/vmx.patch new file mode 100644 index 0000000..8bbb471 --- /dev/null +++ b/utils/vmx.patch @@ -0,0 +1,41 @@ +Index: insns.dat +=================================================================== +RCS file: /home/jarusl/nasm-0.98.39-vmx/insns.dat +retrieving revision 1.46 +diff -u -p -w -r1.46 insns.dat +--- insns.dat 2 Sep 2003 21:38:48 -0000 1.46 ++++ insns.dat 28 Feb 2006 00:43:59 -0000 +@@ -1673,3 +1673,17 @@ MOVSHDUP xmmreg,mem \301\3\xF3\x0F\x16\ + MOVSHDUP xmmreg,xmmreg \3\xF3\x0F\x16\110 PRESCOTT,SSE3 + MOVSLDUP xmmreg,mem \301\3\xF3\x0F\x12\110 PRESCOTT,SSE3 + MOVSLDUP xmmreg,xmmreg \3\xF3\x0F\x12\110 PRESCOTT,SSE3 ++ ++; VMX Instructions ++VMCALL void \3\x0F\x01\xC1 VMX ++VMCLEAR mem \3\x66\x0F\xC7\206 VMX ++VMLAUNCH void \3\x0F\x01\xC2 VMX ++VMPTRLD mem \2\x0F\xC7\206 VMX ++VMPTRST mem \2\x0F\xC7\207 VMX ++VMREAD mem,reg32 \2\x0F\x78\101 VMX ++VMREAD reg32,reg32 \2\x0F\x78\101 VMX ++VMRESUME void \3\x0F\x01\xC3 VMX ++VMWRITE reg32,mem \2\x0F\x79\110 VMX ++VMWRITE reg32,reg32 \2\x0F\x79\110 VMX ++VMXOFF void \3\x0F\x01\xC4 VMX ++VMXON mem \3\xF3\x0F\xC7\206 VMX +Index: insns.h +=================================================================== +RCS file: /home/jarusl/nasm-0.98.39-vmx/insns.h +retrieving revision 1.31 +diff -u -p -w -r1.31 insns.h +--- insns.h 15 Jan 2005 22:15:51 -0000 1.31 ++++ insns.h 28 Feb 2006 00:43:59 -0000 +@@ -78,6 +78,7 @@ struct itemplate { + #define IF_SSE 0x00010000UL /* it's a SSE (KNI, MMX2) instruction */ + #define IF_SSE2 0x00020000UL /* it's a SSE2 instruction */ + #define IF_SSE3 0x00040000UL /* it's a SSE3 (PNI) instruction */ ++#define IF_VMX 0x00080000UL /* it's a VMX instruction */ + #define IF_PMASK 0xFF000000UL /* the mask for processor types */ + #define IF_PLEVEL 0x0F000000UL /* the mask for processor instr. level */ + /* also the highest possible processor */ +