From 0edc821618e7d5da477745644d23af6c01e37bc0 Mon Sep 17 00:00:00 2001 From: Fabian Date: Thu, 31 Dec 2020 19:14:30 -0600 Subject: [PATCH] Jit DIV/IDIV --- gen/x86_table.js | 4 +- src/rust/codegen.rs | 11 +++ src/rust/cpu2/arith.rs | 151 +++++++++++++++++------------------ src/rust/cpu2/cpu.rs | 1 + src/rust/jit_instructions.rs | 84 +++++++++++++++++++ 5 files changed, 173 insertions(+), 78 deletions(-) diff --git a/gen/x86_table.js b/gen/x86_table.js index f9ad930a..a626e24a 100644 --- a/gen/x86_table.js +++ b/gen/x86_table.js @@ -387,8 +387,8 @@ const encodings = [ { opcode: 0xF7, os: 1, e: 1, fixed_g: 3, custom: 1 }, { opcode: 0xF7, os: 1, e: 1, fixed_g: 4, mask_flags: zf | af, custom: 1 }, { opcode: 0xF7, os: 1, e: 1, fixed_g: 5, mask_flags: zf | af, custom: 1 }, - { opcode: 0xF7, os: 1, e: 1, fixed_g: 6, block_boundary: 1, }, // div/idiv: Not a block boundary, but doesn't use control flow exceptions - { opcode: 0xF7, os: 1, e: 1, fixed_g: 7, block_boundary: 1, }, + { opcode: 0xF7, os: 1, e: 1, fixed_g: 6, custom: 1 }, + { opcode: 0xF7, os: 1, e: 1, fixed_g: 7, custom: 1 }, { opcode: 0xF8, }, { opcode: 0xF9, }, diff --git a/src/rust/codegen.rs b/src/rust/codegen.rs index 06f51b55..c2a544e8 100644 --- a/src/rust/codegen.rs +++ b/src/rust/codegen.rs @@ -1585,6 +1585,17 @@ pub fn gen_fpu_load_m64(ctx: &mut JitContext, modrm_byte: u8) { ctx.builder.reinterpret_i64_as_f64(); } +pub fn gen_trigger_de(ctx: &mut JitContext) { + gen_move_registers_from_locals_to_memory(ctx); + gen_set_previous_eip_offset_from_eip_with_low_bits( + ctx.builder, + ctx.start_of_current_instruction as i32 & 0xFFF, + ); + gen_fn0_const(ctx.builder, "trigger_de"); + gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction); + ctx.builder.return_(); +} + pub fn gen_trigger_ud(ctx: &mut JitContext) { gen_move_registers_from_locals_to_memory(ctx); gen_set_previous_eip_offset_from_eip_with_low_bits( diff --git a/src/rust/cpu2/arith.rs b/src/rust/cpu2/arith.rs index 3e32346c..33fd6acd 100644 --- a/src/rust/cpu2/arith.rs +++ b/src/rust/cpu2/arith.rs @@ -694,97 +694,94 @@ pub unsafe fn idiv8(source_operand: i32) { return; }; } + #[no_mangle] +pub unsafe fn div16_without_fault(source_operand: u32) -> bool { + if source_operand == 0 { + return false; + } + let target_operand = + (*reg16.offset(AX as isize) as i32 | (*reg16.offset(DX as isize) as i32) << 16) as u32; + let result = target_operand.wrapping_div(source_operand); + if result >= 0x10000 { + return false; + } + *reg16.offset(AX as isize) = result as u16; + *reg16.offset(DX as isize) = target_operand.wrapping_rem(source_operand) as u16; + return true; +} pub unsafe fn div16(source_operand: u32) { - if source_operand == 0 { - trigger_de(); - return; + if !div16_without_fault(source_operand) { + trigger_de() } - else { - let target_operand = - (*reg16.offset(AX as isize) as i32 | (*reg16.offset(DX as isize) as i32) << 16) as u32; - let result = target_operand.wrapping_div(source_operand); - if result >= 0x10000 { - trigger_de(); - } - else { - *reg16.offset(AX as isize) = result as u16; - *reg16.offset(DX as isize) = target_operand.wrapping_rem(source_operand) as u16 - } - return; - }; } #[no_mangle] +pub unsafe fn idiv16_without_fault(source_operand: i32) -> bool { + if source_operand == 0 { + return false; + } + let target_operand = + *reg16.offset(AX as isize) as i32 | (*reg16.offset(DX as isize) as i32) << 16; + let result = target_operand / source_operand; + if result >= 32768 || result <= -32769 { + return false; + } + *reg16.offset(AX as isize) = result as u16; + *reg16.offset(DX as isize) = (target_operand % source_operand) as u16; + return true; +} pub unsafe fn idiv16(source_operand: i32) { - if source_operand == 0 { - trigger_de(); - return; + if !idiv16_without_fault(source_operand) { + trigger_de() } - else { - let target_operand = - *reg16.offset(AX as isize) as i32 | (*reg16.offset(DX as isize) as i32) << 16; - let result = target_operand / source_operand; - if result >= 32768 || result <= -32769 { - trigger_de(); - } - else { - *reg16.offset(AX as isize) = result as u16; - *reg16.offset(DX as isize) = (target_operand % source_operand) as u16 - } - return; - }; } + #[no_mangle] +pub unsafe fn div32_without_fault(source_operand: u32) -> bool { + if source_operand == 0 { + return false; + } + let target_low = *reg32.offset(EAX as isize) as u32; + let target_high = *reg32.offset(EDX as isize) as u32; + let target_operand = (target_high as u64) << 32 | target_low as u64; + let result = target_operand.wrapping_div(source_operand as u64); + if result > 0xFFFFFFFF { + return false; + } + let mod_0 = target_operand.wrapping_rem(source_operand as u64) as i32; + *reg32.offset(EAX as isize) = result as i32; + *reg32.offset(EDX as isize) = mod_0; + return true; +} pub unsafe fn div32(source_operand: u32) { - if source_operand == 0 { - trigger_de(); - return; + if !div32_without_fault(source_operand) { + trigger_de() } - else { - let target_low = *reg32.offset(EAX as isize) as u32; - let target_high = *reg32.offset(EDX as isize) as u32; - let target_operand = (target_high as u64) << 32 | target_low as u64; - let result = target_operand.wrapping_div(source_operand as u64); - if result > 0xFFFFFFFF { - trigger_de(); - return; - } - else { - let mod_0 = target_operand.wrapping_rem(source_operand as u64) as i32; - *reg32.offset(EAX as isize) = result as i32; - *reg32.offset(EDX as isize) = mod_0; - return; - } - }; } #[no_mangle] -pub unsafe fn idiv32(source_operand: i32) { +pub unsafe fn idiv32_without_fault(source_operand: i32) -> bool { if source_operand == 0 { - trigger_de(); - return; + return false; + } + let target_low = *reg32.offset(EAX as isize) as u32; + let target_high = *reg32.offset(EDX as isize) as u32; + let target_operand = ((target_high as u64) << 32 | target_low as u64) as i64; + if source_operand == -1 && target_operand == -0x80000000_00000000 as i64 { + return false; + } + let result = target_operand / source_operand as i64; + if result < -0x80000000 || result > 0x7FFFFFFF { + return false; + } + let mod_0 = (target_operand % source_operand as i64) as i32; + *reg32.offset(EAX as isize) = result as i32; + *reg32.offset(EDX as isize) = mod_0; + return true; +} +pub unsafe fn idiv32(source_operand: i32) { + if !idiv32_without_fault(source_operand) { + trigger_de() } - else { - let target_low = *reg32.offset(EAX as isize) as u32; - let target_high = *reg32.offset(EDX as isize) as u32; - let target_operand = ((target_high as u64) << 32 | target_low as u64) as i64; - if source_operand == -1 && target_operand == -0x80000000_00000000 as i64 { - trigger_de(); - return; - } - else { - let result = target_operand / source_operand as i64; - if result < -0x80000000 || result > 0x7FFFFFFF { - trigger_de(); - return; - } - else { - let mod_0 = (target_operand % source_operand as i64) as i32; - *reg32.offset(EAX as isize) = result as i32; - *reg32.offset(EDX as isize) = mod_0; - return; - } - } - }; } #[no_mangle] @@ -1056,6 +1053,7 @@ pub unsafe fn btr_reg(bit_base: i32, bit_offset: i32) -> i32 { *flags_changed &= !1; return bit_base & !(1 << bit_offset); } + #[no_mangle] pub unsafe fn bt_mem(virt_addr: i32, mut bit_offset: i32) { let bit_base = return_on_pagefault!(safe_read8(virt_addr + (bit_offset >> 3))); @@ -1090,6 +1088,7 @@ pub unsafe fn bts_mem(virt_addr: i32, mut bit_offset: i32) { *flags_changed &= !1; write8(phys_addr, bit_base | 1 << bit_offset); } + #[no_mangle] pub unsafe fn bsf16(old: i32, bit_base: i32) -> i32 { *flags_changed = FLAGS_ALL & !FLAG_ZERO & !FLAG_CARRY; diff --git a/src/rust/cpu2/cpu.rs b/src/rust/cpu2/cpu.rs index 0d484b24..c5fc90af 100644 --- a/src/rust/cpu2/cpu.rs +++ b/src/rust/cpu2/cpu.rs @@ -2053,6 +2053,7 @@ pub unsafe fn do_many_cycles_native() { } } +#[no_mangle] pub unsafe fn trigger_de() { dbg_log!("#de"); *instruction_pointer = *previous_ip; diff --git a/src/rust/jit_instructions.rs b/src/rust/jit_instructions.rs index 1e7d06d7..03556be4 100644 --- a/src/rust/jit_instructions.rs +++ b/src/rust/jit_instructions.rs @@ -3069,6 +3069,90 @@ pub fn instr32_F7_5_reg_jit(ctx: &mut JitContext, r: u32) { codegen::gen_move_registers_from_memory_to_locals(ctx); } +pub fn instr16_F7_6_mem_jit(ctx: &mut JitContext, modrm_byte: u8) { + codegen::gen_modrm_resolve_safe_read16(ctx, modrm_byte); + codegen::gen_move_registers_from_locals_to_memory(ctx); + codegen::gen_call_fn1_ret(ctx.builder, "div16_without_fault"); + codegen::gen_move_registers_from_memory_to_locals(ctx); + ctx.builder.eqz_i32(); + ctx.builder.if_void(); + codegen::gen_trigger_de(ctx); + ctx.builder.block_end(); +} +pub fn instr16_F7_6_reg_jit(ctx: &mut JitContext, r: u32) { + codegen::gen_get_reg16(ctx, r); + codegen::gen_move_registers_from_locals_to_memory(ctx); + codegen::gen_call_fn1_ret(ctx.builder, "div16_without_fault"); + codegen::gen_move_registers_from_memory_to_locals(ctx); + ctx.builder.eqz_i32(); + ctx.builder.if_void(); + codegen::gen_trigger_de(ctx); + ctx.builder.block_end(); +} +pub fn instr32_F7_6_mem_jit(ctx: &mut JitContext, modrm_byte: u8) { + codegen::gen_modrm_resolve_safe_read32(ctx, modrm_byte); + codegen::gen_move_registers_from_locals_to_memory(ctx); + codegen::gen_call_fn1_ret(ctx.builder, "div32_without_fault"); + codegen::gen_move_registers_from_memory_to_locals(ctx); + ctx.builder.eqz_i32(); + ctx.builder.if_void(); + codegen::gen_trigger_de(ctx); + ctx.builder.block_end(); +} +pub fn instr32_F7_6_reg_jit(ctx: &mut JitContext, r: u32) { + codegen::gen_get_reg32(ctx, r); + codegen::gen_move_registers_from_locals_to_memory(ctx); + codegen::gen_call_fn1_ret(ctx.builder, "div32_without_fault"); + codegen::gen_move_registers_from_memory_to_locals(ctx); + ctx.builder.eqz_i32(); + ctx.builder.if_void(); + codegen::gen_trigger_de(ctx); + ctx.builder.block_end(); +} + +pub fn instr16_F7_7_mem_jit(ctx: &mut JitContext, modrm_byte: u8) { + codegen::gen_modrm_resolve_safe_read16(ctx, modrm_byte); + codegen::sign_extend_i16(ctx.builder); + codegen::gen_move_registers_from_locals_to_memory(ctx); + codegen::gen_call_fn1_ret(ctx.builder, "idiv16_without_fault"); + codegen::gen_move_registers_from_memory_to_locals(ctx); + ctx.builder.eqz_i32(); + ctx.builder.if_void(); + codegen::gen_trigger_de(ctx); + ctx.builder.block_end(); +} +pub fn instr16_F7_7_reg_jit(ctx: &mut JitContext, r: u32) { + codegen::gen_get_reg16(ctx, r); + codegen::sign_extend_i16(ctx.builder); + codegen::gen_move_registers_from_locals_to_memory(ctx); + codegen::gen_call_fn1_ret(ctx.builder, "idiv16_without_fault"); + codegen::gen_move_registers_from_memory_to_locals(ctx); + ctx.builder.eqz_i32(); + ctx.builder.if_void(); + codegen::gen_trigger_de(ctx); + ctx.builder.block_end(); +} +pub fn instr32_F7_7_mem_jit(ctx: &mut JitContext, modrm_byte: u8) { + codegen::gen_modrm_resolve_safe_read32(ctx, modrm_byte); + codegen::gen_move_registers_from_locals_to_memory(ctx); + codegen::gen_call_fn1_ret(ctx.builder, "idiv32_without_fault"); + codegen::gen_move_registers_from_memory_to_locals(ctx); + ctx.builder.eqz_i32(); + ctx.builder.if_void(); + codegen::gen_trigger_de(ctx); + ctx.builder.block_end(); +} +pub fn instr32_F7_7_reg_jit(ctx: &mut JitContext, r: u32) { + codegen::gen_get_reg32(ctx, r); + codegen::gen_move_registers_from_locals_to_memory(ctx); + codegen::gen_call_fn1_ret(ctx.builder, "idiv32_without_fault"); + codegen::gen_move_registers_from_memory_to_locals(ctx); + ctx.builder.eqz_i32(); + ctx.builder.if_void(); + codegen::gen_trigger_de(ctx); + ctx.builder.block_end(); +} + pub fn instr_FA_jit(ctx: &mut JitContext) { codegen::gen_fn0_const_ret(ctx.builder, "instr_FA_without_fault"); ctx.builder.eqz_i32();