aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.rootkeys95
-rw-r--r--BitKeeper/etc/ignore13
-rw-r--r--BitKeeper/etc/logging_ok1
-rw-r--r--docs/src/user.tex10
-rw-r--r--linux-2.4.30-xen-sparse/arch/xen/kernel/setup.c2
-rw-r--r--linux-2.6.11-xen-sparse/arch/xen/i386/kernel/cpu/common.c2
-rw-r--r--linux-2.6.11-xen-sparse/arch/xen/i386/kernel/setup.c8
-rw-r--r--linux-2.6.11-xen-sparse/arch/xen/i386/mm/hypervisor.c4
-rw-r--r--linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c47
-rw-r--r--linux-2.6.11-xen-sparse/arch/xen/kernel/gnttab.c5
-rw-r--r--linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/setup.c9
-rw-r--r--linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/setup64.c4
-rw-r--r--linux-2.6.11-xen-sparse/arch/xen/x86_64/mm/hypervisor.c4
-rw-r--r--linux-2.6.11-xen-sparse/drivers/xen/blktap/blktap_controlmsg.c1
-rw-r--r--linux-2.6.11-xen-sparse/drivers/xen/blktap/blktap_datapath.c18
-rw-r--r--linux-2.6.11-xen-sparse/drivers/xen/blktap/blktap_userdev.c11
-rw-r--r--linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/synch_bitops.h40
-rw-r--r--linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h23
-rw-r--r--linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/system.h18
-rw-r--r--tools/Makefile1
-rw-r--r--tools/blktap/Makefile40
-rw-r--r--tools/blktap/blkint.h105
-rw-r--r--tools/blktap/blktaplib.c30
-rw-r--r--tools/blktap/blktaplib.h50
-rwxr-xr-xtools/blktap/block-async.c479
-rwxr-xr-xtools/blktap/block-async.h40
-rw-r--r--tools/blktap/blockstore.c1
-rw-r--r--tools/blktap/parallax-threaded.c654
-rw-r--r--tools/blktap/parallax-threaded.h24
-rw-r--r--tools/blktap/parallax.c170
-rw-r--r--tools/blktap/radix.c1
-rwxr-xr-xtools/blktap/requests-async.c345
-rwxr-xr-xtools/blktap/requests-async.h14
-rw-r--r--tools/blktap/snaplog.c1
-rw-r--r--tools/blktap/vdi.c26
-rw-r--r--tools/blktap/vdi.h3
-rw-r--r--tools/blktap/vdi_fill.c7
-rw-r--r--tools/blktap/vdi_unittest.c184
-rw-r--r--tools/blktap/vdi_validate.c21
-rw-r--r--tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/Makefile.in (renamed from tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/Makefile.in)2
-rwxr-xr-xtools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure (renamed from tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure)2
-rw-r--r--tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.in (renamed from tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.in)2
-rw-r--r--tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.srv (renamed from tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.srv)0
-rw-r--r--tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c (renamed from tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c)0
-rw-r--r--tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c (renamed from tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c)0
-rwxr-xr-xtools/debugger/gdb/gdb-6.2.1-xen-sparse/mkbuildtree (renamed from tools/gdb/gdb-6.2.1-xen-sparse/mkbuildtree)0
-rwxr-xr-xtools/debugger/gdb/gdbbuild (renamed from tools/gdb/gdbbuild)8
-rw-r--r--tools/debugger/libxendebug/Makefile72
-rw-r--r--tools/debugger/libxendebug/list.h186
-rw-r--r--tools/debugger/libxendebug/xendebug.c599
-rw-r--r--tools/debugger/libxendebug/xendebug.h78
-rw-r--r--tools/debugger/pdb/Domain.ml63
-rw-r--r--tools/debugger/pdb/Domain.mli38
-rw-r--r--tools/debugger/pdb/Intel.ml71
-rw-r--r--tools/debugger/pdb/Makefile56
-rw-r--r--tools/debugger/pdb/OCamlMakefile1149
-rw-r--r--tools/debugger/pdb/PDB.ml180
-rw-r--r--tools/debugger/pdb/Process.ml39
-rw-r--r--tools/debugger/pdb/Process.mli20
-rw-r--r--tools/debugger/pdb/Util.ml153
-rw-r--r--tools/debugger/pdb/debugger.ml315
-rw-r--r--tools/debugger/pdb/evtchn.ml32
-rw-r--r--tools/debugger/pdb/evtchn.mli14
-rw-r--r--tools/debugger/pdb/pdb_caml_xc.c732
-rw-r--r--tools/debugger/pdb/pdb_xen.c93
-rw-r--r--tools/debugger/pdb/server.ml219
-rw-r--r--tools/firmware/Makefile34
-rw-r--r--tools/firmware/README88
-rw-r--r--tools/firmware/rombios/Makefile58
-rw-r--r--tools/firmware/rombios/apmbios.S329
-rw-r--r--tools/firmware/rombios/biossums.c478
-rwxr-xr-xtools/firmware/rombios/makesym.perl31
-rw-r--r--tools/firmware/rombios/rombios.c10825
-rw-r--r--tools/firmware/rombios/rombios.diffs206
-rw-r--r--tools/firmware/vgabios/BUGS3
-rw-r--r--tools/firmware/vgabios/COPYING504
-rw-r--r--tools/firmware/vgabios/ChangeLog1060
-rw-r--r--tools/firmware/vgabios/Makefile77
-rw-r--r--tools/firmware/vgabios/Notes11
-rw-r--r--tools/firmware/vgabios/README191
-rw-r--r--tools/firmware/vgabios/TODO28
-rw-r--r--tools/firmware/vgabios/biossums.c200
-rw-r--r--tools/firmware/vgabios/clext.c1587
-rwxr-xr-xtools/firmware/vgabios/dataseghack23
-rw-r--r--tools/firmware/vgabios/vbe.c1068
-rw-r--r--tools/firmware/vgabios/vbe.h302
-rw-r--r--tools/firmware/vgabios/vbe_display_api.txt227
-rw-r--r--tools/firmware/vgabios/vbetables.h1282
-rw-r--r--tools/firmware/vgabios/vgabios.c3608
-rw-r--r--tools/firmware/vgabios/vgabios.h47
-rw-r--r--tools/firmware/vgabios/vgafonts.h784
-rw-r--r--tools/firmware/vgabios/vgatables.h318
-rw-r--r--tools/firmware/vmxassist/Makefile84
-rw-r--r--tools/firmware/vmxassist/TODO8
-rw-r--r--tools/firmware/vmxassist/gen.c52
-rw-r--r--tools/firmware/vmxassist/head.S162
-rw-r--r--tools/firmware/vmxassist/machine.h203
-rwxr-xr-xtools/firmware/vmxassist/mkhex26
-rw-r--r--tools/firmware/vmxassist/setup.c338
-rw-r--r--tools/firmware/vmxassist/trap.S189
-rw-r--r--tools/firmware/vmxassist/util.c364
-rw-r--r--tools/firmware/vmxassist/util.h41
-rw-r--r--tools/firmware/vmxassist/vm86.c956
-rw-r--r--tools/firmware/vmxassist/vm86.h67
-rw-r--r--tools/firmware/vmxassist/vmxassist.ld34
-rw-r--r--tools/firmware/vmxassist/vmxloader.c110
-rw-r--r--tools/ioemu/hw/i8254.c62
-rw-r--r--tools/ioemu/hw/i8259.c1
-rw-r--r--tools/libxc/Makefile2
-rw-r--r--tools/libxc/xc.h9
-rw-r--r--tools/libxc/xc_evtchn.c18
-rw-r--r--tools/libxc/xc_gnttab.c14
-rw-r--r--tools/libxc/xc_linux_build.c483
-rw-r--r--tools/libxc/xc_load_bin.c299
-rw-r--r--tools/libxc/xc_load_elf.c310
-rw-r--r--tools/libxc/xc_misc.c28
-rw-r--r--tools/libxc/xc_plan9_build.c6
-rw-r--r--tools/libxc/xc_private.c9
-rw-r--r--tools/libxc/xc_private.h69
-rw-r--r--tools/libxc/xc_vmx_build.c22
-rw-r--r--tools/python/xen/lowlevel/xc/xc.c14
-rw-r--r--tools/xcs/xcsdump.c3
-rw-r--r--xen/arch/ia64/Makefile2
-rw-r--r--xen/arch/ia64/asm-offsets.c1
-rw-r--r--xen/arch/ia64/dom0_ops.c3
-rw-r--r--xen/arch/ia64/domain.c6
-rw-r--r--xen/arch/ia64/hpsimserial.c23
-rw-r--r--xen/arch/ia64/irq.c22
-rw-r--r--xen/arch/ia64/patch/linux-2.6.11/setup.c43
-rw-r--r--xen/arch/ia64/pcdp.c120
-rw-r--r--xen/arch/ia64/pdb-stub.c2
-rw-r--r--xen/arch/ia64/tools/mkbuildtree2
-rw-r--r--xen/arch/ia64/vmmu.c1
-rw-r--r--xen/arch/ia64/xensetup.c99
-rw-r--r--xen/arch/x86/acpi/boot.c177
-rw-r--r--xen/arch/x86/audit.c16
-rw-r--r--xen/arch/x86/cdb.c5
-rw-r--r--xen/arch/x86/dom0_ops.c5
-rw-r--r--xen/arch/x86/domain.c4
-rw-r--r--xen/arch/x86/domain_build.c33
-rw-r--r--xen/arch/x86/extable.c1
-rw-r--r--xen/arch/x86/i8259.c174
-rw-r--r--xen/arch/x86/io_apic.c2563
-rw-r--r--xen/arch/x86/irq.c124
-rw-r--r--xen/arch/x86/mm.c278
-rw-r--r--xen/arch/x86/physdev.c3
-rw-r--r--xen/arch/x86/setup.c8
-rw-r--r--xen/arch/x86/shadow.c205
-rw-r--r--xen/arch/x86/smp.c23
-rw-r--r--xen/arch/x86/smpboot.c6
-rw-r--r--xen/arch/x86/traps.c3
-rw-r--r--xen/arch/x86/usercopy.c (renamed from xen/arch/x86/x86_64/usercopy.c)90
-rw-r--r--xen/arch/x86/vmx.c19
-rw-r--r--xen/arch/x86/vmx_io.c10
-rw-r--r--xen/arch/x86/vmx_platform.c40
-rw-r--r--xen/arch/x86/vmx_vmcs.c32
-rw-r--r--xen/arch/x86/x86_32/domain_page.c32
-rw-r--r--xen/arch/x86/x86_32/mm.c4
-rw-r--r--xen/arch/x86/x86_32/traps.c25
-rw-r--r--xen/arch/x86/x86_32/usercopy.c443
-rw-r--r--xen/common/dom0_ops.c14
-rw-r--r--xen/common/dom_mem_ops.c1
-rw-r--r--xen/common/domain.c43
-rw-r--r--xen/common/elf.c18
-rw-r--r--xen/common/event_channel.c364
-rw-r--r--xen/common/page_alloc.c10
-rw-r--r--xen/drivers/char/console.c121
-rw-r--r--xen/drivers/char/ns16550.c47
-rw-r--r--xen/drivers/char/serial.c175
-rw-r--r--xen/include/asm-ia64/config.h3
-rw-r--r--xen/include/asm-ia64/domain_page.h14
-rw-r--r--xen/include/asm-ia64/init.h2
-rw-r--r--xen/include/asm-ia64/mm.h2
-rw-r--r--xen/include/asm-x86/config.h5
-rw-r--r--xen/include/asm-x86/debugger.h9
-rw-r--r--xen/include/asm-x86/domain_page.h5
-rw-r--r--xen/include/asm-x86/hardirq.h4
-rw-r--r--xen/include/asm-x86/io_apic.h38
-rw-r--r--xen/include/asm-x86/irq.h27
-rw-r--r--xen/include/asm-x86/multicall.h8
-rw-r--r--xen/include/asm-x86/page.h12
-rw-r--r--xen/include/asm-x86/shadow.h18
-rw-r--r--xen/include/asm-x86/string.h398
-rw-r--r--xen/include/asm-x86/types.h22
-rw-r--r--xen/include/asm-x86/uaccess.h253
-rw-r--r--xen/include/asm-x86/x86_32/domain_page.h80
-rw-r--r--xen/include/asm-x86/x86_32/page-3level.h10
-rw-r--r--xen/include/asm-x86/x86_32/string.h489
-rw-r--r--xen/include/asm-x86/x86_32/uaccess.h301
-rw-r--r--xen/include/asm-x86/x86_64/domain_page.h21
-rw-r--r--xen/include/asm-x86/x86_64/string.h16
-rw-r--r--xen/include/asm-x86/x86_64/uaccess.h248
-rw-r--r--xen/include/public/dom0_ops.h8
-rw-r--r--xen/include/public/event_channel.h41
-rw-r--r--xen/include/public/xen.h31
-rw-r--r--xen/include/xen/console.h6
-rw-r--r--xen/include/xen/domain_page.h100
-rw-r--r--xen/include/xen/event.h7
-rw-r--r--xen/include/xen/irq.h1
-rw-r--r--xen/include/xen/perfc_defn.h221
-rw-r--r--xen/include/xen/sched.h37
-rw-r--r--xen/include/xen/serial.h40
-rw-r--r--xen/include/xen/smp.h1
203 files changed, 35545 insertions, 6359 deletions
diff --git a/.rootkeys b/.rootkeys
index ae7543d74c..6be475bc10 100644
--- a/.rootkeys
+++ b/.rootkeys
@@ -480,7 +480,6 @@
4209033ewLAHdhGrT_2jo3Gb_5bDcA tools/blktap/README
42277b02mYXxgijE7MFeUe9d8eldMw tools/blktap/README-PARALLAX
4209033fHgtGpb_K16_xC9CpkjNZLw tools/blktap/blkdump.c
-42090340_mvZtozMjghPJO0qsjk4NQ tools/blktap/blkint.h
42090340rc2q1wmlGn6HtiJAkqhtNQ tools/blktap/blktaplib.c
42090340C-WkRPT7N3t-8Lzehzogdw tools/blktap/blktaplib.h
428df8fdkg84W8yveE50EbkbTUZgjQ tools/blktap/block-async.c
@@ -489,8 +488,6 @@
42277b02P1C0FYj3gqwTZUD8sxKCug tools/blktap/blockstore.h
42371b8aL1JsxAXOd4bBhmZKDyjiJg tools/blktap/blockstored.c
42371b8aD_x3L9MKsXciMNqkuk58eQ tools/blktap/bstest.c
-423f270cbEKiTMapKnCyqkuwGvgOMA tools/blktap/parallax-threaded.c
-423f270cFdXryIcD7HTPUl_Dbk4DAQ tools/blktap/parallax-threaded.h
42277b03930x2TJT3PZlw6o0GERXpw tools/blktap/parallax.c
42277b03XQYq8bujXSz7JAZ8N7j_pA tools/blktap/radix.c
42277b03vZ4-jno_mgKmAcCW3ycRAg tools/blktap/radix.h
@@ -507,6 +504,7 @@
423f270c_QDjGLQ_YdaOtyBM5n9BDg tools/blktap/vdi_snap_delete.c
42277b043Fjy5-H7LyBtUPyDlZFo6A tools/blktap/vdi_snap_list.c
42277b04vhqD6Lq3WmGbaESoAAKdhw tools/blktap/vdi_tree.c
+42277b04RnFo07c1LcdmLn-FtRJEmw tools/blktap/vdi_unittest.c
42277b047H8fTVyUf75BWAjh6Zpsqg tools/blktap/vdi_validate.c
4124b307nRyK3dhn1hAsvrY76NuV3g tools/check/Makefile
4124b307vHLUWbfpemVefmaWDcdfag tools/check/README
@@ -519,6 +517,33 @@
4124b307lnAATmulpXYa0M-dzxLBDA tools/check/check_zlib_devel
4124b308ly20ptMKQoiztPyP_X68Mw tools/check/check_zlib_lib
4124b308O8yPHMKbj4YPR_grPGZmdA tools/check/chk
+423d3a7bpoTFd0vqFaocQ-FqC8RuPA tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/Makefile.in
+423d3a7b_HtKYGocoTS1adeOpqDFnw tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure
+423d3a7b2vJq86I8FbYm6up5BsCwfA tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.in
+423d3a7bQPownmVb63qOoyq89ebBVA tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.srv
+423d3a7bHtqhyOgiRWhjWt-S-6wbYg tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c
+4273458dYPghQKVnj_xu5-fC38CcOg tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c
+423d3a7b2ENk2IskDZYZ98pe5NsvIA tools/debugger/gdb/gdb-6.2.1-xen-sparse/mkbuildtree
+423d3a7buANO_q-kgxIRffUu7lMnUw tools/debugger/gdb/gdbbuild
+42a1a777Dt8l7bna7fm1vKmTEX1FCQ tools/debugger/libxendebug/Makefile
+42a0c8d8qbLfvuvDUA0tFB9nHMh-zg tools/debugger/libxendebug/list.h
+42a0c8d98XtmbhyddBgIyyHllz5WTw tools/debugger/libxendebug/xendebug.c
+42a0c8d9ucRxWO41IHTfYI7xYGoKrw tools/debugger/libxendebug/xendebug.h
+42a0c8d9zuGuWoaTux5NW4N3wOw8pg tools/debugger/pdb/Domain.ml
+42a0c8d9pigEXFFtdut3R99jbf73NA tools/debugger/pdb/Domain.mli
+42a0c8d93wnR_hcSAa7VHgn8CSrWEA tools/debugger/pdb/Intel.ml
+42a0c8d95glt-jkgXe8GDOPT6TYN6Q tools/debugger/pdb/Makefile
+42a0c8d9UueJDF0IRX3OozEvUhSTmw tools/debugger/pdb/OCamlMakefile
+42a0c8d9PgBvaWPzTHSFb9ngii7c7w tools/debugger/pdb/PDB.ml
+42a0c8danHHGiNywdeer6j4jzxAc2A tools/debugger/pdb/Process.ml
+42a0c8dav_08OtySI4kYP1lahlVrpQ tools/debugger/pdb/Process.mli
+42a0c8da51EqubQT5PJ4sxCKLF3xSw tools/debugger/pdb/Util.ml
+42a0c8daxftpiXuvLmc9fOOEhdFWiQ tools/debugger/pdb/debugger.ml
+42a0c8da81tzhpvIAfkx9nZqUNrQvg tools/debugger/pdb/evtchn.ml
+42a0c8dasiso9c-2sCvHBzP6YVjATA tools/debugger/pdb/evtchn.mli
+42a0c8daXD_6Y62A_u5-PO_Klrhi0w tools/debugger/pdb/pdb_caml_xc.c
+42a0c8danJXun9ay5SPBhhkKvuUPfg tools/debugger/pdb/pdb_xen.c
+42a0c8dbjK6Du89D2SUcxsuAdlUu3w tools/debugger/pdb/server.ml
401d7e160vaxMBAUSLSicuZ7AQjJ3w tools/examples/Makefile
401d7e16UgeqroJQTIhwkrDVkoWgZQ tools/examples/README
41597996VhTbNuHbuscYSfRb-WR6fA tools/examples/block-enbd
@@ -540,14 +565,46 @@
41090ec8Pj_bkgCBpg2W7WfmNkumEA tools/examples/xmexample1
40cf2937oKlROYOJTN8GWwWM5AmjBg tools/examples/xmexample2
41fc0c18_k4iL81hu4pMIWQu9dKpKA tools/examples/xmexample3
-423d3a7bpoTFd0vqFaocQ-FqC8RuPA tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/Makefile.in
-423d3a7b_HtKYGocoTS1adeOpqDFnw tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure
-423d3a7b2vJq86I8FbYm6up5BsCwfA tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.in
-423d3a7bQPownmVb63qOoyq89ebBVA tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.srv
-423d3a7bHtqhyOgiRWhjWt-S-6wbYg tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c
-4273458dYPghQKVnj_xu5-fC38CcOg tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c
-423d3a7b2ENk2IskDZYZ98pe5NsvIA tools/gdb/gdb-6.2.1-xen-sparse/mkbuildtree
-423d3a7buANO_q-kgxIRffUu7lMnUw tools/gdb/gdbbuild
+42a6b4b7KssGzTDVN-XG2FM1gCEnnw tools/firmware/Makefile
+42a6b4b7qP95OSsEL8XWKKZ1p1myjQ tools/firmware/README
+42a6b4b78PWdYzKYvLt_EHhvQCl9ig tools/firmware/rombios/Makefile
+42a6b4b75sz5KF9Lry2EGnPMhOdnUA tools/firmware/rombios/apmbios.S
+42a6b4b7YwP9rl3AJRTmZbBoal_c6Q tools/firmware/rombios/biossums.c
+42a6b4b83gANosDYd43YaK7ATQvBEg tools/firmware/rombios/makesym.perl
+42a6b4b8qcIQIBXDeOY3JRwsLM6lhw tools/firmware/rombios/rombios.c
+42a6b4b8K7yqnU3-QxndYNZUgHpniw tools/firmware/rombios/rombios.diffs
+42a6b4b86GMM969Y82nK3HuUi6eP9g tools/firmware/vgabios/BUGS
+42a6b4b8J_MHMVmmF_igI7zeDxSiwA tools/firmware/vgabios/COPYING
+42a6b4b8SYW5q21pPPuQt88Bkpqc2Q tools/firmware/vgabios/ChangeLog
+42a6b4b8INe7qe20YYlwATaAADEMQA tools/firmware/vgabios/Makefile
+42a6b4b8AYFCsoAeqqQ8dibmgxkfLA tools/firmware/vgabios/Notes
+42a6b4b8NUXHh1hudvvNCuqgo9cB-Q tools/firmware/vgabios/README
+42a6b4b8MM0Pj6uDwdJ4Eyg6hB-oEA tools/firmware/vgabios/TODO
+42a6b4b8AL0YrgudjmQr7QvJ3we1Cg tools/firmware/vgabios/biossums.c
+42a6b4b8Zce-r8OtpctwvqHBS8cHEw tools/firmware/vgabios/clext.c
+42a6b4b8fIyMd0d8tIPV4JDAvB5l1A tools/firmware/vgabios/dataseghack
+42a6b4b8M4BsNDRAJMHpY8H2iRu0qA tools/firmware/vgabios/vbe.c
+42a6b4b8Z2pSU4e5qrUR5r1vEKNbKQ tools/firmware/vgabios/vbe.h
+42a6b4b8EyiklW2C9eD9_t0OmRfmFQ tools/firmware/vgabios/vbe_display_api.txt
+42a6b4b8oXcw5CgLj-mBVT4dUc-Umw tools/firmware/vgabios/vbetables.h
+42a6b4b85jkZnCar41YreYVUAY7IDQ tools/firmware/vgabios/vgabios.c
+42a6b4b8xxpRYh1BesaSgW3gpgMsaQ tools/firmware/vgabios/vgabios.h
+42a6b4b8WSA5xHF-R5F8iBcB6BC5wA tools/firmware/vgabios/vgafonts.h
+42a6b4b9C66bPuUTaLjCnJ0I-kGz9w tools/firmware/vgabios/vgatables.h
+42a6b4b969QLJRt3TU_v3yYhZI45Gg tools/firmware/vmxassist/Makefile
+42a6b4b95iuk7M2s-edoSFrWcdoYcw tools/firmware/vmxassist/TODO
+42a6b4b9Q6VB27GxRNCARsDN2ZuKNw tools/firmware/vmxassist/gen.c
+42a6b4b9NmLjb36-sXiiWzcGHjTOJA tools/firmware/vmxassist/head.S
+42a6b4b9jmF9m22iiwu8XwEm1j5fnQ tools/firmware/vmxassist/machine.h
+42a6b4b9ABmGHA1LzYjpq63FBs4hcw tools/firmware/vmxassist/mkhex
+42a6b4b9xmj4TLHJtV-DhnwT9mMpfw tools/firmware/vmxassist/setup.c
+42a6b4b9PjgANTP8Y8JFTToBrV9ssg tools/firmware/vmxassist/trap.S
+42a6b4b9GlymU0VmQyan23pagDaRTQ tools/firmware/vmxassist/util.c
+42a6b4b9mmqUyFn487gP4spU_R6xtg tools/firmware/vmxassist/util.h
+42a6b4b9JssxvlpcV_-QcGRMDGgL_w tools/firmware/vmxassist/vm86.c
+42a6b4b92oUAJMzCE-YcVlA2Z-2zyg tools/firmware/vmxassist/vm86.h
+42a6b4b9TlkVUYTkLd_Bvq9vlrEx6g tools/firmware/vmxassist/vmxassist.ld
+42a6b4b92L-2zFg-Qal6YweeE-pMiA tools/firmware/vmxassist/vmxloader.c
428d0d82yOaUzYQuYQxH7VzQytKo-g tools/ioemu/COPYING
428d0d82EdPp1TqJBembLgyB1y413w tools/ioemu/COPYING.LIB
428d0d82fd6-QydvFfHmeQBGrKnrrA tools/ioemu/Changelog
@@ -693,6 +750,8 @@
3fbba6dbNCU7U6nsMYiXzKkp3ztaJg tools/libxc/xc_linux_build.c
3fbba6dbl267zZOAVHYLOdLCdhcZMw tools/libxc/xc_linux_restore.c
3fbba6db7li3FJiABYtCmuGxOJxEGw tools/libxc/xc_linux_save.c
+42a40bc3vE3p9fPSJZQZK0MdQF9B8g tools/libxc/xc_load_bin.c
+42a40bc4diWfFsPGf0RW7qXMufU4YQ tools/libxc/xc_load_elf.c
3fbba6db7WnnJr0KFrIFrqNlSKvFYg tools/libxc/xc_misc.c
4051bce6CHAsYh8P5t2OHDtRWOP9og tools/libxc/xc_physdev.c
41cc934aO1m6NxEh_8eDr9bJIMoLFA tools/libxc/xc_plan9_build.c
@@ -1055,6 +1114,7 @@
421098b2PHgzf_Gg4R65YRNi_QzMKQ xen/arch/ia64/dom0_ops.c
421098b2O7jsNfzQXA1v3rbAc1QhpA xen/arch/ia64/dom_fw.c
421098b2ZlaBcyiuuPr3WpzaSDwg6Q xen/arch/ia64/domain.c
+42a08294zRikvZk_CR1iVojHjcVFZw xen/arch/ia64/hpsimserial.c
4239e98a_HX-FCIcXtVqY0BbrDqVug xen/arch/ia64/hypercall.c
4295e18f42gf1T-8W97A3KSlBaY1tA xen/arch/ia64/hyperprivop.S
421098b3LYAS8xJkQiGP7tiTlyBt0Q xen/arch/ia64/idle0_task.c
@@ -1135,6 +1195,7 @@
421098b5DWbgK-tBR4um8PEAqPwqTA xen/arch/ia64/patch/linux-2.6.7/types.h
421098b5il9YfZM0HpeCnaMgVN_q9g xen/arch/ia64/patch/linux-2.6.7/unaligned.c
421098b65M5cPramsLGbODg8lQwUjQ xen/arch/ia64/patch/linux-2.6.7/wait.h
+42a0d69cCiNxr2Y1GY1khO7qRiNkbw xen/arch/ia64/pcdp.c
421098b6cYDwzXP86ViTLlTO2x7ovA xen/arch/ia64/pdb-stub.c
41a26ebcqaSGVQ8qTMwpPwOJSJ7qSw xen/arch/ia64/privop.c
41a26ebc4BOHDUsT0TSnryPeV2xfRA xen/arch/ia64/process.c
@@ -1232,6 +1293,7 @@
3ddb79bc-Udq7ol-NX4q9XsYnN7A2Q xen/arch/x86/time.c
3ddb79bccYVzXZJyVaxuv5T42Z1Fsw xen/arch/x86/trampoline.S
3ddb79bcOftONV9h4QCxXOfiT0h91w xen/arch/x86/traps.c
+40e96d3ahBTZqbTViInnq0lM03vs7A xen/arch/x86/usercopy.c
41c0c411tD3C7TpfDMiFTf7BaNd_Dg xen/arch/x86/vmx.c
420951dcf1rSGnCH0AEYN2KjWGLG6A xen/arch/x86/vmx_intercept.c
41c0c411ODt8uEmV-yUxpQLpqimE5Q xen/arch/x86/vmx_io.c
@@ -1243,13 +1305,11 @@
3ddb79bcHwuCQDjBICDTSis52hWguw xen/arch/x86/x86_32/mm.c
40f92331jfOlE7MfKwpdkEb1CEf23g xen/arch/x86/x86_32/seg_fixup.c
42000d3ckiFc1qxa4AWqsd0t3lxuyw xen/arch/x86/x86_32/traps.c
-3ddb79bc4nTpGQOe6_-MbyZzkhlhFQ xen/arch/x86/x86_32/usercopy.c
3ddb79bcOMCu9-5mKpjIh5d0qqBDPg xen/arch/x86/x86_32/xen.lds
41bf1717Ty3hwN3E9swdu8QfnvGqww xen/arch/x86/x86_64/asm-offsets.c
40e96d3aLDI-nViMuYneD7VKYlZrVg xen/arch/x86/x86_64/entry.S
41bf1717XhPz_dNT5OKSjgmbFuWBuA xen/arch/x86/x86_64/mm.c
42000d3cMb8o1WuFBXC07c8i3lPZBw xen/arch/x86/x86_64/traps.c
-40e96d3ahBTZqbTViInnq0lM03vs7A xen/arch/x86/x86_64/usercopy.c
40e96d3akN3Hu_J5Bk-WXD8OGscrYQ xen/arch/x86/x86_64/xen.lds
422f27c8J9DQfCpegccMid59XhSmGA xen/arch/x86/x86_emulate.c
3ddb79bdff-gj-jFGKjOejeHLqL8Lg xen/common/Makefile
@@ -1308,7 +1368,6 @@
421098b6ZcIrn_gdqjUtdJyCE0YkZQ xen/include/asm-ia64/debugger.h
421098b6z0zSuW1rcSJK1gR8RUi-fw xen/include/asm-ia64/dom_fw.h
421098b6Nn0I7hGB8Mkd1Cis0KMkhA xen/include/asm-ia64/domain.h
-4241e879ry316Y_teC18DuK7mGKaQw xen/include/asm-ia64/domain_page.h
4241e880hAyo_dk0PPDYj3LsMIvf-Q xen/include/asm-ia64/flushtlb.h
421098b6X3Fs2yht42TE2ufgKqt2Fw xen/include/asm-ia64/ia64_int.h
421098b7psFAn8kbeR-vcRCdc860Vw xen/include/asm-ia64/init.h
@@ -1356,7 +1415,6 @@
3ddb79c34BFiXjBJ_cCKB0aCsV1IDw xen/include/asm-x86/desc.h
40715b2dTokMLYGSuD58BnxOqyWVew xen/include/asm-x86/div64.h
4204e7acwzqgXyTAPKa1nM-L7Ec0Qw xen/include/asm-x86/domain.h
-41febc4bBKTKHhnAu_KPYwgNkHjFlg xen/include/asm-x86/domain_page.h
41d3eaaeIBzW621S1oa0c2yk7X43qQ xen/include/asm-x86/e820.h
3ddb79c3NU8Zy40OTrq3D-i30Y3t4A xen/include/asm-x86/fixmap.h
3e2d29944GI24gf7vOP_7x8EyuqxeA xen/include/asm-x86/flushtlb.h
@@ -1410,7 +1468,7 @@
3ddb79c3Hgbb2g8CyWLMCK-6_ZVQSQ xen/include/asm-x86/smp.h
3ddb79c3jn8ALV_S9W5aeTYUQRKBpg xen/include/asm-x86/smpboot.h
3ddb79c3NiyQE2vQnyGiaBnNjBO1rA xen/include/asm-x86/spinlock.h
-40e1966akOHWvvunCED7x3HPv35QvQ xen/include/asm-x86/string.h
+3e7f358aG11EvMI9VJ4_9hD4LUO7rQ xen/include/asm-x86/string.h
3ddb79c3ezddh34MdelJpa5tNR00Dw xen/include/asm-x86/system.h
42033fc1Bb8ffTshBYFGouGkiAMoUQ xen/include/asm-x86/time.h
3ddb79c4HugMq7IYGxcQKFBpKwKhzA xen/include/asm-x86/types.h
@@ -1422,18 +1480,14 @@
420951dcqyUCe_gXA_XJPu1ix_poKg xen/include/asm-x86/vmx_virpit.h
41c0c412lQ0NVVN9PsOSznQ-qhOiPA xen/include/asm-x86/vmx_vmcs.h
418fbcfe_WliJPToeVM-9VStvym-hw xen/include/asm-x86/x86_32/asm_defns.h
-3e20b82fl1jmQiKdLy7fxMcutfpjWA xen/include/asm-x86/x86_32/domain_page.h
429c852fi3pvfa9kIjryYK5AGBmXAg xen/include/asm-x86/x86_32/page-2level.h
429c852fskvSOgcD5EC25_m9um9t4g xen/include/asm-x86/x86_32/page-3level.h
4208e2a3ZNFroNXbX9OYaOB-xtUyDQ xen/include/asm-x86/x86_32/page.h
3ddb79c3mbqEM7QQr3zVq7NiBNhouA xen/include/asm-x86/x86_32/regs.h
-3e7f358aG11EvMI9VJ4_9hD4LUO7rQ xen/include/asm-x86/x86_32/string.h
3ddb79c3M2n1ROZH6xk3HbyN4CPDqg xen/include/asm-x86/x86_32/uaccess.h
41bf1717bML6GxpclTWJabiaO5W5vg xen/include/asm-x86/x86_64/asm_defns.h
-41febc4b1aCGLsm0Y0b_82h7lFtrEA xen/include/asm-x86/x86_64/domain_page.h
4208e2a3Fktw4ZttKdDxbhvTQ6brfQ xen/include/asm-x86/x86_64/page.h
404f1bb86rAXB3aLS1vYdcqpJiEcyg xen/include/asm-x86/x86_64/regs.h
-40e1966azOJZfNI6Ilthe6Q-T3Hewg xen/include/asm-x86/x86_64/string.h
404f1bc4tWkB9Qr8RkKtZGW5eMQzhw xen/include/asm-x86/x86_64/uaccess.h
422f27c8RHFkePhD34VIEpMMqofZcA xen/include/asm-x86/x86_emulate.h
400304fcmRQmDdFYEzDh0wcBba9alg xen/include/public/COPYING
@@ -1468,6 +1522,7 @@
3ddb79c05DdHQ0UxX_jKsXdR4QlMCA xen/include/xen/delay.h
4294b5efxcDdUVp4XMEE__IFw7nPow xen/include/xen/dmi.h
40f2b4a2hC3HtChu-ArD8LyojxWMjg xen/include/xen/domain.h
+3e20b82fl1jmQiKdLy7fxMcutfpjWA xen/include/xen/domain_page.h
3ddb79c2O729EttZTYu1c8LcsUO_GQ xen/include/xen/elf.h
3ddb79c0HIghfBF8zFUdmXhOU8i6hA xen/include/xen/errno.h
3ddb79c1W0lQca8gRV7sN6j3iY4Luw xen/include/xen/event.h
diff --git a/BitKeeper/etc/ignore b/BitKeeper/etc/ignore
index 60dabbec24..33edc625d6 100644
--- a/BitKeeper/etc/ignore
+++ b/BitKeeper/etc/ignore
@@ -92,6 +92,18 @@ tools/blktap/xen/*
tools/check/.*
tools/cmdline/*
tools/cmdline/xen/*
+tools/firmware/*.bin
+tools/firmware/*.sym
+tools/firmware/*/biossums
+tools/firmware/*bios/*bios*.txt
+tools/firmware/rombios/BIOS-bochs-latest
+tools/firmware/rombios/_rombios_.c
+tools/firmware/rombios/rombios.s
+tools/firmware/vmxassist/gen
+tools/firmware/vmxassist/offsets.h
+tools/firmware/vmxassist/roms.h
+tools/firmware/vmxassist/vmxassist
+tools/firmware/vmxassist/vmxloader
tools/gdb/gdb-6.2.1-linux-i386-xen/*
tools/gdb/gdb-6.2.1/*
tools/ioemu/config-host.*
@@ -136,6 +148,7 @@ tools/xenstore/xs_random
tools/xenstore/xs_stress
tools/xenstore/xs_test
tools/xentrace/xentrace
+tools/xfrd/xfrd
xen/BLOG
xen/TAGS
xen/arch/x86/asm-offsets.s
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index 3cdc0126d1..afc6cd647f 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -1,3 +1,4 @@
+ach61@arcadians.cl.cam.ac.uk
ach61@boulderdash.cl.cam.ac.uk
ach61@labyrinth.cl.cam.ac.uk
ach61@soar.cl.cam.ac.uk
diff --git a/docs/src/user.tex b/docs/src/user.tex
index 37fe19abb6..b3a2786979 100644
--- a/docs/src/user.tex
+++ b/docs/src/user.tex
@@ -1692,9 +1692,6 @@ editing \path{grub.conf}.
\item [watchdog ]
Enable NMI watchdog which can report certain failures.
-\item [noht ]
- Disable Hyperthreading.
-
\item [badpage=$<$page number$>$,$<$page number$>$, \ldots ]
Specify a list of pages not to be allocated for use
because they contain bad bytes. For example, if your
@@ -1729,6 +1726,13 @@ editing \path{grub.conf}.
transmitted/received character.
[NB. Default for this option is `com1,vga']
+\item [sync\_console ]
+ Force synchronous console output. This is useful if you system fails
+ unexpectedly before it has sent all available output to the
+ console. In most cases Xen will automatically enter synchronous mode
+ when an exceptional event occurs, but this option provides a manual
+ fallback.
+
\item [conswitch=$<$switch-char$><$auto-switch-char$>$ ]
Specify how to switch serial-console input between
Xen and DOM0. The required sequence is CTRL-$<$switch-char$>$
diff --git a/linux-2.4.30-xen-sparse/arch/xen/kernel/setup.c b/linux-2.4.30-xen-sparse/arch/xen/kernel/setup.c
index 8fcbf0d720..230e0bb66a 100644
--- a/linux-2.4.30-xen-sparse/arch/xen/kernel/setup.c
+++ b/linux-2.4.30-xen-sparse/arch/xen/kernel/setup.c
@@ -113,7 +113,7 @@ int enable_acpi_smp_table;
/* Raw start-of-day parameters from the hypervisor. */
union xen_start_info_union xen_start_info_union;
-#define COMMAND_LINE_SIZE 256
+#define COMMAND_LINE_SIZE MAX_GUEST_CMDLINE
static char command_line[COMMAND_LINE_SIZE];
char saved_command_line[COMMAND_LINE_SIZE];
diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/cpu/common.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/cpu/common.c
index c608ef099a..197225266d 100644
--- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/cpu/common.c
+++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/cpu/common.c
@@ -554,7 +554,7 @@ void __init early_cpu_init(void)
void __init cpu_gdt_init(struct Xgt_desc_struct *gdt_descr)
{
- unsigned long frames[gdt_descr->size >> PAGE_SHIFT];
+ unsigned long frames[16];
unsigned long va;
int f;
diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/setup.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/setup.c
index c5f6c665fb..938bcabd86 100644
--- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/setup.c
+++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/setup.c
@@ -699,12 +699,14 @@ static inline void copy_edd(void)
static void __init parse_cmdline_early (char ** cmdline_p)
{
char c = ' ', *to = command_line, *from = saved_command_line;
- int len = 0;
+ int len = 0, max_cmdline;
int userdef = 0;
- memcpy(saved_command_line, xen_start_info.cmd_line, MAX_CMDLINE);
+ if ((max_cmdline = MAX_GUEST_CMDLINE) > COMMAND_LINE_SIZE)
+ max_cmdline = COMMAND_LINE_SIZE;
+ memcpy(saved_command_line, xen_start_info.cmd_line, max_cmdline);
/* Save unparsed command line copy for /proc/cmdline */
- saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
+ saved_command_line[max_cmdline-1] = '\0';
for (;;) {
if (c != ' ')
diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/mm/hypervisor.c b/linux-2.6.11-xen-sparse/arch/xen/i386/mm/hypervisor.c
index 16b253866f..641bca708d 100644
--- a/linux-2.6.11-xen-sparse/arch/xen/i386/mm/hypervisor.c
+++ b/linux-2.6.11-xen-sparse/arch/xen/i386/mm/hypervisor.c
@@ -112,7 +112,7 @@ void xen_tlb_flush_mask(cpumask_t *mask)
if ( cpus_empty(*mask) )
return;
op.cmd = MMUEXT_TLB_FLUSH_MULTI;
- op.cpuset = mask->bits;
+ op.vcpumask = mask->bits;
BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
}
@@ -130,7 +130,7 @@ void xen_invlpg_mask(cpumask_t *mask, unsigned long ptr)
if ( cpus_empty(*mask) )
return;
op.cmd = MMUEXT_INVLPG_MULTI;
- op.cpuset = mask->bits;
+ op.vcpumask = mask->bits;
op.linear_addr = ptr & PAGE_MASK;
BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
}
diff --git a/linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c b/linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c
index c88b802268..6d8deeaec2 100644
--- a/linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c
+++ b/linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c
@@ -74,6 +74,33 @@ static int irq_bindcount[NR_IRQS];
/* Bitmap indicating which PIRQs require Xen to be notified on unmask. */
static unsigned long pirq_needs_unmask_notify[NR_PIRQS/sizeof(unsigned long)];
+#ifdef CONFIG_SMP
+
+static u8 cpu_evtchn[NR_EVENT_CHANNELS];
+static u32 cpu_evtchn_mask[NR_CPUS][NR_EVENT_CHANNELS/32];
+
+#define active_evtchns(cpu,sh,idx) \
+ ((sh)->evtchn_pending[idx] & \
+ cpu_evtchn_mask[cpu][idx] & \
+ ~(sh)->evtchn_mask[idx])
+
+static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
+{
+ clear_bit(chn, (unsigned long *)cpu_evtchn_mask[cpu_evtchn[chn]]);
+ set_bit(chn, (unsigned long *)cpu_evtchn_mask[cpu]);
+ cpu_evtchn[chn] = cpu;
+}
+
+#else
+
+#define active_evtchns(cpu,sh,idx) \
+ ((sh)->evtchn_pending[idx] & \
+ ~(sh)->evtchn_mask[idx])
+
+#define bind_evtchn_to_cpu(chn,cpu) ((void)0)
+
+#endif
+
/* Upcall to generic IRQ layer. */
#ifdef CONFIG_X86
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
@@ -109,9 +136,9 @@ asmlinkage void evtchn_do_upcall(struct pt_regs *regs)
{
u32 l1, l2;
unsigned int l1i, l2i, port;
- int irq;
+ int irq, cpu = smp_processor_id();
shared_info_t *s = HYPERVISOR_shared_info;
- vcpu_info_t *vcpu_info = &s->vcpu_data[smp_processor_id()];
+ vcpu_info_t *vcpu_info = &s->vcpu_data[cpu];
vcpu_info->evtchn_upcall_pending = 0;
@@ -122,7 +149,7 @@ asmlinkage void evtchn_do_upcall(struct pt_regs *regs)
l1i = __ffs(l1);
l1 &= ~(1 << l1i);
- while ( (l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i]) != 0 )
+ while ( (l2 = active_evtchns(cpu, s, l1i)) != 0 )
{
l2i = __ffs(l2);
l2 &= ~(1 << l2i);
@@ -171,6 +198,8 @@ int bind_virq_to_irq(int virq)
irq_to_evtchn[irq] = evtchn;
per_cpu(virq_to_irq, cpu)[virq] = irq;
+
+ bind_evtchn_to_cpu(evtchn, cpu);
}
irq_bindcount[irq]++;
@@ -225,8 +254,13 @@ int bind_ipi_on_cpu_to_irq(int cpu, int ipi)
irq_to_evtchn[irq] = evtchn;
per_cpu(ipi_to_evtchn, cpu)[ipi] = evtchn;
- } else
+
+ bind_evtchn_to_cpu(evtchn, cpu);
+ }
+ else
+ {
irq = evtchn_to_irq[evtchn];
+ }
irq_bindcount[irq]++;
@@ -546,6 +580,11 @@ void __init init_IRQ(void)
spin_lock_init(&irq_mapping_update_lock);
+#ifdef CONFIG_SMP
+ /* By default all event channels notify CPU#0. */
+ memset(cpu_evtchn_mask[0], ~0, sizeof(cpu_evtchn_mask[0]));
+#endif
+
for ( cpu = 0; cpu < NR_CPUS; cpu++ ) {
/* No VIRQ -> IRQ mappings. */
for ( i = 0; i < NR_VIRQS; i++ )
diff --git a/linux-2.6.11-xen-sparse/arch/xen/kernel/gnttab.c b/linux-2.6.11-xen-sparse/arch/xen/kernel/gnttab.c
index 8fe43247ac..0106a6fea0 100644
--- a/linux-2.6.11-xen-sparse/arch/xen/kernel/gnttab.c
+++ b/linux-2.6.11-xen-sparse/arch/xen/kernel/gnttab.c
@@ -19,6 +19,7 @@
#include <asm-xen/xen_proc.h>
#include <asm-xen/linux-public/privcmd.h>
#include <asm-xen/gnttab.h>
+#include <asm/synch_bitops.h>
#if 1
#define ASSERT(_p) \
@@ -125,7 +126,7 @@ gnttab_end_foreign_access( grant_ref_t ref, int readonly )
if ( (flags = nflags) & (GTF_reading|GTF_writing) )
printk(KERN_ALERT "WARNING: g.e. still in use!\n");
}
- while ( (nflags = cmpxchg(&shared[ref].flags, flags, 0)) != flags );
+ while ( (nflags = synch_cmpxchg(&shared[ref].flags, flags, 0)) != flags );
put_free_entry(ref);
}
@@ -172,7 +173,7 @@ gnttab_end_foreign_transfer(
* Otherwise invalidate the grant entry against future use.
*/
if ( likely(flags != GTF_accept_transfer) ||
- (cmpxchg(&shared[ref].flags, flags, 0) != GTF_accept_transfer) )
+ (synch_cmpxchg(&shared[ref].flags, flags, 0) != GTF_accept_transfer) )
while ( unlikely((frame = shared[ref].frame) == 0) )
cpu_relax();
diff --git a/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/setup.c b/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/setup.c
index 8638aaa107..8951d61c2a 100644
--- a/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/setup.c
+++ b/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/setup.c
@@ -318,12 +318,13 @@ union xen_start_info_union xen_start_info_union;
static __init void parse_cmdline_early (char ** cmdline_p)
{
char c = ' ', *to = command_line, *from = COMMAND_LINE;
- int len = 0;
+ int len = 0, max_cmdline;
- memcpy(saved_command_line, xen_start_info.cmd_line, MAX_CMDLINE);
+ if ((max_cmdline = MAX_GUEST_CMDLINE) > COMMAND_LINE_SIZE)
+ max_cmdline = COMMAND_LINE_SIZE;
+ memcpy(saved_command_line, xen_start_info.cmd_line, max_cmdline);
/* Save unparsed command line copy for /proc/cmdline */
- memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
- saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
+ saved_command_line[max_cmdline-1] = '\0';
for (;;) {
if (c != ' ')
diff --git a/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/setup64.c b/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/setup64.c
index 32b813661f..03452e1bf3 100644
--- a/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/setup64.c
+++ b/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/setup64.c
@@ -208,7 +208,7 @@ void __init check_efer(void)
void __init cpu_gdt_init(struct desc_ptr *gdt_descr)
{
- unsigned long frames[gdt_descr->size >> PAGE_SHIFT];
+ unsigned long frames[16];
unsigned long va;
int f;
@@ -336,9 +336,7 @@ void __init cpu_init (void)
CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7);
#undef CD
-#if 0
fpu_init();
-#endif
#ifdef CONFIG_NUMA
numa_add_cpu(cpu);
diff --git a/linux-2.6.11-xen-sparse/arch/xen/x86_64/mm/hypervisor.c b/linux-2.6.11-xen-sparse/arch/xen/x86_64/mm/hypervisor.c
index 83a922954c..3923162df8 100644
--- a/linux-2.6.11-xen-sparse/arch/xen/x86_64/mm/hypervisor.c
+++ b/linux-2.6.11-xen-sparse/arch/xen/x86_64/mm/hypervisor.c
@@ -122,7 +122,7 @@ void xen_tlb_flush_mask(cpumask_t *mask)
if ( cpus_empty(*mask) )
return;
op.cmd = MMUEXT_TLB_FLUSH_MULTI;
- op.cpuset = mask->bits;
+ op.vcpumask = mask->bits;
BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
}
@@ -140,7 +140,7 @@ void xen_invlpg_mask(cpumask_t *mask, unsigned long ptr)
if ( cpus_empty(*mask) )
return;
op.cmd = MMUEXT_INVLPG_MULTI;
- op.cpuset = mask->bits;
+ op.vcpumask = mask->bits;
op.linear_addr = ptr & PAGE_MASK;
BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
}
diff --git a/linux-2.6.11-xen-sparse/drivers/xen/blktap/blktap_controlmsg.c b/linux-2.6.11-xen-sparse/drivers/xen/blktap/blktap_controlmsg.c
index 060c6a2dd2..e31fc8f6cd 100644
--- a/linux-2.6.11-xen-sparse/drivers/xen/blktap/blktap_controlmsg.c
+++ b/linux-2.6.11-xen-sparse/drivers/xen/blktap/blktap_controlmsg.c
@@ -443,6 +443,7 @@ void blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
(blktap_mode & BLKTAP_MODE_COPY_FE) ) {
blktap_write_ctrl_ring(msg);
+ blktap_kick_user();
}
switch ( msg->subtype )
diff --git a/linux-2.6.11-xen-sparse/drivers/xen/blktap/blktap_datapath.c b/linux-2.6.11-xen-sparse/drivers/xen/blktap/blktap_datapath.c
index 7eebcf120f..56bf59d718 100644
--- a/linux-2.6.11-xen-sparse/drivers/xen/blktap/blktap_datapath.c
+++ b/linux-2.6.11-xen-sparse/drivers/xen/blktap/blktap_datapath.c
@@ -82,6 +82,8 @@ static inline unsigned long MAKE_ID(domid_t fe_dom, ACTIVE_RING_IDX idx)
/*-----[ Ring helpers ]---------------------------------------------------*/
+static void maybe_trigger_blktap_schedule(void);
+
inline int write_resp_to_fe_ring(blkif_t *blkif, blkif_response_t *rsp)
{
blkif_response_t *resp_d;
@@ -125,6 +127,9 @@ void kick_fe_domain(blkif_t *blkif)
RING_PUSH_RESPONSES(&blkif->blk_ring);
notify_via_evtchn(blkif->evtchn);
DPRINTK("notified FE(dom %u)\n", blkif->domid);
+
+ /* We just feed up a batch of request slots... */
+ maybe_trigger_blktap_schedule();
}
@@ -219,15 +224,10 @@ static int blkio_schedule(void *arg)
add_to_blkdev_list_tail(blkif);
blkif_put(blkif);
}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- /* Push the batch through to disc. */
- run_task_queue(&tq_disk);
-#endif
}
}
-static void maybe_trigger_blkio_schedule(void)
+static void maybe_trigger_blktap_schedule(void)
{
/*
* Needed so that two processes, who together make the following predicate
@@ -236,7 +236,7 @@ static void maybe_trigger_blkio_schedule(void)
*/
smp_mb();
- if ( (NR_ACTIVE_REQS < (MAX_ACTIVE_REQS)) && /* XXX!!! was M_A_R/2*/
+ if ( (NR_ACTIVE_REQS < (MAX_ACTIVE_REQS/2)) &&
!list_empty(&blkio_schedule_list) )
wake_up(&blkio_schedule_wait);
}
@@ -262,7 +262,7 @@ irqreturn_t blkif_ptfe_int(int irq, void *dev_id, struct pt_regs *regs)
blkif_t *blkif = dev_id;
add_to_blkdev_list_tail(blkif);
- maybe_trigger_blkio_schedule();
+ maybe_trigger_blktap_schedule();
return IRQ_HANDLED;
}
@@ -280,8 +280,6 @@ static int do_block_io_op(blkif_t *blkif, int max_to_do)
int more_to_do = 0;
int notify_be = 0, notify_user = 0;
- DPRINTK("PT got FE interrupt.\n");
-
if (NR_ACTIVE_REQS == MAX_ACTIVE_REQS) return 1;
/* lock both rings */
diff --git a/linux-2.6.11-xen-sparse/drivers/xen/blktap/blktap_userdev.c b/linux-2.6.11-xen-sparse/drivers/xen/blktap/blktap_userdev.c
index 78a487662e..c01818b3d2 100644
--- a/linux-2.6.11-xen-sparse/drivers/xen/blktap/blktap_userdev.c
+++ b/linux-2.6.11-xen-sparse/drivers/xen/blktap/blktap_userdev.c
@@ -34,7 +34,7 @@ unsigned long blktap_ring_ok; /* make this ring->state */
static wait_queue_head_t blktap_wait;
/* Where things are inside the device mapping. */
-struct vm_area_struct *blktap_vma;
+struct vm_area_struct *blktap_vma = NULL;
unsigned long mmap_vstart;
unsigned long rings_vstart;
@@ -139,7 +139,14 @@ static int blktap_release(struct inode *inode, struct file *filp)
ClearPageReserved(virt_to_page(blktap_ube_ring.sring));
free_page((unsigned long) blktap_ube_ring.sring);
-
+
+ /* Clear any active mappings. */
+ if (blktap_vma != NULL) {
+ zap_page_range(blktap_vma, blktap_vma->vm_start,
+ blktap_vma->vm_end - blktap_vma->vm_start, NULL);
+ blktap_vma = NULL;
+ }
+
return 0;
}
diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/synch_bitops.h b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/synch_bitops.h
index 8093de0ac9..6af3ad2857 100644
--- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/synch_bitops.h
+++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/synch_bitops.h
@@ -60,6 +60,46 @@ static __inline__ int synch_test_and_change_bit(int nr, volatile void * addr)
return oldbit;
}
+struct __synch_xchg_dummy { unsigned long a[100]; };
+#define __synch_xg(x) ((struct __synch_xchg_dummy *)(x))
+
+#define synch_cmpxchg(ptr, old, new) \
+((__typeof__(*(ptr)))__synch_cmpxchg((ptr),\
+ (unsigned long)(old), \
+ (unsigned long)(new), \
+ sizeof(*(ptr))))
+
+static inline unsigned long __synch_cmpxchg(volatile void *ptr,
+ unsigned long old,
+ unsigned long new, int size)
+{
+ unsigned long prev;
+ switch (size) {
+ case 1:
+ __asm__ __volatile__("lock; cmpxchgb %b1,%2"
+ : "=a"(prev)
+ : "q"(new), "m"(*__synch_xg(ptr)),
+ "0"(old)
+ : "memory");
+ return prev;
+ case 2:
+ __asm__ __volatile__("lock; cmpxchgw %w1,%2"
+ : "=a"(prev)
+ : "q"(new), "m"(*__synch_xg(ptr)),
+ "0"(old)
+ : "memory");
+ return prev;
+ case 4:
+ __asm__ __volatile__("lock; cmpxchgl %1,%2"
+ : "=a"(prev)
+ : "q"(new), "m"(*__synch_xg(ptr)),
+ "0"(old)
+ : "memory");
+ return prev;
+ }
+ return old;
+}
+
static __inline__ int synch_const_test_bit(int nr, const volatile void * addr)
{
return ((1UL << (nr & 31)) &
diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h
index 7fe4f04d1f..22e41ce412 100644
--- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h
+++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h
@@ -107,14 +107,25 @@ static inline unsigned long _get_base(char * addr)
* Clear and set 'TS' bit respectively
*/
#define clts() (HYPERVISOR_fpu_taskswitch(0))
-#define read_cr0() \
- BUG();
+#define read_cr0() ({ \
+ unsigned int __dummy; \
+ __asm__( \
+ "movl %%cr0,%0\n\t" \
+ :"=r" (__dummy)); \
+ __dummy; \
+})
#define write_cr0(x) \
- BUG();
-#define read_cr4() \
- BUG();
+ __asm__("movl %0,%%cr0": :"r" (x));
+
+#define read_cr4() ({ \
+ unsigned int __dummy; \
+ __asm__( \
+ "movl %%cr4,%0\n\t" \
+ :"=r" (__dummy)); \
+ __dummy; \
+})
#define write_cr4(x) \
- BUG();
+ __asm__("movl %0,%%cr4": :"r" (x));
#define stts() (HYPERVISOR_fpu_taskswitch(1))
#endif /* __KERNEL__ */
diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/system.h b/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/system.h
index 7c70eac425..e8badb7533 100644
--- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/system.h
+++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/system.h
@@ -145,30 +145,38 @@ struct alt_instr {
* Clear and set 'TS' bit respectively
*/
#define clts() (HYPERVISOR_fpu_taskswitch(0))
+
static inline unsigned long read_cr0(void)
{
- BUG();
+ unsigned long cr0;
+ asm volatile("movq %%cr0,%0" : "=r" (cr0));
+ return cr0;
}
static inline void write_cr0(unsigned long val)
{
- BUG();
+ asm volatile("movq %0,%%cr0" :: "r" (val));
}
static inline unsigned long read_cr3(void)
{
- BUG();
+ unsigned long cr3;
+ asm("movq %%cr3,%0" : "=r" (cr3));
+ return cr3;
}
static inline unsigned long read_cr4(void)
{
- BUG();
+ unsigned long cr4;
+ asm("movq %%cr4,%0" : "=r" (cr4));
+ return cr4;
}
static inline void write_cr4(unsigned long val)
{
- BUG();
+ asm volatile("movq %0,%%cr4" :: "r" (val));
}
+
#define stts() (HYPERVISOR_fpu_taskswitch(1))
#define wbinvd() \
diff --git a/tools/Makefile b/tools/Makefile
index 9132a7827b..b122ba465a 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -12,6 +12,7 @@ SUBDIRS += xcs
SUBDIRS += xcutils
SUBDIRS += xenstore
SUBDIRS += pygrub
+SUBDIRS += firmware
.PHONY: all install clean check check_clean ioemu eioemuinstall ioemuclean
diff --git a/tools/blktap/Makefile b/tools/blktap/Makefile
index 9807e05387..6ee79ada9c 100644
--- a/tools/blktap/Makefile
+++ b/tools/blktap/Makefile
@@ -15,6 +15,8 @@ INSTALL_DIR = $(INSTALL) -d -m0755
INCLUDES +=
+LIBS := -lpthread -lz
+
SRCS :=
SRCS += blktaplib.c
@@ -24,10 +26,8 @@ PLX_SRCS += radix.c
PLX_SRCS += snaplog.c
PLX_SRCS += blockstore.c
PLX_SRCS += block-async.c
-PLXT_SRCS := $(PLX_SRCS)
-PLXT_SRCS += parallax-threaded.c
-VDI_SRCS := $(PLX_SRCS)
PLX_SRCS += requests-async.c
+VDI_SRCS := $(PLX_SRCS)
PLX_SRCS += parallax.c
VDI_TOOLS :=
@@ -58,7 +58,7 @@ IBINS = blkdump parallax $(VDI_TOOLS)
LIB = libblktap.so libblktap.so.$(MAJOR) libblktap.so.$(MAJOR).$(MINOR)
-all: mk-symlinks blkdump $(VDI_TOOLS) parallax parallax-threaded blockstored
+all: mk-symlinks blkdump $(VDI_TOOLS) parallax blockstored
$(MAKE) $(LIB)
LINUX_ROOT := $(wildcard $(XEN_ROOT)/linux-2.6.*-xen-sparse)
@@ -80,7 +80,7 @@ install: all
$(INSTALL_PROG) $(IBINS) $(DESTDIR)/$(BLKTAP_INSTALL_DIR)
clean:
- rm -rf *.a *.so *.o *.rpm $(LIB) *~ $(DEPS) xen TAGS blkdump $(VDI_TOOLS) parallax parallax-threaded
+ rm -rf *.a *.so *.o *.rpm $(LIB) *~ $(DEPS) xen TAGS blkdump $(VDI_TOOLS) parallax vdi_unittest
rpm: all
rm -rf staging
@@ -96,45 +96,45 @@ libblktap.so:
libblktap.so.$(MAJOR):
ln -sf libblktap.so.$(MAJOR).$(MINOR) $@
libblktap.so.$(MAJOR).$(MINOR): $(OBJS)
- $(CC) -Wl,-soname -Wl,$(SONAME) -shared -o $@ $^ -lpthread -lz
+ $(CC) -Wl,-soname -Wl,$(SONAME) -shared -o $@ $^ $(LIBS)
blkdump: $(LIB)
$(CC) $(CFLAGS) -o blkdump -L$(XEN_LIBXC) -L. -l blktap blkdump.c
parallax: $(LIB) $(PLX_SRCS)
- $(CC) $(CFLAGS) -o parallax -L$(XEN_LIBXC) -L. -lblktap -lpthread $(PLX_SRCS)
-
-parallax-threaded: $(LIB) $(PLXT_SRCS)
- $(CC) $(CFLAGS) -o parallax-threaded -L$(XEN_LIBXC) -L. -lpthread -lblktap $(PLXT_SRCS)
+ $(CC) $(CFLAGS) -o parallax -L$(XEN_LIBXC) -L. -lblktap $(LIBS) $(PLX_SRCS)
vdi_list: $(LIB) vdi_list.c $(VDI_SRCS)
- $(CC) $(CFLAGS) -g3 -o vdi_list vdi_list.c -lpthread $(VDI_SRCS)
+ $(CC) $(CFLAGS) -g3 -o vdi_list vdi_list.c $(LIBS) $(VDI_SRCS)
vdi_create: $(LIB) vdi_create.c $(VDI_SRCS)
- $(CC) $(CFLAGS) -g3 -o vdi_create vdi_create.c -lpthread $(VDI_SRCS)
+ $(CC) $(CFLAGS) -g3 -o vdi_create vdi_create.c $(LIBS) $(VDI_SRCS)
vdi_snap: $(LIB) vdi_snap.c $(VDI_SRCS)
- $(CC) $(CFLAGS) -g3 -o vdi_snap vdi_snap.c -lpthread $(VDI_SRCS)
+ $(CC) $(CFLAGS) -g3 -o vdi_snap vdi_snap.c $(LIBS) $(VDI_SRCS)
vdi_snap_list: $(LIB) vdi_snap_list.c $(VDI_SRCS)
- $(CC) $(CFLAGS) -g3 -o vdi_snap_list vdi_snap_list.c -lpthread $(VDI_SRCS)
+ $(CC) $(CFLAGS) -g3 -o vdi_snap_list vdi_snap_list.c $(LIBS) $(VDI_SRCS)
vdi_snap_delete: $(LIB) vdi_snap_delete.c $(VDI_SRCS)
- $(CC) $(CFLAGS) -g3 -o vdi_snap_delete vdi_snap_delete.c -lpthread $(VDI_SRCS)
+ $(CC) $(CFLAGS) -g3 -o vdi_snap_delete vdi_snap_delete.c $(LIBS) $(VDI_SRCS)
vdi_tree: $(LIB) vdi_tree.c $(VDI_SRCS)
- $(CC) $(CFLAGS) -g3 -o vdi_tree vdi_tree.c -lpthread $(VDI_SRCS)
+ $(CC) $(CFLAGS) -g3 -o vdi_tree vdi_tree.c $(LIBS) $(VDI_SRCS)
vdi_fill: $(LIB) vdi_fill.c $(VDI_SRCS)
- $(CC) $(CFLAGS) -g3 -o vdi_fill vdi_fill.c -lpthread $(VDI_SRCS)
+ $(CC) $(CFLAGS) -g3 -o vdi_fill vdi_fill.c $(LIBS) $(VDI_SRCS)
vdi_validate: $(LIB) vdi_validate.c $(VDI_SRCS)
- $(CC) $(CFLAGS) -g3 -o vdi_validate vdi_validate.c -lpthread $(VDI_SRCS)
+ $(CC) $(CFLAGS) -g3 -o vdi_validate vdi_validate.c $(LIBS) $(VDI_SRCS)
+
+vdi_unittest: $(LIB) vdi_unittest.c $(VDI_SRCS)
+ $(CC) $(CFLAGS) -g3 -o vdi_unittest vdi_unittest.c $(LIBS) $(VDI_SRCS)
blockstored: blockstored.c
- $(CC) $(CFLAGS) -g3 -o blockstored -lpthread blockstored.c
+ $(CC) $(CFLAGS) -g3 -o blockstored $(LIBS) blockstored.c
bstest: bstest.c blockstore.c
- $(CC) $(CFLAGS) -g3 -o bstest bstest.c -lpthread blockstore.c
+ $(CC) $(CFLAGS) -g3 -o bstest bstest.c $(LIBS) blockstore.c
.PHONY: TAGS clean install mk-symlinks rpm
TAGS:
diff --git a/tools/blktap/blkint.h b/tools/blktap/blkint.h
deleted file mode 100644
index e3ce3b55e1..0000000000
--- a/tools/blktap/blkint.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * blkint.h
- *
- * Interfaces for the Xen block interposition driver.
- *
- * (c) 2004, Andrew Warfield, University of Cambridge
- *
- */
-
-#ifndef __BLKINT_H__
-
-//#include "blkif.h"
-
-
-#if 0
-/* Types of ring. */
-#define BLKIF_REQ_RING_TYPE 1
-#define BLKIF_RSP_RING_TYPE 2
-
-/* generic ring struct. */
-typedef struct blkif_generic_ring_struct {
- int type;
-} blkif_generic_ring_t;
-
-/* A requestor's view of a ring. */
-typedef struct blkif_req_ring_struct {
-
- int type; /* Will be BLKIF_REQ_RING_TYPE */
- BLKIF_RING_IDX req_prod; /* PRIVATE req_prod index */
- BLKIF_RING_IDX rsp_cons; /* Response consumer index */
- blkif_ring_t *ring; /* Pointer to shared ring struct */
-
-} blkif_req_ring_t;
-
-#define BLKIF_REQ_RING_INIT { BLKIF_REQ_RING_TYPE, 0, 0, 0 }
-
-/* A responder's view of a ring. */
-typedef struct blkif_rsp_ring_struct {
-
- int type; /* Will be BLKIF_REQ_RING_TYPE */
- BLKIF_RING_IDX rsp_prod; /* PRIVATE rsp_prod index */
- BLKIF_RING_IDX req_cons; /* Request consumer index */
- blkif_ring_t *ring; /* Pointer to shared ring struct */
-
-} blkif_rsp_ring_t;
-
-#define BLKIF_RSP_RING_INIT { BLKIF_RSP_RING_TYPE, 0, 0, 0 }
-
-#define RING(a) (blkif_generic_ring_t *)(a)
-inline int BLKTAP_RING_FULL(blkif_generic_ring_t *ring);
-#endif
-
-/* -------[ interposition -> character device interface ]------------- */
-
-/* /dev/xen/blktap resides at device number major=10, minor=202 */
-#define BLKTAP_MINOR 202
-
-/* size of the extra VMA area to map in attached pages. */
-#define BLKTAP_VMA_PAGES BLKIF_RING_SIZE
-
-/* blktap IOCTLs: */
-#define BLKTAP_IOCTL_KICK_FE 1
-#define BLKTAP_IOCTL_KICK_BE 2
-#define BLKTAP_IOCTL_SETMODE 3
-#define BLKTAP_IOCTL_PRINT_IDXS 100
-
-/* blktap switching modes: (Set with BLKTAP_IOCTL_SETMODE) */
-#define BLKTAP_MODE_PASSTHROUGH 0x00000000 /* default */
-#define BLKTAP_MODE_INTERCEPT_FE 0x00000001
-#define BLKTAP_MODE_INTERCEPT_BE 0x00000002
-#define BLKTAP_MODE_COPY_FE 0x00000004
-#define BLKTAP_MODE_COPY_BE 0x00000008
-#define BLKTAP_MODE_COPY_FE_PAGES 0x00000010
-#define BLKTAP_MODE_COPY_BE_PAGES 0x00000020
-
-#define BLKTAP_MODE_INTERPOSE \
- (BLKTAP_MODE_INTERCEPT_FE | BLKTAP_MODE_INTERCEPT_BE)
-
-#define BLKTAP_MODE_COPY_BOTH \
- (BLKTAP_MODE_COPY_FE | BLKTAP_MODE_COPY_BE)
-
-#define BLKTAP_MODE_COPY_BOTH_PAGES \
- (BLKTAP_MODE_COPY_FE_PAGES | BLKTAP_MODE_COPY_BE_PAGES)
-
-static inline int BLKTAP_MODE_VALID(unsigned long arg)
-{
- return (
- ( arg == BLKTAP_MODE_PASSTHROUGH ) ||
- ( arg == BLKTAP_MODE_INTERCEPT_FE ) ||
- ( arg == BLKTAP_MODE_INTERCEPT_BE ) ||
- ( arg == BLKTAP_MODE_INTERPOSE ) ||
- ( (arg & ~BLKTAP_MODE_COPY_FE_PAGES) == BLKTAP_MODE_COPY_FE ) ||
- ( (arg & ~BLKTAP_MODE_COPY_BE_PAGES) == BLKTAP_MODE_COPY_BE ) ||
- ( (arg & ~BLKTAP_MODE_COPY_BOTH_PAGES) == BLKTAP_MODE_COPY_BOTH )
- );
-}
-
-
-
-
-
-
-
-#define __BLKINT_H__
-#endif
diff --git a/tools/blktap/blktaplib.c b/tools/blktap/blktaplib.c
index ea8b1238ee..8db175a019 100644
--- a/tools/blktap/blktaplib.c
+++ b/tools/blktap/blktaplib.c
@@ -34,7 +34,7 @@
#else
#define DPRINTF(_f, _a...) ((void)0)
#endif
-#define DEBUG_RING_IDXS 1
+#define DEBUG_RING_IDXS 0
#define POLLRDNORM 0x040
@@ -171,27 +171,27 @@ void print_hooks(void)
response_hook_t *rsp_hook;
ctrl_hook_t *ctrl_hook;
- printf("Control Hooks:\n");
+ DPRINTF("Control Hooks:\n");
ctrl_hook = ctrl_hook_chain;
while (ctrl_hook != NULL)
{
- printf(" [0x%p] %s\n", ctrl_hook->func, ctrl_hook->name);
+ DPRINTF(" [0x%p] %s\n", ctrl_hook->func, ctrl_hook->name);
ctrl_hook = ctrl_hook->next;
}
- printf("Request Hooks:\n");
+ DPRINTF("Request Hooks:\n");
req_hook = request_hook_chain;
while (req_hook != NULL)
{
- printf(" [0x%p] %s\n", req_hook->func, req_hook->name);
+ DPRINTF(" [0x%p] %s\n", req_hook->func, req_hook->name);
req_hook = req_hook->next;
}
- printf("Response Hooks:\n");
+ DPRINTF("Response Hooks:\n");
rsp_hook = response_hook_chain;
while (rsp_hook != NULL)
{
- printf(" [0x%p] %s\n", rsp_hook->func, rsp_hook->name);
+ DPRINTF(" [0x%p] %s\n", rsp_hook->func, rsp_hook->name);
rsp_hook = rsp_hook->next;
}
}
@@ -300,7 +300,7 @@ int blktap_attach_poll(int fd, short events, int (*func)(int fd))
ph->events = events;
ph->active = 1;
- printf("Added fd %d at ph index %d, now %d phs.\n", fd, ph_cons-1,
+ DPRINTF("Added fd %d at ph index %d, now %d phs.\n", fd, ph_cons-1,
nr_pollhooks());
return 0;
@@ -318,7 +318,7 @@ void blktap_detach_poll(int fd)
break;
}
- printf("Removed fd %d at ph index %d, now %d phs.\n", fd, i,
+ DPRINTF("Removed fd %d at ph index %d, now %d phs.\n", fd, i,
nr_pollhooks());
}
@@ -337,7 +337,6 @@ void pollhook_init(void)
void __attribute__ ((constructor)) blktaplib_init(void)
{
- printf("[[ C O N S T R U C T O R ]]\n");
pollhook_init();
}
@@ -385,7 +384,7 @@ int blktap_listen(void)
/* assign the rings to the mapped memory */
csring = (ctrl_sring_t *)blktap_mem;
- BACK_RING_INIT(&ctrl_ring, csring, CONTROL_RING_MEM);
+ BACK_RING_INIT(&ctrl_ring, csring, PAGE_SIZE);
sring = (blkif_sring_t *)((unsigned long)blktap_mem + PAGE_SIZE);
FRONT_RING_INIT(&be_ring, sring, PAGE_SIZE);
@@ -393,10 +392,7 @@ int blktap_listen(void)
sring = (blkif_sring_t *)((unsigned long)blktap_mem + (2 *PAGE_SIZE));
BACK_RING_INIT(&fe_ring, sring, PAGE_SIZE);
- mmap_vstart = (unsigned long)blktap_mem + (BLKTAP_RING_PAGES << PAGE_SHIFT);
-
- printf("fe_ring mapped at: %p\n", fe_ring.sring);
- printf("be_ring mapped at: %p\n", be_ring.sring);
+ mmap_vstart = (unsigned long)blktap_mem +(BLKTAP_RING_PAGES << PAGE_SHIFT);
ioctl(fd, BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_INTERPOSE );
@@ -560,7 +556,9 @@ void got_sig_bus() {
}
void got_sig_int() {
- printf("quitting -- returning to passthrough mode.\n");
+ DPRINTF("quitting -- returning to passthrough mode.\n");
if (fd > 0) ioctl(fd, BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_PASSTHROUGH );
+ close(fd);
+ fd = 0;
exit(0);
}
diff --git a/tools/blktap/blktaplib.h b/tools/blktap/blktaplib.h
index 4a46929a63..67ebca64cc 100644
--- a/tools/blktap/blktaplib.h
+++ b/tools/blktap/blktaplib.h
@@ -2,7 +2,6 @@
*
* userland accessors to the block tap.
*
- * for the moment this is rather simple.
*/
#ifndef __BLKTAPLIB_H__
@@ -14,8 +13,51 @@
#include <xen/io/blkif.h>
#include <xen/io/ring.h>
#include <xen/io/domain_controller.h>
-#include "blkint.h"
+/* /dev/xen/blktap resides at device number major=10, minor=202 */
+#define BLKTAP_MINOR 202
+
+/* size of the extra VMA area to map in attached pages. */
+#define BLKTAP_VMA_PAGES BLKIF_RING_SIZE
+
+/* blktap IOCTLs: */
+#define BLKTAP_IOCTL_KICK_FE 1
+#define BLKTAP_IOCTL_KICK_BE 2
+#define BLKTAP_IOCTL_SETMODE 3
+#define BLKTAP_IOCTL_PRINT_IDXS 100
+
+/* blktap switching modes: (Set with BLKTAP_IOCTL_SETMODE) */
+#define BLKTAP_MODE_PASSTHROUGH 0x00000000 /* default */
+#define BLKTAP_MODE_INTERCEPT_FE 0x00000001
+#define BLKTAP_MODE_INTERCEPT_BE 0x00000002
+#define BLKTAP_MODE_COPY_FE 0x00000004
+#define BLKTAP_MODE_COPY_BE 0x00000008
+#define BLKTAP_MODE_COPY_FE_PAGES 0x00000010
+#define BLKTAP_MODE_COPY_BE_PAGES 0x00000020
+
+#define BLKTAP_MODE_INTERPOSE \
+ (BLKTAP_MODE_INTERCEPT_FE | BLKTAP_MODE_INTERCEPT_BE)
+
+#define BLKTAP_MODE_COPY_BOTH \
+ (BLKTAP_MODE_COPY_FE | BLKTAP_MODE_COPY_BE)
+
+#define BLKTAP_MODE_COPY_BOTH_PAGES \
+ (BLKTAP_MODE_COPY_FE_PAGES | BLKTAP_MODE_COPY_BE_PAGES)
+
+static inline int BLKTAP_MODE_VALID(unsigned long arg)
+{
+ return (
+ ( arg == BLKTAP_MODE_PASSTHROUGH ) ||
+ ( arg == BLKTAP_MODE_INTERCEPT_FE ) ||
+ ( arg == BLKTAP_MODE_INTERCEPT_BE ) ||
+ ( arg == BLKTAP_MODE_INTERPOSE ) ||
+ ( (arg & ~BLKTAP_MODE_COPY_FE_PAGES) == BLKTAP_MODE_COPY_FE ) ||
+ ( (arg & ~BLKTAP_MODE_COPY_BE_PAGES) == BLKTAP_MODE_COPY_BE ) ||
+ ( (arg & ~BLKTAP_MODE_COPY_BOTH_PAGES) == BLKTAP_MODE_COPY_BOTH )
+ );
+}
+
+/* Return values for handling messages in hooks. */
#define BLKTAP_PASS 0 /* Keep passing this request as normal. */
#define BLKTAP_RESPOND 1 /* Request is now a reply. Return it. */
#define BLKTAP_STOLEN 2 /* Hook has stolen request. */
@@ -33,7 +75,7 @@ int blktap_attach_poll(int fd, short events, int (*func)(int));
void blktap_detach_poll(int fd);
int blktap_listen(void);
-/*-----[ Accessing attached data page mappings ]-------------------------*/
+/* Accessing attached data page mappings */
#define MMAP_PAGES_PER_REQUEST \
(BLKIF_MAX_SEGMENTS_PER_REQUEST + 1)
#define MMAP_VADDR(_req,_seg) \
@@ -44,7 +86,7 @@ int blktap_listen(void);
extern unsigned long mmap_vstart;
-/*-----[ Defines that are only used by library clients ]-----------------*/
+/* Defines that are only used by library clients */
#ifndef __COMPILING_BLKTAP_LIB
diff --git a/tools/blktap/block-async.c b/tools/blktap/block-async.c
index 6f26071ade..a0460de6fc 100755
--- a/tools/blktap/block-async.c
+++ b/tools/blktap/block-async.c
@@ -31,47 +31,47 @@
*/
struct read_args {
- u64 addr;
+ u64 addr;
};
struct write_args {
- u64 addr;
- char *block;
+ u64 addr;
+ char *block;
};
struct alloc_args {
- char *block;
+ char *block;
};
struct pending_io_req {
- enum {IO_READ, IO_WRITE, IO_ALLOC, IO_RWAKE, IO_WWAKE} op;
- union {
- struct read_args r;
- struct write_args w;
- struct alloc_args a;
- } u;
- io_cb_t cb;
- void *param;
+ enum {IO_READ, IO_WRITE, IO_ALLOC, IO_RWAKE, IO_WWAKE} op;
+ union {
+ struct read_args r;
+ struct write_args w;
+ struct alloc_args a;
+ } u;
+ io_cb_t cb;
+ void *param;
};
void radix_lock_init(struct radix_lock *r)
{
- int i;
-
- pthread_mutex_init(&r->lock, NULL);
- for (i=0; i < 1024; i++) {
- r->lines[i] = 0;
- r->waiters[i] = NULL;
- r->state[i] = ANY;
- }
+ int i;
+
+ pthread_mutex_init(&r->lock, NULL);
+ for (i=0; i < 1024; i++) {
+ r->lines[i] = 0;
+ r->waiters[i] = NULL;
+ r->state[i] = ANY;
+ }
}
/* maximum outstanding I/O requests issued asynchronously */
/* must be a power of 2.*/
-#define MAX_PENDING_IO 1024 //1024
+#define MAX_PENDING_IO 1024
/* how many threads to concurrently issue I/O to the disk. */
-#define IO_POOL_SIZE 10 //10
+#define IO_POOL_SIZE 10
static struct pending_io_req pending_io_reqs[MAX_PENDING_IO];
static int pending_io_list[MAX_PENDING_IO];
@@ -87,276 +87,268 @@ static pthread_cond_t pending_io_cond = PTHREAD_COND_INITIALIZER;
static void init_pending_io(void)
{
- int i;
+ int i;
- for (i=0; i<MAX_PENDING_IO; i++)
- pending_io_list[i] = i;
+ for (i=0; i<MAX_PENDING_IO; i++)
+ pending_io_list[i] = i;
}
void block_read(u64 addr, io_cb_t cb, void *param)
{
- struct pending_io_req *req;
-
- pthread_mutex_lock(&pending_io_lock);
- assert(CAN_PRODUCE_PENDING_IO);
-
- req = PENDING_IO_ENT(io_prod++);
- DPRINTF("Produce (R) %lu (%p)\n", io_prod - 1, req);
- req->op = IO_READ;
- req->u.r.addr = addr;
- req->cb = cb;
- req->param = param;
-
+ struct pending_io_req *req;
+
+ pthread_mutex_lock(&pending_io_lock);
+ assert(CAN_PRODUCE_PENDING_IO);
+
+ req = PENDING_IO_ENT(io_prod++);
+ DPRINTF("Produce (R) %lu (%p)\n", io_prod - 1, req);
+ req->op = IO_READ;
+ req->u.r.addr = addr;
+ req->cb = cb;
+ req->param = param;
+
pthread_cond_signal(&pending_io_cond);
- pthread_mutex_unlock(&pending_io_lock);
+ pthread_mutex_unlock(&pending_io_lock);
}
void block_write(u64 addr, char *block, io_cb_t cb, void *param)
{
- struct pending_io_req *req;
-
- pthread_mutex_lock(&pending_io_lock);
- assert(CAN_PRODUCE_PENDING_IO);
-
- req = PENDING_IO_ENT(io_prod++);
- DPRINTF("Produce (W) %lu (%p)\n", io_prod - 1, req);
- req->op = IO_WRITE;
- req->u.w.addr = addr;
- req->u.w.block = block;
- req->cb = cb;
- req->param = param;
-
+ struct pending_io_req *req;
+
+ pthread_mutex_lock(&pending_io_lock);
+ assert(CAN_PRODUCE_PENDING_IO);
+
+ req = PENDING_IO_ENT(io_prod++);
+ DPRINTF("Produce (W) %lu (%p)\n", io_prod - 1, req);
+ req->op = IO_WRITE;
+ req->u.w.addr = addr;
+ req->u.w.block = block;
+ req->cb = cb;
+ req->param = param;
+
pthread_cond_signal(&pending_io_cond);
- pthread_mutex_unlock(&pending_io_lock);
+ pthread_mutex_unlock(&pending_io_lock);
}
void block_alloc(char *block, io_cb_t cb, void *param)
{
- struct pending_io_req *req;
-
- pthread_mutex_lock(&pending_io_lock);
- assert(CAN_PRODUCE_PENDING_IO);
-
- req = PENDING_IO_ENT(io_prod++);
- req->op = IO_ALLOC;
- req->u.a.block = block;
- req->cb = cb;
- req->param = param;
+ struct pending_io_req *req;
+ pthread_mutex_lock(&pending_io_lock);
+ assert(CAN_PRODUCE_PENDING_IO);
+
+ req = PENDING_IO_ENT(io_prod++);
+ req->op = IO_ALLOC;
+ req->u.a.block = block;
+ req->cb = cb;
+ req->param = param;
+
pthread_cond_signal(&pending_io_cond);
- pthread_mutex_unlock(&pending_io_lock);
+ pthread_mutex_unlock(&pending_io_lock);
}
void block_rlock(struct radix_lock *r, int row, io_cb_t cb, void *param)
{
- struct io_ret ret;
- pthread_mutex_lock(&r->lock);
-
- if (( r->lines[row] >= 0 ) && (r->state[row] != STOP)) {
- r->lines[row]++;
- r->state[row] = READ;
- DPRINTF("RLOCK : %3d (row: %d)\n", r->lines[row], row);
- pthread_mutex_unlock(&r->lock);
- ret.type = IO_INT_T;
- ret.u.i = 0;
- cb(ret, param);
- } else {
- struct radix_wait **rwc;
- struct radix_wait *rw =
- (struct radix_wait *) malloc (sizeof(struct radix_wait));
- DPRINTF("RLOCK : %3d (row: %d) -- DEFERRED!\n", r->lines[row], row);
- rw->type = RLOCK;
- rw->param = param;
- rw->cb = cb;
- rw->next = NULL;
- /* append to waiters list. */
- rwc = &r->waiters[row];
- while (*rwc != NULL) rwc = &(*rwc)->next;
- *rwc = rw;
- pthread_mutex_unlock(&r->lock);
- return;
- }
+ struct io_ret ret;
+ pthread_mutex_lock(&r->lock);
+
+ if (( r->lines[row] >= 0 ) && (r->state[row] != STOP)) {
+ r->lines[row]++;
+ r->state[row] = READ;
+ DPRINTF("RLOCK : %3d (row: %d)\n", r->lines[row], row);
+ pthread_mutex_unlock(&r->lock);
+ ret.type = IO_INT_T;
+ ret.u.i = 0;
+ cb(ret, param);
+ } else {
+ struct radix_wait **rwc;
+ struct radix_wait *rw =
+ (struct radix_wait *) malloc (sizeof(struct radix_wait));
+ DPRINTF("RLOCK : %3d (row: %d) -- DEFERRED!\n", r->lines[row], row);
+ rw->type = RLOCK;
+ rw->param = param;
+ rw->cb = cb;
+ rw->next = NULL;
+ /* append to waiters list. */
+ rwc = &r->waiters[row];
+ while (*rwc != NULL) rwc = &(*rwc)->next;
+ *rwc = rw;
+ pthread_mutex_unlock(&r->lock);
+ return;
+ }
}
void block_wlock(struct radix_lock *r, int row, io_cb_t cb, void *param)
{
- struct io_ret ret;
- pthread_mutex_lock(&r->lock);
-
- /* the second check here is redundant -- just here for debugging now. */
- if ((r->state[row] == ANY) && ( r->lines[row] == 0 )) {
- r->state[row] = STOP;
- r->lines[row] = -1;
- DPRINTF("WLOCK : %3d (row: %d)\n", r->lines[row], row);
- pthread_mutex_unlock(&r->lock);
- ret.type = IO_INT_T;
- ret.u.i = 0;
- cb(ret, param);
- } else {
- struct radix_wait **rwc;
- struct radix_wait *rw =
- (struct radix_wait *) malloc (sizeof(struct radix_wait));
- DPRINTF("WLOCK : %3d (row: %d) -- DEFERRED!\n", r->lines[row], row);
- rw->type = WLOCK;
- rw->param = param;
- rw->cb = cb;
- rw->next = NULL;
- /* append to waiters list. */
- rwc = &r->waiters[row];
- while (*rwc != NULL) rwc = &(*rwc)->next;
- *rwc = rw;
- pthread_mutex_unlock(&r->lock);
- return;
- }
+ struct io_ret ret;
+ pthread_mutex_lock(&r->lock);
+
+ /* the second check here is redundant -- just here for debugging now. */
+ if ((r->state[row] == ANY) && ( r->lines[row] == 0 )) {
+ r->state[row] = STOP;
+ r->lines[row] = -1;
+ DPRINTF("WLOCK : %3d (row: %d)\n", r->lines[row], row);
+ pthread_mutex_unlock(&r->lock);
+ ret.type = IO_INT_T;
+ ret.u.i = 0;
+ cb(ret, param);
+ } else {
+ struct radix_wait **rwc;
+ struct radix_wait *rw =
+ (struct radix_wait *) malloc (sizeof(struct radix_wait));
+ DPRINTF("WLOCK : %3d (row: %d) -- DEFERRED!\n", r->lines[row], row);
+ rw->type = WLOCK;
+ rw->param = param;
+ rw->cb = cb;
+ rw->next = NULL;
+ /* append to waiters list. */
+ rwc = &r->waiters[row];
+ while (*rwc != NULL) rwc = &(*rwc)->next;
+ *rwc = rw;
+ pthread_mutex_unlock(&r->lock);
+ return;
+ }
}
/* called with radix_lock locked and lock count of zero. */
static void wake_waiters(struct radix_lock *r, int row)
{
- struct pending_io_req *req;
- struct radix_wait *rw;
-
- DPRINTF("prewake\n");
- if (r->lines[row] != 0) return;
- if (r->waiters[row] == NULL) {DPRINTF("nowaiters!\n");return;}
-
- DPRINTF("wake\n");
- if (r->waiters[row]->type == WLOCK) {
- rw = r->waiters[row];
- pthread_mutex_lock(&pending_io_lock);
- assert(CAN_PRODUCE_PENDING_IO);
-
- req = PENDING_IO_ENT(io_prod++);
- DPRINTF("Produce (WWAKE) %lu (%p)\n", io_prod - 1, req);
- req->op = IO_WWAKE;
- req->cb = rw->cb;
- req->param = rw->param;
- r->lines[row] = -1; /* write lock the row. */
- r->state[row] = STOP;
- r->waiters[row] = rw->next;
- free(rw);
- pthread_mutex_unlock(&pending_io_lock);
- } else /* RLOCK */ {
- while ((r->waiters[row] != NULL) && (r->waiters[row]->type == RLOCK)) {
- rw = r->waiters[row];
- pthread_mutex_lock(&pending_io_lock);
- assert(CAN_PRODUCE_PENDING_IO);
-
- req = PENDING_IO_ENT(io_prod++);
- DPRINTF("Produce (RWAKE) %lu (%p)\n", io_prod - 1, req);
- req->op = IO_RWAKE;
- req->cb = rw->cb;
- req->param = rw->param;
- r->lines[row]++; /* read lock the row. */
- r->state[row] = READ;
- r->waiters[row] = rw->next;
- free(rw);
- pthread_mutex_unlock(&pending_io_lock);
- }
- if (r->waiters[row] != NULL) /* There is a write queued still */
- r->state[row] = STOP;
- }
-
- DPRINTF("wakedone\n");
- DPRINTF("prod: %lu cons: %lu free: %lu\n", io_prod, io_cons, io_free);
- pthread_mutex_lock(&pending_io_lock);
+ struct pending_io_req *req;
+ struct radix_wait *rw;
+
+ if (r->lines[row] != 0) return;
+ if (r->waiters[row] == NULL) return;
+
+ if (r->waiters[row]->type == WLOCK) {
+
+ rw = r->waiters[row];
+ pthread_mutex_lock(&pending_io_lock);
+ assert(CAN_PRODUCE_PENDING_IO);
+
+ req = PENDING_IO_ENT(io_prod++);
+ req->op = IO_WWAKE;
+ req->cb = rw->cb;
+ req->param = rw->param;
+ r->lines[row] = -1; /* write lock the row. */
+ r->state[row] = STOP;
+ r->waiters[row] = rw->next;
+ free(rw);
+ pthread_mutex_unlock(&pending_io_lock);
+
+ } else /* RLOCK */ {
+
+ while ((r->waiters[row] != NULL) && (r->waiters[row]->type == RLOCK)) {
+ rw = r->waiters[row];
+ pthread_mutex_lock(&pending_io_lock);
+ assert(CAN_PRODUCE_PENDING_IO);
+
+ req = PENDING_IO_ENT(io_prod++);
+ req->op = IO_RWAKE;
+ req->cb = rw->cb;
+ req->param = rw->param;
+ r->lines[row]++; /* read lock the row. */
+ r->state[row] = READ;
+ r->waiters[row] = rw->next;
+ free(rw);
+ pthread_mutex_unlock(&pending_io_lock);
+ }
+
+ if (r->waiters[row] != NULL) /* There is a write queued still */
+ r->state[row] = STOP;
+ }
+
+ pthread_mutex_lock(&pending_io_lock);
pthread_cond_signal(&pending_io_cond);
- pthread_mutex_unlock(&pending_io_lock);
+ pthread_mutex_unlock(&pending_io_lock);
}
void block_runlock(struct radix_lock *r, int row, io_cb_t cb, void *param)
{
- struct io_ret ret;
+ struct io_ret ret;
- pthread_mutex_lock(&r->lock);
- assert(r->lines[row] > 0); /* try to catch misuse. */
- r->lines[row]--;
- DPRINTF("RUNLOCK: %3d (row: %d)\n", r->lines[row], row);
- if (r->lines[row] == 0) {
- r->state[row] = ANY;
- wake_waiters(r, row);
- }
- pthread_mutex_unlock(&r->lock);
- cb(ret, param);
+ pthread_mutex_lock(&r->lock);
+ assert(r->lines[row] > 0); /* try to catch misuse. */
+ r->lines[row]--;
+ if (r->lines[row] == 0) {
+ r->state[row] = ANY;
+ wake_waiters(r, row);
+ }
+ pthread_mutex_unlock(&r->lock);
+ cb(ret, param);
}
void block_wunlock(struct radix_lock *r, int row, io_cb_t cb, void *param)
{
- struct io_ret ret;
-
- pthread_mutex_lock(&r->lock);
- assert(r->lines[row] == -1); /* try to catch misuse. */
- r->lines[row] = 0;
- r->state[row] = ANY;
- DPRINTF("WUNLOCK: %3d (row: %d)\n", r->lines[row], row);
- wake_waiters(r, row);
- pthread_mutex_unlock(&r->lock);
- cb(ret, param);
+ struct io_ret ret;
+
+ pthread_mutex_lock(&r->lock);
+ assert(r->lines[row] == -1); /* try to catch misuse. */
+ r->lines[row] = 0;
+ r->state[row] = ANY;
+ wake_waiters(r, row);
+ pthread_mutex_unlock(&r->lock);
+ cb(ret, param);
}
/* consumer calls */
static void do_next_io_req(struct pending_io_req *req)
{
- struct io_ret ret;
- void *param;
-
- switch (req->op) {
- case IO_READ:
- ret.type = IO_BLOCK_T;
- ret.u.b = readblock(req->u.r.addr);
- break;
- case IO_WRITE:
- ret.type = IO_INT_T;
- ret.u.i = writeblock(req->u.w.addr, req->u.w.block);
- DPRINTF("wrote %d at %Lu\n", *(int *)(req->u.w.block), req->u.w.addr);
- break;
- case IO_ALLOC:
- ret.type = IO_ADDR_T;
- ret.u.a = allocblock(req->u.a.block);
- break;
- case IO_RWAKE:
- DPRINTF("WAKE DEFERRED RLOCK!\n");
- ret.type = IO_INT_T;
- ret.u.i = 0;
- break;
- case IO_WWAKE:
- DPRINTF("WAKE DEFERRED WLOCK!\n");
- ret.type = IO_INT_T;
- ret.u.i = 0;
- break;
- default:
- DPRINTF("Unknown IO operation on pending list!\n");
- return;
- }
+ struct io_ret ret;
+ void *param;
+
+ switch (req->op) {
+ case IO_READ:
+ ret.type = IO_BLOCK_T;
+ ret.u.b = readblock(req->u.r.addr);
+ break;
+ case IO_WRITE:
+ ret.type = IO_INT_T;
+ ret.u.i = writeblock(req->u.w.addr, req->u.w.block);
+ DPRINTF("wrote %d at %Lu\n", *(int *)(req->u.w.block), req->u.w.addr);
+ break;
+ case IO_ALLOC:
+ ret.type = IO_ADDR_T;
+ ret.u.a = allocblock(req->u.a.block);
+ break;
+ case IO_RWAKE:
+ DPRINTF("WAKE DEFERRED RLOCK!\n");
+ ret.type = IO_INT_T;
+ ret.u.i = 0;
+ break;
+ case IO_WWAKE:
+ DPRINTF("WAKE DEFERRED WLOCK!\n");
+ ret.type = IO_INT_T;
+ ret.u.i = 0;
+ break;
+ default:
+ DPRINTF("Unknown IO operation on pending list!\n");
+ return;
+ }
+
+ param = req->param;
+ pthread_mutex_lock(&pending_io_lock);
+ pending_io_list[PENDING_IO_MASK(io_free++)] = PENDING_IO_IDX(req);
+ pthread_mutex_unlock(&pending_io_lock);
- param = req->param;
- DPRINTF("freeing idx %d to slot %lu.\n", PENDING_IO_IDX(req), PENDING_IO_MASK(io_free));
- pthread_mutex_lock(&pending_io_lock);
- pending_io_list[PENDING_IO_MASK(io_free++)] = PENDING_IO_IDX(req);
- DPRINTF(" : prod: %lu cons: %lu free: %lu\n", io_prod, io_cons, io_free);
- pthread_mutex_unlock(&pending_io_lock);
-
- assert(req->cb != NULL);
- req->cb(ret, param);
-
+ assert(req->cb != NULL);
+ req->cb(ret, param);
+
}
void *io_thread(void *param)
{
- int tid;
- struct pending_io_req *req;
-
- /* Set this thread's tid. */
+ int tid;
+ struct pending_io_req *req;
+
+ /* Set this thread's tid. */
tid = *(int *)param;
free(param);
- DPRINTF("IOT %2d started.\n", tid);
-
start:
pthread_mutex_lock(&pending_io_lock);
while (io_prod == io_cons) {
@@ -369,15 +361,12 @@ start:
goto start;
}
- req = PENDING_IO_ENT(io_cons++);
- DPRINTF("IOT %2d has req %04d(%p).\n", tid, PENDING_IO_IDX(req), req);
- DPRINTF(" : prod: %lu cons: %lu free: %lu\n", io_prod, io_cons, io_free);
- pthread_mutex_unlock(&pending_io_lock);
-
+ req = PENDING_IO_ENT(io_cons++);
+ pthread_mutex_unlock(&pending_io_lock);
do_next_io_req(req);
- goto start;
+ goto start;
}
@@ -385,9 +374,9 @@ static pthread_t io_pool[IO_POOL_SIZE];
void start_io_threads(void)
{
- int i, tid=0;
-
- for (i=0; i < IO_POOL_SIZE; i++) {
+ int i, tid=0;
+
+ for (i=0; i < IO_POOL_SIZE; i++) {
int ret, *t;
t = (int *)malloc(sizeof(int));
*t = tid++;
@@ -399,6 +388,6 @@ void start_io_threads(void)
void init_block_async(void)
{
- init_pending_io();
- start_io_threads();
+ init_pending_io();
+ start_io_threads();
}
diff --git a/tools/blktap/block-async.h b/tools/blktap/block-async.h
index b19d464a52..022eea5da1 100755
--- a/tools/blktap/block-async.h
+++ b/tools/blktap/block-async.h
@@ -12,29 +12,29 @@
struct io_ret
{
- enum {IO_ADDR_T, IO_BLOCK_T, IO_INT_T} type;
- union {
- u64 a;
- char *b;
- int i;
- } u;
+ enum {IO_ADDR_T, IO_BLOCK_T, IO_INT_T} type;
+ union {
+ u64 a;
+ char *b;
+ int i;
+ } u;
};
typedef void (*io_cb_t)(struct io_ret r, void *param);
/* per-vdi lock structures to make sure requests run in a safe order. */
struct radix_wait {
- enum {RLOCK, WLOCK} type;
- io_cb_t cb;
- void *param;
- struct radix_wait *next;
+ enum {RLOCK, WLOCK} type;
+ io_cb_t cb;
+ void *param;
+ struct radix_wait *next;
};
struct radix_lock {
- pthread_mutex_t lock;
- int lines[1024];
- struct radix_wait *waiters[1024];
- enum {ANY, READ, STOP} state[1024];
+ pthread_mutex_t lock;
+ int lines[1024];
+ struct radix_wait *waiters[1024];
+ enum {ANY, READ, STOP} state[1024];
};
void radix_lock_init(struct radix_lock *r);
@@ -49,20 +49,20 @@ void init_block_async(void);
static inline u64 IO_ADDR(struct io_ret r)
{
- assert(r.type == IO_ADDR_T);
- return r.u.a;
+ assert(r.type == IO_ADDR_T);
+ return r.u.a;
}
static inline char *IO_BLOCK(struct io_ret r)
{
- assert(r.type == IO_BLOCK_T);
- return r.u.b;
+ assert(r.type == IO_BLOCK_T);
+ return r.u.b;
}
static inline int IO_INT(struct io_ret r)
{
- assert(r.type == IO_INT_T);
- return r.u.i;
+ assert(r.type == IO_INT_T);
+ return r.u.i;
}
diff --git a/tools/blktap/blockstore.c b/tools/blktap/blockstore.c
index a9dde6e461..e15ddcd760 100644
--- a/tools/blktap/blockstore.c
+++ b/tools/blktap/blockstore.c
@@ -17,7 +17,6 @@
#include <stdarg.h>
#include "blockstore.h"
#include <pthread.h>
-#include "parallax-threaded.h"
//#define BLOCKSTORE_REMOTE
//#define BSDEBUG
diff --git a/tools/blktap/parallax-threaded.c b/tools/blktap/parallax-threaded.c
deleted file mode 100644
index 4944474fc7..0000000000
--- a/tools/blktap/parallax-threaded.c
+++ /dev/null
@@ -1,654 +0,0 @@
-/**************************************************************************
- *
- * parallax.c
- *
- * The Parallax Storage Server
- *
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <pthread.h>
-#include "blktaplib.h"
-#include "blockstore.h"
-#include "vdi.h"
-#include "parallax-threaded.h"
-
-#define PARALLAX_DEV 61440
-
-
-#if 0
-#define DPRINTF(_f, _a...) printf ( _f , ## _a )
-#else
-#define DPRINTF(_f, _a...) ((void)0)
-#endif
-
-/* ------[ session records ]----------------------------------------------- */
-
-#define BLKIF_HASHSZ 1024
-#define BLKIF_HASH(_d,_h) (((int)(_d)^(int)(_h))&(BLKIF_HASHSZ-1))
-
-#define VDI_HASHSZ 16
-#define VDI_HASH(_vd) ((((_vd)>>8)^(_vd))&(VDI_HASHSZ-1))
-
-typedef struct blkif {
- domid_t domid;
- unsigned int handle;
- enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
- vdi_t *vdi_hash[VDI_HASHSZ];
- struct blkif *hash_next;
-} blkif_t;
-
-static blkif_t *blkif_hash[BLKIF_HASHSZ];
-
-blkif_t *blkif_find_by_handle(domid_t domid, unsigned int handle)
-{
- if ( handle != 0 )
- printf("blktap/parallax don't currently support non-0 dev handles!\n");
-
- blkif_t *blkif = blkif_hash[BLKIF_HASH(domid, handle)];
- while ( (blkif != NULL) &&
- ((blkif->domid != domid) || (blkif->handle != handle)) )
- blkif = blkif->hash_next;
- return blkif;
-}
-
-vdi_t *blkif_get_vdi(blkif_t *blkif, blkif_vdev_t device)
-{
- vdi_t *vdi = blkif->vdi_hash[VDI_HASH(device)];
-
- while ((vdi != NULL) && (vdi->vdevice != device))
- vdi = vdi->next;
-
- return vdi;
-}
-
-/* ------[ control message handling ]-------------------------------------- */
-
-void blkif_create(blkif_be_create_t *create)
-{
- domid_t domid = create->domid;
- unsigned int handle = create->blkif_handle;
- blkif_t **pblkif, *blkif;
-
- DPRINTF("parallax (blkif_create): create is %p\n", create);
-
- if ( (blkif = (blkif_t *)malloc(sizeof(blkif_t))) == NULL )
- {
- DPRINTF("Could not create blkif: out of memory\n");
- create->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
- return;
- }
-
- memset(blkif, 0, sizeof(*blkif));
- blkif->domid = domid;
- blkif->handle = handle;
- blkif->status = DISCONNECTED;
-/*
- spin_lock_init(&blkif->vbd_lock);
- spin_lock_init(&blkif->blk_ring_lock);
- atomic_set(&blkif->refcnt, 0);
-*/
- pblkif = &blkif_hash[BLKIF_HASH(domid, handle)];
- while ( *pblkif != NULL )
- {
- if ( ((*pblkif)->domid == domid) && ((*pblkif)->handle == handle) )
- {
- DPRINTF("Could not create blkif: already exists\n");
- create->status = BLKIF_BE_STATUS_INTERFACE_EXISTS;
- free(blkif);
- return;
- }
- pblkif = &(*pblkif)->hash_next;
- }
-
- blkif->hash_next = *pblkif;
- *pblkif = blkif;
-
- DPRINTF("Successfully created blkif\n");
- create->status = BLKIF_BE_STATUS_OKAY;
-}
-
-void blkif_destroy(blkif_be_destroy_t *destroy)
-{
- domid_t domid = destroy->domid;
- unsigned int handle = destroy->blkif_handle;
- blkif_t **pblkif, *blkif;
-
- DPRINTF("parallax (blkif_destroy): destroy is %p\n", destroy);
-
- pblkif = &blkif_hash[BLKIF_HASH(domid, handle)];
- while ( (blkif = *pblkif) != NULL )
- {
- if ( (blkif->domid == domid) && (blkif->handle == handle) )
- {
- if ( blkif->status != DISCONNECTED )
- goto still_connected;
- goto destroy;
- }
- pblkif = &blkif->hash_next;
- }
-
- destroy->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
- return;
-
- still_connected:
- destroy->status = BLKIF_BE_STATUS_INTERFACE_CONNECTED;
- return;
-
- destroy:
- *pblkif = blkif->hash_next;
- /* destroy_all_vbds(blkif); */
- free(blkif);
- destroy->status = BLKIF_BE_STATUS_OKAY;
-}
-
-void vbd_create(blkif_be_vbd_create_t *create)
-{
- blkif_t *blkif;
- vdi_t *vdi, **vdip;
- blkif_vdev_t vdevice = create->vdevice;
-
- DPRINTF("parallax (vbd_create): create=%p\n", create);
-
- blkif = blkif_find_by_handle(create->domid, create->blkif_handle);
- if ( blkif == NULL )
- {
- DPRINTF("vbd_create attempted for non-existent blkif (%u,%u)\n",
- create->domid, create->blkif_handle);
- create->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
- return;
- }
-
- /* VDI identifier is in grow->extent.sector_start */
- DPRINTF("vbd_create: create->dev_handle (id) is %lx\n",
- (unsigned long)create->dev_handle);
-
- vdi = vdi_get(create->dev_handle);
- if (vdi == NULL)
- {
- printf("parallax (vbd_create): VDI %lx not found.\n",
- (unsigned long)create->dev_handle);
- create->status = BLKIF_BE_STATUS_VBD_NOT_FOUND;
- return;
- }
-
- vdi->next = NULL;
- vdi->vdevice = vdevice;
- vdip = &blkif->vdi_hash[VDI_HASH(vdevice)];
- while (*vdip != NULL)
- vdip = &(*vdip)->next;
- *vdip = vdi;
-
- DPRINTF("vbd_grow: happy return!\n");
- create->status = BLKIF_BE_STATUS_OKAY;
-}
-
-int parallax_control(control_msg_t *msg)
-{
- domid_t domid;
- int ret;
-
- DPRINTF("parallax_control: msg is %p\n", msg);
-
- if (msg->type != CMSG_BLKIF_BE)
- {
- printf("Unexpected control message (%d)\n", msg->type);
- return 0;
- }
-
- switch(msg->subtype)
- {
- case CMSG_BLKIF_BE_CREATE:
- if ( msg->length != sizeof(blkif_be_create_t) )
- goto parse_error;
- blkif_create((blkif_be_create_t *)msg->msg);
- break;
-
- case CMSG_BLKIF_BE_DESTROY:
- if ( msg->length != sizeof(blkif_be_destroy_t) )
- goto parse_error;
- blkif_destroy((blkif_be_destroy_t *)msg->msg);
- break;
-
- case CMSG_BLKIF_BE_VBD_CREATE:
- if ( msg->length != sizeof(blkif_be_vbd_create_t) )
- goto parse_error;
- vbd_create((blkif_be_vbd_create_t *)msg->msg);
- break;
- }
- return 0;
-parse_error:
- printf("Bad control message!\n");
- return 0;
-
-}
-
-int parallax_probe(blkif_request_t *req, blkif_t *blkif)
-{
- blkif_response_t *rsp;
- vdisk_t *img_info;
- vdi_t *vdi;
- int i, nr_vdis = 0;
-
- DPRINTF("parallax_probe: req=%p, blkif=%p\n", req, blkif);
-
- /* We expect one buffer only. */
- if ( req->nr_segments != 1 )
- goto err;
-
- /* Make sure the buffer is page-sized. */
- if ( (blkif_first_sect(req->frame_and_sects[0]) != 0) ||
- (blkif_last_sect (req->frame_and_sects[0]) != 7) )
- goto err;
-
- /* fill the list of devices */
- for (i=0; i<VDI_HASHSZ; i++) {
- vdi = blkif->vdi_hash[i];
- while (vdi) {
- img_info = (vdisk_t *)MMAP_VADDR(ID_TO_IDX(req->id), 0);
- img_info[nr_vdis].device = vdi->vdevice;
- img_info[nr_vdis].info = 0;
- /* The -2 here accounts for the LSB in the radix tree */
- img_info[nr_vdis].capacity =
- ((1LL << (VDI_HEIGHT-2)) >> SECTOR_SHIFT);
- nr_vdis++;
- vdi = vdi->next;
- }
- }
-
-
- rsp = (blkif_response_t *)req;
- rsp->id = req->id;
- rsp->operation = BLKIF_OP_PROBE;
- rsp->status = nr_vdis; /* number of disks */
-
- DPRINTF("parallax_probe: send positive response (nr_vdis=%d)\n", nr_vdis);
- return BLKTAP_RESPOND;
-err:
- rsp = (blkif_response_t *)req;
- rsp->id = req->id;
- rsp->operation = BLKIF_OP_PROBE;
- rsp->status = BLKIF_RSP_ERROR;
-
- DPRINTF("parallax_probe: send error response\n");
- return BLKTAP_RESPOND;
-}
-
-typedef struct {
- blkif_request_t *req;
- int count;
- pthread_mutex_t mutex;
-} pending_t;
-
-#define MAX_REQUESTS 64
-pending_t pending_list[MAX_REQUESTS];
-
-typedef struct {
- vdi_t *vdi;
- blkif_request_t *req;
- int segment;
- pending_t *pent;
-} readseg_params_t;
-
-#define DISPATCH_SIZE 1024UL
-#define DISPATCH_MASK (DISPATCH_SIZE-1)
-readseg_params_t dispatch_list[DISPATCH_SIZE];
-unsigned long dprod = 0, dcons = 0;
-pthread_mutex_t dispatch_mutex;
-pthread_cond_t dispatch_cond;
-
-void *read_segment(void *param)
-{
- readseg_params_t *p;
- u64 vblock, gblock, sector;
- char *dpage, *spage;
- unsigned long size, start, offset;
- blkif_response_t *rsp;
- int tid;
-
-unsigned long dc, dp;
-
-#ifdef NOTHREADS
-#else
- /* Set this thread's tid. */
- tid = *(int *)param;
- free(param);
-
- pthread_setspecific(tid_key, (void *)tid);
-
- printf("My tid is %d.\n", (int)pthread_getspecific(tid_key));
-start:
- pthread_mutex_lock(&dispatch_mutex);
- while (dprod == dcons)
- pthread_cond_wait(&dispatch_cond, &dispatch_mutex);
-
- if (dprod == dcons) {
- /* unnecessary wakeup. */
- pthread_mutex_unlock(&dispatch_mutex);
- goto start;
- }
-#endif
-dc = dcons;
-dp = dprod;
-
- p = &dispatch_list[dcons & DISPATCH_MASK];
- dcons++;
-#ifdef NOTHREADS
-#else
- pthread_mutex_unlock(&dispatch_mutex);
-#endif
- dpage = (char *)MMAP_VADDR(ID_TO_IDX(p->req->id), p->segment);
-
- /* Round the requested segment to a block address. */
-
- sector = p->req->sector_number + (8*p->segment);
- vblock = (sector << SECTOR_SHIFT) >> BLOCK_SHIFT;
-
- /* Get that block from the store. */
-
- gblock = vdi_lookup_block(p->vdi, vblock, NULL);
-
- /* Calculate read size and offset within the read block. */
-
- offset = (sector << SECTOR_SHIFT) % BLOCK_SIZE;
- size = ( blkif_last_sect (p->req->frame_and_sects[p->segment]) -
- blkif_first_sect(p->req->frame_and_sects[p->segment]) + 1
- ) << SECTOR_SHIFT;
- start = blkif_first_sect(p->req->frame_and_sects[p->segment])
- << SECTOR_SHIFT;
-
- /* If the block does not exist in the store, return zeros. */
- /* Otherwise, copy that region to the guest page. */
-
-// printf(" : (%p, %d, %d) (%d) [c:%lu,p:%lu]\n",
-// p->req, ID_TO_IDX(p->req->id), p->segment,
-// p->pent->count, dc, dp);
-
- DPRINTF("ParallaxRead: sect: %lld (%ld,%ld), "
- "vblock %llx, gblock %llx, "
- "size %lx\n",
- sector, blkif_first_sect(p->req->frame_and_sects[p->segment]),
- blkif_last_sect (p->req->frame_and_sects[p->segment]),
- vblock, gblock, size);
-
- if ( gblock == 0 ) {
-
- memset(dpage + start, '\0', size);
-
- } else {
-
- spage = readblock(gblock);
-
- if (spage == NULL) {
- printf("Error reading gblock from store: %Ld\n", gblock);
- goto err;
- }
-
- memcpy(dpage + start, spage + offset, size);
-
- freeblock(spage);
- }
-
-
- /* Done the read. Now update the pending record. */
-
- pthread_mutex_lock(&p->pent->mutex);
- p->pent->count--;
-
- if (p->pent->count == 0) {
-
-// printf("FINISH: (%d, %d)\n", ID_TO_IDX(p->req->id), p->segment);
- rsp = (blkif_response_t *)p->req;
- rsp->id = p->req->id;
- rsp->operation = BLKIF_OP_READ;
- rsp->status = BLKIF_RSP_OKAY;
-
- blktap_inject_response(rsp);
- }
-
- pthread_mutex_unlock(&p->pent->mutex);
-
-#ifdef NOTHREADS
- return NULL;
-#else
- goto start;
-#endif
-
-err:
- printf("I am screwed!\n");
-#ifdef NOTHREADS
- return NULL;
-#else
- goto start;
-#endif
-}
-
-
-int parallax_read(blkif_request_t *req, blkif_t *blkif)
-{
- blkif_response_t *rsp;
- unsigned long size, offset, start;
- u64 sector;
- u64 vblock, gblock;
- vdi_t *vdi;
- int i;
- char *dpage, *spage;
- pending_t *pent;
- readseg_params_t *params;
-
- vdi = blkif_get_vdi(blkif, req->device);
-
- if ( vdi == NULL )
- goto err;
-
-// printf("START : (%p, %d, %d)\n", req, ID_TO_IDX(req->id), req->nr_segments);
-
- pent = &pending_list[ID_TO_IDX(req->id)];
- pent->count = req->nr_segments;
- pent->req = req;
- pthread_mutex_init(&pent->mutex, NULL);
-
-
- for (i = 0; i < req->nr_segments; i++) {
- pthread_t tid;
- int ret;
-
- params = &dispatch_list[dprod & DISPATCH_MASK];
- params->pent = pent;
- params->vdi = vdi;
- params->req = req;
- params->segment = i;
- wmb();
- dprod++;
-
- pthread_mutex_lock(&dispatch_mutex);
- pthread_cond_signal(&dispatch_cond);
- pthread_mutex_unlock(&dispatch_mutex);
-#ifdef NOTHREADS
- read_segment(NULL);
-#endif
-
- }
-
-
-
-
- return BLKTAP_STOLEN;
-
-err:
- rsp = (blkif_response_t *)req;
- rsp->id = req->id;
- rsp->operation = BLKIF_OP_READ;
- rsp->status = BLKIF_RSP_ERROR;
-
- return BLKTAP_RESPOND;
-}
-
-int parallax_write(blkif_request_t *req, blkif_t *blkif)
-{
- blkif_response_t *rsp;
- u64 sector;
- int i, writable = 0;
- u64 vblock, gblock;
- char *spage;
- unsigned long size, offset, start;
- vdi_t *vdi;
-
- vdi = blkif_get_vdi(blkif, req->device);
-
- if ( vdi == NULL )
- goto err;
-
- for (i = 0; i < req->nr_segments; i++) {
-
- spage = (char *)MMAP_VADDR(ID_TO_IDX(req->id), i);
-
- /* Round the requested segment to a block address. */
-
- sector = req->sector_number + (8*i);
- vblock = (sector << SECTOR_SHIFT) >> BLOCK_SHIFT;
-
- /* Get that block from the store. */
-
- gblock = vdi_lookup_block(vdi, vblock, &writable);
-
- /* Calculate read size and offset within the read block. */
-
- offset = (sector << SECTOR_SHIFT) % BLOCK_SIZE;
- size = ( blkif_last_sect (req->frame_and_sects[i]) -
- blkif_first_sect(req->frame_and_sects[i]) + 1
- ) << SECTOR_SHIFT;
- start = blkif_first_sect(req->frame_and_sects[i]) << SECTOR_SHIFT;
-
- DPRINTF("ParallaxWrite: sect: %lld (%ld,%ld), "
- "vblock %llx, gblock %llx, "
- "size %lx\n",
- sector, blkif_first_sect(req->frame_and_sects[i]),
- blkif_last_sect (req->frame_and_sects[i]),
- vblock, gblock, size);
-
- /* XXX: For now we just freak out if they try to write a */
- /* non block-sized, block-aligned page. */
-
- if ((offset != 0) || (size != BLOCK_SIZE) || (start != 0)) {
- printf("]\n] STRANGE WRITE!\n]\n");
- goto err;
- }
-
- if (( gblock == 0 ) || ( writable == 0 )) {
-
- gblock = allocblock(spage);
- vdi_update_block(vdi, vblock, gblock);
-
- } else {
-
- /* write-in-place, no need to change mappings. */
- writeblock(gblock, spage);
-
- }
-
- }
-
- rsp = (blkif_response_t *)req;
- rsp->id = req->id;
- rsp->operation = BLKIF_OP_WRITE;
- rsp->status = BLKIF_RSP_OKAY;
-
- return BLKTAP_RESPOND;
-err:
- rsp = (blkif_response_t *)req;
- rsp->id = req->id;
- rsp->operation = BLKIF_OP_WRITE;
- rsp->status = BLKIF_RSP_ERROR;
-
- return BLKTAP_RESPOND;
-}
-
-int parallax_request(blkif_request_t *req)
-{
- blkif_response_t *rsp;
- domid_t dom = ID_TO_DOM(req->id);
- blkif_t *blkif = blkif_find_by_handle(dom, 0);
-
- //DPRINTF("parallax_request: req=%p, dom=%d, blkif=%p\n", req, dom, blkif);
-
- if (blkif == NULL)
- goto err;
-
- if ( req->operation == BLKIF_OP_PROBE ) {
-
- return parallax_probe(req, blkif);
-
- } else if ( req->operation == BLKIF_OP_READ ) {
-
- return parallax_read(req, blkif);
-
- } else if ( req->operation == BLKIF_OP_WRITE ) {
-
- return parallax_write(req, blkif);
-
- } else {
- /* Unknown operation */
- goto err;
- }
-
-err:
- rsp = (blkif_response_t *)req;
- rsp->id = req->id;
- rsp->operation = req->operation;
- rsp->status = BLKIF_RSP_ERROR;
- return BLKTAP_RESPOND;
-}
-
-void __init_parallax(void)
-{
- memset(blkif_hash, 0, sizeof(blkif_hash));
-}
-
-
-
-int main(int argc, char *argv[])
-{
- pthread_t read_pool[READ_POOL_SIZE];
- int i, tid=0;
-
- DPRINTF("parallax: starting.\n");
- __init_blockstore();
- DPRINTF("parallax: initialized blockstore...\n");
- __init_vdi();
- DPRINTF("parallax: initialized vdi registry etc...\n");
- __init_parallax();
- DPRINTF("parallax: initialized local stuff..\n");
-
-
- pthread_mutex_init(&dispatch_mutex, NULL);
- pthread_cond_init(&dispatch_cond, NULL);
-
- pthread_key_create(&tid_key, NULL);
- tid = 0;
-
-#ifdef NOTHREADS
-#else
- for (i=0; i < READ_POOL_SIZE; i++) {
- int ret, *t;
- t = (int *)malloc(sizeof(int));
- *t = tid++;
- ret = pthread_create(&read_pool[i], NULL, read_segment, t);
- if (ret != 0) printf("Error starting thread %d\n", i);
- }
-#endif
-
- pthread_setspecific(tid_key, (void *)tid);
-
- printf("*My tid is %d.\n", (int)pthread_getspecific(tid_key));
-
- blktap_register_ctrl_hook("parallax_control", parallax_control);
- blktap_register_request_hook("parallax_request", parallax_request);
- DPRINTF("parallax: added ctrl + request hooks, starting listen...\n");
- blktap_listen();
-
- return 0;
-}
diff --git a/tools/blktap/parallax-threaded.h b/tools/blktap/parallax-threaded.h
deleted file mode 100644
index de39609fcc..0000000000
--- a/tools/blktap/parallax-threaded.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/**************************************************************************
- *
- * parallax-threaded.h
- *
- * a few thread-specific defines
- *
- */
-
-#ifndef __PARALLAX_THREADED_H__
-#define __PARALLAX_THREADED_H__
-
-#if 0
-/* Turn off threading. */
-#define NOTHREADS
-#endif
-
-//#define READ_POOL_SIZE 128
-#define READ_POOL_SIZE 8
-
-/* per-thread identifier */
-pthread_key_t tid_key;
-
-#endif /* __PARALLAX_THREADED_H__ */
-
diff --git a/tools/blktap/parallax.c b/tools/blktap/parallax.c
index dc71b05603..46cdec4496 100644
--- a/tools/blktap/parallax.c
+++ b/tools/blktap/parallax.c
@@ -88,17 +88,14 @@ void blkif_create(blkif_be_create_t *create)
blkif->domid = domid;
blkif->handle = handle;
blkif->status = DISCONNECTED;
-/*
- spin_lock_init(&blkif->vbd_lock);
- spin_lock_init(&blkif->blk_ring_lock);
- atomic_set(&blkif->refcnt, 0);
-*/
+
pblkif = &blkif_hash[BLKIF_HASH(domid, handle)];
while ( *pblkif != NULL )
{
if ( ((*pblkif)->domid == domid) && ((*pblkif)->handle == handle) )
{
- DPRINTF("Could not create blkif: already exists\n");
+ DPRINTF("Could not create blkif: already exists (%d,%d)\n",
+ domid, handle);
create->status = BLKIF_BE_STATUS_INTERFACE_EXISTS;
free(blkif);
return;
@@ -142,7 +139,6 @@ void blkif_destroy(blkif_be_destroy_t *destroy)
destroy:
*pblkif = blkif->hash_next;
- /* destroy_all_vbds(blkif); */
free(blkif);
destroy->status = BLKIF_BE_STATUS_OKAY;
}
@@ -184,10 +180,38 @@ void vbd_create(blkif_be_vbd_create_t *create)
vdip = &(*vdip)->next;
*vdip = vdi;
- DPRINTF("vbd_grow: happy return!\n");
+ DPRINTF("blkif_create succeeded\n");
create->status = BLKIF_BE_STATUS_OKAY;
}
+void vbd_destroy(blkif_be_vbd_destroy_t *destroy)
+{
+ blkif_t *blkif;
+ vdi_t *vdi, **vdip;
+ blkif_vdev_t vdevice = destroy->vdevice;
+
+ blkif = blkif_find_by_handle(destroy->domid, destroy->blkif_handle);
+ if ( blkif == NULL )
+ {
+ DPRINTF("vbd_destroy attempted for non-existent blkif (%u,%u)\n",
+ destroy->domid, destroy->blkif_handle);
+ destroy->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
+ return;
+ }
+
+ vdip = &blkif->vdi_hash[VDI_HASH(vdevice)];
+ while ((*vdip != NULL) && ((*vdip)->vdevice != vdevice))
+ vdip = &(*vdip)->next;
+
+ if (*vdip != NULL)
+ {
+ vdi = *vdip;
+ *vdip = vdi->next;
+ vdi_put(vdi);
+ }
+
+}
+
int parallax_control(control_msg_t *msg)
{
domid_t domid;
@@ -220,6 +244,20 @@ int parallax_control(control_msg_t *msg)
goto parse_error;
vbd_create((blkif_be_vbd_create_t *)msg->msg);
break;
+
+ case CMSG_BLKIF_BE_VBD_DESTROY:
+ if ( msg->length != sizeof(blkif_be_vbd_destroy_t) )
+ goto parse_error;
+ vbd_destroy((blkif_be_vbd_destroy_t *)msg->msg);
+ break;
+
+ case CMSG_BLKIF_BE_CONNECT:
+ case CMSG_BLKIF_BE_DISCONNECT:
+ /* we don't manage the device channel, the tap does. */
+ break;
+
+ default:
+ goto parse_error;
}
return 0;
parse_error:
@@ -290,33 +328,33 @@ typedef struct {
pending_t pending_list[MAX_REQUESTS];
struct cb_param {
- pending_t *pent;
- int segment;
- u64 sector;
- u64 vblock; /* for debug printing -- can be removed. */
+ pending_t *pent;
+ int segment;
+ u64 sector;
+ u64 vblock; /* for debug printing -- can be removed. */
};
static void read_cb(struct io_ret r, void *in_param)
{
- struct cb_param *param = (struct cb_param *)in_param;
- pending_t *p = param->pent;
- int segment = param->segment;
- blkif_request_t *req = p->req;
+ struct cb_param *param = (struct cb_param *)in_param;
+ pending_t *p = param->pent;
+ int segment = param->segment;
+ blkif_request_t *req = p->req;
unsigned long size, offset, start;
- char *dpage, *spage;
+ char *dpage, *spage;
- spage = IO_BLOCK(r);
- if (spage == NULL) { p->error++; goto finish; }
- dpage = (char *)MMAP_VADDR(ID_TO_IDX(req->id), segment);
+ spage = IO_BLOCK(r);
+ if (spage == NULL) { p->error++; goto finish; }
+ dpage = (char *)MMAP_VADDR(ID_TO_IDX(req->id), segment);
/* Calculate read size and offset within the read block. */
offset = (param->sector << SECTOR_SHIFT) % BLOCK_SIZE;
size = ( blkif_last_sect (req->frame_and_sects[segment]) -
blkif_first_sect(req->frame_and_sects[segment]) + 1
- ) << SECTOR_SHIFT;
+ ) << SECTOR_SHIFT;
start = blkif_first_sect(req->frame_and_sects[segment])
- << SECTOR_SHIFT;
+ << SECTOR_SHIFT;
DPRINTF("ParallaxRead: sect: %lld (%ld,%ld), "
"vblock %llx, "
@@ -333,23 +371,23 @@ static void read_cb(struct io_ret r, void *in_param)
pthread_mutex_lock(&p->mutex);
p->count--;
- if (p->count == 0) {
+ if (p->count == 0) {
blkif_response_t *rsp;
rsp = (blkif_response_t *)req;
rsp->id = req->id;
rsp->operation = BLKIF_OP_READ;
if (p->error == 0) {
- rsp->status = BLKIF_RSP_OKAY;
+ rsp->status = BLKIF_RSP_OKAY;
} else {
- rsp->status = BLKIF_RSP_ERROR;
+ rsp->status = BLKIF_RSP_ERROR;
}
blktap_inject_response(rsp);
}
pthread_mutex_unlock(&p->mutex);
- free(param); /* TODO: replace with cached alloc/dealloc */
+ free(param); /* TODO: replace with cached alloc/dealloc */
}
int parallax_read(blkif_request_t *req, blkif_t *blkif)
@@ -376,21 +414,20 @@ int parallax_read(blkif_request_t *req, blkif_t *blkif)
pthread_t tid;
int ret;
struct cb_param *p;
-
- /* Round the requested segment to a block address. */
- sector = req->sector_number + (8*i);
- vblock = (sector << SECTOR_SHIFT) >> BLOCK_SHIFT;
-
- /* TODO: Replace this call to malloc with a cached allocation */
- p = (struct cb_param *)malloc(sizeof(struct cb_param));
- p->pent = pent;
- p->sector = sector;
- p->segment = i;
- p->vblock = vblock; /* dbg */
-
- /* Get that block from the store. */
- async_read(vdi, vblock, read_cb, (void *)p);
-
+
+ /* Round the requested segment to a block address. */
+ sector = req->sector_number + (8*i);
+ vblock = (sector << SECTOR_SHIFT) >> BLOCK_SHIFT;
+
+ /* TODO: Replace this call to malloc with a cached allocation */
+ p = (struct cb_param *)malloc(sizeof(struct cb_param));
+ p->pent = pent;
+ p->sector = sector;
+ p->segment = i;
+ p->vblock = vblock; /* dbg */
+
+ /* Get that block from the store. */
+ vdi_read(vdi, vblock, read_cb, (void *)p);
}
return BLKTAP_STOLEN;
@@ -406,33 +443,33 @@ err:
static void write_cb(struct io_ret r, void *in_param)
{
- struct cb_param *param = (struct cb_param *)in_param;
- pending_t *p = param->pent;
- blkif_request_t *req = p->req;
-
- /* catch errors from the block code. */
- if (IO_INT(r) < 0) p->error++;
-
+ struct cb_param *param = (struct cb_param *)in_param;
+ pending_t *p = param->pent;
+ blkif_request_t *req = p->req;
+
+ /* catch errors from the block code. */
+ if (IO_INT(r) < 0) p->error++;
+
pthread_mutex_lock(&p->mutex);
p->count--;
- if (p->count == 0) {
+ if (p->count == 0) {
blkif_response_t *rsp;
rsp = (blkif_response_t *)req;
rsp->id = req->id;
rsp->operation = BLKIF_OP_WRITE;
if (p->error == 0) {
- rsp->status = BLKIF_RSP_OKAY;
+ rsp->status = BLKIF_RSP_OKAY;
} else {
- rsp->status = BLKIF_RSP_ERROR;
+ rsp->status = BLKIF_RSP_ERROR;
}
blktap_inject_response(rsp);
}
pthread_mutex_unlock(&p->mutex);
- free(param); /* TODO: replace with cached alloc/dealloc */
+ free(param); /* TODO: replace with cached alloc/dealloc */
}
int parallax_write(blkif_request_t *req, blkif_t *blkif)
@@ -458,7 +495,7 @@ int parallax_write(blkif_request_t *req, blkif_t *blkif)
for (i = 0; i < req->nr_segments; i++) {
struct cb_param *p;
-
+
spage = (char *)MMAP_VADDR(ID_TO_IDX(req->id), i);
/* Round the requested segment to a block address. */
@@ -471,7 +508,7 @@ int parallax_write(blkif_request_t *req, blkif_t *blkif)
offset = (sector << SECTOR_SHIFT) % BLOCK_SIZE;
size = ( blkif_last_sect (req->frame_and_sects[i]) -
blkif_first_sect(req->frame_and_sects[i]) + 1
- ) << SECTOR_SHIFT;
+ ) << SECTOR_SHIFT;
start = blkif_first_sect(req->frame_and_sects[i]) << SECTOR_SHIFT;
DPRINTF("ParallaxWrite: sect: %lld (%ld,%ld), "
@@ -480,7 +517,7 @@ int parallax_write(blkif_request_t *req, blkif_t *blkif)
sector, blkif_first_sect(req->frame_and_sects[i]),
blkif_last_sect (req->frame_and_sects[i]),
vblock, gblock, size);
-
+
/* XXX: For now we just freak out if they try to write a */
/* non block-sized, block-aligned page. */
@@ -489,15 +526,15 @@ int parallax_write(blkif_request_t *req, blkif_t *blkif)
goto err;
}
- /* TODO: Replace this call to malloc with a cached allocation */
- p = (struct cb_param *)malloc(sizeof(struct cb_param));
- p->pent = pent;
- p->sector = sector;
- p->segment = i;
- p->vblock = vblock; /* dbg */
-
+ /* TODO: Replace this call to malloc with a cached allocation */
+ p = (struct cb_param *)malloc(sizeof(struct cb_param));
+ p->pent = pent;
+ p->sector = sector;
+ p->segment = i;
+ p->vblock = vblock; /* dbg */
+
/* Issue the write to the store. */
- async_write(vdi, vblock, spage, write_cb, (void *)p);
+ vdi_write(vdi, vblock, spage, write_cb, (void *)p);
}
return BLKTAP_STOLEN;
@@ -516,8 +553,6 @@ int parallax_request(blkif_request_t *req)
blkif_response_t *rsp;
domid_t dom = ID_TO_DOM(req->id);
blkif_t *blkif = blkif_find_by_handle(dom, 0);
-
- //DPRINTF("parallax_request: req=%p, dom=%d, blkif=%p\n", req, dom, blkif);
if (blkif == NULL)
goto err;
@@ -535,14 +570,15 @@ int parallax_request(blkif_request_t *req)
return parallax_write(req, blkif);
} else {
+ printf("Unknown request message type!\n");
/* Unknown operation */
goto err;
}
err:
rsp = (blkif_response_t *)req;
- rsp->id = req->id;
rsp->operation = req->operation;
+ rsp->id = req->id;
rsp->status = BLKIF_RSP_ERROR;
return BLKTAP_RESPOND;
}
@@ -559,7 +595,7 @@ int main(int argc, char *argv[])
DPRINTF("parallax: starting.\n");
__init_blockstore();
DPRINTF("parallax: initialized blockstore...\n");
- init_block_async();
+ init_block_async();
DPRINTF("parallax: initialized async blocks...\n");
__init_vdi();
DPRINTF("parallax: initialized vdi registry etc...\n");
diff --git a/tools/blktap/radix.c b/tools/blktap/radix.c
index 579df2e655..a9f148e336 100644
--- a/tools/blktap/radix.c
+++ b/tools/blktap/radix.c
@@ -49,7 +49,6 @@ rcache_t *rcache[RCHASH_SIZE];
void __rcache_init(void)
{
int i;
-printf("rcache_init!\n");
for (i=0; i<RCHASH_SIZE; i++)
rcache[i] = NULL;
diff --git a/tools/blktap/requests-async.c b/tools/blktap/requests-async.c
index bb2d07b60a..f1e0bc8425 100755
--- a/tools/blktap/requests-async.c
+++ b/tools/blktap/requests-async.c
@@ -1,13 +1,16 @@
-/* read.c
+/* requests-async.c
*
- * asynchronous read experiment for parallax.
+ * asynchronous request dispatcher for radix access in parallax.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include <assert.h>
#include <pthread.h>
+#include <err.h>
+#include <zlib.h> /* for crc32() */
#include "requests-async.h"
#include "vdi.h"
#include "radix.h"
@@ -17,15 +20,16 @@
#define L3_IDX(_a) (((_a) & 0x00000000000001ffULL))
-
-//#define STANDALONE
-
#if 0
#define DPRINTF(_f, _a...) printf ( _f , ## _a )
#else
#define DPRINTF(_f, _a...) ((void)0)
#endif
+struct block_info {
+ u32 crc;
+ u32 unused;
+};
struct io_req {
enum { IO_OP_READ, IO_OP_WRITE } op;
@@ -37,18 +41,27 @@ struct io_req {
struct radix_lock *lock;
/* internal stuff: */
- struct io_ret retval;/* holds the return while we unlock. */
- char *block; /* the block to write */
- radix_tree_node radix[3];
- u64 radix_addr[3];
+ struct io_ret retval;/* holds the return while we unlock. */
+ char *block; /* the block to write */
+ radix_tree_node radix[3];
+ u64 radix_addr[3];
+ struct block_info bi;
};
void clear_w_bits(radix_tree_node node)
{
- int i;
- for (i=0; i<RADIX_TREE_MAP_ENTRIES; i++)
- node[i] = node[i] & ONEMASK;
- return;
+ int i;
+ for (i=0; i<RADIX_TREE_MAP_ENTRIES; i++)
+ node[i] = node[i] & ONEMASK;
+ return;
+}
+
+void clear_L3_w_bits(radix_tree_node node)
+{
+ int i;
+ for (i=0; i<RADIX_TREE_MAP_ENTRIES; i+=2)
+ node[i] = node[i] & ONEMASK;
+ return;
}
enum states {
@@ -66,6 +79,7 @@ enum states {
/* write */
WRITE_LOCKED,
WRITE_DATA,
+ WRITE_L3,
WRITE_UNLOCKED,
/* L3 Zero Path */
@@ -89,15 +103,15 @@ enum states {
ALLOC_L3_L2f,
WRITE_L2_L3f,
- /* L1 Zero Path */
+ /* L1 Zero Path */
ALLOC_DATA_L1z,
ALLOC_L3_L1z,
ALLOC_L2_L1z,
WRITE_L1_L1z,
- /* L1 Fault Path */
- READ_L2_L1f,
- READ_L3_L1f,
+ /* L1 Fault Path */
+ READ_L2_L1f,
+ READ_L3_L1f,
ALLOC_DATA_L1f,
ALLOC_L3_L1f,
ALLOC_L2_L1f,
@@ -115,18 +129,19 @@ enum radix_offsets {
static void read_cb(struct io_ret ret, void *param);
static void write_cb(struct io_ret ret, void *param);
-
-int async_read(vdi_t *vdi, u64 vaddr, io_cb_t cb, void *param)
+int vdi_read(vdi_t *vdi, u64 vaddr, io_cb_t cb, void *param)
{
struct io_req *req;
- DPRINTF("async_read\n");
+ if (!VALID_VADDR(vaddr)) return ERR_BAD_VADDR;
+ /* Every second line in the bottom-level radix tree is used to */
+ /* store crc32 values etc. We shift the vadder here to achied this. */
+ vaddr <<= 1;
req = (struct io_req *)malloc(sizeof (struct io_req));
- req->radix[0] = req->radix[1] = req->radix[2] = NULL;
+ if (req == NULL) return ERR_NOMEM;
- if (req == NULL) {perror("req was NULL in async_read"); return(-1); }
-
+ req->radix[0] = req->radix[1] = req->radix[2] = NULL;
req->op = IO_OP_READ;
req->root = vdi->radix_root;
req->lock = vdi->radix_lock;
@@ -135,41 +150,49 @@ int async_read(vdi_t *vdi, u64 vaddr, io_cb_t cb, void *param)
req->param = param;
req->state = READ_LOCKED;
- block_rlock(req->lock, L1_IDX(vaddr), read_cb, req);
+ block_rlock(req->lock, L1_IDX(vaddr), read_cb, req);
return 0;
}
-int async_write(vdi_t *vdi, u64 vaddr, char *block,
- io_cb_t cb, void *param)
+int vdi_write(vdi_t *vdi, u64 vaddr, char *block,
+ io_cb_t cb, void *param)
{
struct io_req *req;
+ if (!VALID_VADDR(vaddr)) return ERR_BAD_VADDR;
+ /* Every second line in the bottom-level radix tree is used to */
+ /* store crc32 values etc. We shift the vadder here to achied this. */
+ vaddr <<= 1;
req = (struct io_req *)malloc(sizeof (struct io_req));
- req->radix[0] = req->radix[1] = req->radix[2] = NULL;
- //DPRINTF("async_write\n");
-
- if (req == NULL) {perror("req was NULL in async_write"); return(-1); }
-
- req->op = IO_OP_WRITE;
- req->root = vdi->radix_root;
- req->lock = vdi->radix_lock;
- req->vaddr = vaddr;
- req->block = block;
- req->cb = cb;
- req->param = param;
+ if (req == NULL) return ERR_NOMEM;
+
+ req->radix[0] = req->radix[1] = req->radix[2] = NULL;
+ req->op = IO_OP_WRITE;
+ req->root = vdi->radix_root;
+ req->lock = vdi->radix_lock;
+ req->vaddr = vaddr;
+ req->block = block;
+ /* Todo: add a pseodoheader to the block to include some location */
+ /* information in the CRC as well. */
+ req->bi.crc = (u32) crc32(0L, Z_NULL, 0);
+ req->bi.crc = (u32) crc32(req->bi.crc, block, BLOCK_SIZE);
+ req->bi.unused = 0xdeadbeef;
+
+ req->cb = cb;
+ req->param = param;
req->radix_addr[L1] = getid(req->root); /* for consistency */
- req->state = WRITE_LOCKED;
+ req->state = WRITE_LOCKED;
- block_wlock(req->lock, L1_IDX(vaddr), write_cb, req);
+ block_wlock(req->lock, L1_IDX(vaddr), write_cb, req);
- return 0;
+ return 0;
}
-void read_cb(struct io_ret ret, void *param)
+static void read_cb(struct io_ret ret, void *param)
{
struct io_req *req = (struct io_req *)param;
radix_tree_node node;
@@ -197,11 +220,11 @@ void read_cb(struct io_ret ret, void *param)
idx = getid( node[L1_IDX(req->vaddr)] );
free(block);
if ( idx == ZERO ) {
- req->state = RETURN_ZERO;
- block_runlock(req->lock, L1_IDX(req->vaddr), read_cb, req);
+ req->state = RETURN_ZERO;
+ block_runlock(req->lock, L1_IDX(req->vaddr), read_cb, req);
} else {
- req->state = READ_L2;
- block_read(idx, read_cb, req);
+ req->state = READ_L2;
+ block_read(idx, read_cb, req);
}
break;
@@ -214,44 +237,79 @@ void read_cb(struct io_ret ret, void *param)
idx = getid( node[L2_IDX(req->vaddr)] );
free(block);
if ( idx == ZERO ) {
- req->state = RETURN_ZERO;
- block_runlock(req->lock, L1_IDX(req->vaddr), read_cb, req);
+ req->state = RETURN_ZERO;
+ block_runlock(req->lock, L1_IDX(req->vaddr), read_cb, req);
} else {
- req->state = READ_L3;
- block_read(idx, read_cb, req);
+ req->state = READ_L3;
+ block_read(idx, read_cb, req);
}
break;
case READ_L3:
-
+ {
+ struct block_info *bi;
+
DPRINTF("READ_L3\n");
block = IO_BLOCK(ret);
if (block == NULL) goto fail;
node = (radix_tree_node) block;
idx = getid( node[L3_IDX(req->vaddr)] );
+ bi = (struct block_info *) &node[L3_IDX(req->vaddr) + 1];
+ req->bi = *bi;
free(block);
if ( idx == ZERO ) {
- req->state = RETURN_ZERO;
- block_runlock(req->lock, L1_IDX(req->vaddr), read_cb, req);
+ req->state = RETURN_ZERO;
+ block_runlock(req->lock, L1_IDX(req->vaddr), read_cb, req);
} else {
- req->state = READ_DATA;
- block_read(idx, read_cb, req);
+ req->state = READ_DATA;
+ block_read(idx, read_cb, req);
}
break;
-
+ }
case READ_DATA:
-
+ {
+ u32 crc;
+
DPRINTF("READ_DATA\n");
- if (IO_BLOCK(ret) == NULL) goto fail;
+ block = IO_BLOCK(ret);
+ if (block == NULL) goto fail;
+
+ /* crc check */
+ crc = (u32) crc32(0L, Z_NULL, 0);
+ crc = (u32) crc32(crc, block, BLOCK_SIZE);
+ if (crc != req->bi.crc) {
+ /* TODO: add a retry loop here. */
+ /* Do this after the cache is added -- make sure to */
+ /* invalidate the bad page before reissuing the read. */
+
+ warn("Bad CRC on vaddr (%Lu:%d)\n", req->vaddr, req->bi.unused);
+#ifdef PRINT_BADCRC_PAGES
+ {
+ int j;
+ for (j=0; j<BLOCK_SIZE; j++) {
+ if isprint(block[j]) {
+ printf("%c", block[j]);
+ } else {
+ printf(".");
+ }
+ if ((j % 64) == 0) printf("\n");
+ }
+ }
+#endif /* PRINT_BADCRC_PAGES */
+
+ /* fast and loose for the moment. */
+ /* goto fail; */
+ }
+
req->retval = ret;
req->state = READ_UNLOCKED;
block_runlock(req->lock, L1_IDX(req->vaddr), read_cb, req);
break;
-
+ }
case READ_UNLOCKED:
- {
- struct io_ret r;
- io_cb_t cb;
+ {
+ struct io_ret r;
+ io_cb_t cb;
DPRINTF("READ_UNLOCKED\n");
req_param = req->param;
r = req->retval;
@@ -262,18 +320,18 @@ void read_cb(struct io_ret ret, void *param)
}
case RETURN_ZERO:
- {
- struct io_ret r;
- io_cb_t cb;
- DPRINTF("RETURN_ZERO\n");
- req_param = req->param;
+ {
+ struct io_ret r;
+ io_cb_t cb;
+ DPRINTF("RETURN_ZERO\n");
+ req_param = req->param;
cb = req->cb;
- free(req);
+ free(req);
r.type = IO_BLOCK_T;
r.u.b = newblock();
- cb(r, req_param);
- break;
- }
+ cb(r, req_param);
+ break;
+ }
default:
DPRINTF("*** Write: Bad state! (%d) ***\n", req->state);
@@ -283,32 +341,32 @@ void read_cb(struct io_ret ret, void *param)
return;
fail:
- {
- struct io_ret r;
- io_cb_t cb;
- DPRINTF("asyn_read had a read error.\n");
+ {
+ struct io_ret r;
+ io_cb_t cb;
+ DPRINTF("asyn_read had a read error.\n");
req_param = req->param;
r = ret;
cb = req->cb;
free(req);
cb(r, req_param);
- }
+ }
}
-void write_cb(struct io_ret r, void *param)
+static void write_cb(struct io_ret r, void *param)
{
struct io_req *req = (struct io_req *)param;
radix_tree_node node;
u64 a, addr;
void *req_param;
+ struct block_info *bi;
- //DPRINTF("write_cb\n");
switch(req->state) {
case WRITE_LOCKED:
-
+
DPRINTF("WRITE_LOCKED (%llu)\n", L1_IDX(req->vaddr));
req->state = READ_L1;
block_read(getid(req->root), write_cb, req);
@@ -326,9 +384,9 @@ void write_cb(struct io_ret r, void *param)
req->radix[L1] = node;
if ( addr == ZERO ) {
- /* L1 empty subtree: */
- req->state = ALLOC_DATA_L1z;
- block_alloc( req->block, write_cb, req );
+ /* L1 empty subtree: */
+ req->state = ALLOC_DATA_L1z;
+ block_alloc( req->block, write_cb, req );
} else if ( !iswritable(a) ) {
/* L1 fault: */
req->state = READ_L2_L1f;
@@ -351,7 +409,7 @@ void write_cb(struct io_ret r, void *param)
req->radix[L2] = node;
if ( addr == ZERO ) {
- /* L2 empty subtree: */
+ /* L2 empty subtree: */
req->state = ALLOC_DATA_L2z;
block_alloc( req->block, write_cb, req );
} else if ( !iswritable(a) ) {
@@ -388,6 +446,19 @@ void write_cb(struct io_ret r, void *param)
}
break;
+ case WRITE_DATA:
+
+ DPRINTF("WRITE_DATA\n");
+ /* The L3 radix points to the correct block, we just need to */
+ /* update the crc. */
+ if (IO_INT(r) < 0) goto fail;
+ bi = (struct block_info *) &req->radix[L3][L3_IDX(req->vaddr)+1];
+ req->bi.unused = 101;
+ *bi = req->bi;
+ req->state = WRITE_L3;
+ block_write(req->radix_addr[L3], (char*)req->radix[L3], write_cb, req);
+ break;
+
/* L3 Zero Path: */
case ALLOC_DATA_L3z:
@@ -396,6 +467,9 @@ void write_cb(struct io_ret r, void *param)
addr = IO_ADDR(r);
a = writable(addr);
req->radix[L3][L3_IDX(req->vaddr)] = a;
+ bi = (struct block_info *) &req->radix[L3][L3_IDX(req->vaddr)+1];
+ req->bi.unused = 102;
+ *bi = req->bi;
req->state = WRITE_L3_L3z;
block_write(req->radix_addr[L3], (char*)req->radix[L3], write_cb, req);
break;
@@ -403,11 +477,14 @@ void write_cb(struct io_ret r, void *param)
/* L3 Fault Path: */
case ALLOC_DATA_L3f:
-
+
DPRINTF("ALLOC_DATA_L3f\n");
addr = IO_ADDR(r);
a = writable(addr);
req->radix[L3][L3_IDX(req->vaddr)] = a;
+ bi = (struct block_info *) &req->radix[L3][L3_IDX(req->vaddr)+1];
+ req->bi.unused = 103;
+ *bi = req->bi;
req->state = WRITE_L3_L3f;
block_write(req->radix_addr[L3], (char*)req->radix[L3], write_cb, req);
break;
@@ -421,6 +498,9 @@ void write_cb(struct io_ret r, void *param)
a = writable(addr);
req->radix[L3] = newblock();
req->radix[L3][L3_IDX(req->vaddr)] = a;
+ bi = (struct block_info *) &req->radix[L3][L3_IDX(req->vaddr)+1];
+ req->bi.unused = 104;
+ *bi = req->bi;
req->state = ALLOC_L3_L2z;
block_alloc( (char*)req->radix[L3], write_cb, req );
break;
@@ -441,13 +521,13 @@ void write_cb(struct io_ret r, void *param)
DPRINTF("READ_L3_L2f\n");
node = (radix_tree_node) IO_BLOCK(r);
- clear_w_bits(node);
+ clear_L3_w_bits(node);
if (node == NULL) goto fail;
a = node[L2_IDX(req->vaddr)];
addr = getid(a);
req->radix[L3] = node;
- req->state = ALLOC_DATA_L2f;
+ req->state = ALLOC_DATA_L2f;
block_alloc( req->block, write_cb, req );
break;
@@ -457,6 +537,9 @@ void write_cb(struct io_ret r, void *param)
addr = IO_ADDR(r);
a = writable(addr);
req->radix[L3][L3_IDX(req->vaddr)] = a;
+ bi = (struct block_info *) &req->radix[L3][L3_IDX(req->vaddr)+1];
+ req->bi.unused = 105;
+ *bi = req->bi;
req->state = ALLOC_L3_L2f;
block_alloc( (char*)req->radix[L3], write_cb, req );
break;
@@ -480,10 +563,13 @@ void write_cb(struct io_ret r, void *param)
a = writable(addr);
req->radix[L3] = newblock();
req->radix[L3][L3_IDX(req->vaddr)] = a;
+ bi = (struct block_info *) &req->radix[L3][L3_IDX(req->vaddr)+1];
+ req->bi.unused = 106;
+ *bi = req->bi;
req->state = ALLOC_L3_L1z;
block_alloc( (char*)req->radix[L3], write_cb, req );
break;
-
+
case ALLOC_L3_L1z:
DPRINTF("ALLOC_L3_L1z\n");
@@ -520,14 +606,14 @@ void write_cb(struct io_ret r, void *param)
req->radix[L2] = node;
if (addr == ZERO) {
- /* nothing below L2, create an empty L3 and alloc data. */
- /* (So skip READ_L3_L1f.) */
- req->radix[L3] = newblock();
- req->state = ALLOC_DATA_L1f;
- block_alloc( req->block, write_cb, req );
+ /* nothing below L2, create an empty L3 and alloc data. */
+ /* (So skip READ_L3_L1f.) */
+ req->radix[L3] = newblock();
+ req->state = ALLOC_DATA_L1f;
+ block_alloc( req->block, write_cb, req );
} else {
- req->state = READ_L3_L1f;
- block_read( addr, write_cb, req );
+ req->state = READ_L3_L1f;
+ block_read( addr, write_cb, req );
}
break;
@@ -535,13 +621,13 @@ void write_cb(struct io_ret r, void *param)
DPRINTF("READ_L3_L1f\n");
node = (radix_tree_node) IO_BLOCK(r);
- clear_w_bits(node);
+ clear_L3_w_bits(node);
if (node == NULL) goto fail;
a = node[L2_IDX(req->vaddr)];
addr = getid(a);
req->radix[L3] = node;
- req->state = ALLOC_DATA_L1f;
+ req->state = ALLOC_DATA_L1f;
block_alloc( req->block, write_cb, req );
break;
@@ -551,6 +637,9 @@ void write_cb(struct io_ret r, void *param)
addr = IO_ADDR(r);
a = writable(addr);
req->radix[L3][L3_IDX(req->vaddr)] = a;
+ bi = (struct block_info *) &req->radix[L3][L3_IDX(req->vaddr)+1];
+ req->bi.unused = 107;
+ *bi = req->bi;
req->state = ALLOC_L3_L1f;
block_alloc( (char*)req->radix[L3], write_cb, req );
break;
@@ -575,7 +664,7 @@ void write_cb(struct io_ret r, void *param)
block_write(req->radix_addr[L1], (char*)req->radix[L1], write_cb, req);
break;
- case WRITE_DATA:
+ case WRITE_L3:
case WRITE_L3_L3z:
case WRITE_L3_L3f:
case WRITE_L2_L2z:
@@ -587,7 +676,7 @@ void write_cb(struct io_ret r, void *param)
DPRINTF("DONE\n");
/* free any saved node vals. */
for (i=0; i<3; i++)
- if (req->radix[i] != 0) free(req->radix[i]);
+ if (req->radix[i] != 0) free(req->radix[i]);
req->retval = r;
req->state = WRITE_UNLOCKED;
block_wunlock(req->lock, L1_IDX(req->vaddr), write_cb, req);
@@ -595,13 +684,13 @@ void write_cb(struct io_ret r, void *param)
}
case WRITE_UNLOCKED:
{
- struct io_ret r;
- io_cb_t cb;
+ struct io_ret r;
+ io_cb_t cb;
DPRINTF("WRITE_UNLOCKED!\n");
req_param = req->param;
r = req->retval;
cb = req->cb;
- free(req);
+ free(req);
cb(r, req_param);
break;
}
@@ -614,16 +703,60 @@ void write_cb(struct io_ret r, void *param)
return;
fail:
- {
- struct io_ret r;
- io_cb_t cb;
- DPRINTF("asyn_write had a read error mid-way.\n");
+ {
+ struct io_ret r;
+ io_cb_t cb;
+ int i;
+
+ DPRINTF("asyn_write had a read error mid-way.\n");
req_param = req->param;
cb = req->cb;
r.type = IO_INT_T;
r.u.i = -1;
+ /* free any saved node vals. */
+ for (i=0; i<3; i++)
+ if (req->radix[i] != 0) free(req->radix[i]);
free(req);
cb(r, req_param);
- }
+ }
}
+char *vdi_read_s(vdi_t *vdi, u64 vaddr)
+{
+ pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+ char *block = NULL;
+ int ret;
+
+ void reads_cb(struct io_ret r, void *param)
+ {
+ block = IO_BLOCK(r);
+ pthread_mutex_unlock((pthread_mutex_t *)param);
+ }
+
+ pthread_mutex_lock(&m);
+ ret = vdi_read(vdi, vaddr, reads_cb, &m);
+
+ if (ret == 0) pthread_mutex_lock(&m);
+
+ return block;
+}
+
+
+int vdi_write_s(vdi_t *vdi, u64 vaddr, char *block)
+{
+ pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+ int ret, result;
+
+ void writes_cb(struct io_ret r, void *param)
+ {
+ result = IO_INT(r);
+ pthread_mutex_unlock((pthread_mutex_t *)param);
+ }
+
+ pthread_mutex_lock(&m);
+ ret = vdi_write(vdi, vaddr, block, writes_cb, &m);
+
+ if (ret == 0) pthread_mutex_lock(&m);
+
+ return result;
+}
diff --git a/tools/blktap/requests-async.h b/tools/blktap/requests-async.h
index 503a543b7e..451f211bd5 100755
--- a/tools/blktap/requests-async.h
+++ b/tools/blktap/requests-async.h
@@ -13,7 +13,17 @@
#define readonly(x) ((u64)((x) << 1))
*/
-int async_read (vdi_t *vdi, u64 vaddr, io_cb_t cb, void *param);
-int async_write(vdi_t *vdi, u64 vaddr, char *block, io_cb_t cb, void *param);
+#define VADDR_MASK 0x0000000003ffffffLLU /* 26-bits = 256Gig */
+#define VALID_VADDR(x) (((x) & VADDR_MASK) == (x))
+
+int vdi_read (vdi_t *vdi, u64 vaddr, io_cb_t cb, void *param);
+int vdi_write(vdi_t *vdi, u64 vaddr, char *block, io_cb_t cb, void *param);
+/* synchronous versions: */
+char *vdi_read_s (vdi_t *vdi, u64 vaddr);
+int vdi_write_s(vdi_t *vdi, u64 vaddr, char *block);
+
+#define ERR_BAD_VADDR -1
+#define ERR_NOMEM -2
+
#endif //_REQUESTSASYNC_H_
diff --git a/tools/blktap/snaplog.c b/tools/blktap/snaplog.c
index 5c030e3b5b..072497fe72 100644
--- a/tools/blktap/snaplog.c
+++ b/tools/blktap/snaplog.c
@@ -97,6 +97,7 @@ int __snap_block_create(snap_id_t *parent_id, snap_id_t *fork_id,
new_id->index = 0;
new_id->block = allocblock(blk);
+ freeblock(blk);
if (new_id->block == 0)
return -1;
diff --git a/tools/blktap/vdi.c b/tools/blktap/vdi.c
index 490a2e691a..f3181b86b2 100644
--- a/tools/blktap/vdi.c
+++ b/tools/blktap/vdi.c
@@ -14,6 +14,7 @@
#include <pthread.h>
#include "blockstore.h"
#include "block-async.h"
+#include "requests-async.h"
#include "radix.h"
#include "vdi.h"
@@ -128,6 +129,9 @@ vdi_t *vdi_create(snap_id_t *parent_snap, char *name)
return vdi;
}
+/* vdi_get and vdi_put currently act more like alloc/free -- they don't
+ * do refcount-based allocation.
+ */
vdi_t *vdi_get(u64 vdi_id)
{
u64 vdi_blk;
@@ -152,26 +156,10 @@ vdi_t *vdi_get(u64 vdi_id)
return vdi;
}
-u64 vdi_lookup_block(vdi_t *vdi, u64 vdi_block, int *writable)
-{
- u64 gblock;
-
- gblock = lookup(VDI_HEIGHT, vdi->radix_root, vdi_block);
-
- if (writable != NULL) *writable = iswritable(gblock);
-
- return getid(gblock);
-}
-
-void vdi_update_block(vdi_t *vdi, u64 vdi_block, u64 g_block)
+void vdi_put(vdi_t *vdi)
{
- u64 id;
-
- /* updates are always writable. */
- id = writable(g_block);
-
- vdi->radix_root = update(VDI_HEIGHT, vdi->radix_root, vdi_block, id);
- writeblock(vdi->block, vdi);
+ free(vdi->radix_lock);
+ freeblock(vdi);
}
void vdi_snapshot(vdi_t *vdi)
diff --git a/tools/blktap/vdi.h b/tools/blktap/vdi.h
index 1c04e79393..462fa03299 100644
--- a/tools/blktap/vdi.h
+++ b/tools/blktap/vdi.h
@@ -27,7 +27,7 @@ typedef struct vdi {
snap_id_t snap; /* next snapshot slot for this VDI */
struct vdi *next; /* used to hash-chain in blkif. */
blkif_vdev_t vdevice; /* currently mounted as... */
- struct radix_lock *radix_lock;/* per-line L1 RW lock for parallel reqs */
+ struct radix_lock *radix_lock;/* per-line L1 RW lock for parallel reqs */
char name[VDI_NAME_SZ];/* human readable vdi name */
} vdi_t;
@@ -42,6 +42,7 @@ typedef struct vdi_registry {
int __init_vdi(void);
vdi_t *vdi_get(u64 vdi_id);
+void vdi_put(vdi_t *vdi);
vdi_registry_t *get_vdi_registry(void);
vdi_t *vdi_create(snap_id_t *parent_snap, char *name);
u64 vdi_lookup_block(vdi_t *vdi, u64 vdi_block, int *writable);
diff --git a/tools/blktap/vdi_fill.c b/tools/blktap/vdi_fill.c
index 7e3eacc3f3..61025862f7 100644
--- a/tools/blktap/vdi_fill.c
+++ b/tools/blktap/vdi_fill.c
@@ -16,6 +16,7 @@
#include <unistd.h>
#include "blockstore.h"
#include "radix.h"
+#include "requests-async.h"
#include "vdi.h"
int main(int argc, char *argv[])
@@ -30,6 +31,7 @@ int main(int argc, char *argv[])
u64 vblock = 0, count=0;
__init_blockstore();
+ init_block_async();
__init_vdi();
if ( argc < 3 ) {
@@ -64,10 +66,7 @@ int main(int argc, char *argv[])
printf("%011Ld blocks total\n", tot_size / BLOCK_SIZE);
printf(" ");
while ( ( count = read(fd, spage, BLOCK_SIZE) ) > 0 ) {
- u64 gblock = 0;
-
- gblock = allocblock(spage);
- vdi_update_block(vdi, vblock, gblock);
+ vdi_write_s(vdi, vblock, spage);
vblock++;
if ((vblock % 512) == 0)
diff --git a/tools/blktap/vdi_unittest.c b/tools/blktap/vdi_unittest.c
new file mode 100644
index 0000000000..77ecc833be
--- /dev/null
+++ b/tools/blktap/vdi_unittest.c
@@ -0,0 +1,184 @@
+/**************************************************************************
+ *
+ * vdi_unittest.c
+ *
+ * Run a small test workload to ensure that data access through a vdi
+ * is (at least superficially) correct.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "requests-async.h"
+#include "blockstore.h"
+#include "radix.h"
+#include "vdi.h"
+
+#define TEST_PAGES 32
+static char *zero_page;
+static char pages[TEST_PAGES][BLOCK_SIZE];
+static int next_page = 0;
+
+void fill_test_pages(void)
+{
+ int i, j;
+ long *page;
+
+ for (i=0; i< TEST_PAGES; i++) {
+ page = (unsigned long *)pages[i];
+ for (j=0; j<(BLOCK_SIZE/4); j++) {
+ page[j] = random();
+ }
+ }
+
+ zero_page = newblock();
+}
+
+inline u64 make_vaddr(u64 L1, u64 L2, u64 L3)
+{
+ u64 ret = L1;
+
+ ret = (ret << 9) | L2;
+ ret = (ret << 9) | L3;
+
+ return ret;
+}
+
+void touch_block(vdi_t *vdi, u64 L1, u64 L2, u64 L3)
+{
+ u64 vaddr;
+ char *page = pages[next_page++];
+ char *rpage = NULL;
+
+ printf("TOUCH (%3Lu, %3Lu, %3Lu)\n", L1, L2, L3);
+
+ vaddr = make_vaddr(L1, L2, L3);
+ vdi_write_s(vdi, vaddr, page);
+ rpage = vdi_read_s(vdi, vaddr);
+
+ if (rpage == NULL)
+ {
+ printf( "read %Lu returned NULL\n", vaddr);
+ return;
+ }
+
+ if (memcmp(page, rpage, BLOCK_SIZE) != 0)
+ {
+ printf( "read %Lu returned a different page\n", vaddr);
+ return;
+ }
+
+ freeblock(rpage);
+}
+
+void test_block(vdi_t *vdi, u64 L1, u64 L2, u64 L3, char *page)
+{
+ u64 vaddr;
+ char *rpage = NULL;
+
+ printf("TEST (%3Lu, %3Lu, %3Lu)\n", L1, L2, L3);
+
+ vaddr = make_vaddr(L1, L2, L3);
+ rpage = vdi_read_s(vdi, vaddr);
+
+ if (rpage == NULL)
+ {
+ printf( "read %Lu returned NULL\n", vaddr);
+ return;
+ }
+
+ if (memcmp(page, rpage, BLOCK_SIZE) != 0)
+ {
+ printf( "read %Lu returned a different page\n", vaddr);
+ return;
+ }
+
+ freeblock(rpage);
+}
+
+void coverage_test(vdi_t *vdi)
+{
+ u64 vaddr;
+ int i, j, k;
+
+ /* Do a series of writes and reads to test all paths through the
+ * async radix code. The radix request code will dump CRC warnings
+ * if there are data problems here as well.
+ */
+
+ /* L1 Zero */
+ touch_block(vdi, 0, 0, 0);
+
+ /* L2 Zero */
+ i = next_page;
+ touch_block(vdi, 0, 1, 0);
+
+ /* L3 Zero */
+ j = next_page;
+ touch_block(vdi, 0, 0, 1);
+ k = next_page;
+ touch_block(vdi, 0, 1, 1);
+
+ /* Direct write */
+ touch_block(vdi, 0, 0, 0);
+
+ vdi_snapshot(vdi);
+
+ /* L1 fault */
+ touch_block(vdi, 0, 0, 0);
+ /* test the read-only branches that should have been copied over. */
+ test_block(vdi, 0, 1, 0, pages[i]);
+ test_block(vdi, 0, 0, 1, pages[j]);
+
+ /* L2 fault */
+ touch_block(vdi, 0, 1, 0);
+ test_block(vdi, 0, 1, 1, pages[k]);
+
+ /* L3 fault */
+ touch_block(vdi, 0, 0, 1);
+
+ /* read - L1 zero */
+ test_block(vdi, 1, 0, 0, zero_page);
+
+ /* read - L2 zero */
+ test_block(vdi, 0, 2, 0, zero_page);
+
+ /* read - L3 zero */
+ test_block(vdi, 0, 0, 2, zero_page);
+}
+
+int main(int argc, char *argv[])
+{
+ vdi_t *vdi;
+ u64 id;
+ int fd;
+ struct stat st;
+ u64 tot_size;
+ char spage[BLOCK_SIZE];
+ char *dpage;
+ u64 vblock = 0, count=0;
+
+ __init_blockstore();
+ init_block_async();
+ __init_vdi();
+
+ vdi = vdi_create( NULL, "UNIT TEST VDI");
+
+ if ( vdi == NULL ) {
+ printf("Failed to create VDI!\n");
+ freeblock(vdi);
+ exit(-1);
+ }
+
+ fill_test_pages();
+ coverage_test(vdi);
+
+ freeblock(vdi);
+
+ return (0);
+}
diff --git a/tools/blktap/vdi_validate.c b/tools/blktap/vdi_validate.c
index a2468615a0..de7a62d3e9 100644
--- a/tools/blktap/vdi_validate.c
+++ b/tools/blktap/vdi_validate.c
@@ -18,6 +18,7 @@
#include "blockstore.h"
#include "radix.h"
#include "vdi.h"
+#include "requests-async.h"
int main(int argc, char *argv[])
{
@@ -31,6 +32,7 @@ int main(int argc, char *argv[])
u64 vblock = 0, count=0;
__init_blockstore();
+ init_block_async();
__init_vdi();
if ( argc < 3 ) {
@@ -64,17 +66,14 @@ int main(int argc, char *argv[])
printf(" ");
while ( ( count = read(fd, spage, BLOCK_SIZE) ) > 0 ) {
- u64 gblock = 0;
-
- gblock = vdi_lookup_block(vdi, vblock, NULL);
-
- if (gblock == 0) {
+
+ dpage = vdi_read_s(vdi, vblock);
+
+ if (dpage == NULL) {
printf("\n\nfound an unmapped VDI block (%Ld)\n", vblock);
exit(0);
}
-
- dpage = readblock(gblock);
-
+
if (memcmp(spage, dpage, BLOCK_SIZE) != 0) {
printf("\n\nblocks don't match! (%Ld)\n", vblock);
exit(0);
@@ -83,8 +82,10 @@ int main(int argc, char *argv[])
freeblock(dpage);
vblock++;
- printf("\b\b\b\b\b\b\b\b\b\b\b%011Ld", vblock);
- fflush(stdout);
+ if ((vblock % 1024) == 0) {
+ printf("\b\b\b\b\b\b\b\b\b\b\b%011Ld", vblock);
+ fflush(stdout);
+ }
}
printf("\n");
diff --git a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/Makefile.in b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/Makefile.in
index f6843357e7..e470217934 100644
--- a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/Makefile.in
+++ b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/Makefile.in
@@ -83,7 +83,7 @@ READLINE_DEP = $$(READLINE_DIR)
# -I. for config files.
# -I${srcdir} for our headers.
# -I$(srcdir)/../regformats for regdef.h.
-INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../regformats -I$(INCLUDE_DIR) -I../../../../libxc/
+INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../regformats -I$(INCLUDE_DIR) -I../../../../../libxc/
# M{H,T}_CFLAGS, if defined, has host- and target-dependent CFLAGS
# from the config/ directory.
diff --git a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure
index d45d933ab3..3cb8c841bd 100755
--- a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure
+++ b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure
@@ -3475,7 +3475,7 @@ USE_THREAD_DB=
GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj $srv_thread_depfiles"
-GDBSERVER_LIBS="$srv_libs -L../../../../libxc/ -lxc"
+GDBSERVER_LIBS="$srv_libs -L../../../../../libxc/ -lxc"
diff --git a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.in b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.in
index 1d5c22af0b..bf88ae6dcd 100644
--- a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.in
+++ b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.in
@@ -107,7 +107,7 @@ USE_THREAD_DB=
GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj $srv_thread_depfiles"
-GDBSERVER_LIBS="$srv_libs -L../../../../libxc/ -lxc"
+GDBSERVER_LIBS="$srv_libs -L../../../../../libxc/ -lxc"
AC_SUBST(GDBSERVER_DEPFILES)
AC_SUBST(GDBSERVER_LIBS)
diff --git a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.srv b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.srv
index a586a51db9..a586a51db9 100644
--- a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.srv
+++ b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.srv
diff --git a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c
index 015c4f1938..015c4f1938 100644
--- a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c
+++ b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c
diff --git a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c
index 54f508a186..54f508a186 100644
--- a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c
+++ b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c
diff --git a/tools/gdb/gdb-6.2.1-xen-sparse/mkbuildtree b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/mkbuildtree
index 6be1df1753..6be1df1753 100755
--- a/tools/gdb/gdb-6.2.1-xen-sparse/mkbuildtree
+++ b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/mkbuildtree
diff --git a/tools/gdb/gdbbuild b/tools/debugger/gdb/gdbbuild
index 2a52870849..1c1c9a0242 100755
--- a/tools/gdb/gdbbuild
+++ b/tools/debugger/gdb/gdbbuild
@@ -3,17 +3,17 @@
XENROOT=`bk root`
export XENROOT
-cd $XENROOT/tools/gdb
+cd $XENROOT/tools/debugger/gdb
rm -rf gdb-6.2.1 gdb-6.2.1-linux-i386-xen
# FIXME:cw this should be smarter
wget -c ftp://ftp.gnu.org/gnu/gdb/gdb-6.2.1.tar.bz2
tar xjf gdb-6.2.1.tar.bz2
-cd $XENROOT/tools/gdb/gdb-6.2.1-xen-sparse
+cd $XENROOT/tools/debugger/gdb/gdb-6.2.1-xen-sparse
./mkbuildtree ../gdb-6.2.1
-mkdir $XENROOT/tools/gdb/gdb-6.2.1-linux-i386-xen
-cd $XENROOT/tools/gdb/gdb-6.2.1-linux-i386-xen
+mkdir $XENROOT/tools/debugger/gdb/gdb-6.2.1-linux-i386-xen
+cd $XENROOT/tools/debugger/gdb/gdb-6.2.1-linux-i386-xen
../gdb-6.2.1/configure
# some people don't have gmake
if which gmake ; then
diff --git a/tools/debugger/libxendebug/Makefile b/tools/debugger/libxendebug/Makefile
new file mode 100644
index 0000000000..ed478658a4
--- /dev/null
+++ b/tools/debugger/libxendebug/Makefile
@@ -0,0 +1,72 @@
+
+INSTALL = install
+INSTALL_PROG = $(INSTALL) -m0755
+INSTALL_DATA = $(INSTALL) -m0644
+INSTALL_DIR = $(INSTALL) -d -m0755
+
+MAJOR = 3.0
+MINOR = 0
+
+CC = gcc
+
+XEN_ROOT = ../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+SRCS := xendebug.c
+
+CFLAGS += -Wall -Werror -O3 -fno-strict-aliasing
+CFLAGS += $(INCLUDES) -I. -I$(XEN_ROOT)/tools/libxc
+# Get gcc to generate the dependencies for us.
+CFLAGS += -Wp,-MD,.$(@F).d
+DEPS = .*.d
+
+LDFLAGS += -L$(XEN_ROOT)/tools/libxc -lxc
+
+LIB_OBJS := $(patsubst %.c,%.o,$(SRCS))
+PIC_OBJS := $(patsubst %.c,%.opic,$(SRCS))
+
+LIB := libxendebug.a libxendebug.so
+LIB += libxendebug.so.$(MAJOR) libxendebug.so.$(MAJOR).$(MINOR)
+
+all: build
+build:
+ $(MAKE) $(LIB)
+
+install: build
+ [ -d $(DESTDIR)/usr/$(LIBDIR) ] || $(INSTALL_DIR) $(DESTDIR)/usr/$(LIBDIR)
+ [ -d $(DESTDIR)/usr/include ] || $(INSTALL_DIR) $(DESTDIR)/usr/include
+ $(INSTALL_PROG) libxendebug.so.$(MAJOR).$(MINOR) $(DESTDIR)/usr/$(LIBDIR)
+ $(INSTALL_DATA) libxendebug.a $(DESTDIR)/usr/$(LIBDIR)
+ ln -sf libxendebug.so.$(MAJOR).$(MINOR) $(DESTDIR)/usr/$(LIBDIR)/libxendebug.so.$(MAJOR)
+ ln -sf libxendebug.so.$(MAJOR) $(DESTDIR)/usr/$(LIBDIR)/libxendebug.so
+ $(INSTALL_DATA) xendebug.h $(DESTDIR)/usr/include
+
+.PHONY: TAGS clean rpm install all
+
+TAGS:
+ etags -t $(SRCS) *.h
+
+clean:
+ rm -rf *.a *.so* *.o *.opic *.rpm $(LIB) *~ $(DEPS) xen
+
+rpm: build
+ rm -rf staging
+ mkdir staging
+ mkdir staging/i386
+ rpmbuild --define "staging$$PWD/staging" --define '_builddir.' \
+ --define "_rpmdir$$PWD/staging" -bb rpm.spec
+ mv staging/i386/*.rpm .
+ rm -rf staging
+
+libxendebug.a: $(LIB_OBJS)
+ $(AR) rc $@ $^
+
+libxendebug.so: libxendebug.so.$(MAJOR)
+ ln -sf $< $@
+libxendebug.so.$(MAJOR): libxendebug.so.$(MAJOR).$(MINOR)
+ ln -sf $< $@
+
+libxendebug.so.$(MAJOR).$(MINOR): $(PIC_OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-soname -Wl,libxendebug.so.$(MAJOR) -shared -o $@ $^
+
+-include $(DEPS)
diff --git a/tools/debugger/libxendebug/list.h b/tools/debugger/libxendebug/list.h
new file mode 100644
index 0000000000..d2ee720f34
--- /dev/null
+++ b/tools/debugger/libxendebug/list.h
@@ -0,0 +1,186 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_add(struct list_head * new,
+ struct list_head * prev,
+ struct list_head * next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static __inline__ void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_del(struct list_head * prev,
+ struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
+ */
+static __inline__ void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static __inline__ void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static __inline__ int list_empty(struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static __inline__ void list_splice(struct list_head *list, struct list_head *head)
+{
+ struct list_head *first = list->next;
+
+ if (first != list) {
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+#endif /* _LINUX_LIST_H */
+
diff --git a/tools/debugger/libxendebug/xendebug.c b/tools/debugger/libxendebug/xendebug.c
new file mode 100644
index 0000000000..844cdf0e03
--- /dev/null
+++ b/tools/debugger/libxendebug/xendebug.c
@@ -0,0 +1,599 @@
+/*
+ * xendebug.c
+ *
+ * alex ho
+ * http://www.cl.cam.ac.uk/netos/pdb
+ *
+ * xendebug_memory_page adapted from xc_ptrace.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <xc.h>
+#include "list.h"
+
+#if defined(__i386__)
+#define L1_PAGETABLE_SHIFT 12
+#define L2_PAGETABLE_SHIFT 22
+#elif defined(__x86_64__)
+#define L1_PAGETABLE_SHIFT 12
+#define L2_PAGETABLE_SHIFT 21
+#define L3_PAGETABLE_SHIFT 30
+#define L4_PAGETABLE_SHIFT 39
+#endif
+
+#define PAGE_SHIFT L1_PAGETABLE_SHIFT
+#define PAGE_SIZE (1UL<<PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+
+/* from xen/include/asm-x86/processor.h */
+#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
+
+typedef int boolean;
+#define true 1
+#define false 0
+
+
+typedef struct bwcpoint /* break/watch/catch point */
+{
+ struct list_head list;
+ memory_t address;
+ u32 domain;
+ u16 vcpu;
+ u8 old_value; /* old value for software bkpt */
+} bwcpoint_t, *bwcpoint_p;
+
+static bwcpoint_t bwcpoint_list;
+
+
+
+typedef struct domain_context /* local cache of domain state */
+{
+ struct list_head list;
+ u32 domid;
+ boolean valid[MAX_VIRT_CPUS];
+ vcpu_guest_context_t context[MAX_VIRT_CPUS];
+
+ long total_pages;
+ unsigned long *page_array;
+
+ unsigned long cr3_phys[MAX_VIRT_CPUS];
+ unsigned long *cr3_virt[MAX_VIRT_CPUS];
+ unsigned long pde_phys[MAX_VIRT_CPUS];
+ unsigned long *pde_virt[MAX_VIRT_CPUS];
+ unsigned long page_phys[MAX_VIRT_CPUS];
+ unsigned long *page_virt[MAX_VIRT_CPUS];
+ int page_perm[MAX_VIRT_CPUS];
+} domain_context_t, *domain_context_p;
+
+static domain_context_t domain_context_list;
+
+/* initialization */
+
+static boolean xendebug_initialized = false;
+
+static __inline__ void
+xendebug_initialize()
+{
+ if ( !xendebug_initialized )
+ {
+ memset((void *) &domain_context_list, 0, sizeof(domain_context_t));
+ INIT_LIST_HEAD(&domain_context_list.list);
+
+ memset((void *) &bwcpoint_list, 0, sizeof(bwcpoint_t));
+ INIT_LIST_HEAD(&bwcpoint_list.list);
+
+ xendebug_initialized = true;
+ }
+}
+
+/**************/
+
+static domain_context_p
+xendebug_domain_context_search (u32 domid)
+{
+ struct list_head *entry;
+ domain_context_p ctxt;
+
+ list_for_each(entry, &domain_context_list.list)
+ {
+ ctxt = list_entry(entry, domain_context_t, list);
+ if ( domid == ctxt->domid )
+ return ctxt;
+ }
+ return (domain_context_p)NULL;
+}
+
+static __inline__ domain_context_p
+xendebug_get_context (int xc_handle, u32 domid, u32 vcpu)
+{
+ int rc;
+ domain_context_p ctxt;
+
+ xendebug_initialize();
+
+ if ( (ctxt = xendebug_domain_context_search(domid)) == NULL)
+ return NULL;
+
+ if ( !ctxt->valid[vcpu] )
+ {
+ if ( (rc = xc_domain_get_vcpu_context(xc_handle, domid, vcpu,
+ &ctxt->context[vcpu])) )
+ return NULL;
+
+ ctxt->valid[vcpu] = true;
+ }
+
+ return ctxt;
+}
+
+static __inline__ int
+xendebug_set_context (int xc_handle, domain_context_p ctxt, u32 vcpu)
+{
+ dom0_op_t op;
+ int rc;
+
+ if ( !ctxt->valid[vcpu] )
+ return -EINVAL;
+
+ op.interface_version = DOM0_INTERFACE_VERSION;
+ op.cmd = DOM0_SETDOMAININFO;
+ op.u.setdomaininfo.domain = ctxt->domid;
+ op.u.setdomaininfo.vcpu = vcpu;
+ op.u.setdomaininfo.ctxt = &ctxt->context[vcpu];
+
+ if ( (rc = mlock(&ctxt->context[vcpu], sizeof(vcpu_guest_context_t))) )
+ return rc;
+
+ rc = xc_dom0_op(xc_handle, &op);
+ (void) munlock(&ctxt->context[vcpu], sizeof(vcpu_guest_context_t));
+
+ return rc;
+}
+
+/**************/
+
+int
+xendebug_attach(int xc_handle,
+ u32 domid,
+ u32 vcpu)
+{
+ domain_context_p ctxt;
+
+ xendebug_initialize();
+
+ if ( (ctxt = malloc(sizeof(domain_context_t))) == NULL )
+ return -1;
+ memset(ctxt, 0, sizeof(domain_context_t));
+
+ ctxt->domid = domid;
+ list_add(&ctxt->list, &domain_context_list.list);
+
+ return xc_domain_pause(xc_handle, domid);
+}
+
+int
+xendebug_detach(int xc_handle,
+ u32 domid,
+ u32 vcpu)
+{
+ domain_context_p ctxt;
+
+ xendebug_initialize();
+
+ if ( (ctxt = xendebug_domain_context_search (domid)) == NULL)
+ return -EINVAL;
+
+ list_del(&ctxt->list);
+
+ if ( ctxt->page_array ) free(ctxt->page_array);
+
+ free(ctxt);
+
+ return xc_domain_unpause(xc_handle, domid);
+}
+
+int
+xendebug_read_registers(int xc_handle,
+ u32 domid,
+ u32 vcpu,
+ cpu_user_regs_t **regs)
+{
+ domain_context_p ctxt;
+ int rc = -1;
+
+ xendebug_initialize();
+
+ ctxt = xendebug_get_context(xc_handle, domid, vcpu);
+ if (ctxt)
+ {
+ *regs = &ctxt->context[vcpu].user_regs;
+ rc = 0;
+ }
+
+ return rc;
+}
+
+int
+xendebug_read_fpregisters (int xc_handle,
+ u32 domid,
+ u32 vcpu,
+ char **regs)
+{
+ domain_context_p ctxt;
+ int rc = -1;
+
+ xendebug_initialize();
+
+ ctxt = xendebug_get_context(xc_handle, domid, vcpu);
+ if (ctxt)
+ {
+ *regs = ctxt->context[vcpu].fpu_ctxt.x;
+ rc = 0;
+ }
+
+ return rc;
+}
+
+int
+xendebug_write_registers(int xc_handle,
+ u32 domid,
+ u32 vcpu,
+ cpu_user_regs_t *regs)
+{
+ domain_context_p ctxt;
+ int rc = -1;
+
+ xendebug_initialize();
+
+ ctxt = xendebug_get_context(xc_handle, domid, vcpu);
+ if (ctxt)
+ {
+ memcpy(&ctxt->context[vcpu].user_regs, regs, sizeof(cpu_user_regs_t));
+ rc = xendebug_set_context(xc_handle, ctxt, vcpu);
+ }
+
+ return rc;
+}
+
+int
+xendebug_step(int xc_handle,
+ u32 domid,
+ u32 vcpu)
+{
+ domain_context_p ctxt;
+ int rc;
+
+ xendebug_initialize();
+
+ ctxt = xendebug_get_context(xc_handle, domid, vcpu);
+ if (!ctxt) return -EINVAL;
+
+ ctxt->context[vcpu].user_regs.eflags |= X86_EFLAGS_TF;
+
+ if ( (rc = xendebug_set_context(xc_handle, ctxt, vcpu)) )
+ return rc;
+
+ ctxt->valid[vcpu] = false;
+ return xc_domain_unpause(xc_handle, domid);
+}
+
+int
+xendebug_continue(int xc_handle,
+ u32 domid,
+ u32 vcpu)
+{
+ domain_context_p ctxt;
+ int rc;
+
+ xendebug_initialize();
+
+ ctxt = xendebug_get_context(xc_handle, domid, vcpu);
+ if (!ctxt) return -EINVAL;
+
+ if ( ctxt->context[vcpu].user_regs.eflags & X86_EFLAGS_TF )
+ {
+ ctxt->context[vcpu].user_regs.eflags &= ~X86_EFLAGS_TF;
+ if ( (rc = xendebug_set_context(xc_handle, ctxt, vcpu)) )
+ return rc;
+ }
+ ctxt->valid[vcpu] = false;
+ return xc_domain_unpause(xc_handle, domid);
+}
+
+/*************************************************/
+
+#define vtopdi(va) ((va) >> L2_PAGETABLE_SHIFT)
+#define vtopti(va) (((va) >> PAGE_SHIFT) & 0x3ff)
+
+/* access to one page */
+static int
+xendebug_memory_page (domain_context_p ctxt, int xc_handle, u32 vcpu,
+ int protection, memory_t address, int length, u8 *buffer)
+{
+ vcpu_guest_context_t *vcpu_ctxt = &ctxt->context[vcpu];
+ unsigned long pde, page;
+ unsigned long va = (unsigned long)address;
+ void *ptr;
+ long pages;
+
+ pages = xc_get_tot_pages(xc_handle, ctxt->domid);
+
+ if ( ctxt->total_pages != pages )
+ {
+ if ( ctxt->total_pages > 0 ) free( ctxt->page_array );
+ ctxt->total_pages = pages;
+
+ ctxt->page_array = malloc(pages * sizeof(unsigned long));
+ if ( ctxt->page_array == NULL )
+ {
+ printf("Could not allocate memory\n");
+ return 0;
+ }
+
+ if ( xc_get_pfn_list(xc_handle, ctxt->domid, ctxt->page_array,pages) !=
+ pages )
+ {
+ printf("Could not get the page frame list\n");
+ return 0;
+ }
+ }
+
+ if ( vcpu_ctxt->pt_base != ctxt->cr3_phys[vcpu])
+ {
+ ctxt->cr3_phys[vcpu] = vcpu_ctxt->pt_base;
+ if ( ctxt->cr3_virt[vcpu] )
+ munmap(ctxt->cr3_virt[vcpu], PAGE_SIZE);
+ ctxt->cr3_virt[vcpu] = xc_map_foreign_range(xc_handle, ctxt->domid,
+ PAGE_SIZE, PROT_READ, ctxt->cr3_phys[vcpu] >> PAGE_SHIFT);
+ if ( ctxt->cr3_virt[vcpu] == NULL )
+ return 0;
+ }
+
+
+ if ( (pde = ctxt->cr3_virt[vcpu][vtopdi(va)]) == 0) /* logical address */
+ return 0;
+ if (ctxt->context[vcpu].flags & VGCF_VMX_GUEST)
+ pde = ctxt->page_array[pde >> PAGE_SHIFT] << PAGE_SHIFT;
+ if (pde != ctxt->pde_phys[vcpu])
+ {
+ ctxt->pde_phys[vcpu] = pde;
+ if ( ctxt->pde_virt[vcpu])
+ munmap(ctxt->pde_virt[vcpu], PAGE_SIZE);
+ ctxt->pde_virt[vcpu] = xc_map_foreign_range(xc_handle, ctxt->domid,
+ PAGE_SIZE, PROT_READ, ctxt->pde_phys[vcpu] >> PAGE_SHIFT);
+ if ( ctxt->pde_virt[vcpu] == NULL )
+ return 0;
+ }
+
+ if ((page = ctxt->pde_virt[vcpu][vtopti(va)]) == 0) /* logical address */
+ return 0;
+ if (ctxt->context[vcpu].flags & VGCF_VMX_GUEST)
+ page = ctxt->page_array[page >> PAGE_SHIFT] << PAGE_SHIFT;
+ if (page != ctxt->page_phys[vcpu] || protection != ctxt->page_perm[vcpu])
+ {
+ ctxt->page_phys[vcpu] = page;
+ if (ctxt->page_virt[vcpu])
+ munmap(ctxt->page_virt[vcpu], PAGE_SIZE);
+ ctxt->page_virt[vcpu] = xc_map_foreign_range(xc_handle, ctxt->domid,
+ PAGE_SIZE, protection, ctxt->page_phys[vcpu] >> PAGE_SHIFT);
+ if ( ctxt->page_virt[vcpu] == NULL )
+ {
+ printf("cr3 %lx pde %lx page %lx pti %lx\n",
+ vcpu_ctxt->pt_base, pde, page, vtopti(va));
+ ctxt->page_phys[vcpu] = 0;
+ return 0;
+ }
+ ctxt->page_perm[vcpu] = protection;
+ }
+
+ ptr = (void *)( (unsigned long)ctxt->page_virt[vcpu] |
+ (va & ~PAGE_MASK) );
+
+ if ( protection & PROT_WRITE )
+ {
+ memcpy(ptr, buffer, length);
+ }
+ else
+ {
+ memcpy(buffer, ptr, length);
+ }
+
+ return length;
+}
+
+/* divide a memory operation into accesses to individual pages */
+static int
+xendebug_memory_op (domain_context_p ctxt, int xc_handle, u32 vcpu,
+ int protection, memory_t address, int length, u8 *buffer)
+{
+ int remain; /* number of bytes to touch past this page */
+ int bytes = 0;
+
+ while ( (remain = (address + length - 1) - (address | (PAGE_SIZE-1))) > 0)
+ {
+ bytes += xendebug_memory_page(ctxt, xc_handle, vcpu, protection,
+ address, length - remain, buffer);
+ buffer += (length - remain);
+ length = remain;
+ address = (address | (PAGE_SIZE - 1)) + 1;
+ }
+
+ bytes += xendebug_memory_page(ctxt, xc_handle, vcpu, protection,
+ address, length, buffer);
+
+ return bytes;
+}
+
+int
+xendebug_read_memory(int xc_handle,
+ u32 domid,
+ u32 vcpu,
+ memory_t address,
+ u32 length,
+ u8 *data)
+{
+ domain_context_p ctxt;
+
+ xendebug_initialize();
+
+ ctxt = xendebug_get_context(xc_handle, domid, vcpu);
+
+ xendebug_memory_op(ctxt, xc_handle, vcpu, PROT_READ,
+ address, length, data);
+
+ return 0;
+}
+
+int
+xendebug_write_memory(int xc_handle,
+ u32 domid,
+ u32 vcpu,
+ memory_t address,
+ u32 length,
+ u8 *data)
+{
+ domain_context_p ctxt;
+
+ xendebug_initialize();
+
+ ctxt = xendebug_get_context(xc_handle, domid, vcpu);
+ xendebug_memory_op(ctxt, xc_handle, vcpu, PROT_READ | PROT_WRITE,
+
+ address, length, data);
+
+ return 0;
+}
+
+int
+xendebug_insert_memory_breakpoint(int xc_handle,
+ u32 domid,
+ u32 vcpu,
+ memory_t address,
+ u32 length)
+{
+ bwcpoint_p bkpt;
+ u8 breakpoint_opcode = 0xcc;
+
+ printf("insert breakpoint %d:%lx %d\n",
+ domid, address, length);
+
+ xendebug_initialize();
+
+ bkpt = malloc(sizeof(bwcpoint_t));
+ if ( bkpt == NULL )
+ {
+ printf("error: breakpoint length should be 1\n");
+ return -1;
+ }
+
+ if ( length != 1 )
+ {
+ printf("error: breakpoint length should be 1\n");
+ free(bkpt);
+ return -1;
+ }
+
+ bkpt->address = address;
+ bkpt->domain = domid;
+
+ xendebug_read_memory(xc_handle, domid, vcpu, address, 1,
+ &bkpt->old_value);
+
+ xendebug_write_memory(xc_handle, domid, vcpu, address, 1,
+ &breakpoint_opcode);
+
+ list_add(&bkpt->list, &bwcpoint_list.list);
+
+ printf("breakpoint_set %d:%lx 0x%x\n",
+ domid, address, bkpt->old_value);
+
+ return 0;
+}
+
+int
+xendebug_remove_memory_breakpoint(int xc_handle,
+ u32 domid,
+ u32 vcpu,
+ memory_t address,
+ u32 length)
+{
+ bwcpoint_p bkpt = NULL;
+
+ printf ("remove breakpoint %d:%lx\n",
+ domid, address);
+
+ struct list_head *entry;
+ list_for_each(entry, &bwcpoint_list.list)
+ {
+ bkpt = list_entry(entry, bwcpoint_t, list);
+ if ( domid == bkpt->domain && address == bkpt->address )
+ break;
+ }
+
+ if (bkpt == &bwcpoint_list || bkpt == NULL)
+ {
+ printf ("error: no breakpoint found\n");
+ return -1;
+ }
+
+ list_del(&bkpt->list);
+
+ xendebug_write_memory(xc_handle, domid, vcpu, address, 1,
+ &bkpt->old_value);
+
+ free(bkpt);
+ return 0;
+}
+
+int
+xendebug_query_domain_stop(int xc_handle, int *dom_list, int dom_list_size)
+{
+ xc_dominfo_t *info;
+ u32 first_dom = 0;
+ int max_doms = 1024;
+ int nr_doms, loop;
+ int count = 0;
+
+ if ( (info = malloc(max_doms * sizeof(xc_dominfo_t))) == NULL )
+ return -ENOMEM;
+
+ nr_doms = xc_domain_getinfo(xc_handle, first_dom, max_doms, info);
+
+ for (loop = 0; loop < nr_doms; loop++)
+ {
+ printf ("domid: %d", info[loop].domid);
+ printf (" %c%c%c%c%c%c",
+ info[loop].dying ? 'D' : '-',
+ info[loop].crashed ? 'C' : '-',
+ info[loop].shutdown ? 'S' : '-',
+ info[loop].paused ? 'P' : '-',
+ info[loop].blocked ? 'B' : '-',
+ info[loop].running ? 'R' : '-');
+ printf (" pages: %ld, vcpus %d",
+ info[loop].nr_pages, info[loop].vcpus);
+ printf ("\n");
+
+ if ( info[loop].paused && count < dom_list_size)
+ {
+ dom_list[count++] = info[loop].domid;
+ }
+ }
+
+ free(info);
+
+ return count;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/debugger/libxendebug/xendebug.h b/tools/debugger/libxendebug/xendebug.h
new file mode 100644
index 0000000000..66a45104ba
--- /dev/null
+++ b/tools/debugger/libxendebug/xendebug.h
@@ -0,0 +1,78 @@
+/*
+ * xendebug.h
+ *
+ * alex ho
+ * http://www.cl.cam.ac.uk/netos/pdb
+ *
+ */
+
+#ifndef _XENDEBUG_H_DEFINED
+#define _XENDEBUG_H_DEFINED
+
+#include <xc.h>
+
+int xendebug_attach(int xc_handle,
+ u32 domid,
+ u32 vcpu);
+
+int xendebug_detach(int xc_handle,
+ u32 domid,
+ u32 vcpu);
+
+int xendebug_read_registers(int xc_handle,
+ u32 domid,
+ u32 vcpu,
+ cpu_user_regs_t **regs);
+
+int xendebug_read_fpregisters (int xc_handle,
+ u32 domid,
+ u32 vcpu,
+ char **regs);
+
+int xendebug_write_registers(int xc_handle,
+ u32 domid,
+ u32 vcpu,
+ cpu_user_regs_t *regs);
+
+int xendebug_step(int xc_handle,
+ u32 domid,
+ u32 vcpu);
+
+int xendebug_continue(int xc_handle,
+ u32 domid,
+ u32 vcpu);
+
+int xendebug_read_memory(int xc_handle,
+ u32 domid,
+ u32 vcpu,
+ memory_t address,
+ u32 length,
+ u8 *data);
+
+
+int xendebug_write_memory(int xc_handle,
+ u32 domid,
+ u32 vcpu,
+ memory_t address,
+ u32 length,
+ u8 *data);
+
+
+int xendebug_insert_memory_breakpoint(int xc_handle,
+ u32 domid,
+ u32 vcpu,
+ memory_t address,
+ u32 length);
+
+int xendebug_remove_memory_breakpoint(int xc_handle,
+ u32 domid,
+ u32 vcpu,
+ memory_t address,
+ u32 length);
+
+int xendebug_query_domain_stop(int xc_handle,
+ int *dom_list,
+ int dom_list_size);
+
+
+#endif /* _XENDEBUG_H_DEFINED */
diff --git a/tools/debugger/pdb/Domain.ml b/tools/debugger/pdb/Domain.ml
new file mode 100644
index 0000000000..700699a958
--- /dev/null
+++ b/tools/debugger/pdb/Domain.ml
@@ -0,0 +1,63 @@
+(** Domain.ml
+ *
+ * domain context implementation
+ *
+ * @author copyright (c) 2005 alex ho
+ * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
+ * @version 1
+ *)
+
+open Int32
+open Intel
+
+type context_t =
+{
+ mutable domain : int;
+ mutable execution_domain : int
+}
+
+let default_context = { domain = 0; execution_domain = 0 }
+
+let new_context dom exec_dom = {domain = dom; execution_domain = exec_dom}
+
+let set_domain ctx value =
+ ctx.domain <- value;
+ print_endline (Printf.sprintf "ctx.domain <- %d" ctx.domain)
+
+let set_execution_domain ctx value =
+ ctx.execution_domain <- value;
+ print_endline (Printf.sprintf "ctx.execution_domain <- %d"
+ ctx.execution_domain)
+
+let get_domain ctx =
+ ctx.domain
+
+let get_execution_domain ctx =
+ ctx.execution_domain
+
+let string_of_context ctx =
+ Printf.sprintf "{domain} domain: %d, execution_domain: %d"
+ ctx.domain ctx.execution_domain
+
+external read_registers : context_t -> registers = "read_registers"
+external write_register : context_t -> register -> int32 -> unit =
+ "write_register"
+external read_memory : context_t -> int32 -> int -> int list =
+ "read_memory"
+external write_memory : context_t -> int32 -> int list -> unit =
+ "write_memory"
+
+external continue : context_t -> unit = "continue_target"
+external step : context_t -> unit = "step_target"
+
+external insert_memory_breakpoint : context_t -> int32 -> int -> unit =
+ "insert_memory_breakpoint"
+external remove_memory_breakpoint : context_t -> int32 -> int -> unit =
+ "remove_memory_breakpoint"
+
+external attach_debugger : int -> int -> unit = "attach_debugger"
+external detach_debugger : int -> int -> unit = "detach_debugger"
+external pause_target : int -> unit = "pause_target"
+
+let pause ctx =
+ pause_target ctx.domain
diff --git a/tools/debugger/pdb/Domain.mli b/tools/debugger/pdb/Domain.mli
new file mode 100644
index 0000000000..456d19489d
--- /dev/null
+++ b/tools/debugger/pdb/Domain.mli
@@ -0,0 +1,38 @@
+(** Domain.mli
+ *
+ * domain context interface
+ *
+ * @author copyright (c) 2005 alex ho
+ * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
+ * @version 1
+ *)
+
+open Int32
+open Intel
+
+type context_t
+
+val default_context : context_t
+val new_context : int -> int -> context_t
+
+val set_domain : context_t -> int -> unit
+val get_domain : context_t -> int
+val set_execution_domain : context_t -> int -> unit
+val get_execution_domain : context_t -> int
+
+val string_of_context : context_t -> string
+
+val read_registers : context_t -> registers
+val write_register : context_t -> register -> int32 -> unit
+val read_memory : context_t -> int32 -> int -> int list
+val write_memory : context_t -> int32 -> int list -> unit
+
+val continue : context_t -> unit
+val step : context_t -> unit
+
+val insert_memory_breakpoint : context_t -> int32 -> int -> unit
+val remove_memory_breakpoint : context_t -> int32 -> int -> unit
+
+val attach_debugger : int -> int -> unit
+val detach_debugger : int -> int -> unit
+val pause : context_t -> unit
diff --git a/tools/debugger/pdb/Intel.ml b/tools/debugger/pdb/Intel.ml
new file mode 100644
index 0000000000..d82ef8b527
--- /dev/null
+++ b/tools/debugger/pdb/Intel.ml
@@ -0,0 +1,71 @@
+(** Intel.ml
+ *
+ * various sundry Intel x86 definitions
+ *
+ * @author copyright (c) 2005 alex ho
+ * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
+ * @version 1
+ *)
+
+
+type register =
+ | EBX
+ | ECX
+ | EDX
+ | ESI
+ | EDI
+ | EBP
+ | EAX
+ | Error_code
+ | Entry_vector
+ | EIP
+ | CS
+ | EFLAGS
+ | ESP
+ | SS
+ | ES
+ | DS
+ | FS
+ | GS
+
+type registers =
+ { ebx : int32;
+ ecx : int32;
+ edx : int32;
+ esi : int32;
+ edi : int32;
+ ebp : int32;
+ eax : int32;
+ error_code : int32;
+ entry_vector : int32;
+ eip : int32;
+ cs : int32;
+ eflags : int32;
+ esp : int32;
+ ss : int32;
+ es : int32;
+ ds : int32;
+ fs : int32;
+ gs : int32
+ }
+
+let null_registers =
+ { ebx = 0l;
+ ecx = 0l;
+ edx = 0l;
+ esi = 0l;
+ edi = 0l;
+ ebp = 0l;
+ eax = 0l;
+ error_code = 0l;
+ entry_vector = 0l;
+ eip = 0l;
+ cs = 0l;
+ eflags = 0l;
+ esp = 0l;
+ ss = 0l;
+ es = 0l;
+ ds = 0l;
+ fs = 0l;
+ gs = 0l
+ }
diff --git a/tools/debugger/pdb/Makefile b/tools/debugger/pdb/Makefile
new file mode 100644
index 0000000000..579c7da12c
--- /dev/null
+++ b/tools/debugger/pdb/Makefile
@@ -0,0 +1,56 @@
+OCAMLMAKEFILE = OCamlMakefile
+
+XEN_ROOT = ../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+# overwrite LDFLAGS from xen/tool/Rules.mk
+# otherwise, ocamlmktop gets confused.
+LDFLAGS =
+
+OCAML_ROOT=/usr/local
+# force ocaml 3.08
+# OCAML_ROOT = /anfs/nos1/ach61/ocaml
+
+OCAMLC = $(OCAML_ROOT)/bin/ocamlc
+OCAMLMKTOP = $(OCAML_ROOT)/bin/ocamlmktop
+OCAMLLIBPATH= $(OCAML_ROOT)/lib/ocaml
+
+INCLUDES += -I $(XEN_XC)
+INCLUDES += -I $(XEN_LIBXC)
+INCLUDES += -I ../libxendebug
+INCLUDES += -I $(OCAML_ROOT)/lib/ocaml
+
+CFLAGS += $(INCLUDES)
+CFLAGS += -Wall
+CFLAGS += -Werror
+CFLAGS += -g
+
+CLIBS += xc
+CLIBS += xendebug
+CLIBS += pdb
+
+LIBDIRS += $(XEN_LIBXC)
+LIBDIRS += $(XEN_LIBXUTIL)
+LIBDIRS += ../libxendebug
+LIBDIRS += .
+
+LIBS += unix str
+
+PRE_TARGETS = libpdb.a
+
+all : bc
+
+libpdb.a : pdb_xen.o
+ ar rc $@ $^
+ ranlib $@
+
+SOURCES += pdb_caml_xc.c pdb_xen.c
+SOURCES += Util.ml Intel.ml
+SOURCES += evtchn.ml evtchn.mli
+SOURCES += Domain.ml Process.ml
+SOURCES += Domain.mli Process.mli
+SOURCES += PDB.ml debugger.ml server.ml
+RESULT = pdb
+
+include $(OCAMLMAKEFILE)
+
diff --git a/tools/debugger/pdb/OCamlMakefile b/tools/debugger/pdb/OCamlMakefile
new file mode 100644
index 0000000000..0c6d23ab00
--- /dev/null
+++ b/tools/debugger/pdb/OCamlMakefile
@@ -0,0 +1,1149 @@
+###########################################################################
+# OCamlMakefile
+# Copyright (C) 1999-2004 Markus Mottl
+#
+# For updates see:
+# http://www.oefai.at/~markus/ocaml_sources
+#
+# $Id: OCamlMakefile,v 1.1 2005/05/19 09:30:48 root Exp $
+#
+###########################################################################
+
+# Modified by damien for .glade.ml compilation
+
+# Set these variables to the names of the sources to be processed and
+# the result variable. Order matters during linkage!
+
+ifndef SOURCES
+ SOURCES := foo.ml
+endif
+export SOURCES
+
+ifndef RES_CLIB_SUF
+ RES_CLIB_SUF := _stubs
+endif
+export RES_CLIB_SUF
+
+ifndef RESULT
+ RESULT := foo
+endif
+export RESULT
+
+export LIB_PACK_NAME
+
+ifndef DOC_FILES
+ DOC_FILES := $(filter %.mli, $(SOURCES))
+endif
+export DOC_FILES
+
+export BCSUFFIX
+export NCSUFFIX
+
+ifndef TOPSUFFIX
+ TOPSUFFIX := .top
+endif
+export TOPSUFFIX
+
+# Eventually set include- and library-paths, libraries to link,
+# additional compilation-, link- and ocamlyacc-flags
+# Path- and library information needs not be written with "-I" and such...
+# Define THREADS if you need it, otherwise leave it unset (same for
+# USE_CAMLP4)!
+
+export THREADS
+export VMTHREADS
+export ANNOTATE
+export USE_CAMLP4
+
+export INCDIRS
+export LIBDIRS
+export EXTLIBDIRS
+export RESULTDEPS
+export OCAML_DEFAULT_DIRS
+
+export LIBS
+export CLIBS
+
+export OCAMLFLAGS
+export OCAMLNCFLAGS
+export OCAMLBCFLAGS
+
+export OCAMLLDFLAGS
+export OCAMLNLDFLAGS
+export OCAMLBLDFLAGS
+
+ifndef OCAMLCPFLAGS
+ OCAMLCPFLAGS := a
+endif
+
+export OCAMLCPFLAGS
+
+export PPFLAGS
+
+export YFLAGS
+export IDLFLAGS
+
+export OCAMLDOCFLAGS
+
+export OCAMLFIND_INSTFLAGS
+
+export DVIPSFLAGS
+
+export STATIC
+
+# Add a list of optional trash files that should be deleted by "make clean"
+export TRASH
+
+#################### variables depending on your OCaml-installation
+
+ifdef MINGW
+ export MINGW
+ WIN32 := 1
+ CFLAGS_WIN32 := -mno-cygwin
+endif
+ifdef MSVC
+ export MSVC
+ WIN32 := 1
+ ifndef STATIC
+ CPPFLAGS_WIN32 := -DCAML_DLL
+ endif
+ CFLAGS_WIN32 += -nologo
+ EXT_OBJ := obj
+ EXT_LIB := lib
+ ifeq ($(CC),gcc)
+ # work around GNU Make default value
+ ifdef THREADS
+ CC := cl -MT
+ else
+ CC := cl
+ endif
+ endif
+ ifeq ($(CXX),g++)
+ # work around GNU Make default value
+ CXX := $(CC)
+ endif
+ CFLAG_O := -Fo
+endif
+ifdef WIN32
+ EXT_CXX := cpp
+ EXE := .exe
+endif
+
+ifndef EXT_OBJ
+ EXT_OBJ := o
+endif
+ifndef EXT_LIB
+ EXT_LIB := a
+endif
+ifndef EXT_CXX
+ EXT_CXX := cc
+endif
+ifndef EXE
+ EXE := # empty
+endif
+ifndef CFLAG_O
+ CFLAG_O := -o # do not delete this comment (preserves trailing whitespace)!
+endif
+
+export CC
+export CXX
+export CFLAGS
+export CXXFLAGS
+export LDFLAGS
+export CPPFLAGS
+
+ifndef RPATH_FLAG
+ RPATH_FLAG := -R
+endif
+export RPATH_FLAG
+
+ifndef MSVC
+ifndef PIC_CFLAGS
+ PIC_CFLAGS := -fPIC
+endif
+ifndef PIC_CPPFLAGS
+ PIC_CPPFLAGS := -DPIC
+endif
+endif
+
+export PIC_CFLAGS
+export PIC_CPPFLAGS
+
+BCRESULT := $(addsuffix $(BCSUFFIX), $(RESULT))
+NCRESULT := $(addsuffix $(NCSUFFIX), $(RESULT))
+TOPRESULT := $(addsuffix $(TOPSUFFIX), $(RESULT))
+
+ifndef OCAMLFIND
+ OCAMLFIND := ocamlfind
+endif
+export OCAMLFIND
+
+ifndef OCAMLC
+ OCAMLC := ocamlc
+endif
+export OCAMLC
+
+ifndef OCAMLOPT
+ OCAMLOPT := ocamlopt
+endif
+export OCAMLOPT
+
+ifndef OCAMLMKTOP
+ OCAMLMKTOP := ocamlmktop
+endif
+export OCAMLMKTOP
+
+ifndef OCAMLCP
+ OCAMLCP := ocamlcp
+endif
+export OCAMLCP
+
+ifndef OCAMLDEP
+ OCAMLDEP := ocamldep
+endif
+export OCAMLDEP
+
+ifndef OCAMLLEX
+ OCAMLLEX := ocamllex
+endif
+export OCAMLLEX
+
+ifndef OCAMLYACC
+ OCAMLYACC := ocamlyacc
+endif
+export OCAMLYACC
+
+ifndef OCAMLMKLIB
+ OCAMLMKLIB := ocamlmklib
+endif
+export OCAMLMKLIB
+
+ifndef OCAML_GLADECC
+ OCAML_GLADECC := lablgladecc2
+endif
+export OCAML_GLADECC
+
+ifndef OCAML_GLADECC_FLAGS
+ OCAML_GLADECC_FLAGS :=
+endif
+export OCAML_GLADECC_FLAGS
+
+ifndef CAMELEON_REPORT
+ CAMELEON_REPORT := report
+endif
+export CAMELEON_REPORT
+
+ifndef CAMELEON_REPORT_FLAGS
+ CAMELEON_REPORT_FLAGS :=
+endif
+export CAMELEON_REPORT_FLAGS
+
+ifndef CAMELEON_ZOGGY
+ CAMELEON_ZOGGY := camlp4o pa_zog.cma pr_o.cmo
+endif
+export CAMELEON_ZOGGY
+
+ifndef CAMELEON_ZOGGY_FLAGS
+ CAMELEON_ZOGGY_FLAGS :=
+endif
+export CAMELEON_ZOGGY_FLAGS
+
+ifndef OXRIDL
+ OXRIDL := oxridl
+endif
+export OXRIDL
+
+ifndef CAMLIDL
+ CAMLIDL := camlidl
+endif
+export CAMLIDL
+
+ifndef CAMLIDLDLL
+ CAMLIDLDLL := camlidldll
+endif
+export CAMLIDLDLL
+
+ifndef NOIDLHEADER
+ MAYBE_IDL_HEADER := -header
+endif
+export NOIDLHEADER
+
+export NO_CUSTOM
+
+ifndef CAMLP4
+ CAMLP4 := camlp4
+endif
+export CAMLP4
+
+ifndef REAL_OCAMLFIND
+ ifdef PACKS
+ ifndef CREATE_LIB
+ ifdef THREADS
+ PACKS += threads
+ endif
+ endif
+ empty :=
+ space := $(empty) $(empty)
+ comma := ,
+ ifdef PREDS
+ PRE_OCAML_FIND_PREDICATES := $(subst $(space),$(comma),$(PREDS))
+ PRE_OCAML_FIND_PACKAGES := $(subst $(space),$(comma),$(PACKS))
+ OCAML_FIND_PREDICATES := -predicates $(PRE_OCAML_FIND_PREDICATES)
+ # OCAML_DEP_PREDICATES := -syntax $(PRE_OCAML_FIND_PREDICATES)
+ OCAML_FIND_PACKAGES := $(OCAML_FIND_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES)
+ OCAML_DEP_PACKAGES := $(OCAML_DEP_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES)
+ else
+ OCAML_FIND_PACKAGES := -package $(subst $(space),$(comma),$(PACKS))
+ OCAML_DEP_PACKAGES :=
+ endif
+ OCAML_FIND_LINKPKG := -linkpkg
+ REAL_OCAMLFIND := $(OCAMLFIND)
+ endif
+endif
+
+export OCAML_FIND_PACKAGES
+export OCAML_DEP_PACKAGES
+export OCAML_FIND_LINKPKG
+export REAL_OCAMLFIND
+
+ifndef OCAMLDOC
+ OCAMLDOC := ocamldoc
+endif
+export OCAMLDOC
+
+ifndef LATEX
+ LATEX := latex
+endif
+export LATEX
+
+ifndef DVIPS
+ DVIPS := dvips
+endif
+export DVIPS
+
+ifndef PS2PDF
+ PS2PDF := ps2pdf
+endif
+export PS2PDF
+
+ifndef OCAMLMAKEFILE
+ OCAMLMAKEFILE := OCamlMakefile
+endif
+export OCAMLMAKEFILE
+
+ifndef OCAMLLIBPATH
+ OCAMLLIBPATH := \
+ $(shell $(OCAMLC) 2>/dev/null -where || echo /usr/local/lib/ocaml)
+endif
+export OCAMLLIBPATH
+
+ifndef OCAML_LIB_INSTALL
+ OCAML_LIB_INSTALL := $(OCAMLLIBPATH)/contrib
+endif
+export OCAML_LIB_INSTALL
+
+###########################################################################
+
+#################### change following sections only if
+#################### you know what you are doing!
+
+# delete target files when a build command fails
+.PHONY: .DELETE_ON_ERROR
+.DELETE_ON_ERROR:
+
+# for pedants using "--warn-undefined-variables"
+export MAYBE_IDL
+export REAL_RESULT
+export CAMLIDLFLAGS
+export THREAD_FLAG
+export RES_CLIB
+export MAKEDLL
+export ANNOT_FLAG
+export C_OXRIDL
+export SUBPROJS
+export CFLAGS_WIN32
+export CPPFLAGS_WIN32
+
+INCFLAGS :=
+
+SHELL := /bin/sh
+
+MLDEPDIR := ._d
+BCDIDIR := ._bcdi
+NCDIDIR := ._ncdi
+
+FILTER_EXTNS := %.mli %.ml %.mll %.mly %.idl %.oxridl %.c %.$(EXT_CXX) %.rep %.zog %.glade
+
+FILTERED := $(filter $(FILTER_EXTNS), $(SOURCES))
+SOURCE_DIRS := $(filter-out ./, $(sort $(dir $(FILTERED))))
+
+FILTERED_REP := $(filter %.rep, $(FILTERED))
+DEP_REP := $(FILTERED_REP:%.rep=$(MLDEPDIR)/%.d)
+AUTO_REP := $(FILTERED_REP:.rep=.ml)
+
+FILTERED_ZOG := $(filter %.zog, $(FILTERED))
+DEP_ZOG := $(FILTERED_ZOG:%.zog=$(MLDEPDIR)/%.d)
+AUTO_ZOG := $(FILTERED_ZOG:.zog=.ml)
+
+FILTERED_GLADE := $(filter %.glade, $(FILTERED))
+DEP_GLADE := $(FILTERED_GLADE:%.glade=$(MLDEPDIR)/%.d)
+AUTO_GLADE := $(FILTERED_GLADE:.glade=.ml)
+
+FILTERED_ML := $(filter %.ml, $(FILTERED))
+DEP_ML := $(FILTERED_ML:%.ml=$(MLDEPDIR)/%.d)
+
+FILTERED_MLI := $(filter %.mli, $(FILTERED))
+DEP_MLI := $(FILTERED_MLI:.mli=.di)
+
+FILTERED_MLL := $(filter %.mll, $(FILTERED))
+DEP_MLL := $(FILTERED_MLL:%.mll=$(MLDEPDIR)/%.d)
+AUTO_MLL := $(FILTERED_MLL:.mll=.ml)
+
+FILTERED_MLY := $(filter %.mly, $(FILTERED))
+DEP_MLY := $(FILTERED_MLY:%.mly=$(MLDEPDIR)/%.d) $(FILTERED_MLY:.mly=.di)
+AUTO_MLY := $(FILTERED_MLY:.mly=.mli) $(FILTERED_MLY:.mly=.ml)
+
+FILTERED_IDL := $(filter %.idl, $(FILTERED))
+DEP_IDL := $(FILTERED_IDL:%.idl=$(MLDEPDIR)/%.d) $(FILTERED_IDL:.idl=.di)
+C_IDL := $(FILTERED_IDL:%.idl=%_stubs.c)
+ifndef NOIDLHEADER
+ C_IDL += $(FILTERED_IDL:.idl=.h)
+endif
+OBJ_C_IDL := $(FILTERED_IDL:%.idl=%_stubs.$(EXT_OBJ))
+AUTO_IDL := $(FILTERED_IDL:.idl=.mli) $(FILTERED_IDL:.idl=.ml) $(C_IDL)
+
+FILTERED_OXRIDL := $(filter %.oxridl, $(FILTERED))
+DEP_OXRIDL := $(FILTERED_OXRIDL:%.oxridl=$(MLDEPDIR)/%.d) $(FILTERED_OXRIDL:.oxridl=.di)
+AUTO_OXRIDL := $(FILTERED_OXRIDL:.oxridl=.mli) $(FILTERED_OXRIDL:.oxridl=.ml) $(C_OXRIDL)
+
+FILTERED_C_CXX := $(filter %.c %.$(EXT_CXX), $(FILTERED))
+OBJ_C_CXX := $(FILTERED_C_CXX:.c=.$(EXT_OBJ))
+OBJ_C_CXX := $(OBJ_C_CXX:.$(EXT_CXX)=.$(EXT_OBJ))
+
+PRE_TARGETS += $(AUTO_MLL) $(AUTO_MLY) $(AUTO_IDL) $(AUTO_OXRIDL) $(AUTO_ZOG) $(AUTO_REP) $(AUTO_GLADE)
+
+ALL_DEPS := $(DEP_ML) $(DEP_MLI) $(DEP_MLL) $(DEP_MLY) $(DEP_IDL) $(DEP_OXRIDL) $(DEP_ZOG) $(DEP_REP) $(DEP_GLADE)
+
+MLDEPS := $(filter %.d, $(ALL_DEPS))
+MLIDEPS := $(filter %.di, $(ALL_DEPS))
+BCDEPIS := $(MLIDEPS:%.di=$(BCDIDIR)/%.di)
+NCDEPIS := $(MLIDEPS:%.di=$(NCDIDIR)/%.di)
+
+ALLML := $(filter %.mli %.ml %.mll %.mly %.idl %.oxridl %.rep %.zog %.glade, $(FILTERED))
+
+IMPLO_INTF := $(ALLML:%.mli=%.mli.__)
+IMPLO_INTF := $(foreach file, $(IMPLO_INTF), \
+ $(basename $(file)).cmi $(basename $(file)).cmo)
+IMPLO_INTF := $(filter-out %.mli.cmo, $(IMPLO_INTF))
+IMPLO_INTF := $(IMPLO_INTF:%.mli.cmi=%.cmi)
+
+IMPLX_INTF := $(IMPLO_INTF:.cmo=.cmx)
+
+INTF := $(filter %.cmi, $(IMPLO_INTF))
+IMPL_CMO := $(filter %.cmo, $(IMPLO_INTF))
+IMPL_CMX := $(IMPL_CMO:.cmo=.cmx)
+IMPL_ASM := $(IMPL_CMO:.cmo=.asm)
+IMPL_S := $(IMPL_CMO:.cmo=.s)
+
+OBJ_LINK := $(OBJ_C_IDL) $(OBJ_C_CXX)
+OBJ_FILES := $(IMPL_CMO:.cmo=.$(EXT_OBJ)) $(OBJ_LINK)
+
+EXECS := $(addsuffix $(EXE), \
+ $(sort $(TOPRESULT) $(BCRESULT) $(NCRESULT)))
+ifdef WIN32
+ EXECS += $(BCRESULT).dll $(NCRESULT).dll
+endif
+
+CLIB_BASE := $(RESULT)$(RES_CLIB_SUF)
+ifneq ($(strip $(OBJ_LINK)),)
+ RES_CLIB := lib$(CLIB_BASE).$(EXT_LIB)
+endif
+
+ifdef WIN32
+DLLSONAME := $(CLIB_BASE).dll
+else
+DLLSONAME := dll$(CLIB_BASE).so
+endif
+
+NONEXECS := $(INTF) $(IMPL_CMO) $(IMPL_CMX) $(IMPL_ASM) $(IMPL_S) \
+ $(OBJ_FILES) $(PRE_TARGETS) $(BCRESULT).cma $(NCRESULT).cmxa \
+ $(NCRESULT).$(EXT_LIB) $(BCRESULT).cmi $(BCRESULT).cmo \
+ $(NCRESULT).cmi $(NCRESULT).cmx $(NCRESULT).o \
+ $(RES_CLIB) $(IMPL_CMO:.cmo=.annot) \
+ $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(LIB_PACK_NAME).cmx $(LIB_PACK_NAME).o
+
+ifndef STATIC
+ NONEXECS += $(DLLSONAME)
+endif
+
+ifndef LIBINSTALL_FILES
+ LIBINSTALL_FILES := $(RESULT).mli $(RESULT).cmi $(RESULT).cma \
+ $(RESULT).cmxa $(RESULT).$(EXT_LIB) $(RES_CLIB)
+ ifndef STATIC
+ ifneq ($(strip $(OBJ_LINK)),)
+ LIBINSTALL_FILES += $(DLLSONAME)
+ endif
+ endif
+endif
+
+export LIBINSTALL_FILES
+
+ifdef WIN32
+ # some extra stuff is created while linking DLLs
+ NONEXECS += $(BCRESULT).$(EXT_LIB) $(BCRESULT).exp $(NCRESULT).exp $(CLIB_BASE).exp $(CLIB_BASE).lib
+endif
+
+TARGETS := $(EXECS) $(NONEXECS)
+
+# If there are IDL-files
+ifneq ($(strip $(FILTERED_IDL)),)
+ MAYBE_IDL := -cclib -lcamlidl
+endif
+
+ifdef USE_CAMLP4
+ CAMLP4PATH := \
+ $(shell $(CAMLP4) -where 2>/dev/null || echo /usr/local/lib/camlp4)
+ INCFLAGS := -I $(CAMLP4PATH)
+ CINCFLAGS := -I$(CAMLP4PATH)
+endif
+
+DINCFLAGS := $(INCFLAGS) $(SOURCE_DIRS:%=-I %) $(OCAML_DEFAULT_DIRS:%=-I %)
+INCFLAGS := $(DINCFLAGS) $(INCDIRS:%=-I %)
+CINCFLAGS += $(SOURCE_DIRS:%=-I%) $(INCDIRS:%=-I%) $(OCAML_DEFAULT_DIRS:%=-I%)
+
+ifndef MSVC
+CLIBFLAGS += $(SOURCE_DIRS:%=-L%) $(LIBDIRS:%=-L%) \
+ $(EXTLIBDIRS:%=-L%) $(EXTLIBDIRS:%=-Wl,$(RPATH_FLAG)%) \
+ $(OCAML_DEFAULT_DIRS:%=-L%)
+endif
+
+ifndef PROFILING
+ INTF_OCAMLC := $(OCAMLC)
+else
+ ifndef THREADS
+ INTF_OCAMLC := $(OCAMLCP) -p $(OCAMLCPFLAGS)
+ else
+ # OCaml does not support profiling byte code
+ # with threads (yet), therefore we force an error.
+ ifndef REAL_OCAMLC
+ $(error Profiling of multithreaded byte code not yet supported by OCaml)
+ endif
+ INTF_OCAMLC := $(OCAMLC)
+ endif
+endif
+
+ifndef MSVC
+COMMON_LDFLAGS := $(LDFLAGS:%=-ccopt %) $(SOURCE_DIRS:%=-ccopt -L%) \
+ $(LIBDIRS:%=-ccopt -L%) $(EXTLIBDIRS:%=-ccopt -L%) \
+ $(EXTLIBDIRS:%=-ccopt -Wl,$(RPATH_FLAG)%) \
+ $(OCAML_DEFAULT_DIRS:%=-ccopt -L%)
+else
+COMMON_LDFLAGS := -ccopt "/link -NODEFAULTLIB:LIBC $(LDFLAGS:%=%) $(SOURCE_DIRS:%=-LIBPATH:%) \
+ $(LIBDIRS:%=-LIBPATH:%) $(EXTLIBDIRS:%=-LIBPATH:%) \
+ $(OCAML_DEFAULT_DIRS:%=-LIBPATH:%) "
+endif
+
+CLIBS_OPTS := $(CLIBS:%=-cclib -l%)
+ifdef MSVC
+ ifndef STATIC
+ # MSVC libraries do not have 'lib' prefix
+ CLIBS_OPTS := $(CLIBS:%=-cclib %.lib)
+ endif
+endif
+
+ifneq ($(strip $(OBJ_LINK)),)
+ ifdef CREATE_LIB
+ OBJS_LIBS := -cclib -l$(CLIB_BASE) $(CLIBS_OPTS) $(MAYBE_IDL)
+ else
+ OBJS_LIBS := $(OBJ_LINK) $(CLIBS_OPTS) $(MAYBE_IDL)
+ endif
+else
+ OBJS_LIBS := $(CLIBS_OPTS) $(MAYBE_IDL)
+endif
+
+# If we have to make byte-code
+ifndef REAL_OCAMLC
+ BYTE_OCAML := y
+
+ # EXTRADEPS is added dependencies we have to insert for all
+ # executable files we generate. Ideally it should be all of the
+ # libraries we use, but it's hard to find the ones that get searched on
+ # the path since I don't know the paths built into the compiler, so
+ # just include the ones with slashes in their names.
+ EXTRADEPS := $(addsuffix .cma,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i))))
+ SPECIAL_OCAMLFLAGS := $(OCAMLBCFLAGS)
+
+ REAL_OCAMLC := $(INTF_OCAMLC)
+
+ REAL_IMPL := $(IMPL_CMO)
+ REAL_IMPL_INTF := $(IMPLO_INTF)
+ IMPL_SUF := .cmo
+
+ DEPFLAGS :=
+ MAKE_DEPS := $(MLDEPS) $(BCDEPIS)
+
+ ifdef CREATE_LIB
+ CFLAGS := $(PIC_CFLAGS) $(CFLAGS)
+ CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS)
+ ifndef STATIC
+ ifneq ($(strip $(OBJ_LINK)),)
+ MAKEDLL := $(DLLSONAME)
+ ALL_LDFLAGS := -dllib $(DLLSONAME)
+ endif
+ endif
+ endif
+
+ ifndef NO_CUSTOM
+ ifneq "$(strip $(OBJ_LINK) $(THREADS) $(MAYBE_IDL) $(CLIBS))" ""
+ ALL_LDFLAGS += -custom
+ endif
+ endif
+
+ ALL_LDFLAGS += $(INCFLAGS) $(OCAMLLDFLAGS) $(OCAMLBLDFLAGS) \
+ $(COMMON_LDFLAGS) $(LIBS:%=%.cma)
+ CAMLIDLDLLFLAGS :=
+
+ ifdef THREADS
+ ifdef VMTHREADS
+ THREAD_FLAG := -vmthread
+ else
+ THREAD_FLAG := -thread
+ endif
+ ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS)
+ ifndef CREATE_LIB
+ ifndef REAL_OCAMLFIND
+ ALL_LDFLAGS := unix.cma threads.cma $(ALL_LDFLAGS)
+ endif
+ endif
+ endif
+
+# we have to make native-code
+else
+ EXTRADEPS := $(addsuffix .cmxa,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i))))
+ ifndef PROFILING
+ SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS)
+ PLDFLAGS :=
+ else
+ SPECIAL_OCAMLFLAGS := -p $(OCAMLNCFLAGS)
+ PLDFLAGS := -p
+ endif
+
+ REAL_IMPL := $(IMPL_CMX)
+ REAL_IMPL_INTF := $(IMPLX_INTF)
+ IMPL_SUF := .cmx
+
+ CPPFLAGS := -DNATIVE_CODE $(CPPFLAGS)
+
+ DEPFLAGS := -native
+ MAKE_DEPS := $(MLDEPS) $(NCDEPIS)
+
+ ALL_LDFLAGS := $(PLDFLAGS) $(INCFLAGS) $(OCAMLLDFLAGS) \
+ $(OCAMLNLDFLAGS) $(COMMON_LDFLAGS)
+ CAMLIDLDLLFLAGS := -opt
+
+ ifndef CREATE_LIB
+ ALL_LDFLAGS += $(LIBS:%=%.cmxa)
+ else
+ CFLAGS := $(PIC_CFLAGS) $(CFLAGS)
+ CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS)
+ endif
+
+ ifdef THREADS
+ THREAD_FLAG := -thread
+ ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS)
+ ifndef CREATE_LIB
+ ifndef REAL_OCAMLFIND
+ ALL_LDFLAGS := unix.cmxa threads.cmxa $(ALL_LDFLAGS)
+ endif
+ endif
+ endif
+endif
+
+export MAKE_DEPS
+
+ifdef ANNOTATE
+ ANNOT_FLAG := -dtypes
+else
+endif
+
+ALL_OCAMLCFLAGS := $(THREAD_FLAG) $(ANNOT_FLAG) $(OCAMLFLAGS) \
+ $(INCFLAGS) $(SPECIAL_OCAMLFLAGS)
+
+ifdef make_deps
+ -include $(MAKE_DEPS)
+ PRE_TARGETS :=
+endif
+
+###########################################################################
+# USER RULES
+
+# Call "OCamlMakefile QUIET=" to get rid of all of the @'s.
+QUIET=@
+
+# generates byte-code (default)
+byte-code: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \
+ REAL_RESULT="$(BCRESULT)" make_deps=yes
+bc: byte-code
+
+byte-code-nolink: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
+ REAL_RESULT="$(BCRESULT)" make_deps=yes
+bcnl: byte-code-nolink
+
+top: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(TOPRESULT) \
+ REAL_RESULT="$(BCRESULT)" make_deps=yes
+
+# generates native-code
+
+native-code: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \
+ REAL_RESULT="$(NCRESULT)" \
+ REAL_OCAMLC="$(OCAMLOPT)" \
+ make_deps=yes
+nc: native-code
+
+native-code-nolink: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
+ REAL_RESULT="$(NCRESULT)" \
+ REAL_OCAMLC="$(OCAMLOPT)" \
+ make_deps=yes
+ncnl: native-code-nolink
+
+# generates byte-code libraries
+byte-code-library: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+ $(RES_CLIB) $(BCRESULT).cma \
+ REAL_RESULT="$(BCRESULT)" \
+ CREATE_LIB=yes \
+ make_deps=yes
+bcl: byte-code-library
+
+# generates native-code libraries
+native-code-library: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+ $(RES_CLIB) $(NCRESULT).cmxa \
+ REAL_RESULT="$(NCRESULT)" \
+ REAL_OCAMLC="$(OCAMLOPT)" \
+ CREATE_LIB=yes \
+ make_deps=yes
+ncl: native-code-library
+
+ifdef WIN32
+# generates byte-code dll
+byte-code-dll: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+ $(RES_CLIB) $(BCRESULT).dll \
+ REAL_RESULT="$(BCRESULT)" \
+ make_deps=yes
+bcd: byte-code-dll
+
+# generates native-code dll
+native-code-dll: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+ $(RES_CLIB) $(NCRESULT).dll \
+ REAL_RESULT="$(NCRESULT)" \
+ REAL_OCAMLC="$(OCAMLOPT)" \
+ make_deps=yes
+ncd: native-code-dll
+endif
+
+# generates byte-code with debugging information
+debug-code: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \
+ REAL_RESULT="$(BCRESULT)" make_deps=yes \
+ OCAMLFLAGS="-g $(OCAMLFLAGS)" \
+ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
+dc: debug-code
+
+debug-code-nolink: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
+ REAL_RESULT="$(BCRESULT)" make_deps=yes \
+ OCAMLFLAGS="-g $(OCAMLFLAGS)" \
+ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
+dcnl: debug-code-nolink
+
+# generates byte-code libraries with debugging information
+debug-code-library: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+ $(RES_CLIB) $(BCRESULT).cma \
+ REAL_RESULT="$(BCRESULT)" make_deps=yes \
+ CREATE_LIB=yes \
+ OCAMLFLAGS="-g $(OCAMLFLAGS)" \
+ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
+dcl: debug-code-library
+
+# generates byte-code for profiling
+profiling-byte-code: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \
+ REAL_RESULT="$(BCRESULT)" PROFILING="y" \
+ make_deps=yes
+pbc: profiling-byte-code
+
+# generates native-code
+
+profiling-native-code: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \
+ REAL_RESULT="$(NCRESULT)" \
+ REAL_OCAMLC="$(OCAMLOPT)" \
+ PROFILING="y" \
+ make_deps=yes
+pnc: profiling-native-code
+
+# generates byte-code libraries
+profiling-byte-code-library: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+ $(RES_CLIB) $(BCRESULT).cma \
+ REAL_RESULT="$(BCRESULT)" PROFILING="y" \
+ CREATE_LIB=yes \
+ make_deps=yes
+pbcl: profiling-byte-code-library
+
+# generates native-code libraries
+profiling-native-code-library: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+ $(RES_CLIB) $(NCRESULT).cmxa \
+ REAL_RESULT="$(NCRESULT)" PROFILING="y" \
+ REAL_OCAMLC="$(OCAMLOPT)" \
+ CREATE_LIB=yes \
+ make_deps=yes
+pncl: profiling-native-code-library
+
+# packs byte-code objects
+pack-byte-code: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT).cmo \
+ REAL_RESULT="$(BCRESULT)" \
+ PACK_LIB=yes make_deps=yes
+pabc: pack-byte-code
+
+# packs native-code objects
+pack-native-code: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+ $(NCRESULT).cmx $(NCRESULT).o \
+ REAL_RESULT="$(NCRESULT)" \
+ REAL_OCAMLC="$(OCAMLOPT)" \
+ PACK_LIB=yes make_deps=yes
+panc: pack-native-code
+
+# generates HTML-documentation
+htdoc: doc/$(RESULT)/html
+
+# generates Latex-documentation
+ladoc: doc/$(RESULT)/latex
+
+# generates PostScript-documentation
+psdoc: doc/$(RESULT)/latex/doc.ps
+
+# generates PDF-documentation
+pdfdoc: doc/$(RESULT)/latex/doc.pdf
+
+# generates all supported forms of documentation
+doc: htdoc ladoc psdoc pdfdoc
+
+###########################################################################
+# LOW LEVEL RULES
+
+$(REAL_RESULT): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(RESULTDEPS)
+ $(REAL_OCAMLFIND) $(REAL_OCAMLC) \
+ $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \
+ $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@$(EXE) \
+ $(REAL_IMPL)
+
+nolink: $(REAL_IMPL_INTF) $(OBJ_LINK)
+
+ifdef WIN32
+$(REAL_RESULT).dll: $(REAL_IMPL_INTF) $(OBJ_LINK)
+ $(CAMLIDLDLL) $(CAMLIDLDLLFLAGS) $(OBJ_LINK) $(CLIBS) \
+ -o $@ $(REAL_IMPL)
+endif
+
+%$(TOPSUFFIX): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS)
+ $(REAL_OCAMLFIND) $(OCAMLMKTOP) \
+ $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \
+ $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@$(EXE) \
+ $(REAL_IMPL)
+
+.SUFFIXES: .mli .ml .cmi .cmo .cmx .cma .cmxa .$(EXT_OBJ) \
+ .mly .di .d .$(EXT_LIB) .idl %.oxridl .c .$(EXT_CXX) .h .so \
+ .rep .zog .glade
+
+ifndef STATIC
+ifdef MINGW
+$(DLLSONAME): $(OBJ_LINK)
+ $(CC) $(CFLAGS) $(CFLAGS_WIN32) $(OBJ_LINK) -shared -o $@ \
+ -Wl,--whole-archive $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/lib%.a))) \
+ $(OCAMLLIBPATH)/ocamlrun.a \
+ -Wl,--export-all-symbols \
+ -Wl,--no-whole-archive
+else
+ifdef MSVC
+$(DLLSONAME): $(OBJ_LINK)
+ link /NOLOGO /DLL /OUT:$@ $(OBJ_LINK) \
+ $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/%.lib))) \
+ $(OCAMLLIBPATH)/ocamlrun.lib
+
+else
+$(DLLSONAME): $(OBJ_LINK)
+ $(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \
+ -o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) \
+ $(OCAMLMKLIB_FLAGS)
+endif
+endif
+endif
+
+ifndef LIB_PACK_NAME
+$(RESULT).cma: $(REAL_IMPL_INTF) $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS)
+ $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(ALL_LDFLAGS) \
+ $(OBJS_LIBS) -o $@ $(OCAMLBLDFLAGS) $(REAL_IMPL)
+
+$(RESULT).cmxa $(RESULT).$(EXT_LIB): $(REAL_IMPL_INTF) $(EXTRADEPS) $(RESULTDEPS)
+ $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(ALL_LDFLAGS) $(OBJS_LIBS) \
+ $(OCAMLNLDFLAGS) -o $@ $(REAL_IMPL)
+else
+ifdef BYTE_OCAML
+$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo: $(REAL_IMPL_INTF)
+ $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack -o $(LIB_PACK_NAME).cmo $(REAL_IMPL)
+else
+$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx: $(REAL_IMPL_INTF)
+ $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack -o $(LIB_PACK_NAME).cmx $(REAL_IMPL)
+endif
+
+$(RESULT).cma: $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS)
+ $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(ALL_LDFLAGS) \
+ $(OBJS_LIBS) -o $@ $(OCAMLBLDFLAGS) $(LIB_PACK_NAME).cmo
+
+$(RESULT).cmxa $(RESULT).$(EXT_LIB): $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx $(EXTRADEPS) $(RESULTDEPS)
+ $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(ALL_LDFLAGS) $(OBJS_LIBS) \
+ $(OCAMLNLDFLAGS) -o $@ $(LIB_PACK_NAME).cmx
+endif
+
+$(RES_CLIB): $(OBJ_LINK)
+ifndef MSVC
+ ifneq ($(strip $(OBJ_LINK)),)
+ $(AR) rcs $@ $(OBJ_LINK)
+ endif
+else
+ ifneq ($(strip $(OBJ_LINK)),)
+ lib -nologo -debugtype:cv -out:$(RES_CLIB) $(OBJ_LINK)
+ endif
+endif
+
+.mli.cmi: $(EXTRADEPS)
+ $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
+ if [ -z "$$pp" ]; then \
+ echo $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
+ -c $(THREAD_FLAG) $(ANNOT_FLAG) \
+ $(OCAMLFLAGS) $(INCFLAGS) $<; \
+ $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
+ -c $(THREAD_FLAG) $(ANNOT_FLAG) \
+ $(OCAMLFLAGS) $(INCFLAGS) $<; \
+ else \
+ echo $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
+ -c -pp \"$$pp $(PPFLAGS)\" $(THREAD_FLAG) $(ANNOT_FLAG) \
+ $(OCAMLFLAGS) $(INCFLAGS) $<; \
+ $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
+ -c -pp "$$pp $(PPFLAGS)" $(THREAD_FLAG) $(ANNOT_FLAG) \
+ $(OCAMLFLAGS) $(INCFLAGS) $<; \
+ fi
+
+.ml.cmi .ml.$(EXT_OBJ) .ml.cmx .ml.cmo: $(EXTRADEPS)
+ $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
+ if [ -z "$$pp" ]; then \
+ echo $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
+ -c $(ALL_OCAMLCFLAGS) $<; \
+ $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
+ -c $(ALL_OCAMLCFLAGS) $<; \
+ else \
+ echo $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
+ -c -pp \"$$pp $(PPFLAGS)\" $(ALL_OCAMLCFLAGS) $<; \
+ $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
+ -c -pp "$$pp $(PPFLAGS)" $(ALL_OCAMLCFLAGS) $<; \
+ fi
+
+ifdef PACK_LIB
+$(REAL_RESULT).cmo $(REAL_RESULT).cmx $(REAL_RESULT).o: $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS)
+ $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack $(ALL_LDFLAGS) \
+ $(OBJS_LIBS) -o $@ $(REAL_IMPL)
+endif
+
+.PRECIOUS: %.ml
+%.ml: %.mll
+ $(OCAMLLEX) $<
+
+.PRECIOUS: %.ml %.mli
+%.ml %.mli: %.mly
+ $(OCAMLYACC) $(YFLAGS) $<
+ $(QUIET)pp=`sed -n -e 's/.*(\*pp \([^*]*\) \*).*/\1/p;q' $<`; \
+ if [ ! -z "$$pp" ]; then \
+ mv $*.ml $*.ml.temporary; \
+ echo "(*pp $$pp $(PPFLAGS)*)" > $*.ml; \
+ cat $*.ml.temporary >> $*.ml; \
+ rm $*.ml.temporary; \
+ mv $*.mli $*.mli.temporary; \
+ echo "(*pp $$pp $(PPFLAGS)*)" > $*.mli; \
+ cat $*.mli.temporary >> $*.mli; \
+ rm $*.mli.temporary; \
+ fi
+
+
+.PRECIOUS: %.ml
+%.ml: %.rep
+ $(CAMELEON_REPORT) $(CAMELEON_REPORT_FLAGS) -gen $<
+
+.PRECIOUS: %.ml
+%.ml: %.zog
+ $(CAMELEON_ZOGGY) $(CAMELEON_ZOGGY_FLAGS) -impl $< > $@
+
+.PRECIOUS: %.ml
+%.ml: %.glade
+ $(OCAML_GLADECC) $(OCAML_GLADECC_FLAGS) $< > $@
+
+.PRECIOUS: %.ml %.mli
+%.ml %.mli: %.oxridl
+ $(OXRIDL) $<
+
+.PRECIOUS: %.ml %.mli %_stubs.c %.h
+%.ml %.mli %_stubs.c %.h: %.idl
+ $(CAMLIDL) $(MAYBE_IDL_HEADER) $(IDLFLAGS) \
+ $(CAMLIDLFLAGS) $<
+ $(QUIET)if [ $(NOIDLHEADER) ]; then touch $*.h; fi
+
+.c.$(EXT_OBJ):
+ $(OCAMLC) -c -cc "$(CC)" -ccopt "$(CFLAGS) \
+ $(CPPFLAGS) $(CPPFLAGS_WIN32) \
+ $(CFLAGS_WIN32) $(CINCFLAGS) $(CFLAG_O)$@ " $<
+
+.$(EXT_CXX).$(EXT_OBJ):
+ $(CXX) -c $(CXXFLAGS) $(CINCFLAGS) $(CPPFLAGS) \
+ -I'$(OCAMLLIBPATH)' \
+ $< $(CFLAG_O)$@
+
+$(MLDEPDIR)/%.d: %.ml
+ $(QUIET)echo making $@ from $<
+ $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi
+ $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
+ if [ -z "$$pp" ]; then \
+ $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \
+ $(DINCFLAGS) $< > $@; \
+ else \
+ $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \
+ -pp "$$pp $(PPFLAGS)" $(DINCFLAGS) $< > $@; \
+ fi
+
+$(BCDIDIR)/%.di $(NCDIDIR)/%.di: %.mli
+ $(QUIET)echo making $@ from $<
+ $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi
+ $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
+ if [ -z "$$pp" ]; then \
+ $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(DINCFLAGS) $< > $@; \
+ else \
+ $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \
+ -pp "$$pp $(PPFLAGS)" $(DINCFLAGS) $< > $@; \
+ fi
+
+doc/$(RESULT)/html: $(DOC_FILES)
+ rm -rf $@
+ mkdir -p $@
+ $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
+ if [ -z "$$pp" ]; then \
+ echo $(OCAMLDOC) -html -d $@ $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES); \
+ $(OCAMLDOC) -html -d $@ $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES); \
+ else \
+ echo $(OCAMLDOC) -pp \"$$pp $(PPFLAGS)\" -html -d $@ $(OCAMLDOCFLAGS) \
+ $(INCFLAGS) $(DOC_FILES); \
+ $(OCAMLDOC) -pp "$$pp $(PPFLAGS)" -html -d $@ $(OCAMLDOCFLAGS) \
+ $(INCFLAGS) $(DOC_FILES); \
+ fi
+
+doc/$(RESULT)/latex: $(DOC_FILES)
+ rm -rf $@
+ mkdir -p $@
+ $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
+ if [ -z "$$pp" ]; then \
+ echo $(OCAMLDOC) -latex $(OCAMLDOCFLAGS) $(INCFLAGS) \
+ $(DOC_FILES) -o $@/doc.tex; \
+ $(OCAMLDOC) -latex $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES) \
+ -o $@/doc.tex; \
+ else \
+ echo $(OCAMLDOC) -pp \"$$pp $(PPFLAGS)\" -latex $(OCAMLDOCFLAGS) \
+ $(INCFLAGS) $(DOC_FILES) -o $@/doc.tex; \
+ $(OCAMLDOC) -pp "$$pp $(PPFLAGS)" -latex $(OCAMLDOCFLAGS) \
+ $(INCFLAGS) $(DOC_FILES) -o $@/doc.tex; \
+ fi
+
+doc/$(RESULT)/latex/doc.ps: doc/$(RESULT)/latex
+ cd doc/$(RESULT)/latex && \
+ $(LATEX) doc.tex && \
+ $(LATEX) doc.tex && \
+ $(DVIPS) $(DVIPSFLAGS) doc.dvi -o $(@F)
+
+doc/$(RESULT)/latex/doc.pdf: doc/$(RESULT)/latex/doc.ps
+ cd doc/$(RESULT)/latex && $(PS2PDF) $(<F)
+
+define make_subproj
+.PHONY:
+subproj_$(1):
+ $$(eval $$(call PROJ_$(1)))
+ $(QUIET)if [ "$(SUBTARGET)" != "all" ]; then \
+ $(MAKE) -f $(OCAMLMAKEFILE) $(SUBTARGET); \
+ fi
+endef
+
+$(foreach subproj,$(SUBPROJS),$(eval $(call make_subproj,$(subproj))))
+
+.PHONY:
+subprojs: $(SUBPROJS:%=subproj_%)
+
+###########################################################################
+# (UN)INSTALL RULES FOR LIBRARIES
+
+.PHONY: libinstall
+libinstall: all
+ $(QUIET)printf "\nInstalling library with ocamlfind\n"
+ $(OCAMLFIND) install $(OCAMLFIND_INSTFLAGS) $(RESULT) META $(LIBINSTALL_FILES)
+ $(QUIET)printf "\nInstallation successful.\n"
+
+.PHONY: libuninstall
+libuninstall:
+ $(QUIET)printf "\nUninstalling library with ocamlfind\n"
+ $(OCAMLFIND) remove $(OCAMLFIND_INSTFLAGS) $(RESULT)
+ $(QUIET)printf "\nUninstallation successful.\n"
+
+.PHONY: rawinstall
+rawinstall: all
+ $(QUIET)printf "\nInstalling library to: $(OCAML_LIB_INSTALL)\n"
+ -install -d $(OCAML_LIB_INSTALL)
+ for i in $(LIBINSTALL_FILES); do \
+ if [ -f $$i ]; then \
+ install -c -m 0644 $$i $(OCAML_LIB_INSTALL); \
+ fi; \
+ done
+ $(QUIET)printf "\nInstallation successful.\n"
+
+.PHONY: rawuninstall
+rawuninstall:
+ $(QUIET)printf "\nUninstalling library from: $(OCAML_LIB_INSTALL)\n"
+ cd $(OCAML_LIB_INSTALL) && rm $(notdir $(LIBINSTALL_FILES))
+ $(QUIET)printf "\nUninstallation successful.\n"
+
+###########################################################################
+# MAINTAINANCE RULES
+
+.PHONY: clean
+clean::
+ rm -f $(TARGETS) $(TRASH)
+ rm -rf $(BCDIDIR) $(NCDIDIR) $(MLDEPDIR)
+
+.PHONY: cleanup
+cleanup::
+ rm -f $(NONEXECS) $(TRASH)
+ rm -rf $(BCDIDIR) $(NCDIDIR) $(MLDEPDIR)
+
+.PHONY: clean-doc
+clean-doc::
+ rm -rf doc
+
+.PHONY: nobackup
+nobackup:
+ rm -f *.bak *~ *.dup
diff --git a/tools/debugger/pdb/PDB.ml b/tools/debugger/pdb/PDB.ml
new file mode 100644
index 0000000000..0ed121b7aa
--- /dev/null
+++ b/tools/debugger/pdb/PDB.ml
@@ -0,0 +1,180 @@
+(** PDB.ml
+ *
+ * Dispatch debugger commands to the appropriate context
+ *
+ * @author copyright (c) 2005 alex ho
+ * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
+ * @version 1
+ *)
+
+exception Unimplemented of string
+exception Unknown_context of string
+exception Unknown_domain
+
+type context_t =
+ | Void
+ | Event_channel
+ | Domain of Domain.context_t
+ | Process of Process.context_t
+
+let string_of_context ctx =
+ match ctx with
+ | Void -> "{void}"
+ | Event_channel -> "{event channel}"
+ | Domain d -> Domain.string_of_context d
+ | Process p -> Process.string_of_context p
+
+
+
+let read_registers ctx =
+ match ctx with
+ | Domain d -> Domain.read_registers d
+ | _ -> Intel.null_registers
+
+let write_register ctx register value =
+ match ctx with
+ | Domain d -> Domain.write_register d register value
+ | _ -> raise (Unimplemented "write register")
+
+
+let read_memory ctx addr len =
+ match ctx with
+ | Domain d -> Domain.read_memory d addr len
+ | _ -> raise (Unimplemented "read memory")
+
+let write_memory ctx addr values =
+ match ctx with
+ | Domain d -> Domain.write_memory d addr values
+ | _ -> raise (Unimplemented "write memory")
+
+
+let continue ctx =
+ match ctx with
+ | Domain d -> Domain.continue d
+ | _ -> raise (Unimplemented "continue")
+
+let step ctx =
+ match ctx with
+ | Domain d -> Domain.step d
+ | _ -> raise (Unimplemented "step")
+
+
+let insert_memory_breakpoint ctx addr len =
+ match ctx with
+ | Domain d -> Domain.insert_memory_breakpoint d addr len
+ | _ -> raise (Unimplemented "insert memory breakpoint")
+
+let remove_memory_breakpoint ctx addr len =
+ match ctx with
+ | Domain d -> Domain.remove_memory_breakpoint d addr len
+ | _ -> raise (Unimplemented "remove memory breakpoint")
+
+
+let pause ctx =
+ match ctx with
+ | Domain d -> Domain.pause d
+ | _ -> raise (Unimplemented "pause target")
+
+
+let attach_debugger ctx =
+ match ctx with
+ | Domain d -> Domain.attach_debugger (Domain.get_domain d)
+ (Domain.get_execution_domain d)
+ | _ -> raise (Unimplemented "attach debugger")
+
+let detach_debugger ctx =
+ match ctx with
+ | Domain d -> Domain.detach_debugger (Domain.get_domain d)
+ (Domain.get_execution_domain d)
+ | _ -> raise (Unimplemented "detach debugger")
+
+external open_debugger : unit -> unit = "open_context"
+external close_debugger : unit -> unit = "close_context"
+
+(* this is just the domains right now... expand to other contexts later *)
+external debugger_status : unit -> unit = "debugger_status"
+
+
+(***********************************************************)
+
+
+let hash = Hashtbl.create 10
+
+let debug_contexts () =
+ print_endline "context list:";
+ let print_context key ctx =
+ match ctx with
+ | Void -> print_endline (Printf.sprintf " [%s] {void}"
+ (Util.get_connection_info key))
+ | Event_channel -> print_endline (Printf.sprintf " [%s] {event_channel}"
+ (Util.get_connection_info key))
+ | Process p -> print_endline (Printf.sprintf " [%s] %s"
+ (Util.get_connection_info key)
+ (Process.string_of_context p))
+ | Domain d -> print_endline (Printf.sprintf " [%s] %s"
+ (Util.get_connection_info key)
+ (Domain.string_of_context d))
+ in
+ Hashtbl.iter print_context hash
+
+(** add_context : add a new context to the hash table.
+ * if there is an existing context for the same key then it
+ * is first removed implictly by the hash table replace function.
+ *)
+let add_context (key:Unix.file_descr) context params =
+ match context with
+ | "void" -> Hashtbl.replace hash key Void
+ | "event channel" -> Hashtbl.replace hash key Event_channel
+ | "domain" ->
+ begin
+ match params with
+ | dom::exec_dom::_ ->
+ let d = Domain(Domain.new_context dom exec_dom) in
+ attach_debugger d;
+ Hashtbl.replace hash key d
+ | _ -> failwith "bogus parameters to domain context"
+ end
+ | "process" ->
+ begin
+ match params with
+ | dom::pid::_ ->
+ let p = Process.new_context dom pid in
+ Hashtbl.replace hash key (Process(p))
+ | _ -> failwith "bogus parameters to process context"
+ end
+ | _ -> raise (Unknown_context context)
+
+let add_default_context sock =
+ add_context sock "void" []
+
+let find_context key =
+ try
+ Hashtbl.find hash key
+ with
+ Not_found ->
+ print_endline "error: (find_context) PDB context not found";
+ raise Not_found
+
+let delete_context key =
+ Hashtbl.remove hash key
+
+(** find_domain : Locate the context(s) matching a particular domain
+ * and execution_domain pair.
+ *)
+
+let find_domain dom exec_dom =
+ let find key ctx list =
+ match ctx with
+ | Domain d ->
+ if (((Domain.get_domain d) = dom) &&
+ ((Domain.get_execution_domain d) = exec_dom))
+ then
+ key :: list
+ else
+ list
+ | _ -> list
+ in
+ let sock_list = Hashtbl.fold find hash [] in
+ match sock_list with
+ | hd::tl -> hd
+ | [] -> raise Unknown_domain
diff --git a/tools/debugger/pdb/Process.ml b/tools/debugger/pdb/Process.ml
new file mode 100644
index 0000000000..79632b3298
--- /dev/null
+++ b/tools/debugger/pdb/Process.ml
@@ -0,0 +1,39 @@
+(** Process.ml
+ *
+ * process context implementation
+ *
+ * @author copyright (c) 2005 alex ho
+ * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
+ * @version 1
+ *)
+
+open Int32
+open Intel
+
+type context_t =
+{
+ mutable domain : int;
+ mutable process : int;
+}
+
+let default_context = { domain = 0; process = 0 }
+
+let new_context dom proc = { domain = dom; process = proc }
+
+let string_of_context ctx =
+ Printf.sprintf "{process} domain: %d, process: %d"
+ ctx.domain ctx.process
+
+let set_domain ctx value =
+ ctx.domain <- value;
+ print_endline (Printf.sprintf "ctx.domain <- %d" ctx.domain)
+
+let set_process ctx value =
+ ctx.process <- value;
+ print_endline (Printf.sprintf "ctx.process <- %d" ctx.process)
+
+let get_domain ctx =
+ ctx.domain
+
+let get_process ctx =
+ ctx.process
diff --git a/tools/debugger/pdb/Process.mli b/tools/debugger/pdb/Process.mli
new file mode 100644
index 0000000000..39b6221892
--- /dev/null
+++ b/tools/debugger/pdb/Process.mli
@@ -0,0 +1,20 @@
+(** Process.mli
+ *
+ * process context interface
+ *
+ * @author copyright (c) 2005 alex ho
+ * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
+ * @version 1
+ *)
+
+type context_t
+
+val default_context : context_t
+val new_context : int -> int -> context_t
+
+val set_domain : context_t -> int -> unit
+val get_domain : context_t -> int
+val set_process : context_t -> int -> unit
+val get_process : context_t -> int
+
+val string_of_context : context_t -> string
diff --git a/tools/debugger/pdb/Util.ml b/tools/debugger/pdb/Util.ml
new file mode 100644
index 0000000000..a5722242db
--- /dev/null
+++ b/tools/debugger/pdb/Util.ml
@@ -0,0 +1,153 @@
+(** Util.ml
+ *
+ * various utility functions
+ *
+ * @author copyright (c) 2005 alex ho
+ * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
+ * @version 1
+ *)
+
+let int_of_hexchar h =
+ let i = int_of_char h in
+ match h with
+ | '0' .. '9' -> i - (int_of_char '0')
+ | 'a' .. 'f' -> i - (int_of_char 'a') + 10
+ | 'A' .. 'F' -> i - (int_of_char 'A') + 10
+ | _ -> raise (Invalid_argument "unknown hex character")
+
+let hexchar_of_int i =
+ let hexchars = [| '0'; '1'; '2'; '3'; '4'; '5'; '6'; '7';
+ '8'; '9'; 'a'; 'b'; 'c'; 'd'; 'e'; 'f' |]
+ in
+ hexchars.(i)
+
+
+(** flip the bytes of a four byte int
+ *)
+
+let flip_int num =
+ let a = num mod 256
+ and b = (num / 256) mod 256
+ and c = (num / (256 * 256)) mod 256
+ and d = (num / (256 * 256 * 256)) in
+ (a * 256 * 256 * 256) + (b * 256 * 256) + (c * 256) + d
+
+
+let flip_int32 num =
+ let a = Int32.logand num 0xffl
+ and b = Int32.logand (Int32.shift_right_logical num 8) 0xffl
+ and c = Int32.logand (Int32.shift_right_logical num 16) 0xffl
+ and d = (Int32.shift_right_logical num 24) in
+ (Int32.logor
+ (Int32.logor (Int32.shift_left a 24) (Int32.shift_left b 16))
+ (Int32.logor (Int32.shift_left c 8) d))
+
+
+let int_list_of_string_list list =
+ List.map (fun x -> int_of_string x) list
+
+let int_list_of_string str len =
+ let array_of_string s =
+ let int_array = Array.make len 0 in
+ for loop = 0 to len - 1 do
+ int_array.(loop) <- (Char.code s.[loop]);
+ done;
+ int_array
+ in
+ Array.to_list (array_of_string str)
+
+
+(* remove leading and trailing whitespace from a string *)
+
+let chomp str =
+ let head = Str.regexp "^[ \t\r\n]+" in
+ let tail = Str.regexp "[ \t\r\n]+$" in
+ let str = Str.global_replace head "" str in
+ Str.global_replace tail "" str
+
+(* Stupid little parser for "<key>=<value>[,<key>=<value>]*"
+ It first chops the entire command at each ',', so no ',' in key or value!
+ Mucked to return a list of words for "value"
+ *)
+
+let list_of_string str =
+ let delim c = Str.regexp ("[ \t]*" ^ c ^ "[ \t]*") in
+ let str_list = Str.split (delim " ") str in
+ List.map (fun x -> chomp(x)) str_list
+
+let little_parser fn str =
+ let delim c = Str.regexp ("[ \t]*" ^ c ^ "[ \t]*") in
+ let str_list = Str.split (delim ",") str in
+ let pair s =
+ match Str.split (delim "=") s with
+ | [key;value] -> fn (chomp key) (list_of_string value)
+ | [key] -> fn (chomp key) []
+ | _ -> failwith (Printf.sprintf "error: (little_parser) parse error [%s]" str)
+ in
+ List.iter pair str_list
+
+(* boolean list membership test *)
+let not_list_member the_list element =
+ try
+ List.find (fun x -> x = element) the_list;
+ false
+ with
+ Not_found -> true
+
+(* a very inefficient way to remove the elements of one list from another *)
+let list_remove the_list remove_list =
+ List.filter (not_list_member remove_list) the_list
+
+(* get a description of a file descriptor *)
+let get_connection_info fd =
+ let get_local_info fd =
+ let sockname = Unix.getsockname fd in
+ match sockname with
+ | Unix.ADDR_UNIX(s) -> s
+ | Unix.ADDR_INET(a,p) -> ((Unix.string_of_inet_addr a) ^ ":" ^
+ (string_of_int p))
+ and get_remote_info fd =
+ let sockname = Unix.getpeername fd in
+ match sockname with
+ | Unix.ADDR_UNIX(s) -> s
+ | Unix.ADDR_INET(a,p) -> ((Unix.string_of_inet_addr a) ^ ":" ^
+ (string_of_int p))
+ in
+ try
+ get_remote_info fd
+ with
+ | Unix.Unix_error (Unix.ENOTSOCK, s1, s2) ->
+ let s = Unix.fstat fd in
+ Printf.sprintf "dev: %d, inode: %d" s.Unix.st_dev s.Unix.st_ino
+ | _ -> get_local_info fd
+
+
+(* really write a string *)
+let really_write fd str =
+ let strlen = String.length str in
+ let sent = ref 0 in
+ while (!sent < strlen) do
+ sent := !sent + (Unix.write fd str !sent (strlen - !sent))
+ done
+
+let write_character fd ch =
+ let str = String.create 1 in
+ str.[0] <- ch;
+ really_write fd str
+
+
+
+let send_reply fd reply =
+ let checksum = ref 0 in
+ write_character fd '$';
+ for loop = 0 to (String.length reply) - 1 do
+ write_character fd reply.[loop];
+ checksum := !checksum + int_of_char reply.[loop]
+ done;
+ write_character fd '#';
+ write_character fd (hexchar_of_int ((!checksum mod 256) / 16));
+ write_character fd (hexchar_of_int ((!checksum mod 256) mod 16))
+ (*
+ * BUG NEED TO LISTEN FOR REPLY +/- AND POSSIBLY RE-TRANSMIT
+ *)
+
diff --git a/tools/debugger/pdb/debugger.ml b/tools/debugger/pdb/debugger.ml
new file mode 100644
index 0000000000..5a3002470b
--- /dev/null
+++ b/tools/debugger/pdb/debugger.ml
@@ -0,0 +1,315 @@
+(** debugger.ml
+ *
+ * main debug functionality
+ *
+ * @author copyright (c) 2005 alex ho
+ * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
+ * @version 1
+ *)
+
+open Intel
+open PDB
+open Util
+open Str
+
+(** a few debugger commands such as step 's' and continue 'c' do
+ * not immediately return a response to the debugger. in these
+ * cases we raise No_reply instead.
+ *)
+exception No_reply
+
+let initialize_debugger () =
+ ()
+
+let exit_debugger () =
+ ()
+
+
+(**
+ Detach Command
+ Note: response is ignored by gdb. We leave the context in the
+ hash. It will be cleaned up with the socket is closed.
+ *)
+let gdb_detach ctx =
+ PDB.detach_debugger ctx;
+ raise No_reply
+
+(**
+ Kill Command
+ Note: response is ignored by gdb. We leave the context in the
+ hash. It will be cleaned up with the socket is closed.
+ *)
+let gdb_kill () =
+ ""
+
+
+
+(**
+ Continue Command.
+ resume the target
+ *)
+let gdb_continue ctx =
+ PDB.continue ctx;
+ raise No_reply
+
+(**
+ Step Command.
+ single step the target
+ *)
+let gdb_step ctx =
+ PDB.step ctx;
+ raise No_reply
+
+
+(**
+ Read Registers Command.
+ returns 16 4-byte registers in a particular defined by gdb.
+ *)
+let gdb_read_registers ctx =
+ let regs = PDB.read_registers ctx in
+ let str =
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.eax)) ^
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.ecx)) ^
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.edx)) ^
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.ebx)) ^
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.esp)) ^
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.ebp)) ^
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.esi)) ^
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.edi)) ^
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.eip)) ^
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.eflags)) ^
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.cs)) ^
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.ss)) ^
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.ds)) ^
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.es)) ^
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.fs)) ^
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.gs)) in
+ str
+
+(**
+ Set Thread Command
+ *)
+let gdb_set_thread command =
+ "OK"
+
+
+(**
+ Read Memory Packets
+ *)
+let gdb_read_memory ctx command =
+ let int_list_to_string i str =
+ (Printf.sprintf "%02x" i) ^ str
+ in
+ let read_mem addr len =
+ try
+ let mem = PDB.read_memory ctx addr len in
+ List.fold_right int_list_to_string mem ""
+ with
+ Failure s -> "E02"
+ in
+ Scanf.sscanf command "m%lx,%d" read_mem
+
+
+
+(**
+ Write Memory Packets
+ *)
+let gdb_write_memory ctx command =
+ let write_mem addr len =
+ print_endline (Printf.sprintf " gdb_write_memory %lx %x\n" addr len);
+ print_endline (Printf.sprintf " [[ unimplemented ]]\n")
+ in
+ Scanf.sscanf command "M%lx,%d" write_mem;
+ "OK"
+
+
+
+(**
+ Write Register Packets
+ *)
+let gdb_write_register ctx command =
+ let write_reg reg goofy_val =
+ let new_val = Util.flip_int32 goofy_val in
+ match reg with
+ | 0 -> PDB.write_register ctx EAX new_val
+ | 1 -> PDB.write_register ctx ECX new_val
+ | 2 -> PDB.write_register ctx EDX new_val
+ | 3 -> PDB.write_register ctx EBX new_val
+ | 4 -> PDB.write_register ctx ESP new_val
+ | 5 -> PDB.write_register ctx EBP new_val
+ | 6 -> PDB.write_register ctx ESI new_val
+ | 7 -> PDB.write_register ctx EDI new_val
+ | 8 -> PDB.write_register ctx EIP new_val
+ | 9 -> PDB.write_register ctx EFLAGS new_val
+ | 10 -> PDB.write_register ctx CS new_val
+ | 11 -> PDB.write_register ctx SS new_val
+ | 12 -> PDB.write_register ctx DS new_val
+ | 13 -> PDB.write_register ctx ES new_val
+ | 14 -> PDB.write_register ctx FS new_val
+ | 15 -> PDB.write_register ctx GS new_val
+ | _ -> print_endline (Printf.sprintf "write unknown register [%d]" reg)
+ in
+ Scanf.sscanf command "P%x=%lx" write_reg;
+ "OK"
+
+
+(**
+ General Query Packets
+ *)
+let gdb_query command =
+ match command with
+ | "qC" -> ""
+ | "qOffsets" -> ""
+ | "qSymbol::" -> ""
+ | _ ->
+ print_endline (Printf.sprintf "unknown gdb query packet [%s]" command);
+ "E01"
+
+
+(**
+ Write Memory Binary Packets
+ *)
+let gdb_write_memory_binary ctx command =
+ let write_mem addr len =
+ let pos = Str.search_forward (Str.regexp ":") command 0 in
+ let txt = Str.string_after command (pos + 1) in
+ PDB.write_memory ctx addr (int_list_of_string txt len)
+ in
+ Scanf.sscanf command "X%lx,%d" write_mem;
+ "OK"
+
+
+
+(**
+ Last Signal Command
+ *)
+let gdb_last_signal =
+ "S00"
+
+
+
+
+(**
+ Process PDB extensions to the GDB serial protocol.
+ Changes the mutable context state.
+ *)
+let pdb_extensions command sock =
+ let process_extension key value =
+ (* since this command can change the context, we need to grab it each time *)
+ let ctx = PDB.find_context sock in
+ match key with
+ | "status" ->
+ print_endline (string_of_context ctx);
+ PDB.debug_contexts ();
+ debugger_status ()
+ | "context" ->
+ PDB.add_context sock (List.hd value)
+ (int_list_of_string_list (List.tl value))
+ | _ -> failwith (Printf.sprintf "unknown pdb extension command [%s:%s]"
+ key (List.hd value))
+ in
+ try
+ Util.little_parser process_extension
+ (String.sub command 1 ((String.length command) - 1));
+ "OK"
+ with
+ | Unknown_context s ->
+ print_endline (Printf.sprintf "unknown context [%s]" s);
+ "E01"
+ | Failure s -> "E01"
+
+
+(**
+ Insert Breakpoint or Watchpoint Packet
+ *)
+let gdb_insert_bwcpoint ctx command =
+ let insert cmd addr length =
+ try
+ match cmd with
+ | 0 -> PDB.insert_memory_breakpoint ctx addr length; "OK"
+ | _ -> ""
+ with
+ Failure s -> "E03"
+ in
+ Scanf.sscanf command "Z%d,%lx,%d" insert
+
+(**
+ Remove Breakpoint or Watchpoint Packet
+ *)
+let gdb_remove_bwcpoint ctx command =
+ let insert cmd addr length =
+ try
+ match cmd with
+ | 0 -> PDB.remove_memory_breakpoint ctx addr length; "OK"
+ | _ -> ""
+ with
+ Failure s -> "E04"
+ in
+ Scanf.sscanf command "z%d,%lx,%d" insert
+
+(**
+ Do Work!
+
+ @param command char list
+ *)
+
+let process_command command sock =
+ let ctx = PDB.find_context sock in
+ try
+ match command.[0] with
+ | 'c' -> gdb_continue ctx
+ | 'D' -> gdb_detach ctx
+ | 'g' -> gdb_read_registers ctx
+ | 'H' -> gdb_set_thread command
+ | 'k' -> gdb_kill ()
+ | 'm' -> gdb_read_memory ctx command
+ | 'M' -> gdb_write_memory ctx command
+ | 'P' -> gdb_write_register ctx command
+ | 'q' -> gdb_query command
+ | 's' -> gdb_step ctx
+ | 'x' -> pdb_extensions command sock
+ | 'X' -> gdb_write_memory_binary ctx command
+ | '?' -> gdb_last_signal
+ | 'z' -> gdb_remove_bwcpoint ctx command
+ | 'Z' -> gdb_insert_bwcpoint ctx command
+ | _ ->
+ print_endline (Printf.sprintf "unknown gdb command [%s]" command);
+ ""
+ with
+ Unimplemented s ->
+ print_endline (Printf.sprintf "loser. unimplemented command [%s][%s]"
+ command s);
+ ""
+
+
+(**
+ process_evtchn
+
+ This is called each time a virq_pdb is sent from xen to dom 0.
+ It is sent by Xen when a domain hits a breakpoint.
+
+ Think of this as the continuation function for a "c" or "s" command.
+*)
+
+external query_domain_stop : unit -> (int * int) list = "query_domain_stop"
+(* returns a list of paused domains : () -> (domain, vcpu) list *)
+
+let process_evtchn fd =
+ let channel = Evtchn.read fd in
+ let find_pair (dom, vcpu) =
+ print_endline (Printf.sprintf "checking %d.%d" dom vcpu);
+ try
+ let sock = PDB.find_domain dom vcpu in
+ true
+ with
+ Unknown_domain -> false
+ in
+ let dom_list = query_domain_stop () in
+ let (dom, vcpu) = List.find find_pair dom_list in
+ let vec = 3 in
+ let sock = PDB.find_domain dom vcpu in
+ print_endline (Printf.sprintf "handle bkpt d:%d ed:%d v:%d %s"
+ dom vcpu vec (Util.get_connection_info sock));
+ Util.send_reply sock "S05";
+ Evtchn.unmask fd channel (* allow next virq *)
+
diff --git a/tools/debugger/pdb/evtchn.ml b/tools/debugger/pdb/evtchn.ml
new file mode 100644
index 0000000000..5443accd9b
--- /dev/null
+++ b/tools/debugger/pdb/evtchn.ml
@@ -0,0 +1,32 @@
+(** evtchn.ml
+ *
+ * event channel interface
+ *
+ * @author copyright (c) 2005 alex ho
+ * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
+ * @version 1
+ *)
+
+let dev_name = "/dev/xen/evtchn" (* EVTCHN_DEV_NAME *)
+let dev_major = 10 (* EVTCHN_DEV_MAJOR *)
+let dev_minor = 201 (* EVTCHN_DEV_MINOR *)
+
+let virq_pdb = 6 (* as defined VIRQ_PDB *)
+
+external bind_virq : int -> int = "evtchn_bind_virq"
+external bind : Unix.file_descr -> int -> unit = "evtchn_bind"
+external unbind : Unix.file_descr -> int -> unit = "evtchn_unbind"
+external ec_open : string -> int -> int -> Unix.file_descr = "evtchn_open"
+external read : Unix.file_descr -> int = "evtchn_read"
+external ec_close : Unix.file_descr -> unit = "evtchn_close"
+external unmask : Unix.file_descr -> int -> unit = "evtchn_unmask"
+
+let setup () =
+ let port = bind_virq virq_pdb in
+ let fd = ec_open dev_name dev_major dev_minor in
+ bind fd port;
+ fd
+
+let teardown fd =
+ unbind fd virq_pdb;
+ ec_close fd
diff --git a/tools/debugger/pdb/evtchn.mli b/tools/debugger/pdb/evtchn.mli
new file mode 100644
index 0000000000..18b3ed667b
--- /dev/null
+++ b/tools/debugger/pdb/evtchn.mli
@@ -0,0 +1,14 @@
+(** evtchn.mli
+ *
+ * event channel interface
+ *
+ * @author copyright (c) 2005 alex ho
+ * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
+ * @version 1
+ *)
+
+
+val setup : unit -> Unix.file_descr
+val read : Unix.file_descr -> int
+val teardown : Unix.file_descr -> unit
+val unmask : Unix.file_descr -> int -> unit
diff --git a/tools/debugger/pdb/pdb_caml_xc.c b/tools/debugger/pdb/pdb_caml_xc.c
new file mode 100644
index 0000000000..6ba82a92c2
--- /dev/null
+++ b/tools/debugger/pdb/pdb_caml_xc.c
@@ -0,0 +1,732 @@
+/*
+ * pdb_caml_xc.c
+ *
+ * http://www.cl.cam.ac.uk/netos/pdb
+ *
+ * OCaml to libxc interface library for PDB
+ */
+
+#include <xc.h>
+#include <xendebug.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <caml/alloc.h>
+#include <caml/fail.h>
+#include <caml/memory.h>
+#include <caml/mlvalues.h>
+
+int pdb_evtchn_bind_virq (int xc_handle, int virq, int *port);
+int xen_evtchn_bind (int evtchn_fd, int idx);
+int xen_evtchn_unbind (int evtchn_fd, int idx);
+
+/* this order comes from xen/include/public/arch-x86_32.h */
+enum x86_registers { PDB_EBX, PDB_ECX, PDB_EDX, PDB_ESI, PDB_EDI,
+ PDB_EBP, PDB_EAX, PDB_Error_code, PDB_Entry_vector,
+ PDB_EIP, PDB_CS, PDB_EFLAGS, PDB_ESP, PDB_SS,
+ PDB_ES, PDB_DS, PDB_FS, PDB_GS };
+
+static void dump_regs (cpu_user_regs_t *ctx);
+
+static int xc_handle = -1;
+
+typedef struct
+{
+ int domain;
+ int vcpu;
+} context_t;
+
+#define decode_context(_ctx, _ocaml) \
+{ \
+ (_ctx)->domain = Int_val(Field((_ocaml),0)); \
+ (_ctx)->vcpu = Int_val(Field((_ocaml),1)); \
+}
+
+#define encode_context(_ctx, _ocaml) \
+{ \
+ (_ocaml) = caml_alloc_tuple(2); \
+ Store_field((_ocaml), 0, Val_int((_ctx)->domain)); \
+ Store_field((_ocaml), 1, Val_int((_ctx)->vcpu)); \
+}
+
+
+/****************************************************************************/
+
+/*
+ * open_context : unit -> unit
+ */
+value
+open_context (value unit)
+{
+ CAMLparam1(unit);
+
+ xc_handle = xc_interface_open();
+
+ if ( xc_handle < 0 )
+ {
+ fprintf(stderr, "(pdb) error opening xc interface: %d (%s)\n",
+ errno, strerror(errno));
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * close_context : unit -> unit
+ */
+value
+close_context (value unit)
+{
+ CAMLparam1(unit);
+ int rc;
+
+ if ( (rc = xc_interface_close(xc_handle)) < 0 )
+ {
+ fprintf(stderr, "(pdb) error closing xc interface: %d (%s)\n",
+ errno, strerror(errno));
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * read_registers : context_t -> int32
+ */
+value
+read_registers (value context)
+{
+ CAMLparam1(context);
+ CAMLlocal1(result);
+
+ cpu_user_regs_t *regs;
+ context_t ctx;
+
+ decode_context(&ctx, context);
+
+ if ( xendebug_read_registers(xc_handle, ctx.domain, ctx.vcpu, &regs) )
+ {
+ printf("(pdb) read registers error!\n"); fflush(stdout);
+ failwith("read registers error");
+ }
+
+ dump_regs(regs);
+
+ result = caml_alloc_tuple(18); /* FIXME */
+
+ Store_field(result, 0, caml_copy_int32(regs->ebx));
+ Store_field(result, 1, caml_copy_int32(regs->ecx));
+ Store_field(result, 2, caml_copy_int32(regs->edx));
+ Store_field(result, 3, caml_copy_int32(regs->esi));
+ Store_field(result, 4, caml_copy_int32(regs->edi));
+ Store_field(result, 5, caml_copy_int32(regs->ebp));
+ Store_field(result, 6, caml_copy_int32(regs->eax));
+ Store_field(result, 7, caml_copy_int32(regs->error_code)); /* 16 */
+ Store_field(result, 8, caml_copy_int32(regs->entry_vector)); /* 16 */
+ Store_field(result, 9, caml_copy_int32(regs->eip));
+ Store_field(result, 10, caml_copy_int32(regs->cs)); /* 16 */
+ Store_field(result, 11, caml_copy_int32(regs->eflags));
+ Store_field(result, 12, caml_copy_int32(regs->esp));
+ Store_field(result, 13, caml_copy_int32(regs->ss)); /* 16 */
+ Store_field(result, 14, caml_copy_int32(regs->es)); /* 16 */
+ Store_field(result, 15, caml_copy_int32(regs->ds)); /* 16 */
+ Store_field(result, 16, caml_copy_int32(regs->fs)); /* 16 */
+ Store_field(result, 17, caml_copy_int32(regs->gs)); /* 16 */
+
+ CAMLreturn(result);
+}
+
+
+/*
+ * write_register : context_t -> register -> int32 -> unit
+ */
+value
+write_register (value context, value reg, value newval)
+{
+ CAMLparam3(context, reg, newval);
+
+ int my_reg = Int_val(reg);
+ int val = Int32_val(newval);
+
+ context_t ctx;
+ cpu_user_regs_t *regs;
+
+ printf("(pdb) write register\n");
+
+ decode_context(&ctx, context);
+
+ if ( xendebug_read_registers(xc_handle, ctx.domain, ctx.vcpu, &regs) )
+ {
+ printf("(pdb) write register (get) error!\n"); fflush(stdout);
+ failwith("write register error");
+ }
+
+ switch (my_reg)
+ {
+ case PDB_EBX: regs->ebx = val; break;
+ case PDB_ECX: regs->ecx = val; break;
+ case PDB_EDX: regs->edx = val; break;
+ case PDB_ESI: regs->esi = val; break;
+ case PDB_EDI: regs->edi = val; break;
+
+ case PDB_EBP: regs->ebp = val; break;
+ case PDB_EAX: regs->eax = val; break;
+ case PDB_Error_code: regs->error_code = val; break;
+ case PDB_Entry_vector: regs->entry_vector = val; break;
+
+ case PDB_EIP: regs->eip = val; break;
+ case PDB_CS: regs->cs = val; break;
+ case PDB_EFLAGS: regs->eflags = val; break;
+ case PDB_ESP: regs->esp = val; break;
+ case PDB_SS: regs->ss = val; break;
+ case PDB_ES: regs->es = val; break;
+ case PDB_DS: regs->ds = val; break;
+ case PDB_FS: regs->fs = val; break;
+ case PDB_GS: regs->gs = val; break;
+ }
+
+ if ( xendebug_write_registers(xc_handle, ctx.domain, ctx.vcpu, regs) )
+ {
+ printf("(pdb) write register (set) error!\n"); fflush(stdout);
+ failwith("write register error");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * read_memory : context_t -> int32 -> int -> int
+ */
+value
+read_memory (value context, value address, value length)
+{
+ CAMLparam3(context, address, length);
+ CAMLlocal2(result, temp);
+
+ context_t ctx;
+ int loop;
+ char *buffer;
+ memory_t my_address = Int32_val(address);
+ u32 my_length = Int_val(length);
+
+ printf ("(pdb) read memory\n");
+
+ decode_context(&ctx, context);
+
+ buffer = malloc(my_length);
+ if (buffer == NULL)
+ {
+ printf("(pdb) read memory: malloc failed.\n"); fflush(stdout);
+ failwith("read memory error");
+ }
+
+ if ( xendebug_read_memory(xc_handle, ctx.domain, ctx.vcpu,
+ my_address, my_length, buffer) )
+ {
+ printf("(pdb) read memory error!\n"); fflush(stdout);
+ failwith("read memory error");
+ }
+
+ result = caml_alloc(2,0);
+ if ( my_length > 0 ) /* car */
+ {
+ Store_field(result, 0, Val_int(buffer[my_length - 1] & 0xff));
+ }
+ else
+
+ {
+ Store_field(result, 0, Val_int(0));
+ }
+ Store_field(result, 1, Val_int(0)); /* cdr */
+
+ for (loop = 1; loop < my_length; loop++)
+ {
+ temp = result;
+ result = caml_alloc(2,0);
+ Store_field(result, 0, Val_int(buffer[my_length - loop - 1] & 0xff));
+ Store_field(result, 1, temp);
+ }
+
+ CAMLreturn(result);
+}
+
+/*
+ * write_memory : context_t -> int32 -> int list -> unit
+ */
+value
+write_memory (value context, value address, value val_list)
+{
+ CAMLparam3(context, address, val_list);
+ CAMLlocal1(node);
+
+ context_t ctx;
+
+ char buffer[4096]; /* a big buffer */
+ memory_t my_address;
+ u32 length = 0;
+
+ printf ("(pdb) write memory\n");
+
+ decode_context(&ctx, context);
+
+ node = val_list;
+ if ( Int_val(node) == 0 ) /* gdb functionalty test uses empty list */
+ {
+ CAMLreturn(Val_unit);
+ }
+
+ while ( Int_val(Field(node,1)) != 0 )
+ {
+ buffer[length++] = Int_val(Field(node, 0));
+ node = Field(node,1);
+ }
+ buffer[length++] = Int_val(Field(node, 0));
+
+ my_address = (memory_t) Int32_val(address);
+
+ if ( xendebug_write_memory(xc_handle, ctx.domain, ctx.vcpu,
+ my_address, length, buffer) )
+ {
+ printf("(pdb) write memory error!\n"); fflush(stdout);
+ failwith("write memory error");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+
+/*********************************************************************/
+
+void
+dump_regs (cpu_user_regs_t *regs)
+{
+ printf (" eax: %x\n", regs->eax);
+ printf (" ecx: %x\n", regs->ecx);
+ printf (" edx: %x\n", regs->edx);
+ printf (" ebx: %x\n", regs->ebx);
+ printf (" esp: %x\n", regs->esp);
+ printf (" ebp: %x\n", regs->ebp);
+ printf (" esi: %x\n", regs->esi);
+ printf (" edi: %x\n", regs->edi);
+ printf (" eip: %x\n", regs->eip);
+ printf (" flags: %x\n", regs->eflags);
+ printf (" cs: %x\n", regs->cs);
+ printf (" ss: %x\n", regs->ss);
+ printf (" es: %x\n", regs->es);
+ printf (" ds: %x\n", regs->ds);
+ printf (" fs: %x\n", regs->fs);
+ printf (" gs: %x\n", regs->gs);
+
+ return;
+}
+
+/*
+ * continue_target : context_t -> unit
+ */
+value
+continue_target (value context)
+{
+ CAMLparam1(context);
+
+ context_t ctx;
+
+ decode_context(&ctx, context);
+
+ if ( xendebug_continue(xc_handle, ctx.domain, ctx.vcpu) )
+ {
+ printf("(pdb) continue\n"); fflush(stdout);
+ failwith("continue");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * step_target : context_t -> unit
+ */
+value
+step_target (value context)
+{
+ CAMLparam1(context);
+
+ context_t ctx;
+
+ decode_context(&ctx, context);
+
+ if ( xendebug_step(xc_handle, ctx.domain, ctx.vcpu) )
+ {
+ printf("(pdb) step\n"); fflush(stdout);
+ failwith("step");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+
+
+/*
+ * insert_memory_breakpoint : context_t -> int32 -> int list -> unit
+ */
+value
+insert_memory_breakpoint (value context, value address, value length)
+{
+ CAMLparam3(context, address, length);
+
+ context_t ctx;
+ memory_t my_address = (memory_t) Int32_val(address);
+ int my_length = Int_val(length);
+
+ decode_context(&ctx, context);
+
+ printf ("(pdb) insert memory breakpoint 0x%lx %d\n",
+ my_address, my_length);
+
+ if ( xendebug_insert_memory_breakpoint(xc_handle, ctx.domain, ctx.vcpu,
+ my_address, my_length) )
+ {
+ printf("(pdb) error: insert memory breakpoint\n"); fflush(stdout);
+ failwith("insert memory breakpoint");
+ }
+
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * remove_memory_breakpoint : context_t -> int32 -> int list -> unit
+ */
+value
+remove_memory_breakpoint (value context, value address, value length)
+{
+ CAMLparam3(context, address, length);
+
+ context_t ctx;
+
+ memory_t my_address = (memory_t) Int32_val(address);
+ int my_length = Int_val(length);
+
+ printf ("(pdb) remove memory breakpoint 0x%lx %d\n",
+ my_address, my_length);
+
+ decode_context(&ctx, context);
+
+ if ( xendebug_remove_memory_breakpoint(xc_handle,
+ ctx.domain, ctx.vcpu,
+ my_address, my_length) )
+ {
+ printf("(pdb) error: remove memory breakpoint\n"); fflush(stdout);
+ failwith("remove memory breakpoint");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * attach_debugger : int -> int -> unit
+ */
+value
+attach_debugger (value domain, value vcpu)
+{
+ CAMLparam2(domain, vcpu);
+
+ int my_domain = Int_val(domain);
+ int my_vcpu = Int_val(vcpu);
+
+ printf ("(pdb) attach domain [%d.%d]\n", my_domain, my_vcpu);
+
+ if ( xendebug_attach(xc_handle, my_domain, my_vcpu) )
+ {
+ printf("(pdb) attach error!\n"); fflush(stdout);
+ failwith("attach error");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+
+/*
+ * detach_debugger : int -> int -> unit
+ */
+value
+detach_debugger (value domain, value vcpu)
+{
+ CAMLparam2(domain, vcpu);
+
+ int my_domain = Int_val(domain);
+ int my_vcpu = Int_val(vcpu);
+
+ printf ("(pdb) detach domain [%d.%d]\n", my_domain, my_vcpu);
+
+ if ( xendebug_detach(xc_handle, my_domain, my_vcpu) )
+ {
+ printf("(pdb) detach error!\n"); fflush(stdout);
+ failwith("detach error");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+
+/*
+ * debugger_status : unit -> unit
+ */
+value
+debugger_status (value unit)
+{
+ CAMLparam1(unit);
+
+ printf ("(pdb) debugger status\n");
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * pause_target : int -> unit
+ */
+value
+pause_target (value domid)
+{
+ CAMLparam1(domid);
+
+ int my_domid = Int_val(domid);
+
+ printf ("(pdb) pause target %d\n", my_domid);
+
+ xc_domain_pause(xc_handle, my_domid);
+
+ CAMLreturn(Val_unit);
+}
+
+/****************************************************************************/
+/****************************************************************************/
+
+/*
+ * query_domain_stop : unit -> (int * int) list
+ */
+value
+query_domain_stop (value unit)
+{
+ CAMLparam1(unit);
+ CAMLlocal3(result, temp, node);
+
+ int max_domains = 20;
+ int dom_list[max_domains];
+ int loop, count;
+
+ count = xendebug_query_domain_stop(xc_handle, dom_list, max_domains);
+ if ( count < 0 )
+ {
+ printf("(pdb) query domain stop!\n"); fflush(stdout);
+ failwith("query domain stop");
+ }
+
+ printf ("QDS: %d\n", count);
+ for (loop = 0; loop < count; loop ++)
+ printf (" %d %d\n", loop, dom_list[loop]);
+
+ result = caml_alloc(2,0);
+ if ( count > 0 ) /* car */
+ {
+ node = caml_alloc(2,0);
+ Store_field(node, 0, Val_int(dom_list[0])); /* domain id */
+ Store_field(node, 1, Val_int(0)); /* vcpu */
+ Store_field(result, 0, node);
+ }
+ else
+ {
+ Store_field(result, 0, Val_int(0));
+ }
+ Store_field(result, 1, Val_int(0)); /* cdr */
+
+ for ( loop = 1; loop < count; loop++ )
+ {
+ temp = result;
+ result = caml_alloc(2,0);
+ node = caml_alloc(2,0);
+ Store_field(node, 0, Val_int(dom_list[loop])); /* domain id */
+ Store_field(node, 1, Val_int(0)); /* vcpu */
+ Store_field(result, 0, node);
+ Store_field(result, 1, temp);
+ }
+
+ CAMLreturn(result);
+}
+
+/****************************************************************************/
+/****************************************************************************/
+
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/*
+ * evtchn_open : string -> int -> int -> Unix.file_descr
+ *
+ * OCaml's Unix library doesn't have mknod, so it makes more sense just write
+ * this in C. This code is from Keir/Andy.
+ */
+value
+evtchn_open (value filename, value major, value minor)
+{
+ CAMLparam3(filename, major, minor);
+
+ char *myfilename = String_val(filename);
+ int mymajor = Int_val(major);
+ int myminor = Int_val(minor);
+ int evtchn_fd;
+ struct stat st;
+
+ /* Make sure any existing device file links to correct device. */
+ if ( (lstat(myfilename, &st) != 0) ||
+ !S_ISCHR(st.st_mode) ||
+ (st.st_rdev != makedev(mymajor, myminor)) )
+ {
+ (void)unlink(myfilename);
+ }
+
+ reopen:
+ evtchn_fd = open(myfilename, O_RDWR);
+ if ( evtchn_fd == -1 )
+ {
+ if ( (errno == ENOENT) &&
+ ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
+ (mknod(myfilename, S_IFCHR|0600, makedev(mymajor,myminor)) == 0) )
+ {
+ goto reopen;
+ }
+ return -errno;
+ }
+
+ CAMLreturn(Val_int(evtchn_fd));
+}
+
+/*
+ * evtchn_bind_virq : int -> int
+ */
+value
+evtchn_bind_virq (value virq)
+{
+ CAMLparam1(virq);
+
+ int port;
+
+ if ( pdb_evtchn_bind_virq(xc_handle, Int_val(virq), &port) < 0 )
+ {
+ printf("(pdb) evtchn_bind_virq error!\n"); fflush(stdout);
+ failwith("evtchn_bind_virq error");
+ }
+
+ CAMLreturn(Val_int(port));
+}
+
+/*
+ * evtchn_bind : Unix.file_descr -> int -> unit
+ */
+value
+evtchn_bind (value fd, value idx)
+{
+ CAMLparam2(fd, idx);
+
+ int myfd = Int_val(fd);
+ int myidx = Int_val(idx);
+
+ if ( xen_evtchn_bind(myfd, myidx) < 0 )
+ {
+ printf("(pdb) evtchn_bind error!\n"); fflush(stdout);
+ failwith("evtchn_bind error");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * evtchn_unbind : Unix.file_descr -> int -> unit
+ */
+value
+evtchn_unbind (value fd, value idx)
+{
+ CAMLparam2(fd, idx);
+
+ int myfd = Int_val(fd);
+ int myidx = Int_val(idx);
+
+ if ( xen_evtchn_unbind(myfd, myidx) < 0 )
+ {
+ printf("(pdb) evtchn_unbind error!\n"); fflush(stdout);
+ failwith("evtchn_unbind error");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * evtchn_read : Unix.file_descr -> int
+ */
+value
+evtchn_read (value fd)
+{
+ CAMLparam1(fd);
+
+ u16 v;
+ int bytes;
+ int rc = -1;
+ int myfd = Int_val(fd);
+
+ while ( (bytes = read(myfd, &v, sizeof(v))) == -1 )
+ {
+ if ( errno == EINTR ) continue;
+ rc = -errno;
+ goto exit;
+ }
+
+ if ( bytes == sizeof(v) )
+ rc = v;
+
+ exit:
+ CAMLreturn(Val_int(rc));
+}
+
+
+/*
+ * evtchn_close : Unix.file_descr -> unit
+ */
+value
+evtchn_close (value fd)
+{
+ CAMLparam1(fd);
+ int myfd = Int_val(fd);
+
+ (void)close(myfd);
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * evtchn_unmask : Unix.file_descr -> int -> unit
+ */
+value
+evtchn_unmask (value fd, value idx)
+{
+ CAMLparam1(fd);
+
+ int myfd = Int_val(fd);
+ u16 myidx = Int_val(idx);
+
+ (void)write(myfd, &myidx, sizeof(myidx));
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
diff --git a/tools/debugger/pdb/pdb_xen.c b/tools/debugger/pdb/pdb_xen.c
new file mode 100644
index 0000000000..36671dacc0
--- /dev/null
+++ b/tools/debugger/pdb/pdb_xen.c
@@ -0,0 +1,93 @@
+/*
+ * pdb_xen.c
+ *
+ * alex ho
+ * http://www.cl.cam.ac.uk/netos/pdb
+ *
+ * PDB interface library for accessing Xen
+ */
+
+#include <xc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/mman.h>
+
+int
+pdb_open ()
+{
+ int xc_handle = xc_interface_open();
+
+ if ( xc_handle < 0 )
+ {
+ fprintf(stderr, "(pdb) error opening xc interface: %d (%s)\n",
+ errno, strerror(errno));
+ }
+ return xc_handle;
+}
+
+int
+pdb_close (int xc_handle)
+{
+ int rc;
+
+
+ if ( (rc = xc_interface_close(xc_handle)) < 0 )
+ {
+ fprintf(stderr, "(pdb) error closing xc interface: %d (%s)\n",
+ errno, strerror(errno));
+ }
+ return rc;
+}
+
+
+int
+pdb_evtchn_bind_virq (int xc_handle, int virq, int *port)
+{
+ int rc;
+
+ if ( (rc = xc_evtchn_bind_virq(xc_handle, virq, port) < 0 ) )
+ {
+ fprintf(stderr, "(pdb) error binding virq to event channel: %d (%s)\n",
+ errno, strerror(errno));
+ }
+ return rc;
+}
+
+
+#include <sys/ioctl.h>
+
+/* /dev/xen/evtchn ioctls */
+#define EVTCHN_RESET _IO('E', 1) /* clear & reinit buffer */
+#define EVTCHN_BIND _IO('E', 2) /* bind to event channel */
+#define EVTCHN_UNBIND _IO('E', 3) /* unbind from event channel */
+
+int
+xen_evtchn_bind (int evtchn_fd, int idx)
+{
+ if ( ioctl(evtchn_fd, EVTCHN_BIND, idx) != 0 )
+ return -errno;
+
+ return 0;
+}
+
+int
+xen_evtchn_unbind (int evtchn_fd, int idx)
+{
+ if ( ioctl(evtchn_fd, EVTCHN_UNBIND, idx) != 0 )
+ return -errno;
+
+ return 0;
+}
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/debugger/pdb/server.ml b/tools/debugger/pdb/server.ml
new file mode 100644
index 0000000000..2d3a3c7c86
--- /dev/null
+++ b/tools/debugger/pdb/server.ml
@@ -0,0 +1,219 @@
+(** server.ml
+ *
+ * PDB server main loop
+ *
+ * @author copyright (c) 2005 alex ho
+ * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
+ * @version 1
+ *)
+
+open Unix
+open Buffer
+
+
+(**
+ * connection_t: The state for each connection.
+ * buffer & length contains bytes that have been read from the sock
+ * but not yet parsed / processed.
+ *)
+type connection_t =
+{
+ fd : file_descr;
+ mutable buffer : string;
+ mutable length : int;
+}
+
+
+(**
+ * validate_checksum: Compute and compare the checksum of a string
+ * against the provided checksum using the gdb serial protocol algorithm.
+ *
+ *)
+let validate_checksum command checksum =
+ let c0 = ref 0 in
+ for loop = 0 to (String.length command - 1) do
+ c0 := !c0 + int_of_char(command.[loop]);
+ done;
+ if (String.length checksum) = 2
+ then
+ let c1 = Util.int_of_hexchar(checksum.[1]) +
+ Util.int_of_hexchar(checksum.[0]) * 16 in
+ (!c0 mod 256) = (c1 mod 256)
+ else
+ false
+
+
+(**
+ * process_input: Oh, joy! Someone sent us a message. Let's open the
+ * envelope and see what they have to say.
+ *
+ * This function is a paradigm of inefficiency; it performs as many
+ * string copies as possible.
+ *)
+let process_input conn sock =
+ let max_buffer_size = 1024 in
+ let in_string = String.create max_buffer_size in
+
+ let length = read sock in_string 0 max_buffer_size in
+ conn.buffer <- conn.buffer ^ (String.sub in_string 0 length);
+ conn.length <- conn.length + length;
+ let re = Str.regexp "[^\\$]*\\$\\([^#]*\\)#\\(..\\)" in
+
+ begin
+ try
+ let break = String.index conn.buffer '\003' + 1 in
+ print_endline (Printf.sprintf "{{%s}}" (String.escaped conn.buffer));
+
+ (* discard everything seen before the ctrl-c *)
+ conn.buffer <- String.sub conn.buffer break (conn.length - break);
+ conn.length <- conn.length - break;
+
+ (* pause the target *)
+ PDB.pause (PDB.find_context sock);
+
+ (* send a code back to the debugger *)
+ Util.send_reply sock "S05"
+
+ with
+ Not_found -> ()
+ end;
+
+ (* with gdb this is unlikely to loop since you ack each packet *)
+ while ( Str.string_match re conn.buffer 0 ) do
+ let command = Str.matched_group 1 conn.buffer in
+ let checksum = Str.matched_group 2 conn.buffer in
+ let match_end = Str.group_end 2 in
+
+ begin
+ match validate_checksum command checksum with
+ | true ->
+ begin
+ Util.write_character sock '+';
+ try
+ let reply = Debugger.process_command command sock in
+ print_endline (Printf.sprintf "[%s] %s -> \"%s\""
+ (Util.get_connection_info sock)
+ (String.escaped command)
+ (String.escaped reply));
+ Util.send_reply sock reply
+ with
+ Debugger.No_reply ->
+ print_endline (Printf.sprintf "[%s] %s -> null"
+ (Util.get_connection_info sock)
+ (String.escaped command))
+ end
+ | false ->
+ Util.write_character sock '-';
+ end;
+
+ conn.buffer <- String.sub conn.buffer match_end (conn.length - match_end);
+ conn.length <- conn.length - match_end;
+ done;
+ if length = 0 then raise End_of_file
+
+
+
+(** main_server_loop.
+ *
+ * connection_hash is a hash (duh!) with one connection_t for each
+ * open connection.
+ *
+ * in_list is a list of active sockets. it also contains two
+ * magic entries: server_sock for accepting new entries and
+ * event_sock for Xen event channel asynchronous notifications.
+ *)
+let main_server_loop sockaddr =
+ let connection_hash = Hashtbl.create 10
+ in
+ let process_socket svr_sock sockets sock =
+ let (new_list, closed_list) = sockets in
+ if sock == svr_sock
+ then
+ begin
+ let (new_sock, caller) = accept sock in
+ print_endline (Printf.sprintf "[%s] new connection from %s"
+ (Util.get_connection_info sock)
+ (Util.get_connection_info new_sock));
+ Hashtbl.add connection_hash new_sock
+ {fd=new_sock; buffer=""; length = 0};
+ PDB.add_default_context new_sock;
+ (new_sock :: new_list, closed_list)
+ end
+ else
+ begin
+ try
+ match PDB.find_context sock with
+ | PDB.Event_channel ->
+ print_endline (Printf.sprintf "[%s] event channel"
+ (Util.get_connection_info sock));
+ Debugger.process_evtchn sock;
+ (new_list, closed_list)
+ | _ ->
+ let conn = Hashtbl.find connection_hash sock in
+ process_input conn sock;
+ (new_list, closed_list)
+ with
+ | Not_found ->
+ print_endline "error: (main_svr_loop) context not found";
+ PDB.debug_contexts ();
+ raise Not_found
+ | End_of_file ->
+ print_endline (Printf.sprintf "[%s] close connection from %s"
+ (Util.get_connection_info sock)
+ (Util.get_connection_info sock));
+ PDB.delete_context sock;
+ Hashtbl.remove connection_hash sock;
+ close sock;
+ (new_list, sock :: closed_list)
+ end
+ in
+ let rec helper in_list server_sock =
+ (*
+ * List.iter (fun x->Printf.printf "{%s} "
+ * (Util.get_connection_info x)) in_list;
+ * Printf.printf "\n";
+ *)
+ let (rd_list, _, _) = select in_list [] [] (-1.0) in
+ let (new_list, closed_list) = List.fold_left (process_socket server_sock)
+ ([],[]) rd_list in
+ let merge_list = Util.list_remove (new_list @ in_list) closed_list in
+ helper merge_list server_sock
+ in
+ try
+ let server_sock = socket (domain_of_sockaddr sockaddr) SOCK_STREAM 0 in
+ setsockopt server_sock SO_REUSEADDR true;
+ bind server_sock sockaddr;
+ listen server_sock 2;
+
+ PDB.open_debugger ();
+ let event_sock = Evtchn.setup () in
+ PDB.add_context event_sock "event channel" [];
+ helper [server_sock; event_sock] server_sock
+ with
+ | Sys.Break ->
+ print_endline "break: cleaning up";
+ PDB.close_debugger ();
+ Hashtbl.iter (fun sock conn -> close sock) connection_hash
+ | Unix_error(e,err,param) ->
+ Printf.printf "unix error: [%s][%s][%s]\n" (error_message e) err param
+ | Sys_error s -> Printf.printf "sys error: [%s]\n" s
+ | Failure s -> Printf.printf "failure: [%s]\n" s
+ | End_of_file -> Printf.printf "end of file\n"
+
+
+let get_port () =
+ if (Array.length Sys.argv) = 2
+ then
+ int_of_string Sys.argv.(1)
+ else
+ begin
+ print_endline (Printf.sprintf "syntax error: %s <port>" Sys.argv.(0));
+ exit 1
+ end
+
+
+let main =
+ let address = inet_addr_any in
+ let port = get_port () in
+ main_server_loop (ADDR_INET(address, port))
+
diff --git a/tools/firmware/Makefile b/tools/firmware/Makefile
new file mode 100644
index 0000000000..2eeb70baba
--- /dev/null
+++ b/tools/firmware/Makefile
@@ -0,0 +1,34 @@
+XEN_ROOT = ../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+TARGET := vmxassist/vmxloader
+INSTALL_DIR := $(DESTDIR)/usr/lib/xen/boot
+
+SUBDIRS :=
+SUBDIRS += rombios
+SUBDIRS += vgabios
+SUBDIRS += vmxassist
+
+.PHONY: all install clean
+
+all:
+ @set -e; if ! `which bcc 1>/dev/null 2>/dev/null`; then \
+ echo "***********************************************************"; \
+ echo "WARNING: Install dev86 package to build firmware!"; \
+ echo " (http://www.cix.co.uk/~mayday)"; \
+ echo "***********************************************************"; \
+ else \
+ for subdir in $(SUBDIRS); do \
+ $(MAKE) -C $$subdir $@; \
+ done; \
+ fi
+
+
+install: all
+ [ -d $(INSTALL_DIR) ] || install -d -m0755 $(INSTALL_DIR)
+ [ ! -e $(TARGET) ] || install -m0644 $(TARGET) $(INSTALL_DIR)
+
+clean:
+ @set -e; for subdir in $(SUBDIRS); do \
+ $(MAKE) -C $$subdir $@; \
+ done
diff --git a/tools/firmware/README b/tools/firmware/README
new file mode 100644
index 0000000000..0339fa679f
--- /dev/null
+++ b/tools/firmware/README
@@ -0,0 +1,88 @@
+Domain FirmWare support
+-----------------------
+
+One of the key advantages of full virtualization hardware support (such
+as Intel's VT or AMD's Pacifica) is the ability to run unmodified guest
+operating systems. However, since most OSes rely on BIOS support during
+their early bringup, we need to provide a surrogate ROMBIOS and VGABIOS
+firmware layer.
+
+What's more, we need to support real-mode which is required by
+the firmware and bootstrap loaders. Real-mode support is especially
+challenging for Intel's VMX (VT) enabled CPUs where there is no real-mode
+support for VMX guest partitions. In this case you either have to do full
+emulation (full real-mode emulator; more complete but potentially slower)
+or partial emulation (use the VM8086 extensions, emulate only those
+instructions that are missing; faster, but potentially incomplete). The
+vmxassist code in this subdirectory uses the later approach because it
+is smaller and faster.
+
+The approach is relatively straight forward. Vmxloader contains three
+payloads (rombios, vgabios and vmxassist) and it is bootstrapped as any
+other 32-bit OS. Vmxloader copies its payloads to the addresses below
+and transfers control to vmxassist.
+
+ vgabios VGABIOS (standard and Cirrus).
+ Resides at C000:0000.
+
+ vmxassist VMXAssist VM86 realmode emulator for VMX.
+ Resides at D000:0000.
+
+ rombios ROMBIOS code. Derived from Bochs.
+ Resides at F000:0000
+
+Vmxassist first sets up it own world (GDT, IDT, TR, etc), enables
+VM8086 and then transfers control to F000:FFF0 and executes 16-bit
+code. Unsupported instructions cause a general protection failure at
+which point vmxassist kicks in and emulates the offending instruction.
+Whever the emulated code transitions to 32-bit protected mode, vmxassist
+will go away. Whenever 32-bit protected code transitions to real-mode,
+Xen/VMX will detect this and transfer control to vmxassist.
+
+Most of the vmxassist complexity comes from properly handling the
+real to protected mode and protected to real mode transitions and
+the proper emulation of the segment registers. Even though the Intel
+manual clearly states that you should immediately perform a jmp far
+after a mode transition, many operating systems execute additional
+instructions and some even refer to segment selectors and pop data
+from the stack. Vmxassist contains a number of work arounds for these
+OSes.
+
+
+Acknowledgements
+----------------
+
+The rombios was taken (largely unmodified) from Bochs, which was written
+by Kevin Lawton. The VGABIOS was written by Christophe Bothamy. Arun Sharma,
+Asit Mallick and Nitin Kamble (Intel) provided the E820 patches and lots
+of useful feedback.
+
+
+Contact
+-------
+
+Leendert van Doorn
+IBM T.J. Watson Research Center
+19 Skyline Drive
+Hawthorne, NY 10532
+leendert@watson.ibm.com
+
+
+Tested Operating Systems
+------------------------
+
+Since vmxassist uses partial emulation, it may always miss opcodes
+that are required by a particular OS. The table below lists the OSes
+I have tried. The Install column indicates a full CD/DVD install into
+a VMX partition. The Disk column indicates booting from prefabricated
+disk image.
+
+Operating System Install Disk
+------------------------------------------------------------
+RedHat Enterprise Linux (RHEL3_U5) Yes Yes
+Fedora Code (FC3) (-) Yes
+FreeBSD 5.3 (-) Yes
+MS-DOS 5.0 (-) Yes
+
+(-) not tried yet
+
diff --git a/tools/firmware/rombios/Makefile b/tools/firmware/rombios/Makefile
new file mode 100644
index 0000000000..0624e81e96
--- /dev/null
+++ b/tools/firmware/rombios/Makefile
@@ -0,0 +1,58 @@
+BIOS_BUILDS = BIOS-bochs-latest
+#BIOS_BUILDS += BIOS-bochs-2-processors
+#BIOS_BUILDS += BIOS-bochs-4-processors
+#BIOS_BUILDS += BIOS-bochs-8-processors
+
+all: bios
+
+bios: biossums ${BIOS_BUILDS}
+
+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
+
+BIOS-bochs-2-processors: rombios.c biossums
+ gcc -DBX_SMP_PROCESSORS=2 -E -P $< > _rombios2_.c
+ bcc -o rombios2.s -C-c -D__i86__ -0 -S _rombios2_.c
+ sed -e 's/^\.text//' -e 's/^\.data//' rombios2.s > _rombios2_.s
+ as86 _rombios2_.s -b tmp2.bin -u- -w- -g -0 -j -O -l rombios2.txt
+ -perl makesym.perl < rombios2.txt > rombios2.sym
+ mv tmp2.bin BIOS-bochs-2-processors
+ ./biossums BIOS-bochs-2-processors
+ rm -f _rombios2_.s
+
+BIOS-bochs-4-processors: rombios.c biossums
+ gcc -DBX_SMP_PROCESSORS=4 -E -P $< > _rombios4_.c
+ bcc -o rombios4.s -C-c -D__i86__ -0 -S _rombios4_.c
+ sed -e 's/^\.text//' -e 's/^\.data//' rombios4.s > _rombios4_.s
+ as86 _rombios4_.s -b tmp4.bin -u- -w- -g -0 -j -O -l rombios4.txt
+ -perl makesym.perl < rombios4.txt > rombios4.sym
+ mv tmp4.bin BIOS-bochs-4-processors
+ ./biossums BIOS-bochs-4-processors
+ rm -f _rombios4_.s
+
+BIOS-bochs-8-processors: rombios.c biossums
+ gcc -DBX_SMP_PROCESSORS=8 -E -P $< > _rombios8_.c
+ bcc -o rombios8.s -C-c -D__i86__ -0 -S _rombios8_.c
+ sed -e 's/^\.text//' -e 's/^\.data//' rombios8.s > _rombios8_.s
+ as86 _rombios8_.s -b tmp8.bin -u- -w- -g -0 -j -O -l rombios8.txt
+ -perl makesym.perl < rombios8.txt > rombios8.sym
+ mv tmp8.bin BIOS-bochs-8-processors
+ ./biossums BIOS-bochs-8-processors
+ rm -f _rombios8_.s
+
+biossums: biossums.c
+ gcc -o biossums biossums.c
+
diff --git a/tools/firmware/rombios/apmbios.S b/tools/firmware/rombios/apmbios.S
new file mode 100644
index 0000000000..d8ac160848
--- /dev/null
+++ b/tools/firmware/rombios/apmbios.S
@@ -0,0 +1,329 @@
+// 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(07)
+ jmp APMSYM(ok)
+
+;-----------------
+; APM Set Power State
+APMSYM(07):
+ cmp al, #0x07
+ jne APMSYM(0a)
+
+ 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)
+
+;-----------------
+; 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(unimplemented)
+
+ mov ah, #1
+ mov al, #2
+
+ jmp APMSYM(ok)
+
+;-----------------
+APMSYM(ok):
+ popf
+ clc
+#if defined(APM_REAL)
+ jmp iret_modify_cf
+#else
+ retf
+#endif
+APMSYM(unimplemented):
+APMSYM(error):
+ popf
+ stc
+#if defined(APM_REAL)
+ jmp iret_modify_cf
+#else
+ retf
+#endif
+
+#undef APM_PROT32
+#undef APM_PROT16
+#undef APM_REAL
+#undef APMSYM
diff --git a/tools/firmware/rombios/biossums.c b/tools/firmware/rombios/biossums.c
new file mode 100644
index 0000000000..be12e49f35
--- /dev/null
+++ b/tools/firmware/rombios/biossums.c
@@ -0,0 +1,478 @@
+/* biossums.c --- written by Eike W. */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+typedef unsigned char byte;
+
+void check( int value, char* message );
+
+#define LEN_BIOS_DATA 0x10000
+#define MAX_OFFSET (LEN_BIOS_DATA - 1)
+
+
+#define BIOS_OFFSET 0xFFFF
+
+long chksum_bios_get_offset( byte* data, long offset );
+byte chksum_bios_calc_value( byte* data, long offset );
+byte chksum_bios_get_value( byte* data, long offset );
+void chksum_bios_set_value( byte* data, long offset, byte value );
+
+
+#define _32__LEN 9
+#define _32__CHKSUM 10
+
+#define _32__MINHDR 16
+
+long chksum__32__get_offset( byte* data, long offset );
+byte chksum__32__calc_value( byte* data, long offset );
+byte chksum__32__get_value( byte* data, long offset );
+void chksum__32__set_value( byte* data, long offset, byte value );
+
+
+#define _MP__LEN 8
+#define _MP__CHKSUM 10
+
+#define _MP__MINHDR 16
+
+long chksum__mp__get_offset( byte* data, long offset );
+byte chksum__mp__calc_value( byte* data, long offset );
+byte chksum__mp__get_value( byte* data, long offset );
+void chksum__mp__set_value( byte* data, long offset, byte value );
+
+
+#define PCMP_BASELEN 4
+#define PCMP_CHKSUM 7
+#define PCMP_EXT_LEN 40
+#define PCMP_EXT_CHKSUM 42
+
+#define PCMP_MINHDR 42
+
+long chksum_pcmp_get_offset( byte* data, long offset );
+byte chksum_pcmp_calc_value( byte* data, long offset );
+byte chksum_pcmp_get_value( byte* data, long offset );
+void chksum_pcmp_set_value( byte* data, long offset, byte value );
+
+
+#define _PIR_LEN 6
+#define _PIR_CHKSUM 31
+
+#define _PIR_MINHDR 32
+
+long chksum__pir_get_offset( byte *data, long offset );
+byte chksum__pir_calc_value( byte* data, long offset );
+byte chksum__pir_get_value( byte* data, long offset );
+void chksum__pir_set_value( byte* data, long offset, byte value );
+
+
+byte bios_data[LEN_BIOS_DATA];
+
+
+int main( int argc, char* argv[] ) {
+
+ FILE* stream;
+ long offset, tmp_offset;
+ byte cur_val = 0, new_val = 0;
+ int hits;
+
+
+ if( argc != 2 ) {
+ printf( "Error. Need a file-name as an argument.\n" );
+ exit( EXIT_FAILURE );
+ }
+
+ if(( stream = fopen( argv[1], "rb" )) == NULL ) {
+ printf( "Error opening %s for reading.\n", argv[1] );
+ exit( EXIT_FAILURE );
+ }
+ if( fread( bios_data, 1, LEN_BIOS_DATA, stream ) < LEN_BIOS_DATA ) {
+ printf( "Error reading 64KBytes from %s.\n", argv[1] );
+ fclose( stream );
+ exit( EXIT_FAILURE );
+ }
+ fclose( stream );
+
+ hits = 0;
+ offset = 0L;
+ while( (tmp_offset = chksum__32__get_offset( bios_data, offset )) != -1L ) {
+ offset = tmp_offset;
+ cur_val = chksum__32__get_value( bios_data, offset );
+ new_val = chksum__32__calc_value( bios_data, offset );
+ printf( "\n\nPCI-Bios header at: 0x%4lX\n", offset );
+ printf( "Current checksum: 0x%02X\n", cur_val );
+ printf( "Calculated checksum: 0x%02X ", new_val );
+ hits++;
+ }
+ if( hits == 1 && cur_val != new_val ) {
+ printf( "Setting checksum." );
+ chksum__32__set_value( bios_data, offset, new_val );
+ }
+ if( hits >= 2 ) {
+ printf( "Multiple PCI headers! No checksum set." );
+ }
+ if( hits ) {
+ printf( "\n" );
+ }
+
+
+ hits = 0;
+ offset = 0L;
+ while( (tmp_offset = chksum__mp__get_offset( bios_data, offset )) != -1L ) {
+ offset = tmp_offset;
+ cur_val = chksum__mp__get_value( bios_data, offset );
+ new_val = chksum__mp__calc_value( bios_data, offset );
+ printf( "\n\nMP header at: 0x%4lX\n", offset );
+ printf( "Current checksum: 0x%02X\n", cur_val );
+ printf( "Calculated checksum: 0x%02X ", new_val );
+ hits++;
+ }
+ if( hits == 1 && cur_val != new_val ) {
+ printf( "Setting checksum." );
+ chksum__mp__set_value( bios_data, offset, new_val );
+ }
+ if( hits >= 2 ) {
+ printf( "Warning! Multiple MP headers. No checksum set." );
+ }
+ if( hits ) {
+ printf( "\n" );
+ }
+
+
+ hits = 0;
+ offset = 0L;
+ while( (tmp_offset = chksum_pcmp_get_offset( bios_data, offset )) != -1L ) {
+ offset = tmp_offset;
+ cur_val = chksum_pcmp_get_value( bios_data, offset );
+ new_val = chksum_pcmp_calc_value( bios_data, offset );
+ printf( "\n\nPCMP header at: 0x%4lX\n", offset );
+ printf( "Current checksum: 0x%02X\n", cur_val );
+ printf( "Calculated checksum: 0x%02X ", new_val );
+ hits++;
+ }
+ if( hits == 1 && cur_val != new_val ) {
+ printf( "Setting checksum." );
+ chksum_pcmp_set_value( bios_data, offset, new_val );
+ }
+ if( hits >= 2 ) {
+ printf( "Warning! Multiple PCMP headers. No checksum set." );
+ }
+ if( hits ) {
+ printf( "\n" );
+ }
+
+
+ hits = 0;
+ offset = 0L;
+ while( (tmp_offset = chksum__pir_get_offset( bios_data, offset )) != -1L ) {
+ offset = tmp_offset;
+ cur_val = chksum__pir_get_value( bios_data, offset );
+ new_val = chksum__pir_calc_value( bios_data, offset );
+ printf( "\n\n$PIR header at: 0x%4lX\n", offset );
+ printf( "Current checksum: 0x%02X\n", cur_val );
+ printf( "Calculated checksum: 0x%02X\n ", new_val );
+ hits++;
+ }
+ if( hits == 1 && cur_val != new_val ) {
+ printf( "Setting checksum." );
+ chksum__pir_set_value( bios_data, offset, new_val );
+ }
+ if( hits >= 2 ) {
+ printf( "Warning! Multiple $PIR headers. No checksum set." );
+ }
+ if( hits ) {
+ printf( "\n" );
+ }
+
+
+ offset = 0L;
+ offset = chksum_bios_get_offset( bios_data, offset );
+ cur_val = chksum_bios_get_value( bios_data, offset );
+ new_val = chksum_bios_calc_value( bios_data, offset );
+ printf( "\n\nBios checksum at: 0x%4lX\n", offset );
+ printf( "Current checksum: 0x%02X\n", cur_val );
+ printf( "Calculated checksum: 0x%02X ", new_val );
+ if( cur_val != new_val ) {
+ printf( "Setting checksum." );
+ chksum_bios_set_value( bios_data, offset, new_val );
+ }
+ printf( "\n" );
+
+
+ if(( stream = fopen( argv[1], "wb" )) == NULL ) {
+ printf( "Error opening %s for writing.\n", argv[1] );
+ exit( EXIT_FAILURE );
+ }
+ if( fwrite( bios_data, 1, LEN_BIOS_DATA, stream ) < LEN_BIOS_DATA ) {
+ printf( "Error writing 64KBytes to %s.\n", argv[1] );
+ fclose( stream );
+ exit( EXIT_FAILURE );
+ }
+ fclose( stream );
+
+ return( EXIT_SUCCESS );
+}
+
+
+void check( int okay, char* message ) {
+
+ if( !okay ) {
+ printf( "\n\nError. %s.\n", message );
+ exit( EXIT_FAILURE );
+ }
+}
+
+
+long chksum_bios_get_offset( byte* data, long offset ) {
+
+ return( BIOS_OFFSET );
+}
+
+
+byte chksum_bios_calc_value( byte* data, long offset ) {
+
+ int i;
+ byte sum;
+
+ sum = 0;
+ for( i = 0; i < MAX_OFFSET; i++ ) {
+ sum = sum + *( data + i );
+ }
+ sum = -sum; /* iso ensures -s + s == 0 on unsigned types */
+ return( sum );
+}
+
+
+byte chksum_bios_get_value( byte* data, long offset ) {
+
+ return( *( data + BIOS_OFFSET ) );
+}
+
+
+void chksum_bios_set_value( byte* data, long offset, byte value ) {
+
+ *( data + BIOS_OFFSET ) = value;
+}
+
+
+byte chksum__32__calc_value( byte* data, long offset ) {
+
+ int i;
+ int len;
+ byte sum;
+
+ check( offset + _32__MINHDR <= MAX_OFFSET, "_32_ header out of bounds" );
+ len = *( data + offset + _32__LEN ) << 4;
+ check( offset + len <= MAX_OFFSET, "_32_ header-length out of bounds" );
+ sum = 0;
+ for( i = 0; i < len; i++ ) {
+ if( i != _32__CHKSUM ) {
+ sum = sum + *( data + offset + i );
+ }
+ }
+ sum = -sum;
+ return( sum );
+}
+
+
+long chksum__32__get_offset( byte* data, long offset ) {
+
+ long result = -1L;
+
+ offset = offset + 0x0F;
+ offset = offset & ~( 0x0F );
+ while( offset + 16 < MAX_OFFSET ) {
+ offset = offset + 16;
+ if( *( data + offset + 0 ) == '_' && \
+ *( data + offset + 1 ) == '3' && \
+ *( data + offset + 2 ) == '2' && \
+ *( data + offset + 3 ) == '_' ) {
+ result = offset;
+ break;
+ }
+ }
+ return( result );
+}
+
+
+byte chksum__32__get_value( byte* data, long offset ) {
+
+ check( offset + _32__CHKSUM <= MAX_OFFSET, "PCI-Bios checksum out of bounds" );
+ return( *( data + offset + _32__CHKSUM ) );
+}
+
+
+void chksum__32__set_value( byte* data, long offset, byte value ) {
+
+ check( offset + _32__CHKSUM <= MAX_OFFSET, "PCI-Bios checksum out of bounds" );
+ *( data + offset + _32__CHKSUM ) = value;
+}
+
+
+byte chksum__mp__calc_value( byte* data, long offset ) {
+
+ int i;
+ int len;
+ byte sum;
+
+ check( offset + _MP__MINHDR <= MAX_OFFSET, "_MP_ header out of bounds" );
+ len = *( data + offset + _MP__LEN ) << 4;
+ check( offset + len <= MAX_OFFSET, "_MP_ header-length out of bounds" );
+ sum = 0;
+ for( i = 0; i < len; i++ ) {
+ if( i != _MP__CHKSUM ) {
+ sum = sum + *( data + offset + i );
+ }
+ }
+ sum = -sum;
+ return( sum );
+}
+
+
+long chksum__mp__get_offset( byte* data, long offset ) {
+
+ long result = -1L;
+
+ offset = offset + 0x0F;
+ offset = offset & ~( 0x0F );
+ while( offset + 16 < MAX_OFFSET ) {
+ offset = offset + 16;
+ if( *( data + offset + 0 ) == '_' && \
+ *( data + offset + 1 ) == 'M' && \
+ *( data + offset + 2 ) == 'P' && \
+ *( data + offset + 3 ) == '_' ) {
+ result = offset;
+ break;
+ }
+ }
+ return( result );
+}
+
+
+byte chksum__mp__get_value( byte* data, long offset ) {
+
+ check( offset + _MP__CHKSUM <= MAX_OFFSET, "MP checksum out of bounds" );
+ return( *( data + offset + _MP__CHKSUM ) );
+}
+
+
+void chksum__mp__set_value( byte* data, long offset, byte value ) {
+
+ check( offset + _MP__CHKSUM <= MAX_OFFSET, "MP checksum out of bounds" );
+ *( data + offset + _MP__CHKSUM ) = value;
+}
+
+
+byte chksum_pcmp_calc_value( byte* data, long offset ) {
+
+ int i;
+ int len;
+ byte sum;
+
+ check( offset + PCMP_MINHDR <= MAX_OFFSET, "PCMP header out of bounds" );
+ len = *( data + offset + PCMP_BASELEN ) + \
+ ( *( data + offset + PCMP_BASELEN + 1 ) << 8 );
+ check( offset + len <= MAX_OFFSET, "PCMP header-length out of bounds" );
+ if( *( data + offset + PCMP_EXT_LEN ) | \
+ *( data + offset + PCMP_EXT_LEN + 1 ) | \
+ *( data + offset + PCMP_EXT_CHKSUM ) ) {
+ check( 0, "PCMP header indicates extended tables (unsupported)" );
+ }
+ sum = 0;
+ for( i = 0; i < len; i++ ) {
+ if( i != PCMP_CHKSUM ) {
+ sum = sum + *( data + offset + i );
+ }
+ }
+ sum = -sum;
+ return( sum );
+}
+
+
+long chksum_pcmp_get_offset( byte* data, long offset ) {
+
+ long result = -1L;
+
+ offset = offset + 0x0F;
+ offset = offset & ~( 0x0F );
+ while( offset + 16 < MAX_OFFSET ) {
+ offset = offset + 16;
+ if( *( data + offset + 0 ) == 'P' && \
+ *( data + offset + 1 ) == 'C' && \
+ *( data + offset + 2 ) == 'M' && \
+ *( data + offset + 3 ) == 'P' ) {
+ result = offset;
+ break;
+ }
+ }
+ return( result );
+}
+
+
+byte chksum_pcmp_get_value( byte* data, long offset ) {
+
+ check( offset + PCMP_CHKSUM <= MAX_OFFSET, "PCMP checksum out of bounds" );
+ return( *( data + offset + PCMP_CHKSUM ) );
+}
+
+
+void chksum_pcmp_set_value( byte* data, long offset, byte value ) {
+
+ check( offset + PCMP_CHKSUM <= MAX_OFFSET, "PCMP checksum out of bounds" );
+ *( data + offset + PCMP_CHKSUM ) = value;
+}
+
+
+byte chksum__pir_calc_value( byte* data, long offset ) {
+
+ int i;
+ int len;
+ byte sum;
+
+ check( offset + _PIR_MINHDR <= MAX_OFFSET, "$PIR header out of bounds" );
+ len = *( data + offset + _PIR_LEN ) + \
+ ( *( data + offset + _PIR_LEN + 1 ) << 8 );
+ check( offset + len <= MAX_OFFSET, "$PIR header-length out of bounds" );
+ sum = 0;
+ for( i = 0; i < len; i++ ) {
+ if( i != _PIR_CHKSUM ) {
+ sum = sum + *( data + offset + i );
+ }
+ }
+ sum = -sum;
+ return( sum );
+}
+
+
+long chksum__pir_get_offset( byte* data, long offset ) {
+
+ long result = -1L;
+
+ offset = offset + 0x0F;
+ offset = offset & ~( 0x0F );
+ while( offset + 16 < MAX_OFFSET ) {
+ offset = offset + 16;
+ if( *( data + offset + 0 ) == '$' && \
+ *( data + offset + 1 ) == 'P' && \
+ *( data + offset + 2 ) == 'I' && \
+ *( data + offset + 3 ) == 'R' ) {
+ result = offset;
+ break;
+ }
+ }
+ return( result );
+}
+
+
+byte chksum__pir_get_value( byte* data, long offset ) {
+
+ check( offset + _PIR_CHKSUM <= MAX_OFFSET, "$PIR checksum out of bounds" );
+ return( *( data + offset + _PIR_CHKSUM ) );
+}
+
+
+void chksum__pir_set_value( byte* data, long offset, byte value ) {
+
+ check( offset + _PIR_CHKSUM <= MAX_OFFSET, "$PIR checksum out of bounds" );
+ *( data + offset + _PIR_CHKSUM ) = value;
+}
+
diff --git a/tools/firmware/rombios/makesym.perl b/tools/firmware/rombios/makesym.perl
new file mode 100755
index 0000000000..df604e2ae4
--- /dev/null
+++ b/tools/firmware/rombios/makesym.perl
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+#
+# $Id: makesym.perl,v 1.1 2002/11/24 22:45:40 bdenney Exp $
+#
+# Read output file from as86 (e.g. rombios.txt) and write out a symbol
+# table suitable for the Bochs debugger.
+#
+
+$WHERE_BEFORE_SYM_TABLE = 0;
+$WHERE_IN_SYM_TABLE = 1;
+$WHERE_AFTER_SYM_TABLE = 2;
+
+$where = $WHERE_BEFORE_SYM_TABLE;
+while (<STDIN>) {
+ chop;
+ if ($where == WHERE_BEFORE_SYM_TABLE && /^Symbols:/) {
+ $where = $WHERE_IN_SYM_TABLE;
+ } elsif ($where == $WHERE_IN_SYM_TABLE && /^$/) {
+ $where = $WHERE_AFTER_SYM_TABLE;
+ }
+ if ($where == $WHERE_IN_SYM_TABLE) {
+ @F = split (/\s+/);
+ ($name[0], $junk, $addr[0], $junk, $name[1], $junk, $addr[1]) = @F;
+ foreach $col (0,1) {
+ next if length $addr[$col] < 1;
+ $addr[$col] =~ tr/A-Z/a-z/;
+ $addr[$col] = "000f" . $addr[$col];
+ print "$addr[$col] $name[$col]\n";
+ }
+ }
+}
diff --git a/tools/firmware/rombios/rombios.c b/tools/firmware/rombios/rombios.c
new file mode 100644
index 0000000000..c3605ac71e
--- /dev/null
+++ b/tools/firmware/rombios/rombios.c
@@ -0,0 +1,10825 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: rombios.c,v 1.138 2005/05/07 15:55:26 vruppert 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 VMXASSIST
+
+// 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 VMXASSIST
+# define BX_APPNAME "VMXAssist"
+#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.138 $";
+static char bios_date_string[] = "$Date: 2005/05/07 15:55:26 $";
+
+static char CVSID[] = "$Id: rombios.c,v 1.138 2005/05/07 15:55:26 vruppert 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()
+{
+ 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 VMXASSIST
+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 /* VMXASSIST */
+
+#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 VMXASSIST
+ 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;
+
+ /* ------------------- 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 */
+ if ((inb(0x60) != 0xfa)) {
+ 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);
+}
+
+//--------------------------------------------------------------------------
+// keyboard_panic
+//--------------------------------------------------------------------------
+ void
+keyboard_panic(status)
+ Bit16u status;
+{
+ // If you're getting a 993 keyboard panic here,
+ // please see the comment in keyboard_init
+
+ 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(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;
+
+ // 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;
+
+ //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;
+ mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
+ 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;
+
+ //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;
+ mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
+ 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);
+
+ // 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)
+ {
+#ifdef VMXASSIST
+ 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:
+ 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
+
+;; 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 VMXASSIST
+ 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
+#ifdef VMXASSIST
+ ;; The vm86 emulator expects interrupts to be mapped beyond the reserved
+ ;; vectors (0 through 31). Since rombios fully controls the hardware, we
+ ;; map it the way the emulator needs it and expect that it will do the
+ ;; proper 8086 interrupt translation (that is, master pic base is at 0x8
+ ;; and slave pic base is at 0x70).
+ mov al, #0x20
+ out 0x21, al
+ mov al, #0x28
+ out 0xa1, al
+#else
+ mov al, #0x08
+ out 0x21, al
+ mov al, #0x70
+ out 0xa1, al
+#endif
+ 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 VMXASSIST
+ call _copy_e820_table
+#endif
+
+ call pcibios_init
+
+ 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
+
+.org 0xfff0 ; Power-up Entry Point
+ jmp 0xf000:post
+
+.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,
+};
+
+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
diff --git a/tools/firmware/rombios/rombios.diffs b/tools/firmware/rombios/rombios.diffs
new file mode 100644
index 0000000000..8ec23ef9de
--- /dev/null
+++ b/tools/firmware/rombios/rombios.diffs
@@ -0,0 +1,206 @@
+--- /home/leendert/cvs/bochs/bios/rombios.c 2005-05-23 12:18:11.000000000 -0400
++++ rombios.c 2005-06-01 23:46:45.000000000 -0400
+@@ -26,6 +26,7 @@
+
+ // ROM BIOS for use with Bochs/Plex x86 emulation environment
+
++#define VMXASSIST
+
+ // ROM BIOS compatability entry points:
+ // ===================================
+@@ -170,7 +171,9 @@
+ #define BASE_MEM_IN_K (640 - EBDA_SIZE)
+
+ // Define the application NAME
+-#ifdef PLEX86
++#ifdef VMXASSIST
++# define BX_APPNAME "VMXAssist"
++#elif PLEX86
+ # define BX_APPNAME "Plex86"
+ #else
+ # define BX_APPNAME "Bochs"
+@@ -314,7 +317,6 @@
+ ASM_END
+ }
+
+-#if 0
+ // memcpy of count bytes
+ void
+ memcpyb(dseg,doffset,sseg,soffset,count)
+@@ -362,6 +364,7 @@
+ ASM_END
+ }
+
++#if 0
+ // memcpy of count dword
+ void
+ memcpyd(dseg,doffset,sseg,soffset,count)
+@@ -858,6 +861,7 @@
+ 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();
+@@ -1420,6 +1424,16 @@
+ ASM_END
+ }
+
++#ifdef VMXASSIST
++void
++copy_e820_table()
++{
++ Bit8u nr_entries = read_byte(0x9000, 0x1e8);
++ write_word(0xe000, 0x8, nr_entries);
++ memcpyb(0xe000, 0x10, 0x9000, 0x2d0, nr_entries * 0x14);
++}
++#endif /* VMXASSIST */
++
+ #if BX_DEBUG_SERIAL
+ /* serial debug port*/
+ #define BX_DEBUG_PORT 0x03f8
+@@ -1498,6 +1512,9 @@
+ if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
+ uart_tx_byte(BX_DEBUG_PORT, c);
+ #endif
++#ifdef VMXASSIST
++ 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);
+@@ -4053,6 +4070,66 @@
+ case 0x20: // coded by osmaker aka K.J.
+ if(regs.u.r32.edx == 0x534D4150)
+ {
++#ifdef VMXASSIST
++ 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:
+@@ -4070,6 +4147,7 @@
+ 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();
+@@ -4121,6 +4199,7 @@
+ goto int15_unimplemented;
+ break;
+ }
++#endif
+ } else {
+ // if DX != 0x534D4150)
+ goto int15_unimplemented;
+@@ -9497,9 +9576,16 @@
+ ;; int 1C already points at dummy_iret_handler (above)
+ mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
+ out 0x43, al
++#ifdef VMXASSIST
++ 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)
+@@ -9597,10 +9683,22 @@
+ mov al, #0x11 ; send initialisation commands
+ out 0x20, al
+ out 0xa0, al
++#ifdef VMXASSIST
++ ;; The vm86 emulator expects interrupts to be mapped beyond the reserved
++ ;; vectors (0 through 31). Since rombios fully controls the hardware, we
++ ;; map it the way the emulator needs it and expect that it will do the
++ ;; proper 8086 interrupt translation (that is, master pic base is at 0x8
++ ;; and slave pic base is at 0x70).
++ mov al, #0x20
++ out 0x21, al
++ mov al, #0x28
++ out 0xa1, al
++#else
+ mov al, #0x08
+ out 0x21, al
+ mov al, #0x70
+ out 0xa1, al
++#endif
+ mov al, #0x04
+ out 0x21, al
+ mov al, #0x02
+@@ -9617,6 +9715,10 @@
+ #endif
+ out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
+
++#ifdef VMXASSIST
++ call _copy_e820_table
++#endif
++
+ call pcibios_init
+
+ call rom_scan
diff --git a/tools/firmware/vgabios/BUGS b/tools/firmware/vgabios/BUGS
new file mode 100644
index 0000000000..2bf3b062e9
--- /dev/null
+++ b/tools/firmware/vgabios/BUGS
@@ -0,0 +1,3 @@
+Not all the functions have been implemented yet.
+
+Please report any bugs to <info@vruppert.de>
diff --git a/tools/firmware/vgabios/COPYING b/tools/firmware/vgabios/COPYING
new file mode 100644
index 0000000000..223ede7de3
--- /dev/null
+++ b/tools/firmware/vgabios/COPYING
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/tools/firmware/vgabios/ChangeLog b/tools/firmware/vgabios/ChangeLog
new file mode 100644
index 0000000000..08711f0c60
--- /dev/null
+++ b/tools/firmware/vgabios/ChangeLog
@@ -0,0 +1,1060 @@
+2005-05-24 16:50 vruppert
+
+ * vbe.c (1.47), vgabios.c (1.61):
+
+ - output to the vgabios info port can be disabled now. It is still enabled by
+ default and always possible in debug mode. (based on a patch from Alex Beregszaszi)
+
+2005-05-20 16:06 vruppert
+
+ * vbe.c (1.46), vgabios.c (1.60):
+
+ - fixed return value for the default case in the VBE section (non-debug mode)
+ - removed unused macros HALT and PANIC_PORT
+
+2005-03-07 20:39 vruppert
+
+ * README (1.9):
+
+ - updates for 0.5a release
+
+2005-03-06 13:06 vruppert
+
+ * Makefile (1.17):
+
+ - vgabios files with cirrus support added to release target
+
+2005-03-06 12:24 vruppert
+
+ * Makefile (1.16):
+
+ - cross compilation support added (patch from Alex Beregszaszi)
+
+2005-03-05 13:03 vruppert
+
+ * BUGS (1.3), README (1.8), TODO (1.11):
+
+ - documentation updates
+
+2004-12-04 15:26 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.61), VGABIOS-lgpl-latest.cirrus.bin
+ (1.13), VGABIOS-lgpl-latest.cirrus.debug.bin (1.13),
+ VGABIOS-lgpl-latest.debug.bin (1.61), clext.c (1.9):
+
+ - Cirrus extension: support for 1280x1024x15 and 1280x1024x16 modes added (patch
+ from Fabrice Bellard)
+
+2004-08-08 16:53 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.60), VGABIOS-lgpl-latest.cirrus.bin (1.12),
+ VGABIOS-lgpl-latest.cirrus.debug.bin (1.12),
+ VGABIOS-lgpl-latest.debug.bin (1.60), clext.c (1.8):
+
+ - use single bank mode for VBE
+ - enable 16k granularity for VBE only
+
+2004-07-30 19:33 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.59), VGABIOS-lgpl-latest.cirrus.bin (1.11),
+ VGABIOS-lgpl-latest.cirrus.debug.bin (1.11),
+ VGABIOS-lgpl-latest.debug.bin (1.59), clext.c (1.7):
+
+ - cirrus init: set standard vga mode and reset bitblt
+
+2004-07-22 18:38 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.58), VGABIOS-lgpl-latest.cirrus.bin (1.10),
+ VGABIOS-lgpl-latest.cirrus.debug.bin (1.10),
+ VGABIOS-lgpl-latest.debug.bin (1.58), clext.c (1.6), vbe.c (1.45),
+ vbetables.h (1.24):
+
+ - cirrus extension: tables for mode 1280x1024x8 added
+ - vbe: dispi_set_xres() and dispi_set_virt_width() now modify vga compatible
+ registers
+ - vbe: mode list entry for mode 800x600x4 fixed
+
+2004-07-18 20:23 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.57), VGABIOS-lgpl-latest.cirrus.bin (1.9),
+ VGABIOS-lgpl-latest.cirrus.debug.bin (1.9),
+ VGABIOS-lgpl-latest.debug.bin (1.57), vgabios.c (1.59), vgatables.h (1.8):
+
+ - disable CRTC write protection before setting new values
+ - CRTC line for mode 0x6a fixed
+
+2004-07-07 16:08 vruppert
+
+ * Makefile (1.15), VGABIOS-lgpl-latest.bin (1.56),
+ VGABIOS-lgpl-latest.cirrus.bin (1.8), VGABIOS-lgpl-latest.cirrus.debug.bin (1.8),
+ VGABIOS-lgpl-latest.debug.bin (1.56), biossums.c (1.1), clext.c (1.5):
+
+ - biossums utility for the Bochs BIOS adapted for the LGPL'd VGABIOS
+ - VESA3 PMINFO checksum calculated in the source
+ - 24 bpp mode entries fixed (patch from Fabrice Bellard)
+
+2004-06-25 18:28 vruppert
+
+ * VGABIOS-lgpl-latest.cirrus.bin (1.7), VGABIOS-lgpl-latest.cirrus.debug.bin (1.7),
+ clext.c (1.4):
+
+ - 4MB memory probe added (patch from Fabrice Bellard)
+
+2004-06-25 17:31 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.55), VGABIOS-lgpl-latest.cirrus.bin (1.6),
+ VGABIOS-lgpl-latest.cirrus.debug.bin (1.6),
+ VGABIOS-lgpl-latest.debug.bin (1.55), clext.c (1.3):
+
+ - fixed value of sequencer reset register in cirrus mode table
+ - fixed possible overflow error if cirrus start address is >256k
+
+2004-06-23 21:11 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.54), VGABIOS-lgpl-latest.cirrus.bin (1.5),
+ VGABIOS-lgpl-latest.cirrus.debug.bin (1.5),
+ VGABIOS-lgpl-latest.debug.bin (1.54), clext.c (1.2):
+
+ - applied new patch for the cirrus extension from suzu
+ * enable VESA LFB support if a Cirrus PCI adapter is detected
+ * prepared VBE3 protected mode info block (test case required)
+ - added VBE functions 4F06h and 4F07h
+ - some bugfixes
+
+2004-06-17 18:57 vruppert
+
+ * Makefile (1.14), VGABIOS-lgpl-latest.bin (1.53),
+ VGABIOS-lgpl-latest.cirrus.bin (1.2), VGABIOS-lgpl-latest.cirrus.debug.bin (1.2),
+ VGABIOS-lgpl-latest.debug.bin (1.53):
+
+ - fixed makefile targets for the binaries with cirrus extension
+
+2004-06-16 21:11 vruppert
+
+ * Makefile (1.13), VGABIOS-lgpl-latest.bin (1.52),
+ VGABIOS-lgpl-latest.cirrus.bin (1.1), VGABIOS-lgpl-latest.cirrus.debug.bin (1.1),
+ VGABIOS-lgpl-latest.debug.bin (1.52), clext.c (1.1), vgabios.c (1.58):
+
+ - applied suzu's cirrus extension patch. Cirrus SVGA detection, most of the
+ cirrus-specific modes and some basic VBE features are present now.
+
+2004-05-31 21:15 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.51), VGABIOS-lgpl-latest.debug.bin (1.51),
+ vgabios.c (1.57):
+
+ - write character in planar graphics modes: sequencer map mask must be 0x0f and
+ bit operation must be 'replace' if bit 7 of attribute is clear
+ - read/write pixel in planar graphics modes: bit mask setup simplified
+
+2004-05-11 18:08 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.50), VGABIOS-lgpl-latest.debug.bin (1.50),
+ vgabios.c (1.56):
+
+ - biosfn_select_vert_res rewritten in assembler
+ - scroll text in planar graphics modes: attribute for blank line fixed
+ - write character in planar graphics modes: graphics controller values fixed
+
+2004-05-09 20:32 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.49), VGABIOS-lgpl-latest.debug.bin (1.49),
+ vbe.c (1.44), vbe.h (1.24), vgabios.c (1.55):
+
+ - VBE init code and some dispi ioport functions rewritten in assembler
+ - text scroll functions for CGA graphics modes added
+ - scroll text in graphics modes: attribute for blank line fixed
+
+2004-05-08 16:06 vruppert
+
+ * BUGS (1.2), README (1.7), TODO (1.10), VGABIOS-lgpl-latest.bin (1.48),
+ VGABIOS-lgpl-latest.debug.bin (1.48), vbe.c (1.43), vbe.h (1.23),
+ vbe_display_api.txt (1.11), vgabios.c (1.54):
+
+ - VBE internal functions dispi_set_enable and dispi_set_bank now called both from C
+ and asm code
+ - VBE function 0x03 rewritten in assembler
+ - VBE function 0x08 cleaned up
+ - text output and scroll functions for graphics modes rewritten using case
+ structures
+ - documentation and comments updated
+
+2004-05-06 21:18 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.47), VGABIOS-lgpl-latest.debug.bin (1.47),
+ vbe.c (1.42), vbe.h (1.22), vgabios.c (1.53):
+
+ - VBE functions 0x05, 0x06, 0x07 and some dispi ioport functions rewritten in
+ assembler
+ - VBE functions 0x06 and 0x07: get functions now supported, 15 bpp bug fixed
+
+2004-05-05 19:24 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.46), VGABIOS-lgpl-latest.debug.bin (1.46),
+ vbe.c (1.41), vbe.h (1.21), vbe_display_api.txt (1.10), vgabios.c (1.52):
+
+ - 8 bit DAC capability flag set
+ - vbe_biosfn_set_get_dac_palette_format implemented
+ - VBE api description updated
+ - C definitions from header files now used assembler code
+
+2004-05-02 17:27 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.45), VGABIOS-lgpl-latest.debug.bin (1.45),
+ vgabios.c (1.51):
+
+ - text scroll functions for PLANAR1/PLANAR4 graphics modes added
+ - function biosfn_get_ega_info rewritten in assembler
+ - read/write graphics pixel functions rewritten using a case structure
+
+2004-05-01 16:03 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.44), VGABIOS-lgpl-latest.debug.bin (1.44),
+ vgabios.c (1.50):
+
+ - biosfn_enable_cursor_emulation rewritten in assembler
+ - remap of the cursor shape depends on modeset control bit 0
+ - text output in PLANAR4 modes now supports attribute bit 7 (XOR with background)
+
+2004-04-25 20:13 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.43), VGABIOS-lgpl-latest.debug.bin (1.43),
+ vgabios.c (1.49), vgatables.h (1.7):
+
+ - table entries for vga mode 0x0f fixed (PLANAR2 exists on EGA only)
+ - function release_font_access now supports the monochrome text mode
+ - PLANAR1 modes now supported in text output functions and read/write pixel
+ - function AH=0x12/BL=0x32 rewritten in assembler
+
+2004-04-25 08:45 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.42), VGABIOS-lgpl-latest.debug.bin (1.42),
+ vgabios.c (1.48):
+
+ - block address calculation in font functions fixed
+ - functions AX=0x1103, AH=0x12/BL=0x31 and AH=0x12/BL=0x33 rewritten in assembler
+
+2004-04-24 09:59 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.41), VGABIOS-lgpl-latest.debug.bin (1.41),
+ vgabios.c (1.47):
+
+ - read/write graphics pixel for PLANAR4 modes added
+ - CGA specific functions (group AH = 0x0B) implemented
+
+2004-04-23 14:34 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.40), VGABIOS-lgpl-latest.debug.bin (1.40),
+ vgabios.c (1.46):
+
+ - remaining palette and dac read/write functions (except gray scale summing)
+ rewritten in assembler
+
+2004-04-18 13:43 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.39), VGABIOS-lgpl-latest.debug.bin (1.39),
+ vgabios.c (1.45):
+
+ - some palette and dac read/write functions rewritten in assembler
+ - main int10 debug message now works with assembler functions, too
+
+2004-04-18 09:15 japj
+
+ * vbe.c (1.40):
+
+ updated my email address + put vgabios url in the bios copyright string
+ (instead of my old email address)
+
+2004-04-17 07:18 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.38), VGABIOS-lgpl-latest.debug.bin (1.38),
+ vgabios.c (1.44):
+
+ - biosfn_set_video_mode: don't load DAC registers if default palette loading is
+ disabled. Perform gray scale summing if enabled.
+ - biosfn_perform_gray_scale_summing: switch between DAC read and write mode is
+ required to make this function work. Maximum DAC value always set to 0x3f.
+
+2004-04-08 17:50 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.37), VGABIOS-lgpl-latest.debug.bin (1.37),
+ vgabios.c (1.43):
+
+ - write character function for the LINEAR8 mode
+ - get_font_access() and release_font_access() rewritten in assembler
+ - fixed wrong variable name in the init code
+
+2004-04-06 19:31 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.36), VGABIOS-lgpl-latest.debug.bin (1.36),
+ vgabios.c (1.42):
+
+ - init functions rewitten in assembler
+ - function biosfn_set_display_code rewritten in assembler
+
+2004-04-05 19:40 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.35), VGABIOS-lgpl-latest.debug.bin (1.35),
+ vgabios.c (1.41):
+
+ - functions biosfn_get_video_mode() and biosfn_read_display_code() rewritten
+ in assembler
+
+2004-04-04 18:20 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.34), VGABIOS-lgpl-latest.debug.bin (1.34),
+ vgabios.c (1.40):
+
+ - write character function for CGA modes added
+ - read/write graphics pixel for CGA and LINEAR8 modes added
+
+2004-02-23 21:08 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.33), VGABIOS-lgpl-latest.debug.bin (1.33),
+ vbe.c (1.39):
+
+ - dispi_get_max_bpp(): restore the original value of the vbe enable register
+
+2004-02-22 14:17 vruppert
+
+ * README (1.6), vbe.c (1.38), vbe.h (1.20), vbe_display_api.txt (1.9),
+ VGABIOS-lgpl-latest.bin (1.32), VGABIOS-lgpl-latest.debug.bin (1.32):
+
+ - new function dispi_get_max_bpp() returns the bpp capabilities of the Bochs gui
+ - create the mode list depending on the supported bpp capability
+ - unused stuff removed
+ - documentation updated
+
+2004-02-21 18:20 vruppert
+
+ * vbe.c (1.37), vbe.h (1.19), vbetables.h (1.23),
+ VGABIOS-lgpl-latest.bin (1.31), VGABIOS-lgpl-latest.debug.bin (1.31):
+
+ - dynamicly genarated vbe mode_info list works now
+
+2003-11-17 21:04 vruppert
+
+ * vbe.c (1.36), vbetables.h (1.22), vgabios.c (1.39), vgatables.h (1.6),
+ VGABIOS-lgpl-latest.bin (1.30), VGABIOS-lgpl-latest.debug.bin (1.30):
+
+ - new VBE presence flag stored at unused BDA address 0xB9
+ - VBE init code rewritten
+ - added BIOS TTY flag for VBE mode 0x0102 (TODO: scrolling)
+ - vgabios_init_func: load and activate text font already done by set_video_mode
+ - function biosfn_get_all_palette_reg() fixed
+
+2003-11-06 00:26 cbothamy
+
+ * README (1.5):
+
+ - add changes for 0.4c release
+
+2003-11-06 00:22 cbothamy
+
+ * VGABIOS-lgpl-latest.bin (1.29), VGABIOS-lgpl-latest.debug.bin
+ (1.29):
+
+ - compile vgabios.c rev1.38
+
+2003-11-06 00:21 cbothamy
+
+ * vgabios.c (1.38):
+
+ - activate char table after loading it when setting a text video
+ mode
+
+2003-11-06 00:19 cbothamy
+
+ * Makefile (1.12):
+
+ - when making a release, remove unwanted files first, and exclude
+ CVS from the tarball
+
+2003-11-04 22:50 cbothamy
+
+ * ChangeLog (1.20, v0_4b):
+
+ - update ChangeLog for 0.4b release
+
+2003-11-04 22:49 cbothamy
+
+ * README (1.4, v0_4b):
+
+ - update Changes for 0.4b release
+
+2003-11-04 20:26 vruppert
+
+ * vgabios.c (1.37), VGABIOS-lgpl-latest.bin (1.28),
+ VGABIOS-lgpl-latest.debug.bin (1.28) (utags: v0_4b):
+
+ - biosfn_get_font_info(): character height must be returned in CX
+
+2003-11-03 21:57 vruppert
+
+ * vbe.c (1.35, v0_4b), vgabios.c (1.36), VGABIOS-lgpl-latest.bin
+ (1.27), VGABIOS-lgpl-latest.debug.bin (1.27):
+
+ - the 'noclearmem' flag is not stored in the 'current video mode'
+ register (0040h:0049h) - VBE also stores the 'noclear' flag in
+ the 'video control' register (0040h:0087h)
+
+2003-10-05 10:06 vruppert
+
+ * vbe.h (1.18, v0_4b), vbe_display_api.txt (1.8, v0_4b),
+ VGABIOS-lgpl-latest.bin (1.26), VGABIOS-lgpl-latest.debug.bin
+ (1.26):
+
+ - changed VBE i/o registers to 0x01CE/CF (suggestion from Daniel
+ Gimpelevich)
+
+2003-08-18 18:38 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.25), VGABIOS-lgpl-latest.debug.bin
+ (1.25), vgabios.c (1.35):
+
+ - wrong offsets to the character tables (INT 0x1F/0x43) fixed
+ (underscore added) - functions accessing the CRT controller
+ optimized using a local variable 'crtc_addr'
+
+2003-08-17 15:46 cbothamy
+
+ * ChangeLog (1.19, v0_4a):
+
+ - ChangeLog is now automatically generated by running "cvs2cl -r
+ -t -P -S" - update ChangeLog for 0.4a release
+
+2003-08-17 15:44 cbothamy
+
+ * README (1.3, v0_4a):
+
+ - added the old ChangeLog in the HOSTORY section of the README
+ file - update History for 0.4a release, with a summary of Changes
+
+2003-08-17 15:24 cbothamy
+
+ * Makefile (1.11, v0_4b, v0_4a):
+
+ - fix Makefile for "release" target
+
+2003-08-16 01:49 cbothamy
+
+ * Makefile (1.10), README (1.2), VGABIOS-lgpl-latest.bin (1.24,
+ v0_4a), VGABIOS-lgpl-latest.debug.bin (1.24, v0_4a), vgabios.c
+ (1.34, v0_4a):
+
+ - update the Makefile for releases - remove references to old
+ plex86 website - update the Makefile so it build
+ VGABIOS-lgpl-latest.bin and VGABIOS-lgpl-latest.debug.bin
+
+2003-08-07 18:17 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.23), VGABIOS-lgpl-latest.debug.bin
+ (1.23):
+
+ - current VBE mode now stored in BDA (unused address 0xBA)
+
+2003-08-07 17:54 vruppert
+
+ * vbe.c (1.34), vgatables.h (1.5, v0_4b) (utags: v0_4a):
+
+ - current VBE mode now stored in BDA (unused address 0xBA)
+
+2003-07-20 18:05 vruppert
+
+ * vgabios.c (1.33), VGABIOS-lgpl-latest.bin (1.22),
+ VGABIOS-lgpl-latest.debug.bin (1.22):
+
+ - fixed a few functions accessing the attribute controller
+
+2003-07-19 09:33 vruppert
+
+ * vgabios.c (1.32), VGABIOS-lgpl-latest.bin (1.21),
+ VGABIOS-lgpl-latest.debug.bin (1.21):
+
+ - re-enable video after programming the attribute controller -
+ biosfn_set_all_palette_reg(): number of palette registers fixed
+
+2003-07-16 22:32 vruppert
+
+ * ChangeLog (1.18), vbe.c (1.33), vbe.h (1.17, v0_4a),
+ vbe_display_api.txt (1.7, v0_4a), vgabios.c (1.31),
+ VGABIOS-lgpl-latest.bin (1.20), VGABIOS-lgpl-latest.debug.bin
+ (1.20):
+
+ - LFB flag now stored in the register VBE_DISPI_INDEX_ENABLE -
+ release date in Changelog fixed - release date of VBE BIOS 0.6
+ was the same as VGA BIOS 0.3b - year changed in copyright
+ messages
+
+2003-07-15 12:40 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.19), VGABIOS-lgpl-latest.debug.bin
+ (1.19):
+
+ - new function dispi_get_bpp() - function
+ vbe_biosfn_set_get_logical_scan_line_length() fixed for >8bpp -
+ number of image pages of all VBE modes fixed
+
+2003-07-15 12:35 vruppert
+
+ * vbe.c (1.32), vbetables.h (1.21, v0_4b, v0_4a):
+
+ - new function dispi_get_bpp() - function
+ vbe_biosfn_set_get_logical_scan_line_length() fixed for >8bpp -
+ number of image pages of all VBE modes fixed
+
+2003-07-14 19:45 vruppert
+
+ * vbe_display_api.txt (1.6):
+
+ - description of VBE_DISPI_ interface 0xb0c2 added
+
+2003-07-10 19:07 vruppert
+
+ * vbe.c (1.31), vbetables.h (1.20), VGABIOS-lgpl-latest.bin (1.18),
+ VGABIOS-lgpl-latest.debug.bin (1.18):
+
+ - 15 bpp VBE modes added - "Bochs own" mode 0x142 (640x480x32bpp)
+ added
+
+2003-07-01 19:00 vruppert
+
+ * vbe.c (1.30), vbe.h (1.16), vbetables.h (1.19),
+ VGABIOS-lgpl-latest.bin (1.17), VGABIOS-lgpl-latest.debug.bin
+ (1.17):
+
+ - VBE preserve display memory feature implemented - VBE mode
+ entries 0x117 and 0x118 added
+
+2003-06-30 21:27 vruppert
+
+ * vbe.c (1.29), vbe.h (1.15), vbetables.h (1.18),
+ VGABIOS-lgpl-latest.bin (1.16), VGABIOS-lgpl-latest.debug.bin
+ (1.16):
+
+ - VBE mode info blocks of modes with >8bpp enabled - VBE modes
+ with 24 bpp: bytes per scanline fixed - vbe_biosfn_set_mode() now
+ supports >8bpp - VBE will be enabled with new VBE_DISPI_ID2
+ (0xB0C2)
+
+2003-06-29 12:53 vruppert
+
+ * vbetables.h (1.17), VGABIOS-lgpl-latest.bin (1.15),
+ VGABIOS-lgpl-latest.debug.bin (1.15):
+
+ - duplicate lines with VBE_MODE_ATTRIBUTE_GRAPHICS_MODE removed -
+ VBE mode info items of currently unsupported modes fixed
+
+2003-06-15 21:19 vruppert
+
+ * vgabios.c (1.30), VGABIOS-lgpl-latest.bin (1.14),
+ VGABIOS-lgpl-latest.debug.bin (1.14):
+
+ - function write_gfx_char() rewritten
+
+2003-04-26 09:27 vruppert
+
+ * VGABIOS-lgpl-latest.debug.bin (1.13):
+
+ - added missing VBE function dispi_get_bank() - added missing
+ return codes for VBE function 4F05h - memory size is always
+ reported in VBE function 4F00h - fixed scan line length for VBE
+ mode 0102h - fixed function set_active_page() for graphics modes
+ - fixed the page sizes of some VGA modes
+
+2003-04-26 09:22 vruppert
+
+ * vbe.c (1.28), vbetables.h (1.16), vgabios.c (1.29), vgatables.h
+ (1.4), VGABIOS-lgpl-latest.bin (1.13):
+
+ - added missing VBE function dispi_get_bank() - added missing
+ return codes for VBE function 4F05h - memory size is always
+ reported in VBE function 4F00h - fixed scan line length for VBE
+ mode 0102h - fixed function set_active_page() for graphics modes
+ - fixed the page sizes of some VGA modes
+
+2003-04-20 09:51 vruppert
+
+ * vgabios.c (1.28), vgatables.h (1.3), VGABIOS-lgpl-latest.bin
+ (1.12), VGABIOS-lgpl-latest.debug.bin (1.12):
+
+ - function write_gfx_char() now supports different font sizes -
+ some entries of the static functionality table fixed
+
+2003-04-18 09:23 vruppert
+
+ * vbe.c (1.27), vbe.h (1.14), vbetables.h (1.15):
+
+ - applied patch #1331 * new function dispi_set_bank_farcall()
+ * VBE mode info item WinFuncPtr points to the new function if the
+ flag VBE_WINDOW_ATTRIBUTE_RELOCATABLE is set * flag
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE added
+
+2003-02-11 20:17 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.11), VGABIOS-lgpl-latest.debug.bin
+ (1.11), vbe.c (1.26), vbetables.h (1.14):
+
+ - VBE mode search rewritten * improved function
+ mode_info_find_mode() is now used by the VBE functions 0x4F01
+ and 0x4F02 * removed all mode list entries with the LFB bit
+ set. LFB detection is now present in the function
+ mode_info_find_mode()
+
+2003-02-09 20:59 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.10), VGABIOS-lgpl-latest.debug.bin
+ (1.10), vgabios.c (1.27):
+
+ - function write_gfx_char(): memory address now calculated in
+ this function; background color is always black - function
+ biosfn_write_char_attr(): the count parameter is now used in
+ graphics modes too - function biosfn_write_char_only() works
+ the same way as function biosfn_write_char_attr() in graphics
+ mode - copying charmap data optimized using memcpyb()
+
+2003-02-09 11:36 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.9), VGABIOS-lgpl-latest.debug.bin
+ (1.9):
+
+ - VESA mode 0x102 added (uses existing SVGA mode 0x6a) - all VESA
+ modes with the LFB flag set removed from the list (Linux doesn't
+ like mode numbers > 0x07ff)
+
+2003-02-09 11:02 vruppert
+
+ * vbe.c (1.25), vbe.h (1.13), vbetables.h (1.13):
+
+ - VESA mode 0x102 added (uses existing SVGA mode 0x6a) - all VESA
+ modes with the LFB flag set removed from the list (Linux doesn't
+ like mode numbers > 0x07ff)
+
+2003-02-08 13:04 vruppert
+
+ * vbe.c (1.24), vgabios.c (1.26):
+
+ - vbe_biosfn_return_current_mode() now returns the active
+ standard VGA mode TODO: return VESA mode if enabled -
+ biosfn_set_video_mode() now clears the screen in CGA mode
+ correctly - write character functions are now working in all
+ PLANAR4 graphics modes - added stubs for unimplemented features
+ in graphics modes
+
+2003-02-04 22:19 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.8), VGABIOS-lgpl-latest.debug.bin
+ (1.8):
+
+ - set video mode: clear vga memory in graphics mode - set video
+ mode: load default font in text mode - write character
+ implemented for graphics mode 0x12
+
+2003-02-04 22:06 vruppert
+
+ * vgabios.c (1.25):
+
+ - set video mode: clear vga memory in graphics mode - set video
+ mode: load default font in text mode - write character
+ implemented for graphics mode 0x12
+
+2003-01-21 19:30 vruppert
+
+ * vgabios.c (1.24):
+
+ - remap the cursor size if the char height is > 8 and the new
+ values are < 8
+
+2003-01-20 18:24 cbothamy
+
+ * Makefile (1.9):
+
+ - fix so make -j2 does not overwrite temp files
+
+2003-01-19 12:35 vruppert
+
+ * vgabios.c (1.23):
+
+ - function set_scan_lines() recalculates the number of rows and
+ the page size - new values for char height, text rows and page
+ size are stored in the BIOS data segment - asm helper function
+ idiv_u added
+
+2003-01-15 18:49 cbothamy
+
+ * VGABIOS-lgpl-latest.bin (1.7), VGABIOS-lgpl-latest.debug.bin
+ (1.7):
+
+ - compile vgabios rev 1.22
+
+2003-01-15 18:49 cbothamy
+
+ * vgabios.c (1.22):
+
+ - fix bug found by ams : a 8bits index value was compared to
+ 0x100 in some cases in biosfn_set_all_dac_reg,
+ biosfn_read_all_dac_reg, biosfn_perform_gray_scale_summing
+
+2003-01-15 17:34 cbothamy
+
+ * Makefile (1.8):
+
+ - fix symbol table file names, discovered by ams
+
+2003-01-04 21:20 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.6), VGABIOS-lgpl-latest.debug.bin
+ (1.6), vgabios.c (1.21):
+
+ - biosfn_set_video_mode(): reset attribute controller flip-flop
+ before setting up the controller's registers (bug found with
+ amidiag)
+
+2003-01-04 09:50 vruppert
+
+ * vbe.c (1.23):
+
+ - VBE function 0x00 returns VBE 1.x compatible information if no
+ VBE signature is present
+
+2003-01-01 12:44 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.5), VGABIOS-lgpl-latest.debug.bin
+ (1.5):
+
+ - SVGA mode 0x6A (800x600x4) added to the list of graphics modes
+
+2002-12-31 18:07 vruppert
+
+ * vgatables.h (1.2):
+
+ - SVGA mode 0x6A (800x600x4) added to the list of graphics modes
+
+2002-11-23 10:38 cbothamy
+
+ * ChangeLog (1.17, v0_3b):
+
+ - fix changelog for 0.3b release
+
+2002-10-20 17:12 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.4), VGABIOS-lgpl-latest.debug.bin
+ (1.4), vgabios.c (1.20) (utags: v0_3b):
+
+ - new function set_scan_lines() for the font size change (patch
+ from Hartmut Birr) - cursor shape start and end must be updated
+ in set_scan_lines() - set_scan_lines() is called by the functions
+ 0x1110, 0x1111, 0x1112 and 0x1114 after copying the font data
+
+2002-10-04 08:20 vruppert
+
+ * VGABIOS-lgpl-latest.bin (1.3), VGABIOS-lgpl-latest.debug.bin
+ (1.3), vgabios.c (1.19):
+
+ - biosfn_set_single_dac_reg(): the red value is stored in DH
+
+2002-09-19 19:05 cbothamy
+
+ * VGABIOS-lgpl-latest.bin (1.2), VGABIOS-lgpl-latest.debug.bin
+ (1.2):
+
+ - updated with latest changes
+
+2002-09-19 19:03 cbothamy
+
+ * ChangeLog (1.16), Makefile (1.7, v0_3b), vbe.c (1.22, v0_3b),
+ vgabios.c (1.18), vgabios.h (1.3, v0_4b, v0_4a, v0_3b):
+
+ - updated the Makefile - removed display of copyrights. -
+ changed the Copyright string to "LGPL VGABios developers"
+
+2002-09-08 21:14 vruppert
+
+ * vgabios.c (1.17):
+
+ - set the cursor shape depending on the current font height -
+ clear BL before calling int 0x10 function 0x1103 in
+ vgabios_init_func
+
+2002-08-23 22:58 cbothamy
+
+ * vbe.c (1.21), vbetables.h (1.12, v0_3b):
+
+ - added lfb-mode numbers (patch from mathis)
+
+2002-07-21 21:57 japj
+
+ * vbe.c (1.20), vgabios.c (1.16):
+
+ gcc2/3 preprocessing fix
+
+2002-05-18 16:55 cbothamy
+
+ * vgabios.c (1.15):
+
+ - include patch from Volker that adds some text font functions
+
+2002-05-01 23:13 japj
+
+ * VGABIOS-lgpl-latest.bin (1.1), VGABIOS-lgpl-latest.debug.bin
+ (1.1):
+
+ adding latest bin & debug bin of the vgabios
+
+2002-04-29 14:50 japj
+
+ * ChangeLog (1.15), vbe.c (1.19), vbe.h (1.12, v0_3b), vbetables.h
+ (1.11), vgabios.c (1.14):
+
+ - applying hw scrolling/multibuffering patch
+
+2002-04-25 21:59 japj
+
+ * Makefile (1.6), vbe.c (1.18), vgabios.c (1.13):
+
+ - reverting #asm/##asm & endasm patch (does not work with with
+ cygwin)
+
+2002-04-19 19:38 japj
+
+ * Makefile (1.5), vbe.c (1.17), vgabios.c (1.12):
+
+ - fixing preprocessing of vgabios with latest gcc (from Mandrake
+ 8.2)
+
+2002-04-08 23:44 japj
+
+ * ChangeLog (1.14), vbe_display_api.txt (1.5, v0_3b):
+
+ - preparing docs for new DISPI interface (for hardware scrolling)
+
+2002-04-03 19:06 japj
+
+ * ChangeLog (1.13), TODO (1.9, v0_4b, v0_4a, v0_3b), vbe.c (1.16):
+
+ - defaulting LFB on + updated changelog & todo
+
+2002-04-03 00:38 cbothamy
+
+ * vbe.c (1.15), vgabios.c (1.11):
+
+ - changed the logging ports to 0x500 -> 0x502
+
+2002-03-14 17:54 japj
+
+ * vbe.c (1.14):
+
+ - vbetables.h is dependant upon some defines (VBE_HAVE_LFB), so
+ put the include *after* the define
+
+2002-03-13 21:47 japj
+
+ * ChangeLog (1.12), TODO (1.8), vbe.c (1.13), vbetables.h (1.10),
+ vgabios.c (1.10):
+
+ - made LFB dependant upon define - not implement vbe functions
+ return failure - updated todo & docs for things after bochs 1.4
+
+2002-03-13 19:46 japj
+
+ * vbe.h (1.11), vbe_display_api.txt (1.4):
+
+ - added max video memory + documented what is in the 0xb0c0
+ interface
+
+2002-03-12 02:33 cbothamy
+
+ * ChangeLog (1.11), Makefile (1.4):
+
+ - updated for 0.3a. Merged vgabios.bin and vbebios.bin
+
+2002-03-10 21:36 japj
+
+ * ChangeLog (1.10), vbetables.h (1.9):
+
+ - added LFB modes for testing with vbe-lfb patch in Bochs
+
+2002-03-10 17:42 japj
+
+ * vbe.c (1.12, v0_3a):
+
+ - show people when they do NOT have VBE support available
+
+2002-03-10 17:36 japj
+
+ * TODO (1.7, v0_3a), vbe.c (1.11), vbe.h (1.10, v0_3a), vgabios.c
+ (1.9, v0_3a):
+
+ - cleanup of vbe internal functions (set 8bpp mode is now
+ dependant on ModeInfo content instead of hardcoded functions)
+
+2002-03-10 17:20 cbothamy
+
+ * ChangeLog (1.9, v0_3a), TODO (1.6):
+
+ - updated for 0.3a
+
+2002-03-10 17:19 cbothamy
+
+ * vbe.c (1.10), vbe.h (1.9):
+
+ - added vbe_has_vbe_display function that detects an attached vbe
+ display
+
+2002-03-10 17:12 cbothamy
+
+ * vgabios.c (1.8):
+
+ - vbe calls are done only if a vbe display is detected
+
+2002-03-10 11:25 japj
+
+ * vbe.h (1.8), vbe_display_api.txt (1.3, v0_3a):
+
+ - preparing for LFB support
+
+2002-03-09 14:25 japj
+
+ * vgabios.c (1.7):
+
+ - fixing initial cursor shape to _ instead of -
+
+2002-03-08 23:08 japj
+
+ * ChangeLog (1.8), TODO (1.5), vbe.c (1.9), vbe.h (1.7), vgabios.c
+ (1.6):
+
+ - updating vbe code to new API
+
+2002-03-08 21:48 japj
+
+ * vbe.c (1.8), vbe.h (1.6), vbetables.h (1.8, v0_3a):
+
+ - updating vbe code with #defines from API
+
+2002-03-08 21:31 japj
+
+ * vbe_display_api.txt (1.2):
+
+ - adding some text about how banks work
+
+2002-03-08 21:09 japj
+
+ * ChangeLog (1.7), vbe_display_api.txt (1.1):
+
+ - adding vbe_display_api documentation
+
+2002-03-07 21:36 japj
+
+ * ChangeLog (1.6), vbe.c (1.7), vbetables.h (1.7):
+
+ - added 1024x768xbpp support - some more cleanups/comments
+
+2002-03-06 21:55 japj
+
+ * ChangeLog (1.5), TODO (1.4), vbe.c (1.6), vbetables.h (1.6),
+ vgabios.c (1.5):
+
+ - updated changelog with new modi - added 640x480x8 (Mandrake
+ Installer can use this!) - added pre VBE2 compatible 'detection'
+ - fixed problem when normal vga set mode wouldn't disable vbe
+ mode
+
+2002-03-06 20:59 japj
+
+ * TODO (1.3), vbe.c (1.5), vbe.h (1.5), vbetables.h (1.5),
+ vgabios.c (1.4):
+
+ - adding 640x400x8 and 800x600x8 vbe support (this depends
+ HEAVILY on my bochs vga code patch - japj)
+
+2002-03-06 18:00 japj
+
+ * vbe.c (1.4), vbe.h (1.4), vbetables.h (1.4):
+
+ - implemented banked & lfb support for 320x200x8bpp (some fixes
+ for vbetest program not displaying anything)
+
+2002-03-05 20:25 japj
+
+ * Makefile (1.3, v0_3a):
+
+ for vbe debug bios: - print debugging information in assembly
+ output - print source code in assembly output
+
+2002-03-01 19:39 japj
+
+ * ChangeLog (1.4), TODO (1.2), vbe.c (1.3), vbe.h (1.3),
+ vbetables.h (1.3):
+
+ - added vbe support for 320x200x8 using the standard vgamode
+ (0x13)
+
+2002-02-19 00:29 japj
+
+ * ChangeLog (1.3):
+
+ - updating ChangeLog with lfbprof
+
+2002-02-18 23:26 japj
+
+ * tests/lfbprof/: lfbprof.c (1.2), lfbprof.h (1.2) (utags: v0_3a,
+ v0_3b, v0_4a, v0_4b):
+
+ - fixed unsigned short for mode list (-1 != 0xffff otherwise) -
+ fixed LfbMapRealPointer macro mask problem (some modes were
+ skipped) - added some extra 'debugging' printf's
+
+2002-02-18 23:07 japj
+
+ * tests/lfbprof/: Makefile (1.1, v0_4b, v0_4a, v0_3b, v0_3a),
+ lfbprof.c (1.1), lfbprof.h (1.1):
+
+ - Adding lfbprof testprogram (for vbe testing purposes) It
+ needs to be compiled with the Watcom C Compiler
+
+2002-02-18 18:48 japj
+
+ * vbe.c (1.2), vbe.h (1.2):
+
+ - cosmetic updates to vbe.c/h + added bunch of FIXMEs for work
+ that needs to be done
+
+2002-02-18 18:34 japj
+
+ * vbetables.h (1.2):
+
+ - cosmetic updates in vbetables.h
+
+2002-02-18 18:32 japj
+
+ * ChangeLog (1.2):
+
+ updated changelog with merge of vbebios 0.2
+
+2002-02-18 18:07 japj
+
+ * vgabios.c (1.3):
+
+ - small cosmetic cleanup in vgabios vbe code + added FIXMEs
+
+2002-02-18 17:55 japj
+
+ * Makefile (1.2), dataseghack (1.2, v0_4b, v0_4a, v0_3b, v0_3a),
+ vbe.c (1.1), vbe.h (1.1), vbetables.h (1.1), vgabios.c (1.2),
+ vgabios.h (1.2, v0_3a):
+
+ - merging with vbebios 0.2 release
+
+2002-02-18 11:31 cbothamy
+
+ * BUGS (1.1, v0_4b, v0_4a, v0_3b, v0_3a), COPYING (1.1, v0_4b,
+ v0_4a, v0_3b, v0_3a), ChangeLog (1.1), Makefile (1.1), Notes
+ (1.1, v0_4b, v0_4a, v0_3b, v0_3a), README (1.1, v0_3b, v0_3a),
+ TODO (1.1), dataseghack (1.1), vgabios.c (1.1), vgabios.h (1.1),
+ vgafonts.h (1.1, v0_4b, v0_4a, v0_3b, v0_3a), vgatables.h (1.1,
+ v0_3b, v0_3a), tests/testbios.c (1.1, v0_4b, v0_4a, v0_3b,
+ v0_3a):
+
+ - initial import
+
diff --git a/tools/firmware/vgabios/Makefile b/tools/firmware/vgabios/Makefile
new file mode 100644
index 0000000000..929d882e72
--- /dev/null
+++ b/tools/firmware/vgabios/Makefile
@@ -0,0 +1,77 @@
+CC = gcc
+CFLAGS = -g -O2 -Wall -Wstrict-prototypes
+LDFLAGS =
+
+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)\""
+
+all: bios cirrus-bios
+
+bios: biossums vgabios.bin vgabios.debug.bin
+
+cirrus-bios: vgabios-cirrus.bin vgabios-cirrus.debug.bin
+
+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
+
+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: 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: 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: 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: vgabios.c vgabios.h vgafonts.h vgatables.h clext.c
+ $(GCC) -E -P vgabios.c $(VGABIOS_VERS) -DCIRRUS -DCIRRUS_DEBUG $(VGABIOS_DATE) > _vgabios-cirrus-debug_.c
+ $(BCC) -o vgabios-cirrus-debug.s -C-c -D__i86__ -S -0 _vgabios-cirrus-debug_.c
+ sed -e 's/^\.text//' -e 's/^\.data//' vgabios-cirrus-debug.s > _vgabios-cirrus-debug_.s
+ $(AS86) _vgabios-cirrus-debug_.s -b vgabios-cirrus.debug.bin -u -w- -g -0 -j -O -l vgabios-cirrus.debug.txt
+ rm -f _vgabios-cirrus-debug_.s _vgabios-cirrus-debug_.c vgabios-cirrus-debug.s
+ cp vgabios-cirrus.debug.bin VGABIOS-lgpl-latest.cirrus.debug.bin
+ ./biossums VGABIOS-lgpl-latest.cirrus.debug.bin
+ ls -l VGABIOS-lgpl-latest.cirrus.debug.bin
+
+biossums: biossums.c
+ $(CC) -o biossums biossums.c
diff --git a/tools/firmware/vgabios/Notes b/tools/firmware/vgabios/Notes
new file mode 100644
index 0000000000..d5b708dc7f
--- /dev/null
+++ b/tools/firmware/vgabios/Notes
@@ -0,0 +1,11 @@
+Development notes
+-----------------
+
+- need to split video init function
+ 1. set bios variables
+ 2. do the real init with io based on bios variables
+
+- characters format switching will set the bios
+ variables and call function #2 above
+
+- need to rework the tables as explained in Interrupt list
diff --git a/tools/firmware/vgabios/README b/tools/firmware/vgabios/README
new file mode 100644
index 0000000000..69462d93b7
--- /dev/null
+++ b/tools/firmware/vgabios/README
@@ -0,0 +1,191 @@
+Plex86/Bochs VGABios
+--------------------
+
+The goal of this project is to have a LGPL'd Video Bios in plex86,
+Bochs and qemu.
+This VGA Bios is very specific to the emulated VGA card.
+It is NOT meant to drive a physical vga card.
+
+
+Cirrus SVGA extension
+---------------------
+
+The Cirrus SVGA extension is designed for the Cirrus emulation in Bochs and
+qemu. The initial patch for the Cirrus extension has been written by Makoto
+Suzuki (suzu).
+
+
+Install
+-------
+To compile the VGA Bios you will need :
+- gcc
+- bcc
+- as86
+- ld86
+
+Untar the archive, and type make. You should get a "VGABIOS-lgpl-latest.bin"
+file. Alternatively, you can use the binary file "VGABIOS-lgpl-latest.bin",
+i have compiled for you.
+
+Edit your plex86/bochs conf file, and modify the load-rom command in the
+VGA BIOS section, to point to the new vgabios image file.
+
+
+Debugging
+---------
+You can get a very basic debugging system: messages printed by the vgabios.
+You have to register the "unmapped" device driver in plex86 or bochs, and make
+sure it grabs port 0xfff0.
+
+Comment the #undef DEBUG at the beginning of vgabios.c.
+You can then use the "printf" function in the bios.
+
+
+Testing
+-------
+Look at the "testvga.c" file in the archive. This is a minimal Turbo C 2.0
+source file that calls a few int10 functions. Feel free to modify it to suit
+your needs.
+
+
+Copyright and License
+---------------------
+This program has been written by Christophe Bothamy
+It is protected by the GNU Lesser Public License, which you should
+have received a copy of along with this package.
+
+
+Reverse Engineering
+-------------------
+The VGA Bios has been written without reverse-engineering any existing Bios.
+
+
+Acknowledgment
+--------------
+The source code contains code ripped from rombios.c of plex86, written
+by Kevin Lawton <kevin2001@yahoo.com>
+
+The source code contains fonts from fntcol16.zip (c) by Joseph Gil avalable at :
+ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+These fonts are public domain
+
+The source code is based on information taken from :
+- Kevin Lawton's vga card emulation for bochs/plex86
+- Ralf Brown's interrupts list avalaible at
+ http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html
+- Finn Thogersons' VGADOC4b available at http://home.worldonline.dk/~finth/
+- Michael Abrash's Graphics Programming Black Book
+- Francois Gervais' book "programmation des cartes graphiques cga-ega-vga"
+ edited by sybex
+- DOSEMU 1.0.1 source code for several tables values and formulas
+
+
+Feedback
+--------
+Please report any bugs, comments, patches for this VGA Bios to info@vruppert.de
+You can find the latest release at : http://www.nongnu.org/vgabios/
+For any information on bochs, visit the website http://bochs.sourceforge.net/
+For any information on qemu, visit the website http://fabrice.bellard.free.fr/qemu/
+
+
+History
+-------
+vgabios-0.5b : May 24 2005
+ - Volker
+ . fixed return value for the default case in the VBE section (non-debug mode)
+ . removed unused stuff
+
+vgabios-0.5a : Mar 07 2005
+ - Volker
+ . Cirrus SVGA extension (initial patches from Makoto Suzuki, improvements
+ from Fabrice Bellard)
+ . vgabios image size is now exactly 32k with a checksum
+ . a lot of vgabios and vbe functions rewritten in assembler
+ . dynamicly generated VBE mode info list
+ . write character function for CGA and LINEAR8 modes
+ . read/write graphics pixel for some graphics modes
+ . text scroll feature for some graphics modes
+ . VBE 8-bit DAC support
+
+vgabios-0.4c : Nov 06 2003
+ - Christophe
+ . fix font problem on initial screen of NT4 Loader
+
+vgabios-0.4b : Nov 04 2003
+ - Volker
+ . fix offset of character tables
+ . optimizations of CRT controller accesses
+ . VBE i/o registers changed to 0x01CE/CF
+ (suggestion from Daniel Gimpelevich)
+ . "noclear" flag stored in BIOS area
+ . fix character height returned by get_font_info function
+
+vgabios-0.4a : Aug 17 2003
+ - Volker
+ . VBE mode search rewritten (VBE modes with LFB bit removed)
+ . many bugfixes and optimizations
+ . write character function implemented for graphics modes
+ . support for 15bpp, 16bpp, 24bpp and 32bpp VBE modes added
+ . SVGA mode 0x6A added
+ . VBE modes 0x102, 0x117, 0x118 and 0x142 (Bochs specific)
+
+vgabios-0.3b : Nov 23 2002
+ - Christophe
+ . added lfb-mode numbers (patch from mathis)
+ . updated the Makefile
+ . removed display of copyrights.
+ . changed the Copyright string to "LGPL VGABios developers"
+ - Volker
+ . set the cursor shape depending on the current font height
+ . clear BL before calling int 0x10 function 0x1103 in vgabios_init_func
+ . added some text font functions
+ - Jeroen
+ . Forced to new DISPI (0xb0c1) interface (requires latest bochs vbe code)
+ . Added multibuffering support
+ . Added new DISPI interface for: virt width, height, x offset, y offset
+ . Added LFB modes (to be used with the vbe-lfb patch in bochs)
+ see VBE_HAVE_LFB in vbe.c (currently default enabled)
+ . updated TODO & docs for changes after bochs 1.4
+
+vgabios-0.3a : Mar 10 2002
+ - Christophe
+ . Fixed bug in function ah=13
+ - Jeroen
+ . updated vbebios implementation to new api
+ . added vbe_display_api documentation
+ . added 640x400x8, 640x480x8, 800x600x8, 1024x768
+ (>640x480 needs a special bochs patch atm)
+ . added 320x200x8 vbe support (uses the standard 320x200x8 vga mode to
+ display, this allows for testing & having something on screen as well,
+ at least until bochs host side display is up & running)
+ . adding lfbprof (vbe) testprogram (+some small fixes to it)
+ . merging with vbebios 0.2
+
+vgabios-0.2b : Nov 19 2001
+ - Christophe
+ . Fixed bug in function ah=13
+
+vgabios-0.2a : Nov 09 2001
+ - Christophe
+ . Included bugfix from techt@pikeonline.net about grayscale summing
+ . Added the "IBM" string at org 0x1e as Bart Oldeman suggested
+ . Fixed DS and ES that where inverted in the int10 parameters list!
+ . The following have been implemented :
+ - function ax=1a00, ax=1a01, ah=1b
+ - function ax=1130
+ . Added debug messages for unimplemented/unknown functions
+ Must be compiled with DEBUG defined. The output is trapped
+ by the unknown-ioport driver of plex/bochs (port 0xfff0 is used)
+
+vgabios-0.1a : May 8 2001
+ - Christophe
+ . First release. The work has been focused only on text mode.
+ . The following have been implemented :
+ - inits
+ - int 10 handler
+ - functions ah=00, ah=01, ah=02, ah=03, ah=05, ah=06, ah=07, ah=08
+ ah=09, ah=0a, ah=0e, ah=0f, ax=1000, ax=1001, ax=1002, ax=1003
+ ax=1007, ax=1008, ax=1009, ax=1010, ax=1012, ax=1013, ax=1015
+ ax=1017, ax=1018, ax=1019, ax=101a, ax=101b, ah=12 bl=10,
+ ah=12 bl=30, ah=12 bl=31, ah=12 bl=32, ah=12 bl=33, ah=12 bl=34
+ ah=13
diff --git a/tools/firmware/vgabios/TODO b/tools/firmware/vgabios/TODO
new file mode 100644
index 0000000000..0b83ed0992
--- /dev/null
+++ b/tools/firmware/vgabios/TODO
@@ -0,0 +1,28 @@
+Short term :
+------------
+
+General
+ - Fix init mode (ah=00). Should use more BIOS variables
+ - Add new functionalities and modify static functionality table
+ - Performance : 16 bits IO
+
+v0.6
+ - Reimplement the tables so it is compatible with the video save pointer table
+ - Implement the remaining functions (don't know if all are needed):
+ - chargen ax=1120, ax=1121, ax=1122, ax=1123, ax=1124
+ - display switch interface ah=12 bl=35
+ - video refresh control ah=12 bl=36
+ - save/restore state ah=1c
+ - Graphic modes
+
+v1.0
+ - Bugfixes
+
+
+=================================================================================================
+VBE:
+----
+Long term:
+- have plex86 host side display interface
+- have text io functions in vbe mode
+
diff --git a/tools/firmware/vgabios/biossums.c b/tools/firmware/vgabios/biossums.c
new file mode 100644
index 0000000000..bb1d0ad7f7
--- /dev/null
+++ b/tools/firmware/vgabios/biossums.c
@@ -0,0 +1,200 @@
+/* biossums.c --- written by Eike W. for the Bochs BIOS */
+/* adapted for the LGPL'd VGABIOS by vruppert */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+typedef unsigned char byte;
+
+void check( int value, char* message );
+
+#define LEN_BIOS_DATA 0x8000
+#define MAX_OFFSET (LEN_BIOS_DATA - 1)
+
+
+#define BIOS_OFFSET 0x7FFF
+
+long chksum_bios_get_offset( byte* data, long offset );
+byte chksum_bios_calc_value( byte* data, long offset );
+byte chksum_bios_get_value( byte* data, long offset );
+void chksum_bios_set_value( byte* data, long offset, byte value );
+
+
+#define PMID_LEN 20
+#define PMID_CHKSUM 19
+
+long chksum_pmid_get_offset( byte* data, long offset );
+byte chksum_pmid_calc_value( byte* data, long offset );
+byte chksum_pmid_get_value( byte* data, long offset );
+void chksum_pmid_set_value( byte* data, long offset, byte value );
+
+
+byte bios_data[LEN_BIOS_DATA];
+
+
+int main( int argc, char* argv[] ) {
+
+ FILE* stream;
+ long offset, tmp_offset;
+ byte cur_val = 0, new_val = 0;
+ int hits;
+
+
+ if( argc != 2 ) {
+ printf( "Error. Need a file-name as an argument.\n" );
+ exit( EXIT_FAILURE );
+ }
+
+ if(( stream = fopen( argv[1], "rb" )) == NULL ) {
+ printf( "Error opening %s for reading.\n", argv[1] );
+ exit( EXIT_FAILURE );
+ }
+ if( fread( bios_data, 1, LEN_BIOS_DATA, stream ) >= LEN_BIOS_DATA ) {
+ printf( "Error reading max. 32767 Bytes from %s.\n", argv[1] );
+ fclose( stream );
+ exit( EXIT_FAILURE );
+ }
+ fclose( stream );
+
+ hits = 0;
+ offset = 0L;
+ while( (tmp_offset = chksum_pmid_get_offset( bios_data, offset )) != -1L ) {
+ offset = tmp_offset;
+ cur_val = chksum_pmid_get_value( bios_data, offset );
+ new_val = chksum_pmid_calc_value( bios_data, offset );
+ printf( "\nPMID entry at: 0x%4lX\n", offset );
+ printf( "Current checksum: 0x%02X\n", cur_val );
+ printf( "Calculated checksum: 0x%02X ", new_val );
+ hits++;
+ }
+ if( hits == 1 && cur_val != new_val ) {
+ printf( "Setting checksum." );
+ chksum_pmid_set_value( bios_data, offset, new_val );
+ }
+ if( hits >= 2 ) {
+ printf( "Multiple PMID entries! No checksum set." );
+ }
+ if( hits ) {
+ printf( "\n" );
+ }
+
+
+ offset = 0L;
+ offset = chksum_bios_get_offset( bios_data, offset );
+ cur_val = chksum_bios_get_value( bios_data, offset );
+ new_val = chksum_bios_calc_value( bios_data, offset );
+ printf( "\nBios checksum at: 0x%4lX\n", offset );
+ printf( "Current checksum: 0x%02X\n", cur_val );
+ printf( "Calculated checksum: 0x%02X ", new_val );
+ if( cur_val != new_val ) {
+ printf( "Setting checksum." );
+ chksum_bios_set_value( bios_data, offset, new_val );
+ }
+ printf( "\n" );
+
+
+ if(( stream = fopen( argv[1], "wb" )) == NULL ) {
+ printf( "Error opening %s for writing.\n", argv[1] );
+ exit( EXIT_FAILURE );
+ }
+ if( fwrite( bios_data, 1, LEN_BIOS_DATA, stream ) < LEN_BIOS_DATA ) {
+ printf( "Error writing 32KBytes to %s.\n", argv[1] );
+ fclose( stream );
+ exit( EXIT_FAILURE );
+ }
+ fclose( stream );
+
+ return( EXIT_SUCCESS );
+}
+
+
+void check( int okay, char* message ) {
+
+ if( !okay ) {
+ printf( "\n\nError. %s.\n", message );
+ exit( EXIT_FAILURE );
+ }
+}
+
+
+long chksum_bios_get_offset( byte* data, long offset ) {
+
+ return( BIOS_OFFSET );
+}
+
+
+byte chksum_bios_calc_value( byte* data, long offset ) {
+
+ int i;
+ byte sum;
+
+ sum = 0;
+ for( i = 0; i < MAX_OFFSET; i++ ) {
+ sum = sum + *( data + i );
+ }
+ sum = -sum; /* iso ensures -s + s == 0 on unsigned types */
+ return( sum );
+}
+
+
+byte chksum_bios_get_value( byte* data, long offset ) {
+
+ return( *( data + BIOS_OFFSET ) );
+}
+
+
+void chksum_bios_set_value( byte* data, long offset, byte value ) {
+
+ *( data + BIOS_OFFSET ) = value;
+}
+
+
+byte chksum_pmid_calc_value( byte* data, long offset ) {
+
+ int i;
+ int len;
+ byte sum;
+
+ len = PMID_LEN;
+ check( offset + len <= MAX_OFFSET, "PMID entry length out of bounds" );
+ sum = 0;
+ for( i = 0; i < len; i++ ) {
+ if( i != PMID_CHKSUM ) {
+ sum = sum + *( data + offset + i );
+ }
+ }
+ sum = -sum;
+ return( sum );
+}
+
+
+long chksum_pmid_get_offset( byte* data, long offset ) {
+
+ long result = -1L;
+
+ while( offset + PMID_LEN < MAX_OFFSET ) {
+ offset = offset + 1;
+ if( *( data + offset + 0 ) == 'P' && \
+ *( data + offset + 1 ) == 'M' && \
+ *( data + offset + 2 ) == 'I' && \
+ *( data + offset + 3 ) == 'D' ) {
+ result = offset;
+ break;
+ }
+ }
+ return( result );
+}
+
+
+byte chksum_pmid_get_value( byte* data, long offset ) {
+
+ check( offset + PMID_CHKSUM <= MAX_OFFSET, "PMID checksum out of bounds" );
+ return( *( data + offset + PMID_CHKSUM ) );
+}
+
+
+void chksum_pmid_set_value( byte* data, long offset, byte value ) {
+
+ check( offset + PMID_CHKSUM <= MAX_OFFSET, "PMID checksum out of bounds" );
+ *( data + offset + PMID_CHKSUM ) = value;
+}
diff --git a/tools/firmware/vgabios/clext.c b/tools/firmware/vgabios/clext.c
new file mode 100644
index 0000000000..31a50a2326
--- /dev/null
+++ b/tools/firmware/vgabios/clext.c
@@ -0,0 +1,1587 @@
+//
+// 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
+ 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:
+ 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_extbios_handlers:
+ ;; 80h
+ dw cirrus_extbios_80h
+ dw cirrus_extbios_81h
+ dw cirrus_extbios_82h
+ dw cirrus_extbios_unimplemented
+ ;; 84h
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_85h
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ ;; 88h
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ ;; 8Ch
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ ;; 90h
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ ;; 94h
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ ;; 98h
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_9Ah
+ dw cirrus_extbios_unimplemented
+ ;; 9Ch
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ ;; A0h
+ dw cirrus_extbios_A0h
+ dw cirrus_extbios_A1h
+ dw cirrus_extbios_A2h
+ dw cirrus_extbios_unimplemented
+ ;; A4h
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ ;; A8h
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ ;; ACh
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_unimplemented
+ dw cirrus_extbios_AEh
+ dw cirrus_extbios_unimplemented
+
+cirrus_vesa_handlers:
+ ;; 00h
+ dw cirrus_vesa_00h
+ dw cirrus_vesa_01h
+ dw cirrus_vesa_02h
+ dw cirrus_vesa_03h
+ ;; 04h
+ dw cirrus_vesa_unimplemented
+ dw cirrus_vesa_05h
+ dw cirrus_vesa_06h
+ dw cirrus_vesa_07h
+ ;; 08h
+ dw cirrus_vesa_unimplemented
+ dw cirrus_vesa_unimplemented
+ dw cirrus_vesa_unimplemented
+ dw cirrus_vesa_unimplemented
+ ;; 0Ch
+ dw cirrus_vesa_unimplemented
+ dw cirrus_vesa_unimplemented
+ dw cirrus_vesa_unimplemented
+ dw cirrus_vesa_unimplemented
+
+
+
+ASM_END
+
+#ifdef CIRRUS_VESA3_PMINFO
+ASM_START
+cirrus_vesa_pminfo:
+ /* + 0 */
+ .byte 0x50,0x4d,0x49,0x44 ;; signature[4]
+ /* + 4 */
+ dw cirrus_vesa_pmbios_entry ;; entry_bios
+ dw cirrus_vesa_pmbios_init ;; entry_init
+ /* + 8 */
+cirrus_vesa_sel0000_data:
+ dw 0x0000 ;; sel_00000
+cirrus_vesa_selA000_data:
+ dw 0xA000 ;; sel_A0000
+ /* +12 */
+cirrus_vesa_selB000_data:
+ dw 0xB000 ;; sel_B0000
+cirrus_vesa_selB800_data:
+ dw 0xB800 ;; sel_B8000
+ /* +16 */
+cirrus_vesa_selC000_data:
+ dw 0xC000 ;; sel_C0000
+cirrus_vesa_is_protected_mode:
+ ;; protected mode flag and checksum
+ dw (~((0xf2 + (cirrus_vesa_pmbios_entry >> 8) + (cirrus_vesa_pmbios_entry) \
+ + (cirrus_vesa_pmbios_init >> 8) + (cirrus_vesa_pmbios_init)) & 0xff) << 8) + 0x01
+ASM_END
+#endif // CIRRUS_VESA3_PMINFO
+
+
+#ifdef CIRRUS_DEBUG
+static void cirrus_debugmsg(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
+ Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
+{
+ if((GET_AH()!=0x0E)&&(GET_AH()!=0x02)&&(GET_AH()!=0x09)&&(AX!=0x4F05))
+ printf("vgabios call ah%02x al%02x bx%04x cx%04x dx%04x\n",GET_AH(),GET_AL(),BX,CX,DX);
+}
+#endif
diff --git a/tools/firmware/vgabios/dataseghack b/tools/firmware/vgabios/dataseghack
new file mode 100755
index 0000000000..02a2d4c525
--- /dev/null
+++ b/tools/firmware/vgabios/dataseghack
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+awk \
+ 'BEGIN { }\
+ /^\.text/,/DATA_SEG_DEFS_HERE/ { print }\
+ END { }'\
+ $1 > temp.awk.1
+
+awk \
+ 'BEGIN { i = 0; last = "hello" }\
+ /BLOCK_STRINGS_BEGIN/,/^\.bss/ { if ( i > 1 ) { print last } last = $0; i = i + 1 }\
+ END { }'\
+ $1 > temp.awk.2
+
+awk \
+ 'BEGIN { }\
+ /DATA_SEG_DEFS_HERE/,/BLOCK_STRINGS_BEGIN/ { print }\
+ END { }'\
+ $1 > temp.awk.3
+
+cp $1 $1.orig
+cat temp.awk.1 temp.awk.2 temp.awk.3 | sed -e 's/^\.data//' -e 's/^\.bss//' -e 's/^\.text//' > $1
+/bin/rm -f temp.awk.1 temp.awk.2 temp.awk.3 $1.orig
diff --git a/tools/firmware/vgabios/vbe.c b/tools/firmware/vgabios/vbe.c
new file mode 100644
index 0000000000..e71099546e
--- /dev/null
+++ b/tools/firmware/vgabios/vbe.c
@@ -0,0 +1,1068 @@
+// ============================================================================================
+//
+// Copyright (C) 2002 Jeroen Janssen
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// ============================================================================================
+//
+// This VBE is part of the VGA Bios specific to the plex86/bochs Emulated VGA card.
+// You can NOT drive any physical vga card with it.
+//
+// ============================================================================================
+//
+// This VBE Bios is based on information taken from :
+// - VESA BIOS EXTENSION (VBE) Core Functions Standard Version 3.0 located at www.vesa.org
+//
+// ============================================================================================
+
+
+// defines available
+// enable LFB support
+#define VBE_HAVE_LFB
+
+// disable VESA/VBE2 check in vbe info
+//#define VBE2_NO_VESA_CHECK
+
+// dynamicly generate a mode_info list
+#define DYN_LIST
+
+
+#include "vbe.h"
+#include "vbetables.h"
+
+
+// The current OEM Software Revision of this VBE Bios
+#define VBE_OEM_SOFTWARE_REV 0x0002;
+
+extern char vbebios_copyright;
+extern char vbebios_vendor_name;
+extern char vbebios_product_name;
+extern char vbebios_product_revision;
+
+#ifndef DYN_LIST
+extern Bit16u vbebios_mode_list;
+#endif
+
+ASM_START
+// FIXME: 'merge' these (c) etc strings with the vgabios.c strings?
+_vbebios_copyright:
+.ascii "Bochs/Plex86 VBE(C) 2003 http://savannah.nongnu.org/projects/vgabios/"
+.byte 0x00
+
+_vbebios_vendor_name:
+.ascii "Bochs/Plex86 Developers"
+.byte 0x00
+
+_vbebios_product_name:
+.ascii "Bochs/Plex86 VBE Adapter"
+.byte 0x00
+
+_vbebios_product_revision:
+.ascii "$Id: vbe.c,v 1.47 2005/05/24 16:50:50 vruppert 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.47 2005/05/24 16:50:50 vruppert Exp $"
+.byte 0x0a,0x0d, 0x00
+#endif
+
+#ifndef DYN_LIST
+// FIXME: for each new mode add a statement here
+// at least until dynamic list creation is working
+_vbebios_mode_list:
+
+.word VBE_VESA_MODE_640X400X8
+.word VBE_VESA_MODE_640X480X8
+.word VBE_VESA_MODE_800X600X4
+.word VBE_VESA_MODE_800X600X8
+.word VBE_VESA_MODE_1024X768X8
+.word VBE_VESA_MODE_640X480X1555
+.word VBE_VESA_MODE_640X480X565
+.word VBE_VESA_MODE_640X480X888
+.word VBE_VESA_MODE_800X600X1555
+.word VBE_VESA_MODE_800X600X565
+.word VBE_VESA_MODE_800X600X888
+.word VBE_VESA_MODE_1024X768X1555
+.word VBE_VESA_MODE_1024X768X565
+.word VBE_VESA_MODE_1024X768X888
+.word VBE_OWN_MODE_640X480X8888
+.word VBE_OWN_MODE_800X600X8888
+.word VBE_OWN_MODE_1024X768X8888
+.word VBE_OWN_MODE_320X200X8
+.word VBE_VESA_MODE_END_OF_LIST
+#endif
+
+; DISPI ioport functions
+
+dispi_get_id:
+ push dx
+ mov dx, # VBE_DISPI_IOPORT_INDEX
+ mov ax, # VBE_DISPI_INDEX_ID
+ out dx, ax
+ mov dx, # VBE_DISPI_IOPORT_DATA
+ in ax, dx
+ pop dx
+ ret
+
+dispi_set_id:
+ push dx
+ push ax
+ mov dx, # VBE_DISPI_IOPORT_INDEX
+ mov ax, # VBE_DISPI_INDEX_ID
+ out dx, ax
+ pop ax
+ mov dx, # VBE_DISPI_IOPORT_DATA
+ out dx, ax
+ pop dx
+ ret
+ASM_END
+
+static void dispi_set_xres(xres)
+ Bit16u xres;
+{
+ASM_START
+ push bp
+ mov bp, sp
+ push ax
+ push dx
+
+ mov dx, # VBE_DISPI_IOPORT_INDEX
+ mov ax, # VBE_DISPI_INDEX_XRES
+ out dx, ax
+ mov dx, # VBE_DISPI_IOPORT_DATA
+ mov ax, 4[bp] ; xres
+ out dx, ax
+ push ax
+ mov dx, #0x03d4
+ mov ax, #0x0011
+ out dx, ax
+ mov dx, #0x03d4
+ pop ax
+ push ax
+ shr ax, #3
+ dec ax
+ mov ah, al
+ mov al, #0x01
+ out dx, ax
+ pop ax
+ call vga_set_virt_width
+
+ pop dx
+ pop ax
+ pop bp
+ASM_END
+}
+
+static void dispi_set_yres(yres)
+ Bit16u yres;
+{
+ outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_YRES);
+ outw(VBE_DISPI_IOPORT_DATA,yres);
+}
+
+static void dispi_set_bpp(bpp)
+ Bit16u bpp;
+{
+ outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_BPP);
+ outw(VBE_DISPI_IOPORT_DATA,bpp);
+}
+
+ASM_START
+; AL = bits per pixel / AH = bytes per pixel
+dispi_get_bpp:
+ push dx
+ mov dx, # VBE_DISPI_IOPORT_INDEX
+ mov ax, # VBE_DISPI_INDEX_BPP
+ out dx, ax
+ mov dx, # VBE_DISPI_IOPORT_DATA
+ in ax, dx
+ mov ah, al
+ shr ah, 3
+ test al, #0x07
+ jz get_bpp_noinc
+ inc ah
+get_bpp_noinc:
+ pop dx
+ ret
+
+_dispi_get_max_bpp:
+ push dx
+ push bx
+ call dispi_get_enable
+ mov bx, ax
+ or ax, # VBE_DISPI_GETCAPS
+ call _dispi_set_enable
+ mov dx, # VBE_DISPI_IOPORT_INDEX
+ mov ax, # VBE_DISPI_INDEX_BPP
+ out dx, ax
+ mov dx, # VBE_DISPI_IOPORT_DATA
+ in ax, dx
+ push ax
+ mov ax, bx
+ call _dispi_set_enable
+ pop ax
+ pop bx
+ pop dx
+ ret
+
+_dispi_set_enable:
+ push dx
+ push ax
+ mov dx, # VBE_DISPI_IOPORT_INDEX
+ mov ax, # VBE_DISPI_INDEX_ENABLE
+ out dx, ax
+ pop ax
+ mov dx, # VBE_DISPI_IOPORT_DATA
+ out dx, ax
+ pop dx
+ ret
+
+dispi_get_enable:
+ push dx
+ mov dx, # VBE_DISPI_IOPORT_INDEX
+ mov ax, # VBE_DISPI_INDEX_ENABLE
+ out dx, ax
+ mov dx, # VBE_DISPI_IOPORT_DATA
+ in ax, dx
+ pop dx
+ ret
+
+_dispi_set_bank:
+ push dx
+ push ax
+ mov dx, # VBE_DISPI_IOPORT_INDEX
+ mov ax, # VBE_DISPI_INDEX_BANK
+ out dx, ax
+ pop ax
+ mov dx, # VBE_DISPI_IOPORT_DATA
+ out dx, ax
+ pop dx
+ ret
+
+dispi_get_bank:
+ push dx
+ mov dx, # VBE_DISPI_IOPORT_INDEX
+ mov ax, # VBE_DISPI_INDEX_BANK
+ out dx, ax
+ mov dx, # VBE_DISPI_IOPORT_DATA
+ in ax, dx
+ pop dx
+ ret
+ASM_END
+
+static void dispi_set_bank_farcall()
+{
+ASM_START
+ cmp bx,#0x0100
+ je dispi_set_bank_farcall_get
+ or bx,bx
+ jnz dispi_set_bank_farcall_error
+ push dx
+ mov ax,# VBE_DISPI_INDEX_BANK
+ mov dx,# VBE_DISPI_IOPORT_INDEX
+ out dx,ax
+ pop ax
+ mov dx,# VBE_DISPI_IOPORT_DATA
+ out dx,ax
+ retf
+dispi_set_bank_farcall_get:
+ mov ax,# VBE_DISPI_INDEX_BANK
+ mov dx,# VBE_DISPI_IOPORT_INDEX
+ out dx,ax
+ mov dx,# VBE_DISPI_IOPORT_DATA
+ in ax,dx
+ mov dx,ax
+ retf
+dispi_set_bank_farcall_error:
+ mov ax,#0x014F
+ retf
+ASM_END
+}
+
+ASM_START
+dispi_set_x_offset:
+ push dx
+ push ax
+ mov dx, # VBE_DISPI_IOPORT_INDEX
+ mov ax, # VBE_DISPI_INDEX_X_OFFSET
+ out dx, ax
+ pop ax
+ mov dx, # VBE_DISPI_IOPORT_DATA
+ out dx, ax
+ pop dx
+ ret
+
+dispi_get_x_offset:
+ push dx
+ mov dx, # VBE_DISPI_IOPORT_INDEX
+ mov ax, # VBE_DISPI_INDEX_X_OFFSET
+ out dx, ax
+ mov dx, # VBE_DISPI_IOPORT_DATA
+ in ax, dx
+ pop dx
+ ret
+
+dispi_set_y_offset:
+ push dx
+ push ax
+ mov dx, # VBE_DISPI_IOPORT_INDEX
+ mov ax, # VBE_DISPI_INDEX_Y_OFFSET
+ out dx, ax
+ pop ax
+ mov dx, # VBE_DISPI_IOPORT_DATA
+ out dx, ax
+ pop dx
+ ret
+
+dispi_get_y_offset:
+ push dx
+ mov dx, # VBE_DISPI_IOPORT_INDEX
+ mov ax, # VBE_DISPI_INDEX_Y_OFFSET
+ out dx, ax
+ mov dx, # VBE_DISPI_IOPORT_DATA
+ in ax, dx
+ pop dx
+ ret
+
+vga_set_virt_width:
+ push ax
+ push bx
+ push dx
+ mov bx, ax
+ call dispi_get_bpp
+ cmp al, #0x04
+ ja set_width_svga
+ shr bx, #2
+set_width_svga:
+ shr bx, #2
+ mov dx, #0x03d4
+ mov ah, bl
+ mov al, #0x13
+ out dx, ax
+ pop dx
+ pop bx
+ pop ax
+ ret
+
+dispi_set_virt_width:
+ call vga_set_virt_width
+ push dx
+ push ax
+ mov dx, # VBE_DISPI_IOPORT_INDEX
+ mov ax, # VBE_DISPI_INDEX_VIRT_WIDTH
+ out dx, ax
+ pop ax
+ mov dx, # VBE_DISPI_IOPORT_DATA
+ out dx, ax
+ pop dx
+ ret
+
+dispi_get_virt_width:
+ push dx
+ mov dx, # VBE_DISPI_IOPORT_INDEX
+ mov ax, # VBE_DISPI_INDEX_VIRT_WIDTH
+ out dx, ax
+ mov dx, # VBE_DISPI_IOPORT_DATA
+ in ax, dx
+ pop dx
+ ret
+
+dispi_get_virt_height:
+ push dx
+ mov dx, # VBE_DISPI_IOPORT_INDEX
+ mov ax, # VBE_DISPI_INDEX_VIRT_HEIGHT
+ out dx, ax
+ mov dx, # VBE_DISPI_IOPORT_DATA
+ in ax, dx
+ pop dx
+ ret
+ASM_END
+
+
+// ModeInfo helper function
+static ModeInfoListItem* mode_info_find_mode(mode, using_lfb)
+ Bit16u mode; Boolean using_lfb;
+{
+ ModeInfoListItem *cur_info=&mode_info_list;
+
+ while (cur_info->mode != VBE_VESA_MODE_END_OF_LIST)
+ {
+ if (cur_info->mode == mode)
+ {
+ if (!using_lfb)
+ {
+ return cur_info;
+ }
+ else if (cur_info->info.ModeAttributes & VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE)
+ {
+ return cur_info;
+ }
+ else
+ {
+ cur_info++;
+ }
+ }
+ else
+ {
+ cur_info++;
+ }
+ }
+
+ return 0;
+}
+
+ASM_START
+
+; Has VBE display - Returns true if VBE display detected
+
+_vbe_has_vbe_display:
+ push ds
+ push bx
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ mov bx, # BIOSMEM_VBE_FLAG
+ mov al, [bx]
+ and al, #0x01
+ xor ah, ah
+ pop bx
+ pop ds
+ ret
+
+; VBE Init - Initialise the Vesa Bios Extension Code
+; This function does a sanity check on the host side display code interface.
+
+vbe_init:
+ mov ax, # VBE_DISPI_ID0
+ call dispi_set_id
+ call dispi_get_id
+ cmp ax, # VBE_DISPI_ID0
+ jne no_vbe_interface
+ push ds
+ push bx
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ mov bx, # BIOSMEM_VBE_FLAG
+ mov al, #0x01
+ mov [bx], al
+ pop bx
+ pop ds
+ mov ax, # VBE_DISPI_ID3
+ call dispi_set_id
+no_vbe_interface:
+#if defined(USE_BX_INFO) || defined(DEBUG)
+ mov bx, #msg_vbe_init
+ push bx
+ call _printf
+ inc sp
+ inc sp
+#endif
+ ret
+
+; VBE Display Info - Display information on screen about the VBE
+
+vbe_display_info:
+ call _vbe_has_vbe_display
+ test ax, ax
+ jz no_vbe_flag
+ mov ax, #0xc000
+ mov ds, ax
+ mov si, #_vbebios_info_string
+ jmp _display_string
+no_vbe_flag:
+ mov ax, #0xc000
+ mov ds, ax
+ mov si, #_no_vbebios_info_string
+ jmp _display_string
+ASM_END
+
+/** Function 00h - Return VBE Controller Information
+ *
+ * Input:
+ * AX = 4F00h
+ * ES:DI = Pointer to buffer in which to place VbeInfoBlock structure
+ * (VbeSignature should be VBE2 when VBE 2.0 information is desired and
+ * the info block is 512 bytes in size)
+ * Output:
+ * AX = VBE Return Status
+ *
+ */
+void vbe_biosfn_return_controller_information(AX, ES, DI)
+Bit16u *AX;Bit16u ES;Bit16u DI;
+{
+ Bit16u ss=get_SS();
+ VbeInfoBlock vbe_info_block;
+ Bit16u status;
+ Bit16u result;
+ Bit16u vbe2_info;
+ Bit16u cur_mode=0;
+ Bit16u cur_ptr=34;
+ ModeInfoListItem *cur_info=&mode_info_list;
+
+ status = read_word(ss, AX);
+
+#ifdef DEBUG
+ printf("VBE vbe_biosfn_return_vbe_info ES%x DI%x AX%x\n",ES,DI,status);
+#endif
+
+ vbe2_info = 0;
+#ifdef VBE2_NO_VESA_CHECK
+#else
+ // get vbe_info_block into local variable
+ memcpyb(ss, &vbe_info_block, ES, DI, sizeof(vbe_info_block));
+
+ // check for VBE2 signature
+ if (((vbe_info_block.VbeSignature[0] == 'V') &&
+ (vbe_info_block.VbeSignature[1] == 'B') &&
+ (vbe_info_block.VbeSignature[2] == 'E') &&
+ (vbe_info_block.VbeSignature[3] == '2')) ||
+
+ ((vbe_info_block.VbeSignature[0] == 'V') &&
+ (vbe_info_block.VbeSignature[1] == 'E') &&
+ (vbe_info_block.VbeSignature[2] == 'S') &&
+ (vbe_info_block.VbeSignature[3] == 'A')) )
+ {
+ vbe2_info = 1;
+#ifdef DEBUG
+ printf("VBE correct VESA/VBE2 signature found\n");
+#endif
+ }
+#endif
+
+ // VBE Signature
+ vbe_info_block.VbeSignature[0] = 'V';
+ vbe_info_block.VbeSignature[1] = 'E';
+ vbe_info_block.VbeSignature[2] = 'S';
+ vbe_info_block.VbeSignature[3] = 'A';
+
+ // VBE Version supported
+ vbe_info_block.VbeVersion = 0x0200;
+
+ // OEM String
+ vbe_info_block.OemStringPtr_Seg = 0xc000;
+ vbe_info_block.OemStringPtr_Off = &vbebios_copyright;
+
+ // Capabilities
+ vbe_info_block.Capabilities[0] = VBE_CAPABILITY_8BIT_DAC;
+ vbe_info_block.Capabilities[1] = 0;
+ vbe_info_block.Capabilities[2] = 0;
+ vbe_info_block.Capabilities[3] = 0;
+
+#ifdef DYN_LIST
+ // VBE Video Mode Pointer (dynamicly generated from the mode_info_list)
+ vbe_info_block.VideoModePtr_Seg= ES ;
+ vbe_info_block.VideoModePtr_Off= DI + 34;
+#else
+ // VBE Video Mode Pointer (staticly in rom)
+ vbe_info_block.VideoModePtr_Seg = 0xc000;
+ vbe_info_block.VideoModePtr_Off = &vbebios_mode_list;
+#endif
+
+ // VBE Total Memory (in 64b blocks)
+ vbe_info_block.TotalMemory = VBE_TOTAL_VIDEO_MEMORY_DIV_64K;
+
+ if (vbe2_info)
+ {
+ // OEM Stuff
+ vbe_info_block.OemSoftwareRev = VBE_OEM_SOFTWARE_REV;
+ vbe_info_block.OemVendorNamePtr_Seg = 0xc000;
+ vbe_info_block.OemVendorNamePtr_Off = &vbebios_vendor_name;
+ vbe_info_block.OemProductNamePtr_Seg = 0xc000;
+ vbe_info_block.OemProductNamePtr_Off = &vbebios_product_name;
+ vbe_info_block.OemProductRevPtr_Seg = 0xc000;
+ vbe_info_block.OemProductRevPtr_Off = &vbebios_product_revision;
+
+ // copy updates in vbe_info_block back
+ memcpyb(ES, DI, ss, &vbe_info_block, sizeof(vbe_info_block));
+ }
+ else
+ {
+ // copy updates in vbe_info_block back (VBE 1.x compatibility)
+ memcpyb(ES, DI, ss, &vbe_info_block, 256);
+ }
+
+#ifdef DYN_LIST
+ do
+ {
+ if (cur_info->info.BitsPerPixel <= dispi_get_max_bpp()) {
+#ifdef DEBUG
+ printf("VBE found mode %x => %x\n", cur_info->mode,cur_mode);
+#endif
+ write_word(ES, DI + cur_ptr, cur_info->mode);
+ cur_mode++;
+ cur_ptr+=2;
+ }
+ cur_info++;
+ } while (cur_info->mode != VBE_VESA_MODE_END_OF_LIST);
+
+ // Add vesa mode list terminator
+ write_word(ES, DI + cur_ptr, cur_info->mode);
+#endif
+
+ result = 0x4f;
+
+ write_word(ss, AX, result);
+}
+
+
+/** Function 01h - Return VBE Mode Information
+ *
+ * Input:
+ * AX = 4F01h
+ * CX = Mode Number
+ * ES:DI = Pointer to buffer in which to place ModeInfoBlock structure
+ * Output:
+ * AX = VBE Return Status
+ *
+ */
+void vbe_biosfn_return_mode_information(AX, CX, ES, DI)
+Bit16u *AX;Bit16u CX; Bit16u ES;Bit16u DI;
+{
+ Bit16u result=0x0100;
+ Bit16u ss=get_SS();
+ ModeInfoBlock info;
+ ModeInfoListItem *cur_info;
+ Boolean using_lfb;
+
+#ifdef DEBUG
+ printf("VBE vbe_biosfn_return_mode_information ES%x DI%x CX%x\n",ES,DI,CX);
+#endif
+
+ using_lfb=((CX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER);
+
+ CX = (CX & 0x1ff);
+
+ cur_info = mode_info_find_mode(CX, using_lfb, &cur_info);
+
+ if (cur_info != 0)
+ {
+#ifdef DEBUG
+ printf("VBE found mode %x\n",CX);
+#endif
+ memsetb(ss, &info, 0, sizeof(ModeInfoBlock));
+ memcpyb(ss, &info, 0xc000, &(cur_info->info), sizeof(ModeInfoBlockCompact));
+ if (info.WinAAttributes & VBE_WINDOW_ATTRIBUTE_RELOCATABLE) {
+ info.WinFuncPtr = 0xC0000000UL;
+ *(Bit16u *)&(info.WinFuncPtr) = (Bit16u)(dispi_set_bank_farcall);
+ }
+
+ result = 0x4f;
+ }
+ else
+ {
+#ifdef DEBUG
+ printf("VBE *NOT* found mode %x\n",CX);
+#endif
+ result = 0x100;
+ }
+
+ if (result == 0x4f)
+ {
+ // copy updates in mode_info_block back
+ memcpyb(ES, DI, ss, &info, sizeof(info));
+ }
+
+ write_word(ss, AX, result);
+}
+
+/** Function 02h - Set VBE Mode
+ *
+ * Input:
+ * AX = 4F02h
+ * BX = Desired Mode to set
+ * ES:DI = Pointer to CRTCInfoBlock structure
+ * Output:
+ * AX = VBE Return Status
+ *
+ */
+void vbe_biosfn_set_mode(AX, BX, ES, DI)
+Bit16u *AX;Bit16u BX; Bit16u ES;Bit16u DI;
+{
+ Bit16u ss = get_SS();
+ Bit16u result;
+ ModeInfoListItem *cur_info;
+ Boolean using_lfb;
+ Bit8u no_clear;
+ Bit8u lfb_flag;
+
+ using_lfb=((BX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER);
+ lfb_flag=using_lfb?VBE_DISPI_LFB_ENABLED:0;
+ no_clear=((BX & VBE_MODE_PRESERVE_DISPLAY_MEMORY) == VBE_MODE_PRESERVE_DISPLAY_MEMORY)?VBE_DISPI_NOCLEARMEM:0;
+
+ BX = (BX & 0x1ff);
+
+ //result=read_word(ss,AX);
+
+ // check for non vesa mode
+ if (BX<VBE_MODE_VESA_DEFINED)
+ {
+ Bit8u mode;
+
+ dispi_set_enable(VBE_DISPI_DISABLED);
+ // call the vgabios in order to set the video mode
+ // this allows for going back to textmode with a VBE call (some applications expect that to work)
+
+ mode=(BX & 0xff);
+ biosfn_set_video_mode(mode);
+ result = 0x4f;
+ }
+
+ cur_info = mode_info_find_mode(BX, using_lfb, &cur_info);
+
+ if (cur_info != 0)
+ {
+#ifdef DEBUG
+ printf("VBE found mode %x, setting:\n", BX);
+ printf("\txres%x yres%x bpp%x\n",
+ cur_info->info.XResolution,
+ cur_info->info.YResolution,
+ cur_info->info.BitsPerPixel);
+#endif
+
+ // first disable current mode (when switching between vesa modi)
+ dispi_set_enable(VBE_DISPI_DISABLED);
+
+ if (cur_info->mode == VBE_VESA_MODE_800X600X4)
+ {
+ biosfn_set_video_mode(0x6a);
+ }
+
+ dispi_set_bpp(cur_info->info.BitsPerPixel);
+ dispi_set_xres(cur_info->info.XResolution);
+ dispi_set_yres(cur_info->info.YResolution);
+ dispi_set_bank(0);
+ dispi_set_enable(VBE_DISPI_ENABLED | no_clear | lfb_flag);
+
+ write_word(BIOSMEM_SEG,BIOSMEM_VBE_MODE,BX);
+ write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60 | no_clear));
+
+ result = 0x4f;
+ }
+ else
+ {
+#ifdef DEBUG
+ printf("VBE *NOT* found mode %x\n" , BX);
+#endif
+ result = 0x100;
+
+ // FIXME: redirect non VBE modi to normal VGA bios operation
+ // (switch back to VGA mode
+ if (BX == 3)
+ result = 0x4f;
+ }
+
+ write_word(ss, AX, result);
+}
+
+/** Function 03h - Return Current VBE Mode
+ *
+ * Input:
+ * AX = 4F03h
+ * Output:
+ * AX = VBE Return Status
+ * BX = Current VBE Mode
+ *
+ */
+ASM_START
+vbe_biosfn_return_current_mode:
+ push ds
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ call dispi_get_enable
+ and ax, # VBE_DISPI_ENABLED
+ jz no_vbe_mode
+ mov bx, # BIOSMEM_VBE_MODE
+ mov ax, [bx]
+ mov bx, ax
+ jnz vbe_03_ok
+no_vbe_mode:
+ mov bx, # BIOSMEM_CURRENT_MODE
+ mov al, [bx]
+ mov bl, al
+ xor bh, bh
+vbe_03_ok:
+ mov ax, #0x004f
+ pop ds
+ ret
+ASM_END
+
+
+/** Function 04h - Save/Restore State
+ *
+ * Input:
+ * AX = 4F04h
+ * DL = 00h Return Save/Restore State buffer size
+ * 01h Save State
+ * 02h Restore State
+ * CX = Requested states
+ * ES:BX = Pointer to buffer (if DL <> 00h)
+ * Output:
+ * AX = VBE Return Status
+ * BX = Number of 64-byte blocks to hold the state buffer (if DL=00h)
+ *
+ */
+void vbe_biosfn_save_restore_state(AX, DL, CX, ES, BX)
+{
+}
+
+
+/** Function 05h - Display Window Control
+ *
+ * Input:
+ * AX = 4F05h
+ * (16-bit) BH = 00h Set memory window
+ * = 01h Get memory window
+ * BL = Window number
+ * = 00h Window A
+ * = 01h Window B
+ * DX = Window number in video memory in window
+ * granularity units (Set Memory Window only)
+ * Note:
+ * If this function is called while in a linear frame buffer mode,
+ * this function must fail with completion code AH=03h
+ *
+ * Output:
+ * AX = VBE Return Status
+ * DX = Window number in window granularity units
+ * (Get Memory Window only)
+ */
+ASM_START
+vbe_biosfn_display_window_control:
+ cmp bl, #0x00
+ jne vbe_05_failed
+ cmp bh, #0x01
+ je get_display_window
+ jb set_display_window
+ mov ax, #0x0100
+ ret
+set_display_window:
+ mov ax, dx
+ call _dispi_set_bank
+ call dispi_get_bank
+ cmp ax, dx
+ jne vbe_05_failed
+ mov ax, #0x004f
+ ret
+get_display_window:
+ call dispi_get_bank
+ mov dx, ax
+ mov ax, #0x004f
+ ret
+vbe_05_failed:
+ mov ax, #0x014f
+ ret
+ASM_END
+
+
+/** Function 06h - Set/Get Logical Scan Line Length
+ *
+ * Input:
+ * AX = 4F06h
+ * BL = 00h Set Scan Line Length in Pixels
+ * = 01h Get Scan Line Length
+ * = 02h Set Scan Line Length in Bytes
+ * = 03h Get Maximum Scan Line Length
+ * CX = If BL=00h Desired Width in Pixels
+ * If BL=02h Desired Width in Bytes
+ * (Ignored for Get Functions)
+ *
+ * Output:
+ * AX = VBE Return Status
+ * BX = Bytes Per Scan Line
+ * CX = Actual Pixels Per Scan Line
+ * (truncated to nearest complete pixel)
+ * DX = Maximum Number of Scan Lines
+ */
+ASM_START
+vbe_biosfn_set_get_logical_scan_line_length:
+ mov ax, cx
+ cmp bl, #0x01
+ je get_logical_scan_line_length
+ cmp bl, #0x02
+ je set_logical_scan_line_bytes
+ jb set_logical_scan_line_pixels
+ mov ax, #0x0100
+ ret
+set_logical_scan_line_bytes:
+ push ax
+ call dispi_get_bpp
+ xor bh, bh
+ mov bl, ah
+ xor dx, dx
+ pop ax
+ div bx
+set_logical_scan_line_pixels:
+ call dispi_set_virt_width
+get_logical_scan_line_length:
+ call dispi_get_bpp
+ xor bh, bh
+ mov bl, ah
+ call dispi_get_virt_width
+ mov cx, ax
+ mul bx
+ mov bx, ax
+ call dispi_get_virt_height
+ mov dx, ax
+ mov ax, #0x004f
+ ret
+ASM_END
+
+
+/** Function 07h - Set/Get Display Start
+ *
+ * Input(16-bit):
+ * AX = 4F07h
+ * BH = 00h Reserved and must be 00h
+ * BL = 00h Set Display Start
+ * = 01h Get Display Start
+ * = 02h Schedule Display Start (Alternate)
+ * = 03h Schedule Stereoscopic Display Start
+ * = 04h Get Scheduled Display Start Status
+ * = 05h Enable Stereoscopic Mode
+ * = 06h Disable Stereoscopic Mode
+ * = 80h Set Display Start during Vertical Retrace
+ * = 82h Set Display Start during Vertical Retrace (Alternate)
+ * = 83h Set Stereoscopic Display Start during Vertical Retrace
+ * ECX = If BL=02h/82h Display Start Address in bytes
+ * If BL=03h/83h Left Image Start Address in bytes
+ * EDX = If BL=03h/83h Right Image Start Address in bytes
+ * CX = If BL=00h/80h First Displayed Pixel In Scan Line
+ * DX = If BL=00h/80h First Displayed Scan Line
+ *
+ * Output:
+ * AX = VBE Return Status
+ * BH = If BL=01h Reserved and will be 0
+ * CX = If BL=01h First Displayed Pixel In Scan Line
+ * If BL=04h 0 if flip has not occurred, not 0 if it has
+ * DX = If BL=01h First Displayed Scan Line
+ *
+ * Input(32-bit):
+ * BH = 00h Reserved and must be 00h
+ * BL = 00h Set Display Start
+ * = 80h Set Display Start during Vertical Retrace
+ * CX = Bits 0-15 of display start address
+ * DX = Bits 16-31 of display start address
+ * ES = Selector for memory mapped registers
+ */
+ASM_START
+vbe_biosfn_set_get_display_start:
+ cmp bl, #0x80
+ je set_display_start
+ cmp bl, #0x01
+ je get_display_start
+ jb set_display_start
+ mov ax, #0x0100
+ ret
+set_display_start:
+ mov ax, cx
+ call dispi_set_x_offset
+ mov ax, dx
+ call dispi_set_y_offset
+ mov ax, #0x004f
+ ret
+get_display_start:
+ call dispi_get_x_offset
+ mov cx, ax
+ call dispi_get_y_offset
+ mov dx, ax
+ xor bh, bh
+ mov ax, #0x004f
+ ret
+ASM_END
+
+
+/** Function 08h - Set/Get Dac Palette Format
+ *
+ * Input:
+ * AX = 4F08h
+ * BL = 00h set DAC palette width
+ * = 01h get DAC palette width
+ * BH = If BL=00h: desired number of bits per primary color
+ * Output:
+ * AX = VBE Return Status
+ * BH = current number of bits per primary color (06h = standard VGA)
+ */
+ASM_START
+vbe_biosfn_set_get_dac_palette_format:
+ cmp bl, #0x01
+ je get_dac_palette_format
+ jb set_dac_palette_format
+ mov ax, #0x0100
+ ret
+set_dac_palette_format:
+ call dispi_get_enable
+ cmp bh, #0x06
+ je set_normal_dac
+ cmp bh, #0x08
+ jne vbe_08_unsupported
+ or ax, # VBE_DISPI_8BIT_DAC
+ jnz set_dac_mode
+set_normal_dac:
+ and ax, #~ VBE_DISPI_8BIT_DAC
+set_dac_mode:
+ call _dispi_set_enable
+get_dac_palette_format:
+ mov bh, #0x06
+ call dispi_get_enable
+ and ax, # VBE_DISPI_8BIT_DAC
+ jz vbe_08_ok
+ mov bh, #0x08
+vbe_08_ok:
+ mov ax, #0x004f
+ ret
+vbe_08_unsupported:
+ mov ax, #0x014f
+ ret
+ASM_END
+
+
+/** Function 09h - Set/Get Palette Data
+ *
+ * Input:
+ * AX = 4F09h
+ * Output:
+ * AX = VBE Return Status
+ *
+ * FIXME: incomplete API description, Input & Output
+ */
+void vbe_biosfn_set_get_palette_data(AX)
+{
+}
+
+/** Function 0Ah - Return VBE Protected Mode Interface
+ *
+ * Input:
+ * AX = 4F0Ah
+ * Output:
+ * AX = VBE Return Status
+ *
+ * FIXME: incomplete API description, Input & Output
+ */
+void vbe_biosfn_return_protected_mode_interface(AX)
+{
+}
diff --git a/tools/firmware/vgabios/vbe.h b/tools/firmware/vgabios/vbe.h
new file mode 100644
index 0000000000..621048a1c7
--- /dev/null
+++ b/tools/firmware/vgabios/vbe.h
@@ -0,0 +1,302 @@
+#ifndef vbe_h_included
+#define vbe_h_included
+
+#include "vgabios.h"
+
+// DISPI helper function
+void dispi_set_enable(enable);
+
+/** VBE int10 API
+ *
+ * See the function descriptions in vbe.c for more information
+ */
+Boolean vbe_has_vbe_display();
+void vbe_biosfn_return_controller_information(AX, ES, DI);
+void vbe_biosfn_return_mode_information(AX, CX, ES, DI);
+void vbe_biosfn_set_mode(AX, BX, ES, DI);
+void vbe_biosfn_save_restore_state(AX, DL, CX, ES, BX);
+void vbe_biosfn_set_get_palette_data(AX);
+void vbe_biosfn_return_protected_mode_interface(AX);
+
+// The official VBE Information Block
+typedef struct VbeInfoBlock
+{
+ Bit8u VbeSignature[4];
+ Bit16u VbeVersion;
+ Bit16u OemStringPtr_Off;
+ Bit16u OemStringPtr_Seg;
+ Bit8u Capabilities[4];
+ Bit16u VideoModePtr_Off;
+ Bit16u VideoModePtr_Seg;
+ Bit16u TotalMemory;
+ Bit16u OemSoftwareRev;
+ Bit16u OemVendorNamePtr_Off;
+ Bit16u OemVendorNamePtr_Seg;
+ Bit16u OemProductNamePtr_Off;
+ Bit16u OemProductNamePtr_Seg;
+ Bit16u OemProductRevPtr_Off;
+ Bit16u OemProductRevPtr_Seg;
+ Bit16u Reserved[111]; // used for dynamicly generated mode list
+ Bit8u OemData[256];
+} VbeInfoBlock;
+
+
+// This one is for compactly storing a static list of mode info blocks
+// this saves us 189 bytes per block
+typedef struct ModeInfoBlockCompact
+{
+// Mandatory information for all VBE revisions
+ Bit16u ModeAttributes;
+ Bit8u WinAAttributes;
+ Bit8u WinBAttributes;
+ Bit16u WinGranularity;
+ Bit16u WinSize;
+ Bit16u WinASegment;
+ Bit16u WinBSegment;
+ Bit32u WinFuncPtr;
+ Bit16u BytesPerScanLine;
+// Mandatory information for VBE 1.2 and above
+ Bit16u XResolution;
+ Bit16u YResolution;
+ Bit8u XCharSize;
+ Bit8u YCharSize;
+ Bit8u NumberOfPlanes;
+ Bit8u BitsPerPixel;
+ Bit8u NumberOfBanks;
+ Bit8u MemoryModel;
+ Bit8u BankSize;
+ Bit8u NumberOfImagePages;
+ Bit8u Reserved_page;
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ Bit8u RedMaskSize;
+ Bit8u RedFieldPosition;
+ Bit8u GreenMaskSize;
+ Bit8u GreenFieldPosition;
+ Bit8u BlueMaskSize;
+ Bit8u BlueFieldPosition;
+ Bit8u RsvdMaskSize;
+ Bit8u RsvdFieldPosition;
+ Bit8u DirectColorModeInfo;
+// Mandatory information for VBE 2.0 and above
+ Bit32u PhysBasePtr;
+ Bit32u OffScreenMemOffset;
+ Bit16u OffScreenMemSize;
+// Mandatory information for VBE 3.0 and above
+ Bit16u LinBytesPerScanLine;
+ Bit8u BnkNumberOfPages;
+ Bit8u LinNumberOfPages;
+ Bit8u LinRedMaskSize;
+ Bit8u LinRedFieldPosition;
+ Bit8u LinGreenMaskSize;
+ Bit8u LinGreenFieldPosition;
+ Bit8u LinBlueMaskSize;
+ Bit8u LinBlueFieldPosition;
+ Bit8u LinRsvdMaskSize;
+ Bit8u LinRsvdFieldPosition;
+ Bit32u MaxPixelClock;
+// Bit8u Reserved[189]; // DO NOT PUT THIS IN HERE because of Compact Mode Info storage in bios
+} ModeInfoBlockCompact;
+
+typedef struct ModeInfoBlock
+{
+// Mandatory information for all VBE revisions
+ Bit16u ModeAttributes;
+ Bit8u WinAAttributes;
+ Bit8u WinBAttributes;
+ Bit16u WinGranularity;
+ Bit16u WinSize;
+ Bit16u WinASegment;
+ Bit16u WinBSegment;
+ Bit32u WinFuncPtr;
+ Bit16u BytesPerScanLine;
+// Mandatory information for VBE 1.2 and above
+ Bit16u XResolution;
+ Bit16u YResolution;
+ Bit8u XCharSize;
+ Bit8u YCharSize;
+ Bit8u NumberOfPlanes;
+ Bit8u BitsPerPixel;
+ Bit8u NumberOfBanks;
+ Bit8u MemoryModel;
+ Bit8u BankSize;
+ Bit8u NumberOfImagePages;
+ Bit8u Reserved_page;
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ Bit8u RedMaskSize;
+ Bit8u RedFieldPosition;
+ Bit8u GreenMaskSize;
+ Bit8u GreenFieldPosition;
+ Bit8u BlueMaskSize;
+ Bit8u BlueFieldPosition;
+ Bit8u RsvdMaskSize;
+ Bit8u RsvdFieldPosition;
+ Bit8u DirectColorModeInfo;
+// Mandatory information for VBE 2.0 and above
+ Bit32u PhysBasePtr;
+ Bit32u OffScreenMemOffset;
+ Bit16u OffScreenMemSize;
+// Mandatory information for VBE 3.0 and above
+ Bit16u LinBytesPerScanLine;
+ Bit8u BnkNumberOfPages;
+ Bit8u LinNumberOfPages;
+ Bit8u LinRedMaskSize;
+ Bit8u LinRedFieldPosition;
+ Bit8u LinGreenMaskSize;
+ Bit8u LinGreenFieldPosition;
+ Bit8u LinBlueMaskSize;
+ Bit8u LinBlueFieldPosition;
+ Bit8u LinRsvdMaskSize;
+ Bit8u LinRsvdFieldPosition;
+ Bit32u MaxPixelClock;
+ Bit8u Reserved[189];
+} ModeInfoBlock;
+
+// VBE Return Status Info
+// AL
+#define VBE_RETURN_STATUS_SUPPORTED 0x4F
+#define VBE_RETURN_STATUS_UNSUPPORTED 0x00
+// AH
+#define VBE_RETURN_STATUS_SUCCESSFULL 0x00
+#define VBE_RETURN_STATUS_FAILED 0x01
+#define VBE_RETURN_STATUS_NOT_SUPPORTED 0x02
+#define VBE_RETURN_STATUS_INVALID 0x03
+
+// VBE Mode Numbers
+
+#define VBE_MODE_VESA_DEFINED 0x0100
+#define VBE_MODE_REFRESH_RATE_USE_CRTC 0x0800
+#define VBE_MODE_LINEAR_FRAME_BUFFER 0x4000
+#define VBE_MODE_PRESERVE_DISPLAY_MEMORY 0x8000
+
+// VBE GFX Mode Number
+
+#define VBE_VESA_MODE_640X400X8 0x100
+#define VBE_VESA_MODE_640X480X8 0x101
+#define VBE_VESA_MODE_800X600X4 0x102
+#define VBE_VESA_MODE_800X600X8 0x103
+#define VBE_VESA_MODE_1024X768X4 0x104
+#define VBE_VESA_MODE_1024X768X8 0x105
+#define VBE_VESA_MODE_1280X1024X4 0x106
+#define VBE_VESA_MODE_1280X1024X8 0x107
+#define VBE_VESA_MODE_320X200X1555 0x10D
+#define VBE_VESA_MODE_320X200X565 0x10E
+#define VBE_VESA_MODE_320X200X888 0x10F
+#define VBE_VESA_MODE_640X480X1555 0x110
+#define VBE_VESA_MODE_640X480X565 0x111
+#define VBE_VESA_MODE_640X480X888 0x112
+#define VBE_VESA_MODE_800X600X1555 0x113
+#define VBE_VESA_MODE_800X600X565 0x114
+#define VBE_VESA_MODE_800X600X888 0x115
+#define VBE_VESA_MODE_1024X768X1555 0x116
+#define VBE_VESA_MODE_1024X768X565 0x117
+#define VBE_VESA_MODE_1024X768X888 0x118
+#define VBE_VESA_MODE_1280X1024X1555 0x119
+#define VBE_VESA_MODE_1280X1024X565 0x11A
+#define VBE_VESA_MODE_1280X1024X888 0x11B
+
+// BOCHS/PLEX86 'own' mode numbers
+#define VBE_OWN_MODE_320X200X8888 0x140
+#define VBE_OWN_MODE_640X400X8888 0x141
+#define VBE_OWN_MODE_640X480X8888 0x142
+#define VBE_OWN_MODE_800X600X8888 0x143
+#define VBE_OWN_MODE_1024X768X8888 0x144
+#define VBE_OWN_MODE_1280X1024X8888 0x145
+#define VBE_OWN_MODE_320X200X8 0x146
+
+#define VBE_VESA_MODE_END_OF_LIST 0xFFFF
+
+// Capabilities
+
+#define VBE_CAPABILITY_8BIT_DAC 0x0001
+#define VBE_CAPABILITY_NOT_VGA_COMPATIBLE 0x0002
+#define VBE_CAPABILITY_RAMDAC_USE_BLANK_BIT 0x0004
+#define VBE_CAPABILITY_STEREOSCOPIC_SUPPORT 0x0008
+#define VBE_CAPABILITY_STEREO_VIA_VESA_EVC 0x0010
+
+// Mode Attributes
+
+#define VBE_MODE_ATTRIBUTE_SUPPORTED 0x0001
+#define VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE 0x0002
+#define VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT 0x0004
+#define VBE_MODE_ATTRIBUTE_COLOR_MODE 0x0008
+#define VBE_MODE_ATTRIBUTE_GRAPHICS_MODE 0x0010
+#define VBE_MODE_ATTRIBUTE_NOT_VGA_COMPATIBLE 0x0020
+#define VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW 0x0040
+#define VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE 0x0080
+#define VBE_MODE_ATTRIBUTE_DOUBLE_SCAN_MODE 0x0100
+#define VBE_MODE_ATTRIBUTE_INTERLACE_MODE 0x0200
+#define VBE_MODE_ATTRIBUTE_HARDWARE_TRIPLE_BUFFER 0x0400
+#define VBE_MODE_ATTRIBUTE_HARDWARE_STEREOSCOPIC_DISPLAY 0x0800
+#define VBE_MODE_ATTRIBUTE_DUAL_DISPLAY_START_ADDRESS 0x1000
+
+#define VBE_MODE_ATTTRIBUTE_LFB_ONLY ( VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE )
+
+// Window attributes
+
+#define VBE_WINDOW_ATTRIBUTE_RELOCATABLE 0x01
+#define VBE_WINDOW_ATTRIBUTE_READABLE 0x02
+#define VBE_WINDOW_ATTRIBUTE_WRITEABLE 0x04
+
+// Memory model
+
+#define VBE_MEMORYMODEL_TEXT_MODE 0x00
+#define VBE_MEMORYMODEL_CGA_GRAPHICS 0x01
+#define VBE_MEMORYMODEL_HERCULES_GRAPHICS 0x02
+#define VBE_MEMORYMODEL_PLANAR 0x03
+#define VBE_MEMORYMODEL_PACKED_PIXEL 0x04
+#define VBE_MEMORYMODEL_NON_CHAIN_4_256 0x05
+#define VBE_MEMORYMODEL_DIRECT_COLOR 0x06
+#define VBE_MEMORYMODEL_YUV 0x07
+
+// DirectColorModeInfo
+
+#define VBE_DIRECTCOLOR_COLOR_RAMP_PROGRAMMABLE 0x01
+#define VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE 0x02
+
+// GUEST <-> HOST Communication API
+
+// FIXME: either dynamicly ask host for this or put somewhere high in physical memory
+// like 0xE0000000
+
+
+ #define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 4
+
+ #define VBE_DISPI_BANK_ADDRESS 0xA0000
+ #define VBE_DISPI_BANK_SIZE_KB 64
+
+ #define VBE_DISPI_MAX_XRES 1024
+ #define VBE_DISPI_MAX_YRES 768
+
+ #define VBE_DISPI_IOPORT_INDEX 0x01CE
+ #define VBE_DISPI_IOPORT_DATA 0x01CF
+
+ #define VBE_DISPI_INDEX_ID 0x0
+ #define VBE_DISPI_INDEX_XRES 0x1
+ #define VBE_DISPI_INDEX_YRES 0x2
+ #define VBE_DISPI_INDEX_BPP 0x3
+ #define VBE_DISPI_INDEX_ENABLE 0x4
+ #define VBE_DISPI_INDEX_BANK 0x5
+ #define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
+ #define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
+ #define VBE_DISPI_INDEX_X_OFFSET 0x8
+ #define VBE_DISPI_INDEX_Y_OFFSET 0x9
+
+ #define VBE_DISPI_ID0 0xB0C0
+ #define VBE_DISPI_ID1 0xB0C1
+ #define VBE_DISPI_ID2 0xB0C2
+ #define VBE_DISPI_ID3 0xB0C3
+
+ #define VBE_DISPI_DISABLED 0x00
+ #define VBE_DISPI_ENABLED 0x01
+ #define VBE_DISPI_GETCAPS 0x02
+ #define VBE_DISPI_8BIT_DAC 0x20
+ #define VBE_DISPI_LFB_ENABLED 0x40
+ #define VBE_DISPI_NOCLEARMEM 0x80
+
+ #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
+
+
+#define VBE_TOTAL_VIDEO_MEMORY_DIV_64K (VBE_DISPI_TOTAL_VIDEO_MEMORY_MB*1024/64)
+
+
+#endif
diff --git a/tools/firmware/vgabios/vbe_display_api.txt b/tools/firmware/vgabios/vbe_display_api.txt
new file mode 100644
index 0000000000..788e17a790
--- /dev/null
+++ b/tools/firmware/vgabios/vbe_display_api.txt
@@ -0,0 +1,227 @@
+VBE Display API
+-------------------------------------------------------------------------------------------------------------
+ This document is part of the Bochs/VBEBios documentation,
+ it specifies the bochs host <-> vbebios client communication.
+
+ That means, the display code implementation and the vbebios code depend
+ very heavily on each other. As such, this documents needs be synchronised
+ between bochs CVS and the vgabios CVS.
+
+ This document does not describe how the VBEBios implements the VBE2/3 spec.
+ This document does not describe how the Bochs display code will display gfx based upon this spec.
+
+
+API History
+-----------
+0xb0c0 supports the following VBE_DISPI_ interfaces (present in Bochs 1.4):
+ VBE_DISPI_INDEX_ID
+ VBE_DISPI_INDEX_XRES
+ VBE_DISPI_INDEX_YRES
+ VBE_DISPI_INDEX_BPP
+ VBE_DISPI_INDEX_ENABLE
+ VBE_DISPI_INDEX_BANK
+
+ Bpp format supported is:
+ VBE_DISPI_BPP_8
+
+0xb0c1 supports 0xb0c0 VBE_DISPI_ interfaces, additional interfaces (present in Bochs 2.0):
+ VBE_DISPI_INDEX_VIRT_WIDTH
+ VBE_DISPI_INDEX_VIRT_HEIGHT
+ VBE_DISPI_INDEX_X_OFFSET
+ VBE_DISPI_INDEX_Y_OFFSET
+
+0xb0c2 supports 0xb0c1 VBE_DISPI_ interfaces, interfaces updated for
+ additional features (present in Bochs 2.1):
+ VBE_DISPI_INDEX_BPP supports >8bpp color depth (value = bits)
+ VBE_DISPI_INDEX_ENABLE supports new flags VBE_DISPI_NOCLEARMEM and VBE_DISPI_LFB_ENABLED
+ VBE i/o registers changed from 0xFF80/81 to 0x01CE/CF
+
+0xb0c3 supports 0xb0c2 VBE_DISPI_ interfaces, interfaces updated for
+ additional features:
+ VBE_DISPI_INDEX_ENABLE supports new flags VBE_DISPI_GETCAPS and VBE_DISPI_8BIT_DAC
+
+
+History
+-------
+ Version 0.6 2002 Nov 23 Jeroen Janssen
+ - Added LFB support
+ - Added Virt width, height and x,y offset
+
+ Version 0.5 2002 March 08 Jeroen Janssen
+ - Added documentation about panic behaviour / current limits of the data values.
+ - Changed BPP API (in order to include future (A)RGB formats)
+ - Initial version (based upon extended display text of the vbe bochs display patch)
+
+
+Todo
+----
+ Version 0.6+ [random order]
+ - Add lots of different (A)RGB formats
+
+References
+----------
+ [VBE3] VBE 3 Specification at
+ http://www.vesa.org/vbe3.pdf
+
+ [BOCHS] Bochs Open Source IA-32 Emulator at
+ http://bochs.sourceforge.net
+
+ [VBEBIOS] VBE Bios for Bochs at
+ http://savannah.gnu.org/projects/vgabios/
+
+ [Screenshots] Screenshots of programs using the VBE Bios at
+ http://japj.org/projects/bochs_plex86/screenshots.html
+
+Abbreviations
+-------------
+ VBE Vesa Bios Extension
+ DISPI (Bochs) Display Interface
+ BPP Bits Per Pixel
+ LFB Linear Frame Buffer
+
+
+#defines
+--------
+ #define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 4
+ #define VBE_DISPI_BANK_ADDRESS 0xA0000
+ #define VBE_DISPI_BANK_SIZE_KB 64
+
+ #define VBE_DISPI_MAX_XRES 1024
+ #define VBE_DISPI_MAX_YRES 768
+
+ #define VBE_DISPI_IOPORT_INDEX 0x01CE
+ #define VBE_DISPI_IOPORT_DATA 0x01CF
+
+ #define VBE_DISPI_INDEX_ID 0x0
+ #define VBE_DISPI_INDEX_XRES 0x1
+ #define VBE_DISPI_INDEX_YRES 0x2
+ #define VBE_DISPI_INDEX_BPP 0x3
+ #define VBE_DISPI_INDEX_ENABLE 0x4
+ #define VBE_DISPI_INDEX_BANK 0x5
+ #define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
+ #define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
+ #define VBE_DISPI_INDEX_X_OFFSET 0x8
+ #define VBE_DISPI_INDEX_Y_OFFSET 0x9
+
+ #define VBE_DISPI_ID0 0xB0C0
+ #define VBE_DISPI_ID1 0xB0C1
+ #define VBE_DISPI_ID2 0xB0C2
+
+ #define VBE_DISPI_DISABLED 0x00
+ #define VBE_DISPI_ENABLED 0x01
+ #define VBE_DISPI_VBE_ENABLED 0x40
+ #define VBE_DISPI_NOCLEARMEM 0x80
+
+ #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
+
+API
+---
+ The display api works by using a index (VBE_DISPI_IOPORT_INDEX) and
+ data (VBE_DISPI_IOPORT_DATA) ioport. One writes the index of the parameter to the index port.
+ Next, the parameter value can be read or written.
+
+[0xb0c0]
+ * VBE_DISPI_INDEX_ID : WORD {R,W}
+ This parameter can be used to detect the current display API (both bochs & vbebios).
+ The bios writes VBE_DISPI_ID0 to the dataport and reads it back again.
+ This way, the display code knows the vbebios 'ID' and the vbebios can check if the correct
+ display code is present.
+ As a result, a PANIC can be generated if an incompatible vbebios/display code combination is detected.
+ This panic can be generated from the bochs display code (NOT the bios, see Notes).
+
+ Example values: VBE_DISPI_ID0
+
+ * VBE_DISPI_INDEX_XRES : WORD {R,W}
+ This parameter can be used to read/write the vbe display X resolution (in pixels).
+ It's illegal to set the XRES when the VBE is enabled (display code should generate PANIC).
+
+ If the value written exceeds VBE_DISPI_MAX_XRES, the display code needs to generate a PANIC.
+
+ Example values: 320,640,800,1024
+
+ * VBE_DISPI_INDEX_YRES : WORD {R,W}
+ This parameter can be used to read/write the vbe display Y resolution (in pixels).
+ It's illegal to set the YRES when the VBE is enabled (display code should generate PANIC).
+
+ If the value written exceeds VBE_DISPI_MAX_YRES, the display code needs to generate a PANIC.
+
+ Example values: 200,400,480,600,768
+
+ * VBE_DISPI_INDEX_BPP : WORD {R,W}
+ This parameter can be used to read/write the vbe display BPP.
+ It's illegal to set the BPP when the VBE is enabled (display code should generate PANIC).
+
+ If the value written is an incompatible BPP, the display code needs to generate a PANIC.
+
+ Example values: VBE_DISPI_BPP_8
+
+ * VBE_DISPI_INDEX_ENABLE : WORD {R,W}
+ This parameter can be used to read/write the vbe ENABLED state.
+ If the bios writes VBE_DISPI_ENABLED then the display code will setup a hostside display mode
+ with the current XRES, YRES and BPP settings.
+ If the bios write VBE_DISPI_DISABLED then the display code will switch back to normal vga mode behaviour.
+
+ Example values: VBE_DISPI_ENABLED, VBE_DISPI_DISABLED
+
+ * VBE_DISPI_INDEX_BANK : WORD {R,W}
+ This parameter can be used to read/write the current selected BANK (at 0xA0000).
+ This can be used for switching banks in banked mode.
+
+[0xb0c1]
+ * VBE_DISPI_INDEX_VIRT_WIDTH : WORD {R,W}
+ This parameter can be used to read/write the current virtual width.
+ Upon enabling a mode, this will be set to the current xres
+ Setting this field during enabled mode will result in the virtual width to be changed.
+ Value will be adjusted if current setting is not possible.
+
+ * VBE_DISPI_INDEX_VIRT_HEIGHT : WORD {R}
+ This parameter can be read in order to obtain the current virtual height.
+ This setting will be adjusted after setting a virtual width in order to stay within limit of video memory.
+
+ * VBE_DISPI_INDEX_X_OFFSET : WORD {R,W}
+ The current X offset (in pixels!) of the visible screen part.
+ Writing a new offset will also result in a complete screen refresh.
+
+ * VBE_DISPI_INDEX_Y_OFFSET : WORD {R,W}
+ The current Y offset (in pixels!) of the visible screen part.
+ Writing a new offset will also result in a complete screen refresh.
+
+
+[0xb0c2]
+ * VBE_DISPI_INDEX_BPP : WORD {R,W}
+ The value written is now the number of bits per pixel. A value of 0 is treated
+ the same as 8 for backward compatibilty. These values are supported: 8, 15,
+ 16, 24 and 32. The value of 4 is not yet handled in the VBE code.
+ * VBE_DISPI_INDEX_ENABLE : WORD {R,W}
+ The new flag VBE_DISPI_NOCLEARMEM allows to preserve the VBE video memory.
+ The new flag VBE_DISPI_LFB_ENABLED indicates the usage of the LFB.
+
+[0xb0c3]
+ * VBE_DISPI_INDEX_ENABLE : WORD {R,W}
+ If the new flag VBE_DISPI_GETCAPS is enabled, the xres, yres and bpp registers
+ return the gui capabilities.
+ The new flag VBE_DISPI_8BIT_DAC switches the DAC to 8 bit mode.
+
+Displaying GFX (banked mode)
+--------------
+ What happens is that the total screen is devided in banks of 'VBE_DISPI_BANK_SIZE_KB' KiloByte in size.
+ If you want to set a pixel you can calculate its bank by doing:
+
+ offset = pixel_x + pixel_y * resolution_x;
+ bank = offset / 64 Kb (rounded 1.9999 -> 1)
+
+ bank_pixel_pos = offset - bank * 64Kb
+
+ Now you can set the current bank and put the pixel at VBE_DISPI_BANK_ADDRESS + bank_pixel_pos
+
+Displaying GFX (linear frame buffer mode)
+--------------
+ NOT WRITTEN YET
+
+Notes
+-----
+ * Since the XRES/YRES/BPP may not be written when VBE is enabled, if you want to switch from one VBE mode
+ to another, you will need to disable VBE first.
+
+ * Note when the bios doesn't find a valid DISPI_ID, it can disable the VBE functions. This allows people to
+ use the same bios for both vbe enabled and disabled bochs executables.
diff --git a/tools/firmware/vgabios/vbetables.h b/tools/firmware/vgabios/vbetables.h
new file mode 100644
index 0000000000..a742ac74ba
--- /dev/null
+++ b/tools/firmware/vgabios/vbetables.h
@@ -0,0 +1,1282 @@
+#ifndef vbetables_h_included
+#define vbetables_h_included
+
+/* vbetables.h
+
+ This file contains a static mode information list containing all
+ bochs/plex86 "supported" VBE modi and their 'settings'.
+
+*/
+
+typedef struct ModeInfoListItem
+{
+ Bit16u mode;
+ ModeInfoBlockCompact info;
+} ModeInfoListItem;
+
+// FIXME: check all member variables to be correct for the different modi
+// FIXME: add more modi
+static ModeInfoListItem mode_info_list[]=
+{
+ {
+ VBE_VESA_MODE_640X400X8,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 640,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 640,
+ /*Bit16u YResolution*/ 400,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 8,
+ /*Bit8u NumberOfBanks*/ 4, // 640x400/64kb == 4
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 15,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 0,
+ /*Bit8u RedFieldPosition*/ 0,
+ /*Bit8u GreenMaskSize*/ 0,
+ /*Bit8u GreenFieldPosition*/ 0,
+ /*Bit8u BlueMaskSize*/ 0,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 0,
+ /*Bit8u RsvdFieldPosition*/ 0,
+ /*Bit8u DirectColorModeInfo*/ 0,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 640,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 0,
+ /*Bit8u LinRedFieldPosition*/ 0,
+ /*Bit8u LinGreenMaskSize*/ 0,
+ /*Bit8u LinGreenFieldPosition*/ 0,
+ /*Bit8u LinBlueMaskSize*/ 0,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 0,
+ /*Bit8u LinRsvdFieldPosition*/ 0,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_VESA_MODE_640X480X8,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 640,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 640,
+ /*Bit16u YResolution*/ 480,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 8,
+ /*Bit8u NumberOfBanks*/ 5, // 640x480/64kb == 5
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 11,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 0,
+ /*Bit8u RedFieldPosition*/ 0,
+ /*Bit8u GreenMaskSize*/ 0,
+ /*Bit8u GreenFieldPosition*/ 0,
+ /*Bit8u BlueMaskSize*/ 0,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 0,
+ /*Bit8u RsvdFieldPosition*/ 0,
+ /*Bit8u DirectColorModeInfo*/ 0,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 640,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 0,
+ /*Bit8u LinRedFieldPosition*/ 0,
+ /*Bit8u LinGreenMaskSize*/ 0,
+ /*Bit8u LinGreenFieldPosition*/ 0,
+ /*Bit8u LinBlueMaskSize*/ 0,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 0,
+ /*Bit8u LinRsvdFieldPosition*/ 0,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_VESA_MODE_800X600X4,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 100,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 800,
+ /*Bit16u YResolution*/ 600,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 4,
+ /*Bit8u BitsPerPixel*/ 4,
+ /*Bit8u NumberOfBanks*/ 16,
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PLANAR,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 15,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 0,
+ /*Bit8u RedFieldPosition*/ 0,
+ /*Bit8u GreenMaskSize*/ 0,
+ /*Bit8u GreenFieldPosition*/ 0,
+ /*Bit8u BlueMaskSize*/ 0,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 0,
+ /*Bit8u RsvdFieldPosition*/ 0,
+ /*Bit8u DirectColorModeInfo*/ 0,
+// Mandatory information for VBE 2.0 and above
+ /*Bit32u PhysBasePtr*/ 0,
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 100,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 0,
+ /*Bit8u LinRedFieldPosition*/ 0,
+ /*Bit8u LinGreenMaskSize*/ 0,
+ /*Bit8u LinGreenFieldPosition*/ 0,
+ /*Bit8u LinBlueMaskSize*/ 0,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 0,
+ /*Bit8u LinRsvdFieldPosition*/ 0,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_VESA_MODE_800X600X8,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 800,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 800,
+ /*Bit16u YResolution*/ 600,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 8,
+ /*Bit8u NumberOfBanks*/ 8, // 800x600/64kb == 8
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 7,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 0,
+ /*Bit8u RedFieldPosition*/ 0,
+ /*Bit8u GreenMaskSize*/ 0,
+ /*Bit8u GreenFieldPosition*/ 0,
+ /*Bit8u BlueMaskSize*/ 0,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 0,
+ /*Bit8u RsvdFieldPosition*/ 0,
+ /*Bit8u DirectColorModeInfo*/ 0,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 800,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 0,
+ /*Bit8u LinRedFieldPosition*/ 0,
+ /*Bit8u LinGreenMaskSize*/ 0,
+ /*Bit8u LinGreenFieldPosition*/ 0,
+ /*Bit8u LinBlueMaskSize*/ 0,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 0,
+ /*Bit8u LinRsvdFieldPosition*/ 0,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_VESA_MODE_1024X768X8,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 1024,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 1024,
+ /*Bit16u YResolution*/ 768,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 8,
+ /*Bit8u NumberOfBanks*/ 12, // 1024x768/64kb == 12
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 3,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 0,
+ /*Bit8u RedFieldPosition*/ 0,
+ /*Bit8u GreenMaskSize*/ 0,
+ /*Bit8u GreenFieldPosition*/ 0,
+ /*Bit8u BlueMaskSize*/ 0,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 0,
+ /*Bit8u RsvdFieldPosition*/ 0,
+ /*Bit8u DirectColorModeInfo*/ 0,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 1024,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 0,
+ /*Bit8u LinRedFieldPosition*/ 0,
+ /*Bit8u LinGreenMaskSize*/ 0,
+ /*Bit8u LinGreenFieldPosition*/ 0,
+ /*Bit8u LinBlueMaskSize*/ 0,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 0,
+ /*Bit8u LinRsvdFieldPosition*/ 0,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_VESA_MODE_640X480X1555,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 640*2,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 640,
+ /*Bit16u YResolution*/ 480,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 15,
+ /*Bit8u NumberOfBanks*/ 1,
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 5,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 5,
+ /*Bit8u RedFieldPosition*/ 10,
+ /*Bit8u GreenMaskSize*/ 5,
+ /*Bit8u GreenFieldPosition*/ 5,
+ /*Bit8u BlueMaskSize*/ 5,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 1,
+ /*Bit8u RsvdFieldPosition*/ 15,
+ /*Bit8u DirectColorModeInfo*/ 0,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 640*2,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 5,
+ /*Bit8u LinRedFieldPosition*/ 10,
+ /*Bit8u LinGreenMaskSize*/ 0,
+ /*Bit8u LinGreenFieldPosition*/ 5,
+ /*Bit8u LinBlueMaskSize*/ 5,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 1,
+ /*Bit8u LinRsvdFieldPosition*/ 15,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_VESA_MODE_800X600X1555,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 800*2,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 800,
+ /*Bit16u YResolution*/ 600,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 15,
+ /*Bit8u NumberOfBanks*/ 1,
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 3,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 5,
+ /*Bit8u RedFieldPosition*/ 10,
+ /*Bit8u GreenMaskSize*/ 5,
+ /*Bit8u GreenFieldPosition*/ 5,
+ /*Bit8u BlueMaskSize*/ 5,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 1,
+ /*Bit8u RsvdFieldPosition*/ 15,
+ /*Bit8u DirectColorModeInfo*/ 0,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 800*2,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 5,
+ /*Bit8u LinRedFieldPosition*/ 10,
+ /*Bit8u LinGreenMaskSize*/ 5,
+ /*Bit8u LinGreenFieldPosition*/ 5,
+ /*Bit8u LinBlueMaskSize*/ 5,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 1,
+ /*Bit8u LinRsvdFieldPosition*/ 15,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_VESA_MODE_1024X768X1555,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 1024*2,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 1024,
+ /*Bit16u YResolution*/ 768,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 15,
+ /*Bit8u NumberOfBanks*/ 1,
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 1,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 5,
+ /*Bit8u RedFieldPosition*/ 10,
+ /*Bit8u GreenMaskSize*/ 5,
+ /*Bit8u GreenFieldPosition*/ 5,
+ /*Bit8u BlueMaskSize*/ 5,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 1,
+ /*Bit8u RsvdFieldPosition*/ 15,
+ /*Bit8u DirectColorModeInfo*/ 0,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 1024*2,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 5,
+ /*Bit8u LinRedFieldPosition*/ 10,
+ /*Bit8u LinGreenMaskSize*/ 5,
+ /*Bit8u LinGreenFieldPosition*/ 5,
+ /*Bit8u LinBlueMaskSize*/ 5,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 1,
+ /*Bit8u LinRsvdFieldPosition*/ 15,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_VESA_MODE_640X480X565,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 640*2,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 640,
+ /*Bit16u YResolution*/ 480,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 16,
+ /*Bit8u NumberOfBanks*/ 1,
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 5,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 5,
+ /*Bit8u RedFieldPosition*/ 11,
+ /*Bit8u GreenMaskSize*/ 6,
+ /*Bit8u GreenFieldPosition*/ 5,
+ /*Bit8u BlueMaskSize*/ 5,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 0,
+ /*Bit8u RsvdFieldPosition*/ 0,
+ /*Bit8u DirectColorModeInfo*/ 0,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 640*2,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 5,
+ /*Bit8u LinRedFieldPosition*/ 11,
+ /*Bit8u LinGreenMaskSize*/ 6,
+ /*Bit8u LinGreenFieldPosition*/ 5,
+ /*Bit8u LinBlueMaskSize*/ 5,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 0,
+ /*Bit8u LinRsvdFieldPosition*/ 0,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_VESA_MODE_800X600X565,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 800*2,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 800,
+ /*Bit16u YResolution*/ 600,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 16,
+ /*Bit8u NumberOfBanks*/ 1,
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 3,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 5,
+ /*Bit8u RedFieldPosition*/ 11,
+ /*Bit8u GreenMaskSize*/ 6,
+ /*Bit8u GreenFieldPosition*/ 5,
+ /*Bit8u BlueMaskSize*/ 5,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 0,
+ /*Bit8u RsvdFieldPosition*/ 0,
+ /*Bit8u DirectColorModeInfo*/ 0,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 800*2,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 5,
+ /*Bit8u LinRedFieldPosition*/ 11,
+ /*Bit8u LinGreenMaskSize*/ 6,
+ /*Bit8u LinGreenFieldPosition*/ 5,
+ /*Bit8u LinBlueMaskSize*/ 5,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 0,
+ /*Bit8u LinRsvdFieldPosition*/ 0,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_VESA_MODE_1024X768X565,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 1024*2,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 1024,
+ /*Bit16u YResolution*/ 768,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 16,
+ /*Bit8u NumberOfBanks*/ 1,
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 1,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 5,
+ /*Bit8u RedFieldPosition*/ 11,
+ /*Bit8u GreenMaskSize*/ 6,
+ /*Bit8u GreenFieldPosition*/ 5,
+ /*Bit8u BlueMaskSize*/ 5,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 0,
+ /*Bit8u RsvdFieldPosition*/ 0,
+ /*Bit8u DirectColorModeInfo*/ 0,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 1024*2,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 5,
+ /*Bit8u LinRedFieldPosition*/ 11,
+ /*Bit8u LinGreenMaskSize*/ 6,
+ /*Bit8u LinGreenFieldPosition*/ 5,
+ /*Bit8u LinBlueMaskSize*/ 5,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 0,
+ /*Bit8u LinRsvdFieldPosition*/ 0,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_VESA_MODE_640X480X888,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 640*3,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 640,
+ /*Bit16u YResolution*/ 480,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 24,
+ /*Bit8u NumberOfBanks*/ 1,
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 3,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 8,
+ /*Bit8u RedFieldPosition*/ 16,
+ /*Bit8u GreenMaskSize*/ 8,
+ /*Bit8u GreenFieldPosition*/ 8,
+ /*Bit8u BlueMaskSize*/ 8,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 0,
+ /*Bit8u RsvdFieldPosition*/ 0,
+ /*Bit8u DirectColorModeInfo*/ 0,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 640*3,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 8,
+ /*Bit8u LinRedFieldPosition*/ 16,
+ /*Bit8u LinGreenMaskSize*/ 8,
+ /*Bit8u LinGreenFieldPosition*/ 8,
+ /*Bit8u LinBlueMaskSize*/ 8,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 0,
+ /*Bit8u LinRsvdFieldPosition*/ 0,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_VESA_MODE_800X600X888,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 800*3,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 800,
+ /*Bit16u YResolution*/ 600,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 24,
+ /*Bit8u NumberOfBanks*/ 1,
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 1,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 8,
+ /*Bit8u RedFieldPosition*/ 16,
+ /*Bit8u GreenMaskSize*/ 8,
+ /*Bit8u GreenFieldPosition*/ 8,
+ /*Bit8u BlueMaskSize*/ 8,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 0,
+ /*Bit8u RsvdFieldPosition*/ 0,
+ /*Bit8u DirectColorModeInfo*/ 0,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 800*3,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 8,
+ /*Bit8u LinRedFieldPosition*/ 16,
+ /*Bit8u LinGreenMaskSize*/ 8,
+ /*Bit8u LinGreenFieldPosition*/ 8,
+ /*Bit8u LinBlueMaskSize*/ 8,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 0,
+ /*Bit8u LinRsvdFieldPosition*/ 0,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_VESA_MODE_1024X768X888,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 1024*3,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 1024,
+ /*Bit16u YResolution*/ 768,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 24,
+ /*Bit8u NumberOfBanks*/ 1,
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 0,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 8,
+ /*Bit8u RedFieldPosition*/ 16,
+ /*Bit8u GreenMaskSize*/ 8,
+ /*Bit8u GreenFieldPosition*/ 8,
+ /*Bit8u BlueMaskSize*/ 8,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 0,
+ /*Bit8u RsvdFieldPosition*/ 0,
+ /*Bit8u DirectColorModeInfo*/ 0,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 1024*3,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 8,
+ /*Bit8u LinRedFieldPosition*/ 16,
+ /*Bit8u LinGreenMaskSize*/ 8,
+ /*Bit8u LinGreenFieldPosition*/ 8,
+ /*Bit8u LinBlueMaskSize*/ 8,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 0,
+ /*Bit8u LinRsvdFieldPosition*/ 0,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_OWN_MODE_640X480X8888,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 640*4,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 640,
+ /*Bit16u YResolution*/ 480,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 32,
+ /*Bit8u NumberOfBanks*/ 1,
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 1,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 8,
+ /*Bit8u RedFieldPosition*/ 16,
+ /*Bit8u GreenMaskSize*/ 8,
+ /*Bit8u GreenFieldPosition*/ 8,
+ /*Bit8u BlueMaskSize*/ 8,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 8,
+ /*Bit8u RsvdFieldPosition*/ 24,
+ /*Bit8u DirectColorModeInfo*/ VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 640*4,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 8,
+ /*Bit8u LinRedFieldPosition*/ 16,
+ /*Bit8u LinGreenMaskSize*/ 8,
+ /*Bit8u LinGreenFieldPosition*/ 8,
+ /*Bit8u LinBlueMaskSize*/ 8,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 8,
+ /*Bit8u LinRsvdFieldPosition*/ 24,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_OWN_MODE_800X600X8888,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 800*4,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 800,
+ /*Bit16u YResolution*/ 600,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 32,
+ /*Bit8u NumberOfBanks*/ 1,
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 1,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 8,
+ /*Bit8u RedFieldPosition*/ 16,
+ /*Bit8u GreenMaskSize*/ 8,
+ /*Bit8u GreenFieldPosition*/ 8,
+ /*Bit8u BlueMaskSize*/ 8,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 8,
+ /*Bit8u RsvdFieldPosition*/ 24,
+ /*Bit8u DirectColorModeInfo*/ VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 800*4,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 8,
+ /*Bit8u LinRedFieldPosition*/ 16,
+ /*Bit8u LinGreenMaskSize*/ 8,
+ /*Bit8u LinGreenFieldPosition*/ 8,
+ /*Bit8u LinBlueMaskSize*/ 8,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 8,
+ /*Bit8u LinRsvdFieldPosition*/ 24,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_OWN_MODE_1024X768X8888,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 1024*4,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 1024,
+ /*Bit16u YResolution*/ 768,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 32,
+ /*Bit8u NumberOfBanks*/ 1,
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 1,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 8,
+ /*Bit8u RedFieldPosition*/ 16,
+ /*Bit8u GreenMaskSize*/ 8,
+ /*Bit8u GreenFieldPosition*/ 8,
+ /*Bit8u BlueMaskSize*/ 8,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 8,
+ /*Bit8u RsvdFieldPosition*/ 24,
+ /*Bit8u DirectColorModeInfo*/ VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 1024*4,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 8,
+ /*Bit8u LinRedFieldPosition*/ 16,
+ /*Bit8u LinGreenMaskSize*/ 8,
+ /*Bit8u LinGreenFieldPosition*/ 8,
+ /*Bit8u LinBlueMaskSize*/ 8,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 8,
+ /*Bit8u LinRsvdFieldPosition*/ 24,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+ {
+ VBE_OWN_MODE_320X200X8,
+ {
+/*typedef struct ModeInfoBlock
+{*/
+// Mandatory information for all VBE revisions
+ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+#ifdef VBE_HAVE_LFB
+ VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE |
+#endif
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE,
+ /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE,
+ /*Bit8u WinBAttributes*/ 0,
+ /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB,
+ /*Bit16u WinASegment*/ VGAMEM_GRAPH,
+ /*Bit16u WinBSegment*/ 0,
+ /*Bit32u WinFuncPtr*/ 0,
+ /*Bit16u BytesPerScanLine*/ 320,
+// Mandatory information for VBE 1.2 and above
+ /*Bit16u XResolution*/ 320,
+ /*Bit16u YResolution*/ 200,
+ /*Bit8u XCharSize*/ 8,
+ /*Bit8u YCharSize*/ 16,
+ /*Bit8u NumberOfPlanes*/ 1,
+ /*Bit8u BitsPerPixel*/ 8,
+ /*Bit8u NumberOfBanks*/ 1,
+ /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL,
+ /*Bit8u BankSize*/ 0,
+ /*Bit8u NumberOfImagePages*/ 3,
+ /*Bit8u Reserved_page*/ 0,
+// Direct Color fields (required for direct/6 and YUV/7 memory models)
+ /*Bit8u RedMaskSize*/ 0,
+ /*Bit8u RedFieldPosition*/ 0,
+ /*Bit8u GreenMaskSize*/ 0,
+ /*Bit8u GreenFieldPosition*/ 0,
+ /*Bit8u BlueMaskSize*/ 0,
+ /*Bit8u BlueFieldPosition*/ 0,
+ /*Bit8u RsvdMaskSize*/ 0,
+ /*Bit8u RsvdFieldPosition*/ 0,
+ /*Bit8u DirectColorModeInfo*/ 0,
+// Mandatory information for VBE 2.0 and above
+#ifdef VBE_HAVE_LFB
+ /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+#else
+ /*Bit32u PhysBasePtr*/ 0,
+#endif
+ /*Bit32u OffScreenMemOffset*/ 0,
+ /*Bit16u OffScreenMemSize*/ 0,
+// Mandatory information for VBE 3.0 and above
+ /*Bit16u LinBytesPerScanLine*/ 320,
+ /*Bit8u BnkNumberOfPages*/ 0,
+ /*Bit8u LinNumberOfPages*/ 0,
+ /*Bit8u LinRedMaskSize*/ 0,
+ /*Bit8u LinRedFieldPosition*/ 0,
+ /*Bit8u LinGreenMaskSize*/ 0,
+ /*Bit8u LinGreenFieldPosition*/ 0,
+ /*Bit8u LinBlueMaskSize*/ 0,
+ /*Bit8u LinBlueFieldPosition*/ 0,
+ /*Bit8u LinRsvdMaskSize*/ 0,
+ /*Bit8u LinRsvdFieldPosition*/ 0,
+ /*Bit32u MaxPixelClock*/ 0,
+/*} ModeInfoBlock;*/
+ }
+ },
+
+/** END OF THE LIST **/
+ {
+ VBE_VESA_MODE_END_OF_LIST,
+ {
+ 0,
+ }
+ }
+};
+
+#endif
diff --git a/tools/firmware/vgabios/vgabios.c b/tools/firmware/vgabios/vgabios.c
new file mode 100644
index 0000000000..1bca91962d
--- /dev/null
+++ b/tools/firmware/vgabios/vgabios.c
@@ -0,0 +1,3608 @@
+// ============================================================================================
+/*
+ * vgabios.c
+ */
+// ============================================================================================
+//
+// Copyright (C) 2001,2002 the LGPL VGABios developers Team
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// ============================================================================================
+//
+// This VGA Bios is specific to the plex86/bochs Emulated VGA card.
+// You can NOT drive any physical vga card with it.
+//
+// ============================================================================================
+//
+// This file contains code ripped from :
+// - rombios.c of plex86
+//
+// This VGA Bios contains fonts from :
+// - fntcol16.zip (c) by Joseph Gil avalable at :
+// ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+// These fonts are public domain
+//
+// This VGA Bios is based on information taken from :
+// - Kevin Lawton's vga card emulation for bochs/plex86
+// - Ralf Brown's interrupts list available at http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html
+// - Finn Thogersons' VGADOC4b available at http://home.worldonline.dk/~finth/
+// - Michael Abrash's Graphics Programming Black Book
+// - Francois Gervais' book "programmation des cartes graphiques cga-ega-vga" edited by sybex
+// - DOSEMU 1.0.1 source code for several tables values and formulas
+//
+// Thanks for patches, comments and ideas to :
+// - techt@pikeonline.net
+//
+// ============================================================================================
+
+#include "vgabios.h"
+
+#ifdef VBE
+#include "vbe.h"
+#endif
+
+#undef DEBUG
+#define USE_BX_INFO
+
+/* Declares */
+static Bit8u read_byte();
+static Bit16u read_word();
+static void write_byte();
+static void write_word();
+static Bit8u inb();
+static Bit16u inw();
+static void outb();
+static void outw();
+
+static Bit16u get_SS();
+
+// Output
+static void printf();
+static void unimplemented();
+static void unknown();
+
+static Bit8u find_vga_entry();
+
+static void memsetb();
+static void memsetw();
+static void memcpyb();
+static void memcpyw();
+
+static void biosfn_set_video_mode();
+static void biosfn_set_cursor_shape();
+static void biosfn_set_cursor_pos();
+static void biosfn_get_cursor_pos();
+static void biosfn_set_active_page();
+static void biosfn_scroll();
+static void biosfn_read_char_attr();
+static void biosfn_write_char_attr();
+static void biosfn_write_char_only();
+static void biosfn_write_pixel();
+static void biosfn_read_pixel();
+static void biosfn_write_teletype();
+static void biosfn_perform_gray_scale_summing();
+static void biosfn_load_text_user_pat();
+static void biosfn_load_text_8_14_pat();
+static void biosfn_load_text_8_8_pat();
+static void biosfn_load_text_8_16_pat();
+static void biosfn_load_gfx_8_8_chars();
+static void biosfn_load_gfx_user_chars();
+static void biosfn_load_gfx_8_14_chars();
+static void biosfn_load_gfx_8_8_dd_chars();
+static void biosfn_load_gfx_8_16_chars();
+static void biosfn_get_font_info();
+static void biosfn_alternate_prtsc();
+static void biosfn_switch_video_interface();
+static void biosfn_enable_video_refresh_control();
+static void biosfn_write_string();
+static void biosfn_read_state_info();
+static void biosfn_read_video_state_size();
+static void biosfn_save_video_state();
+static void biosfn_restore_video_state();
+
+// This is for compiling with gcc2 and gcc3
+#define ASM_START #asm
+#define ASM_END #endasm
+
+ASM_START
+
+MACRO SET_INT_VECTOR
+ push ds
+ xor ax, ax
+ mov ds, ax
+ mov ax, ?3
+ mov ?1*4, ax
+ mov ax, ?2
+ mov ?1*4+2, ax
+ pop ds
+MEND
+
+ASM_END
+
+ASM_START
+.text
+.rom
+.org 0
+
+use16 386
+
+vgabios_start:
+.byte 0x55, 0xaa /* BIOS signature, required for BIOS extensions */
+
+.byte 0x40 /* BIOS extension length in units of 512 bytes */
+
+
+vgabios_entry_point:
+
+ jmp vgabios_init_func
+
+vgabios_name:
+.ascii "Plex86/Bochs VGABios"
+.ascii " "
+.byte 0x00
+
+// Info from Bart Oldeman
+.org 0x1e
+.ascii "IBM"
+.byte 0x00
+
+vgabios_version:
+#ifndef VGABIOS_VERS
+.ascii "current-cvs"
+#else
+.ascii VGABIOS_VERS
+#endif
+.ascii " "
+
+vgabios_date:
+.ascii VGABIOS_DATE
+.byte 0x0a,0x0d
+.byte 0x00
+
+vgabios_copyright:
+.ascii "(C) 2003 the LGPL VGABios developers Team"
+.byte 0x0a,0x0d
+.byte 0x00
+
+vgabios_license:
+.ascii "This VGA/VBE Bios is released under the GNU LGPL"
+.byte 0x0a,0x0d
+.byte 0x0a,0x0d
+.byte 0x00
+
+vgabios_website:
+.ascii "Please visit :"
+.byte 0x0a,0x0d
+;;.ascii " . http://www.plex86.org"
+;;.byte 0x0a,0x0d
+.ascii " . http://bochs.sourceforge.net"
+.byte 0x0a,0x0d
+.ascii " . http://www.nongnu.org/vgabios"
+.byte 0x0a,0x0d
+.byte 0x0a,0x0d
+.byte 0x00
+
+
+;; ============================================================================================
+;;
+;; Init Entry point
+;;
+;; ============================================================================================
+vgabios_init_func:
+
+;; init vga card
+ call init_vga_card
+
+;; init basic bios vars
+ call init_bios_area
+
+#ifdef VBE
+;; init vbe functions
+ call vbe_init
+#endif
+
+;; set int10 vect
+ SET_INT_VECTOR(0x10, #0xC000, #vgabios_int10_handler)
+
+#ifdef CIRRUS
+ call cirrus_init
+#endif
+
+;; display splash screen
+ call _display_splash_screen
+
+;; init video mode and clear the screen
+ mov ax,#0x0003
+ int #0x10
+
+;; show info
+ call _display_info
+
+#ifdef VBE
+;; show vbe info
+ call vbe_display_info
+#endif
+
+#ifdef CIRRUS
+;; show cirrus info
+ call cirrus_display_info
+#endif
+
+ retf
+ASM_END
+
+/*
+ * int10 handled here
+ */
+ASM_START
+vgabios_int10_handler:
+ pushf
+#ifdef DEBUG
+ push es
+ push ds
+ pusha
+ mov bx, #0xc000
+ mov ds, bx
+ call _int10_debugmsg
+ popa
+ pop ds
+ pop es
+#endif
+ cmp ah, #0x0f
+ jne int10_test_1A
+ call biosfn_get_video_mode
+ jmp int10_end
+int10_test_1A:
+ cmp ah, #0x1a
+ jne int10_test_0B
+ call biosfn_group_1A
+ jmp int10_end
+int10_test_0B:
+ cmp ah, #0x0b
+ jne int10_test_1103
+ call biosfn_group_0B
+ jmp int10_end
+int10_test_1103:
+ cmp ax, #0x1103
+ jne int10_test_12
+ call biosfn_set_text_block_specifier
+ jmp int10_end
+int10_test_12:
+ cmp ah, #0x12
+ jne int10_test_101B
+ cmp bl, #0x10
+ jne int10_test_BL30
+ call biosfn_get_ega_info
+ jmp int10_end
+int10_test_BL30:
+ cmp bl, #0x30
+ jne int10_test_BL31
+ call biosfn_select_vert_res
+ jmp int10_end
+int10_test_BL31:
+ cmp bl, #0x31
+ jne int10_test_BL32
+ call biosfn_enable_default_palette_loading
+ jmp int10_end
+int10_test_BL32:
+ cmp bl, #0x32
+ jne int10_test_BL33
+ call biosfn_enable_video_addressing
+ jmp int10_end
+int10_test_BL33:
+ cmp bl, #0x33
+ jne int10_test_BL34
+ call biosfn_enable_grayscale_summing
+ jmp int10_end
+int10_test_BL34:
+ cmp bl, #0x34
+ jne int10_normal
+ call biosfn_enable_cursor_emulation
+ jmp int10_end
+int10_test_101B:
+ cmp ax, #0x101b
+ je int10_normal
+ cmp ah, #0x10
+#ifndef VBE
+ jne int10_normal
+#else
+ jne int10_test_4F
+#endif
+ call biosfn_group_10
+ jmp int10_end
+#ifdef VBE
+int10_test_4F:
+ cmp ah, #0x4f
+ jne int10_normal
+ cmp al, #0x03
+ jne int10_test_vbe_05
+ call vbe_biosfn_return_current_mode
+ jmp int10_end
+int10_test_vbe_05:
+ cmp al, #0x05
+ jne int10_test_vbe_06
+ call vbe_biosfn_display_window_control
+ jmp int10_end
+int10_test_vbe_06:
+ cmp al, #0x06
+ jne int10_test_vbe_07
+ call vbe_biosfn_set_get_logical_scan_line_length
+ jmp int10_end
+int10_test_vbe_07:
+ cmp al, #0x07
+ jne int10_test_vbe_08
+ call vbe_biosfn_set_get_display_start
+ jmp int10_end
+int10_test_vbe_08:
+ cmp al, #0x08
+ jne int10_normal
+ call vbe_biosfn_set_get_dac_palette_format
+ jmp int10_end
+#endif
+
+int10_normal:
+ push es
+ push ds
+ pusha
+
+;; We have to set ds to access the right data segment
+ mov bx, #0xc000
+ mov ds, bx
+ call _int10_func
+
+ popa
+ pop ds
+ pop es
+int10_end:
+ popf
+ iret
+ASM_END
+
+#include "vgatables.h"
+#include "vgafonts.h"
+
+/*
+ * Boot time harware inits
+ */
+ASM_START
+init_vga_card:
+;; switch to color mode and enable CPU access 480 lines
+ mov dx, #0x3C2
+ mov al, #0xC3
+ outb dx,al
+
+;; more than 64k 3C4/04
+ mov dx, #0x3C4
+ mov al, #0x04
+ outb dx,al
+ mov dx, #0x3C5
+ mov al, #0x02
+ outb dx,al
+
+#if defined(USE_BX_INFO) || defined(DEBUG)
+ mov bx, #msg_vga_init
+ push bx
+ call _printf
+#endif
+ inc sp
+ inc sp
+ ret
+
+#if defined(USE_BX_INFO) || defined(DEBUG)
+msg_vga_init:
+.ascii "VGABios $Id: vgabios.c,v 1.61 2005/05/24 16:50:50 vruppert Exp $"
+.byte 0x0d,0x0a,0x00
+#endif
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+/*
+ * Boot time bios area inits
+ */
+ASM_START
+init_bios_area:
+ push ds
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+
+;; init detected hardware BIOS Area
+ mov bx, # BIOSMEM_INITIAL_MODE
+ mov ax, [bx]
+ and ax, #0xffcf
+ mov [bx], ax
+
+;; Just for the first int10 find its children
+
+;; the default char height
+ mov bx, # BIOSMEM_CHAR_HEIGHT
+ mov al, #0x10
+ mov [bx], al
+
+;; Clear the screen
+ mov bx, # BIOSMEM_VIDEO_CTL
+ mov al, #0x60
+ mov [bx], al
+
+;; Set the basic screen we have
+ mov bx, # BIOSMEM_SWITCHES
+ mov al, #0xf9
+ mov [bx], al
+
+;; Set the basic modeset options
+ mov bx, # BIOSMEM_MODESET_CTL
+ mov al, #0x51
+ mov [bx], al
+
+;; Set the default MSR
+ mov bx, # BIOSMEM_CURRENT_MSR
+ mov al, #0x09
+ mov [bx], al
+
+ pop ds
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+/*
+ * Boot time Splash screen
+ */
+static void display_splash_screen()
+{
+}
+
+// --------------------------------------------------------------------------------------------
+/*
+ * Tell who we are
+ */
+
+static void display_info()
+{
+ASM_START
+ mov ax,#0xc000
+ mov ds,ax
+ mov si,#vgabios_name
+ call _display_string
+ mov si,#vgabios_version
+ call _display_string
+
+ ;;mov si,#vgabios_copyright
+ ;;call _display_string
+ ;;mov si,#crlf
+ ;;call _display_string
+
+ mov si,#vgabios_license
+ call _display_string
+ mov si,#vgabios_website
+ call _display_string
+ASM_END
+}
+
+static void display_string()
+{
+ // Get length of string
+ASM_START
+ mov ax,ds
+ mov es,ax
+ mov di,si
+ xor cx,cx
+ not cx
+ xor al,al
+ cld
+ repne
+ scasb
+ not cx
+ dec cx
+ push cx
+
+ mov ax,#0x0300
+ mov bx,#0x0000
+ int #0x10
+
+ pop cx
+ mov ax,#0x1301
+ mov bx,#0x000b
+ mov bp,si
+ int #0x10
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+#ifdef DEBUG
+static void int10_debugmsg(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
+ Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
+{
+ // 0E is write char...
+ if(GET_AH()!=0x0E)
+ printf("vgabios call ah%02x al%02x bx%04x cx%04x dx%04x\n",GET_AH(),GET_AL(),BX,CX,DX);
+}
+#endif
+
+// --------------------------------------------------------------------------------------------
+/*
+ * int10 main dispatcher
+ */
+static void int10_func(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
+ Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
+{
+
+ // BIOS functions
+ switch(GET_AH())
+ {
+ case 0x00:
+ biosfn_set_video_mode(GET_AL());
+ switch(GET_AL()&0x7F)
+ {case 6:
+ SET_AL(0x3F);
+ break;
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 7:
+ SET_AL(0x30);
+ break;
+ default:
+ SET_AL(0x20);
+ }
+ break;
+ case 0x01:
+ biosfn_set_cursor_shape(GET_CH(),GET_CL());
+ break;
+ case 0x02:
+ biosfn_set_cursor_pos(GET_BH(),DX);
+ break;
+ case 0x03:
+ biosfn_get_cursor_pos(GET_BH(),&CX,&DX);
+ break;
+ case 0x04:
+ // Read light pen pos (unimplemented)
+#ifdef DEBUG
+ unimplemented();
+#endif
+ AX=0x00;
+ BX=0x00;
+ CX=0x00;
+ DX=0x00;
+ break;
+ case 0x05:
+ biosfn_set_active_page(GET_AL());
+ break;
+ case 0x06:
+ biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_UP);
+ break;
+ case 0x07:
+ biosfn_scroll(GET_AL(),GET_BH(),GET_CH(),GET_CL(),GET_DH(),GET_DL(),0xFF,SCROLL_DOWN);
+ break;
+ case 0x08:
+ biosfn_read_char_attr(GET_BH(),&AX);
+ break;
+ case 0x09:
+ biosfn_write_char_attr(GET_AL(),GET_BH(),GET_BL(),CX);
+ break;
+ case 0x0A:
+ biosfn_write_char_only(GET_AL(),GET_BH(),GET_BL(),CX);
+ break;
+ case 0x0C:
+ biosfn_write_pixel(GET_BH(),GET_AL(),CX,DX);
+ break;
+ case 0x0D:
+ biosfn_read_pixel(GET_BH(),CX,DX,&AX);
+ break;
+ case 0x0E:
+ // Ralf Brown Interrupt list is WRONG on bh(page)
+ // We do output only on the current page !
+ biosfn_write_teletype(GET_AL(),0xff,GET_BL(),NO_ATTR);
+ break;
+ case 0x10:
+ // All other functions of group AH=0x10 rewritten in assembler
+ biosfn_perform_gray_scale_summing(BX,CX);
+ break;
+ case 0x11:
+ switch(GET_AL())
+ {
+ case 0x00:
+ case 0x10:
+ biosfn_load_text_user_pat(GET_AL(),ES,BP,CX,DX,GET_BL(),GET_BH());
+ break;
+ case 0x01:
+ case 0x11:
+ biosfn_load_text_8_14_pat(GET_AL(),GET_BL());
+ break;
+ case 0x02:
+ case 0x12:
+ biosfn_load_text_8_8_pat(GET_AL(),GET_BL());
+ break;
+ case 0x04:
+ case 0x14:
+ biosfn_load_text_8_16_pat(GET_AL(),GET_BL());
+ break;
+ case 0x20:
+ biosfn_load_gfx_8_8_chars(ES,BP);
+ break;
+ case 0x21:
+ biosfn_load_gfx_user_chars(ES,BP,CX,GET_BL(),GET_DL());
+ break;
+ case 0x22:
+ biosfn_load_gfx_8_14_chars(GET_BL());
+ break;
+ case 0x23:
+ biosfn_load_gfx_8_8_dd_chars(GET_BL());
+ break;
+ case 0x24:
+ biosfn_load_gfx_8_16_chars(GET_BL());
+ break;
+ case 0x30:
+ biosfn_get_font_info(GET_BH(),&ES,&BP,&CX,&DX);
+ break;
+#ifdef DEBUG
+ default:
+ unknown();
+#endif
+ }
+
+ break;
+ case 0x12:
+ switch(GET_BL())
+ {
+ case 0x20:
+ biosfn_alternate_prtsc();
+ break;
+ case 0x35:
+ biosfn_switch_video_interface(GET_AL(),ES,DX);
+ SET_AL(0x12);
+ break;
+ case 0x36:
+ biosfn_enable_video_refresh_control(GET_AL());
+ SET_AL(0x12);
+ break;
+#ifdef DEBUG
+ default:
+ unknown();
+#endif
+ }
+ break;
+ case 0x13:
+ biosfn_write_string(GET_AL(),GET_BH(),GET_BL(),CX,GET_DH(),GET_DL(),ES,BP);
+ break;
+ case 0x1B:
+ biosfn_read_state_info(BX,ES,DI);
+ SET_AL(0x1B);
+ break;
+ case 0x1C:
+ switch(GET_AL())
+ {
+ case 0x00:
+ biosfn_read_video_state_size(CX,&BX);
+ break;
+ case 0x01:
+ biosfn_save_video_state(CX,ES,BX);
+ break;
+ case 0x02:
+ biosfn_restore_video_state(CX,ES,BX);
+ break;
+#ifdef DEBUG
+ default:
+ unknown();
+#endif
+ }
+ SET_AL(0x1C);
+ break;
+
+#ifdef VBE
+ case 0x4f:
+ if (vbe_has_vbe_display()) {
+ switch(GET_AL())
+ {
+ case 0x00:
+ vbe_biosfn_return_controller_information(&AX,ES,DI);
+ break;
+ case 0x01:
+ vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
+ break;
+ case 0x02:
+ vbe_biosfn_set_mode(&AX,BX,ES,DI);
+ break;
+ case 0x04:
+ //FIXME
+#ifdef DEBUG
+ unimplemented();
+#endif
+ // function failed
+ AX=0x100;
+ break;
+ case 0x09:
+ //FIXME
+#ifdef DEBUG
+ unimplemented();
+#endif
+ // function failed
+ AX=0x100;
+ break;
+ case 0x0A:
+ //FIXME
+#ifdef DEBUG
+ unimplemented();
+#endif
+ // function failed
+ AX=0x100;
+ break;
+ default:
+#ifdef DEBUG
+ unknown();
+#endif
+ // function failed
+ AX=0x100;
+ }
+ }
+ else {
+ // No VBE display
+ AX=0x0100;
+ }
+ break;
+#endif
+
+#ifdef DEBUG
+ default:
+ unknown();
+#endif
+ }
+}
+
+// ============================================================================================
+//
+// BIOS functions
+//
+// ============================================================================================
+
+static void biosfn_set_video_mode(mode) Bit8u mode;
+{// mode: Bit 7 is 1 if no clear screen
+
+ // Should we clear the screen ?
+ Bit8u noclearmem=mode&0x80;
+ Bit8u line,mmask,*palette;
+ Bit16u i,twidth,theight,cheight;
+ Bit8u modeset_ctl,video_ctl,vga_switches;
+ Bit16u crtc_addr;
+
+#ifdef VBE
+ if (vbe_has_vbe_display()) {
+ dispi_set_enable(VBE_DISPI_DISABLED);
+ }
+#endif // def VBE
+
+ // The real mode
+ mode=mode&0x7f;
+
+ // find the entry in the video modes
+ line=find_vga_entry(mode);
+
+#ifdef DEBUG
+ printf("mode search %02x found line %02x\n",mode,line);
+#endif
+
+ if(line==0xFF)
+ return;
+
+ twidth=vga_modes[line].twidth;
+ theight=vga_modes[line].theight;
+ cheight=vga_modes[line].cheight;
+
+ // Read the bios vga control
+ video_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL);
+
+ // Read the bios vga switches
+ vga_switches=read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES);
+
+ // Read the bios mode set control
+ modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
+
+ // Then we know the number of lines
+// FIXME
+
+ // if palette loading (bit 3 of modeset ctl = 0)
+ if((modeset_ctl&0x08)==0)
+ {// Set the PEL mask
+ outb(VGAREG_PEL_MASK,vga_modes[line].pelmask);
+
+ // Set the whole dac always, from 0
+ outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
+
+ // From which palette
+ switch(vga_modes[line].dacmodel)
+ {case 0:
+ palette=&palette0;
+ break;
+ case 1:
+ palette=&palette1;
+ break;
+ case 2:
+ palette=&palette2;
+ break;
+ case 3:
+ palette=&palette3;
+ break;
+ }
+
+ // Always 256*3 values
+ for(i=0;i<0x0100;i++)
+ {
+ if(i<=dac_regs[vga_modes[line].dacmodel])
+ {outb(VGAREG_DAC_DATA,palette[(i*3)+0]);
+ outb(VGAREG_DAC_DATA,palette[(i*3)+1]);
+ outb(VGAREG_DAC_DATA,palette[(i*3)+2]);
+ }
+ else
+ {outb(VGAREG_DAC_DATA,0);
+ outb(VGAREG_DAC_DATA,0);
+ outb(VGAREG_DAC_DATA,0);
+ }
+ }
+ if((modeset_ctl&0x02)==0x02)
+ {
+ biosfn_perform_gray_scale_summing(0x00, 0x100);
+ }
+ }
+
+ // Reset Attribute Ctl flip-flop
+ inb(VGAREG_ACTL_RESET);
+
+ // Set Attribute Ctl
+ for(i=0;i<=ACTL_MAX_REG;i++)
+ {outb(VGAREG_ACTL_ADDRESS,i);
+ outb(VGAREG_ACTL_WRITE_DATA,actl_regs[vga_modes[line].actlmodel][i]);
+ }
+
+ // Set Sequencer Ctl
+ for(i=0;i<=SEQU_MAX_REG;i++)
+ {outb(VGAREG_SEQU_ADDRESS,i);
+ outb(VGAREG_SEQU_DATA,sequ_regs[vga_modes[line].sequmodel][i]);
+ }
+
+ // Set Grafx Ctl
+ for(i=0;i<=GRDC_MAX_REG;i++)
+ {outb(VGAREG_GRDC_ADDRESS,i);
+ outb(VGAREG_GRDC_DATA,grdc_regs[vga_modes[line].grdcmodel][i]);
+ }
+
+ // Set CRTC address VGA or MDA
+ crtc_addr=vga_modes[line].memmodel==MTEXT?VGAREG_MDA_CRTC_ADDRESS:VGAREG_VGA_CRTC_ADDRESS;
+
+ // Disable CRTC write protection
+ outw(crtc_addr,0x0011);
+ // Set CRTC regs
+ for(i=0;i<=CRTC_MAX_REG;i++)
+ {outb(crtc_addr,i);
+ outb(crtc_addr+1,crtc_regs[vga_modes[line].crtcmodel][i]);
+ }
+
+ // Set the misc register
+ outb(VGAREG_WRITE_MISC_OUTPUT,vga_modes[line].miscreg);
+
+ // Enable video
+ outb(VGAREG_ACTL_ADDRESS,0x20);
+ inb(VGAREG_ACTL_RESET);
+
+ if(noclearmem==0x00)
+ {
+ if(vga_modes[line].class==TEXT)
+ {
+ memsetw(vga_modes[line].sstart,0,0x0720,0x4000); // 32k
+ }
+ else
+ {
+ if(mode<0x0d)
+ {
+ memsetw(vga_modes[line].sstart,0,0x0000,0x4000); // 32k
+ }
+ else
+ {
+ outb( VGAREG_SEQU_ADDRESS, 0x02 );
+ mmask = inb( VGAREG_SEQU_DATA );
+ outb( VGAREG_SEQU_DATA, 0x0f ); // all planes
+ memsetw(vga_modes[line].sstart,0,0x0000,0x8000); // 64k
+ outb( VGAREG_SEQU_DATA, mmask );
+ }
+ }
+ }
+
+ // Set the BIOS mem
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,mode);
+ write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS,twidth);
+ write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,vga_modes[line].slength);
+ write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,crtc_addr);
+ write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theight-1);
+ write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,cheight);
+ write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|noclearmem));
+ write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9);
+ write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x7f);
+
+ // FIXME We nearly have the good tables. to be reworked
+ write_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,0x08); // 8 is VGA should be ok for now
+ write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER,0x00);
+ write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER+2,0x00);
+
+ // FIXME
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x00); // Unavailable on vanilla vga, but...
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,0x00); // Unavailable on vanilla vga, but...
+
+ // Set cursor shape
+ if(vga_modes[line].class==TEXT)
+ {
+ biosfn_set_cursor_shape(0x06,0x07);
+ }
+
+ // Set cursor pos for page 0..7
+ for(i=0;i<8;i++)
+ biosfn_set_cursor_pos(i,0x0000);
+
+ // Set active page 0
+ biosfn_set_active_page(0x00);
+
+ // Write the fonts in memory
+ if(vga_modes[line].class==TEXT)
+ {
+ASM_START
+ ;; copy and activate 8x16 font
+ mov ax, #0x1104
+ mov bl, #0x00
+ int #0x10
+ mov ax, #0x1103
+ mov bl, #0x00
+ int #0x10
+ASM_END
+ }
+
+ // Set the ints 0x1F and 0x43
+ASM_START
+ SET_INT_VECTOR(0x1f, #0xC000, #_vgafont8+128*8)
+ASM_END
+
+ switch(cheight)
+ {case 8:
+ASM_START
+ SET_INT_VECTOR(0x43, #0xC000, #_vgafont8)
+ASM_END
+ break;
+ case 14:
+ASM_START
+ SET_INT_VECTOR(0x43, #0xC000, #_vgafont14)
+ASM_END
+ break;
+ case 16:
+ASM_START
+ SET_INT_VECTOR(0x43, #0xC000, #_vgafont16)
+ASM_END
+ break;
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_set_cursor_shape (CH,CL)
+Bit8u CH;Bit8u CL;
+{Bit16u cheight,curs,crtc_addr;
+ Bit8u modeset_ctl;
+
+ CH&=0x3f;
+ CL&=0x1f;
+
+ curs=(CH<<8)+CL;
+ write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE,curs);
+
+ modeset_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
+ cheight = read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT);
+ if((modeset_ctl&0x01) && (cheight>8) && (CL<8) && (CH<0x20))
+ {
+ if(CL!=(CH+1))
+ {
+ CH = ((CH+1) * cheight / 8) -1;
+ }
+ else
+ {
+ CH = ((CL+1) * cheight / 8) - 2;
+ }
+ CL = ((CL+1) * cheight / 8) - 1;
+ }
+
+ // CTRC regs 0x0a and 0x0b
+ crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
+ outb(crtc_addr,0x0a);
+ outb(crtc_addr+1,CH);
+ outb(crtc_addr,0x0b);
+ outb(crtc_addr+1,CL);
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_set_cursor_pos (page, cursor)
+Bit8u page;Bit16u cursor;
+{
+ Bit8u xcurs,ycurs,current;
+ Bit16u nbcols,nbrows,address,crtc_addr;
+
+ // Should not happen...
+ if(page>7)return;
+
+ // Bios cursor pos
+ write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*page, cursor);
+
+ // Set the hardware cursor
+ current=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
+ if(page==current)
+ {
+ // Get the dimensions
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Calculate the address knowing nbcols nbrows and page num
+ address=SCREEN_IO_START(nbcols,nbrows,page)+xcurs+ycurs*nbcols;
+
+ // CRTC regs 0x0e and 0x0f
+ crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
+ outb(crtc_addr,0x0e);
+ outb(crtc_addr+1,(address&0xff00)>>8);
+ outb(crtc_addr,0x0f);
+ outb(crtc_addr+1,address&0x00ff);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_get_cursor_pos (page,shape, pos)
+Bit8u page;Bit16u *shape;Bit16u *pos;
+{
+ Bit16u ss=get_SS();
+
+ // Default
+ write_word(ss, shape, 0);
+ write_word(ss, pos, 0);
+
+ if(page>7)return;
+ // FIXME should handle VGA 14/16 lines
+ write_word(ss,shape,read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE));
+ write_word(ss,pos,read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_POS+page*2));
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_set_active_page (page)
+Bit8u page;
+{
+ Bit16u cursor,dummy,crtc_addr;
+ Bit16u nbcols,nbrows,address;
+ Bit8u mode,line;
+
+ if(page>7)return;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get pos curs pos for the right page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+
+ if(vga_modes[line].class==TEXT)
+ {
+ // Get the dimensions
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+
+ // Calculate the address knowing nbcols nbrows and page num
+ address=SCREEN_MEM_START(nbcols,nbrows,page);
+ write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START,address);
+
+ // Start address
+ address=SCREEN_IO_START(nbcols,nbrows,page);
+ }
+ else
+ {
+ address = page*vga_modes[line].slength;
+ }
+
+ // CRTC regs 0x0c and 0x0d
+ crtc_addr=read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
+ outb(crtc_addr,0x0c);
+ outb(crtc_addr+1,(address&0xff00)>>8);
+ outb(crtc_addr,0x0d);
+ outb(crtc_addr+1,address&0x00ff);
+
+ // And change the BIOS page
+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE,page);
+
+#ifdef DEBUG
+ printf("Set active page %02x address %04x\n",page,address);
+#endif
+
+ // Display the cursor, now the page is active
+ biosfn_set_cursor_pos(page,cursor);
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_copy_pl4(xstart,ysrc,ydest,cols,nbcols,cheight)
+Bit8u xstart;Bit8u ysrc;Bit8u ydest;Bit8u cols;Bit8u nbcols;Bit8u cheight;
+{
+ Bit16u src,dest;
+ Bit8u i;
+
+ src=ysrc*cheight*nbcols+xstart;
+ dest=ydest*cheight*nbcols+xstart;
+ outw(VGAREG_GRDC_ADDRESS, 0x0105);
+ for(i=0;i<cheight;i++)
+ {
+ memcpyb(0xa000,dest+i*nbcols,0xa000,src+i*nbcols,cols);
+ }
+ outw(VGAREG_GRDC_ADDRESS, 0x0005);
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_fill_pl4(xstart,ystart,cols,nbcols,cheight,attr)
+Bit8u xstart;Bit8u ystart;Bit8u cols;Bit8u nbcols;Bit8u cheight;Bit8u attr;
+{
+ Bit16u dest;
+ Bit8u i;
+
+ dest=ystart*cheight*nbcols+xstart;
+ outw(VGAREG_GRDC_ADDRESS, 0x0205);
+ for(i=0;i<cheight;i++)
+ {
+ memsetb(0xa000,dest+i*nbcols,attr,cols);
+ }
+ outw(VGAREG_GRDC_ADDRESS, 0x0005);
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_copy_cga(xstart,ysrc,ydest,cols,nbcols,cheight)
+Bit8u xstart;Bit8u ysrc;Bit8u ydest;Bit8u cols;Bit8u nbcols;Bit8u cheight;
+{
+ Bit16u src,dest;
+ Bit8u i;
+
+ src=((ysrc*cheight*nbcols)>>1)+xstart;
+ dest=((ydest*cheight*nbcols)>>1)+xstart;
+ for(i=0;i<cheight;i++)
+ {
+ if (i & 1)
+ memcpyb(0xb800,0x2000+dest+(i>>1)*nbcols,0xb800,0x2000+src+(i>>1)*nbcols,cols);
+ else
+ memcpyb(0xb800,dest+(i>>1)*nbcols,0xb800,src+(i>>1)*nbcols,cols);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void vgamem_fill_cga(xstart,ystart,cols,nbcols,cheight,attr)
+Bit8u xstart;Bit8u ystart;Bit8u cols;Bit8u nbcols;Bit8u cheight;Bit8u attr;
+{
+ Bit16u dest;
+ Bit8u i;
+
+ dest=((ystart*cheight*nbcols)>>1)+xstart;
+ for(i=0;i<cheight;i++)
+ {
+ if (i & 1)
+ memsetb(0xb800,0x2000+dest+(i>>1)*nbcols,attr,cols);
+ else
+ memsetb(0xb800,dest+(i>>1)*nbcols,attr,cols);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_scroll (nblines,attr,rul,cul,rlr,clr,page,dir)
+Bit8u nblines;Bit8u attr;Bit8u rul;Bit8u cul;Bit8u rlr;Bit8u clr;Bit8u page;Bit8u dir;
+{
+ // page == 0xFF if current
+
+ Bit8u mode,line,cheight,bpp,cols;
+ Bit16u nbcols,nbrows,i;
+ Bit16u address;
+
+ if(rul>rlr)return;
+ if(cul>clr)return;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ // Get the current page
+ if(page==0xFF)
+ page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
+
+ if(rlr>=nbrows)rlr=nbrows-1;
+ if(clr>=nbcols)clr=nbcols-1;
+ if(nblines>nbrows)nblines=0;
+ cols=clr-cul+1;
+
+ if(vga_modes[line].class==TEXT)
+ {
+ // Compute the address
+ address=SCREEN_MEM_START(nbcols,nbrows,page);
+#ifdef DEBUG
+ printf("Scroll, address %04x (%04x %04x %02x)\n",address,nbrows,nbcols,page);
+#endif
+
+ if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
+ {
+ memsetw(vga_modes[line].sstart,address,(Bit16u)attr*0x100+' ',nbrows*nbcols);
+ }
+ else
+ {// if Scroll up
+ if(dir==SCROLL_UP)
+ {for(i=rul;i<=rlr;i++)
+ {
+ if((i+nblines>rlr)||(nblines==0))
+ memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(Bit16u)attr*0x100+' ',cols);
+ else
+ memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i+nblines)*nbcols+cul)*2,cols);
+ }
+ }
+ else
+ {for(i=rlr;i>=rul;i--)
+ {
+ if((i<rul+nblines)||(nblines==0))
+ memsetw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,(Bit16u)attr*0x100+' ',cols);
+ else
+ memcpyw(vga_modes[line].sstart,address+(i*nbcols+cul)*2,vga_modes[line].sstart,((i-nblines)*nbcols+cul)*2,cols);
+ }
+ }
+ }
+ }
+ else
+ {
+ // FIXME gfx mode not complete
+ cheight=vga_modes[line].cheight;
+ switch(vga_modes[line].memmodel)
+ {
+ case PLANAR4:
+ case PLANAR1:
+ if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
+ {
+ outw(VGAREG_GRDC_ADDRESS, 0x0205);
+ memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight);
+ outw(VGAREG_GRDC_ADDRESS, 0x0005);
+ }
+ else
+ {// if Scroll up
+ if(dir==SCROLL_UP)
+ {for(i=rul;i<=rlr;i++)
+ {
+ if((i+nblines>rlr)||(nblines==0))
+ vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
+ else
+ vgamem_copy_pl4(cul,i+nblines,i,cols,nbcols,cheight);
+ }
+ }
+ else
+ {for(i=rlr;i>=rul;i--)
+ {
+ if((i<rul+nblines)||(nblines==0))
+ vgamem_fill_pl4(cul,i,cols,nbcols,cheight,attr);
+ else
+ vgamem_copy_pl4(cul,i,i-nblines,cols,nbcols,cheight);
+ }
+ }
+ }
+ break;
+ case CGA:
+ bpp=vga_modes[line].pixbits;
+ if(nblines==0&&rul==0&&cul==0&&rlr==nbrows-1&&clr==nbcols-1)
+ {
+ memsetb(vga_modes[line].sstart,0,attr,nbrows*nbcols*cheight*bpp);
+ }
+ else
+ {
+ if(bpp==2)
+ {
+ cul<<=1;
+ cols<<=1;
+ nbcols<<=1;
+ }
+ // if Scroll up
+ if(dir==SCROLL_UP)
+ {for(i=rul;i<=rlr;i++)
+ {
+ if((i+nblines>rlr)||(nblines==0))
+ vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
+ else
+ vgamem_copy_cga(cul,i+nblines,i,cols,nbcols,cheight);
+ }
+ }
+ else
+ {for(i=rlr;i>=rul;i--)
+ {
+ if((i<rul+nblines)||(nblines==0))
+ vgamem_fill_cga(cul,i,cols,nbcols,cheight,attr);
+ else
+ vgamem_copy_cga(cul,i,i-nblines,cols,nbcols,cheight);
+ }
+ }
+ }
+ break;
+#ifdef DEBUG
+ default:
+ printf("Scroll in graphics mode ");
+ unimplemented();
+#endif
+ }
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_read_char_attr (page,car)
+Bit8u page;Bit16u *car;
+{Bit16u ss=get_SS();
+ Bit8u xcurs,ycurs,mode,line;
+ Bit16u nbcols,nbrows,address;
+ Bit16u cursor,dummy;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the cursor pos for the page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ if(vga_modes[line].class==TEXT)
+ {
+ // Compute the address
+ address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
+
+ write_word(ss,car,read_word(vga_modes[line].sstart,address));
+ }
+ else
+ {
+ // FIXME gfx mode
+#ifdef DEBUG
+ unimplemented();
+#endif
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight)
+Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;Bit8u cheight;
+{
+ Bit8u i,j,mask;
+ Bit8u *fdata;
+ Bit16u addr,dest,src;
+
+ switch(cheight)
+ {case 14:
+ fdata = &vgafont14;
+ break;
+ case 16:
+ fdata = &vgafont16;
+ break;
+ default:
+ fdata = &vgafont8;
+ }
+ addr=xcurs+ycurs*cheight*nbcols;
+ src = car * cheight;
+ outw(VGAREG_SEQU_ADDRESS, 0x0f02);
+ outw(VGAREG_GRDC_ADDRESS, 0x0205);
+ if(attr&0x80)
+ {
+ outw(VGAREG_GRDC_ADDRESS, 0x1803);
+ }
+ else
+ {
+ outw(VGAREG_GRDC_ADDRESS, 0x0003);
+ }
+ for(i=0;i<cheight;i++)
+ {
+ dest=addr+i*nbcols;
+ for(j=0;j<8;j++)
+ {
+ mask=0x80>>j;
+ outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
+ read_byte(0xa000,dest);
+ if(fdata[src+i]&mask)
+ {
+ write_byte(0xa000,dest,attr&0x0f);
+ }
+ else
+ {
+ write_byte(0xa000,dest,0x00);
+ }
+ }
+ }
+ASM_START
+ mov dx, # VGAREG_GRDC_ADDRESS
+ mov ax, #0xff08
+ out dx, ax
+ mov ax, #0x0005
+ out dx, ax
+ mov ax, #0x0003
+ out dx, ax
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp)
+Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;Bit8u bpp;
+{
+ Bit8u i,j,mask,data;
+ Bit8u *fdata;
+ Bit16u addr,dest,src;
+
+ fdata = &vgafont8;
+ addr=(xcurs*bpp)+ycurs*320;
+ src = car * 8;
+ for(i=0;i<8;i++)
+ {
+ dest=addr+(i>>1)*80;
+ if (i & 1) dest += 0x2000;
+ mask = 0x80;
+ if (bpp == 1)
+ {
+ if (attr & 0x80)
+ {
+ data = read_byte(0xb800,dest);
+ }
+ else
+ {
+ data = 0x00;
+ }
+ for(j=0;j<8;j++)
+ {
+ if (fdata[src+i] & mask)
+ {
+ if (attr & 0x80)
+ {
+ data ^= (attr & 0x01) << (7-j);
+ }
+ else
+ {
+ data |= (attr & 0x01) << (7-j);
+ }
+ }
+ mask >>= 1;
+ }
+ write_byte(0xb800,dest,data);
+ }
+ else
+ {
+ while (mask > 0)
+ {
+ if (attr & 0x80)
+ {
+ data = read_byte(0xb800,dest);
+ }
+ else
+ {
+ data = 0x00;
+ }
+ for(j=0;j<4;j++)
+ {
+ if (fdata[src+i] & mask)
+ {
+ if (attr & 0x80)
+ {
+ data ^= (attr & 0x03) << ((3-j)*2);
+ }
+ else
+ {
+ data |= (attr & 0x03) << ((3-j)*2);
+ }
+ }
+ mask >>= 1;
+ }
+ write_byte(0xb800,dest,data);
+ dest += 1;
+ }
+ }
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols)
+Bit8u car;Bit8u attr;Bit8u xcurs;Bit8u ycurs;Bit8u nbcols;
+{
+ Bit8u i,j,mask,data;
+ Bit8u *fdata;
+ Bit16u addr,dest,src;
+
+ fdata = &vgafont8;
+ addr=xcurs*8+ycurs*nbcols*64;
+ src = car * 8;
+ for(i=0;i<8;i++)
+ {
+ dest=addr+i*nbcols*8;
+ mask = 0x80;
+ for(j=0;j<8;j++)
+ {
+ data = 0x00;
+ if (fdata[src+i] & mask)
+ {
+ data = attr;
+ }
+ write_byte(0xa000,dest+j,data);
+ mask >>= 1;
+ }
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_char_attr (car,page,attr,count)
+Bit8u car;Bit8u page;Bit8u attr;Bit16u count;
+{
+ Bit8u cheight,xcurs,ycurs,mode,line,bpp;
+ Bit16u nbcols,nbrows,address;
+ Bit16u cursor,dummy;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the cursor pos for the page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ if(vga_modes[line].class==TEXT)
+ {
+ // Compute the address
+ address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
+
+ dummy=((Bit16u)attr<<8)+car;
+/*
+printf("sstart=%x\n", vga_modes[line].sstart);
+printf("address=%x\n", address);
+printf("dummy=%x\n", dummy);
+printf("count=%x\n", count);
+*/
+ memsetw(vga_modes[line].sstart,address,dummy,count);
+ }
+ else
+ {
+ // FIXME gfx mode not complete
+ cheight=vga_modes[line].cheight;
+ bpp=vga_modes[line].pixbits;
+ while((count-->0) && (xcurs<nbcols))
+ {
+ switch(vga_modes[line].memmodel)
+ {
+ case PLANAR4:
+ case PLANAR1:
+ write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
+ break;
+ case CGA:
+ write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
+ break;
+ case LINEAR8:
+ write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
+ break;
+#ifdef DEBUG
+ default:
+ unimplemented();
+#endif
+ }
+ xcurs++;
+ }
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_char_only (car,page,attr,count)
+Bit8u car;Bit8u page;Bit8u attr;Bit16u count;
+{
+ Bit8u cheight,xcurs,ycurs,mode,line,bpp;
+ Bit16u nbcols,nbrows,address;
+ Bit16u cursor,dummy;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the cursor pos for the page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ if(vga_modes[line].class==TEXT)
+ {
+ // Compute the address
+ address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
+
+ while(count-->0)
+ {write_byte(vga_modes[line].sstart,address,car);
+ address+=2;
+ }
+ }
+ else
+ {
+ // FIXME gfx mode not complete
+ cheight=vga_modes[line].cheight;
+ bpp=vga_modes[line].pixbits;
+ while((count-->0) && (xcurs<nbcols))
+ {
+ switch(vga_modes[line].memmodel)
+ {
+ case PLANAR4:
+ case PLANAR1:
+ write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
+ break;
+ case CGA:
+ write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
+ break;
+ case LINEAR8:
+ write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
+ break;
+#ifdef DEBUG
+ default:
+ unimplemented();
+#endif
+ }
+ xcurs++;
+ }
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_group_0B:
+ cmp bh, #0x00
+ je biosfn_set_border_color
+ cmp bh, #0x01
+ je biosfn_set_palette
+#ifdef DEBUG
+ call _unknown
+#endif
+ ret
+biosfn_set_border_color:
+ push ax
+ push bx
+ push cx
+ push dx
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x00
+ out dx, al
+ mov al, bl
+ and al, #0x0f
+ test al, #0x08
+ jz set_low_border
+ add al, #0x08
+set_low_border:
+ out dx, al
+ mov cl, #0x01
+ and bl, #0x10
+set_intensity_loop:
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, cl
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ and al, #0xef
+ or al, bl
+ mov dx, # VGAREG_ACTL_ADDRESS
+ out dx, al
+ inc cl
+ cmp cl, #0x04
+ jne set_intensity_loop
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+biosfn_set_palette:
+ push ax
+ push bx
+ push cx
+ push dx
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov cl, #0x01
+ and bl, #0x01
+set_cga_palette_loop:
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, cl
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ and al, #0xfe
+ or al, bl
+ mov dx, # VGAREG_ACTL_ADDRESS
+ out dx, al
+ inc cl
+ cmp cl, #0x04
+ jne set_cga_palette_loop
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_pixel (BH,AL,CX,DX) Bit8u BH;Bit8u AL;Bit16u CX;Bit16u DX;
+{
+ Bit8u mode,line,mask,attr,data;
+ Bit16u addr;
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+ if(vga_modes[line].class==TEXT)return;
+
+ switch(vga_modes[line].memmodel)
+ {
+ case PLANAR4:
+ case PLANAR1:
+ addr = CX/8+DX*read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+ mask = 0x80 >> (CX & 0x07);
+ outw(VGAREG_GRDC_ADDRESS, (mask << 8) | 0x08);
+ outw(VGAREG_GRDC_ADDRESS, 0x0205);
+ data = read_byte(0xa000,addr);
+ if (AL & 0x80)
+ {
+ outw(VGAREG_GRDC_ADDRESS, 0x1803);
+ }
+ write_byte(0xa000,addr,AL);
+ASM_START
+ mov dx, # VGAREG_GRDC_ADDRESS
+ mov ax, #0xff08
+ out dx, ax
+ mov ax, #0x0005
+ out dx, ax
+ mov ax, #0x0003
+ out dx, ax
+ASM_END
+ break;
+ case CGA:
+ if(vga_modes[line].pixbits==2)
+ {
+ addr=(CX>>2)+(DX>>1)*80;
+ }
+ else
+ {
+ addr=(CX>>3)+(DX>>1)*80;
+ }
+ if (DX & 1) addr += 0x2000;
+ data = read_byte(0xb800,addr);
+ if(vga_modes[line].pixbits==2)
+ {
+ attr = (AL & 0x03) << ((3 - (CX & 0x03)) * 2);
+ mask = 0x03 << ((3 - (CX & 0x03)) * 2);
+ }
+ else
+ {
+ attr = (AL & 0x01) << (7 - (CX & 0x07));
+ mask = 0x01 << (7 - (CX & 0x07));
+ }
+ if (AL & 0x80)
+ {
+ data ^= attr;
+ }
+ else
+ {
+ data &= ~mask;
+ data |= attr;
+ }
+ write_byte(0xb800,addr,data);
+ break;
+ case LINEAR8:
+ addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
+ write_byte(0xa000,addr,AL);
+ break;
+#ifdef DEBUG
+ default:
+ unimplemented();
+#endif
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_read_pixel (BH,CX,DX,AX) Bit8u BH;Bit16u CX;Bit16u DX;Bit16u *AX;
+{
+ Bit8u mode,line,mask,attr,data,i;
+ Bit16u addr;
+ Bit16u ss=get_SS();
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+ if(vga_modes[line].class==TEXT)return;
+
+ switch(vga_modes[line].memmodel)
+ {
+ case PLANAR4:
+ case PLANAR1:
+ addr = CX/8+DX*read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+ mask = 0x80 >> (CX & 0x07);
+ attr = 0x00;
+ for(i=0;i<4;i++)
+ {
+ outw(VGAREG_GRDC_ADDRESS, (i << 8) | 0x04);
+ data = read_byte(0xa000,addr) & mask;
+ if (data > 0) attr |= (0x01 << i);
+ }
+ break;
+ case CGA:
+ addr=(CX>>2)+(DX>>1)*80;
+ if (DX & 1) addr += 0x2000;
+ data = read_byte(0xb800,addr);
+ if(vga_modes[line].pixbits==2)
+ {
+ attr = (data >> ((3 - (CX & 0x03)) * 2)) & 0x03;
+ }
+ else
+ {
+ attr = (data >> (7 - (CX & 0x07))) & 0x01;
+ }
+ break;
+ case LINEAR8:
+ addr=CX+DX*(read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
+ attr=read_byte(0xa000,addr);
+ break;
+ default:
+#ifdef DEBUG
+ unimplemented();
+#endif
+ attr = 0;
+ }
+ write_word(ss,AX,(read_word(ss,AX) & 0xff00) | attr);
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_teletype (car, page, attr, flag)
+Bit8u car;Bit8u page;Bit8u attr;Bit8u flag;
+{// flag = WITH_ATTR / NO_ATTR
+
+ Bit8u cheight,xcurs,ycurs,mode,line,bpp;
+ Bit16u nbcols,nbrows,address;
+ Bit16u cursor,dummy;
+
+ // special case if page is 0xff, use current page
+ if(page==0xff)
+ page=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
+
+ // Get the mode
+ mode=read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
+ line=find_vga_entry(mode);
+ if(line==0xFF)return;
+
+ // Get the cursor pos for the page
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+
+ // Get the dimensions
+ nbrows=read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
+ nbcols=read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+
+ switch(car)
+ {
+ case 7:
+ //FIXME should beep
+ break;
+
+ case 8:
+ if(xcurs>0)xcurs--;
+ break;
+
+ case '\r':
+ xcurs=0;
+ break;
+
+ case '\n':
+ xcurs=0;
+ ycurs++;
+ break;
+
+ case '\t':
+ do
+ {
+ biosfn_write_teletype(' ',page,attr,flag);
+ biosfn_get_cursor_pos(page,&dummy,&cursor);
+ xcurs=cursor&0x00ff;ycurs=(cursor&0xff00)>>8;
+ }while(xcurs%8==0);
+ break;
+
+ default:
+
+ if(vga_modes[line].class==TEXT)
+ {
+ // Compute the address
+ address=SCREEN_MEM_START(nbcols,nbrows,page)+(xcurs+ycurs*nbcols)*2;
+
+ // Write the char
+ write_byte(vga_modes[line].sstart,address,car);
+
+ if(flag==WITH_ATTR)
+ write_byte(vga_modes[line].sstart,address+1,attr);
+ }
+ else
+ {
+ // FIXME gfx mode not complete
+ cheight=vga_modes[line].cheight;
+ bpp=vga_modes[line].pixbits;
+ switch(vga_modes[line].memmodel)
+ {
+ case PLANAR4:
+ case PLANAR1:
+ write_gfx_char_pl4(car,attr,xcurs,ycurs,nbcols,cheight);
+ break;
+ case CGA:
+ write_gfx_char_cga(car,attr,xcurs,ycurs,nbcols,bpp);
+ break;
+ case LINEAR8:
+ write_gfx_char_lin(car,attr,xcurs,ycurs,nbcols);
+ break;
+#ifdef DEBUG
+ default:
+ unimplemented();
+#endif
+ }
+ }
+ xcurs++;
+ }
+
+ // Do we need to wrap ?
+ if(xcurs==nbcols)
+ {xcurs=0;
+ ycurs++;
+ }
+
+ // Do we need to scroll ?
+ if(ycurs==nbrows)
+ {
+ if(vga_modes[line].class==TEXT)
+ {
+ biosfn_scroll(0x01,0x07,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
+ }
+ else
+ {
+ biosfn_scroll(0x01,0x00,0,0,nbrows-1,nbcols-1,page,SCROLL_UP);
+ }
+ ycurs-=1;
+ }
+
+ // Set the cursor for the page
+ cursor=ycurs; cursor<<=8; cursor+=xcurs;
+ biosfn_set_cursor_pos(page,cursor);
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_get_video_mode:
+ push ds
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ push bx
+ mov bx, # BIOSMEM_CURRENT_PAGE
+ mov al, [bx]
+ pop bx
+ mov bh, al
+ push bx
+ mov bx, # BIOSMEM_VIDEO_CTL
+ mov ah, [bx]
+ and ah, #0x80
+ mov bx, # BIOSMEM_CURRENT_MODE
+ mov al, [bx]
+ or al, ah
+ mov bx, # BIOSMEM_NB_COLS
+ mov ah, [bx]
+ pop bx
+ pop ds
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_group_10:
+ cmp al, #0x00
+ jne int10_test_1001
+ jmp biosfn_set_single_palette_reg
+int10_test_1001:
+ cmp al, #0x01
+ jne int10_test_1002
+ jmp biosfn_set_overscan_border_color
+int10_test_1002:
+ cmp al, #0x02
+ jne int10_test_1003
+ jmp biosfn_set_all_palette_reg
+int10_test_1003:
+ cmp al, #0x03
+ jne int10_test_1007
+ jmp biosfn_toggle_intensity
+int10_test_1007:
+ cmp al, #0x07
+ jne int10_test_1008
+ jmp biosfn_get_single_palette_reg
+int10_test_1008:
+ cmp al, #0x08
+ jne int10_test_1009
+ jmp biosfn_read_overscan_border_color
+int10_test_1009:
+ cmp al, #0x09
+ jne int10_test_1010
+ jmp biosfn_get_all_palette_reg
+int10_test_1010:
+ cmp al, #0x10
+ jne int10_test_1012
+ jmp biosfn_set_single_dac_reg
+int10_test_1012:
+ cmp al, #0x12
+ jne int10_test_1013
+ jmp biosfn_set_all_dac_reg
+int10_test_1013:
+ cmp al, #0x13
+ jne int10_test_1015
+ jmp biosfn_select_video_dac_color_page
+int10_test_1015:
+ cmp al, #0x15
+ jne int10_test_1017
+ jmp biosfn_read_single_dac_reg
+int10_test_1017:
+ cmp al, #0x17
+ jne int10_test_1018
+ jmp biosfn_read_all_dac_reg
+int10_test_1018:
+ cmp al, #0x18
+ jne int10_test_1019
+ jmp biosfn_set_pel_mask
+int10_test_1019:
+ cmp al, #0x19
+ jne int10_test_101A
+ jmp biosfn_read_pel_mask
+int10_test_101A:
+ cmp al, #0x1a
+ jne int10_group_10_unknown
+ jmp biosfn_read_video_dac_state
+int10_group_10_unknown:
+#ifdef DEBUG
+ call _unknown
+#endif
+ ret
+
+biosfn_set_single_palette_reg:
+ cmp bl, #0x14
+ ja no_actl_reg1
+ push ax
+ push dx
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, bl
+ out dx, al
+ mov al, bh
+ out dx, al
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop ax
+no_actl_reg1:
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_overscan_border_color:
+ push bx
+ mov bl, #0x11
+ call biosfn_set_single_palette_reg
+ pop bx
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_all_palette_reg:
+ push ax
+ push bx
+ push cx
+ push dx
+ mov bx, dx
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov cl, #0x00
+ mov dx, # VGAREG_ACTL_ADDRESS
+set_palette_loop:
+ mov al, cl
+ out dx, al
+ seg es
+ mov al, [bx]
+ out dx, al
+ inc bx
+ inc cl
+ cmp cl, #0x10
+ jne set_palette_loop
+ mov al, #0x11
+ out dx, al
+ seg es
+ mov al, [bx]
+ out dx, al
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_toggle_intensity:
+ push ax
+ push bx
+ push dx
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x10
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ and al, #0xf7
+ and bl, #0x01
+ shl bl, 3
+ or al, bl
+ mov dx, # VGAREG_ACTL_ADDRESS
+ out dx, al
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop bx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_get_single_palette_reg:
+ cmp bl, #0x14
+ ja no_actl_reg2
+ push ax
+ push dx
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, bl
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ mov bh, al
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop ax
+no_actl_reg2:
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_overscan_border_color:
+ push ax
+ push bx
+ mov bl, #0x11
+ call biosfn_get_single_palette_reg
+ mov al, bh
+ pop bx
+ mov bh, al
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_get_all_palette_reg:
+ push ax
+ push bx
+ push cx
+ push dx
+ mov bx, dx
+ mov cl, #0x00
+get_palette_loop:
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, cl
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ seg es
+ mov [bx], al
+ inc bx
+ inc cl
+ cmp cl, #0x10
+ jne get_palette_loop
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x11
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ seg es
+ mov [bx], al
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_single_dac_reg:
+ push ax
+ push dx
+ mov dx, # VGAREG_DAC_WRITE_ADDRESS
+ mov al, bl
+ out dx, al
+ mov dx, # VGAREG_DAC_DATA
+ pop ax
+ push ax
+ mov al, ah
+ out dx, al
+ mov al, ch
+ out dx, al
+ mov al, cl
+ out dx, al
+ pop dx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_all_dac_reg:
+ push ax
+ push bx
+ push cx
+ push dx
+ mov dx, # VGAREG_DAC_WRITE_ADDRESS
+ mov al, bl
+ out dx, al
+ pop dx
+ push dx
+ mov bx, dx
+ mov dx, # VGAREG_DAC_DATA
+set_dac_loop:
+ seg es
+ mov al, [bx]
+ out dx, al
+ inc bx
+ seg es
+ mov al, [bx]
+ out dx, al
+ inc bx
+ seg es
+ mov al, [bx]
+ out dx, al
+ inc bx
+ dec cx
+ jnz set_dac_loop
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_select_video_dac_color_page:
+ push ax
+ push bx
+ push dx
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x10
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ and bl, #0x01
+ jnz set_dac_page
+ and al, #0x7f
+ shl bh, 7
+ or al, bh
+ mov dx, # VGAREG_ACTL_ADDRESS
+ out dx, al
+ jmp set_actl_normal
+set_dac_page:
+ push ax
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x14
+ out dx, al
+ pop ax
+ and al, #0x80
+ jnz set_dac_16_page
+ shl bh, 2
+set_dac_16_page:
+ and bh, #0x0f
+ mov al, bh
+ out dx, al
+set_actl_normal:
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop bx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_single_dac_reg:
+ push ax
+ push dx
+ mov dx, # VGAREG_DAC_READ_ADDRESS
+ mov al, bl
+ out dx, al
+ pop ax
+ mov ah, al
+ mov dx, # VGAREG_DAC_DATA
+ in al, dx
+ xchg al, ah
+ push ax
+ in al, dx
+ mov ch, al
+ in al, dx
+ mov cl, al
+ pop dx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_all_dac_reg:
+ push ax
+ push bx
+ push cx
+ push dx
+ mov dx, # VGAREG_DAC_READ_ADDRESS
+ mov al, bl
+ out dx, al
+ pop dx
+ push dx
+ mov bx, dx
+ mov dx, # VGAREG_DAC_DATA
+read_dac_loop:
+ in al, dx
+ seg es
+ mov [bx], al
+ inc bx
+ in al, dx
+ seg es
+ mov [bx], al
+ inc bx
+ in al, dx
+ seg es
+ mov [bx], al
+ inc bx
+ dec cx
+ jnz read_dac_loop
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_pel_mask:
+ push ax
+ push dx
+ mov dx, # VGAREG_PEL_MASK
+ mov al, bl
+ out dx, al
+ pop dx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_pel_mask:
+ push ax
+ push dx
+ mov dx, # VGAREG_PEL_MASK
+ in al, dx
+ mov bl, al
+ pop dx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_read_video_dac_state:
+ push ax
+ push dx
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x10
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ mov bl, al
+ shr bl, 7
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x14
+ out dx, al
+ mov dx, # VGAREG_ACTL_READ_DATA
+ in al, dx
+ mov bh, al
+ and bh, #0x0f
+ test bl, #0x01
+ jnz get_dac_16_page
+ shr bh, 2
+get_dac_16_page:
+ mov dx, # VGAREG_ACTL_RESET
+ in al, dx
+ mov dx, # VGAREG_ACTL_ADDRESS
+ mov al, #0x20
+ out dx, al
+ pop dx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_perform_gray_scale_summing (start,count)
+Bit16u start;Bit16u count;
+{Bit8u r,g,b;
+ Bit16u i;
+ Bit16u index;
+
+ inb(VGAREG_ACTL_RESET);
+ outb(VGAREG_ACTL_ADDRESS,0x00);
+
+ for( index = 0; index < count; index++ )
+ {
+ // set read address and switch to read mode
+ outb(VGAREG_DAC_READ_ADDRESS,start);
+ // get 6-bit wide RGB data values
+ r=inb( VGAREG_DAC_DATA );
+ g=inb( VGAREG_DAC_DATA );
+ b=inb( VGAREG_DAC_DATA );
+
+ // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
+ i = ( ( 77*r + 151*g + 28*b ) + 0x80 ) >> 8;
+
+ if(i>0x3f)i=0x3f;
+
+ // set write address and switch to write mode
+ outb(VGAREG_DAC_WRITE_ADDRESS,start);
+ // write new intensity value
+ outb( VGAREG_DAC_DATA, i&0xff );
+ outb( VGAREG_DAC_DATA, i&0xff );
+ outb( VGAREG_DAC_DATA, i&0xff );
+ start++;
+ }
+ inb(VGAREG_ACTL_RESET);
+ outb(VGAREG_ACTL_ADDRESS,0x20);
+}
+
+// --------------------------------------------------------------------------------------------
+static void get_font_access()
+{
+ASM_START
+ mov dx, # VGAREG_SEQU_ADDRESS
+ mov ax, #0x0100
+ out dx, ax
+ mov ax, #0x0402
+ out dx, ax
+ mov ax, #0x0704
+ out dx, ax
+ mov ax, #0x0300
+ out dx, ax
+ mov dx, # VGAREG_GRDC_ADDRESS
+ mov ax, #0x0204
+ out dx, ax
+ mov ax, #0x0005
+ out dx, ax
+ mov ax, #0x0406
+ out dx, ax
+ASM_END
+}
+
+static void release_font_access()
+{
+ASM_START
+ mov dx, # VGAREG_SEQU_ADDRESS
+ mov ax, #0x0100
+ out dx, ax
+ mov ax, #0x0302
+ out dx, ax
+ mov ax, #0x0304
+ out dx, ax
+ mov ax, #0x0300
+ out dx, ax
+ mov dx, # VGAREG_READ_MISC_OUTPUT
+ in al, dx
+ and al, #0x01
+ shl al, 2
+ or al, #0x0a
+ mov ah, al
+ mov al, #0x06
+ mov dx, # VGAREG_GRDC_ADDRESS
+ out dx, ax
+ mov ax, #0x0004
+ out dx, ax
+ mov ax, #0x1005
+ out dx, ax
+ASM_END
+}
+
+ASM_START
+idiv_u:
+ xor dx,dx
+ div bx
+ ret
+ASM_END
+
+static void set_scan_lines(lines) Bit8u lines;
+{
+ Bit16u crtc_addr,cols,page,vde;
+ Bit8u crtc_r9,ovl,rows;
+
+ crtc_addr = read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS);
+ outb(crtc_addr, 0x09);
+ crtc_r9 = inb(crtc_addr+1);
+ crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
+ outb(crtc_addr+1, crtc_r9);
+ if(lines==8)
+ {
+ biosfn_set_cursor_shape(0x06,0x07);
+ }
+ else
+ {
+ biosfn_set_cursor_shape(lines-4,lines-3);
+ }
+ write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, lines);
+ outb(crtc_addr, 0x12);
+ vde = inb(crtc_addr+1);
+ outb(crtc_addr, 0x07);
+ ovl = inb(crtc_addr+1);
+ vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
+ rows = vde / lines;
+ write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, rows-1);
+ cols = read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS);
+ write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, rows * cols * 2);
+}
+
+static void biosfn_load_text_user_pat (AL,ES,BP,CX,DX,BL,BH) Bit8u AL;Bit16u ES;Bit16u BP;Bit16u CX;Bit16u DX;Bit8u BL;Bit8u BH;
+{
+ Bit16u blockaddr,dest,i,src;
+
+ get_font_access();
+ blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+ for(i=0;i<CX;i++)
+ {
+ src = BP + i * BH;
+ dest = blockaddr + (DX + i) * 32;
+ memcpyb(0xA000, dest, ES, src, BH);
+ }
+ release_font_access();
+ if(AL>=0x10)
+ {
+ set_scan_lines(BH);
+ }
+}
+
+static void biosfn_load_text_8_14_pat (AL,BL) Bit8u AL;Bit8u BL;
+{
+ Bit16u blockaddr,dest,i,src;
+
+ get_font_access();
+ blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+ for(i=0;i<0x100;i++)
+ {
+ src = i * 14;
+ dest = blockaddr + i * 32;
+ memcpyb(0xA000, dest, 0xC000, vgafont14+src, 14);
+ }
+ release_font_access();
+ if(AL>=0x10)
+ {
+ set_scan_lines(14);
+ }
+}
+
+static void biosfn_load_text_8_8_pat (AL,BL) Bit8u AL;Bit8u BL;
+{
+ Bit16u blockaddr,dest,i,src;
+
+ get_font_access();
+ blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+ for(i=0;i<0x100;i++)
+ {
+ src = i * 8;
+ dest = blockaddr + i * 32;
+ memcpyb(0xA000, dest, 0xC000, vgafont8+src, 8);
+ }
+ release_font_access();
+ if(AL>=0x10)
+ {
+ set_scan_lines(8);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_set_text_block_specifier:
+ push ax
+ push dx
+ mov dx, # VGAREG_SEQU_ADDRESS
+ mov ah, bl
+ mov al, #0x03
+ out dx, ax
+ pop dx
+ pop ax
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_load_text_8_16_pat (AL,BL) Bit8u AL;Bit8u BL;
+{
+ Bit16u blockaddr,dest,i,src;
+
+ get_font_access();
+ blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+ for(i=0;i<0x100;i++)
+ {
+ src = i * 16;
+ dest = blockaddr + i * 32;
+ memcpyb(0xA000, dest, 0xC000, vgafont16+src, 16);
+ }
+ release_font_access();
+ if(AL>=0x10)
+ {
+ set_scan_lines(16);
+ }
+}
+
+static void biosfn_load_gfx_8_8_chars (ES,BP) Bit16u ES;Bit16u BP;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_load_gfx_user_chars (ES,BP,CX,BL,DL) Bit16u ES;Bit16u BP;Bit16u CX;Bit8u BL;Bit8u DL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_load_gfx_8_14_chars (BL) Bit8u BL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_load_gfx_8_8_dd_chars (BL) Bit8u BL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_load_gfx_8_16_chars (BL) Bit8u BL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+// --------------------------------------------------------------------------------------------
+static void biosfn_get_font_info (BH,ES,BP,CX,DX)
+Bit8u BH;Bit16u *ES;Bit16u *BP;Bit16u *CX;Bit16u *DX;
+{Bit16u ss=get_SS();
+
+ switch(BH)
+ {case 0x00:
+ write_word(ss,ES,read_word(0x00,0x1f*4));
+ write_word(ss,BP,read_word(0x00,(0x1f*4)+2));
+ break;
+ case 0x01:
+ write_word(ss,ES,read_word(0x00,0x43*4));
+ write_word(ss,BP,read_word(0x00,(0x43*4)+2));
+ break;
+ case 0x02:
+ write_word(ss,ES,0xC000);
+ write_word(ss,BP,vgafont14);
+ break;
+ case 0x03:
+ write_word(ss,ES,0xC000);
+ write_word(ss,BP,vgafont8);
+ break;
+ case 0x04:
+ write_word(ss,ES,0xC000);
+ write_word(ss,BP,vgafont8+128*8);
+ break;
+ case 0x05:
+ write_word(ss,ES,0xC000);
+ write_word(ss,BP,vgafont14alt);
+ break;
+ case 0x06:
+ write_word(ss,ES,0xC000);
+ write_word(ss,BP,vgafont16);
+ break;
+ case 0x07:
+ write_word(ss,ES,0xC000);
+ write_word(ss,BP,vgafont16alt);
+ break;
+ default:
+ #ifdef DEBUG
+ printf("Get font info BH(%02x) was discarded\n",BH);
+ #endif
+ return;
+ }
+ // Set byte/char of on screen font
+ write_word(ss,CX,(Bit16u)read_byte(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT));
+
+ // Set Highest char row
+ write_word(ss,DX,(Bit16u)read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS));
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_get_ega_info:
+ push ds
+ push ax
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ xor ch, ch
+ mov bx, # BIOSMEM_SWITCHES
+ mov cl, [bx]
+ and cl, #0x0f
+ mov bx, # BIOSMEM_CRTC_ADDRESS
+ mov ax, [bx]
+ mov bx, #0x0003
+ cmp ax, # VGAREG_MDA_CRTC_ADDRESS
+ jne mode_ega_color
+ mov bh, #0x01
+mode_ega_color:
+ pop ax
+ pop ds
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_alternate_prtsc()
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_select_vert_res:
+
+; res : 00 200 lines, 01 350 lines, 02 400 lines
+
+ push ds
+ push bx
+ push dx
+ mov dl, al
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ mov bx, # BIOSMEM_MODESET_CTL
+ mov al, [bx]
+ mov bx, # BIOSMEM_SWITCHES
+ mov ah, [bx]
+ cmp dl, #0x01
+ je vert_res_350
+ jb vert_res_200
+ cmp dl, #0x02
+ je vert_res_400
+#ifdef DEBUG
+ mov al, dl
+ xor ah, ah
+ push ax
+ mov bx, #msg_vert_res
+ push bx
+ call _printf
+ add sp, #4
+#endif
+ jmp set_retcode
+vert_res_400:
+
+ ; reset modeset ctl bit 7 and set bit 4
+ ; set switches bit 3-0 to 0x09
+
+ and al, #0x7f
+ or al, #0x10
+ and ah, #0xf0
+ or ah, #0x09
+ jnz set_vert_res
+vert_res_350:
+
+ ; reset modeset ctl bit 7 and bit 4
+ ; set switches bit 3-0 to 0x09
+
+ and al, #0x6f
+ and ah, #0xf0
+ or ah, #0x09
+ jnz set_vert_res
+vert_res_200:
+
+ ; set modeset ctl bit 7 and reset bit 4
+ ; set switches bit 3-0 to 0x08
+
+ and al, #0xef
+ or al, #0x80
+ and ah, #0xf0
+ or ah, #0x08
+set_vert_res:
+ mov bx, # BIOSMEM_MODESET_CTL
+ mov [bx], al
+ mov bx, # BIOSMEM_SWITCHES
+ mov [bx], ah
+set_retcode:
+ mov ax, #0x1212
+ pop dx
+ pop bx
+ pop ds
+ ret
+
+#ifdef DEBUG
+msg_vert_res:
+.ascii "Select vert res (%02x) was discarded"
+.byte 0x0d,0x0a,0x00
+#endif
+
+
+biosfn_enable_default_palette_loading:
+ push ds
+ push bx
+ push dx
+ mov dl, al
+ and dl, #0x01
+ shl dl, 3
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ mov bx, # BIOSMEM_MODESET_CTL
+ mov al, [bx]
+ and al, #0xf7
+ or al, dl
+ mov [bx], al
+ mov ax, #0x1212
+ pop dx
+ pop bx
+ pop ds
+ ret
+
+
+biosfn_enable_video_addressing:
+ push bx
+ push dx
+ mov bl, al
+ and bl, #0x01
+ xor bl, #0x01
+ shl bl, 1
+ mov dx, # VGAREG_READ_MISC_OUTPUT
+ in al, dx
+ and al, #0xfd
+ or al, bl
+ mov dx, # VGAREG_WRITE_MISC_OUTPUT
+ out dx, al
+ mov ax, #0x1212
+ pop dx
+ pop bx
+ ret
+
+
+biosfn_enable_grayscale_summing:
+ push ds
+ push bx
+ push dx
+ mov dl, al
+ and dl, #0x01
+ xor dl, #0x01
+ shl dl, 1
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ mov bx, # BIOSMEM_MODESET_CTL
+ mov al, [bx]
+ and al, #0xfd
+ or al, dl
+ mov [bx], al
+ mov ax, #0x1212
+ pop dx
+ pop bx
+ pop ds
+ ret
+
+
+biosfn_enable_cursor_emulation:
+ push ds
+ push bx
+ push dx
+ mov dl, al
+ and dl, #0x01
+ xor dl, #0x01
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ mov bx, # BIOSMEM_MODESET_CTL
+ mov al, [bx]
+ and al, #0xfe
+ or al, dl
+ mov [bx], al
+ mov ax, #0x1212
+ pop dx
+ pop bx
+ pop ds
+ ret
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_switch_video_interface (AL,ES,DX) Bit8u AL;Bit16u ES;Bit16u DX;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_enable_video_refresh_control (AL) Bit8u AL;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_write_string (flag,page,attr,count,row,col,seg,offset)
+Bit8u flag;Bit8u page;Bit8u attr;Bit16u count;Bit8u row;Bit8u col;Bit16u seg;Bit16u offset;
+{
+ Bit16u newcurs,oldcurs,dummy;
+ Bit8u car,carattr;
+
+ // Read curs info for the page
+ biosfn_get_cursor_pos(page,&dummy,&oldcurs);
+
+ // if row=0xff special case : use current cursor position
+ if(row==0xff)
+ {col=oldcurs&0x00ff;
+ row=(oldcurs&0xff00)>>8;
+ }
+
+ newcurs=row; newcurs<<=8; newcurs+=col;
+ biosfn_set_cursor_pos(page,newcurs);
+
+ while(count--!=0)
+ {
+ car=read_byte(seg,offset++);
+ if((flag&0x02)!=0)
+ attr=read_byte(seg,offset++);
+
+ biosfn_write_teletype(car,page,attr,WITH_ATTR);
+ }
+
+ // Set back curs pos
+ if((flag&0x01)==0)
+ biosfn_set_cursor_pos(page,oldcurs);
+}
+
+// --------------------------------------------------------------------------------------------
+ASM_START
+biosfn_group_1A:
+ cmp al, #0x00
+ je biosfn_read_display_code
+ cmp al, #0x01
+ je biosfn_set_display_code
+#ifdef DEBUG
+ call _unknown
+#endif
+ ret
+biosfn_read_display_code:
+ push ds
+ push ax
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ mov bx, # BIOSMEM_DCC_INDEX
+ mov al, [bx]
+ mov bl, al
+ xor bh, bh
+ pop ax
+ mov al, ah
+ pop ds
+ ret
+biosfn_set_display_code:
+ push ds
+ push ax
+ push bx
+ mov ax, # BIOSMEM_SEG
+ mov ds, ax
+ mov ax, bx
+ mov bx, # BIOSMEM_DCC_INDEX
+ mov [bx], al
+#ifdef DEBUG
+ mov al, ah
+ xor ah, ah
+ push ax
+ mov bx, #msg_alt_dcc
+ push bx
+ call _printf
+ add sp, #4
+#endif
+ pop bx
+ pop ax
+ mov al, ah
+ pop ds
+ ret
+
+#ifdef DEBUG
+msg_alt_dcc:
+.ascii "Alternate Display code (%02x) was discarded"
+.byte 0x0d,0x0a,0x00
+#endif
+ASM_END
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_read_state_info (BX,ES,DI)
+Bit16u BX;Bit16u ES;Bit16u DI;
+{
+ // Address of static functionality table
+ write_word(ES,DI+0x00,&static_functionality);
+ write_word(ES,DI+0x02,0xC000);
+
+ // Hard coded copy from BIOS area. Should it be cleaner ?
+ memcpyb(ES,DI+0x04,BIOSMEM_SEG,0x49,30);
+ memcpyb(ES,DI+0x22,BIOSMEM_SEG,0x84,3);
+
+ write_byte(ES,DI+0x25,read_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX));
+ write_byte(ES,DI+0x26,0);
+ write_byte(ES,DI+0x27,16);
+ write_byte(ES,DI+0x28,0);
+ write_byte(ES,DI+0x29,8);
+ write_byte(ES,DI+0x2a,2);
+ write_byte(ES,DI+0x2b,0);
+ write_byte(ES,DI+0x2c,0);
+ write_byte(ES,DI+0x31,3);
+ write_byte(ES,DI+0x32,0);
+
+ memsetb(ES,DI+0x33,0,13);
+}
+
+// --------------------------------------------------------------------------------------------
+static void biosfn_read_video_state_size (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_save_video_state (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+static void biosfn_restore_video_state (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX;
+{
+#ifdef DEBUG
+ unimplemented();
+#endif
+}
+
+// ============================================================================================
+//
+// Video Utils
+//
+// ============================================================================================
+
+// --------------------------------------------------------------------------------------------
+static Bit8u find_vga_entry(mode)
+Bit8u mode;
+{
+ Bit8u i,line=0xFF;
+ for(i=0;i<=MODE_MAX;i++)
+ if(vga_modes[i].svgamode==mode)
+ {line=i;
+ break;
+ }
+ return line;
+}
+
+/* =========================================================== */
+/*
+ * Misc Utils
+*/
+/* =========================================================== */
+
+// --------------------------------------------------------------------------------------------
+static void memsetb(seg,offset,value,count)
+ Bit16u seg;
+ Bit16u offset;
+ Bit16u value;
+ Bit16u count;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push cx
+ push es
+ push di
+
+ mov cx, 10[bp] ; count
+ cmp cx, #0x00
+ je memsetb_end
+ mov ax, 4[bp] ; segment
+ mov es, ax
+ mov ax, 6[bp] ; offset
+ mov di, ax
+ mov al, 8[bp] ; value
+ cld
+ rep
+ stosb
+
+memsetb_end:
+ pop di
+ pop es
+ pop cx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void memsetw(seg,offset,value,count)
+ Bit16u seg;
+ Bit16u offset;
+ Bit16u value;
+ Bit16u count;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push cx
+ push es
+ push di
+
+ mov cx, 10[bp] ; count
+ cmp cx, #0x00
+ je memsetw_end
+ mov ax, 4[bp] ; segment
+ mov es, ax
+ mov ax, 6[bp] ; offset
+ mov di, ax
+ mov ax, 8[bp] ; value
+ cld
+ rep
+ stosw
+
+memsetw_end:
+ pop di
+ pop es
+ pop cx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void memcpyb(dseg,doffset,sseg,soffset,count)
+ Bit16u dseg;
+ Bit16u doffset;
+ Bit16u sseg;
+ Bit16u soffset;
+ Bit16u count;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push cx
+ push es
+ push di
+ push ds
+ push si
+
+ mov cx, 12[bp] ; count
+ cmp cx, #0x0000
+ je memcpyb_end
+ mov ax, 4[bp] ; dsegment
+ mov es, ax
+ mov ax, 6[bp] ; doffset
+ mov di, ax
+ mov ax, 8[bp] ; ssegment
+ mov ds, ax
+ mov ax, 10[bp] ; soffset
+ mov si, ax
+ cld
+ rep
+ movsb
+
+memcpyb_end:
+ pop si
+ pop ds
+ pop di
+ pop es
+ pop cx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void memcpyw(dseg,doffset,sseg,soffset,count)
+ Bit16u dseg;
+ Bit16u doffset;
+ Bit16u sseg;
+ Bit16u soffset;
+ Bit16u count;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push cx
+ push es
+ push di
+ push ds
+ push si
+
+ mov cx, 12[bp] ; count
+ cmp cx, #0x0000
+ je memcpyw_end
+ mov ax, 4[bp] ; dsegment
+ mov es, ax
+ mov ax, 6[bp] ; doffset
+ mov di, ax
+ mov ax, 8[bp] ; ssegment
+ mov ds, ax
+ mov ax, 10[bp] ; soffset
+ mov si, ax
+ cld
+ rep
+ movsw
+
+memcpyw_end:
+ pop si
+ pop ds
+ pop di
+ pop es
+ pop cx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+/* =========================================================== */
+/*
+ * These functions where ripped from Kevin's rombios.c
+*/
+/* =========================================================== */
+
+// --------------------------------------------------------------------------------------------
+static Bit8u
+read_byte(seg, offset)
+ Bit16u seg;
+ Bit16u offset;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push bx
+ push ds
+ mov ax, 4[bp] ; segment
+ mov ds, ax
+ mov bx, 6[bp] ; offset
+ mov al, [bx]
+ ;; al = return value (byte)
+ pop ds
+ pop bx
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static Bit16u
+read_word(seg, offset)
+ Bit16u seg;
+ Bit16u offset;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push bx
+ push ds
+ mov ax, 4[bp] ; segment
+ mov ds, ax
+ mov bx, 6[bp] ; offset
+ mov ax, [bx]
+ ;; ax = return value (word)
+ pop ds
+ pop bx
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void
+write_byte(seg, offset, data)
+ Bit16u seg;
+ Bit16u offset;
+ Bit8u data;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push bx
+ push ds
+ mov ax, 4[bp] ; segment
+ mov ds, ax
+ mov bx, 6[bp] ; offset
+ mov al, 8[bp] ; data byte
+ mov [bx], al ; write data byte
+ pop ds
+ pop bx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+static void
+write_word(seg, offset, data)
+ Bit16u seg;
+ Bit16u offset;
+ Bit16u data;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push bx
+ push ds
+ mov ax, 4[bp] ; segment
+ mov ds, ax
+ mov bx, 6[bp] ; offset
+ mov ax, 8[bp] ; data word
+ mov [bx], ax ; write data word
+ pop ds
+ pop bx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+ Bit8u
+inb(port)
+ Bit16u port;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push dx
+ mov dx, 4[bp]
+ in al, dx
+ pop dx
+
+ pop bp
+ASM_END
+}
+
+ Bit16u
+inw(port)
+ Bit16u port;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push dx
+ mov dx, 4[bp]
+ in ax, dx
+ pop dx
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+ void
+outb(port, val)
+ Bit16u port;
+ Bit8u val;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push dx
+ mov dx, 4[bp]
+ mov al, 6[bp]
+ out dx, al
+ pop dx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+// --------------------------------------------------------------------------------------------
+ void
+outw(port, val)
+ Bit16u port;
+ Bit16u val;
+{
+ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+ push dx
+ mov dx, 4[bp]
+ mov ax, 6[bp]
+ out dx, ax
+ pop dx
+ pop ax
+
+ pop bp
+ASM_END
+}
+
+Bit16u get_SS()
+{
+ASM_START
+ mov ax, ss
+ASM_END
+}
+
+#ifdef DEBUG
+void unimplemented()
+{
+ printf("--> Unimplemented\n");
+}
+
+void unknown()
+{
+ printf("--> Unknown int10\n");
+}
+#endif
+
+// --------------------------------------------------------------------------------------------
+#if defined(USE_BX_INFO) || defined(DEBUG) || defined(CIRRUS_DEBUG)
+void printf(s)
+ Bit8u *s;
+{
+ Bit8u c, format_char;
+ Boolean in_format;
+ unsigned format_width, i;
+ Bit16u *arg_ptr;
+ Bit16u arg_seg, arg, digit, nibble, shift_count;
+
+ arg_ptr = &s;
+ arg_seg = get_SS();
+
+ in_format = 0;
+ format_width = 0;
+
+ while (c = read_byte(0xc000, s)) {
+ if ( c == '%' ) {
+ in_format = 1;
+ format_width = 0;
+ }
+ else if (in_format) {
+ if ( (c>='0') && (c<='9') ) {
+ format_width = (format_width * 10) + (c - '0');
+ }
+ else if (c == 'x') {
+ arg_ptr++; // increment to next arg
+ arg = read_word(arg_seg, arg_ptr);
+ if (format_width == 0)
+ format_width = 4;
+ i = 0;
+ digit = format_width - 1;
+ for (i=0; i<format_width; i++) {
+ nibble = (arg >> (4 * digit)) & 0x000f;
+ if (nibble <= 9)
+ outb(0xE9, nibble + '0');
+ else
+ outb(0xE9, (nibble - 10) + 'A');
+ digit--;
+ }
+ in_format = 0;
+ }
+ //else if (c == 'd') {
+ // in_format = 0;
+ // }
+ }
+ else {
+ outb(0xE9, c);
+ }
+ s ++;
+ }
+}
+#endif
+
+#ifdef VBE
+#include "vbe.c"
+#endif
+
+#ifdef CIRRUS
+#include "clext.c"
+#endif
+
+// --------------------------------------------------------------------------------------------
+
+ASM_START
+;; DATA_SEG_DEFS_HERE
+ASM_END
+
+ASM_START
+.ascii "vgabios ends here"
+.byte 0x00
+vgabios_end:
+.byte 0xCB
+;; BLOCK_STRINGS_BEGIN
+ASM_END
diff --git a/tools/firmware/vgabios/vgabios.h b/tools/firmware/vgabios/vgabios.h
new file mode 100644
index 0000000000..3ad4bae94d
--- /dev/null
+++ b/tools/firmware/vgabios/vgabios.h
@@ -0,0 +1,47 @@
+#ifndef vgabios_h_included
+#define vgabios_h_included
+
+/* Types */
+typedef unsigned char Bit8u;
+typedef unsigned short Bit16u;
+typedef unsigned long Bit32u;
+typedef unsigned short Boolean;
+
+/* Defines */
+
+#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
+#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
+#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
+#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
+#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
+#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
+#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
+#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
+
+#define GET_AL() ( AX & 0x00ff )
+#define GET_BL() ( BX & 0x00ff )
+#define GET_CL() ( CX & 0x00ff )
+#define GET_DL() ( DX & 0x00ff )
+#define GET_AH() ( AX >> 8 )
+#define GET_BH() ( BX >> 8 )
+#define GET_CH() ( CX >> 8 )
+#define GET_DH() ( DX >> 8 )
+
+#define SET_CF() FLAGS |= 0x0001
+#define CLEAR_CF() FLAGS &= 0xfffe
+#define GET_CF() (FLAGS & 0x0001)
+
+#define SET_ZF() FLAGS |= 0x0040
+#define CLEAR_ZF() FLAGS &= 0xffbf
+#define GET_ZF() (FLAGS & 0x0040)
+
+#define SCROLL_DOWN 0
+#define SCROLL_UP 1
+#define NO_ATTR 2
+#define WITH_ATTR 3
+
+#define SCREEN_SIZE(x,y) (((x*y*2)|0x00ff)+1)
+#define SCREEN_MEM_START(x,y,p) ((((x*y*2)|0x00ff)+1)*p)
+#define SCREEN_IO_START(x,y,p) ((((x*y)|0x00ff)+1)*p)
+
+#endif
diff --git a/tools/firmware/vgabios/vgafonts.h b/tools/firmware/vgabios/vgafonts.h
new file mode 100644
index 0000000000..0c213e66bc
--- /dev/null
+++ b/tools/firmware/vgabios/vgafonts.h
@@ -0,0 +1,784 @@
+/*
+ * These fonts come from ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+ * The package is (c) by Joseph Gil
+ * The individual fonts are public domain
+ */
+static Bit8u vgafont8[256*8]=
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
+ 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
+ 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
+ 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
+ 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+ 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
+ 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
+ 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
+ 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
+ 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
+ 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
+ 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
+ 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+ 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
+ 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+ 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
+ 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
+ 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+ 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
+ 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
+ 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
+ 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
+ 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+ 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+ 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
+ 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
+ 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
+ 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
+ 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
+ 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
+ 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
+ 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
+ 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
+ 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
+ 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
+ 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
+ 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
+ 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
+ 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
+ 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
+ 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
+ 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
+ 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
+ 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
+ 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+ 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
+ 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
+ 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
+ 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
+ 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+ 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
+ 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
+ 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
+ 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
+ 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
+ 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
+ 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
+ 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
+ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
+ 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
+ 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+ 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
+ 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
+ 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
+ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+ 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
+ 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
+ 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78,
+ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00,
+ 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38,
+ 0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
+ 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
+ 0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00,
+ 0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00,
+ 0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00,
+ 0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00,
+ 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00,
+ 0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00,
+ 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+ 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18,
+ 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00,
+ 0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30,
+ 0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7,
+ 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70,
+ 0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00,
+ 0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00,
+ 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00,
+ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00,
+ 0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00,
+ 0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f,
+ 0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03,
+ 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00,
+ 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00,
+ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00,
+ 0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0,
+ 0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00,
+ 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00,
+ 0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00,
+ 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0,
+ 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc,
+ 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00,
+ 0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00,
+ 0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0,
+ 0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00,
+ 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00,
+ 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00,
+ 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00,
+ 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00,
+ 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70,
+ 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00,
+ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c,
+ 0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static Bit8u vgafont14[256*14]=
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x06, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x66, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x6c, 0x6c, 0x78, 0x6c, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x7c, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x8c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x70, 0x1c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0xc6, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xcc, 0x76, 0x36, 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0xc6, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0xf8, 0xcc, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0x40, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static Bit8u vgafont16[256*16]=
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static Bit8u vgafont14alt[1]={0x00};
+static Bit8u vgafont16alt[1]={0x00};
diff --git a/tools/firmware/vgabios/vgatables.h b/tools/firmware/vgabios/vgatables.h
new file mode 100644
index 0000000000..e5eca1e4e7
--- /dev/null
+++ b/tools/firmware/vgabios/vgatables.h
@@ -0,0 +1,318 @@
+/*
+ *
+ * BIOS Memory
+ *
+ */
+#define BIOSMEM_SEG 0x40
+
+#define BIOSMEM_INITIAL_MODE 0x10
+#define BIOSMEM_CURRENT_MODE 0x49
+#define BIOSMEM_NB_COLS 0x4A
+#define BIOSMEM_PAGE_SIZE 0x4C
+#define BIOSMEM_CURRENT_START 0x4E
+#define BIOSMEM_CURSOR_POS 0x50
+#define BIOSMEM_CURSOR_TYPE 0x60
+#define BIOSMEM_CURRENT_PAGE 0x62
+#define BIOSMEM_CRTC_ADDRESS 0x63
+#define BIOSMEM_CURRENT_MSR 0x65
+#define BIOSMEM_CURRENT_PAL 0x66
+#define BIOSMEM_NB_ROWS 0x84
+#define BIOSMEM_CHAR_HEIGHT 0x85
+#define BIOSMEM_VIDEO_CTL 0x87
+#define BIOSMEM_SWITCHES 0x88
+#define BIOSMEM_MODESET_CTL 0x89
+#define BIOSMEM_DCC_INDEX 0x8A
+#define BIOSMEM_VS_POINTER 0xA8
+#define BIOSMEM_VBE_FLAG 0xB9
+#define BIOSMEM_VBE_MODE 0xBA
+
+
+/*
+ *
+ * VGA registers
+ *
+ */
+#define VGAREG_ACTL_ADDRESS 0x3c0
+#define VGAREG_ACTL_WRITE_DATA 0x3c0
+#define VGAREG_ACTL_READ_DATA 0x3c1
+
+#define VGAREG_INPUT_STATUS 0x3c2
+#define VGAREG_WRITE_MISC_OUTPUT 0x3c2
+#define VGAREG_VIDEO_ENABLE 0x3c3
+#define VGAREG_SEQU_ADDRESS 0x3c4
+#define VGAREG_SEQU_DATA 0x3c5
+
+#define VGAREG_PEL_MASK 0x3c6
+#define VGAREG_DAC_STATE 0x3c7
+#define VGAREG_DAC_READ_ADDRESS 0x3c7
+#define VGAREG_DAC_WRITE_ADDRESS 0x3c8
+#define VGAREG_DAC_DATA 0x3c9
+
+#define VGAREG_READ_FEATURE_CTL 0x3ca
+#define VGAREG_READ_MISC_OUTPUT 0x3cc
+
+#define VGAREG_GRDC_ADDRESS 0x3ce
+#define VGAREG_GRDC_DATA 0x3cf
+
+#define VGAREG_MDA_CRTC_ADDRESS 0x3b4
+#define VGAREG_MDA_CRTC_DATA 0x3b5
+#define VGAREG_VGA_CRTC_ADDRESS 0x3d4
+#define VGAREG_VGA_CRTC_DATA 0x3d5
+
+#define VGAREG_MDA_WRITE_FEATURE_CTL 0x3ba
+#define VGAREG_VGA_WRITE_FEATURE_CTL 0x3da
+#define VGAREG_ACTL_RESET 0x3da
+
+#define VGAREG_MDA_MODECTL 0x3b8
+#define VGAREG_CGA_MODECTL 0x3d8
+#define VGAREG_CGA_PALETTE 0x3d9
+
+/* Video memory */
+#define VGAMEM_GRAPH 0xA000
+#define VGAMEM_CTEXT 0xB800
+#define VGAMEM_MTEXT 0xB000
+
+/*
+ *
+ * Tables of default values for each mode
+ *
+ */
+#define MODE_MAX 0x14
+#define TEXT 0x00
+#define GRAPH 0x01
+
+#define CTEXT 0x00
+#define MTEXT 0x01
+#define CGA 0x02
+#define PLANAR1 0x03
+#define PLANAR4 0x04
+#define LINEAR8 0x05
+
+// for SVGA
+#define LINEAR15 0x10
+#define LINEAR16 0x11
+#define LINEAR24 0x12
+#define LINEAR32 0x13
+
+typedef struct
+{Bit8u svgamode;
+ Bit16u vesamode;
+ Bit8u class; /* TEXT, GRAPH */
+ Bit8u memmodel; /* CTEXT,MTEXT,CGA,PL1,PL2,PL4,P8,P15,P16,P24,P32 */
+ Bit8u nbpages;
+ Bit8u pixbits;
+ Bit16u swidth, sheight;
+ Bit16u twidth, theight;
+ Bit16u cwidth, cheight;
+ Bit16u sstart;
+ Bit16u slength;
+ Bit8u miscreg;
+ Bit8u pelmask;
+ Bit8u crtcmodel;
+ Bit8u actlmodel;
+ Bit8u grdcmodel;
+ Bit8u sequmodel;
+ Bit8u dacmodel; /* 0 1 2 3 */
+} VGAMODES;
+
+static VGAMODES vga_modes[MODE_MAX+1]=
+{//mode vesa class model pg bits sw sh tw th cw ch sstart slength misc pelm crtc actl gdc sequ dac
+ {0x00, 0xFFFF, TEXT, CTEXT, 8, 4, 360, 400, 40, 25, 9, 16, 0xB800, 0x0800, 0x67, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02},
+ {0x01, 0xFFFF, TEXT, CTEXT, 8, 4, 360, 400, 40, 25, 9, 16, 0xB800, 0x0800, 0x67, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02},
+ {0x02, 0xFFFF, TEXT, CTEXT, 4, 4, 720, 400, 80, 25, 9, 16, 0xB800, 0x1000, 0x67, 0xFF, 0x01, 0x00, 0x00, 0x01, 0x02},
+ {0x03, 0xFFFF, TEXT, CTEXT, 4, 4, 720, 400, 80, 25, 9, 16, 0xB800, 0x1000, 0x67, 0xFF, 0x01, 0x00, 0x00, 0x01, 0x02},
+ {0x04, 0xFFFF, GRAPH, CGA, 4, 2, 320, 200, 40, 25, 8, 8, 0xB800, 0x0800, 0x63, 0xFF, 0x02, 0x01, 0x01, 0x02, 0x01},
+ {0x05, 0xFFFF, GRAPH, CGA, 1, 2, 320, 200, 40, 25, 8, 8, 0xB800, 0x0800, 0x63, 0xFF, 0x02, 0x01, 0x01, 0x02, 0x01},
+ {0x06, 0xFFFF, GRAPH, CGA, 1, 1, 640, 200, 80, 25, 8, 8, 0xB800, 0x1000, 0x63, 0xFF, 0x03, 0x02, 0x02, 0x03, 0x01},
+ {0x07, 0xFFFF, TEXT, MTEXT, 4, 4, 720, 400, 80, 25, 9, 16, 0xB000, 0x1000, 0x66, 0xFF, 0x04, 0x03, 0x03, 0x01, 0x00},
+ {0x0D, 0xFFFF, GRAPH, PLANAR4, 8, 4, 320, 200, 40, 25, 8, 8, 0xA000, 0x2000, 0x63, 0xFF, 0x05, 0x04, 0x04, 0x04, 0x01},
+ {0x0E, 0xFFFF, GRAPH, PLANAR4, 4, 4, 640, 200, 80, 25, 8, 8, 0xA000, 0x4000, 0x63, 0xFF, 0x06, 0x04, 0x04, 0x05, 0x01},
+ {0x0F, 0xFFFF, GRAPH, PLANAR1, 2, 1, 640, 350, 80, 25, 8, 14, 0xA000, 0x8000, 0xa3, 0xFF, 0x07, 0x05, 0x04, 0x05, 0x00},
+ {0x10, 0xFFFF, GRAPH, PLANAR4, 2, 4, 640, 350, 80, 25, 8, 14, 0xA000, 0x8000, 0xa3, 0xFF, 0x07, 0x06, 0x04, 0x05, 0x02},
+ {0x11, 0xFFFF, GRAPH, PLANAR1, 1, 1, 640, 480, 80, 30, 8, 16, 0xA000, 0x0000, 0xe3, 0xFF, 0x08, 0x07, 0x04, 0x05, 0x02},
+ {0x12, 0xFFFF, GRAPH, PLANAR4, 1, 4, 640, 480, 80, 30, 8, 16, 0xA000, 0x0000, 0xe3, 0xFF, 0x08, 0x06, 0x04, 0x05, 0x02},
+ {0x13, 0xFFFF, GRAPH, LINEAR8, 1, 8, 320, 200, 40, 25, 8, 8, 0xA000, 0x0000, 0x63, 0xFF, 0x09, 0x08, 0x05, 0x06, 0x03},
+ {0x6A, 0xFFFF, GRAPH, PLANAR4, 1, 4, 800, 600,100, 37, 8, 16, 0xA000, 0x0000, 0xe3, 0xFF, 0x0A, 0x06, 0x04, 0x05, 0x02}
+};
+
+/* CRTC */
+#define CRTC_MAX_REG 0x18
+#define CRTC_MAX_MODEL 0x0A
+static Bit8u crtc_access[CRTC_MAX_REG+1]=
+{ /* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+static Bit8u crtc_regs[CRTC_MAX_MODEL+1][CRTC_MAX_REG+1]=
+{/* Model 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 */
+ /* 00 */ 0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,0xff,
+ /* 01 */ 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,0xff,
+ /* 02 */ 0x2d,0x27,0x28,0x90,0x2b,0x80,0xbf,0x1f,0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,0xff,
+ /* 03 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xc2,0xff,
+ /* 04 */ 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x0f,0x96,0xb9,0xa3,0xff,
+ /* 05 */ 0x2d,0x27,0x28,0x90,0x2b,0x80,0xbf,0x1f,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xe3,0xff,
+ /* 06 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xe3,0xff,
+ /* 07 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x85,0x5d,0x28,0x0f,0x63,0xba,0xe3,0xff,
+ /* 08 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0xea,0x8c,0xdf,0x28,0x00,0xe7,0x04,0xe3,0xff,
+ /* 09 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x40,0x96,0xb9,0xa3,0xff,
+ /* 0A */ 0x7f,0x63,0x63,0x83,0x6b,0x1b,0x72,0xf0,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x8d,0x57,0x32,0x00,0x57,0x73,0xe3,0xff
+};
+
+/* Attribute Controler 0x3c0 */
+#define ACTL_MAX_REG 0x14
+#define ACTL_MAX_MODEL 0x08
+
+static Bit8u actl_access[ACTL_MAX_REG+1]=
+{/* 00 01 02 03 04 05 06 07 08 09 0A 0B OC OD OE OF 10 11 12 13 14 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+
+static Bit8u actl_regs[ACTL_MAX_MODEL+1][ACTL_MAX_REG+1]=
+{/* Model 00 01 02 03 04 05 06 07 08 09 0A 0B OC OD OE OF 10 11 12 13 14 */
+ /* 00 */ 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x0c,0x00,0x0f,0x08,0x00,
+ /* 01 */ 0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x01,0x00,0x03,0x00,0x00,
+ /* 02 */ 0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x01,0x00,0x01,0x00,0x00,
+ /* 03 */ 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0e,0x00,0x0f,0x08,0x00,
+ /* 04 */ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x01,0x00,0x0f,0x00,0x00,
+ /* 05 */ 0x00,0x08,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,0x01,0x00,0x01,0x00,0x00,
+ /* 06 */ 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x01,0x00,0x0f,0x00,0x00,
+ /* 07 */ 0x00,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x01,0x00,0x01,0x00,0x00,
+ /* 08 */ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x41,0x00,0x0f,0x00,0x00
+};
+
+/* Sequencer 0x3c4 */
+#define SEQU_MAX_REG 0x04
+#define SEQU_MAX_MODEL 0x06
+
+static Bit8u sequ_access[SEQU_MAX_REG+1]=
+{ /* 00 01 02 03 04 */
+ 0x00,0x00,0x00,0x00,0x00
+};
+
+static Bit8u sequ_regs[SEQU_MAX_MODEL+1][SEQU_MAX_REG+1]=
+{/* Model 00 01 02 03 04 */
+ /* 00 */ 0x03,0x08,0x03,0x00,0x02,
+ /* 01 */ 0x03,0x00,0x03,0x00,0x02,
+ /* 02 */ 0x03,0x09,0x03,0x00,0x02,
+ /* 03 */ 0x03,0x01,0x01,0x00,0x06,
+ /* 04 */ 0x03,0x09,0x0f,0x00,0x06,
+ /* 05 */ 0x03,0x01,0x0f,0x00,0x06,
+ /* 06 */ 0x03,0x01,0x0f,0x00,0x0e
+};
+
+/* Graphic ctl 0x3ce */
+#define GRDC_MAX_REG 0x08
+#define GRDC_MAX_MODEL 0x05
+
+static Bit8u grdc_access[GRDC_MAX_REG+1]=
+{ /* 00 01 02 03 04 05 06 07 08 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+
+static Bit8u grdc_regs[GRDC_MAX_MODEL+1][GRDC_MAX_REG+1]=
+{/* Model 00 01 02 03 04 05 06 07 08 */
+ /* 00 */ 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x0f,0xff,
+ /* 01 */ 0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x0f,0xff,
+ /* 02 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x0f,0xff,
+ /* 03 */ 0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x0f,0xff,
+ /* 04 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,0xff,
+ /* 05 */ 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,0xff
+};
+
+/* Default Palette */
+#define DAC_MAX_MODEL 3
+
+static Bit8u dac_regs[DAC_MAX_MODEL+1]=
+{0x3f,0x3f,0x3f,0xff};
+
+/* Mono */
+static Bit8u palette0[63+1][3]=
+{
+ 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f,
+ 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f
+};
+
+static Bit8u palette1[63+1][3]=
+{
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f
+};
+
+static Bit8u palette2[63+1][3]=
+{
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x2a,0x00, 0x2a,0x2a,0x2a,
+ 0x00,0x00,0x15, 0x00,0x00,0x3f, 0x00,0x2a,0x15, 0x00,0x2a,0x3f, 0x2a,0x00,0x15, 0x2a,0x00,0x3f, 0x2a,0x2a,0x15, 0x2a,0x2a,0x3f,
+ 0x00,0x15,0x00, 0x00,0x15,0x2a, 0x00,0x3f,0x00, 0x00,0x3f,0x2a, 0x2a,0x15,0x00, 0x2a,0x15,0x2a, 0x2a,0x3f,0x00, 0x2a,0x3f,0x2a,
+ 0x00,0x15,0x15, 0x00,0x15,0x3f, 0x00,0x3f,0x15, 0x00,0x3f,0x3f, 0x2a,0x15,0x15, 0x2a,0x15,0x3f, 0x2a,0x3f,0x15, 0x2a,0x3f,0x3f,
+ 0x15,0x00,0x00, 0x15,0x00,0x2a, 0x15,0x2a,0x00, 0x15,0x2a,0x2a, 0x3f,0x00,0x00, 0x3f,0x00,0x2a, 0x3f,0x2a,0x00, 0x3f,0x2a,0x2a,
+ 0x15,0x00,0x15, 0x15,0x00,0x3f, 0x15,0x2a,0x15, 0x15,0x2a,0x3f, 0x3f,0x00,0x15, 0x3f,0x00,0x3f, 0x3f,0x2a,0x15, 0x3f,0x2a,0x3f,
+ 0x15,0x15,0x00, 0x15,0x15,0x2a, 0x15,0x3f,0x00, 0x15,0x3f,0x2a, 0x3f,0x15,0x00, 0x3f,0x15,0x2a, 0x3f,0x3f,0x00, 0x3f,0x3f,0x2a,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f
+};
+
+static Bit8u palette3[256][3]=
+{
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+ 0x00,0x00,0x00, 0x05,0x05,0x05, 0x08,0x08,0x08, 0x0b,0x0b,0x0b, 0x0e,0x0e,0x0e, 0x11,0x11,0x11, 0x14,0x14,0x14, 0x18,0x18,0x18,
+ 0x1c,0x1c,0x1c, 0x20,0x20,0x20, 0x24,0x24,0x24, 0x28,0x28,0x28, 0x2d,0x2d,0x2d, 0x32,0x32,0x32, 0x38,0x38,0x38, 0x3f,0x3f,0x3f,
+ 0x00,0x00,0x3f, 0x10,0x00,0x3f, 0x1f,0x00,0x3f, 0x2f,0x00,0x3f, 0x3f,0x00,0x3f, 0x3f,0x00,0x2f, 0x3f,0x00,0x1f, 0x3f,0x00,0x10,
+ 0x3f,0x00,0x00, 0x3f,0x10,0x00, 0x3f,0x1f,0x00, 0x3f,0x2f,0x00, 0x3f,0x3f,0x00, 0x2f,0x3f,0x00, 0x1f,0x3f,0x00, 0x10,0x3f,0x00,
+ 0x00,0x3f,0x00, 0x00,0x3f,0x10, 0x00,0x3f,0x1f, 0x00,0x3f,0x2f, 0x00,0x3f,0x3f, 0x00,0x2f,0x3f, 0x00,0x1f,0x3f, 0x00,0x10,0x3f,
+ 0x1f,0x1f,0x3f, 0x27,0x1f,0x3f, 0x2f,0x1f,0x3f, 0x37,0x1f,0x3f, 0x3f,0x1f,0x3f, 0x3f,0x1f,0x37, 0x3f,0x1f,0x2f, 0x3f,0x1f,0x27,
+
+ 0x3f,0x1f,0x1f, 0x3f,0x27,0x1f, 0x3f,0x2f,0x1f, 0x3f,0x37,0x1f, 0x3f,0x3f,0x1f, 0x37,0x3f,0x1f, 0x2f,0x3f,0x1f, 0x27,0x3f,0x1f,
+ 0x1f,0x3f,0x1f, 0x1f,0x3f,0x27, 0x1f,0x3f,0x2f, 0x1f,0x3f,0x37, 0x1f,0x3f,0x3f, 0x1f,0x37,0x3f, 0x1f,0x2f,0x3f, 0x1f,0x27,0x3f,
+ 0x2d,0x2d,0x3f, 0x31,0x2d,0x3f, 0x36,0x2d,0x3f, 0x3a,0x2d,0x3f, 0x3f,0x2d,0x3f, 0x3f,0x2d,0x3a, 0x3f,0x2d,0x36, 0x3f,0x2d,0x31,
+ 0x3f,0x2d,0x2d, 0x3f,0x31,0x2d, 0x3f,0x36,0x2d, 0x3f,0x3a,0x2d, 0x3f,0x3f,0x2d, 0x3a,0x3f,0x2d, 0x36,0x3f,0x2d, 0x31,0x3f,0x2d,
+ 0x2d,0x3f,0x2d, 0x2d,0x3f,0x31, 0x2d,0x3f,0x36, 0x2d,0x3f,0x3a, 0x2d,0x3f,0x3f, 0x2d,0x3a,0x3f, 0x2d,0x36,0x3f, 0x2d,0x31,0x3f,
+ 0x00,0x00,0x1c, 0x07,0x00,0x1c, 0x0e,0x00,0x1c, 0x15,0x00,0x1c, 0x1c,0x00,0x1c, 0x1c,0x00,0x15, 0x1c,0x00,0x0e, 0x1c,0x00,0x07,
+ 0x1c,0x00,0x00, 0x1c,0x07,0x00, 0x1c,0x0e,0x00, 0x1c,0x15,0x00, 0x1c,0x1c,0x00, 0x15,0x1c,0x00, 0x0e,0x1c,0x00, 0x07,0x1c,0x00,
+ 0x00,0x1c,0x00, 0x00,0x1c,0x07, 0x00,0x1c,0x0e, 0x00,0x1c,0x15, 0x00,0x1c,0x1c, 0x00,0x15,0x1c, 0x00,0x0e,0x1c, 0x00,0x07,0x1c,
+
+ 0x0e,0x0e,0x1c, 0x11,0x0e,0x1c, 0x15,0x0e,0x1c, 0x18,0x0e,0x1c, 0x1c,0x0e,0x1c, 0x1c,0x0e,0x18, 0x1c,0x0e,0x15, 0x1c,0x0e,0x11,
+ 0x1c,0x0e,0x0e, 0x1c,0x11,0x0e, 0x1c,0x15,0x0e, 0x1c,0x18,0x0e, 0x1c,0x1c,0x0e, 0x18,0x1c,0x0e, 0x15,0x1c,0x0e, 0x11,0x1c,0x0e,
+ 0x0e,0x1c,0x0e, 0x0e,0x1c,0x11, 0x0e,0x1c,0x15, 0x0e,0x1c,0x18, 0x0e,0x1c,0x1c, 0x0e,0x18,0x1c, 0x0e,0x15,0x1c, 0x0e,0x11,0x1c,
+ 0x14,0x14,0x1c, 0x16,0x14,0x1c, 0x18,0x14,0x1c, 0x1a,0x14,0x1c, 0x1c,0x14,0x1c, 0x1c,0x14,0x1a, 0x1c,0x14,0x18, 0x1c,0x14,0x16,
+ 0x1c,0x14,0x14, 0x1c,0x16,0x14, 0x1c,0x18,0x14, 0x1c,0x1a,0x14, 0x1c,0x1c,0x14, 0x1a,0x1c,0x14, 0x18,0x1c,0x14, 0x16,0x1c,0x14,
+ 0x14,0x1c,0x14, 0x14,0x1c,0x16, 0x14,0x1c,0x18, 0x14,0x1c,0x1a, 0x14,0x1c,0x1c, 0x14,0x1a,0x1c, 0x14,0x18,0x1c, 0x14,0x16,0x1c,
+ 0x00,0x00,0x10, 0x04,0x00,0x10, 0x08,0x00,0x10, 0x0c,0x00,0x10, 0x10,0x00,0x10, 0x10,0x00,0x0c, 0x10,0x00,0x08, 0x10,0x00,0x04,
+ 0x10,0x00,0x00, 0x10,0x04,0x00, 0x10,0x08,0x00, 0x10,0x0c,0x00, 0x10,0x10,0x00, 0x0c,0x10,0x00, 0x08,0x10,0x00, 0x04,0x10,0x00,
+
+ 0x00,0x10,0x00, 0x00,0x10,0x04, 0x00,0x10,0x08, 0x00,0x10,0x0c, 0x00,0x10,0x10, 0x00,0x0c,0x10, 0x00,0x08,0x10, 0x00,0x04,0x10,
+ 0x08,0x08,0x10, 0x0a,0x08,0x10, 0x0c,0x08,0x10, 0x0e,0x08,0x10, 0x10,0x08,0x10, 0x10,0x08,0x0e, 0x10,0x08,0x0c, 0x10,0x08,0x0a,
+ 0x10,0x08,0x08, 0x10,0x0a,0x08, 0x10,0x0c,0x08, 0x10,0x0e,0x08, 0x10,0x10,0x08, 0x0e,0x10,0x08, 0x0c,0x10,0x08, 0x0a,0x10,0x08,
+ 0x08,0x10,0x08, 0x08,0x10,0x0a, 0x08,0x10,0x0c, 0x08,0x10,0x0e, 0x08,0x10,0x10, 0x08,0x0e,0x10, 0x08,0x0c,0x10, 0x08,0x0a,0x10,
+ 0x0b,0x0b,0x10, 0x0c,0x0b,0x10, 0x0d,0x0b,0x10, 0x0f,0x0b,0x10, 0x10,0x0b,0x10, 0x10,0x0b,0x0f, 0x10,0x0b,0x0d, 0x10,0x0b,0x0c,
+ 0x10,0x0b,0x0b, 0x10,0x0c,0x0b, 0x10,0x0d,0x0b, 0x10,0x0f,0x0b, 0x10,0x10,0x0b, 0x0f,0x10,0x0b, 0x0d,0x10,0x0b, 0x0c,0x10,0x0b,
+ 0x0b,0x10,0x0b, 0x0b,0x10,0x0c, 0x0b,0x10,0x0d, 0x0b,0x10,0x0f, 0x0b,0x10,0x10, 0x0b,0x0f,0x10, 0x0b,0x0d,0x10, 0x0b,0x0c,0x10,
+ 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00
+};
+
+static Bit8u static_functionality[0x10]=
+{
+ /* 0 */ 0xff, // All modes supported #1
+ /* 1 */ 0xe0, // All modes supported #2
+ /* 2 */ 0x0f, // All modes supported #3
+ /* 3 */ 0x00, 0x00, 0x00, 0x00, // reserved
+ /* 7 */ 0x07, // 200, 350, 400 scan lines
+ /* 8 */ 0x02, // mamimum number of visible charsets in text mode
+ /* 9 */ 0x08, // total number of charset blocks in text mode
+ /* a */ 0xe7, // Change to add new functions
+ /* b */ 0x0c, // Change to add new functions
+ /* c */ 0x00, // reserved
+ /* d */ 0x00, // reserved
+ /* e */ 0x00, // Change to add new functions
+ /* f */ 0x00 // reserved
+};
diff --git a/tools/firmware/vmxassist/Makefile b/tools/firmware/vmxassist/Makefile
new file mode 100644
index 0000000000..545acdf743
--- /dev/null
+++ b/tools/firmware/vmxassist/Makefile
@@ -0,0 +1,84 @@
+#
+# 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.
+#
+
+# The emulator code lives in ROM space
+TEXTADDR=0x000D0000
+DEFINES=-DDEBUG -DTEXTADDR=${TEXTADDR}
+XENINC=-I../../../xen/include
+#TEXTADDR=0x000E0000
+#DEFINES=-DDEBUG -DTEST -DTEXTADDR=${TEXTADDR}
+#XENINC=-I/home/leendert/xen/xeno-unstable.bk/xen/include
+
+LD=ld
+CC=gcc
+CPP=cpp -P
+OBJCOPY=objcopy -p -O binary -R .note -R .comment -R .bss -S --gap-fill=0
+CFLAGS=${DEFINES} -I. $(XENINC) -Wall -fno-builtin -O2 -msoft-float
+
+OBJECTS = head.o trap.o vm86.o setup.o util.o
+
+all: vmxloader
+
+vmxloader: roms.h vmxloader.c
+ ${CC} ${DEFINES} -c vmxloader.c
+ $(CC) -o vmxloader.tmp -nostdlib -Wl,-N -Wl,-Ttext -Wl,0x100000 vmxloader.o
+ objcopy --change-addresses=0xC0000000 vmxloader.tmp vmxloader
+ rm -f vmxloader.tmp
+
+vmxassist.bin: vmxassist.ld ${OBJECTS}
+ ${CPP} ${DEFINES} vmxassist.ld > vmxassist.tmp
+ ${LD} -o vmxassist -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 head.S
+ ${CC} ${CFLAGS} -D__ASSEMBLY__ ${DEFINES} -c head.S
+
+trap.o: machine.h offsets.h trap.S
+ ${CC} ${CFLAGS} -D__ASSEMBLY__ ${DEFINES} -c trap.S
+
+vm86.o: machine.h vm86.c
+ ${CC} ${CFLAGS} -c vm86.c
+
+setup.o: machine.h setup.c
+ ${CC} ${CFLAGS} -c setup.c
+
+util.o: machine.h util.c
+ ${CC} ${CFLAGS} -c util.c
+
+roms.h: ../rombios/BIOS-bochs-latest ../vgabios/VGABIOS-lgpl-latest.bin ../vgabios/VGABIOS-lgpl-latest.cirrus.bin vmxassist.bin
+ ./mkhex rombios ../rombios/BIOS-bochs-latest > roms.h
+ ./mkhex vgabios_stdvga ../vgabios/VGABIOS-lgpl-latest.bin >> roms.h
+ ./mkhex vgabios_cirrusvga ../vgabios/VGABIOS-lgpl-latest.cirrus.bin >> roms.h
+ ./mkhex vmxassist vmxassist.bin >> roms.h
+
+offsets.h: gen
+ ./gen > offsets.h
+
+gen: gen.c
+ ${CC} ${CFLAGS} -o gen gen.c
+
+clean:
+ rm -f vmxassist vmxassist.tmp vmxassist.bin vmxassist.run vmxassist.sym head.s roms.h
+ rm -f vmxloader vmxloader.tmp vmxloader.o ${OBJECTS}
+ rm -f gen gen.o offsets.h
+
diff --git a/tools/firmware/vmxassist/TODO b/tools/firmware/vmxassist/TODO
new file mode 100644
index 0000000000..2378ff3485
--- /dev/null
+++ b/tools/firmware/vmxassist/TODO
@@ -0,0 +1,8 @@
+
+- Use the VME extensions (interrupt handling)
+
+- Use E820 map in vmxassist instead of cmos hack
+
+- Add ACPI support (Nitin's patch)
+
+
diff --git a/tools/firmware/vmxassist/gen.c b/tools/firmware/vmxassist/gen.c
new file mode 100644
index 0000000000..f18f77a4f3
--- /dev/null
+++ b/tools/firmware/vmxassist/gen.c
@@ -0,0 +1,52 @@
+/*
+ * gen.c: Generate assembler symbols.
+ *
+ * Leendert van Doorn, leendert@watson.ibm.com
+ * Copyright (c) 2005, International Business Machines Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <public/vmx_assist.h>
+
+int
+main()
+{
+ printf("/* MACHINE GENERATED; DO NOT EDIT */\n");
+ printf("#define VMX_ASSIST_CTX_GS_SEL 0x%x\n",
+ offsetof(struct vmx_assist_context, gs_sel));
+ printf("#define VMX_ASSIST_CTX_FS_SEL 0x%x\n",
+ offsetof(struct vmx_assist_context, fs_sel));
+ printf("#define VMX_ASSIST_CTX_DS_SEL 0x%x\n",
+ offsetof(struct vmx_assist_context, ds_sel));
+ printf("#define VMX_ASSIST_CTX_ES_SEL 0x%x\n",
+ offsetof(struct vmx_assist_context, es_sel));
+ printf("#define VMX_ASSIST_CTX_SS_SEL 0x%x\n",
+ offsetof(struct vmx_assist_context, ss_sel));
+ printf("#define VMX_ASSIST_CTX_ESP 0x%x\n",
+ offsetof(struct vmx_assist_context, esp));
+ printf("#define VMX_ASSIST_CTX_EFLAGS 0x%x\n",
+ offsetof(struct vmx_assist_context, eflags));
+ printf("#define VMX_ASSIST_CTX_CS_SEL 0x%x\n",
+ offsetof(struct vmx_assist_context, cs_sel));
+ printf("#define VMX_ASSIST_CTX_EIP 0x%x\n",
+ offsetof(struct vmx_assist_context, eip));
+
+ printf("#define VMX_ASSIST_CTX_CR0 0x%x\n",
+ offsetof(struct vmx_assist_context, cr0));
+
+ return 0;
+}
diff --git a/tools/firmware/vmxassist/head.S b/tools/firmware/vmxassist/head.S
new file mode 100644
index 0000000000..131fbd50cc
--- /dev/null
+++ b/tools/firmware/vmxassist/head.S
@@ -0,0 +1,162 @@
+/*
+ * 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
+_start:
+ cli
+
+ /* clear bss */
+ cld
+ xorb %al, %al
+ movl $_bbss, %edi
+ movl $_ebss, %ecx
+ subl %edi, %ecx
+ rep stosb
+
+ /* 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:
+ pushl $halt_msg
+ call printf
+#ifdef TEST
+ movw $0x8A00, %dx
+ movw $0x8AE0, %ax
+ outw %ax, (%dx)
+#endif
+ cli
+ jmp .
+
+ .data
+halt_msg:
+ .asciz "Halt called from %%eip 0x%x\n"
+
+
+/*
+ * Our stack
+ */
+ .bss
+ .align 8
+ .globl stack, stack_top
+stack:
+ .skip STACK_SIZE
+stack_top:
+
diff --git a/tools/firmware/vmxassist/machine.h b/tools/firmware/vmxassist/machine.h
new file mode 100644
index 0000000000..5d448ef13b
--- /dev/null
+++ b/tools/firmware/vmxassist/machine.h
@@ -0,0 +1,203 @@
+/*
+ * 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 EFLAGS_TF (1 << 8)
+#define EFLAGS_IF (1 << 9)
+#define EFLAGS_DF (1 << 10)
+#define EFLAGS_VM (1 << 17)
+#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;
+ 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;
+}
+
+#ifdef TEST
+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));
+}
+
+static inline void
+breakpoint(void)
+{
+ outw(0x8A00, 0x8AE0);
+}
+#endif /* TEST */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __MACHINE_H__ */
+
diff --git a/tools/firmware/vmxassist/mkhex b/tools/firmware/vmxassist/mkhex
new file mode 100755
index 0000000000..7389d70483
--- /dev/null
+++ b/tools/firmware/vmxassist/mkhex
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+#
+# mkhex: Generate C embeddable hexdumps
+#
+# 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.
+#
+
+echo "unsigned $1[] = {"
+od -v -t x $2 | sed 's/^[0-9]* /0x/' | sed 's/ /, 0x/g' | sed 's/$/,/'
+echo "};"
+
diff --git a/tools/firmware/vmxassist/setup.c b/tools/firmware/vmxassist/setup.c
new file mode 100644
index 0000000000..64b9a6e06d
--- /dev/null
+++ b/tools/firmware/vmxassist/setup.c
@@ -0,0 +1,338 @@
+/*
+ * 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"
+
+#ifndef TEST
+#if (VMXASSIST_BASE != TEXTADDR)
+#error VMXAssist base mismatch
+#endif
+#endif
+
+#define NR_PGD (PGSIZE / sizeof(unsigned))
+
+#define min(a, b) ((a) > (b) ? (b) : (a))
+
+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 };
+#endif
+
+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 */
+
+ printf("Memory size %ld MB\n", memory_size >> 20);
+ 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)
+{
+ /* setup task state segment */
+ memset(&tss, 0, sizeof(0));
+ tss.ss0 = DATA_SELECTOR;
+ tss.esp0 = (unsigned) stack_top - 4*4;
+ tss.iomap_base = offsetof(struct tss, iomap);
+
+ /* initialize gdt's tss selector */
+ unsigned long long addr = (unsigned long long) &tss;
+ 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));
+/* XXX 0x10 == CODE_SELECTOR (figure out gnuas) */
+ __asm__ __volatile__ ("ljmp $0x10,$1f; 1:");
+
+ __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
+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;
+ regs->cs = 0xF000; /* ROM BIOS POST entry point */
+#ifdef TEST
+ regs->eip = 0xFFE0;
+#else
+ regs->eip = 0xFFF0;
+#endif
+ regs->uesp = 0;
+ regs->uss = 0;
+ 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)
+{
+ unsigned long cr0;
+
+ printf("Start BIOS ...\n");
+ initialize_real_mode = 1;
+ cr0 = get_cr0();
+#ifndef TEST
+ set_cr0(cr0 | CR0_PE);
+#endif
+ set_cr0(cr0 & ~CR0_PE);
+ panic("vmxassist returned"); /* "cannot happen" */
+}
+
+int
+main()
+{
+ banner();
+#ifdef TEST
+ setup_paging();
+#endif
+ setup_gdt();
+ setup_idt();
+ setup_ctx();
+ setup_pic();
+ start_bios();
+ return 0;
+}
+
diff --git a/tools/firmware/vmxassist/trap.S b/tools/firmware/vmxassist/trap.S
new file mode 100644
index 0000000000..a469f68fc8
--- /dev/null
+++ b/tools/firmware/vmxassist/trap.S
@@ -0,0 +1,189 @@
+/*
+ * 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 "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
+ .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
+ .align 16
+common_trap: /* common trap handler */
+ pushl %gs
+ pushl %fs
+ pushl %ds
+ pushl %es
+ pushal
+
+ movl $DATA_SELECTOR, %eax /* make sure these are sane */
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %fs
+ movl %eax, %gs
+ movl %esp, %ebp
+
+ pushl %ebp
+ pushl 52(%ebp)
+ pushl 48(%ebp)
+ call trap /* trap(trapno, errno, regs) */
+ addl $12, %esp
+
+trap_return:
+ popal
+ popl %es
+ popl %ds
+ popl %fs
+ popl %gs
+ addl $8, %esp /* skip trapno, errno */
+ iret
+ /* NOT REACHED */
+
+
+/*
+ * A world switch to real mode occured. The hypervisor saved the
+ * executing context into "oldctx" and instantiated "newctx", which
+ * gets us here. Here we push a stack frame that is compatible with
+ * a trap frame (see above) so that we can handle this event as a
+ * regular trap.
+ */
+ .text
+ .align 16
+ .globl switch_to_real_mode
+switch_to_real_mode:
+ pushl oldctx+VMX_ASSIST_CTX_GS_SEL /* 16 to 32-bit transition */
+ pushl oldctx+VMX_ASSIST_CTX_FS_SEL
+ pushl oldctx+VMX_ASSIST_CTX_DS_SEL
+ pushl oldctx+VMX_ASSIST_CTX_ES_SEL
+ pushl oldctx+VMX_ASSIST_CTX_SS_SEL
+ pushl oldctx+VMX_ASSIST_CTX_ESP
+ pushl oldctx+VMX_ASSIST_CTX_EFLAGS
+ pushl oldctx+VMX_ASSIST_CTX_CS_SEL
+ pushl oldctx+VMX_ASSIST_CTX_EIP
+ pushl $-1 /* trapno, errno */
+ pushl $-1
+ pushl %gs
+ pushl %fs
+ pushl %ds
+ pushl %es
+ pushal
+
+ movl %esp, %ebp
+ pushl %ebp
+ call enter_real_mode
+ addl $4, %esp
+
+ jmp trap_return
+ /* NOT REACHED */
+
+
+/*
+ * Switch to protected mode. At this point all the registers have
+ * been reloaded by trap_return and all we have to do is cause a
+ * world switch by turning on CR0.PE.
+ */
+ .text
+ .align 16
+ .globl switch_to_protected_mode
+switch_to_protected_mode:
+ movl oldctx+VMX_ASSIST_CTX_CR0, %esp
+ movl %esp, %cr0 /* actual world switch ! */
+
+ /* NOT REACHED */
+ pushl $switch_failed
+ call panic
+ jmp .
+
+ .data
+ .align 4
+switch_failed:
+ .asciz "World switch to protected mode failed\n"
+
diff --git a/tools/firmware/vmxassist/util.c b/tools/firmware/vmxassist/util.c
new file mode 100644
index 0000000000..53b6addd35
--- /dev/null
+++ b/tools/firmware/vmxassist/util.c
@@ -0,0 +1,364 @@
+/*
+ * 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 <public/vmx_assist.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",
+ oldctx.cr0, get_cr2(), oldctx.cr3, 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
+dump_dtr(unsigned long base, unsigned long limit)
+{
+ unsigned long long entry;
+ int i;
+
+ for (i = 0; i < limit; i += 8) {
+ entry = ((unsigned long long *) base)[i >> 3];
+ printf("[0x%x] = 0x%08x%08x\n", i,
+ (unsigned)(entry >> 32), (unsigned)(entry));
+ }
+}
+
+void
+dump_vmx_context(struct vmx_assist_context *c)
+{
+ printf("eip 0x%lx, esp 0x%lx, eflags 0x%lx\n",
+ c->eip, c->esp, c->eflags);
+
+ printf("cr0 0x%lx, cr3 0x%lx, cr4 0x%lx\n", c->cr0, c->cr3, c->cr4);
+
+ printf("idtr: limit 0x%lx, base 0x%lx\n",
+ c->idtr_limit, c->idtr_base);
+
+ printf("gdtr: limit 0x%lx, base 0x%lx\n",
+ c->gdtr_limit, c->gdtr_base);
+
+ printf("cs: sel 0x%lx, limit 0x%lx, base 0x%lx\n",
+ c->cs_sel, c->cs_limit, 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",
+ c->ds_sel, c->ds_limit, 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",
+ c->es_sel, c->es_limit, 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",
+ c->ss_sel, c->ss_limit, 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",
+ c->fs_sel, c->fs_limit, 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",
+ c->gs_sel, c->gs_limit, 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",
+ c->tr_sel, c->tr_limit, 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",
+ c->ldtr_sel, c->ldtr_limit, 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", c->gdtr_base, c->gdtr_limit);
+ dump_dtr(c->gdtr_base, c->gdtr_limit);
+}
+#endif /* DEBUG */
+
+/*
+ * Lightweight printf that doesn't drag in everything under the sun.
+ */
+int
+printf(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _doprint(putchar, fmt, ap);
+ va_end(ap);
+ return 0; /* for gcc compat */
+}
+
+int
+vprintf(const char *fmt, va_list ap)
+{
+ _doprint(putchar, fmt, ap);
+ return 0; /* for gcc compat */
+}
+
+void
+panic(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _doprint(putchar, fmt, ap);
+ putchar('\n');
+ va_end(ap);
+ halt();
+}
+
+unsigned
+strlen(const char *s)
+{
+ const char *q = s;
+
+ while (*s++)
+ /* void */;
+ return s - q - 1;
+}
+
+static void
+putchar(int ch)
+{
+ outb(0xE9, ch);
+}
+
+/*
+ * A stripped down version of doprint,
+ * but still powerful enough for most tasks.
+ */
+static void
+_doprint(void (*put)(int), char const *fmt, va_list ap)
+{
+ register char *str, c;
+ int lflag, zflag, nflag;
+ char buffer[17];
+ unsigned value;
+ int i, slen, pad;
+
+ for ( ; *fmt != '\0'; fmt++) {
+ pad = zflag = nflag = lflag = 0;
+ if (*fmt == '%') {
+ c = *++fmt;
+ if (c == '-' || isdigit(c)) {
+ if (c == '-') {
+ nflag = 1;
+ c = *++fmt;
+ }
+ zflag = c == '0';
+ for (pad = 0; isdigit(c); c = *++fmt)
+ pad = (pad * 10) + c - '0';
+ }
+ if (c == 'l') { /* long extension */
+ lflag = 1;
+ c = *++fmt;
+ }
+ if (c == 'd' || c == 'u' || c == 'o' || c == 'x') {
+ if (lflag)
+ value = va_arg(ap, unsigned);
+ else
+ value = (unsigned) va_arg(ap, unsigned int);
+ str = buffer;
+ printnum(str, value,
+ c == 'o' ? 8 : (c == 'x' ? 16 : 10));
+ goto printn;
+ } else if (c == 'O' || c == 'D' || c == 'X') {
+ value = va_arg(ap, unsigned);
+ str = buffer;
+ printnum(str, value,
+ c == 'O' ? 8 : (c == 'X' ? 16 : 10));
+ printn:
+ slen = strlen(str);
+ for (i = pad - slen; i > 0; i--)
+ put(zflag ? '0' : ' ');
+ while (*str) put(*str++);
+ } else if (c == 's') {
+ str = va_arg(ap, char *);
+ slen = strlen(str);
+ if (nflag == 0)
+ for (i = pad - slen; i > 0; i--) put(' ');
+ while (*str) put(*str++);
+ if (nflag)
+ for (i = pad - slen; i > 0; i--) put(' ');
+ } else if (c == 'c')
+ put(va_arg(ap, int));
+ else
+ put(*fmt);
+ } else
+ put(*fmt);
+ }
+}
+
+static char *
+printnum(char *p, unsigned long num, int base)
+{
+ unsigned long n;
+
+ if ((n = num/base) > 0)
+ p = printnum(p, n, base);
+ *p++ = "0123456789ABCDEF"[(int)(num % base)];
+ *p = '\0';
+ return p;
+}
+
+void *
+memset(void *s, int c, unsigned n)
+{
+ int t0, t1;
+
+ __asm__ __volatile__ ("cld; rep; stosb"
+ : "=&c" (t0), "=&D" (t1)
+ : "a" (c), "1" (s), "0" (n)
+ : "memory");
+ return s;
+}
+
+void *
+memcpy(void *dest, const void *src, unsigned n)
+{
+ int t0, t1, t2;
+
+ __asm__ __volatile__(
+ "cld\n"
+ "rep; movsl\n"
+ "testb $2,%b4\n"
+ "je 1f\n"
+ "movsw\n"
+ "1: testb $1,%b4\n"
+ "je 2f\n"
+ "movsb\n"
+ "2:"
+ : "=&c" (t0), "=&D" (t1), "=&S" (t2)
+ : "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src)
+ : "memory"
+ );
+ return dest;
+}
+
diff --git a/tools/firmware/vmxassist/util.h b/tools/firmware/vmxassist/util.h
new file mode 100644
index 0000000000..06e030d571
--- /dev/null
+++ b/tools/firmware/vmxassist/util.h
@@ -0,0 +1,41 @@
+/*
+ * 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>
+
+#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 dump_dtr(unsigned long, unsigned long);
+extern void *memcpy(void *, const void *, unsigned);
+extern void *memset(void *, int, unsigned);
+extern int printf(const char *fmt, ...);
+extern int vprintf(const char *fmt, va_list ap);
+extern void panic(const char *format, ...);
+extern void halt(void);
+
+#endif /* __UTIL_H__ */
diff --git a/tools/firmware/vmxassist/vm86.c b/tools/firmware/vmxassist/vm86.c
new file mode 100644
index 0000000000..d63843660e
--- /dev/null
+++ b/tools/firmware/vmxassist/vm86.c
@@ -0,0 +1,956 @@
+/*
+ * 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, 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
+
+unsigned prev_eip = 0;
+enum vm86_mode mode;
+
+#ifdef DEBUG
+int traceset = 0;
+#endif /* DEBUG */
+
+
+unsigned
+address(struct regs *regs, unsigned seg, unsigned off)
+{
+ unsigned long long entry;
+ unsigned addr;
+
+ /* real mode: segment is part of the address */
+ if (mode == VM86_REAL || mode == VM86_REAL_TO_PROTECTED)
+ return ((seg & 0xFFFF) << 4) + off;
+
+ /* protected mode: use seg as index into gdt */
+ if (seg > oldctx.gdtr_limit) {
+ printf("address: Invalid segment descriptor (0x%x)\n", seg);
+ return 0;
+ }
+
+ entry = ((unsigned long long *) oldctx.gdtr_base)[seg >> 3];
+ addr = (((entry >> (56-24)) & 0xFF000000) |
+ ((entry >> (32-16)) & 0x00FF0000) |
+ ((entry >> ( 16)) & 0x0000FFFF)) + off;
+ return addr;
+}
+
+#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);
+}
+
+unsigned
+getreg(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;
+}
+
+void
+setreg(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;
+ }
+}
+
+/*
+ * Operand (modrm) decode
+ */
+unsigned
+operand(unsigned prefix, struct regs *regs, unsigned modrm)
+{
+ int mod, disp = 0, seg;
+
+ seg = regs->vds;
+ 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;
+
+ 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: panic("No SIB decode (yet)");
+ 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: panic("No SIB decode (yet)");
+ 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 getreg(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 MASK16(getreg(regs, modrm));
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Load new IDT
+ */
+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
+ */
+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.
+ */
+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;
+}
+
+/*
+ * Move to and from a control register.
+ */
+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
+ setreg(regs, modrm,
+ oldctx.cr0 & ~(CR0_PE | CR0_NE));
+#else
+ setreg(regs, modrm,
+ oldctx.cr0 & ~(CR0_PE | CR0_NE | CR0_PG));
+#endif
+ break;
+ case 2:
+ setreg(regs, modrm, get_cr2());
+ break;
+ case 3:
+ setreg(regs, modrm, oldctx.cr3);
+ break;
+ case 4:
+ setreg(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 = getreg(regs, modrm) | (CR0_PE | CR0_NE);
+#ifdef TEST
+ oldctx.cr0 |= CR0_PG;
+#endif
+ if (getreg(regs, modrm) & CR0_PE)
+ set_mode(regs, VM86_REAL_TO_PROTECTED);
+
+ break;
+ case 3:
+ oldctx.cr3 = getreg(regs, modrm);
+ break;
+ case 4:
+ oldctx.cr4 = getreg(regs, modrm);
+ break;
+ }
+ break;
+ }
+
+ return 1;
+}
+
+/*
+ * Emulate a segment load in protected mode
+ */
+int
+load_seg(unsigned long sel, unsigned long *base, unsigned long *limit,
+ union vmcs_arbytes *arbytes)
+{
+ unsigned long long entry;
+
+ /* protected mode: use seg as index into gdt */
+ if (sel == 0 || sel > oldctx.gdtr_limit)
+ return 0;
+
+ entry = ((unsigned long long *) oldctx.gdtr_base)[sel >> 3];
+ *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
+ */
+void
+protected_mode(struct regs *regs)
+{
+ regs->eflags &= ~(EFLAGS_TF|EFLAGS_VM);
+
+ oldctx.eip = regs->eip;
+ oldctx.esp = regs->uesp;
+ oldctx.eflags = regs->eflags;
+
+ /* 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;
+
+ if (load_seg(regs->uss, &oldctx.ss_base,
+ &oldctx.ss_limit, &oldctx.ss_arbytes))
+ oldctx.ss_sel = regs->uss;
+
+ if (load_seg(regs->vds, &oldctx.ds_base,
+ &oldctx.ds_limit, &oldctx.ds_arbytes))
+ oldctx.ds_sel = regs->vds;
+
+ if (load_seg(regs->vfs, &oldctx.fs_base,
+ &oldctx.fs_limit, &oldctx.fs_arbytes))
+ oldctx.fs_sel = regs->vfs;
+
+ if (load_seg(regs->vgs, &oldctx.gs_base,
+ &oldctx.gs_limit, &oldctx.gs_arbytes))
+ oldctx.gs_sel = 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
+ */
+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;
+ }
+ 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;
+ }
+ 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;
+ }
+
+ /* 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:
+ TRACE((regs, 0, "<VM86_REAL>"));
+ if (mode == VM86_PROTECTED_TO_REAL) {
+ real_mode(regs);
+ break;
+ } else if (mode == VM86_REAL) {
+ break;
+ } else
+ panic("unexpected real mode transition");
+ break;
+
+ case VM86_REAL_TO_PROTECTED:
+ TRACE((regs, 0, "<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");
+
+ case VM86_PROTECTED:
+ TRACE((regs, 0, "<VM86_PROTECTED>"));
+ if (mode == VM86_REAL_TO_PROTECTED) {
+ protected_mode(regs);
+ break;
+ } else
+ panic("unexpected protected mode transition");
+ break;
+ }
+
+ mode = newmode;
+}
+
+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");
+}
+
+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");
+}
+
+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));
+}
+
+enum { OPC_INVALID, OPC_EMULATED };
+
+/*
+ * 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.
+ */
+int
+opcode(struct regs *regs)
+{
+ unsigned eip = regs->eip;
+ unsigned opc, modrm, disp;
+ unsigned prefix = 0;
+
+ for (;;) {
+ switch ((opc = fetch8(regs))) {
+ 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 0x20: /* mov Rd, Cd (1h) */
+ case 0x22:
+ if (!movcr(regs, prefix, opc))
+ goto invalid;
+ 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 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 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 0xCB: /* retl */
+ if ((mode == VM86_REAL_TO_PROTECTED) ||
+ (mode == VM86_PROTECTED_TO_REAL)) {
+ retl(regs, prefix);
+ return OPC_EMULATED;
+ }
+ 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 0xEA: /* jmpl */
+ if ((mode == VM86_REAL_TO_PROTECTED) ||
+ (mode == VM86_PROTECTED_TO_REAL)) {
+ jmpl(regs, prefix);
+ return OPC_EMULATED;
+ }
+ 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 0xF0: /* lock */
+ TRACE((regs, regs->eip - eip, "lock"));
+ continue;
+
+ 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;
+ 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 (%d) while in %s mode\n",
+ trapno, regs->eflags & EFLAGS_VM ? "real" : "protected");
+ if (trapno == 14)
+ printf("Page fault address 0x%x\n", get_cr2());
+ dump_regs(regs);
+ halt();
+ }
+}
+
diff --git a/tools/firmware/vmxassist/vm86.h b/tools/firmware/vmxassist/vm86.h
new file mode 100644
index 0000000000..ce09bd9c8d
--- /dev/null
+++ b/tools/firmware/vmxassist/vm86.h
@@ -0,0 +1,67 @@
+/*
+ * 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__
+
+#include <public/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 interrupt(struct regs *, int);
+extern void dump_regs(struct regs *);
+extern void trace(struct regs *, int, char *, ...);
+
+extern void set_mode(struct regs *, enum vm86_mode);
+extern void switch_to_real_mode(void);
+extern void switch_to_protected_mode(void);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __VM86_H__ */
diff --git a/tools/firmware/vmxassist/vmxassist.ld b/tools/firmware/vmxassist/vmxassist.ld
new file mode 100644
index 0000000000..c9807c63f6
--- /dev/null
+++ b/tools/firmware/vmxassist/vmxassist.ld
@@ -0,0 +1,34 @@
+/*
+ * vmxassist.ld
+ */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+/*OUTPUT_ARCH(i386)*/
+ENTRY(_start)
+
+SECTIONS
+{
+ .text TEXTADDR :
+ {
+ _btext = .;
+ *(.text)
+ *(.rodata)
+ *(.rodata.str1.1)
+ *(.rodata.str1.4)
+ _etext = .;
+ }
+
+ .data :
+ {
+ _bdata = .;
+ *(.data)
+ _edata = .;
+ }
+
+ .bss :
+ {
+ _bbss = .;
+ *(.bss)
+ _ebss = .;
+ }
+}
+
diff --git a/tools/firmware/vmxassist/vmxloader.c b/tools/firmware/vmxassist/vmxloader.c
new file mode 100644
index 0000000000..39f6a8323f
--- /dev/null
+++ b/tools/firmware/vmxassist/vmxloader.c
@@ -0,0 +1,110 @@
+/*
+ * vmxloader.c: ROM/VMXAssist image loader.
+ *
+ * A quicky so that we can boot rom images as if they were a Linux kernel.
+ * This code will copy the rom images (ROMBIOS/VGABIOS/VM86) into their
+ * respective spaces and transfer control to VM86 to execute the BIOSes.
+ *
+ * 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 "roms.h"
+
+/*
+ * C runtime start off
+ */
+asm(" \n\
+ .text \n\
+ .globl _start \n\
+_start: \n\
+ cli \n\
+ movl $stack_top, %esp \n\
+ movl %esp, %ebp \n\
+ call main \n\
+ jmp halt \n\
+ \n\
+ .globl halt \n\
+halt: \n\
+ sti \n\
+ jmp . \n\
+ \n\
+ .bss \n\
+ .align 8 \n\
+ .globl stack, stack_top \n\
+stack: \n\
+ .skip 0x4000 \n\
+stack_top: \n\
+");
+
+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;
+}
+
+int
+puts(const char *s)
+{
+ while (*s)
+ outb(0xE9, *s++);
+ return 0;
+}
+
+int
+cirrus_check(void)
+{
+ outw(0x3C4, 0x9206);
+ return inb(0x3C5) == 0x12;
+}
+
+int
+main()
+{
+ puts("VMXAssist Loader\n");
+ puts("Loading ROMBIOS ...\n");
+ memcpy((void *)0xF0000, rombios, sizeof(rombios));
+ if (cirrus_check()) {
+ puts("Loading Cirrus VGABIOS ...\n");
+ memcpy((void *)0xC0000,
+ vgabios_cirrusvga, sizeof(vgabios_cirrusvga));
+ } else {
+ puts("Loading Standard VGABIOS ...\n");
+ memcpy((void *)0xC0000,
+ vgabios_stdvga, sizeof(vgabios_stdvga));
+ }
+ puts("Loading VMXAssist ...\n");
+ memcpy((void *)TEXTADDR, vmxassist, sizeof(vmxassist));
+ puts("Go ...\n");
+ ((void (*)())TEXTADDR)();
+}
+
diff --git a/tools/ioemu/hw/i8254.c b/tools/ioemu/hw/i8254.c
index 7fb91191cc..29a270e399 100644
--- a/tools/ioemu/hw/i8254.c
+++ b/tools/ioemu/hw/i8254.c
@@ -50,6 +50,7 @@ typedef struct PITChannelState {
int64_t next_transition_time;
QEMUTimer *irq_timer;
int irq;
+ int vmx_channel; /* Is this accelerated by VMX ? */
} PITChannelState;
struct PITState {
@@ -214,12 +215,47 @@ int pit_get_gate(PITState *pit, int channel)
return s->gate;
}
-static inline void pit_load_count(PITChannelState *s, int val)
+void pit_reset_vmx_vectors()
{
extern void *shared_page;
ioreq_t *req;
- int irq;
+ int irq, i;
+ PITChannelState *s;
+
+ /* Assumes PIT is wired to IRQ0 and -1 is uninitialized irq base */
+ if ((irq = pic_irq2vec(0)) == -1)
+ return;
+
+ for(i = 0; i < 3; i++) {
+ if (pit_state.channels[i].vmx_channel)
+ break;
+ }
+
+ if (i == 3)
+ return;
+ /* Assumes just one VMX accelerated channel */
+ vmx_channel = i;
+ s = &pit_state.channels[vmx_channel];
+ fprintf(logfile,
+ "VMX_PIT:guest init pit channel %d!\n", vmx_channel);
+ req = &((vcpu_iodata_t *) shared_page)->vp_ioreq;
+
+ req->state = STATE_IORESP_HOOK;
+ /*
+ * info passed to HV as following
+ * -- init count:16 bit, timer vec:8 bit,
+ * PIT channel(0~2):2 bit, rw mode:2 bit
+ */
+ req->u.data = s->count;
+ req->u.data |= (irq << 16);
+ req->u.data |= (vmx_channel << 24);
+ req->u.data |= ((s->rw_mode) << 26);
+ fprintf(logfile, "VMX_PIT:pass info 0x%llx to HV!\n", req->u.data);
+}
+
+static inline void pit_load_count(PITChannelState *s, int val)
+{
if (val == 0)
val = 0x10000;
s->count_load_time = qemu_get_clock(vm_clock);
@@ -228,25 +264,8 @@ static inline void pit_load_count(PITChannelState *s, int val)
/* guest init this pit channel for periodic mode. we do not update related
* timer so the channel never send intr from device model*/
if (vmx_channel != -1 && s->mode == 2) {
- /* get the pit irq(0)'s vector from pic DM */
- if ((irq = pic_irq2vec(0)) >= 0) {
- fprintf(logfile,
- "VMX_PIT:guest init pit channel %d!\n", vmx_channel);
- req = &((vcpu_iodata_t *) shared_page)->vp_ioreq;
-
- req->state = STATE_IORESP_HOOK;
- /*
- * info passed to HV as following
- * -- init count:16 bit, timer vec:8 bit,
- * PIT channel(0~2):2 bit, rw mode:2 bit
- */
- req->u.data = s->count;
- req->u.data |= (irq << 16);
- req->u.data |= (vmx_channel << 24);
- req->u.data |= ((s->rw_mode) << 26);
- fprintf(logfile, "VMX_PIT:pass info 0x%llx to HV!\n", req->u.data);
- vmx_channel = -1;
- }
+ pit_reset_vmx_vectors();
+ vmx_channel = -1;
}
/* pit_irq_timer_update(s, s->count_load_time);*/
@@ -306,6 +325,7 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
}
} else {
s = &pit->channels[addr];
+ s->vmx_channel = 1;
vmx_channel = addr;
switch(s->write_state) {
default:
diff --git a/tools/ioemu/hw/i8259.c b/tools/ioemu/hw/i8259.c
index 859c64bdf1..5bdc65d700 100644
--- a/tools/ioemu/hw/i8259.c
+++ b/tools/ioemu/hw/i8259.c
@@ -334,6 +334,7 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
case 1:
s->irq_base = val & 0xf8;
s->init_state = 2;
+ pit_reset_vmx_vectors();
break;
case 2:
if (s->init4) {
diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile
index 598abedb7d..cbe7983a44 100644
--- a/tools/libxc/Makefile
+++ b/tools/libxc/Makefile
@@ -19,6 +19,8 @@ SRCS += xc_core.c
SRCS += xc_domain.c
SRCS += xc_evtchn.c
SRCS += xc_gnttab.c
+SRCS += xc_load_bin.c
+SRCS += xc_load_elf.c
SRCS += xc_linux_build.c
SRCS += xc_plan9_build.c
SRCS += xc_linux_restore.c
diff --git a/tools/libxc/xc.h b/tools/libxc/xc.h
index f759e79d8b..27e7845798 100644
--- a/tools/libxc/xc.h
+++ b/tools/libxc/xc.h
@@ -390,8 +390,8 @@ int xc_physdev_pci_access_modify(int xc_handle,
int enable);
int xc_readconsolering(int xc_handle,
- char *str,
- unsigned int max_chars,
+ char **pbuffer,
+ unsigned int *pnr_chars,
int clear);
typedef dom0_physinfo_t xc_physinfo_t;
@@ -501,5 +501,10 @@ int xc_gnttab_dump_table(int xc_handle,
u32 dom,
s16 *status);
+/* Get current total pages allocated to a domain. */
+long xc_get_tot_pages(int xc_handle, u32 domid);
+
+/* Execute a privileged dom0 operation. */
+int xc_dom0_op(int xc_handle, dom0_op_t *op);
#endif /* __XC_H__ */
diff --git a/tools/libxc/xc_evtchn.c b/tools/libxc/xc_evtchn.c
index 9371e61261..1c0294d83b 100644
--- a/tools/libxc/xc_evtchn.c
+++ b/tools/libxc/xc_evtchn.c
@@ -19,15 +19,16 @@ static int do_evtchn_op(int xc_handle, evtchn_op_t *op)
if ( mlock(op, sizeof(*op)) != 0 )
{
- PERROR("Could not lock memory for Xen hypercall");
- goto out1;
+ PERROR("do_evtchn_op: op mlock failed");
+ goto out;
}
- if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
- goto out2;
+ if ((ret = do_xen_hypercall(xc_handle, &hypercall)) < 0)
+ ERROR("do_evtchn_op: HYPERVISOR_event_channel_op failed: %d", ret);
- out2: (void)munlock(op, sizeof(*op));
- out1: return ret;
+ (void)munlock(op, sizeof(*op));
+ out:
+ return ret;
}
@@ -39,8 +40,9 @@ int xc_evtchn_alloc_unbound(int xc_handle,
int rc;
op.cmd = EVTCHNOP_alloc_unbound;
- op.u.alloc_unbound.dom = (domid_t)dom;
-
+ op.u.alloc_unbound.dom = (domid_t)dom;
+ op.u.alloc_unbound.port = (port != NULL) ? *port : 0;
+
if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 )
{
if ( port != NULL )
diff --git a/tools/libxc/xc_gnttab.c b/tools/libxc/xc_gnttab.c
index 2601c30f60..ad23e68013 100644
--- a/tools/libxc/xc_gnttab.c
+++ b/tools/libxc/xc_gnttab.c
@@ -26,18 +26,16 @@ do_gnttab_op( int xc_handle,
if ( mlock(op, sizeof(*op)) != 0 )
{
- PERROR("Could not lock memory for Xen hypercall");
- goto out1;
+ PERROR("do_gnttab_op: op mlock failed");
+ goto out;
}
if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
- {
- printf("do_gnttab_op: hypercall returned error %d\n", ret);
- goto out2;
- }
+ ERROR("do_gnttab_op: HYPERVISOR_grant_table_op failed: %d", ret);
- out2: (void)munlock(op, sizeof(*op));
- out1: return ret;
+ (void)munlock(op, sizeof(*op));
+ out:
+ return ret;
}
diff --git a/tools/libxc/xc_linux_build.c b/tools/libxc/xc_linux_build.c
index 768874a203..660c30a3f1 100644
--- a/tools/libxc/xc_linux_build.c
+++ b/tools/libxc/xc_linux_build.c
@@ -3,41 +3,49 @@
*/
#include "xc_private.h"
+
+#if defined(__i386__)
#define ELFSIZE 32
+#endif
+
+#if defined(__x86_64__)
+#define ELFSIZE 64
+#endif
+
+
#include "xc_elf.h"
#include <stdlib.h>
#include <zlib.h>
+#if defined(__i386__)
#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+#endif
+
+#if defined(__x86_64__)
+#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER)
+#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+#define L3_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+#define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+#endif
+
#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
#define round_pgdown(_p) ((_p)&PAGE_MASK)
-struct domain_setup_info
+static int probeimageformat(char *image,
+ unsigned long image_size,
+ struct load_funcs *load_funcs)
{
- unsigned long v_start;
- unsigned long v_end;
- unsigned long v_kernstart;
- unsigned long v_kernend;
- unsigned long v_kernentry;
-
- unsigned int load_symtab;
- unsigned long symtab_addr;
- unsigned long symtab_len;
-};
-
-static int
-parseelfimage(
- char *elfbase, unsigned long elfsize, struct domain_setup_info *dsi);
-static int
-loadelfimage(
- char *elfbase, int xch, u32 dom, unsigned long *parray,
- struct domain_setup_info *dsi);
-static int
-loadelfsymtab(
- char *elfbase, int xch, u32 dom, unsigned long *parray,
- struct domain_setup_info *dsi);
+ if ( probe_elf(image, image_size, load_funcs) &&
+ probe_bin(image, image_size, load_funcs) )
+ {
+ ERROR( "Unrecognized image format" );
+ return -EINVAL;
+ }
+
+ return 0;
+}
static int setup_guest(int xc_handle,
u32 dom,
@@ -55,9 +63,17 @@ static int setup_guest(int xc_handle,
{
l1_pgentry_t *vl1tab=NULL, *vl1e=NULL;
l2_pgentry_t *vl2tab=NULL, *vl2e=NULL;
+#if defined(__x86_64__)
+ l3_pgentry_t *vl3tab=NULL, *vl3e=NULL;
+ l4_pgentry_t *vl4tab=NULL, *vl4e=NULL;
+#endif
unsigned long *page_array = NULL;
- unsigned long l2tab;
- unsigned long l1tab;
+ unsigned long l2tab = 0;
+ unsigned long l1tab = 0;
+#if defined(__x86_64__)
+ unsigned long l3tab = 0;
+ unsigned long l4tab = 0;
+#endif
unsigned long count, i;
start_info_t *start_info;
shared_info_t *shared_info;
@@ -68,6 +84,7 @@ static int setup_guest(int xc_handle,
unsigned long ppt_alloc;
unsigned long *physmap, *physmap_e, physmap_pfn;
+ struct load_funcs load_funcs;
struct domain_setup_info dsi;
unsigned long vinitrd_start;
unsigned long vinitrd_end;
@@ -83,9 +100,13 @@ static int setup_guest(int xc_handle,
unsigned long vpt_end;
unsigned long v_end;
+ rc = probeimageformat(image, image_size, &load_funcs);
+ if ( rc != 0 )
+ goto error_out;
+
memset(&dsi, 0, sizeof(struct domain_setup_info));
- rc = parseelfimage(image, image_size, &dsi);
+ rc = (load_funcs.parseimage)(image, image_size, &dsi);
if ( rc != 0 )
goto error_out;
@@ -117,32 +138,47 @@ static int setup_guest(int xc_handle,
vstoreinfo_end = vstartinfo_end + PAGE_SIZE;
vstack_start = vstoreinfo_end;
vstack_end = vstack_start + PAGE_SIZE;
- v_end = (vstack_end + (1<<22)-1) & ~((1<<22)-1);
- if ( (v_end - vstack_end) < (512 << 10) )
- v_end += 1 << 22; /* Add extra 4MB to get >= 512kB padding. */
+ v_end = (vstack_end + (1UL<<22)-1) & ~((1UL<<22)-1);
+ if ( (v_end - vstack_end) < (512UL << 10) )
+ v_end += 1UL << 22; /* Add extra 4MB to get >= 512kB padding. */
+#if defined(__i386__)
if ( (((v_end - dsi.v_start + ((1<<L2_PAGETABLE_SHIFT)-1)) >>
L2_PAGETABLE_SHIFT) + 1) <= nr_pt_pages )
break;
+#endif
+#if defined(__x86_64__)
+#define NR(_l,_h,_s) \
+ (((((_h) + ((1UL<<(_s))-1)) & ~((1UL<<(_s))-1)) - \
+ ((_l) & ~((1UL<<(_s))-1))) >> (_s))
+ if ( (1 + /* # L4 */
+ NR(dsi.v_start, v_end, L4_PAGETABLE_SHIFT) + /* # L3 */
+ NR(dsi.v_start, v_end, L3_PAGETABLE_SHIFT) + /* # L2 */
+ NR(dsi.v_start, v_end, L2_PAGETABLE_SHIFT)) /* # L1 */
+ <= nr_pt_pages )
+ break;
+#endif
}
+#define _p(a) ((void *) (a))
+
printf("VIRTUAL MEMORY ARRANGEMENT:\n"
- " Loaded kernel: %08lx->%08lx\n"
- " Init. ramdisk: %08lx->%08lx\n"
- " Phys-Mach map: %08lx->%08lx\n"
- " Page tables: %08lx->%08lx\n"
- " Start info: %08lx->%08lx\n"
- " Store page: %08lx->%08lx\n"
- " Boot stack: %08lx->%08lx\n"
- " TOTAL: %08lx->%08lx\n",
- dsi.v_kernstart, dsi.v_kernend,
- vinitrd_start, vinitrd_end,
- vphysmap_start, vphysmap_end,
- vpt_start, vpt_end,
- vstartinfo_start, vstartinfo_end,
- vstoreinfo_start, vstoreinfo_end,
- vstack_start, vstack_end,
- dsi.v_start, v_end);
- printf(" ENTRY ADDRESS: %08lx\n", dsi.v_kernentry);
+ " Loaded kernel: %p->%p\n"
+ " Init. ramdisk: %p->%p\n"
+ " Phys-Mach map: %p->%p\n"
+ " Page tables: %p->%p\n"
+ " Start info: %p->%p\n"
+ " Store page: %p->%p\n"
+ " Boot stack: %p->%p\n"
+ " TOTAL: %p->%p\n",
+ _p(dsi.v_kernstart), _p(dsi.v_kernend),
+ _p(vinitrd_start), _p(vinitrd_end),
+ _p(vphysmap_start), _p(vphysmap_end),
+ _p(vpt_start), _p(vpt_end),
+ _p(vstartinfo_start), _p(vstartinfo_end),
+ _p(vstoreinfo_start), _p(vstoreinfo_end),
+ _p(vstack_start), _p(vstack_end),
+ _p(dsi.v_start), _p(v_end));
+ printf(" ENTRY ADDRESS: %p\n", _p(dsi.v_kernentry));
if ( (v_end - dsi.v_start) > (nr_pages * PAGE_SIZE) )
{
@@ -164,7 +200,8 @@ static int setup_guest(int xc_handle,
goto error_out;
}
- loadelfimage(image, xc_handle, dom, page_array, &dsi);
+ (load_funcs.loadimage)(image, image_size, xc_handle, dom, page_array,
+ &dsi);
/* Load the initial ramdisk image. */
if ( initrd_len != 0 )
@@ -186,6 +223,7 @@ static int setup_guest(int xc_handle,
if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL )
goto error_out;
+#if defined(__i386__)
/* First allocate page for page dir. */
ppt_alloc = (vpt_start - dsi.v_start) >> PAGE_SHIFT;
l2tab = page_array[ppt_alloc++] << PAGE_SHIFT;
@@ -225,6 +263,74 @@ static int setup_guest(int xc_handle,
}
munmap(vl1tab, PAGE_SIZE);
munmap(vl2tab, PAGE_SIZE);
+#endif
+#if defined(__x86_64__)
+
+#define alloc_pt(ltab, vltab) \
+ ltab = page_array[ppt_alloc++] << PAGE_SHIFT; \
+ if (vltab != NULL) { \
+ munmap(vltab, PAGE_SIZE); \
+ } \
+ if ((vltab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, \
+ PROT_READ|PROT_WRITE, \
+ ltab >> PAGE_SHIFT)) == NULL) { \
+ munmap(vltab, PAGE_SIZE); \
+ goto error_out; \
+ } \
+ memset(vltab, 0, PAGE_SIZE);
+
+ /* First allocate page for page dir. */
+ ppt_alloc = (vpt_start - dsi.v_start) >> PAGE_SHIFT;
+ l4tab = page_array[ppt_alloc++] << PAGE_SHIFT;
+ ctxt->pt_base = l4tab;
+
+ /* Intiliaize page table */
+ if ( (vl4tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
+ PROT_READ|PROT_WRITE,
+ l4tab >> PAGE_SHIFT)) == NULL )
+ goto error_out;
+ memset(vl4tab, 0, PAGE_SIZE);
+ vl4e = &vl4tab[l4_table_offset(dsi.v_start)];
+
+ for ( count = 0; count < ((v_end-dsi.v_start)>>PAGE_SHIFT); count++)
+ {
+ if ( !((unsigned long)vl1e & (PAGE_SIZE-1)) )
+ {
+ alloc_pt(l1tab, vl1tab);
+
+ if ( !((unsigned long)vl2e & (PAGE_SIZE-1)) )
+ {
+ alloc_pt(l2tab, vl2tab);
+ if ( !((unsigned long)vl3e & (PAGE_SIZE-1)) )
+ {
+ alloc_pt(l3tab, vl3tab);
+ vl3e = &vl3tab[l3_table_offset(dsi.v_start + (count<<PAGE_SHIFT))];
+ *vl4e = l3tab | L4_PROT;
+ vl4e++;
+ }
+ vl2e = &vl2tab[l2_table_offset(dsi.v_start + (count<<PAGE_SHIFT))];
+ *vl3e = l2tab | L3_PROT;
+ vl3e++;
+ }
+ vl1e = &vl1tab[l1_table_offset(dsi.v_start + (count<<PAGE_SHIFT))];
+ *vl2e = l1tab | L2_PROT;
+ vl2e++;
+ }
+
+ *vl1e = (page_array[count] << PAGE_SHIFT) | L1_PROT;
+ if ( (count >= ((vpt_start-dsi.v_start)>>PAGE_SHIFT)) &&
+ (count < ((vpt_end -dsi.v_start)>>PAGE_SHIFT)) )
+ {
+ *vl1e &= ~_PAGE_RW;
+ }
+ vl1e++;
+ }
+
+ munmap(vl1tab, PAGE_SIZE);
+ munmap(vl2tab, PAGE_SIZE);
+ munmap(vl3tab, PAGE_SIZE);
+ munmap(vl4tab, PAGE_SIZE);
+#endif
/* Write the phys->machine and machine->phys table entries. */
physmap_pfn = (vphysmap_start - dsi.v_start) >> PAGE_SHIFT;
@@ -251,13 +357,23 @@ static int setup_guest(int xc_handle,
}
munmap(physmap, PAGE_SIZE);
+#if defined(__i386__)
/*
* Pin down l2tab addr as page dir page - causes hypervisor to provide
* correct protection for the page
*/
if ( pin_table(xc_handle, MMUEXT_PIN_L2_TABLE, l2tab>>PAGE_SHIFT, dom) )
goto error_out;
+#endif
+#if defined(__x86_64__)
+ /*
+ * Pin down l4tab addr as page dir page - causes hypervisor to provide
+ * correct protection for the page
+ */
+ if ( pin_table(xc_handle, MMUEXT_PIN_L4_TABLE, l4tab>>PAGE_SHIFT, dom) )
+ goto error_out;
+#endif
start_info = xc_map_foreign_range(
xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
page_array[(vstartinfo_start-dsi.v_start)>>PAGE_SHIFT]);
@@ -276,8 +392,8 @@ static int setup_guest(int xc_handle,
start_info->mod_start = vinitrd_start;
start_info->mod_len = initrd_len;
}
- strncpy((char *)start_info->cmd_line, cmdline, MAX_CMDLINE);
- start_info->cmd_line[MAX_CMDLINE-1] = '\0';
+ strncpy((char *)start_info->cmd_line, cmdline, MAX_GUEST_CMDLINE);
+ start_info->cmd_line[MAX_GUEST_CMDLINE-1] = '\0';
munmap(start_info, PAGE_SIZE);
/* Tell our caller where we told domain store page was. */
@@ -366,7 +482,7 @@ int xc_linux_build(int xc_handle,
if ( mlock(&st_ctxt, sizeof(st_ctxt) ) )
{
- PERROR("Unable to mlock ctxt");
+ PERROR("xc_linux_build: ctxt mlock failed");
return 1;
}
@@ -426,7 +542,7 @@ int xc_linux_build(int xc_handle,
ctxt->user_regs.es = FLAT_KERNEL_DS;
ctxt->user_regs.fs = FLAT_KERNEL_DS;
ctxt->user_regs.gs = FLAT_KERNEL_DS;
- ctxt->user_regs.ss = FLAT_KERNEL_DS;
+ ctxt->user_regs.ss = FLAT_KERNEL_SS;
ctxt->user_regs.cs = FLAT_KERNEL_CS;
ctxt->user_regs.eip = vkern_entry;
ctxt->user_regs.esp = vstack_start + PAGE_SIZE;
@@ -450,7 +566,7 @@ int xc_linux_build(int xc_handle,
ctxt->gdt_ents = 0;
/* Ring 1 stack is the initial stack. */
- ctxt->kernel_ss = FLAT_KERNEL_DS;
+ ctxt->kernel_ss = FLAT_KERNEL_SS;
ctxt->kernel_sp = vstack_start + PAGE_SIZE;
/* No debugging. */
@@ -489,266 +605,3 @@ int xc_linux_build(int xc_handle,
return -1;
}
-
-static inline int is_loadable_phdr(Elf_Phdr *phdr)
-{
- return ((phdr->p_type == PT_LOAD) &&
- ((phdr->p_flags & (PF_W|PF_X)) != 0));
-}
-
-static int parseelfimage(char *elfbase,
- unsigned long elfsize,
- struct domain_setup_info *dsi)
-{
- Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
- Elf_Phdr *phdr;
- Elf_Shdr *shdr;
- unsigned long kernstart = ~0UL, kernend=0UL;
- char *shstrtab, *guestinfo=NULL, *p;
- int h;
-
- if ( !IS_ELF(*ehdr) )
- {
- ERROR("Kernel image does not have an ELF header.");
- return -EINVAL;
- }
-
- if ( (ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize)) > elfsize )
- {
- ERROR("ELF program headers extend beyond end of image.");
- return -EINVAL;
- }
-
- if ( (ehdr->e_shoff + (ehdr->e_shnum * ehdr->e_shentsize)) > elfsize )
- {
- ERROR("ELF section headers extend beyond end of image.");
- return -EINVAL;
- }
-
- /* Find the section-header strings table. */
- if ( ehdr->e_shstrndx == SHN_UNDEF )
- {
- ERROR("ELF image has no section-header strings table (shstrtab).");
- return -EINVAL;
- }
- shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff +
- (ehdr->e_shstrndx*ehdr->e_shentsize));
- shstrtab = elfbase + shdr->sh_offset;
-
- /* Find the special '__xen_guest' section and check its contents. */
- for ( h = 0; h < ehdr->e_shnum; h++ )
- {
- shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff + (h*ehdr->e_shentsize));
- if ( strcmp(&shstrtab[shdr->sh_name], "__xen_guest") != 0 )
- continue;
-
- guestinfo = elfbase + shdr->sh_offset;
-
- if ( (strstr(guestinfo, "LOADER=generic") == NULL) &&
- (strstr(guestinfo, "GUEST_OS=linux") == NULL) )
- {
- ERROR("Will only load images built for the generic loader "
- "or Linux images");
- ERROR("Actually saw: '%s'", guestinfo);
- return -EINVAL;
- }
-
- if ( (strstr(guestinfo, "XEN_VER=3.0") == NULL) )
- {
- ERROR("Will only load images built for Xen v3.0");
- ERROR("Actually saw: '%s'", guestinfo);
- return -EINVAL;
- }
-
- break;
- }
- if ( guestinfo == NULL )
- {
- ERROR("Not a Xen-ELF image: '__xen_guest' section not found.");
- return -EINVAL;
- }
-
- for ( h = 0; h < ehdr->e_phnum; h++ )
- {
- phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
- if ( !is_loadable_phdr(phdr) )
- continue;
- if ( phdr->p_paddr < kernstart )
- kernstart = phdr->p_paddr;
- if ( (phdr->p_paddr + phdr->p_memsz) > kernend )
- kernend = phdr->p_paddr + phdr->p_memsz;
- }
-
- if ( (kernstart > kernend) ||
- (ehdr->e_entry < kernstart) ||
- (ehdr->e_entry > kernend) )
- {
- ERROR("Malformed ELF image.");
- return -EINVAL;
- }
-
- dsi->v_start = kernstart;
- if ( (p = strstr(guestinfo, "VIRT_BASE=")) != NULL )
- dsi->v_start = strtoul(p+10, &p, 0);
-
- if ( (p = strstr(guestinfo, "BSD_SYMTAB")) != NULL )
- dsi->load_symtab = 1;
-
- dsi->v_kernstart = kernstart;
- dsi->v_kernend = kernend;
- dsi->v_kernentry = ehdr->e_entry;
- dsi->v_end = dsi->v_kernend;
-
- loadelfsymtab(elfbase, 0, 0, NULL, dsi);
-
- return 0;
-}
-
-static int
-loadelfimage(
- char *elfbase, int xch, u32 dom, unsigned long *parray,
- struct domain_setup_info *dsi)
-{
- Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
- Elf_Phdr *phdr;
- int h;
-
- char *va;
- unsigned long pa, done, chunksz;
-
- for ( h = 0; h < ehdr->e_phnum; h++ )
- {
- phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
- if ( !is_loadable_phdr(phdr) )
- continue;
-
- for ( done = 0; done < phdr->p_filesz; done += chunksz )
- {
- pa = (phdr->p_paddr + done) - dsi->v_start;
- va = xc_map_foreign_range(
- xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
- chunksz = phdr->p_filesz - done;
- if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
- chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
- memcpy(va + (pa & (PAGE_SIZE-1)),
- elfbase + phdr->p_offset + done, chunksz);
- munmap(va, PAGE_SIZE);
- }
-
- for ( ; done < phdr->p_memsz; done += chunksz )
- {
- pa = (phdr->p_paddr + done) - dsi->v_start;
- va = xc_map_foreign_range(
- xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
- chunksz = phdr->p_memsz - done;
- if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
- chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
- memset(va + (pa & (PAGE_SIZE-1)), 0, chunksz);
- munmap(va, PAGE_SIZE);
- }
- }
-
- loadelfsymtab(elfbase, xch, dom, parray, dsi);
-
- return 0;
-}
-
-#define ELFROUND (ELFSIZE / 8)
-
-static int
-loadelfsymtab(
- char *elfbase, int xch, u32 dom, unsigned long *parray,
- struct domain_setup_info *dsi)
-{
- Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase, *sym_ehdr;
- Elf_Shdr *shdr;
- unsigned long maxva, symva;
- char *p;
- int h, i;
-
- if ( !dsi->load_symtab )
- return 0;
-
- p = malloc(sizeof(int) + sizeof(Elf_Ehdr) +
- ehdr->e_shnum * sizeof(Elf_Shdr));
- if (p == NULL)
- return 0;
-
- maxva = (dsi->v_kernend + ELFROUND - 1) & ~(ELFROUND - 1);
- symva = maxva;
- maxva += sizeof(int);
- dsi->symtab_addr = maxva;
- dsi->symtab_len = 0;
- maxva += sizeof(Elf_Ehdr) + ehdr->e_shnum * sizeof(Elf_Shdr);
- maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
-
- shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr));
- memcpy(shdr, elfbase + ehdr->e_shoff, ehdr->e_shnum * sizeof(Elf_Shdr));
-
- for ( h = 0; h < ehdr->e_shnum; h++ )
- {
- if ( shdr[h].sh_type == SHT_STRTAB )
- {
- /* Look for a strtab @i linked to symtab @h. */
- for ( i = 0; i < ehdr->e_shnum; i++ )
- if ( (shdr[i].sh_type == SHT_SYMTAB) &&
- (shdr[i].sh_link == h) )
- break;
- /* Skip symtab @h if we found no corresponding strtab @i. */
- if ( i == ehdr->e_shnum )
- {
- shdr[h].sh_offset = 0;
- continue;
- }
- }
-
- if ( (shdr[h].sh_type == SHT_STRTAB) ||
- (shdr[h].sh_type == SHT_SYMTAB) )
- {
- if ( parray != NULL )
- xc_map_memcpy(maxva, elfbase + shdr[h].sh_offset, shdr[h].sh_size,
- xch, dom, parray, dsi->v_start);
-
- /* Mangled to be based on ELF header location. */
- shdr[h].sh_offset = maxva - dsi->symtab_addr;
-
- dsi->symtab_len += shdr[h].sh_size;
- maxva += shdr[h].sh_size;
- maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
- }
-
- shdr[h].sh_name = 0; /* Name is NULL. */
- }
-
- if ( dsi->symtab_len == 0 )
- {
- dsi->symtab_addr = 0;
- goto out;
- }
-
- if ( parray != NULL )
- {
- *(int *)p = maxva - dsi->symtab_addr;
- sym_ehdr = (Elf_Ehdr *)(p + sizeof(int));
- memcpy(sym_ehdr, ehdr, sizeof(Elf_Ehdr));
- sym_ehdr->e_phoff = 0;
- sym_ehdr->e_shoff = sizeof(Elf_Ehdr);
- sym_ehdr->e_phentsize = 0;
- sym_ehdr->e_phnum = 0;
- sym_ehdr->e_shstrndx = SHN_UNDEF;
-
- /* Copy total length, crafted ELF header and section header table */
- xc_map_memcpy(symva, p, sizeof(int) + sizeof(Elf_Ehdr) +
- ehdr->e_shnum * sizeof(Elf_Shdr), xch, dom, parray,
- dsi->v_start);
- }
-
- dsi->symtab_len = maxva - dsi->symtab_addr;
- dsi->v_end = round_pgup(maxva);
-
- out:
- if ( p != NULL )
- free(p);
-
- return 0;
-}
diff --git a/tools/libxc/xc_load_bin.c b/tools/libxc/xc_load_bin.c
new file mode 100644
index 0000000000..965ccd08da
--- /dev/null
+++ b/tools/libxc/xc_load_bin.c
@@ -0,0 +1,299 @@
+/******************************************************************************
+ * xc_bin_load.c
+ *
+ * Based on xc_elf_load.c
+ *
+ * Loads simple binary images. It's like a .COM file in MS-DOS. No headers are
+ * present. The only requirement is that it must have a xen_bin_image table
+ * somewhere in the first 8192 bytes, starting on a 32-bit aligned address.
+ * Those familiar with the multiboot specification should recognize this, it's
+ * (almost) the same as the multiboot header.
+ * The layout of the xen_bin_image table is:
+ *
+ * Offset Type Name Note
+ * 0 u32 magic required
+ * 4 u32 flags required
+ * 8 u32 checksum required
+ * 12 u32 header_addr required
+ * 16 u32 load_addr required
+ * 20 u32 load_end_addr required
+ * 24 u32 bss_end_addr required
+ * 28 u32 entry_addr required
+ *
+ * - magic
+ * Magic number identifying the table. For images to be loaded by Xen 3, the
+ * magic value is 0x336ec578 ("xEn3" with the 0x80 bit of the "E" set).
+ * - flags
+ * bit 0: indicates whether the image needs to be loaded on a page boundary
+ * bit 1: reserved, must be 0 (the multiboot spec uses this bit to indicate
+ * that memory info should be passed to the image)
+ * bit 2: reserved, must be 0 (the multiboot spec uses this bit to indicate
+ * that the bootloader should pass video mode info to the image)
+ * bit 16: reserved, must be 1 (the multiboot spec uses this bit to indicate
+ * that the values in the fields header_addr - entry_addr are
+ * valid)
+ * All other bits should be set to 0.
+ * - checksum
+ * When added to "magic" and "flags", the resulting value should be 0.
+ * - header_addr
+ * Contains the virtual address corresponding to the beginning of the
+ * table - the memory location at which the magic value is supposed to be
+ * loaded. This field serves to synchronize the mapping between OS image
+ * offsets and virtual memory addresses.
+ * - load_addr
+ * Contains the virtual address of the beginning of the text segment. The
+ * offset in the OS image file at which to start loading is defined by the
+ * offset at which the table was found, minus (header addr - load addr).
+ * load addr must be less than or equal to header addr.
+ * - load_end_addr
+ * Contains the virtual address of the end of the data segment.
+ * (load_end_addr - load_addr) specifies how much data to load. This implies
+ * that the text and data segments must be consecutive in the OS image. If
+ * this field is zero, the domain builder assumes that the text and data
+ * segments occupy the whole OS image file.
+ * - bss_end_addr
+ * Contains the virtual address of the end of the bss segment. The domain
+ * builder initializes this area to zero, and reserves the memory it occupies
+ * to avoid placing boot modules and other data relevant to the loaded image
+ * in that area. If this field is zero, the domain builder assumes that no bss
+ * segment is present.
+ * - entry_addr
+ * The virtual address at which to start execution of the loaded image.
+ *
+ * Some of the field descriptions were copied from "The Multiboot
+ * Specification", Copyright 1995, 96 Bryan Ford <baford@cs.utah.edu>,
+ * Erich Stefan Boleyn <erich@uruk.org> Copyright 1999, 2000, 2001, 2002
+ * Free Software Foundation, Inc.
+ */
+
+#include "xc_private.h"
+#include <stdlib.h>
+
+#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
+#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+
+#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
+#define round_pgdown(_p) ((_p)&PAGE_MASK)
+
+struct xen_bin_image_table
+{
+ unsigned long magic;
+ unsigned long flags;
+ unsigned long checksum;
+ unsigned long header_addr;
+ unsigned long load_addr;
+ unsigned long load_end_addr;
+ unsigned long bss_end_addr;
+ unsigned long entry_addr;
+};
+
+#define XEN_REACTOS_MAGIC3 0x336ec578
+
+#define XEN_REACTOS_FLAG_ALIGN4K 0x00000001
+#define XEN_REACTOS_FLAG_NEEDMEMINFO 0x00000002
+#define XEN_REACTOS_FLAG_NEEDVIDINFO 0x00000004
+#define XEN_REACTOS_FLAG_ADDRSVALID 0x00010000
+
+/* Flags we test for */
+#define FLAGS_MASK ((~ 0) & (~ XEN_REACTOS_FLAG_ALIGN4K))
+#define FLAGS_REQUIRED XEN_REACTOS_FLAG_ADDRSVALID
+
+static struct xen_bin_image_table *
+findtable(char *image, unsigned long image_size);
+static int
+parsebinimage(
+ char *image, unsigned long image_size, struct domain_setup_info *dsi);
+static int
+loadbinimage(
+ char *image, unsigned long image_size, int xch, u32 dom,
+ unsigned long *parray, struct domain_setup_info *dsi);
+
+int probe_bin(char *image,
+ unsigned long image_size,
+ struct load_funcs *load_funcs)
+{
+ if ( NULL == findtable(image, image_size) )
+ {
+ return -EINVAL;
+ }
+
+ load_funcs->parseimage = parsebinimage;
+ load_funcs->loadimage = loadbinimage;
+
+ return 0;
+}
+
+static struct xen_bin_image_table *
+findtable(char *image, unsigned long image_size)
+{
+ struct xen_bin_image_table *table;
+ unsigned long *probe_ptr;
+ unsigned probe_index;
+ unsigned probe_count;
+
+ /* Don't go outside the image */
+ if ( image_size < sizeof(struct xen_bin_image_table) )
+ {
+ return NULL;
+ }
+ probe_count = image_size;
+ /* Restrict to first 8k */
+ if ( 8192 < probe_count )
+ {
+ probe_count = 8192;
+ }
+ probe_count = (probe_count - sizeof(struct xen_bin_image_table)) /
+ sizeof(unsigned long);
+
+ /* Search for the magic header */
+ probe_ptr = (unsigned long *) image;
+ table = NULL;
+ for ( probe_index = 0; probe_index < probe_count; probe_index++ )
+ {
+ if ( XEN_REACTOS_MAGIC3 == *probe_ptr )
+ {
+ table = (struct xen_bin_image_table *) probe_ptr;
+ /* Checksum correct? */
+ if ( 0 == table->magic + table->flags + table->checksum )
+ {
+ return table;
+ }
+ }
+ probe_ptr++;
+ }
+
+ return NULL;
+}
+
+static int parsebinimage(char *image,
+ unsigned long image_size,
+ struct domain_setup_info *dsi)
+{
+ struct xen_bin_image_table *image_info;
+ unsigned long start_addr;
+ unsigned long end_addr;
+
+ image_info = findtable(image, image_size);
+ if ( NULL == image_info )
+ {
+ ERROR("Image does not have a valid xen_bin_image_table table.");
+ return -EINVAL;
+ }
+
+ /* Check the flags */
+ if ( FLAGS_REQUIRED != (image_info->flags & FLAGS_MASK) )
+ {
+ ERROR("xen_bin_image_table flags required 0x%08x found 0x%08lx",
+ FLAGS_REQUIRED, image_info->flags & FLAGS_MASK);
+ return -EINVAL;
+ }
+
+ /* Sanity check on the addresses */
+ if ( image_info->header_addr < image_info->load_addr ||
+ ((char *) image_info - image) <
+ (image_info->header_addr - image_info->load_addr) )
+ {
+ ERROR("Invalid header_addr.");
+ return -EINVAL;
+ }
+ start_addr = image_info->header_addr - ((char *) image_info - image);
+ if ( 0 != image_info->load_end_addr &&
+ ( image_info->load_end_addr < image_info->load_end_addr ||
+ start_addr + image_size < image_info->load_end_addr ) )
+ {
+ ERROR("Invalid load_end_addr");
+ return -EINVAL;
+ }
+ end_addr = (0 == image_info->load_end_addr ? start_addr + image_size :
+ image_info->load_end_addr);
+ if ( 0 != image_info->bss_end_addr &&
+ image_info->bss_end_addr < end_addr )
+ {
+ ERROR("Invalid bss_end_addr");
+ return -EINVAL;
+ }
+
+ dsi->v_start = image_info->load_addr;
+ if ( 0 != image_info->bss_end_addr )
+ {
+ dsi->v_end = image_info->bss_end_addr;
+ }
+ else if ( 0 != image_info->load_end_addr )
+ {
+ dsi->v_end = image_info->load_end_addr;
+ }
+ else
+ {
+ dsi->v_end = image_info->load_addr + image_size -
+ (((char *) image_info - image) -
+ (image_info->header_addr - image_info->load_addr));
+ }
+ dsi->v_kernstart = dsi->v_start;
+ dsi->v_kernend = dsi->v_end;
+ dsi->v_kernentry = image_info->entry_addr;
+
+ return 0;
+}
+
+static int
+loadbinimage(
+ char *image, unsigned long image_size, int xch, u32 dom,
+ unsigned long *parray, struct domain_setup_info *dsi)
+{
+ unsigned long size;
+ char *va;
+ unsigned long done, chunksz;
+ struct xen_bin_image_table *image_info;
+
+ image_info = findtable(image, image_size);
+ if ( NULL == image_info )
+ {
+ ERROR("Image does not have a valid xen_bin_image_table table.");
+ return -EINVAL;
+ }
+
+ /* Determine image size */
+ if ( 0 == image_info->load_end_addr )
+ {
+ size = image_size - (((char *) image_info - image) -
+ (image_info->header_addr -
+ image_info->load_addr));
+ }
+ else
+ {
+ size = image_info->load_end_addr - image_info->load_addr;
+ }
+
+ /* It's possible that we need to skip the first part of the image */
+ image += ((char *)image_info - image) -
+ (image_info->header_addr - image_info->load_addr);
+
+ for ( done = 0; done < size; done += chunksz )
+ {
+ va = xc_map_foreign_range(
+ xch, dom, PAGE_SIZE, PROT_WRITE, parray[done>>PAGE_SHIFT]);
+ chunksz = size - done;
+ if ( chunksz > PAGE_SIZE )
+ chunksz = PAGE_SIZE;
+ memcpy(va, image + done, chunksz);
+ munmap(va, PAGE_SIZE);
+ }
+
+ if ( 0 != image_info->bss_end_addr &&
+ image_info->load_addr + size < image_info->bss_end_addr )
+ {
+ size = image_info->bss_end_addr - image_info->load_addr;
+ }
+ for ( ; done < size; done += chunksz )
+ {
+ va = xc_map_foreign_range(
+ xch, dom, PAGE_SIZE, PROT_WRITE, parray[done>>PAGE_SHIFT]);
+ chunksz = size - done;
+ if ( chunksz > (PAGE_SIZE - (done & (PAGE_SIZE-1))) )
+ chunksz = PAGE_SIZE - (done & (PAGE_SIZE-1));
+ memset(va + (done & (PAGE_SIZE-1)), 0, chunksz);
+ munmap(va, PAGE_SIZE);
+ }
+
+ return 0;
+}
diff --git a/tools/libxc/xc_load_elf.c b/tools/libxc/xc_load_elf.c
new file mode 100644
index 0000000000..bc46636d75
--- /dev/null
+++ b/tools/libxc/xc_load_elf.c
@@ -0,0 +1,310 @@
+/******************************************************************************
+ * xc_elf_load.c
+ */
+
+#include "xc_private.h"
+
+#if defined(__i386__)
+#define ELFSIZE 32
+#endif
+#if defined(__x86_64__)
+#define ELFSIZE 64
+#endif
+
+#include "xc_elf.h"
+#include <stdlib.h>
+
+#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
+#define round_pgdown(_p) ((_p)&PAGE_MASK)
+
+static int
+parseelfimage(
+ char *image, unsigned long image_size, struct domain_setup_info *dsi);
+static int
+loadelfimage(
+ char *image, unsigned long image_size, int xch, u32 dom,
+ unsigned long *parray, struct domain_setup_info *dsi);
+static int
+loadelfsymtab(
+ char *image, int xch, u32 dom, unsigned long *parray,
+ struct domain_setup_info *dsi);
+
+int probe_elf(char *image,
+ unsigned long image_size,
+ struct load_funcs *load_funcs)
+{
+ Elf_Ehdr *ehdr = (Elf_Ehdr *)image;
+
+ if ( !IS_ELF(*ehdr) )
+ {
+ return -EINVAL;
+ }
+
+ load_funcs->parseimage = parseelfimage;
+ load_funcs->loadimage = loadelfimage;
+
+ return 0;
+}
+
+static inline int is_loadable_phdr(Elf_Phdr *phdr)
+{
+ return ((phdr->p_type == PT_LOAD) &&
+ ((phdr->p_flags & (PF_W|PF_X)) != 0));
+}
+
+static int parseelfimage(char *image,
+ unsigned long elfsize,
+ struct domain_setup_info *dsi)
+{
+ Elf_Ehdr *ehdr = (Elf_Ehdr *)image;
+ Elf_Phdr *phdr;
+ Elf_Shdr *shdr;
+ unsigned long kernstart = ~0UL, kernend=0UL;
+ char *shstrtab, *guestinfo=NULL, *p;
+ int h;
+
+ if ( !IS_ELF(*ehdr) )
+ {
+ ERROR("Kernel image does not have an ELF header.");
+ return -EINVAL;
+ }
+
+ if ( (ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize)) > elfsize )
+ {
+ ERROR("ELF program headers extend beyond end of image.");
+ return -EINVAL;
+ }
+
+ if ( (ehdr->e_shoff + (ehdr->e_shnum * ehdr->e_shentsize)) > elfsize )
+ {
+ ERROR("ELF section headers extend beyond end of image.");
+ return -EINVAL;
+ }
+
+ /* Find the section-header strings table. */
+ if ( ehdr->e_shstrndx == SHN_UNDEF )
+ {
+ ERROR("ELF image has no section-header strings table (shstrtab).");
+ return -EINVAL;
+ }
+ shdr = (Elf_Shdr *)(image + ehdr->e_shoff +
+ (ehdr->e_shstrndx*ehdr->e_shentsize));
+ shstrtab = image + shdr->sh_offset;
+
+ /* Find the special '__xen_guest' section and check its contents. */
+ for ( h = 0; h < ehdr->e_shnum; h++ )
+ {
+ shdr = (Elf_Shdr *)(image + ehdr->e_shoff + (h*ehdr->e_shentsize));
+ if ( strcmp(&shstrtab[shdr->sh_name], "__xen_guest") != 0 )
+ continue;
+
+ guestinfo = image + shdr->sh_offset;
+
+ if ( (strstr(guestinfo, "LOADER=generic") == NULL) &&
+ (strstr(guestinfo, "GUEST_OS=linux") == NULL) )
+ {
+ ERROR("Will only load images built for the generic loader "
+ "or Linux images");
+ ERROR("Actually saw: '%s'", guestinfo);
+ return -EINVAL;
+ }
+
+ if ( (strstr(guestinfo, "XEN_VER=3.0") == NULL) )
+ {
+ ERROR("Will only load images built for Xen v3.0");
+ ERROR("Actually saw: '%s'", guestinfo);
+ return -EINVAL;
+ }
+
+ break;
+ }
+ if ( guestinfo == NULL )
+ {
+ ERROR("Not a Xen-ELF image: '__xen_guest' section not found.");
+ return -EINVAL;
+ }
+
+ for ( h = 0; h < ehdr->e_phnum; h++ )
+ {
+ phdr = (Elf_Phdr *)(image + ehdr->e_phoff + (h*ehdr->e_phentsize));
+ if ( !is_loadable_phdr(phdr) )
+ continue;
+ if ( phdr->p_paddr < kernstart )
+ kernstart = phdr->p_paddr;
+ if ( (phdr->p_paddr + phdr->p_memsz) > kernend )
+ kernend = phdr->p_paddr + phdr->p_memsz;
+ }
+
+ if ( (kernstart > kernend) ||
+ (ehdr->e_entry < kernstart) ||
+ (ehdr->e_entry > kernend) )
+ {
+ ERROR("Malformed ELF image.");
+ return -EINVAL;
+ }
+
+ dsi->v_start = kernstart;
+ if ( (p = strstr(guestinfo, "VIRT_BASE=")) != NULL )
+ dsi->v_start = strtoul(p+10, &p, 0);
+
+ if ( (p = strstr(guestinfo, "BSD_SYMTAB")) != NULL )
+ dsi->load_symtab = 1;
+
+ dsi->v_kernstart = kernstart;
+ dsi->v_kernend = kernend;
+ dsi->v_kernentry = ehdr->e_entry;
+ dsi->v_end = dsi->v_kernend;
+
+ loadelfsymtab(image, 0, 0, NULL, dsi);
+
+ return 0;
+}
+
+static int
+loadelfimage(
+ char *image, unsigned long elfsize, int xch, u32 dom,
+ unsigned long *parray, struct domain_setup_info *dsi)
+{
+ Elf_Ehdr *ehdr = (Elf_Ehdr *)image;
+ Elf_Phdr *phdr;
+ int h;
+
+ char *va;
+ unsigned long pa, done, chunksz;
+
+ for ( h = 0; h < ehdr->e_phnum; h++ )
+ {
+ phdr = (Elf_Phdr *)(image + ehdr->e_phoff + (h*ehdr->e_phentsize));
+ if ( !is_loadable_phdr(phdr) )
+ continue;
+
+ for ( done = 0; done < phdr->p_filesz; done += chunksz )
+ {
+ pa = (phdr->p_paddr + done) - dsi->v_start;
+ va = xc_map_foreign_range(
+ xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
+ chunksz = phdr->p_filesz - done;
+ if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
+ chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
+ memcpy(va + (pa & (PAGE_SIZE-1)),
+ image + phdr->p_offset + done, chunksz);
+ munmap(va, PAGE_SIZE);
+ }
+
+ for ( ; done < phdr->p_memsz; done += chunksz )
+ {
+ pa = (phdr->p_paddr + done) - dsi->v_start;
+ va = xc_map_foreign_range(
+ xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
+ chunksz = phdr->p_memsz - done;
+ if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
+ chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
+ memset(va + (pa & (PAGE_SIZE-1)), 0, chunksz);
+ munmap(va, PAGE_SIZE);
+ }
+ }
+
+ loadelfsymtab(image, xch, dom, parray, dsi);
+
+ return 0;
+}
+
+#define ELFROUND (ELFSIZE / 8)
+
+static int
+loadelfsymtab(
+ char *image, int xch, u32 dom, unsigned long *parray,
+ struct domain_setup_info *dsi)
+{
+ Elf_Ehdr *ehdr = (Elf_Ehdr *)image, *sym_ehdr;
+ Elf_Shdr *shdr;
+ unsigned long maxva, symva;
+ char *p;
+ int h, i;
+
+ if ( !dsi->load_symtab )
+ return 0;
+
+ p = malloc(sizeof(int) + sizeof(Elf_Ehdr) +
+ ehdr->e_shnum * sizeof(Elf_Shdr));
+ if (p == NULL)
+ return 0;
+
+ maxva = (dsi->v_kernend + ELFROUND - 1) & ~(ELFROUND - 1);
+ symva = maxva;
+ maxva += sizeof(int);
+ dsi->symtab_addr = maxva;
+ dsi->symtab_len = 0;
+ maxva += sizeof(Elf_Ehdr) + ehdr->e_shnum * sizeof(Elf_Shdr);
+ maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
+
+ shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr));
+ memcpy(shdr, image + ehdr->e_shoff, ehdr->e_shnum * sizeof(Elf_Shdr));
+
+ for ( h = 0; h < ehdr->e_shnum; h++ )
+ {
+ if ( shdr[h].sh_type == SHT_STRTAB )
+ {
+ /* Look for a strtab @i linked to symtab @h. */
+ for ( i = 0; i < ehdr->e_shnum; i++ )
+ if ( (shdr[i].sh_type == SHT_SYMTAB) &&
+ (shdr[i].sh_link == h) )
+ break;
+ /* Skip symtab @h if we found no corresponding strtab @i. */
+ if ( i == ehdr->e_shnum )
+ {
+ shdr[h].sh_offset = 0;
+ continue;
+ }
+ }
+
+ if ( (shdr[h].sh_type == SHT_STRTAB) ||
+ (shdr[h].sh_type == SHT_SYMTAB) )
+ {
+ if ( parray != NULL )
+ xc_map_memcpy(maxva, image + shdr[h].sh_offset, shdr[h].sh_size,
+ xch, dom, parray, dsi->v_start);
+
+ /* Mangled to be based on ELF header location. */
+ shdr[h].sh_offset = maxva - dsi->symtab_addr;
+
+ dsi->symtab_len += shdr[h].sh_size;
+ maxva += shdr[h].sh_size;
+ maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
+ }
+
+ shdr[h].sh_name = 0; /* Name is NULL. */
+ }
+
+ if ( dsi->symtab_len == 0 )
+ {
+ dsi->symtab_addr = 0;
+ goto out;
+ }
+
+ if ( parray != NULL )
+ {
+ *(int *)p = maxva - dsi->symtab_addr;
+ sym_ehdr = (Elf_Ehdr *)(p + sizeof(int));
+ memcpy(sym_ehdr, ehdr, sizeof(Elf_Ehdr));
+ sym_ehdr->e_phoff = 0;
+ sym_ehdr->e_shoff = sizeof(Elf_Ehdr);
+ sym_ehdr->e_phentsize = 0;
+ sym_ehdr->e_phnum = 0;
+ sym_ehdr->e_shstrndx = SHN_UNDEF;
+
+ /* Copy total length, crafted ELF header and section header table */
+ xc_map_memcpy(symva, p, sizeof(int) + sizeof(Elf_Ehdr) +
+ ehdr->e_shnum * sizeof(Elf_Shdr), xch, dom, parray,
+ dsi->v_start);
+ }
+
+ dsi->symtab_len = maxva - dsi->symtab_addr;
+ dsi->v_end = round_pgup(maxva);
+
+ out:
+ if ( p != NULL )
+ free(p);
+
+ return 0;
+}
diff --git a/tools/libxc/xc_misc.c b/tools/libxc/xc_misc.c
index 9ce8548709..40291bc3ef 100644
--- a/tools/libxc/xc_misc.c
+++ b/tools/libxc/xc_misc.c
@@ -19,34 +19,35 @@ int xc_interface_close(int xc_handle)
return close(xc_handle);
}
-
-#define CONSOLE_RING_CLEAR 1
-
int xc_readconsolering(int xc_handle,
- char *str,
- unsigned int max_chars,
+ char **pbuffer,
+ unsigned int *pnr_chars,
int clear)
{
int ret;
dom0_op_t op;
+ char *buffer = *pbuffer;
+ unsigned int nr_chars = *pnr_chars;
op.cmd = DOM0_READCONSOLE;
- op.u.readconsole.str = (unsigned long)str;
- op.u.readconsole.count = max_chars;
- op.u.readconsole.cmd = clear ? CONSOLE_RING_CLEAR : 0;
+ op.u.readconsole.buffer = buffer;
+ op.u.readconsole.count = nr_chars;
+ op.u.readconsole.clear = clear;
- if ( (ret = mlock(str, max_chars)) != 0 )
+ if ( (ret = mlock(buffer, nr_chars)) != 0 )
return ret;
- if ( (ret = do_dom0_op(xc_handle, &op)) >= 0 )
- str[ret] = '\0';
+ if ( (ret = do_dom0_op(xc_handle, &op)) == 0 )
+ {
+ *pbuffer = op.u.readconsole.buffer;
+ *pnr_chars = op.u.readconsole.count;
+ }
- (void)munlock(str, max_chars);
+ (void)munlock(buffer, nr_chars);
return ret;
}
-
int xc_physinfo(int xc_handle,
xc_physinfo_t *put_info)
{
@@ -64,7 +65,6 @@ int xc_physinfo(int xc_handle,
return 0;
}
-
int xc_sched_id(int xc_handle,
int *sched_id)
{
diff --git a/tools/libxc/xc_plan9_build.c b/tools/libxc/xc_plan9_build.c
index 08ac06d08a..7f697d2115 100644
--- a/tools/libxc/xc_plan9_build.c
+++ b/tools/libxc/xc_plan9_build.c
@@ -357,8 +357,8 @@ setup_guest(int xc_handle,
start_info->flags = 0;
DPRINTF((" control event channel is %d\n", control_evtchn));
start_info->domain_controller_evtchn = control_evtchn;
- strncpy((char *)start_info->cmd_line, cmdline, MAX_CMDLINE);
- start_info->cmd_line[MAX_CMDLINE - 1] = '\0';
+ strncpy((char *)start_info->cmd_line, cmdline, MAX_GUEST_CMDLINE);
+ start_info->cmd_line[MAX_GUEST_CMDLINE - 1] = '\0';
munmap(start_info, PAGE_SIZE);
DPRINTF(("done setting up start_info\n"));
@@ -434,7 +434,7 @@ xc_plan9_build(int xc_handle,
DPRINTF(("xc_get_tot_pages returns %ld pages\n", tot_pages));
if (mlock(&st_ctxt, sizeof (st_ctxt))) {
- PERROR("Unable to mlock ctxt");
+ PERROR("xc_plan9_build: ctxt mlock failed");
return 1;
}
diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c
index 0645af7a91..87e5ecd1f3 100644
--- a/tools/libxc/xc_private.c
+++ b/tools/libxc/xc_private.c
@@ -122,7 +122,7 @@ static int flush_mmu_updates(int xc_handle, mmu_t *mmu)
if ( mlock(mmu->updates, sizeof(mmu->updates)) != 0 )
{
- PERROR("Could not lock pagetable update array");
+ PERROR("flush_mmu_updates: mmu updates mlock failed");
err = 1;
goto out;
}
@@ -226,7 +226,7 @@ int xc_get_pfn_list(int xc_handle,
if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
{
- PERROR("Could not lock pfn list buffer");
+ PERROR("xc_get_pfn_list: pfn_buf mlock failed");
return -1;
}
@@ -363,3 +363,8 @@ void xc_map_memcpy(unsigned long dst, char *src, unsigned long size,
munmap(va, PAGE_SIZE);
}
}
+
+int xc_dom0_op(int xc_handle, dom0_op_t *op)
+{
+ return do_dom0_op(xc_handle, op);
+}
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index ec8b21c21c..baf1e5f26d 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -29,12 +29,25 @@
#define _PAGE_PSE 0x080
#define _PAGE_GLOBAL 0x100
-
+#if defined(__i386__)
#define L1_PAGETABLE_SHIFT 12
#define L2_PAGETABLE_SHIFT 22
-
+#elif defined(__x86_64__)
+#define L1_PAGETABLE_SHIFT 12
+#define L2_PAGETABLE_SHIFT 21
+#define L3_PAGETABLE_SHIFT 30
+#define L4_PAGETABLE_SHIFT 39
+#endif
+
+#if defined(__i386__)
#define ENTRIES_PER_L1_PAGETABLE 1024
#define ENTRIES_PER_L2_PAGETABLE 1024
+#elif defined(__x86_64__)
+#define L1_PAGETABLE_ENTRIES 512
+#define L2_PAGETABLE_ENTRIES 512
+#define L3_PAGETABLE_ENTRIES 512
+#define L4_PAGETABLE_ENTRIES 512
+#endif
#define PAGE_SHIFT L1_PAGETABLE_SHIFT
#define PAGE_SIZE (1UL << PAGE_SHIFT)
@@ -42,11 +55,51 @@
typedef unsigned long l1_pgentry_t;
typedef unsigned long l2_pgentry_t;
+#if defined(__x86_64__)
+typedef unsigned long l3_pgentry_t;
+typedef unsigned long l4_pgentry_t;
+#endif
+#if defined(__i386__)
#define l1_table_offset(_a) \
(((_a) >> L1_PAGETABLE_SHIFT) & (ENTRIES_PER_L1_PAGETABLE - 1))
#define l2_table_offset(_a) \
((_a) >> L2_PAGETABLE_SHIFT)
+#elif defined(__x86_64__)
+#define l1_table_offset(_a) \
+ (((_a) >> L1_PAGETABLE_SHIFT) & (L1_PAGETABLE_ENTRIES - 1))
+#define l2_table_offset(_a) \
+ (((_a) >> L2_PAGETABLE_SHIFT) & (L2_PAGETABLE_ENTRIES - 1))
+#define l3_table_offset(_a) \
+ (((_a) >> L3_PAGETABLE_SHIFT) & (L3_PAGETABLE_ENTRIES - 1))
+#define l4_table_offset(_a) \
+ (((_a) >> L4_PAGETABLE_SHIFT) & (L4_PAGETABLE_ENTRIES - 1))
+#endif
+
+struct domain_setup_info
+{
+ unsigned long v_start;
+ unsigned long v_end;
+ unsigned long v_kernstart;
+ unsigned long v_kernend;
+ unsigned long v_kernentry;
+
+ unsigned int load_symtab;
+ unsigned long symtab_addr;
+ unsigned long symtab_len;
+};
+
+typedef int (*parseimagefunc)(char *image, unsigned long image_size,
+ struct domain_setup_info *dsi);
+typedef int (*loadimagefunc)(char *image, unsigned long image_size, int xch,
+ u32 dom, unsigned long *parray,
+ struct domain_setup_info *dsi);
+
+struct load_funcs
+{
+ parseimagefunc parseimage;
+ loadimagefunc loadimage;
+};
#define ERROR(_m, _a...) \
fprintf(stderr, "ERROR: " _m "\n" , ## _a )
@@ -232,9 +285,7 @@ typedef struct mfn_mapper {
} mfn_mapper_t;
-unsigned long xc_get_m2p_start_mfn ( int xc_handle );
-
-long xc_get_tot_pages(int xc_handle, u32 domid);
+unsigned long xc_get_m2p_start_mfn (int xc_handle);
int xc_copy_to_domain_page(int xc_handle, u32 domid,
unsigned long dst_pfn, void *src_page);
@@ -247,7 +298,11 @@ void xc_map_memcpy(unsigned long dst, char *src, unsigned long size,
int xch, u32 dom, unsigned long *parray,
unsigned long vstart);
-int pin_table(
- int xc_handle, unsigned int type, unsigned long mfn, domid_t dom);
+int pin_table(int xc_handle, unsigned int type, unsigned long mfn,
+ domid_t dom);
+
+/* image loading */
+int probe_elf(char *image, unsigned long image_size, struct load_funcs *funcs);
+int probe_bin(char *image, unsigned long image_size, struct load_funcs *funcs);
#endif /* __XC_PRIVATE_H__ */
diff --git a/tools/libxc/xc_vmx_build.c b/tools/libxc/xc_vmx_build.c
index 5cbd9b8577..c30fd4c49b 100644
--- a/tools/libxc/xc_vmx_build.c
+++ b/tools/libxc/xc_vmx_build.c
@@ -20,22 +20,13 @@
#define LINUX_KERNEL_ENTR_ADDR 0x00100000
#define LINUX_PAGE_OFFSET 0xC0000000
-struct domain_setup_info
-{
- unsigned long v_start;
- unsigned long v_end;
- unsigned long v_kernstart;
- unsigned long v_kernend;
- unsigned long v_kernentry;
-};
-
static int
parseelfimage(
char *elfbase, unsigned long elfsize, struct domain_setup_info *dsi);
static int
loadelfimage(
char *elfbase, int xch, u32 dom, unsigned long *parray,
- unsigned long vstart);
+ struct domain_setup_info *dsi);
static void build_e820map(struct mem_map *mem_mapp, unsigned long mem_size)
{
@@ -255,7 +246,7 @@ static int setup_guest(int xc_handle,
goto error_out;
}
- loadelfimage(image, xc_handle, dom, page_array, dsi.v_start);
+ loadelfimage(image, xc_handle, dom, page_array, &dsi);
/* Load the initial ramdisk image. */
if ( initrd_len != 0 )
@@ -538,7 +529,7 @@ int xc_vmx_build(int xc_handle,
if ( mlock(&st_ctxt, sizeof(st_ctxt) ) )
{
- PERROR("Unable to mlock ctxt");
+ PERROR("xc_vmx_build: ctxt mlock failed");
return 1;
}
@@ -626,6 +617,7 @@ int xc_vmx_build(int xc_handle,
launch_op.cmd = DOM0_SETDOMAININFO;
rc = do_dom0_op(xc_handle, &launch_op);
+
return rc;
error_out:
@@ -717,7 +709,7 @@ static int parseelfimage(char *elfbase,
static int
loadelfimage(
char *elfbase, int xch, u32 dom, unsigned long *parray,
- unsigned long vstart)
+ struct domain_setup_info *dsi)
{
Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
Elf_Phdr *phdr;
@@ -734,7 +726,7 @@ loadelfimage(
for ( done = 0; done < phdr->p_filesz; done += chunksz )
{
- pa = (phdr->p_paddr + done) - vstart - LINUX_PAGE_OFFSET;
+ pa = (phdr->p_paddr + done) - dsi->v_start - LINUX_PAGE_OFFSET;
if ((va = xc_map_foreign_range(
xch, dom, PAGE_SIZE, PROT_WRITE,
parray[pa>>PAGE_SHIFT])) == 0)
@@ -749,7 +741,7 @@ loadelfimage(
for ( ; done < phdr->p_memsz; done += chunksz )
{
- pa = (phdr->p_paddr + done) - vstart - LINUX_PAGE_OFFSET;
+ pa = (phdr->p_paddr + done) - dsi->v_start - LINUX_PAGE_OFFSET;
if ((va = xc_map_foreign_range(
xch, dom, PAGE_SIZE, PROT_WRITE,
parray[pa>>PAGE_SHIFT])) == 0)
diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c
index 5018a4e4e7..13d60be08e 100644
--- a/tools/python/xen/lowlevel/xc/xc.c
+++ b/tools/python/xen/lowlevel/xc/xc.c
@@ -498,11 +498,12 @@ static PyObject *pyxc_evtchn_alloc_unbound(PyObject *self,
XcObject *xc = (XcObject *)self;
u32 dom;
- int port;
+ int port = 0;
- static char *kwd_list[] = { "dom", NULL };
+ static char *kwd_list[] = { "dom", "port", NULL };
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) )
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
+ &dom, &port) )
return NULL;
if ( xc_evtchn_alloc_unbound(xc->xc_handle, dom, &port) != 0 )
@@ -681,7 +682,8 @@ static PyObject *pyxc_readconsolering(PyObject *self,
XcObject *xc = (XcObject *)self;
unsigned int clear = 0;
- char str[32768];
+ char _str[32768], *str = _str;
+ unsigned int count = 32768;
int ret;
static char *kwd_list[] = { "clear", NULL };
@@ -689,11 +691,11 @@ static PyObject *pyxc_readconsolering(PyObject *self,
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwd_list, &clear) )
return NULL;
- ret = xc_readconsolering(xc->xc_handle, str, sizeof(str), clear);
+ ret = xc_readconsolering(xc->xc_handle, &str, &count, clear);
if ( ret < 0 )
return PyErr_SetFromErrno(xc_error);
- return PyString_FromStringAndSize(str, ret);
+ return PyString_FromStringAndSize(str, count);
}
static PyObject *pyxc_physinfo(PyObject *self,
diff --git a/tools/xcs/xcsdump.c b/tools/xcs/xcsdump.c
index 656de24986..dfc166b154 100644
--- a/tools/xcs/xcsdump.c
+++ b/tools/xcs/xcsdump.c
@@ -196,8 +196,9 @@ int main(int argc, char* argv[])
break;
case XCS_VIRQ:
printf("[VIRQ ] : %d\n", msg.u.control.local_port);
+ break;
default:
- printf("[UNKNOWN ]\n");
+ printf("[UNKNOWN ] : %d\n", msg.type);
}
}
diff --git a/xen/arch/ia64/Makefile b/xen/arch/ia64/Makefile
index 568cbe5957..d323f407c5 100644
--- a/xen/arch/ia64/Makefile
+++ b/xen/arch/ia64/Makefile
@@ -4,7 +4,7 @@ include $(BASEDIR)/Rules.mk
OBJS = xensetup.o setup.o time.o irq.o ia64_ksyms.o process.o smp.o \
xenmisc.o pdb-stub.o acpi.o hypercall.o \
- machvec.o dom0_ops.o domain.o \
+ machvec.o dom0_ops.o domain.o hpsimserial.o pcdp.o \
idle0_task.o pal.o hpsim.o efi.o efi_stub.o ivt.o mm_contig.o \
xenmem.o sal.o cmdline.o mm_init.o tlb.o smpboot.o \
extable.o linuxextable.o xenirq.o xentime.o \
diff --git a/xen/arch/ia64/asm-offsets.c b/xen/arch/ia64/asm-offsets.c
index 0fd0757853..56847d15dc 100644
--- a/xen/arch/ia64/asm-offsets.c
+++ b/xen/arch/ia64/asm-offsets.c
@@ -11,6 +11,7 @@
#include <public/xen.h>
#ifdef CONFIG_VTI
#include <asm/tlb.h>
+#include <asm/regs.h>
#endif // CONFIG_VTI
#define task_struct vcpu
diff --git a/xen/arch/ia64/dom0_ops.c b/xen/arch/ia64/dom0_ops.c
index daaa87445c..e0b48080bc 100644
--- a/xen/arch/ia64/dom0_ops.c
+++ b/xen/arch/ia64/dom0_ops.c
@@ -13,12 +13,9 @@
#include <public/dom0_ops.h>
#include <xen/sched.h>
#include <xen/event.h>
-#include <asm/domain_page.h>
-//#include <asm/msr.h>
#include <asm/pdb.h>
#include <xen/trace.h>
#include <xen/console.h>
-//#include <xen/shadow.h>
#include <public/sched_ctl.h>
#define TRC_DOM0OP_ENTER_BASE 0x00020000
diff --git a/xen/arch/ia64/domain.c b/xen/arch/ia64/domain.c
index 144a4f149b..bcaabbb023 100644
--- a/xen/arch/ia64/domain.c
+++ b/xen/arch/ia64/domain.c
@@ -823,14 +823,14 @@ int construct_dom0(struct domain *d,
/* Temp workaround */
if (running_on_sim)
- dsi.xen_elf_image = 1;
+ dsi.xen_section_string = (char *)1;
- if ((!vmx_enabled) && !dsi.xen_elf_image) {
+ if ((!vmx_enabled) && !dsi.xen_section_string) {
printk("Lack of hardware support for unmodified vmx dom0\n");
panic("");
}
- if (vmx_enabled && !dsi.xen_elf_image) {
+ if (vmx_enabled && !dsi.xen_section_string) {
printk("Dom0 is vmx domain!\n");
vmx_dom0 = 1;
}
diff --git a/xen/arch/ia64/hpsimserial.c b/xen/arch/ia64/hpsimserial.c
new file mode 100644
index 0000000000..3e87aa3332
--- /dev/null
+++ b/xen/arch/ia64/hpsimserial.c
@@ -0,0 +1,23 @@
+/*
+ * HP Ski simulator serial I/O
+ *
+ * Copyright (C) 2004 Hewlett-Packard Co
+ * Dan Magenheimer <dan.magenheimer@hp.com>
+ */
+
+#include <linux/config.h>
+#include <xen/sched.h>
+#include <xen/serial.h>
+#include <asm/hpsim_ssc.h>
+
+static void hp_ski_putc(struct serial_port *port, char c)
+{
+ ia64_ssc(c,0,0,0,SSC_PUTCHAR);
+}
+
+static struct uart_driver hp_ski = { .putc = hp_ski_putc };
+
+void hpsim_serial_init(void)
+{
+ serial_register_uart(0, &hp_ski, 0);
+}
diff --git a/xen/arch/ia64/irq.c b/xen/arch/ia64/irq.c
index 5d4fda28a4..473e0afdae 100644
--- a/xen/arch/ia64/irq.c
+++ b/xen/arch/ia64/irq.c
@@ -1471,28 +1471,6 @@ int pirq_guest_unbind(struct domain *d, int irq)
return 0;
}
-int pirq_guest_bindable(int irq, int will_share)
-{
- irq_desc_t *desc = &irq_desc[irq];
- irq_guest_action_t *action;
- unsigned long flags;
- int okay;
-
- spin_lock_irqsave(&desc->lock, flags);
-
- action = (irq_guest_action_t *)desc->action;
-
- /*
- * To be bindable the IRQ must either be not currently bound (1), or
- * it must be shareable (2) and not at its share limit (3).
- */
- okay = ((!(desc->status & IRQ_GUEST) && (action == NULL)) || /* 1 */
- (action->shareable && will_share && /* 2 */
- (action->nr_guests != IRQ_MAX_GUESTS))); /* 3 */
-
- spin_unlock_irqrestore(&desc->lock, flags);
- return okay;
-}
#endif
#ifdef XEN
diff --git a/xen/arch/ia64/patch/linux-2.6.11/setup.c b/xen/arch/ia64/patch/linux-2.6.11/setup.c
index e7bc927d7d..2fea5662fd 100644
--- a/xen/arch/ia64/patch/linux-2.6.11/setup.c
+++ b/xen/arch/ia64/patch/linux-2.6.11/setup.c
@@ -1,5 +1,5 @@
---- /home/adsharma/disk2/xen-ia64/xeno-unstable-rebase.bk/xen/../../linux-2.6.11/arch/ia64/kernel/setup.c 2005-03-01 23:37:49.000000000 -0800
-+++ /home/adsharma/disk2/xen-ia64/xeno-unstable-rebase.bk/xen/arch/ia64/setup.c 2005-05-18 12:40:50.000000000 -0700
+--- ../../linux-2.6.11/arch/ia64/kernel/setup.c 2005-03-02 00:37:49.000000000 -0700
++++ arch/ia64/setup.c 2005-06-03 10:14:24.000000000 -0600
@@ -51,6 +51,10 @@
#include <asm/smp.h>
#include <asm/system.h>
@@ -11,7 +11,7 @@
#if defined(CONFIG_SMP) && (IA64_CPU_SIZE > PAGE_SIZE)
# error "struct cpuinfo_ia64 too big!"
-@@ -127,7 +130,16 @@
+@@ -127,7 +131,16 @@
range_end = min(end, rsvd_region[i].start);
if (range_start < range_end)
@@ -28,7 +28,7 @@
/* nothing more available in this segment */
if (range_end == end) return 0;
-@@ -185,7 +197,12 @@
+@@ -185,7 +198,12 @@
n++;
rsvd_region[n].start = (unsigned long) ia64_imva((void *)KERNEL_START);
@@ -41,7 +41,7 @@
n++;
#ifdef CONFIG_BLK_DEV_INITRD
-@@ -299,7 +316,11 @@
+@@ -299,17 +317,25 @@
}
void __init
@@ -53,22 +53,33 @@
{
unw_init();
-@@ -308,8 +329,14 @@
+ ia64_patch_vtop((u64) __start___vtop_patchlist, (u64) __end___vtop_patchlist);
+
*cmdline_p = __va(ia64_boot_param->command_line);
++#ifdef XEN
++ efi_init();
++#else
strlcpy(saved_command_line, *cmdline_p, COMMAND_LINE_SIZE);
-+#ifdef XEN
-+ cmdline_parse(*cmdline_p);
-+#undef CONFIG_ACPI_BOOT
-+#endif
efi_init();
-+#ifndef XEN
io_port_init();
+#endif
#ifdef CONFIG_IA64_GENERIC
{
-@@ -351,8 +378,18 @@
+@@ -336,6 +362,11 @@
+ }
+ #endif
+
++#ifdef XEN
++ early_cmdline_parse(cmdline_p);
++ cmdline_parse(*cmdline_p);
++#undef CONFIG_ACPI_BOOT
++#endif
+ if (early_console_setup(*cmdline_p) == 0)
+ mark_bsp_online();
+
+@@ -351,8 +382,18 @@
# endif
#endif /* CONFIG_APCI_BOOT */
@@ -87,7 +98,7 @@
/* process SAL system table: */
ia64_sal_init(efi.sal_systab);
-@@ -360,6 +397,10 @@
+@@ -360,6 +401,10 @@
cpu_physical_id(0) = hard_smp_processor_id();
#endif
@@ -98,7 +109,7 @@
cpu_init(); /* initialize the bootstrap CPU */
#ifdef CONFIG_ACPI_BOOT
-@@ -492,12 +533,14 @@
+@@ -492,12 +537,14 @@
{
}
@@ -113,7 +124,7 @@
void
identify_cpu (struct cpuinfo_ia64 *c)
-@@ -551,6 +594,12 @@
+@@ -551,6 +598,12 @@
}
c->unimpl_va_mask = ~((7L<<61) | ((1L << (impl_va_msb + 1)) - 1));
c->unimpl_pa_mask = ~((1L<<63) | ((1L << phys_addr_size) - 1));
@@ -126,7 +137,7 @@
}
void
-@@ -659,7 +708,11 @@
+@@ -659,7 +712,11 @@
| IA64_DCR_DA | IA64_DCR_DD | IA64_DCR_LC));
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
diff --git a/xen/arch/ia64/pcdp.c b/xen/arch/ia64/pcdp.c
new file mode 100644
index 0000000000..e2ab84a8c7
--- /dev/null
+++ b/xen/arch/ia64/pcdp.c
@@ -0,0 +1,120 @@
+/*
+ * Parse the EFI PCDP table to locate the console device.
+ *
+ * (c) Copyright 2002, 2003, 2004 Hewlett-Packard Development Company, L.P.
+ * Khalid Aziz <khalid.aziz@hp.com>
+ * Alex Williamson <alex.williamson@hp.com>
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/console.h>
+#include <linux/efi.h>
+#include <linux/serial.h>
+#ifdef XEN
+#include <linux/errno.h>
+#endif
+#include "pcdp.h"
+
+static int __init
+setup_serial_console(struct pcdp_uart *uart)
+{
+#ifdef XEN
+ extern char opt_com1[1];
+ if (opt_com1[0]) return 0;
+ sprintf(&opt_com1[0], "0x%lx,%lu,%dn1",
+ uart->addr.address, uart->baud,
+ uart->bits ? uart->bits : 8);
+ return 0;
+#else
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+ int mmio;
+ static char options[64];
+
+ mmio = (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
+ snprintf(options, sizeof(options), "console=uart,%s,0x%lx,%lun%d",
+ mmio ? "mmio" : "io", uart->addr.address, uart->baud,
+ uart->bits ? uart->bits : 8);
+
+ return early_serial_console_init(options);
+#else
+ return -ENODEV;
+#endif
+#endif
+}
+
+#ifndef XEN
+static int __init
+setup_vga_console(struct pcdp_vga *vga)
+{
+#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
+ if (efi_mem_type(0xA0000) == EFI_CONVENTIONAL_MEMORY) {
+ printk(KERN_ERR "PCDP: VGA selected, but frame buffer is not MMIO!\n");
+ return -ENODEV;
+ }
+
+ conswitchp = &vga_con;
+ printk(KERN_INFO "PCDP: VGA console\n");
+ return 0;
+#else
+ return -ENODEV;
+#endif
+}
+#endif
+
+int __init
+efi_setup_pcdp_console(char *cmdline)
+{
+ struct pcdp *pcdp;
+ struct pcdp_uart *uart;
+ struct pcdp_device *dev, *end;
+ int i, serial = 0;
+
+ pcdp = efi.hcdp;
+ if (!pcdp)
+ return -ENODEV;
+
+#ifndef XEN
+ printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, __pa(pcdp));
+#endif
+
+ if (strstr(cmdline, "console=hcdp")) {
+ if (pcdp->rev < 3)
+ serial = 1;
+ } else if (strstr(cmdline, "console=")) {
+#ifndef XEN
+ printk(KERN_INFO "Explicit \"console=\"; ignoring PCDP\n");
+#endif
+ return -ENODEV;
+ }
+
+ if (pcdp->rev < 3 && efi_uart_console_only())
+ serial = 1;
+
+ for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) {
+ if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) {
+ if (uart->type == PCDP_CONSOLE_UART) {
+ return setup_serial_console(uart);
+ }
+ }
+ }
+
+#ifndef XEN
+ end = (struct pcdp_device *) ((u8 *) pcdp + pcdp->length);
+ for (dev = (struct pcdp_device *) (pcdp->uart + pcdp->num_uarts);
+ dev < end;
+ dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) {
+ if (dev->flags & PCDP_PRIMARY_CONSOLE) {
+ if (dev->type == PCDP_CONSOLE_VGA) {
+ return setup_vga_console((struct pcdp_vga *) dev);
+ }
+ }
+ }
+#endif
+
+ return -ENODEV;
+}
diff --git a/xen/arch/ia64/pdb-stub.c b/xen/arch/ia64/pdb-stub.c
index 8c1ea5d06b..49c8131312 100644
--- a/xen/arch/ia64/pdb-stub.c
+++ b/xen/arch/ia64/pdb-stub.c
@@ -14,8 +14,6 @@
#include <xen/sched.h>
#include <asm/ptrace.h>
#include <xen/keyhandler.h>
-//#include <asm/apic.h>
-#include <asm/domain_page.h> /* [un]map_domain_mem */
#include <asm/processor.h>
#include <asm/pdb.h>
#include <xen/list.h>
diff --git a/xen/arch/ia64/tools/mkbuildtree b/xen/arch/ia64/tools/mkbuildtree
index c88b9841b9..e1d373f545 100644
--- a/xen/arch/ia64/tools/mkbuildtree
+++ b/xen/arch/ia64/tools/mkbuildtree
@@ -309,6 +309,8 @@ softlink include/linux/topology.h include/asm-ia64/linux/topology.h
softlink include/linux/seqlock.h include/asm-ia64/linux/seqlock.h
softlink include/linux/jiffies.h include/asm-ia64/linux/jiffies.h
+softlink drivers/firmware/pcdp.h arch/ia64/pcdp.h
+
null include/asm-ia64/linux/file.h
null include/asm-ia64/linux/module.h
null include/asm-ia64/linux/swap.h
diff --git a/xen/arch/ia64/vmmu.c b/xen/arch/ia64/vmmu.c
index 69f8cc7279..c39d6f2851 100644
--- a/xen/arch/ia64/vmmu.c
+++ b/xen/arch/ia64/vmmu.c
@@ -20,6 +20,7 @@
* Yaozu Dong (Eddie Dong) (Eddie.dong@intel.com)
*/
#include <linux/sched.h>
+#include <linux/mm.h>
#include <asm/tlb.h>
#include <asm/gcc_intrin.h>
#include <asm/vcpu.h>
diff --git a/xen/arch/ia64/xensetup.c b/xen/arch/ia64/xensetup.c
index cb65ff67a2..e669ae51e7 100644
--- a/xen/arch/ia64/xensetup.c
+++ b/xen/arch/ia64/xensetup.c
@@ -19,6 +19,7 @@
#include <asm/meminit.h>
#include <asm/page.h>
#include <asm/setup.h>
+#include <xen/string.h>
unsigned long xenheap_phys_end;
@@ -35,39 +36,14 @@ extern unsigned long domain0_ready;
int find_max_pfn (unsigned long, unsigned long, void *);
void start_of_day(void);
-/* opt_console: comma-separated list of console outputs. */
-#ifdef IA64
-unsigned char opt_console[30] = "com1";
-#else
-unsigned char opt_console[30] = "com1,vga";
-#endif
-/* opt_conswitch: a character pair controlling console switching. */
-/* Char 1: CTRL+<char1> is used to switch console input between Xen and DOM0 */
-/* Char 2: If this character is 'x', then do not auto-switch to DOM0 when it */
-/* boots. Any other value, or omitting the char, enables auto-switch */
-unsigned char opt_conswitch[5] = "a"; /* NB. '`' would disable switching. */
-/* opt_com[12]: Config serial port with a string <baud>,DPS,<io-base>,<irq>. */
-unsigned char opt_com1[30] = "", opt_com2[30] = "";
-/* opt_dom0_mem: Kilobytes of memory allocated to domain 0. */
-unsigned int opt_dom0_mem = 16000;
-/* opt_noht: If true, Hyperthreading is ignored. */
-int opt_noht=0;
/* opt_nosmp: If true, secondary processors are ignored. */
-int opt_nosmp=0;
-/* opt_noreboot: If true, machine will need manual reset on error. */
-int opt_noreboot=0;
-/* opt_watchdog: If true, run a watchdog NMI on each processor. */
-int opt_watchdog=0;
-/* opt_pdb: Name of serial port for Xen pervasive debugger (and enable pdb) */
-unsigned char opt_pdb[10] = "none";
-/* opt_tbuf_size: trace buffer size (in pages) */
-unsigned int opt_tbuf_size = 10;
-/* opt_sched: scheduler - default to Borrowed Virtual Time */
-char opt_sched[10] = "bvt";
-/* opt_leveltrigger, opt_edgetrigger: Force an IO-APIC-routed IRQ to be */
-/* level- or edge-triggered. */
-/* Example: 'leveltrigger=4,5,6,20 edgetrigger=21'. */
-char opt_leveltrigger[30] = "", opt_edgetrigger[30] = "";
+static int opt_nosmp = 0;
+boolean_param("nosmp", opt_nosmp);
+
+/* maxcpus: maximum number of CPUs to activate. */
+static unsigned int max_cpus = NR_CPUS;
+integer_param("maxcpus", max_cpus);
+
/*
* opt_xenheap_megabytes: Size of Xen heap in megabytes, including:
* xen image
@@ -80,23 +56,6 @@ char opt_leveltrigger[30] = "", opt_edgetrigger[30] = "";
*/
unsigned int opt_xenheap_megabytes = XENHEAP_DEFAULT_MB;
unsigned long xenheap_size = XENHEAP_DEFAULT_SIZE;
-/*
- * opt_nmi: one of 'ignore', 'dom0', or 'fatal'.
- * fatal: Xen prints diagnostic message and then hangs.
- * dom0: The NMI is virtualised to DOM0.
- * ignore: The NMI error is cleared and ignored.
- */
-#ifdef NDEBUG
-char opt_nmi[10] = "dom0";
-#else
-char opt_nmi[10] = "fatal";
-#endif
-/*
- * Comma-separated list of hexadecimal page numbers containing bad bytes.
- * e.g. 'badpage=0x3f45,0x8a321'.
- */
-char opt_badpage[100] = "";
-
extern long running_on_sim;
unsigned long xen_pstart;
@@ -133,6 +92,45 @@ static void __init do_initcalls(void)
(*call)();
}
+/*
+ * IPF loader only supports one commaind line currently, for
+ * both xen and guest kernel. This function provides pre-parse
+ * to mixed command line, to split it into two parts.
+ *
+ * User should split the parameters by "--", with strings after
+ * spliter for guest kernel. Missing "--" means whole line belongs
+ * to guest. Example:
+ * "com2=57600,8n1 console=com2 -- console=ttyS1 console=tty
+ * root=/dev/sda3 ro"
+ */
+static char null[4] = { 0 };
+
+void early_cmdline_parse(char **cmdline_p)
+{
+ char *guest_cmd;
+ char *split = "--";
+
+ if (*cmdline_p == NULL) {
+ *cmdline_p = &null[0];
+ saved_command_line[0] = '\0';
+ return;
+ }
+
+ guest_cmd = strstr(*cmdline_p, split);
+ /* If no spliter, whole line is for guest */
+ if (guest_cmd == NULL) {
+ guest_cmd = *cmdline_p;
+ *cmdline_p = &null[0];
+ } else {
+ *guest_cmd = '\0'; /* Split boot parameters for xen and guest */
+ guest_cmd += strlen(split);
+ while (*guest_cmd == ' ') guest_cmd++;
+ }
+
+ strlcpy(saved_command_line, guest_cmd, COMMAND_LINE_SIZE);
+ return;
+}
+
void start_kernel(void)
{
unsigned char *cmdline;
@@ -154,7 +152,8 @@ void start_kernel(void)
early_setup_arch(&cmdline);
/* We initialise the serial devices very early so we can get debugging. */
- ns16550_init();
+ if (running_on_sim) hpsim_serial_init();
+ else ns16550_init();
serial_init_preirq();
init_console();
diff --git a/xen/arch/x86/acpi/boot.c b/xen/arch/x86/acpi/boot.c
index 5b25f53cd5..c209012950 100644
--- a/xen/arch/x86/acpi/boot.c
+++ b/xen/arch/x86/acpi/boot.c
@@ -88,22 +88,6 @@ EXPORT_SYMBOL(x86_acpiid_to_apicid);
*/
enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PIC;
-#if 0/*def CONFIG_X86_64*/
-
-/* rely on all ACPI tables being in the direct mapping */
-char *__acpi_map_table(unsigned long phys_addr, unsigned long size)
-{
- if (!phys_addr || !size)
- return NULL;
-
- if (phys_addr < (end_pfn_map << PAGE_SHIFT))
- return __va(phys_addr);
-
- return NULL;
-}
-
-#else
-
/*
* Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END,
* to map the target physical address. The problem is that set_fixmap()
@@ -143,7 +127,6 @@ char *__acpi_map_table(unsigned long phys, unsigned long size)
return ((char *) base + offset);
}
-#endif
#ifdef CONFIG_PCI_MMCONFIG
static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
@@ -289,42 +272,6 @@ acpi_parse_ioapic (
return 0;
}
-#ifdef CONFIG_ACPI_INTERPRETER
-/*
- * Parse Interrupt Source Override for the ACPI SCI
- */
-static void
-acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
-{
- if (trigger == 0) /* compatible SCI trigger is level */
- trigger = 3;
-
- if (polarity == 0) /* compatible SCI polarity is low */
- polarity = 3;
-
- /* Command-line over-ride via acpi_sci= */
- if (acpi_sci_flags.trigger)
- trigger = acpi_sci_flags.trigger;
-
- if (acpi_sci_flags.polarity)
- polarity = acpi_sci_flags.polarity;
-
- /*
- * mp_config_acpi_legacy_irqs() already setup IRQs < 16
- * If GSI is < 16, this will update its flags,
- * else it will create a new mp_irqs[] entry.
- */
- mp_override_legacy_irq(gsi, polarity, trigger, gsi);
-
- /*
- * stash over-ride to indicate we've been here
- * and for later update of acpi_fadt
- */
- acpi_sci_override_gsi = gsi;
- return;
-}
-#endif
-
static int __init
acpi_parse_int_src_ovr (
acpi_table_entry_header *header, const unsigned long end)
@@ -338,14 +285,6 @@ acpi_parse_int_src_ovr (
acpi_table_print_madt_entry(header);
-#ifdef CONFIG_ACPI_INTERPRETER
- if (intsrc->bus_irq == acpi_fadt.sci_int) {
- acpi_sci_ioapic_setup(intsrc->global_irq,
- intsrc->flags.polarity, intsrc->flags.trigger);
- return 0;
- }
-#endif
-
if (acpi_skip_timer_override &&
intsrc->bus_irq == 0 && intsrc->global_irq == 2) {
printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n");
@@ -382,122 +321,6 @@ acpi_parse_nmi_src (
#endif /* CONFIG_X86_IO_APIC */
-#ifdef CONFIG_ACPI_BUS
-
-/*
- * acpi_pic_sci_set_trigger()
- *
- * use ELCR to set PIC-mode trigger type for SCI
- *
- * If a PIC-mode SCI is not recognized or gives spurious IRQ7's
- * it may require Edge Trigger -- use "acpi_sci=edge"
- *
- * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers
- * for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge.
- * ECLR1 is IRQ's 0-7 (IRQ 0, 1, 2 must be 0)
- * ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0)
- */
-
-void __init
-acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
-{
- unsigned int mask = 1 << irq;
- unsigned int old, new;
-
- /* Real old ELCR mask */
- old = inb(0x4d0) | (inb(0x4d1) << 8);
-
- /*
- * If we use ACPI to set PCI irq's, then we should clear ELCR
- * since we will set it correctly as we enable the PCI irq
- * routing.
- */
- new = acpi_noirq ? old : 0;
-
- /*
- * Update SCI information in the ELCR, it isn't in the PCI
- * routing tables..
- */
- switch (trigger) {
- case 1: /* Edge - clear */
- new &= ~mask;
- break;
- case 3: /* Level - set */
- new |= mask;
- break;
- }
-
- if (old == new)
- return;
-
- printk(PREFIX "setting ELCR to %04x (from %04x)\n", new, old);
- outb(new, 0x4d0);
- outb(new >> 8, 0x4d1);
-}
-
-
-#endif /* CONFIG_ACPI_BUS */
-
-int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
-{
-#ifdef CONFIG_X86_IO_APIC
- if (use_pci_vector() && !platform_legacy_irq(gsi))
- *irq = IO_APIC_VECTOR(gsi);
- else
-#endif
- *irq = gsi;
- return 0;
-}
-
-unsigned int acpi_register_gsi(u32 gsi, int edge_level, int active_high_low)
-{
- unsigned int irq;
- unsigned int plat_gsi = gsi;
-
-#ifdef CONFIG_PCI
- /*
- * Make sure all (legacy) PCI IRQs are set as level-triggered.
- */
- if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) {
- extern void eisa_set_level_irq(unsigned int irq);
-
- if (edge_level == ACPI_LEVEL_SENSITIVE)
- eisa_set_level_irq(gsi);
- }
-#endif
-
-#ifdef CONFIG_X86_IO_APIC
- if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) {
- plat_gsi = mp_register_gsi(gsi, edge_level, active_high_low);
- }
-#endif
- acpi_gsi_to_irq(plat_gsi, &irq);
- return irq;
-}
-EXPORT_SYMBOL(acpi_register_gsi);
-
-/*
- * ACPI based hotplug support for CPU
- */
-#ifdef CONFIG_ACPI_HOTPLUG_CPU
-int
-acpi_map_lsapic(acpi_handle handle, int *pcpu)
-{
- /* TBD */
- return -EINVAL;
-}
-EXPORT_SYMBOL(acpi_map_lsapic);
-
-
-int
-acpi_unmap_lsapic(int cpu)
-{
- /* TBD */
- return -EINVAL;
-}
-EXPORT_SYMBOL(acpi_unmap_lsapic);
-#endif /* CONFIG_ACPI_HOTPLUG_CPU */
-
static unsigned long __init
acpi_scan_rsdp (
unsigned long start,
diff --git a/xen/arch/x86/audit.c b/xen/arch/x86/audit.c
index ef58f52eff..dc2a14979a 100644
--- a/xen/arch/x86/audit.c
+++ b/xen/arch/x86/audit.c
@@ -122,7 +122,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy)
void adjust_l2_page(unsigned long mfn, int shadow)
{
- unsigned long *pt = map_domain_mem(mfn << PAGE_SHIFT);
+ unsigned long *pt = map_domain_page(mfn);
int i;
for ( i = 0; i < l2limit; i++ )
@@ -205,12 +205,12 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy)
adjust(hl2page, 0);
}
- unmap_domain_mem(pt);
+ unmap_domain_page(pt);
}
void adjust_hl2_page(unsigned long hl2mfn)
{
- unsigned long *pt = map_domain_mem(hl2mfn << PAGE_SHIFT);
+ unsigned long *pt = map_domain_page(hl2mfn);
int i;
for ( i = 0; i < l2limit; i++ )
@@ -251,12 +251,12 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy)
}
}
- unmap_domain_mem(pt);
+ unmap_domain_page(pt);
}
void adjust_l1_page(unsigned long l1mfn)
{
- unsigned long *pt = map_domain_mem(l1mfn << PAGE_SHIFT);
+ unsigned long *pt = map_domain_page(l1mfn);
int i;
for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
@@ -323,7 +323,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy)
}
}
- unmap_domain_mem(pt);
+ unmap_domain_page(pt);
}
void adjust_shadow_tables()
@@ -615,7 +615,7 @@ void _audit_domain(struct domain *d, int flags)
unsigned long mfn)
{
struct pfn_info *page = &frame_table[mfn];
- unsigned long *pt = map_domain_mem(mfn<<PAGE_SHIFT);
+ unsigned long *pt = map_domain_page(mfn);
int i;
for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
@@ -627,7 +627,7 @@ void _audit_domain(struct domain *d, int flags)
page->count_info, i, pt[i]);
}
- unmap_domain_mem(pt);
+ unmap_domain_page(pt);
}
void scan_for_pfn_in_grant_table(struct domain *d, unsigned xmfn)
diff --git a/xen/arch/x86/cdb.c b/xen/arch/x86/cdb.c
index ff9b6af076..1c95245e22 100644
--- a/xen/arch/x86/cdb.c
+++ b/xen/arch/x86/cdb.c
@@ -358,6 +358,7 @@ __trap_to_cdb(struct cpu_user_regs *regs)
local_irq_save(flags);
watchdog_disable();
+ console_start_sync();
/* Shouldn't really do this, but otherwise we stop for no
obvious reason, which is Bad */
@@ -383,9 +384,13 @@ __trap_to_cdb(struct cpu_user_regs *regs)
ASSERT(!local_irq_is_enabled());
}
}
+
+ console_end_sync();
watchdog_enable();
atomic_inc(&xendbg_running);
+
local_irq_restore(flags);
+
return 0;
}
diff --git a/xen/arch/x86/dom0_ops.c b/xen/arch/x86/dom0_ops.c
index a26e41abfe..dbb723090d 100644
--- a/xen/arch/x86/dom0_ops.c
+++ b/xen/arch/x86/dom0_ops.c
@@ -13,7 +13,7 @@
#include <public/dom0_ops.h>
#include <xen/sched.h>
#include <xen/event.h>
-#include <asm/domain_page.h>
+#include <xen/domain_page.h>
#include <asm/msr.h>
#include <xen/trace.h>
#include <xen/console.h>
@@ -155,7 +155,10 @@ long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op)
{
if ( (d->arch.iobmp_mask = xmalloc_array(
u8, IOBMP_BYTES)) == NULL )
+ {
+ put_domain(d);
break;
+ }
memset(d->arch.iobmp_mask, 0xFF, IOBMP_BYTES);
}
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 66732d8995..ae4099a008 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -123,6 +123,9 @@ void machine_restart(char * __unused)
safe_halt();
}
+ watchdog_disable();
+ console_start_sync();
+
local_irq_enable();
/* Ensure we are the boot CPU. */
@@ -174,6 +177,7 @@ void __attribute__((noreturn)) __machine_halt(void *unused)
void machine_halt(void)
{
watchdog_disable();
+ console_start_sync();
smp_call_function(__machine_halt, NULL, 1, 0);
__machine_halt(NULL);
}
diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c
index b4012c1660..78dea289e6 100644
--- a/xen/arch/x86/domain_build.c
+++ b/xen/arch/x86/domain_build.c
@@ -74,8 +74,7 @@ int construct_dom0(struct domain *d,
unsigned long _initrd_start, unsigned long initrd_len,
char *cmdline)
{
- char *dst;
- int i, rc;
+ int i, rc, dom0_pae, xen_pae;
unsigned long pfn, mfn;
unsigned long nr_pages;
unsigned long nr_pt_pages;
@@ -123,7 +122,8 @@ int construct_dom0(struct domain *d,
unsigned long mpt_alloc;
extern void physdev_init_dom0(struct domain *);
- extern void translate_l2pgtable(struct domain *d, l1_pgentry_t *p2m, unsigned long l2mfn);
+ extern void translate_l2pgtable(
+ struct domain *d, l1_pgentry_t *p2m, unsigned long l2mfn);
/* Sanity! */
if ( d->domain_id != 0 )
@@ -151,6 +151,21 @@ int construct_dom0(struct domain *d,
if ( (rc = parseelfimage(&dsi)) != 0 )
return rc;
+ if ( dsi.xen_section_string == NULL )
+ {
+ printk("Not a Xen-ELF image: '__xen_guest' section not found.\n");
+ return -EINVAL;
+ }
+
+ dom0_pae = !!strstr(dsi.xen_section_string, "PAE=yes");
+ xen_pae = (CONFIG_PAGING_LEVELS == 3);
+ if ( dom0_pae != xen_pae )
+ {
+ printk("PAE mode mismatch between Xen and DOM0 (xen=%s, dom0=%s)\n",
+ xen_pae ? "yes" : "no", dom0_pae ? "yes" : "no");
+ return -EINVAL;
+ }
+
/* Align load address to 4MB boundary. */
dsi.v_start &= ~((1UL<<22)-1);
@@ -580,17 +595,9 @@ int construct_dom0(struct domain *d,
si->mod_len, si->mod_start);
}
- dst = (char *)si->cmd_line;
+ memset(si->cmd_line, 0, sizeof(si->cmd_line));
if ( cmdline != NULL )
- {
- for ( i = 0; i < 255; i++ )
- {
- if ( cmdline[i] == '\0' )
- break;
- *dst++ = cmdline[i];
- }
- }
- *dst = '\0';
+ strncpy((char *)si->cmd_line, cmdline, sizeof(si->cmd_line)-1);
/* Reinstate the caller's page tables. */
write_ptbase(current);
diff --git a/xen/arch/x86/extable.c b/xen/arch/x86/extable.c
index 13a46f69b3..3d7fe36151 100644
--- a/xen/arch/x86/extable.c
+++ b/xen/arch/x86/extable.c
@@ -6,6 +6,7 @@
#ifdef PERF_COUNTERS
#include <xen/sched.h>
#include <xen/perfc.h>
+#include <asm/current.h>
#endif
extern struct exception_table_entry __start___ex_table[];
diff --git a/xen/arch/x86/i8259.c b/xen/arch/x86/i8259.c
index 91bc24f5d9..17128adc35 100644
--- a/xen/arch/x86/i8259.c
+++ b/xen/arch/x86/i8259.c
@@ -35,36 +35,18 @@
BUILD_COMMON_IRQ()
#define BI(x,y) \
- BUILD_IRQ(x##y)
+ BUILD_IRQ(x##y)
#define BUILD_16_IRQS(x) \
- BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
- BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
- BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
- BI(x,c) BI(x,d) BI(x,e) BI(x,f)
+ BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
+ BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
+ BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
+ BI(x,c) BI(x,d) BI(x,e) BI(x,f)
-/*
- * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
- * (these are usually mapped to vectors 0x20-0x2f)
- */
-BUILD_16_IRQS(0x0)
-
-#ifdef CONFIG_X86_IO_APIC
-/*
- * The IO-APIC gives us many more interrupt sources. Most of these
- * are unused but an SMP system is supposed to have enough memory ...
- * sometimes (mostly wrt. hw bugs) we get corrupted vectors all
- * across the spectrum, so we really want to be prepared to get all
- * of these. Plus, more powerful systems might have more than 64
- * IO-APIC registers.
- *
- * (these are usually mapped into the 0x20-0xff vector range)
- */
-BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
+BUILD_16_IRQS(0x0) BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
-BUILD_16_IRQS(0xc)
-#endif
+BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf)
#undef BUILD_16_IRQS
#undef BI
@@ -75,11 +57,9 @@ BUILD_16_IRQS(0xc)
* is no hardware IRQ pin equivalent for them, they are triggered
* through the ICC by us (IPIs)
*/
-#ifdef CONFIG_SMP
BUILD_SMP_INTERRUPT(event_check_interrupt,EVENT_CHECK_VECTOR)
BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR)
BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
-#endif
/*
* Every pentium local APIC has two 'local interrupts', with a
@@ -93,23 +73,19 @@ BUILD_SMP_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR)
BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
#define IRQ(x,y) \
- IRQ##x##y##_interrupt
+ IRQ##x##y##_interrupt
#define IRQLIST_16(x) \
- IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
- IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
- IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
- IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
-
- void (*interrupt[NR_IRQS])(void) = {
- IRQLIST_16(0x0),
-
-#ifdef CONFIG_X86_IO_APIC
- IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3),
- IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
- IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
- IRQLIST_16(0xc)
-#endif
+ IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
+ IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
+ IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
+ IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
+
+ static void (*interrupt[])(void) = {
+ IRQLIST_16(0x0), IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3),
+ IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
+ IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
+ IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf)
};
#undef IRQ
@@ -126,31 +102,38 @@ BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED;
-static void end_8259A_irq (unsigned int irq)
+static void disable_8259A_vector(unsigned int vector)
+{
+ disable_8259A_irq(LEGACY_IRQ_FROM_VECTOR(vector));
+}
+
+static void enable_8259A_vector(unsigned int vector)
{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- enable_8259A_irq(irq);
+ enable_8259A_irq(LEGACY_IRQ_FROM_VECTOR(vector));
}
-#define shutdown_8259A_irq disable_8259A_irq
+static void mask_and_ack_8259A_vector(unsigned int);
-void mask_and_ack_8259A(unsigned int);
+static void end_8259A_vector(unsigned int vector)
+{
+ if (!(irq_desc[vector].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_8259A_vector(vector);
+}
-static unsigned int startup_8259A_irq(unsigned int irq)
+static unsigned int startup_8259A_vector(unsigned int vector)
{
- enable_8259A_irq(irq);
+ enable_8259A_vector(vector);
return 0; /* never anything pending */
}
static struct hw_interrupt_type i8259A_irq_type = {
- "XT-PIC",
- startup_8259A_irq,
- shutdown_8259A_irq,
- enable_8259A_irq,
- disable_8259A_irq,
- mask_and_ack_8259A,
- end_8259A_irq,
- NULL
+ .typename = "XT-PIC",
+ .startup = startup_8259A_vector,
+ .shutdown = disable_8259A_vector,
+ .enable = enable_8259A_vector,
+ .disable = disable_8259A_vector,
+ .ack = mask_and_ack_8259A_vector,
+ .end = end_8259A_vector
};
/*
@@ -162,9 +145,9 @@ static struct hw_interrupt_type i8259A_irq_type = {
*/
static unsigned int cached_irq_mask = 0xffff;
-#define __byte(x,y) (((unsigned char *)&(y))[x])
-#define cached_21 (__byte(0,cached_irq_mask))
-#define cached_A1 (__byte(1,cached_irq_mask))
+#define __byte(x,y) (((unsigned char *)&(y))[x])
+#define cached_21 (__byte(0,cached_irq_mask))
+#define cached_A1 (__byte(1,cached_irq_mask))
/*
* Not all IRQs can be routed through the IO-APIC, eg. on certain (older)
@@ -225,7 +208,6 @@ void make_8259A_irq(unsigned int irq)
{
disable_irq_nosync(irq);
io_apic_irqs &= ~(1<<irq);
- irq_desc[irq].handler = &i8259A_irq_type;
enable_irq(irq);
}
@@ -241,14 +223,14 @@ static inline int i8259A_irq_real(unsigned int irq)
int irqmask = 1<<irq;
if (irq < 8) {
- outb(0x0B,0x20); /* ISR register */
+ outb(0x0B,0x20); /* ISR register */
value = inb(0x20) & irqmask;
- outb(0x0A,0x20); /* back to the IRR register */
+ outb(0x0A,0x20); /* back to the IRR register */
return value;
}
- outb(0x0B,0xA0); /* ISR register */
+ outb(0x0B,0xA0); /* ISR register */
value = inb(0xA0) & (irqmask >> 8);
- outb(0x0A,0xA0); /* back to the IRR register */
+ outb(0x0A,0xA0); /* back to the IRR register */
return value;
}
@@ -258,8 +240,9 @@ static inline int i8259A_irq_real(unsigned int irq)
* first, _then_ send the EOI, and the order of EOI
* to the two 8259s is important!
*/
-void mask_and_ack_8259A(unsigned int irq)
+static void mask_and_ack_8259A_vector(unsigned int vector)
{
+ unsigned int irq = LEGACY_IRQ_FROM_VECTOR(vector);
unsigned int irqmask = 1 << irq;
unsigned long flags;
@@ -285,14 +268,14 @@ void mask_and_ack_8259A(unsigned int irq)
handle_real_irq:
if (irq & 8) {
- inb(0xA1); /* DUMMY - (do we need this?) */
+ inb(0xA1); /* DUMMY - (do we need this?) */
outb(cached_A1,0xA1);
outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */
- outb(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */
+ outb(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */
} else {
- inb(0x21); /* DUMMY - (do we need this?) */
+ inb(0x21); /* DUMMY - (do we need this?) */
outb(cached_21,0x21);
- outb(0x60+irq,0x20); /* 'Specific EOI' to master */
+ outb(0x60+irq,0x20); /* 'Specific EOI' to master */
}
spin_unlock_irqrestore(&i8259A_lock, flags);
return;
@@ -334,39 +317,39 @@ void __init init_8259A(int auto_eoi)
spin_lock_irqsave(&i8259A_lock, flags);
- outb(0xff, 0x21); /* mask all of 8259A-1 */
- outb(0xff, 0xA1); /* mask all of 8259A-2 */
+ outb(0xff, 0x21); /* mask all of 8259A-1 */
+ outb(0xff, 0xA1); /* mask all of 8259A-2 */
/*
* outb_p - this has to work on a wide range of PC hardware.
*/
- outb_p(0x11, 0x20); /* ICW1: select 8259A-1 init */
- outb_p(0x20 + 0, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */
- outb_p(0x04, 0x21); /* 8259A-1 (the master) has a slave on IR2 */
+ outb_p(0x11, 0x20); /* ICW1: select 8259A-1 init */
+ outb_p(0x20 + 0, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */
+ outb_p(0x04, 0x21); /* 8259A-1 (the master) has a slave on IR2 */
if (auto_eoi)
- outb_p(0x03, 0x21); /* master does Auto EOI */
+ outb_p(0x03, 0x21); /* master does Auto EOI */
else
- outb_p(0x01, 0x21); /* master expects normal EOI */
+ outb_p(0x01, 0x21); /* master expects normal EOI */
- outb_p(0x11, 0xA0); /* ICW1: select 8259A-2 init */
- outb_p(0x20 + 8, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */
- outb_p(0x02, 0xA1); /* 8259A-2 is a slave on master's IR2 */
- outb_p(0x01, 0xA1); /* (slave's support for AEOI in flat mode
- is to be investigated) */
+ outb_p(0x11, 0xA0); /* ICW1: select 8259A-2 init */
+ outb_p(0x20 + 8, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */
+ outb_p(0x02, 0xA1); /* 8259A-2 is a slave on master's IR2 */
+ outb_p(0x01, 0xA1); /* (slave's support for AEOI in flat mode
+ is to be investigated) */
if (auto_eoi)
/*
* in AEOI mode we just have to mask the interrupt
* when acking.
*/
- i8259A_irq_type.ack = disable_8259A_irq;
+ i8259A_irq_type.ack = disable_8259A_vector;
else
- i8259A_irq_type.ack = mask_and_ack_8259A;
+ i8259A_irq_type.ack = mask_and_ack_8259A_vector;
- udelay(100); /* wait for 8259A to initialize */
+ udelay(100); /* wait for 8259A to initialize */
- outb(cached_21, 0x21); /* restore master IRQ mask */
- outb(cached_A1, 0xA1); /* restore slave IRQ mask */
+ outb(cached_21, 0x21); /* restore master IRQ mask */
+ outb(cached_A1, 0xA1); /* restore slave IRQ mask */
spin_unlock_irqrestore(&i8259A_lock, flags);
}
@@ -384,11 +367,17 @@ void __init init_IRQ(void)
for ( i = 0; i < NR_IRQS; i++ )
{
irq_desc[i].status = IRQ_DISABLED;
- irq_desc[i].handler = (i<16) ? &i8259A_irq_type : &no_irq_type;
+ irq_desc[i].handler = &no_irq_type;
irq_desc[i].action = NULL;
irq_desc[i].depth = 1;
spin_lock_init(&irq_desc[i].lock);
- set_intr_gate(FIRST_EXTERNAL_VECTOR+i, interrupt[i]);
+ set_intr_gate(i, interrupt[i]);
+ }
+
+ for ( i = 0; i < 16; i++ )
+ {
+ vector_irq[LEGACY_VECTOR(i)] = i;
+ irq_desc[LEGACY_VECTOR(i)].handler = &i8259A_irq_type;
}
/*
@@ -397,7 +386,6 @@ void __init init_IRQ(void)
*/
irq_vector[0] = FIRST_DEVICE_VECTOR;
vector_irq[FIRST_DEVICE_VECTOR] = 0;
- set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
/* Various IPI functions. */
set_intr_gate(EVENT_CHECK_VECTOR, event_check_interrupt);
@@ -414,9 +402,9 @@ void __init init_IRQ(void)
/* Set the clock to HZ Hz */
#define CLOCK_TICK_RATE 1193180 /* crystal freq (Hz) */
#define LATCH (((CLOCK_TICK_RATE)+(HZ/2))/HZ)
- outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
- outb_p(LATCH & 0xff , 0x40); /* LSB */
- outb(LATCH >> 8 , 0x40); /* MSB */
+ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
+ outb_p(LATCH & 0xff , 0x40); /* LSB */
+ outb(LATCH >> 8 , 0x40); /* MSB */
setup_irq(2, &cascade);
}
diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c
index a0020c7ec2..f41de09f1a 100644
--- a/xen/arch/x86/io_apic.c
+++ b/xen/arch/x86/io_apic.c
@@ -61,16 +61,10 @@ int nr_ioapic_registers[MAX_IO_APICS];
*/
static struct irq_pin_list {
- int apic, pin, next;
+ int apic, pin, next;
} irq_2_pin[PIN_MAP_SIZE];
int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
-#ifdef CONFIG_PCI_MSI
-#define vector_to_irq(vector) \
- (platform_legacy_irq(vector) ? vector : vector_irq[vector])
-#else
-#define vector_to_irq(vector) (vector)
-#endif
/*
* The common case is 1:1 IRQ<->pin mappings. Sometimes there are
@@ -79,20 +73,20 @@ int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
*/
static void add_pin_to_irq(unsigned int irq, int apic, int pin)
{
- static int first_free_entry = NR_IRQS;
- struct irq_pin_list *entry = irq_2_pin + irq;
+ static int first_free_entry = NR_IRQS;
+ struct irq_pin_list *entry = irq_2_pin + irq;
- while (entry->next)
- entry = irq_2_pin + entry->next;
+ while (entry->next)
+ entry = irq_2_pin + entry->next;
- if (entry->pin != -1) {
- entry->next = first_free_entry;
- entry = irq_2_pin + entry->next;
- if (++first_free_entry >= PIN_MAP_SIZE)
- panic("io_apic.c: whoops");
- }
- entry->apic = apic;
- entry->pin = pin;
+ if (entry->pin != -1) {
+ entry->next = first_free_entry;
+ entry = irq_2_pin + entry->next;
+ if (++first_free_entry >= PIN_MAP_SIZE)
+ panic("io_apic.c: whoops");
+ }
+ entry->apic = apic;
+ entry->pin = pin;
}
/*
@@ -102,585 +96,151 @@ static void __init replace_pin_at_irq(unsigned int irq,
int oldapic, int oldpin,
int newapic, int newpin)
{
- struct irq_pin_list *entry = irq_2_pin + irq;
-
- while (1) {
- if (entry->apic == oldapic && entry->pin == oldpin) {
- entry->apic = newapic;
- entry->pin = newpin;
- }
- if (!entry->next)
- break;
- entry = irq_2_pin + entry->next;
- }
+ struct irq_pin_list *entry = irq_2_pin + irq;
+
+ while (1) {
+ if (entry->apic == oldapic && entry->pin == oldpin) {
+ entry->apic = newapic;
+ entry->pin = newpin;
+ }
+ if (!entry->next)
+ break;
+ entry = irq_2_pin + entry->next;
+ }
}
static void __modify_IO_APIC_irq (unsigned int irq, unsigned long enable, unsigned long disable)
{
- struct irq_pin_list *entry = irq_2_pin + irq;
- unsigned int pin, reg;
-
- for (;;) {
- pin = entry->pin;
- if (pin == -1)
- break;
- reg = io_apic_read(entry->apic, 0x10 + pin*2);
- reg &= ~disable;
- reg |= enable;
- io_apic_modify(entry->apic, 0x10 + pin*2, reg);
- if (!entry->next)
- break;
- entry = irq_2_pin + entry->next;
- }
+ struct irq_pin_list *entry = irq_2_pin + irq;
+ unsigned int pin, reg;
+
+ for (;;) {
+ pin = entry->pin;
+ if (pin == -1)
+ break;
+ reg = io_apic_read(entry->apic, 0x10 + pin*2);
+ reg &= ~disable;
+ reg |= enable;
+ io_apic_modify(entry->apic, 0x10 + pin*2, reg);
+ if (!entry->next)
+ break;
+ entry = irq_2_pin + entry->next;
+ }
}
/* mask = 1 */
static void __mask_IO_APIC_irq (unsigned int irq)
{
- __modify_IO_APIC_irq(irq, 0x00010000, 0);
+ __modify_IO_APIC_irq(irq, 0x00010000, 0);
}
/* mask = 0 */
static void __unmask_IO_APIC_irq (unsigned int irq)
{
- __modify_IO_APIC_irq(irq, 0, 0x00010000);
+ __modify_IO_APIC_irq(irq, 0, 0x00010000);
}
/* trigger = 0 */
static void __edge_IO_APIC_irq (unsigned int irq)
{
- __modify_IO_APIC_irq(irq, 0, 0x00008000);
+ __modify_IO_APIC_irq(irq, 0, 0x00008000);
}
/* trigger = 1 */
static void __level_IO_APIC_irq (unsigned int irq)
{
- __modify_IO_APIC_irq(irq, 0x00008000, 0);
+ __modify_IO_APIC_irq(irq, 0x00008000, 0);
}
static void mask_IO_APIC_irq (unsigned int irq)
{
- unsigned long flags;
+ unsigned long flags;
- spin_lock_irqsave(&ioapic_lock, flags);
- __mask_IO_APIC_irq(irq);
- spin_unlock_irqrestore(&ioapic_lock, flags);
+ spin_lock_irqsave(&ioapic_lock, flags);
+ __mask_IO_APIC_irq(irq);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
}
static void unmask_IO_APIC_irq (unsigned int irq)
{
- unsigned long flags;
+ unsigned long flags;
- spin_lock_irqsave(&ioapic_lock, flags);
- __unmask_IO_APIC_irq(irq);
- spin_unlock_irqrestore(&ioapic_lock, flags);
+ spin_lock_irqsave(&ioapic_lock, flags);
+ __unmask_IO_APIC_irq(irq);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
}
void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
{
- struct IO_APIC_route_entry entry;
- unsigned long flags;
+ struct IO_APIC_route_entry entry;
+ unsigned long flags;
- /* Check delivery_mode to be sure we're not clearing an SMI pin */
- spin_lock_irqsave(&ioapic_lock, flags);
- *(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
- *(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
- spin_unlock_irqrestore(&ioapic_lock, flags);
- if (entry.delivery_mode == dest_SMI)
- return;
-
- /*
- * Disable it in the IO-APIC irq-routing table:
- */
- memset(&entry, 0, sizeof(entry));
- entry.mask = 1;
- spin_lock_irqsave(&ioapic_lock, flags);
- io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
- io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
- spin_unlock_irqrestore(&ioapic_lock, flags);
+ /* Check delivery_mode to be sure we're not clearing an SMI pin */
+ spin_lock_irqsave(&ioapic_lock, flags);
+ *(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
+ *(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+ if (entry.delivery_mode == dest_SMI)
+ return;
+
+ /*
+ * Disable it in the IO-APIC irq-routing table:
+ */
+ memset(&entry, 0, sizeof(entry));
+ entry.mask = 1;
+ spin_lock_irqsave(&ioapic_lock, flags);
+ io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
+ io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
+ spin_unlock_irqrestore(&ioapic_lock, flags);
}
static void clear_IO_APIC (void)
{
- int apic, pin;
+ int apic, pin;
- for (apic = 0; apic < nr_ioapics; apic++)
- for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
- clear_IO_APIC_pin(apic, pin);
+ for (apic = 0; apic < nr_ioapics; apic++)
+ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
+ clear_IO_APIC_pin(apic, pin);
}
static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
{
- unsigned long flags;
- int pin;
- struct irq_pin_list *entry = irq_2_pin + irq;
- unsigned int apicid_value;
-
- apicid_value = cpu_mask_to_apicid(cpumask);
- /* Prepare to do the io_apic_write */
- apicid_value = apicid_value << 24;
- spin_lock_irqsave(&ioapic_lock, flags);
- for (;;) {
- pin = entry->pin;
- if (pin == -1)
- break;
- io_apic_write(entry->apic, 0x10 + 1 + pin*2, apicid_value);
- if (!entry->next)
- break;
- entry = irq_2_pin + entry->next;
- }
- spin_unlock_irqrestore(&ioapic_lock, flags);
-}
-
-#if defined(CONFIG_IRQBALANCE)
-# include <asm/processor.h> /* kernel_thread() */
-# include <xen/kernel_stat.h> /* kstat */
-# include <xen/xmalloc.h> /* kmalloc() */
-# include <xen/timer.h> /* time_after() */
-
-# ifdef CONFIG_BALANCED_IRQ_DEBUG
-# define TDprintk(x...) do { printk("<%ld:%s:%d>: ", jiffies, __FILE__, __LINE__); printk(x); } while (0)
-# define Dprintk(x...) do { TDprintk(x); } while (0)
-# else
-# define TDprintk(x...)
-# define Dprintk(x...)
-# endif
-
-cpumask_t __cacheline_aligned pending_irq_balance_cpumask[NR_IRQS];
-
-#define IRQBALANCE_CHECK_ARCH -999
-static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH;
-static int physical_balance = 0;
-
-struct irq_cpu_info {
- unsigned long * last_irq;
- unsigned long * irq_delta;
- unsigned long irq;
-} irq_cpu_data[NR_CPUS];
-
-#define CPU_IRQ(cpu) (irq_cpu_data[cpu].irq)
-#define LAST_CPU_IRQ(cpu,irq) (irq_cpu_data[cpu].last_irq[irq])
-#define IRQ_DELTA(cpu,irq) (irq_cpu_data[cpu].irq_delta[irq])
-
-#define IDLE_ENOUGH(cpu,now) \
- (idle_cpu(cpu) && ((now) - irq_stat[(cpu)].idle_timestamp > 1))
-
-#define IRQ_ALLOWED(cpu, allowed_mask) cpu_isset(cpu, allowed_mask)
-
-#define CPU_TO_PACKAGEINDEX(i) (first_cpu(cpu_sibling_map[i]))
-
-#define MAX_BALANCED_IRQ_INTERVAL (5*HZ)
-#define MIN_BALANCED_IRQ_INTERVAL (HZ/2)
-#define BALANCED_IRQ_MORE_DELTA (HZ/10)
-#define BALANCED_IRQ_LESS_DELTA (HZ)
-
-long balanced_irq_interval = MAX_BALANCED_IRQ_INTERVAL;
-
-static unsigned long move(int curr_cpu, cpumask_t allowed_mask,
- unsigned long now, int direction)
-{
- int search_idle = 1;
- int cpu = curr_cpu;
-
- goto inside;
-
- do {
- if (unlikely(cpu == curr_cpu))
- search_idle = 0;
-inside:
- if (direction == 1) {
- cpu++;
- if (cpu >= NR_CPUS)
- cpu = 0;
- } else {
- cpu--;
- if (cpu == -1)
- cpu = NR_CPUS-1;
- }
- } while (!cpu_online(cpu) || !IRQ_ALLOWED(cpu,allowed_mask) ||
- (search_idle && !IDLE_ENOUGH(cpu,now)));
-
- return cpu;
-}
-
-static inline void balance_irq(int cpu, int irq)
-{
- unsigned long now = jiffies;
- cpumask_t allowed_mask;
- unsigned int new_cpu;
-
- if (irqbalance_disabled)
- return;
-
- cpus_and(allowed_mask, cpu_online_map, irq_affinity[irq]);
- new_cpu = move(cpu, allowed_mask, now, 1);
- if (cpu != new_cpu) {
- irq_desc_t *desc = irq_desc + irq;
- unsigned long flags;
-
- spin_lock_irqsave(&desc->lock, flags);
- pending_irq_balance_cpumask[irq] = cpumask_of_cpu(new_cpu);
- spin_unlock_irqrestore(&desc->lock, flags);
- }
-}
-
-static inline void rotate_irqs_among_cpus(unsigned long useful_load_threshold)
-{
- int i, j;
- Dprintk("Rotating IRQs among CPUs.\n");
- for (i = 0; i < NR_CPUS; i++) {
- for (j = 0; cpu_online(i) && (j < NR_IRQS); j++) {
- if (!irq_desc[j].action)
- continue;
- /* Is it a significant load ? */
- if (IRQ_DELTA(CPU_TO_PACKAGEINDEX(i),j) <
- useful_load_threshold)
- continue;
- balance_irq(i, j);
- }
- }
- balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL,
- balanced_irq_interval - BALANCED_IRQ_LESS_DELTA);
- return;
-}
-
-static void do_irq_balance(void)
-{
- int i, j;
- unsigned long max_cpu_irq = 0, min_cpu_irq = (~0);
- unsigned long move_this_load = 0;
- int max_loaded = 0, min_loaded = 0;
- int load;
- unsigned long useful_load_threshold = balanced_irq_interval + 10;
- int selected_irq;
- int tmp_loaded, first_attempt = 1;
- unsigned long tmp_cpu_irq;
- unsigned long imbalance = 0;
- cpumask_t allowed_mask, target_cpu_mask, tmp;
-
- for (i = 0; i < NR_CPUS; i++) {
- int package_index;
- CPU_IRQ(i) = 0;
- if (!cpu_online(i))
- continue;
- package_index = CPU_TO_PACKAGEINDEX(i);
- for (j = 0; j < NR_IRQS; j++) {
- unsigned long value_now, delta;
- /* Is this an active IRQ? */
- if (!irq_desc[j].action)
- continue;
- if ( package_index == i )
- IRQ_DELTA(package_index,j) = 0;
- /* Determine the total count per processor per IRQ */
- value_now = (unsigned long) kstat_cpu(i).irqs[j];
-
- /* Determine the activity per processor per IRQ */
- delta = value_now - LAST_CPU_IRQ(i,j);
-
- /* Update last_cpu_irq[][] for the next time */
- LAST_CPU_IRQ(i,j) = value_now;
-
- /* Ignore IRQs whose rate is less than the clock */
- if (delta < useful_load_threshold)
- continue;
- /* update the load for the processor or package total */
- IRQ_DELTA(package_index,j) += delta;
-
- /* Keep track of the higher numbered sibling as well */
- if (i != package_index)
- CPU_IRQ(i) += delta;
- /*
- * We have sibling A and sibling B in the package
- *
- * cpu_irq[A] = load for cpu A + load for cpu B
- * cpu_irq[B] = load for cpu B
- */
- CPU_IRQ(package_index) += delta;
- }
- }
- /* Find the least loaded processor package */
- for (i = 0; i < NR_CPUS; i++) {
- if (!cpu_online(i))
- continue;
- if (i != CPU_TO_PACKAGEINDEX(i))
- continue;
- if (min_cpu_irq > CPU_IRQ(i)) {
- min_cpu_irq = CPU_IRQ(i);
- min_loaded = i;
- }
- }
- max_cpu_irq = ULONG_MAX;
-
-tryanothercpu:
- /* Look for heaviest loaded processor.
- * We may come back to get the next heaviest loaded processor.
- * Skip processors with trivial loads.
- */
- tmp_cpu_irq = 0;
- tmp_loaded = -1;
- for (i = 0; i < NR_CPUS; i++) {
- if (!cpu_online(i))
- continue;
- if (i != CPU_TO_PACKAGEINDEX(i))
- continue;
- if (max_cpu_irq <= CPU_IRQ(i))
- continue;
- if (tmp_cpu_irq < CPU_IRQ(i)) {
- tmp_cpu_irq = CPU_IRQ(i);
- tmp_loaded = i;
- }
- }
-
- if (tmp_loaded == -1) {
- /* In the case of small number of heavy interrupt sources,
- * loading some of the cpus too much. We use Ingo's original
- * approach to rotate them around.
- */
- if (!first_attempt && imbalance >= useful_load_threshold) {
- rotate_irqs_among_cpus(useful_load_threshold);
- return;
- }
- goto not_worth_the_effort;
- }
-
- first_attempt = 0; /* heaviest search */
- max_cpu_irq = tmp_cpu_irq; /* load */
- max_loaded = tmp_loaded; /* processor */
- imbalance = (max_cpu_irq - min_cpu_irq) / 2;
-
- Dprintk("max_loaded cpu = %d\n", max_loaded);
- Dprintk("min_loaded cpu = %d\n", min_loaded);
- Dprintk("max_cpu_irq load = %ld\n", max_cpu_irq);
- Dprintk("min_cpu_irq load = %ld\n", min_cpu_irq);
- Dprintk("load imbalance = %lu\n", imbalance);
-
- /* if imbalance is less than approx 10% of max load, then
- * observe diminishing returns action. - quit
- */
- if (imbalance < (max_cpu_irq >> 3)) {
- Dprintk("Imbalance too trivial\n");
- goto not_worth_the_effort;
- }
-
-tryanotherirq:
- /* if we select an IRQ to move that can't go where we want, then
- * see if there is another one to try.
- */
- move_this_load = 0;
- selected_irq = -1;
- for (j = 0; j < NR_IRQS; j++) {
- /* Is this an active IRQ? */
- if (!irq_desc[j].action)
- continue;
- if (imbalance <= IRQ_DELTA(max_loaded,j))
- continue;
- /* Try to find the IRQ that is closest to the imbalance
- * without going over.
- */
- if (move_this_load < IRQ_DELTA(max_loaded,j)) {
- move_this_load = IRQ_DELTA(max_loaded,j);
- selected_irq = j;
- }
- }
- if (selected_irq == -1) {
- goto tryanothercpu;
- }
-
- imbalance = move_this_load;
-
- /* For physical_balance case, we accumlated both load
- * values in the one of the siblings cpu_irq[],
- * to use the same code for physical and logical processors
- * as much as possible.
- *
- * NOTE: the cpu_irq[] array holds the sum of the load for
- * sibling A and sibling B in the slot for the lowest numbered
- * sibling (A), _AND_ the load for sibling B in the slot for
- * the higher numbered sibling.
- *
- * We seek the least loaded sibling by making the comparison
- * (A+B)/2 vs B
- */
- load = CPU_IRQ(min_loaded) >> 1;
- for_each_cpu_mask(j, cpu_sibling_map[min_loaded]) {
- if (load > CPU_IRQ(j)) {
- /* This won't change cpu_sibling_map[min_loaded] */
- load = CPU_IRQ(j);
- min_loaded = j;
- }
- }
-
- cpus_and(allowed_mask, cpu_online_map, irq_affinity[selected_irq]);
- target_cpu_mask = cpumask_of_cpu(min_loaded);
- cpus_and(tmp, target_cpu_mask, allowed_mask);
-
- if (!cpus_empty(tmp)) {
- irq_desc_t *desc = irq_desc + selected_irq;
- unsigned long flags;
-
- Dprintk("irq = %d moved to cpu = %d\n",
- selected_irq, min_loaded);
- /* mark for change destination */
- spin_lock_irqsave(&desc->lock, flags);
- pending_irq_balance_cpumask[selected_irq] =
- cpumask_of_cpu(min_loaded);
- spin_unlock_irqrestore(&desc->lock, flags);
- /* Since we made a change, come back sooner to
- * check for more variation.
- */
- balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL,
- balanced_irq_interval - BALANCED_IRQ_LESS_DELTA);
- return;
- }
- goto tryanotherirq;
-
-not_worth_the_effort:
- /*
- * if we did not find an IRQ to move, then adjust the time interval
- * upward
- */
- balanced_irq_interval = min((long)MAX_BALANCED_IRQ_INTERVAL,
- balanced_irq_interval + BALANCED_IRQ_MORE_DELTA);
- Dprintk("IRQ worth rotating not found\n");
- return;
-}
-
-static int balanced_irq(void *unused)
-{
- int i;
- unsigned long prev_balance_time = jiffies;
- long time_remaining = balanced_irq_interval;
-
- daemonize("kirqd");
-
- /* push everything to CPU 0 to give us a starting point. */
- for (i = 0 ; i < NR_IRQS ; i++) {
- pending_irq_balance_cpumask[i] = cpumask_of_cpu(0);
- }
-
- for ( ; ; ) {
- set_current_state(TASK_INTERRUPTIBLE);
- time_remaining = schedule_timeout(time_remaining);
- try_to_freeze(PF_FREEZE);
- if (time_after(jiffies,
- prev_balance_time+balanced_irq_interval)) {
- do_irq_balance();
- prev_balance_time = jiffies;
- time_remaining = balanced_irq_interval;
- }
- }
- return 0;
-}
-
-static int __init balanced_irq_init(void)
-{
- int i;
- struct cpuinfo_x86 *c;
- cpumask_t tmp;
-
- cpus_shift_right(tmp, cpu_online_map, 2);
- c = &boot_cpu_data;
- /* When not overwritten by the command line ask subarchitecture. */
- if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH)
- irqbalance_disabled = NO_BALANCE_IRQ;
- if (irqbalance_disabled)
- return 0;
-
- /* disable irqbalance completely if there is only one processor online */
- if (num_online_cpus() < 2) {
- irqbalance_disabled = 1;
- return 0;
- }
- /*
- * Enable physical balance only if more than 1 physical processor
- * is present
- */
- if (smp_num_siblings > 1 && !cpus_empty(tmp))
- physical_balance = 1;
-
- for (i = 0; i < NR_CPUS; i++) {
- if (!cpu_online(i))
- continue;
- irq_cpu_data[i].irq_delta = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL);
- irq_cpu_data[i].last_irq = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL);
- if (irq_cpu_data[i].irq_delta == NULL || irq_cpu_data[i].last_irq == NULL) {
- printk(KERN_ERR "balanced_irq_init: out of memory");
- goto failed;
- }
- memset(irq_cpu_data[i].irq_delta,0,sizeof(unsigned long) * NR_IRQS);
- memset(irq_cpu_data[i].last_irq,0,sizeof(unsigned long) * NR_IRQS);
- }
+ unsigned long flags;
+ int pin;
+ struct irq_pin_list *entry = irq_2_pin + irq;
+ unsigned int apicid_value;
- printk(KERN_INFO "Starting balanced_irq\n");
- if (kernel_thread(balanced_irq, NULL, CLONE_KERNEL) >= 0)
- return 0;
- else
- printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq");
-failed:
- for (i = 0; i < NR_CPUS; i++) {
- if(irq_cpu_data[i].irq_delta)
- kfree(irq_cpu_data[i].irq_delta);
- if(irq_cpu_data[i].last_irq)
- kfree(irq_cpu_data[i].last_irq);
- }
- return 0;
-}
-
-int __init irqbalance_disable(char *str)
-{
- irqbalance_disabled = 1;
- return 0;
-}
-
-__setup("noirqbalance", irqbalance_disable);
-
-static inline void move_irq(int irq)
-{
- /* note - we hold the desc->lock */
- if (unlikely(!cpus_empty(pending_irq_balance_cpumask[irq]))) {
- set_ioapic_affinity_irq(irq, pending_irq_balance_cpumask[irq]);
- cpus_clear(pending_irq_balance_cpumask[irq]);
- }
-}
-
-late_initcall(balanced_irq_init);
-
-#else /* !CONFIG_IRQBALANCE */
-static inline void move_irq(int irq) { }
-#endif /* CONFIG_IRQBALANCE */
-
-#ifndef CONFIG_SMP
-void fastcall send_IPI_self(int vector)
-{
- unsigned int cfg;
-
- /*
- * Wait for idle.
- */
- apic_wait_icr_idle();
- cfg = APIC_DM_FIXED | APIC_DEST_SELF | vector | APIC_DEST_LOGICAL;
- /*
- * Send the IPI. The write to APIC_ICR fires this off.
- */
- apic_write_around(APIC_ICR, cfg);
+ apicid_value = cpu_mask_to_apicid(cpumask);
+ /* Prepare to do the io_apic_write */
+ apicid_value = apicid_value << 24;
+ spin_lock_irqsave(&ioapic_lock, flags);
+ for (;;) {
+ pin = entry->pin;
+ if (pin == -1)
+ break;
+ io_apic_write(entry->apic, 0x10 + 1 + pin*2, apicid_value);
+ if (!entry->next)
+ break;
+ entry = irq_2_pin + entry->next;
+ }
+ spin_unlock_irqrestore(&ioapic_lock, flags);
}
-#endif /* !CONFIG_SMP */
/*
* Find the IRQ entry number of a certain pin.
*/
static int find_irq_entry(int apic, int pin, int type)
{
- int i;
+ int i;
- for (i = 0; i < mp_irq_entries; i++)
- if (mp_irqs[i].mpc_irqtype == type &&
- (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid ||
- mp_irqs[i].mpc_dstapic == MP_APIC_ALL) &&
- mp_irqs[i].mpc_dstirq == pin)
- return i;
+ for (i = 0; i < mp_irq_entries; i++)
+ if (mp_irqs[i].mpc_irqtype == type &&
+ (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid ||
+ mp_irqs[i].mpc_dstapic == MP_APIC_ALL) &&
+ mp_irqs[i].mpc_dstirq == pin)
+ return i;
- return -1;
+ return -1;
}
/*
@@ -688,22 +248,22 @@ static int find_irq_entry(int apic, int pin, int type)
*/
static int find_isa_irq_pin(int irq, int type)
{
- int i;
+ int i;
- for (i = 0; i < mp_irq_entries; i++) {
- int lbus = mp_irqs[i].mpc_srcbus;
+ for (i = 0; i < mp_irq_entries; i++) {
+ int lbus = mp_irqs[i].mpc_srcbus;
- if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||
- mp_bus_id_to_type[lbus] == MP_BUS_EISA ||
- mp_bus_id_to_type[lbus] == MP_BUS_MCA ||
- mp_bus_id_to_type[lbus] == MP_BUS_NEC98
- ) &&
- (mp_irqs[i].mpc_irqtype == type) &&
- (mp_irqs[i].mpc_srcbusirq == irq))
+ if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||
+ mp_bus_id_to_type[lbus] == MP_BUS_EISA ||
+ mp_bus_id_to_type[lbus] == MP_BUS_MCA ||
+ mp_bus_id_to_type[lbus] == MP_BUS_NEC98
+ ) &&
+ (mp_irqs[i].mpc_irqtype == type) &&
+ (mp_irqs[i].mpc_srcbusirq == irq))
- return mp_irqs[i].mpc_dstirq;
- }
- return -1;
+ return mp_irqs[i].mpc_dstirq;
+ }
+ return -1;
}
/*
@@ -712,68 +272,28 @@ static int find_isa_irq_pin(int irq, int type)
*/
static int pin_2_irq(int idx, int apic, int pin);
-int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
-{
- int apic, i, best_guess = -1;
-
- apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, "
- "slot:%d, pin:%d.\n", bus, slot, pin);
- if (mp_bus_id_to_pci_bus[bus] == -1) {
- printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
- return -1;
- }
- for (i = 0; i < mp_irq_entries; i++) {
- int lbus = mp_irqs[i].mpc_srcbus;
-
- for (apic = 0; apic < nr_ioapics; apic++)
- if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic ||
- mp_irqs[i].mpc_dstapic == MP_APIC_ALL)
- break;
-
- if ((mp_bus_id_to_type[lbus] == MP_BUS_PCI) &&
- !mp_irqs[i].mpc_irqtype &&
- (bus == lbus) &&
- (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) {
- int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq);
-
- if (!(apic || IO_APIC_IRQ(irq)))
- continue;
-
- if (pin == (mp_irqs[i].mpc_srcbusirq & 3))
- return irq;
- /*
- * Use the first all-but-pin matching entry as a
- * best-guess fuzzy result for broken mptables.
- */
- if (best_guess < 0)
- best_guess = irq;
- }
- }
- return best_guess;
-}
-
/*
- * This function currently is only a helper for the i386 smp boot process where
- * we need to reprogram the ioredtbls to cater for the cpus which have come online
- * so mask in all cases should simply be TARGET_CPUS
+ * This function currently is only a helper for the i386 smp boot process where
+ * we need to reprogram the ioredtbls to cater for the cpus which have come
+ * online so mask in all cases should simply be TARGET_CPUS
*/
void __init setup_ioapic_dest(void)
{
- int pin, ioapic, irq, irq_entry;
+ int pin, ioapic, irq, irq_entry;
- if (skip_ioapic_setup == 1)
- return;
+ if (skip_ioapic_setup == 1)
+ return;
- for (ioapic = 0; ioapic < nr_ioapics; ioapic++) {
- for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) {
- irq_entry = find_irq_entry(ioapic, pin, mp_INT);
- if (irq_entry == -1)
- continue;
- irq = pin_2_irq(irq_entry, ioapic, pin);
- set_ioapic_affinity_irq(irq, TARGET_CPUS);
- }
+ for (ioapic = 0; ioapic < nr_ioapics; ioapic++) {
+ for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) {
+ irq_entry = find_irq_entry(ioapic, pin, mp_INT);
+ if (irq_entry == -1)
+ continue;
+ irq = pin_2_irq(irq_entry, ioapic, pin);
+ set_ioapic_affinity_irq(irq, TARGET_CPUS);
+ }
- }
+ }
}
/*
@@ -781,13 +301,13 @@ void __init setup_ioapic_dest(void)
*/
static int EISA_ELCR(unsigned int irq)
{
- if (irq < 16) {
- unsigned int port = 0x4d0 + (irq >> 3);
- return (inb(port) >> (irq & 7)) & 1;
- }
- apic_printk(APIC_VERBOSE, KERN_INFO
- "Broken MPtable reports ISA irq %d\n", irq);
- return 0;
+ if (irq < 16) {
+ unsigned int port = 0x4d0 + (irq >> 3);
+ return (inb(port) >> (irq & 7)) & 1;
+ }
+ apic_printk(APIC_VERBOSE, KERN_INFO
+ "Broken MPtable reports ISA irq %d\n", irq);
+ return 0;
}
/* EISA interrupts are always polarity zero and can be edge or level
@@ -824,227 +344,227 @@ static int EISA_ELCR(unsigned int irq)
static int __init MPBIOS_polarity(int idx)
{
- int bus = mp_irqs[idx].mpc_srcbus;
- int polarity;
+ int bus = mp_irqs[idx].mpc_srcbus;
+ int polarity;
- /*
- * Determine IRQ line polarity (high active or low active):
- */
- switch (mp_irqs[idx].mpc_irqflag & 3)
- {
- case 0: /* conforms, ie. bus-type dependent polarity */
- {
- switch (mp_bus_id_to_type[bus])
- {
- case MP_BUS_ISA: /* ISA pin */
- {
- polarity = default_ISA_polarity(idx);
- break;
- }
- case MP_BUS_EISA: /* EISA pin */
- {
- polarity = default_EISA_polarity(idx);
- break;
- }
- case MP_BUS_PCI: /* PCI pin */
- {
- polarity = default_PCI_polarity(idx);
- break;
- }
- case MP_BUS_MCA: /* MCA pin */
- {
- polarity = default_MCA_polarity(idx);
- break;
- }
- case MP_BUS_NEC98: /* NEC 98 pin */
- {
- polarity = default_NEC98_polarity(idx);
- break;
- }
- default:
- {
- printk(KERN_WARNING "broken BIOS!!\n");
- polarity = 1;
- break;
- }
- }
- break;
- }
- case 1: /* high active */
- {
- polarity = 0;
- break;
- }
- case 2: /* reserved */
- {
- printk(KERN_WARNING "broken BIOS!!\n");
- polarity = 1;
- break;
- }
- case 3: /* low active */
- {
- polarity = 1;
- break;
- }
- default: /* invalid */
- {
- printk(KERN_WARNING "broken BIOS!!\n");
- polarity = 1;
- break;
- }
- }
- return polarity;
+ /*
+ * Determine IRQ line polarity (high active or low active):
+ */
+ switch (mp_irqs[idx].mpc_irqflag & 3)
+ {
+ case 0: /* conforms, ie. bus-type dependent polarity */
+ {
+ switch (mp_bus_id_to_type[bus])
+ {
+ case MP_BUS_ISA: /* ISA pin */
+ {
+ polarity = default_ISA_polarity(idx);
+ break;
+ }
+ case MP_BUS_EISA: /* EISA pin */
+ {
+ polarity = default_EISA_polarity(idx);
+ break;
+ }
+ case MP_BUS_PCI: /* PCI pin */
+ {
+ polarity = default_PCI_polarity(idx);
+ break;
+ }
+ case MP_BUS_MCA: /* MCA pin */
+ {
+ polarity = default_MCA_polarity(idx);
+ break;
+ }
+ case MP_BUS_NEC98: /* NEC 98 pin */
+ {
+ polarity = default_NEC98_polarity(idx);
+ break;
+ }
+ default:
+ {
+ printk(KERN_WARNING "broken BIOS!!\n");
+ polarity = 1;
+ break;
+ }
+ }
+ break;
+ }
+ case 1: /* high active */
+ {
+ polarity = 0;
+ break;
+ }
+ case 2: /* reserved */
+ {
+ printk(KERN_WARNING "broken BIOS!!\n");
+ polarity = 1;
+ break;
+ }
+ case 3: /* low active */
+ {
+ polarity = 1;
+ break;
+ }
+ default: /* invalid */
+ {
+ printk(KERN_WARNING "broken BIOS!!\n");
+ polarity = 1;
+ break;
+ }
+ }
+ return polarity;
}
static int MPBIOS_trigger(int idx)
{
- int bus = mp_irqs[idx].mpc_srcbus;
- int trigger;
+ int bus = mp_irqs[idx].mpc_srcbus;
+ int trigger;
- /*
- * Determine IRQ trigger mode (edge or level sensitive):
- */
- switch ((mp_irqs[idx].mpc_irqflag>>2) & 3)
- {
- case 0: /* conforms, ie. bus-type dependent */
- {
- switch (mp_bus_id_to_type[bus])
- {
- case MP_BUS_ISA: /* ISA pin */
- {
- trigger = default_ISA_trigger(idx);
- break;
- }
- case MP_BUS_EISA: /* EISA pin */
- {
- trigger = default_EISA_trigger(idx);
- break;
- }
- case MP_BUS_PCI: /* PCI pin */
- {
- trigger = default_PCI_trigger(idx);
- break;
- }
- case MP_BUS_MCA: /* MCA pin */
- {
- trigger = default_MCA_trigger(idx);
- break;
- }
- case MP_BUS_NEC98: /* NEC 98 pin */
- {
- trigger = default_NEC98_trigger(idx);
- break;
- }
- default:
- {
- printk(KERN_WARNING "broken BIOS!!\n");
- trigger = 1;
- break;
- }
- }
- break;
- }
- case 1: /* edge */
- {
- trigger = 0;
- break;
- }
- case 2: /* reserved */
- {
- printk(KERN_WARNING "broken BIOS!!\n");
- trigger = 1;
- break;
- }
- case 3: /* level */
- {
- trigger = 1;
- break;
- }
- default: /* invalid */
- {
- printk(KERN_WARNING "broken BIOS!!\n");
- trigger = 0;
- break;
- }
- }
- return trigger;
+ /*
+ * Determine IRQ trigger mode (edge or level sensitive):
+ */
+ switch ((mp_irqs[idx].mpc_irqflag>>2) & 3)
+ {
+ case 0: /* conforms, ie. bus-type dependent */
+ {
+ switch (mp_bus_id_to_type[bus])
+ {
+ case MP_BUS_ISA: /* ISA pin */
+ {
+ trigger = default_ISA_trigger(idx);
+ break;
+ }
+ case MP_BUS_EISA: /* EISA pin */
+ {
+ trigger = default_EISA_trigger(idx);
+ break;
+ }
+ case MP_BUS_PCI: /* PCI pin */
+ {
+ trigger = default_PCI_trigger(idx);
+ break;
+ }
+ case MP_BUS_MCA: /* MCA pin */
+ {
+ trigger = default_MCA_trigger(idx);
+ break;
+ }
+ case MP_BUS_NEC98: /* NEC 98 pin */
+ {
+ trigger = default_NEC98_trigger(idx);
+ break;
+ }
+ default:
+ {
+ printk(KERN_WARNING "broken BIOS!!\n");
+ trigger = 1;
+ break;
+ }
+ }
+ break;
+ }
+ case 1: /* edge */
+ {
+ trigger = 0;
+ break;
+ }
+ case 2: /* reserved */
+ {
+ printk(KERN_WARNING "broken BIOS!!\n");
+ trigger = 1;
+ break;
+ }
+ case 3: /* level */
+ {
+ trigger = 1;
+ break;
+ }
+ default: /* invalid */
+ {
+ printk(KERN_WARNING "broken BIOS!!\n");
+ trigger = 0;
+ break;
+ }
+ }
+ return trigger;
}
static inline int irq_polarity(int idx)
{
- return MPBIOS_polarity(idx);
+ return MPBIOS_polarity(idx);
}
static inline int irq_trigger(int idx)
{
- return MPBIOS_trigger(idx);
+ return MPBIOS_trigger(idx);
}
static int pin_2_irq(int idx, int apic, int pin)
{
- int irq, i;
- int bus = mp_irqs[idx].mpc_srcbus;
+ int irq, i;
+ int bus = mp_irqs[idx].mpc_srcbus;
- /*
- * Debugging check, we are in big trouble if this message pops up!
- */
- if (mp_irqs[idx].mpc_dstirq != pin)
- printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n");
-
- switch (mp_bus_id_to_type[bus])
- {
- case MP_BUS_ISA: /* ISA pin */
- case MP_BUS_EISA:
- case MP_BUS_MCA:
- case MP_BUS_NEC98:
- {
- irq = mp_irqs[idx].mpc_srcbusirq;
- break;
- }
- case MP_BUS_PCI: /* PCI pin */
- {
- /*
- * PCI IRQs are mapped in order
- */
- i = irq = 0;
- while (i < apic)
- irq += nr_ioapic_registers[i++];
- irq += pin;
-
- /*
- * For MPS mode, so far only needed by ES7000 platform
- */
- if (ioapic_renumber_irq)
- irq = ioapic_renumber_irq(apic, irq);
-
- break;
- }
- default:
- {
- printk(KERN_ERR "unknown bus type %d.\n",bus);
- irq = 0;
- break;
- }
- }
+ /*
+ * Debugging check, we are in big trouble if this message pops up!
+ */
+ if (mp_irqs[idx].mpc_dstirq != pin)
+ printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n");
+
+ switch (mp_bus_id_to_type[bus])
+ {
+ case MP_BUS_ISA: /* ISA pin */
+ case MP_BUS_EISA:
+ case MP_BUS_MCA:
+ case MP_BUS_NEC98:
+ {
+ irq = mp_irqs[idx].mpc_srcbusirq;
+ break;
+ }
+ case MP_BUS_PCI: /* PCI pin */
+ {
+ /*
+ * PCI IRQs are mapped in order
+ */
+ i = irq = 0;
+ while (i < apic)
+ irq += nr_ioapic_registers[i++];
+ irq += pin;
+
+ /*
+ * For MPS mode, so far only needed by ES7000 platform
+ */
+ if (ioapic_renumber_irq)
+ irq = ioapic_renumber_irq(apic, irq);
+
+ break;
+ }
+ default:
+ {
+ printk(KERN_ERR "unknown bus type %d.\n",bus);
+ irq = 0;
+ break;
+ }
+ }
- return irq;
+ return irq;
}
static inline int IO_APIC_irq_trigger(int irq)
{
- int apic, idx, pin;
-
- for (apic = 0; apic < nr_ioapics; apic++) {
- for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
- idx = find_irq_entry(apic,pin,mp_INT);
- if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin)))
- return irq_trigger(idx);
- }
- }
- /*
- * nonexistent IRQs are edge default
- */
- return 0;
+ int apic, idx, pin;
+
+ for (apic = 0; apic < nr_ioapics; apic++) {
+ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+ idx = find_irq_entry(apic,pin,mp_INT);
+ if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin)))
+ return irq_trigger(idx);
+ }
+ }
+ /*
+ * nonexistent IRQs are edge default
+ */
+ return 0;
}
/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
@@ -1052,34 +572,34 @@ u8 irq_vector[NR_IRQ_VECTORS];
int assign_irq_vector(int irq)
{
- static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
-
- BUG_ON(irq >= NR_IRQ_VECTORS);
- if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0)
- return IO_APIC_VECTOR(irq);
-next:
- current_vector += 8;
-
- /* Skip the hypercall vector. */
- if (current_vector == HYPERCALL_VECTOR)
- goto next;
-
- /* Skip the Linux/BSD fast-trap vector. */
- if (current_vector == 0x80)
- goto next;
-
- if (current_vector >= FIRST_SYSTEM_VECTOR) {
- offset++;
- if (!(offset%8))
- return -ENOSPC;
- current_vector = FIRST_DEVICE_VECTOR + offset;
- }
+ static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
+
+ BUG_ON(irq >= NR_IRQ_VECTORS);
+ if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0)
+ return IO_APIC_VECTOR(irq);
+ next:
+ current_vector += 8;
+
+ /* Skip the hypercall vector. */
+ if (current_vector == HYPERCALL_VECTOR)
+ goto next;
+
+ /* Skip the Linux/BSD fast-trap vector. */
+ if (current_vector == 0x80)
+ goto next;
+
+ if (current_vector >= FIRST_SYSTEM_VECTOR) {
+ offset++;
+ if (!(offset%8))
+ return -ENOSPC;
+ current_vector = FIRST_DEVICE_VECTOR + offset;
+ }
- vector_irq[current_vector] = irq;
- if (irq != AUTO_ASSIGN)
- IO_APIC_VECTOR(irq) = current_vector;
+ vector_irq[current_vector] = irq;
+ if (irq != AUTO_ASSIGN)
+ IO_APIC_VECTOR(irq) = current_vector;
- return current_vector;
+ return current_vector;
}
static struct hw_interrupt_type ioapic_level_type;
@@ -1091,97 +611,87 @@ static struct hw_interrupt_type ioapic_edge_type;
static inline void ioapic_register_intr(int irq, int vector, unsigned long trigger)
{
- if (use_pci_vector() && !platform_legacy_irq(irq)) {
- if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
- trigger == IOAPIC_LEVEL)
- irq_desc[vector].handler = &ioapic_level_type;
- else
- irq_desc[vector].handler = &ioapic_edge_type;
- set_intr_gate(vector, interrupt[vector]);
- } else {
- if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
- trigger == IOAPIC_LEVEL)
- irq_desc[irq].handler = &ioapic_level_type;
- else
- irq_desc[irq].handler = &ioapic_edge_type;
- set_intr_gate(vector, interrupt[irq]);
- }
+ if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
+ trigger == IOAPIC_LEVEL)
+ irq_desc[vector].handler = &ioapic_level_type;
+ else
+ irq_desc[vector].handler = &ioapic_edge_type;
}
void __init setup_IO_APIC_irqs(void)
{
- struct IO_APIC_route_entry entry;
- int apic, pin, idx, irq, first_notcon = 1, vector;
- unsigned long flags;
+ struct IO_APIC_route_entry entry;
+ int apic, pin, idx, irq, first_notcon = 1, vector;
+ unsigned long flags;
- apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n");
+ apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n");
- for (apic = 0; apic < nr_ioapics; apic++) {
+ for (apic = 0; apic < nr_ioapics; apic++) {
for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
- /*
- * add it to the IO-APIC irq-routing table:
- */
- memset(&entry,0,sizeof(entry));
-
- entry.delivery_mode = INT_DELIVERY_MODE;
- entry.dest_mode = INT_DEST_MODE;
- entry.mask = 0; /* enable IRQ */
- entry.dest.logical.logical_dest =
- cpu_mask_to_apicid(TARGET_CPUS);
-
- idx = find_irq_entry(apic,pin,mp_INT);
- if (idx == -1) {
- if (first_notcon) {
- apic_printk(APIC_VERBOSE, KERN_DEBUG
- " IO-APIC (apicid-pin) %d-%d",
- mp_ioapics[apic].mpc_apicid,
- pin);
- first_notcon = 0;
- } else
- apic_printk(APIC_VERBOSE, ", %d-%d",
- mp_ioapics[apic].mpc_apicid, pin);
- continue;
- }
-
- entry.trigger = irq_trigger(idx);
- entry.polarity = irq_polarity(idx);
-
- if (irq_trigger(idx)) {
- entry.trigger = 1;
- entry.mask = 1;
- }
-
- irq = pin_2_irq(idx, apic, pin);
- /*
- * skip adding the timer int on secondary nodes, which causes
- * a small but painful rift in the time-space continuum
- */
- if (multi_timer_check(apic, irq))
- continue;
- else
- add_pin_to_irq(irq, apic, pin);
-
- if (!apic && !IO_APIC_IRQ(irq))
- continue;
-
- if (IO_APIC_IRQ(irq)) {
- vector = assign_irq_vector(irq);
- entry.vector = vector;
- ioapic_register_intr(irq, vector, IOAPIC_AUTO);
+ /*
+ * add it to the IO-APIC irq-routing table:
+ */
+ memset(&entry,0,sizeof(entry));
+
+ entry.delivery_mode = INT_DELIVERY_MODE;
+ entry.dest_mode = INT_DEST_MODE;
+ entry.mask = 0; /* enable IRQ */
+ entry.dest.logical.logical_dest =
+ cpu_mask_to_apicid(TARGET_CPUS);
+
+ idx = find_irq_entry(apic,pin,mp_INT);
+ if (idx == -1) {
+ if (first_notcon) {
+ apic_printk(APIC_VERBOSE, KERN_DEBUG
+ " IO-APIC (apicid-pin) %d-%d",
+ mp_ioapics[apic].mpc_apicid,
+ pin);
+ first_notcon = 0;
+ } else
+ apic_printk(APIC_VERBOSE, ", %d-%d",
+ mp_ioapics[apic].mpc_apicid, pin);
+ continue;
+ }
+
+ entry.trigger = irq_trigger(idx);
+ entry.polarity = irq_polarity(idx);
+
+ if (irq_trigger(idx)) {
+ entry.trigger = 1;
+ entry.mask = 1;
+ }
+
+ irq = pin_2_irq(idx, apic, pin);
+ /*
+ * skip adding the timer int on secondary nodes, which causes
+ * a small but painful rift in the time-space continuum
+ */
+ if (multi_timer_check(apic, irq))
+ continue;
+ else
+ add_pin_to_irq(irq, apic, pin);
+
+ if (!apic && !IO_APIC_IRQ(irq))
+ continue;
+
+ if (IO_APIC_IRQ(irq)) {
+ vector = assign_irq_vector(irq);
+ entry.vector = vector;
+ ioapic_register_intr(irq, vector, IOAPIC_AUTO);
- if (!apic && (irq < 16))
- disable_8259A_irq(irq);
- }
- spin_lock_irqsave(&ioapic_lock, flags);
- io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
- io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
- spin_unlock_irqrestore(&ioapic_lock, flags);
- }
+ if (!apic && (irq < 16))
+ disable_8259A_irq(irq);
+ }
+ spin_lock_irqsave(&ioapic_lock, flags);
+ io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
+ io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
+ spin_unlock_irqrestore(&ioapic_lock, flags);
}
+ }
- if (!first_notcon)
- apic_printk(APIC_VERBOSE, " not connected.\n");
+ if (!first_notcon)
+ apic_printk(APIC_VERBOSE, " not connected.\n");
}
/*
@@ -1189,43 +699,43 @@ void __init setup_IO_APIC_irqs(void)
*/
void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector)
{
- struct IO_APIC_route_entry entry;
- unsigned long flags;
-
- memset(&entry,0,sizeof(entry));
-
- disable_8259A_irq(0);
-
- /* mask LVT0 */
- apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
-
- /*
- * We use logical delivery to get the timer IRQ
- * to the first CPU.
- */
- entry.dest_mode = INT_DEST_MODE;
- entry.mask = 0; /* unmask IRQ now */
- entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
- entry.delivery_mode = INT_DELIVERY_MODE;
- entry.polarity = 0;
- entry.trigger = 0;
- entry.vector = vector;
-
- /*
- * The timer IRQ doesn't have to know that behind the
- * scene we have a 8259A-master in AEOI mode ...
- */
- irq_desc[0].handler = &ioapic_edge_type;
+ struct IO_APIC_route_entry entry;
+ unsigned long flags;
- /*
- * Add it to the IO-APIC irq-routing table:
- */
- spin_lock_irqsave(&ioapic_lock, flags);
- io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
- io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
- spin_unlock_irqrestore(&ioapic_lock, flags);
+ memset(&entry,0,sizeof(entry));
+
+ disable_8259A_irq(0);
+
+ /* mask LVT0 */
+ apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
+
+ /*
+ * We use logical delivery to get the timer IRQ
+ * to the first CPU.
+ */
+ entry.dest_mode = INT_DEST_MODE;
+ entry.mask = 0; /* unmask IRQ now */
+ entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
+ entry.delivery_mode = INT_DELIVERY_MODE;
+ entry.polarity = 0;
+ entry.trigger = 0;
+ entry.vector = vector;
+
+ /*
+ * The timer IRQ doesn't have to know that behind the
+ * scene we have a 8259A-master in AEOI mode ...
+ */
+ irq_desc[IO_APIC_VECTOR(0)].handler = &ioapic_edge_type;
+
+ /*
+ * Add it to the IO-APIC irq-routing table:
+ */
+ spin_lock_irqsave(&ioapic_lock, flags);
+ io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
+ io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
+ spin_unlock_irqrestore(&ioapic_lock, flags);
- enable_8259A_irq(0);
+ enable_8259A_irq(0);
}
static inline void UNEXPECTED_IO_APIC(void)
@@ -1234,36 +744,36 @@ static inline void UNEXPECTED_IO_APIC(void)
void __init print_IO_APIC(void)
{
- int apic, i;
- union IO_APIC_reg_00 reg_00;
- union IO_APIC_reg_01 reg_01;
- union IO_APIC_reg_02 reg_02;
- union IO_APIC_reg_03 reg_03;
- unsigned long flags;
+ int apic, i;
+ union IO_APIC_reg_00 reg_00;
+ union IO_APIC_reg_01 reg_01;
+ union IO_APIC_reg_02 reg_02;
+ union IO_APIC_reg_03 reg_03;
+ unsigned long flags;
- if (apic_verbosity == APIC_QUIET)
- return;
+ if (apic_verbosity == APIC_QUIET)
+ return;
- printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
- for (i = 0; i < nr_ioapics; i++)
- printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n",
- mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]);
+ printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
+ for (i = 0; i < nr_ioapics; i++)
+ printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n",
+ mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]);
- /*
- * We are a bit conservative about what we expect. We have to
- * know about every hardware change ASAP.
- */
- printk(KERN_INFO "testing the IO APIC.......................\n");
+ /*
+ * We are a bit conservative about what we expect. We have to
+ * know about every hardware change ASAP.
+ */
+ printk(KERN_INFO "testing the IO APIC.......................\n");
- for (apic = 0; apic < nr_ioapics; apic++) {
+ for (apic = 0; apic < nr_ioapics; apic++) {
spin_lock_irqsave(&ioapic_lock, flags);
reg_00.raw = io_apic_read(apic, 0);
reg_01.raw = io_apic_read(apic, 1);
if (reg_01.bits.version >= 0x10)
- reg_02.raw = io_apic_read(apic, 2);
+ reg_02.raw = io_apic_read(apic, 2);
if (reg_01.bits.version >= 0x20)
- reg_03.raw = io_apic_read(apic, 3);
+ reg_03.raw = io_apic_read(apic, 3);
spin_unlock_irqrestore(&ioapic_lock, flags);
printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid);
@@ -1272,9 +782,9 @@ void __init print_IO_APIC(void)
printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.bits.delivery_type);
printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.bits.LTS);
if (reg_00.bits.ID >= get_physical_broadcast())
- UNEXPECTED_IO_APIC();
+ UNEXPECTED_IO_APIC();
if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2)
- UNEXPECTED_IO_APIC();
+ UNEXPECTED_IO_APIC();
printk(KERN_DEBUG ".... register #01: %08X\n", reg_01.raw);
printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries);
@@ -1285,8 +795,8 @@ void __init print_IO_APIC(void)
(reg_01.bits.entries != 0x22) && /* bigger Xeon boards */
(reg_01.bits.entries != 0x2E) &&
(reg_01.bits.entries != 0x3F)
- )
- UNEXPECTED_IO_APIC();
+ )
+ UNEXPECTED_IO_APIC();
printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ);
printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.bits.version);
@@ -1295,10 +805,10 @@ void __init print_IO_APIC(void)
(reg_01.bits.version != 0x11) && /* Pentium/Pro IO-APICs */
(reg_01.bits.version != 0x13) && /* Xeon IO-APICs */
(reg_01.bits.version != 0x20) /* Intel P64H (82806 AA) */
- )
- UNEXPECTED_IO_APIC();
+ )
+ UNEXPECTED_IO_APIC();
if (reg_01.bits.__reserved_1 || reg_01.bits.__reserved_2)
- UNEXPECTED_IO_APIC();
+ UNEXPECTED_IO_APIC();
/*
* Some Intel chipsets with IO APIC VERSION of 0x1? don't have reg_02,
@@ -1306,10 +816,10 @@ void __init print_IO_APIC(void)
* value, so ignore it if reg_02 == reg_01.
*/
if (reg_01.bits.version >= 0x10 && reg_02.raw != reg_01.raw) {
- printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw);
- printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration);
- if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2)
- UNEXPECTED_IO_APIC();
+ printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw);
+ printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration);
+ if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2)
+ UNEXPECTED_IO_APIC();
}
/*
@@ -1319,93 +829,89 @@ void __init print_IO_APIC(void)
*/
if (reg_01.bits.version >= 0x20 && reg_03.raw != reg_02.raw &&
reg_03.raw != reg_01.raw) {
- printk(KERN_DEBUG ".... register #03: %08X\n", reg_03.raw);
- printk(KERN_DEBUG "....... : Boot DT : %X\n", reg_03.bits.boot_DT);
- if (reg_03.bits.__reserved_1)
- UNEXPECTED_IO_APIC();
+ printk(KERN_DEBUG ".... register #03: %08X\n", reg_03.raw);
+ printk(KERN_DEBUG "....... : Boot DT : %X\n", reg_03.bits.boot_DT);
+ if (reg_03.bits.__reserved_1)
+ UNEXPECTED_IO_APIC();
}
printk(KERN_DEBUG ".... IRQ redirection table:\n");
printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol"
- " Stat Dest Deli Vect: \n");
+ " Stat Dest Deli Vect: \n");
for (i = 0; i <= reg_01.bits.entries; i++) {
- struct IO_APIC_route_entry entry;
+ struct IO_APIC_route_entry entry;
- spin_lock_irqsave(&ioapic_lock, flags);
- *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2);
- *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2);
- spin_unlock_irqrestore(&ioapic_lock, flags);
+ spin_lock_irqsave(&ioapic_lock, flags);
+ *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2);
+ *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
- printk(KERN_DEBUG " %02x %03X %02X ",
- i,
- entry.dest.logical.logical_dest,
- entry.dest.physical.physical_dest
+ printk(KERN_DEBUG " %02x %03X %02X ",
+ i,
+ entry.dest.logical.logical_dest,
+ entry.dest.physical.physical_dest
);
- printk("%1d %1d %1d %1d %1d %1d %1d %02X\n",
- entry.mask,
- entry.trigger,
- entry.irr,
- entry.polarity,
- entry.delivery_status,
- entry.dest_mode,
- entry.delivery_mode,
- entry.vector
+ printk("%1d %1d %1d %1d %1d %1d %1d %02X\n",
+ entry.mask,
+ entry.trigger,
+ entry.irr,
+ entry.polarity,
+ entry.delivery_status,
+ entry.dest_mode,
+ entry.delivery_mode,
+ entry.vector
);
}
- }
- if (use_pci_vector())
- printk(KERN_INFO "Using vector-based indexing\n");
- printk(KERN_DEBUG "IRQ to pin mappings:\n");
- for (i = 0; i < NR_IRQS; i++) {
- struct irq_pin_list *entry = irq_2_pin + i;
- if (entry->pin < 0)
- continue;
- if (use_pci_vector() && !platform_legacy_irq(i))
- printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));
- else
- printk(KERN_DEBUG "IRQ%d ", i);
- for (;;) {
- printk("-> %d:%d", entry->apic, entry->pin);
- if (!entry->next)
- break;
- entry = irq_2_pin + entry->next;
- }
- printk("\n");
- }
+ }
+ printk(KERN_INFO "Using vector-based indexing\n");
+ printk(KERN_DEBUG "IRQ to pin mappings:\n");
+ for (i = 0; i < NR_IRQS; i++) {
+ struct irq_pin_list *entry = irq_2_pin + i;
+ if (entry->pin < 0)
+ continue;
+ printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));
+ for (;;) {
+ printk("-> %d:%d", entry->apic, entry->pin);
+ if (!entry->next)
+ break;
+ entry = irq_2_pin + entry->next;
+ }
+ printk("\n");
+ }
- printk(KERN_INFO ".................................... done.\n");
+ printk(KERN_INFO ".................................... done.\n");
- return;
+ return;
}
static void __init enable_IO_APIC(void)
{
- union IO_APIC_reg_01 reg_01;
- int i;
- unsigned long flags;
+ union IO_APIC_reg_01 reg_01;
+ int i;
+ unsigned long flags;
- for (i = 0; i < PIN_MAP_SIZE; i++) {
- irq_2_pin[i].pin = -1;
- irq_2_pin[i].next = 0;
- }
+ for (i = 0; i < PIN_MAP_SIZE; i++) {
+ irq_2_pin[i].pin = -1;
+ irq_2_pin[i].next = 0;
+ }
- /*
- * The number of IO-APIC IRQ registers (== #pins):
- */
- for (i = 0; i < nr_ioapics; i++) {
- spin_lock_irqsave(&ioapic_lock, flags);
- reg_01.raw = io_apic_read(i, 1);
- spin_unlock_irqrestore(&ioapic_lock, flags);
- nr_ioapic_registers[i] = reg_01.bits.entries+1;
- }
+ /*
+ * The number of IO-APIC IRQ registers (== #pins):
+ */
+ for (i = 0; i < nr_ioapics; i++) {
+ spin_lock_irqsave(&ioapic_lock, flags);
+ reg_01.raw = io_apic_read(i, 1);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+ nr_ioapic_registers[i] = reg_01.bits.entries+1;
+ }
- /*
- * Do not trust the IO-APIC being empty at bootup
- */
- clear_IO_APIC();
+ /*
+ * Do not trust the IO-APIC being empty at bootup
+ */
+ clear_IO_APIC();
}
/*
@@ -1413,12 +919,12 @@ static void __init enable_IO_APIC(void)
*/
void disable_IO_APIC(void)
{
- /*
- * Clear the IO-APIC before rebooting:
+ /*
+ * Clear the IO-APIC before rebooting:
*/
- clear_IO_APIC();
+ clear_IO_APIC();
- disconnect_bsp_APIC();
+ disconnect_bsp_APIC();
}
/*
@@ -1431,105 +937,105 @@ void disable_IO_APIC(void)
#ifndef CONFIG_X86_NUMAQ
static void __init setup_ioapic_ids_from_mpc(void)
{
- union IO_APIC_reg_00 reg_00;
- physid_mask_t phys_id_present_map;
- int apic;
- int i;
- unsigned char old_id;
- unsigned long flags;
+ union IO_APIC_reg_00 reg_00;
+ physid_mask_t phys_id_present_map;
+ int apic;
+ int i;
+ unsigned char old_id;
+ unsigned long flags;
- /*
- * This is broken; anything with a real cpu count has to
- * circumvent this idiocy regardless.
- */
- phys_id_present_map = ioapic_phys_id_map(phys_cpu_present_map);
+ /*
+ * This is broken; anything with a real cpu count has to
+ * circumvent this idiocy regardless.
+ */
+ phys_id_present_map = ioapic_phys_id_map(phys_cpu_present_map);
+
+ /*
+ * Set the IOAPIC ID to the value stored in the MPC table.
+ */
+ for (apic = 0; apic < nr_ioapics; apic++) {
+
+ /* Read the register 0 value */
+ spin_lock_irqsave(&ioapic_lock, flags);
+ reg_00.raw = io_apic_read(apic, 0);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+
+ old_id = mp_ioapics[apic].mpc_apicid;
+
+ if (mp_ioapics[apic].mpc_apicid >= get_physical_broadcast()) {
+ printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
+ apic, mp_ioapics[apic].mpc_apicid);
+ printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
+ reg_00.bits.ID);
+ mp_ioapics[apic].mpc_apicid = reg_00.bits.ID;
+ }
- /*
- * Set the IOAPIC ID to the value stored in the MPC table.
- */
- for (apic = 0; apic < nr_ioapics; apic++) {
+ /* Don't check I/O APIC IDs for some xAPIC systems. They have
+ * no meaning without the serial APIC bus. */
+ if (NO_IOAPIC_CHECK)
+ continue;
+ /*
+ * Sanity check, is the ID really free? Every APIC in a
+ * system must have a unique ID or we get lots of nice
+ * 'stuck on smp_invalidate_needed IPI wait' messages.
+ */
+ if (check_apicid_used(phys_id_present_map,
+ mp_ioapics[apic].mpc_apicid)) {
+ printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
+ apic, mp_ioapics[apic].mpc_apicid);
+ for (i = 0; i < get_physical_broadcast(); i++)
+ if (!physid_isset(i, phys_id_present_map))
+ break;
+ if (i >= get_physical_broadcast())
+ panic("Max APIC ID exceeded!\n");
+ printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
+ i);
+ physid_set(i, phys_id_present_map);
+ mp_ioapics[apic].mpc_apicid = i;
+ } else {
+ physid_mask_t tmp;
+ tmp = apicid_to_cpu_present(mp_ioapics[apic].mpc_apicid);
+ apic_printk(APIC_VERBOSE, "Setting %d in the "
+ "phys_id_present_map\n",
+ mp_ioapics[apic].mpc_apicid);
+ physids_or(phys_id_present_map, phys_id_present_map, tmp);
+ }
- /* Read the register 0 value */
- spin_lock_irqsave(&ioapic_lock, flags);
- reg_00.raw = io_apic_read(apic, 0);
- spin_unlock_irqrestore(&ioapic_lock, flags);
-
- old_id = mp_ioapics[apic].mpc_apicid;
-
- if (mp_ioapics[apic].mpc_apicid >= get_physical_broadcast()) {
- printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
- apic, mp_ioapics[apic].mpc_apicid);
- printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
- reg_00.bits.ID);
- mp_ioapics[apic].mpc_apicid = reg_00.bits.ID;
- }
-
- /* Don't check I/O APIC IDs for some xAPIC systems. They have
- * no meaning without the serial APIC bus. */
- if (NO_IOAPIC_CHECK)
- continue;
- /*
- * Sanity check, is the ID really free? Every APIC in a
- * system must have a unique ID or we get lots of nice
- * 'stuck on smp_invalidate_needed IPI wait' messages.
- */
- if (check_apicid_used(phys_id_present_map,
- mp_ioapics[apic].mpc_apicid)) {
- printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
- apic, mp_ioapics[apic].mpc_apicid);
- for (i = 0; i < get_physical_broadcast(); i++)
- if (!physid_isset(i, phys_id_present_map))
- break;
- if (i >= get_physical_broadcast())
- panic("Max APIC ID exceeded!\n");
- printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
- i);
- physid_set(i, phys_id_present_map);
- mp_ioapics[apic].mpc_apicid = i;
- } else {
- physid_mask_t tmp;
- tmp = apicid_to_cpu_present(mp_ioapics[apic].mpc_apicid);
- apic_printk(APIC_VERBOSE, "Setting %d in the "
- "phys_id_present_map\n",
- mp_ioapics[apic].mpc_apicid);
- physids_or(phys_id_present_map, phys_id_present_map, tmp);
- }
-
-
- /*
- * We need to adjust the IRQ routing table
- * if the ID changed.
- */
- if (old_id != mp_ioapics[apic].mpc_apicid)
- for (i = 0; i < mp_irq_entries; i++)
- if (mp_irqs[i].mpc_dstapic == old_id)
- mp_irqs[i].mpc_dstapic
- = mp_ioapics[apic].mpc_apicid;
-
- /*
- * Read the right value from the MPC table and
- * write it into the ID register.
- */
- apic_printk(APIC_VERBOSE, KERN_INFO
- "...changing IO-APIC physical APIC ID to %d ...",
- mp_ioapics[apic].mpc_apicid);
-
- reg_00.bits.ID = mp_ioapics[apic].mpc_apicid;
- spin_lock_irqsave(&ioapic_lock, flags);
- io_apic_write(apic, 0, reg_00.raw);
- spin_unlock_irqrestore(&ioapic_lock, flags);
-
- /*
- * Sanity check
- */
- spin_lock_irqsave(&ioapic_lock, flags);
- reg_00.raw = io_apic_read(apic, 0);
- spin_unlock_irqrestore(&ioapic_lock, flags);
- if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid)
- printk("could not set ID!\n");
- else
- apic_printk(APIC_VERBOSE, " ok.\n");
- }
+
+ /*
+ * We need to adjust the IRQ routing table
+ * if the ID changed.
+ */
+ if (old_id != mp_ioapics[apic].mpc_apicid)
+ for (i = 0; i < mp_irq_entries; i++)
+ if (mp_irqs[i].mpc_dstapic == old_id)
+ mp_irqs[i].mpc_dstapic
+ = mp_ioapics[apic].mpc_apicid;
+
+ /*
+ * Read the right value from the MPC table and
+ * write it into the ID register.
+ */
+ apic_printk(APIC_VERBOSE, KERN_INFO
+ "...changing IO-APIC physical APIC ID to %d ...",
+ mp_ioapics[apic].mpc_apicid);
+
+ reg_00.bits.ID = mp_ioapics[apic].mpc_apicid;
+ spin_lock_irqsave(&ioapic_lock, flags);
+ io_apic_write(apic, 0, reg_00.raw);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+
+ /*
+ * Sanity check
+ */
+ spin_lock_irqsave(&ioapic_lock, flags);
+ reg_00.raw = io_apic_read(apic, 0);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+ if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid)
+ printk("could not set ID!\n");
+ else
+ apic_printk(APIC_VERBOSE, " ok.\n");
+ }
}
#else
static void __init setup_ioapic_ids_from_mpc(void) { }
@@ -1545,23 +1051,23 @@ static void __init setup_ioapic_ids_from_mpc(void) { }
*/
static int __init timer_irq_works(void)
{
- unsigned long t1 = jiffies;
+ unsigned long t1 = jiffies;
- local_irq_enable();
- /* Let ten ticks pass... */
- mdelay((10 * 1000) / HZ);
+ local_irq_enable();
+ /* Let ten ticks pass... */
+ mdelay((10 * 1000) / HZ);
- /*
- * Expect a few ticks at least, to be sure some possible
- * glue logic does not lock up after one or two first
- * ticks in a non-ExtINT mode. Also the local APIC
- * might have cached one ExtINT interrupt. Finally, at
- * least one tick may be lost due to delays.
- */
- if (jiffies - t1 > 4)
- return 1;
+ /*
+ * Expect a few ticks at least, to be sure some possible
+ * glue logic does not lock up after one or two first
+ * ticks in a non-ExtINT mode. Also the local APIC
+ * might have cached one ExtINT interrupt. Finally, at
+ * least one tick may be lost due to delays.
+ */
+ if (jiffies - t1 > 4)
+ return 1;
- return 0;
+ return 0;
}
/*
@@ -1588,19 +1094,19 @@ static int __init timer_irq_works(void)
*/
static unsigned int startup_edge_ioapic_irq(unsigned int irq)
{
- int was_pending = 0;
- unsigned long flags;
+ int was_pending = 0;
+ unsigned long flags;
- spin_lock_irqsave(&ioapic_lock, flags);
- if (irq < 16) {
- disable_8259A_irq(irq);
- if (i8259A_irq_pending(irq))
- was_pending = 1;
- }
- __unmask_IO_APIC_irq(irq);
- spin_unlock_irqrestore(&ioapic_lock, flags);
+ spin_lock_irqsave(&ioapic_lock, flags);
+ if (irq < 16) {
+ disable_8259A_irq(irq);
+ if (i8259A_irq_pending(irq))
+ was_pending = 1;
+ }
+ __unmask_IO_APIC_irq(irq);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
- return was_pending;
+ return was_pending;
}
/*
@@ -1610,11 +1116,10 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq)
*/
static void ack_edge_ioapic_irq(unsigned int irq)
{
- move_irq(irq);
- if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
- == (IRQ_PENDING | IRQ_DISABLED))
- mask_IO_APIC_irq(irq);
- ack_APIC_irq();
+ if ((irq_desc[IO_APIC_VECTOR(irq)].status & (IRQ_PENDING | IRQ_DISABLED))
+ == (IRQ_PENDING | IRQ_DISABLED))
+ mask_IO_APIC_irq(irq);
+ ack_APIC_irq();
}
/*
@@ -1633,19 +1138,17 @@ static void ack_edge_ioapic_irq(unsigned int irq)
*/
static unsigned int startup_level_ioapic_irq (unsigned int irq)
{
- unmask_IO_APIC_irq(irq);
+ unmask_IO_APIC_irq(irq);
- return 0; /* don't check for pending */
+ return 0; /* don't check for pending */
}
static void mask_and_ack_level_ioapic_irq (unsigned int irq)
{
- unsigned long v;
- int i;
-
- move_irq(irq);
+ unsigned long v;
+ int i;
- mask_IO_APIC_irq(irq);
+ mask_IO_APIC_irq(irq);
/*
* It appears there is an erratum which affects at least version 0x11
* of I/O APIC (that's the 82093AA and cores integrated into various
@@ -1665,84 +1168,82 @@ static void mask_and_ack_level_ioapic_irq (unsigned int irq)
* operation to prevent an edge-triggered interrupt escaping meanwhile.
* The idea is from Manfred Spraul. --macro
*/
- i = IO_APIC_VECTOR(irq);
+ i = IO_APIC_VECTOR(irq);
- v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
+ v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
- ack_APIC_irq();
+ ack_APIC_irq();
- if (!(v & (1 << (i & 0x1f)))) {
- atomic_inc(&irq_mis_count);
- spin_lock(&ioapic_lock);
- __edge_IO_APIC_irq(irq);
- __level_IO_APIC_irq(irq);
- spin_unlock(&ioapic_lock);
- }
+ if (!(v & (1 << (i & 0x1f)))) {
+ atomic_inc(&irq_mis_count);
+ spin_lock(&ioapic_lock);
+ __edge_IO_APIC_irq(irq);
+ __level_IO_APIC_irq(irq);
+ spin_unlock(&ioapic_lock);
+ }
}
static void end_level_ioapic_irq (unsigned int irq)
{
- unmask_IO_APIC_irq(irq);
+ unmask_IO_APIC_irq(irq);
}
-#ifdef CONFIG_PCI_MSI
static unsigned int startup_edge_ioapic_vector(unsigned int vector)
{
- int irq = vector_to_irq(vector);
-
- return startup_edge_ioapic_irq(irq);
+ int irq = vector_to_irq(vector);
+ return startup_edge_ioapic_irq(irq);
}
static void ack_edge_ioapic_vector(unsigned int vector)
{
- int irq = vector_to_irq(vector);
-
- ack_edge_ioapic_irq(irq);
+ int irq = vector_to_irq(vector);
+ ack_edge_ioapic_irq(irq);
}
-static unsigned int startup_level_ioapic_vector (unsigned int vector)
+static unsigned int startup_level_ioapic_vector(unsigned int vector)
{
- int irq = vector_to_irq(vector);
-
- return startup_level_ioapic_irq (irq);
+ int irq = vector_to_irq(vector);
+ return startup_level_ioapic_irq (irq);
}
-static void mask_and_ack_level_ioapic_vector (unsigned int vector)
+static void mask_and_ack_level_ioapic_vector(unsigned int vector)
{
- int irq = vector_to_irq(vector);
-
- mask_and_ack_level_ioapic_irq(irq);
+ int irq = vector_to_irq(vector);
+ mask_and_ack_level_ioapic_irq(irq);
}
-static void end_level_ioapic_vector (unsigned int vector)
+static void end_level_ioapic_vector(unsigned int vector)
{
- int irq = vector_to_irq(vector);
-
- end_level_ioapic_irq(irq);
+ int irq = vector_to_irq(vector);
+ end_level_ioapic_irq(irq);
}
-static void mask_IO_APIC_vector (unsigned int vector)
+static void mask_IO_APIC_vector(unsigned int vector)
{
- int irq = vector_to_irq(vector);
-
- mask_IO_APIC_irq(irq);
+ int irq = vector_to_irq(vector);
+ mask_IO_APIC_irq(irq);
}
-static void unmask_IO_APIC_vector (unsigned int vector)
+static void unmask_IO_APIC_vector(unsigned int vector)
{
- int irq = vector_to_irq(vector);
+ int irq = vector_to_irq(vector);
+ unmask_IO_APIC_irq(irq);
+}
- unmask_IO_APIC_irq(irq);
+static void set_ioapic_affinity_vector(
+ unsigned int vector, cpumask_t cpu_mask)
+{
+ int irq = vector_to_irq(vector);
+ set_ioapic_affinity_irq(irq, cpu_mask);
}
-static void set_ioapic_affinity_vector (unsigned int vector,
- cpumask_t cpu_mask)
+static void disable_edge_ioapic_vector(unsigned int vector)
{
- int irq = vector_to_irq(vector);
+}
- set_ioapic_affinity_irq(irq, cpu_mask);
+static void end_edge_ioapic_vector(unsigned int vector)
+{
}
-#endif
/*
* Level and edge triggered IO-APIC interrupts need different handling,
@@ -1753,95 +1254,66 @@ static void set_ioapic_affinity_vector (unsigned int vector,
* races.
*/
static struct hw_interrupt_type ioapic_edge_type = {
- .typename = "IO-APIC-edge",
- .startup = startup_edge_ioapic,
- .shutdown = shutdown_edge_ioapic,
- .enable = enable_edge_ioapic,
- .disable = disable_edge_ioapic,
- .ack = ack_edge_ioapic,
- .end = end_edge_ioapic,
- .set_affinity = set_ioapic_affinity,
+ .typename = "IO-APIC-edge",
+ .startup = startup_edge_ioapic_vector,
+ .shutdown = disable_edge_ioapic_vector,
+ .enable = unmask_IO_APIC_vector,
+ .disable = disable_edge_ioapic_vector,
+ .ack = ack_edge_ioapic_vector,
+ .end = end_edge_ioapic_vector,
+ .set_affinity = set_ioapic_affinity_vector,
};
static struct hw_interrupt_type ioapic_level_type = {
- .typename = "IO-APIC-level",
- .startup = startup_level_ioapic,
- .shutdown = shutdown_level_ioapic,
- .enable = enable_level_ioapic,
- .disable = disable_level_ioapic,
- .ack = mask_and_ack_level_ioapic,
- .end = end_level_ioapic,
- .set_affinity = set_ioapic_affinity,
+ .typename = "IO-APIC-level",
+ .startup = startup_level_ioapic_vector,
+ .shutdown = mask_IO_APIC_vector,
+ .enable = unmask_IO_APIC_vector,
+ .disable = mask_IO_APIC_vector,
+ .ack = mask_and_ack_level_ioapic_vector,
+ .end = end_level_ioapic_vector,
+ .set_affinity = set_ioapic_affinity_vector,
};
static inline void init_IO_APIC_traps(void)
{
- int irq;
-
- /*
- * NOTE! The local APIC isn't very good at handling
- * multiple interrupts at the same interrupt level.
- * As the interrupt level is determined by taking the
- * vector number and shifting that right by 4, we
- * want to spread these out a bit so that they don't
- * all fall in the same interrupt level.
- *
- * Also, we've got to be careful not to trash gate
- * 0x80, because int 0x80 is hm, kind of importantish. ;)
- */
- for (irq = 0; irq < NR_IRQS ; irq++) {
- int tmp = irq;
- if (use_pci_vector()) {
- if (!platform_legacy_irq(tmp))
- if ((tmp = vector_to_irq(tmp)) == -1)
- continue;
- }
- if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) {
- /*
- * Hmm.. We don't have an entry for this,
- * so default to an old-fashioned 8259
- * interrupt if we can..
- */
- if (irq < 16)
- make_8259A_irq(irq);
- else
- /* Strange. Oh, well.. */
- irq_desc[irq].handler = &no_irq_type;
- }
- }
+ int irq;
+ for (irq = 0; irq < NR_IRQS ; irq++)
+ if (IO_APIC_IRQ(irq) && !IO_APIC_VECTOR(irq) && (irq < 16))
+ make_8259A_irq(irq);
}
-static void enable_lapic_irq (unsigned int irq)
+static void enable_lapic_vector(unsigned int vector)
{
- unsigned long v;
+ unsigned long v;
- v = apic_read(APIC_LVT0);
- apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
+ v = apic_read(APIC_LVT0);
+ apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
}
-static void disable_lapic_irq (unsigned int irq)
+static void disable_lapic_vector(unsigned int vector)
{
- unsigned long v;
+ unsigned long v;
- v = apic_read(APIC_LVT0);
- apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
+ v = apic_read(APIC_LVT0);
+ apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
}
-static void ack_lapic_irq (unsigned int irq)
+static void ack_lapic_vector(unsigned int vector)
{
- ack_APIC_irq();
+ ack_APIC_irq();
}
-static void end_lapic_irq (unsigned int i) { /* nothing */ }
+static void end_lapic_vector(unsigned int vector) { /* nothing */ }
static struct hw_interrupt_type lapic_irq_type = {
- .typename = "local-APIC-edge",
- .startup = NULL, /* startup_irq() not used for IRQ0 */
- .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */
- .enable = enable_lapic_irq,
- .disable = disable_lapic_irq,
- .ack = ack_lapic_irq,
- .end = end_lapic_irq
+ .typename = "local-APIC-edge",
+ .startup = NULL, /* startup_irq() not used for IRQ0 */
+ .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */
+ .enable = enable_lapic_vector,
+ .disable = disable_lapic_vector,
+ .ack = ack_lapic_vector,
+ .end = end_lapic_vector
};
/*
@@ -1853,57 +1325,57 @@ static struct hw_interrupt_type lapic_irq_type = {
*/
static inline void unlock_ExtINT_logic(void)
{
- int pin, i;
- struct IO_APIC_route_entry entry0, entry1;
- unsigned char save_control, save_freq_select;
- unsigned long flags;
+ int pin, i;
+ struct IO_APIC_route_entry entry0, entry1;
+ unsigned char save_control, save_freq_select;
+ unsigned long flags;
- pin = find_isa_irq_pin(8, mp_INT);
- if (pin == -1)
- return;
+ pin = find_isa_irq_pin(8, mp_INT);
+ if (pin == -1)
+ return;
- spin_lock_irqsave(&ioapic_lock, flags);
- *(((int *)&entry0) + 1) = io_apic_read(0, 0x11 + 2 * pin);
- *(((int *)&entry0) + 0) = io_apic_read(0, 0x10 + 2 * pin);
- spin_unlock_irqrestore(&ioapic_lock, flags);
- clear_IO_APIC_pin(0, pin);
+ spin_lock_irqsave(&ioapic_lock, flags);
+ *(((int *)&entry0) + 1) = io_apic_read(0, 0x11 + 2 * pin);
+ *(((int *)&entry0) + 0) = io_apic_read(0, 0x10 + 2 * pin);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+ clear_IO_APIC_pin(0, pin);
- memset(&entry1, 0, sizeof(entry1));
+ memset(&entry1, 0, sizeof(entry1));
- entry1.dest_mode = 0; /* physical delivery */
- entry1.mask = 0; /* unmask IRQ now */
- entry1.dest.physical.physical_dest = hard_smp_processor_id();
- entry1.delivery_mode = dest_ExtINT;
- entry1.polarity = entry0.polarity;
- entry1.trigger = 0;
- entry1.vector = 0;
+ entry1.dest_mode = 0; /* physical delivery */
+ entry1.mask = 0; /* unmask IRQ now */
+ entry1.dest.physical.physical_dest = hard_smp_processor_id();
+ entry1.delivery_mode = dest_ExtINT;
+ entry1.polarity = entry0.polarity;
+ entry1.trigger = 0;
+ entry1.vector = 0;
- spin_lock_irqsave(&ioapic_lock, flags);
- io_apic_write(0, 0x11 + 2 * pin, *(((int *)&entry1) + 1));
- io_apic_write(0, 0x10 + 2 * pin, *(((int *)&entry1) + 0));
- spin_unlock_irqrestore(&ioapic_lock, flags);
+ spin_lock_irqsave(&ioapic_lock, flags);
+ io_apic_write(0, 0x11 + 2 * pin, *(((int *)&entry1) + 1));
+ io_apic_write(0, 0x10 + 2 * pin, *(((int *)&entry1) + 0));
+ spin_unlock_irqrestore(&ioapic_lock, flags);
- save_control = CMOS_READ(RTC_CONTROL);
- save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
- CMOS_WRITE((save_freq_select & ~RTC_RATE_SELECT) | 0x6,
- RTC_FREQ_SELECT);
- CMOS_WRITE(save_control | RTC_PIE, RTC_CONTROL);
-
- i = 100;
- while (i-- > 0) {
- mdelay(10);
- if ((CMOS_READ(RTC_INTR_FLAGS) & RTC_PF) == RTC_PF)
- i -= 10;
- }
+ save_control = CMOS_READ(RTC_CONTROL);
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+ CMOS_WRITE((save_freq_select & ~RTC_RATE_SELECT) | 0x6,
+ RTC_FREQ_SELECT);
+ CMOS_WRITE(save_control | RTC_PIE, RTC_CONTROL);
+
+ i = 100;
+ while (i-- > 0) {
+ mdelay(10);
+ if ((CMOS_READ(RTC_INTR_FLAGS) & RTC_PF) == RTC_PF)
+ i -= 10;
+ }
- CMOS_WRITE(save_control, RTC_CONTROL);
- CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
- clear_IO_APIC_pin(0, pin);
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+ clear_IO_APIC_pin(0, pin);
- spin_lock_irqsave(&ioapic_lock, flags);
- io_apic_write(0, 0x11 + 2 * pin, *(((int *)&entry0) + 1));
- io_apic_write(0, 0x10 + 2 * pin, *(((int *)&entry0) + 0));
- spin_unlock_irqrestore(&ioapic_lock, flags);
+ spin_lock_irqsave(&ioapic_lock, flags);
+ io_apic_write(0, 0x11 + 2 * pin, *(((int *)&entry0) + 1));
+ io_apic_write(0, 0x10 + 2 * pin, *(((int *)&entry0) + 0));
+ spin_unlock_irqrestore(&ioapic_lock, flags);
}
/*
@@ -1914,102 +1386,105 @@ static inline void unlock_ExtINT_logic(void)
*/
static inline void check_timer(void)
{
- int pin1, pin2;
- int vector;
-
- /*
- * get/set the timer IRQ vector:
- */
- disable_8259A_irq(0);
- vector = assign_irq_vector(0);
- set_intr_gate(vector, interrupt[0]);
-
- /*
- * Subtle, code in do_timer_interrupt() expects an AEOI
- * mode for the 8259A whenever interrupts are routed
- * through I/O APICs. Also IRQ0 has to be enabled in
- * the 8259A which implies the virtual wire has to be
- * disabled in the local APIC.
- */
- apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
- init_8259A(1);
- timer_ack = 1;
- enable_8259A_irq(0);
-
- pin1 = find_isa_irq_pin(0, mp_INT);
- pin2 = find_isa_irq_pin(0, mp_ExtINT);
-
- printk(KERN_INFO "..TIMER: vector=0x%02X pin1=%d pin2=%d\n", vector, pin1, pin2);
-
- if (pin1 != -1) {
- /*
- * Ok, does IRQ0 through the IOAPIC work?
- */
- unmask_IO_APIC_irq(0);
- if (timer_irq_works()) {
- return;
- }
- clear_IO_APIC_pin(0, pin1);
- printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n");
- }
+ int pin1, pin2;
+ int vector;
+
+ /*
+ * get/set the timer IRQ vector:
+ */
+ disable_8259A_irq(0);
+ vector = assign_irq_vector(0);
+
+ irq_desc[IO_APIC_VECTOR(0)].action = irq_desc[LEGACY_VECTOR(0)].action;
+ irq_desc[IO_APIC_VECTOR(0)].depth = 0;
+ irq_desc[IO_APIC_VECTOR(0)].status &= ~IRQ_DISABLED;
+
+ /*
+ * Subtle, code in do_timer_interrupt() expects an AEOI
+ * mode for the 8259A whenever interrupts are routed
+ * through I/O APICs. Also IRQ0 has to be enabled in
+ * the 8259A which implies the virtual wire has to be
+ * disabled in the local APIC.
+ */
+ apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
+ init_8259A(1);
+ timer_ack = 1;
+ enable_8259A_irq(0);
+
+ pin1 = find_isa_irq_pin(0, mp_INT);
+ pin2 = find_isa_irq_pin(0, mp_ExtINT);
+
+ printk(KERN_INFO "..TIMER: vector=0x%02X pin1=%d pin2=%d\n", vector, pin1, pin2);
+
+ if (pin1 != -1) {
+ /*
+ * Ok, does IRQ0 through the IOAPIC work?
+ */
+ unmask_IO_APIC_irq(0);
+ if (timer_irq_works()) {
+ return;
+ }
+ clear_IO_APIC_pin(0, pin1);
+ printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n");
+ }
- printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... ");
- if (pin2 != -1) {
- printk("\n..... (found pin %d) ...", pin2);
- /*
- * legacy devices should be connected to IO APIC #0
- */
- setup_ExtINT_IRQ0_pin(pin2, vector);
- if (timer_irq_works()) {
- printk("works.\n");
- if (pin1 != -1)
- replace_pin_at_irq(0, 0, pin1, 0, pin2);
- else
- add_pin_to_irq(0, 0, pin2);
- return;
- }
- /*
- * Cleanup, just in case ...
- */
- clear_IO_APIC_pin(0, pin2);
- }
- printk(" failed.\n");
+ printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... ");
+ if (pin2 != -1) {
+ printk("\n..... (found pin %d) ...", pin2);
+ /*
+ * legacy devices should be connected to IO APIC #0
+ */
+ setup_ExtINT_IRQ0_pin(pin2, vector);
+ if (timer_irq_works()) {
+ printk("works.\n");
+ if (pin1 != -1)
+ replace_pin_at_irq(0, 0, pin1, 0, pin2);
+ else
+ add_pin_to_irq(0, 0, pin2);
+ return;
+ }
+ /*
+ * Cleanup, just in case ...
+ */
+ clear_IO_APIC_pin(0, pin2);
+ }
+ printk(" failed.\n");
- if (nmi_watchdog == NMI_IO_APIC) {
- printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n");
- nmi_watchdog = 0;
- }
+ if (nmi_watchdog == NMI_IO_APIC) {
+ printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n");
+ nmi_watchdog = 0;
+ }
- printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
+ printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
- disable_8259A_irq(0);
- irq_desc[0].handler = &lapic_irq_type;
- apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */
- enable_8259A_irq(0);
+ disable_8259A_irq(0);
+ irq_desc[vector].handler = &lapic_irq_type;
+ apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */
+ enable_8259A_irq(0);
- if (timer_irq_works()) {
- printk(" works.\n");
- return;
- }
- apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | vector);
- printk(" failed.\n");
+ if (timer_irq_works()) {
+ printk(" works.\n");
+ return;
+ }
+ apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | vector);
+ printk(" failed.\n");
- printk(KERN_INFO "...trying to set up timer as ExtINT IRQ...");
+ printk(KERN_INFO "...trying to set up timer as ExtINT IRQ...");
- timer_ack = 0;
- init_8259A(0);
- make_8259A_irq(0);
- apic_write_around(APIC_LVT0, APIC_DM_EXTINT);
+ timer_ack = 0;
+ init_8259A(0);
+ make_8259A_irq(0);
+ apic_write_around(APIC_LVT0, APIC_DM_EXTINT);
- unlock_ExtINT_logic();
+ unlock_ExtINT_logic();
- if (timer_irq_works()) {
- printk(" works.\n");
- return;
- }
- printk(" failed :(.\n");
- panic("IO-APIC + timer doesn't work! Boot with apic=debug and send a "
- "report. Then try booting with the 'noapic' option");
+ if (timer_irq_works()) {
+ printk(" works.\n");
+ return;
+ }
+ printk(" failed :(.\n");
+ panic("IO-APIC + timer doesn't work! Boot with apic=debug and send a "
+ "report. Then try booting with the 'noapic' option");
}
#define NR_IOAPIC_BIOSIDS 256
@@ -2033,27 +1508,27 @@ static void store_ioapic_biosid_mapping(void)
void __init setup_IO_APIC(void)
{
- store_ioapic_biosid_mapping();
+ store_ioapic_biosid_mapping();
- enable_IO_APIC();
+ enable_IO_APIC();
- if (acpi_ioapic)
- io_apic_irqs = ~0; /* all IRQs go through IOAPIC */
- else
- io_apic_irqs = ~PIC_IRQS;
+ if (acpi_ioapic)
+ io_apic_irqs = ~0; /* all IRQs go through IOAPIC */
+ else
+ io_apic_irqs = ~PIC_IRQS;
- printk("ENABLING IO-APIC IRQs\n");
+ printk("ENABLING IO-APIC IRQs\n");
- /*
- * Set up IO-APIC IRQ routing.
- */
- if (!acpi_ioapic)
- setup_ioapic_ids_from_mpc();
- sync_Arb_IDs();
- setup_IO_APIC_irqs();
- init_IO_APIC_traps();
- check_timer();
- print_IO_APIC();
+ /*
+ * Set up IO-APIC IRQ routing.
+ */
+ if (!acpi_ioapic)
+ setup_ioapic_ids_from_mpc();
+ sync_Arb_IDs();
+ setup_IO_APIC_irqs();
+ init_IO_APIC_traps();
+ check_timer();
+ print_IO_APIC();
}
/* --------------------------------------------------------------------------
@@ -2064,153 +1539,153 @@ void __init setup_IO_APIC(void)
int __init io_apic_get_unique_id (int ioapic, int apic_id)
{
- union IO_APIC_reg_00 reg_00;
- static physid_mask_t apic_id_map = PHYSID_MASK_NONE;
- physid_mask_t tmp;
- unsigned long flags;
- int i = 0;
+ union IO_APIC_reg_00 reg_00;
+ static physid_mask_t apic_id_map = PHYSID_MASK_NONE;
+ physid_mask_t tmp;
+ unsigned long flags;
+ int i = 0;
- /*
- * The P4 platform supports up to 256 APIC IDs on two separate APIC
- * buses (one for LAPICs, one for IOAPICs), where predecessors only
- * supports up to 16 on one shared APIC bus.
- *
- * TBD: Expand LAPIC/IOAPIC support on P4-class systems to take full
- * advantage of new APIC bus architecture.
- */
+ /*
+ * The P4 platform supports up to 256 APIC IDs on two separate APIC
+ * buses (one for LAPICs, one for IOAPICs), where predecessors only
+ * supports up to 16 on one shared APIC bus.
+ *
+ * TBD: Expand LAPIC/IOAPIC support on P4-class systems to take full
+ * advantage of new APIC bus architecture.
+ */
- if (physids_empty(apic_id_map))
- apic_id_map = ioapic_phys_id_map(phys_cpu_present_map);
+ if (physids_empty(apic_id_map))
+ apic_id_map = ioapic_phys_id_map(phys_cpu_present_map);
- spin_lock_irqsave(&ioapic_lock, flags);
- reg_00.raw = io_apic_read(ioapic, 0);
- spin_unlock_irqrestore(&ioapic_lock, flags);
+ spin_lock_irqsave(&ioapic_lock, flags);
+ reg_00.raw = io_apic_read(ioapic, 0);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
- if (apic_id >= get_physical_broadcast()) {
- printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying "
- "%d\n", ioapic, apic_id, reg_00.bits.ID);
- apic_id = reg_00.bits.ID;
- }
+ if (apic_id >= get_physical_broadcast()) {
+ printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying "
+ "%d\n", ioapic, apic_id, reg_00.bits.ID);
+ apic_id = reg_00.bits.ID;
+ }
- /*
- * Every APIC in a system must have a unique ID or we get lots of nice
- * 'stuck on smp_invalidate_needed IPI wait' messages.
- */
- if (check_apicid_used(apic_id_map, apic_id)) {
+ /*
+ * Every APIC in a system must have a unique ID or we get lots of nice
+ * 'stuck on smp_invalidate_needed IPI wait' messages.
+ */
+ if (check_apicid_used(apic_id_map, apic_id)) {
- for (i = 0; i < get_physical_broadcast(); i++) {
- if (!check_apicid_used(apic_id_map, i))
- break;
- }
+ for (i = 0; i < get_physical_broadcast(); i++) {
+ if (!check_apicid_used(apic_id_map, i))
+ break;
+ }
- if (i == get_physical_broadcast())
- panic("Max apic_id exceeded!\n");
+ if (i == get_physical_broadcast())
+ panic("Max apic_id exceeded!\n");
- printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, "
- "trying %d\n", ioapic, apic_id, i);
+ printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, "
+ "trying %d\n", ioapic, apic_id, i);
- apic_id = i;
- }
+ apic_id = i;
+ }
- tmp = apicid_to_cpu_present(apic_id);
- physids_or(apic_id_map, apic_id_map, tmp);
+ tmp = apicid_to_cpu_present(apic_id);
+ physids_or(apic_id_map, apic_id_map, tmp);
- if (reg_00.bits.ID != apic_id) {
- reg_00.bits.ID = apic_id;
+ if (reg_00.bits.ID != apic_id) {
+ reg_00.bits.ID = apic_id;
- spin_lock_irqsave(&ioapic_lock, flags);
- io_apic_write(ioapic, 0, reg_00.raw);
- reg_00.raw = io_apic_read(ioapic, 0);
- spin_unlock_irqrestore(&ioapic_lock, flags);
+ spin_lock_irqsave(&ioapic_lock, flags);
+ io_apic_write(ioapic, 0, reg_00.raw);
+ reg_00.raw = io_apic_read(ioapic, 0);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
- /* Sanity check */
- if (reg_00.bits.ID != apic_id)
- panic("IOAPIC[%d]: Unable change apic_id!\n", ioapic);
- }
+ /* Sanity check */
+ if (reg_00.bits.ID != apic_id)
+ panic("IOAPIC[%d]: Unable change apic_id!\n", ioapic);
+ }
- apic_printk(APIC_VERBOSE, KERN_INFO
- "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id);
+ apic_printk(APIC_VERBOSE, KERN_INFO
+ "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id);
- return apic_id;
+ return apic_id;
}
int __init io_apic_get_version (int ioapic)
{
- union IO_APIC_reg_01 reg_01;
- unsigned long flags;
+ union IO_APIC_reg_01 reg_01;
+ unsigned long flags;
- spin_lock_irqsave(&ioapic_lock, flags);
- reg_01.raw = io_apic_read(ioapic, 1);
- spin_unlock_irqrestore(&ioapic_lock, flags);
+ spin_lock_irqsave(&ioapic_lock, flags);
+ reg_01.raw = io_apic_read(ioapic, 1);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
- return reg_01.bits.version;
+ return reg_01.bits.version;
}
int __init io_apic_get_redir_entries (int ioapic)
{
- union IO_APIC_reg_01 reg_01;
- unsigned long flags;
+ union IO_APIC_reg_01 reg_01;
+ unsigned long flags;
- spin_lock_irqsave(&ioapic_lock, flags);
- reg_01.raw = io_apic_read(ioapic, 1);
- spin_unlock_irqrestore(&ioapic_lock, flags);
+ spin_lock_irqsave(&ioapic_lock, flags);
+ reg_01.raw = io_apic_read(ioapic, 1);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
- return reg_01.bits.entries;
+ return reg_01.bits.entries;
}
int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int active_high_low)
{
- struct IO_APIC_route_entry entry;
- unsigned long flags;
+ struct IO_APIC_route_entry entry;
+ unsigned long flags;
- if (!IO_APIC_IRQ(irq)) {
- printk(KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
- ioapic);
- return -EINVAL;
- }
+ if (!IO_APIC_IRQ(irq)) {
+ printk(KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
+ ioapic);
+ return -EINVAL;
+ }
- /*
- * Generate a PCI IRQ routing entry and program the IOAPIC accordingly.
- * Note that we mask (disable) IRQs now -- these get enabled when the
- * corresponding device driver registers for this IRQ.
- */
+ /*
+ * Generate a PCI IRQ routing entry and program the IOAPIC accordingly.
+ * Note that we mask (disable) IRQs now -- these get enabled when the
+ * corresponding device driver registers for this IRQ.
+ */
- memset(&entry,0,sizeof(entry));
+ memset(&entry,0,sizeof(entry));
- entry.delivery_mode = INT_DELIVERY_MODE;
- entry.dest_mode = INT_DEST_MODE;
- entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
- entry.trigger = edge_level;
- entry.polarity = active_high_low;
- entry.mask = 1;
+ entry.delivery_mode = INT_DELIVERY_MODE;
+ entry.dest_mode = INT_DEST_MODE;
+ entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
+ entry.trigger = edge_level;
+ entry.polarity = active_high_low;
+ entry.mask = 1;
- /*
- * IRQs < 16 are already in the irq_2_pin[] map
- */
- if (irq >= 16)
- add_pin_to_irq(irq, ioapic, pin);
+ /*
+ * IRQs < 16 are already in the irq_2_pin[] map
+ */
+ if (irq >= 16)
+ add_pin_to_irq(irq, ioapic, pin);
- entry.vector = assign_irq_vector(irq);
+ entry.vector = assign_irq_vector(irq);
- apic_printk(APIC_DEBUG, KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry "
+ apic_printk(APIC_DEBUG, KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry "
"(%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i)\n", ioapic,
mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq,
edge_level, active_high_low);
- ioapic_register_intr(irq, entry.vector, edge_level);
+ ioapic_register_intr(irq, entry.vector, edge_level);
- if (!ioapic && (irq < 16))
- disable_8259A_irq(irq);
+ if (!ioapic && (irq < 16))
+ disable_8259A_irq(irq);
- spin_lock_irqsave(&ioapic_lock, flags);
- io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1));
- io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0));
- spin_unlock_irqrestore(&ioapic_lock, flags);
+ spin_lock_irqsave(&ioapic_lock, flags);
+ io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1));
+ io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0));
+ spin_unlock_irqrestore(&ioapic_lock, flags);
- return 0;
+ return 0;
}
#endif /*CONFIG_ACPI_BOOT*/
@@ -2225,7 +1700,7 @@ int ioapic_guest_read(int apicid, int address, u32 *pval)
if ( (apicid >= NR_IOAPIC_BIOSIDS) ||
((apicenum = ioapic_biosid_to_apic_enum[apicid]) >= nr_ioapics) )
- return -EINVAL;
+ return -EINVAL;
spin_lock_irqsave(&ioapic_lock, flags);
val = io_apic_read(apicenum, address);
@@ -2252,7 +1727,7 @@ int ioapic_guest_write(int apicid, int address, u32 val)
if ( (apicid >= NR_IOAPIC_BIOSIDS) ||
((apicenum = ioapic_biosid_to_apic_enum[apicid]) >= nr_ioapics) )
- return -EINVAL;
+ return -EINVAL;
/* Only write to the first half of a route entry. */
if ( (address < 0x10) || (address & 1) )
@@ -2271,7 +1746,7 @@ int ioapic_guest_write(int apicid, int address, u32 val)
return 0;
/* Set the correct irq-handling type. */
- irq_desc[irq].handler = rte.trigger ?
+ irq_desc[IO_APIC_VECTOR(irq)].handler = rte.trigger ?
&ioapic_level_type: &ioapic_edge_type;
/* Record the pin<->irq mapping. */
diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c
index a5657e72f8..7307e9bead 100644
--- a/xen/arch/x86/irq.c
+++ b/xen/arch/x86/irq.c
@@ -16,16 +16,16 @@
irq_desc_t irq_desc[NR_IRQS];
-static void __do_IRQ_guest(int irq);
+static void __do_IRQ_guest(int vector);
void no_action(int cpl, void *dev_id, struct cpu_user_regs *regs) { }
-static void enable_none(unsigned int irq) { }
-static unsigned int startup_none(unsigned int irq) { return 0; }
-static void disable_none(unsigned int irq) { }
-static void ack_none(unsigned int irq)
+static void enable_none(unsigned int vector) { }
+static unsigned int startup_none(unsigned int vector) { return 0; }
+static void disable_none(unsigned int vector) { }
+static void ack_none(unsigned int vector)
{
- printk("Unexpected IRQ trap at vector %02x.\n", irq);
+ printk("Unexpected IRQ trap at vector %02x.\n", vector);
ack_APIC_irq();
}
@@ -46,7 +46,8 @@ atomic_t irq_err_count;
inline void disable_irq_nosync(unsigned int irq)
{
- irq_desc_t *desc = &irq_desc[irq];
+ unsigned int vector = irq_to_vector(irq);
+ irq_desc_t *desc = &irq_desc[vector];
unsigned long flags;
spin_lock_irqsave(&desc->lock, flags);
@@ -54,21 +55,16 @@ inline void disable_irq_nosync(unsigned int irq)
if ( desc->depth++ == 0 )
{
desc->status |= IRQ_DISABLED;
- desc->handler->disable(irq);
+ desc->handler->disable(vector);
}
spin_unlock_irqrestore(&desc->lock, flags);
}
-void disable_irq(unsigned int irq)
-{
- disable_irq_nosync(irq);
- do { smp_mb(); } while ( irq_desc[irq].status & IRQ_INPROGRESS );
-}
-
void enable_irq(unsigned int irq)
{
- irq_desc_t *desc = &irq_desc[irq];
+ unsigned int vector = irq_to_vector(irq);
+ irq_desc_t *desc = &irq_desc[vector];
unsigned long flags;
spin_lock_irqsave(&desc->lock, flags);
@@ -77,30 +73,27 @@ void enable_irq(unsigned int irq)
{
desc->status &= ~IRQ_DISABLED;
if ( (desc->status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING )
- {
desc->status |= IRQ_REPLAY;
- hw_resend_irq(desc->handler,irq);
- }
- desc->handler->enable(irq);
+ desc->handler->enable(vector);
}
spin_unlock_irqrestore(&desc->lock, flags);
}
asmlinkage void do_IRQ(struct cpu_user_regs *regs)
-{
- unsigned int irq = regs->entry_vector;
- irq_desc_t *desc = &irq_desc[irq];
+{
+ unsigned int vector = regs->entry_vector;
+ irq_desc_t *desc = &irq_desc[vector];
struct irqaction *action;
perfc_incrc(irqs);
spin_lock(&desc->lock);
- desc->handler->ack(irq);
+ desc->handler->ack(vector);
if ( likely(desc->status & IRQ_GUEST) )
{
- __do_IRQ_guest(irq);
+ __do_IRQ_guest(vector);
spin_unlock(&desc->lock);
return;
}
@@ -121,23 +114,24 @@ asmlinkage void do_IRQ(struct cpu_user_regs *regs)
while ( desc->status & IRQ_PENDING )
{
desc->status &= ~IRQ_PENDING;
- irq_enter(smp_processor_id(), irq);
+ irq_enter(smp_processor_id());
spin_unlock_irq(&desc->lock);
- action->handler(irq, action->dev_id, regs);
+ action->handler(vector_to_irq(vector), action->dev_id, regs);
spin_lock_irq(&desc->lock);
- irq_exit(smp_processor_id(), irq);
+ irq_exit(smp_processor_id());
}
desc->status &= ~IRQ_INPROGRESS;
out:
- desc->handler->end(irq);
+ desc->handler->end(vector);
spin_unlock(&desc->lock);
}
void free_irq(unsigned int irq)
{
- irq_desc_t *desc = &irq_desc[irq];
+ unsigned int vector = irq_to_vector(irq);
+ irq_desc_t *desc = &irq_desc[vector];
unsigned long flags;
spin_lock_irqsave(&desc->lock,flags);
@@ -148,12 +142,13 @@ void free_irq(unsigned int irq)
spin_unlock_irqrestore(&desc->lock,flags);
/* Wait to make sure it's not being used on another CPU */
- do { smp_mb(); } while ( irq_desc[irq].status & IRQ_INPROGRESS );
+ do { smp_mb(); } while ( desc->status & IRQ_INPROGRESS );
}
int setup_irq(unsigned int irq, struct irqaction *new)
{
- irq_desc_t *desc = &irq_desc[irq];
+ unsigned int vector = irq_to_vector(irq);
+ irq_desc_t *desc = &irq_desc[vector];
unsigned long flags;
spin_lock_irqsave(&desc->lock,flags);
@@ -167,7 +162,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
desc->action = new;
desc->depth = 0;
desc->status &= ~IRQ_DISABLED;
- desc->handler->startup(irq);
+ desc->handler->startup(vector);
spin_unlock_irqrestore(&desc->lock,flags);
@@ -184,22 +179,23 @@ typedef struct {
u8 nr_guests;
u8 in_flight;
u8 shareable;
- struct vcpu *guest[IRQ_MAX_GUESTS];
+ struct domain *guest[IRQ_MAX_GUESTS];
} irq_guest_action_t;
-static void __do_IRQ_guest(int irq)
+static void __do_IRQ_guest(int vector)
{
- irq_desc_t *desc = &irq_desc[irq];
+ unsigned int irq = vector_to_irq(vector);
+ irq_desc_t *desc = &irq_desc[vector];
irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
- struct vcpu *v;
+ struct domain *d;
int i;
for ( i = 0; i < action->nr_guests; i++ )
{
- v = action->guest[i];
- if ( !test_and_set_bit(irq, &v->domain->pirq_mask) )
+ d = action->guest[i];
+ if ( !test_and_set_bit(irq, &d->pirq_mask) )
action->in_flight++;
- send_guest_pirq(v, irq);
+ send_guest_pirq(d, irq);
}
}
@@ -218,12 +214,12 @@ int pirq_guest_unmask(struct domain *d)
j = find_first_set_bit(m);
m &= ~(1 << j);
pirq = (i << 5) + j;
- desc = &irq_desc[pirq];
+ desc = &irq_desc[irq_to_vector(pirq)];
spin_lock_irq(&desc->lock);
if ( !test_bit(d->pirq_to_evtchn[pirq], &s->evtchn_mask[0]) &&
test_and_clear_bit(pirq, &d->pirq_mask) &&
(--((irq_guest_action_t *)desc->action)->in_flight == 0) )
- desc->handler->end(pirq);
+ desc->handler->end(irq_to_vector(pirq));
spin_unlock_irq(&desc->lock);
}
}
@@ -233,8 +229,9 @@ int pirq_guest_unmask(struct domain *d)
int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
{
+ unsigned int vector = irq_to_vector(irq);
struct domain *d = v->domain;
- irq_desc_t *desc = &irq_desc[irq];
+ irq_desc_t *desc = &irq_desc[vector];
irq_guest_action_t *action;
unsigned long flags;
int rc = 0;
@@ -243,6 +240,9 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
if ( !IS_CAPABLE_PHYSDEV(d) )
return -EPERM;
+ if ( vector == 0 )
+ return -EBUSY;
+
spin_lock_irqsave(&desc->lock, flags);
action = (irq_guest_action_t *)desc->action;
@@ -272,12 +272,12 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
desc->depth = 0;
desc->status |= IRQ_GUEST;
desc->status &= ~IRQ_DISABLED;
- desc->handler->startup(irq);
+ desc->handler->startup(vector);
/* Attempt to bind the interrupt target to the correct CPU. */
cpu_set(v->processor, cpumask);
if ( desc->handler->set_affinity != NULL )
- desc->handler->set_affinity(irq, cpumask);
+ desc->handler->set_affinity(vector, cpumask);
}
else if ( !will_share || !action->shareable )
{
@@ -294,7 +294,7 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
goto out;
}
- action->guest[action->nr_guests++] = v;
+ action->guest[action->nr_guests++] = v->domain;
out:
spin_unlock_irqrestore(&desc->lock, flags);
@@ -303,18 +303,21 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
int pirq_guest_unbind(struct domain *d, int irq)
{
- irq_desc_t *desc = &irq_desc[irq];
+ unsigned int vector = irq_to_vector(irq);
+ irq_desc_t *desc = &irq_desc[vector];
irq_guest_action_t *action;
unsigned long flags;
int i;
+ BUG_ON(vector == 0);
+
spin_lock_irqsave(&desc->lock, flags);
action = (irq_guest_action_t *)desc->action;
if ( test_and_clear_bit(irq, &d->pirq_mask) &&
(--action->in_flight == 0) )
- desc->handler->end(irq);
+ desc->handler->end(vector);
if ( action->nr_guests == 1 )
{
@@ -323,12 +326,12 @@ int pirq_guest_unbind(struct domain *d, int irq)
desc->depth = 1;
desc->status |= IRQ_DISABLED;
desc->status &= ~IRQ_GUEST;
- desc->handler->shutdown(irq);
+ desc->handler->shutdown(vector);
}
else
{
i = 0;
- while ( action->guest[i] && action->guest[i]->domain != d )
+ while ( action->guest[i] && (action->guest[i] != d) )
i++;
memmove(&action->guest[i], &action->guest[i+1], IRQ_MAX_GUESTS-i-1);
action->nr_guests--;
@@ -337,26 +340,3 @@ int pirq_guest_unbind(struct domain *d, int irq)
spin_unlock_irqrestore(&desc->lock, flags);
return 0;
}
-
-int pirq_guest_bindable(int irq, int will_share)
-{
- irq_desc_t *desc = &irq_desc[irq];
- irq_guest_action_t *action;
- unsigned long flags;
- int okay;
-
- spin_lock_irqsave(&desc->lock, flags);
-
- action = (irq_guest_action_t *)desc->action;
-
- /*
- * To be bindable the IRQ must either be not currently bound (1), or
- * it must be shareable (2) and not at its share limit (3).
- */
- okay = ((!(desc->status & IRQ_GUEST) && (action == NULL)) || /* 1 */
- (action->shareable && will_share && /* 2 */
- (action->nr_guests != IRQ_MAX_GUESTS))); /* 3 */
-
- spin_unlock_irqrestore(&desc->lock, flags);
- return okay;
-}
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index bda7d9725a..083d967e25 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -94,12 +94,12 @@
#include <xen/perfc.h>
#include <xen/irq.h>
#include <xen/softirq.h>
+#include <xen/domain_page.h>
#include <asm/shadow.h>
#include <asm/page.h>
#include <asm/flushtlb.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#include <asm/domain_page.h>
#include <asm/ldt.h>
#include <asm/x86_emulate.h>
@@ -269,17 +269,17 @@ static int alloc_segdesc_page(struct pfn_info *page)
struct desc_struct *descs;
int i;
- descs = map_domain_mem((page-frame_table) << PAGE_SHIFT);
+ descs = map_domain_page(page_to_pfn(page));
for ( i = 0; i < 512; i++ )
if ( unlikely(!check_descriptor(&descs[i])) )
goto fail;
- unmap_domain_mem(descs);
+ unmap_domain_page(descs);
return 1;
fail:
- unmap_domain_mem(descs);
+ unmap_domain_page(descs);
return 0;
}
@@ -665,14 +665,14 @@ static int alloc_l1_table(struct pfn_info *page)
ASSERT(!shadow_mode_refcounts(d));
- pl1e = map_domain_mem(pfn << PAGE_SHIFT);
+ pl1e = map_domain_page(pfn);
for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
if ( is_guest_l1_slot(i) &&
unlikely(!get_page_from_l1e(pl1e[i], d)) )
goto fail;
- unmap_domain_mem(pl1e);
+ unmap_domain_page(pl1e);
return 1;
fail:
@@ -680,58 +680,83 @@ static int alloc_l1_table(struct pfn_info *page)
if ( is_guest_l1_slot(i) )
put_page_from_l1e(pl1e[i], d);
- unmap_domain_mem(pl1e);
+ unmap_domain_page(pl1e);
return 0;
}
#ifdef CONFIG_X86_PAE
-static inline int fixup_pae_linear_mappings(l3_pgentry_t *pl3e)
+static int create_pae_xen_mappings(l3_pgentry_t *pl3e)
{
- l2_pgentry_t *pl2e;
- unsigned long vaddr;
- int i,idx;
+ struct pfn_info *page;
+ l2_pgentry_t *pl2e;
+ l3_pgentry_t l3e3;
+ int i;
- while ((unsigned long)pl3e & ~PAGE_MASK)
- pl3e--;
+ pl3e = (l3_pgentry_t *)((unsigned long)pl3e & PAGE_MASK);
- if (!(l3e_get_flags(pl3e[3]) & _PAGE_PRESENT)) {
- printk("Installing a L3 PAE pt without L2 in slot #3 isn't going to fly ...\n");
+ /* 3rd L3 slot contains L2 with Xen-private mappings. It *must* exist. */
+ l3e3 = pl3e[3];
+ if ( !(l3e_get_flags(l3e3) & _PAGE_PRESENT) )
+ {
+ MEM_LOG("PAE L3 3rd slot is empty");
return 0;
}
- pl2e = map_domain_mem(l3e_get_paddr(pl3e[3]));
- for (i = 0; i < 4; i++) {
- vaddr = LINEAR_PT_VIRT_START + (i << L2_PAGETABLE_SHIFT);
- idx = (vaddr >> L2_PAGETABLE_SHIFT) & (L2_PAGETABLE_ENTRIES-1);
- if (l3e_get_flags(pl3e[i]) & _PAGE_PRESENT) {
- pl2e[idx] = l2e_from_paddr(l3e_get_paddr(pl3e[i]),
- __PAGE_HYPERVISOR);
- } else
- pl2e[idx] = l2e_empty();
+ /*
+ * The Xen-private mappings include linear mappings. The L2 thus cannot
+ * be shared by multiple L3 tables. The test here is adequate because:
+ * 1. Cannot appear in slots != 3 because the page would then then have
+ * unknown va backpointer, which get_page_type() explicitly disallows.
+ * 2. Cannot appear in another page table's L3:
+ * a. alloc_l3_table() calls this function and this check will fail
+ * b. mod_l3_entry() disallows updates to slot 3 in an existing table
+ */
+ page = l3e_get_page(l3e3);
+ BUG_ON(page->u.inuse.type_info & PGT_pinned);
+ BUG_ON((page->u.inuse.type_info & PGT_count_mask) == 0);
+ if ( (page->u.inuse.type_info & PGT_count_mask) != 1 )
+ {
+ MEM_LOG("PAE L3 3rd slot is shared");
+ return 0;
}
- unmap_domain_mem(pl2e);
+
+ /* Xen private mappings. */
+ pl2e = map_domain_page(l3e_get_pfn(l3e3));
+ memcpy(&pl2e[L2_PAGETABLE_FIRST_XEN_SLOT & (L2_PAGETABLE_ENTRIES-1)],
+ &idle_pg_table_l2[L2_PAGETABLE_FIRST_XEN_SLOT],
+ L2_PAGETABLE_XEN_SLOTS * sizeof(l2_pgentry_t));
+ for ( i = 0; i < (PERDOMAIN_MBYTES >> (L2_PAGETABLE_SHIFT - 20)); i++ )
+ pl2e[l2_table_offset(PERDOMAIN_VIRT_START) + i] =
+ l2e_from_page(
+ virt_to_page(page_get_owner(page)->arch.mm_perdomain_pt) + i,
+ __PAGE_HYPERVISOR);
+ for ( i = 0; i < (LINEARPT_MBYTES >> (L2_PAGETABLE_SHIFT - 20)); i++ )
+ pl2e[l2_table_offset(LINEAR_PT_VIRT_START) + i] =
+ (l3e_get_flags(pl3e[i]) & _PAGE_PRESENT) ?
+ l2e_from_pfn(l3e_get_pfn(pl3e[i]), __PAGE_HYPERVISOR) :
+ l2e_empty();
+ unmap_domain_page(pl2e);
return 1;
}
-static inline unsigned long fixup_pae_vaddr(unsigned long l2vaddr,
- unsigned long l2type)
+static inline int l1_backptr(
+ unsigned long *backptr, unsigned long offset_in_l2, unsigned long l2_type)
{
- unsigned long l3vaddr;
-
- if ((l2type & PGT_va_mask) == PGT_va_unknown) {
- printk("%s: hooking one l2 pt into multiple l3 slots isn't allowed, sorry\n",
- __FUNCTION__);
- domain_crash();
- }
- l3vaddr = ((l2type & PGT_va_mask) >> PGT_va_shift)
- << L3_PAGETABLE_SHIFT;
- return l3vaddr + l2vaddr;
+ unsigned long l2_backptr = l2_type & PGT_va_mask;
+ BUG_ON(l2_backptr == PGT_va_unknown);
+ if ( l2_backptr == PGT_va_mutable )
+ return 0;
+ *backptr =
+ ((l2_backptr >> PGT_va_shift) << L3_PAGETABLE_SHIFT) |
+ (offset_in_l2 << L2_PAGETABLE_SHIFT);
+ return 1;
}
#else
-# define fixup_pae_linear_mappings(unused) (1)
-# define fixup_pae_vaddr(vaddr, type) (vaddr)
+# define create_pae_xen_mappings(pl3e) (1)
+# define l1_backptr(bp,l2o,l2t) \
+ ({ *(bp) = (l2o) << L2_PAGETABLE_SHIFT; 1; })
#endif
static int alloc_l2_table(struct pfn_info *page, unsigned int type)
@@ -742,18 +767,18 @@ static int alloc_l2_table(struct pfn_info *page, unsigned int type)
l2_pgentry_t *pl2e;
int i;
- // See the code in shadow_promote() to understand why this is here...
+ /* See the code in shadow_promote() to understand why this is here. */
if ( (PGT_base_page_table == PGT_l2_page_table) &&
unlikely(shadow_mode_refcounts(d)) )
return 1;
- ASSERT( !shadow_mode_refcounts(d) );
-
+ ASSERT(!shadow_mode_refcounts(d));
- pl2e = map_domain_mem(pfn << PAGE_SHIFT);
+ pl2e = map_domain_page(pfn);
- for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ ) {
- vaddr = i << L2_PAGETABLE_SHIFT;
- vaddr = fixup_pae_vaddr(vaddr,type);
+ for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ )
+ {
+ if ( !l1_backptr(&vaddr, i, type) )
+ goto fail;
if ( is_guest_l2_slot(type, i) &&
unlikely(!get_page_from_l2e(pl2e[i], pfn, d, vaddr)) )
goto fail;
@@ -771,26 +796,8 @@ static int alloc_l2_table(struct pfn_info *page, unsigned int type)
virt_to_page(page_get_owner(page)->arch.mm_perdomain_pt),
__PAGE_HYPERVISOR);
#endif
-#if CONFIG_PAGING_LEVELS == 3
- if (3 == ((type & PGT_va_mask) >> PGT_va_shift)) {
- unsigned long v,src,dst;
- void *virt;
- /* Xen private mappings. */
- dst = L2_PAGETABLE_FIRST_XEN_SLOT & (L2_PAGETABLE_ENTRIES-1);
- src = L2_PAGETABLE_FIRST_XEN_SLOT;
- memcpy(&pl2e[dst], &idle_pg_table_l2[src],
- L2_PAGETABLE_XEN_SLOTS * sizeof(l2_pgentry_t));
- for (v = PERDOMAIN_VIRT_START; v < PERDOMAIN_VIRT_END;
- v += (1 << L2_PAGETABLE_SHIFT)) {
- dst = (v >> L2_PAGETABLE_SHIFT) & (L2_PAGETABLE_ENTRIES-1);
- virt = page_get_owner(page)->arch.mm_perdomain_pt + (v-PERDOMAIN_VIRT_START);
- pl2e[dst] = l2e_from_page(virt_to_page(virt), __PAGE_HYPERVISOR);
- }
- /* see fixup_pae_linear_mappings() for linear pagetables */
- }
-#endif
- unmap_domain_mem(pl2e);
+ unmap_domain_page(pl2e);
return 1;
fail:
@@ -798,13 +805,12 @@ static int alloc_l2_table(struct pfn_info *page, unsigned int type)
if ( is_guest_l2_slot(type, i) )
put_page_from_l2e(pl2e[i], pfn);
- unmap_domain_mem(pl2e);
+ unmap_domain_page(pl2e);
return 0;
}
#if CONFIG_PAGING_LEVELS >= 3
-
static int alloc_l3_table(struct pfn_info *page)
{
struct domain *d = page_get_owner(page);
@@ -813,19 +819,21 @@ static int alloc_l3_table(struct pfn_info *page)
l3_pgentry_t *pl3e;
int i;
- ASSERT( !shadow_mode_refcounts(d) );
+ ASSERT(!shadow_mode_refcounts(d));
- pl3e = map_domain_mem(pfn << PAGE_SHIFT);
- for ( i = 0; i < L3_PAGETABLE_ENTRIES; i++ ) {
+ pl3e = map_domain_page(pfn);
+ for ( i = 0; i < L3_PAGETABLE_ENTRIES; i++ )
+ {
vaddr = i << L3_PAGETABLE_SHIFT;
if ( is_guest_l3_slot(i) &&
unlikely(!get_page_from_l3e(pl3e[i], pfn, d, vaddr)) )
goto fail;
}
- if (!fixup_pae_linear_mappings(pl3e))
+ if ( !create_pae_xen_mappings(pl3e) )
goto fail;
- unmap_domain_mem(pl3e);
+
+ unmap_domain_page(pl3e);
return 1;
fail:
@@ -833,14 +841,14 @@ static int alloc_l3_table(struct pfn_info *page)
if ( is_guest_l3_slot(i) )
put_page_from_l3e(pl3e[i], pfn);
- unmap_domain_mem(pl3e);
+ unmap_domain_page(pl3e);
return 0;
}
-
+#else
+#define alloc_l3_table(page) (0)
#endif
#if CONFIG_PAGING_LEVELS >= 4
-
static int alloc_l4_table(struct pfn_info *page)
{
struct domain *d = page_get_owner(page);
@@ -848,12 +856,11 @@ static int alloc_l4_table(struct pfn_info *page)
l4_pgentry_t *pl4e = page_to_virt(page);
int i;
- // See the code in shadow_promote() to understand why this is here...
+ /* See the code in shadow_promote() to understand why this is here. */
if ( (PGT_base_page_table == PGT_l4_page_table) &&
shadow_mode_refcounts(d) )
return 1;
-
- ASSERT( !shadow_mode_refcounts(d) );
+ ASSERT(!shadow_mode_refcounts(d));
for ( i = 0; i < L4_PAGETABLE_ENTRIES; i++ )
if ( is_guest_l4_slot(i) &&
@@ -880,8 +887,9 @@ static int alloc_l4_table(struct pfn_info *page)
return 0;
}
-
-#endif /* __x86_64__ */
+#else
+#define alloc_l4_table(page) (0)
+#endif
static void free_l1_table(struct pfn_info *page)
@@ -891,13 +899,13 @@ static void free_l1_table(struct pfn_info *page)
l1_pgentry_t *pl1e;
int i;
- pl1e = map_domain_mem(pfn << PAGE_SHIFT);
+ pl1e = map_domain_page(pfn);
for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
if ( is_guest_l1_slot(i) )
put_page_from_l1e(pl1e[i], d);
- unmap_domain_mem(pl1e);
+ unmap_domain_page(pl1e);
}
@@ -907,14 +915,13 @@ static void free_l2_table(struct pfn_info *page)
l2_pgentry_t *pl2e;
int i;
- pl2e = map_domain_mem(pfn << PAGE_SHIFT);
+ pl2e = map_domain_page(pfn);
- for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ ) {
+ for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ )
if ( is_guest_l2_slot(page->u.inuse.type_info, i) )
put_page_from_l2e(pl2e[i], pfn);
- }
- unmap_domain_mem(pl2e);
+ unmap_domain_page(pl2e);
}
@@ -926,13 +933,13 @@ static void free_l3_table(struct pfn_info *page)
l3_pgentry_t *pl3e;
int i;
- pl3e = map_domain_mem(pfn << PAGE_SHIFT);
+ pl3e = map_domain_page(pfn);
for ( i = 0; i < L3_PAGETABLE_ENTRIES; i++ )
if ( is_guest_l3_slot(i) )
put_page_from_l3e(pl3e[i], pfn);
- unmap_domain_mem(pl3e);
+ unmap_domain_page(pl3e);
}
#endif
@@ -1060,10 +1067,8 @@ static int mod_l2_entry(l2_pgentry_t *pl2e,
if ( !l2e_has_changed(ol2e, nl2e, _PAGE_PRESENT))
return UPDATE_ENTRY(l2, pl2e, ol2e, nl2e);
- vaddr = (((unsigned long)pl2e & ~PAGE_MASK) / sizeof(l2_pgentry_t))
- << L2_PAGETABLE_SHIFT;
- vaddr = fixup_pae_vaddr(vaddr,type);
- if ( unlikely(!get_page_from_l2e(nl2e, pfn, current->domain, vaddr)) )
+ if ( unlikely(!l1_backptr(&vaddr, pgentry_ptr_to_slot(pl2e), type)) ||
+ unlikely(!get_page_from_l2e(nl2e, pfn, current->domain, vaddr)) )
return 0;
if ( unlikely(!UPDATE_ENTRY(l2, pl2e, ol2e, nl2e)) )
@@ -1099,6 +1104,15 @@ static int mod_l3_entry(l3_pgentry_t *pl3e,
return 0;
}
+#ifdef CONFIG_X86_PAE
+ /*
+ * Disallow updates to final L3 slot. It contains Xen mappings, and it
+ * would be a pain to ensure they remain continuously valid throughout.
+ */
+ if ( pgentry_ptr_to_slot(pl3e) >= 3 )
+ return 0;
+#endif
+
if ( unlikely(__copy_from_user(&ol3e, pl3e, sizeof(ol3e)) != 0) )
return 0;
@@ -1120,9 +1134,9 @@ static int mod_l3_entry(l3_pgentry_t *pl3e,
if ( unlikely(!get_page_from_l3e(nl3e, pfn, current->domain, vaddr)) )
return 0;
- if ( unlikely(!UPDATE_ENTRY(l3, pl3e, ol3e, nl3e) ||
- !fixup_pae_linear_mappings(pl3e)) )
+ if ( unlikely(!UPDATE_ENTRY(l3, pl3e, ol3e, nl3e)) )
{
+ BUG_ON(!create_pae_xen_mappings(pl3e));
put_page_from_l3e(nl3e, pfn);
return 0;
}
@@ -1131,9 +1145,11 @@ static int mod_l3_entry(l3_pgentry_t *pl3e,
return 1;
}
- if ( unlikely(!UPDATE_ENTRY(l3, pl3e, ol3e, nl3e) ||
- !fixup_pae_linear_mappings(pl3e)) )
+ if ( unlikely(!UPDATE_ENTRY(l3, pl3e, ol3e, nl3e)) )
+ {
+ BUG_ON(!create_pae_xen_mappings(pl3e));
return 0;
+ }
put_page_from_l3e(ol3e, pfn);
return 1;
@@ -1202,14 +1218,10 @@ int alloc_page_type(struct pfn_info *page, unsigned int type)
return alloc_l1_table(page);
case PGT_l2_page_table:
return alloc_l2_table(page, type);
-#if CONFIG_PAGING_LEVELS >= 3
case PGT_l3_page_table:
return alloc_l3_table(page);
-#endif
-#if CONFIG_PAGING_LEVELS >= 4
case PGT_l4_page_table:
return alloc_l4_table(page);
-#endif
case PGT_gdt_page:
case PGT_ldt_page:
return alloc_segdesc_page(page);
@@ -1388,13 +1400,14 @@ int get_page_type(struct pfn_info *page, u32 type)
else if ( ((type & PGT_va_mask) != PGT_va_mutable) &&
((type & PGT_va_mask) != (x & PGT_va_mask)) )
{
- /* This table is may be mapped at multiple locations. */
+#ifdef CONFIG_X86_PAE
+ /* We use backptr as extra typing. Cannot be unknown. */
+ if ( (type & PGT_type_mask) == PGT_l2_page_table )
+ return 0;
+#endif
+ /* This table is possibly mapped at multiple locations. */
nx &= ~PGT_va_mask;
nx |= PGT_va_unknown;
-#if 0 /* debug */
- printk("%s: pfn %lx type %x -> %x (tag as unknown)\n",
- __FUNCTION__,page_to_pfn(page),x,nx);
-#endif
}
}
if ( unlikely(!(x & PGT_validated)) )
@@ -1658,21 +1671,19 @@ int do_mmuext_op(
break;
+#ifndef CONFIG_X86_PAE /* Unsafe on PAE because of Xen-private mappings. */
case MMUEXT_PIN_L2_TABLE:
type = PGT_l2_page_table;
goto pin_page;
+#endif
-#if CONFIG_PAGING_LEVELS >= 3
case MMUEXT_PIN_L3_TABLE:
type = PGT_l3_page_table;
goto pin_page;
-#endif
-#if CONFIG_PAGING_LEVELS >= 4
case MMUEXT_PIN_L4_TABLE:
type = PGT_l4_page_table;
goto pin_page;
-#endif
case MMUEXT_UNPIN_TABLE:
if ( unlikely(!(okay = get_page_from_pagenr(op.mfn, FOREIGNDOM))) )
@@ -1940,7 +1951,7 @@ int do_mmu_update(
struct vcpu *v = current;
struct domain *d = v->domain;
u32 type_info;
- struct map_dom_mem_cache mapcache, sh_mapcache;
+ struct domain_mmap_cache mapcache, sh_mapcache;
LOCK_BIGLOCK(d);
@@ -1956,8 +1967,8 @@ int do_mmu_update(
(void)get_user(done, pdone);
}
- init_map_domain_mem_cache(&mapcache);
- init_map_domain_mem_cache(&sh_mapcache);
+ domain_mmap_cache_init(&mapcache);
+ domain_mmap_cache_init(&sh_mapcache);
if ( !set_foreigndom(cpu, foreigndom) )
{
@@ -2011,7 +2022,8 @@ int do_mmu_update(
break;
}
- va = map_domain_mem_with_cache(req.ptr, &mapcache);
+ va = map_domain_page_with_cache(mfn, &mapcache);
+ va = (void *)((unsigned long)va + (req.ptr & ~PAGE_MASK));
page = &frame_table[mfn];
switch ( (type_info = page->u.inuse.type_info) & PGT_type_mask )
@@ -2105,7 +2117,7 @@ int do_mmu_update(
break;
}
- unmap_domain_mem_with_cache(va, &mapcache);
+ unmap_domain_page_with_cache(va, &mapcache);
put_page(page);
break;
@@ -2169,8 +2181,8 @@ int do_mmu_update(
}
out:
- destroy_map_domain_mem_cache(&mapcache);
- destroy_map_domain_mem_cache(&sh_mapcache);
+ domain_mmap_cache_destroy(&mapcache);
+ domain_mmap_cache_destroy(&sh_mapcache);
process_deferred_ops(cpu);
@@ -2452,6 +2464,7 @@ long do_update_descriptor(unsigned long pa, u64 desc)
struct domain *dom = current->domain;
unsigned long gpfn = pa >> PAGE_SHIFT;
unsigned long mfn;
+ unsigned int offset = (pa & ~PAGE_MASK) / sizeof(struct desc_struct);
struct desc_struct *gdt_pent, d;
struct pfn_info *page;
long ret = -EINVAL;
@@ -2460,18 +2473,18 @@ long do_update_descriptor(unsigned long pa, u64 desc)
LOCK_BIGLOCK(dom);
- if ( !VALID_MFN(mfn = __gpfn_to_mfn(dom, gpfn)) ) {
- UNLOCK_BIGLOCK(dom);
- return -EINVAL;
- }
-
- if ( (pa & 7) || (mfn >= max_page) || !check_descriptor(&d) ) {
+ if ( !VALID_MFN(mfn = __gpfn_to_mfn(dom, gpfn)) ||
+ ((pa % sizeof(struct desc_struct)) != 0) ||
+ (mfn >= max_page) ||
+ !check_descriptor(&d) )
+ {
UNLOCK_BIGLOCK(dom);
return -EINVAL;
}
page = &frame_table[mfn];
- if ( unlikely(!get_page(page, dom)) ) {
+ if ( unlikely(!get_page(page, dom)) )
+ {
UNLOCK_BIGLOCK(dom);
return -EINVAL;
}
@@ -2505,9 +2518,9 @@ long do_update_descriptor(unsigned long pa, u64 desc)
}
/* All is good so make the update. */
- gdt_pent = map_domain_mem((mfn << PAGE_SHIFT) | (pa & ~PAGE_MASK));
- memcpy(gdt_pent, &d, 8);
- unmap_domain_mem(gdt_pent);
+ gdt_pent = map_domain_page(mfn);
+ memcpy(&gdt_pent[offset], &d, 8);
+ unmap_domain_page(gdt_pent);
if ( shadow_mode_enabled(dom) )
shadow_unlock(dom);
@@ -2650,7 +2663,7 @@ void ptwr_flush(struct domain *d, const int which)
pl1e = d->arch.ptwr[which].pl1e;
modified = revalidate_l1(d, pl1e, d->arch.ptwr[which].page);
- unmap_domain_mem(pl1e);
+ unmap_domain_page(pl1e);
perfc_incr_histo(wpt_updates, modified, PT_UPDATES);
d->arch.ptwr[which].prev_nr_updates = modified;
@@ -2741,13 +2754,14 @@ static int ptwr_emulated_update(
return X86EMUL_UNHANDLEABLE;
/* Checked successfully: do the update (write or cmpxchg). */
- pl1e = map_domain_mem(page_to_phys(page) + (addr & ~PAGE_MASK));
+ pl1e = map_domain_page(page_to_pfn(page));
+ pl1e = (l1_pgentry_t *)((unsigned long)pl1e + (addr & ~PAGE_MASK));
if ( do_cmpxchg )
{
ol1e = l1e_from_intpte(old);
if ( cmpxchg((unsigned long *)pl1e, old, val) != old )
{
- unmap_domain_mem(pl1e);
+ unmap_domain_page(pl1e);
put_page_from_l1e(nl1e, d);
return X86EMUL_CMPXCHG_FAILED;
}
@@ -2757,7 +2771,7 @@ static int ptwr_emulated_update(
ol1e = *pl1e;
*pl1e = nl1e;
}
- unmap_domain_mem(pl1e);
+ unmap_domain_page(pl1e);
/* Finally, drop the old PTE. */
put_page_from_l1e(ol1e, d);
@@ -2909,7 +2923,7 @@ int ptwr_do_page_fault(struct domain *d, unsigned long addr)
}
/* Temporarily map the L1 page, and make a copy of it. */
- d->arch.ptwr[which].pl1e = map_domain_mem(pfn << PAGE_SHIFT);
+ d->arch.ptwr[which].pl1e = map_domain_page(pfn);
memcpy(d->arch.ptwr[which].page,
d->arch.ptwr[which].pl1e,
L1_PAGETABLE_ENTRIES * sizeof(l1_pgentry_t));
@@ -2922,7 +2936,7 @@ int ptwr_do_page_fault(struct domain *d, unsigned long addr)
MEM_LOG("ptwr: Could not update pte at %p", (unsigned long *)
&linear_pg_table[addr>>PAGE_SHIFT]);
/* Toss the writable pagetable state and crash. */
- unmap_domain_mem(d->arch.ptwr[which].pl1e);
+ unmap_domain_page(d->arch.ptwr[which].pl1e);
d->arch.ptwr[which].l1va = 0;
domain_crash();
return 0;
diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c
index 6eba1bfb22..1cbed74240 100644
--- a/xen/arch/x86/physdev.c
+++ b/xen/arch/x86/physdev.c
@@ -60,7 +60,7 @@ long do_physdev_op(physdev_op_t *uop)
break;
op.u.irq_status_query.flags = 0;
/* Edge-triggered interrupts don't need an explicit unmask downcall. */
- if ( strstr(irq_desc[irq].handler->typename, "edge") == NULL )
+ if ( strstr(irq_desc[irq_to_vector(irq)].handler->typename, "edge") == NULL )
op.u.irq_status_query.flags |= PHYSDEVOP_IRQ_NEEDS_UNMASK_NOTIFY;
ret = 0;
break;
@@ -89,7 +89,6 @@ long do_physdev_op(physdev_op_t *uop)
return -EINVAL;
op.u.irq_op.vector = assign_irq_vector(irq);
- set_intr_gate(op.u.irq_op.vector, interrupt[irq]);
ret = 0;
break;
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index c0db9f9c7d..0903967796 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -11,13 +11,13 @@
#include <xen/serial.h>
#include <xen/trace.h>
#include <xen/multiboot.h>
+#include <xen/domain_page.h>
#include <asm/bitops.h>
#include <asm/smp.h>
#include <asm/processor.h>
#include <asm/mpspec.h>
#include <asm/apic.h>
#include <asm/desc.h>
-#include <asm/domain_page.h>
#include <asm/shadow.h>
#include <asm/e820.h>
@@ -33,10 +33,6 @@ static unsigned int opt_xenheap_megabytes = XENHEAP_DEFAULT_MB;
integer_param("xenheap_megabytes", opt_xenheap_megabytes);
#endif
-/* opt_noht: If true, Hyperthreading is ignored. */
-int opt_noht = 0;
-boolean_param("noht", opt_noht);
-
/* opt_nosmp: If true, secondary processors are ignored. */
static int opt_nosmp = 0;
boolean_param("nosmp", opt_nosmp);
@@ -409,7 +405,7 @@ void __init __start_xen(multiboot_info_t *mbi)
cmdline = (char *)(mod[0].string ? __va(mod[0].string) : NULL);
if ( cmdline != NULL )
{
- static char dom0_cmdline[256];
+ static char dom0_cmdline[MAX_GUEST_CMDLINE];
/* Skip past the image name. */
while ( *cmdline == ' ' ) cmdline++;
diff --git a/xen/arch/x86/shadow.c b/xen/arch/x86/shadow.c
index cd71ee48af..bac8f23ad6 100644
--- a/xen/arch/x86/shadow.c
+++ b/xen/arch/x86/shadow.c
@@ -23,8 +23,8 @@
#include <xen/config.h>
#include <xen/types.h>
#include <xen/mm.h>
+#include <xen/domain_page.h>
#include <asm/shadow.h>
-#include <asm/domain_page.h>
#include <asm/page.h>
#include <xen/event.h>
#include <xen/sched.h>
@@ -222,9 +222,9 @@ alloc_shadow_page(struct domain *d,
else
{
page = alloc_domheap_page(NULL);
- void *l1 = map_domain_mem(page_to_phys(page));
+ void *l1 = map_domain_page(page_to_pfn(page));
memset(l1, 0, PAGE_SIZE);
- unmap_domain_mem(l1);
+ unmap_domain_page(l1);
}
}
else
@@ -315,7 +315,7 @@ alloc_shadow_page(struct domain *d,
static void inline
free_shadow_l1_table(struct domain *d, unsigned long smfn)
{
- l1_pgentry_t *pl1e = map_domain_mem(smfn << PAGE_SHIFT);
+ l1_pgentry_t *pl1e = map_domain_page(smfn);
int i;
struct pfn_info *spage = pfn_to_page(smfn);
u32 min_max = spage->tlbflush_timestamp;
@@ -328,13 +328,13 @@ free_shadow_l1_table(struct domain *d, unsigned long smfn)
pl1e[i] = l1e_empty();
}
- unmap_domain_mem(pl1e);
+ unmap_domain_page(pl1e);
}
static void inline
free_shadow_hl2_table(struct domain *d, unsigned long smfn)
{
- l1_pgentry_t *hl2 = map_domain_mem(smfn << PAGE_SHIFT);
+ l1_pgentry_t *hl2 = map_domain_page(smfn);
int i, limit;
SH_VVLOG("%s: smfn=%lx freed", __func__, smfn);
@@ -354,13 +354,13 @@ free_shadow_hl2_table(struct domain *d, unsigned long smfn)
put_page(pfn_to_page(l1e_get_pfn(hl2[i])));
}
- unmap_domain_mem(hl2);
+ unmap_domain_page(hl2);
}
static void inline
free_shadow_l2_table(struct domain *d, unsigned long smfn, unsigned int type)
{
- l2_pgentry_t *pl2e = map_domain_mem(smfn << PAGE_SHIFT);
+ l2_pgentry_t *pl2e = map_domain_page(smfn);
int i, external = shadow_mode_external(d);
for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ )
@@ -376,7 +376,7 @@ free_shadow_l2_table(struct domain *d, unsigned long smfn, unsigned int type)
put_shadow_ref(l2e_get_pfn(pl2e[l2_table_offset(LINEAR_PT_VIRT_START)]));
}
- unmap_domain_mem(pl2e);
+ unmap_domain_page(pl2e);
}
void free_shadow_page(unsigned long smfn)
@@ -689,8 +689,8 @@ static void alloc_monitor_pagetable(struct vcpu *v)
mmfn_info = alloc_domheap_page(NULL);
ASSERT(mmfn_info != NULL);
- mmfn = (unsigned long) (mmfn_info - frame_table);
- mpl2e = (l2_pgentry_t *) map_domain_mem(mmfn << PAGE_SHIFT);
+ mmfn = page_to_pfn(mmfn_info);
+ mpl2e = (l2_pgentry_t *)map_domain_page(mmfn);
memset(mpl2e, 0, PAGE_SIZE);
#ifdef __i386__ /* XXX screws x86/64 build */
@@ -749,7 +749,7 @@ void free_monitor_pagetable(struct vcpu *v)
put_shadow_ref(mfn);
}
- unmap_domain_mem(mpl2e);
+ unmap_domain_page(mpl2e);
/*
* Then free monitor_table.
@@ -763,40 +763,40 @@ void free_monitor_pagetable(struct vcpu *v)
int
set_p2m_entry(struct domain *d, unsigned long pfn, unsigned long mfn,
- struct map_dom_mem_cache *l2cache,
- struct map_dom_mem_cache *l1cache)
+ struct domain_mmap_cache *l2cache,
+ struct domain_mmap_cache *l1cache)
{
- unsigned long phystab = pagetable_get_paddr(d->arch.phys_table);
+ unsigned long tabpfn = pagetable_get_pfn(d->arch.phys_table);
l2_pgentry_t *l2, l2e;
l1_pgentry_t *l1;
struct pfn_info *l1page;
unsigned long va = pfn << PAGE_SHIFT;
- ASSERT( phystab );
+ ASSERT(tabpfn != 0);
- l2 = map_domain_mem_with_cache(phystab, l2cache);
+ l2 = map_domain_page_with_cache(tabpfn, l2cache);
l2e = l2[l2_table_offset(va)];
if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) )
{
l1page = alloc_domheap_page(NULL);
if ( !l1page )
{
- unmap_domain_mem_with_cache(l2, l2cache);
+ unmap_domain_page_with_cache(l2, l2cache);
return 0;
}
- l1 = map_domain_mem_with_cache(page_to_phys(l1page), l1cache);
+ l1 = map_domain_page_with_cache(page_to_pfn(l1page), l1cache);
memset(l1, 0, PAGE_SIZE);
- unmap_domain_mem_with_cache(l1, l1cache);
+ unmap_domain_page_with_cache(l1, l1cache);
l2e = l2e_from_page(l1page, __PAGE_HYPERVISOR);
l2[l2_table_offset(va)] = l2e;
}
- unmap_domain_mem_with_cache(l2, l2cache);
+ unmap_domain_page_with_cache(l2, l2cache);
- l1 = map_domain_mem_with_cache(l2e_get_paddr(l2e), l1cache);
+ l1 = map_domain_page_with_cache(l2e_get_pfn(l2e), l1cache);
l1[l1_table_offset(va)] = l1e_from_pfn(mfn, __PAGE_HYPERVISOR);
- unmap_domain_mem_with_cache(l1, l1cache);
+ unmap_domain_page_with_cache(l1, l1cache);
return 1;
}
@@ -808,19 +808,19 @@ alloc_p2m_table(struct domain *d)
struct pfn_info *page, *l2page;
l2_pgentry_t *l2;
unsigned long mfn, pfn;
- struct map_dom_mem_cache l1cache, l2cache;
+ struct domain_mmap_cache l1cache, l2cache;
l2page = alloc_domheap_page(NULL);
if ( l2page == NULL )
return 0;
- init_map_domain_mem_cache(&l1cache);
- init_map_domain_mem_cache(&l2cache);
+ domain_mmap_cache_init(&l1cache);
+ domain_mmap_cache_init(&l2cache);
d->arch.phys_table = mk_pagetable(page_to_phys(l2page));
- l2 = map_domain_mem_with_cache(page_to_phys(l2page), &l2cache);
+ l2 = map_domain_page_with_cache(page_to_pfn(l2page), &l2cache);
memset(l2, 0, PAGE_SIZE);
- unmap_domain_mem_with_cache(l2, &l2cache);
+ unmap_domain_page_with_cache(l2, &l2cache);
list_ent = d->page_list.next;
while ( list_ent != &d->page_list )
@@ -851,8 +851,8 @@ alloc_p2m_table(struct domain *d)
list_ent = page->list.next;
}
- destroy_map_domain_mem_cache(&l2cache);
- destroy_map_domain_mem_cache(&l1cache);
+ domain_mmap_cache_destroy(&l2cache);
+ domain_mmap_cache_destroy(&l1cache);
return 1;
}
@@ -888,7 +888,7 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode)
if ( v->arch.guest_vtable &&
(v->arch.guest_vtable != __linear_l2_table) )
{
- unmap_domain_mem(v->arch.guest_vtable);
+ unmap_domain_page(v->arch.guest_vtable);
}
if ( (mode & (SHM_translate | SHM_external)) == SHM_translate )
v->arch.guest_vtable = __linear_l2_table;
@@ -901,7 +901,7 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode)
if ( v->arch.shadow_vtable &&
(v->arch.shadow_vtable != __shadow_linear_l2_table) )
{
- unmap_domain_mem(v->arch.shadow_vtable);
+ unmap_domain_page(v->arch.shadow_vtable);
}
if ( !(mode & SHM_external) )
v->arch.shadow_vtable = __shadow_linear_l2_table;
@@ -914,7 +914,7 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode)
if ( v->arch.hl2_vtable &&
(v->arch.hl2_vtable != __linear_hl2_table) )
{
- unmap_domain_mem(v->arch.hl2_vtable);
+ unmap_domain_page(v->arch.hl2_vtable);
}
if ( (mode & (SHM_translate | SHM_external)) == SHM_translate )
v->arch.hl2_vtable = __linear_hl2_table;
@@ -1073,7 +1073,7 @@ translate_l1pgtable(struct domain *d, l1_pgentry_t *p2m, unsigned long l1mfn)
int i;
l1_pgentry_t *l1;
- l1 = map_domain_mem(l1mfn << PAGE_SHIFT);
+ l1 = map_domain_page(l1mfn);
for (i = 0; i < L1_PAGETABLE_ENTRIES; i++)
{
if ( is_guest_l1_slot(i) &&
@@ -1085,7 +1085,7 @@ translate_l1pgtable(struct domain *d, l1_pgentry_t *p2m, unsigned long l1mfn)
l1[i] = l1e_from_pfn(gpfn, l1e_get_flags(l1[i]));
}
}
- unmap_domain_mem(l1);
+ unmap_domain_page(l1);
}
// This is not general enough to handle arbitrary pagetables
@@ -1101,7 +1101,7 @@ translate_l2pgtable(struct domain *d, l1_pgentry_t *p2m, unsigned long l2mfn,
ASSERT(shadow_mode_translate(d) && !shadow_mode_external(d));
- l2 = map_domain_mem(l2mfn << PAGE_SHIFT);
+ l2 = map_domain_page(l2mfn);
for (i = 0; i < L2_PAGETABLE_ENTRIES; i++)
{
if ( is_guest_l2_slot(type, i) &&
@@ -1114,7 +1114,7 @@ translate_l2pgtable(struct domain *d, l1_pgentry_t *p2m, unsigned long l2mfn,
translate_l1pgtable(d, p2m, mfn);
}
}
- unmap_domain_mem(l2);
+ unmap_domain_page(l2);
}
static void free_shadow_ht_entries(struct domain *d)
@@ -1404,24 +1404,23 @@ gpfn_to_mfn_foreign(struct domain *d, unsigned long gpfn)
perfc_incrc(gpfn_to_mfn_foreign);
unsigned long va = gpfn << PAGE_SHIFT;
- unsigned long phystab = pagetable_get_paddr(d->arch.phys_table);
- l2_pgentry_t *l2 = map_domain_mem(phystab);
+ unsigned long tabpfn = pagetable_get_pfn(d->arch.phys_table);
+ l2_pgentry_t *l2 = map_domain_page(tabpfn);
l2_pgentry_t l2e = l2[l2_table_offset(va)];
- unmap_domain_mem(l2);
+ unmap_domain_page(l2);
if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) )
{
printk("gpfn_to_mfn_foreign(d->id=%d, gpfn=%lx) => 0 l2e=%" PRIpte "\n",
d->domain_id, gpfn, l2e_get_intpte(l2e));
return INVALID_MFN;
}
- unsigned long l1tab = l2e_get_paddr(l2e);
- l1_pgentry_t *l1 = map_domain_mem(l1tab);
+ l1_pgentry_t *l1 = map_domain_page(l2e_get_pfn(l2e));
l1_pgentry_t l1e = l1[l1_table_offset(va)];
- unmap_domain_mem(l1);
+ unmap_domain_page(l1);
#if 0
- printk("gpfn_to_mfn_foreign(d->id=%d, gpfn=%lx) => %lx phystab=%lx l2e=%lx l1tab=%lx, l1e=%lx\n",
- d->domain_id, gpfn, l1_pgentry_val(l1e) >> PAGE_SHIFT, phystab, l2e, l1tab, l1e);
+ printk("gpfn_to_mfn_foreign(d->id=%d, gpfn=%lx) => %lx tabpfn=%lx l2e=%lx l1tab=%lx, l1e=%lx\n",
+ d->domain_id, gpfn, l1_pgentry_val(l1e) >> PAGE_SHIFT, tabpfn, l2e, l1tab, l1e);
#endif
if ( !(l1e_get_flags(l1e) & _PAGE_PRESENT) )
@@ -1455,7 +1454,7 @@ shadow_hl2_table(struct domain *d, unsigned long gpfn, unsigned long gmfn,
gpfn, gmfn, smfn, hl2mfn);
perfc_incrc(shadow_hl2_table_count);
- hl2 = map_domain_mem(hl2mfn << PAGE_SHIFT);
+ hl2 = map_domain_page(hl2mfn);
#ifdef __i386__
if ( shadow_mode_external(d) )
@@ -1483,7 +1482,7 @@ shadow_hl2_table(struct domain *d, unsigned long gpfn, unsigned long gmfn,
l1e_from_pfn(hl2mfn, __PAGE_HYPERVISOR);
}
- unmap_domain_mem(hl2);
+ unmap_domain_page(hl2);
return hl2mfn;
}
@@ -1510,7 +1509,7 @@ static unsigned long shadow_l2_table(
BUG(); /* XXX Deal gracefully with failure. */
}
- spl2e = (l2_pgentry_t *)map_domain_mem(smfn << PAGE_SHIFT);
+ spl2e = (l2_pgentry_t *)map_domain_page(smfn);
/* Install hypervisor and 2x linear p.t. mapings. */
if ( (PGT_base_page_table == PGT_l2_page_table) &&
@@ -1565,7 +1564,7 @@ static unsigned long shadow_l2_table(
memset(spl2e, 0, L2_PAGETABLE_ENTRIES*sizeof(l2_pgentry_t));
}
- unmap_domain_mem(spl2e);
+ unmap_domain_page(spl2e);
SH_VLOG("shadow_l2_table(%lx -> %lx)", gmfn, smfn);
return smfn;
@@ -1776,11 +1775,11 @@ shadow_make_snapshot(
min *= sizeof(l1_pgentry_t);
length *= sizeof(l1_pgentry_t);
- original = map_domain_mem(gmfn << PAGE_SHIFT);
- snapshot = map_domain_mem(smfn << PAGE_SHIFT);
+ original = map_domain_page(gmfn);
+ snapshot = map_domain_page(smfn);
memcpy(snapshot + min, original + min, length);
- unmap_domain_mem(original);
- unmap_domain_mem(snapshot);
+ unmap_domain_page(original);
+ unmap_domain_page(snapshot);
return smfn;
}
@@ -1800,9 +1799,9 @@ shadow_free_snapshot(struct domain *d, struct out_of_sync_entry *entry)
// XXX Need to think about how to protect the domain's
// information less expensively.
//
- snapshot = map_domain_mem(entry->snapshot_mfn << PAGE_SHIFT);
+ snapshot = map_domain_page(entry->snapshot_mfn);
memset(snapshot, 0, PAGE_SIZE);
- unmap_domain_mem(snapshot);
+ unmap_domain_page(snapshot);
put_shadow_ref(entry->snapshot_mfn);
}
@@ -1915,7 +1914,7 @@ static int snapshot_entry_matches(
if ( !smfn )
return 0;
- snapshot = map_domain_mem(smfn << PAGE_SHIFT);
+ snapshot = map_domain_page(smfn);
// This could probably be smarter, but this is sufficent for
// our current needs.
@@ -1923,7 +1922,7 @@ static int snapshot_entry_matches(
entries_match = !l1e_has_changed(guest_pt[index], snapshot[index],
PAGE_FLAG_MASK);
- unmap_domain_mem(snapshot);
+ unmap_domain_page(snapshot);
#ifdef PERF_COUNTERS
if ( entries_match )
@@ -2065,7 +2064,7 @@ static u32 remove_all_write_access_in_ptpage(
unsigned long readonly_gpfn, unsigned long readonly_gmfn,
u32 max_refs_to_find, unsigned long prediction)
{
- l1_pgentry_t *pt = map_domain_mem(pt_mfn << PAGE_SHIFT);
+ l1_pgentry_t *pt = map_domain_page(pt_mfn);
l1_pgentry_t match;
unsigned long flags = _PAGE_RW | _PAGE_PRESENT;
int i;
@@ -2105,7 +2104,7 @@ static u32 remove_all_write_access_in_ptpage(
{
perfc_incrc(remove_write_fast_exit);
increase_writable_pte_prediction(d, readonly_gpfn, prediction);
- unmap_domain_mem(pt);
+ unmap_domain_page(pt);
return found;
}
@@ -2115,7 +2114,7 @@ static u32 remove_all_write_access_in_ptpage(
break;
}
- unmap_domain_mem(pt);
+ unmap_domain_page(pt);
return found;
#undef MATCH_ENTRY
@@ -2207,7 +2206,7 @@ int shadow_remove_all_write_access(
static u32 remove_all_access_in_page(
struct domain *d, unsigned long l1mfn, unsigned long forbidden_gmfn)
{
- l1_pgentry_t *pl1e = map_domain_mem(l1mfn << PAGE_SHIFT);
+ l1_pgentry_t *pl1e = map_domain_page(l1mfn);
l1_pgentry_t match;
unsigned long flags = _PAGE_PRESENT;
int i;
@@ -2233,7 +2232,7 @@ static u32 remove_all_access_in_page(
}
}
- unmap_domain_mem(pl1e);
+ unmap_domain_page(pl1e);
return count;
}
@@ -2321,11 +2320,11 @@ static int resync_all(struct domain *d, u32 stype)
// Compare guest's new contents to its snapshot, validating
// and updating its shadow as appropriate.
//
- guest = map_domain_mem(entry->gmfn << PAGE_SHIFT);
- snapshot = map_domain_mem(entry->snapshot_mfn << PAGE_SHIFT);
+ guest = map_domain_page(entry->gmfn);
+ snapshot = map_domain_page(entry->snapshot_mfn);
if ( smfn )
- shadow = map_domain_mem(smfn << PAGE_SHIFT);
+ shadow = map_domain_page(smfn);
else
shadow = NULL;
@@ -2466,9 +2465,9 @@ static int resync_all(struct domain *d, u32 stype)
}
if ( smfn )
- unmap_domain_mem(shadow);
- unmap_domain_mem(snapshot);
- unmap_domain_mem(guest);
+ unmap_domain_page(shadow);
+ unmap_domain_page(snapshot);
+ unmap_domain_page(guest);
if ( unlikely(unshadow) )
{
@@ -2507,7 +2506,9 @@ void __shadow_sync_all(struct domain *d)
if ( entry->writable_pl1e & (sizeof(l1_pgentry_t)-1) )
continue;
- l1_pgentry_t *ppte = map_domain_mem(entry->writable_pl1e);
+ l1_pgentry_t *ppte = (l1_pgentry_t *)(
+ (char *)map_domain_page(entry->writable_pl1e >> PAGE_SHIFT) +
+ (entry->writable_pl1e & ~PAGE_MASK));
l1_pgentry_t opte = *ppte;
l1_pgentry_t npte = opte;
l1e_remove_flags(npte, _PAGE_RW);
@@ -2518,7 +2519,7 @@ void __shadow_sync_all(struct domain *d)
*ppte = npte;
shadow_put_page_from_l1e(opte, d);
- unmap_domain_mem(ppte);
+ unmap_domain_page(ppte);
}
// XXX mafetter: SMP
@@ -2682,7 +2683,7 @@ int shadow_fault(unsigned long va, struct cpu_user_regs *regs)
void shadow_l1_normal_pt_update(
struct domain *d,
unsigned long pa, l1_pgentry_t gpte,
- struct map_dom_mem_cache *cache)
+ struct domain_mmap_cache *cache)
{
unsigned long sl1mfn;
l1_pgentry_t *spl1e, spte;
@@ -2696,9 +2697,9 @@ void shadow_l1_normal_pt_update(
(void *)pa, l1e_get_intpte(gpte));
l1pte_propagate_from_guest(current->domain, gpte, &spte);
- spl1e = map_domain_mem_with_cache(sl1mfn << PAGE_SHIFT, cache);
+ spl1e = map_domain_page_with_cache(sl1mfn, cache);
spl1e[(pa & ~PAGE_MASK) / sizeof(l1_pgentry_t)] = spte;
- unmap_domain_mem_with_cache(spl1e, cache);
+ unmap_domain_page_with_cache(spl1e, cache);
}
shadow_unlock(d);
@@ -2707,7 +2708,7 @@ void shadow_l1_normal_pt_update(
void shadow_l2_normal_pt_update(
struct domain *d,
unsigned long pa, l2_pgentry_t gpde,
- struct map_dom_mem_cache *cache)
+ struct domain_mmap_cache *cache)
{
unsigned long sl2mfn;
l2_pgentry_t *spl2e;
@@ -2719,10 +2720,10 @@ void shadow_l2_normal_pt_update(
{
SH_VVLOG("shadow_l2_normal_pt_update pa=%p, gpde=%" PRIpte,
(void *)pa, l2e_get_intpte(gpde));
- spl2e = map_domain_mem_with_cache(sl2mfn << PAGE_SHIFT, cache);
+ spl2e = map_domain_page_with_cache(sl2mfn, cache);
validate_pde_change(d, gpde,
&spl2e[(pa & ~PAGE_MASK) / sizeof(l2_pgentry_t)]);
- unmap_domain_mem_with_cache(spl2e, cache);
+ unmap_domain_page_with_cache(spl2e, cache);
}
shadow_unlock(d);
@@ -2732,7 +2733,7 @@ void shadow_l2_normal_pt_update(
void shadow_l3_normal_pt_update(
struct domain *d,
unsigned long pa, l3_pgentry_t gpde,
- struct map_dom_mem_cache *cache)
+ struct domain_mmap_cache *cache)
{
BUG(); // not yet implemented
}
@@ -2742,7 +2743,7 @@ void shadow_l3_normal_pt_update(
void shadow_l4_normal_pt_update(
struct domain *d,
unsigned long pa, l4_pgentry_t gpde,
- struct map_dom_mem_cache *cache)
+ struct domain_mmap_cache *cache)
{
BUG(); // not yet implemented
}
@@ -2831,8 +2832,8 @@ void __update_pagetables(struct vcpu *v)
if ( max_mode & (SHM_enable | SHM_external) )
{
if ( likely(v->arch.guest_vtable != NULL) )
- unmap_domain_mem(v->arch.guest_vtable);
- v->arch.guest_vtable = map_domain_mem(gmfn << PAGE_SHIFT);
+ unmap_domain_page(v->arch.guest_vtable);
+ v->arch.guest_vtable = map_domain_page(gmfn);
}
/*
@@ -2855,8 +2856,8 @@ void __update_pagetables(struct vcpu *v)
if ( max_mode == SHM_external )
{
if ( v->arch.shadow_vtable )
- unmap_domain_mem(v->arch.shadow_vtable);
- v->arch.shadow_vtable = map_domain_mem(smfn << PAGE_SHIFT);
+ unmap_domain_page(v->arch.shadow_vtable);
+ v->arch.shadow_vtable = map_domain_page(smfn);
}
/*
@@ -2871,8 +2872,8 @@ void __update_pagetables(struct vcpu *v)
if ( unlikely(!(hl2mfn = __shadow_status(d, gpfn, PGT_hl2_shadow))) )
hl2mfn = shadow_hl2_table(d, gpfn, gmfn, smfn);
if ( v->arch.hl2_vtable )
- unmap_domain_mem(v->arch.hl2_vtable);
- v->arch.hl2_vtable = map_domain_mem(hl2mfn << PAGE_SHIFT);
+ unmap_domain_page(v->arch.hl2_vtable);
+ v->arch.hl2_vtable = map_domain_page(hl2mfn);
}
/*
@@ -2934,22 +2935,22 @@ mark_shadows_as_reflecting_snapshot(struct domain *d, unsigned long gpfn)
if ( (smfn = __shadow_status(d, gpfn, PGT_l1_shadow)) )
{
- l1e = map_domain_mem(smfn << PAGE_SHIFT);
+ l1e = map_domain_page(smfn);
for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
if ( is_guest_l1_slot(i) &&
(l1e_get_flags(l1e[i]) & _PAGE_PRESENT) )
l1e_add_flags(l1e[i], SHADOW_REFLECTS_SNAPSHOT);
- unmap_domain_mem(l1e);
+ unmap_domain_page(l1e);
}
if ( (smfn = __shadow_status(d, gpfn, PGT_l2_shadow)) )
{
- l2e = map_domain_mem(smfn << PAGE_SHIFT);
+ l2e = map_domain_page(smfn);
for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ )
if ( is_guest_l2_slot(0, i) &&
(l2e_get_flags(l2e[i]) & _PAGE_PRESENT) )
l2e_add_flags(l2e[i], SHADOW_REFLECTS_SNAPSHOT);
- unmap_domain_mem(l2e);
+ unmap_domain_page(l2e);
}
}
@@ -3117,21 +3118,21 @@ static int check_l1_table(
{
snapshot_mfn = __shadow_status(d, gpfn, PGT_snapshot);
ASSERT(snapshot_mfn);
- p_snapshot = map_domain_mem(snapshot_mfn << PAGE_SHIFT);
+ p_snapshot = map_domain_page(snapshot_mfn);
}
- p_guest = map_domain_mem(gmfn << PAGE_SHIFT);
- p_shadow = map_domain_mem(smfn << PAGE_SHIFT);
+ p_guest = map_domain_page(gmfn);
+ p_shadow = map_domain_page(smfn);
for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
errors += check_pte(v, p_guest+i, p_shadow+i,
p_snapshot ? p_snapshot+i : NULL,
1, l2_idx, i);
- unmap_domain_mem(p_shadow);
- unmap_domain_mem(p_guest);
+ unmap_domain_page(p_shadow);
+ unmap_domain_page(p_guest);
if ( p_snapshot )
- unmap_domain_mem(p_snapshot);
+ unmap_domain_page(p_snapshot);
return errors;
}
@@ -3146,8 +3147,8 @@ int check_l2_table(
struct vcpu *v, unsigned long gmfn, unsigned long smfn, int oos_pdes)
{
struct domain *d = v->domain;
- l2_pgentry_t *gpl2e = (l2_pgentry_t *)map_domain_mem(gmfn << PAGE_SHIFT);
- l2_pgentry_t *spl2e = (l2_pgentry_t *)map_domain_mem(smfn << PAGE_SHIFT);
+ l2_pgentry_t *gpl2e = (l2_pgentry_t *)map_domain_page(gmfn);
+ l2_pgentry_t *spl2e = (l2_pgentry_t *)map_domain_page(smfn);
l2_pgentry_t match;
int i;
int errors = 0;
@@ -3219,8 +3220,8 @@ int check_l2_table(
NULL,
2, i, 0);
- unmap_domain_mem(spl2e);
- unmap_domain_mem(gpl2e);
+ unmap_domain_page(spl2e);
+ unmap_domain_page(gpl2e);
#if 1
if ( errors )
@@ -3267,8 +3268,8 @@ int _check_pagetable(struct vcpu *v, char *s)
errors += check_l2_table(v, ptbase_mfn, smfn, oos_pdes);
- gpl2e = (l2_pgentry_t *) map_domain_mem( ptbase_mfn << PAGE_SHIFT );
- spl2e = (l2_pgentry_t *) map_domain_mem( smfn << PAGE_SHIFT );
+ gpl2e = (l2_pgentry_t *) map_domain_page(ptbase_mfn);
+ spl2e = (l2_pgentry_t *) map_domain_page(smfn);
/* Go back and recurse. */
#ifdef __i386__
@@ -3292,8 +3293,8 @@ int _check_pagetable(struct vcpu *v, char *s)
}
}
- unmap_domain_mem(spl2e);
- unmap_domain_mem(gpl2e);
+ unmap_domain_page(spl2e);
+ unmap_domain_page(gpl2e);
#if 0
SH_VVLOG("PT verified : l2_present = %d, l1_present = %d",
diff --git a/xen/arch/x86/smp.c b/xen/arch/x86/smp.c
index 5a8f6de6f0..b0782ec5d7 100644
--- a/xen/arch/x86/smp.c
+++ b/xen/arch/x86/smp.c
@@ -272,6 +272,7 @@ void smp_send_event_check_mask(cpumask_t mask)
struct call_data_struct {
void (*func) (void *info);
void *info;
+ int wait;
atomic_t started;
atomic_t finished;
};
@@ -299,6 +300,7 @@ int smp_call_function(
data.func = func;
data.info = info;
+ data.wait = wait;
atomic_set(&data.started, 0);
atomic_set(&data.finished, 0);
@@ -345,17 +347,22 @@ asmlinkage void smp_event_check_interrupt(void)
asmlinkage void smp_call_function_interrupt(void)
{
- void (*func) (void *info) = call_data->func;
+ void (*func)(void *info) = call_data->func;
void *info = call_data->info;
ack_APIC_irq();
perfc_incrc(ipis);
- mb();
- atomic_inc(&call_data->started);
-
- (*func)(info);
-
- mb();
- atomic_inc(&call_data->finished);
+ if ( call_data->wait )
+ {
+ (*func)(info);
+ mb();
+ atomic_inc(&call_data->finished);
+ }
+ else
+ {
+ mb();
+ atomic_inc(&call_data->started);
+ (*func)(info);
+ }
}
diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c
index 382fee8d15..f276e9632e 100644
--- a/xen/arch/x86/smpboot.c
+++ b/xen/arch/x86/smpboot.c
@@ -1178,12 +1178,6 @@ void __init smp_cpus_done(unsigned int max_cpus)
void __init smp_intr_init(void)
{
/*
- * IRQ0 must be given a fixed assignment and initialized,
- * because it's used before the IO-APIC is set up.
- */
- set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
-
- /*
* The reschedule interrupt is a CPU-to-CPU reschedule-helper
* IPI, driven by wakeup.
*/
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 35940b0df8..cf7aaa3d19 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -39,8 +39,8 @@
#include <xen/irq.h>
#include <xen/perfc.h>
#include <xen/softirq.h>
+#include <xen/domain_page.h>
#include <asm/shadow.h>
-#include <asm/domain_page.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/atomic.h>
@@ -205,6 +205,7 @@ asmlinkage void fatal_trap(int trapnr, struct cpu_user_regs *regs)
};
watchdog_disable();
+ console_start_sync();
show_registers(regs);
diff --git a/xen/arch/x86/x86_64/usercopy.c b/xen/arch/x86/usercopy.c
index 685cd7b1a3..f16c4da102 100644
--- a/xen/arch/x86/x86_64/usercopy.c
+++ b/xen/arch/x86/usercopy.c
@@ -10,73 +10,36 @@
#include <xen/lib.h>
#include <asm/uaccess.h>
-/*
- * Zero Userspace
- */
-
-unsigned long __clear_user(void *addr, unsigned long size)
-{
- long __d0;
- /* no memory constraint because it doesn't change any memory gcc knows
- about */
- asm volatile(
- " testq %[size8],%[size8]\n"
- " jz 4f\n"
- "0: movq %[zero],(%[dst])\n"
- " addq %[eight],%[dst]\n"
- " decl %%ecx ; jnz 0b\n"
- "4: movq %[size1],%%rcx\n"
- " testl %%ecx,%%ecx\n"
- " jz 2f\n"
- "1: movb %b[zero],(%[dst])\n"
- " incq %[dst]\n"
- " decl %%ecx ; jnz 1b\n"
- "2:\n"
- ".section .fixup,\"ax\"\n"
- "3: lea 0(%[size1],%[size8],8),%[size8]\n"
- " jmp 2b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b,3b\n"
- " .quad 1b,2b\n"
- ".previous"
- : [size8] "=c"(size), [dst] "=&D" (__d0)
- : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr),
- [zero] "r" (0UL), [eight] "r" (8UL));
- return size;
-}
-
unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned n)
{
unsigned long __d0, __d1, __d2, __n = n;
__asm__ __volatile__(
- " cmpq $15,%0\n"
+ " cmp $"STR(2*BYTES_PER_LONG-1)",%0\n"
" jbe 1f\n"
" mov %1,%0\n"
" neg %0\n"
- " and $7,%0\n"
+ " and $"STR(BYTES_PER_LONG-1)",%0\n"
" sub %0,%3\n"
"4: rep; movsb\n" /* make 'to' address aligned */
" mov %3,%0\n"
- " shr $3,%0\n"
- " and $7,%3\n"
+ " shr $"STR(LONG_BYTEORDER)",%0\n"
+ " and $"STR(BYTES_PER_LONG-1)",%3\n"
" .align 2,0x90\n"
- "0: rep; movsq\n" /* as many quadwords as possible... */
+ "0: rep; movs"__OS"\n" /* as many words as possible... */
" mov %3,%0\n"
"1: rep; movsb\n" /* ...remainder copied as bytes */
"2:\n"
".section .fixup,\"ax\"\n"
"5: add %3,%0\n"
" jmp 2b\n"
- "3: lea 0(%3,%0,8),%0\n"
+ "3: lea 0(%3,%0,"STR(BYTES_PER_LONG)"),%0\n"
" jmp 2b\n"
".previous\n"
".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 4b,5b\n"
- " .quad 0b,3b\n"
- " .quad 1b,2b\n"
+ " "__FIXUP_ALIGN"\n"
+ " "__FIXUP_WORD" 4b,5b\n"
+ " "__FIXUP_WORD" 0b,3b\n"
+ " "__FIXUP_WORD" 1b,2b\n"
".previous"
: "=&c"(__n), "=&D" (__d0), "=&S" (__d1), "=r"(__d2)
: "3"(__n), "0"(__n), "1"(to), "2"(from)
@@ -89,38 +52,38 @@ __copy_from_user_ll(void *to, const void __user *from, unsigned n)
{
unsigned long __d0, __d1, __d2, __n = n;
__asm__ __volatile__(
- " cmp $15,%0\n"
+ " cmp $"STR(2*BYTES_PER_LONG-1)",%0\n"
" jbe 1f\n"
" mov %1,%0\n"
" neg %0\n"
- " and $7,%0\n"
+ " and $"STR(BYTES_PER_LONG-1)",%0\n"
" sub %0,%3\n"
"4: rep; movsb\n" /* make 'to' address aligned */
" mov %3,%0\n"
- " shr $3,%0\n"
- " and $7,%3\n"
+ " shr $"STR(LONG_BYTEORDER)",%0\n"
+ " and $"STR(BYTES_PER_LONG-1)",%3\n"
" .align 2,0x90\n"
- "0: rep; movsq\n" /* as many quadwords as possible... */
+ "0: rep; movs"__OS"\n" /* as many words as possible... */
" mov %3,%0\n"
"1: rep; movsb\n" /* ...remainder copied as bytes */
"2:\n"
".section .fixup,\"ax\"\n"
"5: add %3,%0\n"
" jmp 6f\n"
- "3: lea 0(%3,%0,8),%0\n"
+ "3: lea 0(%3,%0,"STR(BYTES_PER_LONG)"),%0\n"
"6: push %0\n"
- " push %%rax\n"
- " xor %%rax,%%rax\n"
+ " push %%"__OP"ax\n"
+ " xor %%eax,%%eax\n"
" rep; stosb\n"
- " pop %%rax\n"
+ " pop %%"__OP"ax\n"
" pop %0\n"
" jmp 2b\n"
".previous\n"
".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 4b,5b\n"
- " .quad 0b,3b\n"
- " .quad 1b,6b\n"
+ " "__FIXUP_ALIGN"\n"
+ " "__FIXUP_WORD" 4b,5b\n"
+ " "__FIXUP_WORD" 0b,3b\n"
+ " "__FIXUP_WORD" 1b,6b\n"
".previous"
: "=&c"(__n), "=&D" (__d0), "=&S" (__d1), "=r"(__d2)
: "3"(__n), "0"(__n), "1"(to), "2"(from)
@@ -128,13 +91,6 @@ __copy_from_user_ll(void *to, const void __user *from, unsigned n)
return (unsigned)__n;
}
-unsigned long clear_user(void *to, unsigned long n)
-{
- if (access_ok(to, n))
- return __clear_user(to, n);
- return n;
-}
-
/**
* copy_to_user: - Copy a block of data into user space.
* @to: Destination address, in user space.
diff --git a/xen/arch/x86/vmx.c b/xen/arch/x86/vmx.c
index 8aa476f3c6..ffc22f638b 100644
--- a/xen/arch/x86/vmx.c
+++ b/xen/arch/x86/vmx.c
@@ -24,6 +24,7 @@
#include <xen/sched.h>
#include <xen/irq.h>
#include <xen/softirq.h>
+#include <xen/domain_page.h>
#include <asm/current.h>
#include <asm/io.h>
#include <asm/shadow.h>
@@ -102,7 +103,7 @@ void stop_vmx(void)
}
/*
- * Not all cases recevie valid value in the VM-exit instruction length field.
+ * Not all cases receive valid value in the VM-exit instruction length field.
*/
#define __get_instruction_length(len) \
__vmread(INSTRUCTION_LEN, &(len)); \
@@ -118,8 +119,6 @@ static void inline __update_guest_eip(unsigned long inst_len)
}
-#include <asm/domain_page.h>
-
static int vmx_do_page_fault(unsigned long va, struct cpu_user_regs *regs)
{
unsigned long eip;
@@ -468,23 +467,24 @@ enum { COPY_IN = 0, COPY_OUT };
static inline int
vmx_copy(void *buf, unsigned long laddr, int size, int dir)
{
- unsigned char *addr;
+ char *addr;
unsigned long mfn;
- if ((size + (laddr & (PAGE_SIZE - 1))) >= PAGE_SIZE) {
+ if ( (size + (laddr & (PAGE_SIZE - 1))) >= PAGE_SIZE )
+ {
printf("vmx_copy exceeds page boundary\n");
- return 0;
+ return 0;
}
mfn = phys_to_machine_mapping(laddr >> PAGE_SHIFT);
- addr = map_domain_mem((mfn << PAGE_SHIFT) | (laddr & ~PAGE_MASK));
+ addr = (char *)map_domain_page(mfn) + (laddr & ~PAGE_MASK);
if (dir == COPY_IN)
memcpy(buf, addr, size);
else
memcpy(addr, buf, size);
- unmap_domain_mem(addr);
+ unmap_domain_page(addr);
return 1;
}
@@ -1262,8 +1262,7 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
if (vector == LOCAL_TIMER_VECTOR) {
smp_apic_timer_interrupt(&regs);
} else {
- regs.entry_vector = (vector == FIRST_DEVICE_VECTOR?
- 0 : vector_irq[vector]);
+ regs.entry_vector = vector;
do_IRQ(&regs);
}
break;
diff --git a/xen/arch/x86/vmx_io.c b/xen/arch/x86/vmx_io.c
index 95fa95aec8..240a327223 100644
--- a/xen/arch/x86/vmx_io.c
+++ b/xen/arch/x86/vmx_io.c
@@ -283,7 +283,7 @@ int vmx_clear_pending_io_event(struct vcpu *v)
/* Note: VMX domains may need upcalls as well */
if (!v->vcpu_info->evtchn_pending_sel)
- v->vcpu_info->evtchn_upcall_pending = 0;
+ clear_bit(0, &v->vcpu_info->evtchn_upcall_pending);
/* clear the pending bit for IOPACKET_PORT */
return test_and_clear_bit(IOPACKET_PORT,
@@ -311,10 +311,16 @@ void vmx_wait_io()
extern void do_block();
do {
- do_block();
+ if(!test_bit(IOPACKET_PORT,
+ &current->domain->shared_info->evtchn_pending[0]))
+ do_block();
vmx_check_events(current);
if (!test_bit(ARCH_VMX_IO_WAIT, &current->arch.arch_vmx.flags))
break;
+ /* Events other than IOPACKET_PORT might have woken us up. In that
+ case, safely go back to sleep. */
+ clear_bit(IOPACKET_PORT>>5, &current->vcpu_info->evtchn_pending_sel);
+ clear_bit(0, &current->vcpu_info->evtchn_upcall_pending);
} while(1);
}
diff --git a/xen/arch/x86/vmx_platform.c b/xen/arch/x86/vmx_platform.c
index 7d976a42e8..96e7572750 100644
--- a/xen/arch/x86/vmx_platform.c
+++ b/xen/arch/x86/vmx_platform.c
@@ -21,7 +21,7 @@
#include <xen/types.h>
#include <xen/mm.h>
#include <asm/shadow.h>
-#include <asm/domain_page.h>
+#include <xen/domain_page.h>
#include <asm/page.h>
#include <xen/event.h>
#include <xen/trace.h>
@@ -411,43 +411,41 @@ int inst_copy_from_guest(unsigned char *buf, unsigned long guest_eip,
{
l1_pgentry_t gpte;
unsigned long mfn;
- unsigned long ma;
- unsigned char * inst_start;
+ unsigned char *inst_start;
int remaining = 0;
- if (inst_len > MAX_INST_LEN || inst_len <= 0) {
+ if ( (inst_len > MAX_INST_LEN) || (inst_len <= 0) )
return 0;
- }
- if (vmx_paging_enabled(current)) {
+ if ( vmx_paging_enabled(current) )
+ {
gpte = gva_to_gpte(guest_eip);
mfn = phys_to_machine_mapping(l1e_get_pfn(gpte));
/* Does this cross a page boundary ? */
- if ((guest_eip & PAGE_MASK) != ((guest_eip + inst_len) & PAGE_MASK)) {
+ if ( (guest_eip & PAGE_MASK) != ((guest_eip + inst_len) & PAGE_MASK) )
+ {
remaining = (guest_eip + inst_len) & ~PAGE_MASK;
inst_len -= remaining;
}
-
- } else {
+ }
+ else
+ {
mfn = phys_to_machine_mapping(guest_eip >> PAGE_SHIFT);
}
- ma = (mfn << PAGE_SHIFT) | (guest_eip & (PAGE_SIZE - 1));
- inst_start = (unsigned char *)map_domain_mem(ma);
-
- memcpy((char *)buf, inst_start, inst_len);
- unmap_domain_mem(inst_start);
- if (remaining) {
+ inst_start = map_domain_page(mfn);
+ memcpy((char *)buf, inst_start + (guest_eip & ~PAGE_MASK), inst_len);
+ unmap_domain_page(inst_start);
+
+ if ( remaining )
+ {
gpte = gva_to_gpte(guest_eip+inst_len+remaining);
mfn = phys_to_machine_mapping(l1e_get_pfn(gpte));
-
- ma = (mfn << PAGE_SHIFT);
- inst_start = (unsigned char *)map_domain_mem(ma);
-
+ inst_start = map_domain_page(mfn);
memcpy((char *)buf+inst_len, inst_start, remaining);
- unmap_domain_mem(inst_start);
-
+ unmap_domain_page(inst_start);
}
+
return inst_len+remaining;
}
diff --git a/xen/arch/x86/vmx_vmcs.c b/xen/arch/x86/vmx_vmcs.c
index fa01316aa2..5fed12c279 100644
--- a/xen/arch/x86/vmx_vmcs.c
+++ b/xen/arch/x86/vmx_vmcs.c
@@ -22,7 +22,7 @@
#include <xen/mm.h>
#include <xen/lib.h>
#include <xen/errno.h>
-
+#include <xen/domain_page.h>
#include <asm/current.h>
#include <asm/cpufeature.h>
#include <asm/processor.h>
@@ -31,7 +31,6 @@
#include <xen/event.h>
#include <xen/kernel.h>
#include <public/io/ioreq.h>
-#include <asm/domain_page.h>
#ifdef CONFIG_VMX
@@ -122,8 +121,9 @@ int vmx_setup_platform(struct vcpu *d, struct cpu_user_regs *regs)
addr = regs->edi;
offset = (addr & ~PAGE_MASK);
addr = round_pgdown(addr);
+
mpfn = phys_to_machine_mapping(addr >> PAGE_SHIFT);
- p = map_domain_mem(mpfn << PAGE_SHIFT);
+ p = map_domain_page(mpfn);
e820p = (struct e820entry *) ((unsigned long) p + offset);
@@ -131,28 +131,28 @@ int vmx_setup_platform(struct vcpu *d, struct cpu_user_regs *regs)
print_e820_memory_map(e820p, n);
#endif
- for (i = 0; i < n; i++) {
- if (e820p[i].type == E820_SHARED_PAGE) {
+ for ( i = 0; i < n; i++ )
+ {
+ if ( e820p[i].type == E820_SHARED_PAGE )
+ {
gpfn = (e820p[i].addr >> PAGE_SHIFT);
break;
}
}
- if (gpfn == 0) {
- printk("No shared Page ?\n");
- unmap_domain_mem(p);
+ if ( gpfn == 0 )
+ {
+ unmap_domain_page(p);
return -1;
}
- unmap_domain_mem(p);
- mpfn = phys_to_machine_mapping(gpfn);
- p = map_domain_mem(mpfn << PAGE_SHIFT);
- ASSERT(p != NULL);
+ unmap_domain_page(p);
/* Initialise shared page */
+ mpfn = phys_to_machine_mapping(gpfn);
+ p = map_domain_page(mpfn);
memset(p, 0, PAGE_SIZE);
-
- d->arch.arch_vmx.vmx_platform.shared_page_va = (unsigned long) p;
+ d->arch.arch_vmx.vmx_platform.shared_page_va = (unsigned long)p;
return 0;
}
@@ -445,12 +445,12 @@ int store_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
void vm_launch_fail(unsigned long eflags)
{
- BUG();
+ __vmx_bug(guest_cpu_user_regs());
}
void vm_resume_fail(unsigned long eflags)
{
- BUG();
+ __vmx_bug(guest_cpu_user_regs());
}
#endif /* CONFIG_VMX */
diff --git a/xen/arch/x86/x86_32/domain_page.c b/xen/arch/x86/x86_32/domain_page.c
index 40d0f8f964..6bec96bc87 100644
--- a/xen/arch/x86/x86_32/domain_page.c
+++ b/xen/arch/x86/x86_32/domain_page.c
@@ -15,30 +15,19 @@
#include <xen/sched.h>
#include <xen/mm.h>
#include <xen/perfc.h>
+#include <xen/domain_page.h>
#include <asm/current.h>
-#include <asm/domain_page.h>
#include <asm/flushtlb.h>
#include <asm/hardirq.h>
+#define MAPCACHE_ORDER 10
+#define MAPCACHE_ENTRIES (1 << MAPCACHE_ORDER)
+
l1_pgentry_t *mapcache;
static unsigned int map_idx, epoch, shadow_epoch[NR_CPUS];
static spinlock_t map_lock = SPIN_LOCK_UNLOCKED;
-/* Use a spare PTE bit to mark entries ready for recycling. */
-#define READY_FOR_TLB_FLUSH (1<<10)
-
-static void flush_all_ready_maps(void)
-{
- l1_pgentry_t *cache = mapcache;
- unsigned int i;
-
- for ( i = 0; i < MAPCACHE_ENTRIES; i++ )
- if ( (l1e_get_flags(cache[i]) & READY_FOR_TLB_FLUSH) )
- cache[i] = l1e_empty();
-}
-
-
-void *map_domain_mem(unsigned long pa)
+void *map_domain_page(unsigned long pfn)
{
unsigned long va;
unsigned int idx, cpu = smp_processor_id();
@@ -48,7 +37,7 @@ void *map_domain_mem(unsigned long pa)
#endif
ASSERT(!in_irq());
- perfc_incrc(map_domain_mem_count);
+ perfc_incrc(map_domain_page_count);
spin_lock(&map_lock);
@@ -65,7 +54,6 @@ void *map_domain_mem(unsigned long pa)
if ( unlikely(idx == 0) )
{
ASSERT(flush_count++ == 0);
- flush_all_ready_maps();
perfc_incrc(domain_page_tlb_flush);
local_flush_tlb();
shadow_epoch[cpu] = ++epoch;
@@ -73,19 +61,19 @@ void *map_domain_mem(unsigned long pa)
}
while ( l1e_get_flags(cache[idx]) & _PAGE_PRESENT );
- cache[idx] = l1e_from_paddr(pa & PAGE_MASK, __PAGE_HYPERVISOR);
+ cache[idx] = l1e_from_pfn(pfn, __PAGE_HYPERVISOR);
spin_unlock(&map_lock);
- va = MAPCACHE_VIRT_START + (idx << PAGE_SHIFT) + (pa & ~PAGE_MASK);
+ va = MAPCACHE_VIRT_START + (idx << PAGE_SHIFT);
return (void *)va;
}
-void unmap_domain_mem(void *va)
+void unmap_domain_page(void *va)
{
unsigned int idx;
ASSERT((void *)MAPCACHE_VIRT_START <= va);
ASSERT(va < (void *)MAPCACHE_VIRT_END);
idx = ((unsigned long)va - MAPCACHE_VIRT_START) >> PAGE_SHIFT;
- l1e_add_flags(mapcache[idx], READY_FOR_TLB_FLUSH);
+ mapcache[idx] = l1e_empty();
}
diff --git a/xen/arch/x86/x86_32/mm.c b/xen/arch/x86/x86_32/mm.c
index 99dd178fea..686064baa4 100644
--- a/xen/arch/x86/x86_32/mm.c
+++ b/xen/arch/x86/x86_32/mm.c
@@ -22,11 +22,13 @@
#include <xen/lib.h>
#include <xen/init.h>
#include <xen/mm.h>
+#include <xen/sched.h>
#include <asm/current.h>
#include <asm/page.h>
#include <asm/flushtlb.h>
#include <asm/fixmap.h>
-#include <asm/domain_page.h>
+
+extern l1_pgentry_t *mapcache;
unsigned int PAGE_HYPERVISOR = __PAGE_HYPERVISOR;
unsigned int PAGE_HYPERVISOR_NOCACHE = __PAGE_HYPERVISOR_NOCACHE;
diff --git a/xen/arch/x86/x86_32/traps.c b/xen/arch/x86/x86_32/traps.c
index b950707989..3a489f244c 100644
--- a/xen/arch/x86/x86_32/traps.c
+++ b/xen/arch/x86/x86_32/traps.c
@@ -8,10 +8,7 @@
#include <xen/irq.h>
#include <asm/current.h>
#include <asm/flushtlb.h>
-
-#ifdef CONFIG_VMX
#include <asm/vmx.h>
-#endif
/* All CPUs have their own IDT to allow int80 direct trap. */
idt_entry_t *idt_tables[NR_CPUS] = { 0 };
@@ -19,10 +16,8 @@ idt_entry_t *idt_tables[NR_CPUS] = { 0 };
void show_registers(struct cpu_user_regs *regs)
{
unsigned long ss, ds, es, fs, gs, cs;
- unsigned long eip, esp, eflags;
+ unsigned long eip, esp, eflags, cr0, cr3;
const char *context;
-#ifdef CONFIG_VMX
- unsigned long cr0, cr3;
if ( VMX_DOMAIN(current) && (regs->eflags == 0) )
{
@@ -40,10 +35,13 @@ void show_registers(struct cpu_user_regs *regs)
context = "vmx guest";
}
else
-#endif
{
- eip = regs->eip;
+ eip = regs->eip;
eflags = regs->eflags;
+ cr0 = read_cr0();
+ cr3 = read_cr3();
+
+ __asm__ ( "movl %%fs,%0 ; movl %%gs,%1" : "=r" (fs), "=r" (gs) );
if ( GUEST_MODE(regs) )
{
@@ -51,21 +49,16 @@ void show_registers(struct cpu_user_regs *regs)
ss = regs->ss & 0xffff;
ds = regs->ds & 0xffff;
es = regs->es & 0xffff;
- fs = regs->fs & 0xffff;
- gs = regs->gs & 0xffff;
cs = regs->cs & 0xffff;
context = "guest";
}
else
{
- esp = (unsigned long)(&regs->esp);
+ esp = (unsigned long)&regs->esp;
ss = __HYPERVISOR_DS;
ds = __HYPERVISOR_DS;
es = __HYPERVISOR_DS;
- fs = __HYPERVISOR_DS;
- gs = __HYPERVISOR_DS;
cs = __HYPERVISOR_CS;
-
context = "hypervisor";
}
}
@@ -78,12 +71,10 @@ void show_registers(struct cpu_user_regs *regs)
regs->eax, regs->ebx, regs->ecx, regs->edx);
printk("esi: %08x edi: %08x ebp: %08x esp: %08lx\n",
regs->esi, regs->edi, regs->ebp, esp);
+ printk("cr0: %08lx cr3: %08lx\n", cr0, cr3);
printk("ds: %04lx es: %04lx fs: %04lx gs: %04lx "
"ss: %04lx cs: %04lx\n",
ds, es, fs, gs, ss, cs);
-#ifdef CONFIG_VMX
- printk("cr0: %08lx cr3: %08lx\n", cr0, cr3);
-#endif
if ( GUEST_MODE(regs) )
show_guest_stack();
diff --git a/xen/arch/x86/x86_32/usercopy.c b/xen/arch/x86/x86_32/usercopy.c
deleted file mode 100644
index c05ffd429d..0000000000
--- a/xen/arch/x86/x86_32/usercopy.c
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
- * User address space access functions.
- * The non inlined parts of asm-i386/uaccess.h are here.
- *
- * Copyright 1997 Andi Kleen <ak@muc.de>
- * Copyright 1997 Linus Torvalds
- */
-
-#include <xen/config.h>
-#include <xen/lib.h>
-#include <asm/uaccess.h>
-
-static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned long n)
-{
-#ifdef CONFIG_X86_INTEL_USERCOPY
- if (n >= 64 && ((a1 ^ a2) & movsl_mask.mask))
- return 0;
-#endif
- return 1;
-}
-#define movsl_is_ok(a1,a2,n) \
- __movsl_is_ok((unsigned long)(a1),(unsigned long)(a2),(n))
-
-
-/*
- * Zero Userspace
- */
-
-#define __do_clear_user(addr,size) \
-do { \
- int __d0; \
- __asm__ __volatile__( \
- "0: rep; stosl\n" \
- " movl %2,%0\n" \
- "1: rep; stosb\n" \
- "2:\n" \
- ".section .fixup,\"ax\"\n" \
- "3: lea 0(%2,%0,4),%0\n" \
- " jmp 2b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 0b,3b\n" \
- " .long 1b,2b\n" \
- ".previous" \
- : "=&c"(size), "=&D" (__d0) \
- : "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \
-} while (0)
-
-/**
- * clear_user: - Zero a block of memory in user space.
- * @to: Destination address, in user space.
- * @n: Number of bytes to zero.
- *
- * Zero a block of memory in user space.
- *
- * Returns number of bytes that could not be cleared.
- * On success, this will be zero.
- */
-unsigned long
-clear_user(void __user *to, unsigned long n)
-{
- if (access_ok(to, n))
- __do_clear_user(to, n);
- return n;
-}
-
-/**
- * __clear_user: - Zero a block of memory in user space, with less checking.
- * @to: Destination address, in user space.
- * @n: Number of bytes to zero.
- *
- * Zero a block of memory in user space. Caller must check
- * the specified block with access_ok() before calling this function.
- *
- * Returns number of bytes that could not be cleared.
- * On success, this will be zero.
- */
-unsigned long
-__clear_user(void __user *to, unsigned long n)
-{
- __do_clear_user(to, n);
- return n;
-}
-
-#ifdef CONFIG_X86_INTEL_USERCOPY
-static unsigned long
-__copy_user_intel(void __user *to, const void *from, unsigned long size)
-{
- int d0, d1;
- __asm__ __volatile__(
- " .align 2,0x90\n"
- "1: movl 32(%4), %%eax\n"
- " cmpl $67, %0\n"
- " jbe 3f\n"
- "2: movl 64(%4), %%eax\n"
- " .align 2,0x90\n"
- "3: movl 0(%4), %%eax\n"
- "4: movl 4(%4), %%edx\n"
- "5: movl %%eax, 0(%3)\n"
- "6: movl %%edx, 4(%3)\n"
- "7: movl 8(%4), %%eax\n"
- "8: movl 12(%4),%%edx\n"
- "9: movl %%eax, 8(%3)\n"
- "10: movl %%edx, 12(%3)\n"
- "11: movl 16(%4), %%eax\n"
- "12: movl 20(%4), %%edx\n"
- "13: movl %%eax, 16(%3)\n"
- "14: movl %%edx, 20(%3)\n"
- "15: movl 24(%4), %%eax\n"
- "16: movl 28(%4), %%edx\n"
- "17: movl %%eax, 24(%3)\n"
- "18: movl %%edx, 28(%3)\n"
- "19: movl 32(%4), %%eax\n"
- "20: movl 36(%4), %%edx\n"
- "21: movl %%eax, 32(%3)\n"
- "22: movl %%edx, 36(%3)\n"
- "23: movl 40(%4), %%eax\n"
- "24: movl 44(%4), %%edx\n"
- "25: movl %%eax, 40(%3)\n"
- "26: movl %%edx, 44(%3)\n"
- "27: movl 48(%4), %%eax\n"
- "28: movl 52(%4), %%edx\n"
- "29: movl %%eax, 48(%3)\n"
- "30: movl %%edx, 52(%3)\n"
- "31: movl 56(%4), %%eax\n"
- "32: movl 60(%4), %%edx\n"
- "33: movl %%eax, 56(%3)\n"
- "34: movl %%edx, 60(%3)\n"
- " addl $-64, %0\n"
- " addl $64, %4\n"
- " addl $64, %3\n"
- " cmpl $63, %0\n"
- " ja 1b\n"
- "35: movl %0, %%eax\n"
- " shrl $2, %0\n"
- " andl $3, %%eax\n"
- " cld\n"
- "99: rep; movsl\n"
- "36: movl %%eax, %0\n"
- "37: rep; movsb\n"
- "100:\n"
- ".section .fixup,\"ax\"\n"
- "101: lea 0(%%eax,%0,4),%0\n"
- " jmp 100b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,100b\n"
- " .long 2b,100b\n"
- " .long 3b,100b\n"
- " .long 4b,100b\n"
- " .long 5b,100b\n"
- " .long 6b,100b\n"
- " .long 7b,100b\n"
- " .long 8b,100b\n"
- " .long 9b,100b\n"
- " .long 10b,100b\n"
- " .long 11b,100b\n"
- " .long 12b,100b\n"
- " .long 13b,100b\n"
- " .long 14b,100b\n"
- " .long 15b,100b\n"
- " .long 16b,100b\n"
- " .long 17b,100b\n"
- " .long 18b,100b\n"
- " .long 19b,100b\n"
- " .long 20b,100b\n"
- " .long 21b,100b\n"
- " .long 22b,100b\n"
- " .long 23b,100b\n"
- " .long 24b,100b\n"
- " .long 25b,100b\n"
- " .long 26b,100b\n"
- " .long 27b,100b\n"
- " .long 28b,100b\n"
- " .long 29b,100b\n"
- " .long 30b,100b\n"
- " .long 31b,100b\n"
- " .long 32b,100b\n"
- " .long 33b,100b\n"
- " .long 34b,100b\n"
- " .long 35b,100b\n"
- " .long 36b,100b\n"
- " .long 37b,100b\n"
- " .long 99b,101b\n"
- ".previous"
- : "=&c"(size), "=&D" (d0), "=&S" (d1)
- : "1"(to), "2"(from), "0"(size)
- : "eax", "edx", "memory");
- return size;
-}
-
-static unsigned long
-__copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size)
-{
- int d0, d1;
- __asm__ __volatile__(
- " .align 2,0x90\n"
- "0: movl 32(%4), %%eax\n"
- " cmpl $67, %0\n"
- " jbe 2f\n"
- "1: movl 64(%4), %%eax\n"
- " .align 2,0x90\n"
- "2: movl 0(%4), %%eax\n"
- "21: movl 4(%4), %%edx\n"
- " movl %%eax, 0(%3)\n"
- " movl %%edx, 4(%3)\n"
- "3: movl 8(%4), %%eax\n"
- "31: movl 12(%4),%%edx\n"
- " movl %%eax, 8(%3)\n"
- " movl %%edx, 12(%3)\n"
- "4: movl 16(%4), %%eax\n"
- "41: movl 20(%4), %%edx\n"
- " movl %%eax, 16(%3)\n"
- " movl %%edx, 20(%3)\n"
- "10: movl 24(%4), %%eax\n"
- "51: movl 28(%4), %%edx\n"
- " movl %%eax, 24(%3)\n"
- " movl %%edx, 28(%3)\n"
- "11: movl 32(%4), %%eax\n"
- "61: movl 36(%4), %%edx\n"
- " movl %%eax, 32(%3)\n"
- " movl %%edx, 36(%3)\n"
- "12: movl 40(%4), %%eax\n"
- "71: movl 44(%4), %%edx\n"
- " movl %%eax, 40(%3)\n"
- " movl %%edx, 44(%3)\n"
- "13: movl 48(%4), %%eax\n"
- "81: movl 52(%4), %%edx\n"
- " movl %%eax, 48(%3)\n"
- " movl %%edx, 52(%3)\n"
- "14: movl 56(%4), %%eax\n"
- "91: movl 60(%4), %%edx\n"
- " movl %%eax, 56(%3)\n"
- " movl %%edx, 60(%3)\n"
- " addl $-64, %0\n"
- " addl $64, %4\n"
- " addl $64, %3\n"
- " cmpl $63, %0\n"
- " ja 0b\n"
- "5: movl %0, %%eax\n"
- " shrl $2, %0\n"
- " andl $3, %%eax\n"
- " cld\n"
- "6: rep; movsl\n"
- " movl %%eax,%0\n"
- "7: rep; movsb\n"
- "8:\n"
- ".section .fixup,\"ax\"\n"
- "9: lea 0(%%eax,%0,4),%0\n"
- "16: pushl %0\n"
- " pushl %%eax\n"
- " xorl %%eax,%%eax\n"
- " rep; stosb\n"
- " popl %%eax\n"
- " popl %0\n"
- " jmp 8b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,16b\n"
- " .long 1b,16b\n"
- " .long 2b,16b\n"
- " .long 21b,16b\n"
- " .long 3b,16b\n"
- " .long 31b,16b\n"
- " .long 4b,16b\n"
- " .long 41b,16b\n"
- " .long 10b,16b\n"
- " .long 51b,16b\n"
- " .long 11b,16b\n"
- " .long 61b,16b\n"
- " .long 12b,16b\n"
- " .long 71b,16b\n"
- " .long 13b,16b\n"
- " .long 81b,16b\n"
- " .long 14b,16b\n"
- " .long 91b,16b\n"
- " .long 6b,9b\n"
- " .long 7b,16b\n"
- ".previous"
- : "=&c"(size), "=&D" (d0), "=&S" (d1)
- : "1"(to), "2"(from), "0"(size)
- : "eax", "edx", "memory");
- return size;
-}
-#else
-/*
- * Leave these declared but undefined. They should not be any references to
- * them
- */
-unsigned long
-__copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size);
-unsigned long
-__copy_user_intel(void __user *to, const void *from, unsigned long size);
-#endif /* CONFIG_X86_INTEL_USERCOPY */
-
-/* Generic arbitrary sized copy. */
-#define __copy_user(to,from,size) \
-do { \
- int __d0, __d1, __d2; \
- __asm__ __volatile__( \
- " cmp $7,%0\n" \
- " jbe 1f\n" \
- " movl %1,%0\n" \
- " negl %0\n" \
- " andl $7,%0\n" \
- " subl %0,%3\n" \
- "4: rep; movsb\n" \
- " movl %3,%0\n" \
- " shrl $2,%0\n" \
- " andl $3,%3\n" \
- " .align 2,0x90\n" \
- "0: rep; movsl\n" \
- " movl %3,%0\n" \
- "1: rep; movsb\n" \
- "2:\n" \
- ".section .fixup,\"ax\"\n" \
- "5: addl %3,%0\n" \
- " jmp 2b\n" \
- "3: lea 0(%3,%0,4),%0\n" \
- " jmp 2b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 4b,5b\n" \
- " .long 0b,3b\n" \
- " .long 1b,2b\n" \
- ".previous" \
- : "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \
- : "3"(size), "0"(size), "1"(to), "2"(from) \
- : "memory"); \
-} while (0)
-
-#define __copy_user_zeroing(to,from,size) \
-do { \
- int __d0, __d1, __d2; \
- __asm__ __volatile__( \
- " cmp $7,%0\n" \
- " jbe 1f\n" \
- " movl %1,%0\n" \
- " negl %0\n" \
- " andl $7,%0\n" \
- " subl %0,%3\n" \
- "4: rep; movsb\n" \
- " movl %3,%0\n" \
- " shrl $2,%0\n" \
- " andl $3,%3\n" \
- " .align 2,0x90\n" \
- "0: rep; movsl\n" \
- " movl %3,%0\n" \
- "1: rep; movsb\n" \
- "2:\n" \
- ".section .fixup,\"ax\"\n" \
- "5: addl %3,%0\n" \
- " jmp 6f\n" \
- "3: lea 0(%3,%0,4),%0\n" \
- "6: pushl %0\n" \
- " pushl %%eax\n" \
- " xorl %%eax,%%eax\n" \
- " rep; stosb\n" \
- " popl %%eax\n" \
- " popl %0\n" \
- " jmp 2b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 4b,5b\n" \
- " .long 0b,3b\n" \
- " .long 1b,6b\n" \
- ".previous" \
- : "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \
- : "3"(size), "0"(size), "1"(to), "2"(from) \
- : "memory"); \
-} while (0)
-
-
-unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned long n)
-{
- if (movsl_is_ok(to, from, n))
- __copy_user(to, from, n);
- else
- n = __copy_user_intel(to, from, n);
- return n;
-}
-
-unsigned long
-__copy_from_user_ll(void *to, const void __user *from, unsigned long n)
-{
- if (movsl_is_ok(to, from, n))
- __copy_user_zeroing(to, from, n);
- else
- n = __copy_user_zeroing_intel(to, from, n);
- return n;
-}
-
-/**
- * copy_to_user: - Copy a block of data into user space.
- * @to: Destination address, in user space.
- * @from: Source address, in kernel space.
- * @n: Number of bytes to copy.
- *
- * Context: User context only. This function may sleep.
- *
- * Copy data from kernel space to user space.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- */
-unsigned long
-copy_to_user(void __user *to, const void *from, unsigned long n)
-{
- if (access_ok(to, n))
- n = __copy_to_user(to, from, n);
- return n;
-}
-
-/**
- * copy_from_user: - Copy a block of data from user space.
- * @to: Destination address, in kernel space.
- * @from: Source address, in user space.
- * @n: Number of bytes to copy.
- *
- * Context: User context only. This function may sleep.
- *
- * Copy data from user space to kernel space.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- *
- * If some data could not be copied, this function will pad the copied
- * data to the requested size using zero bytes.
- */
-unsigned long
-copy_from_user(void *to, const void __user *from, unsigned long n)
-{
- if (access_ok(from, n))
- n = __copy_from_user(to, from, n);
- else
- memset(to, 0, n);
- return n;
-}
diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c
index 89654c7c45..216af3854a 100644
--- a/xen/common/dom0_ops.c
+++ b/xen/common/dom0_ops.c
@@ -10,15 +10,15 @@
#include <xen/types.h>
#include <xen/lib.h>
#include <xen/mm.h>
-#include <public/dom0_ops.h>
#include <xen/sched.h>
#include <xen/domain.h>
#include <xen/event.h>
-#include <asm/domain_page.h>
+#include <xen/domain_page.h>
#include <xen/trace.h>
#include <xen/console.h>
-#include <public/sched_ctl.h>
#include <asm/current.h>
+#include <public/dom0_ops.h>
+#include <public/sched_ctl.h>
extern long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op);
extern void arch_getdomaininfo_ctxt(
@@ -449,9 +449,11 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
case DOM0_READCONSOLE:
{
- ret = read_console_ring(op->u.readconsole.str,
- op->u.readconsole.count,
- op->u.readconsole.cmd);
+ ret = read_console_ring(
+ &op->u.readconsole.buffer,
+ &op->u.readconsole.count,
+ op->u.readconsole.clear);
+ copy_to_user(u_dom0_op, op, sizeof(*op));
}
break;
diff --git a/xen/common/dom_mem_ops.c b/xen/common/dom_mem_ops.c
index 9e974be44d..ad53b91d1c 100644
--- a/xen/common/dom_mem_ops.c
+++ b/xen/common/dom_mem_ops.c
@@ -15,7 +15,6 @@
#include <xen/event.h>
#include <xen/shadow.h>
#include <asm/current.h>
-#include <asm/domain_page.h>
#include <asm/hardirq.h>
/*
diff --git a/xen/common/domain.c b/xen/common/domain.c
index a3c42c1464..5c5214926c 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -15,9 +15,9 @@
#include <xen/time.h>
#include <xen/console.h>
#include <xen/softirq.h>
-#include <public/dom0_ops.h>
-#include <asm/domain_page.h>
+#include <xen/domain_page.h>
#include <asm/debugger.h>
+#include <public/dom0_ops.h>
/* Both these structures are protected by the domlist_lock. */
rwlock_t domlist_lock = RW_LOCK_UNLOCKED;
@@ -54,9 +54,9 @@ struct domain *do_createdomain(domid_t dom_id, unsigned int cpu)
set_bit(_DOMF_idle_domain, &d->domain_flags);
if ( !is_idle_task(d) &&
- ((init_event_channels(d) != 0) || (grant_table_create(d) != 0)) )
+ ((evtchn_init(d) != 0) || (grant_table_create(d) != 0)) )
{
- destroy_event_channels(d);
+ evtchn_destroy(d);
free_domain_struct(d);
return NULL;
}
@@ -122,18 +122,9 @@ void domain_kill(struct domain *d)
void domain_crash(void)
{
- struct domain *d = current->domain;
-
- if ( d->domain_id == 0 )
- {
- show_registers(guest_cpu_user_regs());
- panic("Domain 0 crashed!\n");
- }
-
-#ifndef NDEBUG
+ printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
+ current->domain->domain_id, current->vcpu_id, smp_processor_id());
show_registers(guest_cpu_user_regs());
-#endif
-
domain_shutdown(SHUTDOWN_crash);
}
@@ -224,6 +215,26 @@ void domain_shutdown(u8 reason)
}
+void domain_pause_for_debugger(void)
+{
+ struct domain *d = current->domain;
+ struct vcpu *v;
+
+ /*
+ * NOTE: This does not synchronously pause the domain. The debugger
+ * must issue a PAUSEDOMAIN command to ensure that all execution
+ * has ceased and guest state is committed to memory.
+ */
+ for_each_vcpu ( d, v )
+ {
+ set_bit(_VCPUF_ctrl_pause, &v->vcpu_flags);
+ domain_sleep_nosync(v);
+ }
+
+ send_guest_virq(dom0->vcpu[0], VIRQ_DEBUGGER);
+}
+
+
/* Release resources belonging to task @p. */
void domain_destruct(struct domain *d)
{
@@ -251,7 +262,7 @@ void domain_destruct(struct domain *d)
*pd = d->next_in_hashbucket;
write_unlock(&domlist_lock);
- destroy_event_channels(d);
+ evtchn_destroy(d);
grant_table_destroy(d);
free_perdomain_pt(d);
diff --git a/xen/common/elf.c b/xen/common/elf.c
index 42c88b0d96..08ff377d7c 100644
--- a/xen/common/elf.c
+++ b/xen/common/elf.c
@@ -11,12 +11,6 @@
#include <xen/elf.h>
#include <xen/sched.h>
-#ifdef CONFIG_X86
-#define FORCE_XENELF_IMAGE 1
-#elif defined(__ia64__)
-#define FORCE_XENELF_IMAGE 0
-#endif
-
static void loadelfsymtab(struct domain_setup_info *dsi, int doload);
static inline int is_loadable_phdr(Elf_Phdr *phdr)
{
@@ -85,16 +79,8 @@ int parseelfimage(struct domain_setup_info *dsi)
break;
}
- if ( guestinfo == NULL )
- {
- printk("Not a Xen-ELF image: '__xen_guest' section not found.\n");
- dsi->xen_elf_image = 0;
-#if FORCE_XENELF_IMAGE
- return -EINVAL;
-#endif
- } else {
- dsi->xen_elf_image = 1;
- }
+
+ dsi->xen_section_string = guestinfo;
for ( h = 0; h < ehdr->e_phnum; h++ )
{
diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
index d2f0c47452..6f6e707667 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -27,50 +27,33 @@
#include <public/xen.h>
#include <public/event_channel.h>
-#define INIT_EVENT_CHANNELS 16
-#define MAX_EVENT_CHANNELS 1024
-#define EVENT_CHANNELS_SPREAD 32
+#define bucket_from_port(d,p) \
+ ((d)->evtchn[(p)/EVTCHNS_PER_BUCKET])
+#define port_is_valid(d,p) \
+ (((p) >= 0) && ((p) < MAX_EVTCHNS) && \
+ (bucket_from_port(d,p) != NULL))
+#define evtchn_from_port(d,p) \
+ (&(bucket_from_port(d,p))[(p)&(EVTCHNS_PER_BUCKET-1)])
+#define ERROR_EXIT(_errno) do { rc = (_errno); goto out; } while ( 0 )
-static int get_free_port(struct vcpu *v)
+static int get_free_port(struct domain *d)
{
- struct domain *d = v->domain;
- int max, port;
- event_channel_t *chn;
-
- max = d->max_event_channel;
- chn = d->event_channel;
-
- for ( port = v->vcpu_id * EVENT_CHANNELS_SPREAD; port < max; port++ )
- if ( chn[port].state == ECS_FREE )
- break;
-
- if ( port >= max )
- {
- if ( max == MAX_EVENT_CHANNELS )
- return -ENOSPC;
-
- if ( port == 0 )
- max = INIT_EVENT_CHANNELS;
- else
- max = port + EVENT_CHANNELS_SPREAD;
-
- chn = xmalloc_array(event_channel_t, max);
- if ( unlikely(chn == NULL) )
- return -ENOMEM;
+ struct evtchn *chn;
+ int port;
- memset(chn, 0, max * sizeof(event_channel_t));
+ for ( port = 0; port_is_valid(d, port); port++ )
+ if ( evtchn_from_port(d, port)->state == ECS_FREE )
+ return port;
- if ( d->event_channel != NULL )
- {
- memcpy(chn, d->event_channel, d->max_event_channel *
- sizeof(event_channel_t));
- xfree(d->event_channel);
- }
+ if ( port == MAX_EVTCHNS )
+ return -ENOSPC;
- d->event_channel = chn;
- d->max_event_channel = max;
- }
+ chn = xmalloc_array(struct evtchn, EVTCHNS_PER_BUCKET);
+ if ( unlikely(chn == NULL) )
+ return -ENOMEM;
+ memset(chn, 0, EVTCHNS_PER_BUCKET * sizeof(*chn));
+ bucket_from_port(d, port) = chn;
return port;
}
@@ -78,32 +61,52 @@ static int get_free_port(struct vcpu *v)
static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
{
+ struct evtchn *chn;
struct domain *d = current->domain;
- int port;
+ int port = alloc->port;
+ long rc = 0;
- spin_lock(&d->event_channel_lock);
+ spin_lock(&d->evtchn_lock);
- if ( (port = get_free_port(current)) >= 0 )
+ /* Obtain, or ensure that we already have, a valid <port>. */
+ if ( port == 0 )
{
- d->event_channel[port].state = ECS_UNBOUND;
- d->event_channel[port].u.unbound.remote_domid = alloc->dom;
+ if ( (port = get_free_port(d)) < 0 )
+ ERROR_EXIT(port);
}
+ else if ( !port_is_valid(d, port) )
+ ERROR_EXIT(-EINVAL);
+ chn = evtchn_from_port(d, port);
- spin_unlock(&d->event_channel_lock);
+ /* Validate channel's current state. */
+ switch ( chn->state )
+ {
+ case ECS_FREE:
+ chn->state = ECS_UNBOUND;
+ chn->u.unbound.remote_domid = alloc->dom;
+ break;
- if ( port < 0 )
- return port;
+ case ECS_UNBOUND:
+ if ( chn->u.unbound.remote_domid != alloc->dom )
+ ERROR_EXIT(-EINVAL);
+ break;
+
+ default:
+ ERROR_EXIT(-EINVAL);
+ }
+
+ out:
+ spin_unlock(&d->evtchn_lock);
alloc->port = port;
- return 0;
+ return rc;
}
static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
{
-#define ERROR_EXIT(_errno) do { rc = (_errno); goto out; } while ( 0 )
+ struct evtchn *chn1, *chn2;
struct domain *d1, *d2;
- struct vcpu *v1, *v2;
int port1 = bind->port1, port2 = bind->port2;
domid_t dom1 = bind->dom1, dom2 = bind->dom2;
long rc = 0;
@@ -111,9 +114,6 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
if ( !IS_PRIV(current->domain) && (dom1 != DOMID_SELF) )
return -EPERM;
- if ( (port1 < 0) || (port2 < 0) )
- return -EINVAL;
-
if ( dom1 == DOMID_SELF )
dom1 = current->domain->domain_id;
if ( dom2 == DOMID_SELF )
@@ -127,63 +127,61 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
return -ESRCH;
}
- v1 = d1->vcpu[0]; /* XXX */
- v2 = d2->vcpu[0]; /* XXX */
-
/* Avoid deadlock by first acquiring lock of domain with smaller id. */
if ( d1 < d2 )
{
- spin_lock(&d1->event_channel_lock);
- spin_lock(&d2->event_channel_lock);
+ spin_lock(&d1->evtchn_lock);
+ spin_lock(&d2->evtchn_lock);
}
else
{
if ( d1 != d2 )
- spin_lock(&d2->event_channel_lock);
- spin_lock(&d1->event_channel_lock);
+ spin_lock(&d2->evtchn_lock);
+ spin_lock(&d1->evtchn_lock);
}
/* Obtain, or ensure that we already have, a valid <port1>. */
if ( port1 == 0 )
{
- if ( (port1 = get_free_port(v1)) < 0 )
+ if ( (port1 = get_free_port(d1)) < 0 )
ERROR_EXIT(port1);
}
- else if ( port1 >= d1->max_event_channel )
+ else if ( !port_is_valid(d1, port1) )
ERROR_EXIT(-EINVAL);
+ chn1 = evtchn_from_port(d1, port1);
/* Obtain, or ensure that we already have, a valid <port2>. */
if ( port2 == 0 )
{
/* Make port1 non-free while we allocate port2 (in case dom1==dom2). */
- u16 tmp = d1->event_channel[port1].state;
- d1->event_channel[port1].state = ECS_INTERDOMAIN;
- port2 = get_free_port(v2);
- d1->event_channel[port1].state = tmp;
+ u16 state = chn1->state;
+ chn1->state = ECS_INTERDOMAIN;
+ port2 = get_free_port(d2);
+ chn1->state = state;
if ( port2 < 0 )
ERROR_EXIT(port2);
}
- else if ( port2 >= d2->max_event_channel )
+ else if ( !port_is_valid(d2, port2) )
ERROR_EXIT(-EINVAL);
+ chn2 = evtchn_from_port(d2, port2);
/* Validate <dom1,port1>'s current state. */
- switch ( d1->event_channel[port1].state )
+ switch ( chn1->state )
{
case ECS_FREE:
break;
case ECS_UNBOUND:
- if ( d1->event_channel[port1].u.unbound.remote_domid != dom2 )
+ if ( chn1->u.unbound.remote_domid != dom2 )
ERROR_EXIT(-EINVAL);
break;
case ECS_INTERDOMAIN:
- if ( d1->event_channel[port1].u.interdomain.remote_dom != v2 )
+ if ( chn1->u.interdomain.remote_dom != d2 )
ERROR_EXIT(-EINVAL);
- if ( (d1->event_channel[port1].u.interdomain.remote_port != port2) &&
- (bind->port2 != 0) )
+ if ( (chn1->u.interdomain.remote_port != port2) && (bind->port2 != 0) )
ERROR_EXIT(-EINVAL);
- port2 = d1->event_channel[port1].u.interdomain.remote_port;
+ port2 = chn1->u.interdomain.remote_port;
goto out;
default:
@@ -191,7 +189,7 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
}
/* Validate <dom2,port2>'s current state. */
- switch ( d2->event_channel[port2].state )
+ switch ( chn2->state )
{
case ECS_FREE:
if ( !IS_PRIV(current->domain) && (dom2 != DOMID_SELF) )
@@ -199,17 +197,16 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
break;
case ECS_UNBOUND:
- if ( d2->event_channel[port2].u.unbound.remote_domid != dom1 )
+ if ( chn2->u.unbound.remote_domid != dom1 )
ERROR_EXIT(-EINVAL);
break;
case ECS_INTERDOMAIN:
- if ( d2->event_channel[port2].u.interdomain.remote_dom != v1 )
+ if ( chn2->u.interdomain.remote_dom != d1 )
ERROR_EXIT(-EINVAL);
- if ( (d2->event_channel[port2].u.interdomain.remote_port != port1) &&
- (bind->port1 != 0) )
+ if ( (chn2->u.interdomain.remote_port != port1) && (bind->port1 != 0) )
ERROR_EXIT(-EINVAL);
- port1 = d2->event_channel[port2].u.interdomain.remote_port;
+ port1 = chn2->u.interdomain.remote_port;
goto out;
default:
@@ -220,18 +217,18 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
* Everything checked out okay -- bind <dom1,port1> to <dom2,port2>.
*/
- d1->event_channel[port1].u.interdomain.remote_dom = v2;
- d1->event_channel[port1].u.interdomain.remote_port = (u16)port2;
- d1->event_channel[port1].state = ECS_INTERDOMAIN;
+ chn1->u.interdomain.remote_dom = d2;
+ chn1->u.interdomain.remote_port = (u16)port2;
+ chn1->state = ECS_INTERDOMAIN;
- d2->event_channel[port2].u.interdomain.remote_dom = v1;
- d2->event_channel[port2].u.interdomain.remote_port = (u16)port1;
- d2->event_channel[port2].state = ECS_INTERDOMAIN;
+ chn2->u.interdomain.remote_dom = d1;
+ chn2->u.interdomain.remote_port = (u16)port1;
+ chn2->state = ECS_INTERDOMAIN;
out:
- spin_unlock(&d1->event_channel_lock);
+ spin_unlock(&d1->evtchn_lock);
if ( d1 != d2 )
- spin_unlock(&d2->event_channel_lock);
+ spin_unlock(&d2->evtchn_lock);
put_domain(d1);
put_domain(d2);
@@ -240,12 +237,12 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
bind->port2 = port2;
return rc;
-#undef ERROR_EXIT
}
static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
{
+ struct evtchn *chn;
struct vcpu *v = current;
struct domain *d = v->domain;
int port, virq = bind->virq;
@@ -253,23 +250,25 @@ static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
if ( virq >= ARRAY_SIZE(v->virq_to_evtchn) )
return -EINVAL;
- spin_lock(&d->event_channel_lock);
+ spin_lock(&d->evtchn_lock);
/*
* Port 0 is the fallback port for VIRQs that haven't been explicitly
* bound yet.
*/
if ( ((port = v->virq_to_evtchn[virq]) != 0) ||
- ((port = get_free_port(v)) < 0) )
+ ((port = get_free_port(d)) < 0) )
goto out;
- d->event_channel[port].state = ECS_VIRQ;
- d->event_channel[port].u.virq = virq;
+ chn = evtchn_from_port(d, port);
+ chn->state = ECS_VIRQ;
+ chn->notify_vcpu_id = v->vcpu_id;
+ chn->u.virq = virq;
v->virq_to_evtchn[virq] = port;
out:
- spin_unlock(&d->event_channel_lock);
+ spin_unlock(&d->evtchn_lock);
if ( port < 0 )
return port;
@@ -278,24 +277,26 @@ static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
return 0;
}
+
static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
{
- struct vcpu *v = current;
- struct domain *d = v->domain;
+ struct evtchn *chn;
+ struct domain *d = current->domain;
int port, ipi_vcpu = bind->ipi_vcpu;
- if ( ipi_vcpu >= MAX_VIRT_CPUS )
+ if ( (ipi_vcpu >= MAX_VIRT_CPUS) || (d->vcpu[ipi_vcpu] == NULL) )
return -EINVAL;
- spin_lock(&d->event_channel_lock);
+ spin_lock(&d->evtchn_lock);
- if ( (port = get_free_port(v)) >= 0 )
+ if ( (port = get_free_port(d)) >= 0 )
{
- d->event_channel[port].state = ECS_IPI;
- d->event_channel[port].u.ipi_vcpu = ipi_vcpu;
+ chn = evtchn_from_port(d, port);
+ chn->state = ECS_IPI;
+ chn->notify_vcpu_id = ipi_vcpu;
}
- spin_unlock(&d->event_channel_lock);
+ spin_unlock(&d->evtchn_lock);
if ( port < 0 )
return port;
@@ -307,20 +308,23 @@ static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
{
+ struct evtchn *chn;
struct domain *d = current->domain;
int port, rc, pirq = bind->pirq;
if ( pirq >= ARRAY_SIZE(d->pirq_to_evtchn) )
return -EINVAL;
- spin_lock(&d->event_channel_lock);
+ spin_lock(&d->evtchn_lock);
if ( ((rc = port = d->pirq_to_evtchn[pirq]) != 0) ||
- ((rc = port = get_free_port(current)) < 0) )
+ ((rc = port = get_free_port(d)) < 0) )
goto out;
+ chn = evtchn_from_port(d, port);
+
d->pirq_to_evtchn[pirq] = port;
- rc = pirq_guest_bind(current, pirq,
+ rc = pirq_guest_bind(d->vcpu[chn->notify_vcpu_id], pirq,
!!(bind->flags & BIND_PIRQ__WILL_SHARE));
if ( rc != 0 )
{
@@ -328,11 +332,11 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
goto out;
}
- d->event_channel[port].state = ECS_PIRQ;
- d->event_channel[port].u.pirq = pirq;
+ chn->state = ECS_PIRQ;
+ chn->u.pirq = pirq;
out:
- spin_unlock(&d->event_channel_lock);
+ spin_unlock(&d->evtchn_lock);
if ( rc < 0 )
return rc;
@@ -344,24 +348,23 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
static long __evtchn_close(struct domain *d1, int port1)
{
- struct domain *d2 = NULL;
- struct vcpu *v;
- event_channel_t *chn1, *chn2;
- int port2;
- long rc = 0;
+ struct domain *d2 = NULL;
+ struct vcpu *v;
+ struct evtchn *chn1, *chn2;
+ int port2;
+ long rc = 0;
again:
- spin_lock(&d1->event_channel_lock);
+ spin_lock(&d1->evtchn_lock);
- chn1 = d1->event_channel;
-
- if ( (port1 < 0) || (port1 >= d1->max_event_channel) )
+ if ( !port_is_valid(d1, port1) )
{
rc = -EINVAL;
goto out;
}
- switch ( chn1[port1].state )
+ chn1 = evtchn_from_port(d1, port1);
+ switch ( chn1->state )
{
case ECS_FREE:
case ECS_RESERVED:
@@ -372,15 +375,14 @@ static long __evtchn_close(struct domain *d1, int port1)
break;
case ECS_PIRQ:
- if ( (rc = pirq_guest_unbind(d1, chn1[port1].u.pirq)) == 0 )
- d1->pirq_to_evtchn[chn1[port1].u.pirq] = 0;
+ if ( (rc = pirq_guest_unbind(d1, chn1->u.pirq)) == 0 )
+ d1->pirq_to_evtchn[chn1->u.pirq] = 0;
break;
case ECS_VIRQ:
- /* XXX could store vcpu in chn1[port1].u */
for_each_vcpu ( d1, v )
- if (v->virq_to_evtchn[chn1[port1].u.virq] == port1)
- v->virq_to_evtchn[chn1[port1].u.virq] = 0;
+ if ( v->virq_to_evtchn[chn1->u.virq] == port1 )
+ v->virq_to_evtchn[chn1->u.virq] = 0;
break;
case ECS_IPI:
@@ -389,7 +391,7 @@ static long __evtchn_close(struct domain *d1, int port1)
case ECS_INTERDOMAIN:
if ( d2 == NULL )
{
- d2 = chn1[port1].u.interdomain.remote_dom->domain;
+ d2 = chn1->u.interdomain.remote_dom;
/* If we unlock d1 then we could lose d2. Must get a reference. */
if ( unlikely(!get_domain(d2)) )
@@ -404,50 +406,47 @@ static long __evtchn_close(struct domain *d1, int port1)
if ( d1 < d2 )
{
- spin_lock(&d2->event_channel_lock);
+ spin_lock(&d2->evtchn_lock);
}
else if ( d1 != d2 )
{
- spin_unlock(&d1->event_channel_lock);
- spin_lock(&d2->event_channel_lock);
+ spin_unlock(&d1->evtchn_lock);
+ spin_lock(&d2->evtchn_lock);
goto again;
}
}
- else if ( d2 != chn1[port1].u.interdomain.remote_dom->domain )
+ else if ( d2 != chn1->u.interdomain.remote_dom )
{
rc = -EINVAL;
goto out;
}
- chn2 = d2->event_channel;
- port2 = chn1[port1].u.interdomain.remote_port;
-
- if ( port2 >= d2->max_event_channel )
- BUG();
- if ( chn2[port2].state != ECS_INTERDOMAIN )
- BUG();
- if ( chn2[port2].u.interdomain.remote_dom->domain != d1 )
- BUG();
-
- chn2[port2].state = ECS_UNBOUND;
- chn2[port2].u.unbound.remote_domid = d1->domain_id;
+ port2 = chn1->u.interdomain.remote_port;
+ BUG_ON(!port_is_valid(d2, port2));
+
+ chn2 = evtchn_from_port(d2, port2);
+ BUG_ON(chn2->state != ECS_INTERDOMAIN);
+ BUG_ON(chn2->u.interdomain.remote_dom != d1);
+
+ chn2->state = ECS_UNBOUND;
+ chn2->u.unbound.remote_domid = d1->domain_id;
break;
default:
BUG();
}
- chn1[port1].state = ECS_FREE;
+ chn1->state = ECS_FREE;
out:
if ( d2 != NULL )
{
if ( d1 != d2 )
- spin_unlock(&d2->event_channel_lock);
+ spin_unlock(&d2->evtchn_lock);
put_domain(d2);
}
- spin_unlock(&d1->event_channel_lock);
+ spin_unlock(&d1->evtchn_lock);
return rc;
}
@@ -476,50 +475,52 @@ static long evtchn_close(evtchn_close_t *close)
long evtchn_send(int lport)
{
- struct domain *ld = current->domain;
- struct vcpu *rd;
+ struct evtchn *lchn, *rchn;
+ struct domain *ld = current->domain, *rd;
int rport, ret = 0;
- spin_lock(&ld->event_channel_lock);
+ spin_lock(&ld->evtchn_lock);
- if ( unlikely(lport < 0) ||
- unlikely(lport >= ld->max_event_channel))
+ if ( unlikely(!port_is_valid(ld, lport)) )
{
- spin_unlock(&ld->event_channel_lock);
+ spin_unlock(&ld->evtchn_lock);
return -EINVAL;
}
- switch ( ld->event_channel[lport].state )
+ lchn = evtchn_from_port(ld, lport);
+ switch ( lchn->state )
{
case ECS_INTERDOMAIN:
- rd = ld->event_channel[lport].u.interdomain.remote_dom;
- rport = ld->event_channel[lport].u.interdomain.remote_port;
-
- evtchn_set_pending(rd, rport);
+ rd = lchn->u.interdomain.remote_dom;
+ rport = lchn->u.interdomain.remote_port;
+ rchn = evtchn_from_port(rd, rport);
+ evtchn_set_pending(rd->vcpu[rchn->notify_vcpu_id], rport);
break;
case ECS_IPI:
- rd = ld->vcpu[ld->event_channel[lport].u.ipi_vcpu];
- if ( rd )
- evtchn_set_pending(rd, lport);
- else
- ret = -EINVAL;
+ evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport);
break;
default:
ret = -EINVAL;
}
- spin_unlock(&ld->event_channel_lock);
+ spin_unlock(&ld->evtchn_lock);
return ret;
}
+void send_guest_pirq(struct domain *d, int pirq)
+{
+ int port = d->pirq_to_evtchn[pirq];
+ struct evtchn *chn = evtchn_from_port(d, port);
+ evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port);
+}
static long evtchn_status(evtchn_status_t *status)
{
struct domain *d;
domid_t dom = status->dom;
int port = status->port;
- event_channel_t *chn;
+ struct evtchn *chn;
long rc = 0;
if ( dom == DOMID_SELF )
@@ -530,17 +531,16 @@ static long evtchn_status(evtchn_status_t *status)
if ( (d = find_domain_by_id(dom)) == NULL )
return -ESRCH;
- spin_lock(&d->event_channel_lock);
-
- chn = d->event_channel;
+ spin_lock(&d->evtchn_lock);
- if ( (port < 0) || (port >= d->max_event_channel) )
+ if ( !port_is_valid(d, port) )
{
rc = -EINVAL;
goto out;
}
- switch ( chn[port].state )
+ chn = evtchn_from_port(d, port);
+ switch ( chn->state )
{
case ECS_FREE:
case ECS_RESERVED:
@@ -548,32 +548,32 @@ static long evtchn_status(evtchn_status_t *status)
break;
case ECS_UNBOUND:
status->status = EVTCHNSTAT_unbound;
- status->u.unbound.dom = chn[port].u.unbound.remote_domid;
+ status->u.unbound.dom = chn->u.unbound.remote_domid;
break;
case ECS_INTERDOMAIN:
status->status = EVTCHNSTAT_interdomain;
status->u.interdomain.dom =
- chn[port].u.interdomain.remote_dom->domain->domain_id;
- status->u.interdomain.port = chn[port].u.interdomain.remote_port;
+ chn->u.interdomain.remote_dom->domain_id;
+ status->u.interdomain.port = chn->u.interdomain.remote_port;
break;
case ECS_PIRQ:
status->status = EVTCHNSTAT_pirq;
- status->u.pirq = chn[port].u.pirq;
+ status->u.pirq = chn->u.pirq;
break;
case ECS_VIRQ:
status->status = EVTCHNSTAT_virq;
- status->u.virq = chn[port].u.virq;
+ status->u.virq = chn->u.virq;
break;
case ECS_IPI:
status->status = EVTCHNSTAT_ipi;
- status->u.ipi_vcpu = chn[port].u.ipi_vcpu;
+ status->u.ipi_vcpu = chn->notify_vcpu_id;
break;
default:
BUG();
}
out:
- spin_unlock(&d->event_channel_lock);
+ spin_unlock(&d->evtchn_lock);
put_domain(d);
return rc;
}
@@ -642,26 +642,26 @@ long do_event_channel_op(evtchn_op_t *uop)
}
-int init_event_channels(struct domain *d)
+int evtchn_init(struct domain *d)
{
- spin_lock_init(&d->event_channel_lock);
- /* Call get_free_port to initialize d->event_channel */
- if ( get_free_port(d->vcpu[0]) != 0 )
+ spin_lock_init(&d->evtchn_lock);
+ if ( get_free_port(d) != 0 )
return -EINVAL;
- d->event_channel[0].state = ECS_RESERVED;
+ evtchn_from_port(d, 0)->state = ECS_RESERVED;
return 0;
}
-void destroy_event_channels(struct domain *d)
+void evtchn_destroy(struct domain *d)
{
int i;
- if ( d->event_channel != NULL )
- {
- for ( i = 0; i < d->max_event_channel; i++ )
+
+ for ( i = 0; port_is_valid(d, i); i++ )
(void)__evtchn_close(d, i);
- xfree(d->event_channel);
- }
+
+ for ( i = 0; i < NR_EVTCHN_BUCKETS; i++ )
+ if ( d->evtchn[i] != NULL )
+ xfree(d->evtchn[i]);
}
/*
diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index d2524ba009..610fbdb020 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -31,7 +31,7 @@
#include <xen/irq.h>
#include <xen/softirq.h>
#include <xen/shadow.h>
-#include <asm/domain_page.h>
+#include <xen/domain_page.h>
#include <asm/page.h>
/*
@@ -383,9 +383,9 @@ void scrub_heap_pages(void)
}
else
{
- p = map_domain_mem(pfn << PAGE_SHIFT);
+ p = map_domain_page(pfn);
clear_page(p);
- unmap_domain_mem(p);
+ unmap_domain_page(p);
}
}
@@ -674,9 +674,9 @@ static void page_scrub_softirq(void)
{
pg = list_entry(ent, struct pfn_info, list);
ent = ent->prev;
- p = map_domain_mem(page_to_phys(pg));
+ p = map_domain_page(page_to_pfn(pg));
clear_page(p);
- unmap_domain_mem(p);
+ unmap_domain_page(p);
free_heap_pages(MEMZONE_DOM, pg, 0);
}
} while ( (NOW() - start) < MILLISECS(1) );
diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c
index 6f6234c8d0..5ade44b42b 100644
--- a/xen/drivers/char/console.c
+++ b/xen/drivers/char/console.c
@@ -16,6 +16,7 @@
#include <xen/spinlock.h>
#include <xen/console.h>
#include <xen/serial.h>
+#include <xen/softirq.h>
#include <xen/keyhandler.h>
#include <xen/mm.h>
#include <xen/delay.h>
@@ -24,27 +25,28 @@
#include <asm/debugger.h>
#include <asm/io.h>
-/* opt_console: comma-separated list of console outputs. */
+/* console: comma-separated list of console outputs. */
static char opt_console[30] = OPT_CONSOLE_STR;
string_param("console", opt_console);
-/* opt_conswitch: a character pair controlling console switching. */
+/* conswitch: a character pair controlling console switching. */
/* Char 1: CTRL+<char1> is used to switch console input between Xen and DOM0 */
/* Char 2: If this character is 'x', then do not auto-switch to DOM0 when it */
/* boots. Any other value, or omitting the char, enables auto-switch */
static unsigned char opt_conswitch[5] = "a";
string_param("conswitch", opt_conswitch);
+/* sync_console: force synchronous console output (useful for debugging). */
+static int opt_sync_console;
+boolean_param("sync_console", opt_sync_console);
+
static int xpos, ypos;
static unsigned char *video;
-#define CONSOLE_RING_SIZE 16392
-typedef struct console_ring_st
-{
- char buf[CONSOLE_RING_SIZE];
- unsigned int len;
-} console_ring_t;
-static console_ring_t console_ring;
+#define CONRING_SIZE 16384
+#define CONRING_IDX_MASK(i) ((i)&(CONRING_SIZE-1))
+static char conring[CONRING_SIZE];
+static unsigned int conringc, conringp;
static char printk_prefix[16] = "";
@@ -214,23 +216,33 @@ static void putchar_console(int c)
static void putchar_console_ring(int c)
{
- if ( console_ring.len < CONSOLE_RING_SIZE )
- console_ring.buf[console_ring.len++] = (char)c;
+ conring[CONRING_IDX_MASK(conringp++)] = c;
+ if ( (conringp - conringc) > CONRING_SIZE )
+ conringc = conringp - CONRING_SIZE;
}
-long read_console_ring(unsigned long str, unsigned int count, unsigned cmd)
+long read_console_ring(char **pstr, u32 *pcount, int clear)
{
- unsigned int len;
-
- len = (console_ring.len < count) ? console_ring.len : count;
-
- if ( copy_to_user((char *)str, console_ring.buf, len) )
- return -EFAULT;
+ char *str = *pstr;
+ u32 count = *pcount;
+ unsigned int p, q;
+ unsigned long flags;
- if ( cmd & CONSOLE_RING_CLEAR )
- console_ring.len = 0;
-
- return len;
+ /* Start of buffer may get overwritten during copy. So copy backwards. */
+ for ( p = conringp, q = count; (p > conringc) && (q > 0); p--, q-- )
+ if ( put_user(conring[CONRING_IDX_MASK(p-1)], (char *)str+q-1) )
+ return -EFAULT;
+
+ if ( clear )
+ {
+ spin_lock_irqsave(&console_lock, flags);
+ conringc = conringp;
+ spin_unlock_irqrestore(&console_lock, flags);
+ }
+
+ *pstr = str + q;
+ *pcount = count - q;
+ return 0;
}
@@ -297,13 +309,44 @@ static void serial_rx(char c, struct cpu_user_regs *regs)
__serial_rx(c, regs);
}
+long guest_console_write(char *buffer, int count)
+{
+ char kbuf[128];
+ int kcount;
+
+ while ( count > 0 )
+ {
+ while ( serial_tx_space(sercon_handle) < (SERIAL_TXBUFSZ / 2) )
+ {
+ if ( hypercall_preempt_check() )
+ break;
+ cpu_relax();
+ }
+
+ if ( hypercall_preempt_check() )
+ return hypercall3_create_continuation(
+ __HYPERVISOR_console_io, CONSOLEIO_write, count, buffer);
+
+ kcount = min_t(int, count, sizeof(kbuf)-1);
+ if ( copy_from_user(kbuf, buffer, kcount) )
+ return -EFAULT;
+ kbuf[kcount] = '\0';
+
+ serial_puts(sercon_handle, kbuf);
+
+ buffer += kcount;
+ count -= kcount;
+ }
+
+ return 0;
+}
+
long do_console_io(int cmd, int count, char *buffer)
{
- char *kbuf;
- long rc;
+ long rc;
#ifndef VERBOSE
- /* Only domain-0 may access the emergency console. */
+ /* Only domain 0 may access the emergency console. */
if ( current->domain->domain_id != 0 )
return -EPERM;
#endif
@@ -311,17 +354,7 @@ long do_console_io(int cmd, int count, char *buffer)
switch ( cmd )
{
case CONSOLEIO_write:
- if ( count > (PAGE_SIZE-1) )
- count = PAGE_SIZE-1;
- if ( (kbuf = (char *)alloc_xenheap_page()) == NULL )
- return -ENOMEM;
- kbuf[count] = '\0';
- rc = count;
- if ( copy_from_user(kbuf, buffer, count) )
- rc = -EFAULT;
- else
- serial_puts(sercon_handle, kbuf);
- free_xenheap_page((unsigned long)kbuf);
+ rc = guest_console_write(buffer, count);
break;
case CONSOLEIO_read:
rc = 0;
@@ -437,6 +470,12 @@ void init_console(void)
XEN_COMPILER, XEN_COMPILE_DATE);
printk(" Latest ChangeSet: %s\n\n", XEN_CHANGESET);
set_printk_prefix("(XEN) ");
+
+ if ( opt_sync_console )
+ {
+ serial_start_sync(sercon_handle);
+ printk("Console output is synchronous.\n");
+ }
}
void console_endboot(int disable_vga)
@@ -467,6 +506,16 @@ void console_force_lock(void)
spin_lock(&console_lock);
}
+void console_start_sync(void)
+{
+ serial_start_sync(sercon_handle);
+}
+
+void console_end_sync(void)
+{
+ serial_end_sync(sercon_handle);
+}
+
void console_putc(char c)
{
serial_putc(sercon_handle, c);
diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
index 3a58e34767..680a6ef1bc 100644
--- a/xen/drivers/char/ns16550.c
+++ b/xen/drivers/char/ns16550.c
@@ -16,7 +16,7 @@
#include <asm/io.h>
/* Config serial port with a string <baud>,DPS,<io-base>,<irq>. */
-static char opt_com1[30] = "", opt_com2[30] = "";
+char opt_com1[30] = "", opt_com2[30] = "";
string_param("com1", opt_com1);
string_param("com2", opt_com2);
@@ -49,7 +49,15 @@ static struct ns16550 {
#define IER_ELSI 0x04 /* rx line status */
#define IER_EMSI 0x08 /* MODEM status */
-/* FIFO control register */
+/* Interrupt Identification Register */
+#define IIR_NOINT 0x01 /* no interrupt pending */
+#define IIR_IMASK 0x06 /* interrupt identity: */
+#define IIR_LSI 0x06 /* - rx line status */
+#define IIR_RDAI 0x04 /* - rx data recv'd */
+#define IIR_THREI 0x02 /* - tx reg. empty */
+#define IIR_MSI 0x00 /* - MODEM status */
+
+/* FIFO Control Register */
#define FCR_ENABLE 0x01 /* enable FIFO */
#define FCR_CLRX 0x02 /* clear Rx FIFO */
#define FCR_CLTX 0x04 /* clear Tx FIFO */
@@ -59,7 +67,7 @@ static struct ns16550 {
#define FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */
#define FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */
-/* Line control register */
+/* Line Control Register */
#define LCR_DLAB 0x80 /* Divisor Latch Access */
/* Modem Control Register */
@@ -101,16 +109,25 @@ static void ns_write_reg(struct ns16550 *uart, int reg, char c)
static void ns16550_interrupt(
int irq, void *dev_id, struct cpu_user_regs *regs)
{
- serial_rx_interrupt(dev_id, regs);
+ struct serial_port *port = dev_id;
+ struct ns16550 *uart = port->uart;
+
+ while ( !(ns_read_reg(uart, IIR) & IIR_NOINT) )
+ {
+ serial_tx_interrupt(port, regs);
+ serial_rx_interrupt(port, regs);
+ }
}
-static void ns16550_putc(struct serial_port *port, char c)
+static int ns16550_tx_empty(struct serial_port *port)
{
struct ns16550 *uart = port->uart;
+ return !!(ns_read_reg(uart, LSR) & LSR_THRE);
+}
- while ( !(ns_read_reg(uart, LSR) & LSR_THRE) )
- cpu_relax();
-
+static void ns16550_putc(struct serial_port *port, char c)
+{
+ struct ns16550 *uart = port->uart;
ns_write_reg(uart, THR, c);
}
@@ -150,6 +167,10 @@ static void ns16550_init_preirq(struct serial_port *port)
/* Enable and clear the FIFOs. Set a large trigger threshold. */
ns_write_reg(uart, FCR, FCR_ENABLE | FCR_CLRX | FCR_CLTX | FCR_TRG14);
+
+ /* Check this really is a 16550+. Otherwise we have no FIFOs. */
+ if ( (ns_read_reg(uart, IIR) & 0xc0) == 0xc0 )
+ port->tx_fifo_size = 16;
}
static void ns16550_init_postirq(struct serial_port *port)
@@ -157,20 +178,19 @@ static void ns16550_init_postirq(struct serial_port *port)
struct ns16550 *uart = port->uart;
int rc;
+ serial_async_transmit(port);
+
uart->irqaction.handler = ns16550_interrupt;
uart->irqaction.name = "ns16550";
uart->irqaction.dev_id = port;
if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
printk("ERROR: Failed to allocate na16550 IRQ %d\n", uart->irq);
- /* For sanity, clear the receive FIFO. */
- ns_write_reg(uart, FCR, FCR_ENABLE | FCR_CLRX | FCR_TRG14);
-
/* Master interrupt enable; also keep DTR/RTS asserted. */
ns_write_reg(uart, MCR, MCR_OUT2 | MCR_DTR | MCR_RTS);
- /* Enable receive interrupts. */
- ns_write_reg(uart, IER, IER_ERDAI);
+ /* Enable receive and transmit interrupts. */
+ ns_write_reg(uart, IER, IER_ERDAI | IER_ETHREI);
}
#ifdef CONFIG_X86
@@ -188,6 +208,7 @@ static struct uart_driver ns16550_driver = {
.init_preirq = ns16550_init_preirq,
.init_postirq = ns16550_init_postirq,
.endboot = ns16550_endboot,
+ .tx_empty = ns16550_tx_empty,
.putc = ns16550_putc,
.getc = ns16550_getc
};
diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c
index e8d75a343b..a59146da0a 100644
--- a/xen/drivers/char/serial.c
+++ b/xen/drivers/char/serial.c
@@ -22,40 +22,93 @@ static struct serial_port com[2] = {
void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
{
char c;
- serial_rx_fn fn;
+ serial_rx_fn fn = NULL;
unsigned long flags;
- BUG_ON(!port->driver);
- BUG_ON(!port->driver->getc);
+ spin_lock_irqsave(&port->lock, flags);
- for ( ; ; )
+ if ( port->driver->getc(port, &c) )
{
- spin_lock_irqsave(&port->lock, flags);
-
- if ( !port->driver->getc(port, &c) )
- break;
-
- fn = NULL;
if ( port->rx != NULL )
fn = port->rx;
else if ( (c & 0x80) && (port->rx_hi != NULL) )
fn = port->rx_hi;
else if ( !(c & 0x80) && (port->rx_lo != NULL) )
fn = port->rx_lo;
- else if ( (port->rxbufp - port->rxbufc) != RXBUFSZ )
- port->rxbuf[MASK_RXBUF_IDX(port->rxbufp++)] = c;
+ else if ( (port->rxbufp - port->rxbufc) != SERIAL_RXBUFSZ )
+ port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufp++)] = c;
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
- spin_unlock_irqrestore(&port->lock, flags);
+ if ( fn != NULL )
+ (*fn)(c & 0x7f, regs);
+}
+
+void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
+{
+ int i;
+ unsigned long flags;
- if ( fn != NULL )
- (*fn)(c & 0x7f, regs);
+ spin_lock_irqsave(&port->lock, flags);
- cpu_relax();
+ if ( port->driver->tx_empty(port) )
+ {
+ for ( i = 0; i < port->tx_fifo_size; i++ )
+ {
+ if ( port->txbufc == port->txbufp )
+ break;
+ port->driver->putc(
+ port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
+ }
}
spin_unlock_irqrestore(&port->lock, flags);
}
+static void __serial_putc(struct serial_port *port, char c)
+{
+ int i;
+
+ if ( (port->txbuf != NULL) && !port->sync )
+ {
+ /* Interrupt-driven (asynchronous) transmitter. */
+ if ( (port->txbufp - port->txbufc) == SERIAL_TXBUFSZ )
+ {
+ /* Buffer is full: we spin, but could alternatively drop chars. */
+ while ( !port->driver->tx_empty(port) )
+ cpu_relax();
+ for ( i = 0; i < port->tx_fifo_size; i++ )
+ port->driver->putc(
+ port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
+ port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufp++)] = c;
+ }
+ else if ( ((port->txbufp - port->txbufc) == 0) &&
+ port->driver->tx_empty(port) )
+ {
+ /* Buffer and UART FIFO are both empty. */
+ port->driver->putc(port, c);
+ }
+ else
+ {
+ /* Normal case: buffer the character. */
+ port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufp++)] = c;
+ }
+ }
+ else if ( port->driver->tx_empty )
+ {
+ /* Synchronous finite-capacity transmitter. */
+ while ( !port->driver->tx_empty(port) )
+ cpu_relax();
+ port->driver->putc(port, c);
+ }
+ else
+ {
+ /* Simple synchronous transmitter. */
+ port->driver->putc(port, c);
+ }
+}
+
void serial_putc(int handle, char c)
{
struct serial_port *port = &com[handle & SERHND_IDX];
@@ -67,22 +120,43 @@ void serial_putc(int handle, char c)
spin_lock_irqsave(&port->lock, flags);
if ( (c == '\n') && (handle & SERHND_COOKED) )
- port->driver->putc(port, '\r');
+ __serial_putc(port, '\r');
if ( handle & SERHND_HI )
c |= 0x80;
else if ( handle & SERHND_LO )
c &= 0x7f;
- port->driver->putc(port, c);
+ __serial_putc(port, c);
spin_unlock_irqrestore(&port->lock, flags);
}
void serial_puts(int handle, const char *s)
{
- while ( *s != '\0' )
- serial_putc(handle, *s++);
+ struct serial_port *port = &com[handle & SERHND_IDX];
+ unsigned long flags;
+ char c;
+
+ if ( (handle == -1) || !port->driver || !port->driver->putc )
+ return;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ while ( (c = *s++) != '\0' )
+ {
+ if ( (c == '\n') && (handle & SERHND_COOKED) )
+ __serial_putc(port, '\r');
+
+ if ( handle & SERHND_HI )
+ c |= 0x80;
+ else if ( handle & SERHND_LO )
+ c &= 0x7f;
+
+ __serial_putc(port, c);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
}
char serial_getc(int handle)
@@ -101,7 +175,7 @@ char serial_getc(int handle)
if ( port->rxbufp != port->rxbufc )
{
- c = port->rxbuf[MASK_RXBUF_IDX(port->rxbufc++)];
+ c = port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufc++)];
break;
}
@@ -201,6 +275,54 @@ void serial_force_unlock(int handle)
struct serial_port *port = &com[handle & SERHND_IDX];
if ( handle != -1 )
port->lock = SPIN_LOCK_UNLOCKED;
+ serial_start_sync(handle);
+}
+
+void serial_start_sync(int handle)
+{
+ struct serial_port *port = &com[handle & SERHND_IDX];
+ unsigned long flags;
+
+ if ( handle == -1 )
+ return;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ if ( port->sync++ == 0 )
+ {
+ while ( (port->txbufp - port->txbufc) != 0 )
+ {
+ while ( !port->driver->tx_empty(port) )
+ cpu_relax();
+ port->driver->putc(
+ port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
+ }
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+void serial_end_sync(int handle)
+{
+ struct serial_port *port = &com[handle & SERHND_IDX];
+ unsigned long flags;
+
+ if ( handle == -1 )
+ return;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ port->sync--;
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+int serial_tx_space(int handle)
+{
+ struct serial_port *port = &com[handle & SERHND_IDX];
+ if ( handle == -1 )
+ return SERIAL_TXBUFSZ;
+ return SERIAL_TXBUFSZ - (port->txbufp - port->txbufc);
}
void serial_init_preirq(void)
@@ -229,8 +351,19 @@ void serial_endboot(void)
void serial_register_uart(int idx, struct uart_driver *driver, void *uart)
{
+ /* Store UART-specific info. */
com[idx].driver = driver;
com[idx].uart = uart;
+
+ /* Default is no transmit FIFO. */
+ com[idx].tx_fifo_size = 1;
+}
+
+void serial_async_transmit(struct serial_port *port)
+{
+ BUG_ON(!port->driver->tx_empty);
+ if ( !port->txbuf )
+ port->txbuf = (char *)alloc_xenheap_pages(get_order(SERIAL_TXBUFSZ));
}
/*
diff --git a/xen/include/asm-ia64/config.h b/xen/include/asm-ia64/config.h
index c419adf8be..fbff17469f 100644
--- a/xen/include/asm-ia64/config.h
+++ b/xen/include/asm-ia64/config.h
@@ -18,6 +18,8 @@
#define CONFIG_IA64_PAGE_SIZE_16KB // 4KB doesn't work?!?
#define CONFIG_IA64_GRANULE_16MB
+#define CONFIG_EFI_PCDP
+
#ifndef __ASSEMBLY__
// can't find where this typedef was before?!?
@@ -223,7 +225,6 @@ struct screen_info { };
#define FORCE_CRASH() asm("break 0;;");
// these declarations got moved at some point, find a better place for them
-extern int opt_noht;
extern int ht_per_core;
// needed for include/xen/smp.h
diff --git a/xen/include/asm-ia64/domain_page.h b/xen/include/asm-ia64/domain_page.h
deleted file mode 100644
index d131576267..0000000000
--- a/xen/include/asm-ia64/domain_page.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/******************************************************************************
- * domain_page.h
- *
- * This is a trivial no-op on ia64, where we can 1:1 map all RAM.
- */
-
-#ifndef __ASM_DOMAIN_PAGE_H__
-#define __ASM_DOMAIN_PAGE_H__
-
-#define map_domain_mem(_pa) phys_to_virt(_pa)
-#define unmap_domain_mem(_va) ((void)(_va))
-
-#endif /* __ASM_DOMAIN_PAGE_H__ */
-
diff --git a/xen/include/asm-ia64/init.h b/xen/include/asm-ia64/init.h
index e828ab6d85..7e5df20da6 100644
--- a/xen/include/asm-ia64/init.h
+++ b/xen/include/asm-ia64/init.h
@@ -14,7 +14,7 @@
#define __exitdata \
__attribute_used__ __attribute__ ((__section__ (".data.exit")))
#define __initsetup \
- __attribute_used__ __attribute__ ((__section__ (".setup.init")))
+ __attribute_used__ __attribute__ ((__section__ (".init.setup")))
#define __init_call \
__attribute_used__ __attribute__ ((__section__ (".initcall1.init")))
#define __exit_call \
diff --git a/xen/include/asm-ia64/mm.h b/xen/include/asm-ia64/mm.h
index 56df1706f9..a762ec6318 100644
--- a/xen/include/asm-ia64/mm.h
+++ b/xen/include/asm-ia64/mm.h
@@ -90,7 +90,7 @@ struct page
/* Page is on a free list. */
struct {
/* Mask of possibly-tainted TLBs. */
- u64 cpu_mask;
+ cpumask_t cpumask;
/* Order-size of the free chunk this page is the head of. */
u8 order;
} free;
diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h
index 48fe47a953..bf196d0b17 100644
--- a/xen/include/asm-x86/config.h
+++ b/xen/include/asm-x86/config.h
@@ -189,7 +189,8 @@ extern unsigned long _end; /* standard ELF symbol */
#elif defined(__i386__)
-#define CONFIG_X86_32 1
+#define CONFIG_X86_32 1
+#define CONFIG_DOMAIN_PAGE 1
#define asmlinkage __attribute__((regparm(0)))
@@ -198,7 +199,7 @@ extern unsigned long _end; /* standard ELF symbol */
* ------ ------
* I/O remapping area ( 4MB)
* Direct-map (1:1) area [Xen code/data/heap] (12MB)
- * map_domain_mem cache ( 4MB)
+ * map_domain_page cache ( 4MB)
* Per-domain mappings ( 4MB)
* Shadow linear pagetable ( 4MB) ( 8MB)
* Guest linear pagetable ( 4MB) ( 8MB)
diff --git a/xen/include/asm-x86/debugger.h b/xen/include/asm-x86/debugger.h
index 34ff5bdddc..aa2050f849 100644
--- a/xen/include/asm-x86/debugger.h
+++ b/xen/include/asm-x86/debugger.h
@@ -55,22 +55,22 @@ static inline int debugger_trap_fatal(
#elif defined(DOMU_DEBUG)
-#include <xen/softirq.h>
+#include <xen/sched.h>
+#include <asm/regs.h>
static inline int debugger_trap_entry(
unsigned int vector, struct cpu_user_regs *regs)
{
struct vcpu *v = current;
- if ( !KERNEL_MODE(ed, regs) || (ed->domain->domain_id == 0) )
+ if ( !KERNEL_MODE(v, regs) || (v->domain->domain_id == 0) )
return 0;
switch ( vector )
{
case TRAP_int3:
case TRAP_debug:
- set_bit(_VCPUF_ctrl_pause, &ed->vcpu_flags);
- raise_softirq(SCHEDULE_SOFTIRQ);
+ domain_pause_for_debugger();
return 1;
}
@@ -80,7 +80,6 @@ static inline int debugger_trap_entry(
#define debugger_trap_fatal(_v, _r) (0)
#define debugger_trap_immediate()
-
#elif 0
extern int kdb_trap(int, int, struct cpu_user_regs *);
diff --git a/xen/include/asm-x86/domain_page.h b/xen/include/asm-x86/domain_page.h
deleted file mode 100644
index 3eae53933d..0000000000
--- a/xen/include/asm-x86/domain_page.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef __x86_64__
-#include <asm/x86_64/domain_page.h>
-#else
-#include <asm/x86_32/domain_page.h>
-#endif
diff --git a/xen/include/asm-x86/hardirq.h b/xen/include/asm-x86/hardirq.h
index 576efd3c7c..04fa38b4be 100644
--- a/xen/include/asm-x86/hardirq.h
+++ b/xen/include/asm-x86/hardirq.h
@@ -15,7 +15,7 @@ typedef struct {
#define in_irq() (local_irq_count(smp_processor_id()) != 0)
-#define irq_enter(cpu, irq) (local_irq_count(cpu)++)
-#define irq_exit(cpu, irq) (local_irq_count(cpu)--)
+#define irq_enter(cpu) (local_irq_count(cpu)++)
+#define irq_exit(cpu) (local_irq_count(cpu)--)
#endif /* __ASM_HARDIRQ_H */
diff --git a/xen/include/asm-x86/io_apic.h b/xen/include/asm-x86/io_apic.h
index 5e9448a847..4cacb8b419 100644
--- a/xen/include/asm-x86/io_apic.h
+++ b/xen/include/asm-x86/io_apic.h
@@ -14,44 +14,6 @@
#ifdef CONFIG_X86_IO_APIC
-#ifdef CONFIG_PCI_MSI
-static inline int use_pci_vector(void) {return 1;}
-static inline void disable_edge_ioapic_vector(unsigned int vector) { }
-static inline void end_edge_ioapic_vector (unsigned int vector) { }
-#define startup_level_ioapic startup_level_ioapic_vector
-#define shutdown_level_ioapic mask_IO_APIC_vector
-#define enable_level_ioapic unmask_IO_APIC_vector
-#define disable_level_ioapic mask_IO_APIC_vector
-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector
-#define end_level_ioapic end_level_ioapic_vector
-#define set_ioapic_affinity set_ioapic_affinity_vector
-
-#define startup_edge_ioapic startup_edge_ioapic_vector
-#define shutdown_edge_ioapic disable_edge_ioapic_vector
-#define enable_edge_ioapic unmask_IO_APIC_vector
-#define disable_edge_ioapic disable_edge_ioapic_vector
-#define ack_edge_ioapic ack_edge_ioapic_vector
-#define end_edge_ioapic end_edge_ioapic_vector
-#else
-static inline int use_pci_vector(void) {return 0;}
-static inline void disable_edge_ioapic_irq(unsigned int irq) { }
-static inline void end_edge_ioapic_irq (unsigned int irq) { }
-#define startup_level_ioapic startup_level_ioapic_irq
-#define shutdown_level_ioapic mask_IO_APIC_irq
-#define enable_level_ioapic unmask_IO_APIC_irq
-#define disable_level_ioapic mask_IO_APIC_irq
-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq
-#define end_level_ioapic end_level_ioapic_irq
-#define set_ioapic_affinity set_ioapic_affinity_irq
-
-#define startup_edge_ioapic startup_edge_ioapic_irq
-#define shutdown_edge_ioapic disable_edge_ioapic_irq
-#define enable_edge_ioapic unmask_IO_APIC_irq
-#define disable_edge_ioapic disable_edge_ioapic_irq
-#define ack_edge_ioapic ack_edge_ioapic_irq
-#define end_edge_ioapic end_edge_ioapic_irq
-#endif
-
#define IO_APIC_BASE(idx) \
((volatile int *)(__fix_to_virt(FIX_IO_APIC_BASE_0 + idx) \
+ (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK)))
diff --git a/xen/include/asm-x86/irq.h b/xen/include/asm-x86/irq.h
index 97f143ad44..8ebbeb184a 100644
--- a/xen/include/asm-x86/irq.h
+++ b/xen/include/asm-x86/irq.h
@@ -8,17 +8,23 @@
#include <asm/asm_defns.h>
#include <irq_vectors.h>
-extern void disable_irq(unsigned int);
+#define IO_APIC_IRQ(irq) (((irq) >= 16) || ((1<<(irq)) & io_apic_irqs))
+#define IO_APIC_VECTOR(irq) (irq_vector[irq])
+
+#define LEGACY_VECTOR(irq) ((irq) + FIRST_EXTERNAL_VECTOR)
+#define LEGACY_IRQ_FROM_VECTOR(vec) ((vec) - FIRST_EXTERNAL_VECTOR)
+
+#define irq_to_vector(irq) \
+ (IO_APIC_IRQ(irq) ? IO_APIC_VECTOR(irq) : LEGACY_VECTOR(irq))
+#define vector_to_irq(vec) (vector_irq[vec])
+
extern void disable_irq_nosync(unsigned int);
extern void enable_irq(unsigned int);
extern int vector_irq[NR_VECTORS];
extern u8 irq_vector[NR_IRQ_VECTORS];
-#define IO_APIC_VECTOR(irq) irq_vector[irq]
#define AUTO_ASSIGN -1
-extern void (*interrupt[NR_IRQS])(void);
-
#define platform_legacy_irq(irq) ((irq) < 16)
void disable_8259A_irq(unsigned int irq);
@@ -26,13 +32,10 @@ void enable_8259A_irq(unsigned int irq);
int i8259A_irq_pending(unsigned int irq);
void make_8259A_irq(unsigned int irq);
void init_8259A(int aeoi);
-void send_IPI_self(int vector);
-void init_VISWS_APIC_irqs(void);
+
void setup_IO_APIC(void);
void disable_IO_APIC(void);
void print_IO_APIC(void);
-int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
-void send_IPI(int dest, int vector);
void setup_ioapic_dest(void);
extern unsigned long io_apic_irqs;
@@ -40,12 +43,4 @@ extern unsigned long io_apic_irqs;
extern atomic_t irq_err_count;
extern atomic_t irq_mis_count;
-#define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
-
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
-{
- if (IO_APIC_IRQ(i))
- send_IPI_self(IO_APIC_VECTOR(i));
-}
-
#endif /* _ASM_HW_IRQ_H */
diff --git a/xen/include/asm-x86/multicall.h b/xen/include/asm-x86/multicall.h
index f4bac0a150..23d7c8e5ba 100644
--- a/xen/include/asm-x86/multicall.h
+++ b/xen/include/asm-x86/multicall.h
@@ -24,7 +24,9 @@
"callq *(%%rax); " \
"movq %%rax,"STR(MULTICALL_result)"(%0); " \
: : "b" (_call) \
- : "rax", "rdi", "rsi", "rdx", "rcx", "r8" ); \
+ /* all the caller-saves registers */ \
+ : "rax", "rcx", "rdx", "rsi", "rdi", \
+ "r8", "r9", "r10", "r11" ); \
} while ( 0 )
#else
@@ -42,7 +44,9 @@
"call *hypercall_table(,%%eax,4); " \
"movl %%eax,"STR(MULTICALL_result)"(%0); "\
"addl $20,%%esp; " \
- : : "b" (_call) : "eax", "ecx", "edx" ); \
+ : : "b" (_call) \
+ /* all the caller-saves registers */ \
+ : "eax", "ecx", "edx" ); \
} while ( 0 )
#endif
diff --git a/xen/include/asm-x86/page.h b/xen/include/asm-x86/page.h
index 536cb63275..883acd13dd 100644
--- a/xen/include/asm-x86/page.h
+++ b/xen/include/asm-x86/page.h
@@ -185,22 +185,26 @@ typedef struct { u64 pfn; } pagetable_t;
#define pfn_valid(_pfn) ((_pfn) < max_page)
/* High table entries are reserved by the hypervisor. */
-/* FIXME: this breaks with PAE -- kraxel */
+#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_PAE)
#define DOMAIN_ENTRIES_PER_L2_PAGETABLE \
(HYPERVISOR_VIRT_START >> L2_PAGETABLE_SHIFT)
#define HYPERVISOR_ENTRIES_PER_L2_PAGETABLE \
(L2_PAGETABLE_ENTRIES - DOMAIN_ENTRIES_PER_L2_PAGETABLE)
+#else
+#define DOMAIN_ENTRIES_PER_L2_PAGETABLE 0
+#define HYPERVISOR_ENTRIES_PER_L2_PAGETABLE 0
+#endif
#define linear_l1_table \
((l1_pgentry_t *)(LINEAR_PT_VIRT_START))
-#define __linear_l2_table \
+#define __linear_l2_table \
((l2_pgentry_t *)(LINEAR_PT_VIRT_START + \
(LINEAR_PT_VIRT_START >> (PAGETABLE_ORDER<<0))))
-#define __linear_l3_table \
+#define __linear_l3_table \
((l3_pgentry_t *)(LINEAR_PT_VIRT_START + \
(LINEAR_PT_VIRT_START >> (PAGETABLE_ORDER<<0)) + \
(LINEAR_PT_VIRT_START >> (PAGETABLE_ORDER<<1))))
-#define __linear_l4_table \
+#define __linear_l4_table \
((l4_pgentry_t *)(LINEAR_PT_VIRT_START + \
(LINEAR_PT_VIRT_START >> (PAGETABLE_ORDER<<0)) + \
(LINEAR_PT_VIRT_START >> (PAGETABLE_ORDER<<1)) + \
diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h
index 6099a6e8a3..e4788054e0 100644
--- a/xen/include/asm-x86/shadow.h
+++ b/xen/include/asm-x86/shadow.h
@@ -27,14 +27,12 @@
#include <xen/perfc.h>
#include <xen/sched.h>
#include <xen/mm.h>
+#include <xen/domain_page.h>
#include <asm/current.h>
#include <asm/flushtlb.h>
#include <asm/processor.h>
-#include <asm/domain_page.h>
-#include <public/dom0_ops.h>
-#ifdef CONFIG_VMX
#include <asm/vmx.h>
-#endif
+#include <public/dom0_ops.h>
/* Shadow PT operation mode : shadow-mode variable in arch_domain. */
@@ -121,25 +119,25 @@ extern void __shadow_sync_all(struct domain *d);
extern int __shadow_out_of_sync(struct vcpu *v, unsigned long va);
extern int set_p2m_entry(
struct domain *d, unsigned long pfn, unsigned long mfn,
- struct map_dom_mem_cache *l2cache,
- struct map_dom_mem_cache *l1cache);
+ struct domain_mmap_cache *l2cache,
+ struct domain_mmap_cache *l1cache);
extern void remove_shadow(struct domain *d, unsigned long gpfn, u32 stype);
extern void shadow_l1_normal_pt_update(struct domain *d,
unsigned long pa, l1_pgentry_t l1e,
- struct map_dom_mem_cache *cache);
+ struct domain_mmap_cache *cache);
extern void shadow_l2_normal_pt_update(struct domain *d,
unsigned long pa, l2_pgentry_t l2e,
- struct map_dom_mem_cache *cache);
+ struct domain_mmap_cache *cache);
#if CONFIG_PAGING_LEVELS >= 3
extern void shadow_l3_normal_pt_update(struct domain *d,
unsigned long pa, l3_pgentry_t l3e,
- struct map_dom_mem_cache *cache);
+ struct domain_mmap_cache *cache);
#endif
#if CONFIG_PAGING_LEVELS >= 4
extern void shadow_l4_normal_pt_update(struct domain *d,
unsigned long pa, l4_pgentry_t l4e,
- struct map_dom_mem_cache *cache);
+ struct domain_mmap_cache *cache);
#endif
extern int shadow_do_update_va_mapping(unsigned long va,
l1_pgentry_t val,
diff --git a/xen/include/asm-x86/string.h b/xen/include/asm-x86/string.h
index fd7ae02a85..6dee130fa7 100644
--- a/xen/include/asm-x86/string.h
+++ b/xen/include/asm-x86/string.h
@@ -1,5 +1,397 @@
-#ifdef __x86_64__
-#include <asm/x86_64/string.h>
+#ifndef __X86_STRING_H__
+#define __X86_STRING_H__
+
+#include <xen/config.h>
+
+#define __HAVE_ARCH_STRCPY
+static inline char *strcpy(char *dest, const char *src)
+{
+ long d0, d1, d2;
+ __asm__ __volatile__ (
+ "1: lodsb \n"
+ " stosb \n"
+ " test %%al,%%al \n"
+ " jne 1b \n"
+ : "=&S" (d0), "=&D" (d1), "=&a" (d2)
+ : "0" (src), "1" (dest) : "memory" );
+ return dest;
+}
+
+#define __HAVE_ARCH_STRNCPY
+static inline char *strncpy(char *dest, const char *src, size_t count)
+{
+ long d0, d1, d2, d3;
+ __asm__ __volatile__ (
+ "1: dec %2 \n"
+ " js 2f \n"
+ " lodsb \n"
+ " stosb \n"
+ " test %%al,%%al \n"
+ " jne 1b \n"
+ " rep ; stosb \n"
+ "2: \n"
+ : "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
+ : "0" (src), "1" (dest), "2" (count) : "memory" );
+ return dest;
+}
+
+#define __HAVE_ARCH_STRCAT
+static inline char *strcat(char *dest, const char *src)
+{
+ long d0, d1, d2, d3;
+ __asm__ __volatile__ (
+ " repne ; scasb \n"
+ " dec %1 \n"
+ "1: lodsb \n"
+ " stosb \n"
+ " test %%al,%%al \n"
+ " jne 1b \n"
+ : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
+ : "0" (src), "1" (dest), "2" (0UL), "3" (0xffffffffUL) : "memory" );
+ return dest;
+}
+
+#define __HAVE_ARCH_STRNCAT
+static inline char *strncat(char *dest, const char *src, size_t count)
+{
+ long d0, d1, d2, d3;
+ __asm__ __volatile__ (
+ " repne ; scasb \n"
+ " dec %1 \n"
+ " mov %8,%3 \n"
+ "1: dec %3 \n"
+ " js 2f \n"
+ " lodsb \n"
+ " stosb \n"
+ " test %%al,%%al \n"
+ " jne 1b \n"
+ "2: xor %%eax,%%eax\n"
+ " stosb"
+ : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
+ : "0" (src), "1" (dest), "2" (0UL), "3" (0xffffffffUL), "g" (count)
+ : "memory" );
+ return dest;
+}
+
+#define __HAVE_ARCH_STRCMP
+static inline int strcmp(const char *cs, const char *ct)
+{
+ long d0, d1;
+ register int __res;
+ __asm__ __volatile__ (
+ "1: lodsb \n"
+ " scasb \n"
+ " jne 2f \n"
+ " test %%al,%%al \n"
+ " jne 1b \n"
+ " xor %%eax,%%eax\n"
+ " jmp 3f \n"
+ "2: sbb %%eax,%%eax\n"
+ " or $1,%%al \n"
+ "3: \n"
+ : "=a" (__res), "=&S" (d0), "=&D" (d1)
+ : "1" (cs), "2" (ct) );
+ return __res;
+}
+
+#define __HAVE_ARCH_STRNCMP
+static inline int strncmp(const char *cs, const char *ct, size_t count)
+{
+ long d0, d1, d2;
+ register int __res;
+ __asm__ __volatile__ (
+ "1: dec %3 \n"
+ " js 2f \n"
+ " lodsb \n"
+ " scasb \n"
+ " jne 3f \n"
+ " test %%al,%%al \n"
+ " jne 1b \n"
+ "2: xor %%eax,%%eax\n"
+ " jmp 4f \n"
+ "3: sbb %%eax,%%eax\n"
+ " or $1,%%al \n"
+ "4: \n"
+ : "=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
+ : "1" (cs), "2" (ct), "3" (count) );
+ return __res;
+}
+
+#define __HAVE_ARCH_STRCHR
+static inline char *strchr(const char *s, int c)
+{
+ long d0;
+ register char *__res;
+ __asm__ __volatile__ (
+ " mov %%al,%%ah \n"
+ "1: lodsb \n"
+ " cmp %%ah,%%al \n"
+ " je 2f \n"
+ " test %%al,%%al \n"
+ " jne 1b \n"
+ " mov $1,%1 \n"
+ "2: mov %1,%0 \n"
+ " dec %0 \n"
+ : "=a" (__res), "=&S" (d0) : "1" (s), "0" (c) );
+ return __res;
+}
+
+#define __HAVE_ARCH_STRLEN
+static inline size_t strlen(const char *s)
+{
+ long d0;
+ register int __res;
+ __asm__ __volatile__ (
+ " repne ; scasb \n"
+ " notl %0 \n"
+ " decl %0 \n"
+ : "=c" (__res), "=&D" (d0) : "1" (s), "a" (0), "0" (0xffffffffUL) );
+ return __res;
+}
+
+static inline void *__variable_memcpy(void *to, const void *from, size_t n)
+{
+ long d0, d1, d2;
+ __asm__ __volatile__ (
+ " rep ; movs"__OS"\n"
+ " mov %4,%3 \n"
+ " rep ; movsb \n"
+ : "=&c" (d0), "=&D" (d1), "=&S" (d2)
+ : "0" (n/BYTES_PER_LONG), "r" (n%BYTES_PER_LONG), "1" (to), "2" (from)
+ : "memory" );
+ return to;
+}
+
+/*
+ * This looks horribly ugly, but the compiler can optimize it totally,
+ * as the count is constant.
+ */
+static always_inline void * __constant_memcpy(
+ void * to, const void * from, size_t n)
+{
+ switch ( n )
+ {
+ case 0:
+ return to;
+ case 1:
+ *(u8 *)to = *(const u8 *)from;
+ return to;
+ case 2:
+ *(u16 *)to = *(const u16 *)from;
+ return to;
+ case 3:
+ *(u16 *)to = *(const u16 *)from;
+ *(2+(u8 *)to) = *(2+(const u8 *)from);
+ return to;
+ case 4:
+ *(u32 *)to = *(const u32 *)from;
+ return to;
+ case 5:
+ *(u32 *)to = *(const u32 *)from;
+ *(4+(u8 *)to) = *(4+(const u8 *)from);
+ return to;
+ case 6:
+ *(u32 *)to = *(const u32 *)from;
+ *(2+(u16 *)to) = *(2+(const u16 *)from);
+ return to;
+ case 7:
+ *(u32 *)to = *(const u32 *)from;
+ *(2+(u16 *)to) = *(2+(const u16 *)from);
+ *(6+(u8 *)to) = *(6+(const u8 *)from);
+ return to;
+ case 8:
+ *(u64 *)to = *(const u64 *)from;
+ return to;
+ case 12:
+ *(u64 *)to = *(const u64 *)from;
+ *(2+(u32 *)to) = *(2+(const u32 *)from);
+ return to;
+ case 16:
+ *(u64 *)to = *(const u64 *)from;
+ *(1+(u64 *)to) = *(1+(const u64 *)from);
+ return to;
+ case 20:
+ *(u64 *)to = *(const u64 *)from;
+ *(1+(u64 *)to) = *(1+(const u64 *)from);
+ *(4+(u32 *)to) = *(4+(const u32 *)from);
+ return to;
+ }
+#define COMMON(x) \
+ __asm__ __volatile__ ( \
+ "rep ; movs"__OS \
+ x \
+ : "=&c" (d0), "=&D" (d1), "=&S" (d2) \
+ : "0" (n/BYTES_PER_LONG), "1" (to), "2" (from) \
+ : "memory" );
+ {
+ long d0, d1, d2;
+ switch ( n % BYTES_PER_LONG )
+ {
+ case 0: COMMON(""); return to;
+ case 1: COMMON("\n\tmovsb"); return to;
+ case 2: COMMON("\n\tmovsw"); return to;
+ case 3: COMMON("\n\tmovsw\n\tmovsb"); return to;
+ case 4: COMMON("\n\tmovsl"); return to;
+ case 5: COMMON("\n\tmovsl\n\tmovsb"); return to;
+ case 6: COMMON("\n\tmovsl\n\tmovsw"); return to;
+ case 7: COMMON("\n\tmovsl\n\tmovsw\n\tmovsb"); return to;
+ }
+ }
+#undef COMMON
+ return to;
+}
+
+#define __HAVE_ARCH_MEMCPY
+#define memcpy(t,f,n) (__memcpy((t),(f),(n)))
+static always_inline
+void *__memcpy(void *t, const void *f, size_t n)
+{
+ return (__builtin_constant_p(n) ?
+ __constant_memcpy((t),(f),(n)) :
+ __variable_memcpy((t),(f),(n)));
+}
+
+/* Some version of gcc don't have this builtin. It's non-critical anyway. */
+#define __HAVE_ARCH_MEMMOVE
+extern void *memmove(void *dest, const void *src, size_t n);
+
+#define __HAVE_ARCH_MEMCMP
+#define memcmp __builtin_memcmp
+
+#define __HAVE_ARCH_MEMCHR
+static inline void *memchr(const void *cs, int c, size_t count)
+{
+ long d0;
+ register void *__res;
+ if ( count == 0 )
+ return NULL;
+ __asm__ __volatile__ (
+ " repne ; scasb\n"
+ " je 1f \n"
+ " mov $1,%0 \n"
+ "1: dec %0 \n"
+ : "=D" (__res), "=&c" (d0) : "a" (c), "0" (cs), "1" (count) );
+ return __res;
+}
+
+static inline void *__memset_generic(void *s, char c, size_t count)
+{
+ long d0, d1;
+ __asm__ __volatile__ (
+ "rep ; stosb"
+ : "=&c" (d0), "=&D" (d1) : "a" (c), "1" (s), "0" (count) : "memory" );
+ return s;
+}
+
+/* we might want to write optimized versions of these later */
+#define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count))
+
+/*
+ * memset(x,0,y) is a reasonably common thing to do, so we want to fill
+ * things 32 bits at a time even when we don't know the size of the
+ * area at compile-time..
+ */
+static inline void *__constant_c_memset(void *s, unsigned long c, size_t count)
+{
+ long d0, d1;
+ __asm__ __volatile__(
+ " rep ; stos"__OS"\n"
+ " mov %3,%4 \n"
+ " rep ; stosb \n"
+ : "=&c" (d0), "=&D" (d1)
+ : "a" (c), "r" (count%BYTES_PER_LONG),
+ "0" (count/BYTES_PER_LONG), "1" (s)
+ : "memory" );
+ return s;
+}
+
+/*
+ * This looks horribly ugly, but the compiler can optimize it totally,
+ * as we by now know that both pattern and count is constant..
+ */
+static always_inline void *__constant_c_and_count_memset(
+ void *s, unsigned long pattern, size_t count)
+{
+ switch ( count )
+ {
+ case 0:
+ return s;
+ case 1:
+ *(u8 *)s = pattern;
+ return s;
+ case 2:
+ *(u16 *)s = pattern;
+ return s;
+ case 3:
+ *(u16 *)s = pattern;
+ *(2+(u8 *)s) = pattern;
+ return s;
+ case 4:
+ *(u32 *)s = pattern;
+ return s;
+ case 5:
+ *(u32 *)s = pattern;
+ *(4+(u8 *)s) = pattern;
+ return s;
+ case 6:
+ *(u32 *)s = pattern;
+ *(2+(u16 *)s) = pattern;
+ return s;
+ case 7:
+ *(u32 *)s = pattern;
+ *(2+(u16 *)s) = pattern;
+ *(6+(u8 *)s) = pattern;
+ return s;
+ case 8:
+ *(u64 *)s = pattern;
+ return s;
+ }
+#define COMMON(x) \
+ __asm__ __volatile__ ( \
+ "rep ; stos"__OS \
+ x \
+ : "=&c" (d0), "=&D" (d1) \
+ : "a" (pattern), "0" (count/BYTES_PER_LONG), "1" (s) \
+ : "memory" )
+ {
+ long d0, d1;
+ switch ( count % BYTES_PER_LONG )
+ {
+ case 0: COMMON(""); return s;
+ case 1: COMMON("\n\tstosb"); return s;
+ case 2: COMMON("\n\tstosw"); return s;
+ case 3: COMMON("\n\tstosw\n\tstosb"); return s;
+ case 4: COMMON("\n\tstosl"); return s;
+ case 5: COMMON("\n\tstosl\n\tstosb"); return s;
+ case 6: COMMON("\n\tstosl\n\tstosw"); return s;
+ case 7: COMMON("\n\tstosl\n\tstosw\n\tstosb"); return s;
+ }
+ }
+#undef COMMON
+ return s;
+}
+
+#define __constant_c_x_memset(s, c, count) \
+(__builtin_constant_p(count) ? \
+ __constant_c_and_count_memset((s),(c),(count)) : \
+ __constant_c_memset((s),(c),(count)))
+
+#define __var_x_memset(s, c, count) \
+(__builtin_constant_p(count) ? \
+ __constant_count_memset((s),(c),(count)) : \
+ __memset_generic((s),(c),(count)))
+
+#ifdef CONFIG_X86_64
+#define MEMSET_PATTERN_MUL 0x0101010101010101UL
#else
-#include <asm/x86_32/string.h>
+#define MEMSET_PATTERN_MUL 0x01010101UL
#endif
+
+#define __HAVE_ARCH_MEMSET
+#define memset(s, c, count) (__memset((s),(c),(count)))
+#define __memset(s, c, count) \
+(__builtin_constant_p(c) ? \
+ __constant_c_x_memset((s),(MEMSET_PATTERN_MUL*(unsigned char)(c)),(count)) : \
+ __var_x_memset((s),(c),(count)))
+
+#endif /* __X86_STRING_H__ */
diff --git a/xen/include/asm-x86/types.h b/xen/include/asm-x86/types.h
index 5dd6c6c1af..9cec42e7a7 100644
--- a/xen/include/asm-x86/types.h
+++ b/xen/include/asm-x86/types.h
@@ -1,8 +1,5 @@
-#ifndef _X86_TYPES_H
-#define _X86_TYPES_H
-
-typedef unsigned short umode_t;
-
+#ifndef __X86_TYPES_H__
+#define __X86_TYPES_H__
/*
* __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
@@ -43,7 +40,8 @@ typedef unsigned int u32;
typedef signed long long s64;
typedef unsigned long long u64;
#define BITS_PER_LONG 32
-typedef unsigned int size_t;
+#define BYTES_PER_LONG 4
+#define LONG_BYTEORDER 2
#if defined(CONFIG_X86_PAE)
typedef u64 physaddr_t;
#else
@@ -53,15 +51,11 @@ typedef u32 physaddr_t;
typedef signed long s64;
typedef unsigned long u64;
#define BITS_PER_LONG 64
-typedef unsigned long size_t;
+#define BYTES_PER_LONG 8
+#define LONG_BYTEORDER 3
typedef u64 physaddr_t;
#endif
-/* DMA addresses come in generic and 64-bit flavours. */
-
-typedef unsigned long dma_addr_t;
-typedef u64 dma64_addr_t;
-
-typedef unsigned short xmem_bufctl_t;
+typedef unsigned long size_t;
-#endif
+#endif /* __X86_TYPES_H__ */
diff --git a/xen/include/asm-x86/uaccess.h b/xen/include/asm-x86/uaccess.h
index 46c02ecef4..e5e32d0938 100644
--- a/xen/include/asm-x86/uaccess.h
+++ b/xen/include/asm-x86/uaccess.h
@@ -2,12 +2,265 @@
#ifndef __X86_UACCESS_H__
#define __X86_UACCESS_H__
+#include <xen/config.h>
+#include <xen/compiler.h>
+#include <xen/errno.h>
+#include <xen/prefetch.h>
+#include <asm/page.h>
+
+#define __user
+
#ifdef __x86_64__
#include <asm/x86_64/uaccess.h>
#else
#include <asm/x86_32/uaccess.h>
#endif
+unsigned long copy_to_user(void *to, const void *from, unsigned len);
+unsigned long copy_from_user(void *to, const void *from, unsigned len);
+/* Handles exceptions in both to and from, but doesn't do access_ok */
+unsigned long __copy_to_user_ll(void *to, const void *from, unsigned n);
+unsigned long __copy_from_user_ll(void *to, const void *from, unsigned n);
+
+extern long __get_user_bad(void);
+extern void __put_user_bad(void);
+
+/**
+ * get_user: - Get a simple variable from user space.
+ * @x: Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space. It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
+#define get_user(x,ptr) \
+ __get_user_check((x),(ptr),sizeof(*(ptr)))
+
+/**
+ * put_user: - Write a simple value into user space.
+ * @x: Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space. It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
+#define put_user(x,ptr) \
+ __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+/**
+ * __get_user: - Get a simple variable from user space, with less checking.
+ * @x: Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space. It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
+#define __get_user(x,ptr) \
+ __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+
+/**
+ * __put_user: - Write a simple value into user space, with less checking.
+ * @x: Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space. It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
+#define __put_user(x,ptr) \
+ __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+#define __put_user_nocheck(x,ptr,size) \
+({ \
+ long __pu_err; \
+ __put_user_size((x),(ptr),(size),__pu_err,-EFAULT); \
+ __pu_err; \
+})
+
+#define __put_user_check(x,ptr,size) \
+({ \
+ long __pu_err = -EFAULT; \
+ __typeof__(*(ptr)) __user *__pu_addr = (ptr); \
+ if (__addr_ok(__pu_addr)) \
+ __put_user_size((x),__pu_addr,(size),__pu_err,-EFAULT); \
+ __pu_err; \
+})
+
+#define __get_user_nocheck(x,ptr,size) \
+({ \
+ long __gu_err, __gu_val; \
+ __get_user_size(__gu_val,(ptr),(size),__gu_err,-EFAULT);\
+ (x) = (__typeof__(*(ptr)))__gu_val; \
+ __gu_err; \
+})
+
+#define __get_user_check(x,ptr,size) \
+({ \
+ long __gu_err, __gu_val; \
+ __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
+ __get_user_size(__gu_val,__gu_addr,(size),__gu_err,-EFAULT); \
+ (x) = (__typeof__(*(ptr)))__gu_val; \
+ if (!__addr_ok(__gu_addr)) __gu_err = -EFAULT; \
+ __gu_err; \
+})
+
+struct __large_struct { unsigned long buf[100]; };
+#define __m(x) (*(struct __large_struct *)(x))
+
+/*
+ * Tell gcc we read from memory instead of writing: this is because
+ * we do not write to any memory gcc knows about, so there are no
+ * aliasing issues.
+ */
+#define __put_user_asm(x, addr, err, itype, rtype, ltype, errret) \
+ __asm__ __volatile__( \
+ "1: mov"itype" %"rtype"1,%2\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: mov %3,%0\n" \
+ " jmp 2b\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " "__FIXUP_ALIGN"\n" \
+ " "__FIXUP_WORD" 1b,3b\n" \
+ ".previous" \
+ : "=r"(err) \
+ : ltype (x), "m"(__m(addr)), "i"(errret), "0"(err))
+
+#define __get_user_asm(x, addr, err, itype, rtype, ltype, errret) \
+ __asm__ __volatile__( \
+ "1: mov"itype" %2,%"rtype"1\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: mov %3,%0\n" \
+ " xor"itype" %"rtype"1,%"rtype"1\n" \
+ " jmp 2b\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " "__FIXUP_ALIGN"\n" \
+ " "__FIXUP_WORD" 1b,3b\n" \
+ ".previous" \
+ : "=r"(err), ltype (x) \
+ : "m"(__m(addr)), "i"(errret), "0"(err))
+
+/**
+ * __copy_to_user: - Copy a block of data into user space, with less checking
+ * @to: Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n: Number of bytes to copy.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Copy data from kernel space to user space. Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+static always_inline unsigned long
+__copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+ if (__builtin_constant_p(n)) {
+ unsigned long ret;
+
+ switch (n) {
+ case 1:
+ __put_user_size(*(u8 *)from, (u8 __user *)to, 1, ret, 1);
+ return ret;
+ case 2:
+ __put_user_size(*(u16 *)from, (u16 __user *)to, 2, ret, 2);
+ return ret;
+ case 4:
+ __put_user_size(*(u32 *)from, (u32 __user *)to, 4, ret, 4);
+ return ret;
+ case 8:
+ __put_user_size(*(u64 *)from, (u64 __user *)to, 8, ret, 8);
+ return ret;
+ }
+ }
+ return __copy_to_user_ll(to, from, n);
+}
+
+/**
+ * __copy_from_user: - Copy a block of data from user space, with less checking
+ * @to: Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n: Number of bytes to copy.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Copy data from user space to kernel space. Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
+ */
+static always_inline unsigned long
+__copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+ if (__builtin_constant_p(n)) {
+ unsigned long ret;
+
+ switch (n) {
+ case 1:
+ __get_user_size(*(u8 *)to, from, 1, ret, 1);
+ return ret;
+ case 2:
+ __get_user_size(*(u16 *)to, from, 2, ret, 2);
+ return ret;
+ case 4:
+ __get_user_size(*(u32 *)to, from, 4, ret, 4);
+ return ret;
+ case 8:
+ __get_user_size(*(u64*)to, from, 8, ret, 8);
+ return ret;
+ }
+ }
+ return __copy_from_user_ll(to, from, n);
+}
+
/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
diff --git a/xen/include/asm-x86/x86_32/domain_page.h b/xen/include/asm-x86/x86_32/domain_page.h
deleted file mode 100644
index d46f21b67a..0000000000
--- a/xen/include/asm-x86/x86_32/domain_page.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/******************************************************************************
- * domain_page.h
- *
- * Allow temporary mapping of domain page frames into Xen space.
- */
-
-#ifndef __ASM_DOMAIN_PAGE_H__
-#define __ASM_DOMAIN_PAGE_H__
-
-#include <xen/config.h>
-#include <xen/sched.h>
-
-extern l1_pgentry_t *mapcache;
-#define MAPCACHE_ORDER 10
-#define MAPCACHE_ENTRIES (1 << MAPCACHE_ORDER)
-
-/*
- * Maps a given physical address, returning corresponding virtual address.
- * The entire page containing that VA is now accessible until a
- * corresponding call to unmap_domain_mem().
- */
-extern void *map_domain_mem(unsigned long pa);
-
-/*
- * Pass a VA within a page previously mapped with map_domain_mem().
- * That page will then be removed from the mapping lists.
- */
-extern void unmap_domain_mem(void *va);
-
-struct map_dom_mem_cache {
- unsigned long pa;
- void *va;
-};
-
-static inline void
-init_map_domain_mem_cache(struct map_dom_mem_cache *cache)
-{
- ASSERT(cache != NULL);
- cache->pa = 0;
-}
-
-static inline void *
-map_domain_mem_with_cache(unsigned long pa, struct map_dom_mem_cache *cache)
-{
- ASSERT(cache != NULL);
-
- if ( likely(cache->pa) )
- {
- if ( likely((pa & PAGE_MASK) == (cache->pa & PAGE_MASK)) )
- goto done;
- unmap_domain_mem(cache->va);
- }
-
- cache->pa = (pa & PAGE_MASK) | 1;
- cache->va = map_domain_mem(cache->pa);
-
- done:
- return (void *)(((unsigned long)cache->va & PAGE_MASK) |
- (pa & ~PAGE_MASK));
-}
-
-static inline void
-unmap_domain_mem_with_cache(void *va, struct map_dom_mem_cache *cache)
-{
- ASSERT(cache != NULL);
- unmap_domain_mem(va);
-}
-
-static inline void
-destroy_map_domain_mem_cache(struct map_dom_mem_cache *cache)
-{
- ASSERT(cache != NULL);
- if ( likely(cache->pa) )
- {
- unmap_domain_mem(cache->va);
- cache->pa = 0;
- }
-}
-
-#endif /* __ASM_DOMAIN_PAGE_H__ */
diff --git a/xen/include/asm-x86/x86_32/page-3level.h b/xen/include/asm-x86/x86_32/page-3level.h
index 0033759b99..1fc423c073 100644
--- a/xen/include/asm-x86/x86_32/page-3level.h
+++ b/xen/include/asm-x86/x86_32/page-3level.h
@@ -47,11 +47,11 @@ typedef l3_pgentry_t root_pgentry_t;
#define PGT_root_page_table PGT_l3_page_table
/* misc */
-#define is_guest_l1_slot(_s) (1)
-#define is_guest_l2_slot(_t,_s) \
- ((3 != (((_t) & PGT_va_mask) >> PGT_va_shift)) || \
- ((_s) < (L2_PAGETABLE_FIRST_XEN_SLOT & (L2_PAGETABLE_ENTRIES-1))))
-#define is_guest_l3_slot(_s) (1)
+#define is_guest_l1_slot(s) (1)
+#define is_guest_l2_slot(t,s) \
+ ( ((((t) & PGT_va_mask) >> PGT_va_shift) != 3) || \
+ ((s) < (L2_PAGETABLE_FIRST_XEN_SLOT & (L2_PAGETABLE_ENTRIES - 1))) )
+#define is_guest_l3_slot(s) (1)
/*
* PTE pfn and flags:
diff --git a/xen/include/asm-x86/x86_32/string.h b/xen/include/asm-x86/x86_32/string.h
deleted file mode 100644
index b25ec8df61..0000000000
--- a/xen/include/asm-x86/x86_32/string.h
+++ /dev/null
@@ -1,489 +0,0 @@
-#ifndef _I386_STRING_H_
-#define _I386_STRING_H_
-
-#include <xen/config.h>
-
-/*
- * This string-include defines all string functions as inline
- * functions. Use gcc. It also assumes ds=es=data space, this should be
- * normal. Most of the string-functions are rather heavily hand-optimized,
- * see especially strtok,strstr,str[c]spn. They should work, but are not
- * very easy to understand. Everything is done entirely within the register
- * set, making the functions fast and clean. String instructions have been
- * used through-out, making for "slightly" unclear code :-)
- *
- * NO Copyright (C) 1991, 1992 Linus Torvalds,
- * consider these trivial functions to be PD.
- */
-
-
-#define __HAVE_ARCH_STRCPY
-static inline char * strcpy(char * dest,const char *src)
-{
-int d0, d1, d2;
-__asm__ __volatile__(
- "1:\tlodsb\n\t"
- "stosb\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b"
- : "=&S" (d0), "=&D" (d1), "=&a" (d2)
- :"0" (src),"1" (dest) : "memory");
-return dest;
-}
-
-#define __HAVE_ARCH_STRNCPY
-static inline char * strncpy(char * dest,const char *src,size_t count)
-{
-int d0, d1, d2, d3;
-__asm__ __volatile__(
- "1:\tdecl %2\n\t"
- "js 2f\n\t"
- "lodsb\n\t"
- "stosb\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n\t"
- "rep\n\t"
- "stosb\n"
- "2:"
- : "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
- :"0" (src),"1" (dest),"2" (count) : "memory");
-return dest;
-}
-
-#define __HAVE_ARCH_STRCAT
-static inline char * strcat(char * dest,const char * src)
-{
-int d0, d1, d2, d3;
-__asm__ __volatile__(
- "repne\n\t"
- "scasb\n\t"
- "decl %1\n"
- "1:\tlodsb\n\t"
- "stosb\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b"
- : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
- : "0" (src), "1" (dest), "2" (0), "3" (0xffffffff):"memory");
-return dest;
-}
-
-#define __HAVE_ARCH_STRNCAT
-static inline char * strncat(char * dest,const char * src,size_t count)
-{
-int d0, d1, d2, d3;
-__asm__ __volatile__(
- "repne\n\t"
- "scasb\n\t"
- "decl %1\n\t"
- "movl %8,%3\n"
- "1:\tdecl %3\n\t"
- "js 2f\n\t"
- "lodsb\n\t"
- "stosb\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n"
- "2:\txorl %2,%2\n\t"
- "stosb"
- : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
- : "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count)
- : "memory");
-return dest;
-}
-
-#define __HAVE_ARCH_STRCMP
-static inline int strcmp(const char * cs,const char * ct)
-{
-int d0, d1;
-register int __res;
-__asm__ __volatile__(
- "1:\tlodsb\n\t"
- "scasb\n\t"
- "jne 2f\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n\t"
- "xorl %%eax,%%eax\n\t"
- "jmp 3f\n"
- "2:\tsbbl %%eax,%%eax\n\t"
- "orb $1,%%al\n"
- "3:"
- :"=a" (__res), "=&S" (d0), "=&D" (d1)
- :"1" (cs),"2" (ct));
-return __res;
-}
-
-#define __HAVE_ARCH_STRNCMP
-static inline int strncmp(const char * cs,const char * ct,size_t count)
-{
-register int __res;
-int d0, d1, d2;
-__asm__ __volatile__(
- "1:\tdecl %3\n\t"
- "js 2f\n\t"
- "lodsb\n\t"
- "scasb\n\t"
- "jne 3f\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n"
- "2:\txorl %%eax,%%eax\n\t"
- "jmp 4f\n"
- "3:\tsbbl %%eax,%%eax\n\t"
- "orb $1,%%al\n"
- "4:"
- :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
- :"1" (cs),"2" (ct),"3" (count));
-return __res;
-}
-
-#define __HAVE_ARCH_STRCHR
-static inline char * strchr(const char * s, int c)
-{
-int d0;
-register char * __res;
-__asm__ __volatile__(
- "movb %%al,%%ah\n"
- "1:\tlodsb\n\t"
- "cmpb %%ah,%%al\n\t"
- "je 2f\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n\t"
- "movl $1,%1\n"
- "2:\tmovl %1,%0\n\t"
- "decl %0"
- :"=a" (__res), "=&S" (d0) : "1" (s),"0" (c));
-return __res;
-}
-
-#define __HAVE_ARCH_STRRCHR
-static inline char * strrchr(const char * s, int c)
-{
-int d0, d1;
-register char * __res;
-__asm__ __volatile__(
- "movb %%al,%%ah\n"
- "1:\tlodsb\n\t"
- "cmpb %%ah,%%al\n\t"
- "jne 2f\n\t"
- "leal -1(%%esi),%0\n"
- "2:\ttestb %%al,%%al\n\t"
- "jne 1b"
- :"=g" (__res), "=&S" (d0), "=&a" (d1) :"0" (0),"1" (s),"2" (c));
-return __res;
-}
-
-#define __HAVE_ARCH_STRLEN
-static inline size_t strlen(const char * s)
-{
-int d0;
-register int __res;
-__asm__ __volatile__(
- "repne\n\t"
- "scasb\n\t"
- "notl %0\n\t"
- "decl %0"
- :"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffff));
-return __res;
-}
-
-static inline void * __variable_memcpy(void * to, const void * from, size_t n)
-{
-int d0, d1, d2;
-__asm__ __volatile__(
- "rep ; movsl\n\t"
- "testb $2,%b4\n\t"
- "je 1f\n\t"
- "movsw\n"
- "1:\ttestb $1,%b4\n\t"
- "je 2f\n\t"
- "movsb\n"
- "2:"
- : "=&c" (d0), "=&D" (d1), "=&S" (d2)
- :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
- : "memory");
-return (to);
-}
-
-/*
- * This looks horribly ugly, but the compiler can optimize it totally,
- * as the count is constant.
- */
-static always_inline void * __constant_memcpy(void * to, const void * from, size_t n)
-{
- switch (n) {
- case 0:
- return to;
- case 1:
- *(unsigned char *)to = *(const unsigned char *)from;
- return to;
- case 2:
- *(unsigned short *)to = *(const unsigned short *)from;
- return to;
- case 3:
- *(unsigned short *)to = *(const unsigned short *)from;
- *(2+(unsigned char *)to) = *(2+(const unsigned char *)from);
- return to;
- case 4:
- *(unsigned long *)to = *(const unsigned long *)from;
- return to;
- case 6: /* for Ethernet addresses */
- *(unsigned long *)to = *(const unsigned long *)from;
- *(2+(unsigned short *)to) = *(2+(const unsigned short *)from);
- return to;
- case 8:
- *(unsigned long *)to = *(const unsigned long *)from;
- *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
- return to;
- case 12:
- *(unsigned long *)to = *(const unsigned long *)from;
- *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
- *(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
- return to;
- case 16:
- *(unsigned long *)to = *(const unsigned long *)from;
- *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
- *(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
- *(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
- return to;
- case 20:
- *(unsigned long *)to = *(const unsigned long *)from;
- *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
- *(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
- *(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
- *(4+(unsigned long *)to) = *(4+(const unsigned long *)from);
- return to;
- }
-#define COMMON(x) \
-__asm__ __volatile__( \
- "rep ; movsl" \
- x \
- : "=&c" (d0), "=&D" (d1), "=&S" (d2) \
- : "0" (n/4),"1" ((long) to),"2" ((long) from) \
- : "memory");
-{
- int d0, d1, d2;
- switch (n % 4) {
- case 0: COMMON(""); return to;
- case 1: COMMON("\n\tmovsb"); return to;
- case 2: COMMON("\n\tmovsw"); return to;
- default: COMMON("\n\tmovsw\n\tmovsb"); return to;
- }
-}
-
-#undef COMMON
-}
-
-#define __HAVE_ARCH_MEMCPY
-#define memcpy(t,f,n) (__memcpy((t),(f),(n)))
-static always_inline
-void *__memcpy(void *t, const void *f, size_t n)
-{
- return (__builtin_constant_p(n) ?
- __constant_memcpy((t),(f),(n)) :
- __variable_memcpy((t),(f),(n)));
-}
-
-/*
- * struct_cpy(x,y), copy structure *x into (matching structure) *y.
- *
- * We get link-time errors if the structure sizes do not match.
- * There is no runtime overhead, it's all optimized away at
- * compile time.
- */
-//extern void __struct_cpy_bug (void);
-
-/*
-#define struct_cpy(x,y) \
-({ \
- if (sizeof(*(x)) != sizeof(*(y))) \
- __struct_cpy_bug; \
- memcpy(x, y, sizeof(*(x))); \
-})
-*/
-
-#define __HAVE_ARCH_MEMMOVE
-#define memmove(dest,src,n) (__memmove((dest),(src),(n)))
-static inline void *__memmove(void * dest,const void * src, size_t n)
-{
-int d0, d1, d2;
-if (dest<src)
-__asm__ __volatile__(
- "rep\n\t"
- "movsb"
- : "=&c" (d0), "=&S" (d1), "=&D" (d2)
- :"0" (n),"1" (src),"2" (dest)
- : "memory");
-else
-__asm__ __volatile__(
- "std\n\t"
- "rep\n\t"
- "movsb\n\t"
- "cld"
- : "=&c" (d0), "=&S" (d1), "=&D" (d2)
- :"0" (n),
- "1" (n-1+(const char *)src),
- "2" (n-1+(char *)dest)
- :"memory");
-return dest;
-}
-
-#define __HAVE_ARCH_MEMCMP
-#define memcmp __builtin_memcmp
-
-#define __HAVE_ARCH_MEMCHR
-static inline void * memchr(const void * cs,int c,size_t count)
-{
-int d0;
-register void * __res;
-if (!count)
- return NULL;
-__asm__ __volatile__(
- "repne\n\t"
- "scasb\n\t"
- "je 1f\n\t"
- "movl $1,%0\n"
- "1:\tdecl %0"
- :"=D" (__res), "=&c" (d0) : "a" (c),"0" (cs),"1" (count));
-return __res;
-}
-
-static inline void * __memset_generic(void * s, char c,size_t count)
-{
-int d0, d1;
-__asm__ __volatile__(
- "rep\n\t"
- "stosb"
- : "=&c" (d0), "=&D" (d1)
- :"a" (c),"1" (s),"0" (count)
- :"memory");
-return s;
-}
-
-/* we might want to write optimized versions of these later */
-#define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count))
-
-/*
- * memset(x,0,y) is a reasonably common thing to do, so we want to fill
- * things 32 bits at a time even when we don't know the size of the
- * area at compile-time..
- */
-static inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
-{
-int d0, d1;
-__asm__ __volatile__(
- "rep ; stosl\n\t"
- "testb $2,%b3\n\t"
- "je 1f\n\t"
- "stosw\n"
- "1:\ttestb $1,%b3\n\t"
- "je 2f\n\t"
- "stosb\n"
- "2:"
- : "=&c" (d0), "=&D" (d1)
- :"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
- :"memory");
-return (s);
-}
-
-/* Added by Gertjan van Wingerde to make minix and sysv module work */
-#define __HAVE_ARCH_STRNLEN
-static inline size_t strnlen(const char * s, size_t count)
-{
-int d0;
-register int __res;
-__asm__ __volatile__(
- "movl %2,%0\n\t"
- "jmp 2f\n"
- "1:\tcmpb $0,(%0)\n\t"
- "je 3f\n\t"
- "incl %0\n"
- "2:\tdecl %1\n\t"
- "cmpl $-1,%1\n\t"
- "jne 1b\n"
- "3:\tsubl %2,%0"
- :"=a" (__res), "=&d" (d0)
- :"c" (s),"1" (count));
-return __res;
-}
-/* end of additional stuff */
-
-//#define __HAVE_ARCH_STRSTR
-
-//extern char *strstr(const char *cs, const char *ct);
-
-/*
- * This looks horribly ugly, but the compiler can optimize it totally,
- * as we by now know that both pattern and count is constant..
- */
-static always_inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
-{
- switch (count) {
- case 0:
- return s;
- case 1:
- *(unsigned char *)s = pattern;
- return s;
- case 2:
- *(unsigned short *)s = pattern;
- return s;
- case 3:
- *(unsigned short *)s = pattern;
- *(2+(unsigned char *)s) = pattern;
- return s;
- case 4:
- *(unsigned long *)s = pattern;
- return s;
- }
-#define COMMON(x) \
-__asm__ __volatile__( \
- "rep ; stosl" \
- x \
- : "=&c" (d0), "=&D" (d1) \
- : "a" (pattern),"0" (count/4),"1" ((long) s) \
- : "memory")
-{
- int d0, d1;
- switch (count % 4) {
- case 0: COMMON(""); return s;
- case 1: COMMON("\n\tstosb"); return s;
- case 2: COMMON("\n\tstosw"); return s;
- default: COMMON("\n\tstosw\n\tstosb"); return s;
- }
-}
-
-#undef COMMON
-}
-
-#define __constant_c_x_memset(s, c, count) \
-(__builtin_constant_p(count) ? \
- __constant_c_and_count_memset((s),(c),(count)) : \
- __constant_c_memset((s),(c),(count)))
-
-#define __var_x_memset(s, c, count) \
-(__builtin_constant_p(count) ? \
- __constant_count_memset((s),(c),(count)) : \
- __memset_generic((s),(c),(count)))
-
-#define __HAVE_ARCH_MEMSET
-#define memset(s, c, count) (__memset((s),(c),(count)))
-#define __memset(s, c, count) \
-(__builtin_constant_p(c) ? \
- __constant_c_x_memset((s),(0x01010101UL*(unsigned char)(c)),(count)) : \
- __var_x_memset((s),(c),(count)))
-
-/*
- * find the first occurrence of byte 'c', or 1 past the area if none
- */
-#define __HAVE_ARCH_MEMSCAN
-static inline void * memscan(void * addr, int c, size_t size)
-{
- if (!size)
- return addr;
- __asm__("repnz; scasb\n\t"
- "jnz 1f\n\t"
- "dec %%edi\n"
- "1:"
- : "=D" (addr), "=c" (size)
- : "0" (addr), "1" (size), "a" (c));
- return addr;
-}
-
-#endif
diff --git a/xen/include/asm-x86/x86_32/uaccess.h b/xen/include/asm-x86/x86_32/uaccess.h
index 772aa3f990..eb9b87ceb1 100644
--- a/xen/include/asm-x86/x86_32/uaccess.h
+++ b/xen/include/asm-x86/x86_32/uaccess.h
@@ -1,25 +1,6 @@
#ifndef __i386_UACCESS_H
#define __i386_UACCESS_H
-/*
- * User space memory access functions
- */
-#include <xen/config.h>
-#include <xen/errno.h>
-#include <xen/prefetch.h>
-#include <xen/string.h>
-
-#define __user
-
-/*
- * movsl can be slow when source and dest are not both 8-byte aligned
- */
-#ifdef CONFIG_X86_INTEL_USERCOPY
-extern struct movsl_mask {
- int mask;
-} __cacheline_aligned movsl_mask;
-#endif
-
#define __addr_ok(addr) ((unsigned long)(addr) < HYPERVISOR_VIRT_START)
/*
@@ -41,112 +22,7 @@ extern struct movsl_mask {
#define array_access_ok(addr,count,size) \
(likely(count < (~0UL/size)) && access_ok(addr,count*size))
-extern long __get_user_bad(void);
-extern void __put_user_bad(void);
-
-/**
- * get_user: - Get a simple variable from user space.
- * @x: Variable to store result.
- * @ptr: Source address, in user space.
- *
- * Context: User context only. This function may sleep.
- *
- * This macro copies a single simple variable from user space to kernel
- * space. It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and the result of
- * dereferencing @ptr must be assignable to @x without a cast.
- *
- * Returns zero on success, or -EFAULT on error.
- * On error, the variable @x is set to zero.
- */
-#define get_user(x,ptr) \
- __get_user_check((x),(ptr),sizeof(*(ptr)))
-
-/**
- * put_user: - Write a simple value into user space.
- * @x: Value to copy to user space.
- * @ptr: Destination address, in user space.
- *
- * Context: User context only. This function may sleep.
- *
- * This macro copies a single simple value from kernel space to user
- * space. It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and @x must be assignable
- * to the result of dereferencing @ptr.
- *
- * Returns zero on success, or -EFAULT on error.
- */
-#define put_user(x,ptr) \
- __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
-
-
-/**
- * __get_user: - Get a simple variable from user space, with less checking.
- * @x: Variable to store result.
- * @ptr: Source address, in user space.
- *
- * Context: User context only. This function may sleep.
- *
- * This macro copies a single simple variable from user space to kernel
- * space. It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and the result of
- * dereferencing @ptr must be assignable to @x without a cast.
- *
- * Caller must check the pointer with access_ok() before calling this
- * function.
- *
- * Returns zero on success, or -EFAULT on error.
- * On error, the variable @x is set to zero.
- */
-#define __get_user(x,ptr) \
- __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
-
-
-/**
- * __put_user: - Write a simple value into user space, with less checking.
- * @x: Value to copy to user space.
- * @ptr: Destination address, in user space.
- *
- * Context: User context only. This function may sleep.
- *
- * This macro copies a single simple value from kernel space to user
- * space. It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and @x must be assignable
- * to the result of dereferencing @ptr.
- *
- * Caller must check the pointer with access_ok() before calling this
- * function.
- *
- * Returns zero on success, or -EFAULT on error.
- */
-#define __put_user(x,ptr) \
- __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
-
-#define __put_user_nocheck(x,ptr,size) \
-({ \
- long __pu_err; \
- __put_user_size((x),(ptr),(size),__pu_err,-EFAULT); \
- __pu_err; \
-})
-
-#define __put_user_check(x,ptr,size) \
-({ \
- long __pu_err = -EFAULT; \
- __typeof__(*(ptr)) __user *__pu_addr = (ptr); \
- if (__addr_ok(__pu_addr)) \
- __put_user_size((x),__pu_addr,(size),__pu_err,-EFAULT); \
- __pu_err; \
-})
-
-#define __put_user_u64(x, addr, err) \
+#define __put_user_u64(x, addr, retval, errret) \
__asm__ __volatile__( \
"1: movl %%eax,0(%2)\n" \
"2: movl %%edx,4(%2)\n" \
@@ -160,8 +36,8 @@ extern void __put_user_bad(void);
" .long 1b,4b\n" \
" .long 2b,4b\n" \
".previous" \
- : "=r"(err) \
- : "A" (x), "r" (addr), "i"(-EFAULT), "0"(err))
+ : "=r"(retval) \
+ : "A" (x), "r" (addr), "i"(errret), "0"(retval))
#define __put_user_size(x,ptr,size,retval,errret) \
do { \
@@ -170,52 +46,29 @@ do { \
case 1: __put_user_asm(x,ptr,retval,"b","b","iq",errret);break; \
case 2: __put_user_asm(x,ptr,retval,"w","w","ir",errret);break; \
case 4: __put_user_asm(x,ptr,retval,"l","","ir",errret); break; \
- case 8: __put_user_u64((__typeof__(*ptr))(x),ptr,retval); break;\
- default: __put_user_bad(); \
+ case 8: __put_user_u64((__typeof__(*ptr))(x),ptr,retval,errret);break;\
+ default: __put_user_bad(); \
} \
} while (0)
-struct __large_struct { unsigned long buf[100]; };
-#define __m(x) (*(struct __large_struct *)(x))
-
-/*
- * Tell gcc we read from memory instead of writing: this is because
- * we do not write to any memory gcc knows about, so there are no
- * aliasing issues.
- */
-#define __put_user_asm(x, addr, err, itype, rtype, ltype, errret) \
- __asm__ __volatile__( \
- "1: mov"itype" %"rtype"1,%2\n" \
- "2:\n" \
- ".section .fixup,\"ax\"\n" \
- "3: movl %3,%0\n" \
- " jmp 2b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 1b,3b\n" \
- ".previous" \
- : "=r"(err) \
- : ltype (x), "m"(__m(addr)), "i"(errret), "0"(err))
-
-
-#define __get_user_nocheck(x,ptr,size) \
-({ \
- long __gu_err, __gu_val; \
- __get_user_size(__gu_val,(ptr),(size),__gu_err,-EFAULT);\
- (x) = (__typeof__(*(ptr)))__gu_val; \
- __gu_err; \
-})
-
-#define __get_user_check(x,ptr,size) \
-({ \
- long __gu_err, __gu_val; \
- __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
- __get_user_size(__gu_val,__gu_addr,(size),__gu_err,-EFAULT); \
- (x) = (__typeof__(*(ptr)))__gu_val; \
- if (!__addr_ok(__gu_addr)) __gu_err = -EFAULT; \
- __gu_err; \
-})
+#define __get_user_u64(x, addr, retval, errret) \
+ __asm__ __volatile__( \
+ "1: movl 0(%2),%%eax\n" \
+ "2: movl 4(%2),%%edx\n" \
+ "3:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "4: movl %3,%0\n" \
+ " xorl %%eax,%%eax\n" \
+ " xorl %%edx,%%edx\n" \
+ " jmp 3b\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 4\n" \
+ " .long 1b,4b\n" \
+ " .long 2b,4b\n" \
+ ".previous" \
+ : "=r" (retval), "=A" (x) \
+ : "r" (addr), "i"(errret), "0"(retval))
#define __get_user_size(x,ptr,size,retval,errret) \
do { \
@@ -224,115 +77,9 @@ do { \
case 1: __get_user_asm(x,ptr,retval,"b","b","=q",errret);break; \
case 2: __get_user_asm(x,ptr,retval,"w","w","=r",errret);break; \
case 4: __get_user_asm(x,ptr,retval,"l","","=r",errret);break; \
+ case 8: __get_user_u64(x,ptr,retval,errret);break; \
default: (x) = __get_user_bad(); \
} \
} while (0)
-#define __get_user_asm(x, addr, err, itype, rtype, ltype, errret) \
- __asm__ __volatile__( \
- "1: mov"itype" %2,%"rtype"1\n" \
- "2:\n" \
- ".section .fixup,\"ax\"\n" \
- "3: movl %3,%0\n" \
- " xor"itype" %"rtype"1,%"rtype"1\n" \
- " jmp 2b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 1b,3b\n" \
- ".previous" \
- : "=r"(err), ltype (x) \
- : "m"(__m(addr)), "i"(errret), "0"(err))
-
-
-unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned long n);
-unsigned long __copy_from_user_ll(void *to, const void __user *from, unsigned long n);
-
-/*
- * Here we special-case 1, 2 and 4-byte copy_*_user invocations. On a fault
- * we return the initial request size (1, 2 or 4), as copy_*_user should do.
- * If a store crosses a page boundary and gets a fault, the x86 will not write
- * anything, so this is accurate.
- */
-
-/**
- * __copy_to_user: - Copy a block of data into user space, with less checking.
- * @to: Destination address, in user space.
- * @from: Source address, in kernel space.
- * @n: Number of bytes to copy.
- *
- * Context: User context only. This function may sleep.
- *
- * Copy data from kernel space to user space. Caller must check
- * the specified block with access_ok() before calling this function.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- */
-static always_inline unsigned long
-__copy_to_user(void __user *to, const void *from, unsigned long n)
-{
- if (__builtin_constant_p(n)) {
- unsigned long ret;
-
- switch (n) {
- case 1:
- __put_user_size(*(u8 *)from, (u8 __user *)to, 1, ret, 1);
- return ret;
- case 2:
- __put_user_size(*(u16 *)from, (u16 __user *)to, 2, ret, 2);
- return ret;
- case 4:
- __put_user_size(*(u32 *)from, (u32 __user *)to, 4, ret, 4);
- return ret;
- }
- }
- return __copy_to_user_ll(to, from, n);
-}
-
-/**
- * __copy_from_user: - Copy a block of data from user space, with less checking.
- * @to: Destination address, in kernel space.
- * @from: Source address, in user space.
- * @n: Number of bytes to copy.
- *
- * Context: User context only. This function may sleep.
- *
- * Copy data from user space to kernel space. Caller must check
- * the specified block with access_ok() before calling this function.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- *
- * If some data could not be copied, this function will pad the copied
- * data to the requested size using zero bytes.
- */
-static always_inline unsigned long
-__copy_from_user(void *to, const void __user *from, unsigned long n)
-{
- if (__builtin_constant_p(n)) {
- unsigned long ret;
-
- switch (n) {
- case 1:
- __get_user_size(*(u8 *)to, from, 1, ret, 1);
- return ret;
- case 2:
- __get_user_size(*(u16 *)to, from, 2, ret, 2);
- return ret;
- case 4:
- __get_user_size(*(u32 *)to, from, 4, ret, 4);
- return ret;
- }
- }
- return __copy_from_user_ll(to, from, n);
-}
-
-unsigned long copy_to_user(void __user *to, const void *from, unsigned long n);
-unsigned long copy_from_user(void *to,
- const void __user *from, unsigned long n);
-
-unsigned long clear_user(void __user *mem, unsigned long len);
-unsigned long __clear_user(void __user *mem, unsigned long len);
-
#endif /* __i386_UACCESS_H */
diff --git a/xen/include/asm-x86/x86_64/domain_page.h b/xen/include/asm-x86/x86_64/domain_page.h
deleted file mode 100644
index 2a59fb1e5e..0000000000
--- a/xen/include/asm-x86/x86_64/domain_page.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/******************************************************************************
- * domain_page.h
- *
- * This is a trivial no-op on x86/64, where we can 1:1 map all RAM.
- */
-
-#ifndef __ASM_DOMAIN_PAGE_H__
-#define __ASM_DOMAIN_PAGE_H__
-
-#define map_domain_mem(_pa) phys_to_virt(_pa)
-#define unmap_domain_mem(_va) ((void)(_va))
-
-struct map_dom_mem_cache {
-};
-
-#define init_map_domain_mem_cache(_c) ((void)(_c))
-#define map_domain_mem_with_cache(_p,_c) (map_domain_mem(_p))
-#define unmap_domain_mem_with_cache(_v,_c) ((void)(_v))
-#define destroy_map_domain_mem_cache(_c) ((void)(_c))
-
-#endif /* __ASM_DOMAIN_PAGE_H__ */
diff --git a/xen/include/asm-x86/x86_64/string.h b/xen/include/asm-x86/x86_64/string.h
deleted file mode 100644
index 613c982718..0000000000
--- a/xen/include/asm-x86/x86_64/string.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _X86_64_STRING_H_
-#define _X86_64_STRING_H_
-
-#define __HAVE_ARCH_MEMCPY
-#define memcpy(t,f,n) (__memcpy((t),(f),(n)))
-#define __memcpy(t,f,n) (__builtin_memcpy((t),(f),(n)))
-
-#define __HAVE_ARCH_MEMSET
-#define memset(s, c, count) (__memset((s),(c),(count)))
-#define __memset(s, c, count) (__builtin_memset((s),(c),(count)))
-
-/* Some versions of 64-bit gcc don't have this built in. */
-#define __HAVE_ARCH_MEMMOVE
-extern void *memmove(void *dest, const void *src, size_t n);
-
-#endif
diff --git a/xen/include/asm-x86/x86_64/uaccess.h b/xen/include/asm-x86/x86_64/uaccess.h
index d655e01f83..4d5f65c890 100644
--- a/xen/include/asm-x86/x86_64/uaccess.h
+++ b/xen/include/asm-x86/x86_64/uaccess.h
@@ -2,17 +2,6 @@
#define __X86_64_UACCESS_H
/*
- * User space memory access functions
- */
-#include <xen/config.h>
-#include <xen/compiler.h>
-#include <xen/errno.h>
-#include <xen/prefetch.h>
-#include <asm/page.h>
-
-#define __user
-
-/*
* Valid if in +ve half of 48-bit address space, or above Xen-reserved area.
* This is also valid for range checks (addr, addr+size). As long as the
* start address is outside the Xen-reserved area then we will access a
@@ -26,111 +15,6 @@
#define array_access_ok(addr, count, size) (__addr_ok(addr))
-extern long __get_user_bad(void);
-extern void __put_user_bad(void);
-
-/**
- * get_user: - Get a simple variable from user space.
- * @x: Variable to store result.
- * @ptr: Source address, in user space.
- *
- * Context: User context only. This function may sleep.
- *
- * This macro copies a single simple variable from user space to kernel
- * space. It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and the result of
- * dereferencing @ptr must be assignable to @x without a cast.
- *
- * Returns zero on success, or -EFAULT on error.
- * On error, the variable @x is set to zero.
- */
-#define get_user(x,ptr) \
- __get_user_check((x),(ptr),sizeof(*(ptr)))
-
-/**
- * put_user: - Write a simple value into user space.
- * @x: Value to copy to user space.
- * @ptr: Destination address, in user space.
- *
- * Context: User context only. This function may sleep.
- *
- * This macro copies a single simple value from kernel space to user
- * space. It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and @x must be assignable
- * to the result of dereferencing @ptr.
- *
- * Returns zero on success, or -EFAULT on error.
- */
-#define put_user(x,ptr) \
- __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
-
-
-/**
- * __get_user: - Get a simple variable from user space, with less checking.
- * @x: Variable to store result.
- * @ptr: Source address, in user space.
- *
- * Context: User context only. This function may sleep.
- *
- * This macro copies a single simple variable from user space to kernel
- * space. It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and the result of
- * dereferencing @ptr must be assignable to @x without a cast.
- *
- * Caller must check the pointer with access_ok() before calling this
- * function.
- *
- * Returns zero on success, or -EFAULT on error.
- * On error, the variable @x is set to zero.
- */
-#define __get_user(x,ptr) \
- __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
-
-
-/**
- * __put_user: - Write a simple value into user space, with less checking.
- * @x: Value to copy to user space.
- * @ptr: Destination address, in user space.
- *
- * Context: User context only. This function may sleep.
- *
- * This macro copies a single simple value from kernel space to user
- * space. It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and @x must be assignable
- * to the result of dereferencing @ptr.
- *
- * Caller must check the pointer with access_ok() before calling this
- * function.
- *
- * Returns zero on success, or -EFAULT on error.
- */
-#define __put_user(x,ptr) \
- __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
-
-#define __put_user_nocheck(x,ptr,size) \
-({ \
- long __pu_err; \
- __put_user_size((x),(ptr),(size),__pu_err,-EFAULT); \
- __pu_err; \
-})
-
-#define __put_user_check(x,ptr,size) \
-({ \
- long __pu_err = -EFAULT; \
- __typeof__(*(ptr)) __user *__pu_addr = (ptr); \
- if (__addr_ok(__pu_addr)) \
- __put_user_size((x),__pu_addr,(size),__pu_err,-EFAULT); \
- __pu_err; \
-})
-
#define __put_user_size(x,ptr,size,retval,errret) \
do { \
retval = 0; \
@@ -143,47 +27,6 @@ do { \
} \
} while (0)
-struct __large_struct { unsigned long buf[100]; };
-#define __m(x) (*(struct __large_struct *)(x))
-
-/*
- * Tell gcc we read from memory instead of writing: this is because
- * we do not write to any memory gcc knows about, so there are no
- * aliasing issues.
- */
-#define __put_user_asm(x, addr, err, itype, rtype, ltype, errret) \
- __asm__ __volatile__( \
- "1: mov"itype" %"rtype"1,%2\n" \
- "2:\n" \
- ".section .fixup,\"ax\"\n" \
- "3: mov %3,%0\n" \
- " jmp 2b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 8\n" \
- " .quad 1b,3b\n" \
- ".previous" \
- : "=r"(err) \
- : ltype (x), "m"(__m(addr)), "i"(errret), "0"(err))
-
-#define __get_user_nocheck(x,ptr,size) \
-({ \
- long __gu_err, __gu_val; \
- __get_user_size(__gu_val,(ptr),(size),__gu_err,-EFAULT);\
- (x) = (__typeof__(*(ptr)))__gu_val; \
- __gu_err; \
-})
-
-#define __get_user_check(x,ptr,size) \
-({ \
- long __gu_err, __gu_val; \
- __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
- __get_user_size(__gu_val,__gu_addr,(size),__gu_err,-EFAULT); \
- (x) = (__typeof__(*(ptr)))__gu_val; \
- if (!__addr_ok(__gu_addr)) __gu_err = -EFAULT; \
- __gu_err; \
-})
-
#define __get_user_size(x,ptr,size,retval,errret) \
do { \
retval = 0; \
@@ -196,95 +39,4 @@ do { \
} \
} while (0)
-#define __get_user_asm(x, addr, err, itype, rtype, ltype, errret) \
- __asm__ __volatile__( \
- "1: mov"itype" %2,%"rtype"1\n" \
- "2:\n" \
- ".section .fixup,\"ax\"\n" \
- "3: mov %3,%0\n" \
- " xor"itype" %"rtype"1,%"rtype"1\n" \
- " jmp 2b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 8\n" \
- " .quad 1b,3b\n" \
- ".previous" \
- : "=r"(err), ltype (x) \
- : "m"(__m(addr)), "i"(errret), "0"(err))
-
-
-/*
- * Copy To/From Userspace
- */
-
-/* Handles exceptions in both to and from, but doesn't do access_ok */
-unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned n);
-unsigned long __copy_from_user_ll(void *to, const void __user *from, unsigned n);
-
-unsigned long copy_to_user(void __user *to, const void *from, unsigned len);
-unsigned long copy_from_user(void *to, const void __user *from, unsigned len);
-
-static always_inline int __copy_from_user(void *dst, const void __user *src, unsigned size)
-{
- int ret = 0;
- if (!__builtin_constant_p(size))
- return __copy_from_user_ll(dst,(void *)src,size);
- switch (size) {
- case 1:__get_user_asm(*(u8*)dst,(u8 __user *)src,ret,"b","b","=q",1);
- return ret;
- case 2:__get_user_asm(*(u16*)dst,(u16 __user *)src,ret,"w","w","=r",2);
- return ret;
- case 4:__get_user_asm(*(u32*)dst,(u32 __user *)src,ret,"l","k","=r",4);
- return ret;
- case 8:__get_user_asm(*(u64*)dst,(u64 __user *)src,ret,"q","","=r",8);
- return ret;
- case 10:
- __get_user_asm(*(u64*)dst,(u64 __user *)src,ret,"q","","=r",16);
- if (unlikely(ret)) return ret;
- __get_user_asm(*(u16*)(8+(char*)dst),(u16 __user *)(8+(char __user *)src),ret,"w","w","=r",2);
- return ret;
- case 16:
- __get_user_asm(*(u64*)dst,(u64 __user *)src,ret,"q","","=r",16);
- if (unlikely(ret)) return ret;
- __get_user_asm(*(u64*)(8+(char*)dst),(u64 __user *)(8+(char __user *)src),ret,"q","","=r",8);
- return ret;
- default:
- return __copy_from_user_ll(dst,(void *)src,size);
- }
-}
-
-static always_inline int __copy_to_user(void __user *dst, const void *src, unsigned size)
-{
- int ret = 0;
- if (!__builtin_constant_p(size))
- return __copy_to_user_ll((void *)dst,src,size);
- switch (size) {
- case 1:__put_user_asm(*(u8*)src,(u8 __user *)dst,ret,"b","b","iq",1);
- return ret;
- case 2:__put_user_asm(*(u16*)src,(u16 __user *)dst,ret,"w","w","ir",2);
- return ret;
- case 4:__put_user_asm(*(u32*)src,(u32 __user *)dst,ret,"l","k","ir",4);
- return ret;
- case 8:__put_user_asm(*(u64*)src,(u64 __user *)dst,ret,"q","","ir",8);
- return ret;
- case 10:
- __put_user_asm(*(u64*)src,(u64 __user *)dst,ret,"q","","ir",10);
- if (unlikely(ret)) return ret;
- asm("":::"memory");
- __put_user_asm(4[(u16*)src],4+(u16 __user *)dst,ret,"w","w","ir",2);
- return ret;
- case 16:
- __put_user_asm(*(u64*)src,(u64 __user *)dst,ret,"q","","ir",16);
- if (unlikely(ret)) return ret;
- asm("":::"memory");
- __put_user_asm(1[(u64*)src],1+(u64 __user *)dst,ret,"q","","ir",8);
- return ret;
- default:
- return __copy_to_user_ll((void *)dst,src,size);
- }
-}
-
-unsigned long clear_user(void __user *mem, unsigned long len);
-unsigned long __clear_user(void __user *mem, unsigned long len);
-
#endif /* __X86_64_UACCESS_H */
diff --git a/xen/include/public/dom0_ops.h b/xen/include/public/dom0_ops.h
index 4c3d5271a2..0768b8c6ae 100644
--- a/xen/include/public/dom0_ops.h
+++ b/xen/include/public/dom0_ops.h
@@ -164,9 +164,11 @@ typedef struct {
*/
#define DOM0_READCONSOLE 19
typedef struct {
- memory_t str;
- u32 count;
- u32 cmd;
+ /* IN variables. */
+ u32 clear; /* Non-zero -> clear after reading. */
+ /* IN/OUT variables. */
+ char *buffer; /* In: Buffer start; Out: Used buffer start */
+ u32 count; /* In: Buffer size; Out: Used buffer size */
} dom0_readconsole_t;
/*
diff --git a/xen/include/public/event_channel.h b/xen/include/public/event_channel.h
index a1973c6ea7..e787a0524a 100644
--- a/xen/include/public/event_channel.h
+++ b/xen/include/public/event_channel.h
@@ -10,15 +10,16 @@
#define __XEN_PUBLIC_EVENT_CHANNEL_H__
/*
- * EVTCHNOP_alloc_unbound: Allocate a fresh local port and prepare
- * it for binding to <dom>.
+ * EVTCHNOP_alloc_unbound: Prepare a local port for binding to <dom>.
+ * <port> may be wildcarded by setting to zero, in which case a fresh port
+ * will be allocated, and the field filled in on return.
*/
#define EVTCHNOP_alloc_unbound 6
typedef struct {
/* IN parameters */
domid_t dom; /* 0 */
u16 __pad;
- /* OUT parameters */
+ /* IN/OUT parameters */
u32 port; /* 4 */
} PACKED evtchn_alloc_unbound_t; /* 8 bytes */
@@ -51,9 +52,11 @@ typedef struct {
} PACKED evtchn_bind_interdomain_t; /* 12 bytes */
/*
- * EVTCHNOP_bind_virq: Bind a local event channel to IRQ <irq>.
+ * EVTCHNOP_bind_virq: Bind a local event channel to IRQ <irq> on calling vcpu.
* NOTES:
- * 1. A virtual IRQ may be bound to at most one event channel per domain.
+ * 1. A virtual IRQ may be bound to at most one event channel per vcpu.
+ * 2. The allocated event channel is bound to the calling vcpu. The binding
+ * may not be changed.
*/
#define EVTCHNOP_bind_virq 1
typedef struct {
@@ -80,6 +83,20 @@ typedef struct {
} PACKED evtchn_bind_pirq_t; /* 12 bytes */
/*
+ * EVTCHNOP_bind_ipi: Bind a local event channel to receive events.
+ * NOTES:
+ * 1. The allocated event channel is bound to the calling vcpu. The binding
+ * may not be changed.
+ */
+#define EVTCHNOP_bind_ipi 7
+typedef struct {
+ /* IN parameters. */
+ u32 ipi_vcpu; /* 0 */
+ /* OUT parameters. */
+ u32 port; /* 4 */
+} PACKED evtchn_bind_ipi_t; /* 8 bytes */
+
+/*
* EVTCHNOP_close: Close the communication channel which has an endpoint at
* <dom, port>. If the channel is interdomain then the remote end is placed in
* the unbound state (EVTCHNSTAT_unbound), awaiting a new connection.
@@ -145,18 +162,6 @@ typedef struct {
} PACKED u;
} PACKED evtchn_status_t; /* 20 bytes */
-/*
- * EVTCHNOP_bind_ipi: Bind a local event channel to receive events.
- */
-#define EVTCHNOP_bind_ipi 7
-typedef struct {
- /* IN parameters. */
- u32 ipi_vcpu; /* 0 */
- /* OUT parameters. */
- u32 port; /* 4 */
-} PACKED evtchn_bind_ipi_t; /* 8 bytes */
-
-
typedef struct {
u32 cmd; /* EVTCHNOP_* */ /* 0 */
u32 __reserved; /* 4 */
@@ -165,10 +170,10 @@ typedef struct {
evtchn_bind_interdomain_t bind_interdomain;
evtchn_bind_virq_t bind_virq;
evtchn_bind_pirq_t bind_pirq;
+ evtchn_bind_ipi_t bind_ipi;
evtchn_close_t close;
evtchn_send_t send;
evtchn_status_t status;
- evtchn_bind_ipi_t bind_ipi;
u8 __dummy[24];
} PACKED u;
} PACKED evtchn_op_t; /* 32 bytes */
diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h
index a6e2f50d81..d46472c16c 100644
--- a/xen/include/public/xen.h
+++ b/xen/include/public/xen.h
@@ -70,6 +70,7 @@
#define VIRQ_DOM_EXC 3 /* (DOM0) Exceptional event for some domain. */
#define VIRQ_PARITY_ERR 4 /* (DOM0) NMI parity error. */
#define VIRQ_IO_ERR 5 /* (DOM0) NMI I/O error. */
+#define VIRQ_DEBUGGER 6 /* (DOM0) A domain has paused for debugging. */
#define NR_VIRQS 7
/*
@@ -429,32 +430,32 @@ typedef struct shared_info_st
* extended by an extra 4MB to ensure this.
*/
-#define MAX_CMDLINE 256
+#define MAX_GUEST_CMDLINE 1024
typedef struct {
- /* THE FOLLOWING ARE FILLED IN BOTH ON INITIAL BOOT AND ON RESUME. */
- memory_t nr_pages; /* 0: Total pages allocated to this domain. */
+ /* THE FOLLOWING ARE FILLED IN BOTH ON INITIAL BOOT AND ON RESUME. */
+ memory_t nr_pages; /* 0: Total pages allocated to this domain. */
_MEMORY_PADDING(A);
- memory_t shared_info; /* 8: MACHINE address of shared info struct. */
+ memory_t shared_info; /* 8: MACHINE address of shared info struct. */
_MEMORY_PADDING(B);
- u32 flags; /* 16: SIF_xxx flags. */
+ u32 flags; /* 16: SIF_xxx flags. */
u16 domain_controller_evtchn; /* 20 */
u16 __pad;
- /* THE FOLLOWING ARE ONLY FILLED IN ON INITIAL BOOT (NOT RESUME). */
- memory_t pt_base; /* 24: VIRTUAL address of page directory. */
+ /* THE FOLLOWING ARE ONLY FILLED IN ON INITIAL BOOT (NOT RESUME). */
+ memory_t pt_base; /* 24: VIRTUAL address of page directory. */
_MEMORY_PADDING(C);
- memory_t nr_pt_frames; /* 32: Number of bootstrap p.t. frames. */
+ memory_t nr_pt_frames; /* 32: Number of bootstrap p.t. frames. */
_MEMORY_PADDING(D);
- memory_t mfn_list; /* 40: VIRTUAL address of page-frame list. */
+ memory_t mfn_list; /* 40: VIRTUAL address of page-frame list. */
_MEMORY_PADDING(E);
- memory_t mod_start; /* 48: VIRTUAL address of pre-loaded module. */
+ memory_t mod_start; /* 48: VIRTUAL address of pre-loaded module. */
_MEMORY_PADDING(F);
- memory_t mod_len; /* 56: Size (bytes) of pre-loaded module. */
+ memory_t mod_len; /* 56: Size (bytes) of pre-loaded module. */
_MEMORY_PADDING(G);
- s8 cmd_line[MAX_CMDLINE]; /* 64 */
- memory_t store_page; /* 320: VIRTUAL address of store page. */
+ s8 cmd_line[MAX_GUEST_CMDLINE]; /* 64 */
+ memory_t store_page; /* 1088: VIRTUAL address of store page. */
_MEMORY_PADDING(H);
- u16 store_evtchn; /* 328: Event channel for store communication. */
-} PACKED start_info_t; /* 332/336 bytes */
+ u16 store_evtchn; /* 1096: Event channel for store communication. */
+} PACKED start_info_t; /* 1098 bytes */
/* These flags are passed in the 'flags' field of start_info_t. */
#define SIF_PRIVILEGED (1<<0) /* Is the domain privileged? */
diff --git a/xen/include/xen/console.h b/xen/include/xen/console.h
index 024840c0ad..12028cdc97 100644
--- a/xen/include/xen/console.h
+++ b/xen/include/xen/console.h
@@ -13,8 +13,7 @@ extern spinlock_t console_lock;
void set_printk_prefix(const char *prefix);
-#define CONSOLE_RING_CLEAR 1
-long read_console_ring(unsigned long, unsigned int, unsigned int);
+long read_console_ring(char **, u32 *, int);
void init_console(void);
void console_endboot(int disable_vga);
@@ -22,4 +21,7 @@ void console_endboot(int disable_vga);
void console_force_unlock(void);
void console_force_lock(void);
+void console_start_sync(void);
+void console_end_sync(void);
+
#endif /* __CONSOLE_H__ */
diff --git a/xen/include/xen/domain_page.h b/xen/include/xen/domain_page.h
new file mode 100644
index 0000000000..f20e3f28c3
--- /dev/null
+++ b/xen/include/xen/domain_page.h
@@ -0,0 +1,100 @@
+/******************************************************************************
+ * domain_page.h
+ *
+ * Allow temporary mapping of domain page frames into Xen space.
+ */
+
+#ifndef __XEN_DOMAIN_PAGE_H__
+#define __XEN_DOMAIN_PAGE_H__
+
+#include <xen/config.h>
+#include <xen/mm.h>
+
+#ifdef CONFIG_DOMAIN_PAGE
+
+/*
+ * Maps a given page frame, returning the mmap'ed virtual address. The page is
+ * now accessible until a corresponding call to unmap_domain_page().
+ */
+extern void *map_domain_page(unsigned long pfn);
+
+/*
+ * Pass a VA within a page previously mapped with map_domain_page().
+ * That page will then be removed from the mapping lists.
+ */
+extern void unmap_domain_page(void *va);
+
+#define DMCACHE_ENTRY_VALID 1U
+#define DMCACHE_ENTRY_HELD 2U
+
+struct domain_mmap_cache {
+ unsigned long pfn;
+ void *va;
+ unsigned int flags;
+};
+
+static inline void
+domain_mmap_cache_init(struct domain_mmap_cache *cache)
+{
+ ASSERT(cache != NULL);
+ cache->flags = 0;
+}
+
+static inline void *
+map_domain_page_with_cache(unsigned long pfn, struct domain_mmap_cache *cache)
+{
+ ASSERT(cache != NULL);
+ BUG_ON(cache->flags & DMCACHE_ENTRY_HELD);
+
+ if ( likely(cache->flags & DMCACHE_ENTRY_VALID) )
+ {
+ cache->flags |= DMCACHE_ENTRY_HELD;
+ if ( likely(pfn == cache->pfn) )
+ goto done;
+ unmap_domain_page(cache->va);
+ }
+
+ cache->pfn = pfn;
+ cache->va = map_domain_page(pfn);
+ cache->flags = DMCACHE_ENTRY_HELD | DMCACHE_ENTRY_VALID;
+
+ done:
+ return cache->va;
+}
+
+static inline void
+unmap_domain_page_with_cache(void *va, struct domain_mmap_cache *cache)
+{
+ ASSERT(cache != NULL);
+ cache->flags &= ~DMCACHE_ENTRY_HELD;
+}
+
+static inline void
+domain_mmap_cache_destroy(struct domain_mmap_cache *cache)
+{
+ ASSERT(cache != NULL);
+ BUG_ON(cache->flags & DMCACHE_ENTRY_HELD);
+
+ if ( likely(cache->flags & DMCACHE_ENTRY_VALID) )
+ {
+ unmap_domain_page(cache->va);
+ cache->flags = 0;
+ }
+}
+
+#else /* !CONFIG_DOMAIN_PAGE */
+
+#define map_domain_page(pfn) phys_to_virt((pfn)<<PAGE_SHIFT)
+#define unmap_domain_page(va) ((void)(va))
+
+struct domain_mmap_cache {
+};
+
+#define domain_mmap_cache_init(c) ((void)(c))
+#define map_domain_page_with_cache(pfn,c) (map_domain_page(pfn))
+#define unmap_domain_page_with_cache(va,c) ((void)(va))
+#define domain_mmap_cache_destroy(c) ((void)(c))
+
+#endif /* !CONFIG_DOMAIN_PAGE */
+
+#endif /* __XEN_DOMAIN_PAGE_H__ */
diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h
index a7d911771d..734427266b 100644
--- a/xen/include/xen/event.h
+++ b/xen/include/xen/event.h
@@ -53,7 +53,7 @@ static inline void evtchn_set_pending(struct vcpu *v, int port)
/*
* send_guest_virq:
- * @d: Domain to which virtual IRQ should be sent
+ * @v: VCPU to which virtual IRQ should be sent
* @virq: Virtual IRQ number (VIRQ_*)
*/
static inline void send_guest_virq(struct vcpu *v, int virq)
@@ -69,10 +69,7 @@ static inline void send_guest_virq(struct vcpu *v, int virq)
* @d: Domain to which physical IRQ should be sent
* @pirq: Physical IRQ number
*/
-static inline void send_guest_pirq(struct vcpu *v, int pirq)
-{
- evtchn_set_pending(v, v->domain->pirq_to_evtchn[pirq]);
-}
+extern void send_guest_pirq(struct domain *d, int pirq);
#define event_pending(_d) \
((_d)->vcpu_info->evtchn_upcall_pending && \
diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h
index 0bc8558ae0..7b1f826198 100644
--- a/xen/include/xen/irq.h
+++ b/xen/include/xen/irq.h
@@ -71,6 +71,5 @@ struct vcpu;
extern int pirq_guest_unmask(struct domain *p);
extern int pirq_guest_bind(struct vcpu *p, int irq, int will_share);
extern int pirq_guest_unbind(struct domain *p, int irq);
-extern int pirq_guest_bindable(int irq, int will_share);
#endif /* __XEN_IRQ_H__ */
diff --git a/xen/include/xen/perfc_defn.h b/xen/include/xen/perfc_defn.h
index c7f2493a1a..abc17e0b68 100644
--- a/xen/include/xen/perfc_defn.h
+++ b/xen/include/xen/perfc_defn.h
@@ -1,112 +1,127 @@
+#ifndef __XEN_PERFC_DEFN_H__
+#define __XEN_PERFC_DEFN_H__
+
#define PERFC_MAX_PT_UPDATES 64
#define PERFC_PT_UPDATES_BUCKET_SIZE 3
-PERFCOUNTER_ARRAY( wpt_updates, "writable pt updates", PERFC_MAX_PT_UPDATES )
-PERFCOUNTER_ARRAY( bpt_updates, "batched pt updates", PERFC_MAX_PT_UPDATES )
-PERFCOUNTER_ARRAY( l1_entries_checked, "l1 entries checked", PERFC_MAX_PT_UPDATES )
-PERFCOUNTER_ARRAY( shm_l2_updates, "shadow mode L2 pt updates", PERFC_MAX_PT_UPDATES )
-PERFCOUNTER_ARRAY( shm_hl2_updates, "shadow mode HL2 pt updates", PERFC_MAX_PT_UPDATES )
-PERFCOUNTER_ARRAY( snapshot_copies, "entries copied per snapshot", PERFC_MAX_PT_UPDATES )
-
-PERFCOUNTER_ARRAY( hypercalls, "hypercalls", NR_hypercalls )
-PERFCOUNTER_ARRAY( exceptions, "exceptions", 32 )
+PERFCOUNTER_ARRAY(wpt_updates, "writable pt updates",
+ PERFC_MAX_PT_UPDATES)
+PERFCOUNTER_ARRAY(bpt_updates, "batched pt updates",
+ PERFC_MAX_PT_UPDATES)
+PERFCOUNTER_ARRAY(l1_entries_checked, "l1 entries checked",
+ PERFC_MAX_PT_UPDATES)
+PERFCOUNTER_ARRAY(shm_l2_updates, "shadow mode L2 pt updates",
+ PERFC_MAX_PT_UPDATES)
+PERFCOUNTER_ARRAY(shm_hl2_updates, "shadow mode HL2 pt updates",
+ PERFC_MAX_PT_UPDATES)
+PERFCOUNTER_ARRAY(snapshot_copies, "entries copied per snapshot",
+ PERFC_MAX_PT_UPDATES)
+
+PERFCOUNTER_ARRAY(hypercalls, "hypercalls", NR_hypercalls)
+PERFCOUNTER_ARRAY(exceptions, "exceptions", 32)
#define VMX_PERF_EXIT_REASON_SIZE 37
#define VMX_PERF_VECTOR_SIZE 0x20
-PERFCOUNTER_ARRAY( vmexits, "vmexits", VMX_PERF_EXIT_REASON_SIZE )
-PERFCOUNTER_ARRAY( cause_vector, "cause vector", VMX_PERF_VECTOR_SIZE )
-
-PERFCOUNTER_CPU (seg_fixups, "segmentation fixups" )
-
-PERFCOUNTER_CPU( irqs, "#interrupts" )
-PERFCOUNTER_CPU( ipis, "#IPIs" )
-PERFCOUNTER_CPU( irq_time, "cycles spent in irq handler" )
-
-PERFCOUNTER_CPU( apic_timer, "apic timer interrupts" )
-PERFCOUNTER_CPU( ac_timer_max, "ac_timer max error (ns)" )
-PERFCOUNTER_CPU( sched_irq, "sched: timer" )
-PERFCOUNTER_CPU( sched_run, "sched: runs through scheduler" )
-PERFCOUNTER_CPU( sched_ctx, "sched: context switches" )
-
-PERFCOUNTER_CPU( domain_page_tlb_flush, "domain page tlb flushes" )
-PERFCOUNTER_CPU( need_flush_tlb_flush, "PG_need_flush tlb flushes" )
-
-PERFCOUNTER_CPU( calls_to_mmu_update, "calls_to_mmu_update" )
-PERFCOUNTER_CPU( num_page_updates, "num_page_updates" )
-PERFCOUNTER_CPU( calls_to_update_va, "calls_to_update_va_map" )
-PERFCOUNTER_CPU( page_faults, "page faults" )
-PERFCOUNTER_CPU( copy_user_faults, "copy_user faults" )
-
-PERFCOUNTER_CPU(shadow_fault_calls, "calls to shadow_fault")
-PERFCOUNTER_CPU(shadow_fault_bail_pde_not_present, "sf bailed due to pde not present")
-PERFCOUNTER_CPU(shadow_fault_bail_pte_not_present, "sf bailed due to pte not present")
-PERFCOUNTER_CPU(shadow_fault_bail_ro_mapping, "sf bailed due to a ro mapping")
-PERFCOUNTER_CPU(shadow_fault_fixed, "sf fixed the pgfault")
-PERFCOUNTER_CPU(write_fault_bail, "sf bailed due to write_fault")
-PERFCOUNTER_CPU(read_fault_bail, "sf bailed due to read_fault")
-
-PERFCOUNTER_CPU( map_domain_mem_count, "map_domain_mem count" )
-PERFCOUNTER_CPU( ptwr_emulations, "writable pt emulations" )
-
-PERFCOUNTER_CPU( shadow_l2_table_count, "shadow_l2_table count" )
-PERFCOUNTER_CPU( shadow_l1_table_count, "shadow_l1_table count" )
-PERFCOUNTER_CPU( unshadow_table_count, "unshadow_table count" )
-PERFCOUNTER_CPU( shadow_fixup_count, "shadow_fixup count" )
-PERFCOUNTER_CPU( shadow_update_va_fail1, "shadow_update_va_fail1" )
-PERFCOUNTER_CPU( shadow_update_va_fail2, "shadow_update_va_fail2" )
+PERFCOUNTER_ARRAY(vmexits, "vmexits", VMX_PERF_EXIT_REASON_SIZE)
+PERFCOUNTER_ARRAY(cause_vector, "cause vector", VMX_PERF_VECTOR_SIZE)
+
+PERFCOUNTER_CPU(seg_fixups, "segmentation fixups")
+
+PERFCOUNTER_CPU(irqs, "#interrupts")
+PERFCOUNTER_CPU(ipis, "#IPIs")
+PERFCOUNTER_CPU(irq_time, "cycles spent in irq handler")
+
+PERFCOUNTER_CPU(apic_timer, "apic timer interrupts")
+PERFCOUNTER_CPU(ac_timer_max, "ac_timer max error (ns)")
+PERFCOUNTER_CPU(sched_irq, "sched: timer")
+PERFCOUNTER_CPU(sched_run, "sched: runs through scheduler")
+PERFCOUNTER_CPU(sched_ctx, "sched: context switches")
+
+PERFCOUNTER_CPU(domain_page_tlb_flush, "domain page tlb flushes")
+PERFCOUNTER_CPU(need_flush_tlb_flush, "PG_need_flush tlb flushes")
+
+PERFCOUNTER_CPU(calls_to_mmu_update, "calls_to_mmu_update")
+PERFCOUNTER_CPU(num_page_updates, "num_page_updates")
+PERFCOUNTER_CPU(calls_to_update_va, "calls_to_update_va_map")
+PERFCOUNTER_CPU(page_faults, "page faults")
+PERFCOUNTER_CPU(copy_user_faults, "copy_user faults")
+
+PERFCOUNTER_CPU(shadow_fault_calls, "calls to shadow_fault")
+PERFCOUNTER_CPU(shadow_fault_bail_pde_not_present,
+ "sf bailed due to pde not present")
+PERFCOUNTER_CPU(shadow_fault_bail_pte_not_present,
+ "sf bailed due to pte not present")
+PERFCOUNTER_CPU(shadow_fault_bail_ro_mapping,
+ "sf bailed due to a ro mapping")
+PERFCOUNTER_CPU(shadow_fault_fixed, "sf fixed the pgfault")
+PERFCOUNTER_CPU(write_fault_bail, "sf bailed due to write_fault")
+PERFCOUNTER_CPU(read_fault_bail, "sf bailed due to read_fault")
+
+PERFCOUNTER_CPU(map_domain_page_count, "map_domain_page count")
+PERFCOUNTER_CPU(ptwr_emulations, "writable pt emulations")
+
+PERFCOUNTER_CPU(shadow_l2_table_count, "shadow_l2_table count")
+PERFCOUNTER_CPU(shadow_l1_table_count, "shadow_l1_table count")
+PERFCOUNTER_CPU(unshadow_table_count, "unshadow_table count")
+PERFCOUNTER_CPU(shadow_fixup_count, "shadow_fixup count")
+PERFCOUNTER_CPU(shadow_update_va_fail1, "shadow_update_va_fail1")
+PERFCOUNTER_CPU(shadow_update_va_fail2, "shadow_update_va_fail2")
/* STATUS counters do not reset when 'P' is hit */
-PERFSTATUS( shadow_l2_pages, "current # shadow L2 pages" )
-PERFSTATUS( shadow_l1_pages, "current # shadow L1 pages" )
-PERFSTATUS( hl2_table_pages, "current # hl2 pages" )
-PERFSTATUS( snapshot_pages, "current # fshadow snapshot pages" )
-PERFSTATUS( writable_pte_predictions, "# writable pte predictions")
-PERFSTATUS( free_l1_pages, "current # free shadow L1 pages" )
-
-PERFCOUNTER_CPU( check_pagetable, "calls to check_pagetable" )
-PERFCOUNTER_CPU( check_all_pagetables, "calls to check_all_pagetables" )
-
-PERFCOUNTER_CPU( shadow_hl2_table_count, "shadow_hl2_table count" )
-PERFCOUNTER_CPU( shadow_set_l1e_force_map, "shadow_set_l1e forced to map l1" )
-PERFCOUNTER_CPU( shadow_set_l1e_unlinked, "shadow_set_l1e found unlinked l1" )
-PERFCOUNTER_CPU( shadow_set_l1e_fail, "shadow_set_l1e failed (no sl1)" )
-PERFCOUNTER_CPU( shadow_invlpg_faults, "shadow_invlpg's get_user faulted")
-PERFCOUNTER_CPU( unshadow_l2_count, "unpinned L2 count")
+PERFSTATUS(shadow_l2_pages, "current # shadow L2 pages")
+PERFSTATUS(shadow_l1_pages, "current # shadow L1 pages")
+PERFSTATUS(hl2_table_pages, "current # hl2 pages")
+PERFSTATUS(snapshot_pages, "current # fshadow snapshot pages")
+PERFSTATUS(writable_pte_predictions, "# writable pte predictions")
+PERFSTATUS(free_l1_pages, "current # free shadow L1 pages")
+
+PERFCOUNTER_CPU(check_pagetable, "calls to check_pagetable")
+PERFCOUNTER_CPU(check_all_pagetables, "calls to check_all_pagetables")
+
+PERFCOUNTER_CPU(shadow_hl2_table_count, "shadow_hl2_table count")
+PERFCOUNTER_CPU(shadow_set_l1e_force_map, "shadow_set_l1e forced to map l1")
+PERFCOUNTER_CPU(shadow_set_l1e_unlinked, "shadow_set_l1e found unlinked l1")
+PERFCOUNTER_CPU(shadow_set_l1e_fail, "shadow_set_l1e failed (no sl1)")
+PERFCOUNTER_CPU(shadow_invlpg_faults, "shadow_invlpg's get_user faulted")
+PERFCOUNTER_CPU(unshadow_l2_count, "unpinned L2 count")
PERFCOUNTER_CPU(shadow_status_shortcut, "fastpath miss on shadow cache")
-PERFCOUNTER_CPU(shadow_status_calls, "calls to ___shadow_status" )
-PERFCOUNTER_CPU(shadow_status_miss, "missed shadow cache" )
-PERFCOUNTER_CPU(shadow_status_hit_head, "hits on head of bucket" )
-PERFCOUNTER_CPU(shadow_max_type, "calls to shadow_max_type" )
-
-PERFCOUNTER_CPU(shadow_sync_all, "calls to shadow_sync_all")
-PERFCOUNTER_CPU(shadow_sync_va, "calls to shadow_sync_va")
-PERFCOUNTER_CPU(resync_l1, "resync L1 page")
-PERFCOUNTER_CPU(resync_l2, "resync L2 page")
-PERFCOUNTER_CPU(resync_hl2, "resync HL2 page")
-PERFCOUNTER_CPU(shadow_make_snapshot, "snapshots created")
-PERFCOUNTER_CPU(shadow_mark_mfn_out_of_sync_calls, "calls to shadow_mk_out_of_sync")
-PERFCOUNTER_CPU(shadow_out_of_sync_calls, "calls to shadow_out_of_sync")
-PERFCOUNTER_CPU(snapshot_entry_matches_calls, "calls to ss_entry_matches")
-PERFCOUNTER_CPU(snapshot_entry_matches_true, "ss_entry_matches returns true")
-
-PERFCOUNTER_CPU(validate_pte_calls, "calls to validate_pte_change")
-PERFCOUNTER_CPU(validate_pte_changes1, "validate_pte makes changes1")
-PERFCOUNTER_CPU(validate_pte_changes2, "validate_pte makes changes2")
-PERFCOUNTER_CPU(validate_pte_changes3, "validate_pte makes changes3")
-PERFCOUNTER_CPU(validate_pte_changes4, "validate_pte makes changes4")
-PERFCOUNTER_CPU(validate_pde_calls, "calls to validate_pde_change")
-PERFCOUNTER_CPU(validate_pde_changes, "validate_pde makes changes")
-PERFCOUNTER_CPU(shadow_get_page_fail, "shadow_get_page_from_l1e fails" )
-PERFCOUNTER_CPU(validate_hl2e_calls, "calls to validate_hl2e_change")
-PERFCOUNTER_CPU(validate_hl2e_changes, "validate_hl2e makes changes")
-PERFCOUNTER_CPU(exception_fixed, "pre-exception fixed")
-PERFCOUNTER_CPU(gpfn_to_mfn_foreign, "calls to gpfn_to_mfn_foreign")
-PERFCOUNTER_CPU(remove_all_access, "calls to remove_all_access")
-PERFCOUNTER_CPU(remove_write_access, "calls to remove_write_access")
-PERFCOUNTER_CPU(remove_write_access_easy, "easy outs of remove_write_access")
-PERFCOUNTER_CPU(remove_write_no_work, "no work in remove_write_access")
-PERFCOUNTER_CPU(remove_write_not_writable, "remove_write non-writable page")
-PERFCOUNTER_CPU(remove_write_fast_exit, "remove_write hit predicted entry")
-PERFCOUNTER_CPU(remove_write_predicted, "remove_write predict hit&exit")
-PERFCOUNTER_CPU(remove_write_bad_prediction, "remove_write bad prediction")
-PERFCOUNTER_CPU(update_hl2e_invlpg, "update_hl2e calls invlpg")
+PERFCOUNTER_CPU(shadow_status_calls, "calls to ___shadow_status")
+PERFCOUNTER_CPU(shadow_status_miss, "missed shadow cache")
+PERFCOUNTER_CPU(shadow_status_hit_head, "hits on head of bucket")
+PERFCOUNTER_CPU(shadow_max_type, "calls to shadow_max_type")
+
+PERFCOUNTER_CPU(shadow_sync_all, "calls to shadow_sync_all")
+PERFCOUNTER_CPU(shadow_sync_va, "calls to shadow_sync_va")
+PERFCOUNTER_CPU(resync_l1, "resync L1 page")
+PERFCOUNTER_CPU(resync_l2, "resync L2 page")
+PERFCOUNTER_CPU(resync_hl2, "resync HL2 page")
+PERFCOUNTER_CPU(shadow_make_snapshot, "snapshots created")
+PERFCOUNTER_CPU(shadow_mark_mfn_out_of_sync_calls,
+ "calls to shadow_mk_out_of_sync")
+PERFCOUNTER_CPU(shadow_out_of_sync_calls, "calls to shadow_out_of_sync")
+PERFCOUNTER_CPU(snapshot_entry_matches_calls, "calls to ss_entry_matches")
+PERFCOUNTER_CPU(snapshot_entry_matches_true, "ss_entry_matches returns true")
+
+PERFCOUNTER_CPU(validate_pte_calls, "calls to validate_pte_change")
+PERFCOUNTER_CPU(validate_pte_changes1, "validate_pte makes changes1")
+PERFCOUNTER_CPU(validate_pte_changes2, "validate_pte makes changes2")
+PERFCOUNTER_CPU(validate_pte_changes3, "validate_pte makes changes3")
+PERFCOUNTER_CPU(validate_pte_changes4, "validate_pte makes changes4")
+PERFCOUNTER_CPU(validate_pde_calls, "calls to validate_pde_change")
+PERFCOUNTER_CPU(validate_pde_changes, "validate_pde makes changes")
+PERFCOUNTER_CPU(shadow_get_page_fail, "shadow_get_page_from_l1e fails")
+PERFCOUNTER_CPU(validate_hl2e_calls, "calls to validate_hl2e_change")
+PERFCOUNTER_CPU(validate_hl2e_changes, "validate_hl2e makes changes")
+PERFCOUNTER_CPU(exception_fixed, "pre-exception fixed")
+PERFCOUNTER_CPU(gpfn_to_mfn_foreign, "calls to gpfn_to_mfn_foreign")
+PERFCOUNTER_CPU(remove_all_access, "calls to remove_all_access")
+PERFCOUNTER_CPU(remove_write_access, "calls to remove_write_access")
+PERFCOUNTER_CPU(remove_write_access_easy, "easy outs of remove_write_access")
+PERFCOUNTER_CPU(remove_write_no_work, "no work in remove_write_access")
+PERFCOUNTER_CPU(remove_write_not_writable, "remove_write non-writable page")
+PERFCOUNTER_CPU(remove_write_fast_exit, "remove_write hit predicted entry")
+PERFCOUNTER_CPU(remove_write_predicted, "remove_write predict hit&exit")
+PERFCOUNTER_CPU(remove_write_bad_prediction, "remove_write bad prediction")
+PERFCOUNTER_CPU(update_hl2e_invlpg, "update_hl2e calls invlpg")
+
+#endif /* __XEN_PERFC_DEFN_H__ */
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 3eb2537fa5..35a3c36cab 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -19,7 +19,11 @@ extern rwlock_t domlist_lock;
/* A global pointer to the initial domain (DOM0). */
extern struct domain *dom0;
-typedef struct event_channel_st
+#define MAX_EVTCHNS 1024
+#define EVTCHNS_PER_BUCKET 128
+#define NR_EVTCHN_BUCKETS (MAX_EVTCHNS / EVTCHNS_PER_BUCKET)
+
+struct evtchn
{
#define ECS_FREE 0 /* Channel is available for use. */
#define ECS_RESERVED 1 /* Channel is reserved. */
@@ -28,24 +32,23 @@ typedef struct event_channel_st
#define ECS_PIRQ 4 /* Channel is bound to a physical IRQ line. */
#define ECS_VIRQ 5 /* Channel is bound to a virtual IRQ line. */
#define ECS_IPI 6 /* Channel is bound to a virtual IPI line. */
- u16 state;
+ u16 state; /* ECS_* */
+ u16 notify_vcpu_id; /* VCPU for local delivery notification */
union {
struct {
domid_t remote_domid;
- } __attribute__ ((packed)) unbound; /* state == ECS_UNBOUND */
+ } unbound; /* state == ECS_UNBOUND */
struct {
- u16 remote_port;
- struct vcpu *remote_dom;
- } __attribute__ ((packed)) interdomain; /* state == ECS_INTERDOMAIN */
- u16 pirq; /* state == ECS_PIRQ */
- u16 virq; /* state == ECS_VIRQ */
- u32 ipi_vcpu; /* state == ECS_IPI */
+ u16 remote_port;
+ struct domain *remote_dom;
+ } interdomain; /* state == ECS_INTERDOMAIN */
+ u16 pirq; /* state == ECS_PIRQ */
+ u16 virq; /* state == ECS_VIRQ */
} u;
-} event_channel_t;
+};
-int init_event_channels(struct domain *d);
-void destroy_event_channels(struct domain *d);
-int init_vcpu_event_channels(struct vcpu *v);
+int evtchn_init(struct domain *d);
+void evtchn_destroy(struct domain *d);
#define CPUMAP_RUNANYWHERE 0xFFFFFFFF
@@ -109,9 +112,8 @@ struct domain
struct domain *next_in_hashbucket;
/* Event channel information. */
- event_channel_t *event_channel;
- unsigned int max_event_channel;
- spinlock_t event_channel_lock;
+ struct evtchn *evtchn[NR_EVTCHN_BUCKETS];
+ spinlock_t evtchn_lock;
grant_table_t *grant_table;
@@ -153,7 +155,7 @@ struct domain_setup_info
unsigned long symtab_addr;
unsigned long symtab_len;
/* Indicate whether it's xen specific image */
- unsigned int xen_elf_image;
+ char *xen_section_string;
};
extern struct domain idle0_domain;
@@ -215,6 +217,7 @@ struct domain *find_domain_by_id(domid_t dom);
extern void domain_destruct(struct domain *d);
extern void domain_kill(struct domain *d);
extern void domain_shutdown(u8 reason);
+extern void domain_pause_for_debugger(void);
/*
* Mark current domain as crashed. This function returns: the domain is not
diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h
index 73daa385f0..8d5f246ab2 100644
--- a/xen/include/xen/serial.h
+++ b/xen/include/xen/serial.h
@@ -16,8 +16,12 @@ typedef void (*serial_rx_fn)(char, struct cpu_user_regs *);
void serial_set_rx_handler(int handle, serial_rx_fn fn);
/* Number of characters we buffer for a polling receiver. */
-#define RXBUFSZ 32
-#define MASK_RXBUF_IDX(_i) ((_i)&(RXBUFSZ-1))
+#define SERIAL_RXBUFSZ 32
+#define MASK_SERIAL_RXBUF_IDX(_i) ((_i)&(SERIAL_RXBUFSZ-1))
+
+/* Number of characters we buffer for an interrupt-driven transmitter. */
+#define SERIAL_TXBUFSZ 16384
+#define MASK_SERIAL_TXBUF_IDX(_i) ((_i)&(SERIAL_TXBUFSZ-1))
struct uart_driver;
@@ -25,10 +29,17 @@ struct serial_port {
/* Uart-driver parameters. */
struct uart_driver *driver;
void *uart;
+ /* Number of characters the port can hold for transmit. */
+ int tx_fifo_size;
+ /* Transmit data buffer (interrupt-driven uart). */
+ char *txbuf;
+ unsigned int txbufp, txbufc;
+ /* Force synchronous transmit. */
+ int sync;
/* Receiver callback functions (asynchronous receivers). */
serial_rx_fn rx_lo, rx_hi, rx;
/* Receive data buffer (polling receivers). */
- char rxbuf[RXBUFSZ];
+ char rxbuf[SERIAL_RXBUFSZ];
unsigned int rxbufp, rxbufc;
/* Serial I/O is concurrency-safe. */
spinlock_t lock;
@@ -40,9 +51,11 @@ struct uart_driver {
void (*init_postirq)(struct serial_port *);
/* Hook to clean up after Xen bootstrap (before domain 0 runs). */
void (*endboot)(struct serial_port *);
- /* Put a char onto the serial line. */
+ /* Transmit FIFO ready to receive up to @tx_fifo_size characters? */
+ int (*tx_empty)(struct serial_port *);
+ /* Put a character onto the serial line. */
void (*putc)(struct serial_port *, char);
- /* Get a char from the serial line: returns FALSE if no char available. */
+ /* Get a character from the serial line: returns 0 if none available. */
int (*getc)(struct serial_port *, char *);
};
@@ -76,13 +89,26 @@ void serial_puts(int handle, const char *s);
char serial_getc(int handle);
/* Forcibly prevent serial lockup when the system is in a bad way. */
+/* (NB. This also forces an implicit serial_start_sync()). */
void serial_force_unlock(int handle);
+/* Start/end a synchronous region (temporarily disable interrupt-driven tx). */
+void serial_start_sync(int handle);
+void serial_end_sync(int handle);
+
+/* Return number of bytes headroom in transmit buffer. */
+int serial_tx_space(int handle);
+
+/*
+ * Initialisation and helper functions for uart drivers.
+ */
/* Register a uart on serial port @idx (e.g., @idx==0 is COM1). */
void serial_register_uart(int idx, struct uart_driver *driver, void *uart);
-
-/* Driver helper function: process receive work in interrupt context. */
+/* Place the serial port into asynchronous transmit mode. */
+void serial_async_transmit(struct serial_port *port);
+/* Process work in interrupt context. */
void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs);
+void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs);
/*
* Initialisers for individual uart drivers.
diff --git a/xen/include/xen/smp.h b/xen/include/xen/smp.h
index 19e91b0fe0..2004211589 100644
--- a/xen/include/xen/smp.h
+++ b/xen/include/xen/smp.h
@@ -59,7 +59,6 @@ static inline int on_each_cpu(void (*func) (void *info), void *info,
}
extern int ht_per_core;
-extern int opt_noht;
extern volatile unsigned long smp_msg_data;
extern volatile int smp_src_cpu;