--- /dev/null
+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.
--- /dev/null
+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.
--- /dev/null
+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.
+
--- /dev/null
+# 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
+#=======================================================================
--- /dev/null
+# 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
--- /dev/null
+This file is just here to ensure that the directory exists.
--- /dev/null
+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
--- /dev/null
+This file is just here to ensure that the directory exists.
--- /dev/null
+This file is just here to ensure that the directory exists.
--- /dev/null
+This file is just here to ensure that the directory exists.
--- /dev/null
+This file is just here to ensure that the directory exists.
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+
+ 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));
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+#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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+#include "../libc/fmtout.h"
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+#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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+#ifndef REBOOT_H
+#define REBOOT_H
+
+void machine_real_restart();
+
+
+#endif
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+#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
--- /dev/null
+#include "../libc/string.h"
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+#! /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
--- /dev/null
+#! /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();
--- /dev/null
+#!/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";
+}
--- /dev/null
+#! /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
--- /dev/null
+#! /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);
+}
--- /dev/null
+#! /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";
+}
--- /dev/null
+#! /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
--- /dev/null
+#! /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";
--- /dev/null
+#! /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();
--- /dev/null
+#! /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();
+}
--- /dev/null
+#! /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);
+}
--- /dev/null
+#! /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";
--- /dev/null
+#!/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;
+
+
--- /dev/null
+#! /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();
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/***********************************************************
+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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+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.
--- /dev/null
+// 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
--- /dev/null
+; 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
--- /dev/null
+/* 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 */
--- /dev/null
+; 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
--- /dev/null
+; 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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)
+ );
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 ¤t->tlocalData[k];
+}
+
+/*
+ * Clean up any thread-local data upon thread exit. Assumes
+ * this is called with interrupts disabled. We follow the POSIX style
+ * of possibly invoking a destructor more than once, because a
+ * destructor to some thread-local data might cause other thread-local
+ * data to become alive once again. If everything is NULL by the end
+ * of an iteration, we are done.
+ */
+static void Tlocal_Exit(struct Kernel_Thread* curr) {
+ int i, j, called = 0;
+
+ KASSERT(!Interrupts_Enabled());
+
+ for (j = 0; 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(¤t->joinQueue);
+
+ /* Remove the thread's implicit reference to itself. */
+ Detach_Thread(g_currentThread);
+
+ /*
+ * Schedule a new thread.
+ * Since the old thread wasn't placed on any
+ * thread queue, it won't get scheduled again.
+ */
+ Schedule();
+
+ /* Shouldn't get here */
+ KASSERT(false);
+ // the build dies on a warning for a 'noreturn' violation
+ // This ensures that this function never returns
+ while(1);
+}
+
+/*
+ * Wait for given thread to die.
+ * Interrupts must be enabled.
+ * Returns the thread exit code.
+ */
+int Join(struct Kernel_Thread* kthread)
+{
+ int exitCode;
+
+ KASSERT(Interrupts_Enabled());
+
+ /* It is only legal for the owner to join */
+ KASSERT(kthread->owner == g_currentThread);
+
+ Disable_Interrupts();
+
+ /* Wait for it to die */
+ while (kthread->alive) {
+ Wait(&kthread->joinQueue);
+ }
+
+ /* Get thread exit code. */
+ exitCode = kthread->exitCode;
+
+ /* Release our reference to the thread */
+ Detach_Thread(kthread);
+
+ Enable_Interrupts();
+
+ return exitCode;
+}
+
+/*
+ * Look up a thread by its process id.
+ * The caller must be the thread's owner.
+ */
+struct Kernel_Thread* Lookup_Thread(int pid)
+{
+ struct Kernel_Thread *result = 0;
+
+ bool iflag = Begin_Int_Atomic();
+
+ /*
+ * TODO: we could remove the requirement that the caller
+ * needs to be the thread's owner by specifying that another
+ * reference is added to the thread before it is returned.
+ */
+
+ result = Get_Front_Of_All_Thread_List(&s_allThreadList);
+ while (result != 0) {
+ if (result->pid == pid) {
+ if (g_currentThread != result->owner)
+ result = 0;
+ break;
+ }
+ result = Get_Next_In_All_Thread_List(result);
+ }
+
+ End_Int_Atomic(iflag);
+
+ return result;
+}
+
+
+/*
+ * Wait on given wait queue.
+ * Must be called with interrupts disabled!
+ * Note that the function will return with interrupts
+ * disabled. This is desirable, because it allows us to
+ * atomically test a condition that can be affected by an interrupt
+ * and wait for it to be satisfied (if necessary).
+ * See the Wait_For_Key() function in keyboard.c
+ * for an example.
+ */
+void Wait(struct Thread_Queue* waitQueue)
+{
+ struct Kernel_Thread* current = g_currentThread;
+
+ KASSERT(!Interrupts_Enabled());
+
+ /* Add the thread to the wait queue. */
+ Enqueue_Thread(waitQueue, current);
+
+ /* Find another thread to run. */
+ Schedule();
+}
+
+/*
+ * Wake up all threads waiting on given wait queue.
+ * Must be called with interrupts disabled!
+ * See Keyboard_Interrupt_Handler() function in keyboard.c
+ * for an example.
+ */
+void Wake_Up(struct Thread_Queue* waitQueue)
+{
+ struct Kernel_Thread *kthread = waitQueue->head, *next;
+
+ KASSERT(!Interrupts_Enabled());
+
+ /*
+ * Walk throught the list of threads in the wait queue,
+ * transferring each one to the run queue.
+ */
+ while (kthread != 0) {
+ next = Get_Next_In_Thread_Queue(kthread);
+ Make_Runnable(kthread);
+ kthread = next;
+ }
+
+ /* The wait queue is now empty. */
+ Clear_Thread_Queue(waitQueue);
+}
+
+/*
+ * Wake up a single thread waiting on given wait queue
+ * (if there are any threads waiting). Chooses the highest priority thread.
+ * Interrupts must be disabled!
+ */
+void Wake_Up_One(struct Thread_Queue* waitQueue)
+{
+ struct Kernel_Thread* best;
+
+ KASSERT(!Interrupts_Enabled());
+
+ best = Find_Best(waitQueue);
+
+ if (best != 0) {
+ Remove_Thread(waitQueue, best);
+ Make_Runnable(best);
+ /*Print("Wake_Up_One: waking up %x from %x\n", best, g_currentThread); */
+ }
+}
+
+/*
+ * Allocate a key for accessing thread-local data.
+ */
+int Tlocal_Create(tlocal_key_t *key, tlocal_destructor_t destructor)
+{
+ KASSERT(key);
+
+ bool iflag = Begin_Int_Atomic();
+
+ if (s_tlocalKeyCounter == MAX_TLOCAL_KEYS) return -1;
+ s_tlocalDestructors[s_tlocalKeyCounter] = destructor;
+ *key = s_tlocalKeyCounter++;
+
+ End_Int_Atomic(iflag);
+
+ return 0;
+}
+
+/*
+ * Store a value for a thread-local item
+ */
+void Tlocal_Put(tlocal_key_t k, const void *v)
+{
+ const void **pv;
+
+ KASSERT(k < s_tlocalKeyCounter);
+
+ pv = Get_Tlocal_Pointer(k);
+ *pv = v;
+}
+
+/*
+ * Acquire a thread-local value
+ */
+void *Tlocal_Get(tlocal_key_t k)
+{
+ const void **pv;
+
+ KASSERT(k < s_tlocalKeyCounter);
+
+ pv = Get_Tlocal_Pointer(k);
+ return (void *)*pv;
+}
+
+/*
+ * Print list of all threads in system.
+ * For debugging.
+ */
+void Dump_All_Thread_List(void)
+{
+ struct Kernel_Thread *kthread;
+ int count = 0;
+ bool iflag = Begin_Int_Atomic();
+
+ kthread = Get_Front_Of_All_Thread_List(&s_allThreadList);
+
+ Print("[");
+ while (kthread != 0) {
+ ++count;
+ Print("<%lx,%lx,%lx>",
+ (ulong_t) Get_Prev_In_All_Thread_List(kthread),
+ (ulong_t) kthread,
+ (ulong_t) Get_Next_In_All_Thread_List(kthread));
+ KASSERT(kthread != Get_Next_In_All_Thread_List(kthread));
+ kthread = Get_Next_In_All_Thread_List(kthread);
+ }
+ Print("]\n");
+ Print("%d threads are running\n", count);
+
+ End_Int_Atomic(iflag);
+}
--- /dev/null
+; -*- 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)
--- /dev/null
+/*
+ * 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);
+}
+
+
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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");
+}
+
--- /dev/null
+#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)));
+}
--- /dev/null
+/*
+ * 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);
+}
+
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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");
+ }
+}
--- /dev/null
+; -*- 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
--- /dev/null
+#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;
+
+}
--- /dev/null
+; 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
--- /dev/null
+/*
+ * 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 */
+}
--- /dev/null
+# -*- 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
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+; 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
--- /dev/null
+#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");
+}
--- /dev/null
+%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
+
--- /dev/null
+#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");
+}
--- /dev/null
+#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;
+}
+
+
--- /dev/null
+; -*- 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
--- /dev/null
+#include <conio.h>
+#include <stddef.h>
+
+void *Malloc(size_t n)
+{
+ Print("Malloc not implemented in user mode\n");
+ return 0;
+}
--- /dev/null
+
+.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
+
--- /dev/null
+// 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
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+#!/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";
+ }
+ }
+}
--- /dev/null
+/////////////////////////////////////////////////////////////////////////
+// $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
--- /dev/null
+Not all the functions have been implemented yet.
+
+Please report any bugs to <info@vruppert.de>
--- /dev/null
+ 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!
+
+
--- /dev/null
+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
+
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
+
--- /dev/null
+/* 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;
+}
--- /dev/null
+//
+// 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
--- /dev/null
+#!/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
--- /dev/null
+// ============================================================================================
+//
+// 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)
+{
+}
--- /dev/null
+#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
--- /dev/null
+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.
--- /dev/null
+#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
--- /dev/null
+// ============================================================================================
+/*
+ * 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
--- /dev/null
+#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
--- /dev/null
+/*
+ * 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};
--- /dev/null
+/*
+ *
+ * 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
+};
--- /dev/null
+#
+# 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
+
--- /dev/null
+#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__ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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:
+
--- /dev/null
+/*
+ * 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__ */
+
--- /dev/null
+/* 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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"
+
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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 = .;
+}
+
--- /dev/null
+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 */
+