diff options
203 files changed, 35545 insertions, 6359 deletions
@@ -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, ®s) ) + { + 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, ®s) ) + { + 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(®s); } else { - regs.entry_vector = (vector == FIRST_DEVICE_VECTOR? - 0 : vector_irq[vector]); + regs.entry_vector = vector; do_IRQ(®s); } 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, + ¤t->domain->shared_info->evtchn_pending[0])) + do_block(); vmx_check_events(current); if (!test_bit(ARCH_VMX_IO_WAIT, ¤t->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, ¤t->vcpu_info->evtchn_pending_sel); + clear_bit(0, ¤t->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)(®s->esp); + esp = (unsigned long)®s->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; |