Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Initial revision
Peter Dinda [Thu, 29 Nov 2007 20:26:38 +0000 (20:26 +0000)]
145 files changed:
palacios/COPYING.geekos [new file with mode: 0644]
palacios/LICENSE-klibc.geekos [new file with mode: 0644]
palacios/README [new file with mode: 0644]
palacios/build/.bochsrc [new file with mode: 0644]
palacios/build/Makefile [new file with mode: 0644]
palacios/build/common/.ignore [new file with mode: 0644]
palacios/build/depend.mak [new file with mode: 0644]
palacios/build/geekos/.ignore [new file with mode: 0644]
palacios/build/libc/.ignore [new file with mode: 0644]
palacios/build/noboot.img [new file with mode: 0644]
palacios/build/tools/.ignore [new file with mode: 0644]
palacios/build/user/.ignore [new file with mode: 0644]
palacios/include/geekos/argblock.h [new file with mode: 0644]
palacios/include/geekos/bget.h [new file with mode: 0644]
palacios/include/geekos/bootinfo.h [new file with mode: 0644]
palacios/include/geekos/crc32.h [new file with mode: 0644]
palacios/include/geekos/defs.h [new file with mode: 0644]
palacios/include/geekos/errno.h [new file with mode: 0644]
palacios/include/geekos/fmtout.h [new file with mode: 0644]
palacios/include/geekos/gdt.h [new file with mode: 0644]
palacios/include/geekos/idt.h [new file with mode: 0644]
palacios/include/geekos/int.h [new file with mode: 0644]
palacios/include/geekos/io.h [new file with mode: 0644]
palacios/include/geekos/io_devs.h [new file with mode: 0644]
palacios/include/geekos/irq.h [new file with mode: 0644]
palacios/include/geekos/kassert.h [new file with mode: 0644]
palacios/include/geekos/keyboard.h [new file with mode: 0644]
palacios/include/geekos/kthread.h [new file with mode: 0644]
palacios/include/geekos/ktypes.h [new file with mode: 0644]
palacios/include/geekos/list.h [new file with mode: 0644]
palacios/include/geekos/malloc.h [new file with mode: 0644]
palacios/include/geekos/mem.h [new file with mode: 0644]
palacios/include/geekos/paging.h [new file with mode: 0644]
palacios/include/geekos/range.h [new file with mode: 0644]
palacios/include/geekos/reboot.h [new file with mode: 0644]
palacios/include/geekos/screen.h [new file with mode: 0644]
palacios/include/geekos/segment.h [new file with mode: 0644]
palacios/include/geekos/serial.h [new file with mode: 0644]
palacios/include/geekos/string.h [new file with mode: 0644]
palacios/include/geekos/symbol.h [new file with mode: 0644]
palacios/include/geekos/synch.h [new file with mode: 0644]
palacios/include/geekos/timer.h [new file with mode: 0644]
palacios/include/geekos/trap.h [new file with mode: 0644]
palacios/include/geekos/tss.h [new file with mode: 0644]
palacios/include/geekos/vmcs.h [new file with mode: 0644]
palacios/include/geekos/vmcs_gen.h [new file with mode: 0644]
palacios/include/geekos/vmm_sizes.h [new file with mode: 0644]
palacios/include/geekos/vmx.h [new file with mode: 0644]
palacios/include/libc/fmtout.h [new file with mode: 0644]
palacios/include/libc/string.h [new file with mode: 0644]
palacios/scripts/eipToFunction [new file with mode: 0755]
palacios/scripts/findaddr [new file with mode: 0755]
palacios/scripts/generate_vmcs_serialization.pl [new file with mode: 0755]
palacios/scripts/generrs [new file with mode: 0755]
palacios/scripts/kerninfo [new file with mode: 0755]
palacios/scripts/mkcdisk [new file with mode: 0755]
palacios/scripts/mkuprog [new file with mode: 0755]
palacios/scripts/numsecs [new file with mode: 0755]
palacios/scripts/pad [new file with mode: 0755]
palacios/scripts/pcat [new file with mode: 0755]
palacios/scripts/pw [new file with mode: 0755]
palacios/scripts/scan [new file with mode: 0755]
palacios/scripts/vmcs_entries_to_asm.pl [new file with mode: 0755]
palacios/scripts/zerofile [new file with mode: 0755]
palacios/src/common/fmtout.c [new file with mode: 0644]
palacios/src/common/memmove.c [new file with mode: 0644]
palacios/src/common/string.c [new file with mode: 0644]
palacios/src/geekos/README.txt [new file with mode: 0644]
palacios/src/geekos/bget.c [new file with mode: 0644]
palacios/src/geekos/bootsect.asm [new file with mode: 0644]
palacios/src/geekos/crc32.c [new file with mode: 0644]
palacios/src/geekos/defs.asm [new file with mode: 0644]
palacios/src/geekos/depend.mak [new file with mode: 0644]
palacios/src/geekos/fd_boot.asm [new file with mode: 0644]
palacios/src/geekos/gdt.c [new file with mode: 0644]
palacios/src/geekos/idt.c [new file with mode: 0644]
palacios/src/geekos/int.c [new file with mode: 0644]
palacios/src/geekos/io.c [new file with mode: 0644]
palacios/src/geekos/irq.c [new file with mode: 0644]
palacios/src/geekos/keyboard.c [new file with mode: 0644]
palacios/src/geekos/kthread.c [new file with mode: 0644]
palacios/src/geekos/lowlevel.asm [new file with mode: 0644]
palacios/src/geekos/main.c [new file with mode: 0644]
palacios/src/geekos/malloc.c [new file with mode: 0644]
palacios/src/geekos/mem.c [new file with mode: 0644]
palacios/src/geekos/paging.c [new file with mode: 0644]
palacios/src/geekos/reboot.c [new file with mode: 0644]
palacios/src/geekos/screen.c [new file with mode: 0644]
palacios/src/geekos/segment.c [new file with mode: 0644]
palacios/src/geekos/serial.c [new file with mode: 0644]
palacios/src/geekos/setup.asm [new file with mode: 0644]
palacios/src/geekos/show_sizes.c [new file with mode: 0644]
palacios/src/geekos/symbol.asm [new file with mode: 0644]
palacios/src/geekos/synch.c [new file with mode: 0644]
palacios/src/geekos/testvm.s [new file with mode: 0644]
palacios/src/geekos/timer.c [new file with mode: 0644]
palacios/src/geekos/trap.c [new file with mode: 0644]
palacios/src/geekos/tss.c [new file with mode: 0644]
palacios/src/geekos/util.asm [new file with mode: 0644]
palacios/src/geekos/vmcs.c [new file with mode: 0644]
palacios/src/geekos/vmcs_fields.asm [new file with mode: 0644]
palacios/src/geekos/vmcs_gen.c [new file with mode: 0644]
palacios/src/geekos/vmx.c [new file with mode: 0644]
palacios/src/geekos/vmx_lowlevel.asm [new file with mode: 0644]
palacios/src/libc/compat.c [new file with mode: 0644]
palacios/src/vmboot/rombios/Makefile [new file with mode: 0644]
palacios/src/vmboot/rombios/apmbios.S [new file with mode: 0644]
palacios/src/vmboot/rombios/biossums.c [new file with mode: 0644]
palacios/src/vmboot/rombios/makesym.perl [new file with mode: 0755]
palacios/src/vmboot/rombios/rombios.c [new file with mode: 0644]
palacios/src/vmboot/vgabios/BUGS [new file with mode: 0644]
palacios/src/vmboot/vgabios/COPYING [new file with mode: 0644]
palacios/src/vmboot/vgabios/ChangeLog [new file with mode: 0644]
palacios/src/vmboot/vgabios/Makefile [new file with mode: 0644]
palacios/src/vmboot/vgabios/Notes [new file with mode: 0644]
palacios/src/vmboot/vgabios/README [new file with mode: 0644]
palacios/src/vmboot/vgabios/TODO [new file with mode: 0644]
palacios/src/vmboot/vgabios/biossums.c [new file with mode: 0644]
palacios/src/vmboot/vgabios/clext.c [new file with mode: 0644]
palacios/src/vmboot/vgabios/dataseghack [new file with mode: 0755]
palacios/src/vmboot/vgabios/vbe.c [new file with mode: 0644]
palacios/src/vmboot/vgabios/vbe.h [new file with mode: 0644]
palacios/src/vmboot/vgabios/vbe_display_api.txt [new file with mode: 0644]
palacios/src/vmboot/vgabios/vbetables.h [new file with mode: 0644]
palacios/src/vmboot/vgabios/vgabios.c [new file with mode: 0644]
palacios/src/vmboot/vgabios/vgabios.h [new file with mode: 0644]
palacios/src/vmboot/vgabios/vgafonts.h [new file with mode: 0644]
palacios/src/vmboot/vgabios/vgatables.h [new file with mode: 0644]
palacios/src/vmboot/vmxassist/Makefile [new file with mode: 0644]
palacios/src/vmboot/vmxassist/e820.h [new file with mode: 0644]
palacios/src/vmboot/vmxassist/gen.c [new file with mode: 0644]
palacios/src/vmboot/vmxassist/head.S [new file with mode: 0644]
palacios/src/vmboot/vmxassist/machine.h [new file with mode: 0644]
palacios/src/vmboot/vmxassist/offsets.h [new file with mode: 0644]
palacios/src/vmboot/vmxassist/setup.c [new file with mode: 0644]
palacios/src/vmboot/vmxassist/trap.S [new file with mode: 0644]
palacios/src/vmboot/vmxassist/util.c [new file with mode: 0644]
palacios/src/vmboot/vmxassist/util.h [new file with mode: 0644]
palacios/src/vmboot/vmxassist/vm86.c [new file with mode: 0644]
palacios/src/vmboot/vmxassist/vm86.h [new file with mode: 0644]
palacios/src/vmboot/vmxassist/vmx_assist.h [new file with mode: 0644]
palacios/src/vmboot/vmxassist/vmxassist.ld [new file with mode: 0644]
utils/binutils-2.16.91.0.7.tar.gz [new file with mode: 0644]
utils/nasm-0.98.39.tar.gz [new file with mode: 0644]
utils/vmx.patch [new file with mode: 0644]

diff --git a/palacios/COPYING.geekos b/palacios/COPYING.geekos
new file mode 100644 (file)
index 0000000..f07e852
--- /dev/null
@@ -0,0 +1,23 @@
+Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
+
+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 (file)
index 0000000..b512ff9
--- /dev/null
@@ -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 (file)
index 0000000..332be74
--- /dev/null
@@ -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 (file)
index 0000000..e95aa5a
--- /dev/null
@@ -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 (file)
index 0000000..941b8bd
--- /dev/null
@@ -0,0 +1,396 @@
+# Makefile for GeekOS kernel, userspace, and tools
+# Copyright (c) 2004,2005 David H. Hovemeyer <daveho@cs.umd.edu>
+# $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 (file)
index 0000000..491aec8
--- /dev/null
@@ -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 (file)
index 0000000..b7fa572
--- /dev/null
@@ -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 (file)
index 0000000..491aec8
--- /dev/null
@@ -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 (file)
index 0000000..491aec8
--- /dev/null
@@ -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 (file)
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 (file)
index 0000000..491aec8
--- /dev/null
@@ -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 (file)
index 0000000..491aec8
--- /dev/null
@@ -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 (file)
index 0000000..54fac8b
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Create and extract the command line argument block for a process
+ * Copyright (c) 2003 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 (file)
index 0000000..63a0857
--- /dev/null
@@ -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 (file)
index 0000000..bb50de1
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Boot information structure, passed to kernel Main() routine
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 (file)
index 0000000..1628b77
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef GEEKOS_CRC32_H
+#define GEEKOS_CRC32_H
+
+#include <stddef.h>
+#include <geekos/ktypes.h>
+
+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 (file)
index 0000000..bc631c1
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Misc. kernel definitions
+ * Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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<<PAGE_POWER)
+#define PAGE_MASK (~(0xffffffff << PAGE_POWER))
+
+
+
+/* Ultimate Memory Layout
+
+TOP_OF_MEM:    
+        GDT (one page)
+        TSS (one page)
+        IDT (one page)
+        KernelImage
+          VMBootPackage
+             rombios (2nd copy)
+             vmxassist
+             vgabios
+             rombios (1st copy)
+        PageList           (varies - must be an integral number of pages)
+       KernelHeap         (varies - KERNEL_HEAP_SIZE; must be integral number of pages)
+        KernelStack        (one page)
+        KernelThreadObject (one page)
+0+VM_SIZE:
+        VM (including ISA hole)          
+        (KernelImage, GDT, and IDT start down here and are moved up)
+        (VMBoot Package is copied down to the first MB to start the VM boot)
+        (VMXAssist is used to provide real mode emulation for initial VM boot steps)
+0:      
+*/
+
+// This is for a 1 GB Machine
+// The last address (+1) at which physical memory ends
+#define TOP_OF_MEM (0x40000000)
+// How much space to reserve for the VM
+#define VM_SIZE    (0x20000000)
+// Where the VM starts in physical memory
+#define START_OF_VM (0x0)
+
+
+
+#define GDT_SIZE PAGE_SIZE
+#define TSS_SIZE PAGE_SIZE
+#define IDT_SIZE PAGE_SIZE
+#define KERNEL_HEAP_SIZE (256*PAGE_SIZE)
+#define KERNEL_STACK_SIZE PAGE_SIZE
+#define KERNEL_THREAD_OBJECT_SIZE PAGE_SIZE
+
+
+
+
+/*
+ *  * Keep these up to date with defs.asm.
+ */
+#define GDT_LOCATION          (TOP_OF_MEM-GDT_SIZE)
+#define TSS_LOCATION          (GDT_LOCATION-TSS_SIZE)
+#define IDT_LOCATION          (TSS_LOCATION-IDT_SIZE)
+
+
+#define FINAL_KERNEL_START    (IDT_LOCATION-MAX_VMM)
+#define FINAL_KERNEL_END      (FINAL_KERNEL_START+KERNEL_CORE_LENGTH-1)
+#define FINAL_BIOS_START      (FINAL_KERNEL_START+KERNEL_CORE_LENGTH)
+#define FINAL_BIOS_END        (FINAL_BIOS_START+BIOS_LENGTH-1)
+#define FINAL_VGA_BIOS_START  (FINAL_BIOS_START+BIOS_LENGTH)
+#define FINAL_VGA_BIOS_END    (FINAL_VGA_BIOS_START+VGA_BIOS_LENGTH-1)
+#define FINAL_VMXASSIST_START (FINAL_VGA_BIOS_START+VGA_BIOS_LENGTH)
+#define FINAL_VMXASSIST_END   (FINAL_VMXASSIST_START+VMXASSIST_LENGTH-1)
+#define FINAL_BIOS2_START     (FINAL_VMXASSIST_START+VMXASSIST_LENGTH)
+#define FINAL_BIOS2_END       (FINAL_BIOS2_START+BIOS_LENGTH-1)
+#define FINAL_VMBOOTSTART     (FINAL_BIOS_START)
+#define FINAL_VMBOOTEND       (FINAL_BIOS2_END)
+
+#if (FINAL_VMBOOTEND>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 (file)
index 0000000..3159eae
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * GeekOS error codes
+ * Copyright (c) 2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 (file)
index 0000000..cb3f168
--- /dev/null
@@ -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 (file)
index 0000000..3ae7b2b
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Initialize kernel GDT.
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 (file)
index 0000000..b88cf28
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * GeekOS IDT initialization code
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <geekos/int.h>
+
+/*
+ * 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 (file)
index 0000000..a80d142
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * GeekOS interrupt handling data structures and functions
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <geekos/kassert.h>
+#include <geekos/ktypes.h>
+#include <geekos/defs.h>
+
+/*
+ * 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 (file)
index 0000000..bd23614
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * x86 port IO routines
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <geekos/ktypes.h>
+
+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 (file)
index 0000000..6e6e24a
--- /dev/null
@@ -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 (file)
index 0000000..3164170
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * This is the device-driver interface to the interrupt system.
+ * Copyright (c) 2001,2003 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <geekos/int.h>
+
+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 (file)
index 0000000..434a8a8
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Definition of KASSERT() macro, and other useful debug macros
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <geekos/screen.h>
+
+#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 (file)
index 0000000..1ab5c42
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Keyboard driver
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <geekos/ktypes.h>
+
+/* ----------------------------------------------------------------------
+ * 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 (file)
index 0000000..f0ef23c
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Kernel threads
+ * Copyright (c) 2001,2003 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <geekos/ktypes.h>
+#include <geekos/list.h>
+
+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 (file)
index 0000000..7c72a3b
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Kernel data types
+ * Copyright (c) 2001,2003 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <stdbool.h>
+
+/*
+ * 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 (file)
index 0000000..96a7870
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Generic list data type
+ * Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <geekos/ktypes.h>
+#include <geekos/kassert.h>
+
+/*
+ * 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 (file)
index 0000000..ba70e92
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * GeekOS memory allocation API
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <geekos/ktypes.h>
+
+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 (file)
index 0000000..fdac1aa
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Physical memory allocation
+ * Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
+ * $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 <geekos/ktypes.h>
+#include <geekos/defs.h>
+#include <geekos/list.h>
+#include <geekos/paging.h>
+
+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 (file)
index 0000000..1810f0b
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Paging (virtual memory) support
+ * Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
+ * Copyright (c) 2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <geekos/ktypes.h>
+#include <geekos/defs.h>
+#include <geekos/bootinfo.h>
+#include <geekos/list.h>
+
+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 (file)
index 0000000..15bd023
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Range checking
+ * Copyright (c) 2003, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <geekos/ktypes.h>
+
+/*
+ * 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 (file)
index 0000000..e954a2c
--- /dev/null
@@ -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 (file)
index 0000000..241fc6f
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * GeekOS text screen output
+ * Copyright (c) 2001,2003 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <geekos/ktypes.h>
+
+#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 (file)
index 0000000..06f302a
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * General data structures and routines for segmentation
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <geekos/ktypes.h>
+
+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 (file)
index 0000000..4ebe0b0
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef SERIAL_H
+#define SERIAL_H
+
+#include <geekos/irq.h>
+#include <geekos/string.h>
+#include <geekos/io.h>
+#include <geekos/screen.h>
+
+#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 (file)
index 0000000..661a148
--- /dev/null
@@ -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 (file)
index 0000000..61e47bd
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Symbol mangling macros
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 (file)
index 0000000..5cb95ef
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Synchronization primitives
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <geekos/kthread.h>
+
+/*
+ * 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 (file)
index 0000000..37dda14
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * GeekOS timer interrupt support
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 (file)
index 0000000..73c28b8
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Trap handlers
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 (file)
index 0000000..66ea118
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * x86 TSS data structure and routines
+ * Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 (file)
index 0000000..30af389
--- /dev/null
@@ -0,0 +1,586 @@
+#ifndef __VMCS_H
+#define __VMCS_H
+
+#include <geekos/ktypes.h>
+
+
+/* 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 <geekos/serial.h>
+#include <geekos/vmcs_gen.h>
+
+#endif 
diff --git a/palacios/include/geekos/vmcs_gen.h b/palacios/include/geekos/vmcs_gen.h
new file mode 100644 (file)
index 0000000..4bdef7c
--- /dev/null
@@ -0,0 +1,779 @@
+#ifndef vmcs_gen
+#define vmcs_gen
+#include <geekos/vmcs.h>
+
+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 (file)
index 0000000..7d8d0bc
--- /dev/null
@@ -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 (file)
index 0000000..62531a6
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef __VMX_H
+#define __VMX_H
+
+#include <geekos/ktypes.h>
+#include <geekos/vmcs.h>
+
+#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 (file)
index 0000000..429d7fd
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Generalized support for printf()-style formatted output
+ * Copyright (c) 2004, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <stdarg.h>
+
+/*
+ * 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 (file)
index 0000000..fb146c0
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * String library
+ * Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <stddef.h>
+
+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 <stdio.h>, 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 (executable)
index 0000000..98bffa6
--- /dev/null
@@ -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 <eip value>\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 (executable)
index 0000000..7b9b877
--- /dev/null
@@ -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 <storage map> <symbol name>\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 (executable)
index 0000000..ca1fdeb
--- /dev/null
@@ -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 <geekos/vmcs.h>\n";
+print SOURCE "#include <geekos/$file.h>\n";
+
+while (<STDIN>) {
+  if (/\#define\s+(\S+)\s+/) {
+    push @list, $1;
+    GenSerUnserCode($1);
+  }
+}
+
+GenPrintAllCode(@list);
+
+print HEADER "#endif\n";
+
+sub GenSerUnserCode {
+  my $name=shift;
+
+  print SOURCE <<END
+
+void    Set_$name(uint_t val) { VMCS_WRITE($name,val); } 
+uint_t  Get_$name() { uint_t rc; VMCS_READ($name,&rc); return rc; }
+
+void    SerialPrint_$name() { SerialPrint("$name = %x\\n", Get_$name()); }
+
+END
+
+;
+  print HEADER <<END2
+
+void    Set_$name(uint_t val);
+uint_t  Get_$name();
+
+void    SerialPrint_$name();
+
+END2
+
+;
+
+}
+
+
+sub GenPrintAllCode  {
+  print SOURCE "void SerialPrint_VMCS_ALL() {\n";
+  while (my $name=shift) { 
+    print SOURCE "  SerialPrint_$name();\n";
+  }
+  print SOURCE "}\n";
+  print HEADER "void SerialPrint_VMCS_ALL();\n";
+}
diff --git a/palacios/scripts/generrs b/palacios/scripts/generrs
new file mode 100755 (executable)
index 0000000..1b76e81
--- /dev/null
@@ -0,0 +1,28 @@
+#! /usr/bin/perl
+
+# Script to process include/geekos/errno.h to produce a table
+# of error description strings that can be compiled and
+# linked into libc.
+
+use strict qw(refs vars);
+
+my @errs = ();
+my @syms = ();
+
+$errs[0] = 'No error';
+
+while (<>) {
+       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 (executable)
index 0000000..9241e3a
--- /dev/null
@@ -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 <kernfile>\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 (executable)
index 0000000..d3f4477
--- /dev/null
@@ -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 <diskImage> <filenames>\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 (executable)
index 0000000..1581b4b
--- /dev/null
@@ -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 <filename> <progname> <entry addr>\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 (executable)
index 0000000..708a893
--- /dev/null
@@ -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 <filename>\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 (executable)
index 0000000..c1c5329
--- /dev/null
@@ -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 <filename> <multiple>\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 (executable)
index 0000000..d58f9fd
--- /dev/null
@@ -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 (executable)
index 0000000..7edc728
--- /dev/null
@@ -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 <filename> <offset>\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 (executable)
index 0000000..cbfe6dc
--- /dev/null
@@ -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 <filename> <word value in hex>\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 (executable)
index 0000000..04bea4f
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/perl
+
+
+$file = $ARGV[0];
+$ofile = $ARGV[1];
+
+open(INFILE, "$file");
+@lines = <INFILE>;
+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 (executable)
index 0000000..52e744a
--- /dev/null
@@ -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 <output file> <num sectors>\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 (file)
index 0000000..c097eb4
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ * This code was originally part of klibc-0.103.
+ * It was adapted by David Hovemeyer <daveho@cs.umd.edu>
+ * 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 <stdarg.h>
+#include <stddef.h>
+#include <geekos/string.h>
+#include <limits.h>
+#include <geekos/fmtout.h> /* 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 ( o<n )
+    *q = '\0';                 /* No overflow */
+  else if ( n>0 )
+    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 (file)
index 0000000..27f04a5
--- /dev/null
@@ -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 <string.h>
+
+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 (file)
index 0000000..7db896c
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * String library
+ * Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <fmtout.h>
+#include <string.h>
+
+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 (file)
index 0000000..52b6ec4
--- /dev/null
@@ -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 (file)
index 0000000..cccbe16
--- /dev/null
@@ -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 <assert.h> 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 <len> bytes, using the storage starting at
+    <buffer>.  You  can  call  bpool()  subsequently  to   contribute
+    additional storage to the overall buffer pool.
+
+           void *bget(bufsize size);
+
+    Allocate  a  buffer of <size> 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 <size> 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  <newsize>  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  <buf>, 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 <compact> is non-NULL, whenever
+    a buffer allocation request fails, the <compact> 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  <compact>  attempting  to   satisfy   this
+    allocation request.   The sequence number is 1 for the first call
+    on <compact> for a given allocation  request,  and increments  on
+    subsequent calls,  permitting  the  <compact>  function  to  take
+    increasingly dire measures in an attempt to free up  storage.   If
+    the  <compact>  function  returns  a nonzero value, the allocation
+    attempt is re-tried.  If <compact> 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 <acquire> argument is non-NULL.  At the time
+    the  <compact>  function  is  called,  the state  of  the  buffer
+    allocator  is  identical  to  that at  the  moment the allocation
+    request was made; consequently, the <compact>  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  <compact>  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 <compact> function that released a buffer
+    in the  process  of  being reallocated with bgetr() would lead to
+    disaster.  Implementing a safe and effective  <compact>  mechanism
+    requires  careful  design of an application's memory architecture,
+    and cannot generally be easily retrofitted into existing code.
+
+    If <acquire> is non-NULL, that function will be called whenever an
+    allocation request  fails.  If the <acquire> function succeeds in
+    allocating the requested space and returns a pointer  to  the  new
+    area,  allocation will proceed using the expanded buffer pool.  If
+    <acquire> cannot obtain the requested space, it should return NULL
+    and   the  entire  allocation  process  will  fail.   <pool_incr>
+    specifies the normal expansion block size. Providing an <acquire>
+    function will cause subsequent bget()  requests  for  buffers  too
+    large  to  be  managed in the linked-block scheme (in other words,
+    larger than <pool_incr> minus the buffer overhead) to be satisfied
+    directly by calls to the <acquire> function.  Automatic release of
+    empty pool blocks will occur only if all pool blocks in the system
+    are the size given by <pool_incr>.
+
+           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 <curalloc>.  The total free space (sum of
+    all free blocks in the pool) is stored into the  variable  pointed
+    to by  <totfree>, and the size of the largest single block in the
+    free space pool  is  stored  into  the  variable  pointed  to  by
+    <maxfree>.  The  variables  pointed  to  by <nget> and <nrel> 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 <pool_incr>, 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  <npool>.  The variables pointed to by <npget> and
+    <nprel> will be filled with, respectively, the number of expansion
+    block   acquisitions   and releases  which  have  occurred.   The
+    variables pointed to by <ndget> and <ndrel> 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 <buf> is dumped on standard output.
+
+           void bpoold(void *pool, int dumpalloc, int dumpfree);
+
+    All buffers in the buffer pool <pool>, previously initialised by a
+    call on bpool(), are listed in ascending memory address order.  If
+    <dumpalloc> is nonzero, the  contents  of  allocated  buffers  are
+    dumped;  if <dumpfree> 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 <geekos/string.h> // for memset()
+
+// Provide an assert() macro
+#include <geekos/kassert.h>
+#define assert(exp) KASSERT(exp)
+
+#else // define (GEEKOS)
+
+#include <stdio.h>
+
+#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 <assert.h>
+#include <memory.h>
+
+#endif // defined (GEEKOS)
+
+#ifdef BufDump                       /* BufDump implies DumpData */
+#ifndef DumpData
+#define DumpData    1
+#endif
+#endif
+
+#ifdef DumpData
+#include <ctype.h>
+#endif
+
+/*  Declare the interface, including the requested buffer size type,
+    bufsize.  */
+
+#include <geekos/bget.h>
+
+#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 <math.h>
+
+#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 (file)
index 0000000..9986818
--- /dev/null
@@ -0,0 +1,247 @@
+; Boot sector for GeekOS
+; Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+; $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 (file)
index 0000000..0165c3b
--- /dev/null
@@ -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 <geekos/crc32.h>
+#include <geekos/kassert.h>
+#include <geekos/serial.h>
+
+#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 (file)
index 0000000..362fc83
--- /dev/null
@@ -0,0 +1,88 @@
+; Definitions for use in GeekOS boot code
+; Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+; $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 <geekos/pfat.h>.
+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 (file)
index 0000000..6e60675
--- /dev/null
@@ -0,0 +1 @@
+dummy:
diff --git a/palacios/src/geekos/fd_boot.asm b/palacios/src/geekos/fd_boot.asm
new file mode 100644 (file)
index 0000000..e541a9c
--- /dev/null
@@ -0,0 +1,295 @@
+; Boot sector for GeekOS
+; Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+; Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
+; $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 (file)
index 0000000..dd0ca5b
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Initialize kernel GDT.
+ * Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $Revision: 1.1 $
+ * 
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+#include <geekos/kassert.h>
+#include <geekos/segment.h>
+#include <geekos/int.h>
+#include <geekos/tss.h>
+#include <geekos/gdt.h>
+#include <libc/string.h>
+
+
+/*
+ * 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;i<NUM_GDT_ENTRIES;i++) { 
+    if (s_GDT[i].present) { 
+      Print("%d: base=%u, limit=%u, sizeLow=%u,  baseLow=%u, type=%u, system=%u, dpl=%u, preent=%u, sizeHigh=%u, avail=%u, reserved=%u, dbBit=%u, granularity=%u, baseHigh=%u\n", 
+           i,
+           (s_GDT[i].baseHigh<<24) + s_GDT[i].baseLow,
+           (s_GDT[i].sizeHigh<<16) + s_GDT[i].sizeLow,
+           s_GDT[i].sizeLow,
+           s_GDT[i].baseLow,
+           s_GDT[i].type,
+           s_GDT[i].system,
+           s_GDT[i].dpl,
+           s_GDT[i].present,
+           s_GDT[i].sizeHigh,
+           s_GDT[i].avail,
+           s_GDT[i].reserved,
+           s_GDT[i].dbBit,
+           s_GDT[i].granularity,
+           s_GDT[i].baseHigh  );
+    } else {
+      Print("%d: Not Present\n",i);
+    }
+  }
+}
+
+
+/* ----------------------------------------------------------------------
+ * Functions
+ * ---------------------------------------------------------------------- */
+
+/*
+ * Allocate an descriptor from the GDT.
+ * Returns null if there are none left.
+ */
+struct Segment_Descriptor* Allocate_Segment_Descriptor(void)
+{
+    struct Segment_Descriptor* result = 0;
+    int i;
+    bool iflag;
+
+    iflag = Begin_Int_Atomic();
+
+    /* Note; entry 0 is unused (thus never allocated) */
+    for (i = 1; i < NUM_GDT_ENTRIES; ++i) {
+       struct Segment_Descriptor *desc = &s_GDT[ i ];
+       if (desc->avail) {
+           ++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 (file)
index 0000000..37c7fd0
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * GeekOS IDT initialization code
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $Revision: 1.1 $
+ * 
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+#include <geekos/kassert.h>
+#include <geekos/defs.h>
+#include <geekos/idt.h>
+#include <geekos/serial.h>
+
+/* ----------------------------------------------------------------------
+ * 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<NUM_IDT_ENTRIES/16;i++) { 
+    if (s_IDT[i].ig.present) { 
+      Print("%d: segmentselector=%u, offset=%u, offsetLow=%u, segmentSelector=%u, reserved=%u, signature=%u, dpl=%u, present=%u, offsetHigh=%u\n",
+           i,
+           s_IDT[i].ig.segmentSelector,
+           (s_IDT[i].ig.offsetHigh<<16) + s_IDT[i].ig.offsetLow,
+           s_IDT[i].ig.offsetLow,
+           s_IDT[i].ig.segmentSelector,
+           s_IDT[i].ig.reserved,
+           s_IDT[i].ig.signature,
+           s_IDT[i].ig.dpl,
+           s_IDT[i].ig.present,
+           s_IDT[i].ig.offsetHigh);
+    }
+  }
+}
+
+
+void SerialDumpIDT()
+{
+  int i;
+  SerialPrint("IDT Contents:\n");
+
+  for (i=0;i<NUM_IDT_ENTRIES;i++) { 
+    if (s_IDT[i].ig.present) { 
+      SerialPrint("%d: segmentselector=%u, offset=%u, offsetLow=%u, segmentSelector=%u, reserved=%u, signature=%u, dpl=%u, present=%u, offsetHigh=%u\n",
+           i,
+           s_IDT[i].ig.segmentSelector,
+           (s_IDT[i].ig.offsetHigh<<16) + s_IDT[i].ig.offsetLow,
+           s_IDT[i].ig.offsetLow,
+           s_IDT[i].ig.segmentSelector,
+           s_IDT[i].ig.reserved,
+           s_IDT[i].ig.signature,
+           s_IDT[i].ig.dpl,
+           s_IDT[i].ig.present,
+           s_IDT[i].ig.offsetHigh);
+      SerialPrint("\n");
+    }
+  }
+}
+
+
+
+/* ----------------------------------------------------------------------
+ * Public functions
+ * ---------------------------------------------------------------------- */
+
+/*
+ * Initialize the Interrupt Descriptor Table.
+ * This will allow us to install C handler functions
+ * for interrupts, both processor-generated and
+ * those generated by external hardware.
+ */
+void Init_IDT(void)
+{
+    int i;
+    ushort_t limitAndBase[3];
+    ulong_t idtBaseAddr = (ulong_t) s_IDT;
+    ulong_t tableBaseAddr = (ulong_t) &g_entryPointTableStart;
+    ulong_t addr;
+
+    PrintBoth("Initializing IDT\n");
+
+    /* Make sure the layout of the entry point table is as we expect. */
+    KASSERT(g_handlerSizeNoErr == g_handlerSizeErr);
+    KASSERT((&g_entryPointTableEnd - &g_entryPointTableStart) ==
+            g_handlerSizeNoErr * NUM_IDT_ENTRIES);
+
+    /*
+     * Build the IDT.
+     * We're taking advantage of the fact that all of the
+     * entry points are laid out consecutively, and that they
+     * are all padded to be the same size.
+     */
+    for (i = 0, addr = tableBaseAddr; i < NUM_IDT_ENTRIES; ++i) {
+       /*
+        * All interrupts except for the syscall interrupt
+        * must have kernel privilege to access.
+        */
+       int dpl = (i == SYSCALL_INT) ? USER_PRIVILEGE : KERNEL_PRIVILEGE;
+       Init_Interrupt_Gate(&s_IDT[i], addr, dpl);
+       addr += g_handlerSizeNoErr;
+    }
+
+    /*
+     * Cruft together a 16 bit limit and 32 bit base address
+     * to load into the IDTR.
+     */
+    limitAndBase[0] = 8 * NUM_IDT_ENTRIES;
+    limitAndBase[1] = idtBaseAddr & 0xffff;
+    limitAndBase[2] = idtBaseAddr >> 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 (file)
index 0000000..319017b
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * GeekOS interrupt handling data structures and functions
+ * Copyright (c) 2001,2003 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $Revision: 1.1 $
+ * 
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+#include <geekos/idt.h>         /* x86-specific int handling stuff */
+#include <geekos/screen.h>
+#include <geekos/kassert.h>
+#include <geekos/int.h>
+#include <geekos/serial.h>
+#include <geekos/vmcs.h>
+
+#include <geekos/cpu.h>
+
+/*
+ * 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 (file)
index 0000000..3132733
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * x86 port IO routines
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $Revision: 1.1 $
+ * 
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+#include <geekos/io.h>
+
+/*
+ * 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 (file)
index 0000000..24c5104
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * This is the device-driver interface to the interrupt system.
+ * Copyright (c) 2001,2003 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $Revision: 1.1 $
+ * 
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+#include <geekos/kassert.h>
+#include <geekos/idt.h>
+#include <geekos/io.h>
+#include <geekos/irq.h>
+
+/* ----------------------------------------------------------------------
+ * 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 (file)
index 0000000..409d9a4
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * Keyboard driver
+ * Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <peter@pcswebdesign.nl> 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 <geekos/kthread.h>
+#include <geekos/kassert.h>
+#include <geekos/screen.h>
+#include <geekos/irq.h>
+#include <geekos/io.h>
+#include <geekos/keyboard.h>
+
+/* ----------------------------------------------------------------------
+ * 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 (file)
index 0000000..e2a6df2
--- /dev/null
@@ -0,0 +1,818 @@
+/*
+ * Kernel threads
+ * Copyright (c) 2001,2003 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $Revision: 1.1 $
+ * 
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+#include <geekos/kassert.h>
+#include <geekos/defs.h>
+#include <geekos/screen.h>
+#include <geekos/int.h>
+#include <geekos/mem.h>
+#include <geekos/symbol.h>
+#include <geekos/string.h>
+#include <geekos/kthread.h>
+#include <geekos/malloc.h>
+#include <geekos/serial.h>
+
+/* ----------------------------------------------------------------------
+ * 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 &current->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; j<MIN_DESTRUCTOR_ITERATIONS; j++) {
+
+        for (i = 0; i<MAX_TLOCAL_KEYS; i++) {
+
+           void *x = (void *)curr->tlocalData[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(&current->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 (file)
index 0000000..63f93c2
--- /dev/null
@@ -0,0 +1,576 @@
+; -*- fundamental -*-
+; Low level interrupt/thread handling code for GeekOS.
+; Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+; Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
+; $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 (file)
index 0000000..2da73ac
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * GeekOS C code entry point
+ * Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
+ * Copyright (c) 2004, Iulian Neamtiu <neamtiu@cs.umd.edu>
+ * $Revision: 1.1 $
+ * 
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+#include <geekos/bootinfo.h>
+#include <geekos/string.h>
+#include <geekos/screen.h>
+#include <geekos/mem.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/reboot.h>
+#include <geekos/mem.h>
+#include <geekos/paging.h>
+#include <geekos/vmx.h>
+#include <geekos/vmcs.h>
+
+#include <geekos/gdt.h>
+
+#include <geekos/vmm_sizes.h>
+
+/*
+  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;i<num;i++) { 
+    Out_Byte(SPEAKER_PORT, init|0x2);
+    for (j=0;j<delay;j++) { 
+      x+=j;
+    }
+    Out_Byte(SPEAKER_PORT, init);
+    for (j=0;j<delay;j++) { 
+      x+=j;
+    }
+  }
+}
+
+inline void MyOut_Byte(ushort_t port, uchar_t value)
+{
+    __asm__ __volatile__ (
+       "outb %b0, %w1"
+       :
+       : "a" (value), "Nd" (port)
+    );
+}
+
+/*
+ * Read a byte from an I/O port.
+ */
+inline uchar_t MyIn_Byte(ushort_t port)
+{
+    uchar_t value;
+
+    __asm__ __volatile__ (
+       "inb %w1, %b0"
+       : "=a" (value)
+       : "Nd" (port)
+    );
+
+    return value;
+}
+
+
+extern void MyBuzzVM();
+
+#define MYBUZZVM_START MyBuzzVM
+#define MYBUZZVM_LEN   0x3d
+
+void BuzzVM()
+{
+  int x;
+  int j;
+  unsigned char init;
+  
+  
+  init=MyIn_Byte(SPEAKER_PORT);
+
+  while (1) {
+    MyOut_Byte(SPEAKER_PORT, init|0x2);
+    for (j=0;j<1000000;j++) { 
+      x+=j;
+    }
+    MyOut_Byte(SPEAKER_PORT, init);
+    for (j=0;j<1000000;j++) { 
+      x+=j;
+    }
+  }
+}
+
+extern void RunVM();
+
+int vmRunning = 0;
+
+void RunVM() {
+  vmRunning = 1;
+
+  while(1);
+}
+
+
+
+
+extern uint_t VMCS_STORE();
+extern uint_t VMCS_READ();
+
+
+
+void Buzzer(ulong_t arg) {
+  ulong_t *doIBuzz = (ulong_t*)arg;
+  while (1) {
+    // Quick and dirty hack to save my hearing...
+    // I'm not too worried about timing, so I'll deal with concurrency later...
+    if (*doIBuzz == 1) {
+      Buzz(1000000, 10);
+    }
+  }
+
+}
+
+
+
+void Hello(ulong_t arg)
+{
+  char *b="hello ";
+  char byte;
+  short port=0xe9;
+  int i;
+  while(1){
+    for (i=0;i<6;i++) { 
+      byte=b[i];
+      __asm__ __volatile__ ("outb %b0, %w1" : : "a"(byte), "Nd"(port) );
+    }
+  }
+}
+
+void Keyboard_Listener(ulong_t arg) {
+  ulong_t * doIBuzz = (ulong_t*)arg;
+  Keycode key_press;
+
+  Print("Press F4 to turn on/off the speaker\n");
+
+  while ((key_press = Wait_For_Key())) {    
+    if (key_press == KEY_F4) {
+      Print("\nToggling Speaker Port\n");
+      SerialPrintLevel(100,"\nToggling Speaker Port\n");
+      *doIBuzz = (*doIBuzz + 1) % 2;
+    } else if (key_press == KEY_F5) {
+      Print("\nMachine Restart\n");
+      SerialPrintLevel(100,"\nMachine Restart\n");
+      machine_real_restart();
+    }
+  }
+  return;
+}
+
+
+
+extern char BSS_START, BSS_END;
+
+extern char end;
+
+
+void VM_Thread(ulong_t arg) 
+{
+  int ret;
+  struct VMDescriptor *vm = (struct VMDescriptor *) arg;
+
+  SerialPrintLevel(100,"VM_Thread: Launching VM with (entry_ip=%x, exit_eip=%x, guest_esp=%x)\n",
+             vm->entry_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<start+length;address+=PAGE_SIZE) { 
+    void *page;
+    pte_t pte = template_pte;
+    
+    page=Alloc_Page();
+    KASSERT(page);
+    
+    pte.pageBaseAddr=PAGE_ALLIGNED_ADDR(page);
+
+    KASSERT(MapPage((void*)address,&pte,1));
+  }
+  
+  return 0;
+}
+    
+
+
+/*
+ * Kernel C code entry point.
+ * Initializes kernel subsystems, mounts filesystems,
+ * and spawns init process.
+ */
+void Main(struct Boot_Info* bootInfo)
+{
+  struct Kernel_Thread * key_thread;
+  struct Kernel_Thread * spkr_thread;
+  struct Kernel_Thread * vm_thread;
+  struct VMDescriptor    vm;
+
+  ulong_t doIBuzz = 0;
+
+
+
+  Init_BSS();
+  Init_Screen();
+  InitSerial();
+  Init_Mem(bootInfo);
+  Init_CRC32();
+  Init_TSS();
+  Init_Interrupts();
+  Init_Scheduler();
+  Init_Traps();
+  Init_Timer();
+  Init_Keyboard();
+  Init_VM(bootInfo);
+  Init_Paging();
+  
+
+
+
+
+  
+#if 1
+  SerialPrint("Dumping VMXASSIST Code (first 512 bytes @ 0x%x)\n",VMXASSIST_START);
+  SerialMemDump((unsigned char *)VMXASSIST_START, 512);
+  SerialPrint("Dumping ROMBIOS Code (first 512 bytes @ 0x%x)\n",BIOS_START);
+  SerialMemDump((unsigned char *)BIOS_START, 512);
+  SerialPrint("Dumping ROMBIOS Code (Second copy) (first 512 bytes @ 0x%x)\n",BIOS2_START);
+  SerialMemDump((unsigned char *)BIOS2_START, 512);
+  SerialPrint("Dumping VGABIOS Code (first 512 bytes @ 0x%x)\n",VGA_BIOS_START);
+  SerialMemDump((unsigned char *)VGA_BIOS_START, 512);
+  
+#endif
+  
+
+
+  SerialPrint("\n\nHello, Welcome to this horrid output-only serial interface\n");
+  SerialPrint("Eventually, this will let us control the VMM\n\n");
+  SerialPrint("\n\n===>");
+  
+  
+  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 (file)
index 0000000..ea76959
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * GeekOS memory allocation API
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $Revision: 1.1 $
+ * 
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+#include <geekos/screen.h>
+#include <geekos/int.h>
+#include <geekos/bget.h>
+#include <geekos/kassert.h>
+#include <geekos/malloc.h>
+
+/*
+ * 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 (file)
index 0000000..2fbc0f5
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * Physical memory allocation
+ * Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
+ * $Revision: 1.1 $
+ * 
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+#include <geekos/defs.h>
+#include <geekos/ktypes.h>
+#include <geekos/kassert.h>
+#include <geekos/bootinfo.h>
+#include <geekos/gdt.h>
+#include <geekos/screen.h>
+#include <geekos/int.h>
+#include <geekos/malloc.h>
+#include <geekos/string.h>
+#include <geekos/mem.h>
+
+#include <geekos/vmm_sizes.h>
+#include <geekos/serial.h>
+
+/* ----------------------------------------------------------------------
+ * 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 (file)
index 0000000..bb19af3
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * Paging (virtual memory) support
+ * Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
+ * Copyright (c) 2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $Revision: 1.1 $
+ * 
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+#include <geekos/string.h>
+#include <geekos/int.h>
+#include <geekos/idt.h>
+#include <geekos/kthread.h>
+#include <geekos/kassert.h>
+#include <geekos/screen.h>
+#include <geekos/mem.h>
+#include <geekos/malloc.h>
+#include <geekos/gdt.h>
+#include <geekos/segment.h>
+//#include <geekos/user.h>
+//#include <geekos/vfs.h>
+#include <geekos/crc32.h>
+#include <geekos/paging.h>
+#include <geekos/serial.h>
+#include <geekos/vmcs.h>
+
+/* ----------------------------------------------------------------------
+ * 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<NUM_PAGE_DIR_ENTRIES && pde[i].present;i++) { 
+    SerialPrintPDE((void*)(PAGE_SIZE*NUM_PAGE_TABLE_ENTRIES*i),&(pde[i]));
+  }
+}
+
+void SerialPrintPT(void *starting_address, pte_t *pte) 
+{
+  int i;
+
+  SerialPrint("Page Table at %p:\n",pte);
+  for (i=0;i<NUM_PAGE_TABLE_ENTRIES && pte[i].present;i++) { 
+    SerialPrintPTE(starting_address + PAGE_SIZE*i,&(pte[i]));
+  }
+}
+
+
+void SerialPrintPDE(void *virtual_address, pde_t *pde)
+{
+  SerialPrint("PDE %p -> %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;i<NUM_PAGE_DIR_ENTRIES && pde[i].present;i++) { 
+    SerialPrintPDE((void*)(PAGE_SIZE*NUM_PAGE_TABLE_ENTRIES*i),&(pde[i]));
+    SerialPrintPT((void*)(PAGE_SIZE*NUM_PAGE_TABLE_ENTRIES*i),(void*)(pde[i].pageTableBaseAddr<<PAGE_POWER));
+  }
+}
+    
+    
+    
+
+
+int checkPaging()
+{
+  unsigned long reg=0;
+  __asm__ __volatile__( "movl %%cr0, %0" : "=a" (reg));
+  Print("Paging on ? : %d\n", (reg & (1<<31)) != 0);
+  return (reg & (1<<31)) != 0;
+}
+
+
+/*
+ * Print diagnostic information for a page fault.
+ */
+static void Print_Fault_Info(uint_t address, faultcode_t faultCode)
+{
+    extern uint_t g_freePageCount;
+
+    g_freePageCount+=0;
+
+    SerialPrintLevel(100,"Pid %d, Page Fault received, at address %x (%d pages free)\n",
+        g_currentThread->pid, 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<NUM_PAGE_DIR_ENTRIES;i++) { 
+    if (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<NUM_PAGE_TABLE_ENTRIES;j++) { 
+       if (i*NUM_PAGE_TABLE_ENTRIES + 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;i<NUM_PAGE_TABLE_ENTRIES;i++) { 
+    pt[i].present=0;
+  }
+
+  pde_t *pde = Get_PDBR();
+  
+  pde=&(pde[PAGE_DIRECTORY_INDEX(vaddr)]);
+
+  KASSERT(!(pde->present));
+  
+  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 (file)
index 0000000..08f307d
--- /dev/null
@@ -0,0 +1,161 @@
+#include <geekos/reboot.h>
+#include <libc/string.h>
+// 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 (file)
index 0000000..9c78dde
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * GeekOS text screen output
+ * Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $Revision: 1.1 $
+ * 
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+#include <stdarg.h>
+#include <geekos/kassert.h>
+#include <geekos/ktypes.h>
+#include <geekos/io.h>
+#include <geekos/int.h>
+#include <geekos/fmtout.h>
+#include <geekos/screen.h>
+
+/*
+ * 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 (file)
index 0000000..4e83db0
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * General data structures and routines for segmentation
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <geekos/kassert.h>
+#include <geekos/string.h>
+#include <geekos/tss.h>
+#include <geekos/segment.h>
+
+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 (file)
index 0000000..68ef275
--- /dev/null
@@ -0,0 +1,140 @@
+#include <geekos/serial.h>
+#include <geekos/reboot.h>
+#include <geekos/gdt.h>
+#include <geekos/idt.h>
+
+
+
+
+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<n;i+=16) {
+    SerialPrint("%8x", (unsigned)(start+i));
+    for (j=i; j<i+16 && j<n; j+=2) {
+      SerialPrint(" ");
+      SerialPrintHex(*((unsigned char *)(start+j)));
+      if ((j+1)<n) { 
+       SerialPrintHex(*((unsigned char *)(start+j+1)));
+      }
+    }
+    SerialPrint(" ");
+    for (j=i; j<i+16 && j<n;j++) {
+      SerialPrint("%c", ((start[j]>=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 (file)
index 0000000..56c9938
--- /dev/null
@@ -0,0 +1,247 @@
+; -*- fundamental -*-
+; GeekOS setup code
+; Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+; $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 (file)
index 0000000..c75d119
--- /dev/null
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#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 (file)
index 0000000..0bb1584
--- /dev/null
@@ -0,0 +1,43 @@
+; Symbol mangling macros
+; Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+; $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 (file)
index 0000000..86e7191
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Synchronization primitives
+ * Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $Revision: 1.1 $
+ * 
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+#include <geekos/kthread.h>
+#include <geekos/int.h>
+#include <geekos/kassert.h>
+#include <geekos/screen.h>
+#include <geekos/synch.h>
+
+/*
+ * 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 (file)
index 0000000..1ab713e
--- /dev/null
@@ -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 (file)
index 0000000..cd89f86
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * GeekOS timer interrupt support
+ * Copyright (c) 2001,2003 David H. Hovemeyer <daveho@cs.umd.edu>
+ * Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
+ * $Revision: 1.1 $
+ * 
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+#include <limits.h>
+#include <geekos/io.h>
+#include <geekos/int.h>
+#include <geekos/irq.h>
+#include <geekos/kthread.h>
+#include <geekos/timer.h>
+
+#include <geekos/serial.h>
+
+#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 (file)
index 0000000..2085a99
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Trap handlers
+ * Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $Revision: 1.1 $
+ * 
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+#include <geekos/idt.h>
+#include <geekos/kthread.h>
+#include <geekos/defs.h>
+#include <geekos/trap.h>
+#include <geekos/serial.h>
+
+/*
+ * 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 (file)
index 0000000..a94bc52
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * x86 TSS data structure and routines
+ * Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * $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 <geekos/kassert.h>
+#include <geekos/defs.h>
+#include <geekos/gdt.h>
+#include <geekos/segment.h>
+#include <geekos/string.h>
+#include <geekos/tss.h>
+
+#include <geekos/serial.h>
+
+/*
+ * 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 (file)
index 0000000..86a019b
--- /dev/null
@@ -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 (file)
index 0000000..5f9de3a
--- /dev/null
@@ -0,0 +1,789 @@
+#include <geekos/vmcs.h>
+#include <geekos/serial.h>
+
+
+
+
+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 (file)
index 0000000..f354cf1
--- /dev/null
@@ -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 (file)
index 0000000..c96127e
--- /dev/null
@@ -0,0 +1,926 @@
+#include <geekos/vmcs_gen.h>
+
+
+
+
+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 (file)
index 0000000..4ce96e0
--- /dev/null
@@ -0,0 +1,894 @@
+#include <geekos/vmx.h>
+#include <geekos/vmcs.h>
+#include <geekos/mem.h>
+#include <geekos/serial.h>
+#include <geekos/segment.h>
+#include <geekos/gdt.h>
+#include <geekos/idt.h>
+
+
+#include <geekos/cpu.h>
+#include <geekos/io_devs.h>
+
+
+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 (file)
index 0000000..05257c9
--- /dev/null
@@ -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 (file)
index 0000000..995a03b
--- /dev/null
@@ -0,0 +1,8 @@
+#include <conio.h>
+#include <stddef.h>
+
+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 (file)
index 0000000..1d16fb2
--- /dev/null
@@ -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 (file)
index 0000000..a010949
--- /dev/null
@@ -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 (file)
index 0000000..be12e49
--- /dev/null
@@ -0,0 +1,478 @@
+/* biossums.c  --- written by Eike W. */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+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 (executable)
index 0000000..a3c7705
--- /dev/null
@@ -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 (<STDIN>) {
+  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 (file)
index 0000000..b8322d0
--- /dev/null
@@ -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; channel<BX_MAX_ATA_INTERFACES; channel++) {
+    write_byte(ebda_seg,&EbdaData->ata.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; device<BX_MAX_ATA_DEVICES; device++) {
+    write_byte(ebda_seg,&EbdaData->ata.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; device<BX_MAX_ATA_DEVICES; device++) {
+    write_byte(ebda_seg,&EbdaData->ata.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; device<BX_MAX_ATA_DEVICES; device++) {
+    Bit16u iobase1, iobase2;
+    Bit8u  channel, slave, shift;
+    Bit8u  sc, sn, cl, ch, st;
+
+    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);
+
+    // 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<<version))!=0)
+            break;
+            }
+
+          // Read model name
+          for(i=0;i<20;i++){
+            write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
+            write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
+            }
+
+          // Reformat
+          write_byte(get_SS(),model+40,0x00);
+          for(i=39;i>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;device++) {
+    if (atapi_is_cdrom(device)) break;
+    }
+  
+  // if not found
+  if(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 (file)
index 0000000..2bf3b06
--- /dev/null
@@ -0,0 +1,3 @@
+Not all the functions have been implemented yet. 
+
+Please report any bugs to <info@vruppert.de>
diff --git a/palacios/src/vmboot/vgabios/COPYING b/palacios/src/vmboot/vgabios/COPYING
new file mode 100644 (file)
index 0000000..223ede7
--- /dev/null
@@ -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.
+\f
+  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.
+\f
+                 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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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
+\f
+           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.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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.
+
+  <signature of Ty Coon>, 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 (file)
index 0000000..08711f0
--- /dev/null
@@ -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 (file)
index 0000000..b5482ea
--- /dev/null
@@ -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 (file)
index 0000000..d5b708d
--- /dev/null
@@ -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 (file)
index 0000000..69462d9
--- /dev/null
@@ -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 <kevin2001@yahoo.com>
+
+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 (file)
index 0000000..0b83ed0
--- /dev/null
@@ -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 (file)
index 0000000..bb1d0ad
--- /dev/null
@@ -0,0 +1,200 @@
+/* biossums.c  --- written by Eike W. for the Bochs BIOS */
+/* adapted for the LGPL'd VGABIOS by vruppert */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+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 (file)
index 0000000..1eb3c69
--- /dev/null
@@ -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 (executable)
index 0000000..02a2d4c
--- /dev/null
@@ -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 (file)
index 0000000..8c06473
--- /dev/null
@@ -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 (BX<VBE_MODE_VESA_DEFINED)
+        {
+                Bit8u   mode;
+                
+                dispi_set_enable(VBE_DISPI_DISABLED);
+                // call the vgabios in order to set the video mode
+                // this allows for going back to textmode with a VBE call (some applications expect that to work)
+                
+                mode=(BX & 0xff);
+                biosfn_set_video_mode(mode);
+                result = 0x4f;
+        }
+        
+        cur_info = mode_info_find_mode(BX, using_lfb, &cur_info);
+
+        if (cur_info != 0)
+        {
+#ifdef DEBUG
+                printf("VBE found mode %x, setting:\n", BX);
+                printf("\txres%x yres%x bpp%x\n",
+                        cur_info->info.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 (file)
index 0000000..621048a
--- /dev/null
@@ -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 (file)
index 0000000..788e17a
--- /dev/null
@@ -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 (file)
index 0000000..a742ac7
--- /dev/null
@@ -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 (file)
index 0000000..6afa337
--- /dev/null
@@ -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<cheight;i++)
+  {
+   memcpyb(0xa000,dest+i*nbcols,0xa000,src+i*nbcols,cols);
+  }
+ outw(VGAREG_GRDC_ADDRESS, 0x0005);
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_fill_pl4(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+xstart;
+ outw(VGAREG_GRDC_ADDRESS, 0x0205);
+ for(i=0;i<cheight;i++)
+  {
+   memsetb(0xa000,dest+i*nbcols,attr,cols);
+  }
+ outw(VGAREG_GRDC_ADDRESS, 0x0005);
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_copy_cga(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)>>1)+xstart;
+ dest=((ydest*cheight*nbcols)>>1)+xstart;
+ for(i=0;i<cheight;i++)
+  {
+   if (i & 1)
+     memcpyb(0xb800,0x2000+dest+(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<cheight;i++)
+  {
+   if (i & 1)
+     memsetb(0xb800,0x2000+dest+(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((i<rul+nblines)||(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
+  {
+   // FIXME gfx mode not complete
+   cheight=vga_modes[line].cheight;
+   switch(vga_modes[line].memmodel)
+    {
+     case PLANAR4:
+     case PLANAR1:
+       if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
+        {
+         outw(VGAREG_GRDC_ADDRESS, 0x0205);
+         memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight);
+         outw(VGAREG_GRDC_ADDRESS, 0x0005);
+        }
+       else
+        {// if Scroll up
+         if(dir==SCROLL_UP)
+          {for(i=rul;i<=rlr;i++)
+            {
+             if((i+nblines>rlr)||(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((i<rul+nblines)||(nblines==0))
+              vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
+             else
+              vgamem_copy_pl4(cul,i,i-nblines,cols,nbcols,cheight);
+            }
+          }
+        }
+       break;
+     case CGA:
+       bpp=vga_modes[line].pixbits;
+       if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
+        {
+         memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight*bpp);
+        }
+       else
+        {
+         if(bpp==2)
+          {
+           cul<<=1;
+           cols<<=1;
+           nbcols<<=1;
+          }
+         // if Scroll up
+         if(dir==SCROLL_UP)
+          {for(i=rul;i<=rlr;i++)
+            {
+             if((i+nblines>rlr)||(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<rul+nblines)||(nblines==0))
+              vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
+             else
+              vgamem_copy_cga(cul,i,i-nblines,cols,nbcols,cheight);
+            }
+          }
+        }
+       break;
+#ifdef DEBUG
+     default:
+       printf("Scroll in graphics mode ");
+       unimplemented();
+#endif
+    }
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_read_char_attr (page,car) 
+Bit8u page;Bit16u *car;
+{Bit16u ss=get_SS();
+ Bit8u xcurs,ycurs,mode,line;
+ 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;
+
+   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<cheight;i++)
+  {
+   dest=addr+i*nbcols;
+   for(j=0;j<8;j++)
+    {
+     mask=0x80>>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<nbcols))
+    {
+     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++;
+    }
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_char_only (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;
+
+   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<nbcols))
+    {
+     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++;
+    }
+  }
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_group_0B:
+  cmp   bh, #0x00
+  je    biosfn_set_border_color
+  cmp   bh, #0x01
+  je    biosfn_set_palette
+#ifdef DEBUG
+  call  _unknown
+#endif
+  ret
+biosfn_set_border_color:
+  push  ax
+  push  bx
+  push  cx
+  push  dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, #0x00
+  out   dx, al
+  mov   al, bl
+  and   al, #0x0f
+  test  al, #0x08
+  jz    set_low_border
+  add   al, #0x08
+set_low_border:
+  out   dx, al
+  mov   cl, #0x01
+  and   bl, #0x10
+set_intensity_loop:
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, cl
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  and   al, #0xef
+  or    al, bl
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  out   dx, al
+  inc   cl
+  cmp   cl, #0x04
+  jne   set_intensity_loop
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+  ret
+biosfn_set_palette:
+  push  ax
+  push  bx
+  push  cx
+  push  dx
+  mov   dx, # VGAREG_ACTL_RESET
+  in    al, dx
+  mov   cl, #0x01
+  and   bl, #0x01
+set_cga_palette_loop:
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  mov   al, cl
+  out   dx, al
+  mov   dx, # VGAREG_ACTL_READ_DATA
+  in    al, dx
+  and   al, #0xfe
+  or    al, bl
+  mov   dx, # VGAREG_ACTL_ADDRESS
+  out   dx, al
+  inc   cl
+  cmp   cl, #0x04
+  jne   set_cga_palette_loop
+  mov   al, #0x20
+  out   dx, al
+  pop   dx
+  pop   cx
+  pop   bx
+  pop   ax
+  ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_pixel (BH,AL,CX,DX) Bit8u BH;Bit8u AL;Bit16u CX;Bit16u DX;
+{
+ Bit8u mode,line,mask,attr,data;
+ Bit16u addr;
+
+ // 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);
+     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<CX;i++)
+  {
+   src = BP + i * BH;
+   dest = blockaddr + (DX + i) * 32;
+   memcpyb(0xA000, dest, ES, src, BH);
+  }
+ release_font_access();
+ if(AL>=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<format_width; i++) {
+          nibble = (arg >> (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 (file)
index 0000000..3ad4bae
--- /dev/null
@@ -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 (file)
index 0000000..0c213e6
--- /dev/null
@@ -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 (file)
index 0000000..e5eca1e
--- /dev/null
@@ -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 (file)
index 0000000..116692d
--- /dev/null
@@ -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 (file)
index 0000000..8190c76
--- /dev/null
@@ -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 (file)
index 0000000..2dcb229
--- /dev/null
@@ -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 <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <vm86.h>
+
+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 (file)
index 0000000..b183fac
--- /dev/null
@@ -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 (file)
index 0000000..0ea2adf
--- /dev/null
@@ -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 (file)
index 0000000..8049f8c
--- /dev/null
@@ -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 (file)
index 0000000..0576900
--- /dev/null
@@ -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 (file)
index 0000000..468da0a
--- /dev/null
@@ -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 (file)
index 0000000..0181fe7
--- /dev/null
@@ -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 <stdarg.h>
+
+#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 (file)
index 0000000..9c2982f
--- /dev/null
@@ -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 <stdarg.h>
+#include <vm86.h>
+
+#include <e820.h>
+#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 (file)
index 0000000..8c620a4
--- /dev/null
@@ -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[] = {
+       "<VM86_REAL>",
+       "<VM86_REAL_TO_PROTECTED>",
+       "<VM86_PROTECTED_TO_REAL>",
+       "<VM86_PROTECTED>"
+};
+
+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("<VM86_PROTECTED>\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 (file)
index 0000000..e0997e4
--- /dev/null
@@ -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 <stdint.h>
+#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 (file)
index 0000000..f987b0f
--- /dev/null
@@ -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 (file)
index 0000000..088519b
--- /dev/null
@@ -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 (file)
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 (file)
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 (file)
index 0000000..8bbb471
--- /dev/null
@@ -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 */
+