From aebcff84edd4e51dc2e31bd0df1d1768936ae2a5 Mon Sep 17 00:00:00 2001 From: Fabian Date: Wed, 5 Jul 2017 18:59:48 -0500 Subject: [PATCH] Big squash e72eac2fc A few more sse instructions bdf83e0f0 temp rebase to resolve conflicts 58aa08353 replace all usage of modrm_byte with the set/get fns 7f1dbadf4 move registers to wasm memory 9a0432708 remove stdio inclusion 60f49f735 partial branch port of read_e8 747c51979 partial port of do_div32 8700c3042 remove wasm file from repo c69bc5c91 revert div32 to js ead0195b9 move last_op1 to wasm 16e9a2801 move last_op2 to wasm 4b5e749c8 move last_op_size to wasm 3a02ec98c move last_add_result, last_result, flags_changed to wasm 882b5476b implement add in C 8a8b15e11 move flags to wasm 4667917a9 implement getcf in C 1199537a1 implement adc in C a8a2f81ba implement sub in C 697cb4070 implement sbb in C 1e4e08079 implement inc in C 35259ddc3 implement dec in C 82498a632 implement neg in C 47fe549af copy opsize and reg constants 39c0f07aa implement mul8 in C 443aef4b2 implement imul8 in C afd2ec864 refactor memory accessing from C f937617bc implement mul16 in C af430b023 rewrite reg_* macros 6639f23a7 implement imul16 in C 6c490e88d add wasm build to makefile ea698b8bc refactor modrm_byte access 71899e821 split cpu.c into individual files 00dc878be capitalize flag constants e1ccf9477 remove unused buffer view f0175e480 refactor JS to wasm replacement f52c5f3a6 add assert.h ccf73539e implement imul_reg16 in C 8ae41facd implement do_mul32 in C and port mul32_result to wasm memory 77d3875eb implement do_imul32 in C af1cdc85d implement mul32 in C 820f514e3 implement imul32 in C e165f02e0 implement imul_reg32 in C fdee993e9 implement xadd8 in C 4e5d6f1c2 implement xadd16 in C 1c903565f implement xadd32 in C 1be111a93 implement getaf in C 4c2bc9f43 implement bcd_daa in C 3852cee61 implement bcd_das in C ed68e2777 implement bcd_aad in C b56c17640 implement bcd_aaa in C 5650e48c6 implement bcd_aas in C 99aeb5682 implement and in C 39d2308aa implement or in C c76e59a0b implement xor in C b14b87b95 async wasm instantiation 7f11605bc implement rol8 in C 161c662cf implement rol16 in C 37bf420f6 implement rol32 in C 921f06821 implement rcl8 in C 2f1bf0c2d implement rcl16 in C ad1d56ebe implement rcl32 in C ebcded69e implement ror8 in C 9bc225ff0 implement ror16 in C 403125717 implement ror32 in C 2a21a0896 implement rcr8 in C 80bf2667e implement rcr16 in C f8fe46c47 implement rcr32 in C 95493a272 split error_code flag in call_interrupt_vector a6f19110e export throw_cpu_exception to C dd5d8ce0d export call_interrupt_vector to C 537c08f65 implement raise_exception_with_code to C 8347e787e port instruction_pointer to wasm memory (offset 556) 0e62a7046 port previous_ip to wasm memory (offset 560) c09089e40 implement trigger_gp in C a4f0fed1b implement raise_exception in C 0b41949f4 implement trigger_de in C fc2a568a6 implement div8 in C acc6bbb54 implement idiv8 in C 5a3db2d09 implement div16 in C d77f0d151 Move wasm replacements to a dedicated function 135b19af0 port idtr_size and idtr_offset to wasm (offset 564, 568) 5f0ad7257 port gdtr_size to wasm (offset 572) dc17f7b7a port gdtr_offset to wasm (offset 576) 07876e86f port cr to wasm (offsets 580-608) 50b0213c2 port cpl to wasm (offset 612) 5cea3efcc port page_size_extensions to wasm (offset 616) 89d6fd6e8 port last_virt_eip to wasm (offset 620) 68f4111fd port eip_phys to wasm (offset 624) 73b146319 port last_virt_esp to wasm (offset 628) dbf920ff7 port esp_phys to wasm (offset 632) c05177c5a port sysenter_cs to wasm (offset 636) 63dd72194 port sysenter_esp to wasm (offset 640) 59d8aa686 port sysenter_eip to wasm (offset 644) c5e02dd8b port prefixes to wasm (offset 648) 259ca5d72 port tsc_offset to wasm (offset 652) 62ecc8825 port phys_addr to wasm (offset 656) 188ea275e port phys_addr_high to wasm (offset 660) f458cb2bb port timestamp_counter to wasm (offset 664) 890449fa3 port sreg to wasm (offsets 668-682) ebe65e6f3 port dreg to wasm (offsets 684-716) df6553220 port fw_value to wasm (offset 720) 0cd3b78ea port segment isnull, offsets and limits to wasm (offset 724-796) 4fb0ecebc Turn off verbose logging b55bc2cae fix unzip command in readme f5b897bc3 fix docs links to api.md ba03a7b4e Remove outdated test 930483ac4 Add elf parser 6597973c8 Shift addresses correctly 189903a7d Add comment to lss #ud 0a46ec4a9 Fix iret #gp error code (Windows XP) 28986b7ee Lower TIME_PER_FRAME 4ce987d71 Add acpi PM timer 43c31ea99 Handle access to debug registers when cr4.DE is set 283305215 Add run_hardware_timers c617846f2 A few more assertions for IO ports 32e7444f4 Make Closure Compiler happy a661c408c Buffer get written blocks 9306fd080 Add debug panel (#108) 795ff1a50 More complete APIC and IOAPIC implementation (#86) 4a4253956 Makefile: Refactor using addprefix ac1009331 More VGA logging 18ee4ecde Only check irqs when irr changed cdbc55e03 Add multiboot image loading, currently only supporting kvm-unit-test (#95, #129) 3ee9a1c85 Disable advanced optimisations for libv86. Fixes tests 12df5c76d Import kvm-unit-test into this repo 249f9ba37 Add kvm-unit-test (#129) 99b824f49 Mention than FreeBSD works 91fe8a3a1 ATA flush cache 0af630d99 PCI: Fix command/status 30fc01491 Rename function 569d1f3d6 APIC version write df376842c Split movsx/movzx into 16/32 bit versions dda21c5e2 CR3 ignored bits b1f039211 Implement #NP (kvm-unit-test) 57dd8358f Minor (style and logging) 17fd08e29 Less incomplete task switch implementation 797fd5bd8 cpuid level 5 24e66a43f Missing parameter a679829f0 PIC logging e68ea4573 Don't create new arrays in reset(), set to 0 instead 550e55186 Update readme regarding Arch Linux 3b565e54e Use local kolibriOS image on https. Temporary workaround for #141 1a0f804d6 Fix restoring state b397f1934 Leave ACPI disabled, fixes #151 83db7e871 add note about range header in SimpleHTTPServer a20794873 update linux 9p image mount hook doc 88e65312e Improve fprem instruction implementation to update FPU status word's condition codes 9844ef433 Remove comments from fprem instruction a429bbe73 Disable Oberon tests ba3092060 Add kvm-unit-test to travis CI (#129) 6a8813567 Travis fix 46da581de Travis fix (gcc-multilib) c78dcb105 Travis fix (switch to Trusty) dbc2ab704 Reduce memory for kvm-unit-test 2c6bd1889 Fix multiboot images smaller than 8192 bytes f5dead1f5 expand Archlinux doc with scripted install example a34cd08d9 fix raw RangeHTTPServer link to wget 35f9923fb change state to initial state in archlinux doc 2aed2636f extend archlinux doc with networking example 2aa8f3722 First entry in LDT is valid (#145) 7492c8d3c Basic 16-bit tss implementation. Fixes #127. Fixes #145. Fixes windows 3.0 098d84a02 Minor b9c93f8c6 Proper CD IDE DMA implementation, fixes #147, fixes #107 9b9123d6e Improved file loading in nodejs, simplify tests 40ee13f9b Add dummy screen a58bd7419 Fix test: Check if disk image is missing c8a7fd8dc Reenable Oberon tests bd63f49ad Minor: Semicolons d10f0b7ff Implement elcr in legacy pic aed5b441a Change virtio irq to 10, old one collides with ps2 mouse b93519c8a PS2 minor changes 25e64afa6 Update build command 5377f9457 Add maximum debug to emscripten build dac6ce6a4 Reduce logging f44f3b467 Convert argument for call from C e1808f222 Raise when C assertion fails bb6d38e6e Add cpu imports, in order to be called from C f3f909d5d Port constants 7bab32657 Port protected_mode, is_32 and stack_size_32 ee02cdd86 Port the main instruction table fe15a6cc0 fixes for prop mangling and closure type checks 11935fcc0 remove redundant pointer timestamp_counter a7021eb20 port read_imm8 to wasm f7a432691 strip useless brackets 90c7435f8 Reduce logging 047f0f405 Port a few small functions df293f8d4 Port get_seg* 37774b0d1 Remove useless comparison 47f7a89b9 Port instructions with 0F prefix 8a822bae4 Remove useless brackets again (lost in rebase) and use correct quote style 2f6e90023 port read_imm{8s,16,32s} 8f5ce2dbf remove redundant declaration 5785195ce port read_write_e8 and write_e8 5fa1a15af Make instruction functions static 4a2336d12 Port jmp_rel16, jmpcc8, jmpcc16, jmpcc32 8633cfad9 Port set_e* f024aec98 Port read_imm* aliases d39cb4d7b Port read_g* fa838388d Port read_e* 2f1c41d93 Port write_g* 43157269f Port logging and assertions ac2c937d5 Port read_write_e{16,32} and write_e{16,32} eeb7340c2 Port safe_read* 54d89b3d1 Port safe_write* c5557a227 Port diverged, branch_taken, branch_taken e3bb35939 Fix loading in node 00f6b2638 Remove useless `| 0` and `>> 0`. Use unsigned comparison 70fa762e3 Optimise read_imm8 4487917fd Port a20_enabled to wasm a8f16cb20 Fix a20_enabled booleans for closure compiler 95145ec53 Move mul32 result so offsets are reserved in order (and mention length) a3264e132 Move global pointer reservations to its own header file and make sure all .c files include all headers 78c779cbd Port FPU's stack_empty to wasm (offset 816) 4f25fc4b7 Port FPU's safe_tag_word function to wasm 8589a1c21 Port emms instruction to wasm feb5079c7 port memory_size to wasm (offset 812) 262559291 port in_mapped_range to C 8a72ad56c Port a20_enabled to wasm ce393e211 [wip] port read8 e936b49d1 port read8 to wasm 80cf98a3a port read16 to wasm 3a423372b port read_aligned16 to wasm 4725e1bac port read32s to wasm 60815b748 port write8 to wasm 5d64b295b port write16 to wasm 5fc83a791 port write32 to wasm 7148b6804 port push{16,32} to wasm 697222408 port pusha{16,32} to wasm 6adb5be15 Port paging, tlb_info, tlb_info_global and tlb_data c8ab560af Port translate_address_* 8bb3e4285 Port get_eflags and getzf c7a70a79b Port getsf 0d35dd621 Port getof e4d3ec252 Port getpf 9aacf2cfe Port test_* (branch conditions) 9cb64f970 Add v86-debug.wasm build target 37012099d Call mmap_* functions statically 8fb9da298 Add missing voids 0bcbe7ef4 Silence warning 6fb9db2fd Simplify translate_address_read and translate_address_write 28b66ca6b Optimized versions of resolve_modrm32 and resolve_sib cf4aea666 Silence warning b4915a2d2 Port adjust_stack_reg, get_stack_pointer and pop32s 7ddc14948 Optimised memory reads and writes --- .gitignore | 3 +- Makefile | 32 + src/arith.js | 583 ++++--- src/browser/lib.js | 36 + src/browser/starter.js | 189 +- src/config.js | 2 +- src/cpu.js | 1062 ++++++------ src/debug.js | 30 +- src/externs.js | 1 + src/fpu.js | 67 +- src/instructions.js | 818 +++++---- src/io.js | 4 +- src/ioapic.js | 2 +- src/log.js | 21 + src/main.js | 9 +- src/memory.js | 22 +- src/misc_instr.js | 76 +- src/native/all.c | 19 + src/native/arith.c | 825 +++++++++ src/native/const.h | 159 ++ src/native/cpu.c | 572 ++++++ src/native/fpu.c | 20 + src/native/global_pointers.h | 69 + src/native/instructions.c | 3171 ++++++++++++++++++++++++++++++++++ src/native/instructions_0f.c | 3155 +++++++++++++++++++++++++++++++++ src/native/log.c | 13 + src/native/memory.c | 112 ++ src/native/misc_instr.c | 232 +++ src/native/modrm.c | 230 +++ src/pci.js | 5 + src/string.js | 248 +-- src/virtio.js | 2 + tests/kvm-unit-tests/run.js | 2 +- 33 files changed, 10494 insertions(+), 1297 deletions(-) create mode 100644 src/native/all.c create mode 100644 src/native/arith.c create mode 100644 src/native/const.h create mode 100644 src/native/cpu.c create mode 100644 src/native/fpu.c create mode 100644 src/native/global_pointers.h create mode 100644 src/native/instructions.c create mode 100644 src/native/instructions_0f.c create mode 100644 src/native/log.c create mode 100644 src/native/memory.c create mode 100644 src/native/misc_instr.c create mode 100644 src/native/modrm.c diff --git a/.gitignore b/.gitignore index 70f4645f..8118bc7f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,8 +9,9 @@ closure-compiler/ images/ *.bak *.orig +*.wasm *.o *.bin *.img *.fixture -*.fuse_hidden* \ No newline at end of file +*.fuse_hidden* diff --git a/Makefile b/Makefile index 1dabe9cd..f22d696e 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ NASM_TEST_DIR=./tests/nasm all: build/v86_all.js browser: build/v86_all.js +wasm: build/v86.wasm # Used for nodejs builds and in order to profile code. # `debug` gives identifiers a readable name, make sure it doesn't have any side effects. @@ -123,11 +124,42 @@ build/libv86.js: $(CLOSURE) src/*.js lib/*.js src/browser/*.js ls -lh build/libv86.js +build/v86.wasm: src/native/*.c src/native/*.h + mkdir -p build + -ls -lh build/v86.wasm + # --llvm-opts 3 + # -Wno-extra-semi + # EMCC_WASM_BACKEND=1 + emcc src/native/all.c \ + -Wall -Wpedantic -Wextra \ + -DDEBUG=false \ + -DNDEBUG \ + -Wno-bitwise-op-parentheses -Wno-gnu-binary-literal \ + -fcolor-diagnostics \ + -fwrapv \ + --llvm-opts 3 \ + -O3 \ + -g4 \ + -s WASM=1 -s SIDE_MODULE=1 -o build/v86.wasm + ls -lh build/v86.wasm + +build/v86-debug.wasm: src/native/*.c src/native/*.h + emcc src/native/all.c \ + -Wall -Wpedantic -Wextra \ + -Wno-bitwise-op-parentheses -Wno-gnu-binary-literal \ + -fcolor-diagnostics \ + -fwrapv \ + -Os \ + -g4 \ + -s WASM=1 -s SIDE_MODULE=1 -o build/v86-debug.wasm + ls -lh build/v86-debug.wasm + clean: -rm build/libv86.js -rm build/v86_all.js -rm build/libv86.js.map -rm build/v86_all.js.map + -rm build/v86.wasm $(MAKE) -C $(NASM_TEST_DIR) clean run: diff --git a/src/arith.js b/src/arith.js index 2bab9b6f..5334af8a 100644 --- a/src/arith.js +++ b/src/arith.js @@ -45,52 +45,52 @@ CPU.prototype.add = function(dest_operand, source_operand, op_size) { //if(this.safe_read32s(this.instruction_pointer + 1) === 0 && this.safe_read32s(this.instruction_pointer + 5) === 0) throw "0000000"; - this.last_op1 = dest_operand; - this.last_op2 = source_operand; - this.last_add_result = this.last_result = dest_operand + source_operand | 0; + this.last_op1[0] = dest_operand; + this.last_op2[0] = source_operand; + this.last_add_result[0] = this.last_result[0] = dest_operand + source_operand | 0; - this.last_op_size = op_size; - this.flags_changed = flags_all; + this.last_op_size[0] = op_size; + this.flags_changed[0] = flags_all; - return this.last_result; + return this.last_result[0]; } CPU.prototype.adc = function(dest_operand, source_operand, op_size) { var cf = this.getcf(); - this.last_op1 = dest_operand; - this.last_op2 = source_operand; - this.last_add_result = this.last_result = (dest_operand + source_operand | 0) + cf | 0; + this.last_op1[0] = dest_operand; + this.last_op2[0] = source_operand; + this.last_add_result[0] = this.last_result[0] = (dest_operand + source_operand | 0) + cf | 0; - this.last_op_size = op_size; - this.flags_changed = flags_all; + this.last_op_size[0] = op_size; + this.flags_changed[0] = flags_all; - return this.last_result; + return this.last_result[0]; } CPU.prototype.sub = function(dest_operand, source_operand, op_size) { - this.last_add_result = dest_operand; - this.last_op2 = source_operand; - this.last_op1 = this.last_result = dest_operand - source_operand | 0; + this.last_add_result[0] = dest_operand; + this.last_op2[0] = source_operand; + this.last_op1[0] = this.last_result[0] = dest_operand - source_operand | 0; - this.last_op_size = op_size; - this.flags_changed = flags_all; + this.last_op_size[0] = op_size; + this.flags_changed[0] = flags_all; - return this.last_result; + return this.last_result[0]; } CPU.prototype.sbb = function(dest_operand, source_operand, op_size) { var cf = this.getcf(); - this.last_add_result = dest_operand; - this.last_op2 = source_operand; - this.last_op1 = this.last_result = dest_operand - source_operand - cf | 0; - this.last_op_size = op_size; + this.last_add_result[0] = dest_operand; + this.last_op2[0] = source_operand; + this.last_op1[0] = this.last_result[0] = dest_operand - source_operand - cf | 0; + this.last_op_size[0] = op_size; - this.flags_changed = flags_all; + this.flags_changed[0] = flags_all; - return this.last_result; + return this.last_result[0]; } /* @@ -107,28 +107,28 @@ CPU.prototype.dec32 = function(dest) { return this.dec(dest, OPSIZE_32); } CPU.prototype.inc = function(dest_operand, op_size) { - this.flags = (this.flags & ~1) | this.getcf(); - this.last_op1 = dest_operand; - this.last_op2 = 1; - this.last_add_result = this.last_result = dest_operand + 1 | 0; - this.last_op_size = op_size; + this.flags[0] = (this.flags[0] & ~1) | this.getcf(); + this.last_op1[0] = dest_operand; + this.last_op2[0] = 1; + this.last_add_result[0] = this.last_result[0] = dest_operand + 1 | 0; + this.last_op_size[0] = op_size; - this.flags_changed = flags_all & ~1; + this.flags_changed[0] = flags_all & ~1; - return this.last_result; + return this.last_result[0]; } CPU.prototype.dec = function(dest_operand, op_size) { - this.flags = (this.flags & ~1) | this.getcf(); - this.last_add_result = dest_operand; - this.last_op2 = 1; - this.last_op1 = this.last_result = dest_operand - 1 | 0; - this.last_op_size = op_size; + this.flags[0] = (this.flags[0] & ~1) | this.getcf(); + this.last_add_result[0] = dest_operand; + this.last_op2[0] = 1; + this.last_op1[0] = this.last_result[0] = dest_operand - 1 | 0; + this.last_op_size[0] = op_size; - this.flags_changed = flags_all & ~1; + this.flags_changed[0] = flags_all & ~1; - return this.last_result; + return this.last_result[0]; } @@ -141,17 +141,16 @@ CPU.prototype.neg32 = function(dest) { return this.neg(dest, OPSIZE_32); } CPU.prototype.neg = function(dest_operand, op_size) { - this.last_op1 = this.last_result = -dest_operand | 0; + this.last_op1[0] = this.last_result[0] = -dest_operand | 0; - this.flags_changed = flags_all; - this.last_add_result = 0; - this.last_op2 = dest_operand; - this.last_op_size = op_size; + this.flags_changed[0] = flags_all; + this.last_add_result[0] = 0; + this.last_op2[0] = dest_operand; + this.last_op_size[0] = op_size; - return this.last_result; + return this.last_result[0]; } - /* * mul, imul, div, idiv * @@ -165,19 +164,19 @@ CPU.prototype.mul8 = function(source_operand) var result = source_operand * this.reg8[reg_al]; this.reg16[reg_ax] = result; - this.last_result = result & 0xFF; - this.last_op_size = OPSIZE_8; + this.last_result[0] = result & 0xFF; + this.last_op_size[0] = OPSIZE_8; if(result < 0x100) { - this.flags = this.flags & ~1 & ~flag_overflow; + this.flags[0] = this.flags[0] & ~1 & ~flag_overflow; } else { - this.flags = this.flags | 1 | flag_overflow; + this.flags[0] = this.flags[0] | 1 | flag_overflow; } - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; } CPU.prototype.imul8 = function(source_operand) @@ -185,18 +184,18 @@ CPU.prototype.imul8 = function(source_operand) var result = source_operand * this.reg8s[reg_al]; this.reg16[reg_ax] = result; - this.last_result = result & 0xFF; - this.last_op_size = OPSIZE_8; + this.last_result[0] = result & 0xFF; + this.last_op_size[0] = OPSIZE_8; if(result > 0x7F || result < -0x80) { - this.flags = this.flags | 1 | flag_overflow; + this.flags[0] = this.flags[0] | 1 | flag_overflow; } else { - this.flags = this.flags & ~1 & ~flag_overflow; + this.flags[0] = this.flags[0] & ~1 & ~flag_overflow; } - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; } CPU.prototype.mul16 = function(source_operand) @@ -208,18 +207,18 @@ CPU.prototype.mul16 = function(source_operand) this.reg16[reg_ax] = result; this.reg16[reg_dx] = high_result; - this.last_result = result & 0xFFFF; - this.last_op_size = OPSIZE_16; + this.last_result[0] = result & 0xFFFF; + this.last_op_size[0] = OPSIZE_16; if(high_result === 0) { - this.flags &= ~1 & ~flag_overflow; + this.flags[0] &= ~1 & ~flag_overflow; } else { - this.flags |= 1 | flag_overflow; + this.flags[0] |= 1 | flag_overflow; } - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; } /* @@ -233,18 +232,18 @@ CPU.prototype.imul16 = function(source_operand) this.reg16[reg_ax] = result; this.reg16[reg_dx] = result >> 16; - this.last_result = result & 0xFFFF; - this.last_op_size = OPSIZE_16; + this.last_result[0] = result & 0xFFFF; + this.last_op_size[0] = OPSIZE_16; if(result > 0x7FFF || result < -0x8000) { - this.flags |= 1 | flag_overflow; + this.flags[0] |= 1 | flag_overflow; } else { - this.flags &= ~1 & ~flag_overflow; + this.flags[0] &= ~1 & ~flag_overflow; } - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; } /* @@ -259,18 +258,18 @@ CPU.prototype.imul_reg16 = function(operand1, operand2) var result = operand1 * operand2; - this.last_result = result & 0xFFFF; - this.last_op_size = OPSIZE_16; + this.last_result[0] = result & 0xFFFF; + this.last_op_size[0] = OPSIZE_16; if(result > 0x7FFF || result < -0x8000) { - this.flags |= 1 | flag_overflow; + this.flags[0] |= 1 | flag_overflow; } else { - this.flags &= ~1 & ~flag_overflow; + this.flags[0] &= ~1 & ~flag_overflow; } - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; return result; } @@ -290,6 +289,14 @@ CPU.prototype.do_mul32 = function(a, b) return this.mul32_result; }; +//XXX: do_mul32 returns a typedarray object which we can't do from a wasm +//function, so we rewrite it here differently from other ports. Would +//change this when callers of do_mul32 are rewritten in wasm. +CPU.prototype.do_mul32 = function(a, b) { + this.wm.funcs['_do_mul32'](a, b); + return this.mul32_result; +}; + CPU.prototype.do_imul32 = function(a, b) { var is_neg = false; @@ -309,6 +316,12 @@ CPU.prototype.do_imul32 = function(a, b) return result; } +//XXX: same issue as do_mul32. rewrite after callers are ported to wasm +CPU.prototype.do_imul32 = function(a, b) { + this.wm.funcs['_do_imul32'](a, b); + return this.mul32_result; +}; + CPU.prototype.mul32 = function(source_operand) { var dest_operand = this.reg32s[reg_eax]; @@ -318,18 +331,18 @@ CPU.prototype.mul32 = function(source_operand) this.reg32s[reg_eax] = result[0]; this.reg32s[reg_edx] = result[1]; - this.last_result = result[0]; - this.last_op_size = OPSIZE_32; + this.last_result[0] = result[0]; + this.last_op_size[0] = OPSIZE_32; if(result[1] === 0) { - this.flags &= ~1 & ~flag_overflow; + this.flags[0] &= ~1 & ~flag_overflow; } else { - this.flags |= 1 | flag_overflow; + this.flags[0] |= 1 | flag_overflow; } - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; //console.log(h(source_operand >>> 0, 8) + " * " + h(dest_operand >>> 0, 8)); //console.log("= " + h(this.reg32[reg_edx], 8) + ":" + h(this.reg32[reg_eax], 8)); @@ -346,18 +359,18 @@ CPU.prototype.imul32 = function(source_operand) this.reg32s[reg_eax] = result[0]; this.reg32s[reg_edx] = result[1]; - this.last_result = result[0]; - this.last_op_size = OPSIZE_32; + this.last_result[0] = result[0]; + this.last_op_size[0] = OPSIZE_32; if(result[1] === (result[0] >> 31)) { - this.flags &= ~1 & ~flag_overflow; + this.flags[0] &= ~1 & ~flag_overflow; } else { - this.flags |= 1 | flag_overflow; + this.flags[0] |= 1 | flag_overflow; } - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; //console.log(target_operand + " * " + source_operand); //console.log("= " + h(this.reg32[reg_edx]) + " " + h(this.reg32[reg_eax])); @@ -375,18 +388,18 @@ CPU.prototype.imul_reg32 = function(operand1, operand2) var result = this.do_imul32(operand1, operand2); - this.last_result = result[0]; - this.last_op_size = OPSIZE_32; + this.last_result[0] = result[0]; + this.last_op_size[0] = OPSIZE_32; if(result[1] === (result[0] >> 31)) { - this.flags &= ~1 & ~flag_overflow; + this.flags[0] &= ~1 & ~flag_overflow; } else { - this.flags |= 1 | flag_overflow; + this.flags[0] |= 1 | flag_overflow; } - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; return result[0]; @@ -502,7 +515,7 @@ CPU.prototype.do_div32 = function(div_low, div_high, quot) this.trigger_de(); } - var result = 0; + var result = 0; if(div_high > 0x100000) { @@ -545,6 +558,7 @@ CPU.prototype.do_div32 = function(div_low, div_high, quot) CPU.prototype.div32 = function(source_operand) { + source_operand >>>= 0; dbg_assert(source_operand >= 0 && source_operand <= 0xffffffff); var dest_operand_low = this.reg32[reg_eax], @@ -666,23 +680,23 @@ CPU.prototype.bcd_daa = function() old_cf = this.getcf(), old_af = this.getaf(); - this.flags &= ~1 & ~flag_adjust + this.flags[0] &= ~1 & ~flag_adjust if((old_al & 0xF) > 9 || old_af) { this.reg8[reg_al] += 6; - this.flags |= flag_adjust; + this.flags[0] |= flag_adjust; } if(old_al > 0x99 || old_cf) { this.reg8[reg_al] += 0x60; - this.flags |= 1; + this.flags[0] |= 1; } - this.last_result = this.reg8[reg_al]; - this.last_op_size = OPSIZE_8; - this.last_op1 = this.last_op2 = 0; - this.flags_changed = flags_all & ~1 & ~flag_adjust & ~flag_overflow; + this.last_result[0] = this.reg8[reg_al]; + this.last_op_size[0] = OPSIZE_8; + this.last_op1[0] = this.last_op2[0] = 0; + this.flags_changed[0] = flags_all & ~1 & ~flag_adjust & ~flag_overflow; } CPU.prototype.bcd_das = function() @@ -692,29 +706,29 @@ CPU.prototype.bcd_das = function() var old_al = this.reg8[reg_al], old_cf = this.getcf(); - this.flags &= ~1; + this.flags[0] &= ~1; if((old_al & 0xF) > 9 || this.getaf()) { this.reg8[reg_al] -= 6; - this.flags |= flag_adjust; - this.flags = this.flags & ~1 | old_cf | (old_al < 6); + this.flags[0] |= flag_adjust; + this.flags[0] = this.flags[0] & ~1 | old_cf | (old_al < 6); } else { - this.flags &= ~flag_adjust; + this.flags[0] &= ~flag_adjust; } if(old_al > 0x99 || old_cf) { this.reg8[reg_al] -= 0x60; - this.flags |= 1; + this.flags[0] |= 1; } - this.last_result = this.reg8[reg_al]; - this.last_op_size = OPSIZE_8; - this.last_op1 = this.last_op2 = 0; - this.flags_changed = flags_all & ~1 & ~flag_adjust & ~flag_overflow; + this.last_result[0] = this.reg8[reg_al]; + this.last_op_size[0] = OPSIZE_8; + this.last_op1[0] = this.last_op2[0] = 0; + this.flags_changed[0] = flags_all & ~1 & ~flag_adjust & ~flag_overflow; } CPU.prototype.bcd_aam = function(imm8) @@ -732,10 +746,10 @@ CPU.prototype.bcd_aam = function(imm8) this.reg8[reg_ah] = temp / imm8; this.reg8[reg_al] = temp % imm8; - this.last_result = this.reg8[reg_al]; + this.last_result[0] = this.reg8[reg_al]; - this.flags_changed = flags_all & ~1 & ~flag_adjust & ~flag_overflow; - this.flags &= ~1 & ~flag_adjust & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_adjust & ~flag_overflow; + this.flags[0] &= ~1 & ~flag_adjust & ~flag_overflow; } } @@ -745,16 +759,16 @@ CPU.prototype.bcd_aad = function(imm8) // ascii adjust before division var result = this.reg8[reg_al] + this.reg8[reg_ah] * imm8; - this.last_result = result & 0xFF; - this.reg16[reg_ax] = this.last_result; - this.last_op_size = OPSIZE_8; + this.last_result[0] = result & 0xFF; + this.reg16[reg_ax] = this.last_result[0]; + this.last_op_size[0] = OPSIZE_8; - this.flags_changed = flags_all & ~1 & ~flag_adjust & ~flag_overflow; - this.flags &= ~1 & ~flag_adjust & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_adjust & ~flag_overflow; + this.flags[0] &= ~1 & ~flag_adjust & ~flag_overflow; if(result > 0xFFFF) { - this.flags |= 1; + this.flags[0] |= 1; } } @@ -765,15 +779,15 @@ CPU.prototype.bcd_aaa = function() { this.reg16[reg_ax] += 6; this.reg8[reg_ah] += 1; - this.flags |= flag_adjust | 1; + this.flags[0] |= flag_adjust | 1; } else { - this.flags &= ~flag_adjust & ~1; + this.flags[0] &= ~flag_adjust & ~1; } this.reg8[reg_al] &= 0xF; - this.flags_changed &= ~flag_adjust & ~1; + this.flags_changed[0] &= ~flag_adjust & ~1; }; @@ -784,15 +798,15 @@ CPU.prototype.bcd_aas = function() { this.reg16[reg_ax] -= 6; this.reg8[reg_ah] -= 1; - this.flags |= flag_adjust | 1; + this.flags[0] |= flag_adjust | 1; } else { - this.flags &= ~flag_adjust & ~1; + this.flags[0] &= ~flag_adjust & ~1; } this.reg8[reg_al] &= 0xF; - this.flags_changed &= ~flag_adjust & ~1; + this.flags_changed[0] &= ~flag_adjust & ~1; } @@ -826,35 +840,35 @@ CPU.prototype.xor32 = function(dest, src) { return this.xor(dest, src, OPSIZE_32 CPU.prototype.and = function(dest_operand, source_operand, op_size) { - this.last_result = dest_operand & source_operand; + this.last_result[0] = dest_operand & source_operand; - this.last_op_size = op_size; - this.flags &= ~1 & ~flag_overflow & ~flag_adjust; - this.flags_changed = flags_all & ~1 & ~flag_overflow & ~flag_adjust; + this.last_op_size[0] = op_size; + this.flags[0] &= ~1 & ~flag_overflow & ~flag_adjust; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow & ~flag_adjust; - return this.last_result; + return this.last_result[0]; } CPU.prototype.or = function(dest_operand, source_operand, op_size) { - this.last_result = dest_operand | source_operand; + this.last_result[0] = dest_operand | source_operand; - this.last_op_size = op_size; - this.flags &= ~1 & ~flag_overflow & ~flag_adjust; - this.flags_changed = flags_all & ~1 & ~flag_overflow & ~flag_adjust; + this.last_op_size[0] = op_size; + this.flags[0] &= ~1 & ~flag_overflow & ~flag_adjust; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow & ~flag_adjust; - return this.last_result; + return this.last_result[0]; } CPU.prototype.xor = function(dest_operand, source_operand, op_size) { - this.last_result = dest_operand ^ source_operand; + this.last_result[0] = dest_operand ^ source_operand; - this.last_op_size = op_size; - this.flags &= ~1 & ~flag_overflow & ~flag_adjust; - this.flags_changed = flags_all & ~1 & ~flag_overflow & ~flag_adjust; + this.last_op_size[0] = op_size; + this.flags[0] &= ~1 & ~flag_overflow & ~flag_adjust; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow & ~flag_adjust; - return this.last_result; + return this.last_result[0]; } @@ -872,8 +886,8 @@ CPU.prototype.rol8 = function(dest_operand, count) var result = dest_operand << count | dest_operand >> (8 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result & 1) | (result << 11 ^ result << 4) & flag_overflow; @@ -890,8 +904,8 @@ CPU.prototype.rol16 = function(dest_operand, count) var result = dest_operand << count | dest_operand >> (16 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result & 1) | (result << 11 ^ result >> 4) & flag_overflow; @@ -907,8 +921,8 @@ CPU.prototype.rol32 = function(dest_operand, count) var result = dest_operand << count | dest_operand >>> (32 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result & 1) | (result << 11 ^ result >> 20) & flag_overflow; @@ -925,8 +939,8 @@ CPU.prototype.rcl8 = function(dest_operand, count) var result = dest_operand << count | this.getcf() << (count - 1) | dest_operand >> (9 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result >> 8 & 1) | (result << 3 ^ result << 4) & flag_overflow; @@ -943,8 +957,8 @@ CPU.prototype.rcl16 = function(dest_operand, count) var result = dest_operand << count | this.getcf() << (count - 1) | dest_operand >> (17 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result >> 16 & 1) | (result >> 5 ^ result >> 4) & flag_overflow; @@ -965,9 +979,9 @@ CPU.prototype.rcl32 = function(dest_operand, count) result |= dest_operand >>> (33 - count); } - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) | (dest_operand >>> (32 - count) & 1); - this.flags |= (this.flags << 11 ^ result >> 20) & flag_overflow; + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >>> (32 - count) & 1); + this.flags[0] |= (this.flags[0] << 11 ^ result >> 20) & flag_overflow; return result; } @@ -982,8 +996,8 @@ CPU.prototype.ror8 = function(dest_operand, count) count &= 7; var result = dest_operand >> count | dest_operand << (8 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result >> 7 & 1) | (result << 4 ^ result << 5) & flag_overflow; @@ -1000,8 +1014,8 @@ CPU.prototype.ror16 = function(dest_operand, count) count &= 15; var result = dest_operand >> count | dest_operand << (16 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result >> 15 & 1) | (result >> 4 ^ result >> 3) & flag_overflow; @@ -1017,8 +1031,8 @@ CPU.prototype.ror32 = function(dest_operand, count) var result = dest_operand >>> count | dest_operand << (32 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result >> 31 & 1) | (result >> 20 ^ result >> 19) & flag_overflow; @@ -1035,8 +1049,8 @@ CPU.prototype.rcr8 = function(dest_operand, count) var result = dest_operand >> count | this.getcf() << (8 - count) | dest_operand << (9 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result >> 8 & 1) | (result << 4 ^ result << 5) & flag_overflow; @@ -1053,8 +1067,8 @@ CPU.prototype.rcr16 = function(dest_operand, count) var result = dest_operand >> count | this.getcf() << (16 - count) | dest_operand << (17 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result >> 16 & 1) | (result >> 4 ^ result >> 3) & flag_overflow; @@ -1075,8 +1089,8 @@ CPU.prototype.rcr32 = function(dest_operand, count) result |= dest_operand << (33 - count); } - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1) | (result >> 20 ^ result >> 19) & flag_overflow; @@ -1090,15 +1104,15 @@ CPU.prototype.shl8 = function(dest_operand, count) return dest_operand; } - this.last_result = dest_operand << count; + this.last_result[0] = dest_operand << count; - this.last_op_size = OPSIZE_8; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) - | (this.last_result >> 8 & 1) - | (this.last_result << 3 ^ this.last_result << 4) & flag_overflow; + this.last_op_size[0] = OPSIZE_8; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) + | (this.last_result[0] >> 8 & 1) + | (this.last_result[0] << 3 ^ this.last_result[0] << 4) & flag_overflow; - return this.last_result; + return this.last_result[0]; } CPU.prototype.shl16 = function(dest_operand, count) @@ -1108,15 +1122,15 @@ CPU.prototype.shl16 = function(dest_operand, count) return dest_operand; } - this.last_result = dest_operand << count; + this.last_result[0] = dest_operand << count; - this.last_op_size = OPSIZE_16; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) - | (this.last_result >> 16 & 1) - | (this.last_result >> 5 ^ this.last_result >> 4) & flag_overflow; + this.last_op_size[0] = OPSIZE_16; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) + | (this.last_result[0] >> 16 & 1) + | (this.last_result[0] >> 5 ^ this.last_result[0] >> 4) & flag_overflow; - return this.last_result; + return this.last_result[0]; } CPU.prototype.shl32 = function(dest_operand, count) @@ -1126,15 +1140,15 @@ CPU.prototype.shl32 = function(dest_operand, count) return dest_operand; } - this.last_result = dest_operand << count; + this.last_result[0] = dest_operand << count; - this.last_op_size = OPSIZE_32; - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.last_op_size[0] = OPSIZE_32; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; // test this - this.flags = (this.flags & ~1 & ~flag_overflow) | (dest_operand >>> (32 - count) & 1); - this.flags |= ((this.flags & 1) ^ (this.last_result >> 31 & 1)) << 11 & flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >>> (32 - count) & 1); + this.flags[0] |= ((this.flags[0] & 1) ^ (this.last_result[0] >> 31 & 1)) << 11 & flag_overflow; - return this.last_result; + return this.last_result[0]; } CPU.prototype.shr8 = function(dest_operand, count) @@ -1144,15 +1158,15 @@ CPU.prototype.shr8 = function(dest_operand, count) return dest_operand; } - this.last_result = dest_operand >> count; + this.last_result[0] = dest_operand >> count; - this.last_op_size = OPSIZE_8; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.last_op_size[0] = OPSIZE_8; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1) | (dest_operand >> 7 & 1) << 11 & flag_overflow; - return this.last_result; + return this.last_result[0]; } CPU.prototype.shr16 = function(dest_operand, count) @@ -1162,15 +1176,15 @@ CPU.prototype.shr16 = function(dest_operand, count) return dest_operand; } - this.last_result = dest_operand >> count; + this.last_result[0] = dest_operand >> count; - this.last_op_size = OPSIZE_16; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.last_op_size[0] = OPSIZE_16; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1) | (dest_operand >> 4) & flag_overflow; - return this.last_result; + return this.last_result[0]; } CPU.prototype.shr32 = function(dest_operand, count) @@ -1180,15 +1194,15 @@ CPU.prototype.shr32 = function(dest_operand, count) return dest_operand; } - this.last_result = dest_operand >>> count; + this.last_result[0] = dest_operand >>> count; - this.last_op_size = OPSIZE_32; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.last_op_size[0] = OPSIZE_32; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >>> (count - 1) & 1) | (dest_operand >> 20) & flag_overflow; - return this.last_result; + return this.last_result[0]; } CPU.prototype.sar8 = function(dest_operand, count) @@ -1200,20 +1214,20 @@ CPU.prototype.sar8 = function(dest_operand, count) if(count < 8) { - this.last_result = dest_operand << 24 >> count + 24; + this.last_result[0] = dest_operand << 24 >> count + 24; // of is zero - this.flags = (this.flags & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1); + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1); } else { - this.last_result = dest_operand << 24 >> 31; - this.flags = (this.flags & ~1 & ~flag_overflow) | (this.last_result & 1); + this.last_result[0] = dest_operand << 24 >> 31; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (this.last_result[0] & 1); } - this.last_op_size = OPSIZE_8; - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.last_op_size[0] = OPSIZE_8; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; - return this.last_result; + return this.last_result[0]; } CPU.prototype.sar16 = function(dest_operand, count) @@ -1225,19 +1239,19 @@ CPU.prototype.sar16 = function(dest_operand, count) if(count < 16) { - this.last_result = dest_operand << 16 >> count + 16; - this.flags = (this.flags & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1); + this.last_result[0] = dest_operand << 16 >> count + 16; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1); } else { - this.last_result = dest_operand << 16 >> 31; - this.flags = (this.flags & ~1 & ~flag_overflow) | (this.last_result & 1); + this.last_result[0] = dest_operand << 16 >> 31; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (this.last_result[0] & 1); } - this.last_op_size = OPSIZE_16; - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.last_op_size[0] = OPSIZE_16; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; - return this.last_result; + return this.last_result[0]; } CPU.prototype.sar32 = function(dest_operand, count) @@ -1247,13 +1261,13 @@ CPU.prototype.sar32 = function(dest_operand, count) return dest_operand; } - this.last_result = dest_operand >> count; + this.last_result[0] = dest_operand >> count; - this.last_op_size = OPSIZE_32; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) | (dest_operand >>> (count - 1) & 1); + this.last_op_size[0] = OPSIZE_32; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >>> (count - 1) & 1); - return this.last_result; + return this.last_result[0]; } @@ -1266,20 +1280,20 @@ CPU.prototype.shrd16 = function(dest_operand, source_operand, count) if(count <= 16) { - this.last_result = dest_operand >> count | source_operand << (16 - count); - this.flags = (this.flags & ~1) | (dest_operand >> (count - 1) & 1); + this.last_result[0] = dest_operand >> count | source_operand << (16 - count); + this.flags[0] = (this.flags[0] & ~1) | (dest_operand >> (count - 1) & 1); } else { - this.last_result = dest_operand << (32 - count) | source_operand >> (count - 16); - this.flags = (this.flags & ~1) | (source_operand >> (count - 17) & 1); + this.last_result[0] = dest_operand << (32 - count) | source_operand >> (count - 16); + this.flags[0] = (this.flags[0] & ~1) | (source_operand >> (count - 17) & 1); } - this.last_op_size = OPSIZE_16; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~flag_overflow) | ((this.last_result ^ dest_operand) >> 4 & flag_overflow); + this.last_op_size[0] = OPSIZE_16; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~flag_overflow) | ((this.last_result[0] ^ dest_operand) >> 4 & flag_overflow); - return this.last_result; + return this.last_result[0]; } CPU.prototype.shrd32 = function(dest_operand, source_operand, count) @@ -1289,14 +1303,14 @@ CPU.prototype.shrd32 = function(dest_operand, source_operand, count) return dest_operand; } - this.last_result = dest_operand >>> count | source_operand << (32 - count); + this.last_result[0] = dest_operand >>> count | source_operand << (32 - count); - this.last_op_size = OPSIZE_32; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~1) | (dest_operand >>> (count - 1) & 1); - this.flags = (this.flags & ~flag_overflow) | ((this.last_result ^ dest_operand) >> 20 & flag_overflow); + this.last_op_size[0] = OPSIZE_32; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1) | (dest_operand >>> (count - 1) & 1); + this.flags[0] = (this.flags[0] & ~flag_overflow) | ((this.last_result[0] ^ dest_operand) >> 20 & flag_overflow); - return this.last_result; + return this.last_result[0]; } CPU.prototype.shld16 = function(dest_operand, source_operand, count) @@ -1308,20 +1322,20 @@ CPU.prototype.shld16 = function(dest_operand, source_operand, count) if(count <= 16) { - this.last_result = dest_operand << count | source_operand >>> (16 - count); - this.flags = (this.flags & ~1) | (dest_operand >>> (16 - count) & 1); + this.last_result[0] = dest_operand << count | source_operand >>> (16 - count); + this.flags[0] = (this.flags[0] & ~1) | (dest_operand >>> (16 - count) & 1); } else { - this.last_result = dest_operand >> (32 - count) | source_operand << (count - 16); - this.flags = (this.flags & ~1) | (source_operand >>> (32 - count) & 1); + this.last_result[0] = dest_operand >> (32 - count) | source_operand << (count - 16); + this.flags[0] = (this.flags[0] & ~1) | (source_operand >>> (32 - count) & 1); } - this.last_op_size = OPSIZE_16; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~flag_overflow) | ((this.flags & 1) ^ (this.last_result >> 15 & 1)) << 11; + this.last_op_size[0] = OPSIZE_16; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~flag_overflow) | ((this.flags[0] & 1) ^ (this.last_result[0] >> 15 & 1)) << 11; - return this.last_result; + return this.last_result[0]; } CPU.prototype.shld32 = function(dest_operand, source_operand, count) @@ -1331,51 +1345,51 @@ CPU.prototype.shld32 = function(dest_operand, source_operand, count) return dest_operand; } - this.last_result = dest_operand << count | source_operand >>> (32 - count); + this.last_result[0] = dest_operand << count | source_operand >>> (32 - count); - this.last_op_size = OPSIZE_32; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~1) | (dest_operand >>> (32 - count) & 1); + this.last_op_size[0] = OPSIZE_32; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1) | (dest_operand >>> (32 - count) & 1); if(count === 1) { - this.flags = (this.flags & ~flag_overflow) | ((this.flags & 1) ^ (this.last_result >> 31 & 1)) << 11; + this.flags[0] = (this.flags[0] & ~flag_overflow) | ((this.flags[0] & 1) ^ (this.last_result[0] >> 31 & 1)) << 11; } else { - this.flags &= ~flag_overflow; + this.flags[0] &= ~flag_overflow; } - return this.last_result; + return this.last_result[0]; } CPU.prototype.bt_reg = function(bit_base, bit_offset) { - this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1); - this.flags_changed &= ~1; + this.flags[0] = (this.flags[0] & ~1) | (bit_base >> bit_offset & 1); + this.flags_changed[0] &= ~1; } CPU.prototype.btc_reg = function(bit_base, bit_offset) { - this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1); - this.flags_changed &= ~1; + this.flags[0] = (this.flags[0] & ~1) | (bit_base >> bit_offset & 1); + this.flags_changed[0] &= ~1; return bit_base ^ 1 << bit_offset; } CPU.prototype.bts_reg = function(bit_base, bit_offset) { - this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1); - this.flags_changed &= ~1; + this.flags[0] = (this.flags[0] & ~1) | (bit_base >> bit_offset & 1); + this.flags_changed[0] &= ~1; return bit_base | 1 << bit_offset; } CPU.prototype.btr_reg = function(bit_base, bit_offset) { - this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1); - this.flags_changed &= ~1; + this.flags[0] = (this.flags[0] & ~1) | (bit_base >> bit_offset & 1); + this.flags_changed[0] &= ~1; return bit_base & ~(1 << bit_offset); } @@ -1385,8 +1399,8 @@ CPU.prototype.bt_mem = function(virt_addr, bit_offset) var bit_base = this.safe_read8(virt_addr + (bit_offset >> 3) | 0); bit_offset &= 7; - this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1); - this.flags_changed &= ~1; + this.flags[0] = (this.flags[0] & ~1) | (bit_base >> bit_offset & 1); + this.flags_changed[0] &= ~1; } CPU.prototype.btc_mem = function(virt_addr, bit_offset) @@ -1396,8 +1410,8 @@ CPU.prototype.btc_mem = function(virt_addr, bit_offset) bit_offset &= 7; - this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1); - this.flags_changed &= ~1; + this.flags[0] = (this.flags[0] & ~1) | (bit_base >> bit_offset & 1); + this.flags_changed[0] &= ~1; this.write8(phys_addr, bit_base ^ 1 << bit_offset); } @@ -1409,8 +1423,8 @@ CPU.prototype.btr_mem = function(virt_addr, bit_offset) bit_offset &= 7; - this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1); - this.flags_changed &= ~1; + this.flags[0] = (this.flags[0] & ~1) | (bit_base >> bit_offset & 1); + this.flags_changed[0] &= ~1; this.write8(phys_addr, bit_base & ~(1 << bit_offset)); } @@ -1422,94 +1436,97 @@ CPU.prototype.bts_mem = function(virt_addr, bit_offset) bit_offset &= 7; - this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1); - this.flags_changed &= ~1; + this.flags[0] = (this.flags[0] & ~1) | (bit_base >> bit_offset & 1); + this.flags_changed[0] &= ~1; this.write8(phys_addr, bit_base | 1 << bit_offset); } CPU.prototype.bsf16 = function(old, bit_base) { - this.flags_changed = flags_all & ~flag_zero; - this.last_op_size = OPSIZE_16; + this.flags_changed[0] = flags_all & ~flag_zero; + this.last_op_size[0] = OPSIZE_16; if(bit_base === 0) { - this.flags |= flag_zero; - this.last_result = bit_base; + this.flags[0] |= flag_zero; + this.last_result[0] = bit_base; // not defined in the docs, but value doesn't change on my intel machine return old; } else { - this.flags &= ~flag_zero; + this.flags[0] &= ~flag_zero; // http://jsperf.com/lowest-bit-index - return this.last_result = v86util.int_log2(-bit_base & bit_base); + return this.last_result[0] = v86util.int_log2(-bit_base & bit_base); } } CPU.prototype.bsf32 = function(old, bit_base) { - this.flags_changed = flags_all & ~flag_zero; - this.last_op_size = OPSIZE_32; + this.flags_changed[0] = flags_all & ~flag_zero; + this.last_op_size[0] = OPSIZE_32; if(bit_base === 0) { - this.flags |= flag_zero; - this.last_result = bit_base; + this.flags[0] |= flag_zero; + this.last_result[0] = bit_base; + return old; } else { - this.flags &= ~flag_zero; + this.flags[0] &= ~flag_zero; - return this.last_result = v86util.int_log2((-bit_base & bit_base) >>> 0); + return this.last_result[0] = v86util.int_log2((-bit_base & bit_base) >>> 0); } } CPU.prototype.bsr16 = function(old, bit_base) { - this.flags_changed = flags_all & ~flag_zero; - this.last_op_size = OPSIZE_16; + this.flags_changed[0] = flags_all & ~flag_zero; + this.last_op_size[0] = OPSIZE_16; if(bit_base === 0) { - this.flags |= flag_zero; - this.last_result = bit_base; + this.flags[0] |= flag_zero; + this.last_result[0] = bit_base; + return old; } else { - this.flags &= ~flag_zero; + this.flags[0] &= ~flag_zero; - return this.last_result = v86util.int_log2(bit_base); + return this.last_result[0] = v86util.int_log2(bit_base); } } CPU.prototype.bsr32 = function(old, bit_base) { - this.flags_changed = flags_all & ~flag_zero; - this.last_op_size = OPSIZE_32; + this.flags_changed[0] = flags_all & ~flag_zero; + this.last_op_size[0] = OPSIZE_32; if(bit_base === 0) { - this.flags |= flag_zero; - this.last_result = bit_base; + this.flags[0] |= flag_zero; + this.last_result[0] = bit_base; + return old; } else { - this.flags &= ~flag_zero; - return this.last_result = v86util.int_log2(bit_base >>> 0); + this.flags[0] &= ~flag_zero; + return this.last_result[0] = v86util.int_log2(bit_base >>> 0); } } CPU.prototype.popcnt = function(v) { - this.flags_changed = 0; - this.flags &= ~flags_all; + this.flags_changed[0] = 0; + this.flags[0] &= ~flags_all; if(v) { @@ -1520,7 +1537,7 @@ CPU.prototype.popcnt = function(v) } else { - this.flags |= flag_zero; + this.flags[0] |= flag_zero; return 0; } }; diff --git a/src/browser/lib.js b/src/browser/lib.js index 368849fc..14c08b03 100644 --- a/src/browser/lib.js +++ b/src/browser/lib.js @@ -18,6 +18,42 @@ var ASYNC_SAFE = false; v86util.AsyncFileBuffer = AsyncFileBuffer; v86util.SyncFileBuffer = SyncFileBuffer; + v86util.load_wasm = function load_wasm(filename, imports, cb) { + if (!imports) { + imports = {}; + } + const STATIC_MEMORY_BASE = 64 * 1024 * 1024; // XXX + + v86util.load_file(filename, { done: function(buffer) + { + WebAssembly.compile(buffer) + .then(module => { + if (!imports['env']) { + imports['env'] = {}; + } + imports['env']['___assert_fail'] = (a, b, c, d) => { + console.error('Assertion Failed', a, b, c, d); + dbg_assert(false); + }; + imports['env']['memoryBase'] = STATIC_MEMORY_BASE; + imports['env']['tableBase'] = 0; + imports['env']['memory'] = new WebAssembly.Memory({ ['initial']: 4096, }); + imports['env']['table'] = new WebAssembly.Table({ ['initial']: 18, ['element']: 'anyfunc' }); + return WebAssembly.instantiate(module, imports).then(instance => ({ instance, module })); + }) + .then(({ instance, module }) => { + cb({ + mem: imports['env']['memory'], + funcs: instance['exports'], + instance, + imports, + filename, + }); + }); + } + }); + }; + /** * @param {string} filename * @param {Object} options diff --git a/src/browser/starter.js b/src/browser/starter.js index 2cd969f6..7aa17b9e 100644 --- a/src/browser/starter.js +++ b/src/browser/starter.js @@ -92,7 +92,190 @@ function V86Starter(options) var bus = Bus.create(); var adapter_bus = this.bus = bus[0]; this.emulator_bus = bus[1]; - var emulator = this.v86 = new v86(this.emulator_bus); + var emulator; + var cpu; + var mem; + var wasm_shared_funcs = { + "_throw_cpu_exception": () => { throw MAGIC_CPU_EXCEPTION; }, + "_hlt_op": function() { return cpu.hlt_op(); }, + "abort": function() { dbg_assert(false); }, + "_dbg_assert": function() { return cpu.dbg_assert.apply(cpu, arguments); }, + "_dbg_log": function() { return cpu.dbg_log.apply(cpu, arguments); }, + "_todo": function() { return cpu.todo.apply(cpu, arguments); }, + "_undefined_instruction": function() { return cpu.undefined_instruction.apply(cpu, arguments); }, + "_unimplemented_sse": function() { return cpu.unimplemented_sse_wasm(); }, + "_microtick": function() { return v86.microtick(); }, + "_get_rand_int": function() { return v86util.get_rand_int(); }, + "_has_rand_int": function() { return v86util.has_rand_int(); }, + "_printf": function(offset) { dbg_log_wasm(mem, offset, [].slice.call(arguments, 1)); }, + + "_call_interrupt_vector": function(interrupt_nr, is_software_int, has_error_code, error_code) { + cpu.call_interrupt_vector(interrupt_nr, is_software_int, !!has_error_code, error_code); + }, + "_far_jump": function(eip, selector, is_call) { return cpu.far_jump(eip, selector, !!is_call); }, + "_far_return": function(eip, selector, stack_adjust) { return cpu.far_return(eip, selector, stack_adjust); }, + "_switch_seg": function(reg, selector) { cpu.switch_seg(reg, selector); }, + "_iret16": function() { return cpu.iret16(); }, + "_iret32": function() { return cpu.iret32(); }, + + "_io_port_read8": function(addr) { return cpu.io.port_read8(addr); }, + "_io_port_read16": function(addr) { return cpu.io.port_read16(addr); }, + "_io_port_read32": function(addr) { return cpu.io.port_read32(addr); }, + "_io_port_write8": function(addr, value) { cpu.io.port_write8(addr, value); }, + "_io_port_write16": function(addr, value) { cpu.io.port_write16(addr, value); }, + "_io_port_write32": function(addr, value) { cpu.io.port_write32(addr, value); }, + + "_mmap_read8": function(addr) { return cpu.mmap_read8(addr); }, + "_mmap_read16": function(addr) { return cpu.mmap_read16(addr); }, + "_mmap_read32": function(addr) { return cpu.mmap_read32(addr); }, + "_mmap_write8": function(addr, value) { return cpu.mmap_write8(addr, value); }, + "_mmap_write16": function(addr, value) { return cpu.mmap_write16(addr, value); }, + "_mmap_write32": function(addr, value) { return cpu.mmap_write32(addr, value); }, + + "_fpu_op_D8_reg": function() { return cpu.fpu.op_D8_reg.apply(cpu.fpu, arguments); }, + "_fpu_op_D9_reg": function() { return cpu.fpu.op_D9_reg.apply(cpu.fpu, arguments); }, + "_fpu_op_DA_reg": function() { return cpu.fpu.op_DA_reg.apply(cpu.fpu, arguments); }, + "_fpu_op_DB_reg": function() { return cpu.fpu.op_DB_reg.apply(cpu.fpu, arguments); }, + "_fpu_op_DC_reg": function() { return cpu.fpu.op_DC_reg.apply(cpu.fpu, arguments); }, + "_fpu_op_DD_reg": function() { return cpu.fpu.op_DD_reg.apply(cpu.fpu, arguments); }, + "_fpu_op_DE_reg": function() { return cpu.fpu.op_DE_reg.apply(cpu.fpu, arguments); }, + "_fpu_op_DF_reg": function() { return cpu.fpu.op_DF_reg.apply(cpu.fpu, arguments); }, + + "_fpu_op_D8_mem": function() { return cpu.fpu.op_D8_mem.apply(cpu.fpu, arguments); }, + "_fpu_op_D9_mem": function() { return cpu.fpu.op_D9_mem.apply(cpu.fpu, arguments); }, + "_fpu_op_DA_mem": function() { return cpu.fpu.op_DA_mem.apply(cpu.fpu, arguments); }, + "_fpu_op_DB_mem": function() { return cpu.fpu.op_DB_mem.apply(cpu.fpu, arguments); }, + "_fpu_op_DC_mem": function() { return cpu.fpu.op_DC_mem.apply(cpu.fpu, arguments); }, + "_fpu_op_DD_mem": function() { return cpu.fpu.op_DD_mem.apply(cpu.fpu, arguments); }, + "_fpu_op_DE_mem": function() { return cpu.fpu.op_DE_mem.apply(cpu.fpu, arguments); }, + "_fpu_op_DF_mem": function() { return cpu.fpu.op_DF_mem.apply(cpu.fpu, arguments); }, + "_fwait": function() { return cpu.fpu.fwait(); }, + + "_do_page_translation": function() { return cpu.do_page_translation.apply(cpu, arguments); }, + "_read_reg_e16": function() { return cpu.read_reg_e16.apply(cpu, arguments); }, + "_read_reg_e32s": function() { return cpu.read_reg_e32s.apply(cpu, arguments); }, + "_write_reg_e16": function() { return cpu.write_reg_e16.apply(cpu, arguments); }, + "_write_reg_e32": function() { return cpu.write_reg_e32.apply(cpu, arguments); }, + "_read_moffs": function() { return cpu.read_moffs.apply(cpu, arguments); }, + "_popa16": function() { return cpu.popa16.apply(cpu, arguments); }, + "_popa32": function() { return cpu.popa32.apply(cpu, arguments); }, + "_arpl": function() { return cpu.arpl.apply(cpu, arguments); }, + "_trigger_ud": function() { return cpu.trigger_ud.apply(cpu, arguments); }, + "_trigger_nm": function() { return cpu.trigger_nm.apply(cpu, arguments); }, + "_pop16": function() { return cpu.pop16.apply(cpu, arguments); }, + "_virt_boundary_read16": function() { return cpu.virt_boundary_read16.apply(cpu, arguments); }, + "_virt_boundary_read32s": function() { return cpu.virt_boundary_read32s.apply(cpu, arguments); }, + "_virt_boundary_write16": function() { return cpu.virt_boundary_write16.apply(cpu, arguments); }, + "_virt_boundary_write32": function() { return cpu.virt_boundary_write32.apply(cpu, arguments); }, + "_set_stack_reg": function() { return cpu.set_stack_reg.apply(cpu, arguments); }, + "_getiopl": function() { return cpu.getiopl.apply(cpu, arguments); }, + "_vm86_mode": function() { return cpu.vm86_mode.apply(cpu, arguments); }, + "_shl8": function() { return cpu.shl8.apply(cpu, arguments); }, + "_shr8": function() { return cpu.shr8.apply(cpu, arguments); }, + "_sar8": function() { return cpu.sar8.apply(cpu, arguments); }, + "_shl16": function() { return cpu.shl16.apply(cpu, arguments); }, + "_shr16": function() { return cpu.shr16.apply(cpu, arguments); }, + "_sar16": function() { return cpu.sar16.apply(cpu, arguments); }, + "_shl32": function() { return cpu.shl32.apply(cpu, arguments); }, + "_shr32": function() { return cpu.shr32.apply(cpu, arguments); }, + "_sar32": function() { return cpu.sar32.apply(cpu, arguments); }, + + "_shrd16": function() { return cpu.shrd16.apply(cpu, arguments); }, + "_shrd32": function() { return cpu.shrd32.apply(cpu, arguments); }, + "_shld16": function() { return cpu.shld16.apply(cpu, arguments); }, + "_shld32": function() { return cpu.shld32.apply(cpu, arguments); }, + + "_bt_reg": function() { return cpu.bt_reg.apply(cpu, arguments); }, + "_bt_mem": function() { return cpu.bt_mem.apply(cpu, arguments); }, + "_btr_reg": function() { return cpu.btr_reg.apply(cpu, arguments); }, + "_btr_mem": function() { return cpu.btr_mem.apply(cpu, arguments); }, + "_btc_reg": function() { return cpu.btc_reg.apply(cpu, arguments); }, + "_btc_mem": function() { return cpu.btc_mem.apply(cpu, arguments); }, + "_bts_reg": function() { return cpu.bts_reg.apply(cpu, arguments); }, + "_bts_mem": function() { return cpu.bts_mem.apply(cpu, arguments); }, + + "_bsf16": function() { return cpu.bsf16.apply(cpu, arguments); }, + "_bsf32": function() { return cpu.bsf32.apply(cpu, arguments); }, + "_bsr16": function() { return cpu.bsr16.apply(cpu, arguments); }, + "_bsr32": function() { return cpu.bsr32.apply(cpu, arguments); }, + "_popcnt": function() { return cpu.popcnt.apply(cpu, arguments); }, + "_bswap": function() { return cpu.bswap.apply(cpu, arguments); }, + + "_setcc": function() { return cpu.setcc.apply(cpu, arguments); }, + "_cmovcc16": function() { return cpu.cmovcc16.apply(cpu, arguments); }, + "_cmovcc32": function() { return cpu.cmovcc32.apply(cpu, arguments); }, + + "_lar": function() { return cpu.lar.apply(cpu, arguments); }, + "_lsl": function() { return cpu.lsl.apply(cpu, arguments); }, + "_verw": function() { return cpu.verw.apply(cpu, arguments); }, + "_verr": function() { return cpu.verr.apply(cpu, arguments); }, + + "_full_clear_tlb": function() { return cpu.full_clear_tlb.apply(cpu, arguments); }, + "_invlpg": function() { return cpu.invlpg.apply(cpu, arguments); }, + "_writable_or_pagefault": function() { return cpu.writable_or_pagefault.apply(cpu, arguments); }, + + "_cpl_changed": function() { return cpu.cpl_changed.apply(cpu, arguments); }, + "_set_cr0": function() { return cpu.set_cr0.apply(cpu, arguments); }, + "_update_cs_size": function() { return cpu.update_cs_size.apply(cpu, arguments); }, + "_clear_tlb": function() { return cpu.clear_tlb.apply(cpu, arguments); }, + "_cpuid": function() { return cpu.cpuid.apply(cpu, arguments); }, + + "_load_ldt": function() { return cpu.load_ldt.apply(cpu, arguments); }, + "_load_tr": function() { return cpu.load_tr.apply(cpu, arguments); }, + + "_idiv16": function() { return cpu.idiv16.apply(cpu, arguments); }, + "_div32": function() { return cpu.div32.apply(cpu, arguments); }, + "_idiv32": function() { return cpu.idiv32.apply(cpu, arguments); }, + "_insb": function() { return cpu.insb.apply(cpu, arguments); }, + "_insw": function() { return cpu.insw.apply(cpu, arguments); }, + "_insd": function() { return cpu.insd.apply(cpu, arguments); }, + "_outsb": function() { return cpu.outsb.apply(cpu, arguments); }, + "_outsw": function() { return cpu.outsw.apply(cpu, arguments); }, + "_outsd": function() { return cpu.outsd.apply(cpu, arguments); }, + "_movsb": function() { return cpu.movsb.apply(cpu, arguments); }, + "_movsw": function() { return cpu.movsw.apply(cpu, arguments); }, + "_movsd": function() { return cpu.movsd.apply(cpu, arguments); }, + "_cmpsb": function() { return cpu.cmpsb.apply(cpu, arguments); }, + "_cmpsw": function() { return cpu.cmpsw.apply(cpu, arguments); }, + "_cmpsd": function() { return cpu.cmpsd.apply(cpu, arguments); }, + "_stosb": function() { return cpu.stosb.apply(cpu, arguments); }, + "_stosw": function() { return cpu.stosw.apply(cpu, arguments); }, + "_stosd": function() { return cpu.stosd.apply(cpu, arguments); }, + "_lodsb": function() { return cpu.lodsb.apply(cpu, arguments); }, + "_lodsw": function() { return cpu.lodsw.apply(cpu, arguments); }, + "_lodsd": function() { return cpu.lodsd.apply(cpu, arguments); }, + "_scasb": function() { return cpu.scasb.apply(cpu, arguments); }, + "_scasw": function() { return cpu.scasw.apply(cpu, arguments); }, + "_scasd": function() { return cpu.scasd.apply(cpu, arguments); }, + "_lss16": function() { return cpu.lss16.apply(cpu, arguments); }, + "_lss32": function() { return cpu.lss32.apply(cpu, arguments); }, + "_enter16": function() { return cpu.enter16.apply(cpu, arguments); }, + "_enter32": function() { return cpu.enter32.apply(cpu, arguments); }, + "_update_eflags": function() { return cpu.update_eflags.apply(cpu, arguments); }, + "_handle_irqs": function() { return cpu.handle_irqs.apply(cpu, arguments); }, + "_get_real_eip": function() { return cpu.get_real_eip.apply(cpu, arguments); }, + "_xchg8": function() { return cpu.xchg8.apply(cpu, arguments); }, + "_xchg16": function() { return cpu.xchg16.apply(cpu, arguments); }, + "_xchg16r": function() { return cpu.xchg16r.apply(cpu, arguments); }, + "_xchg32": function() { return cpu.xchg32.apply(cpu, arguments); }, + "_xchg32r": function() { return cpu.xchg32r.apply(cpu, arguments); }, + "_loop": function() { return cpu.loop.apply(cpu, arguments); }, + "_loope": function() { return cpu.loope.apply(cpu, arguments); }, + "_loopne": function() { return cpu.loopne.apply(cpu, arguments); }, + "_bcd_aam": function() { return cpu.bcd_aam.apply(cpu, arguments); }, + "_task_switch_test": function() { return cpu.task_switch_test.apply(cpu, arguments); }, + "_jcxz": function() { return cpu.jcxz.apply(cpu, arguments); }, + "_test_privileges_for_io": function() { return cpu.test_privileges_for_io.apply(cpu, arguments); }, + + "_fxsave": function() { return cpu.fxsave.apply(cpu, arguments); }, + "_fxrstor": function() { return cpu.fxrstor.apply(cpu, arguments); }, + }; + + let wasm_file = DEBUG ? "v86-debug.wasm" : "v86.wasm"; + v86util.load_wasm("build/" + wasm_file, { 'env': wasm_shared_funcs }, wm => { + emulator = this.v86 = new v86(this.emulator_bus, wm); + cpu = emulator.cpu; + mem = wm.mem.buffer; this.bus.register("emulator-stopped", function() { @@ -423,6 +606,8 @@ function V86Starter(options) }.bind(this), 0); }.bind(this), 0); } + + }); } /** @@ -627,7 +812,7 @@ V86Starter.prototype.get_instruction_counter = function() { if(this.v86) { - return this.v86.cpu.timestamp_counter; + return this.v86.cpu.timestamp_counter[0]; } else { diff --git a/src/config.js b/src/config.js index 6890fad4..4fe8dcbd 100644 --- a/src/config.js +++ b/src/config.js @@ -26,7 +26,7 @@ var LOG_PAGE_FAULTS = false; var LOG_LEVEL = LOG_ALL & ~LOG_PS2 & ~LOG_PIT & ~LOG_VIRTIO & ~LOG_9P & ~LOG_PIC & - ~LOG_DMA & ~LOG_SERIAL & ~LOG_NET & ~LOG_FLOPPY & ~LOG_DISK; + ~LOG_DMA & ~LOG_SERIAL & ~LOG_NET & ~LOG_FLOPPY & ~LOG_DISK & ~LOG_VGA; /** @const */ diff --git a/src/cpu.js b/src/cpu.js index 699f8dd4..ee350f91 100644 --- a/src/cpu.js +++ b/src/cpu.js @@ -1,7 +1,7 @@ "use strict"; /** @const */ -var CPU_LOG_VERBOSE = true; +var CPU_LOG_VERBOSE = false; // Resources: @@ -11,14 +11,17 @@ var CPU_LOG_VERBOSE = true; /** @constructor */ -function CPU(bus) +function CPU(bus, wm) { - /** @type {number} */ - this.memory_size = 0; + this.wm = wm; + this.wasm_patch(wm); + + this.memory_size = new Uint32Array(wm.mem.buffer, 812, 1); // Note: Currently unused (degrades performance and not required by any OS // that we support) - this.a20_enabled = true; + this.a20_enabled = new Int32Array(wm.mem.buffer, 552, 1); + this.a20_enabled[0] = +true; this.mem_page_infos = undefined; @@ -26,16 +29,16 @@ function CPU(bus) this.mem16 = new Uint16Array(this.mem8.buffer); this.mem32s = new Int32Array(this.mem8.buffer); - this.segment_is_null = new Uint8Array(8); - this.segment_limits = new Uint32Array(8); - //this.segment_infos = new Uint32Array(8); - this.segment_offsets = new Int32Array(8); + this.segment_is_null = new Uint8Array(wm.mem.buffer, 724, 8); + this.segment_offsets = new Int32Array(wm.mem.buffer, 736, 8); + this.segment_limits = new Uint32Array(wm.mem.buffer, 768, 8); + //this.segment_infos = []; /** * Translation Lookaside Buffer * @const */ - this.tlb_data = new Int32Array(1 << 20); + this.tlb_data = new Int32Array(wm.mem.buffer, 2048 + 0x100000*2, 0x100000); /** * Information about which pages are cached in the tlb. @@ -46,35 +49,27 @@ function CPU(bus) * 3 user, write * @const */ - this.tlb_info = new Uint8Array(1 << 20); + this.tlb_info = new Uint8Array(wm.mem.buffer, 2048, 0x100000); /** * Same as tlb_info, except it only contains global pages * @const */ - this.tlb_info_global = new Uint8Array(1 << 20); + this.tlb_info_global = new Uint8Array(wm.mem.buffer, 2048 + 0x100000, 0x100000); /** * Wheter or not in protected mode - * @type {boolean} */ - this.protected_mode = false; + this.protected_mode = new Int32Array(wm.mem.buffer, 800, 1); - /** - * interrupt descriptor table - * @type {number} - */ - this.idtr_size = 0; - /** @type {number} */ - this.idtr_offset = 0; + this.idtr_size = new Int32Array(wm.mem.buffer, 564, 1); + this.idtr_offset = new Int32Array(wm.mem.buffer, 568, 1); /** * global descriptor table register - * @type {number} */ - this.gdtr_size = 0; - /** @type {number} */ - this.gdtr_offset = 0; + this.gdtr_size = new Int32Array(wm.mem.buffer, 572, 1); + this.gdtr_offset = new Int32Array(wm.mem.buffer, 576, 1); this.tss_size_32 = false; @@ -83,7 +78,7 @@ function CPU(bus) */ this.page_fault = false; - this.cr = new Int32Array(8); + this.cr = new Int32Array(wm.mem.buffer, 580, 8); /** @type {number} */ this.cr[0] = 0; @@ -95,19 +90,15 @@ function CPU(bus) this.cr[4] = 0; // current privilege level - /** @type {number} */ - this.cpl = 0; + this.cpl = new Int32Array(wm.mem.buffer, 612, 1); // if false, pages are 4 KiB, else 4 Mib - /** @type {number} */ - this.page_size_extensions = 0; + this.page_size_extensions = new Int32Array(wm.mem.buffer, 616, 1); // current operand/address size - /** @type {boolean} */ - this.is_32 = false; + this.is_32 = new Int32Array(wm.mem.buffer, 804, 1); - /** @type {boolean} */ - this.stack_size_32 = false; + this.stack_size_32 = new Int32Array(wm.mem.buffer, 808, 1); /** * Was the last instruction a hlt? @@ -115,70 +106,52 @@ function CPU(bus) */ this.in_hlt = false; - /** @type {number} */ - this.last_virt_eip = 0; + this.last_virt_eip = new Int32Array(wm.mem.buffer, 620, 1); - /** @type {number} */ - this.eip_phys = 0; + this.eip_phys = new Int32Array(wm.mem.buffer, 624, 1); - /** @type {number} */ - this.last_virt_esp = 0; + this.last_virt_esp = new Int32Array(wm.mem.buffer, 628, 1); - /** @type {number} */ - this.esp_phys = 0; + this.esp_phys = new Int32Array(wm.mem.buffer, 632, 1); - /** @type {number} */ - this.sysenter_cs = 0; + this.sysenter_cs = new Int32Array(wm.mem.buffer, 636, 1); - /** @type {number} */ - this.sysenter_esp = 0; + this.sysenter_esp = new Int32Array(wm.mem.buffer, 640, 1); - /** @type {number} */ - this.sysenter_eip = 0; + this.sysenter_eip = new Int32Array(wm.mem.buffer, 644, 1); - /** @type {number} */ - this.prefixes = 0; + this.prefixes = new Int32Array(wm.mem.buffer, 648, 1); - /** @type {number} */ - this.flags = 0; + this.flags = new Int32Array(wm.mem.buffer, 536, 1); /** * bitmap of flags which are not updated in the flags variable * changed by arithmetic instructions, so only relevant to arithmetic flags - * @type {number} */ - this.flags_changed = 0; + this.flags_changed = new Int32Array(wm.mem.buffer, 532, 1); /** * the last 2 operators and the result and size of the last arithmetic operation - * @type {number} */ - this.last_op1 = 0; - /** @type {number} */ - this.last_op2 = 0; - /** @type {number} */ - this.last_op_size = 0; + this.last_op1 = new Int32Array(wm.mem.buffer, 512, 1); + this.last_op2 = new Int32Array(wm.mem.buffer, 516, 1); + this.last_op_size = new Int32Array(wm.mem.buffer, 520, 1); - /** @type {number} */ - this.last_add_result = 0; + this.last_add_result = new Int32Array(wm.mem.buffer, 524, 1); - /** @type {number} */ - this.last_result = 0; + this.last_result = new Int32Array(wm.mem.buffer, 528, 1); - this.mul32_result = new Int32Array(2); + this.mul32_result = new Int32Array(wm.mem.buffer, 544, 2); this.div32_result = new Float64Array(2); - this.tsc_offset = 0; + this.tsc_offset = new Int32Array(wm.mem.buffer, 652, 1); - /** @type {number} */ - this.modrm_byte = 0; + this.modrm_byte = new Int32Array(wm.mem.buffer, 540, 1); - /** @type {number} */ - this.phys_addr = 0; + this.phys_addr = new Int32Array(wm.mem.buffer, 656, 1); - /** @type {number} */ - this.phys_addr_high = 0; + this.phys_addr_high = new Int32Array(wm.mem.buffer, 660, 1); /** @type {!Object} */ this.devices = {}; @@ -186,46 +159,14 @@ function CPU(bus) this.table = []; // paging enabled - /** @type {boolean} */ - this.paging = false; + this.paging = new Uint8Array(wm.mem.buffer, 820, 1); - /** @type {number} */ - this.instruction_pointer = 0; + this.instruction_pointer = new Int32Array(wm.mem.buffer, 556, 1); - /** @type {number} */ - this.previous_ip = 0; + this.previous_ip = new Int32Array(wm.mem.buffer, 560, 1); this.apic_enabled = true; - /** - * @type {number} - */ - this.timestamp_counter = 0; - - // registers - this.reg32s = new Int32Array(8); - this.reg32 = new Uint32Array(this.reg32s.buffer); - this.reg16s = new Int16Array(this.reg32s.buffer); - this.reg16 = new Uint16Array(this.reg32s.buffer); - this.reg8s = new Int8Array(this.reg32s.buffer); - this.reg8 = new Uint8Array(this.reg32s.buffer); - - // mm0-mm7 split up into 32 bit pairs - this.reg_mmxs = new Int32Array(16); - this.reg_mmx = new Uint32Array(this.reg_mmxs.buffer); - this.reg_mmx8s = new Int8Array(this.reg_mmxs.buffer); - this.reg_mmx8 = new Uint8Array(this.reg_mmxs.buffer); - - this.reg_xmm32s = new Int32Array(8 * 4); - this.mxcsr = 0x1F80; - - // segment registers, tr and ldtr - this.sreg = new Uint16Array(8); - - // debug registers - this.dreg = new Int32Array(8); - - // managed in io.js /** @const */ this.memory_map_read8 = []; /** @const */ this.memory_map_write8 = []; @@ -241,8 +182,32 @@ function CPU(bus) vga: null, }; - /** @type {number} */ - this.fw_value = 0; + this.timestamp_counter = new Int32Array(wm.mem.buffer, 664, 1); + + // registers + this.reg32s = new Int32Array(wm.mem.buffer, 4, 8); + this.reg32 = new Uint32Array(this.reg32s.buffer, 4, 8); + this.reg16s = new Int16Array(this.reg32s.buffer, 4, 16); + this.reg16 = new Uint16Array(this.reg32s.buffer, 4, 16); + this.reg8s = new Int8Array(this.reg32s.buffer, 4, 32); + this.reg8 = new Uint8Array(this.reg32s.buffer, 4, 32); + + // mm0-mm7 split up into 32 bit pairs + this.reg_mmxs = new Int32Array(16); + this.reg_mmx = new Uint32Array(this.reg_mmxs.buffer); + this.reg_mmx8s = new Int8Array(this.reg_mmxs.buffer); + this.reg_mmx8 = new Uint8Array(this.reg_mmxs.buffer); + + this.reg_xmm32s = new Int32Array(8 * 4); + this.mxcsr = new Int32Array(wm.mem.buffer, 824, 1); + + // segment registers, tr and ldtr + this.sreg = new Uint16Array(wm.mem.buffer, 668, 8); + + // debug registers + this.dreg = new Int32Array(wm.mem.buffer, 684, 8); + + this.fw_value = new Int32Array(wm.mem.buffer, 720, 1); this.io = undefined; this.fpu = undefined; @@ -254,7 +219,7 @@ function CPU(bus) this.update_operand_size(); - this.tsc_offset = v86.microtick(); + this.tsc_offset[0] = v86.microtick(); this.debug_init(); @@ -263,44 +228,115 @@ function CPU(bus) //Object.seal(this); } +CPU.prototype.wasm_patch = function(wm) +{ + this.add = this.wm.funcs['_add']; + this.adc = this.wm.funcs['_adc']; + this.sub = this.wm.funcs['_sub']; + this.sbb = this.wm.funcs['_sbb']; + this.inc = this.wm.funcs['_inc']; + this.dec = this.wm.funcs['_dec']; + this.neg = this.wm.funcs['_neg']; + this.mul8 = this.wm.funcs['_mul8']; + this.imul8 = this.wm.funcs['_imul8']; + this.mul16 = this.wm.funcs['_mul16']; + this.imul16 = this.wm.funcs['_imul16']; + this.imul_reg16 = this.wm.funcs['_imul_reg16']; + this.mul32 = this.wm.funcs['_mul32']; + this.imul32 = this.wm.funcs['_imul32']; + this.imul_reg32 = this.wm.funcs['_imul_reg32']; + this.xadd8 = this.wm.funcs['_xadd8']; + this.xadd16 = this.wm.funcs['_xadd16']; + this.xadd32 = this.wm.funcs['_xadd32']; + this.bcd_daa = this.wm.funcs['_bcd_daa']; + this.bcd_das = this.wm.funcs['_bcd_das']; + this.bcd_aad = this.wm.funcs['_bcd_aad']; + this.bcd_aaa = this.wm.funcs['_bcd_aaa']; + this.bcd_aas = this.wm.funcs['_bcd_aas']; + this.and = this.wm.funcs['_and']; + this.or = this.wm.funcs['_or']; + this.xor = this.wm.funcs['_xor']; + this.rol8 = this.wm.funcs['_rol8']; + this.rol16 = this.wm.funcs['_rol16']; + this.rol32 = this.wm.funcs['_rol32']; + this.rcl8 = this.wm.funcs['_rcl8']; + this.rcl16 = this.wm.funcs['_rcl16']; + this.rcl32 = this.wm.funcs['_rcl32']; + this.ror8 = this.wm.funcs['_ror8']; + this.ror16 = this.wm.funcs['_ror16']; + this.ror32 = this.wm.funcs['_ror32']; + this.rcr8 = this.wm.funcs['_rcr8']; + this.rcr16 = this.wm.funcs['_rcr16']; + this.rcr32 = this.wm.funcs['_rcr32']; + this.div8 = this.wm.funcs['_div8']; + this.idiv8 = this.wm.funcs['_idiv8']; + this.div16 = this.wm.funcs['_div16']; + this.getcf = this.wm.funcs['_getcf']; + this.getaf = this.wm.funcs['_getaf']; + this.raise_exception = this.wm.funcs['_raise_exception']; + this.raise_exception_with_code = this.wm.funcs['_raise_exception_with_code']; + this.trigger_de = this.wm.funcs['_trigger_de']; + this.trigger_gp = this.wm.funcs['_trigger_gp']; + + this.do_many_cycles_unsafe = this.wm.funcs['_do_many_cycles_unsafe']; + + this.read_imm8 = this.wm.funcs['_read_imm8']; + this.read_imm8s = this.wm.funcs['_read_imm8s']; + this.read_imm16 = this.wm.funcs['_read_imm16']; + this.read_imm32s = this.wm.funcs['_read_imm32s']; + this.read_write_e8 = this.wm.funcs['_read_write_e8']; + this.write_e8 = this.wm.funcs['_write_e8']; + this.in_mapped_range = this.wm.funcs['_in_mapped_range']; + this.read16 = this.wm.funcs['_read16']; + this.read_aligned16 = this.wm.funcs['_read_aligned16']; + this.read32s = this.wm.funcs['_read32s']; + this.write8 = this.wm.funcs['_write8']; + this.write16 = this.wm.funcs['_write16']; + this.write32 = this.wm.funcs['_write32']; + this.push16 = this.wm.funcs['_push16']; + this.push32 = this.wm.funcs['_push32']; + this.pusha16 = this.wm.funcs['_pusha16']; + this.pusha32 = this.wm.funcs['_pusha32']; +}; + CPU.prototype.get_state = function() { var state = []; - state[0] = this.memory_size; + state[0] = this.memory_size[0]; state[1] = this.segment_is_null; state[2] = this.segment_offsets; state[3] = this.segment_limits; - state[4] = this.protected_mode; - state[5] = this.idtr_offset; - state[6] = this.idtr_size; - state[7] = this.gdtr_offset; - state[8] = this.gdtr_size; + state[4] = this.protected_mode[0]; + state[5] = this.idtr_offset[0]; + state[6] = this.idtr_size[0]; + state[7] = this.gdtr_offset[0]; + state[8] = this.gdtr_size[0]; state[9] = this.page_fault; state[10] = this.cr; - state[11] = this.cpl; - state[12] = this.page_size_extensions; - state[13] = this.is_32; + state[11] = this.cpl[0]; + state[12] = this.page_size_extensions[0]; + state[13] = this.is_32[0]; - state[16] = this.stack_size_32; + state[16] = this.stack_size_32[0]; state[17] = this.in_hlt; - state[18] = this.last_virt_eip; - state[19] = this.eip_phys; - state[20] = this.last_virt_esp; - state[21] = this.esp_phys; - state[22] = this.sysenter_cs; - state[23] = this.sysenter_eip; - state[24] = this.sysenter_esp; - state[25] = this.prefixes; + state[18] = this.last_virt_eip[0]; + state[19] = this.eip_phys[0]; + state[20] = this.last_virt_esp[0]; + state[21] = this.esp_phys[0]; + state[22] = this.sysenter_cs[0]; + state[23] = this.sysenter_eip[0]; + state[24] = this.sysenter_esp[0]; + state[25] = this.prefixes[0]; state[26] = this.flags; state[27] = this.flags_changed; state[28] = this.last_op1; state[29] = this.last_op2; state[30] = this.last_op_size; state[31] = this.last_add_result; - state[32] = this.modrm_byte; + state[32] = this.modrm_byte[0]; - state[36] = this.paging; + state[36] = this.paging[0]; state[37] = this.instruction_pointer; state[38] = this.previous_ip; state[39] = this.reg32s; @@ -326,8 +362,12 @@ CPU.prototype.get_state = function() state[59] = this.devices.net; state[60] = this.devices.pic; - state[61] = this.a20_enabled; - state[62] = this.fw_value; + state[61] = this.a20_enabled[0]; + state[62] = this.fw_value[0]; + + state[63] = this.devices.ioapic; + + state[64] = this.tss_size_32; state[63] = this.devices.ioapic; @@ -340,32 +380,32 @@ CPU.prototype.get_state = function() CPU.prototype.set_state = function(state) { - this.memory_size = state[0]; + this.memory_size[0] = state[0]; this.segment_is_null = state[1]; this.segment_offsets = state[2]; this.segment_limits = state[3]; - this.protected_mode = state[4]; - this.idtr_offset = state[5]; - this.idtr_size = state[6]; - this.gdtr_offset = state[7]; - this.gdtr_size = state[8]; + this.protected_mode[0] = state[4]; + this.idtr_offset[0] = state[5]; + this.idtr_size[0] = state[6]; + this.gdtr_offset[0] = state[7]; + this.gdtr_size[0] = state[8]; this.page_fault = state[9]; this.cr = state[10]; - this.cpl = state[11]; - this.page_size_extensions = state[12]; - this.is_32 = state[13]; + this.cpl[0] = state[11]; + this.page_size_extensions[0] = state[12]; + this.is_32[0] = state[13]; - this.stack_size_32 = state[16]; + this.stack_size_32[0] = state[16]; this.in_hlt = state[17]; - this.last_virt_eip = state[18]; - this.eip_phys = state[19]; - this.last_virt_esp = state[20]; - this.esp_phys = state[21]; - this.sysenter_cs = state[22]; - this.sysenter_eip = state[23]; - this.sysenter_esp = state[24]; - this.prefixes = state[25]; + this.last_virt_eip[0] = state[18]; + this.eip_phys[0] = state[19]; + this.last_virt_esp[0] = state[20]; + this.esp_phys[0] = state[21]; + this.sysenter_cs[0] = state[22]; + this.sysenter_eip[0] = state[23]; + this.sysenter_esp[0] = state[24]; + this.prefixes[0] = state[25]; this.flags = state[26]; this.flags_changed = state[27]; @@ -375,7 +415,7 @@ CPU.prototype.set_state = function(state) this.last_add_result = state[31]; this.modrm_byte = state[32]; - this.paging = state[36]; + this.paging[0] = state[36]; this.instruction_pointer = state[37]; this.previous_ip = state[38]; this.reg32s = state[39]; @@ -401,8 +441,12 @@ CPU.prototype.set_state = function(state) this.devices.net = state[59]; this.devices.pic = state[60]; - this.a20_enabled = state[61]; - this.fw_value = state[62]; + this.a20_enabled[0] = state[61]; + this.fw_value[0] = state[62]; + + this.devices.ioapic = state[63]; + + this.tss_size_32 = state[64]; this.devices.ioapic = state[63]; @@ -491,25 +535,17 @@ CPU.prototype.reboot_internal = function() CPU.prototype.reset = function() { - this.a20_enabled = true; + this.a20_enabled[0] = +true; - for(let i = 0; i < 8; i++) - { - this.segment_is_null[i] = 0; - this.segment_limits[i] = 0; - //this.segment_infos = new Uint32Array(8); - this.segment_offsets[i] = 0; - } + this.segment_is_null.fill(0); + this.segment_limits.fill(0); + //this.segment_infos = new Uint32Array(8); + this.segment_offsets.fill(0); - this.full_clear_tlb(); + this.reg32s.fill(0); - for(let i = 0; i < 8; i++) - { - this.reg32s[i] = 0; - this.sreg[i] = 0; - this.cr[i] = 0; - this.dreg[i] = 0; - } + this.sreg.fill(0); + this.dreg.fill(0); for(let i = 0; i < this.reg_mmxs.length; i++) { @@ -520,16 +556,18 @@ CPU.prototype.reset = function() { this.reg_xmm32s[i] = 0; } - this.mxcsr = 0x1F80; + this.mxcsr[0] = 0x1F80; - this.protected_mode = false; + this.full_clear_tlb(); + + this.protected_mode[0] = +false; // http://www.sandpile.org/x86/initial.htm - this.idtr_size = 0; - this.idtr_offset = 0; + this.idtr_size[0] = 0; + this.idtr_offset[0] = 0; - this.gdtr_size = 0; - this.gdtr_offset = 0; + this.gdtr_size[0] = 0; + this.gdtr_offset[0] = 0; this.page_fault = false; this.cr[0] = 1 << 30 | 1 << 29 | 1 << 4; @@ -538,38 +576,38 @@ CPU.prototype.reset = function() this.cr[4] = 0; this.dreg[6] = 0xFFFF0FF0|0; this.dreg[7] = 0x400; - this.cpl = 0; - this.paging = false; - this.page_size_extensions = 0; - this.is_32 = false; - this.stack_size_32 = false; - this.prefixes = 0; + this.cpl[0] = 0; + this.paging[0] = 0; + this.page_size_extensions[0] = 0; + this.is_32[0] = +false; + this.stack_size_32[0] = +false; + this.prefixes[0] = 0; - this.last_virt_eip = -1; - this.last_virt_esp = -1; + this.last_virt_eip[0] = -1; + this.last_virt_esp[0] = -1; this.update_operand_size(); - this.timestamp_counter = 0; - this.previous_ip = 0; + this.timestamp_counter[0] = 0; + this.previous_ip[0] = 0; this.in_hlt = false; - this.sysenter_cs = 0; - this.sysenter_esp = 0; - this.sysenter_eip = 0; + this.sysenter_cs[0] = 0; + this.sysenter_esp[0] = 0; + this.sysenter_eip[0] = 0; - this.flags = flags_default; - this.flags_changed = 0; + this.flags[0] = flags_default; + this.flags_changed.fill(0); - this.last_result = 0; - this.last_add_result = 0; - this.last_op1 = 0; - this.last_op2 = 0; - this.last_op_size = 0; + this.last_result.fill(0); + this.last_add_result.fill(0); + this.last_op1.fill(0); + this.last_op2.fill(0); + this.last_op_size.fill(0); - this.tsc_offset = v86.microtick(); + this.tsc_offset[0] = v86.microtick(); - this.instruction_pointer = 0xFFFF0; + this.instruction_pointer[0] = 0xFFFF0; this.switch_cs_real_mode(0xF000); this.switch_seg(reg_ss, 0x30); @@ -580,7 +618,7 @@ CPU.prototype.reset = function() this.devices.virtio.reset(); } - this.fw_value = 0; + this.fw_value[0] = 0; }; /** @export */ @@ -599,13 +637,13 @@ CPU.prototype.create_memory = function(size) dbg_assert((size | 0) > 0); dbg_assert((size & MMAP_BLOCK_SIZE - 1) === 0); - this.memory_size = size; + this.memory_size[0] = size; - var buffer = new ArrayBuffer(size); + var buffer = this.wm.mem.buffer; - this.mem8 = new Uint8Array(buffer); - this.mem16 = new Uint16Array(buffer); - this.mem32s = new Int32Array(buffer); + this.mem8 = new Uint8Array(buffer, 2048 + 0x100000 * 6); + this.mem16 = new Uint16Array(buffer, 2048 + 0x100000 * 6); + this.mem32s = new Int32Array(buffer, 2048 + 0x100000 * 6); }; CPU.prototype.init = function(settings, device_bus) @@ -645,8 +683,8 @@ CPU.prototype.init = function(settings, device_bus) io.register_read(0x511, this, function() { // bios config port (used by seabios and kvm-unit-test) - let result = this.fw_value & 0xFF; - this.fw_value >>>= 8; + let result = this.fw_value[0] & 0xFF; + this.fw_value[0] >>>= 8; return result; }); io.register_write(0x510, this, undefined, function(value) @@ -657,20 +695,20 @@ CPU.prototype.init = function(settings, device_bus) { // We could pretend to be QEMU here to control certain options in // seabios, but for now this isn't needed - this.fw_value = 0xfab0fab0|0; + this.fw_value[0] = 0xfab0fab0|0; } else if(value === FW_CFG_RAM_SIZE) { - this.fw_value = this.memory_size; + this.fw_value[0] = this.memory_size[0]; } else if(value === FW_CFG_NB_CPUS) { - this.fw_value = 1; + this.fw_value[0] = 1; } else { dbg_assert(false, "Unimplemented fw index: " + h(value)); - this.fw_value = 0; + this.fw_value[0] = 0; } }); @@ -811,10 +849,10 @@ CPU.prototype.load_multiboot = function(buffer) this.write32(multiboot_info_addr, 0); this.cr[0] = 1; - this.protected_mode = true; - this.flags = flags_default; + this.protected_mode[0] = +true; + this.flags[0] = flags_default; this.update_cs_size(true); - this.stack_size_32 = true; + this.stack_size_32[0] = +true; for(var i = 0; i < 6; i++) { @@ -860,7 +898,7 @@ CPU.prototype.load_multiboot = function(buffer) let blob = new Uint8Array(buffer, file_start, length); this.write_blob(blob, load_addr); - this.instruction_pointer = this.get_seg(reg_cs) + entry_addr | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + entry_addr | 0; } else if(buf32[0] === ELF_MAGIC) { @@ -868,7 +906,7 @@ CPU.prototype.load_multiboot = function(buffer) let elf = read_elf(buffer); - this.instruction_pointer = this.get_seg(reg_cs) + elf.header.entry | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + elf.header.entry | 0; for(let program of elf.program_headers) { @@ -964,9 +1002,9 @@ CPU.prototype.fill_cmos = function(rtc, settings) rtc.cmos_write(CMOS_MEM_BASE_HIGH, 640 >> 8); var memory_above_1m = 0; // in k - if(this.memory_size >= 1024 * 1024) + if(this.memory_size[0] >= 1024 * 1024) { - memory_above_1m = (this.memory_size - 1024 * 1024) >> 10; + memory_above_1m = (this.memory_size[0] - 1024 * 1024) >> 10; memory_above_1m = Math.min(memory_above_1m, 0xFFFF); } @@ -976,9 +1014,9 @@ CPU.prototype.fill_cmos = function(rtc, settings) rtc.cmos_write(CMOS_MEM_EXTMEM_HIGH, memory_above_1m >> 8 & 0xFF); var memory_above_16m = 0; // in 64k blocks - if(this.memory_size >= 16 * 1024 * 1024) + if(this.memory_size[0] >= 16 * 1024 * 1024) { - memory_above_16m = (this.memory_size - 16 * 1024 * 1024) >> 16; + memory_above_16m = (this.memory_size[0] - 16 * 1024 * 1024) >> 16; memory_above_16m = Math.min(memory_above_16m, 0xFFFF); } rtc.cmos_write(CMOS_MEM_EXTMEM2_LOW, memory_above_16m & 0xFF); @@ -1096,6 +1134,7 @@ CPU.prototype.do_many_cycles = function() CPU.prototype.do_many_cycles_unsafe = function() { + dbg_assert(false); // inner loop: // runs only cycles for(var k = LOOP_COUNTER; k--;) @@ -1151,9 +1190,9 @@ if(PROFILING) */ CPU.prototype.cycle_internal = function() { - this.previous_ip = this.instruction_pointer; + this.previous_ip[0] = this.instruction_pointer[0]; - this.timestamp_counter++; + this.timestamp_counter[0]++; if(PROFILING) { @@ -1165,7 +1204,7 @@ CPU.prototype.cycle_internal = function() if(DEBUG) { - this.debug.logop(this.instruction_pointer - 1 >>> 0, opcode); + this.debug.logop(this.instruction_pointer[0] - 1 >>> 0, opcode); } // call the instruction @@ -1178,7 +1217,7 @@ CPU.prototype.cycle_internal = function() instruction_count[opcode]++; } - if(this.flags & flag_trap) + if(this.flags[0] & flag_trap) { // TODO dbg_log("Trap flag: Ignored", LOG_CPU); @@ -1198,12 +1237,34 @@ CPU.prototype.cycle = function() } }; +CPU.prototype.run_instruction_0f = function() +{ + if(this.is_osize_32()) + { + this.table0F_32[this.read_op0F()](this); + } + else + { + this.table0F_16[this.read_op0F()](this); + } +}; + +CPU.prototype.dbg_log = function() +{ + dbg_log("from wasm: " + [].join.call(arguments)); +}; + +CPU.prototype.dbg_assert = function(x) +{ + dbg_assert(x); +}; + CPU.prototype.segment_prefix_op = function(sreg) { dbg_assert(sreg <= 5); - this.prefixes |= sreg + 1; + this.prefixes[0] |= sreg + 1; this.run_prefix_instruction(); - this.prefixes = 0; + this.prefixes[0] = 0; }; CPU.prototype.run_prefix_instruction = function() @@ -1220,7 +1281,7 @@ CPU.prototype.run_prefix_instruction = function() CPU.prototype.hlt_loop = function() { - dbg_assert(this.flags & flag_interrupt); + dbg_assert(this.flags[0] & flag_interrupt); //dbg_log("In HLT loop", LOG_CPU); this.run_hardware_timers(v86.microtick()); @@ -1252,7 +1313,7 @@ CPU.prototype.run_hardware_timers = function(now) CPU.prototype.clear_prefixes = function() { - this.prefixes = 0; + this.prefixes[0] = 0; }; CPU.prototype.set_cr0 = function(cr0) @@ -1276,14 +1337,13 @@ CPU.prototype.set_cr0 = function(cr0) var new_paging = (this.cr[0] & CR0_PG) === CR0_PG; - dbg_assert(typeof this.paging === "boolean"); - if(new_paging !== this.paging) + if(new_paging !== Boolean(this.paging[0])) { - this.paging = new_paging; + this.paging[0] = +new_paging; this.full_clear_tlb(); } - this.protected_mode = (this.cr[0] & CR0_PE) === CR0_PE; + this.protected_mode[0] = +((this.cr[0] & CR0_PE) === CR0_PE); }; CPU.prototype.set_cr4 = function(cr4) @@ -1309,7 +1369,7 @@ CPU.prototype.set_cr4 = function(cr4) } this.cr[4] = cr4; - this.page_size_extensions = (cr4 & CR4_PSE) ? PSE_ENABLED : 0; + this.page_size_extensions[0] = (cr4 & CR4_PSE) ? PSE_ENABLED : 0; if(cr4 & CR4_PAE) { @@ -1327,20 +1387,20 @@ CPU.prototype.set_cr4 = function(cr4) CPU.prototype.cpl_changed = function() { - this.last_virt_eip = -1; - this.last_virt_esp = -1; + this.last_virt_eip[0] = -1; + this.last_virt_esp[0] = -1; }; CPU.prototype.read_imm8 = function() { - if((this.instruction_pointer & ~0xFFF) ^ this.last_virt_eip) + if((this.instruction_pointer[0] & ~0xFFF) ^ this.last_virt_eip[0]) { - this.eip_phys = this.translate_address_read(this.instruction_pointer) ^ this.instruction_pointer; - this.last_virt_eip = this.instruction_pointer & ~0xFFF; + this.eip_phys[0] = this.translate_address_read(this.instruction_pointer[0]) ^ this.instruction_pointer[0]; + this.last_virt_eip[0] = this.instruction_pointer[0] & ~0xFFF; } - var data8 = this.read8(this.eip_phys ^ this.instruction_pointer); - this.instruction_pointer = this.instruction_pointer + 1 | 0; + var data8 = this.read8(this.eip_phys[0] ^ this.instruction_pointer[0]); + this.instruction_pointer[0] = this.instruction_pointer[0] + 1 | 0; return data8; }; @@ -1355,13 +1415,13 @@ CPU.prototype.read_imm16 = function() // Two checks in one comparison: // 1. Did the high 20 bits of eip change // or 2. Are the low 12 bits of eip 0xFFF (and this read crosses a page boundary) - if(((this.instruction_pointer ^ this.last_virt_eip) >>> 0) > 0xFFE) + if(((this.instruction_pointer[0] ^ this.last_virt_eip[0]) >>> 0) > 0xFFE) { return this.read_imm8() | this.read_imm8() << 8; } - var data16 = this.read16(this.eip_phys ^ this.instruction_pointer); - this.instruction_pointer = this.instruction_pointer + 2 | 0; + var data16 = this.read16(this.eip_phys[0] ^ this.instruction_pointer[0]); + this.instruction_pointer[0] = this.instruction_pointer[0] + 2 | 0; return data16; }; @@ -1369,13 +1429,13 @@ CPU.prototype.read_imm16 = function() CPU.prototype.read_imm32s = function() { // Analogue to the above comment - if(((this.instruction_pointer ^ this.last_virt_eip) >>> 0) > 0xFFC) + if(((this.instruction_pointer[0] ^ this.last_virt_eip[0]) >>> 0) > 0xFFC) { return this.read_imm16() | this.read_imm16() << 16; } - var data32 = this.read32s(this.eip_phys ^ this.instruction_pointer); - this.instruction_pointer = this.instruction_pointer + 4 | 0; + var data32 = this.read32s(this.eip_phys[0] ^ this.instruction_pointer[0]); + this.instruction_pointer[0] = this.instruction_pointer[0] + 4 | 0; return data32; }; @@ -1403,7 +1463,7 @@ CPU.prototype.create_atom128s = function(d0, d1, d2, d3) CPU.prototype.read_modrm_byte = function() { - this.modrm_byte = this.read_imm8(); + this.modrm_byte[0] = this.read_imm8(); }; CPU.prototype.read_op0F = CPU.prototype.read_imm8; @@ -1527,7 +1587,7 @@ CPU.prototype.safe_read8 = function(addr) CPU.prototype.safe_read16 = function(addr) { - if(this.paging && (addr & 0xFFF) === 0xFFF) + if(this.paging[0] && (addr & 0xFFF) === 0xFFF) { return this.safe_read8(addr) | this.safe_read8(addr + 1 | 0) << 8; } @@ -1539,7 +1599,7 @@ CPU.prototype.safe_read16 = function(addr) CPU.prototype.safe_read32s = function(addr) { - if(this.paging && (addr & 0xFFF) >= 0xFFD) + if(this.paging[0] && (addr & 0xFFF) >= 0xFFD) { return this.safe_read16(addr) | this.safe_read16(addr + 2 | 0) << 16; } @@ -1613,7 +1673,6 @@ CPU.prototype.safe_write32 = function(addr, value) if((addr & 0xFFF) >= 0xFFD) { - // XXX this.virt_boundary_write32(phys_low, this.translate_address_write(addr + 3 & ~3) | (addr + 3) & 3, value); } else @@ -1654,17 +1713,17 @@ CPU.prototype.read_moffs = function() CPU.prototype.getiopl = function() { - return this.flags >> 12 & 3; + return this.flags[0] >> 12 & 3; }; CPU.prototype.vm86_mode = function() { - return !!(this.flags & flag_vm); + return !!(this.flags[0] & flag_vm); }; CPU.prototype.get_eflags = function() { - return (this.flags & ~flags_all) | !!this.getcf() | !!this.getpf() << 2 | !!this.getaf() << 4 | + return (this.flags[0] & ~flags_all) | !!this.getcf() | !!this.getpf() << 2 | !!this.getaf() << 4 | !!this.getzf() << 6 | !!this.getsf() << 7 | !!this.getof() << 11; }; @@ -1676,7 +1735,7 @@ CPU.prototype.update_eflags = function(new_flags) var dont_update = flag_rf | flag_vm | flag_vip | flag_vif, clear = ~flag_vip & ~flag_vif & flags_mask; - if(this.flags & flag_vm) + if(this.flags[0] & flag_vm) { // other case needs to be handled in popf or iret dbg_assert(this.getiopl() === 3); @@ -1688,15 +1747,15 @@ CPU.prototype.update_eflags = function(new_flags) } else { - if(!this.protected_mode) dbg_assert(this.cpl === 0); + if(!this.protected_mode[0]) dbg_assert(this.cpl[0] === 0); - if(this.cpl) + if(this.cpl[0]) { // cpl > 0 // cannot update iopl dont_update |= flag_iopl; - if(this.cpl > this.getiopl()) + if(this.cpl[0] > this.getiopl()) { // cpl > iopl // cannot update interrupt flag @@ -1705,14 +1764,14 @@ CPU.prototype.update_eflags = function(new_flags) } } - this.flags = (new_flags ^ ((this.flags ^ new_flags) & dont_update)) & clear | flags_default; + this.flags[0] = (new_flags ^ ((this.flags[0] ^ new_flags) & dont_update)) & clear | flags_default; - this.flags_changed = 0; + this.flags_changed[0] = 0; }; CPU.prototype.get_stack_reg = function() { - if(this.stack_size_32) + if(this.stack_size_32[0]) { return this.reg32s[reg_esp]; } @@ -1724,7 +1783,7 @@ CPU.prototype.get_stack_reg = function() CPU.prototype.set_stack_reg = function(value) { - if(this.stack_size_32) + if(this.stack_size_32[0]) { this.reg32s[reg_esp] = value; } @@ -1736,7 +1795,7 @@ CPU.prototype.set_stack_reg = function(value) CPU.prototype.adjust_stack_reg = function(value) { - if(this.stack_size_32) + if(this.stack_size_32[0]) { this.reg32s[reg_esp] += value; } @@ -1748,7 +1807,7 @@ CPU.prototype.adjust_stack_reg = function(value) CPU.prototype.get_stack_pointer = function(mod) { - if(this.stack_size_32) + if(this.stack_size_32[0]) { return this.get_seg(reg_ss) + this.reg32s[reg_esp] + mod | 0; } @@ -1764,10 +1823,10 @@ CPU.prototype.get_stack_pointer = function(mod) */ CPU.prototype.get_real_eip = function() { - return this.instruction_pointer - this.get_seg(reg_cs) | 0; + return this.instruction_pointer[0] - this.get_seg(reg_cs) | 0; }; -CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, error_code) +CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, has_error_code, error_code) { //dbg_log("int " + h(interrupt_nr, 2) + " (" + (is_software_int ? "soft" : "hard") + "ware)", LOG_CPU); CPU_LOG_VERBOSE && this.debug.dump_state("int " + h(interrupt_nr) + " start" + @@ -1776,14 +1835,15 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er this.debug.debug_interrupt(interrupt_nr); - dbg_assert(error_code === false || typeof error_code === "number"); + dbg_assert(typeof has_error_code === "boolean"); + dbg_assert(has_error_code === false || typeof error_code === "number"); // we have to leave hlt_loop at some point, this is a // good place to do it //this.in_hlt && dbg_log("Leave HLT loop", LOG_CPU); this.in_hlt = false; - if(this.protected_mode) + if(this.protected_mode[0]) { if(this.vm86_mode() && (this.cr[4] & CR4_VME)) { @@ -1797,17 +1857,17 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er this.trigger_gp(0); } - if((interrupt_nr << 3 | 7) > this.idtr_size) + if((interrupt_nr << 3 | 7) > this.idtr_size[0]) { dbg_log(interrupt_nr, LOG_CPU); dbg_trace(LOG_CPU); throw this.debug.unimpl("#GP handler"); } - var addr = this.idtr_offset + (interrupt_nr << 3) | 0; + var addr = this.idtr_offset[0] + (interrupt_nr << 3) | 0; dbg_assert((addr & 0xFFF) < 0xFF8); - if(this.paging) + if(this.paging[0]) { addr = this.translate_address_system_read(addr); } @@ -1824,7 +1884,7 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er throw this.debug.unimpl("#NP handler"); } - if(is_software_int && dpl < this.cpl) + if(is_software_int && dpl < this.cpl[0]) { dbg_log("#gp software interrupt (" + h(interrupt_nr, 2) + ") and dpl < cpl", LOG_CPU); dbg_trace(LOG_CPU); @@ -1864,7 +1924,7 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er dbg_log("is null"); throw this.debug.unimpl("#GP handler"); } - if(!info.is_executable || info.dpl > this.cpl) + if(!info.is_executable || info.dpl > this.cpl[0]) { dbg_log("not exec"); throw this.debug.unimpl("#GP handler"); @@ -1878,9 +1938,9 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er var old_flags = this.get_eflags(); - //dbg_log("interrupt " + h(interrupt_nr, 2) + " (" + (is_software_int ? "soft" : "hard") + "ware) from cpl=" + this.cpl + " vm=" + (this.flags & flag_vm) + " cs:eip=" + h(this.sreg[reg_cs], 4) + ":" + h(this.get_real_eip(), 8) + " to cpl=" + //dbg_log("interrupt " + h(interrupt_nr, 2) + " (" + (is_software_int ? "soft" : "hard") + "ware) from cpl=" + this.cpl[0] + " vm=" + (this.flags[0] & flag_vm) + " cs:eip=" + h(this.sreg[reg_cs], 4) + ":" + h(this.get_real_eip(), 8) + " to cpl=" - if(!info.dc_bit && info.dpl < this.cpl) + if(!info.dc_bit && info.dpl < this.cpl[0]) { // inter privilege level interrupt // interrupt from vm86 mode @@ -1935,7 +1995,7 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er dbg_assert(info.dpl === 0, "switch to non-0 dpl from vm86 mode"); } - var stack_space = (is_16 ? 2 : 4) * (5 + (error_code !== false) + 4 * ((old_flags & flag_vm) === flag_vm)); + var stack_space = (is_16 ? 2 : 4) * (5 + (has_error_code === true) + 4 * ((old_flags & flag_vm) === flag_vm)); var new_stack_pointer = ss_info.base + (ss_info.size ? new_esp - stack_space : (new_esp - stack_space & 0xFFFF)); // XXX: with new cpl or with cpl 0? @@ -1944,12 +2004,12 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er // no exceptions below - this.cpl = info.dpl; + this.cpl[0] = info.dpl; this.cpl_changed(); this.update_cs_size(info.size); - this.flags &= ~flag_vm & ~flag_rf; + this.flags[0] &= ~flag_vm & ~flag_rf; this.switch_seg(reg_ss, new_ss); this.set_stack_reg(new_esp); @@ -1980,22 +2040,22 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er this.push32(old_esp); } } - else if(info.dc_bit || info.dpl === this.cpl) + else if(info.dc_bit || info.dpl === this.cpl[0]) { // intra privilege level interrupt //dbg_log("Intra privilege interrupt gate=" + h(selector, 4) + ":" + h(base >>> 0, 8) + // " trap=" + is_trap + " 16bit=" + is_16 + - // " cpl=" + this.cpl + " dpl=" + info.dpl + " conforming=" + +info.dc_bit, LOG_CPU); - //this.debug.dump_regs(); + // " cpl=" + this.cpl[0] + " dpl=" + info.dpl + " conforming=" + +info.dc_bit, LOG_CPU); + //this.debug.dump_regs_short(); - if(this.flags & flag_vm) + if(this.flags[0] & flag_vm) { dbg_assert(false, "check error code"); this.trigger_gp(selector & ~3); } - var stack_space = (is_16 ? 2 : 4) * (3 + (error_code !== false)); + var stack_space = (is_16 ? 2 : 4) * (3 + (has_error_code === true)); // XXX: with current cpl or with cpl 0? this.writable_or_pagefault(this.get_stack_pointer(-stack_space), stack_space); @@ -2013,7 +2073,7 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er this.push16(this.sreg[reg_cs]); this.push16(this.get_real_eip()); - if(error_code !== false) + if(has_error_code === true) { this.push16(error_code); } @@ -2026,7 +2086,7 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er this.push32(this.sreg[reg_cs]); this.push32(this.get_real_eip()); - if(error_code !== false) + if(has_error_code === true) { this.push32(error_code); } @@ -2040,22 +2100,22 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er this.switch_seg(reg_es, 0); } - this.sreg[reg_cs] = selector & ~3 | this.cpl; - dbg_assert((this.sreg[reg_cs] & 3) === this.cpl); + this.sreg[reg_cs] = selector & ~3 | this.cpl[0]; + dbg_assert((this.sreg[reg_cs] & 3) === this.cpl[0]); this.update_cs_size(info.size); this.segment_limits[reg_cs] = info.effective_limit; this.segment_offsets[reg_cs] = info.base; - this.instruction_pointer = this.get_seg(reg_cs) + base | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + base | 0; - this.flags &= ~flag_nt & ~flag_vm & ~flag_rf & ~flag_trap; + this.flags[0] &= ~flag_nt & ~flag_vm & ~flag_rf & ~flag_trap; if(!is_trap) { // clear int flag for interrupt gates - this.flags &= ~flag_interrupt; + this.flags[0] &= ~flag_interrupt; } else { @@ -2078,10 +2138,10 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er this.push16(this.sreg[reg_cs]); this.push16(this.get_real_eip()); - this.flags &= ~flag_interrupt; + this.flags[0] &= ~flag_interrupt; this.switch_cs_real_mode(new_cs); - this.instruction_pointer = this.get_seg(reg_cs) + new_ip | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + new_ip | 0; } //dbg_log("int to:", LOG_CPU); @@ -2124,7 +2184,7 @@ CPU.prototype.iret = function(is_16) var new_flags = this.safe_read32s(this.get_stack_pointer(8)); } - if(!this.protected_mode || (this.vm86_mode() && this.getiopl() === 3)) + if(!this.protected_mode[0] || (this.vm86_mode() && this.getiopl() === 3)) { if(new_eip & 0xFFFF0000) { @@ -2132,11 +2192,11 @@ CPU.prototype.iret = function(is_16) } this.switch_cs_real_mode(new_cs); - this.instruction_pointer = new_eip + this.get_seg(reg_cs) | 0; + this.instruction_pointer[0] = new_eip + this.get_seg(reg_cs) | 0; if(is_16) { - this.update_eflags(new_flags | this.flags & ~0xFFFF); + this.update_eflags(new_flags | this.flags[0] & ~0xFFFF); this.adjust_stack_reg(3 * 2); } else @@ -2154,7 +2214,7 @@ CPU.prototype.iret = function(is_16) dbg_assert(!this.vm86_mode()); - if(this.flags & flag_nt) + if(this.flags[0] & flag_nt) { if(DEBUG) throw this.debug.unimpl("nt"); this.trigger_gp(0); @@ -2162,7 +2222,7 @@ CPU.prototype.iret = function(is_16) if(new_flags & flag_vm) { - if(this.cpl === 0) + if(this.cpl[0] === 0) { // return to virtual 8086 mode @@ -2187,10 +2247,10 @@ CPU.prototype.iret = function(is_16) // no exceptions below this.update_eflags(new_flags); - this.flags |= flag_vm; + this.flags[0] |= flag_vm; this.switch_cs_real_mode(new_cs); - this.instruction_pointer = (new_eip & 0xFFFF) + this.get_seg(reg_cs) | 0; + this.instruction_pointer[0] = (new_eip & 0xFFFF) + this.get_seg(reg_cs) | 0; this.switch_seg(reg_es, new_es); this.switch_seg(reg_ds, new_ds); @@ -2202,7 +2262,7 @@ CPU.prototype.iret = function(is_16) this.reg32s[reg_esp] = temp_esp; this.switch_seg(reg_ss, temp_ss); - this.cpl = 3; + this.cpl[0] = 3; this.cpl_changed(); this.update_cs_size(false); @@ -2239,7 +2299,7 @@ CPU.prototype.iret = function(is_16) { throw this.debug.unimpl("not exec"); } - if(info.rpl < this.cpl) + if(info.rpl < this.cpl[0]) { throw this.debug.unimpl("rpl < cpl"); } @@ -2254,7 +2314,7 @@ CPU.prototype.iret = function(is_16) this.trigger_gp(new_cs & ~3); } - if(info.rpl > this.cpl) + if(info.rpl > this.cpl[0]) { // outer privilege return if(is_16) @@ -2300,42 +2360,42 @@ CPU.prototype.iret = function(is_16) if(is_16) { - this.update_eflags(new_flags | this.flags & ~0xFFFF); + this.update_eflags(new_flags | this.flags[0] & ~0xFFFF); } else { this.update_eflags(new_flags); } - this.cpl = info.rpl; + this.cpl[0] = info.rpl; this.cpl_changed(); - //dbg_log("outer privilege return: from=" + this.cpl + " to=" + info.rpl + " ss:esp=" + h(temp_ss, 4) + ":" + h(temp_esp >>> 0, 8), LOG_CPU); + //dbg_log("outer privilege return: from=" + this.cpl[0] + " to=" + info.rpl + " ss:esp=" + h(temp_ss, 4) + ":" + h(temp_esp >>> 0, 8), LOG_CPU); this.switch_seg(reg_ss, temp_ss); this.set_stack_reg(temp_esp); - if(this.cpl === 0) + if(this.cpl[0] === 0) { - this.flags = this.flags & ~flag_vif & ~flag_vip | (new_flags & (flag_vif | flag_vip)); + this.flags[0] = this.flags[0] & ~flag_vif & ~flag_vip | (new_flags & (flag_vif | flag_vip)); } // XXX: Set segment to 0 if it's not usable in the new cpl // XXX: Use cached segment information //var ds_info = this.lookup_segment_selector(this.sreg[reg_ds]); - //if(this.cpl > ds_info.dpl && (!ds_info.is_executable || !ds_info.dc_bit)) this.switch_seg(reg_ds, 0); + //if(this.cpl[0] > ds_info.dpl && (!ds_info.is_executable || !ds_info.dc_bit)) this.switch_seg(reg_ds, 0); // ... } - else if(info.rpl === this.cpl) + else if(info.rpl === this.cpl[0]) { // same privilege return // no exceptions below if(is_16) { this.adjust_stack_reg(3 * 2); - this.update_eflags(new_flags | this.flags & ~0xFFFF); + this.update_eflags(new_flags | this.flags[0] & ~0xFFFF); } else { @@ -2344,9 +2404,9 @@ CPU.prototype.iret = function(is_16) } // update vip and vif, which are not changed by update_eflags - if(this.cpl === 0) + if(this.cpl[0] === 0) { - this.flags = this.flags & ~flag_vif & ~flag_vip | (new_flags & (flag_vif | flag_vip)); + this.flags[0] = this.flags[0] & ~flag_vif & ~flag_vip | (new_flags & (flag_vif | flag_vip)); } } else @@ -2355,14 +2415,14 @@ CPU.prototype.iret = function(is_16) } this.sreg[reg_cs] = new_cs; - dbg_assert((new_cs & 3) === this.cpl); + dbg_assert((new_cs & 3) === this.cpl[0]); this.update_cs_size(info.size); this.segment_limits[reg_cs] = info.effective_limit; this.segment_offsets[reg_cs] = info.base; - this.instruction_pointer = new_eip + this.get_seg(reg_cs) | 0; + this.instruction_pointer[0] = new_eip + this.get_seg(reg_cs) | 0; CPU_LOG_VERBOSE && this.debug.dump_state("iret" + (is_16 ? "16" : "32") + " end"); @@ -2371,7 +2431,7 @@ CPU.prototype.iret = function(is_16) CPU.prototype.switch_cs_real_mode = function(selector) { - dbg_assert(!this.protected_mode || this.vm86_mode()); + dbg_assert(!this.protected_mode[0] || this.vm86_mode()); this.sreg[reg_cs] = selector; this.segment_is_null[reg_cs] = 0; @@ -2385,16 +2445,16 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust) //dbg_log("far return eip=" + h(eip >>> 0, 8) + " cs=" + h(selector, 4) + " stack_adjust=" + h(stack_adjust), LOG_CPU); CPU_LOG_VERBOSE && this.debug.dump_state("far ret start"); - if(!this.protected_mode) + if(!this.protected_mode[0]) { - dbg_assert(!this.is_32); - //dbg_assert(!this.stack_size_32); + dbg_assert(!this.is_32[0]); + //dbg_assert(!this.stack_size_32[0]); } - if(!this.protected_mode || this.vm86_mode()) + if(!this.protected_mode[0] || this.vm86_mode()) { this.switch_cs_real_mode(selector); - this.instruction_pointer = this.get_seg(reg_cs) + eip | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + eip | 0; this.adjust_stack_reg(2 * (this.is_osize_32() ? 4 : 2) + stack_adjust); return; } @@ -2425,7 +2485,7 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust) this.trigger_gp(selector & ~3); } - if(info.rpl < this.cpl) + if(info.rpl < this.cpl[0]) { dbg_log("cs rpl < cpl: " + h(selector), LOG_CPU); this.trigger_gp(selector & ~3); @@ -2450,9 +2510,9 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust) this.trigger_np(selector & ~3); } - if(info.rpl > this.cpl) + if(info.rpl > this.cpl[0]) { - dbg_log("far return privilege change cs: " + h(selector) + " from=" + this.cpl + " to=" + info.rpl + " is_16=" + this.is_osize_32(), LOG_CPU); + dbg_log("far return privilege change cs: " + h(selector) + " from=" + this.cpl[0] + " to=" + info.rpl + " is_16=" + this.is_osize_32(), LOG_CPU); if(this.is_osize_32()) { @@ -2469,7 +2529,7 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust) var temp_ss = this.safe_read16(this.get_stack_pointer(stack_adjust + 6)); } - this.cpl = info.rpl; + this.cpl[0] = info.rpl; this.cpl_changed(); // XXX: Can raise, conditions should be checked before side effects @@ -2501,7 +2561,7 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust) } } - //dbg_assert(this.cpl === info.dpl); + //dbg_assert(this.cpl[0] === info.dpl); this.update_cs_size(info.size); @@ -2511,10 +2571,9 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust) this.segment_offsets[reg_cs] = info.base; this.sreg[reg_cs] = selector; + dbg_assert((selector & 3) === this.cpl[0]); - dbg_assert((selector & 3) === this.cpl); - - this.instruction_pointer = this.get_seg(reg_cs) + eip | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + eip | 0; //dbg_log("far return to:", LOG_CPU) CPU_LOG_VERBOSE && this.debug.dump_state("far ret end"); @@ -2522,12 +2581,13 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust) CPU.prototype.far_jump = function(eip, selector, is_call) { + is_call = !!is_call; dbg_assert(typeof selector === "number" && selector < 0x10000 && selector >= 0); //dbg_log("far " + ["jump", "call"][+is_call] + " eip=" + h(eip >>> 0, 8) + " cs=" + h(selector, 4), LOG_CPU); CPU_LOG_VERBOSE && this.debug.dump_state("far " + ["jump", "call"][+is_call]); - if(!this.protected_mode || this.vm86_mode()) + if(!this.protected_mode[0] || this.vm86_mode()) { if(is_call) { @@ -2545,7 +2605,7 @@ CPU.prototype.far_jump = function(eip, selector, is_call) } } this.switch_cs_real_mode(selector); - this.instruction_pointer = this.get_seg(reg_cs) + eip | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + eip | 0; return; } @@ -2574,7 +2634,7 @@ CPU.prototype.far_jump = function(eip, selector, is_call) // call gate var is_16 = info.type === 4; - if(info.dpl < this.cpl || info.dpl < info.rpl) + if(info.dpl < this.cpl[0] || info.dpl < info.rpl) { dbg_log("#gp cs gate dpl < cpl or dpl < rpl: " + h(selector), LOG_CPU); this.trigger_gp(selector & ~3); @@ -2607,7 +2667,7 @@ CPU.prototype.far_jump = function(eip, selector, is_call) this.trigger_gp(cs_selector & ~3); } - if(cs_info.dpl > this.cpl) + if(cs_info.dpl > this.cpl[0]) { dbg_log("#gp dpl > cpl: " + h(cs_selector), LOG_CPU); this.trigger_gp(cs_selector & ~3); @@ -2619,9 +2679,9 @@ CPU.prototype.far_jump = function(eip, selector, is_call) this.trigger_np(cs_selector & ~3); } - if(!cs_info.dc_bit && cs_info.dpl < this.cpl) + if(!cs_info.dc_bit && cs_info.dpl < this.cpl[0]) { - dbg_log("more privilege call gate is_16=" + is_16 + " from=" + this.cpl + " to=" + cs_info.dpl); + dbg_log("more privilege call gate is_16=" + is_16 + " from=" + this.cpl[0] + " to=" + cs_info.dpl); var tss_stack_addr = this.get_tss_stack_addr(cs_info.dpl); if(this.tss_size_32) @@ -2685,7 +2745,7 @@ CPU.prototype.far_jump = function(eip, selector, is_call) //dbg_log("old_esp=" + h(old_esp)); - this.cpl = cs_info.dpl; + this.cpl[0] = cs_info.dpl; this.cpl_changed(); this.update_cs_size(cs_info.size); @@ -2739,7 +2799,7 @@ CPU.prototype.far_jump = function(eip, selector, is_call) } else { - dbg_log("same privilege call gate is_16=" + is_16 + " from=" + this.cpl + " to=" + cs_info.dpl + " conforming=" + cs_info.dc_bit); + dbg_log("same privilege call gate is_16=" + is_16 + " from=" + this.cpl[0] + " to=" + cs_info.dpl + " conforming=" + cs_info.dc_bit); // ok if(is_call) @@ -2775,10 +2835,10 @@ CPU.prototype.far_jump = function(eip, selector, is_call) this.segment_limits[reg_cs] = cs_info.effective_limit; //this.segment_infos[reg_cs] = 0; // TODO this.segment_offsets[reg_cs] = cs_info.base; - this.sreg[reg_cs] = cs_selector & ~3 | this.cpl; - dbg_assert((this.sreg[reg_cs] & 3) === this.cpl); + this.sreg[reg_cs] = cs_selector & ~3 | this.cpl[0]; + dbg_assert((this.sreg[reg_cs] & 3) === this.cpl[0]); - this.instruction_pointer = this.get_seg(reg_cs) + new_eip | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + new_eip | 0; } else { @@ -2797,7 +2857,7 @@ CPU.prototype.far_jump = function(eip, selector, is_call) if(info.dc_bit) { // conforming code segment - if(info.dpl > this.cpl) + if(info.dpl > this.cpl[0]) { dbg_log("#gp cs dpl > cpl: " + h(selector), LOG_CPU); this.trigger_gp(selector & ~3); @@ -2807,7 +2867,7 @@ CPU.prototype.far_jump = function(eip, selector, is_call) { // non-conforming code segment - if(info.rpl > this.cpl || info.dpl !== this.cpl) + if(info.rpl > this.cpl[0] || info.dpl !== this.cpl[0]) { dbg_log("#gp cs rpl > cpl or dpl != cpl: " + h(selector), LOG_CPU); this.trigger_gp(selector & ~3); @@ -2846,9 +2906,9 @@ CPU.prototype.far_jump = function(eip, selector, is_call) //this.segment_infos[reg_cs] = 0; // TODO this.segment_offsets[reg_cs] = info.base; - this.sreg[reg_cs] = selector & ~3 | this.cpl; + this.sreg[reg_cs] = selector & ~3 | this.cpl[0]; - this.instruction_pointer = this.get_seg(reg_cs) + eip | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + eip | 0; } //dbg_log("far " + ["jump", "call"][+is_call] + " to:", LOG_CPU) @@ -2883,7 +2943,7 @@ CPU.prototype.get_tss_stack_addr = function(dpl) dbg_assert((tss_stack_addr & 0xFFF) <= 0x1000 - 4); } - if(this.paging) + if(this.paging[0]) { tss_stack_addr = this.translate_address_system_read(tss_stack_addr); } @@ -2978,7 +3038,7 @@ CPU.prototype.do_task_switch = function(selector, error_code) var new_cr3 = this.safe_read32s(new_tsr_offset + TSR_CR3); - this.flags &= ~flag_vm; + this.flags[0] &= ~flag_vm; var new_eip = this.safe_read32s(new_tsr_offset + TSR_EIP); var new_cs = this.safe_read16(new_tsr_offset + TSR_CS); @@ -3054,7 +3114,7 @@ CPU.prototype.do_task_switch = function(selector, error_code) if(true /* call or int */) { - this.flags |= flag_nt; + this.flags[0] |= flag_nt; } var new_ldt = this.safe_read16(new_tsr_offset + TSR_LDT); @@ -3076,7 +3136,7 @@ CPU.prototype.do_task_switch = function(selector, error_code) this.switch_seg(reg_fs, this.safe_read16(new_tsr_offset + TSR_FS)); this.switch_seg(reg_gs, this.safe_read16(new_tsr_offset + TSR_GS)); - this.instruction_pointer = this.get_seg(reg_cs) + new_eip | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + new_eip | 0; this.segment_offsets[reg_tr] = descriptor.base; this.segment_limits[reg_tr] = descriptor.effective_limit; @@ -3103,12 +3163,12 @@ CPU.prototype.do_task_switch = function(selector, error_code) CPU.prototype.hlt_op = function() { - if(this.cpl) + if(this.cpl[0]) { this.trigger_gp(0); } - if((this.flags & flag_interrupt) === 0) + if((this.flags[0] & flag_interrupt) === 0) { this.debug.show("cpu halted"); this.bus.send("cpu-event-halt"); @@ -3148,7 +3208,7 @@ CPU.prototype.raise_exception = function(interrupt_nr) // this.debug.dump_state(); //} - this.call_interrupt_vector(interrupt_nr, false, false); + this.call_interrupt_vector(interrupt_nr, false, false, 0); throw MAGIC_CPU_EXCEPTION; }; @@ -3163,49 +3223,49 @@ CPU.prototype.raise_exception_with_code = function(interrupt_nr, error_code) // this.debug.dump_regs(); //} - this.call_interrupt_vector(interrupt_nr, false, error_code); + this.call_interrupt_vector(interrupt_nr, false, true, error_code); throw MAGIC_CPU_EXCEPTION; }; CPU.prototype.trigger_de = function() { - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; this.raise_exception(0); }; CPU.prototype.trigger_ud = function() { - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; this.raise_exception(6); }; CPU.prototype.trigger_nm = function() { - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; this.raise_exception(7); }; CPU.prototype.trigger_ts = function(code) { - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; this.raise_exception_with_code(10, code); }; CPU.prototype.trigger_gp = function(code) { - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; this.raise_exception_with_code(13, code); }; CPU.prototype.trigger_np = function(code) { - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; this.raise_exception_with_code(11, code); }; CPU.prototype.trigger_ss = function(code) { - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; this.raise_exception_with_code(12, code); }; @@ -3259,19 +3319,29 @@ CPU.prototype.unimplemented_sse = function() this.trigger_ud(); }; -CPU.prototype.get_seg_prefix_ds = function() +CPU.prototype.unimplemented_sse_wasm = function() { - return this.get_seg_prefix(reg_ds); + this.instruction_pointer[0] -= 1; + + this.table0F_32[this.read_op0F()](this); }; -CPU.prototype.get_seg_prefix_ss = function() +CPU.prototype.get_seg_prefix_ds = function(offset) { - return this.get_seg_prefix(reg_ss); + offset = offset || 0; + return this.get_seg_prefix(reg_ds) + offset | 0; }; -CPU.prototype.get_seg_prefix_cs = function() +CPU.prototype.get_seg_prefix_ss = function(offset) { - return this.get_seg_prefix(reg_cs); + offset = offset || 0; + return this.get_seg_prefix(reg_ss) + offset | 0; +}; + +CPU.prototype.get_seg_prefix_cs = function(offset) +{ + offset = offset || 0; + return this.get_seg_prefix(reg_cs) + offset | 0; }; /** @@ -3280,7 +3350,7 @@ CPU.prototype.get_seg_prefix_cs = function() */ CPU.prototype.get_seg_prefix = function(default_segment /*, offset*/) { - var prefix = this.prefixes & PREFIX_MASK_SEGMENT; + var prefix = this.prefixes[0] & PREFIX_MASK_SEGMENT; if(prefix) { @@ -3307,7 +3377,7 @@ CPU.prototype.get_seg = function(segment /*, offset*/) { dbg_assert(segment >= 0 && segment < 8); - if(this.protected_mode) + if(this.protected_mode[0]) { if(this.segment_is_null[segment]) { @@ -3328,10 +3398,11 @@ CPU.prototype.get_seg = function(segment /*, offset*/) CPU.prototype.read_e8 = function() { - if(this.modrm_byte < 0xC0) { - return this.safe_read8(this.modrm_resolve(this.modrm_byte)); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + return this.safe_read8(this.modrm_resolve(modrm_byte)); } else { - return this.reg8[this.modrm_byte << 2 & 0xC | this.modrm_byte >> 2 & 1]; + return this.wm.funcs['_read_e8_partial_branch'](); } }; @@ -3342,10 +3413,11 @@ CPU.prototype.read_e8s = function() CPU.prototype.read_e16 = function() { - if(this.modrm_byte < 0xC0) { - return this.safe_read16(this.modrm_resolve(this.modrm_byte)); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + return this.safe_read16(this.modrm_resolve(modrm_byte)); } else { - return this.reg16[this.modrm_byte << 1 & 14]; + return this.reg16[modrm_byte << 1 & 14]; } }; @@ -3356,10 +3428,11 @@ CPU.prototype.read_e16s = function() CPU.prototype.read_e32s = function() { - if(this.modrm_byte < 0xC0) { - return this.safe_read32s(this.modrm_resolve(this.modrm_byte)); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + return this.safe_read32s(this.modrm_resolve(modrm_byte)); } else { - return this.reg32s[this.modrm_byte & 7]; + return this.reg32s[modrm_byte & 7]; } }; @@ -3435,31 +3508,34 @@ CPU.prototype.read_xmm_mem128s_unaligned = function() CPU.prototype.set_e8 = function(value) { - if(this.modrm_byte < 0xC0) { - var addr = this.modrm_resolve(this.modrm_byte); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + var addr = this.modrm_resolve(modrm_byte); this.safe_write8(addr, value); } else { - this.reg8[this.modrm_byte << 2 & 0xC | this.modrm_byte >> 2 & 1] = value; + this.reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = value; } }; CPU.prototype.set_e16 = function(value) { - if(this.modrm_byte < 0xC0) { - var addr = this.modrm_resolve(this.modrm_byte); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + var addr = this.modrm_resolve(modrm_byte); this.safe_write16(addr, value); } else { - this.reg16[this.modrm_byte << 1 & 14] = value; + this.reg16[modrm_byte << 1 & 14] = value; } }; CPU.prototype.set_e32 = function(value) { - if(this.modrm_byte < 0xC0) { - var addr = this.modrm_resolve(this.modrm_byte); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + var addr = this.modrm_resolve(modrm_byte); this.safe_write32(addr, value); } else { - this.reg32s[this.modrm_byte & 7] = value; + this.reg32s[modrm_byte & 7] = value; } }; @@ -3476,141 +3552,147 @@ CPU.prototype.set_mmx_mem64s = function(low, high) CPU.prototype.read_write_e8 = function() { - if(this.modrm_byte < 0xC0) { - var virt_addr = this.modrm_resolve(this.modrm_byte); - this.phys_addr = this.translate_address_write(virt_addr); - return this.read8(this.phys_addr); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + var virt_addr = this.modrm_resolve(modrm_byte); + this.phys_addr[0] = this.translate_address_write(virt_addr); + return this.read8(this.phys_addr[0]); } else { - return this.reg8[this.modrm_byte << 2 & 0xC | this.modrm_byte >> 2 & 1]; + return this.reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; } }; CPU.prototype.write_e8 = function(value) { - if(this.modrm_byte < 0xC0) { - this.write8(this.phys_addr, value); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + this.write8(this.phys_addr[0], value); } else { - this.reg8[this.modrm_byte << 2 & 0xC | this.modrm_byte >> 2 & 1] = value; + this.reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = value; } }; CPU.prototype.read_write_e16 = function() { - if(this.modrm_byte < 0xC0) { - var virt_addr = this.modrm_resolve(this.modrm_byte); - this.phys_addr = this.translate_address_write(virt_addr); - if(this.paging && (virt_addr & 0xFFF) === 0xFFF) { - this.phys_addr_high = this.translate_address_write(virt_addr + 1 | 0); - dbg_assert(this.phys_addr_high); - return this.virt_boundary_read16(this.phys_addr, this.phys_addr_high); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + var virt_addr = this.modrm_resolve(modrm_byte); + this.phys_addr[0] = this.translate_address_write(virt_addr); + if(this.paging[0] && (virt_addr & 0xFFF) === 0xFFF) { + this.phys_addr_high[0] = this.translate_address_write(virt_addr + 1 | 0); + dbg_assert(this.phys_addr_high[0]); + return this.virt_boundary_read16(this.phys_addr[0], this.phys_addr_high[0]); } else { - this.phys_addr_high = 0; - return this.read16(this.phys_addr); + this.phys_addr_high[0] = 0; + return this.read16(this.phys_addr[0]); } } else { - return this.reg16[this.modrm_byte << 1 & 14]; + return this.reg16[modrm_byte << 1 & 14]; } }; CPU.prototype.write_e16 = function(value) { - if(this.modrm_byte < 0xC0) { - if(this.phys_addr_high) { - this.virt_boundary_write16(this.phys_addr, this.phys_addr_high, value); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + if(this.phys_addr_high[0]) { + this.virt_boundary_write16(this.phys_addr[0], this.phys_addr_high[0], value); } else { - this.write16(this.phys_addr, value); + this.write16(this.phys_addr[0], value); } } else { - this.reg16[this.modrm_byte << 1 & 14] = value; + this.reg16[modrm_byte << 1 & 14] = value; } }; CPU.prototype.read_write_e32 = function() { - if(this.modrm_byte < 0xC0) { - var virt_addr = this.modrm_resolve(this.modrm_byte); - this.phys_addr = this.translate_address_write(virt_addr); - if(this.paging && (virt_addr & 0xFFF) >= 0xFFD) { - //this.phys_addr_high = this.translate_address_write(virt_addr + 3 | 0); - this.phys_addr_high = this.translate_address_write(virt_addr + 3 & ~3) | (virt_addr + 3) & 3; - dbg_assert(this.phys_addr_high); - return this.virt_boundary_read32s(this.phys_addr, this.phys_addr_high); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + var virt_addr = this.modrm_resolve(modrm_byte); + this.phys_addr[0] = this.translate_address_write(virt_addr); + if(this.paging[0] && (virt_addr & 0xFFF) >= 0xFFD) { + //this.phys_addr_high[0] = this.translate_address_write(virt_addr + 3 | 0); + this.phys_addr_high[0] = this.translate_address_write(virt_addr + 3 & ~3) | (virt_addr + 3) & 3; + dbg_assert(this.phys_addr_high[0]); + return this.virt_boundary_read32s(this.phys_addr[0], this.phys_addr_high[0]); } else { - this.phys_addr_high = 0; - return this.read32s(this.phys_addr); + this.phys_addr_high[0] = 0; + return this.read32s(this.phys_addr[0]); } } else { - return this.reg32s[this.modrm_byte & 7]; + return this.reg32s[modrm_byte & 7]; } }; CPU.prototype.write_e32 = function(value) { - if(this.modrm_byte < 0xC0) { - if(this.phys_addr_high) { - this.virt_boundary_write32(this.phys_addr, this.phys_addr_high, value); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + if(this.phys_addr_high[0]) { + this.virt_boundary_write32(this.phys_addr[0], this.phys_addr_high[0], value); } else { - this.write32(this.phys_addr, value); + this.write32(this.phys_addr[0], value); } } else { - this.reg32s[this.modrm_byte & 7] = value; + this.reg32s[modrm_byte & 7] = value; } }; CPU.prototype.read_reg_e16 = function() { - return this.reg16[this.modrm_byte << 1 & 14]; + return this.reg16[this.modrm_byte[0] << 1 & 14]; }; CPU.prototype.write_reg_e16 = function(value) { - this.reg16[this.modrm_byte << 1 & 14] = value; + this.reg16[this.modrm_byte[0] << 1 & 14] = value; }; CPU.prototype.read_reg_e32s = function() { - return this.reg32s[this.modrm_byte & 7]; + return this.reg32s[this.modrm_byte[0] & 7]; }; CPU.prototype.write_reg_e32 = function(value) { - this.reg32s[this.modrm_byte & 7] = value; + this.reg32s[this.modrm_byte[0] & 7] = value; }; CPU.prototype.read_g8 = function() { - return this.reg8[this.modrm_byte >> 1 & 0xC | this.modrm_byte >> 5 & 1]; + return this.reg8[this.modrm_byte[0] >> 1 & 0xC | this.modrm_byte[0] >> 5 & 1]; }; CPU.prototype.write_g8 = function(value) { - this.reg8[this.modrm_byte >> 1 & 0xC | this.modrm_byte >> 5 & 1] = value; + this.reg8[this.modrm_byte[0] >> 1 & 0xC | this.modrm_byte[0] >> 5 & 1] = value; }; CPU.prototype.read_g16 = function() { - return this.reg16[this.modrm_byte >> 2 & 14]; + return this.reg16[this.modrm_byte[0] >> 2 & 14]; }; CPU.prototype.read_g16s = function() { - return this.reg16s[this.modrm_byte >> 2 & 14]; + return this.reg16s[this.modrm_byte[0] >> 2 & 14]; }; CPU.prototype.write_g16 = function(value) { - this.reg16[this.modrm_byte >> 2 & 14] = value; + this.reg16[this.modrm_byte[0] >> 2 & 14] = value; }; CPU.prototype.read_g32s = function() { - return this.reg32s[this.modrm_byte >> 3 & 7]; + return this.reg32s[this.modrm_byte[0] >> 3 & 7]; }; CPU.prototype.write_g32 = function(value) { - this.reg32[this.modrm_byte >> 3 & 7] = value; + this.reg32[this.modrm_byte[0] >> 3 & 7] = value; }; CPU.prototype.read_xmm64s = function() @@ -3666,8 +3748,8 @@ CPU.prototype.pic_call_irq = function(int) { try { - this.previous_ip = this.instruction_pointer; - this.call_interrupt_vector(int, false, false); + this.previous_ip[0] = this.instruction_pointer[0]; + this.call_interrupt_vector(int, false, false, 0); } catch(e) { @@ -3681,7 +3763,7 @@ CPU.prototype.handle_irqs = function() this.diverged(); - if((this.flags & flag_interrupt) && !this.page_fault) + if((this.flags[0] & flag_interrupt) && !this.page_fault) { if(this.devices.pic) { @@ -3724,7 +3806,7 @@ CPU.prototype.device_lower_irq = function(i) CPU.prototype.test_privileges_for_io = function(port, size) { - if(this.protected_mode && (this.cpl > this.getiopl() || (this.flags & flag_vm))) + if(this.protected_mode[0] && (this.cpl[0] > this.getiopl() || (this.flags[0] & flag_vm))) { if(!this.tss_size_32) { @@ -3887,19 +3969,19 @@ CPU.prototype.cpuid = function() CPU.prototype.update_cs_size = function(new_size) { - dbg_assert(typeof new_size === "boolean"); + new_size = Boolean(new_size); - if(this.is_32 !== new_size) + if(Boolean(this.is_32[0]) !== new_size) { this.clear_instruction_cache(); - this.is_32 = new_size; + this.is_32[0] = +new_size; this.update_operand_size(); } }; CPU.prototype.update_operand_size = function() { - if(this.is_32) + if(this.is_32[0]) { this.table = this.table32; } @@ -3955,8 +4037,8 @@ CPU.prototype.lookup_segment_selector = function(selector) if(is_gdt) { - table_offset = this.gdtr_offset; - table_limit = this.gdtr_size; + table_offset = this.gdtr_offset[0]; + table_limit = this.gdtr_size[0]; } else { @@ -3981,7 +4063,7 @@ CPU.prototype.lookup_segment_selector = function(selector) table_offset = table_offset + selector_offset | 0; - if(this.paging) + if(this.paging[0]) { table_offset = this.translate_address_system_read(table_offset); } @@ -4041,7 +4123,7 @@ CPU.prototype.switch_seg = function(reg, selector) dbg_assert(reg >= 0 && reg <= 5); dbg_assert(typeof selector === "number" && selector < 0x10000 && selector >= 0); - if(!this.protected_mode || this.vm86_mode()) + if(!this.protected_mode[0] || this.vm86_mode()) { this.sreg[reg] = selector; this.segment_is_null[reg] = 0; @@ -4049,7 +4131,7 @@ CPU.prototype.switch_seg = function(reg, selector) if(reg === reg_ss) { - this.stack_size_32 = false; + this.stack_size_32[0] = +false; } return; } @@ -4067,9 +4149,9 @@ CPU.prototype.switch_seg = function(reg, selector) if(!info.is_valid || info.is_system || - info.rpl !== this.cpl || + info.rpl !== this.cpl[0] || !info.is_writable || - info.dpl !== this.cpl) + info.dpl !== this.cpl[0]) { dbg_log("#GP for loading invalid in SS sel=" + h(selector, 4), LOG_CPU); dbg_trace(LOG_CPU); @@ -4083,7 +4165,7 @@ CPU.prototype.switch_seg = function(reg, selector) this.trigger_ss(selector & ~3); } - this.stack_size_32 = info.size; + this.stack_size_32[0] = info.size; } else if(reg === reg_cs) { @@ -4106,7 +4188,7 @@ CPU.prototype.switch_seg = function(reg, selector) info.is_system || !info.is_readable || (!info.is_conforming_executable && - (info.rpl > info.dpl || this.cpl > info.dpl)) + (info.rpl > info.dpl || this.cpl[0] > info.dpl)) ) { dbg_log("#GP for loading invalid in seg " + reg + " sel=" + h(selector, 4), LOG_CPU); this.debug.dump_state(); @@ -4228,16 +4310,16 @@ CPU.prototype.load_ldt = function(selector) CPU.prototype.arpl = function(seg, r16) { - this.flags_changed &= ~flag_zero; + this.flags_changed[0] &= ~flag_zero; if((seg & 3) < (this.reg16[r16] & 3)) { - this.flags |= flag_zero; + this.flags[0] |= flag_zero; return seg & ~3 | this.reg16[r16] & 3; } else { - this.flags &= ~flag_zero; + this.flags[0] &= ~flag_zero; return seg; } }; @@ -4251,21 +4333,21 @@ CPU.prototype.lar = function(selector, original) 1 << 0xD | 1 << 0xE | 1 << 0xF; var info = this.lookup_segment_selector(selector); - this.flags_changed &= ~flag_zero; + this.flags_changed[0] &= ~flag_zero; - var dpl_bad = info.dpl < this.cpl || info.dpl < info.rpl; + var dpl_bad = info.dpl < this.cpl[0] || info.dpl < info.rpl; if(info.is_null || !info.is_valid || (info.is_system ? (LAR_INVALID_TYPE >> info.type & 1) || dpl_bad : !info.is_conforming_executable && dpl_bad) ) { - this.flags &= ~flag_zero; + this.flags[0] &= ~flag_zero; dbg_log("lar: invalid selector=" + h(selector, 4) + " is_null=" + info.is_null, LOG_CPU); return original; } else { - this.flags |= flag_zero; + this.flags[0] |= flag_zero; return info.raw1 & 0x00FFFF00; } }; @@ -4279,21 +4361,21 @@ CPU.prototype.lsl = function(selector, original) 1 << 0xA | 1 << 0xC | 1 << 0xD | 1 << 0xE | 1 << 0xF; var info = this.lookup_segment_selector(selector); - this.flags_changed &= ~flag_zero; + this.flags_changed[0] &= ~flag_zero; - var dpl_bad = info.dpl < this.cpl || info.dpl < info.rpl; + var dpl_bad = info.dpl < this.cpl[0] || info.dpl < info.rpl; if(info.is_null || !info.is_valid || (info.is_system ? (LSL_INVALID_TYPE >> info.type & 1) || dpl_bad : !info.is_conforming_executable && dpl_bad) ) { - this.flags &= ~flag_zero; + this.flags[0] &= ~flag_zero; dbg_log("lsl: invalid selector=" + h(selector, 4) + " is_null=" + info.is_null, LOG_CPU); return original; } else { - this.flags |= flag_zero; + this.flags[0] |= flag_zero; return info.effective_limit | 0; } @@ -4302,46 +4384,45 @@ CPU.prototype.lsl = function(selector, original) CPU.prototype.verr = function(selector) { var info = this.lookup_segment_selector(selector); - this.flags_changed &= ~flag_zero; + this.flags_changed[0] &= ~flag_zero; if(info.is_null || !info.is_valid || info.is_system || !info.is_readable || - (!info.is_conforming_executable && (info.dpl < this.cpl || info.dpl < info.rpl))) + (!info.is_conforming_executable && (info.dpl < this.cpl[0] || info.dpl < info.rpl))) { dbg_log("verr -> invalid. selector=" + h(selector, 4), LOG_CPU); - this.flags &= ~flag_zero; + this.flags[0] &= ~flag_zero; } else { dbg_log("verr -> valid. selector=" + h(selector, 4), LOG_CPU); - this.flags |= flag_zero; + this.flags[0] |= flag_zero; } }; CPU.prototype.verw = function(selector) { var info = this.lookup_segment_selector(selector); - this.flags_changed &= ~flag_zero; + this.flags_changed[0] &= ~flag_zero; if(info.is_null || !info.is_valid || info.is_system || !info.is_writable || - info.dpl < this.cpl || info.dpl < info.rpl) + info.dpl < this.cpl[0] || info.dpl < info.rpl) { dbg_log("verw invalid " + " " + h(selector) + " " + info.is_null + " " + !info.is_valid + " " + info.is_system + " " + !info.is_writable + " " + - (info.dpl < this.cpl) + " " + (info.dpl < info.rpl) + " " + LOG_CPU); - this.flags &= ~flag_zero; + (info.dpl < this.cpl[0]) + " " + (info.dpl < info.rpl) + " " + LOG_CPU); + this.flags[0] &= ~flag_zero; } else { - dbg_log("verw valid", LOG_CPU); - this.flags |= flag_zero; + this.flags[0] |= flag_zero; } }; CPU.prototype.clear_tlb = function() { // clear tlb excluding global pages - this.last_virt_eip = -1; - this.last_virt_esp = -1; + this.last_virt_eip[0] = -1; + this.last_virt_esp[0] = -1; this.tlb_info.set(this.tlb_info_global); @@ -4353,7 +4434,10 @@ CPU.prototype.full_clear_tlb = function() //dbg_log("TLB full clear", LOG_CPU); // clear tlb including global pages - var buf32 = new Int32Array(this.tlb_info_global.buffer); + var buf32 = new Int32Array( + this.tlb_info_global.buffer, + this.tlb_info_global.byteOffset, + this.tlb_info_global.length >>> 2); for(var i = 0; i < (1 << 18); ) { buf32[i++] = buf32[i++] = buf32[i++] = buf32[i++] = 0; @@ -4370,18 +4454,18 @@ CPU.prototype.invlpg = function(addr) this.tlb_info[page] = 0; this.tlb_info_global[page] = 0; - this.last_virt_eip = -1; - this.last_virt_esp = -1; + this.last_virt_eip[0] = -1; + this.last_virt_esp[0] = -1; }; CPU.prototype.translate_address_read = function(addr) { - if(!this.paging) + if(!this.paging[0]) { return addr; } - if(this.cpl === 3) + if(this.cpl[0] === 3) { return this.translate_address_user_read(addr); } @@ -4393,12 +4477,12 @@ CPU.prototype.translate_address_read = function(addr) CPU.prototype.translate_address_write = function(addr) { - if(!this.paging) + if(!this.paging[0]) { return addr; } - if(this.cpl === 3) + if(this.cpl[0] === 3) { return this.translate_address_user_write(addr); } @@ -4410,7 +4494,7 @@ CPU.prototype.translate_address_write = function(addr) CPU.prototype.translate_address_user_write = function(addr) { - if(!this.paging) + if(!this.paging[0]) { return addr; } @@ -4429,7 +4513,7 @@ CPU.prototype.translate_address_user_write = function(addr) CPU.prototype.translate_address_user_read = function(addr) { - if(!this.paging) + if(!this.paging[0]) { return addr; } @@ -4448,7 +4532,7 @@ CPU.prototype.translate_address_user_read = function(addr) CPU.prototype.translate_address_system_write = function(addr) { - if(!this.paging) + if(!this.paging[0]) { return addr; } @@ -4467,7 +4551,7 @@ CPU.prototype.translate_address_system_write = function(addr) CPU.prototype.translate_address_system_read = function(addr) { - if(!this.paging) + if(!this.paging[0]) { return addr; } @@ -4542,7 +4626,7 @@ CPU.prototype.do_page_translation = function(addr, for_writing, user) } } - if(page_dir_entry & this.page_size_extensions) + if(page_dir_entry & this.page_size_extensions[0]) { // size bit is set @@ -4642,12 +4726,12 @@ CPU.prototype.writable_or_pagefault = function(addr, size) dbg_assert(size < 0x1000, "not supported yet"); dbg_assert(size > 0); - if(!this.paging) + if(!this.paging[0]) { return; } - var user = this.cpl === 3 ? 1 : 0, + var user = this.cpl[0] === 3 ? 1 : 0, mask = user ? TLB_USER_WRITE : TLB_SYSTEM_WRITE, page = addr >>> 12; @@ -4686,21 +4770,21 @@ CPU.prototype.trigger_pagefault = function(write, user, present) this.tlb_info[page] = 0; this.tlb_info_global[page] = 0; - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; this.page_fault = true; - this.call_interrupt_vector(14, false, user << 2 | write << 1 | present); + this.call_interrupt_vector(14, false, true, user << 2 | write << 1 | present); throw MAGIC_CPU_EXCEPTION; }; CPU.prototype.is_osize_32 = function() { - return this.is_32 !== ((this.prefixes & PREFIX_MASK_OPSIZE) === PREFIX_MASK_OPSIZE); + return Boolean(this.is_32[0]) !== ((this.prefixes[0] & PREFIX_MASK_OPSIZE) === PREFIX_MASK_OPSIZE); }; CPU.prototype.is_asize_32 = function() { - return this.is_32 !== ((this.prefixes & PREFIX_MASK_ADDRSIZE) === PREFIX_MASK_ADDRSIZE); + return Boolean(this.is_32[0]) !== ((this.prefixes[0] & PREFIX_MASK_ADDRSIZE) === PREFIX_MASK_ADDRSIZE); }; CPU.prototype.get_reg_asize = function(reg) diff --git a/src/debug.js b/src/debug.js index c7d5771f..97453d25 100644 --- a/src/debug.js +++ b/src/debug.js @@ -130,7 +130,7 @@ CPU.prototype.debug_init = function() cpu.running = false; var a = parseInt(prompt("input hex", ""), 16); - if(a) while(cpu.instruction_pointer != a) step(); + if(a) while(cpu.instruction_pointer[0] != a) step(); } // http://ref.x86asm.net/x86reference.xml @@ -215,15 +215,17 @@ CPU.prototype.debug_init = function() function get_state(where) { - var vm = (cpu.flags & flag_vm) ? 1 : 0; - var mode = cpu.protected_mode ? vm ? "vm86" : "prot" : "real"; + if(!DEBUG) return; + + var mode = cpu.protected_mode[0] ? "prot" : "real"; + var vm = (cpu.flags[0] & flag_vm) ? 1 : 0; var flags = cpu.get_eflags(); var iopl = cpu.getiopl(); - var cpl = cpu.cpl; + var cpl = cpu.cpl[0]; var cs_eip = h(cpu.sreg[reg_cs], 4) + ":" + h(cpu.get_real_eip() >>> 0, 8); var ss_esp = h(cpu.sreg[reg_ss], 4) + ":" + h(cpu.get_stack_reg() >>> 0, 8); - var op_size = cpu.is_32 ? "32" : "16"; - var if_ = (cpu.flags & flag_interrupt) ? 1 : 0; + var op_size = cpu.is_32[0] ? "32" : "16"; + var if_ = (cpu.flags[0] & flag_interrupt) ? 1 : 0; var flag_names = { [flag_carry]: "c", @@ -253,12 +255,12 @@ CPU.prototype.debug_init = function() } } - return ("mode=" + mode + "/" + op_size + " paging=" + (+cpu.paging) + + return ("mode=" + mode + "/" + op_size + " paging=" + (+cpu.paging[0]) + " iopl=" + iopl + " cpl=" + cpl + " if=" + if_ + " cs:eip=" + cs_eip + " cs_off=" + h(cpu.get_seg(reg_cs) >>> 0, 8) + " flgs=" + h(cpu.get_eflags() >>> 0, 6) + " (" + flag_string + ")" + " ss:esp=" + ss_esp + - " ssize=" + (+cpu.stack_size_32) + + " ssize=" + (+cpu.stack_size_32[0]) + (where ? " in " + where : "")); } @@ -357,8 +359,8 @@ CPU.prototype.debug_init = function() { if(!DEBUG) return; - dbg_log("gdt: (len = " + h(cpu.gdtr_size) + ")"); - dump_table(cpu.translate_address_system_read(cpu.gdtr_offset), cpu.gdtr_size); + dbg_log("gdt: (len = " + h(cpu.gdtr_size[0]) + ")"); + dump_table(cpu.translate_address_system_read(cpu.gdtr_offset[0]), cpu.gdtr_size[0]); dbg_log("\nldt: (len = " + h(cpu.segment_limits[reg_ldtr]) + ")"); dump_table(cpu.translate_address_system_read(cpu.segment_offsets[reg_ldtr]), cpu.segment_limits[reg_ldtr]); @@ -439,9 +441,9 @@ CPU.prototype.debug_init = function() { if(!DEBUG) return; - for(var i = 0; i < cpu.idtr_size; i += 8) + for(var i = 0; i < cpu.idtr_size[0]; i += 8) { - var addr = cpu.translate_address_system_read(cpu.idtr_offset + i), + var addr = cpu.translate_address_system_read(cpu.idtr_offset[0] + i), base = cpu.read16(addr) | cpu.read16(addr + 6) << 16, selector = cpu.read16(addr + 2), type = cpu.read8(addr + 5), @@ -583,7 +585,7 @@ CPU.prototype.debug_init = function() if(start === undefined) { start = 0; - count = cpu.memory_size; + count = cpu.memory_size[0]; } else if(count === undefined) { @@ -630,7 +632,7 @@ CPU.prototype.debug_init = function() var width = 0x80, height = 0x10, - block_size = cpu.memory_size / width / height | 0, + block_size = cpu.memory_size[0] / width / height | 0, row; for(var i = 0; i < height; i++) diff --git a/src/externs.js b/src/externs.js index a24e1730..cd914398 100644 --- a/src/externs.js +++ b/src/externs.js @@ -14,3 +14,4 @@ var exports = {}; var define = {}; var module = {}; +var WebAssembly = { Memory() {}, Table() {}, instantiate() {}, compile() {} }; diff --git a/src/fpu.js b/src/fpu.js index ba33a493..cb592ece 100644 --- a/src/fpu.js +++ b/src/fpu.js @@ -76,7 +76,8 @@ function FPU(cpu) // bitmap of which stack registers are empty - this.stack_empty = 0xff; + this.stack_empty = new Int32Array(cpu.wm.mem.buffer, 816, 1); + this.stack_empty[0] = 0xff; this.stack_ptr = 0; this.control_word = 0x37F; @@ -96,14 +97,20 @@ function FPU(cpu) Math.log(2) / Math.LN10, Math.LN2, 0 ]); + this.wasm_patch(); } +FPU.prototype.wasm_patch = function() +{ + this.set_tag_word = this.cpu.wm.funcs["_safe_tag_word"]; +}; + FPU.prototype.get_state = function() { var state = []; state[0] = this.st; - state[1] = this.stack_empty; + state[1] = this.stack_empty[0]; state[2] = this.stack_ptr; state[3] = this.control_word; state[4] = this.fpu_dp_selector; @@ -119,7 +126,7 @@ FPU.prototype.get_state = function() FPU.prototype.set_state = function(state) { this.st.set(state[0]); - this.stack_empty = state[1]; + this.stack_empty[0] = state[1]; this.stack_ptr = state[2]; this.control_word = state[3]; this.fpu_dp_selector = state[4]; @@ -182,23 +189,23 @@ FPU.prototype.fcomi = function(y) { var x = this.st[this.stack_ptr]; - this.cpu.flags_changed &= ~(1 | flag_parity | flag_zero); - this.cpu.flags &= ~(1 | flag_parity | flag_zero); + this.cpu.flags_changed[0] &= ~(1 | flag_parity | flag_zero); + this.cpu.flags[0] &= ~(1 | flag_parity | flag_zero); if(x > y) { } else if(y > x) { - this.cpu.flags |= 1; + this.cpu.flags[0] |= 1; } else if(x === y) { - this.cpu.flags |= flag_zero; + this.cpu.flags[0] |= flag_zero; } else { - this.cpu.flags |= 1 | flag_parity | flag_zero; + this.cpu.flags[0] |= 1 | flag_parity | flag_zero; } } @@ -233,7 +240,7 @@ FPU.prototype.fxam = function(x) this.status_word &= ~FPU_RESULT_FLAGS; this.status_word |= this.sign(0) << 9; - if(this.stack_empty >> this.stack_ptr & 1) + if(this.stack_empty[0] >> this.stack_ptr & 1) { this.status_word |= FPU_C3 | FPU_C0; } @@ -265,7 +272,7 @@ FPU.prototype.finit = function() this.fpu_dp = 0; this.fpu_opcode = 0; - this.stack_empty = 0xFF; + this.stack_empty[0] = 0xFF; this.stack_ptr = 0; } @@ -289,7 +296,7 @@ FPU.prototype.load_tag_word = function() { value = this.st[i]; - if(this.stack_empty >> i & 1) + if(this.stack_empty[0] >> i & 1) { tag_word |= 3 << (i << 1); } @@ -303,18 +310,18 @@ FPU.prototype.load_tag_word = function() } } - //dbg_log("load tw=" + h(tag_word) + " se=" + h(this.stack_empty) + " sp=" + this.stack_ptr, LOG_FPU); + //dbg_log("load tw=" + h(tag_word) + " se=" + h(this.stack_empty[0]) + " sp=" + this.stack_ptr, LOG_FPU); return tag_word; } FPU.prototype.set_tag_word = function(tag_word) { - this.stack_empty = 0; + this.stack_empty[0] = 0; for(var i = 0; i < 8; i++) { - this.stack_empty |= (tag_word >> i) & (tag_word >> i + 1) & 1 << i; + this.stack_empty[0] |= (tag_word >> i) & (tag_word >> i + 1) & 1 << i; } //dbg_log("set_tag_word tw=" + h(tag_word) + " se=" + h(this.stack_empty), LOG_FPU); @@ -447,10 +454,10 @@ FPU.prototype.push = function(x) { this.stack_ptr = this.stack_ptr - 1 & 7; - if(this.stack_empty >> this.stack_ptr & 1) + if(this.stack_empty[0] >> this.stack_ptr & 1) { this.status_word &= ~FPU_C1; - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); this.st[this.stack_ptr] = x; } else @@ -463,7 +470,7 @@ FPU.prototype.push = function(x) FPU.prototype.pop = function() { - this.stack_empty |= 1 << this.stack_ptr; + this.stack_empty[0] |= 1 << this.stack_ptr; this.stack_ptr = this.stack_ptr + 1 & 7; } @@ -473,7 +480,7 @@ FPU.prototype.get_sti = function(i) i = i + this.stack_ptr & 7; - if(this.stack_empty >> i & 1) + if(this.stack_empty[0] >> i & 1) { this.status_word &= ~FPU_C1; this.stack_fault(); @@ -487,7 +494,7 @@ FPU.prototype.get_sti = function(i) FPU.prototype.get_st0 = function() { - if(this.stack_empty >> this.stack_ptr & 1) + if(this.stack_empty[0] >> this.stack_ptr & 1) { this.status_word &= ~FPU_C1; this.stack_fault(); @@ -646,12 +653,12 @@ FPU.prototype.dbg_log_fpu_op = function(op, imm8) if(imm8 >= 0xC0) { dbg_log(h(op, 2) + " " + h(imm8, 2) + "/" + (imm8 >> 3 & 7) + "/" + (imm8 & 7) + - " @" + h(this.cpu.instruction_pointer >>> 0, 8) + " sp=" + this.stack_ptr + " st=" + h(this.stack_empty, 2), LOG_FPU); + " @" + h(this.cpu.instruction_pointer[0] >>> 0, 8) + " sp=" + this.stack_ptr + " st=" + h(this.stack_empty[0], 2), LOG_FPU); } else { dbg_log(h(op, 2) + " /" + (imm8 >> 3 & 7) + - " @" + h(this.cpu.instruction_pointer >>> 0, 8) + " sp=" + this.stack_ptr + " st=" + h(this.stack_empty, 2), LOG_FPU); + " @" + h(this.cpu.instruction_pointer[0] >>> 0, 8) + " sp=" + this.stack_ptr + " st=" + h(this.stack_empty[0], 2), LOG_FPU); } } @@ -987,7 +994,7 @@ FPU.prototype.op_DA_reg = function(imm8) if(this.cpu.test_b()) { this.st[this.stack_ptr] = this.get_sti(low); - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); } break; case 1: @@ -995,7 +1002,7 @@ FPU.prototype.op_DA_reg = function(imm8) if(this.cpu.test_z()) { this.st[this.stack_ptr] = this.get_sti(low); - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); } break; case 2: @@ -1003,7 +1010,7 @@ FPU.prototype.op_DA_reg = function(imm8) if(this.cpu.test_be()) { this.st[this.stack_ptr] = this.get_sti(low); - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); } break; case 3: @@ -1011,7 +1018,7 @@ FPU.prototype.op_DA_reg = function(imm8) if(this.cpu.test_p()) { this.st[this.stack_ptr] = this.get_sti(low); - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); } break; case 5: @@ -1096,7 +1103,7 @@ FPU.prototype.op_DB_reg = function(imm8) if(!this.cpu.test_b()) { this.st[this.stack_ptr] = this.get_sti(low); - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); } break; case 1: @@ -1104,7 +1111,7 @@ FPU.prototype.op_DB_reg = function(imm8) if(!this.cpu.test_z()) { this.st[this.stack_ptr] = this.get_sti(low); - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); } break; case 2: @@ -1112,7 +1119,7 @@ FPU.prototype.op_DB_reg = function(imm8) if(!this.cpu.test_be()) { this.st[this.stack_ptr] = this.get_sti(low); - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); } break; case 3: @@ -1120,7 +1127,7 @@ FPU.prototype.op_DB_reg = function(imm8) if(!this.cpu.test_p()) { this.st[this.stack_ptr] = this.get_sti(low); - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); } break; case 4: @@ -1329,7 +1336,7 @@ FPU.prototype.op_DD_reg = function(imm8) { case 0: // ffree - this.stack_empty |= 1 << (this.stack_ptr + low & 7); + this.stack_empty[0] |= 1 << (this.stack_ptr + low & 7); break; case 2: // fst diff --git a/src/instructions.js b/src/instructions.js index 59b483bb..53558a3d 100644 --- a/src/instructions.js +++ b/src/instructions.js @@ -230,9 +230,9 @@ t[0x62] = cpu => { t[0x63] = cpu => { cpu.read_modrm_byte(); // arpl //dbg_log("arpl", LOG_CPU); - if(cpu.protected_mode && !cpu.vm86_mode()) + if(cpu.protected_mode[0] && !cpu.vm86_mode()) { - cpu.write_e16(cpu.arpl(cpu.read_write_e16(), cpu.modrm_byte >> 2 & 14)); + cpu.write_e16(cpu.arpl(cpu.read_write_e16(), cpu.modrm_byte[0] >> 2 & 14)); } else { @@ -246,18 +246,18 @@ t[0x65] = cpu => { cpu.segment_prefix_op(reg_gs); }; t[0x66] = cpu => { // Operand-size override prefix - cpu.prefixes |= PREFIX_MASK_OPSIZE; + cpu.prefixes[0] |= PREFIX_MASK_OPSIZE; cpu.run_prefix_instruction(); - cpu.prefixes = 0; + cpu.prefixes[0] = 0; }; t[0x67] = cpu => { // Address-size override prefix - dbg_assert(cpu.is_asize_32() === cpu.is_32); + dbg_assert(cpu.is_asize_32() === Boolean(cpu.is_32[0])); - cpu.prefixes |= PREFIX_MASK_ADDRSIZE; + cpu.prefixes[0] |= PREFIX_MASK_ADDRSIZE; cpu.run_prefix_instruction(); - cpu.prefixes = 0; + cpu.prefixes[0] = 0; }; t16[0x68] = cpu => { cpu.push16(cpu.read_op16()); }; @@ -305,7 +305,7 @@ t[0x7E] = cpu => { cpu.jmpcc8( cpu.test_le()); }; t[0x7F] = cpu => { cpu.jmpcc8(!cpu.test_le()); }; t[0x80] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: cpu.write_e8(cpu.add8(cpu.read_write_e8(), cpu.read_op8())); break; case 1: cpu.write_e8(cpu. or8(cpu.read_write_e8(), cpu.read_op8())); break; @@ -318,7 +318,7 @@ t[0x80] = cpu => { cpu.read_modrm_byte(); } }; t16[0x81] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: cpu.write_e16(cpu.add16(cpu.read_write_e16(), cpu.read_op16())); break; case 1: cpu.write_e16(cpu. or16(cpu.read_write_e16(), cpu.read_op16())); break; @@ -331,7 +331,7 @@ t16[0x81] = cpu => { cpu.read_modrm_byte(); } }; t32[0x81] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: cpu.write_e32(cpu.add32(cpu.read_write_e32(), cpu.read_op32s())); break; case 1: cpu.write_e32(cpu. or32(cpu.read_write_e32(), cpu.read_op32s())); break; @@ -345,7 +345,7 @@ t32[0x81] = cpu => { cpu.read_modrm_byte(); }; t[0x82] = t[0x80]; // alias t16[0x83] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: cpu.write_e16(cpu.add16(cpu.read_write_e16(), cpu.read_op8s())); break; case 1: cpu.write_e16(cpu. or16(cpu.read_write_e16(), cpu.read_op8s())); break; @@ -358,7 +358,7 @@ t16[0x83] = cpu => { cpu.read_modrm_byte(); } }; t32[0x83] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: cpu.write_e32(cpu.add32(cpu.read_write_e32(), cpu.read_op8s())); break; case 1: cpu.write_e32(cpu. or32(cpu.read_write_e32(), cpu.read_op8s())); break; @@ -376,12 +376,12 @@ t16[0x85] = cpu => { cpu.read_modrm_byte(); var data = cpu.read_e16(); cpu.test1 t32[0x85] = cpu => { cpu.read_modrm_byte(); var data = cpu.read_e32s(); cpu.test32(data, cpu.read_g32s()); } -t[0x86] = cpu => { cpu.read_modrm_byte(); var data = cpu.read_write_e8(); cpu.write_e8(cpu.xchg8(data, cpu.modrm_byte)); }; +t[0x86] = cpu => { cpu.read_modrm_byte(); var data = cpu.read_write_e8(); cpu.write_e8(cpu.xchg8(data, cpu.modrm_byte[0])); }; t16[0x87] = cpu => { cpu.read_modrm_byte(); - var data = cpu.read_write_e16(); cpu.write_e16(cpu.xchg16(data, cpu.modrm_byte)); + var data = cpu.read_write_e16(); cpu.write_e16(cpu.xchg16(data, cpu.modrm_byte[0])); }; t32[0x87] = cpu => { cpu.read_modrm_byte(); - var data = cpu.read_write_e32(); cpu.write_e32(cpu.xchg32(data, cpu.modrm_byte)); + var data = cpu.read_write_e32(); cpu.write_e32(cpu.xchg32(data, cpu.modrm_byte[0])); }; t[0x88] = cpu => { cpu.read_modrm_byte(); cpu.set_e8(cpu.read_g8()); }; @@ -402,41 +402,41 @@ t32[0x8B] = cpu => { cpu.read_modrm_byte(); }; t16[0x8C] = cpu => { cpu.read_modrm_byte(); - cpu.set_e16(cpu.sreg[cpu.modrm_byte >> 3 & 7]); + cpu.set_e16(cpu.sreg[cpu.modrm_byte[0] >> 3 & 7]); }; t32[0x8C] = cpu => { cpu.read_modrm_byte(); - cpu.set_e32(cpu.sreg[cpu.modrm_byte >> 3 & 7]); + cpu.set_e32(cpu.sreg[cpu.modrm_byte[0] >> 3 & 7]); }; t16[0x8D] = cpu => { cpu.read_modrm_byte(); // lea - if(cpu.modrm_byte >= 0xC0) + if(cpu.modrm_byte[0] >= 0xC0) { dbg_log("lea #ud", LOG_CPU); cpu.trigger_ud(); } - var mod = cpu.modrm_byte >> 3 & 7; + var mod = cpu.modrm_byte[0] >> 3 & 7; // override prefix, so modrm_resolve does not return the segment part - cpu.prefixes |= SEG_PREFIX_ZERO; - cpu.reg16[mod << 1] = cpu.modrm_resolve(cpu.modrm_byte); - cpu.prefixes = 0; + cpu.prefixes[0] |= SEG_PREFIX_ZERO; + cpu.reg16[mod << 1] = cpu.modrm_resolve(cpu.modrm_byte[0]); + cpu.prefixes[0] = 0; }; t32[0x8D] = cpu => { cpu.read_modrm_byte(); - if(cpu.modrm_byte >= 0xC0) + if(cpu.modrm_byte[0] >= 0xC0) { dbg_log("lea #ud", LOG_CPU); cpu.trigger_ud(); } - var mod = cpu.modrm_byte >> 3 & 7; + var mod = cpu.modrm_byte[0] >> 3 & 7; - cpu.prefixes |= SEG_PREFIX_ZERO; - cpu.reg32s[mod] = cpu.modrm_resolve(cpu.modrm_byte); - cpu.prefixes = 0; + cpu.prefixes[0] |= SEG_PREFIX_ZERO; + cpu.reg32s[mod] = cpu.modrm_resolve(cpu.modrm_byte[0]); + cpu.prefixes[0] = 0; }; t[0x8E] = cpu => { cpu.read_modrm_byte(); - var mod = cpu.modrm_byte >> 3 & 7; + var mod = cpu.modrm_byte[0] >> 3 & 7; var data = cpu.read_e16(); cpu.switch_seg(mod, data); @@ -454,8 +454,8 @@ t16[0x8F] = cpu => { cpu.read_modrm_byte(); cpu.adjust_stack_reg(2); - if(cpu.modrm_byte < 0xC0) { - var addr = cpu.modrm_resolve(cpu.modrm_byte); + if(cpu.modrm_byte[0] < 0xC0) { + var addr = cpu.modrm_resolve(cpu.modrm_byte[0]); cpu.adjust_stack_reg(-2); cpu.safe_write16(addr, sp); cpu.adjust_stack_reg(2); @@ -469,8 +469,8 @@ t32[0x8F] = cpu => { cpu.read_modrm_byte(); // change esp first, then resolve modrm address cpu.adjust_stack_reg(4); - if(cpu.modrm_byte < 0xC0) { - var addr = cpu.modrm_resolve(cpu.modrm_byte); + if(cpu.modrm_byte[0] < 0xC0) { + var addr = cpu.modrm_resolve(cpu.modrm_byte[0]); // Before attempting a write that might cause a page fault, // we must set esp to the old value. Fuck Intel. @@ -516,7 +516,7 @@ t32[0x9A] = cpu => { var new_ip = cpu.read_op32s(); var new_cs = cpu.read_disp16(); - if(!cpu.protected_mode || cpu.vm86_mode()) + if(!cpu.protected_mode[0] || cpu.vm86_mode()) { if(new_ip & 0xFFFF0000) { @@ -551,9 +551,9 @@ t[0x9B] = cpu => { }; t16[0x9C] = cpu => { // pushf - if((cpu.flags & flag_vm) && cpu.getiopl() < 3) + if((cpu.flags[0] & flag_vm) && cpu.getiopl() < 3) { - dbg_assert(cpu.protected_mode); + dbg_assert(cpu.protected_mode[0]); dbg_log("pushf #gp", LOG_CPU); cpu.trigger_gp(0); } @@ -564,10 +564,10 @@ t16[0x9C] = cpu => { }; t32[0x9C] = cpu => { // pushf - if((cpu.flags & flag_vm) && cpu.getiopl() < 3) + if((cpu.flags[0] & flag_vm) && cpu.getiopl() < 3) { // trap to virtual 8086 monitor - dbg_assert(cpu.protected_mode); + dbg_assert(cpu.protected_mode[0]); dbg_log("pushf #gp", LOG_CPU); cpu.trigger_gp(0); } @@ -579,20 +579,20 @@ t32[0x9C] = cpu => { }; t16[0x9D] = cpu => { // popf - if((cpu.flags & flag_vm) && cpu.getiopl() < 3) + if((cpu.flags[0] & flag_vm) && cpu.getiopl() < 3) { dbg_log("popf #gp", LOG_CPU); cpu.trigger_gp(0); } - cpu.update_eflags((cpu.flags & ~0xFFFF) | cpu.pop16()); + cpu.update_eflags((cpu.flags[0] & ~0xFFFF) | cpu.pop16()); - if(cpu.flags & flag_trap) + if(cpu.flags[0] & flag_trap) { // XXX: Problems with fdgame //cpu.clear_prefixes(); //cpu.cycle_internal(); - cpu.flags &= ~flag_trap; + cpu.flags[0] &= ~flag_trap; //cpu.instruction_pointer = cpu.previous_ip; //cpu.raise_exception(1); } @@ -603,7 +603,7 @@ t16[0x9D] = cpu => { }; t32[0x9D] = cpu => { // popf - if((cpu.flags & flag_vm) && cpu.getiopl() < 3) + if((cpu.flags[0] & flag_vm) && cpu.getiopl() < 3) { dbg_log("popf #gp", LOG_CPU); cpu.trigger_gp(0); @@ -614,9 +614,9 @@ t32[0x9D] = cpu => { }; t[0x9E] = cpu => { // sahf - cpu.flags = (cpu.flags & ~0xFF) | cpu.reg8[reg_ah]; - cpu.flags = (cpu.flags & flags_mask) | flags_default; - cpu.flags_changed = 0; + cpu.flags[0] = (cpu.flags[0] & ~0xFF) | cpu.reg8[reg_ah]; + cpu.flags[0] = (cpu.flags[0] & flags_mask) | flags_default; + cpu.flags_changed[0] = 0; }; t[0x9F] = cpu => { // lahf @@ -708,7 +708,7 @@ t[0xC0] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e8(); var op2 = cpu.read_op8() & 31; var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol8(op1, op2); break; case 1: result = cpu.ror8(op1, op2); break; @@ -725,7 +725,7 @@ t16[0xC1] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e16(); var op2 = cpu.read_op8() & 31; var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol16(op1, op2); break; case 1: result = cpu.ror16(op1, op2); break; @@ -742,7 +742,7 @@ t32[0xC1] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e32(); var op2 = cpu.read_op8() & 31; var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol32(op1, op2); break; case 1: result = cpu.ror32(op1, op2); break; @@ -760,7 +760,7 @@ t16[0xC2] = cpu => { // retn var imm16 = cpu.read_op16(); - cpu.instruction_pointer = cpu.get_seg(reg_cs) + cpu.pop16() | 0; + cpu.instruction_pointer[0] = cpu.get_seg(reg_cs) + cpu.pop16() | 0; dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000); cpu.adjust_stack_reg(imm16); cpu.diverged(); @@ -771,20 +771,20 @@ t32[0xC2] = cpu => { var ip = cpu.pop32s(); dbg_assert(cpu.is_asize_32() || ip < 0x10000); - cpu.instruction_pointer = cpu.get_seg(reg_cs) + ip | 0; + cpu.instruction_pointer[0] = cpu.get_seg(reg_cs) + ip | 0; cpu.adjust_stack_reg(imm16); cpu.diverged(); }; t16[0xC3] = cpu => { // retn - cpu.instruction_pointer = cpu.get_seg(reg_cs) + cpu.pop16() | 0; + cpu.instruction_pointer[0] = cpu.get_seg(reg_cs) + cpu.pop16() | 0; cpu.diverged(); }; t32[0xC3] = cpu => { // retn var ip = cpu.pop32s(); dbg_assert(cpu.is_asize_32() || ip < 0x10000); - cpu.instruction_pointer = cpu.get_seg(reg_cs) + ip | 0; + cpu.instruction_pointer[0] = cpu.get_seg(reg_cs) + ip | 0; cpu.diverged(); }; @@ -802,24 +802,24 @@ t32[0xC5] = cpu => { cpu.read_modrm_byte(); }; t[0xC6] = cpu => { cpu.read_modrm_byte(); - if(cpu.modrm_byte < 0xC0) { - cpu.safe_write8(cpu.modrm_resolve(cpu.modrm_byte), cpu.read_op8()); + if(cpu.modrm_byte[0] < 0xC0) { + cpu.safe_write8(cpu.modrm_resolve(cpu.modrm_byte[0]), cpu.read_op8()); } else { - cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = cpu.read_op8(); + cpu.reg8[cpu.modrm_byte[0] << 2 & 0xC | cpu.modrm_byte[0] >> 2 & 1] = cpu.read_op8(); } } t16[0xC7] = cpu => { cpu.read_modrm_byte(); - if(cpu.modrm_byte < 0xC0) { - cpu.safe_write16(cpu.modrm_resolve(cpu.modrm_byte), cpu.read_op16()); + if(cpu.modrm_byte[0] < 0xC0) { + cpu.safe_write16(cpu.modrm_resolve(cpu.modrm_byte[0]), cpu.read_op16()); } else { - cpu.reg16[cpu.modrm_byte << 1 & 14] = cpu.read_op16(); + cpu.reg16[cpu.modrm_byte[0] << 1 & 14] = cpu.read_op16(); } }; t32[0xC7] = cpu => { cpu.read_modrm_byte(); - if(cpu.modrm_byte < 0xC0) { - cpu.safe_write32(cpu.modrm_resolve(cpu.modrm_byte), cpu.read_op32s()); + if(cpu.modrm_byte[0] < 0xC0) { + cpu.safe_write32(cpu.modrm_resolve(cpu.modrm_byte[0]), cpu.read_op32s()); } else { - cpu.reg32s[cpu.modrm_byte & 7] = cpu.read_op32s(); + cpu.reg32s[cpu.modrm_byte[0] & 7] = cpu.read_op32s(); } } @@ -827,13 +827,13 @@ t16[0xC8] = cpu => { cpu.enter16(cpu.read_op16(), cpu.read_disp8()); }; t32[0xC8] = cpu => { cpu.enter32(cpu.read_op16(), cpu.read_disp8()); }; t16[0xC9] = cpu => { // leave - var old_vbp = cpu.stack_size_32 ? cpu.reg32s[reg_ebp] : cpu.reg16[reg_bp]; + var old_vbp = cpu.stack_size_32[0] ? cpu.reg32s[reg_ebp] : cpu.reg16[reg_bp]; var new_bp = cpu.safe_read16(cpu.get_seg(reg_ss) + old_vbp | 0); cpu.set_stack_reg(old_vbp + 2 | 0); cpu.reg16[reg_bp] = new_bp; }; t32[0xC9] = cpu => { - var old_vbp = cpu.stack_size_32 ? cpu.reg32s[reg_ebp] : cpu.reg16[reg_bp]; + var old_vbp = cpu.stack_size_32[0] ? cpu.reg32s[reg_ebp] : cpu.reg16[reg_bp]; var new_ebp = cpu.safe_read32s(cpu.get_seg(reg_ss) + old_vbp | 0); cpu.set_stack_reg(old_vbp + 4 | 0); cpu.reg32s[reg_ebp] = new_ebp; @@ -880,13 +880,13 @@ t[0xCC] = cpu => { // INT3 // TODO: inhibit iopl checks dbg_log("INT3", LOG_CPU); - cpu.call_interrupt_vector(3, true, false); + cpu.call_interrupt_vector(3, true, false, 0); cpu.diverged(); }; t[0xCD] = cpu => { // INT var imm8 = cpu.read_op8(); - cpu.call_interrupt_vector(imm8, true, false); + cpu.call_interrupt_vector(imm8, true, false, 0); cpu.diverged(); }; t[0xCE] = cpu => { @@ -895,7 +895,7 @@ t[0xCE] = cpu => { if(cpu.getof()) { // TODO: inhibit iopl checks - cpu.call_interrupt_vector(4, true, false); + cpu.call_interrupt_vector(4, true, false, 0); } cpu.diverged(); }; @@ -913,7 +913,7 @@ t32[0xCF] = cpu => { t[0xD0] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e8(); var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol8(op1, 1); break; case 1: result = cpu.ror8(op1, 1); break; @@ -929,7 +929,7 @@ t[0xD0] = cpu => { cpu.read_modrm_byte(); t16[0xD1] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e16(); var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol16(op1, 1); break; case 1: result = cpu.ror16(op1, 1); break; @@ -945,7 +945,7 @@ t16[0xD1] = cpu => { cpu.read_modrm_byte(); t32[0xD1] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e32(); var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol32(op1, 1); break; case 1: result = cpu.ror32(op1, 1); break; @@ -963,7 +963,7 @@ t[0xD2] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e8(); var op2 = cpu.reg8[reg_cl] & 31; var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol8(op1, op2); break; case 1: result = cpu.ror8(op1, op2); break; @@ -980,7 +980,7 @@ t16[0xD3] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e16(); var op2 = cpu.reg8[reg_cl] & 31; var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol16(op1, op2); break; case 1: result = cpu.ror16(op1, op2); break; @@ -997,7 +997,7 @@ t32[0xD3] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e32(); var op2 = cpu.reg8[reg_cl] & 31; var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol32(op1, op2); break; case 1: result = cpu.ror32(op1, op2); break; @@ -1036,59 +1036,59 @@ t[0xD7] = cpu => { t[0xD8] = cpu => { cpu.read_modrm_byte(); cpu.task_switch_test(); - if(cpu.modrm_byte < 0xC0) - cpu.fpu.op_D8_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); + if(cpu.modrm_byte[0] < 0xC0) + cpu.fpu.op_D8_mem(cpu.modrm_byte[0], cpu.modrm_resolve(cpu.modrm_byte[0])); else - cpu.fpu.op_D8_reg(cpu.modrm_byte); + cpu.fpu.op_D8_reg(cpu.modrm_byte[0]); }; t[0xD9] = cpu => { cpu.read_modrm_byte(); cpu.task_switch_test(); - if(cpu.modrm_byte < 0xC0) - cpu.fpu.op_D9_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); + if(cpu.modrm_byte[0] < 0xC0) + cpu.fpu.op_D9_mem(cpu.modrm_byte[0], cpu.modrm_resolve(cpu.modrm_byte[0])); else - cpu.fpu.op_D9_reg(cpu.modrm_byte); + cpu.fpu.op_D9_reg(cpu.modrm_byte[0]); }; t[0xDA] = cpu => { cpu.read_modrm_byte(); cpu.task_switch_test(); - if(cpu.modrm_byte < 0xC0) - cpu.fpu.op_DA_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); + if(cpu.modrm_byte[0] < 0xC0) + cpu.fpu.op_DA_mem(cpu.modrm_byte[0], cpu.modrm_resolve(cpu.modrm_byte[0])); else - cpu.fpu.op_DA_reg(cpu.modrm_byte); + cpu.fpu.op_DA_reg(cpu.modrm_byte[0]); }; t[0xDB] = cpu => { cpu.read_modrm_byte(); cpu.task_switch_test(); - if(cpu.modrm_byte < 0xC0) - cpu.fpu.op_DB_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); + if(cpu.modrm_byte[0] < 0xC0) + cpu.fpu.op_DB_mem(cpu.modrm_byte[0], cpu.modrm_resolve(cpu.modrm_byte[0])); else - cpu.fpu.op_DB_reg(cpu.modrm_byte); + cpu.fpu.op_DB_reg(cpu.modrm_byte[0]); }; t[0xDC] = cpu => { cpu.read_modrm_byte(); cpu.task_switch_test(); - if(cpu.modrm_byte < 0xC0) - cpu.fpu.op_DC_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); + if(cpu.modrm_byte[0] < 0xC0) + cpu.fpu.op_DC_mem(cpu.modrm_byte[0], cpu.modrm_resolve(cpu.modrm_byte[0])); else - cpu.fpu.op_DC_reg(cpu.modrm_byte); + cpu.fpu.op_DC_reg(cpu.modrm_byte[0]); }; t[0xDD] = cpu => { cpu.read_modrm_byte(); cpu.task_switch_test(); - if(cpu.modrm_byte < 0xC0) - cpu.fpu.op_DD_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); + if(cpu.modrm_byte[0] < 0xC0) + cpu.fpu.op_DD_mem(cpu.modrm_byte[0], cpu.modrm_resolve(cpu.modrm_byte[0])); else - cpu.fpu.op_DD_reg(cpu.modrm_byte); + cpu.fpu.op_DD_reg(cpu.modrm_byte[0]); }; t[0xDE] = cpu => { cpu.read_modrm_byte(); cpu.task_switch_test(); - if(cpu.modrm_byte < 0xC0) - cpu.fpu.op_DE_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); + if(cpu.modrm_byte[0] < 0xC0) + cpu.fpu.op_DE_mem(cpu.modrm_byte[0], cpu.modrm_resolve(cpu.modrm_byte[0])); else - cpu.fpu.op_DE_reg(cpu.modrm_byte); + cpu.fpu.op_DE_reg(cpu.modrm_byte[0]); }; t[0xDF] = cpu => { cpu.read_modrm_byte(); cpu.task_switch_test(); - if(cpu.modrm_byte < 0xC0) - cpu.fpu.op_DF_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); + if(cpu.modrm_byte[0] < 0xC0) + cpu.fpu.op_DF_mem(cpu.modrm_byte[0], cpu.modrm_resolve(cpu.modrm_byte[0])); else - cpu.fpu.op_DF_reg(cpu.modrm_byte); + cpu.fpu.op_DF_reg(cpu.modrm_byte[0]); }; t[0xE0] = cpu => { cpu.loopne(cpu.read_op8s()); }; @@ -1146,7 +1146,7 @@ t32[0xE8] = cpu => { var imm32s = cpu.read_op32s(); cpu.push32(cpu.get_real_eip()); - cpu.instruction_pointer = cpu.instruction_pointer + imm32s | 0; + cpu.instruction_pointer[0] = cpu.instruction_pointer[0] + imm32s | 0; dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000); cpu.diverged(); }; @@ -1159,7 +1159,7 @@ t16[0xE9] = cpu => { t32[0xE9] = cpu => { // jmp var imm32s = cpu.read_op32s(); - cpu.instruction_pointer = cpu.instruction_pointer + imm32s | 0; + cpu.instruction_pointer[0] = cpu.instruction_pointer[0] + imm32s | 0; dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000); cpu.diverged(); }; @@ -1182,7 +1182,7 @@ t32[0xEA] = cpu => { t[0xEB] = cpu => { // jmp near var imm8 = cpu.read_op8s(); - cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; + cpu.instruction_pointer[0] = cpu.instruction_pointer[0] + imm8 | 0; dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000); cpu.diverged(); }; @@ -1241,17 +1241,17 @@ t[0xF1] = cpu => { t[0xF2] = cpu => { // repnz - dbg_assert((cpu.prefixes & PREFIX_MASK_REP) === 0); - cpu.prefixes |= PREFIX_REPNZ; + dbg_assert((cpu.prefixes[0] & PREFIX_MASK_REP) === 0); + cpu.prefixes[0] |= PREFIX_REPNZ; cpu.run_prefix_instruction(); - cpu.prefixes = 0; + cpu.prefixes[0] = 0; }; t[0xF3] = cpu => { // repz - dbg_assert((cpu.prefixes & PREFIX_MASK_REP) === 0); - cpu.prefixes |= PREFIX_REPZ; + dbg_assert((cpu.prefixes[0] & PREFIX_MASK_REP) === 0); + cpu.prefixes[0] |= PREFIX_REPZ; cpu.run_prefix_instruction(); - cpu.prefixes = 0; + cpu.prefixes[0] = 0; }; t[0xF4] = cpu => { @@ -1260,12 +1260,12 @@ t[0xF4] = cpu => { t[0xF5] = cpu => { // cmc - cpu.flags = (cpu.flags | 1) ^ cpu.getcf(); - cpu.flags_changed &= ~1; + cpu.flags[0] = (cpu.flags[0] | 1) ^ cpu.getcf(); + cpu.flags_changed[0] &= ~1; }; t[0xF6] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: var data = cpu.read_e8(); cpu.test8(data, cpu.read_op8()); @@ -1295,7 +1295,7 @@ t[0xF6] = cpu => { cpu.read_modrm_byte(); }; t16[0xF7] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: var data = cpu.read_e16(); cpu.test16(data, cpu.read_op16()); @@ -1324,7 +1324,7 @@ t16[0xF7] = cpu => { cpu.read_modrm_byte(); } }; t32[0xF7] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: var data = cpu.read_e32s(); cpu.test32(data, cpu.read_op32s()); @@ -1355,31 +1355,31 @@ t32[0xF7] = cpu => { cpu.read_modrm_byte(); t[0xF8] = cpu => { // clc - cpu.flags &= ~flag_carry; - cpu.flags_changed &= ~1; + cpu.flags[0] &= ~flag_carry; + cpu.flags_changed[0] &= ~1; }; t[0xF9] = cpu => { // stc - cpu.flags |= flag_carry; - cpu.flags_changed &= ~1; + cpu.flags[0] |= flag_carry; + cpu.flags_changed[0] &= ~1; }; t[0xFA] = cpu => { // cli //dbg_log("interrupts off"); - if(!cpu.protected_mode || ((cpu.flags & flag_vm) ? - cpu.getiopl() === 3 : cpu.getiopl() >= cpu.cpl)) + if(!cpu.protected_mode[0] || ((cpu.flags[0] & flag_vm) ? + cpu.getiopl() === 3 : cpu.getiopl() >= cpu.cpl[0])) { - cpu.flags &= ~flag_interrupt; + cpu.flags[0] &= ~flag_interrupt; } else { - //if(cpu.getiopl() < 3 && ((cpu.flags & flag_vm) ? + //if(cpu.getiopl() < 3 && ((cpu.flags[0] & flag_vm) ? // (cpu.cr[4] & CR4_VME) : - // (cpu.cpl === 3 && (cpu.cr[4] & CR4_PVI)))) + // (cpu.cpl[0] === 3 && (cpu.cr[4] & CR4_PVI)))) //{ - // cpu.flags &= ~flag_vif; + // cpu.flags[0] &= ~flag_vif; //} //else { @@ -1392,10 +1392,10 @@ t[0xFB] = cpu => { // sti //dbg_log("interrupts on"); - if(!cpu.protected_mode || ((cpu.flags & flag_vm) ? - cpu.getiopl() === 3 : cpu.getiopl() >= cpu.cpl)) + if(!cpu.protected_mode[0] || ((cpu.flags[0] & flag_vm) ? + cpu.getiopl() === 3 : cpu.getiopl() >= cpu.cpl[0])) { - cpu.flags |= flag_interrupt; + cpu.flags[0] |= flag_interrupt; cpu.clear_prefixes(); cpu.cycle_internal(); @@ -1404,11 +1404,11 @@ t[0xFB] = cpu => { } else { - //if(cpu.getiopl() < 3 && (cpu.flags & flag_vip) === 0 && ((cpu.flags & flag_vm) ? + //if(cpu.getiopl() < 3 && (cpu.flags[0] & flag_vip) === 0 && ((cpu.flags[0] & flag_vm) ? // (cpu.cr[4] & CR4_VME) : - // (cpu.cpl === 3 && (cpu.cr[4] & CR4_PVI)))) + // (cpu.cpl[0] === 3 && (cpu.cr[4] & CR4_PVI)))) //{ - // cpu.flags |= flag_vif; + // cpu.flags[0] |= flag_vif; //} //else { @@ -1421,15 +1421,15 @@ t[0xFB] = cpu => { t[0xFC] = cpu => { // cld - cpu.flags &= ~flag_direction; + cpu.flags[0] &= ~flag_direction; }; t[0xFD] = cpu => { // std - cpu.flags |= flag_direction; + cpu.flags[0] |= flag_direction; }; t[0xFE] = cpu => { cpu.read_modrm_byte(); - var mod = cpu.modrm_byte & 56; + var mod = cpu.modrm_byte[0] & 56; if(mod === 0) { @@ -1445,7 +1445,7 @@ t[0xFE] = cpu => { cpu.read_modrm_byte(); } }; t16[0xFF] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: var data = cpu.read_write_e16(); cpu.write_e16(cpu.inc16(data)); @@ -1457,20 +1457,20 @@ t16[0xFF] = cpu => { cpu.read_modrm_byte(); // 2, call near var data = cpu.read_e16(); cpu.push16(cpu.get_real_eip()); - cpu.instruction_pointer = cpu.get_seg(reg_cs) + data | 0; + cpu.instruction_pointer[0] = cpu.get_seg(reg_cs) + data | 0; dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000); cpu.diverged(); break; case 3: // 3, callf - if(cpu.modrm_byte >= 0xC0) + if(cpu.modrm_byte[0] >= 0xC0) { dbg_log("callf #ud", LOG_CPU); cpu.trigger_ud(); dbg_assert(false, "unreachable"); } - var virt_addr = cpu.modrm_resolve(cpu.modrm_byte); + var virt_addr = cpu.modrm_resolve(cpu.modrm_byte[0]); var new_ip = cpu.safe_read16(virt_addr); var new_cs = cpu.safe_read16(virt_addr + 2 | 0); @@ -1481,20 +1481,20 @@ t16[0xFF] = cpu => { cpu.read_modrm_byte(); case 4: // 4, jmp near var data = cpu.read_e16(); - cpu.instruction_pointer = cpu.get_seg(reg_cs) + data | 0; + cpu.instruction_pointer[0] = cpu.get_seg(reg_cs) + data | 0; dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000); cpu.diverged(); break; case 5: // 5, jmpf - if(cpu.modrm_byte >= 0xC0) + if(cpu.modrm_byte[0] >= 0xC0) { dbg_log("jmpf #ud", LOG_CPU); cpu.trigger_ud(); dbg_assert(false, "unreachable"); } - var virt_addr = cpu.modrm_resolve(cpu.modrm_byte); + var virt_addr = cpu.modrm_resolve(cpu.modrm_byte[0]); var new_ip = cpu.safe_read16(virt_addr); var new_cs = cpu.safe_read16(virt_addr + 2 | 0); @@ -1512,7 +1512,7 @@ t16[0xFF] = cpu => { cpu.read_modrm_byte(); } }; t32[0xFF] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: var data = cpu.read_write_e32(); cpu.write_e32(cpu.inc32(data)); @@ -1526,23 +1526,23 @@ t32[0xFF] = cpu => { cpu.read_modrm_byte(); cpu.push32(cpu.get_real_eip()); dbg_assert(cpu.is_asize_32() || data < 0x10000); - cpu.instruction_pointer = cpu.get_seg(reg_cs) + data | 0; + cpu.instruction_pointer[0] = cpu.get_seg(reg_cs) + data | 0; cpu.diverged(); break; case 3: // 3, callf - if(cpu.modrm_byte >= 0xC0) + if(cpu.modrm_byte[0] >= 0xC0) { dbg_log("callf #ud", LOG_CPU); cpu.trigger_ud(); dbg_assert(false, "unreachable"); } - var virt_addr = cpu.modrm_resolve(cpu.modrm_byte); + var virt_addr = cpu.modrm_resolve(cpu.modrm_byte[0]); var new_ip = cpu.safe_read32s(virt_addr); var new_cs = cpu.safe_read16(virt_addr + 4 | 0); - if(!cpu.protected_mode || cpu.vm86_mode()) + if(!cpu.protected_mode[0] || cpu.vm86_mode()) { if(new_ip & 0xFFFF0000) { @@ -1558,23 +1558,23 @@ t32[0xFF] = cpu => { cpu.read_modrm_byte(); // 4, jmp near var data = cpu.read_e32s(); dbg_assert(cpu.is_asize_32() || data < 0x10000); - cpu.instruction_pointer = cpu.get_seg(reg_cs) + data | 0; + cpu.instruction_pointer[0] = cpu.get_seg(reg_cs) + data | 0; cpu.diverged(); break; case 5: // 5, jmpf - if(cpu.modrm_byte >= 0xC0) + if(cpu.modrm_byte[0] >= 0xC0) { dbg_log("jmpf #ud", LOG_CPU); cpu.trigger_ud(); dbg_assert(false, "unreachable"); } - var virt_addr = cpu.modrm_resolve(cpu.modrm_byte); + var virt_addr = cpu.modrm_resolve(cpu.modrm_byte[0]); var new_ip = cpu.safe_read32s(virt_addr); var new_cs = cpu.safe_read16(virt_addr + 4 | 0); - if(!cpu.protected_mode || cpu.vm86_mode()) + if(!cpu.protected_mode[0] || cpu.vm86_mode()) { if(new_ip & 0xFFFF0000) { @@ -1625,34 +1625,34 @@ t32 = []; // 0F ops start here t[0x00] = cpu => { cpu.read_modrm_byte(); - if(!cpu.protected_mode || cpu.vm86_mode()) + if(!cpu.protected_mode[0] || cpu.vm86_mode()) { // No GP, UD is correct here dbg_log("0f 00 #ud", LOG_CPU); cpu.trigger_ud(); } - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: // sldt cpu.set_e16(cpu.sreg[reg_ldtr]); - if(cpu.is_osize_32() && cpu.modrm_byte >= 0xC0) + if(cpu.is_osize_32() && cpu.modrm_byte[0] >= 0xC0) { - cpu.reg32s[cpu.modrm_byte & 7] &= 0xFFFF; + cpu.reg32s[cpu.modrm_byte[0] & 7] &= 0xFFFF; } break; case 1: // str cpu.set_e16(cpu.sreg[reg_tr]); - if(cpu.is_osize_32() && cpu.modrm_byte >= 0xC0) + if(cpu.is_osize_32() && cpu.modrm_byte[0] >= 0xC0) { - cpu.reg32s[cpu.modrm_byte & 7] &= 0xFFFF; + cpu.reg32s[cpu.modrm_byte[0] & 7] &= 0xFFFF; } break; case 2: // lldt - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } @@ -1662,7 +1662,7 @@ t[0x00] = cpu => { cpu.read_modrm_byte(); break; case 3: // ltr - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } @@ -1678,18 +1678,18 @@ t[0x00] = cpu => { cpu.read_modrm_byte(); break; default: - dbg_log(cpu.modrm_byte >> 3 & 7, LOG_CPU); + dbg_log(cpu.modrm_byte[0] >> 3 & 7, LOG_CPU); cpu.todo(); } }; t[0x01] = cpu => { cpu.read_modrm_byte(); - var mod = cpu.modrm_byte >> 3 & 7; + var mod = cpu.modrm_byte[0] >> 3 & 7; if(mod === 4) { // smsw - if(cpu.modrm_byte >= 0xC0 && cpu.is_osize_32()) + if(cpu.modrm_byte[0] >= 0xC0 && cpu.is_osize_32()) { cpu.set_e32(cpu.cr[0]); } @@ -1702,7 +1702,7 @@ t[0x01] = cpu => { cpu.read_modrm_byte(); else if(mod === 6) { // lmsw - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } @@ -1711,7 +1711,7 @@ t[0x01] = cpu => { cpu.read_modrm_byte(); cr0 = (cpu.cr[0] & ~0xF) | (cr0 & 0xF); - if(cpu.protected_mode) + if(cpu.protected_mode[0]) { // lmsw cannot be used to switch back cr0 |= CR0_PE; @@ -1721,34 +1721,34 @@ t[0x01] = cpu => { cpu.read_modrm_byte(); return; } - if(cpu.modrm_byte >= 0xC0) + if(cpu.modrm_byte[0] >= 0xC0) { // only memory dbg_log("0f 01 #ud", LOG_CPU); cpu.trigger_ud(); } - var addr = cpu.modrm_resolve(cpu.modrm_byte); + var addr = cpu.modrm_resolve(cpu.modrm_byte[0]); switch(mod) { case 0: // sgdt cpu.writable_or_pagefault(addr, 6); - cpu.safe_write16(addr, cpu.gdtr_size); + cpu.safe_write16(addr, cpu.gdtr_size[0]); var mask = cpu.is_osize_32() ? -1 : 0x00FFFFFF; - cpu.safe_write32(addr + 2, cpu.gdtr_offset & mask); + cpu.safe_write32(addr + 2, cpu.gdtr_offset[0] & mask); break; case 1: // sidt cpu.writable_or_pagefault(addr, 6); - cpu.safe_write16(addr, cpu.idtr_size); + cpu.safe_write16(addr, cpu.idtr_size[0]); var mask = cpu.is_osize_32() ? -1 : 0x00FFFFFF; - cpu.safe_write32(addr + 2, cpu.idtr_offset & mask); + cpu.safe_write32(addr + 2, cpu.idtr_offset[0] & mask); break; case 2: // lgdt - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } @@ -1756,22 +1756,22 @@ t[0x01] = cpu => { cpu.read_modrm_byte(); var size = cpu.safe_read16(addr); var offset = cpu.safe_read32s(addr + 2); - cpu.gdtr_size = size; - cpu.gdtr_offset = offset; + cpu.gdtr_size[0] = size; + cpu.gdtr_offset[0] = offset; if(!cpu.is_osize_32()) { - cpu.gdtr_offset &= 0xFFFFFF; + cpu.gdtr_offset[0] &= 0xFFFFFF; } - //dbg_log("gdt at " + h(cpu.gdtr_offset) + ", " + cpu.gdtr_size + " bytes", LOG_CPU); + //dbg_log("gdt at " + h(cpu.gdtr_offset[0]) + ", " + cpu.gdtr_size[0] + " bytes", LOG_CPU); //cpu.debug.dump_state(); //cpu.debug.dump_regs_short(); //cpu.debug.dump_gdt_ldt(); break; case 3: // lidt - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } @@ -1779,20 +1779,20 @@ t[0x01] = cpu => { cpu.read_modrm_byte(); var size = cpu.safe_read16(addr); var offset = cpu.safe_read32s(addr + 2); - cpu.idtr_size = size; - cpu.idtr_offset = offset; + cpu.idtr_size[0] = size; + cpu.idtr_offset[0] = offset; if(!cpu.is_osize_32()) { - cpu.idtr_offset &= 0xFFFFFF; + cpu.idtr_offset[0] &= 0xFFFFFF; } //dbg_log("[" + h(cpu.instruction_pointer) + "] idt at " + - // h(idtr_offset) + ", " + cpu.idtr_size + " bytes " + h(addr), LOG_CPU); + // h(idtr_offset) + ", " + cpu.idtr_size[0] + " bytes " + h(addr), LOG_CPU); break; case 7: // flush translation lookaside buffer - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } @@ -1807,7 +1807,7 @@ t[0x01] = cpu => { cpu.read_modrm_byte(); t16[0x02] = cpu => { cpu.read_modrm_byte(); // lar - if(!cpu.protected_mode || cpu.vm86_mode()) + if(!cpu.protected_mode[0] || cpu.vm86_mode()) { dbg_log("lar #ud", LOG_CPU); cpu.trigger_ud(); @@ -1816,7 +1816,7 @@ t16[0x02] = cpu => { cpu.read_modrm_byte(); cpu.write_g16(cpu.lar(data, cpu.read_g16())); }; t32[0x02] = cpu => { cpu.read_modrm_byte(); - if(!cpu.protected_mode || cpu.vm86_mode()) + if(!cpu.protected_mode[0] || cpu.vm86_mode()) { dbg_log("lar #ud", LOG_CPU); cpu.trigger_ud(); @@ -1827,7 +1827,7 @@ t32[0x02] = cpu => { cpu.read_modrm_byte(); t16[0x03] = cpu => { cpu.read_modrm_byte(); // lsl - if(!cpu.protected_mode || cpu.vm86_mode()) + if(!cpu.protected_mode[0] || cpu.vm86_mode()) { dbg_log("lsl #ud", LOG_CPU); cpu.trigger_ud(); @@ -1836,7 +1836,7 @@ t16[0x03] = cpu => { cpu.read_modrm_byte(); cpu.write_g16(cpu.lsl(data, cpu.read_g16())); }; t32[0x03] = cpu => { cpu.read_modrm_byte(); - if(!cpu.protected_mode || cpu.vm86_mode()) + if(!cpu.protected_mode[0] || cpu.vm86_mode()) { dbg_log("lsl #ud", LOG_CPU); cpu.trigger_ud(); @@ -1850,7 +1850,7 @@ t[0x05] = cpu => { cpu.undefined_instruction(); }; t[0x06] = cpu => { // clts - if(cpu.cpl) + if(cpu.cpl[0]) { dbg_log("clts #gp", LOG_CPU); cpu.trigger_gp(0); @@ -1869,7 +1869,7 @@ t[0x08] = cpu => { }; t[0x09] = cpu => { - if(cpu.cpl) + if(cpu.cpl[0]) { dbg_log("wbinvd #gp", LOG_CPU); cpu.trigger_gp(0); @@ -1913,7 +1913,21 @@ t[0x13] = cpu => { var addr = cpu.modrm_resolve(cpu.modrm_byte); cpu.safe_write64(addr, data[0], data[1]); }; -t[0x14] = cpu => { cpu.unimplemented_sse(); }; +t[0x14] = cpu => { + // unpcklpd xmm, xmm/m128 + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === PREFIX_66); + cpu.task_switch_test_mmx(); + cpu.read_modrm_byte(); + let source = cpu.read_xmm_mem64s(); + let destination = cpu.read_xmm64s(); + + cpu.write_xmm128s( + destination[0], + destination[1], + source[0], + source[1] + ); +}; t[0x15] = cpu => { cpu.unimplemented_sse(); }; t[0x16] = cpu => { cpu.unimplemented_sse(); }; t[0x17] = cpu => { cpu.unimplemented_sse(); }; @@ -1921,8 +1935,8 @@ t[0x17] = cpu => { cpu.unimplemented_sse(); }; t[0x18] = cpu => { cpu.read_modrm_byte(); // prefetch // nop for us - if(cpu.modrm_byte < 0xC0) - cpu.modrm_resolve(cpu.modrm_byte); + if(cpu.modrm_byte[0] < 0xC0) + cpu.modrm_resolve(cpu.modrm_byte[0]); }; t[0x19] = cpu => { cpu.unimplemented_sse(); }; @@ -1933,22 +1947,22 @@ t[0x1D] = cpu => { cpu.unimplemented_sse(); }; t[0x1E] = cpu => { cpu.unimplemented_sse(); }; t[0x1F] = cpu => { cpu.read_modrm_byte() // multi-byte nop - if(cpu.modrm_byte < 0xC0) - cpu.modrm_resolve(cpu.modrm_byte); + if(cpu.modrm_byte[0] < 0xC0) + cpu.modrm_resolve(cpu.modrm_byte[0]); }; t[0x20] = cpu => { cpu.read_modrm_byte(); - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } - //dbg_log("cr" + (cpu.modrm_byte >> 3 & 7) + " read", LOG_CPU); + //dbg_log("cr" + (cpu.modrm_byte[0] >> 3 & 7) + " read", LOG_CPU); // mov addr, cr // mod = which control register - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: cpu.write_reg_e32(cpu.cr[0]); @@ -1972,12 +1986,12 @@ t[0x20] = cpu => { cpu.read_modrm_byte(); }; t[0x21] = cpu => { cpu.read_modrm_byte(); - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } - var dreg = cpu.modrm_byte >> 3 & 7; + var dreg = cpu.modrm_byte[0] >> 3 & 7; if((cpu.cr[4] & CR4_DE) && (dreg === 4 || dreg === 5)) { dbg_log("#ud mov dreg 4/5 with cr4.DE set", LOG_CPU); @@ -1985,24 +1999,24 @@ t[0x21] = cpu => { cpu.read_modrm_byte(); } // high two bits of modrm are ignored - cpu.reg32s[cpu.modrm_byte & 7] = cpu.dreg[dreg]; + cpu.reg32s[cpu.modrm_byte[0] & 7] = cpu.dreg[dreg]; //dbg_log("read dr" + dreg + ": " + h(cpu.dreg[dreg] >>> 0), LOG_CPU); }; t[0x22] = cpu => { cpu.read_modrm_byte(); - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } var data = cpu.read_reg_e32s(); - //dbg_log("cr" + (cpu.modrm_byte >> 3 & 7) + " written: " + h(data >>> 0, 8), LOG_CPU); + //dbg_log("cr" + (cpu.modrm_byte[0] >> 3 & 7) + " written: " + h(data >>> 0, 8), LOG_CPU); // mov cr, addr // mod = which control register - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: cpu.set_cr0(data); @@ -2036,12 +2050,12 @@ t[0x22] = cpu => { cpu.read_modrm_byte(); } }; t[0x23] = cpu => { cpu.read_modrm_byte(); - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } - var dreg = cpu.modrm_byte >> 3 & 7; + var dreg = cpu.modrm_byte[0] >> 3 & 7; if((cpu.cr[4] & CR4_DE) && (dreg === 4 || dreg === 5)) { dbg_log("#ud mov dreg 4/5 with cr4.DE set", LOG_CPU); @@ -2060,10 +2074,20 @@ t[0x26] = cpu => { cpu.undefined_instruction(); }; t[0x27] = cpu => { cpu.undefined_instruction(); }; t[0x28] = cpu => { - // movaps xmm, xmm/m128 - dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === 0); cpu.task_switch_test_mmx(); cpu.read_modrm_byte(); + + if((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === PREFIX_66) + { + // movapd xmm, xmm/m128 + // (note: same as movaps, see google.com/?q=MOVAPD+vs+MOVAPS) + } + else + { + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === 0); + // movaps xmm, xmm/m128 + } + let data = cpu.read_xmm_mem128s(); cpu.write_xmm128s(data[0], data[1], data[2], data[3]); }; @@ -2073,25 +2097,60 @@ t[0x29] = cpu => { if((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === PREFIX_66) { // movapd xmm/m128, xmm - // (note: same as below, see google.com/?q=MOVAPD+vs+MOVAPS) - let data = cpu.read_xmm128s(); - dbg_assert(cpu.modrm_byte < 0xC0); - let addr = cpu.modrm_resolve(cpu.modrm_byte); - cpu.safe_write128(addr, data[0], data[1], data[2], data[3]); + // (note: same as movaps, see google.com/?q=MOVAPD+vs+MOVAPS) } else { // movaps xmm/m128, xmm dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === 0); - let data = cpu.read_xmm128s(); - dbg_assert(cpu.modrm_byte < 0xC0); - let addr = cpu.modrm_resolve(cpu.modrm_byte); - cpu.safe_write128(addr, data[0], data[1], data[2], data[3]); } + + let data = cpu.read_xmm128s(); + dbg_assert(cpu.modrm_byte < 0xC0); + let addr = cpu.modrm_resolve(cpu.modrm_byte); + cpu.safe_write128(addr, data[0], data[1], data[2], data[3]); }; t[0x2A] = cpu => { cpu.unimplemented_sse(); }; -t[0x2B] = cpu => { cpu.unimplemented_sse(); }; -t[0x2C] = cpu => { cpu.unimplemented_sse(); }; +t[0x2B] = cpu => { + cpu.task_switch_test_mmx(); + cpu.read_modrm_byte(); + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0 || + (cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === PREFIX_66); + + if(cpu.modrm_byte >= 0xC0) + { + cpu.trigger_ud(); + } + + // movntps m128, xmm + // movntpd m128, xmm + + let data = cpu.read_xmm128s(); + let addr = cpu.modrm_resolve(cpu.modrm_byte); + cpu.safe_write128(addr, data[0], data[1], data[2], data[3]); +}; +t[0x2C] = cpu => { + cpu.task_switch_test_mmx(); + cpu.read_modrm_byte(); + if((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === PREFIX_F2) + { + // cvttsd2si r32, xmm/m64 + let source = cpu.read_xmm_mem64s(); + let source_f64 = new Float64Array(source.buffer); + let f = source_f64[0]; + + if(!(f <= 0x7FFFFFFF && f >= -0x80000000)) + { + f = 0x80000000 | 0; + } + + cpu.write_g32(f); + } + else + { + dbg_assert(false); + } +}; t[0x2D] = cpu => { cpu.unimplemented_sse(); }; t[0x2E] = cpu => { cpu.unimplemented_sse(); }; t[0x2F] = cpu => { cpu.unimplemented_sse(); }; @@ -2100,7 +2159,7 @@ t[0x2F] = cpu => { cpu.unimplemented_sse(); }; t[0x30] = cpu => { // wrmsr - write maschine specific register - if(cpu.cpl) + if(cpu.cpl[0]) { // cpl > 0 or vm86 mode (vm86 mode is always runs with cpl=3) cpu.trigger_gp(0); @@ -2119,15 +2178,15 @@ t[0x30] = cpu => { switch(index) { case IA32_SYSENTER_CS: - cpu.sysenter_cs = low & 0xFFFF; + cpu.sysenter_cs[0] = low & 0xFFFF; break; case IA32_SYSENTER_EIP: - cpu.sysenter_eip = low; + cpu.sysenter_eip[0] = low; break; case IA32_SYSENTER_ESP: - cpu.sysenter_esp = low; + cpu.sysenter_esp[0] = low; break; case IA32_APIC_BASE_MSR: @@ -2140,7 +2199,7 @@ t[0x30] = cpu => { case IA32_TIME_STAMP_COUNTER: var new_tick = (low >>> 0) + 0x100000000 * (high >>> 0); - cpu.tsc_offset = v86.microtick() - new_tick / TSC_RATE; + cpu.tsc_offset[0] = v86.microtick() - new_tick / TSC_RATE; break; case IA32_BIOS_SIGN_ID: @@ -2167,9 +2226,9 @@ t[0x30] = cpu => { t[0x31] = cpu => { // rdtsc - read timestamp counter - if(!cpu.cpl || !(cpu.cr[4] & CR4_TSD)) + if(!cpu.cpl[0] || !(cpu.cr[4] & CR4_TSD)) { - var n = v86.microtick() - cpu.tsc_offset; + var n = v86.microtick() - cpu.tsc_offset[0]; dbg_assert(isFinite(n), "non-finite tsc: " + n); cpu.reg32s[reg_eax] = n * TSC_RATE; @@ -2185,7 +2244,7 @@ t[0x31] = cpu => { t[0x32] = cpu => { // rdmsr - read maschine specific register - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } @@ -2200,19 +2259,19 @@ t[0x32] = cpu => { switch(index) { case IA32_SYSENTER_CS: - low = cpu.sysenter_cs; + low = cpu.sysenter_cs[0]; break; case IA32_SYSENTER_EIP: - low = cpu.sysenter_eip; + low = cpu.sysenter_eip[0]; break; case IA32_SYSENTER_ESP: - low = cpu.sysenter_esp; + low = cpu.sysenter_esp[0]; break; case IA32_TIME_STAMP_COUNTER: - var n = v86.microtick() - cpu.tsc_offset; + var n = v86.microtick() - cpu.tsc_offset[0]; low = n * TSC_RATE; high = n * (TSC_RATE / 0x100000000); break; @@ -2271,20 +2330,23 @@ t[0x33] = cpu => { t[0x34] = cpu => { // sysenter - var seg = cpu.sysenter_cs & 0xFFFC; + var seg = cpu.sysenter_cs[0] & 0xFFFC; - if(!cpu.protected_mode || seg === 0) + if(!cpu.protected_mode[0] || seg === 0) { cpu.trigger_gp(0); } - //dbg_log("sysenter cs:eip=" + h(seg , 4) + ":" + h(cpu.sysenter_eip >>> 0, 8) + - // " ss:esp=" + h(seg + 8, 4) + ":" + h(cpu.sysenter_esp >>> 0, 8), LOG_CPU); + if(CPU_LOG_VERBOSE) + { + dbg_log("sysenter cs:eip=" + h(seg , 4) + ":" + h(cpu.sysenter_eip[0] >>> 0, 8) + + " ss:esp=" + h(seg + 8, 4) + ":" + h(cpu.sysenter_esp[0] >>> 0, 8), LOG_CPU); + } - cpu.flags &= ~flag_vm & ~flag_interrupt; + cpu.flags[0] &= ~flag_vm & ~flag_interrupt; - cpu.instruction_pointer = cpu.sysenter_eip; - cpu.reg32s[reg_esp] = cpu.sysenter_esp; + cpu.instruction_pointer[0] = cpu.sysenter_eip[0]; + cpu.reg32s[reg_esp] = cpu.sysenter_esp[0]; cpu.sreg[reg_cs] = seg; cpu.segment_is_null[reg_cs] = 0; @@ -2293,7 +2355,7 @@ t[0x34] = cpu => { cpu.update_cs_size(true); - cpu.cpl = 0; + cpu.cpl[0] = 0; cpu.cpl_changed(); cpu.sreg[reg_ss] = seg + 8; @@ -2301,23 +2363,26 @@ t[0x34] = cpu => { cpu.segment_limits[reg_ss] = -1; cpu.segment_offsets[reg_ss] = 0; - cpu.stack_size_32 = true; + cpu.stack_size_32[0] = true; cpu.diverged(); }; t[0x35] = cpu => { // sysexit - var seg = cpu.sysenter_cs & 0xFFFC; + var seg = cpu.sysenter_cs[0] & 0xFFFC; - if(!cpu.protected_mode || cpu.cpl || seg === 0) + if(!cpu.protected_mode[0] || cpu.cpl[0] || seg === 0) { cpu.trigger_gp(0); } - //dbg_log("sysexit cs:eip=" + h(seg + 16, 4) + ":" + h(cpu.reg32s[reg_edx] >>> 0, 8) + - // " ss:esp=" + h(seg + 24, 4) + ":" + h(cpu.reg32s[reg_ecx] >>> 0, 8), LOG_CPU); + if(CPU_LOG_VERBOSE) + { + dbg_log("sysexit cs:eip=" + h(seg + 16, 4) + ":" + h(cpu.reg32s[reg_edx] >>> 0, 8) + + " ss:esp=" + h(seg + 24, 4) + ":" + h(cpu.reg32s[reg_ecx] >>> 0, 8), LOG_CPU); + } - cpu.instruction_pointer = cpu.reg32s[reg_edx]; + cpu.instruction_pointer[0] = cpu.reg32s[reg_edx]; cpu.reg32s[reg_esp] = cpu.reg32s[reg_ecx]; cpu.sreg[reg_cs] = seg + 16 | 3; @@ -2328,7 +2393,7 @@ t[0x35] = cpu => { cpu.update_cs_size(true); - cpu.cpl = 3; + cpu.cpl[0] = 3; cpu.cpl_changed(); cpu.sreg[reg_ss] = seg + 24 | 3; @@ -2336,7 +2401,7 @@ t[0x35] = cpu => { cpu.segment_limits[reg_ss] = -1; cpu.segment_offsets[reg_ss] = 0; - cpu.stack_size_32 = true; + cpu.stack_size_32[0] = true; cpu.diverged(); }; @@ -2396,7 +2461,23 @@ t[0x50] = cpu => { cpu.unimplemented_sse(); }; t[0x51] = cpu => { cpu.unimplemented_sse(); }; t[0x52] = cpu => { cpu.unimplemented_sse(); }; t[0x53] = cpu => { cpu.unimplemented_sse(); }; -t[0x54] = cpu => { cpu.unimplemented_sse(); }; +t[0x54] = cpu => { + // andps xmm, xmm/mem128 + // andpd xmm, xmm/mem128 + // Note: Same code as pand + cpu.task_switch_test_mmx(); + cpu.read_modrm_byte(); + + let source = cpu.read_xmm_mem128s(); + let destination = cpu.read_xmm128s(); + + cpu.write_xmm128s( + source[0] & destination[0], + source[1] & destination[1], + source[2] & destination[2], + source[3] & destination[3] + ); +}; t[0x55] = cpu => { cpu.unimplemented_sse(); }; t[0x56] = cpu => { cpu.unimplemented_sse(); }; t[0x57] = cpu => { @@ -3053,7 +3134,6 @@ t[0x72] = cpu => { t[0x73] = cpu => { cpu.read_modrm_byte(); - dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); cpu.task_switch_test_mmx(); if(cpu.modrm_byte < 0xC0) @@ -3066,32 +3146,65 @@ t[0x73] = cpu => { switch(cpu.modrm_byte >> 3 & 7) { case 2: - // psrlq mm, imm8 - var source = cpu.read_op8(); - var destination = cpu.modrm_byte & 7; + if((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == PREFIX_66) + { + // psrlq xmm, imm8 + var shift = cpu.read_op8(); - var destination_low = cpu.reg_mmxs[2 * destination]; - var destination_high = cpu.reg_mmxs[2 * destination + 1]; + if(shift === 0) + { + return; + } - var shift = source; - var low = 0; - var high = 0; + let destination = cpu.read_xmm128s(); + let result = cpu.create_atom128s(0, 0, 0, 0); - if (shift <= 31) { - low = destination_low >>> shift | (destination_high << (32 - shift)); - high = destination_high >>> shift; + if (shift <= 31) + { + result[0] = destination[0] >>> shift | destination[1] << (32 - shift); + result[1] = destination[1] >>> shift; + + result[2] = destination[2] >>> shift | destination[3] << (32 - shift); + result[3] = destination[3] >>> shift; + } + else if (shift <= 63) + { + result[0] = destination[1] >>> shift; + result[2] = destination[3] >>> shift; + } + + cpu.write_xmm128s(result[0], result[1], result[2], result[3]); } - else if (shift <= 63) { - low = destination_high >>> (shift & 0x1F); - high = 0; + else + { + // psrlq mm, imm8 + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); + var source = cpu.read_op8(); + var destination = cpu.modrm_byte & 7; + + var destination_low = cpu.reg_mmxs[2 * destination]; + var destination_high = cpu.reg_mmxs[2 * destination + 1]; + + var shift = source; + var low = 0; + var high = 0; + + if (shift <= 31) { + low = destination_low >>> shift | (destination_high << (32 - shift)); + high = destination_high >>> shift; + } + else if (shift <= 63) { + low = destination_high >>> (shift & 0x1F); + high = 0; + } + + cpu.reg_mmxs[2 * destination] = low; + cpu.reg_mmxs[2 * destination + 1] = high; } - - cpu.reg_mmxs[2 * destination] = low; - cpu.reg_mmxs[2 * destination + 1] = high; - break; case 6: // psllq mm, imm8 + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); var source = cpu.read_op8(); var destination = cpu.modrm_byte & 7; @@ -3115,6 +3228,7 @@ t[0x73] = cpu => { cpu.reg_mmxs[2 * destination + 1] = high; break; + default: cpu.unimplemented_sse(); break; @@ -3171,24 +3285,47 @@ t[0x74] = cpu => { }; t[0x75] = cpu => { - // pcmpeqw mm, mm/m64 - dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); cpu.task_switch_test_mmx(); cpu.read_modrm_byte(); - let source = cpu.read_mmx_mem64s(); - let destination_low = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7)]; - let destination_high = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7) + 1]; + if((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == PREFIX_66) + { + // pcmpeqw xmm, xmm/m128 + let source64s = cpu.read_xmm_mem128s(); + let source16 = new Uint16Array(source64s.buffer); - let word0 = (destination_low & 0xFFFF) === (source[0] & 0xFFFF) ? 0xFFFF : 0; - let word1 = (destination_low & 0xFFFF0000) === (source[0] & 0xFFFF0000) ? 0xFFFF : 0; - let word2 = (destination_high & 0xFFFF) === (source[1] & 0xFFFF) ? 0xFFFF : 0; - let word3 = (destination_high & 0xFFFF0000) === (source[1] & 0xFFFF0000) ? 0xFFFF : 0; + let destination128 = cpu.read_xmm128s(); + let destination16 = new Uint16Array(destination128.buffer); - let low = word0 | word1 << 16; - let high = word2 | word3 << 16; + let result = cpu.create_atom128s(0, 0, 0, 0); + let result16 = new Uint16Array(result.buffer); - cpu.write_mmx64s(low, high); + for(let i = 0; i < 8; i++) + { + result16[i] = source16[i] === destination16[i] ? 0xFFFF : 0; + } + + cpu.write_xmm128s(result[0], result[1], result[2], result[3]) + } + else + { + // pcmpeqw mm, mm/m64 + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); + + let source = cpu.read_mmx_mem64s(); + let destination_low = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7)]; + let destination_high = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7) + 1]; + + let word0 = (destination_low & 0xFFFF) === (source[0] & 0xFFFF) ? 0xFFFF : 0; + let word1 = (destination_low & 0xFFFF0000) === (source[0] & 0xFFFF0000) ? 0xFFFF : 0; + let word2 = (destination_high & 0xFFFF) === (source[1] & 0xFFFF) ? 0xFFFF : 0; + let word3 = (destination_high & 0xFFFF0000) === (source[1] & 0xFFFF0000) ? 0xFFFF : 0; + + let low = word0 | word1 << 16; + let high = word2 | word3 << 16; + + cpu.write_mmx64s(low, high); + } }; t[0x76] = cpu => { @@ -3228,7 +3365,7 @@ t[0x77] = cpu => { // emms dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); cpu.task_switch_test_mmx(); - cpu.fpu.stack_empty = 0xFF; + cpu.fpu.stack_empty[0] = 0xFF; }; t[0x78] = cpu => { cpu.unimplemented_sse(); }; @@ -3835,7 +3972,21 @@ t[0xC3] = cpu => { cpu.set_e32(cpu.read_g32s()); }; t[0xC4] = cpu => { cpu.unimplemented_sse(); }; -t[0xC5] = cpu => { cpu.unimplemented_sse(); }; +t[0xC5] = cpu => { + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === PREFIX_66); + // pextrw r32/m16, xmm, imm8 + cpu.task_switch_test_mmx(); + cpu.read_modrm_byte(); + + if(cpu.modrm_byte < 0xC0) cpu.trigger_ud(); + + let data = cpu.read_xmm_mem128s(); + let data16 = new Uint16Array(data.buffer); + let index = cpu.read_imm8() & 7; + let result = data16[index]; + + cpu.write_g32(result); +}; t[0xC6] = cpu => { cpu.unimplemented_sse(); }; t[0xC7] = cpu => { @@ -3859,14 +4010,14 @@ t[0xC7] = cpu => { if(cpu.reg32s[reg_eax] === m64_low && cpu.reg32s[reg_edx] === m64_high) { - cpu.flags |= flag_zero; + cpu.flags[0] |= flag_zero; cpu.safe_write32(addr, cpu.reg32s[reg_ebx]); cpu.safe_write32(addr + 4 | 0, cpu.reg32s[reg_ecx]); } else { - cpu.flags &= ~flag_zero; + cpu.flags[0] &= ~flag_zero; cpu.reg32s[reg_eax] = m64_low; cpu.reg32s[reg_edx] = m64_high; @@ -3875,7 +4026,7 @@ t[0xC7] = cpu => { cpu.safe_write32(addr + 4 | 0, m64_high); } - cpu.flags_changed &= ~flag_zero; + cpu.flags_changed[0] &= ~flag_zero; break; case 6: @@ -3900,9 +4051,9 @@ t[0xC7] = cpu => { cpu.set_e16(rand); } - cpu.flags &= ~flags_all; - cpu.flags |= has_rand; - cpu.flags_changed = 0; + cpu.flags[0] &= ~flags_all; + cpu.flags[0] |= has_rand; + cpu.flags_changed[0] = 0; break; default: @@ -3972,35 +4123,69 @@ t[0xD2] = cpu => { }; t[0xD3] = cpu => { - // psrlq mm, mm/m64 - dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); cpu.task_switch_test_mmx(); cpu.read_modrm_byte(); - let source = cpu.read_mmx_mem64s(); - let destination_low = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7)]; - let destination_high = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7) + 1]; - - let shift = source[0] >>> 0; - - if(shift === 0) + if((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === PREFIX_66) { - return; - } + // psrlq xmm, mm/m64 + let source = cpu.read_xmm_mem64s(); + var shift = source[0] >>> 0; - let low = 0; - let high = 0; + if(shift === 0) + { + return; + } - if (shift <= 31) { - low = destination_low >>> shift | (destination_high << (32 - shift)); - high = destination_high >>> shift; - } - else if (shift <= 63) { - low = destination_high >>> (shift & 0x1F); - high = 0; - } + let destination = cpu.read_xmm128s(); + let result = cpu.create_atom128s(0, 0, 0, 0); - cpu.write_mmx64s(low, high); + if (shift <= 31) + { + result[0] = destination[0] >>> shift | destination[1] << (32 - shift); + result[1] = destination[1] >>> shift; + + result[2] = destination[2] >>> shift | destination[3] << (32 - shift); + result[3] = destination[3] >>> shift; + } + else if (shift <= 63) + { + result[0] = destination[1] >>> shift; + result[2] = destination[3] >>> shift; + } + + cpu.write_xmm128s(result[0], result[1], result[2], result[3]); + } + else + { + // psrlq mm, mm/m64 + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); + + let source = cpu.read_mmx_mem64s(); + let destination_low = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7)]; + let destination_high = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7) + 1]; + + let shift = source[0] >>> 0; + + if(shift === 0) + { + return; + } + + let low = 0; + let high = 0; + + if (shift <= 31) { + low = destination_low >>> shift | (destination_high << (32 - shift)); + high = destination_high >>> shift; + } + else if (shift <= 63) { + low = destination_high >>> (shift & 0x1F); + high = 0; + } + + cpu.write_mmx64s(low, high); + } }; t[0xD4] = cpu => { cpu.unimplemented_sse(); }; @@ -4740,19 +4925,36 @@ t[0xF9] = cpu => { }; t[0xFA] = cpu => { - // psubd mm, mm/m64 - dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); cpu.task_switch_test_mmx(); cpu.read_modrm_byte(); - let source = cpu.read_mmx_mem64s(); - let destination_low = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7)]; - let destination_high = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7) + 1]; + if((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == PREFIX_66) + { + // psubd xmm, xmm/m128 + let source = cpu.read_xmm_mem128s(); + let destination = cpu.read_xmm128s(); - let low = destination_low - source[0]; - let high = destination_high - source[1]; + cpu.write_xmm128s( + destination[0] - source[0], + destination[1] - source[1], + destination[2] - source[2], + destination[3] - source[3] + ); + } + else + { + // psubd mm, mm/m64 + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); - cpu.write_mmx64s(low, high); + let source = cpu.read_mmx_mem64s(); + let destination_low = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7)]; + let destination_high = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7) + 1]; + + cpu.write_mmx64s( + destination_low - source[0], + destination_high - source[1] + ); + } }; t[0xFB] = cpu => { cpu.unimplemented_sse(); }; diff --git a/src/io.js b/src/io.js index 5d2d1ccb..b8a93451 100644 --- a/src/io.js +++ b/src/io.js @@ -20,7 +20,7 @@ function IO(cpu) this.ports[i] = this.create_empty_entry(); } - var memory_size = cpu.memory_size; + var memory_size = cpu.memory_size[0]; for(var i = 0; (i << MMAP_BLOCK_BITS) < memory_size; i++) { @@ -253,7 +253,7 @@ IO.prototype.in_mmap_range = function(start, count) var end = start + count; - if(end >= this.cpu.memory_size) + if(end >= this.cpu.memory_size[0]) { return true; } diff --git a/src/ioapic.js b/src/ioapic.js index 811cbea6..77a1fcc3 100644 --- a/src/ioapic.js +++ b/src/ioapic.js @@ -120,7 +120,7 @@ function IOAPIC(cpu) dbg_assert(false); } }); -} +}; IOAPIC.prototype.remote_eoi = function(vector) { diff --git a/src/log.js b/src/log.js index 1e740950..881b095f 100644 --- a/src/log.js +++ b/src/log.js @@ -87,6 +87,27 @@ var dbg_log = (function() return dbg_log_; })(); +function dbg_log_wasm(memory, offset, args) +{ + if(!(LOG_LEVEL & LOG_CPU)) + { + return; + } + + let s = new Uint8Array(memory, offset); + let length = s.indexOf(0); + if(length !== -1) + { + s = new Uint8Array(memory, offset, length); + } + + let format_string = "[CPU ] " + String.fromCharCode.apply(String, s); + let format_args = [format_string]; + format_args.push.apply(format_args, args); + + console.log.apply(console, format_args); +} + /** * @param {number=} level */ diff --git a/src/main.js b/src/main.js index 46e6cf3a..fd163347 100644 --- a/src/main.js +++ b/src/main.js @@ -1,7 +1,10 @@ "use strict"; -/** @constructor */ -function v86(bus) +/** + * @constructor + * @param {Object=} wm + */ +function v86(bus, wm) { /** @type {boolean} */ this.running = false; @@ -10,7 +13,7 @@ function v86(bus) this.stopped = false; /** @type {CPU} */ - this.cpu = new CPU(bus); + this.cpu = new CPU(bus, wm); this.bus = bus; bus.register("cpu-init", this.init, this); diff --git a/src/memory.js b/src/memory.js index 9db53240..3f4ca06d 100644 --- a/src/memory.js +++ b/src/memory.js @@ -81,7 +81,7 @@ CPU.prototype.mmap_write32 = function(addr, value) CPU.prototype.in_mapped_range = function(addr) { - return (addr | 0) >= 0xA0000 && (addr | 0) < 0xC0000 || (addr >>> 0) >= (this.memory_size >>> 0); + return (addr | 0) >= 0xA0000 && (addr | 0) < 0xC0000 || (addr >>> 0) >= (this.memory_size[0] >>> 0); }; /** @@ -90,7 +90,7 @@ CPU.prototype.in_mapped_range = function(addr) CPU.prototype.read8 = function(addr) { this.debug_read(addr, 1); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK; if(this.in_mapped_range(addr)) { @@ -108,7 +108,7 @@ CPU.prototype.read8 = function(addr) CPU.prototype.read16 = function(addr) { this.debug_read(addr, 2); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK; if(this.in_mapped_range(addr)) { @@ -127,7 +127,7 @@ CPU.prototype.read_aligned16 = function(addr) { dbg_assert(addr >= 0 && addr < 0x80000000); this.debug_read(addr << 1, 2); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK16; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK16; if(this.in_mapped_range(addr << 1)) { @@ -145,7 +145,7 @@ CPU.prototype.read_aligned16 = function(addr) CPU.prototype.read32s = function(addr) { this.debug_read(addr, 4); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK; if(this.in_mapped_range(addr)) { @@ -165,7 +165,7 @@ CPU.prototype.read_aligned32 = function(addr) { dbg_assert(addr >= 0 && addr < 0x40000000); this.debug_read(addr << 2, 4); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK32; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK32; if(this.in_mapped_range(addr << 2)) { @@ -184,7 +184,7 @@ CPU.prototype.read_aligned32 = function(addr) CPU.prototype.write8 = function(addr, value) { this.debug_write(addr, 1, value); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK; if(this.in_mapped_range(addr)) { @@ -203,7 +203,7 @@ CPU.prototype.write8 = function(addr, value) CPU.prototype.write16 = function(addr, value) { this.debug_write(addr, 2, value); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK; if(this.in_mapped_range(addr)) { @@ -224,7 +224,7 @@ CPU.prototype.write_aligned16 = function(addr, value) { dbg_assert(addr >= 0 && addr < 0x80000000); this.debug_write(addr << 1, 2, value); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK16; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK16; if(this.in_mapped_range(addr << 1)) { @@ -243,7 +243,7 @@ CPU.prototype.write_aligned16 = function(addr, value) CPU.prototype.write32 = function(addr, value) { this.debug_write(addr, 4, value); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK; if(this.in_mapped_range(addr)) { @@ -262,7 +262,7 @@ CPU.prototype.write_aligned32 = function(addr, value) { dbg_assert(addr >= 0 && addr < 0x40000000); this.debug_write(addr << 2, 4, value); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK32; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK32; if(this.in_mapped_range(addr << 2)) { diff --git a/src/misc_instr.js b/src/misc_instr.js index 37003121..48f83226 100644 --- a/src/misc_instr.js +++ b/src/misc_instr.js @@ -20,7 +20,7 @@ CPU.prototype.jmpcc8 = function(condition) var imm8 = this.read_op8s(); if(condition) { - this.instruction_pointer = this.instruction_pointer + imm8 | 0; + this.instruction_pointer[0] = this.instruction_pointer[0] + imm8 | 0; this.branch_taken(); } else @@ -35,9 +35,9 @@ CPU.prototype.jmp_rel16 = function(rel16) // limit ip to 16 bit // ugly - this.instruction_pointer -= current_cs; - this.instruction_pointer = (this.instruction_pointer + rel16) & 0xFFFF; - this.instruction_pointer = this.instruction_pointer + current_cs | 0; + this.instruction_pointer[0] -= current_cs; + this.instruction_pointer[0] = (this.instruction_pointer[0] + rel16) & 0xFFFF; + this.instruction_pointer[0] = this.instruction_pointer[0] + current_cs | 0; }; CPU.prototype.jmpcc16 = function(condition) @@ -54,7 +54,6 @@ CPU.prototype.jmpcc16 = function(condition) } } - CPU.prototype.jmpcc32 = function(condition) { var imm32s = this.read_op32s(); @@ -63,7 +62,7 @@ CPU.prototype.jmpcc32 = function(condition) // don't change to `this.instruction_pointer += this.read_op32s()`, // since read_op32s modifies instruction_pointer - this.instruction_pointer = this.instruction_pointer + imm32s | 0; + this.instruction_pointer[0] = this.instruction_pointer[0] + imm32s | 0; this.branch_taken(); } else @@ -99,7 +98,7 @@ CPU.prototype.loopne = function(imm8s) { if(this.decr_ecx_asize() && !this.getzf()) { - this.instruction_pointer = this.instruction_pointer + imm8s | 0; + this.instruction_pointer[0] = this.instruction_pointer[0] + imm8s | 0; this.branch_taken(); } else @@ -112,7 +111,7 @@ CPU.prototype.loope = function(imm8s) { if(this.decr_ecx_asize() && this.getzf()) { - this.instruction_pointer = this.instruction_pointer + imm8s | 0; + this.instruction_pointer[0] = this.instruction_pointer[0] + imm8s | 0; this.branch_taken(); } else @@ -125,7 +124,7 @@ CPU.prototype.loop = function(imm8s) { if(this.decr_ecx_asize()) { - this.instruction_pointer = this.instruction_pointer + imm8s | 0; + this.instruction_pointer[0] = this.instruction_pointer[0] + imm8s | 0; this.branch_taken(); } else @@ -138,7 +137,7 @@ CPU.prototype.jcxz = function(imm8s) { if(this.get_reg_asize(reg_ecx) === 0) { - this.instruction_pointer = this.instruction_pointer + imm8s | 0; + this.instruction_pointer[0] = this.instruction_pointer[0] + imm8s | 0; this.branch_taken(); } else @@ -149,83 +148,82 @@ CPU.prototype.jcxz = function(imm8s) /** * @return {number} - * @const */ CPU.prototype.getcf = function() { - if(this.flags_changed & 1) + if(this.flags_changed[0] & 1) { - return (this.last_op1 ^ (this.last_op1 ^ this.last_op2) & (this.last_op2 ^ this.last_add_result)) >>> this.last_op_size & 1; + return (this.last_op1[0] ^ (this.last_op1[0] ^ this.last_op2[0]) & (this.last_op2[0] ^ this.last_add_result[0])) >>> this.last_op_size[0] & 1; } else { - return this.flags & 1; + return this.flags[0] & 1; } }; /** @return {number} */ CPU.prototype.getpf = function() { - if(this.flags_changed & flag_parity) + if(this.flags_changed[0] & flag_parity) { // inverted lookup table - return 0x9669 << 2 >> ((this.last_result ^ this.last_result >> 4) & 0xF) & flag_parity; + return 0x9669 << 2 >> ((this.last_result[0] ^ this.last_result[0] >> 4) & 0xF) & flag_parity; } else { - return this.flags & flag_parity; + return this.flags[0] & flag_parity; } }; /** @return {number} */ CPU.prototype.getaf = function() { - if(this.flags_changed & flag_adjust) + if(this.flags_changed[0] & flag_adjust) { - return (this.last_op1 ^ this.last_op2 ^ this.last_add_result) & flag_adjust; + return (this.last_op1[0] ^ this.last_op2[0] ^ this.last_add_result[0]) & flag_adjust; } else { - return this.flags & flag_adjust; + return this.flags[0] & flag_adjust; } }; /** @return {number} */ CPU.prototype.getzf = function() { - if(this.flags_changed & flag_zero) + if(this.flags_changed[0] & flag_zero) { - return (~this.last_result & this.last_result - 1) >>> this.last_op_size & 1; + return (~this.last_result[0] & this.last_result[0] - 1) >>> this.last_op_size[0] & 1; } else { - return this.flags & flag_zero; + return this.flags[0] & flag_zero; } }; /** @return {number} */ CPU.prototype.getsf = function() { - if(this.flags_changed & flag_sign) + if(this.flags_changed[0] & flag_sign) { - return this.last_result >>> this.last_op_size & 1; + return this.last_result[0] >>> this.last_op_size[0] & 1; } else { - return this.flags & flag_sign; + return this.flags[0] & flag_sign; } }; /** @return {number} */ CPU.prototype.getof = function() { - if(this.flags_changed & flag_overflow) + if(this.flags_changed[0] & flag_overflow) { - return ((this.last_op1 ^ this.last_add_result) & (this.last_op2 ^ this.last_add_result)) >>> this.last_op_size & 1; + return ((this.last_op1[0] ^ this.last_add_result[0]) & (this.last_op2[0] ^ this.last_add_result[0])) >>> this.last_op_size[0] & 1; } else { - return this.flags & flag_overflow; + return this.flags[0] & flag_overflow; } }; @@ -402,44 +400,44 @@ CPU.prototype.xchg32r = function(operand) CPU.prototype.lss16 = function(seg) { - if(this.modrm_byte >= 0xC0) + if(this.modrm_byte[0] >= 0xC0) { // 0xc4c4 #ud (EMULATOR_BOP) is used by reactos and windows to exit vm86 mode this.trigger_ud(); } - var addr = this.modrm_resolve(this.modrm_byte); + var addr = this.modrm_resolve(this.modrm_byte[0]); var new_reg = this.safe_read16(addr), new_seg = this.safe_read16(addr + 2 | 0); this.switch_seg(seg, new_seg); - this.reg16[this.modrm_byte >> 2 & 14] = new_reg; + this.reg16[this.modrm_byte[0] >> 2 & 14] = new_reg; } CPU.prototype.lss32 = function(seg) { - if(this.modrm_byte >= 0xC0) + if(this.modrm_byte[0] >= 0xC0) { this.trigger_ud(); } - var addr = this.modrm_resolve(this.modrm_byte); + var addr = this.modrm_resolve(this.modrm_byte[0]); var new_reg = this.safe_read32s(addr), new_seg = this.safe_read16(addr + 4 | 0); this.switch_seg(seg, new_seg); - this.reg32s[this.modrm_byte >> 3 & 7] = new_reg; + this.reg32s[this.modrm_byte[0] >> 3 & 7] = new_reg; } CPU.prototype.enter16 = function(size, nesting_level) { nesting_level &= 31; - if(nesting_level) dbg_log("enter16 stack=" + (this.stack_size_32 ? 32 : 16) + " size=" + size + " nest=" + nesting_level, LOG_CPU); + if(nesting_level) dbg_log("enter16 stack=" + (this.stack_size_32[0] ? 32 : 16) + " size=" + size + " nest=" + nesting_level, LOG_CPU); this.push16(this.reg16[reg_bp]); var frame_temp = this.reg16[reg_sp]; @@ -461,7 +459,7 @@ CPU.prototype.enter32 = function(size, nesting_level) { nesting_level &= 31; - if(nesting_level) dbg_log("enter32 stack=" + (this.stack_size_32 ? 32 : 16) + " size=" + size + " nest=" + nesting_level, LOG_CPU); + if(nesting_level) dbg_log("enter32 stack=" + (this.stack_size_32[0] ? 32 : 16) + " size=" + size + " nest=" + nesting_level, LOG_CPU); this.push32(this.reg32s[reg_ebp]); var frame_temp = this.reg32s[reg_esp]; @@ -492,7 +490,7 @@ CPU.prototype.fxsave = function(addr) this.safe_write16(addr + 0 | 0, this.fpu.control_word); this.safe_write16(addr + 2 | 0, this.fpu.load_status_word()); - this.safe_write8( addr + 4 | 0, ~this.fpu.stack_empty & 0xFF); + this.safe_write8( addr + 4 | 0, ~this.fpu.stack_empty[0] & 0xFF); this.safe_write16(addr + 6 | 0, this.fpu.fpu_opcode); this.safe_write32(addr + 8 | 0, this.fpu.fpu_ip); this.safe_write16(addr + 12 | 0, this.fpu.fpu_ip_selector); @@ -534,7 +532,7 @@ CPU.prototype.fxrstor = function(addr) this.fpu.control_word = this.safe_read16(addr + 0 | 0); this.fpu.set_status_word(this.safe_read16(addr + 2 | 0)); - this.fpu.stack_empty = ~this.safe_read8(addr + 4 | 0) & 0xFF; + this.fpu.stack_empty[0] = ~this.safe_read8(addr + 4 | 0) & 0xFF; this.fpu.fpu_opcode = this.safe_read16(addr + 6 | 0); this.fpu.fpu_ip = this.safe_read32s(addr + 8 | 0); this.fpu.fpu_ip = this.safe_read16(addr + 12 | 0); diff --git a/src/native/all.c b/src/native/all.c new file mode 100644 index 00000000..b208ed84 --- /dev/null +++ b/src/native/all.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include + +extern void call_interrupt_vector(int32_t interrupt_nr, bool is_software_int, bool has_error_code, int32_t error_code); +extern void throw_cpu_exception(void); + +#include "const.h" +#include "global_pointers.h" +#include "log.c" +#include "cpu.c" +#include "memory.c" +#include "modrm.c" +#include "misc_instr.c" +#include "arith.c" +#include "fpu.c" +#include "instructions.c" +#include "instructions_0f.c" diff --git a/src/native/arith.c b/src/native/arith.c new file mode 100644 index 00000000..e9cc853f --- /dev/null +++ b/src/native/arith.c @@ -0,0 +1,825 @@ +#include +#include +#include +#include + +#include + +#include "const.h" +#include "global_pointers.h" + +int32_t add(int32_t dest_operand, int32_t source_operand, int32_t op_size) +{ + *last_op1 = dest_operand; + *last_op2 = source_operand; + int32_t res = dest_operand + source_operand; + *last_add_result = *last_result = res; + + *last_op_size = op_size; + *flags_changed = FLAGS_ALL; + + return res; +} + +int32_t adc(int32_t dest_operand, int32_t source_operand, int32_t op_size) +{ + int32_t cf = getcf(); + *last_op1 = dest_operand; + *last_op2 = source_operand; + + int32_t res = dest_operand + source_operand + cf; + + *last_add_result = *last_result = res; + + *last_op_size = op_size; + *flags_changed = FLAGS_ALL; + + return res; +} + +int32_t sub(int32_t dest_operand, int32_t source_operand, int32_t op_size) +{ + *last_add_result = dest_operand; + *last_op2 = source_operand; + + int32_t res = dest_operand - source_operand; + + *last_op1 = *last_result = res; + + *last_op_size = op_size; + *flags_changed = FLAGS_ALL; + + return res; +} + +int32_t sbb(int32_t dest_operand, int32_t source_operand, int32_t op_size) +{ + int32_t cf = getcf(); + *last_add_result = dest_operand; + *last_op2 = source_operand; + + int32_t res = dest_operand - source_operand - cf; + + *last_op1 = *last_result = res; + + *last_op_size = op_size; + *flags_changed = FLAGS_ALL; + + return res; +} + +int32_t add8(int32_t x, int32_t y) { return add(x, y, OPSIZE_8); } +int32_t add16(int32_t x, int32_t y) { return add(x, y, OPSIZE_16); } +int32_t add32(int32_t x, int32_t y) { return add(x, y, OPSIZE_32); } + +int32_t sub8(int32_t x, int32_t y) { return sub(x, y, OPSIZE_8); } +int32_t sub16(int32_t x, int32_t y) { return sub(x, y, OPSIZE_16); } +int32_t sub32(int32_t x, int32_t y) { return sub(x, y, OPSIZE_32); } + +int32_t adc8(int32_t x, int32_t y) { return adc(x, y, OPSIZE_8); } +int32_t adc16(int32_t x, int32_t y) { return adc(x, y, OPSIZE_16); } +int32_t adc32(int32_t x, int32_t y) { return adc(x, y, OPSIZE_32); } + +int32_t sbb8(int32_t x, int32_t y) { return sbb(x, y, OPSIZE_8); } +int32_t sbb16(int32_t x, int32_t y) { return sbb(x, y, OPSIZE_16); } +int32_t sbb32(int32_t x, int32_t y) { return sbb(x, y, OPSIZE_32); } + +void cmp8(int32_t x, int32_t y) { sub(x, y, OPSIZE_8); } +void cmp16(int32_t x, int32_t y) { sub(x, y, OPSIZE_16); } +void cmp32(int32_t x, int32_t y) { sub(x, y, OPSIZE_32); } + +int32_t inc(int32_t dest_operand, int32_t op_size) +{ + *flags = (*flags & ~1) | getcf(); + *last_op1 = dest_operand; + *last_op2 = 1; + + int32_t res = dest_operand + 1; + + *last_add_result = *last_result = res; + *last_op_size = op_size; + *flags_changed = FLAGS_ALL & ~1; + + return res; +} + +int32_t dec(int32_t dest_operand, int32_t op_size) +{ + *flags = (*flags & ~1) | getcf(); + *last_add_result = dest_operand; + *last_op2 = 1; + + int32_t res = dest_operand - 1; + + *last_op1 = *last_result = res; + *last_op_size = op_size; + *flags_changed = FLAGS_ALL & ~1; + + return res; +} + +int32_t inc8(int32_t x) { return inc(x, OPSIZE_8); } +int32_t inc16(int32_t x) { return inc(x, OPSIZE_16); } +int32_t inc32(int32_t x) { return inc(x, OPSIZE_32); } + +int32_t dec8(int32_t x) { return dec(x, OPSIZE_8); } +int32_t dec16(int32_t x) { return dec(x, OPSIZE_16); } +int32_t dec32(int32_t x) { return dec(x, OPSIZE_32); } + +int32_t neg(int32_t dest_operand, int32_t op_size) +{ + int32_t res = -dest_operand; + *last_op1 = *last_result = res; + *flags_changed = FLAGS_ALL; + *last_add_result = 0; + *last_op2 = dest_operand; + *last_op_size = op_size; + + return res; +} + +int32_t neg8(int32_t x) { return neg(x, OPSIZE_8); } +int32_t neg16(int32_t x) { return neg(x, OPSIZE_16); } +int32_t neg32(int32_t x) { return neg(x, OPSIZE_32); } + +void mul8(int32_t source_operand) +{ + int32_t result = source_operand * reg8[AL]; + + reg16[AX] = result; + *last_result = result & 0xFF; + *last_op_size = OPSIZE_8; + + if(result < 0x100) + { + *flags = *flags & ~1 & ~FLAG_OVERFLOW; + } + else + { + *flags = *flags | 1 | FLAG_OVERFLOW; + } + + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW; +} + +void imul8(int32_t source_operand) +{ + int32_t result = source_operand * reg8s[AL]; + + reg16[AX] = result; + *last_result = result & 0xFF; + *last_op_size = OPSIZE_8; + + if(result > 0x7F || result < -0x80) + { + *flags = *flags | 1 | FLAG_OVERFLOW; + } + else + { + *flags = *flags & ~1 & ~FLAG_OVERFLOW; + } + + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW; +} + +void mul16(uint32_t source_operand) +{ + uint32_t result = source_operand * reg16[AX]; + uint32_t high_result = result >> 16; + + + reg16[AX] = result; + reg16[DX] = high_result; + + *last_result = result & 0xFFFF; + *last_op_size = OPSIZE_16; + + if(high_result == 0) + { + *flags &= ~1 & ~FLAG_OVERFLOW; + } + else + { + *flags |= *flags | 1 | FLAG_OVERFLOW; + } + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW; +} + +void imul16(int32_t source_operand) +{ + int32_t result = source_operand * reg16s[AX]; + + reg16[AX] = result; + reg16[DX] = result >> 16; + + *last_result = result & 0xFFFF; + *last_op_size = OPSIZE_16; + + if(result > 0x7FFF || result < -0x8000) + { + *flags |= 1 | FLAG_OVERFLOW; + } + else + { + *flags &= ~1 & ~FLAG_OVERFLOW; + } + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW; +} + +int32_t imul_reg16(int32_t operand1, int32_t operand2) +{ + assert(operand1 < 0x8000 && operand1 >= -0x8000); + assert(operand2 < 0x8000 && operand2 >= -0x8000); + + int32_t result = operand1 * operand2; + + *last_result = result & 0xFFFF; + *last_op_size = OPSIZE_16; + + if(result > 0x7FFF || result < -0x8000) + { + *flags |= 1 | FLAG_OVERFLOW; + } + else + { + *flags &= ~1 & ~FLAG_OVERFLOW; + } + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW; + + return result; +} + +void do_mul32(uint32_t a, uint32_t b) +{ + uint32_t a00 = a & 0xFFFF; + uint32_t a16 = a >> 16; + uint32_t b00 = b & 0xFFFF; + int32_t b16 = b >> 16; + uint32_t low_result = a00 * b00; + uint32_t mid = (low_result >> 16) + (a16 * b00); + uint32_t high_result = mid >> 16; + mid = (mid & 0xFFFF) + (a00 * b16); + mul32_result[0] = (mid << 16) | low_result & 0xFFFF; + mul32_result[1] = ((mid >> 16) + (a16 * b16)) + high_result; +} + +void do_imul32(int32_t a, int32_t b) +{ + bool is_neg = false; + if(a < 0) { + is_neg = true; + a = -a; + } + if(b < 0) { + is_neg = !is_neg; + b = -b; + } + do_mul32(a, b); + if(is_neg) { + mul32_result[0] = -mul32_result[0]; + mul32_result[1] = ~mul32_result[1] + !mul32_result[0]; + } +} + +void mul32(int32_t source_operand) +{ + int32_t dest_operand = reg32s[EAX]; + + do_mul32(dest_operand, source_operand); + + reg32s[EAX] = mul32_result[0]; + reg32s[EDX] = mul32_result[1]; + + *last_result = mul32_result[0]; + *last_op_size = OPSIZE_32; + + if(mul32_result[1] == 0) + { + *flags &= ~1 & ~FLAG_OVERFLOW; + } + else + { + *flags |= 1 | FLAG_OVERFLOW; + } + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW; +} + +void imul32(int32_t source_operand) +{ + //XXX: this assert fails since the limits here are out of bounds for int32 + //but the assert is present in the original JS source :| + //assert(source_operand < 0x80000000 && source_operand >= -0x80000000); + + int32_t dest_operand = reg32s[EAX]; + + do_imul32(dest_operand, source_operand); + + reg32s[EAX] = mul32_result[0]; + reg32s[EDX] = mul32_result[1]; + + *last_result = mul32_result[0]; + *last_op_size = OPSIZE_32; + + if(mul32_result[1] == (mul32_result[0] >> 31)) + { + *flags &= ~1 & ~FLAG_OVERFLOW; + } + else + { + *flags |= 1 | FLAG_OVERFLOW; + } + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW; +} + +int32_t imul_reg32(int32_t operand1, int32_t operand2) +{ + //XXX: assert limits OOB for int32 + //dbg_assert(operand1 < 0x80000000 && operand1 >= -0x80000000); + //dbg_assert(operand2 < 0x80000000 && operand2 >= -0x80000000); + + do_imul32(operand1, operand2); + + *last_result = mul32_result[0]; + *last_op_size = OPSIZE_32; + + if(mul32_result[1] == (mul32_result[0] >> 31)) + { + *flags &= ~1 & ~FLAG_OVERFLOW; + } + else + { + *flags |= 1 | FLAG_OVERFLOW; + } + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW; + + return mul32_result[0]; +} + +int32_t xadd8(int32_t source_operand, int32_t reg) +{ + int32_t tmp = reg8[reg]; + + reg8[reg] = source_operand; + + return add(source_operand, tmp, OPSIZE_8); +} + +int32_t xadd16(int32_t source_operand, int32_t reg) +{ + int32_t tmp = reg16[reg]; + + reg16[reg] = source_operand; + + return add(source_operand, tmp, OPSIZE_16); +} + +int32_t xadd32(int32_t source_operand, int32_t reg) +{ + int32_t tmp = reg32s[reg]; + + reg32s[reg] = source_operand; + + return add(source_operand, tmp, OPSIZE_32); +} + +void bcd_daa() +{ + int32_t old_al = reg8[AL]; + int32_t old_cf = getcf(); + int32_t old_af = getaf(); + + *flags &= ~1 & ~FLAG_ADJUST; + + if((old_al & 0xF) > 9 || old_af) + { + reg8[AL] += 6; + *flags |= FLAG_ADJUST; + } + if(old_al > 0x99 || old_cf) + { + reg8[AL] += 0x60; + *flags |= 1; + } + + *last_result = reg8[AL]; + *last_op_size = OPSIZE_8; + *last_op1 = *last_op2 = 0; + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_ADJUST & ~FLAG_OVERFLOW; +} + +void bcd_das() +{ + int32_t old_al = reg8[AL]; + int32_t old_cf = getcf(); + + *flags &= ~1; + + if((old_al & 0xF) > 9 || getaf()) + { + reg8[AL] -= 6; + *flags |= FLAG_ADJUST; + *flags = *flags & ~1 | old_cf | (old_al < 6); + } + else + { + *flags &= ~FLAG_ADJUST; + } + + if(old_al > 0x99 || old_cf) + { + reg8[AL] -= 0x60; + *flags |= 1; + } + + *last_result = reg8[AL]; + *last_op_size = OPSIZE_8; + *last_op1 = *last_op2 = 0; + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_ADJUST & ~FLAG_OVERFLOW; +} + +void bcd_aad(int32_t imm8) +{ + int32_t result = reg8[AL] + reg8[AH] * imm8; + *last_result = result & 0xFF; + reg16[AX] = *last_result; + *last_op_size = OPSIZE_8; + + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_ADJUST & ~FLAG_OVERFLOW; + *flags &= ~1 & ~FLAG_ADJUST & ~FLAG_OVERFLOW; + + if(result > 0xFFFF) + { + *flags |= 1; + } +} + +void bcd_aaa() +{ + if((reg8[AL] & 0xF) > 9 || getaf()) + { + reg16[AX] += 6; + reg8[AH] += 1; + *flags |= FLAG_ADJUST | 1; + } + else + { + *flags &= ~FLAG_ADJUST & ~1; + } + reg8[AL] &= 0xF; + + *flags_changed &= ~FLAG_ADJUST & ~1; +} + +void bcd_aas() +{ + if((reg8[AL] & 0xF) > 9 || getaf()) + { + reg16[AX] -= 6; + reg8[AH] -= 1; + *flags |= FLAG_ADJUST | 1; + } + else + { + *flags &= ~FLAG_ADJUST & ~1; + } + reg8[AL] &= 0xF; + + *flags_changed &= ~FLAG_ADJUST & ~1; +} + +int32_t and(int32_t dest_operand, int32_t source_operand, int32_t op_size) +{ + *last_result = dest_operand & source_operand; + + *last_op_size = op_size; + *flags &= ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST; + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST; + + return *last_result; +} + +int32_t or(int32_t dest_operand, int32_t source_operand, int32_t op_size) +{ + *last_result = dest_operand | source_operand; + + *last_op_size = op_size; + *flags &= ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST; + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST; + + return *last_result; +} + +int32_t xor(int32_t dest_operand, int32_t source_operand, int32_t op_size) +{ + *last_result = dest_operand ^ source_operand; + + *last_op_size = op_size; + *flags &= ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST; + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST; + + return *last_result; +} + +int32_t and8(int32_t x, int32_t y) { return and(x, y, OPSIZE_8); } +int32_t and16(int32_t x, int32_t y) { return and(x, y, OPSIZE_16); } +int32_t and32(int32_t x, int32_t y) { return and(x, y, OPSIZE_32); } + +void test8(int32_t x, int32_t y) { and(x, y, OPSIZE_8); } +void test16(int32_t x, int32_t y) { and(x, y, OPSIZE_16); } +void test32(int32_t x, int32_t y) { and(x, y, OPSIZE_32); } + +int32_t or8(int32_t x, int32_t y) { return or(x, y, OPSIZE_8); } +int32_t or16(int32_t x, int32_t y) { return or(x, y, OPSIZE_16); } +int32_t or32(int32_t x, int32_t y) { return or(x, y, OPSIZE_32); } + +int32_t xor8(int32_t x, int32_t y) { return xor(x, y, OPSIZE_8); } +int32_t xor16(int32_t x, int32_t y) { return xor(x, y, OPSIZE_16); } +int32_t xor32(int32_t x, int32_t y) { return xor(x, y, OPSIZE_32); } + +int32_t rol8(int32_t dest_operand, int32_t count) +{ + if(!count) + { + return dest_operand; + } + count &= 7; + + int32_t result = dest_operand << count | dest_operand >> (8 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result & 1) + | (result << 11 ^ result << 4) & FLAG_OVERFLOW; + + return result; +} + +int32_t rol16(int32_t dest_operand, int32_t count) +{ + if(!count) + { + return dest_operand; + } + count &= 15; + + int32_t result = dest_operand << count | dest_operand >> (16 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result & 1) + | (result << 11 ^ result >> 4) & FLAG_OVERFLOW; + + return result; +} + +int32_t rol32(int32_t dest_operand, int32_t count) +{ + if(!count) + { + return dest_operand; + } + + int32_t result = dest_operand << count | ((uint32_t) dest_operand) >> (32 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result & 1) + | (result << 11 ^ result >> 20) & FLAG_OVERFLOW; + + return result; +} + +int32_t rcl8(int32_t dest_operand, int32_t count) +{ + count %= 9; + if(!count) + { + return dest_operand; + } + + int32_t result = dest_operand << count | getcf() << (count - 1) | dest_operand >> (9 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result >> 8 & 1) + | (result << 3 ^ result << 4) & FLAG_OVERFLOW; + + return result; +} + +int32_t rcl16(int32_t dest_operand, int32_t count) +{ + count %= 17; + if(!count) + { + return dest_operand; + } + + int32_t result = dest_operand << count | getcf() << (count - 1) | dest_operand >> (17 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result >> 16 & 1) + | (result >> 5 ^ result >> 4) & FLAG_OVERFLOW; + + return result; +} + +int32_t rcl32(int32_t dest_operand, int32_t count) +{ + if(!count) + { + return dest_operand; + } + + int32_t result = dest_operand << count | getcf() << (count - 1); + + if(count > 1) + { + result |= ((uint32_t) dest_operand) >> (33 - count); + } + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) | (((uint32_t) dest_operand) >> (32 - count) & 1); + *flags |= (*flags << 11 ^ result >> 20) & FLAG_OVERFLOW; + + return result; +} + +int32_t ror8(int32_t dest_operand, int32_t count) +{ + if(!count) + { + return dest_operand; + } + + count &= 7; + int32_t result = dest_operand >> count | dest_operand << (8 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result >> 7 & 1) + | (result << 4 ^ result << 5) & FLAG_OVERFLOW; + + return result; +} + +int32_t ror16(int32_t dest_operand, int32_t count) +{ + if(!count) + { + return dest_operand; + } + + count &= 15; + int32_t result = dest_operand >> count | dest_operand << (16 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result >> 15 & 1) + | (result >> 4 ^ result >> 3) & FLAG_OVERFLOW; + + return result; +} + +int32_t ror32(int32_t dest_operand, int32_t count) +{ + if(!count) + { + return dest_operand; + } + + int32_t result = ((uint32_t) dest_operand) >> count | dest_operand << (32 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result >> 31 & 1) + | (result >> 20 ^ result >> 19) & FLAG_OVERFLOW; + + return result; +} + +int32_t rcr8(int32_t dest_operand, int32_t count) +{ + count %= 9; + if(!count) + { + return dest_operand; + } + + int32_t result = dest_operand >> count | getcf() << (8 - count) | dest_operand << (9 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result >> 8 & 1) + | (result << 4 ^ result << 5) & FLAG_OVERFLOW; + + return result; +} + +int32_t rcr16(int32_t dest_operand, int32_t count) +{ + count %= 17; + if(!count) + { + return dest_operand; + } + + int32_t result = dest_operand >> count | getcf() << (16 - count) | dest_operand << (17 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result >> 16 & 1) + | (result >> 4 ^ result >> 3) & FLAG_OVERFLOW; + + return result; +} + +int32_t rcr32(int32_t dest_operand, int32_t count) +{ + if(!count) + { + return dest_operand; + } + + int32_t result = ((uint32_t) dest_operand) >> count | getcf() << (32 - count); + + if(count > 1) + { + result |= dest_operand << (33 - count); + } + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (dest_operand >> (count - 1) & 1) + | (result >> 20 ^ result >> 19) & FLAG_OVERFLOW; + + return result; +} + +void div8(uint32_t source_operand) +{ + if(source_operand == 0) + { + trigger_de(); + return; + } + + uint16_t target_operand = reg16[AX]; + uint16_t result = target_operand / source_operand; + + if(result >= 0x100) + { + trigger_de(); + } + else + { + reg8[AL] = result; + reg8[AH] = target_operand % source_operand; + } +} + +void idiv8(int32_t source_operand) +{ + if(source_operand == 0) + { + trigger_de(); + return; + } + + int32_t target_operand = reg16s[AX]; + int32_t result = target_operand / source_operand; + + if(result >= 0x80 || result <= -0x81) + { + trigger_de(); + } + else + { + reg8[AL] = result; + reg8[AH] = target_operand % source_operand; + } +} + +void div16(uint32_t source_operand) +{ + if(source_operand == 0) + { + trigger_de(); + return; + } + + uint32_t target_operand = reg16[AX] | reg16[DX] << 16; + uint32_t result = target_operand / source_operand; + + if(result >= 0x10000) + { + trigger_de(); + } + else + { + reg16[AX] = result; + reg16[DX] = target_operand % source_operand; + } +} + diff --git a/src/native/const.h b/src/native/const.h new file mode 100644 index 00000000..b5f8e10f --- /dev/null +++ b/src/native/const.h @@ -0,0 +1,159 @@ +#ifndef DEBUG +#define DEBUG true +#endif + +#define FLAG_CARRY 1 +#define FLAG_PARITY 4 +#define FLAG_ADJUST 16 +#define FLAG_ZERO 64 +#define FLAG_SIGN 128 +#define FLAG_TRAP 256 +#define FLAG_INTERRUPT 512 +#define FLAG_DIRECTION 1024 +#define FLAG_OVERFLOW 2048 +#define FLAG_IOPL (1 << 12 | 1 << 13) +#define FLAG_NT (1 << 14) +#define FLAG_RF (1 << 16) +#define FLAG_VM (1 << 17) +#define FLAG_AC (1 << 18) +#define FLAG_VIF (1 << 19) +#define FLAG_VIP (1 << 20) +#define FLAG_ID (1 << 21) +#define FLAGS_DEFAULT (1 << 1) + +#define FLAGS_MASK ( \ + FLAG_CARRY | FLAG_PARITY | FLAG_ADJUST | FLAG_ZERO | FLAG_SIGN | FLAG_TRAP | FLAG_INTERRUPT | \ + FLAG_DIRECTION | FLAG_OVERFLOW | FLAG_IOPL | FLAG_NT | FLAG_RF | FLAG_VM | FLAG_AC | \ + FLAG_VIF | FLAG_VIP | FLAG_ID) + +#define FLAGS_ALL (FLAG_CARRY | FLAG_PARITY | FLAG_ADJUST | FLAG_ZERO | FLAG_SIGN | FLAG_OVERFLOW) + +#define OPSIZE_8 7 +#define OPSIZE_16 15 +#define OPSIZE_32 31 + +#define EAX 0 +#define ECX 1 +#define EDX 2 +#define EBX 3 +#define ESP 4 +#define EBP 5 +#define ESI 6 +#define EDI 7 + +#define AX 0 +#define CX 2 +#define DX 4 +#define BX 6 +#define SP 8 +#define BP 10 +#define SI 12 +#define DI 14 + +#define AL 0 +#define CL 4 +#define DL 8 +#define BL 12 +#define AH 1 +#define CH 5 +#define DH 9 +#define BH 13 + +#define ES 0 +#define CS 1 +#define SS 2 +#define DS 3 +#define FS 4 +#define GS 5 + +#define TR 6 +#define LDTR 7 + + +#define TLB_SYSTEM_READ 1 +#define TLB_SYSTEM_WRITE 2 +#define TLB_USER_READ 4 +#define TLB_USER_WRITE 8 + + +#define PSE_ENABLED 128 + +#define MMAP_BLOCK_BITS 17 +#define MMAP_BLOCK_SIZE = (1 << MMAP_BLOCK_BITS) + +#define CR0_PE 1 +#define CR0_MP (1 << 1) +#define CR0_EM (1 << 2) +#define CR0_TS (1 << 3) +#define CR0_ET (1 << 4) +#define CR0_WP (1 << 16) +#define CR0_NW (1 << 29) +#define CR0_CD (1 << 30) +#define CR0_PG (1 << 31) + +#define CR4_VME (1) +#define CR4_PVI (1 << 1) +#define CR4_TSD (1 << 2) +#define CR4_PSE (1 << 4) +#define CR4_DE (1 << 3) +#define CR4_PAE (1 << 5) +#define CR4_PGE (1 << 7) + + +#define IA32_SYSENTER_CS 0x174 +#define IA32_SYSENTER_ESP 0x175 +#define IA32_SYSENTER_EIP 0x176 + +#define IA32_TIME_STAMP_COUNTER 0x10 +#define IA32_PLATFORM_ID 0x17 +#define IA32_APIC_BASE_MSR 0x1B +#define IA32_BIOS_SIGN_ID 0x8B +#define IA32_MISC_ENABLE 0x1A0 +#define IA32_RTIT_CTL 0x570 +#define MSR_SMI_COUNT 0x34 +#define IA32_MCG_CAP 0x179 +#define IA32_KERNEL_GS_BASE 0xC0000101 +#define MSR_PKG_C2_RESIDENCY 0x60D + +#define IA32_APIC_BASE_BSP (1 << 8) +#define IA32_APIC_BASE_EXTD (1 << 10) +#define IA32_APIC_BASE_EN (1 << 11) + + +// Note: Duplicated in apic.js +#define APIC_ADDRESS ((int32_t)0xFEE00000) + + +// Segment prefixes must not collide with reg_*s variables +// _ZERO is a special zero offset segment +#define SEG_PREFIX_NONE (-1) +#define SEG_PREFIX_ZERO 7 + +#define PREFIX_MASK_REP 0b11000 +#define PREFIX_REPZ 0b01000 +#define PREFIX_REPNZ 0b10000 + +#define PREFIX_MASK_SEGMENT 0b111 +#define PREFIX_MASK_OPSIZE 0b100000 +#define PREFIX_MASK_ADDRSIZE 0b1000000 + + + +/** + * How many cycles the CPU does at a time before running hardware timers + */ +#define LOOP_COUNTER 11001 + +#define TSC_RATE (8 * 1024) + +#define LOG_CPU 0x000002 +#define CPU_LOG_VERBOSE false +#define ENABLE_ACPI false + +#define A20_MASK (~(1 << 20)) +#define A20_MASK16 (~(1 << (20 - 1))) +#define A20_MASK32 (~(1 << (20 - 2))) + +#define USE_A20 false + +#define MXCSR_MASK (0xFFFF & ~(1 << 6)) diff --git a/src/native/cpu.c b/src/native/cpu.c new file mode 100644 index 00000000..46b45a7e --- /dev/null +++ b/src/native/cpu.c @@ -0,0 +1,572 @@ +#include +#include +#include +#include +#include + +#include "const.h" +#include "global_pointers.h" + +int32_t read_e8_partial_branch() { + return reg8[*modrm_byte << 2 & 0xC | *modrm_byte >> 2 & 1]; +} + +int32_t translate_address_read(int32_t); +int32_t translate_address_write(int32_t); +int32_t read8(uint32_t); +int32_t read16(uint32_t); +int32_t read32s(uint32_t); +int32_t virt_boundary_read16(int32_t, int32_t); +int32_t virt_boundary_read32s(int32_t, int32_t); +void write8(uint32_t, uint8_t); +void write16(uint32_t, uint16_t); +void write32(uint32_t, int32_t); +void virt_boundary_write16(int32_t, int32_t, int32_t); +void virt_boundary_write32(int32_t, int32_t, int32_t); + +void trigger_gp(int32_t); + +int32_t safe_read8(int32_t); +int32_t safe_read16(int32_t); +int32_t safe_read32s(int32_t); + +void safe_write8(int32_t, int32_t); +void safe_write16(int32_t, int32_t); +void safe_write32(int32_t, int32_t); + +void fxsave(int32_t); +void fxrstor(int32_t); + +int32_t do_page_translation(int32_t, bool, bool); + +void diverged() {} +void branch_taken() {} +void branch_not_taken() {} + +int32_t getcf(void); +int32_t getpf(void); +int32_t getaf(void); +int32_t getzf(void); +int32_t getsf(void); +int32_t getof(void); + + +int32_t get_eflags() +{ + return (*flags & ~FLAGS_ALL) | !!getcf() | !!getpf() << 2 | !!getaf() << 4 | + !!getzf() << 6 | !!getsf() << 7 | !!getof() << 11; +} + +int32_t translate_address_read(int32_t address) +{ + if(!*paging) return address; + + int32_t base = (uint32_t)address >> 12; + if(tlb_info[base] & (*cpl == 3 ? TLB_USER_READ : TLB_SYSTEM_READ)) + { + return tlb_data[base] ^ address; + } + else + { + return do_page_translation(address, 0, *cpl == 3) | address & 0xFFF; + } +} + +int32_t translate_address_write(int32_t address) +{ + if(!*paging) return address; + + int32_t base = (uint32_t)address >> 12; + if(tlb_info[base] & (*cpl == 3 ? TLB_USER_WRITE : TLB_SYSTEM_WRITE)) + { + return tlb_data[base] ^ address; + } + else + { + return do_page_translation(address, 1, *cpl == 3) | address & 0xFFF; + } +} + +int32_t read_imm8() +{ + int32_t eip = *instruction_pointer; + + if((eip & ~0xFFF) ^ *last_virt_eip) + { + *eip_phys = translate_address_read(eip) ^ eip; + *last_virt_eip = eip & ~0xFFF; + } + + int32_t data8 = read8(*eip_phys ^ eip); + *instruction_pointer = eip + 1; + + return data8; +} + +int32_t read_imm8s() +{ + return read_imm8() << 24 >> 24; +} + +int32_t read_imm16() +{ + // Two checks in one comparison: + // 1. Did the high 20 bits of eip change + // or 2. Are the low 12 bits of eip 0xFFF (and this read crosses a page boundary) + if((uint32_t)(*instruction_pointer ^ *last_virt_eip) > 0xFFE) + { + return read_imm8() | read_imm8() << 8; + } + + int32_t data16 = read16(*eip_phys ^ *instruction_pointer); + *instruction_pointer = *instruction_pointer + 2; + + return data16; +} + +int32_t read_imm32s() +{ + // Analogue to the above comment + if((uint32_t)(*instruction_pointer ^ *last_virt_eip) > 0xFFC) + { + return read_imm16() | read_imm16() << 16; + } + + int32_t data32 = read32s(*eip_phys ^ *instruction_pointer); + *instruction_pointer = *instruction_pointer + 4; + + return data32; +} + +int32_t read_op0F() { return read_imm8(); } +int32_t read_sib() { return read_imm8(); } +int32_t read_op8() { return read_imm8(); } +int32_t read_op8s() { return read_imm8s(); } +int32_t read_op16() { return read_imm16(); } +int32_t read_op32s() { return read_imm32s(); } +int32_t read_disp8() { return read_imm8(); } +int32_t read_disp8s() { return read_imm8s(); } +int32_t read_disp16() { return read_imm16(); } +int32_t read_disp32s() { return read_imm32s(); } + +bool is_osize_32() +{ + return *is_32 != ((*prefixes & PREFIX_MASK_OPSIZE) == PREFIX_MASK_OPSIZE); +} + +bool is_asize_32() +{ + return *is_32 != ((*prefixes & PREFIX_MASK_ADDRSIZE) == PREFIX_MASK_ADDRSIZE); +} + +void read_modrm_byte() +{ + *modrm_byte = read_imm8(); +} + +int32_t get_seg(int32_t segment) +{ + assert(segment >= 0 && segment < 8); + + // TODO: Remove protected_mode check + if(*protected_mode) + { + if(segment_is_null[segment]) + { + assert(segment != CS && segment != SS); + trigger_gp(0); + } + } + + return segment_offsets[segment]; +} + +int32_t get_seg_prefix(int32_t default_segment) +{ + int32_t prefix = *prefixes & PREFIX_MASK_SEGMENT; + + if(prefix) + { + if(prefix == SEG_PREFIX_ZERO) + { + return 0; // TODO: Remove this special case + } + else + { + return get_seg(prefix - 1); + } + } + else + { + return get_seg(default_segment); + } +} + +int32_t get_seg_prefix_ds(int32_t offset) { return get_seg_prefix(DS) + offset; } +int32_t get_seg_prefix_ss(int32_t offset) { return get_seg_prefix(SS) + offset; } +int32_t get_seg_prefix_cs(int32_t offset) { return get_seg_prefix(CS) + offset; } + +static void run_instruction(int32_t); +static int32_t resolve_modrm16(int32_t); +static int32_t resolve_modrm32(int32_t); + +static int32_t modrm_resolve(int32_t modrm_byte) +{ + if(is_asize_32()) + { + return resolve_modrm32(modrm_byte); + } + else + { + return resolve_modrm16(modrm_byte); + } +} + +void set_e8(int32_t value) +{ + int32_t modrm_byte_ = *modrm_byte; + if(modrm_byte_ < 0xC0) { + int32_t addr = modrm_resolve(modrm_byte_); + safe_write8(addr, value); + } else { + reg8[modrm_byte_ << 2 & 0xC | modrm_byte_ >> 2 & 1] = value; + } +} + +void set_e16(int32_t value) +{ + int32_t modrm_byte_ = *modrm_byte; + if(modrm_byte_ < 0xC0) { + int32_t addr = modrm_resolve(modrm_byte_); + safe_write16(addr, value); + } else { + reg16[modrm_byte_ << 1 & 14] = value; + } +} + +void set_e32(int32_t value) +{ + int32_t modrm_byte_ = *modrm_byte; + if(modrm_byte_ < 0xC0) { + int32_t addr = modrm_resolve(modrm_byte_); + safe_write32(addr, value); + } else { + reg32s[modrm_byte_ & 7] = value; + } +} + +int32_t read_g8() +{ + return reg8[*modrm_byte >> 1 & 0xC | *modrm_byte >> 5 & 1]; +} + +int32_t read_g16() +{ + return reg16[*modrm_byte >> 2 & 14]; +} + +int32_t read_g16s() +{ + return reg16s[*modrm_byte >> 2 & 14]; +} + +int32_t read_g32s() +{ + return reg32s[*modrm_byte >> 3 & 7]; +} + +void write_g8(int32_t value) +{ + reg8[*modrm_byte >> 1 & 0xC | *modrm_byte >> 5 & 1] = value; +} + +void write_g16(int32_t value) +{ + reg16[*modrm_byte >> 2 & 14] = value; +} + +void write_g32(int32_t value) +{ + reg32s[*modrm_byte >> 3 & 7] = value; +} + +int32_t read_e8() +{ + if(*modrm_byte < 0xC0) + { + return safe_read8(modrm_resolve(*modrm_byte)); + } + else + { + return reg8[*modrm_byte << 2 & 0xC | *modrm_byte >> 2 & 1]; + } +} + +int32_t read_e8s() +{ + return read_e8() << 24 >> 24; +} + +int32_t read_e16() +{ + if(*modrm_byte < 0xC0) + { + return safe_read16(modrm_resolve(*modrm_byte)); + } + else + { + return reg16[*modrm_byte << 1 & 14]; + } +} + +int32_t read_e16s() +{ + return read_e16() << 16 >> 16; +} + +int32_t read_e32s() +{ + if(*modrm_byte < 0xC0) + { + return safe_read32s(modrm_resolve(*modrm_byte)); + } + else + { + return reg32s[*modrm_byte & 7]; + } +} + +void cycle_internal() +{ + previous_ip[0] = instruction_pointer[0]; + + (*timestamp_counter)++; + + int32_t opcode = read_imm8(); + + run_instruction(opcode); +} + +static void run_prefix_instruction() +{ + run_instruction(read_imm8()); +} + +void clear_prefixes() +{ + *prefixes = 0; +} + +void segment_prefix_op(int32_t seg) +{ + assert(seg <= 5); + *prefixes |= seg + 1; + run_prefix_instruction(); + *prefixes = 0; +} + +void do_many_cycles_unsafe() +{ + for(int32_t k = 0; k < LOOP_COUNTER; k++) + { + cycle_internal(); + } +} + +void raise_exception(int32_t interrupt_nr) +{ + call_interrupt_vector(interrupt_nr, false, false, 0); + throw_cpu_exception(); +} + +void raise_exception_with_code(int32_t interrupt_nr, int32_t error_code) +{ + call_interrupt_vector(interrupt_nr, false, true, error_code); + throw_cpu_exception(); +} + +void trigger_de() +{ + *instruction_pointer = *previous_ip; + raise_exception(0); +} + +void trigger_gp(int32_t code) +{ + *instruction_pointer = *previous_ip; + raise_exception_with_code(13, code); +} + +int32_t safe_read8(int32_t addr) +{ + return read8(translate_address_read(addr)); +} + +int32_t safe_read16(int32_t addr) +{ + if((addr & 0xFFF) == 0xFFF) + { + return safe_read8(addr) | safe_read8(addr + 1) << 8; + } + else + { + return read16(translate_address_read(addr)); + } +} + +int32_t safe_read32s(int32_t addr) +{ + if((addr & 0xFFF) >= 0xFFD) + { + return safe_read16(addr) | safe_read16(addr + 2) << 16; + } + else + { + return read32s(translate_address_read(addr)); + } +} + +void safe_write8(int32_t addr, int32_t value) +{ + write8(translate_address_write(addr), value); +} + +void safe_write16(int32_t addr, int32_t value) +{ + int32_t phys_low = translate_address_write(addr); + + if((addr & 0xFFF) == 0xFFF) + { + virt_boundary_write16(phys_low, translate_address_write(addr + 1), value); + } + else + { + write16(phys_low, value); + } +} + +void safe_write32(int32_t addr, int32_t value) +{ + int32_t phys_low = translate_address_write(addr); + + if((addr & 0xFFF) >= 0xFFD) + { + virt_boundary_write32(phys_low, translate_address_write(addr + 3 & ~3) | (addr + 3) & 3, value); + } + else + { + write32(phys_low, value); + } +} + +int32_t read_write_e8() +{ + if(*modrm_byte < 0xC0) + { + int32_t virt_addr = modrm_resolve(*modrm_byte); + *phys_addr = translate_address_write(virt_addr); + return read8(*phys_addr); + } + else + { + return reg8[*modrm_byte << 2 & 0xC | *modrm_byte >> 2 & 1]; + } +} + +void write_e8(int32_t value) +{ + if(*modrm_byte < 0xC0) + { + write8(*phys_addr, value); + } + else + { + reg8[*modrm_byte << 2 & 0xC | *modrm_byte >> 2 & 1] = value; + } +} + +int32_t read_write_e16() +{ + if(*modrm_byte < 0xC0) + { + int32_t virt_addr = modrm_resolve(*modrm_byte); + *phys_addr = translate_address_write(virt_addr); + if((virt_addr & 0xFFF) == 0xFFF) + { + *phys_addr_high = translate_address_write(virt_addr + 1); + dbg_assert(*phys_addr_high); + return virt_boundary_read16(*phys_addr, *phys_addr_high); + } + else + { + *phys_addr_high = 0; + return read16(*phys_addr); + } + } + else + { + return reg16[*modrm_byte << 1 & 14]; + } +} + +void write_e16(int32_t value) +{ + if(*modrm_byte < 0xC0) + { + if(*phys_addr_high) + { + virt_boundary_write16(*phys_addr, *phys_addr_high, value); + } + else + { + write16(*phys_addr, value); + } + } + else + { + reg16[*modrm_byte << 1 & 14] = value; + } +} + +int32_t read_write_e32() +{ + if(*modrm_byte < 0xC0) + { + int32_t virt_addr = modrm_resolve(*modrm_byte); + *phys_addr = translate_address_write(virt_addr); + if((virt_addr & 0xFFF) >= 0xFFD) + { + *phys_addr_high = translate_address_write(virt_addr + 3 & ~3) | (virt_addr + 3) & 3; + dbg_assert(*phys_addr_high); + return virt_boundary_read32s(*phys_addr, *phys_addr_high); + } + else + { + *phys_addr_high = 0; + return read32s(*phys_addr); + } + } + else + { + return reg32s[*modrm_byte & 7]; + } +} + +void write_e32(int32_t value) +{ + if(*modrm_byte < 0xC0) + { + if(*phys_addr_high) + { + virt_boundary_write32(*phys_addr, *phys_addr_high, value); + } + else + { + write32(*phys_addr, value); + } + } + else + { + reg32s[*modrm_byte & 7] = value; + } +} diff --git a/src/native/fpu.c b/src/native/fpu.c new file mode 100644 index 00000000..aab2b889 --- /dev/null +++ b/src/native/fpu.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +#include + +#include "const.h" +#include "global_pointers.h" + +void safe_tag_word(int32_t tag_word) { + *stack_empty = 0; + + for(int i = 0; i < 8; i++) + { + *stack_empty |= (tag_word >> i) & (tag_word >> (i + 1)) & 1 << i; + } + + //dbg_log("safe tw=" + h(tag_word) + " se=" + h(this.stack_empty[0]), LOG_FPU); +} diff --git a/src/native/global_pointers.h b/src/native/global_pointers.h new file mode 100644 index 00000000..5651a416 --- /dev/null +++ b/src/native/global_pointers.h @@ -0,0 +1,69 @@ +#ifndef _GLOBAL_POINTERS_H +#define _GLOBAL_POINTERS_H + +uint8_t* const reg8 = (uint8_t* const) 4; +uint16_t* const reg16 = (uint16_t* const) 4; +int8_t* const reg8s = (int8_t* const) 4; +int16_t* const reg16s = (int16_t* const) 4; +int32_t* const reg32s = (int32_t* const) 4; + +int32_t* const last_op1 = (int32_t* const) 512; +int32_t* const last_op2 = (int32_t* const) 516; +int32_t* const last_op_size = (int32_t* const) 520; +int32_t* const last_add_result = (int32_t* const) 524; +int32_t* const last_result = (int32_t* const) 528; +int32_t* const flags_changed = (int32_t* const) 532; +int32_t* const flags = (int32_t* const) 536; +int32_t* const modrm_byte = (int32_t* const) 540; +int32_t* const mul32_result = (int32_t* const) 544; // length 2 + +bool* const a20_enabled = (bool* const) 552; +int32_t* const instruction_pointer = (int32_t* const) 556; +int32_t* const previous_ip = (int32_t* const) 560; + +int32_t* const idtr_size = (int32_t* const) 564; +int32_t* const idtr_offset = (int32_t* const) 568; +int32_t* const gdtr_size = (int32_t* const) 572; +int32_t* const gdtr_offset = (int32_t* const) 576; +int32_t* const cr = (int32_t* const) 580; // length 8 + +int32_t* const cpl = (int32_t* const) 612; +int32_t* const page_size_extensions = (int32_t* const) 616; +int32_t* const last_virt_eip = (int32_t* const) 620; +int32_t* const eip_phys = (int32_t* const) 624; +int32_t* const last_virt_esp = (int32_t* const) 628; +int32_t* const esp_phys = (int32_t* const) 632; +int32_t* const sysenter_cs = (int32_t* const) 636; +int32_t* const sysenter_esp = (int32_t* const) 640; +int32_t* const sysenter_eip = (int32_t* const) 644; +int32_t* const prefixes = (int32_t* const) 648; +int32_t* const tsc_offset = (int32_t* const) 652; +int32_t* const phys_addr = (int32_t* const) 656; +int32_t* const phys_addr_high = (int32_t* const) 660; +int32_t* const timestamp_counter = (int32_t* const) 664; + +uint16_t* const sreg = (uint16_t* const) 668; +int32_t* const dreg = (int32_t* const) 684; // length 8 +int32_t* const fw_value = (int32_t* const) 720; +uint8_t* const segment_is_null = (uint8_t* const) 724; // length 8 +int32_t* const segment_offsets = (int32_t* const) 736; // length 8 +uint32_t* const segment_limits = (uint32_t* const) 768; // length 8 + +bool* const protected_mode = (bool* const) 800; +bool* const is_32 = (bool* const) 804; +bool* const stack_size_32 = (bool* const) 808; +uint32_t* const memory_size = (uint32_t* const) 812; +int32_t* const stack_empty = (int32_t* const) 816; + +bool* const paging = (bool* const) 820; + +bool* const mxcsr = (bool* const) 824; + +uint8_t* const tlb_info = (uint8_t* const) 2048; // length 0x100000 +uint8_t* const tlb_info_global = (uint8_t* const) (2048 + 0x100000); // length 0x100000 +int32_t* const tlb_data = (int32_t* const) (2048 + 0x100000 + 0x100000); // length 0x100000*4 + +uint8_t* const mem8 = (uint8_t* const) (2048 + 0x100000 * 6); +uint16_t* const mem16 = (uint16_t* const) (2048 + 0x100000 * 6); + +#endif diff --git a/src/native/instructions.c b/src/native/instructions.c new file mode 100644 index 00000000..9280ec74 --- /dev/null +++ b/src/native/instructions.c @@ -0,0 +1,3171 @@ +#include +#include +#include +#include + +#include + +#include "const.h" +#include "global_pointers.h" + +int32_t translate_address_write(int32_t); +int32_t resolve_modrm(int32_t); + +/* +int32_t phys_read8(int32_t); +int32_t phys_write8(int32_t, int32_t); + + +#define RE8 reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] +#define E8 e8 +#define G8 reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1] + +#define IDX_E8 (modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1) +#define IDX_G8 (modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1) + +#define READ_WRITE_E8_(f)\ +{\ + int32_t modrm_byte = read_modrm_byte();\ + if(modrm_byte < 0xC0) {\ + int32_t phys_addr = translate_address_write(resolve_modrm(modrm_byte));\ + int32_t e8 = phys_read8(phys_addr);\ + phys_write8(phys_addr, f);\ + }\ + else {\ + int32_t e8 = RE8;\ + RE8 = f;\ + }\ +} + +#define READ_WRITE_E8(f)\ +{\ + int32_t modrm_byte = read_modrm_byte();\ + if(modrm_byte < 0xC0) {\ + int32_t virt_addr = resolve_modrm(modrm_byte);\ + f ## _rm(virt_addr, IDX_G8);\ + }\ + else {\ + f ## _rr(IDX_E8, IDX_G8);\ + }\ +} +*/ + + +// XXX: Remove these declarations when they are implemented in C +int32_t read_write_e8(void); +int32_t read_write_e16(void); +int32_t read_write_e32(void); +int32_t read_g8(void); +int32_t read_g16(void); +int32_t read_g32s(void); + +int32_t read_e8(void); +int32_t read_e8s(void); +int32_t read_e16(void); +int32_t read_e16s(void); +int32_t read_e32(void); +int32_t read_e32s(void); + +void write_e8(int32_t); +void write_e16(int32_t); +void write_e32(int32_t); + +void write_reg_e16(int32_t); +void write_reg_e32(int32_t); + +void set_e8(int32_t); +void set_e16(int32_t); +void set_e32(int32_t); + +void write_g8(int32_t); +void write_g16(int32_t); +void write_g32(int32_t); + +int32_t read_op8(void); +int32_t read_op8s(void); +int32_t read_op16(void); +int32_t read_op32s(void); + +int32_t read_disp8(void); +int32_t read_disp16(void); + +int32_t read_moffs(void); + +void push16(int32_t); +void push32(int32_t); + +void pusha16(void); +void pusha32(void); +void popa16(void); +void popa32(void); +int32_t arpl(int32_t, int32_t); + +void trigger_ud(void); +void trigger_nm(void); +static void run_prefix_instruction(void); + +int32_t pop16(void); +int32_t pop32s(void); + +int32_t safe_read8(int32_t); +int32_t safe_read16(int32_t); +int32_t safe_read32s(int32_t); + +void safe_write8(int32_t, int32_t); +void safe_write16(int32_t, int32_t); +void safe_write32(int32_t, int32_t); + +void push32(int32_t); +int32_t get_stack_pointer(int32_t); +void adjust_stack_reg(int32_t); +void set_stack_reg(int32_t); + +int32_t getiopl(void); +int32_t get_eflags(void); +int32_t getof(void); +int32_t getzf(void); + +void switch_seg(int32_t, int32_t); + +bool vm86_mode(void); + +int32_t shl8(int32_t, int32_t); +int32_t shr8(int32_t, int32_t); +int32_t sar8(int32_t, int32_t); +int32_t ror8(int32_t, int32_t); +int32_t rol8(int32_t, int32_t); +int32_t rcr8(int32_t, int32_t); +int32_t rcl8(int32_t, int32_t); + +int32_t shl16(int32_t, int32_t); +int32_t shr16(int32_t, int32_t); +int32_t sar16(int32_t, int32_t); +int32_t ror16(int32_t, int32_t); +int32_t rol16(int32_t, int32_t); +int32_t rcr16(int32_t, int32_t); +int32_t rcl16(int32_t, int32_t); + +int32_t shl32(int32_t, int32_t); +int32_t shr32(int32_t, int32_t); +int32_t sar32(int32_t, int32_t); +int32_t ror32(int32_t, int32_t); +int32_t rol32(int32_t, int32_t); +int32_t rcr32(int32_t, int32_t); +int32_t rcl32(int32_t, int32_t); + +int32_t idiv16(int32_t); +int32_t div32(int32_t); +int32_t idiv32(int32_t); + + +void insb(void); +void insw(void); +void insd(void); +void outsb(void); +void outsw(void); +void outsd(void); +void movsb(void); +void movsw(void); +void movsd(void); +void cmpsb(void); +void cmpsw(void); +void cmpsd(void); +void stosb(void); +void stosw(void); +void stosd(void); +void lodsb(void); +void lodsw(void); +void lodsd(void); +void scasb(void); +void scasw(void); +void scasd(void); + +void fpu_op_D8_mem(int32_t, int32_t); +void fpu_op_D8_reg(int32_t); +void fpu_op_D9_mem(int32_t, int32_t); +void fpu_op_D9_reg(int32_t); +void fpu_op_DA_mem(int32_t, int32_t); +void fpu_op_DA_reg(int32_t); +void fpu_op_DB_mem(int32_t, int32_t); +void fpu_op_DB_reg(int32_t); +void fpu_op_DC_mem(int32_t, int32_t); +void fpu_op_DC_reg(int32_t); +void fpu_op_DD_mem(int32_t, int32_t); +void fpu_op_DD_reg(int32_t); +void fpu_op_DE_mem(int32_t, int32_t); +void fpu_op_DE_reg(int32_t); +void fpu_op_DF_mem(int32_t, int32_t); +void fpu_op_DF_reg(int32_t); + +int32_t test_o(void); +int32_t test_b(void); +int32_t test_z(void); +int32_t test_s(void); +int32_t test_p(void); +int32_t test_be(void); +int32_t test_l(void); +int32_t test_le(void); + +void jmpcc8(bool); + +void far_jump(int32_t, int32_t, int32_t); +void far_return(int32_t, int32_t, int32_t); + +void iret16(); +void iret32(); + +void lss16(int32_t); +void lss32(int32_t); + +void enter16(int32_t, int32_t); +void enter32(int32_t, int32_t); + +int32_t get_seg(int32_t); +int32_t get_seg_prefix(int32_t); +void update_eflags(int32_t); +void handle_irqs(void); +int32_t get_real_eip(void); +void diverged(void); + +int32_t xchg8(int32_t, int32_t); +int32_t xchg16(int32_t, int32_t); +int32_t xchg16r(int32_t); +int32_t xchg32(int32_t, int32_t); +int32_t xchg32r(int32_t); + +int32_t loop(int32_t); +int32_t loope(int32_t); +int32_t loopne(int32_t); + +void bcd_aam(int32_t); +void task_switch_test(void); +void jcxz(int32_t); +void test_privileges_for_io(int32_t, int32_t); +int32_t io_port_read8(int32_t); +int32_t io_port_read16(int32_t); +int32_t io_port_read32(int32_t); +void jmp_rel16(int32_t); +void hlt_op(void); + +void io_port_write8(int32_t, int32_t); +void io_port_write16(int32_t, int32_t); +void io_port_write32(int32_t, int32_t); + +int32_t modrm_resolve(int32_t); + +static void run_instruction0f_16(int32_t); +static void run_instruction0f_32(int32_t); + +void clear_prefixes(void); +void cycle_internal(void); + + +void fwait(void); + + +static void instr_00() { read_modrm_byte(); write_e8(add8(read_write_e8(), read_g8())); } +static void instr16_01() { read_modrm_byte(); write_e16(add16(read_write_e16(), read_g16())); } +static void instr32_01() { read_modrm_byte(); write_e32(add32(read_write_e32(), read_g32s())); } +static void instr_02() { read_modrm_byte(); write_g8(add8(read_g8(), read_e8())); } +static void instr16_03() { read_modrm_byte(); write_g16(add16(read_g16(), read_e16())); } +static void instr32_03() { read_modrm_byte(); write_g32(add32(read_g32s(), read_e32s())); } +static void instr_04() { reg8[AL] = add8(reg8[AL], read_op8()); } +static void instr16_05() { reg16[AX] = add16(reg16[AX], read_op16()); } +static void instr32_05() { reg32s[EAX] = add32(reg32s[EAX], read_op32s()); } + +static void instr16_06() { push16(sreg[ES]); } +static void instr32_06() { push32(sreg[ES]); } +static void instr16_07() { + switch_seg(ES, safe_read16(get_stack_pointer(0))); + adjust_stack_reg(2); +} +static void instr32_07() { + switch_seg(ES, safe_read32s(get_stack_pointer(0)) & 0xFFFF); + adjust_stack_reg(4); +} + +static void instr_08() { read_modrm_byte(); write_e8(or8(read_write_e8(), read_g8())); } +static void instr16_09() { read_modrm_byte(); write_e16(or16(read_write_e16(), read_g16())); } +static void instr32_09() { read_modrm_byte(); write_e32(or32(read_write_e32(), read_g32s())); } +static void instr_0A() { read_modrm_byte(); write_g8(or8(read_g8(), read_e8())); } +static void instr16_0B() { read_modrm_byte(); write_g16(or16(read_g16(), read_e16())); } +static void instr32_0B() { read_modrm_byte(); write_g32(or32(read_g32s(), read_e32s())); } +static void instr_0C() { reg8[AL] = or8(reg8[AL], read_op8()); } +static void instr16_0D() { reg16[AX] = or16(reg16[AX], read_op16()); } +static void instr32_0D() { reg32s[EAX] = or32(reg32s[EAX], read_op32s()); } + + +static void instr16_0E() { push16(sreg[CS]); } +static void instr32_0E() { push32(sreg[CS]); } +static void instr16_0F() { + run_instruction0f_16(read_imm8()); +} +static void instr32_0F() { + run_instruction0f_32(read_imm8()); +} + +static void instr_10() { read_modrm_byte(); write_e8(adc8(read_write_e8(), read_g8())); } +static void instr16_11() { read_modrm_byte(); write_e16(adc16(read_write_e16(), read_g16())); } +static void instr32_11() { read_modrm_byte(); write_e32(adc32(read_write_e32(), read_g32s())); } +static void instr_12() { read_modrm_byte(); write_g8(adc8(read_g8(), read_e8())); } +static void instr16_13() { read_modrm_byte(); write_g16(adc16(read_g16(), read_e16())); } +static void instr32_13() { read_modrm_byte(); write_g32(adc32(read_g32s(), read_e32s())); } +static void instr_14() { reg8[AL] = adc8(reg8[AL], read_op8()); } +static void instr16_15() { reg16[AX] = adc16(reg16[AX], read_op16()); } +static void instr32_15() { reg32s[EAX] = adc32(reg32s[EAX], read_op32s()); } + +static void instr16_16() { push16(sreg[SS]); } +static void instr32_16() { push32(sreg[SS]); } +static void instr16_17() { + switch_seg(SS, safe_read16(get_stack_pointer(0))); + adjust_stack_reg(2); + clear_prefixes(); + cycle_internal(); +} +static void instr32_17() { + switch_seg(SS, safe_read32s(get_stack_pointer(0)) & 0xFFFF); + adjust_stack_reg(4); + clear_prefixes(); + cycle_internal(); +} + +static void instr_18() { read_modrm_byte(); write_e8(sbb8(read_write_e8(), read_g8())); } +static void instr16_19() { read_modrm_byte(); write_e16(sbb16(read_write_e16(), read_g16())); } +static void instr32_19() { read_modrm_byte(); write_e32(sbb32(read_write_e32(), read_g32s())); } +static void instr_1A() { read_modrm_byte(); write_g8(sbb8(read_g8(), read_e8())); } +static void instr16_1B() { read_modrm_byte(); write_g16(sbb16(read_g16(), read_e16())); } +static void instr32_1B() { read_modrm_byte(); write_g32(sbb32(read_g32s(), read_e32s())); } +static void instr_1C() { reg8[AL] = sbb8(reg8[AL], read_op8()); } +static void instr16_1D() { reg16[AX] = sbb16(reg16[AX], read_op16()); } +static void instr32_1D() { reg32s[EAX] = sbb32(reg32s[EAX], read_op32s()); } + + +static void instr16_1E() { push16(sreg[DS]); } +static void instr32_1E() { push32(sreg[DS]); } +static void instr16_1F() { + switch_seg(DS, safe_read16(get_stack_pointer(0))); + adjust_stack_reg(2); +} +static void instr32_1F() { + switch_seg(DS, safe_read32s(get_stack_pointer(0)) & 0xFFFF); + adjust_stack_reg(4); +} + +static void instr_20() { read_modrm_byte(); write_e8(and8(read_write_e8(), read_g8())); } +static void instr16_21() { read_modrm_byte(); write_e16(and16(read_write_e16(), read_g16())); } +static void instr32_21() { read_modrm_byte(); write_e32(and32(read_write_e32(), read_g32s())); } +static void instr_22() { read_modrm_byte(); write_g8(and8(read_g8(), read_e8())); } +static void instr16_23() { read_modrm_byte(); write_g16(and16(read_g16(), read_e16())); } +static void instr32_23() { read_modrm_byte(); write_g32(and32(read_g32s(), read_e32s())); } +static void instr_24() { reg8[AL] = and8(reg8[AL], read_op8()); } +static void instr16_25() { reg16[AX] = and16(reg16[AX], read_op16()); } +static void instr32_25() { reg32s[EAX] = and32(reg32s[EAX], read_op32s()); } + + +static void instr_26() { segment_prefix_op(ES); } +static void instr_27() { bcd_daa(); } + +static void instr_28() { read_modrm_byte(); write_e8(sub8(read_write_e8(), read_g8())); } +static void instr16_29() { read_modrm_byte(); write_e16(sub16(read_write_e16(), read_g16())); } +static void instr32_29() { read_modrm_byte(); write_e32(sub32(read_write_e32(), read_g32s())); } +static void instr_2A() { read_modrm_byte(); write_g8(sub8(read_g8(), read_e8())); } +static void instr16_2B() { read_modrm_byte(); write_g16(sub16(read_g16(), read_e16())); } +static void instr32_2B() { read_modrm_byte(); write_g32(sub32(read_g32s(), read_e32s())); } +static void instr_2C() { reg8[AL] = sub8(reg8[AL], read_op8()); } +static void instr16_2D() { reg16[AX] = sub16(reg16[AX], read_op16()); } +static void instr32_2D() { reg32s[EAX] = sub32(reg32s[EAX], read_op32s()); } + +static void instr_2E() { segment_prefix_op(CS); } +static void instr_2F() { bcd_das(); } + +static void instr_30() { read_modrm_byte(); write_e8(xor8(read_write_e8(), read_g8())); } +static void instr16_31() { read_modrm_byte(); write_e16(xor16(read_write_e16(), read_g16())); } +static void instr32_31() { read_modrm_byte(); write_e32(xor32(read_write_e32(), read_g32s())); } +static void instr_32() { read_modrm_byte(); write_g8(xor8(read_g8(), read_e8())); } +static void instr16_33() { read_modrm_byte(); write_g16(xor16(read_g16(), read_e16())); } +static void instr32_33() { read_modrm_byte(); write_g32(xor32(read_g32s(), read_e32s())); } +static void instr_34() { reg8[AL] = xor8(reg8[AL], read_op8()); } +static void instr16_35() { reg16[AX] = xor16(reg16[AX], read_op16()); } +static void instr32_35() { reg32s[EAX] = xor32(reg32s[EAX], read_op32s()); } + +static void instr_36() { segment_prefix_op(SS); } +static void instr_37() { bcd_aaa(); } + +static void instr_38() { read_modrm_byte(); cmp8(read_e8(), read_g8()); } +static void instr16_39() { read_modrm_byte(); cmp16(read_e16(), read_g16()); } +static void instr32_39() { read_modrm_byte(); cmp32(read_e32s(), read_g32s()); } +static void instr_3A() { read_modrm_byte(); cmp8(read_g8(), read_e8()); } +static void instr16_3B() { read_modrm_byte(); cmp16(read_g16(), read_e16()); } +static void instr32_3B() { read_modrm_byte(); cmp32(read_g32s(), read_e32s()); } +static void instr_3C() { cmp8(reg8[AL], read_op8()); } +static void instr16_3D() { cmp16(reg16[AX], read_op16()); } +static void instr32_3D() { cmp32(reg32s[EAX], read_op32s()); } + +static void instr_3E() { segment_prefix_op(DS); } +static void instr_3F() { bcd_aas(); } + + +static void instr16_40() { reg16[AX] = inc16(reg16[AX]); } +static void instr32_40() { reg32s[EAX] = inc32(reg32s[EAX]); } +static void instr16_41() { reg16[CX] = inc16(reg16[CX]); } +static void instr32_41() { reg32s[ECX] = inc32(reg32s[ECX]); } +static void instr16_42() { reg16[DX] = inc16(reg16[DX]); } +static void instr32_42() { reg32s[EDX] = inc32(reg32s[EDX]); } +static void instr16_43() { reg16[BX] = inc16(reg16[BX]); } +static void instr32_43() { reg32s[EBX] = inc32(reg32s[EBX]); } +static void instr16_44() { reg16[SP] = inc16(reg16[SP]); } +static void instr32_44() { reg32s[ESP] = inc32(reg32s[ESP]); } +static void instr16_45() { reg16[BP] = inc16(reg16[BP]); } +static void instr32_45() { reg32s[EBP] = inc32(reg32s[EBP]); } +static void instr16_46() { reg16[SI] = inc16(reg16[SI]); } +static void instr32_46() { reg32s[ESI] = inc32(reg32s[ESI]); } +static void instr16_47() { reg16[DI] = inc16(reg16[DI]); } +static void instr32_47() { reg32s[EDI] = inc32(reg32s[EDI]); } + + +static void instr16_48() { reg16[AX] = dec16(reg16[AX]); } +static void instr32_48() { reg32s[EAX] = dec32(reg32s[EAX]); } +static void instr16_49() { reg16[CX] = dec16(reg16[CX]); } +static void instr32_49() { reg32s[ECX] = dec32(reg32s[ECX]); } +static void instr16_4A() { reg16[DX] = dec16(reg16[DX]); } +static void instr32_4A() { reg32s[EDX] = dec32(reg32s[EDX]); } +static void instr16_4B() { reg16[BX] = dec16(reg16[BX]); } +static void instr32_4B() { reg32s[EBX] = dec32(reg32s[EBX]); } +static void instr16_4C() { reg16[SP] = dec16(reg16[SP]); } +static void instr32_4C() { reg32s[ESP] = dec32(reg32s[ESP]); } +static void instr16_4D() { reg16[BP] = dec16(reg16[BP]); } +static void instr32_4D() { reg32s[EBP] = dec32(reg32s[EBP]); } +static void instr16_4E() { reg16[SI] = dec16(reg16[SI]); } +static void instr32_4E() { reg32s[ESI] = dec32(reg32s[ESI]); } +static void instr16_4F() { reg16[DI] = dec16(reg16[DI]); } +static void instr32_4F() { reg32s[EDI] = dec32(reg32s[EDI]); } + + +static void instr16_50() { push16(reg16[AX]); } +static void instr32_50() { push32(reg32s[EAX]); } +static void instr16_51() { push16(reg16[CX]); } +static void instr32_51() { push32(reg32s[ECX]); } +static void instr16_52() { push16(reg16[DX]); } +static void instr32_52() { push32(reg32s[EDX]); } +static void instr16_53() { push16(reg16[BX]); } +static void instr32_53() { push32(reg32s[EBX]); } +static void instr16_54() { push16(reg16[SP]); } +static void instr32_54() { push32(reg32s[ESP]); } +static void instr16_55() { push16(reg16[BP]); } +static void instr32_55() { push32(reg32s[EBP]); } +static void instr16_56() { push16(reg16[SI]); } +static void instr32_56() { push32(reg32s[ESI]); } +static void instr16_57() { push16(reg16[DI]); } +static void instr32_57() { push32(reg32s[EDI]); } + +static void instr16_58() { reg16[AX] = pop16(); } +static void instr32_58() { reg32s[EAX] = pop32s(); } +static void instr16_59() { reg16[CX] = pop16(); } +static void instr32_59() { reg32s[ECX] = pop32s(); } +static void instr16_5A() { reg16[DX] = pop16(); } +static void instr32_5A() { reg32s[EDX] = pop32s(); } +static void instr16_5B() { reg16[BX] = pop16(); } +static void instr32_5B() { reg32s[EBX] = pop32s(); } +static void instr16_5C() { reg16[SP] = pop16(); } +static void instr32_5C() { reg32s[ESP] = pop32s(); } +static void instr16_5D() { reg16[BP] = pop16(); } +static void instr32_5D() { reg32s[EBP] = pop32s(); } +static void instr16_5E() { reg16[SI] = pop16(); } +static void instr32_5E() { reg32s[ESI] = pop32s(); } +static void instr16_5F() { reg16[DI] = pop16(); } +static void instr32_5F() { reg32s[EDI] = pop32s(); } + + +static void instr16_60() { pusha16(); } +static void instr32_60() { pusha32(); } +static void instr16_61() { popa16(); } +static void instr32_61() { popa32(); } + +static void instr_62() { + // bound + dbg_log("Unimplemented BOUND instruction"); + dbg_assert(false); +} +static void instr_63() { read_modrm_byte(); + // arpl + //dbg_log("arpl"); + if(*protected_mode && !vm86_mode()) + { + write_e16(arpl(read_write_e16(), modrm_byte[0] >> 2 & 14)); + } + else + { + dbg_log("arpl #ud"); + trigger_ud(); + } +} + +static void instr_64() { segment_prefix_op(FS); } +static void instr_65() { segment_prefix_op(GS); } + +static void instr_66() { + // Operand-size override prefix + *prefixes |= PREFIX_MASK_OPSIZE; + run_prefix_instruction(); + *prefixes = 0; +} + +static void instr_67() { + // Address-size override prefix + dbg_assert(is_asize_32() == *is_32); + + *prefixes |= PREFIX_MASK_ADDRSIZE; + run_prefix_instruction(); + *prefixes = 0; +} + +static void instr16_68() { push16(read_op16()); } +static void instr32_68() { push32(read_op32s()); } + +static void instr16_69() { read_modrm_byte(); + write_g16(imul_reg16(read_e16s(), read_op16() << 16 >> 16)); +} +static void instr32_69() { read_modrm_byte(); + write_g32(imul_reg32(read_e32s(), read_op32s())); +} + +static void instr16_6A() { push16(read_op8s()); } +static void instr32_6A() { push32(read_op8s()); } + +static void instr16_6B() { read_modrm_byte(); + write_g16(imul_reg16(read_e16s(), read_op8s())); +} +static void instr32_6B() { read_modrm_byte(); + write_g32(imul_reg32(read_e32s(), read_op8s())); +} + +static void instr_6C() { insb(); } +static void instr16_6D() { insw(); } +static void instr32_6D() { insd(); } +static void instr_6E() { outsb(); } +static void instr16_6F() { outsw(); } +static void instr32_6F() { outsd(); } + +static void instr_70() { jmpcc8( test_o()); } +static void instr_71() { jmpcc8(!test_o()); } +static void instr_72() { jmpcc8( test_b()); } +static void instr_73() { jmpcc8(!test_b()); } +static void instr_74() { jmpcc8( test_z()); } +static void instr_75() { jmpcc8(!test_z()); } +static void instr_76() { jmpcc8( test_be()); } +static void instr_77() { jmpcc8(!test_be()); } +static void instr_78() { jmpcc8( test_s()); } +static void instr_79() { jmpcc8(!test_s()); } +static void instr_7A() { jmpcc8( test_p()); } +static void instr_7B() { jmpcc8(!test_p()); } +static void instr_7C() { jmpcc8( test_l()); } +static void instr_7D() { jmpcc8(!test_l()); } +static void instr_7E() { jmpcc8( test_le()); } +static void instr_7F() { jmpcc8(!test_le()); } + +static void instr_80() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: write_e8(add8(read_write_e8(), read_op8())); break; + case 1: write_e8( or8(read_write_e8(), read_op8())); break; + case 2: write_e8(adc8(read_write_e8(), read_op8())); break; + case 3: write_e8(sbb8(read_write_e8(), read_op8())); break; + case 4: write_e8(and8(read_write_e8(), read_op8())); break; + case 5: write_e8(sub8(read_write_e8(), read_op8())); break; + case 6: write_e8(xor8(read_write_e8(), read_op8())); break; + case 7: cmp8(read_e8(), read_op8()); break; + } +} +static void instr16_81() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: write_e16(add16(read_write_e16(), read_op16())); break; + case 1: write_e16( or16(read_write_e16(), read_op16())); break; + case 2: write_e16(adc16(read_write_e16(), read_op16())); break; + case 3: write_e16(sbb16(read_write_e16(), read_op16())); break; + case 4: write_e16(and16(read_write_e16(), read_op16())); break; + case 5: write_e16(sub16(read_write_e16(), read_op16())); break; + case 6: write_e16(xor16(read_write_e16(), read_op16())); break; + case 7: cmp16(read_e16(), read_op16()); break; + } +} +static void instr32_81() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: write_e32(add32(read_write_e32(), read_op32s())); break; + case 1: write_e32( or32(read_write_e32(), read_op32s())); break; + case 2: write_e32(adc32(read_write_e32(), read_op32s())); break; + case 3: write_e32(sbb32(read_write_e32(), read_op32s())); break; + case 4: write_e32(and32(read_write_e32(), read_op32s())); break; + case 5: write_e32(sub32(read_write_e32(), read_op32s())); break; + case 6: write_e32(xor32(read_write_e32(), read_op32s())); break; + case 7: cmp32(read_e32s(), read_op32s()); break; + } +} +static void instr_82() { instr_80(); } // alias +static void instr16_83() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: write_e16(add16(read_write_e16(), read_op8s())); break; + case 1: write_e16( or16(read_write_e16(), read_op8s())); break; + case 2: write_e16(adc16(read_write_e16(), read_op8s())); break; + case 3: write_e16(sbb16(read_write_e16(), read_op8s())); break; + case 4: write_e16(and16(read_write_e16(), read_op8s())); break; + case 5: write_e16(sub16(read_write_e16(), read_op8s())); break; + case 6: write_e16(xor16(read_write_e16(), read_op8s())); break; + case 7: cmp16(read_e16(), read_op8s()); break; + } +} +static void instr32_83() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: write_e32(add32(read_write_e32(), read_op8s())); break; + case 1: write_e32( or32(read_write_e32(), read_op8s())); break; + case 2: write_e32(adc32(read_write_e32(), read_op8s())); break; + case 3: write_e32(sbb32(read_write_e32(), read_op8s())); break; + case 4: write_e32(and32(read_write_e32(), read_op8s())); break; + case 5: write_e32(sub32(read_write_e32(), read_op8s())); break; + case 6: write_e32(xor32(read_write_e32(), read_op8s())); break; + case 7: cmp32(read_e32s(), read_op8s()); break; + } +} + +static void instr_84() { read_modrm_byte(); int32_t data = read_e8(); test8(data, read_g8()); } +static void instr16_85() { read_modrm_byte(); int32_t data = read_e16(); test16(data, read_g16()); } +static void instr32_85() { read_modrm_byte(); int32_t data = read_e32s(); test32(data, read_g32s()); } + + +static void instr_86() { read_modrm_byte(); int32_t data = read_write_e8(); write_e8(xchg8(data, modrm_byte[0])); } +static void instr16_87() { read_modrm_byte(); + int32_t data = read_write_e16(); write_e16(xchg16(data, modrm_byte[0])); +} +static void instr32_87() { read_modrm_byte(); + int32_t data = read_write_e32(); write_e32(xchg32(data, modrm_byte[0])); +} + +static void instr_88() { read_modrm_byte(); set_e8(read_g8()); } +static void instr16_89() { read_modrm_byte(); set_e16(read_g16()); } +static void instr32_89() { read_modrm_byte(); set_e32(read_g32s()); } + +static void instr_8A() { read_modrm_byte(); + int32_t data = read_e8(); + write_g8(data); +} +static void instr16_8B() { read_modrm_byte(); + int32_t data = read_e16(); + write_g16(data); +} +static void instr32_8B() { read_modrm_byte(); + int32_t data = read_e32s(); + write_g32(data); +} + +static void instr16_8C() { read_modrm_byte(); + set_e16(sreg[modrm_byte[0] >> 3 & 7]); +} +static void instr32_8C() { read_modrm_byte(); + set_e32(sreg[modrm_byte[0] >> 3 & 7]); +} + +static void instr16_8D() { read_modrm_byte(); + // lea + if(modrm_byte[0] >= 0xC0) + { + dbg_log("lea #ud"); + trigger_ud(); + } + int32_t mod = modrm_byte[0] >> 3 & 7; + + // override prefix, so modrm_resolve does not return the segment part + *prefixes |= SEG_PREFIX_ZERO; + reg16[mod << 1] = modrm_resolve(modrm_byte[0]); + *prefixes = 0; +} +static void instr32_8D() { read_modrm_byte(); + if(modrm_byte[0] >= 0xC0) + { + dbg_log("lea #ud"); + trigger_ud(); + } + int32_t mod = modrm_byte[0] >> 3 & 7; + + *prefixes |= SEG_PREFIX_ZERO; + reg32s[mod] = modrm_resolve(modrm_byte[0]); + *prefixes = 0; +} + +static void instr_8E() { read_modrm_byte(); + int32_t mod = modrm_byte[0] >> 3 & 7; + int32_t data = read_e16(); + switch_seg(mod, data); + + if(mod == SS) + { + // run next instruction, so no interrupts are handled + clear_prefixes(); + cycle_internal(); + } +} + +static void instr16_8F() { read_modrm_byte(); + // pop + int32_t sp = safe_read16(get_stack_pointer(0)); + + adjust_stack_reg(2); + + if(modrm_byte[0] < 0xC0) { + int32_t addr = modrm_resolve(modrm_byte[0]); + adjust_stack_reg(-2); + safe_write16(addr, sp); + adjust_stack_reg(2); + } else { + write_reg_e16(sp); + } +} +static void instr32_8F() { read_modrm_byte(); + int32_t sp = safe_read32s(get_stack_pointer(0)); + + // change esp first, then resolve modrm address + adjust_stack_reg(4); + + if(modrm_byte[0] < 0xC0) { + int32_t addr = modrm_resolve(modrm_byte[0]); + + // Before attempting a write that might cause a page fault, + // we must set esp to the old value. Fuck Intel. + adjust_stack_reg(-4); + safe_write32(addr, sp); + adjust_stack_reg(4); + } else { + write_reg_e32(sp); + } +} + +static void instr_90() { } +static void instr16_91() { xchg16r(CX); } +static void instr32_91() { xchg32r(ECX); } +static void instr16_92() { xchg16r(DX); } +static void instr32_92() { xchg32r(EDX); } +static void instr16_93() { xchg16r(BX); } +static void instr32_93() { xchg32r(EBX); } +static void instr16_94() { xchg16r(SP); } +static void instr32_94() { xchg32r(ESP); } +static void instr16_95() { xchg16r(BP); } +static void instr32_95() { xchg32r(EBP); } +static void instr16_96() { xchg16r(SI); } +static void instr32_96() { xchg32r(ESI); } +static void instr16_97() { xchg16r(DI); } +static void instr32_97() { xchg32r(EDI); } + +static void instr16_98() { /* cbw */ reg16[AX] = reg8s[AL]; } +static void instr32_98() { /* cwde */ reg32s[EAX] = reg16s[AX]; } +static void instr16_99() { /* cwd */ reg16[DX] = reg16s[AX] >> 15; } +static void instr32_99() { /* cdq */ reg32s[EDX] = reg32s[EAX] >> 31; } + +static void instr16_9A() { + // callf + int32_t new_ip = read_op16(); + int32_t new_cs = read_disp16(); + + far_jump(new_ip, new_cs, true); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} +static void instr32_9A() { + int32_t new_ip = read_op32s(); + int32_t new_cs = read_disp16(); + + if(!*protected_mode || vm86_mode()) + { + if(new_ip & 0xFFFF0000) + { + assert(false); + //throw debug.unimpl("#GP handler"); + } + } + + far_jump(new_ip, new_cs, true); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} + +static void instr_9B() { + // fwait: check for pending fpu exceptions + if((cr[0] & (CR0_MP | CR0_TS)) == (CR0_MP | CR0_TS)) + { + // task switched and MP bit is set + trigger_nm(); + } + else + { + //if(fpu) + { + fwait(); + } + //else + //{ + // // EM bit isn't checked + // // If there's no FPU, do nothing + //} + } +} +static void instr16_9C() { + // pushf + if((flags[0] & FLAG_VM) && getiopl() < 3) + { + dbg_assert(*protected_mode); + dbg_log("pushf #gp"); + trigger_gp(0); + } + else + { + push16(get_eflags()); + } +} +static void instr32_9C() { + // pushf + if((flags[0] & FLAG_VM) && getiopl() < 3) + { + // trap to virtual 8086 monitor + dbg_assert(*protected_mode); + dbg_log("pushf #gp"); + trigger_gp(0); + } + else + { + // vm and rf flag are cleared in image stored on the stack + push32(get_eflags() & 0x00FCFFFF); + } +} +static void instr16_9D() { + // popf + if((flags[0] & FLAG_VM) && getiopl() < 3) + { + dbg_log("popf #gp"); + trigger_gp(0); + } + + update_eflags((flags[0] & ~0xFFFF) | pop16()); + + if(flags[0] & FLAG_TRAP) + { + // XXX: Problems with fdgame + //clear_prefixes(); + //cycle_internal(); + flags[0] &= ~FLAG_TRAP; + //instruction_pointer = previous_ip; + //raise_exception(1); + } + else + { + handle_irqs(); + } +} +static void instr32_9D() { + // popf + if((flags[0] & FLAG_VM) && getiopl() < 3) + { + dbg_log("popf #gp"); + trigger_gp(0); + } + + update_eflags(pop32s()); + handle_irqs(); +} +static void instr_9E() { + // sahf + flags[0] = (flags[0] & ~0xFF) | reg8[AH]; + flags[0] = (flags[0] & FLAGS_MASK) | FLAGS_DEFAULT; + flags_changed[0] = 0; +} +static void instr_9F() { + // lahf + reg8[AH] = get_eflags(); +} + +static void instr_A0() { + // mov + int32_t data = safe_read8(read_moffs()); + reg8[AL] = data; +} +static void instr16_A1() { + // mov + int32_t data = safe_read16(read_moffs()); + reg16[AX] = data; +} +static void instr32_A1() { + int32_t data = safe_read32s(read_moffs()); + reg32s[EAX] = data; +} +static void instr_A2() { + // mov + safe_write8(read_moffs(), reg8[AL]); +} +static void instr16_A3() { + // mov + safe_write16(read_moffs(), reg16[AX]); +} +static void instr32_A3() { + safe_write32(read_moffs(), reg32s[EAX]); +} + +static void instr_A4() { movsb(); } +static void instr16_A5() { movsw(); } +static void instr32_A5() { movsd(); } +static void instr_A6() { cmpsb(); } +static void instr16_A7() { cmpsw(); } +static void instr32_A7() { cmpsd(); } + +static void instr_A8() { + test8(reg8[AL], read_op8()); +} +static void instr16_A9() { + test16(reg16[AX], read_op16()); +} +static void instr32_A9() { + test32(reg32s[EAX], read_op32s()); +} + +static void instr_AA() { stosb(); } +static void instr16_AB() { stosw(); } +static void instr32_AB() { stosd(); } +static void instr_AC() { lodsb(); } +static void instr16_AD() { lodsw(); } +static void instr32_AD() { lodsd(); } +static void instr_AE() { scasb(); } +static void instr16_AF() { scasw(); } +static void instr32_AF() { scasd(); } + + +static void instr_B0() { reg8[AL] = read_op8(); } +static void instr_B1() { reg8[CL] = read_op8(); } +static void instr_B2() { reg8[DL] = read_op8(); } +static void instr_B3() { reg8[BL] = read_op8(); } +static void instr_B4() { reg8[AH] = read_op8(); } +static void instr_B5() { reg8[CH] = read_op8(); } +static void instr_B6() { reg8[DH] = read_op8(); } +static void instr_B7() { reg8[BH] = read_op8(); } + +static void instr16_B8() { reg16[AX] = read_op16(); } +static void instr32_B8() { reg32s[EAX] = read_op32s(); } +static void instr16_B9() { reg16[CX] = read_op16(); } +static void instr32_B9() { reg32s[ECX] = read_op32s(); } +static void instr16_BA() { reg16[DX] = read_op16(); } +static void instr32_BA() { reg32s[EDX] = read_op32s(); } +static void instr16_BB() { reg16[BX] = read_op16(); } +static void instr32_BB() { reg32s[EBX] = read_op32s(); } +static void instr16_BC() { reg16[SP] = read_op16(); } +static void instr32_BC() { reg32s[ESP] = read_op32s(); } +static void instr16_BD() { reg16[BP] = read_op16(); } +static void instr32_BD() { reg32s[EBP] = read_op32s(); } +static void instr16_BE() { reg16[SI] = read_op16(); } +static void instr32_BE() { reg32s[ESI] = read_op32s(); } +static void instr16_BF() { reg16[DI] = read_op16(); } +static void instr32_BF() { reg32s[EDI] = read_op32s(); } + + +static void instr_C0() { read_modrm_byte(); + int32_t op1 = read_write_e8(); + int32_t op2 = read_op8() & 31; + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol8(op1, op2); break; + case 1: result = ror8(op1, op2); break; + case 2: result = rcl8(op1, op2); break; + case 3: result = rcr8(op1, op2); break; + case 4: result = shl8(op1, op2); break; + case 5: result = shr8(op1, op2); break; + case 6: result = shl8(op1, op2); break; + case 7: result = sar8(op1, op2); break; + } + write_e8(result); +} +static void instr16_C1() { read_modrm_byte(); + int32_t op1 = read_write_e16(); + int32_t op2 = read_op8() & 31; + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol16(op1, op2); break; + case 1: result = ror16(op1, op2); break; + case 2: result = rcl16(op1, op2); break; + case 3: result = rcr16(op1, op2); break; + case 4: result = shl16(op1, op2); break; + case 5: result = shr16(op1, op2); break; + case 6: result = shl16(op1, op2); break; + case 7: result = sar16(op1, op2); break; + } + write_e16(result); +} +static void instr32_C1() { read_modrm_byte(); + int32_t op1 = read_write_e32(); + int32_t op2 = read_op8() & 31; + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol32(op1, op2); break; + case 1: result = ror32(op1, op2); break; + case 2: result = rcl32(op1, op2); break; + case 3: result = rcr32(op1, op2); break; + case 4: result = shl32(op1, op2); break; + case 5: result = shr32(op1, op2); break; + case 6: result = shl32(op1, op2); break; + case 7: result = sar32(op1, op2); break; + } + write_e32(result); +} + +static void instr16_C2() { + // retn + int32_t imm16 = read_op16(); + + instruction_pointer[0] = get_seg(CS) + pop16(); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + adjust_stack_reg(imm16); + diverged(); +} +static void instr32_C2() { + // retn + int32_t imm16 = read_op16(); + int32_t ip = pop32s(); + + dbg_assert(is_asize_32() || ip < 0x10000); + instruction_pointer[0] = get_seg(CS) + ip; + adjust_stack_reg(imm16); + diverged(); +} +static void instr16_C3() { + // retn + instruction_pointer[0] = get_seg(CS) + pop16(); + diverged(); +} +static void instr32_C3() { + // retn + int32_t ip = pop32s(); + dbg_assert(is_asize_32() || ip < 0x10000); + instruction_pointer[0] = get_seg(CS) + ip; + diverged(); +} + +static void instr16_C4() { read_modrm_byte(); + lss16(ES); +} +static void instr32_C4() { read_modrm_byte(); + lss32(ES); +} +static void instr16_C5() { read_modrm_byte(); + lss16(DS); +} +static void instr32_C5() { read_modrm_byte(); + lss32(DS); +} + +static void instr_C6() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + safe_write8(modrm_resolve(modrm_byte[0]), read_op8()); + } else { + reg8[modrm_byte[0] << 2 & 0xC | modrm_byte[0] >> 2 & 1] = read_op8(); + } +} +static void instr16_C7() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + safe_write16(modrm_resolve(modrm_byte[0]), read_op16()); + } else { + reg16[modrm_byte[0] << 1 & 14] = read_op16(); + } +} +static void instr32_C7() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + safe_write32(modrm_resolve(modrm_byte[0]), read_op32s()); + } else { + reg32s[modrm_byte[0] & 7] = read_op32s(); + } +} + +static void instr16_C8() { enter16(read_op16(), read_disp8()); } +static void instr32_C8() { enter32(read_op16(), read_disp8()); } +static void instr16_C9() { + // leave + int32_t old_vbp = *stack_size_32 ? reg32s[EBP] : reg16[BP]; + int32_t new_bp = safe_read16(get_seg(SS) + old_vbp); + set_stack_reg(old_vbp + 2); + reg16[BP] = new_bp; +} +static void instr32_C9() { + int32_t old_vbp = *stack_size_32 ? reg32s[EBP] : reg16[BP]; + int32_t new_ebp = safe_read32s(get_seg(SS) + old_vbp); + set_stack_reg(old_vbp + 4); + reg32s[EBP] = new_ebp; +} +static void instr16_CA() { + // retf + int32_t imm16 = read_op16(); + int32_t ip = safe_read16(get_stack_pointer(0)); + int32_t cs = safe_read16(get_stack_pointer(2)); + + far_return(ip, cs, imm16); + diverged(); +} +static void instr32_CA() { + // retf + int32_t imm16 = read_op16(); + int32_t ip = safe_read32s(get_stack_pointer(0)); + int32_t cs = safe_read32s(get_stack_pointer(4)) & 0xFFFF; + + far_return(ip, cs, imm16); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} +static void instr16_CB() { + // retf + int32_t ip = safe_read16(get_stack_pointer(0)); + int32_t cs = safe_read16(get_stack_pointer(2)); + + far_return(ip, cs, 0); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} +static void instr32_CB() { + // retf + int32_t ip = safe_read32s(get_stack_pointer(0)); + int32_t cs = safe_read32s(get_stack_pointer(4)) & 0xFFFF; + + far_return(ip, cs, 0); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} + +static void instr_CC() { + // INT3 + // TODO: inhibit iopl checks + dbg_log("INT3"); + call_interrupt_vector(3, true, false, 0); + diverged(); +} +static void instr_CD() { + // INT + int32_t imm8 = read_op8(); + call_interrupt_vector(imm8, true, false, 0); + diverged(); +} +static void instr_CE() { + // INTO + dbg_log("INTO"); + if(getof()) + { + // TODO: inhibit iopl checks + call_interrupt_vector(4, true, false, 0); + } + diverged(); +} + +static void instr16_CF() { + // iret + iret16(); + diverged(); +} +static void instr32_CF() { + iret32(); + diverged(); +} + +static void instr_D0() { read_modrm_byte(); + int32_t op1 = read_write_e8(); + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol8(op1, 1); break; + case 1: result = ror8(op1, 1); break; + case 2: result = rcl8(op1, 1); break; + case 3: result = rcr8(op1, 1); break; + case 4: result = shl8(op1, 1); break; + case 5: result = shr8(op1, 1); break; + case 6: result = shl8(op1, 1); break; + case 7: result = sar8(op1, 1); break; + } + write_e8(result); +} +static void instr16_D1() { read_modrm_byte(); + int32_t op1 = read_write_e16(); + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol16(op1, 1); break; + case 1: result = ror16(op1, 1); break; + case 2: result = rcl16(op1, 1); break; + case 3: result = rcr16(op1, 1); break; + case 4: result = shl16(op1, 1); break; + case 5: result = shr16(op1, 1); break; + case 6: result = shl16(op1, 1); break; + case 7: result = sar16(op1, 1); break; + } + write_e16(result); +} +static void instr32_D1() { read_modrm_byte(); + int32_t op1 = read_write_e32(); + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol32(op1, 1); break; + case 1: result = ror32(op1, 1); break; + case 2: result = rcl32(op1, 1); break; + case 3: result = rcr32(op1, 1); break; + case 4: result = shl32(op1, 1); break; + case 5: result = shr32(op1, 1); break; + case 6: result = shl32(op1, 1); break; + case 7: result = sar32(op1, 1); break; + } + write_e32(result); +} + +static void instr_D2() { read_modrm_byte(); + int32_t op1 = read_write_e8(); + int32_t op2 = reg8[CL] & 31; + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol8(op1, op2); break; + case 1: result = ror8(op1, op2); break; + case 2: result = rcl8(op1, op2); break; + case 3: result = rcr8(op1, op2); break; + case 4: result = shl8(op1, op2); break; + case 5: result = shr8(op1, op2); break; + case 6: result = shl8(op1, op2); break; + case 7: result = sar8(op1, op2); break; + } + write_e8(result); +} +static void instr16_D3() { read_modrm_byte(); + int32_t op1 = read_write_e16(); + int32_t op2 = reg8[CL] & 31; + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol16(op1, op2); break; + case 1: result = ror16(op1, op2); break; + case 2: result = rcl16(op1, op2); break; + case 3: result = rcr16(op1, op2); break; + case 4: result = shl16(op1, op2); break; + case 5: result = shr16(op1, op2); break; + case 6: result = shl16(op1, op2); break; + case 7: result = sar16(op1, op2); break; + } + write_e16(result); +} +static void instr32_D3() { read_modrm_byte(); + int32_t op1 = read_write_e32(); + int32_t op2 = reg8[CL] & 31; + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol32(op1, op2); break; + case 1: result = ror32(op1, op2); break; + case 2: result = rcl32(op1, op2); break; + case 3: result = rcr32(op1, op2); break; + case 4: result = shl32(op1, op2); break; + case 5: result = shr32(op1, op2); break; + case 6: result = shl32(op1, op2); break; + case 7: result = sar32(op1, op2); break; + } + write_e32(result); +} + +static void instr_D4() { + bcd_aam(read_op8()); +} +static void instr_D5() { + bcd_aad(read_op8()); +} + +static void instr_D6() { + // salc + reg8[AL] = -getcf(); +} +static void instr_D7() { + // xlat + if(is_asize_32()) + { + reg8[AL] = safe_read8(get_seg_prefix(DS) + reg32s[EBX] + reg8[AL]); + } + else + { + reg8[AL] = safe_read8(get_seg_prefix(DS) + (reg16[BX] + reg8[AL] & 0xFFFF)); + } +} + +static void instr_D8() { read_modrm_byte(); + task_switch_test(); + if(modrm_byte[0] < 0xC0) + fpu_op_D8_mem(modrm_byte[0], modrm_resolve(modrm_byte[0])); + else + fpu_op_D8_reg(modrm_byte[0]); +} +static void instr_D9() { read_modrm_byte(); + task_switch_test(); + if(modrm_byte[0] < 0xC0) + fpu_op_D9_mem(modrm_byte[0], modrm_resolve(modrm_byte[0])); + else + fpu_op_D9_reg(modrm_byte[0]); +} +static void instr_DA() { read_modrm_byte(); + task_switch_test(); + if(modrm_byte[0] < 0xC0) + fpu_op_DA_mem(modrm_byte[0], modrm_resolve(modrm_byte[0])); + else + fpu_op_DA_reg(modrm_byte[0]); +} +static void instr_DB() { read_modrm_byte(); + task_switch_test(); + if(modrm_byte[0] < 0xC0) + fpu_op_DB_mem(modrm_byte[0], modrm_resolve(modrm_byte[0])); + else + fpu_op_DB_reg(modrm_byte[0]); +} +static void instr_DC() { read_modrm_byte(); + task_switch_test(); + if(modrm_byte[0] < 0xC0) + fpu_op_DC_mem(modrm_byte[0], modrm_resolve(modrm_byte[0])); + else + fpu_op_DC_reg(modrm_byte[0]); +} +static void instr_DD() { read_modrm_byte(); + task_switch_test(); + if(modrm_byte[0] < 0xC0) + fpu_op_DD_mem(modrm_byte[0], modrm_resolve(modrm_byte[0])); + else + fpu_op_DD_reg(modrm_byte[0]); +} +static void instr_DE() { read_modrm_byte(); + task_switch_test(); + if(modrm_byte[0] < 0xC0) + fpu_op_DE_mem(modrm_byte[0], modrm_resolve(modrm_byte[0])); + else + fpu_op_DE_reg(modrm_byte[0]); +} +static void instr_DF() { read_modrm_byte(); + task_switch_test(); + if(modrm_byte[0] < 0xC0) + fpu_op_DF_mem(modrm_byte[0], modrm_resolve(modrm_byte[0])); + else + fpu_op_DF_reg(modrm_byte[0]); +} + +static void instr_E0() { loopne(read_op8s()); } +static void instr_E1() { loope(read_op8s()); } +static void instr_E2() { loop(read_op8s()); } +static void instr_E3() { jcxz(read_op8s()); } + +static void instr_E4() { + int32_t port = read_op8(); + test_privileges_for_io(port, 1); + reg8[AL] = io_port_read8(port); + diverged(); +} +static void instr16_E5() { + int32_t port = read_op8(); + test_privileges_for_io(port, 2); + reg16[AX] = io_port_read16(port); + diverged(); +} +static void instr32_E5() { + int32_t port = read_op8(); + test_privileges_for_io(port, 4); + reg32s[EAX] = io_port_read32(port); + diverged(); +} +static void instr_E6() { + int32_t port = read_op8(); + test_privileges_for_io(port, 1); + io_port_write8(port, reg8[AL]); + diverged(); +} +static void instr16_E7() { + int32_t port = read_op8(); + test_privileges_for_io(port, 2); + io_port_write16(port, reg16[AX]); + diverged(); +} +static void instr32_E7() { + int32_t port = read_op8(); + test_privileges_for_io(port, 4); + io_port_write32(port, reg32s[EAX]); + diverged(); +} + +static void instr16_E8() { + // call + int32_t imm16 = read_op16(); + push16(get_real_eip()); + + jmp_rel16(imm16); + diverged(); +} +static void instr32_E8() { + // call + int32_t imm32s = read_op32s(); + push32(get_real_eip()); + + instruction_pointer[0] = instruction_pointer[0] + imm32s; + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} +static void instr16_E9() { + // jmp + int32_t imm16 = read_op16(); + jmp_rel16(imm16); + diverged(); +} +static void instr32_E9() { + // jmp + int32_t imm32s = read_op32s(); + instruction_pointer[0] = instruction_pointer[0] + imm32s; + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} +static void instr16_EA() { + // jmpf + int32_t ip = read_op16(); + int32_t cs = read_disp16(); + far_jump(ip, cs, false); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} +static void instr32_EA() { + // jmpf + int32_t new_ip = read_op32s(); + int32_t cs = read_disp16(); + far_jump(new_ip, cs, false); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} +static void instr_EB() { + // jmp near + int32_t imm8 = read_op8s(); + instruction_pointer[0] = instruction_pointer[0] + imm8; + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} + +static void instr_EC() { + int32_t port = reg16[DX]; + test_privileges_for_io(port, 1); + reg8[AL] = io_port_read8(port); + diverged(); +} +static void instr16_ED() { + int32_t port = reg16[DX]; + test_privileges_for_io(port, 2); + reg16[AX] = io_port_read16(port); + diverged(); +} +static void instr32_ED() { + int32_t port = reg16[DX]; + test_privileges_for_io(port, 4); + reg32s[EAX] = io_port_read32(port); + diverged(); +} +static void instr_EE() { + int32_t port = reg16[DX]; + test_privileges_for_io(port, 1); + io_port_write8(port, reg8[AL]); + diverged(); +} +static void instr16_EF() { + int32_t port = reg16[DX]; + test_privileges_for_io(port, 2); + io_port_write16(port, reg16[AX]); + diverged(); +} +static void instr32_EF() { + int32_t port = reg16[DX]; + test_privileges_for_io(port, 4); + io_port_write32(port, reg32s[EAX]); + diverged(); +} + +static void instr_F0() { + // lock + //dbg_log("lock"); + + // TODO + // This triggers UD when used with + // some instructions that don't write to memory + run_prefix_instruction(); +} +static void instr_F1() { + // INT1 + // https://code.google.com/p/corkami/wiki/x86oddities#IceBP + //throw debug.unimpl("int1 instruction"); + assert(false); +} + +static void instr_F2() { + // repnz + dbg_assert((*prefixes & PREFIX_MASK_REP) == 0); + *prefixes |= PREFIX_REPNZ; + run_prefix_instruction(); + *prefixes = 0; +} +static void instr_F3() { + // repz + dbg_assert((*prefixes & PREFIX_MASK_REP) == 0); + *prefixes |= PREFIX_REPZ; + run_prefix_instruction(); + *prefixes = 0; +} + +static void instr_F4() { + hlt_op(); +} + +static void instr_F5() { + // cmc + flags[0] = (flags[0] | 1) ^ getcf(); + flags_changed[0] &= ~1; +} + +static void instr_F6() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: + test8(read_e8(), read_op8()); + break; + case 1: + test8(read_e8(), read_op8()); + break; + case 2: + write_e8(~(read_write_e8())); + break; + case 3: + write_e8(neg8(read_write_e8())); + break; + case 4: + mul8(read_e8()); + break; + case 5: + imul8(read_e8s()); + break; + case 6: + div8(read_e8()); + break; + case 7: + idiv8(read_e8s()); + break; + } +} + +static void instr16_F7() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: + test16(read_e16(), read_op16()); + break; + case 1: + test16(read_e16(), read_op16()); + break; + case 2: + write_e16(~(read_write_e16())); + break; + case 3: + write_e16(neg16(read_write_e16())); + break; + case 4: + mul16(read_e16()); + break; + case 5: + imul16(read_e16s()); + break; + case 6: + div16(read_e16()); + break; + case 7: + idiv16(read_e16s()); + break; + } +} +static void instr32_F7() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: + test32(read_e32s(), read_op32s()); + break; + case 1: + test32(read_e32s(), read_op32s()); + break; + case 2: + write_e32(~(read_write_e32())); + break; + case 3: + write_e32(neg32(read_write_e32())); + break; + case 4: + mul32(read_e32s()); + break; + case 5: + imul32(read_e32s()); + break; + case 6: + div32(read_e32s()); + break; + case 7: + idiv32(read_e32s()); + break; + } +} + +static void instr_F8() { + // clc + flags[0] &= ~FLAG_CARRY; + flags_changed[0] &= ~1; +} +static void instr_F9() { + // stc + flags[0] |= FLAG_CARRY; + flags_changed[0] &= ~1; +} + +static void instr_FA() { + // cli + //dbg_log("interrupts off"); + + if(!*protected_mode || ((flags[0] & FLAG_VM) ? + getiopl() == 3 : getiopl() >= *cpl)) + { + flags[0] &= ~FLAG_INTERRUPT; + } + else + { + //if(getiopl() < 3 && ((flags & FLAG_VM) ? + // (cr[4] & CR4_VME) : + // (*cpl == 3 && (cr[4] & CR4_PVI)))) + //{ + // flags &= ~flag_vif; + //} + //else + { + dbg_log("cli #gp"); + trigger_gp(0); + } + } +} +static void instr_FB() { + // sti + //dbg_log("interrupts on"); + + if(!*protected_mode || ((flags[0] & FLAG_VM) ? + getiopl() == 3 : getiopl() >= *cpl)) + { + flags[0] |= FLAG_INTERRUPT; + + clear_prefixes(); + cycle_internal(); + + handle_irqs(); + } + else + { + //if(getiopl() < 3 && (flags & flag_vip) == 0 && ((flags & FLAG_VM) ? + // (cr[4] & CR4_VME) : + // (cpl == 3 && (cr[4] & CR4_PVI)))) + //{ + // flags |= flag_vif; + //} + //else + { + dbg_log("sti #gp"); + trigger_gp(0); + } + } + +} + +static void instr_FC() { + // cld + flags[0] &= ~FLAG_DIRECTION; +} +static void instr_FD() { + // std + flags[0] |= FLAG_DIRECTION; +} + +static void instr_FE() { read_modrm_byte(); + int32_t mod = modrm_byte[0] & 56; + + if(mod == 0) + { + int32_t data = read_write_e8(); write_e8(inc8(data)); + } + else if(mod == 8) + { + int32_t data = read_write_e8(); write_e8(dec8(data)); + } + else + { + assert(false); + } +} +static void instr16_FF() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: + write_e16(inc16(read_write_e16())); + break; + case 1: + write_e16(dec16(read_write_e16())); + break; + case 2: + // 2, call near + { + int32_t data = read_e16(); + push16(get_real_eip()); + instruction_pointer[0] = get_seg(CS) + data; + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); + } + break; + case 3: + // 3, callf + { + if(modrm_byte[0] >= 0xC0) + { + dbg_log("callf #ud"); + trigger_ud(); + dbg_assert_message(false, "unreachable"); + } + + int32_t virt_addr = modrm_resolve(modrm_byte[0]); + int32_t new_ip = safe_read16(virt_addr); + int32_t new_cs = safe_read16(virt_addr + 2); + + far_jump(new_ip, new_cs, true); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); + } + break; + case 4: + // 4, jmp near + { + int32_t data = read_e16(); + instruction_pointer[0] = get_seg(CS) + data; + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); + } + break; + case 5: + // 5, jmpf + { + if(modrm_byte[0] >= 0xC0) + { + dbg_log("jmpf #ud"); + trigger_ud(); + dbg_assert_message(false, "unreachable"); + } + + int32_t virt_addr = modrm_resolve(modrm_byte[0]); + int32_t new_ip = safe_read16(virt_addr); + int32_t new_cs = safe_read16(virt_addr + 2); + + far_jump(new_ip, new_cs, false); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); + } + break; + case 6: + // 6, push + push16(read_e16()); + break; + case 7: + assert(false); + } +} +static void instr32_FF() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: + write_e32(inc32(read_write_e32())); + break; + case 1: + write_e32(dec32(read_write_e32())); + break; + case 2: + // 2, call near + { + int32_t data = read_e32s(); + push32(get_real_eip()); + + dbg_assert(is_asize_32() || data < 0x10000); + instruction_pointer[0] = get_seg(CS) + data; + diverged(); + } + break; + case 3: + // 3, callf + { + if(modrm_byte[0] >= 0xC0) + { + dbg_log("callf #ud"); + trigger_ud(); + dbg_assert_message(false, "unreachable"); + } + + int32_t virt_addr = modrm_resolve(modrm_byte[0]); + int32_t new_ip = safe_read32s(virt_addr); + int32_t new_cs = safe_read16(virt_addr + 4); + + if(!*protected_mode || vm86_mode()) + { + if(new_ip & 0xFFFF0000) + { + //throw debug.unimpl("#GP handler"); + assert(false); + } + } + + far_jump(new_ip, new_cs, true); + dbg_assert(is_asize_32() || new_ip < 0x10000); + diverged(); + } + break; + case 4: + // 4, jmp near + { + int32_t data = read_e32s(); + dbg_assert(is_asize_32() || data < 0x10000); + instruction_pointer[0] = get_seg(CS) + data; + diverged(); + } + break; + case 5: + // 5, jmpf + { + if(modrm_byte[0] >= 0xC0) + { + dbg_log("jmpf #ud"); + trigger_ud(); + dbg_assert_message(false, "unreachable"); + } + + int32_t virt_addr = modrm_resolve(modrm_byte[0]); + int32_t new_ip = safe_read32s(virt_addr); + int32_t new_cs = safe_read16(virt_addr + 4); + + if(!*protected_mode || vm86_mode()) + { + if(new_ip & 0xFFFF0000) + { + //throw debug.unimpl("#GP handler"); + assert(false); + } + } + + far_jump(new_ip, new_cs, false); + dbg_assert(is_asize_32() || new_ip < 0x10000); + diverged(); + } + break; + case 6: + // push + push32(read_e32s()); + break; + case 7: + assert(false); + } +} + +static void run_instruction(int32_t opcode) +{ + //dbg_log(opcode); + // XXX: This table is generated. Don't modify + switch(opcode | is_osize_32() << 8) + { +case 0x00: +case 0x00|0x100: + instr_00(); + break; +case 0x01: + instr16_01(); + break; +case 0x01|0x100: + instr32_01(); + break; +case 0x02: +case 0x02|0x100: + instr_02(); + break; +case 0x03: + instr16_03(); + break; +case 0x03|0x100: + instr32_03(); + break; +case 0x04: +case 0x04|0x100: + instr_04(); + break; +case 0x05: + instr16_05(); + break; +case 0x05|0x100: + instr32_05(); + break; +case 0x06: + instr16_06(); + break; +case 0x06|0x100: + instr32_06(); + break; +case 0x07: + instr16_07(); + break; +case 0x07|0x100: + instr32_07(); + break; +case 0x08: +case 0x08|0x100: + instr_08(); + break; +case 0x09: + instr16_09(); + break; +case 0x09|0x100: + instr32_09(); + break; +case 0x0A: +case 0x0A|0x100: + instr_0A(); + break; +case 0x0B: + instr16_0B(); + break; +case 0x0B|0x100: + instr32_0B(); + break; +case 0x0C: +case 0x0C|0x100: + instr_0C(); + break; +case 0x0D: + instr16_0D(); + break; +case 0x0D|0x100: + instr32_0D(); + break; +case 0x0E: + instr16_0E(); + break; +case 0x0E|0x100: + instr32_0E(); + break; +case 0x0F: + instr16_0F(); + break; +case 0x0F|0x100: + instr32_0F(); + break; +case 0x10: +case 0x10|0x100: + instr_10(); + break; +case 0x11: + instr16_11(); + break; +case 0x11|0x100: + instr32_11(); + break; +case 0x12: +case 0x12|0x100: + instr_12(); + break; +case 0x13: + instr16_13(); + break; +case 0x13|0x100: + instr32_13(); + break; +case 0x14: +case 0x14|0x100: + instr_14(); + break; +case 0x15: + instr16_15(); + break; +case 0x15|0x100: + instr32_15(); + break; +case 0x16: + instr16_16(); + break; +case 0x16|0x100: + instr32_16(); + break; +case 0x17: + instr16_17(); + break; +case 0x17|0x100: + instr32_17(); + break; +case 0x18: +case 0x18|0x100: + instr_18(); + break; +case 0x19: + instr16_19(); + break; +case 0x19|0x100: + instr32_19(); + break; +case 0x1A: +case 0x1A|0x100: + instr_1A(); + break; +case 0x1B: + instr16_1B(); + break; +case 0x1B|0x100: + instr32_1B(); + break; +case 0x1C: +case 0x1C|0x100: + instr_1C(); + break; +case 0x1D: + instr16_1D(); + break; +case 0x1D|0x100: + instr32_1D(); + break; +case 0x1E: + instr16_1E(); + break; +case 0x1E|0x100: + instr32_1E(); + break; +case 0x1F: + instr16_1F(); + break; +case 0x1F|0x100: + instr32_1F(); + break; +case 0x20: +case 0x20|0x100: + instr_20(); + break; +case 0x21: + instr16_21(); + break; +case 0x21|0x100: + instr32_21(); + break; +case 0x22: +case 0x22|0x100: + instr_22(); + break; +case 0x23: + instr16_23(); + break; +case 0x23|0x100: + instr32_23(); + break; +case 0x24: +case 0x24|0x100: + instr_24(); + break; +case 0x25: + instr16_25(); + break; +case 0x25|0x100: + instr32_25(); + break; +case 0x26: +case 0x26|0x100: + instr_26(); + break; +case 0x27: +case 0x27|0x100: + instr_27(); + break; +case 0x28: +case 0x28|0x100: + instr_28(); + break; +case 0x29: + instr16_29(); + break; +case 0x29|0x100: + instr32_29(); + break; +case 0x2A: +case 0x2A|0x100: + instr_2A(); + break; +case 0x2B: + instr16_2B(); + break; +case 0x2B|0x100: + instr32_2B(); + break; +case 0x2C: +case 0x2C|0x100: + instr_2C(); + break; +case 0x2D: + instr16_2D(); + break; +case 0x2D|0x100: + instr32_2D(); + break; +case 0x2E: +case 0x2E|0x100: + instr_2E(); + break; +case 0x2F: +case 0x2F|0x100: + instr_2F(); + break; +case 0x30: +case 0x30|0x100: + instr_30(); + break; +case 0x31: + instr16_31(); + break; +case 0x31|0x100: + instr32_31(); + break; +case 0x32: +case 0x32|0x100: + instr_32(); + break; +case 0x33: + instr16_33(); + break; +case 0x33|0x100: + instr32_33(); + break; +case 0x34: +case 0x34|0x100: + instr_34(); + break; +case 0x35: + instr16_35(); + break; +case 0x35|0x100: + instr32_35(); + break; +case 0x36: +case 0x36|0x100: + instr_36(); + break; +case 0x37: +case 0x37|0x100: + instr_37(); + break; +case 0x38: +case 0x38|0x100: + instr_38(); + break; +case 0x39: + instr16_39(); + break; +case 0x39|0x100: + instr32_39(); + break; +case 0x3A: +case 0x3A|0x100: + instr_3A(); + break; +case 0x3B: + instr16_3B(); + break; +case 0x3B|0x100: + instr32_3B(); + break; +case 0x3C: +case 0x3C|0x100: + instr_3C(); + break; +case 0x3D: + instr16_3D(); + break; +case 0x3D|0x100: + instr32_3D(); + break; +case 0x3E: +case 0x3E|0x100: + instr_3E(); + break; +case 0x3F: +case 0x3F|0x100: + instr_3F(); + break; +case 0x40: + instr16_40(); + break; +case 0x40|0x100: + instr32_40(); + break; +case 0x41: + instr16_41(); + break; +case 0x41|0x100: + instr32_41(); + break; +case 0x42: + instr16_42(); + break; +case 0x42|0x100: + instr32_42(); + break; +case 0x43: + instr16_43(); + break; +case 0x43|0x100: + instr32_43(); + break; +case 0x44: + instr16_44(); + break; +case 0x44|0x100: + instr32_44(); + break; +case 0x45: + instr16_45(); + break; +case 0x45|0x100: + instr32_45(); + break; +case 0x46: + instr16_46(); + break; +case 0x46|0x100: + instr32_46(); + break; +case 0x47: + instr16_47(); + break; +case 0x47|0x100: + instr32_47(); + break; +case 0x48: + instr16_48(); + break; +case 0x48|0x100: + instr32_48(); + break; +case 0x49: + instr16_49(); + break; +case 0x49|0x100: + instr32_49(); + break; +case 0x4A: + instr16_4A(); + break; +case 0x4A|0x100: + instr32_4A(); + break; +case 0x4B: + instr16_4B(); + break; +case 0x4B|0x100: + instr32_4B(); + break; +case 0x4C: + instr16_4C(); + break; +case 0x4C|0x100: + instr32_4C(); + break; +case 0x4D: + instr16_4D(); + break; +case 0x4D|0x100: + instr32_4D(); + break; +case 0x4E: + instr16_4E(); + break; +case 0x4E|0x100: + instr32_4E(); + break; +case 0x4F: + instr16_4F(); + break; +case 0x4F|0x100: + instr32_4F(); + break; +case 0x50: + instr16_50(); + break; +case 0x50|0x100: + instr32_50(); + break; +case 0x51: + instr16_51(); + break; +case 0x51|0x100: + instr32_51(); + break; +case 0x52: + instr16_52(); + break; +case 0x52|0x100: + instr32_52(); + break; +case 0x53: + instr16_53(); + break; +case 0x53|0x100: + instr32_53(); + break; +case 0x54: + instr16_54(); + break; +case 0x54|0x100: + instr32_54(); + break; +case 0x55: + instr16_55(); + break; +case 0x55|0x100: + instr32_55(); + break; +case 0x56: + instr16_56(); + break; +case 0x56|0x100: + instr32_56(); + break; +case 0x57: + instr16_57(); + break; +case 0x57|0x100: + instr32_57(); + break; +case 0x58: + instr16_58(); + break; +case 0x58|0x100: + instr32_58(); + break; +case 0x59: + instr16_59(); + break; +case 0x59|0x100: + instr32_59(); + break; +case 0x5A: + instr16_5A(); + break; +case 0x5A|0x100: + instr32_5A(); + break; +case 0x5B: + instr16_5B(); + break; +case 0x5B|0x100: + instr32_5B(); + break; +case 0x5C: + instr16_5C(); + break; +case 0x5C|0x100: + instr32_5C(); + break; +case 0x5D: + instr16_5D(); + break; +case 0x5D|0x100: + instr32_5D(); + break; +case 0x5E: + instr16_5E(); + break; +case 0x5E|0x100: + instr32_5E(); + break; +case 0x5F: + instr16_5F(); + break; +case 0x5F|0x100: + instr32_5F(); + break; +case 0x60: + instr16_60(); + break; +case 0x60|0x100: + instr32_60(); + break; +case 0x61: + instr16_61(); + break; +case 0x61|0x100: + instr32_61(); + break; +case 0x62: +case 0x62|0x100: + instr_62(); + break; +case 0x63: +case 0x63|0x100: + instr_63(); + break; +case 0x64: +case 0x64|0x100: + instr_64(); + break; +case 0x65: +case 0x65|0x100: + instr_65(); + break; +case 0x66: +case 0x66|0x100: + instr_66(); + break; +case 0x67: +case 0x67|0x100: + instr_67(); + break; +case 0x68: + instr16_68(); + break; +case 0x68|0x100: + instr32_68(); + break; +case 0x69: + instr16_69(); + break; +case 0x69|0x100: + instr32_69(); + break; +case 0x6A: + instr16_6A(); + break; +case 0x6A|0x100: + instr32_6A(); + break; +case 0x6B: + instr16_6B(); + break; +case 0x6B|0x100: + instr32_6B(); + break; +case 0x6C: +case 0x6C|0x100: + instr_6C(); + break; +case 0x6D: + instr16_6D(); + break; +case 0x6D|0x100: + instr32_6D(); + break; +case 0x6E: +case 0x6E|0x100: + instr_6E(); + break; +case 0x6F: + instr16_6F(); + break; +case 0x6F|0x100: + instr32_6F(); + break; +case 0x70: +case 0x70|0x100: + instr_70(); + break; +case 0x71: +case 0x71|0x100: + instr_71(); + break; +case 0x72: +case 0x72|0x100: + instr_72(); + break; +case 0x73: +case 0x73|0x100: + instr_73(); + break; +case 0x74: +case 0x74|0x100: + instr_74(); + break; +case 0x75: +case 0x75|0x100: + instr_75(); + break; +case 0x76: +case 0x76|0x100: + instr_76(); + break; +case 0x77: +case 0x77|0x100: + instr_77(); + break; +case 0x78: +case 0x78|0x100: + instr_78(); + break; +case 0x79: +case 0x79|0x100: + instr_79(); + break; +case 0x7A: +case 0x7A|0x100: + instr_7A(); + break; +case 0x7B: +case 0x7B|0x100: + instr_7B(); + break; +case 0x7C: +case 0x7C|0x100: + instr_7C(); + break; +case 0x7D: +case 0x7D|0x100: + instr_7D(); + break; +case 0x7E: +case 0x7E|0x100: + instr_7E(); + break; +case 0x7F: +case 0x7F|0x100: + instr_7F(); + break; +case 0x80: +case 0x80|0x100: + instr_80(); + break; +case 0x81: + instr16_81(); + break; +case 0x81|0x100: + instr32_81(); + break; +case 0x82: +case 0x82|0x100: + instr_82(); + break; +case 0x83: + instr16_83(); + break; +case 0x83|0x100: + instr32_83(); + break; +case 0x84: +case 0x84|0x100: + instr_84(); + break; +case 0x85: + instr16_85(); + break; +case 0x85|0x100: + instr32_85(); + break; +case 0x86: +case 0x86|0x100: + instr_86(); + break; +case 0x87: + instr16_87(); + break; +case 0x87|0x100: + instr32_87(); + break; +case 0x88: +case 0x88|0x100: + instr_88(); + break; +case 0x89: + instr16_89(); + break; +case 0x89|0x100: + instr32_89(); + break; +case 0x8A: +case 0x8A|0x100: + instr_8A(); + break; +case 0x8B: + instr16_8B(); + break; +case 0x8B|0x100: + instr32_8B(); + break; +case 0x8C: + instr16_8C(); + break; +case 0x8C|0x100: + instr32_8C(); + break; +case 0x8D: + instr16_8D(); + break; +case 0x8D|0x100: + instr32_8D(); + break; +case 0x8E: +case 0x8E|0x100: + instr_8E(); + break; +case 0x8F: + instr16_8F(); + break; +case 0x8F|0x100: + instr32_8F(); + break; +case 0x90: +case 0x90|0x100: + instr_90(); + break; +case 0x91: + instr16_91(); + break; +case 0x91|0x100: + instr32_91(); + break; +case 0x92: + instr16_92(); + break; +case 0x92|0x100: + instr32_92(); + break; +case 0x93: + instr16_93(); + break; +case 0x93|0x100: + instr32_93(); + break; +case 0x94: + instr16_94(); + break; +case 0x94|0x100: + instr32_94(); + break; +case 0x95: + instr16_95(); + break; +case 0x95|0x100: + instr32_95(); + break; +case 0x96: + instr16_96(); + break; +case 0x96|0x100: + instr32_96(); + break; +case 0x97: + instr16_97(); + break; +case 0x97|0x100: + instr32_97(); + break; +case 0x98: + instr16_98(); + break; +case 0x98|0x100: + instr32_98(); + break; +case 0x99: + instr16_99(); + break; +case 0x99|0x100: + instr32_99(); + break; +case 0x9A: + instr16_9A(); + break; +case 0x9A|0x100: + instr32_9A(); + break; +case 0x9B: +case 0x9B|0x100: + instr_9B(); + break; +case 0x9C: + instr16_9C(); + break; +case 0x9C|0x100: + instr32_9C(); + break; +case 0x9D: + instr16_9D(); + break; +case 0x9D|0x100: + instr32_9D(); + break; +case 0x9E: +case 0x9E|0x100: + instr_9E(); + break; +case 0x9F: +case 0x9F|0x100: + instr_9F(); + break; +case 0xA0: +case 0xA0|0x100: + instr_A0(); + break; +case 0xA1: + instr16_A1(); + break; +case 0xA1|0x100: + instr32_A1(); + break; +case 0xA2: +case 0xA2|0x100: + instr_A2(); + break; +case 0xA3: + instr16_A3(); + break; +case 0xA3|0x100: + instr32_A3(); + break; +case 0xA4: +case 0xA4|0x100: + instr_A4(); + break; +case 0xA5: + instr16_A5(); + break; +case 0xA5|0x100: + instr32_A5(); + break; +case 0xA6: +case 0xA6|0x100: + instr_A6(); + break; +case 0xA7: + instr16_A7(); + break; +case 0xA7|0x100: + instr32_A7(); + break; +case 0xA8: +case 0xA8|0x100: + instr_A8(); + break; +case 0xA9: + instr16_A9(); + break; +case 0xA9|0x100: + instr32_A9(); + break; +case 0xAA: +case 0xAA|0x100: + instr_AA(); + break; +case 0xAB: + instr16_AB(); + break; +case 0xAB|0x100: + instr32_AB(); + break; +case 0xAC: +case 0xAC|0x100: + instr_AC(); + break; +case 0xAD: + instr16_AD(); + break; +case 0xAD|0x100: + instr32_AD(); + break; +case 0xAE: +case 0xAE|0x100: + instr_AE(); + break; +case 0xAF: + instr16_AF(); + break; +case 0xAF|0x100: + instr32_AF(); + break; +case 0xB0: +case 0xB0|0x100: + instr_B0(); + break; +case 0xB1: +case 0xB1|0x100: + instr_B1(); + break; +case 0xB2: +case 0xB2|0x100: + instr_B2(); + break; +case 0xB3: +case 0xB3|0x100: + instr_B3(); + break; +case 0xB4: +case 0xB4|0x100: + instr_B4(); + break; +case 0xB5: +case 0xB5|0x100: + instr_B5(); + break; +case 0xB6: +case 0xB6|0x100: + instr_B6(); + break; +case 0xB7: +case 0xB7|0x100: + instr_B7(); + break; +case 0xB8: + instr16_B8(); + break; +case 0xB8|0x100: + instr32_B8(); + break; +case 0xB9: + instr16_B9(); + break; +case 0xB9|0x100: + instr32_B9(); + break; +case 0xBA: + instr16_BA(); + break; +case 0xBA|0x100: + instr32_BA(); + break; +case 0xBB: + instr16_BB(); + break; +case 0xBB|0x100: + instr32_BB(); + break; +case 0xBC: + instr16_BC(); + break; +case 0xBC|0x100: + instr32_BC(); + break; +case 0xBD: + instr16_BD(); + break; +case 0xBD|0x100: + instr32_BD(); + break; +case 0xBE: + instr16_BE(); + break; +case 0xBE|0x100: + instr32_BE(); + break; +case 0xBF: + instr16_BF(); + break; +case 0xBF|0x100: + instr32_BF(); + break; +case 0xC0: +case 0xC0|0x100: + instr_C0(); + break; +case 0xC1: + instr16_C1(); + break; +case 0xC1|0x100: + instr32_C1(); + break; +case 0xC2: + instr16_C2(); + break; +case 0xC2|0x100: + instr32_C2(); + break; +case 0xC3: + instr16_C3(); + break; +case 0xC3|0x100: + instr32_C3(); + break; +case 0xC4: + instr16_C4(); + break; +case 0xC4|0x100: + instr32_C4(); + break; +case 0xC5: + instr16_C5(); + break; +case 0xC5|0x100: + instr32_C5(); + break; +case 0xC6: +case 0xC6|0x100: + instr_C6(); + break; +case 0xC7: + instr16_C7(); + break; +case 0xC7|0x100: + instr32_C7(); + break; +case 0xC8: + instr16_C8(); + break; +case 0xC8|0x100: + instr32_C8(); + break; +case 0xC9: + instr16_C9(); + break; +case 0xC9|0x100: + instr32_C9(); + break; +case 0xCA: + instr16_CA(); + break; +case 0xCA|0x100: + instr32_CA(); + break; +case 0xCB: + instr16_CB(); + break; +case 0xCB|0x100: + instr32_CB(); + break; +case 0xCC: +case 0xCC|0x100: + instr_CC(); + break; +case 0xCD: +case 0xCD|0x100: + instr_CD(); + break; +case 0xCE: +case 0xCE|0x100: + instr_CE(); + break; +case 0xCF: + instr16_CF(); + break; +case 0xCF|0x100: + instr32_CF(); + break; +case 0xD0: +case 0xD0|0x100: + instr_D0(); + break; +case 0xD1: + instr16_D1(); + break; +case 0xD1|0x100: + instr32_D1(); + break; +case 0xD2: +case 0xD2|0x100: + instr_D2(); + break; +case 0xD3: + instr16_D3(); + break; +case 0xD3|0x100: + instr32_D3(); + break; +case 0xD4: +case 0xD4|0x100: + instr_D4(); + break; +case 0xD5: +case 0xD5|0x100: + instr_D5(); + break; +case 0xD6: +case 0xD6|0x100: + instr_D6(); + break; +case 0xD7: +case 0xD7|0x100: + instr_D7(); + break; +case 0xD8: +case 0xD8|0x100: + instr_D8(); + break; +case 0xD9: +case 0xD9|0x100: + instr_D9(); + break; +case 0xDA: +case 0xDA|0x100: + instr_DA(); + break; +case 0xDB: +case 0xDB|0x100: + instr_DB(); + break; +case 0xDC: +case 0xDC|0x100: + instr_DC(); + break; +case 0xDD: +case 0xDD|0x100: + instr_DD(); + break; +case 0xDE: +case 0xDE|0x100: + instr_DE(); + break; +case 0xDF: +case 0xDF|0x100: + instr_DF(); + break; +case 0xE0: +case 0xE0|0x100: + instr_E0(); + break; +case 0xE1: +case 0xE1|0x100: + instr_E1(); + break; +case 0xE2: +case 0xE2|0x100: + instr_E2(); + break; +case 0xE3: +case 0xE3|0x100: + instr_E3(); + break; +case 0xE4: +case 0xE4|0x100: + instr_E4(); + break; +case 0xE5: + instr16_E5(); + break; +case 0xE5|0x100: + instr32_E5(); + break; +case 0xE6: +case 0xE6|0x100: + instr_E6(); + break; +case 0xE7: + instr16_E7(); + break; +case 0xE7|0x100: + instr32_E7(); + break; +case 0xE8: + instr16_E8(); + break; +case 0xE8|0x100: + instr32_E8(); + break; +case 0xE9: + instr16_E9(); + break; +case 0xE9|0x100: + instr32_E9(); + break; +case 0xEA: + instr16_EA(); + break; +case 0xEA|0x100: + instr32_EA(); + break; +case 0xEB: +case 0xEB|0x100: + instr_EB(); + break; +case 0xEC: +case 0xEC|0x100: + instr_EC(); + break; +case 0xED: + instr16_ED(); + break; +case 0xED|0x100: + instr32_ED(); + break; +case 0xEE: +case 0xEE|0x100: + instr_EE(); + break; +case 0xEF: + instr16_EF(); + break; +case 0xEF|0x100: + instr32_EF(); + break; +case 0xF0: +case 0xF0|0x100: + instr_F0(); + break; +case 0xF1: +case 0xF1|0x100: + instr_F1(); + break; +case 0xF2: +case 0xF2|0x100: + instr_F2(); + break; +case 0xF3: +case 0xF3|0x100: + instr_F3(); + break; +case 0xF4: +case 0xF4|0x100: + instr_F4(); + break; +case 0xF5: +case 0xF5|0x100: + instr_F5(); + break; +case 0xF6: +case 0xF6|0x100: + instr_F6(); + break; +case 0xF7: + instr16_F7(); + break; +case 0xF7|0x100: + instr32_F7(); + break; +case 0xF8: +case 0xF8|0x100: + instr_F8(); + break; +case 0xF9: +case 0xF9|0x100: + instr_F9(); + break; +case 0xFA: +case 0xFA|0x100: + instr_FA(); + break; +case 0xFB: +case 0xFB|0x100: + instr_FB(); + break; +case 0xFC: +case 0xFC|0x100: + instr_FC(); + break; +case 0xFD: +case 0xFD|0x100: + instr_FD(); + break; +case 0xFE: +case 0xFE|0x100: + instr_FE(); + break; +case 0xFF: + instr16_FF(); + break; +case 0xFF|0x100: + instr32_FF(); + break; +default: + assert(false); + } +} diff --git a/src/native/instructions_0f.c b/src/native/instructions_0f.c new file mode 100644 index 00000000..ceb70a3a --- /dev/null +++ b/src/native/instructions_0f.c @@ -0,0 +1,3155 @@ +#include +#include +#include +#include + +#include "const.h" +#include "global_pointers.h" + +// XXX: Remove these declarations when they are implemented in C +void cmovcc16(bool); +void cmovcc32(bool); +void jmpcc16(bool); +void jmpcc32(bool); +void setcc(bool); +void cpuid(); + +int32_t bt_mem(int32_t, int32_t); +int32_t bt_reg(int32_t, int32_t); +int32_t bts_mem(int32_t, int32_t); +int32_t bts_reg(int32_t, int32_t); +int32_t btc_mem(int32_t, int32_t); +int32_t btc_reg(int32_t, int32_t); +int32_t btr_mem(int32_t, int32_t); +int32_t btr_reg(int32_t, int32_t); +int32_t bsf16(int32_t, int32_t); +int32_t bsf32(int32_t, int32_t); +int32_t bsr16(int32_t, int32_t); +int32_t bsr32(int32_t, int32_t); + +int32_t popcnt(int32_t); +int32_t bswap(int32_t); + +int32_t read_g16s(void); +int32_t read_reg_e16(void); +int32_t read_reg_e32s(void); + +void cpl_changed(void); +void update_cs_size(int32_t); +void unimplemented_sse(void); + +int32_t shld16(int32_t, int32_t, int32_t); +int32_t shld32(int32_t, int32_t, int32_t); +int32_t shrd16(int32_t, int32_t, int32_t); +int32_t shrd32(int32_t, int32_t, int32_t); + +bool has_rand_int(void); +int32_t get_rand_int(void); + +void todo(); +void undefined_instruction(); + +void clear_tlb(); +void full_clear_tlb(); + +int32_t microtick(); + +int32_t lsl(int32_t, int32_t); +int32_t lar(int32_t, int32_t); +int32_t verw(int32_t); +int32_t verr(int32_t); + +void invlpg(int32_t); +void load_tr(int32_t); +void load_ldt(int32_t); + +int32_t set_cr0(int32_t); +void writable_or_pagefault(int32_t, int32_t); + +bool* const apic_enabled; + + +static void instr_0F00() { read_modrm_byte(); + if(!protected_mode[0] || vm86_mode()) + { + // No GP, UD is correct here + dbg_log("0f 00 #ud"); + trigger_ud(); + } + + switch(modrm_byte[0] >> 3 & 7) + { + case 0: + // sldt + set_e16(sreg[LDTR]); + if(is_osize_32() && modrm_byte[0] >= 0xC0) + { + reg32s[modrm_byte[0] & 7] &= 0xFFFF; + } + break; + case 1: + // str + set_e16(sreg[LDTR]); + if(is_osize_32() && modrm_byte[0] >= 0xC0) + { + reg32s[modrm_byte[0] & 7] &= 0xFFFF; + } + break; + case 2: + // lldt + if(cpl[0]) + { + trigger_gp(0); + } + + { + int32_t data = read_e16(); + load_ldt(data); + } + break; + case 3: + // ltr + if(cpl[0]) + { + trigger_gp(0); + } + + int32_t data = read_e16(); + load_tr(data); + break; + case 4: + verr(read_e16()); + break; + case 5: + verw(read_e16()); + break; + + default: + dbg_log("%d", modrm_byte[0] >> 3 & 7); + todo(); + } +} + +static void instr_0F01() { read_modrm_byte(); + int32_t mod = modrm_byte[0] >> 3 & 7; + + if(mod == 4) + { + // smsw + if(modrm_byte[0] >= 0xC0 && is_osize_32()) + { + set_e32(cr[0]); + } + else + { + set_e16(cr[0]); + } + return; + } + else if(mod == 6) + { + // lmsw + if(cpl[0]) + { + trigger_gp(0); + } + + int32_t cr0 = read_e16(); + + cr0 = (cr[0] & ~0xF) | (cr0 & 0xF); + + if(protected_mode[0]) + { + // lmsw cannot be used to switch back + cr0 |= CR0_PE; + } + + set_cr0(cr0); + return; + } + + if(modrm_byte[0] >= 0xC0) + { + // only memory + dbg_log("0f 01 #ud"); + trigger_ud(); + } + + int32_t addr = modrm_resolve(modrm_byte[0]); + + switch(mod) + { + case 0: + // sgdt + writable_or_pagefault(addr, 6); + safe_write16(addr, gdtr_size[0]); + { + int32_t mask = is_osize_32() ? -1 : 0x00FFFFFF; + safe_write32(addr + 2, gdtr_offset[0] & mask); + } + break; + case 1: + // sidt + writable_or_pagefault(addr, 6); + safe_write16(addr, idtr_size[0]); + { + int32_t mask = is_osize_32() ? -1 : 0x00FFFFFF; + safe_write32(addr + 2, idtr_offset[0] & mask); + } + break; + case 2: + // lgdt + if(cpl[0]) + { + trigger_gp(0); + } + + { + int32_t size = safe_read16(addr); + int32_t offset = safe_read32s(addr + 2); + + gdtr_size[0] = size; + gdtr_offset[0] = offset; + + if(!is_osize_32()) + { + gdtr_offset[0] &= 0xFFFFFF; + } + + //dbg_log("gdt at " + h(gdtr_offset[0]) + ", " + gdtr_size[0] + " bytes"); + //debug.dump_state(); + //debug.dump_regs_short(); + //debug.dump_gdt_ldt(); + } + break; + case 3: + // lidt + if(cpl[0]) + { + trigger_gp(0); + } + + { + int32_t size = safe_read16(addr); + int32_t offset = safe_read32s(addr + 2); + + idtr_size[0] = size; + idtr_offset[0] = offset; + + if(!is_osize_32()) + { + idtr_offset[0] &= 0xFFFFFF; + } + + //dbg_log("[" + h(instruction_pointer) + "] idt at " + + // h(idtr_offset) + ", " + idtr_size[0] + " bytes " + h(addr)); + } + break; + case 7: + // flush translation lookaside buffer + if(cpl[0]) + { + trigger_gp(0); + } + + invlpg(addr); + break; + default: + dbg_log("%d", mod); + todo(); + } +} + +static void instr16_0F02() { read_modrm_byte(); + // lar + if(!protected_mode[0] || vm86_mode()) + { + dbg_log("lar #ud"); + trigger_ud(); + } + int32_t data = read_e16(); + write_g16(lar(data, read_g16())); +} +static void instr32_0F02() { read_modrm_byte(); + if(!protected_mode[0] || vm86_mode()) + { + dbg_log("lar #ud"); + trigger_ud(); + } + int32_t data = read_e16(); + write_g32(lar(data, read_g32s())); +} + +static void instr16_0F03() { read_modrm_byte(); + // lsl + if(!protected_mode[0] || vm86_mode()) + { + dbg_log("lsl #ud"); + trigger_ud(); + } + int32_t data = read_e16(); + write_g16(lsl(data, read_g16())); +} +static void instr32_0F03() { read_modrm_byte(); + if(!protected_mode[0] || vm86_mode()) + { + dbg_log("lsl #ud"); + trigger_ud(); + } + int32_t data = read_e16(); + write_g32(lsl(data, read_g32s())); +} + +static void instr_0F04() { undefined_instruction(); } +static void instr_0F05() { undefined_instruction(); } + +static void instr_0F06() { + // clts + if(cpl[0]) + { + dbg_log("clts #gp"); + trigger_gp(0); + } + else + { + //dbg_log("clts"); + cr[0] &= ~CR0_TS; + } +} + +static void instr_0F07() { undefined_instruction(); } +static void instr_0F08() { + // invd + todo(); +} + +static void instr_0F09() { + if(cpl[0]) + { + dbg_log("wbinvd #gp"); + trigger_gp(0); + } + // wbinvd +} + + +static void instr_0F0A() { undefined_instruction(); } +static void instr_0F0B() { + // UD2 + trigger_ud(); +} +static void instr_0F0C() { undefined_instruction(); } + +static void instr_0F0D() { + // nop + todo(); +} + +static void instr_0F0E() { undefined_instruction(); } +static void instr_0F0F() { undefined_instruction(); } + +static void instr_0F10() { unimplemented_sse(); } +static void instr_0F11() { unimplemented_sse(); } +static void instr_0F12() { unimplemented_sse(); } +static void instr_0F13() { unimplemented_sse(); } +static void instr_0F14() { unimplemented_sse(); } +static void instr_0F15() { unimplemented_sse(); } +static void instr_0F16() { unimplemented_sse(); } +static void instr_0F17() { unimplemented_sse(); } + +static void instr_0F18() { read_modrm_byte(); + // prefetch + // nop for us + if(modrm_byte[0] < 0xC0) + modrm_resolve(modrm_byte[0]); +} + +static void instr_0F19() { unimplemented_sse(); } +static void instr_0F1A() { unimplemented_sse(); } +static void instr_0F1B() { unimplemented_sse(); } +static void instr_0F1C() { unimplemented_sse(); } +static void instr_0F1D() { unimplemented_sse(); } +static void instr_0F1E() { unimplemented_sse(); } +static void instr_0F1F() { read_modrm_byte(); + // multi-byte nop + if(modrm_byte[0] < 0xC0) + modrm_resolve(modrm_byte[0]); +} + + +static void instr_0F20() { read_modrm_byte(); + + if(cpl[0]) + { + trigger_gp(0); + } + //dbg_log("cr" + (modrm_byte[0] >> 3 & 7) + " read"); + + // mov addr, cr + // mod = which control register + switch(modrm_byte[0] >> 3 & 7) + { + case 0: + write_reg_e32(cr[0]); + break; + case 2: + //dbg_log("read cr2 at " + h(instruction_pointer, 8)); + write_reg_e32(cr[2]); + break; + case 3: + //dbg_log("read cr3 (" + h(cr[3], 8) + ")"); + write_reg_e32(cr[3]); + break; + case 4: + write_reg_e32(cr[4]); + break; + default: + dbg_log("%d", modrm_byte[0] >> 3 & 7); + todo(); + } +} + +static void instr_0F21() { read_modrm_byte(); + if(cpl[0]) + { + trigger_gp(0); + } + + int32_t dreg_index = modrm_byte[0] >> 3 & 7; + if((cr[4] & CR4_DE) && (dreg_index == 4 || dreg_index == 5)) + { + dbg_log("#ud mov dreg 4/5 with cr4.DE set"); + trigger_ud(); + } + + // high two bits of modrm are ignored + reg32s[modrm_byte[0] & 7] = dreg[dreg_index]; + + //dbg_log("read dr" + dreg + ": " + h(dreg[dreg_index])); +} + +static void instr_0F22() { read_modrm_byte(); + + if(cpl[0]) + { + trigger_gp(0); + } + + int32_t data = read_reg_e32s(); + //dbg_log("cr" + (modrm_byte[0] >> 3 & 7) + " written: " + h(data, 8)); + + // mov cr, addr + // mod = which control register + switch(modrm_byte[0] >> 3 & 7) + { + case 0: + set_cr0(data); + //dbg_log("cr0=" + h(data)); + break; + + case 2: + cr[2] = data; + //dbg_log("cr2=" + h(data)); + break; + + case 3: + //dbg_log("cr3=" + h(data)); + data &= ~0b111111100111; + dbg_assert_message((data & 0xFFF) == 0, "TODO"); + cr[3] = data; + clear_tlb(); + + //dump_page_directory(); + //dbg_log("page directory loaded at " + h(cr[3], 8)); + break; + + case 4: + if(data & (1 << 11 | 1 << 12 | 1 << 15 | 1 << 16 | 1 << 19 | 0xFFC00000)) + { + trigger_gp(0); + } + + if((cr[4] ^ data) & CR4_PGE) + { + if(data & CR4_PGE) + { + // The PGE bit has been enabled. The global TLB is + // still empty, so we only have to copy it over + clear_tlb(); + } + else + { + // Clear the global TLB + full_clear_tlb(); + } + } + + cr[4] = data; + page_size_extensions[0] = (cr[4] & CR4_PSE) ? PSE_ENABLED : 0; + + if(cr[4] & CR4_PAE) + { + //throw debug.unimpl("PAE"); + assert(false); + } + + //dbg_log("cr4=" + h(cr[4])); + break; + + default: + dbg_log("%d", modrm_byte[0] >> 3 & 7); + todo(); + } +} +static void instr_0F23() { read_modrm_byte(); + if(cpl[0]) + { + trigger_gp(0); + } + + int32_t dreg_index = modrm_byte[0] >> 3 & 7; + if((cr[4] & CR4_DE) && (dreg_index == 4 || dreg_index == 5)) + { + dbg_log("#ud mov dreg 4/5 with cr4.DE set"); + trigger_ud(); + } + + // high two bits of modrm are ignored + dreg[dreg_index] = read_reg_e32s(); + + //dbg_log("write dr" + dreg + ": " + h(dreg[dreg_index])); +} + +static void instr_0F24() { undefined_instruction(); } +static void instr_0F25() { undefined_instruction(); } +static void instr_0F26() { undefined_instruction(); } +static void instr_0F27() { undefined_instruction(); } + +static void instr_0F28() { unimplemented_sse(); } +static void instr_0F29() { unimplemented_sse(); } +static void instr_0F2A() { unimplemented_sse(); } +static void instr_0F2B() { unimplemented_sse(); } +static void instr_0F2C() { unimplemented_sse(); } +static void instr_0F2D() { unimplemented_sse(); } +static void instr_0F2E() { unimplemented_sse(); } +static void instr_0F2F() { unimplemented_sse(); } + +// wrmsr +static void instr_0F30() { + // wrmsr - write maschine specific register + + if(cpl[0]) + { + // cpl > 0 or vm86 mode (vm86 mode is always runs with cpl=3) + trigger_gp(0); + } + + int32_t index = reg32s[ECX]; + int32_t low = reg32s[EAX]; + int32_t high = reg32s[EDX]; + + if(index != IA32_SYSENTER_ESP) + { + //dbg_log("wrmsr ecx=" + h(index, 8) + + // " data=" + h(high, 8) + ":" + h(low, 8)); + } + + switch(index) + { + case IA32_SYSENTER_CS: + sysenter_cs[0] = low & 0xFFFF; + break; + + case IA32_SYSENTER_EIP: + sysenter_eip[0] = low; + break; + + case IA32_SYSENTER_ESP: + sysenter_esp[0] = low; + break; + + case IA32_APIC_BASE_MSR: + { + dbg_assert_message(high == 0, "Changing APIC address (high 32 bits) not supported"); + int32_t address = low & ~(IA32_APIC_BASE_BSP | IA32_APIC_BASE_EXTD | IA32_APIC_BASE_EN); + dbg_assert_message(address == APIC_ADDRESS, "Changing APIC address not supported"); + dbg_assert_message((low & IA32_APIC_BASE_EXTD) == 0, "x2apic not supported"); + *apic_enabled = (low & IA32_APIC_BASE_EN) == IA32_APIC_BASE_EN; + } + break; + + case IA32_TIME_STAMP_COUNTER: + { + int32_t new_tick = (low) + 0x100000000 * (high); + tsc_offset[0] = microtick() - new_tick / TSC_RATE; // XXX: float + } + break; + + case IA32_BIOS_SIGN_ID: + break; + + case IA32_MISC_ENABLE: // Enable Misc. Processor Features + break; + + case IA32_MCG_CAP: + // netbsd + break; + + case IA32_KERNEL_GS_BASE: + // Only used in 64 bit mode (by SWAPGS), but set by kvm-unit-test + dbg_log("GS Base written"); + break; + + default: + assert(false); + //dbg_assert(false, "Unknown msr: " + h(index, 8)); + } +} + +static void instr_0F31() { + // rdtsc - read timestamp counter + + if(!cpl[0] || !(cr[4] & CR4_TSD)) + { + int32_t n = microtick() - tsc_offset[0]; // XXX: float + //dbg_assert(isFinite(n), "non-finite tsc: " + n); + + reg32s[EAX] = n * TSC_RATE; + reg32s[EDX] = n * (TSC_RATE / 0x100000000); + + //dbg_log("rdtsc edx:eax=" + h(reg32[EDX], 8) + ":" + h(reg32[EAX], 8)); + } + else + { + trigger_gp(0); + } +} + +static void instr_0F32() { + // rdmsr - read maschine specific register + if(cpl[0]) + { + trigger_gp(0); + } + + int32_t index = reg32s[ECX]; + + //dbg_log("rdmsr ecx=" + h(index, 8)); + + int32_t low = 0; + int32_t high = 0; + + switch(index) + { + case IA32_SYSENTER_CS: + low = sysenter_cs[0]; + break; + + case IA32_SYSENTER_EIP: + low = sysenter_eip[0]; + break; + + case IA32_SYSENTER_ESP: + low = sysenter_esp[0]; + break; + + case IA32_TIME_STAMP_COUNTER: + { + int32_t n = microtick() - tsc_offset[0]; // XXX: float + low = n * TSC_RATE; + high = n * (TSC_RATE / 0x100000000); + } + break; + + case IA32_PLATFORM_ID: + break; + + case IA32_APIC_BASE_MSR: + if(ENABLE_ACPI) + { + low = APIC_ADDRESS; + + if(*apic_enabled) + { + low |= IA32_APIC_BASE_EN; + } + } + break; + + case IA32_BIOS_SIGN_ID: + break; + + case IA32_MISC_ENABLE: // Enable Misc. Processor Features + break; + + case IA32_RTIT_CTL: + // linux4 + break; + + case MSR_SMI_COUNT: + break; + + case IA32_MCG_CAP: + // netbsd + break; + + case MSR_PKG_C2_RESIDENCY: + break; + + default: + assert(false); + //dbg_assert(false, "Unknown msr: " + h(index, 8)); + } + + reg32s[EAX] = low; + reg32s[EDX] = high; +} + +static void instr_0F33() { + // rdpmc + todo(); +} + +static void instr_0F34() { + // sysenter + int32_t seg = sysenter_cs[0] & 0xFFFC; + + if(!protected_mode[0] || seg == 0) + { + trigger_gp(0); + } + + if(CPU_LOG_VERBOSE) + { + //dbg_log("sysenter cs:eip=" + h(seg , 4) + ":" + h(sysenter_eip[0], 8) + + // " ss:esp=" + h(seg + 8, 4) + ":" + h(sysenter_esp[0], 8)); + } + + flags[0] &= ~FLAG_VM & ~FLAG_INTERRUPT; + + instruction_pointer[0] = sysenter_eip[0]; + reg32s[ESP] = sysenter_esp[0]; + + sreg[CS] = seg; + segment_is_null[CS] = 0; + segment_limits[CS] = -1; + segment_offsets[CS] = 0; + + update_cs_size(true); + + cpl[0] = 0; + cpl_changed(); + + sreg[SS] = seg + 8; + segment_is_null[SS] = 0; + segment_limits[SS] = -1; + segment_offsets[SS] = 0; + + stack_size_32[0] = true; + diverged(); +} + +static void instr_0F35() { + // sysexit + int32_t seg = sysenter_cs[0] & 0xFFFC; + + if(!protected_mode[0] || cpl[0] || seg == 0) + { + trigger_gp(0); + } + + if(CPU_LOG_VERBOSE) + { + //dbg_log("sysexit cs:eip=" + h(seg + 16, 4) + ":" + h(reg32s[EDX], 8) + + // " ss:esp=" + h(seg + 24, 4) + ":" + h(reg32s[ECX], 8)); + } + + instruction_pointer[0] = reg32s[EDX]; + reg32s[ESP] = reg32s[ECX]; + + sreg[CS] = seg + 16 | 3; + + segment_is_null[CS] = 0; + segment_limits[CS] = -1; + segment_offsets[CS] = 0; + + update_cs_size(true); + + cpl[0] = 3; + cpl_changed(); + + sreg[SS] = seg + 24 | 3; + segment_is_null[SS] = 0; + segment_limits[SS] = -1; + segment_offsets[SS] = 0; + + stack_size_32[0] = true; + diverged(); +} + +static void instr_0F36() { undefined_instruction(); } + +static void instr_0F37() { + // getsec + todo(); +} + +static void instr_0F38() { unimplemented_sse(); } +static void instr_0F39() { unimplemented_sse(); } +static void instr_0F3A() { unimplemented_sse(); } +static void instr_0F3B() { unimplemented_sse(); } +static void instr_0F3C() { unimplemented_sse(); } +static void instr_0F3D() { unimplemented_sse(); } +static void instr_0F3E() { unimplemented_sse(); } +static void instr_0F3F() { unimplemented_sse(); } + + +// cmov +static void instr16_0F40() { read_modrm_byte(); cmovcc16( test_o()); } +static void instr32_0F40() { read_modrm_byte(); cmovcc32( test_o()); } +static void instr16_0F41() { read_modrm_byte(); cmovcc16(!test_o()); } +static void instr32_0F41() { read_modrm_byte(); cmovcc32(!test_o()); } +static void instr16_0F42() { read_modrm_byte(); cmovcc16( test_b()); } +static void instr32_0F42() { read_modrm_byte(); cmovcc32( test_b()); } +static void instr16_0F43() { read_modrm_byte(); cmovcc16(!test_b()); } +static void instr32_0F43() { read_modrm_byte(); cmovcc32(!test_b()); } +static void instr16_0F44() { read_modrm_byte(); cmovcc16( test_z()); } +static void instr32_0F44() { read_modrm_byte(); cmovcc32( test_z()); } +static void instr16_0F45() { read_modrm_byte(); cmovcc16(!test_z()); } +static void instr32_0F45() { read_modrm_byte(); cmovcc32(!test_z()); } +static void instr16_0F46() { read_modrm_byte(); cmovcc16( test_be()); } +static void instr32_0F46() { read_modrm_byte(); cmovcc32( test_be()); } +static void instr16_0F47() { read_modrm_byte(); cmovcc16(!test_be()); } +static void instr32_0F47() { read_modrm_byte(); cmovcc32(!test_be()); } +static void instr16_0F48() { read_modrm_byte(); cmovcc16( test_s()); } +static void instr32_0F48() { read_modrm_byte(); cmovcc32( test_s()); } +static void instr16_0F49() { read_modrm_byte(); cmovcc16(!test_s()); } +static void instr32_0F49() { read_modrm_byte(); cmovcc32(!test_s()); } +static void instr16_0F4A() { read_modrm_byte(); cmovcc16( test_p()); } +static void instr32_0F4A() { read_modrm_byte(); cmovcc32( test_p()); } +static void instr16_0F4B() { read_modrm_byte(); cmovcc16(!test_p()); } +static void instr32_0F4B() { read_modrm_byte(); cmovcc32(!test_p()); } +static void instr16_0F4C() { read_modrm_byte(); cmovcc16( test_l()); } +static void instr32_0F4C() { read_modrm_byte(); cmovcc32( test_l()); } +static void instr16_0F4D() { read_modrm_byte(); cmovcc16(!test_l()); } +static void instr32_0F4D() { read_modrm_byte(); cmovcc32(!test_l()); } +static void instr16_0F4E() { read_modrm_byte(); cmovcc16( test_le()); } +static void instr32_0F4E() { read_modrm_byte(); cmovcc32( test_le()); } +static void instr16_0F4F() { read_modrm_byte(); cmovcc16(!test_le()); } +static void instr32_0F4F() { read_modrm_byte(); cmovcc32(!test_le()); } + + +static void instr_0F50() { unimplemented_sse(); } +static void instr_0F51() { unimplemented_sse(); } +static void instr_0F52() { unimplemented_sse(); } +static void instr_0F53() { unimplemented_sse(); } +static void instr_0F54() { unimplemented_sse(); } +static void instr_0F55() { unimplemented_sse(); } +static void instr_0F56() { unimplemented_sse(); } +static void instr_0F57() { unimplemented_sse(); } + +static void instr_0F58() { unimplemented_sse(); } +static void instr_0F59() { unimplemented_sse(); } +static void instr_0F5A() { unimplemented_sse(); } +static void instr_0F5B() { unimplemented_sse(); } +static void instr_0F5C() { unimplemented_sse(); } +static void instr_0F5D() { unimplemented_sse(); } +static void instr_0F5E() { unimplemented_sse(); } +static void instr_0F5F() { unimplemented_sse(); } + +static void instr_0F60() { unimplemented_sse(); } +static void instr_0F61() { unimplemented_sse(); } +static void instr_0F62() { unimplemented_sse(); } +static void instr_0F63() { unimplemented_sse(); } +static void instr_0F64() { unimplemented_sse(); } +static void instr_0F65() { unimplemented_sse(); } +static void instr_0F66() { unimplemented_sse(); } +static void instr_0F67() { unimplemented_sse(); } + +static void instr_0F68() { unimplemented_sse(); } +static void instr_0F69() { unimplemented_sse(); } +static void instr_0F6A() { unimplemented_sse(); } +static void instr_0F6B() { unimplemented_sse(); } +static void instr_0F6C() { unimplemented_sse(); } +static void instr_0F6D() { unimplemented_sse(); } +static void instr_0F6E() { unimplemented_sse(); } +static void instr_0F6F() { unimplemented_sse(); } + +static void instr_0F70() { unimplemented_sse(); } +static void instr_0F71() { unimplemented_sse(); } +static void instr_0F72() { unimplemented_sse(); } +static void instr_0F73() { unimplemented_sse(); } +static void instr_0F74() { unimplemented_sse(); } +static void instr_0F75() { unimplemented_sse(); } +static void instr_0F76() { unimplemented_sse(); } +static void instr_0F77() { + // emms + dbg_assert((*prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); + + if(cr[0] & (CR0_EM | CR0_TS)) { + if(cr[0] & CR0_TS) { + trigger_nm(); + } + else { + trigger_ud(); + } + } + + safe_tag_word(0xFFFF); +} + +static void instr_0F78() { unimplemented_sse(); } +static void instr_0F79() { unimplemented_sse(); } +static void instr_0F7A() { unimplemented_sse(); } +static void instr_0F7B() { unimplemented_sse(); } +static void instr_0F7C() { unimplemented_sse(); } +static void instr_0F7D() { unimplemented_sse(); } +static void instr_0F7E() { unimplemented_sse(); } +static void instr_0F7F() { unimplemented_sse(); } + +// jmpcc +static void instr16_0F80() { jmpcc16( test_o()); } +static void instr32_0F80() { jmpcc32( test_o()); } +static void instr16_0F81() { jmpcc16(!test_o()); } +static void instr32_0F81() { jmpcc32(!test_o()); } +static void instr16_0F82() { jmpcc16( test_b()); } +static void instr32_0F82() { jmpcc32( test_b()); } +static void instr16_0F83() { jmpcc16(!test_b()); } +static void instr32_0F83() { jmpcc32(!test_b()); } +static void instr16_0F84() { jmpcc16( test_z()); } +static void instr32_0F84() { jmpcc32( test_z()); } +static void instr16_0F85() { jmpcc16(!test_z()); } +static void instr32_0F85() { jmpcc32(!test_z()); } +static void instr16_0F86() { jmpcc16( test_be()); } +static void instr32_0F86() { jmpcc32( test_be()); } +static void instr16_0F87() { jmpcc16(!test_be()); } +static void instr32_0F87() { jmpcc32(!test_be()); } +static void instr16_0F88() { jmpcc16( test_s()); } +static void instr32_0F88() { jmpcc32( test_s()); } +static void instr16_0F89() { jmpcc16(!test_s()); } +static void instr32_0F89() { jmpcc32(!test_s()); } +static void instr16_0F8A() { jmpcc16( test_p()); } +static void instr32_0F8A() { jmpcc32( test_p()); } +static void instr16_0F8B() { jmpcc16(!test_p()); } +static void instr32_0F8B() { jmpcc32(!test_p()); } +static void instr16_0F8C() { jmpcc16( test_l()); } +static void instr32_0F8C() { jmpcc32( test_l()); } +static void instr16_0F8D() { jmpcc16(!test_l()); } +static void instr32_0F8D() { jmpcc32(!test_l()); } +static void instr16_0F8E() { jmpcc16( test_le()); } +static void instr32_0F8E() { jmpcc32( test_le()); } +static void instr16_0F8F() { jmpcc16(!test_le()); } +static void instr32_0F8F() { jmpcc32(!test_le()); } + +// setcc +static void instr_0F90() { read_modrm_byte(); setcc( test_o()); } +static void instr_0F91() { read_modrm_byte(); setcc(!test_o()); } +static void instr_0F92() { read_modrm_byte(); setcc( test_b()); } +static void instr_0F93() { read_modrm_byte(); setcc(!test_b()); } +static void instr_0F94() { read_modrm_byte(); setcc( test_z()); } +static void instr_0F95() { read_modrm_byte(); setcc(!test_z()); } +static void instr_0F96() { read_modrm_byte(); setcc( test_be()); } +static void instr_0F97() { read_modrm_byte(); setcc(!test_be()); } +static void instr_0F98() { read_modrm_byte(); setcc( test_s()); } +static void instr_0F99() { read_modrm_byte(); setcc(!test_s()); } +static void instr_0F9A() { read_modrm_byte(); setcc( test_p()); } +static void instr_0F9B() { read_modrm_byte(); setcc(!test_p()); } +static void instr_0F9C() { read_modrm_byte(); setcc( test_l()); } +static void instr_0F9D() { read_modrm_byte(); setcc(!test_l()); } +static void instr_0F9E() { read_modrm_byte(); setcc( test_le()); } +static void instr_0F9F() { read_modrm_byte(); setcc(!test_le()); } + +static void instr16_0FA0() { push16(sreg[FS]); } +static void instr32_0FA0() { push32(sreg[FS]); } +static void instr16_0FA1() { + switch_seg(FS, safe_read16(get_stack_pointer(0))); + adjust_stack_reg(2); +} +static void instr32_0FA1() { + switch_seg(FS, safe_read32s(get_stack_pointer(0)) & 0xFFFF); + adjust_stack_reg(4); +} + +static void instr_0FA2() { cpuid(); } + +static void instr16_0FA3() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) + { + bt_mem(modrm_resolve(modrm_byte[0]), read_g16s()); + } + else + { + bt_reg(read_reg_e16(), read_g16() & 15); + } +} +static void instr32_0FA3() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) + { + bt_mem(modrm_resolve(modrm_byte[0]), read_g32s()); + } + else + { + bt_reg(read_reg_e32s(), read_g32s() & 31); + } +} + +static void instr16_0FA4() { read_modrm_byte(); + int32_t data = read_write_e16(); write_e16(shld16(data, read_g16(), read_op8() & 31)); +} +static void instr32_0FA4() { read_modrm_byte(); + int32_t data = read_write_e32(); write_e32(shld32(data, read_g32s(), read_op8() & 31)); +} +static void instr16_0FA5() { read_modrm_byte(); + int32_t data = read_write_e16(); write_e16(shld16(data, read_g16(), reg8[CL] & 31)); +} +static void instr32_0FA5() { read_modrm_byte(); + int32_t data = read_write_e32(); write_e32(shld32(data, read_g32s(), reg8[CL] & 31)); +} + +static void instr_0FA6() { + // obsolete cmpxchg (os/2) + trigger_ud(); +} +static void instr_0FA7() { undefined_instruction(); } + +static void instr16_0FA8() { push16(sreg[GS]); } +static void instr32_0FA8() { push32(sreg[GS]); } +static void instr16_0FA9() { + switch_seg(GS, safe_read16(get_stack_pointer(0))); + adjust_stack_reg(2); +} +static void instr32_0FA9() { + switch_seg(GS, safe_read32s(get_stack_pointer(0)) & 0xFFFF); + adjust_stack_reg(4); +} + + +static void instr_0FAA() { + // rsm + todo(); +} + +static void instr16_0FAB() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + bts_mem(modrm_resolve(modrm_byte[0]), read_g16s()); + } else { + write_reg_e16(bts_reg(read_reg_e16(), read_g16s() & 15)); + } +} +static void instr32_0FAB() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + bts_mem(modrm_resolve(modrm_byte[0]), read_g32s()); + } else { + write_reg_e32(bts_reg(read_reg_e32s(), read_g32s() & 31)); + } +} + + +static void instr16_0FAC() { read_modrm_byte(); + int32_t data = read_write_e16(); write_e16(shrd16(data, read_g16(), read_op8() & 31)); +} +static void instr32_0FAC() { read_modrm_byte(); + int32_t data = read_write_e32(); write_e32(shrd32(data, read_g32s(), read_op8() & 31)); +} +static void instr16_0FAD() { read_modrm_byte(); + int32_t data = read_write_e16(); write_e16(shrd16(data, read_g16(), reg8[CL] & 31)); +} +static void instr32_0FAD() { read_modrm_byte(); + int32_t data = read_write_e32(); write_e32(shrd32(data, read_g32s(), reg8[CL] & 31)); +} + +static void instr_0FAE() { read_modrm_byte(); + // fxsave, fxrstor, ldmxcsr ... + + switch(modrm_byte[0] >> 3 & 7) + { + case 0: // fxsave + if(modrm_byte[0] >= 0xC0) trigger_ud(); + { + int32_t addr = modrm_resolve(modrm_byte[0]); + fxsave(addr); + } + break; + + case 1: // fxrstor + if(modrm_byte[0] >= 0xC0) trigger_ud(); + { + int32_t addr = modrm_resolve(modrm_byte[0]); + fxrstor(addr); + } + break; + + case 2: // ldmxcsr + if(modrm_byte[0] >= 0xC0) trigger_ud(); + { + int32_t addr = modrm_resolve(modrm_byte[0]); + int32_t new_mxcsr = safe_read32s(addr); + if(new_mxcsr & ~MXCSR_MASK) + { + //dbg_log("Invalid mxcsr bits: " + h((new_mxcsr & ~MXCSR_MASK), 8)); + assert(false); + trigger_gp(0); + } + *mxcsr = new_mxcsr; + } + break; + + case 3: // stmxcsr + if(modrm_byte[0] >= 0xC0) trigger_ud(); + { + int32_t addr = modrm_resolve(modrm_byte[0]); + safe_write32(addr, *mxcsr); + } + break; + + case 5: + // lfence + dbg_assert_message(modrm_byte[0] >= 0xC0, "Unexpected mfence encoding"); + if(modrm_byte[0] < 0xC0) trigger_ud(); + break; + + case 6: + // mfence + dbg_assert_message(modrm_byte[0] >= 0xC0, "Unexpected mfence encoding"); + if(modrm_byte[0] < 0xC0) trigger_ud(); + break; + + case 7: + // sfence or clflush + dbg_assert_message(modrm_byte[0] >= 0xC0, "Unexpected sfence encoding"); + if(modrm_byte[0] < 0xC0) trigger_ud(); + break; + + default: + //dbg_log("missing " + (modrm_byte[0] >> 3 & 7)); + todo(); + } +} + +static void instr16_0FAF() { read_modrm_byte(); + int32_t data = read_e16s(); + write_g16(imul_reg16(read_g16s(), data)); +} +static void instr32_0FAF() { read_modrm_byte(); + int32_t data = read_e32s(); + write_g32(imul_reg32(read_g32s(), data)); +} + + +static void instr_0FB0() { read_modrm_byte(); + // cmpxchg8 + int32_t data = 0; + int32_t virt_addr = 0; + if(modrm_byte[0] < 0xC0) + { + virt_addr = modrm_resolve(modrm_byte[0]); + writable_or_pagefault(virt_addr, 1); + + data = safe_read8(virt_addr); + } + else + data = reg8[modrm_byte[0] << 2 & 0xC | modrm_byte[0] >> 2 & 1]; + + + cmp8(reg8[AL], data); + + if(getzf()) + { + if(modrm_byte[0] < 0xC0) + safe_write8(virt_addr, read_g8()); + else + reg8[modrm_byte[0] << 2 & 0xC | modrm_byte[0] >> 2 & 1] = read_g8(); + } + else + { + if(modrm_byte[0] < 0xC0) + safe_write8(virt_addr, data); + + reg8[AL] = data; + } +} +static void instr16_0FB1() { read_modrm_byte(); + // cmpxchg16/32 + int32_t data = 0; + int32_t virt_addr = 0; + if(modrm_byte[0] < 0xC0) + { + virt_addr = modrm_resolve(modrm_byte[0]); + writable_or_pagefault(virt_addr, 2); + + data = safe_read16(virt_addr); + } + else + data = read_reg_e16(); + + cmp16(reg16[AX], data); + + if(getzf()) + { + if(modrm_byte[0] < 0xC0) + safe_write16(virt_addr, read_g16()); + else + write_reg_e16(read_g16()); + } + else + { + if(modrm_byte[0] < 0xC0) + safe_write16(virt_addr, data); + + reg16[AX] = data; + } +} +static void instr32_0FB1() { read_modrm_byte(); + int32_t virt_addr = 0; + int32_t data = 0; + if(modrm_byte[0] < 0xC0) + { + virt_addr = modrm_resolve(modrm_byte[0]); + writable_or_pagefault(virt_addr, 4); + + data = safe_read32s(virt_addr); + } + else + { + data = read_reg_e32s(); + } + + cmp32(reg32s[EAX], data); + + if(getzf()) + { + if(modrm_byte[0] < 0xC0) + safe_write32(virt_addr, read_g32s()); + else + write_reg_e32(read_g32s()); + } + else + { + if(modrm_byte[0] < 0xC0) + safe_write32(virt_addr, data); + + reg32s[EAX] = data; + } +} + +// lss +static void instr16_0FB2() { read_modrm_byte(); + lss16(SS); +} +static void instr32_0FB2() { read_modrm_byte(); + lss32(SS); +} + +static void instr16_0FB3() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + btr_mem(modrm_resolve(modrm_byte[0]), read_g16s()); + } else { + write_reg_e16(btr_reg(read_reg_e16(), read_g16s() & 15)); + } +} +static void instr32_0FB3() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + btr_mem(modrm_resolve(modrm_byte[0]), read_g32s()); + } else { + write_reg_e32(btr_reg(read_reg_e32s(), read_g32s() & 31)); + } +} + +// lfs, lgs +static void instr16_0FB4() { read_modrm_byte(); + lss16(FS); +} +static void instr32_0FB4() { read_modrm_byte(); + lss32(FS); +} +static void instr16_0FB5() { read_modrm_byte(); + lss16(GS); +} +static void instr32_0FB5() { read_modrm_byte(); + lss32(GS); +} + +static void instr16_0FB6() { read_modrm_byte(); + // movzx + int32_t data = read_e8(); + write_g16(data); +} +static void instr32_0FB6() { read_modrm_byte(); + int32_t data = read_e8(); + write_g32(data); +} + +static void instr16_0FB7() { read_modrm_byte(); + // movzx + dbg_assert_message(false, "Possibly invalid encoding"); + int32_t data = read_e16(); + write_g16(data); +} +static void instr32_0FB7() { read_modrm_byte(); + int32_t data = read_e16(); + write_g32(data); +} + +static void instr16_0FB8() { read_modrm_byte(); + // popcnt + int32_t data = read_e16(); + write_g16(popcnt(data)); +} +static void instr32_0FB8() { read_modrm_byte(); + int32_t data = read_e32s(); + write_g32(popcnt(data)); +} + +static void instr_0FB9() { + // UD + todo(); +} + +static void instr16_0FBA() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 4: + if(modrm_byte[0] < 0xC0) + { + bt_mem(modrm_resolve(modrm_byte[0]), read_op8() & 15); + } + else + { + bt_reg(read_reg_e16(), read_op8() & 15); + } + break; + case 5: + if(modrm_byte[0] < 0xC0) { + bts_mem(modrm_resolve(modrm_byte[0]), read_op8() & 15); + } else { + write_reg_e16(bts_reg(read_reg_e16(), read_op8() & 15)); + } + break; + case 6: + if(modrm_byte[0] < 0xC0) { + btr_mem(modrm_resolve(modrm_byte[0]), read_op8() & 15); + } else { + write_reg_e16(btr_reg(read_reg_e16(), read_op8() & 15)); + } + break; + case 7: + if(modrm_byte[0] < 0xC0) { + btc_mem(modrm_resolve(modrm_byte[0]), read_op8() & 15); + } else { + write_reg_e16(btc_reg(read_reg_e16(), read_op8() & 15)); + } + break; + default: + dbg_log("%d", modrm_byte[0] >> 3 & 7); + todo(); + } +} +static void instr32_0FBA() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 4: + if(modrm_byte[0] < 0xC0) + { + bt_mem(modrm_resolve(modrm_byte[0]), read_op8() & 31); + } + else + { + bt_reg(read_reg_e32s(), read_op8() & 31); + } + break; + case 5: + if(modrm_byte[0] < 0xC0) { + bts_mem(modrm_resolve(modrm_byte[0]), read_op8() & 31); + } else { + write_reg_e32(bts_reg(read_reg_e32s(), read_op8() & 31)); + } + break; + case 6: + if(modrm_byte[0] < 0xC0) { + btr_mem(modrm_resolve(modrm_byte[0]), read_op8() & 31); + } else { + write_reg_e32(btr_reg(read_reg_e32s(), read_op8() & 31)); + } + break; + case 7: + if(modrm_byte[0] < 0xC0) { + btc_mem(modrm_resolve(modrm_byte[0]), read_op8() & 31); + } else { + write_reg_e32(btc_reg(read_reg_e32s(), read_op8() & 31)); + } + break; + default: + dbg_log("%d", modrm_byte[0] >> 3 & 7); + todo(); + } +} + +static void instr16_0FBB() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + btc_mem(modrm_resolve(modrm_byte[0]), read_g16s()); + } else { + write_reg_e16(btc_reg(read_reg_e16(), read_g16s() & 15)); + } +} +static void instr32_0FBB() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + btc_mem(modrm_resolve(modrm_byte[0]), read_g32s()); + } else { + write_reg_e32(btc_reg(read_reg_e32s(), read_g32s() & 31)); + } +} + +static void instr16_0FBC() { read_modrm_byte(); + int32_t data = read_e16(); + write_g16(bsf16(read_g16(), data)); +} +static void instr32_0FBC() { read_modrm_byte(); + int32_t data = read_e32s(); + write_g32(bsf32(read_g32s(), data)); +} + +static void instr16_0FBD() { read_modrm_byte(); + int32_t data = read_e16(); + write_g16(bsr16(read_g16(), data)); +} +static void instr32_0FBD() { read_modrm_byte(); + int32_t data = read_e32s(); + write_g32(bsr32(read_g32s(), data)); +} + +static void instr16_0FBE() { read_modrm_byte(); + // movsx + int32_t data = read_e8s(); + write_g16(data); +} +static void instr32_0FBE() { read_modrm_byte(); + int32_t data = read_e8s(); + write_g32(data); +} + +static void instr16_0FBF() { read_modrm_byte(); + // movsx + dbg_assert_message(false, "Possibly invalid encoding"); + int32_t data = read_e16(); + write_g16(data); +} + +static void instr32_0FBF() { read_modrm_byte(); + int32_t data = read_e16s(); + write_g32(data); +} + +static void instr_0FC0() { read_modrm_byte(); + int32_t data = read_write_e8(); write_e8(xadd8(data, modrm_byte[0] >> 1 & 0xC | modrm_byte[0] >> 5 & 1)); +} + +static void instr16_0FC1() { read_modrm_byte(); + int32_t data = read_write_e16(); + write_e16(xadd16(data, modrm_byte[0] >> 2 & 14)); +} +static void instr32_0FC1() { read_modrm_byte(); + int32_t data = read_write_e32(); + write_e32(xadd32(data, modrm_byte[0] >> 3 & 7)); +} + + +static void instr_0FC2() { unimplemented_sse(); } +static void instr_0FC3() { unimplemented_sse(); } +static void instr_0FC4() { unimplemented_sse(); } +static void instr_0FC5() { unimplemented_sse(); } +static void instr_0FC6() { unimplemented_sse(); } + +static void instr_0FC7() { + read_modrm_byte(); + + switch(modrm_byte[0] >> 3 & 7) + { + case 1: + // cmpxchg8b + if(modrm_byte[0] >= 0xC0) + { + trigger_ud(); + } + + int32_t addr = modrm_resolve(modrm_byte[0]); + writable_or_pagefault(addr, 8); + + int32_t m64_low = safe_read32s(addr); + int32_t m64_high = safe_read32s(addr + 4); + + if(reg32s[EAX] == m64_low && + reg32s[EDX] == m64_high) + { + flags[0] |= FLAG_ZERO; + + safe_write32(addr, reg32s[EBX]); + safe_write32(addr + 4, reg32s[ECX]); + } + else + { + flags[0] &= ~FLAG_ZERO; + + reg32s[EAX] = m64_low; + reg32s[EDX] = m64_high; + + safe_write32(addr, m64_low); + safe_write32(addr + 4, m64_high); + } + + flags_changed[0] &= ~FLAG_ZERO; + break; + + case 6: + { + int32_t has_rand = has_rand_int(); + + int32_t rand = 0; + if(has_rand) + { + rand = get_rand_int(); + } + //dbg_log("rdrand -> " + h(rand, 8)); + + if(is_osize_32()) + { + set_e32(rand); + } + else + { + set_e16(rand); + } + + flags[0] &= ~FLAGS_ALL; + flags[0] |= has_rand; + flags_changed[0] = 0; + } + break; + + default: + dbg_log("%d", modrm_byte[0] >> 3 & 7); + todo(); + } +} + +static void instr_0FC8() { bswap(EAX); } +static void instr_0FC9() { bswap(ECX); } +static void instr_0FCA() { bswap(EDX); } +static void instr_0FCB() { bswap(EBX); } +static void instr_0FCC() { bswap(ESP); } +static void instr_0FCD() { bswap(EBP); } +static void instr_0FCE() { bswap(ESI); } +static void instr_0FCF() { bswap(EDI); } + +static void instr_0FD0() { unimplemented_sse(); } +static void instr_0FD1() { unimplemented_sse(); } +static void instr_0FD2() { unimplemented_sse(); } +static void instr_0FD3() { unimplemented_sse(); } +static void instr_0FD4() { unimplemented_sse(); } +static void instr_0FD5() { unimplemented_sse(); } +static void instr_0FD6() { unimplemented_sse(); } +static void instr_0FD7() { unimplemented_sse(); } + +static void instr_0FD8() { unimplemented_sse(); } +static void instr_0FD9() { unimplemented_sse(); } +static void instr_0FDA() { unimplemented_sse(); } +static void instr_0FDB() { unimplemented_sse(); } +static void instr_0FDC() { unimplemented_sse(); } +static void instr_0FDD() { unimplemented_sse(); } +static void instr_0FDE() { unimplemented_sse(); } +static void instr_0FDF() { unimplemented_sse(); } + +static void instr_0FE0() { unimplemented_sse(); } +static void instr_0FE1() { unimplemented_sse(); } +static void instr_0FE2() { unimplemented_sse(); } +static void instr_0FE3() { unimplemented_sse(); } +static void instr_0FE4() { unimplemented_sse(); } +static void instr_0FE5() { unimplemented_sse(); } +static void instr_0FE6() { unimplemented_sse(); } +static void instr_0FE7() { unimplemented_sse(); } + +static void instr_0FE8() { unimplemented_sse(); } +static void instr_0FE9() { unimplemented_sse(); } +static void instr_0FEA() { unimplemented_sse(); } +static void instr_0FEB() { unimplemented_sse(); } +static void instr_0FEC() { unimplemented_sse(); } +static void instr_0FED() { unimplemented_sse(); } +static void instr_0FEE() { unimplemented_sse(); } +static void instr_0FEF() { unimplemented_sse(); } + +static void instr_0FF0() { unimplemented_sse(); } +static void instr_0FF1() { unimplemented_sse(); } +static void instr_0FF2() { unimplemented_sse(); } +static void instr_0FF3() { unimplemented_sse(); } +static void instr_0FF4() { unimplemented_sse(); } +static void instr_0FF5() { unimplemented_sse(); } +static void instr_0FF6() { unimplemented_sse(); } +static void instr_0FF7() { unimplemented_sse(); } + +static void instr_0FF8() { unimplemented_sse(); } +static void instr_0FF9() { unimplemented_sse(); } +static void instr_0FFA() { unimplemented_sse(); } +static void instr_0FFB() { unimplemented_sse(); } +static void instr_0FFC() { unimplemented_sse(); } +static void instr_0FFD() { unimplemented_sse(); } +static void instr_0FFE() { unimplemented_sse(); } + +static void instr_0FFF() { + // Windows 98 + dbg_log("#ud: 0F FF"); + trigger_ud(); +} + + +static void run_instruction0f_16(int32_t opcode) +{ + // XXX: This table is generated. Don't modify + switch(opcode) + { +case 0x00: + instr_0F00(); + break; +case 0x01: + instr_0F01(); + break; +case 0x02: + instr16_0F02(); + break; +case 0x03: + instr16_0F03(); + break; +case 0x04: + instr_0F04(); + break; +case 0x05: + instr_0F05(); + break; +case 0x06: + instr_0F06(); + break; +case 0x07: + instr_0F07(); + break; +case 0x08: + instr_0F08(); + break; +case 0x09: + instr_0F09(); + break; +case 0x0A: + instr_0F0A(); + break; +case 0x0B: + instr_0F0B(); + break; +case 0x0C: + instr_0F0C(); + break; +case 0x0D: + instr_0F0D(); + break; +case 0x0E: + instr_0F0E(); + break; +case 0x0F: + instr_0F0F(); + break; +case 0x10: + instr_0F10(); + break; +case 0x11: + instr_0F11(); + break; +case 0x12: + instr_0F12(); + break; +case 0x13: + instr_0F13(); + break; +case 0x14: + instr_0F14(); + break; +case 0x15: + instr_0F15(); + break; +case 0x16: + instr_0F16(); + break; +case 0x17: + instr_0F17(); + break; +case 0x18: + instr_0F18(); + break; +case 0x19: + instr_0F19(); + break; +case 0x1A: + instr_0F1A(); + break; +case 0x1B: + instr_0F1B(); + break; +case 0x1C: + instr_0F1C(); + break; +case 0x1D: + instr_0F1D(); + break; +case 0x1E: + instr_0F1E(); + break; +case 0x1F: + instr_0F1F(); + break; +case 0x20: + instr_0F20(); + break; +case 0x21: + instr_0F21(); + break; +case 0x22: + instr_0F22(); + break; +case 0x23: + instr_0F23(); + break; +case 0x24: + instr_0F24(); + break; +case 0x25: + instr_0F25(); + break; +case 0x26: + instr_0F26(); + break; +case 0x27: + instr_0F27(); + break; +case 0x28: + instr_0F28(); + break; +case 0x29: + instr_0F29(); + break; +case 0x2A: + instr_0F2A(); + break; +case 0x2B: + instr_0F2B(); + break; +case 0x2C: + instr_0F2C(); + break; +case 0x2D: + instr_0F2D(); + break; +case 0x2E: + instr_0F2E(); + break; +case 0x2F: + instr_0F2F(); + break; +case 0x30: + instr_0F30(); + break; +case 0x31: + instr_0F31(); + break; +case 0x32: + instr_0F32(); + break; +case 0x33: + instr_0F33(); + break; +case 0x34: + instr_0F34(); + break; +case 0x35: + instr_0F35(); + break; +case 0x36: + instr_0F36(); + break; +case 0x37: + instr_0F37(); + break; +case 0x38: + instr_0F38(); + break; +case 0x39: + instr_0F39(); + break; +case 0x3A: + instr_0F3A(); + break; +case 0x3B: + instr_0F3B(); + break; +case 0x3C: + instr_0F3C(); + break; +case 0x3D: + instr_0F3D(); + break; +case 0x3E: + instr_0F3E(); + break; +case 0x3F: + instr_0F3F(); + break; +case 0x40: + instr16_0F40(); + break; +case 0x41: + instr16_0F41(); + break; +case 0x42: + instr16_0F42(); + break; +case 0x43: + instr16_0F43(); + break; +case 0x44: + instr16_0F44(); + break; +case 0x45: + instr16_0F45(); + break; +case 0x46: + instr16_0F46(); + break; +case 0x47: + instr16_0F47(); + break; +case 0x48: + instr16_0F48(); + break; +case 0x49: + instr16_0F49(); + break; +case 0x4A: + instr16_0F4A(); + break; +case 0x4B: + instr16_0F4B(); + break; +case 0x4C: + instr16_0F4C(); + break; +case 0x4D: + instr16_0F4D(); + break; +case 0x4E: + instr16_0F4E(); + break; +case 0x4F: + instr16_0F4F(); + break; +case 0x50: + instr_0F50(); + break; +case 0x51: + instr_0F51(); + break; +case 0x52: + instr_0F52(); + break; +case 0x53: + instr_0F53(); + break; +case 0x54: + instr_0F54(); + break; +case 0x55: + instr_0F55(); + break; +case 0x56: + instr_0F56(); + break; +case 0x57: + instr_0F57(); + break; +case 0x58: + instr_0F58(); + break; +case 0x59: + instr_0F59(); + break; +case 0x5A: + instr_0F5A(); + break; +case 0x5B: + instr_0F5B(); + break; +case 0x5C: + instr_0F5C(); + break; +case 0x5D: + instr_0F5D(); + break; +case 0x5E: + instr_0F5E(); + break; +case 0x5F: + instr_0F5F(); + break; +case 0x60: + instr_0F60(); + break; +case 0x61: + instr_0F61(); + break; +case 0x62: + instr_0F62(); + break; +case 0x63: + instr_0F63(); + break; +case 0x64: + instr_0F64(); + break; +case 0x65: + instr_0F65(); + break; +case 0x66: + instr_0F66(); + break; +case 0x67: + instr_0F67(); + break; +case 0x68: + instr_0F68(); + break; +case 0x69: + instr_0F69(); + break; +case 0x6A: + instr_0F6A(); + break; +case 0x6B: + instr_0F6B(); + break; +case 0x6C: + instr_0F6C(); + break; +case 0x6D: + instr_0F6D(); + break; +case 0x6E: + instr_0F6E(); + break; +case 0x6F: + instr_0F6F(); + break; +case 0x70: + instr_0F70(); + break; +case 0x71: + instr_0F71(); + break; +case 0x72: + instr_0F72(); + break; +case 0x73: + instr_0F73(); + break; +case 0x74: + instr_0F74(); + break; +case 0x75: + instr_0F75(); + break; +case 0x76: + instr_0F76(); + break; +case 0x77: + instr_0F77(); + break; +case 0x78: + instr_0F78(); + break; +case 0x79: + instr_0F79(); + break; +case 0x7A: + instr_0F7A(); + break; +case 0x7B: + instr_0F7B(); + break; +case 0x7C: + instr_0F7C(); + break; +case 0x7D: + instr_0F7D(); + break; +case 0x7E: + instr_0F7E(); + break; +case 0x7F: + instr_0F7F(); + break; +case 0x80: + instr16_0F80(); + break; +case 0x81: + instr16_0F81(); + break; +case 0x82: + instr16_0F82(); + break; +case 0x83: + instr16_0F83(); + break; +case 0x84: + instr16_0F84(); + break; +case 0x85: + instr16_0F85(); + break; +case 0x86: + instr16_0F86(); + break; +case 0x87: + instr16_0F87(); + break; +case 0x88: + instr16_0F88(); + break; +case 0x89: + instr16_0F89(); + break; +case 0x8A: + instr16_0F8A(); + break; +case 0x8B: + instr16_0F8B(); + break; +case 0x8C: + instr16_0F8C(); + break; +case 0x8D: + instr16_0F8D(); + break; +case 0x8E: + instr16_0F8E(); + break; +case 0x8F: + instr16_0F8F(); + break; +case 0x90: + instr_0F90(); + break; +case 0x91: + instr_0F91(); + break; +case 0x92: + instr_0F92(); + break; +case 0x93: + instr_0F93(); + break; +case 0x94: + instr_0F94(); + break; +case 0x95: + instr_0F95(); + break; +case 0x96: + instr_0F96(); + break; +case 0x97: + instr_0F97(); + break; +case 0x98: + instr_0F98(); + break; +case 0x99: + instr_0F99(); + break; +case 0x9A: + instr_0F9A(); + break; +case 0x9B: + instr_0F9B(); + break; +case 0x9C: + instr_0F9C(); + break; +case 0x9D: + instr_0F9D(); + break; +case 0x9E: + instr_0F9E(); + break; +case 0x9F: + instr_0F9F(); + break; +case 0xA0: + instr16_0FA0(); + break; +case 0xA1: + instr16_0FA1(); + break; +case 0xA2: + instr_0FA2(); + break; +case 0xA3: + instr16_0FA3(); + break; +case 0xA4: + instr16_0FA4(); + break; +case 0xA5: + instr16_0FA5(); + break; +case 0xA6: + instr_0FA6(); + break; +case 0xA7: + instr_0FA7(); + break; +case 0xA8: + instr16_0FA8(); + break; +case 0xA9: + instr16_0FA9(); + break; +case 0xAA: + instr_0FAA(); + break; +case 0xAB: + instr16_0FAB(); + break; +case 0xAC: + instr16_0FAC(); + break; +case 0xAD: + instr16_0FAD(); + break; +case 0xAE: + instr_0FAE(); + break; +case 0xAF: + instr16_0FAF(); + break; +case 0xB0: + instr_0FB0(); + break; +case 0xB1: + instr16_0FB1(); + break; +case 0xB2: + instr16_0FB2(); + break; +case 0xB3: + instr16_0FB3(); + break; +case 0xB4: + instr16_0FB4(); + break; +case 0xB5: + instr16_0FB5(); + break; +case 0xB6: + instr16_0FB6(); + break; +case 0xB7: + instr16_0FB7(); + break; +case 0xB8: + instr16_0FB8(); + break; +case 0xB9: + instr_0FB9(); + break; +case 0xBA: + instr16_0FBA(); + break; +case 0xBB: + instr16_0FBB(); + break; +case 0xBC: + instr16_0FBC(); + break; +case 0xBD: + instr16_0FBD(); + break; +case 0xBE: + instr16_0FBE(); + break; +case 0xBF: + instr16_0FBF(); + break; +case 0xC0: + instr_0FC0(); + break; +case 0xC1: + instr16_0FC1(); + break; +case 0xC2: + instr_0FC2(); + break; +case 0xC3: + instr_0FC3(); + break; +case 0xC4: + instr_0FC4(); + break; +case 0xC5: + instr_0FC5(); + break; +case 0xC6: + instr_0FC6(); + break; +case 0xC7: + instr_0FC7(); + break; +case 0xC8: + instr_0FC8(); + break; +case 0xC9: + instr_0FC9(); + break; +case 0xCA: + instr_0FCA(); + break; +case 0xCB: + instr_0FCB(); + break; +case 0xCC: + instr_0FCC(); + break; +case 0xCD: + instr_0FCD(); + break; +case 0xCE: + instr_0FCE(); + break; +case 0xCF: + instr_0FCF(); + break; +case 0xD0: + instr_0FD0(); + break; +case 0xD1: + instr_0FD1(); + break; +case 0xD2: + instr_0FD2(); + break; +case 0xD3: + instr_0FD3(); + break; +case 0xD4: + instr_0FD4(); + break; +case 0xD5: + instr_0FD5(); + break; +case 0xD6: + instr_0FD6(); + break; +case 0xD7: + instr_0FD7(); + break; +case 0xD8: + instr_0FD8(); + break; +case 0xD9: + instr_0FD9(); + break; +case 0xDA: + instr_0FDA(); + break; +case 0xDB: + instr_0FDB(); + break; +case 0xDC: + instr_0FDC(); + break; +case 0xDD: + instr_0FDD(); + break; +case 0xDE: + instr_0FDE(); + break; +case 0xDF: + instr_0FDF(); + break; +case 0xE0: + instr_0FE0(); + break; +case 0xE1: + instr_0FE1(); + break; +case 0xE2: + instr_0FE2(); + break; +case 0xE3: + instr_0FE3(); + break; +case 0xE4: + instr_0FE4(); + break; +case 0xE5: + instr_0FE5(); + break; +case 0xE6: + instr_0FE6(); + break; +case 0xE7: + instr_0FE7(); + break; +case 0xE8: + instr_0FE8(); + break; +case 0xE9: + instr_0FE9(); + break; +case 0xEA: + instr_0FEA(); + break; +case 0xEB: + instr_0FEB(); + break; +case 0xEC: + instr_0FEC(); + break; +case 0xED: + instr_0FED(); + break; +case 0xEE: + instr_0FEE(); + break; +case 0xEF: + instr_0FEF(); + break; +case 0xF0: + instr_0FF0(); + break; +case 0xF1: + instr_0FF1(); + break; +case 0xF2: + instr_0FF2(); + break; +case 0xF3: + instr_0FF3(); + break; +case 0xF4: + instr_0FF4(); + break; +case 0xF5: + instr_0FF5(); + break; +case 0xF6: + instr_0FF6(); + break; +case 0xF7: + instr_0FF7(); + break; +case 0xF8: + instr_0FF8(); + break; +case 0xF9: + instr_0FF9(); + break; +case 0xFA: + instr_0FFA(); + break; +case 0xFB: + instr_0FFB(); + break; +case 0xFC: + instr_0FFC(); + break; +case 0xFD: + instr_0FFD(); + break; +case 0xFE: + instr_0FFE(); + break; +case 0xFF: + instr_0FFF(); + break; +default: assert(false); + } +} + +static void run_instruction0f_32(int32_t opcode) +{ + // XXX: This table is generated. Don't modify + switch(opcode) + { +case 0x00: + instr_0F00(); + break; +case 0x01: + instr_0F01(); + break; +case 0x02: + instr32_0F02(); + break; +case 0x03: + instr32_0F03(); + break; +case 0x04: + instr_0F04(); + break; +case 0x05: + instr_0F05(); + break; +case 0x06: + instr_0F06(); + break; +case 0x07: + instr_0F07(); + break; +case 0x08: + instr_0F08(); + break; +case 0x09: + instr_0F09(); + break; +case 0x0A: + instr_0F0A(); + break; +case 0x0B: + instr_0F0B(); + break; +case 0x0C: + instr_0F0C(); + break; +case 0x0D: + instr_0F0D(); + break; +case 0x0E: + instr_0F0E(); + break; +case 0x0F: + instr_0F0F(); + break; +case 0x10: + instr_0F10(); + break; +case 0x11: + instr_0F11(); + break; +case 0x12: + instr_0F12(); + break; +case 0x13: + instr_0F13(); + break; +case 0x14: + instr_0F14(); + break; +case 0x15: + instr_0F15(); + break; +case 0x16: + instr_0F16(); + break; +case 0x17: + instr_0F17(); + break; +case 0x18: + instr_0F18(); + break; +case 0x19: + instr_0F19(); + break; +case 0x1A: + instr_0F1A(); + break; +case 0x1B: + instr_0F1B(); + break; +case 0x1C: + instr_0F1C(); + break; +case 0x1D: + instr_0F1D(); + break; +case 0x1E: + instr_0F1E(); + break; +case 0x1F: + instr_0F1F(); + break; +case 0x20: + instr_0F20(); + break; +case 0x21: + instr_0F21(); + break; +case 0x22: + instr_0F22(); + break; +case 0x23: + instr_0F23(); + break; +case 0x24: + instr_0F24(); + break; +case 0x25: + instr_0F25(); + break; +case 0x26: + instr_0F26(); + break; +case 0x27: + instr_0F27(); + break; +case 0x28: + instr_0F28(); + break; +case 0x29: + instr_0F29(); + break; +case 0x2A: + instr_0F2A(); + break; +case 0x2B: + instr_0F2B(); + break; +case 0x2C: + instr_0F2C(); + break; +case 0x2D: + instr_0F2D(); + break; +case 0x2E: + instr_0F2E(); + break; +case 0x2F: + instr_0F2F(); + break; +case 0x30: + instr_0F30(); + break; +case 0x31: + instr_0F31(); + break; +case 0x32: + instr_0F32(); + break; +case 0x33: + instr_0F33(); + break; +case 0x34: + instr_0F34(); + break; +case 0x35: + instr_0F35(); + break; +case 0x36: + instr_0F36(); + break; +case 0x37: + instr_0F37(); + break; +case 0x38: + instr_0F38(); + break; +case 0x39: + instr_0F39(); + break; +case 0x3A: + instr_0F3A(); + break; +case 0x3B: + instr_0F3B(); + break; +case 0x3C: + instr_0F3C(); + break; +case 0x3D: + instr_0F3D(); + break; +case 0x3E: + instr_0F3E(); + break; +case 0x3F: + instr_0F3F(); + break; +case 0x40: + instr32_0F40(); + break; +case 0x41: + instr32_0F41(); + break; +case 0x42: + instr32_0F42(); + break; +case 0x43: + instr32_0F43(); + break; +case 0x44: + instr32_0F44(); + break; +case 0x45: + instr32_0F45(); + break; +case 0x46: + instr32_0F46(); + break; +case 0x47: + instr32_0F47(); + break; +case 0x48: + instr32_0F48(); + break; +case 0x49: + instr32_0F49(); + break; +case 0x4A: + instr32_0F4A(); + break; +case 0x4B: + instr32_0F4B(); + break; +case 0x4C: + instr32_0F4C(); + break; +case 0x4D: + instr32_0F4D(); + break; +case 0x4E: + instr32_0F4E(); + break; +case 0x4F: + instr32_0F4F(); + break; +case 0x50: + instr_0F50(); + break; +case 0x51: + instr_0F51(); + break; +case 0x52: + instr_0F52(); + break; +case 0x53: + instr_0F53(); + break; +case 0x54: + instr_0F54(); + break; +case 0x55: + instr_0F55(); + break; +case 0x56: + instr_0F56(); + break; +case 0x57: + instr_0F57(); + break; +case 0x58: + instr_0F58(); + break; +case 0x59: + instr_0F59(); + break; +case 0x5A: + instr_0F5A(); + break; +case 0x5B: + instr_0F5B(); + break; +case 0x5C: + instr_0F5C(); + break; +case 0x5D: + instr_0F5D(); + break; +case 0x5E: + instr_0F5E(); + break; +case 0x5F: + instr_0F5F(); + break; +case 0x60: + instr_0F60(); + break; +case 0x61: + instr_0F61(); + break; +case 0x62: + instr_0F62(); + break; +case 0x63: + instr_0F63(); + break; +case 0x64: + instr_0F64(); + break; +case 0x65: + instr_0F65(); + break; +case 0x66: + instr_0F66(); + break; +case 0x67: + instr_0F67(); + break; +case 0x68: + instr_0F68(); + break; +case 0x69: + instr_0F69(); + break; +case 0x6A: + instr_0F6A(); + break; +case 0x6B: + instr_0F6B(); + break; +case 0x6C: + instr_0F6C(); + break; +case 0x6D: + instr_0F6D(); + break; +case 0x6E: + instr_0F6E(); + break; +case 0x6F: + instr_0F6F(); + break; +case 0x70: + instr_0F70(); + break; +case 0x71: + instr_0F71(); + break; +case 0x72: + instr_0F72(); + break; +case 0x73: + instr_0F73(); + break; +case 0x74: + instr_0F74(); + break; +case 0x75: + instr_0F75(); + break; +case 0x76: + instr_0F76(); + break; +case 0x77: + instr_0F77(); + break; +case 0x78: + instr_0F78(); + break; +case 0x79: + instr_0F79(); + break; +case 0x7A: + instr_0F7A(); + break; +case 0x7B: + instr_0F7B(); + break; +case 0x7C: + instr_0F7C(); + break; +case 0x7D: + instr_0F7D(); + break; +case 0x7E: + instr_0F7E(); + break; +case 0x7F: + instr_0F7F(); + break; +case 0x80: + instr32_0F80(); + break; +case 0x81: + instr32_0F81(); + break; +case 0x82: + instr32_0F82(); + break; +case 0x83: + instr32_0F83(); + break; +case 0x84: + instr32_0F84(); + break; +case 0x85: + instr32_0F85(); + break; +case 0x86: + instr32_0F86(); + break; +case 0x87: + instr32_0F87(); + break; +case 0x88: + instr32_0F88(); + break; +case 0x89: + instr32_0F89(); + break; +case 0x8A: + instr32_0F8A(); + break; +case 0x8B: + instr32_0F8B(); + break; +case 0x8C: + instr32_0F8C(); + break; +case 0x8D: + instr32_0F8D(); + break; +case 0x8E: + instr32_0F8E(); + break; +case 0x8F: + instr32_0F8F(); + break; +case 0x90: + instr_0F90(); + break; +case 0x91: + instr_0F91(); + break; +case 0x92: + instr_0F92(); + break; +case 0x93: + instr_0F93(); + break; +case 0x94: + instr_0F94(); + break; +case 0x95: + instr_0F95(); + break; +case 0x96: + instr_0F96(); + break; +case 0x97: + instr_0F97(); + break; +case 0x98: + instr_0F98(); + break; +case 0x99: + instr_0F99(); + break; +case 0x9A: + instr_0F9A(); + break; +case 0x9B: + instr_0F9B(); + break; +case 0x9C: + instr_0F9C(); + break; +case 0x9D: + instr_0F9D(); + break; +case 0x9E: + instr_0F9E(); + break; +case 0x9F: + instr_0F9F(); + break; +case 0xA0: + instr32_0FA0(); + break; +case 0xA1: + instr32_0FA1(); + break; +case 0xA2: + instr_0FA2(); + break; +case 0xA3: + instr32_0FA3(); + break; +case 0xA4: + instr32_0FA4(); + break; +case 0xA5: + instr32_0FA5(); + break; +case 0xA6: + instr_0FA6(); + break; +case 0xA7: + instr_0FA7(); + break; +case 0xA8: + instr32_0FA8(); + break; +case 0xA9: + instr32_0FA9(); + break; +case 0xAA: + instr_0FAA(); + break; +case 0xAB: + instr32_0FAB(); + break; +case 0xAC: + instr32_0FAC(); + break; +case 0xAD: + instr32_0FAD(); + break; +case 0xAE: + instr_0FAE(); + break; +case 0xAF: + instr32_0FAF(); + break; +case 0xB0: + instr_0FB0(); + break; +case 0xB1: + instr32_0FB1(); + break; +case 0xB2: + instr32_0FB2(); + break; +case 0xB3: + instr32_0FB3(); + break; +case 0xB4: + instr32_0FB4(); + break; +case 0xB5: + instr32_0FB5(); + break; +case 0xB6: + instr32_0FB6(); + break; +case 0xB7: + instr32_0FB7(); + break; +case 0xB8: + instr32_0FB8(); + break; +case 0xB9: + instr_0FB9(); + break; +case 0xBA: + instr32_0FBA(); + break; +case 0xBB: + instr32_0FBB(); + break; +case 0xBC: + instr32_0FBC(); + break; +case 0xBD: + instr32_0FBD(); + break; +case 0xBE: + instr32_0FBE(); + break; +case 0xBF: + instr32_0FBF(); + break; +case 0xC0: + instr_0FC0(); + break; +case 0xC1: + instr32_0FC1(); + break; +case 0xC2: + instr_0FC2(); + break; +case 0xC3: + instr_0FC3(); + break; +case 0xC4: + instr_0FC4(); + break; +case 0xC5: + instr_0FC5(); + break; +case 0xC6: + instr_0FC6(); + break; +case 0xC7: + instr_0FC7(); + break; +case 0xC8: + instr_0FC8(); + break; +case 0xC9: + instr_0FC9(); + break; +case 0xCA: + instr_0FCA(); + break; +case 0xCB: + instr_0FCB(); + break; +case 0xCC: + instr_0FCC(); + break; +case 0xCD: + instr_0FCD(); + break; +case 0xCE: + instr_0FCE(); + break; +case 0xCF: + instr_0FCF(); + break; +case 0xD0: + instr_0FD0(); + break; +case 0xD1: + instr_0FD1(); + break; +case 0xD2: + instr_0FD2(); + break; +case 0xD3: + instr_0FD3(); + break; +case 0xD4: + instr_0FD4(); + break; +case 0xD5: + instr_0FD5(); + break; +case 0xD6: + instr_0FD6(); + break; +case 0xD7: + instr_0FD7(); + break; +case 0xD8: + instr_0FD8(); + break; +case 0xD9: + instr_0FD9(); + break; +case 0xDA: + instr_0FDA(); + break; +case 0xDB: + instr_0FDB(); + break; +case 0xDC: + instr_0FDC(); + break; +case 0xDD: + instr_0FDD(); + break; +case 0xDE: + instr_0FDE(); + break; +case 0xDF: + instr_0FDF(); + break; +case 0xE0: + instr_0FE0(); + break; +case 0xE1: + instr_0FE1(); + break; +case 0xE2: + instr_0FE2(); + break; +case 0xE3: + instr_0FE3(); + break; +case 0xE4: + instr_0FE4(); + break; +case 0xE5: + instr_0FE5(); + break; +case 0xE6: + instr_0FE6(); + break; +case 0xE7: + instr_0FE7(); + break; +case 0xE8: + instr_0FE8(); + break; +case 0xE9: + instr_0FE9(); + break; +case 0xEA: + instr_0FEA(); + break; +case 0xEB: + instr_0FEB(); + break; +case 0xEC: + instr_0FEC(); + break; +case 0xED: + instr_0FED(); + break; +case 0xEE: + instr_0FEE(); + break; +case 0xEF: + instr_0FEF(); + break; +case 0xF0: + instr_0FF0(); + break; +case 0xF1: + instr_0FF1(); + break; +case 0xF2: + instr_0FF2(); + break; +case 0xF3: + instr_0FF3(); + break; +case 0xF4: + instr_0FF4(); + break; +case 0xF5: + instr_0FF5(); + break; +case 0xF6: + instr_0FF6(); + break; +case 0xF7: + instr_0FF7(); + break; +case 0xF8: + instr_0FF8(); + break; +case 0xF9: + instr_0FF9(); + break; +case 0xFA: + instr_0FFA(); + break; +case 0xFB: + instr_0FFB(); + break; +case 0xFC: + instr_0FFC(); + break; +case 0xFD: + instr_0FFD(); + break; +case 0xFE: + instr_0FFE(); + break; +case 0xFF: + instr_0FFF(); + break; +default: assert(false); + } +} diff --git a/src/native/log.c b/src/native/log.c new file mode 100644 index 00000000..24a673bb --- /dev/null +++ b/src/native/log.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + +#include + +#include "const.h" +#include "global_pointers.h" + +#define dbg_log(...) { if(DEBUG) { printf(__VA_ARGS__); } } +#define dbg_assert(condition) { if(DEBUG) { assert(condition); } } +#define dbg_assert_message(condition, message) { if(DEBUG && !(condition)) { dbg_log(message); assert(false); } } diff --git a/src/native/memory.c b/src/native/memory.c new file mode 100644 index 00000000..1f049f08 --- /dev/null +++ b/src/native/memory.c @@ -0,0 +1,112 @@ +#include + +bool in_mapped_range(uint32_t addr) +{ + return (addr >= 0xA0000 && addr < 0xC0000) || addr >= *memory_size; +} + +int32_t mmap_read8(uint32_t); +int32_t mmap_read16(uint32_t); +int32_t mmap_read32(uint32_t); +void mmap_write8(uint32_t, uint8_t); +void mmap_write16(uint32_t, uint16_t); +void mmap_write32(uint32_t, uint32_t); + +int32_t read8(uint32_t addr) +{ + if(USE_A20 && *a20_enabled) addr &= A20_MASK; + + if(in_mapped_range(addr)) + { + return mmap_read8(addr); + } + else + { + return mem8[addr]; + } +} + +int32_t read16(uint32_t addr) +{ + if(USE_A20 && !*a20_enabled) addr &= A20_MASK; + + if(in_mapped_range(addr)) + { + return mmap_read16(addr); + } + else + { + return *(uint16_t*)(mem8 + addr); + } +} + +uint16_t read_aligned16(uint32_t addr) +{ + dbg_assert(addr >= 0 && addr < 0x80000000); + if(USE_A20 && !*a20_enabled) addr &= A20_MASK16; + + if(in_mapped_range(addr << 1)) + { + return mmap_read16(addr << 1); + } + else + { + return mem16[addr]; + } +} + +int32_t read32s(uint32_t addr) +{ + if(USE_A20 && *a20_enabled) addr &= A20_MASK; + + if(in_mapped_range(addr)) + { + return mmap_read32(addr); + } + else + { + return *(int32_t*)(mem8 + addr); + } +} + +void write8(uint32_t addr, uint8_t value) +{ + if(USE_A20 && !*a20_enabled) addr &= A20_MASK; + + if(in_mapped_range(addr)) + { + mmap_write8(addr, value); + } + else + { + mem8[addr] = value; + } +} + +void write16(uint32_t addr, uint16_t value) +{ + if(USE_A20 && !*a20_enabled) addr &= A20_MASK; + + if(in_mapped_range(addr)) + { + mmap_write16(addr, value); + } + else + { + *(uint16_t*)(mem8 + addr) = value; + } +} + +void write32(uint32_t addr, int32_t value) +{ + if(USE_A20 && !*a20_enabled) addr &= A20_MASK; + + if(in_mapped_range(addr)) + { + mmap_write32(addr, value); + } + else + { + *(int32_t*)(mem8 + addr) = value; + } +} diff --git a/src/native/misc_instr.c b/src/native/misc_instr.c new file mode 100644 index 00000000..5d4f9ee4 --- /dev/null +++ b/src/native/misc_instr.c @@ -0,0 +1,232 @@ +#include +#include +#include +#include + +#include + +#include "const.h" +#include "global_pointers.h" + +static int32_t get_stack_pointer(int32_t); +static void adjust_stack_reg(int32_t); +void branch_taken(); +void branch_not_taken(); +void writable_or_pagefault(int32_t, int32_t); + + +int32_t getcf() +{ + if(*flags_changed & 1) + { + return (*last_op1 ^ (*last_op1 ^ *last_op2) & (*last_op2 ^ *last_add_result)) >> *last_op_size & 1; + } + else + { + return *flags & 1; + } +} + +int32_t getpf() +{ + if(*flags_changed & FLAG_PARITY) + { + // inverted lookup table + return 0x9669 << 2 >> ((*last_result ^ *last_result >> 4) & 0xF) & FLAG_PARITY; + } + else + { + return *flags & FLAG_PARITY; + } +} + +int32_t getaf() +{ + if(*flags_changed & FLAG_ADJUST) + { + return (*last_op1 ^ *last_op2 ^ *last_add_result) & FLAG_ADJUST; + } + else + { + return *flags & FLAG_ADJUST; + } +} + +int32_t getzf() +{ + if(*flags_changed & FLAG_ZERO) + { + return (~*last_result & *last_result - 1) >> *last_op_size & 1; + } + else + { + return *flags & FLAG_ZERO; + } +} + +int32_t getsf() +{ + if(*flags_changed & FLAG_SIGN) + { + return *last_result >> *last_op_size & 1; + } + else + { + return *flags & FLAG_SIGN; + } +} + +int32_t getof() +{ + if(*flags_changed & FLAG_OVERFLOW) + { + return ((*last_op1 ^ *last_add_result) & (*last_op2 ^ *last_add_result)) >> *last_op_size & 1; + } + else + { + return *flags & FLAG_OVERFLOW; + } +} + +int32_t test_o() { return getof(); } +int32_t test_b() { return getcf(); } +int32_t test_z() { return getzf(); } +int32_t test_s() { return getsf(); } +int32_t test_p() { return getpf(); } +int32_t test_be() { return getcf() || getzf(); } +int32_t test_l() { return !getsf() != !getof(); } +int32_t test_le() { return getzf() || !getsf() != !getof(); } + +void jmp_rel16(int32_t rel16) +{ + int32_t cs_offset = get_seg(CS); + + // limit ip to 16 bit + *instruction_pointer = cs_offset + ((*instruction_pointer - cs_offset + rel16) & 0xFFFF); +} + +void jmpcc8(bool condition) +{ + int32_t imm8 = read_imm8s(); + if(condition) + { + *instruction_pointer += imm8; + branch_taken(); + } + else + { + branch_not_taken(); + } +} + +void jmpcc16(bool condition) +{ + int32_t imm16 = read_imm16(); + + if(condition) + { + jmp_rel16(imm16); + branch_taken(); + } + else + { + branch_not_taken(); + } +} + +void jmpcc32(bool condition) +{ + int32_t op = read_imm32s(); + + if(condition) + { + *instruction_pointer += op; + branch_taken(); + } + else + { + branch_not_taken(); + } +} + +static int32_t get_stack_pointer(int32_t offset) +{ + if(*stack_size_32) + { + return get_seg(SS) + reg32s[ESP] + offset; + } + else + { + return get_seg(SS) + (reg16[SP] + offset & 0xFFFF); + } +} + +static void adjust_stack_reg(int32_t adjustment) +{ + if(*stack_size_32) + { + reg32s[ESP] += adjustment; + } + else + { + reg16[SP] += adjustment; + } +} + +void push16(int32_t imm16) +{ + int32_t sp = get_stack_pointer(-2); + + safe_write16(sp, imm16); + adjust_stack_reg(-2); +} + +void push32(int32_t imm32) +{ + int32_t sp = get_stack_pointer(-4); + + safe_write32(sp, imm32); + adjust_stack_reg(-4); +} + +void pusha16() +{ + uint16_t temp = reg16[SP]; + + // make sure we don't get a pagefault after having + // pushed several registers already + writable_or_pagefault(get_stack_pointer(-16), 16); + + push16(reg16[AX]); + push16(reg16[CX]); + push16(reg16[DX]); + push16(reg16[BX]); + push16(temp); + push16(reg16[BP]); + push16(reg16[SI]); + push16(reg16[DI]); +} + +void pusha32() +{ + int32_t temp = reg32s[ESP]; + + writable_or_pagefault(get_stack_pointer(-32), 32); + + push32(reg32s[EAX]); + push32(reg32s[ECX]); + push32(reg32s[EDX]); + push32(reg32s[EBX]); + push32(temp); + push32(reg32s[EBP]); + push32(reg32s[ESI]); + push32(reg32s[EDI]); +} + +int32_t pop32s() +{ + int32_t sp = get_stack_pointer(0); + int32_t result = safe_read32s(sp); + adjust_stack_reg(4); + return result; +} diff --git a/src/native/modrm.c b/src/native/modrm.c new file mode 100644 index 00000000..42794ac5 --- /dev/null +++ b/src/native/modrm.c @@ -0,0 +1,230 @@ +#include +#include +#include +#include + +#include + +#include "const.h" +#include "global_pointers.h" + +// XXX: Remove these declarations when they are implemented in C +static int32_t resolve_sib(bool); + + +#define ds get_seg_prefix_ds +#define ss get_seg_prefix_ss + +#define MODRM_ENTRY(n, offset)\ + case (n) | 0 << 3:\ + case (n) | 1 << 3:\ + case (n) | 2 << 3:\ + case (n) | 3 << 3:\ + case (n) | 4 << 3:\ + case (n) | 5 << 3:\ + case (n) | 6 << 3:\ + case (n) | 7 << 3:\ + return offset; + +#define MODRM_ENTRY16(row, seg, value)\ + MODRM_ENTRY(0x00 | row, seg(((value) & 0xFFFF)))\ + MODRM_ENTRY(0x40 | row, seg(((value) + read_imm8s() & 0xFFFF)))\ + MODRM_ENTRY(0x80 | row, seg(((value) + read_imm16() & 0xFFFF)))\ + + +static int32_t resolve_modrm16(int32_t modrm_byte) +{ + switch(modrm_byte) + { + MODRM_ENTRY16(0, ds, reg16[BX] + reg16[SI]) + MODRM_ENTRY16(1, ds, reg16[BX] + reg16[DI]) + MODRM_ENTRY16(2, ss, reg16[BP] + reg16[SI]) + MODRM_ENTRY16(3, ss, reg16[BP] + reg16[DI]) + MODRM_ENTRY16(4, ds, reg16[SI]) + MODRM_ENTRY16(5, ds, reg16[DI]) + + // special case + MODRM_ENTRY(0x00 | 6, ds(read_imm16())) + MODRM_ENTRY(0x40 | 6, ss(reg16[BP] + read_imm8s() & 0xFFFF)) + MODRM_ENTRY(0x80 | 6, ss(reg16[BP] + read_imm16() & 0xFFFF)) + + MODRM_ENTRY16(7, ds, reg16[BX]) + + default: + assert(false); + } + + return 0; +} + +#undef MODRM_ENTRY16 + +#define MODRM_ENTRY32(row, seg, value)\ + MODRM_ENTRY(0x00 | row, seg((value)))\ + MODRM_ENTRY(0x40 | row, seg((value) + read_imm8s()))\ + MODRM_ENTRY(0x80 | row, seg((value) + read_imm32s()))\ + +static int32_t resolve_modrm32(int32_t modrm_byte) +{ + switch(modrm_byte) + { + MODRM_ENTRY32(0, ds, reg32s[EAX]) + MODRM_ENTRY32(1, ds, reg32s[ECX]) + MODRM_ENTRY32(2, ds, reg32s[EDX]) + MODRM_ENTRY32(3, ds, reg32s[EBX]) + + // special cases + MODRM_ENTRY(0x00 | 4, resolve_sib(false)) + MODRM_ENTRY(0x40 | 4, resolve_sib(true) + read_imm8s()) + MODRM_ENTRY(0x80 | 4, resolve_sib(true) + read_imm32s()) + MODRM_ENTRY(0x00 | 5, ds(read_imm32s())) + MODRM_ENTRY(0x40 | 5, ss(reg32s[EBP] + read_imm8s())) + MODRM_ENTRY(0x80 | 5, ss(reg32s[EBP] + read_imm32s())) + + MODRM_ENTRY32(6, ds, reg32s[ESI]) + MODRM_ENTRY32(7, ds, reg32s[EDI]) + + default: + assert(false); + } + + return 0; +} + +#undef MODRM_ENTRY32 +#undef MODRM_ENTRY + + +#define SIB_ENTRY_LEVEL3(n, offset)\ + case n: return offset; + +#define SIB_ENTRY_LEVEL2(n, offset)\ + SIB_ENTRY_LEVEL3(n | 0, ds((offset) + reg32s[EAX]))\ + SIB_ENTRY_LEVEL3(n | 1, ds((offset) + reg32s[ECX]))\ + SIB_ENTRY_LEVEL3(n | 2, ds((offset) + reg32s[EDX]))\ + SIB_ENTRY_LEVEL3(n | 3, ds((offset) + reg32s[EBX]))\ + SIB_ENTRY_LEVEL3(n | 4, ss((offset) + reg32s[ESP]))\ + SIB_ENTRY_LEVEL3(n | 5, (mod ? ss((offset) + reg32s[EBP]) : ds((offset) + read_imm32s())))\ + SIB_ENTRY_LEVEL3(n | 6, ds((offset) + reg32s[ESI]))\ + SIB_ENTRY_LEVEL3(n | 7, ds((offset) + reg32s[EDI])) + +#define SIB_ENTRY_LEVEL1(n, reg1)\ + SIB_ENTRY_LEVEL2(0x00 | (n) << 3, (reg1))\ + SIB_ENTRY_LEVEL2(0x40 | (n) << 3, (reg1) << 1)\ + SIB_ENTRY_LEVEL2(0x80 | (n) << 3, (reg1) << 2)\ + SIB_ENTRY_LEVEL2(0xC0 | (n) << 3, (reg1) << 3) + +static int32_t resolve_sib_(bool mod) +{ + switch(read_imm8()) + { + SIB_ENTRY_LEVEL1(0, reg32s[EAX]); + SIB_ENTRY_LEVEL1(1, reg32s[ECX]); + SIB_ENTRY_LEVEL1(2, reg32s[EDX]); + SIB_ENTRY_LEVEL1(3, reg32s[EBX]); + SIB_ENTRY_LEVEL1(4, 0 ); + SIB_ENTRY_LEVEL1(5, reg32s[EBP]); + SIB_ENTRY_LEVEL1(6, reg32s[ESI]); + SIB_ENTRY_LEVEL1(7, reg32s[EDI]); + + default: + assert(false); + } + + return 0; +} + +#undef SIB_ENTRY_LEVEL3 +#undef SIB_ENTRY_LEVEL2 +#undef SIB_ENTRY_LEVEL1 + +#undef ds +#undef ss + + +static int32_t resolve_sib(bool mod) +{ + uint8_t sib_byte = read_imm8(); + uint8_t r = sib_byte & 7; + uint8_t m = sib_byte >> 3 & 7; + + int32_t base; + int32_t seg; + + if(r == 4) + { + base = reg32s[ESP]; + seg = SS; + } + else if(r == 5) + { + if(mod) + { + base = reg32s[EBP]; + seg = SS; + } + else + { + base = read_imm32s(); + seg = DS; + } + } + else + { + base = reg32s[r]; + seg = DS; + } + + int32_t offset; + if(m == 4) + { + offset = 0; + } + else + { + uint8_t s = sib_byte >> 6 & 3; + offset = reg32s[m] << s; + } + + return get_seg_prefix(seg) + base + offset; +} + +static int32_t resolve_modrm32_(int32_t modrm_byte) +{ + uint8_t r = modrm_byte & 7; + assert(modrm_byte < 0xC0); + + if(r == 4) + { + if(modrm_byte < 0x40) + { + return resolve_sib(false); + } + else + { + return resolve_sib(true) + (modrm_byte < 0x80 ? read_imm8s() : read_imm32s()); + } + } + else if(r == 5) + { + if(modrm_byte < 0x40) + { + return get_seg_prefix_ds(read_imm32s()); + } + else + { + return get_seg_prefix_ss(reg32s[EBP] + (modrm_byte < 0x80 ? read_imm8s() : read_imm32s())); + } + } + else + { + if(modrm_byte < 0x40) + { + return get_seg_prefix_ds(reg32s[r]); + } + else + { + return get_seg_prefix_ds(reg32s[r] + (modrm_byte < 0x80 ? read_imm8s() : read_imm32s())); + } + } +} diff --git a/src/pci.js b/src/pci.js index c79405fa..dca6e2e2 100644 --- a/src/pci.js +++ b/src/pci.js @@ -446,6 +446,11 @@ PCI.prototype.pci_write32 = function(address, written) space[addr >> 2] = 0; } } + else if(addr === 0x04) + { + dbg_log("PCI write dev=" + h(bdf >> 3, 2) + " (" + device.name + ") addr=" + h(addr, 4) + + " value=" + h(written >>> 0, 8), LOG_PCI); + } else { dbg_log("PCI write dev=" + h(bdf >> 3, 2) + " (" + device.name + ") addr=" + h(addr, 4) + diff --git a/src/string.js b/src/string.js index cf1b934e..b38a20ce 100644 --- a/src/string.js +++ b/src/string.js @@ -46,9 +46,9 @@ CPU.prototype.movsb = function() var cpu = this; var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -1 : 1; + var size = cpu.flags[0] & flag_direction ? -1 : 1; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -57,7 +57,7 @@ CPU.prototype.movsb = function() var cycle_counter = MAX_COUNT_PER_CYCLE; var phys_src = cpu.translate_address_read(src); var phys_dest = cpu.translate_address_write(dest); - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count2(size, src, dest); } @@ -73,10 +73,10 @@ CPU.prototype.movsb = function() cpu.add_reg_asize(reg_edi, diff); cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -93,9 +93,9 @@ CPU.prototype.movsw = function() var cpu = this; var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -2 : 2; + var size = cpu.flags[0] & flag_direction ? -2 : 2; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -107,7 +107,7 @@ CPU.prototype.movsw = function() var single_size = size < 0 ? -1 : 1; var phys_src = cpu.translate_address_read(src) >>> 1; var phys_dest = cpu.translate_address_write(dest) >>> 1; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count2(size, src, dest); } @@ -123,7 +123,7 @@ CPU.prototype.movsw = function() cpu.add_reg_asize(reg_edi, diff); cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -140,7 +140,7 @@ CPU.prototype.movsw = function() } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -156,7 +156,7 @@ CPU.prototype.movsd = function() { var cpu = this; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { // often used by memcpy, well worth optimizing // using cpu.mem32s.set @@ -173,16 +173,16 @@ CPU.prototype.movsd = function() // must be page-aligned if cpu.paging is enabled // and dword-aligned in general - var align_mask = cpu.paging ? 0xFFF : 3; + var align_mask = cpu.paging[0] ? 0xFFF : 3; if((dest & align_mask) === 0 && (src & align_mask) === 0 && // If df is set, alignment works a different // This should be unlikely - (cpu.flags & flag_direction) === 0) + (cpu.flags[0] & flag_direction) === 0) { var cont = false; - if(cpu.paging) + if(cpu.paging[0]) { src = cpu.translate_address_read(src); dest = cpu.translate_address_write(dest); @@ -208,7 +208,7 @@ CPU.prototype.movsd = function() if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } return; @@ -218,9 +218,9 @@ CPU.prototype.movsd = function() var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -4 : 4; + var size = cpu.flags[0] & flag_direction ? -4 : 4; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -232,7 +232,7 @@ CPU.prototype.movsd = function() var single_size = size < 0 ? -1 : 1; var phys_src = cpu.translate_address_read(src) >>> 2; var phys_dest = cpu.translate_address_write(dest) >>> 2; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count2(size, src, dest); } @@ -248,7 +248,7 @@ CPU.prototype.movsd = function() cpu.add_reg_asize(reg_edi, diff); cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -265,7 +265,7 @@ CPU.prototype.movsd = function() } if(cont) { - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; } } else @@ -282,19 +282,19 @@ function cmpsb(cpu) var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; var data_src, data_dest; - var size = cpu.flags & flag_direction ? -1 : 1; + var size = cpu.flags[0] & flag_direction ? -1 : 1; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; var cont = false; var start_count = count; - var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ; + var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ; var cycle_counter = MAX_COUNT_PER_CYCLE; var phys_src = cpu.translate_address_read(src); var phys_dest = cpu.translate_address_read(dest); - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count2(size, src, dest); } @@ -311,10 +311,10 @@ function cmpsb(cpu) cpu.add_reg_asize(reg_edi, diff); cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -334,22 +334,22 @@ function cmpsw(cpu) var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; var data_src, data_dest; - var size = cpu.flags & flag_direction ? -2 : 2; + var size = cpu.flags[0] & flag_direction ? -2 : 2; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; var cont = false; var start_count = count; - var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ; + var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ; var cycle_counter = MAX_COUNT_PER_CYCLE; if(!(dest & 1) && !(src & 1)) { var single_size = size < 0 ? -1 : 1; var phys_src = cpu.translate_address_read(src) >>> 1; var phys_dest = cpu.translate_address_read(dest) >>> 1; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count2(size, src, dest); } @@ -366,7 +366,7 @@ function cmpsw(cpu) cpu.add_reg_asize(reg_edi, diff); cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -384,7 +384,7 @@ function cmpsw(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -404,22 +404,22 @@ function cmpsd(cpu) var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; var data_src, data_dest; - var size = cpu.flags & flag_direction ? -4 : 4; + var size = cpu.flags[0] & flag_direction ? -4 : 4; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; var cont = false; var start_count = count; - var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ; + var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ; var cycle_counter = MAX_COUNT_PER_CYCLE; if(!(dest & 3) && !(src & 3)) { var single_size = size < 0 ? -1 : 1; var phys_src = cpu.translate_address_read(src) >>> 2; var phys_dest = cpu.translate_address_read(dest) >>> 2; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count2(size, src, dest); } @@ -436,7 +436,7 @@ function cmpsd(cpu) cpu.add_reg_asize(reg_edi, diff); cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -454,7 +454,7 @@ function cmpsd(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -473,9 +473,9 @@ function stosb(cpu) { var data = cpu.reg8[reg_al]; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -1 : 1; + var size = cpu.flags[0] & flag_direction ? -1 : 1; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -483,7 +483,7 @@ function stosb(cpu) var start_count = count; var cycle_counter = MAX_COUNT_PER_CYCLE; var phys_dest = cpu.translate_address_write(dest); - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -497,10 +497,10 @@ function stosb(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -515,9 +515,9 @@ function stosw(cpu) { var data = cpu.reg16[reg_ax]; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -2 : 2; + var size = cpu.flags[0] & flag_direction ? -2 : 2; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -528,7 +528,7 @@ function stosw(cpu) { var single_size = size < 0 ? -1 : 1; var phys_dest = cpu.translate_address_write(dest) >>> 1; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -542,7 +542,7 @@ function stosw(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -557,7 +557,7 @@ function stosw(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -572,9 +572,9 @@ function stosd(cpu) { var data = cpu.reg32s[reg_eax]; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -4 : 4; + var size = cpu.flags[0] & flag_direction ? -4 : 4; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -585,7 +585,7 @@ function stosd(cpu) { var single_size = size < 0 ? -1 : 1; var phys_dest = cpu.translate_address_write(dest) >>> 2; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -599,7 +599,7 @@ function stosd(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -614,7 +614,7 @@ function stosd(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -628,9 +628,9 @@ function stosd(cpu) function lodsb(cpu) { var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; - var size = cpu.flags & flag_direction ? -1 : 1; + var size = cpu.flags[0] & flag_direction ? -1 : 1; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -638,7 +638,7 @@ function lodsb(cpu) var start_count = count; var cycle_counter = MAX_COUNT_PER_CYCLE; var phys_src = cpu.translate_address_read(src); - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, src); } @@ -652,10 +652,10 @@ function lodsb(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -669,9 +669,9 @@ function lodsb(cpu) function lodsw(cpu) { var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; - var size = cpu.flags & flag_direction ? -2 : 2; + var size = cpu.flags[0] & flag_direction ? -2 : 2; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -687,7 +687,7 @@ function lodsw(cpu) while(cont && cycle_counter--); if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -701,9 +701,9 @@ function lodsw(cpu) function lodsd(cpu) { var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; - var size = cpu.flags & flag_direction ? -4 : 4; + var size = cpu.flags[0] & flag_direction ? -4 : 4; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -719,7 +719,7 @@ function lodsd(cpu) while(cont && cycle_counter--); if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -733,20 +733,20 @@ function lodsd(cpu) function scasb(cpu) { var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -1 : 1; + var size = cpu.flags[0] & flag_direction ? -1 : 1; var data_dest; var data_src = cpu.reg8[reg_al]; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; var cont = false; var start_count = count; - var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ; + var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ; var cycle_counter = MAX_COUNT_PER_CYCLE; var phys_dest = cpu.translate_address_read(dest); - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -760,10 +760,10 @@ function scasb(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -779,23 +779,23 @@ function scasb(cpu) function scasw(cpu) { var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -2 : 2; + var size = cpu.flags[0] & flag_direction ? -2 : 2; var data_dest; var data_src = cpu.reg16[reg_al]; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; var cont = false; var start_count = count; - var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ; + var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ; var cycle_counter = MAX_COUNT_PER_CYCLE; if(!(dest & 1)) { var single_size = size < 0 ? -1 : 1; var phys_dest = cpu.translate_address_read(dest) >>> 1; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -809,7 +809,7 @@ function scasw(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -824,7 +824,7 @@ function scasw(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -840,23 +840,23 @@ function scasw(cpu) function scasd(cpu) { var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -4 : 4; + var size = cpu.flags[0] & flag_direction ? -4 : 4; var data_dest; var data_src = cpu.reg32s[reg_eax]; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; var cont = false; var start_count = count; - var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ; + var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ; var cycle_counter = MAX_COUNT_PER_CYCLE; if(!(dest & 3)) { var single_size = size < 0 ? -1 : 1; var phys_dest = cpu.translate_address_read(dest) >>> 2; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -870,7 +870,7 @@ function scasd(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -885,7 +885,7 @@ function scasd(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -904,9 +904,9 @@ function insb(cpu) cpu.test_privileges_for_io(port, 1); var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -1 : 1; + var size = cpu.flags[0] & flag_direction ? -1 : 1; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -914,7 +914,7 @@ function insb(cpu) var start_count = count; var cycle_counter = MAX_COUNT_PER_CYCLE; var phys_dest = cpu.translate_address_write(dest); - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -928,10 +928,10 @@ function insb(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -949,9 +949,9 @@ function insw(cpu) cpu.test_privileges_for_io(port, 2); var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -2 : 2; + var size = cpu.flags[0] & flag_direction ? -2 : 2; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -962,7 +962,7 @@ function insw(cpu) { var single_size = size < 0 ? -1 : 1; var phys_dest = cpu.translate_address_write(dest) >>> 1; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -976,7 +976,7 @@ function insw(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -991,7 +991,7 @@ function insw(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -1009,9 +1009,9 @@ function insd(cpu) cpu.test_privileges_for_io(port, 4); var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -4 : 4; + var size = cpu.flags[0] & flag_direction ? -4 : 4; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -1022,7 +1022,7 @@ function insd(cpu) { var single_size = size < 0 ? -1 : 1; var phys_dest = cpu.translate_address_write(dest) >>> 2; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -1036,7 +1036,7 @@ function insd(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -1051,7 +1051,7 @@ function insd(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -1069,9 +1069,9 @@ function outsb(cpu) cpu.test_privileges_for_io(port, 1); var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; - var size = cpu.flags & flag_direction ? -1 : 1; + var size = cpu.flags[0] & flag_direction ? -1 : 1; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -1079,7 +1079,7 @@ function outsb(cpu) var start_count = count; var cycle_counter = MAX_COUNT_PER_CYCLE; var phys_src = cpu.translate_address_read(src); - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, src); } @@ -1093,10 +1093,10 @@ function outsb(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -1113,9 +1113,9 @@ function outsw(cpu) cpu.test_privileges_for_io(port, 2); var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; - var size = cpu.flags & flag_direction ? -2 : 2; + var size = cpu.flags[0] & flag_direction ? -2 : 2; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -1126,7 +1126,7 @@ function outsw(cpu) { var single_size = size < 0 ? -1 : 1; var phys_src = cpu.translate_address_read(src) >>> 1; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, src); } @@ -1140,7 +1140,7 @@ function outsw(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -1155,7 +1155,7 @@ function outsw(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -1172,9 +1172,9 @@ function outsd(cpu) cpu.test_privileges_for_io(port, 4); var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; - var size = cpu.flags & flag_direction ? -4 : 4; + var size = cpu.flags[0] & flag_direction ? -4 : 4; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -1185,7 +1185,7 @@ function outsd(cpu) { var single_size = size < 0 ? -1 : 1; var phys_src = cpu.translate_address_read(src) >>> 2; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, src); } @@ -1199,7 +1199,7 @@ function outsd(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -1214,7 +1214,7 @@ function outsd(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -1224,3 +1224,27 @@ function outsd(cpu) } cpu.diverged(); } + +CPU.prototype.stosb = function() { stosb(this); } +CPU.prototype.stosw = function() { stosw(this); } +CPU.prototype.stosd = function() { stosd(this); } + +CPU.prototype.lodsb = function() { lodsb(this); } +CPU.prototype.lodsw = function() { lodsw(this); } +CPU.prototype.lodsd = function() { lodsd(this); } + +CPU.prototype.cmpsb = function() { cmpsb(this); } +CPU.prototype.cmpsw = function() { cmpsw(this); } +CPU.prototype.cmpsd = function() { cmpsd(this); } + +CPU.prototype.scasb = function() { scasb(this); } +CPU.prototype.scasw = function() { scasw(this); } +CPU.prototype.scasd = function() { scasd(this); } + +CPU.prototype.insb = function() { insb(this); } +CPU.prototype.insw = function() { insw(this); } +CPU.prototype.insd = function() { insd(this); } + +CPU.prototype.outsb = function() { outsb(this); } +CPU.prototype.outsw = function() { outsw(this); } +CPU.prototype.outsd = function() { outsd(this); } diff --git a/src/virtio.js b/src/virtio.js index ef3cb202..cc63e9db 100644 --- a/src/virtio.js +++ b/src/virtio.js @@ -11,6 +11,8 @@ function VirtIO(cpu, bus, filesystem) { // http://ozlabs.org/~rusty/virtio-spec/virtio-0.9.5.pdf + this.irq = 10; + this.pci_space = [ 0xf4, 0x1a, 0x09, 0x10, 0x07, 0x05, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa8, 0x00, 0x00, 0x00, 0x10, 0xbf, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/tests/kvm-unit-tests/run.js b/tests/kvm-unit-tests/run.js index 9ac5b93f..7f9e27b5 100755 --- a/tests/kvm-unit-tests/run.js +++ b/tests/kvm-unit-tests/run.js @@ -33,7 +33,7 @@ var emulator = new V86({ emulator.bus.register("emulator-started", function() { - emulator.v86.cpu.io.register_write_consecutive(0xF4, this, + emulator.v86.cpu.io.register_write_consecutive(0xF4, {}, function(value) { console.log("Test exited with code " + value);