Handle pagefaults without JS exceptions
This commit makes the return type of most basic memory access primitives Result, where the Err(()) case means a page fault happened, the instruction should be aborted and execution should continue at the page fault handler. The following primites have a Result return type: safe_{read,write}*, translate_address_*, read_imm*, writable_or_pagefault, get_phys_eip, modrm_resolve, push*, pop*. Any instruction needs to handle the page fault cases and abort execution appropriately. The return_on_pagefault! macro has been provided to get the same behaviour as the previously used JS exceptions (local to the function). Calls from JavaScript abort on a pagefault, except for writable_or_pagefault, which returns a boolean. JS needs to check before calling any function that may pagefault. This commit does not yet pervasively apply return_on_pagefault!, this will be added in the next commit. Jitted code does not yet properly handle the new form of page faults, this will be added in a later commit.
This commit is contained in:
parent
11ee22176d
commit
a88420910d
|
@ -26,6 +26,11 @@ console.assert(
|
|||
|
||||
gen_table();
|
||||
|
||||
function wrap_imm_call(imm)
|
||||
{
|
||||
return `match ${imm} { Ok(o) => o, Err(()) => return }`;
|
||||
}
|
||||
|
||||
function gen_read_imm_call(op, size_variant)
|
||||
{
|
||||
let size = (op.os || op.opcode % 2 === 1) ? size_variant : 8;
|
||||
|
@ -34,18 +39,18 @@ function gen_read_imm_call(op, size_variant)
|
|||
{
|
||||
if(op.imm8)
|
||||
{
|
||||
return "read_imm8()";
|
||||
return wrap_imm_call("read_imm8()");
|
||||
}
|
||||
else if(op.imm8s)
|
||||
{
|
||||
return "read_imm8s()";
|
||||
return wrap_imm_call("read_imm8s()");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(op.immaddr)
|
||||
{
|
||||
// immaddr: depends on address size
|
||||
return "read_moffs()";
|
||||
return wrap_imm_call("read_moffs()");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -53,12 +58,12 @@ function gen_read_imm_call(op, size_variant)
|
|||
|
||||
if(op.imm1632 && size === 16 || op.imm16)
|
||||
{
|
||||
return "read_imm16()";
|
||||
return wrap_imm_call("read_imm16()");
|
||||
}
|
||||
else
|
||||
{
|
||||
console.assert(op.imm1632 && size === 32 || op.imm32);
|
||||
return "read_imm32s()";
|
||||
return wrap_imm_call("read_imm32s()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +129,7 @@ function gen_instruction_body(encodings, size)
|
|||
|
||||
if(encoding.e)
|
||||
{
|
||||
code.push("let modrm_byte = read_imm8();");
|
||||
code.push(`let modrm_byte = ${wrap_imm_call("read_imm8()")};`);
|
||||
}
|
||||
|
||||
if(has_66.length || has_F2.length || has_F3.length)
|
||||
|
@ -246,19 +251,11 @@ function gen_instruction_body_after_fixed_g(encoding, size)
|
|||
|
||||
const instruction_name = make_instruction_name(encoding, size);
|
||||
|
||||
let modrm_resolve_prefix = undefined;
|
||||
|
||||
if(encoding.requires_prefix_call)
|
||||
{
|
||||
modrm_resolve_prefix = gen_call(instruction_name + "_mem_pre");
|
||||
}
|
||||
|
||||
const imm_read = gen_read_imm_call(encoding, size);
|
||||
|
||||
if(encoding.ignore_mod)
|
||||
{
|
||||
console.assert(!imm_read, "Unexpected instruction (ignore mod with immediate value)");
|
||||
console.assert(!modrm_resolve_prefix, "Unexpected instruction (ignore mod with prefix call)");
|
||||
|
||||
// Has modrm byte, but the 2 mod bits are ignored and both
|
||||
// operands are always registers (0f20-0f24)
|
||||
|
@ -271,7 +268,18 @@ function gen_instruction_body_after_fixed_g(encoding, size)
|
|||
}
|
||||
else
|
||||
{
|
||||
const mem_args = ["modrm_resolve(modrm_byte)"];
|
||||
let mem_args;
|
||||
|
||||
if(encoding.custom_modrm_resolve)
|
||||
{
|
||||
// requires special handling around modrm_resolve
|
||||
mem_args = ["modrm_byte"];
|
||||
}
|
||||
else
|
||||
{
|
||||
mem_args = ["match modrm_resolve(modrm_byte) { Ok(a) => a, Err(()) => return }"];
|
||||
}
|
||||
|
||||
const reg_args = ["modrm_byte & 7"];
|
||||
|
||||
if(encoding.fixed_g === undefined)
|
||||
|
@ -294,7 +302,6 @@ function gen_instruction_body_after_fixed_g(encoding, size)
|
|||
{
|
||||
condition: "modrm_byte < 0xC0",
|
||||
body: [].concat(
|
||||
modrm_resolve_prefix ? [modrm_resolve_prefix] : [],
|
||||
gen_call(`${instruction_name}_mem`, mem_args)
|
||||
),
|
||||
}
|
||||
|
@ -319,12 +326,12 @@ function gen_instruction_body_after_fixed_g(encoding, size)
|
|||
if(encoding.extra_imm16)
|
||||
{
|
||||
console.assert(imm_read);
|
||||
args.push("read_imm16()");
|
||||
args.push(wrap_imm_call("read_imm16()"));
|
||||
}
|
||||
else if(encoding.extra_imm8)
|
||||
{
|
||||
console.assert(imm_read);
|
||||
args.push("read_imm8()");
|
||||
args.push(wrap_imm_call("read_imm8()"));
|
||||
}
|
||||
|
||||
return [].concat(
|
||||
|
@ -397,11 +404,12 @@ function gen_table()
|
|||
if(to_generate.interpreter)
|
||||
{
|
||||
const code = [
|
||||
"#![cfg_attr(rustfmt, rustfmt_skip)]",
|
||||
|
||||
"use cpu2::cpu::*;",
|
||||
"use cpu2::instructions::*;",
|
||||
"use cpu2::global_pointers::*;",
|
||||
|
||||
"#[cfg_attr(rustfmt, rustfmt_skip)]",
|
||||
"pub unsafe fn run(opcode: u32) {",
|
||||
table,
|
||||
"}",
|
||||
|
@ -466,11 +474,12 @@ function gen_table()
|
|||
if(to_generate.interpreter0f_16)
|
||||
{
|
||||
const code = [
|
||||
"#![cfg_attr(rustfmt, rustfmt_skip)]",
|
||||
|
||||
"use cpu2::cpu::*;",
|
||||
"use cpu2::instructions_0f::*;",
|
||||
"use cpu2::global_pointers::*;",
|
||||
|
||||
"#[cfg_attr(rustfmt, rustfmt_skip)]",
|
||||
"pub unsafe fn run(opcode: u8) {",
|
||||
table0f_16,
|
||||
"}",
|
||||
|
@ -486,11 +495,12 @@ function gen_table()
|
|||
if(to_generate.interpreter0f_32)
|
||||
{
|
||||
const code = [
|
||||
"#![cfg_attr(rustfmt, rustfmt_skip)]",
|
||||
|
||||
"use cpu2::cpu::*;",
|
||||
"use cpu2::instructions_0f::*;",
|
||||
"use cpu2::global_pointers::*;",
|
||||
|
||||
"#[cfg_attr(rustfmt, rustfmt_skip)]",
|
||||
"pub unsafe fn run(opcode: u8) {",
|
||||
table0f_32,
|
||||
"}",
|
||||
|
|
|
@ -107,9 +107,9 @@ const encodings = [
|
|||
{ opcode: 0x8B, custom: 1, nonfaulting: 1, os: 1, e: 1, },
|
||||
|
||||
{ opcode: 0x8C, block_boundary: 1, os: 1, e: 1, skip: 1, }, // mov reg, sreg: block_boundary as it can trigger #ud
|
||||
{ opcode: 0x8D, reg_ud: 1, memory_nonfaulting: 1, os: 1, e: 1, requires_prefix_call: 1, custom: 1, }, // lea
|
||||
{ opcode: 0x8D, reg_ud: 1, memory_nonfaulting: 1, os: 1, e: 1, custom_modrm_resolve: 1, custom: 1, }, // lea
|
||||
{ opcode: 0x8E, block_boundary: 1, e: 1, skip: 1, }, // mov sreg
|
||||
{ opcode: 0x8F, os: 1, e: 1, fixed_g: 0, requires_prefix_call: 1, custom: 1, }, // pop r/m
|
||||
{ opcode: 0x8F, os: 1, e: 1, fixed_g: 0, custom_modrm_resolve: 1, custom: 1, block_boundary: 1, }, // pop r/m
|
||||
|
||||
{ opcode: 0x90, custom: 1, nonfaulting: 1, },
|
||||
{ opcode: 0x91, nonfaulting: 1, os: 1, },
|
||||
|
|
139
src/cpu.js
139
src/cpu.js
|
@ -296,8 +296,7 @@ CPU.prototype.wasm_patch = function(wm)
|
|||
this.trigger_np = this.v86oxide.exports["trigger_np"];
|
||||
this.trigger_ss = this.v86oxide.exports["trigger_ss"];
|
||||
|
||||
//this.do_many_cycles_unsafe = this.wm.exports["_do_many_cycles_unsafe"];
|
||||
this.do_many_cycles_unsafe = this.v86oxide.exports["do_many_cycles_unsafe"];
|
||||
this.do_many_cycles_native = this.v86oxide.exports["do_many_cycles_native"];
|
||||
this.cycle_internal = this.v86oxide.exports["cycle_internal"];
|
||||
|
||||
this.read8 = this.v86oxide.exports["read8"];
|
||||
|
@ -308,27 +307,27 @@ CPU.prototype.wasm_patch = function(wm)
|
|||
this.write32 = this.v86oxide.exports["write32"];
|
||||
this.in_mapped_range = this.v86oxide.exports["in_mapped_range"];
|
||||
|
||||
this.push16 = this.v86oxide.exports["push16"];
|
||||
this.push32 = this.v86oxide.exports["push32"];
|
||||
this.pop16 = this.v86oxide.exports["pop16"];
|
||||
this.pop32s = this.v86oxide.exports["pop32s"];
|
||||
this.push16 = this.v86oxide.exports["push16_js"];
|
||||
this.push32 = this.v86oxide.exports["push32_js"];
|
||||
this.pop16 = this.v86oxide.exports["pop16_js"];
|
||||
this.pop32s = this.v86oxide.exports["pop32s_js"];
|
||||
|
||||
this.set_stack_reg = this.v86oxide.exports["set_stack_reg"];
|
||||
|
||||
this.translate_address_read = this.v86oxide.exports["translate_address_read"];
|
||||
this.translate_address_system_read = this.v86oxide.exports["translate_address_system_read"];
|
||||
this.translate_address_system_write = this.v86oxide.exports["translate_address_system_write"];
|
||||
this.translate_address_read = this.v86oxide.exports["translate_address_read_js"];
|
||||
this.translate_address_system_read = this.v86oxide.exports["translate_address_system_read_js"];
|
||||
this.translate_address_system_write = this.v86oxide.exports["translate_address_system_write_js"];
|
||||
|
||||
this.get_seg = this.v86oxide.exports["get_seg"];
|
||||
this.adjust_stack_reg = this.v86oxide.exports["adjust_stack_reg"];
|
||||
this.get_real_eip = this.v86oxide.exports["get_real_eip"];
|
||||
this.get_stack_pointer = this.v86oxide.exports["get_stack_pointer"];
|
||||
|
||||
this.writable_or_pagefault = this.v86oxide.exports["writable_or_pagefault"];
|
||||
this.safe_write32 = this.v86oxide.exports["safe_write32"];
|
||||
this.safe_read32s = this.v86oxide.exports["safe_read32s"];
|
||||
this.safe_write16 = this.v86oxide.exports["safe_write16"];
|
||||
this.safe_read16 = this.v86oxide.exports["safe_read16"];
|
||||
this.writable_or_pagefault = this.v86oxide.exports["writable_or_pagefault_js"];
|
||||
this.safe_write32 = this.v86oxide.exports["safe_write32_js"];
|
||||
this.safe_read32s = this.v86oxide.exports["safe_read32s_js"];
|
||||
this.safe_write16 = this.v86oxide.exports["safe_write16_js"];
|
||||
this.safe_read16 = this.v86oxide.exports["safe_read16_js"];
|
||||
|
||||
this.clear_tlb = this.v86oxide.exports["clear_tlb"];
|
||||
this.full_clear_tlb = this.v86oxide.exports["full_clear_tlb"];
|
||||
|
@ -596,8 +595,6 @@ CPU.prototype.reboot_internal = function()
|
|||
{
|
||||
this.reset();
|
||||
this.load_bios();
|
||||
|
||||
throw MAGIC_CPU_EXCEPTION;
|
||||
};
|
||||
|
||||
CPU.prototype.reset = function()
|
||||
|
@ -1230,13 +1227,7 @@ CPU.prototype.do_many_cycles = function()
|
|||
var start_time = v86.microtick();
|
||||
}
|
||||
|
||||
try {
|
||||
this.do_many_cycles_unsafe();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
this.exception_cleanup(e);
|
||||
}
|
||||
this.do_many_cycles_native();
|
||||
|
||||
if(ENABLE_PROFILER)
|
||||
{
|
||||
|
@ -1250,28 +1241,10 @@ CPU.prototype.do_many_cycles = function()
|
|||
/** @export */
|
||||
CPU.prototype.cycle = function()
|
||||
{
|
||||
try {
|
||||
// XXX: May do several cycles
|
||||
this.cycle_internal();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
this.exception_cleanup(e);
|
||||
}
|
||||
// XXX: May do several cycles
|
||||
this.cycle_internal();
|
||||
};
|
||||
|
||||
// Some functions must not be inlined, because then more code is in the
|
||||
// deoptimized try-catch block.
|
||||
// This trick is a bit ugly, but it works without further complication.
|
||||
if(typeof window !== "undefined")
|
||||
{
|
||||
window["__no_inline_for_closure_compiler__"] = [
|
||||
CPU.prototype.exception_cleanup,
|
||||
CPU.prototype.do_many_cycles_unsafe,
|
||||
CPU.prototype.do_many_cycles,
|
||||
];
|
||||
}
|
||||
|
||||
var seen_code = {};
|
||||
var seen_code_uncompiled = {};
|
||||
|
||||
|
@ -1752,7 +1725,10 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, ha
|
|||
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);
|
||||
if(!this.writable_or_pagefault(this.get_stack_pointer(-stack_space), stack_space))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// no exceptions below
|
||||
}
|
||||
|
@ -1821,10 +1797,7 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, ha
|
|||
{
|
||||
if((this.flags[0] & flag_interrupt) && !(old_flags & flag_interrupt))
|
||||
{
|
||||
if(!this.page_fault[0]) // XXX
|
||||
{
|
||||
this.handle_irqs();
|
||||
}
|
||||
this.handle_irqs();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2316,13 +2289,21 @@ CPU.prototype.far_jump = function(eip, selector, is_call)
|
|||
{
|
||||
if(this.is_osize_32())
|
||||
{
|
||||
this.writable_or_pagefault(this.get_stack_pointer(-8), 8);
|
||||
if(!this.writable_or_pagefault(this.get_stack_pointer(-8), 8))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.push32(this.sreg[reg_cs]);
|
||||
this.push32(this.get_real_eip());
|
||||
}
|
||||
else
|
||||
{
|
||||
this.writable_or_pagefault(this.get_stack_pointer(-4), 4);
|
||||
if(!this.writable_or_pagefault(this.get_stack_pointer(-4), 4))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.push16(this.sreg[reg_cs]);
|
||||
this.push16(this.get_real_eip());
|
||||
}
|
||||
|
@ -2460,15 +2441,17 @@ CPU.prototype.far_jump = function(eip, selector, is_call)
|
|||
}
|
||||
if(ss_info.size)
|
||||
{
|
||||
//try {
|
||||
this.writable_or_pagefault(ss_info.base + new_esp - stack_space | 0, stack_space); // , cs_info.dpl
|
||||
//} catch(e) { debugger; }
|
||||
if(this.writable_or_pagefault(ss_info.base + new_esp - stack_space | 0, stack_space)) // , cs_info.dpl
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//try {
|
||||
this.writable_or_pagefault(ss_info.base + (new_esp - stack_space & 0xFFFF) | 0, stack_space); // , cs_info.dpl
|
||||
//} catch(e) { debugger; }
|
||||
if(this.writable_or_pagefault(ss_info.base + (new_esp - stack_space & 0xFFFF) | 0, stack_space)) // , cs_info.dpl
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var old_esp = this.reg32s[reg_esp];
|
||||
|
@ -2539,13 +2522,21 @@ CPU.prototype.far_jump = function(eip, selector, is_call)
|
|||
{
|
||||
if(is_16)
|
||||
{
|
||||
this.writable_or_pagefault(this.get_stack_pointer(-4), 4);
|
||||
if(!this.writable_or_pagefault(this.get_stack_pointer(-4), 4))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.push16(this.sreg[reg_cs]);
|
||||
this.push16(this.get_real_eip());
|
||||
}
|
||||
else
|
||||
{
|
||||
this.writable_or_pagefault(this.get_stack_pointer(-8), 8);
|
||||
if(!this.writable_or_pagefault(this.get_stack_pointer(-8), 8))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.push32(this.sreg[reg_cs]);
|
||||
this.push32(this.get_real_eip());
|
||||
}
|
||||
|
@ -2622,13 +2613,21 @@ CPU.prototype.far_jump = function(eip, selector, is_call)
|
|||
{
|
||||
if(this.is_osize_32())
|
||||
{
|
||||
this.writable_or_pagefault(this.get_stack_pointer(-8), 8);
|
||||
if(!this.writable_or_pagefault(this.get_stack_pointer(-8), 8))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.push32(this.sreg[reg_cs]);
|
||||
this.push32(this.get_real_eip());
|
||||
}
|
||||
else
|
||||
{
|
||||
this.writable_or_pagefault(this.get_stack_pointer(-4), 4);
|
||||
if(!this.writable_or_pagefault(this.get_stack_pointer(-4), 4))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.push16(this.sreg[reg_cs]);
|
||||
this.push16(this.get_real_eip());
|
||||
}
|
||||
|
@ -2730,7 +2729,10 @@ CPU.prototype.do_task_switch = function(selector, error_code)
|
|||
old_eflags &= ~flag_nt;
|
||||
}
|
||||
|
||||
this.writable_or_pagefault(tsr_offset, 0x66);
|
||||
if(this.writable_or_pagefault(tsr_offset, 0x66))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//this.safe_write32(tsr_offset + TSR_CR3, this.cr[3]);
|
||||
|
||||
|
@ -2944,10 +2946,9 @@ CPU.prototype.pic_call_irq = function(int)
|
|||
|
||||
CPU.prototype.handle_irqs = function()
|
||||
{
|
||||
dbg_assert(!this.page_fault[0]);
|
||||
//dbg_assert(this.prefixes[0] === 0);
|
||||
|
||||
if((this.flags[0] & flag_interrupt) && !this.page_fault[0])
|
||||
if((this.flags[0] & flag_interrupt))
|
||||
{
|
||||
if(this.devices.pic)
|
||||
{
|
||||
|
@ -3740,7 +3741,11 @@ CPU.prototype.enter16 = function(size, nesting_level)
|
|||
}
|
||||
|
||||
// check if write to final stack pointer would case a page fault
|
||||
this.writable_or_pagefault(ss + (frame_temp - size & ss_mask), 2);
|
||||
if(!this.writable_or_pagefault(ss + (frame_temp - size & ss_mask), 2))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.safe_write16(ss + (frame_temp & ss_mask) | 0, this.reg16[reg_bp]);
|
||||
this.reg16[reg_bp] = frame_temp;
|
||||
this.adjust_stack_reg(-size - 2);
|
||||
|
@ -3768,7 +3773,11 @@ CPU.prototype.enter32 = function(size, nesting_level)
|
|||
}
|
||||
|
||||
// check if write to final stack pointer would case a page fault
|
||||
this.writable_or_pagefault(ss + (frame_temp - size & ss_mask), 4);
|
||||
if(!this.writable_or_pagefault(ss + (frame_temp - size & ss_mask), 4))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.safe_write32(ss + (frame_temp & ss_mask) | 0, this.reg32s[reg_ebp]);
|
||||
this.reg32s[reg_ebp] = frame_temp;
|
||||
this.adjust_stack_reg(-size - 4);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
)]
|
||||
#![feature(extern_types, libc)]
|
||||
|
||||
use cpu2::modrm::{resolve_modrm16, resolve_modrm32};
|
||||
|
||||
extern "C" {
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -64,8 +66,6 @@ extern "C" {
|
|||
#[no_mangle]
|
||||
fn write_aligned32(addr: u32, value: i32) -> ();
|
||||
#[no_mangle]
|
||||
fn throw_cpu_exception() -> ();
|
||||
#[no_mangle]
|
||||
fn call_interrupt_vector(
|
||||
interrupt_nr: i32,
|
||||
is_software_int: bool,
|
||||
|
@ -97,10 +97,6 @@ extern "C" {
|
|||
#[no_mangle]
|
||||
static protected_mode: *mut bool;
|
||||
#[no_mangle]
|
||||
fn resolve_modrm16(modrm_byte: i32) -> i32;
|
||||
#[no_mangle]
|
||||
fn resolve_modrm32(modrm_byte: i32) -> i32;
|
||||
#[no_mangle]
|
||||
fn run_instruction(opcode: i32) -> ();
|
||||
#[no_mangle]
|
||||
fn logop(_: i32, _: i32) -> ();
|
||||
|
@ -248,16 +244,16 @@ pub const S_SAFE_READ32_SLOW_NOT_USER: stat_name = 18;
|
|||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub union reg64 {
|
||||
i8_0: [i8; 8],
|
||||
i16_0: [i16; 4],
|
||||
i32_0: [i32; 2],
|
||||
i64_0: [i64; 1],
|
||||
u8_0: [u8; 8],
|
||||
u16_0: [u16; 4],
|
||||
u32_0: [u32; 2],
|
||||
u64_0: [u64; 1],
|
||||
f32_0: [f32; 2],
|
||||
f64_0: [f64; 1],
|
||||
pub i8_0: [i8; 8],
|
||||
pub i16_0: [i16; 4],
|
||||
pub i32_0: [i32; 2],
|
||||
pub i64_0: [i64; 1],
|
||||
pub u8_0: [u8; 8],
|
||||
pub u16_0: [u16; 4],
|
||||
pub u32_0: [u32; 2],
|
||||
pub u64_0: [u64; 1],
|
||||
pub f32_0: [f32; 2],
|
||||
pub f64_0: [f64; 1],
|
||||
}
|
||||
pub const S_SAFE_READ32_SLOW_IN_MAPPED_RANGE: stat_name = 19;
|
||||
|
||||
|
@ -284,16 +280,16 @@ pub const S_SAFE_WRITE32_SLOW_NOT_USER: stat_name = 23;
|
|||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub union reg128 {
|
||||
i8_0: [i8; 16],
|
||||
i16_0: [i16; 8],
|
||||
i32_0: [i32; 4],
|
||||
i64_0: [i64; 2],
|
||||
u8_0: [u8; 16],
|
||||
u16_0: [u16; 8],
|
||||
u32_0: [u32; 4],
|
||||
u64_0: [u64; 2],
|
||||
f32_0: [f32; 4],
|
||||
f64_0: [f64; 2],
|
||||
pub i8_0: [i8; 16],
|
||||
pub i16_0: [i16; 8],
|
||||
pub i32_0: [i32; 4],
|
||||
pub i64_0: [i64; 2],
|
||||
pub u8_0: [u8; 16],
|
||||
pub u16_0: [u16; 8],
|
||||
pub u32_0: [u32; 4],
|
||||
pub u64_0: [u64; 2],
|
||||
pub f32_0: [f32; 4],
|
||||
pub f64_0: [f64; 2],
|
||||
}
|
||||
pub const S_SAFE_WRITE32_SLOW_IN_MAPPED_RANGE: stat_name = 24;
|
||||
pub const S_SAFE_WRITE32_SLOW_NOT_VALID: stat_name = 22;
|
||||
|
@ -1360,15 +1356,15 @@ pub unsafe extern "C" fn get_eflags() -> i32 {
|
|||
| (getof() as i32) << 11i32;
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn translate_address_read(mut address: i32) -> u32 {
|
||||
pub unsafe extern "C" fn translate_address_read(mut address: i32) -> Result<u32, ()> {
|
||||
let mut base: i32 = (address as u32 >> 12i32) as i32;
|
||||
let mut entry: i32 = *tlb_data.offset(base as isize);
|
||||
let mut user: bool = *cpl.offset(0isize) as i32 == 3i32;
|
||||
if entry & (TLB_VALID | if 0 != user as i32 { TLB_NO_USER } else { 0i32 }) == TLB_VALID {
|
||||
return (entry & !4095i32 ^ address) as u32;
|
||||
return Ok((entry & !4095i32 ^ address) as u32);
|
||||
}
|
||||
else {
|
||||
return (do_page_translation(address, 0 != 0i32, user) | address & 4095i32) as u32;
|
||||
return Ok((do_page_translation(address, 0 != 0i32, user)? | address & 4095i32) as u32);
|
||||
};
|
||||
}
|
||||
#[no_mangle]
|
||||
|
@ -1376,7 +1372,7 @@ pub unsafe extern "C" fn do_page_translation(
|
|||
mut addr: i32,
|
||||
mut for_writing: bool,
|
||||
mut user: bool,
|
||||
) -> i32 {
|
||||
) -> Result<i32, ()> {
|
||||
let mut can_write: bool = 0 != 1i32;
|
||||
let mut global: bool = false;
|
||||
let mut allow_user: bool = 0 != 1i32;
|
||||
|
@ -1401,15 +1397,14 @@ pub unsafe extern "C" fn do_page_translation(
|
|||
c_comment!(("- prevent execution of the function that triggered this call"));
|
||||
*cr.offset(2isize) = addr;
|
||||
trigger_pagefault(for_writing, user, 0 != 0i32);
|
||||
c_comment!(("never reached as trigger_pagefault throws"));
|
||||
dbg_assert!(0 != 0i32);
|
||||
return Err(());
|
||||
}
|
||||
if page_dir_entry & PAGE_TABLE_RW_MASK == 0i32 && !kernel_write_override {
|
||||
can_write = 0 != 0i32;
|
||||
if for_writing {
|
||||
*cr.offset(2isize) = addr;
|
||||
trigger_pagefault(for_writing, user, 0 != 1i32);
|
||||
dbg_assert!(0 != 0i32);
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
if page_dir_entry & PAGE_TABLE_USER_MASK == 0i32 {
|
||||
|
@ -1418,7 +1413,7 @@ pub unsafe extern "C" fn do_page_translation(
|
|||
c_comment!(("Page Fault: page table accessed by non-supervisor"));
|
||||
*cr.offset(2isize) = addr;
|
||||
trigger_pagefault(for_writing, user, 0 != 1i32);
|
||||
dbg_assert!(0 != 0i32);
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
if 0 != page_dir_entry & PAGE_TABLE_PSE_MASK && 0 != *cr.offset(4isize) & CR4_PSE {
|
||||
|
@ -1444,14 +1439,14 @@ pub unsafe extern "C" fn do_page_translation(
|
|||
if page_table_entry & PAGE_TABLE_PRESENT_MASK == 0i32 {
|
||||
*cr.offset(2isize) = addr;
|
||||
trigger_pagefault(for_writing, user, 0 != 0i32);
|
||||
dbg_assert!(0 != 0i32);
|
||||
return Err(());
|
||||
}
|
||||
if page_table_entry & PAGE_TABLE_RW_MASK == 0i32 && !kernel_write_override {
|
||||
can_write = 0 != 0i32;
|
||||
if for_writing {
|
||||
*cr.offset(2isize) = addr;
|
||||
trigger_pagefault(for_writing, user, 0 != 1i32);
|
||||
dbg_assert!(0 != 0i32);
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
if page_table_entry & PAGE_TABLE_USER_MASK == 0i32 {
|
||||
|
@ -1459,7 +1454,7 @@ pub unsafe extern "C" fn do_page_translation(
|
|||
if user {
|
||||
*cr.offset(2isize) = addr;
|
||||
trigger_pagefault(for_writing, user, 0 != 1i32);
|
||||
dbg_assert!(0 != 0i32);
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
c_comment!(("set the accessed and dirty bits"));
|
||||
|
@ -1551,7 +1546,7 @@ pub unsafe extern "C" fn do_page_translation(
|
|||
};
|
||||
dbg_assert!((high ^ page << 12i32) & 4095i32 == 0i32);
|
||||
*tlb_data.offset(page as isize) = high ^ page << 12i32 | info_bits;
|
||||
return high;
|
||||
return Ok(high);
|
||||
}
|
||||
#[no_mangle]
|
||||
pub static mut CHECK_TLB_INVARIANTS: bool = unsafe { 0 != 0i32 };
|
||||
|
@ -1634,41 +1629,40 @@ pub unsafe extern "C" fn trigger_pagefault(
|
|||
dbg_assert!(0 != 0i32);
|
||||
}
|
||||
}
|
||||
if *page_fault {
|
||||
dbg_log_c!(("double fault"));
|
||||
dbg_trace();
|
||||
dbg_assert!(0 != 0i32);
|
||||
}
|
||||
//if *page_fault {
|
||||
// dbg_log_c!(("double fault"));
|
||||
// dbg_trace();
|
||||
// dbg_assert!(0 != 0i32);
|
||||
//}
|
||||
c_comment!(("invalidate tlb entry"));
|
||||
let mut page: i32 = (*cr.offset(2isize) as u32 >> 12i32) as i32;
|
||||
*tlb_data.offset(page as isize) = 0i32;
|
||||
*instruction_pointer = *previous_ip;
|
||||
*page_fault = 0 != 1i32;
|
||||
//*page_fault = 0 != 1i32;
|
||||
call_interrupt_vector(
|
||||
CPU_EXCEPTION_PF,
|
||||
0 != 0i32,
|
||||
0 != 1i32,
|
||||
(user as i32) << 2i32 | (write as i32) << 1i32 | present as i32,
|
||||
);
|
||||
profiler_stat_increment(S_TRIGGER_CPU_EXCEPTION);
|
||||
throw_cpu_exception();
|
||||
//profiler_stat_increment(S_TRIGGER_CPU_EXCEPTION);
|
||||
}
|
||||
#[no_mangle]
|
||||
pub static mut must_not_fault: bool = unsafe { 0 != 0i32 };
|
||||
#[no_mangle]
|
||||
pub static mut DEBUG: bool = unsafe { 0 != 1i32 };
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn translate_address_write(mut address: i32) -> u32 {
|
||||
pub unsafe extern "C" fn translate_address_write(mut address: i32) -> Result<u32, ()> {
|
||||
let mut base: i32 = (address as u32 >> 12i32) as i32;
|
||||
let mut entry: i32 = *tlb_data.offset(base as isize);
|
||||
let mut user: bool = *cpl.offset(0isize) as i32 == 3i32;
|
||||
if entry & (TLB_VALID | if 0 != user as i32 { TLB_NO_USER } else { 0i32 } | TLB_READONLY)
|
||||
== TLB_VALID
|
||||
{
|
||||
return (entry & !4095i32 ^ address) as u32;
|
||||
return Ok((entry & !4095i32 ^ address) as u32);
|
||||
}
|
||||
else {
|
||||
return (do_page_translation(address, 0 != 1i32, user) | address & 4095i32) as u32;
|
||||
return Ok((do_page_translation(address, 0 != 1i32, user)? | address & 4095i32) as u32);
|
||||
};
|
||||
}
|
||||
#[no_mangle]
|
||||
|
@ -1715,11 +1709,11 @@ pub unsafe extern "C" fn check_tlb_invariants() -> () {
|
|||
};
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn writable_or_pagefault(mut addr: i32, mut size: i32) -> () {
|
||||
pub unsafe extern "C" fn writable_or_pagefault(mut addr: i32, mut size: i32) -> Result<(), ()> {
|
||||
dbg_assert!(size < 4096i32);
|
||||
dbg_assert!(size > 0i32);
|
||||
if *cr.offset(0isize) & CR0_PG == 0i32 {
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
else {
|
||||
let mut user: bool = *cpl.offset(0isize) as i32 == 3i32;
|
||||
|
@ -1728,57 +1722,59 @@ pub unsafe extern "C" fn writable_or_pagefault(mut addr: i32, mut size: i32) ->
|
|||
let mut expect: i32 = TLB_VALID;
|
||||
let mut page: i32 = (addr as u32 >> 12i32) as i32;
|
||||
if *tlb_data.offset(page as isize) & mask != expect {
|
||||
do_page_translation(addr, 0 != 1i32, user);
|
||||
do_page_translation(addr, 0 != 1i32, user)?;
|
||||
}
|
||||
let mut next_page: i32 = ((addr + size - 1i32) as u32 >> 12i32) as i32;
|
||||
if page != next_page {
|
||||
dbg_assert!(next_page == page + 1i32);
|
||||
c_comment!(("XXX: possibly out of bounds"));
|
||||
if *tlb_data.offset(next_page as isize) & mask != expect {
|
||||
do_page_translation(next_page << 12i32, 0 != 1i32, user);
|
||||
do_page_translation(next_page << 12i32, 0 != 1i32, user)?;
|
||||
}
|
||||
}
|
||||
return;
|
||||
return Ok(());
|
||||
};
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn read_imm8() -> i32 {
|
||||
pub unsafe extern "C" fn read_imm8() -> Result<i32, ()> {
|
||||
let mut eip: i32 = *instruction_pointer;
|
||||
if 0 != eip & !4095i32 ^ *last_virt_eip {
|
||||
*eip_phys = (translate_address_read(eip) ^ eip as u32) as i32;
|
||||
*eip_phys = (translate_address_read(eip)? ^ eip as u32) as i32;
|
||||
*last_virt_eip = eip & !4095i32
|
||||
}
|
||||
dbg_assert!(!in_mapped_range((*eip_phys ^ eip) as u32));
|
||||
let mut data8: i32 = *mem8.offset((*eip_phys ^ eip) as isize) as i32;
|
||||
*instruction_pointer = eip + 1i32;
|
||||
return data8;
|
||||
return Ok(data8);
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn read_imm8s() -> i32 { return read_imm8() << 24i32 >> 24i32; }
|
||||
pub unsafe extern "C" fn read_imm8s() -> Result<i32, ()> {
|
||||
return Ok(read_imm8()? << 24i32 >> 24i32);
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn read_imm16() -> i32 {
|
||||
pub unsafe extern "C" fn read_imm16() -> Result<i32, ()> {
|
||||
c_comment!(("Two checks in one comparison:"));
|
||||
c_comment!(("1. Did the high 20 bits of eip change"));
|
||||
c_comment!(("or 2. Are the low 12 bits of eip 0xFFF (and this read crosses a page boundary)"));
|
||||
if (*instruction_pointer ^ *last_virt_eip) as u32 > 4094i32 as u32 {
|
||||
return read_imm8() | read_imm8() << 8i32;
|
||||
return Ok(read_imm8()? | read_imm8()? << 8i32);
|
||||
}
|
||||
else {
|
||||
let mut data16: i32 = read16((*eip_phys ^ *instruction_pointer) as u32);
|
||||
*instruction_pointer = *instruction_pointer + 2i32;
|
||||
return data16;
|
||||
return Ok(data16);
|
||||
};
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn read_imm32s() -> i32 {
|
||||
pub unsafe extern "C" fn read_imm32s() -> Result<i32, ()> {
|
||||
c_comment!(("Analogue to the above comment"));
|
||||
if (*instruction_pointer ^ *last_virt_eip) as u32 > 4092i32 as u32 {
|
||||
return read_imm16() | read_imm16() << 16i32;
|
||||
return Ok(read_imm16()? | read_imm16()? << 16i32);
|
||||
}
|
||||
else {
|
||||
let mut data32: i32 = read32s((*eip_phys ^ *instruction_pointer) as u32);
|
||||
*instruction_pointer = *instruction_pointer + 4i32;
|
||||
return data32;
|
||||
return Ok(data32);
|
||||
};
|
||||
}
|
||||
#[no_mangle]
|
||||
|
@ -1798,6 +1794,7 @@ pub unsafe extern "C" fn get_seg(mut segment: i32) -> i32 {
|
|||
if *segment_is_null.offset(segment as isize) {
|
||||
dbg_assert!(segment != CS && segment != SS);
|
||||
dbg_log_c!(("#gp: Access null segment"));
|
||||
assert!(false);
|
||||
trigger_gp(0i32);
|
||||
}
|
||||
}
|
||||
|
@ -1824,13 +1821,13 @@ pub unsafe extern "C" fn raise_exception_with_code(
|
|||
dbg_assert!(0 != 0i32);
|
||||
}
|
||||
if cpu_exception_hook(interrupt_nr) {
|
||||
throw_cpu_exception();
|
||||
assert!(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
profiler_stat_increment(S_TRIGGER_CPU_EXCEPTION);
|
||||
call_interrupt_vector(interrupt_nr, 0 != 0i32, 0 != 1i32, error_code);
|
||||
throw_cpu_exception();
|
||||
assert!(false);
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_seg_cs() -> i32 { return *segment_offsets.offset(CS as isize); }
|
||||
|
@ -1864,13 +1861,13 @@ pub unsafe extern "C" fn get_seg_prefix_cs(mut offset: i32) -> i32 {
|
|||
return get_seg_prefix(CS) + offset;
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn modrm_resolve(mut modrm_byte: i32) -> i32 {
|
||||
pub unsafe extern "C" fn modrm_resolve(mut modrm_byte: i32) -> Result<i32, ()> {
|
||||
if is_asize_32() {
|
||||
return resolve_modrm32(modrm_byte);
|
||||
resolve_modrm32(modrm_byte)
|
||||
}
|
||||
else {
|
||||
return resolve_modrm16(modrm_byte);
|
||||
};
|
||||
resolve_modrm16(modrm_byte)
|
||||
}
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn cycle_internal() -> () {
|
||||
|
@ -1924,15 +1921,15 @@ pub unsafe extern "C" fn cycle_internal() -> () {
|
|||
}
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_phys_eip() -> i32 {
|
||||
pub unsafe extern "C" fn get_phys_eip() -> Result<i32, ()> {
|
||||
let mut eip: i32 = *instruction_pointer;
|
||||
if 0 != eip & !4095i32 ^ *last_virt_eip {
|
||||
*eip_phys = (translate_address_read(eip) ^ eip as u32) as i32;
|
||||
*eip_phys = (translate_address_read(eip)? ^ eip as u32) as i32;
|
||||
*last_virt_eip = eip & !4095i32
|
||||
}
|
||||
let mut phys_addr: u32 = (*eip_phys ^ eip) as u32;
|
||||
dbg_assert!(!in_mapped_range(phys_addr));
|
||||
return phys_addr as i32;
|
||||
return Ok(phys_addr as i32);
|
||||
}
|
||||
unsafe extern "C" fn jit_run_interpreted(mut phys_addr: i32) -> () {
|
||||
profiler_stat_increment(S_RUN_INTERPRETED);
|
||||
|
@ -1946,7 +1943,7 @@ unsafe extern "C" fn jit_run_interpreted(mut phys_addr: i32) -> () {
|
|||
while !jit_block_boundary && 0 != same_page(*previous_ip, *instruction_pointer) as i32 {
|
||||
*previous_ip.offset(0isize) = *instruction_pointer.offset(0isize);
|
||||
*timestamp_counter = (*timestamp_counter).wrapping_add(1);
|
||||
let mut opcode_0: i32 = read_imm8();
|
||||
let mut opcode_0: i32 = return_on_pagefault!(read_imm8());
|
||||
if DEBUG {
|
||||
logop(*previous_ip.offset(0isize), opcode_0);
|
||||
}
|
||||
|
@ -1974,7 +1971,7 @@ pub unsafe extern "C" fn has_flat_segmentation() -> bool {
|
|||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn run_prefix_instruction() -> () {
|
||||
run_instruction(read_imm8() | (is_osize_32() as i32) << 8i32);
|
||||
run_instruction(return_on_pagefault!(read_imm8()) | (is_osize_32() as i32) << 8i32);
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn clear_prefixes() -> () { *prefixes = 0i32 as u8; }
|
||||
|
@ -1986,7 +1983,7 @@ pub unsafe extern "C" fn segment_prefix_op(mut seg: i32) -> () {
|
|||
*prefixes = 0i32 as u8;
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn do_many_cycles_unsafe() -> () {
|
||||
pub unsafe extern "C" fn do_many_cycles_native() -> () {
|
||||
profiler_stat_increment(S_DO_MANY_CYCLES);
|
||||
let mut initial_timestamp_counter: u32 = *timestamp_counter;
|
||||
while (*timestamp_counter).wrapping_sub(initial_timestamp_counter) < LOOP_COUNTER as u32
|
||||
|
@ -1997,23 +1994,23 @@ pub unsafe extern "C" fn do_many_cycles_unsafe() -> () {
|
|||
}
|
||||
#[no_mangle]
|
||||
pub static mut LOOP_COUNTER: i32 = unsafe { 20011i32 };
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn raise_exception(mut interrupt_nr: i32) -> () {
|
||||
if DEBUG {
|
||||
if must_not_fault {
|
||||
dbg_log_c!(("Unexpected fault: 0x%x"), interrupt_nr);
|
||||
dbg_trace();
|
||||
dbg_assert!(0 != 0i32);
|
||||
}
|
||||
if cpu_exception_hook(interrupt_nr) {
|
||||
throw_cpu_exception();
|
||||
return;
|
||||
}
|
||||
}
|
||||
profiler_stat_increment(S_TRIGGER_CPU_EXCEPTION);
|
||||
call_interrupt_vector(interrupt_nr, 0 != 0i32, 0 != 0i32, 0i32);
|
||||
throw_cpu_exception();
|
||||
}
|
||||
//#[no_mangle]
|
||||
//pub unsafe extern "C" fn raise_exception(mut interrupt_nr: i32) -> () {
|
||||
// if DEBUG {
|
||||
// if must_not_fault {
|
||||
// dbg_log_c!(("Unexpected fault: 0x%x"), interrupt_nr);
|
||||
// dbg_trace();
|
||||
// dbg_assert!(0 != 0i32);
|
||||
// }
|
||||
// if cpu_exception_hook(interrupt_nr) {
|
||||
// throw_cpu_exception();
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// profiler_stat_increment(S_TRIGGER_CPU_EXCEPTION);
|
||||
// call_interrupt_vector(interrupt_nr, 0 != 0i32, 0 != 0i32, 0i32);
|
||||
// throw_cpu_exception();
|
||||
//}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn trigger_de() -> () {
|
||||
if DEBUG {
|
||||
|
@ -2121,12 +2118,13 @@ pub unsafe extern "C" fn virt_boundary_write32(mut low: i32, mut high: i32, mut
|
|||
write8(high as u32, value >> 24i32);
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn safe_read8(mut addr: i32) -> i32 {
|
||||
pub unsafe extern "C" fn safe_read8(mut addr: i32) -> Result<i32, ()> {
|
||||
assert_no_cpu_exception();
|
||||
return read8(translate_address_read(addr));
|
||||
return Ok(read8(translate_address_read(addr)?));
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn assert_no_cpu_exception() -> () {
|
||||
return;
|
||||
if current_cpu_exception != -1i32 {
|
||||
dbg_log_c!(("Expected no cpu exception, got %d"), current_cpu_exception);
|
||||
dbg_trace();
|
||||
|
@ -2134,7 +2132,7 @@ pub unsafe extern "C" fn assert_no_cpu_exception() -> () {
|
|||
};
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn safe_read16(mut address: i32) -> i32 {
|
||||
pub unsafe extern "C" fn safe_read16(mut address: i32) -> Result<i32, ()> {
|
||||
let mut base: i32 = (address as u32 >> 12i32) as i32;
|
||||
let mut entry: i32 = *tlb_data.offset(base as isize);
|
||||
let mut info_bits: i32 = entry & 4095i32 & !TLB_READONLY & !TLB_GLOBAL & !TLB_HAS_CODE;
|
||||
|
@ -2143,24 +2141,24 @@ pub unsafe extern "C" fn safe_read16(mut address: i32) -> i32 {
|
|||
c_comment!(("- can be accessed from any cpl"));
|
||||
let mut phys_address: u32 = (entry & !4095i32 ^ address) as u32;
|
||||
dbg_assert!(!in_mapped_range(phys_address));
|
||||
return *(mem8.offset(phys_address as isize) as *mut u16) as i32;
|
||||
return Ok(*(mem8.offset(phys_address as isize) as *mut u16) as i32);
|
||||
}
|
||||
else {
|
||||
return safe_read16_slow(address);
|
||||
return Ok(safe_read16_slow(address)?);
|
||||
};
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn safe_read16_slow(mut addr: i32) -> i32 {
|
||||
pub unsafe extern "C" fn safe_read16_slow(mut addr: i32) -> Result<i32, ()> {
|
||||
assert_no_cpu_exception();
|
||||
if addr & 4095i32 == 4095i32 {
|
||||
return safe_read8(addr) | safe_read8(addr + 1i32) << 8i32;
|
||||
return Ok(safe_read8(addr)? | safe_read8(addr + 1i32)? << 8i32);
|
||||
}
|
||||
else {
|
||||
return read16(translate_address_read(addr));
|
||||
return Ok(read16(translate_address_read(addr)?));
|
||||
};
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn safe_read32s(mut address: i32) -> i32 {
|
||||
pub unsafe extern "C" fn safe_read32s(mut address: i32) -> Result<i32, ()> {
|
||||
assert_no_cpu_exception();
|
||||
let mut base: i32 = (address as u32 >> 12i32) as i32;
|
||||
let mut entry: i32 = *tlb_data.offset(base as isize);
|
||||
|
@ -2171,7 +2169,7 @@ pub unsafe extern "C" fn safe_read32s(mut address: i32) -> i32 {
|
|||
c_comment!(("- can be accessed from any cpl"));
|
||||
let mut phys_address: u32 = (entry & !4095i32 ^ address) as u32;
|
||||
dbg_assert!(!in_mapped_range(phys_address));
|
||||
return *(mem8.offset(phys_address as isize) as *mut i32);
|
||||
return Ok(*(mem8.offset(phys_address as isize) as *mut i32));
|
||||
}
|
||||
else {
|
||||
if address & 4095i32 > 4096i32 - 4i32 {
|
||||
|
@ -2193,51 +2191,81 @@ pub unsafe extern "C" fn safe_read32s(mut address: i32) -> i32 {
|
|||
};
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn safe_read32s_slow(mut addr: i32) -> i32 {
|
||||
pub unsafe extern "C" fn safe_read32s_slow(mut addr: i32) -> Result<i32, ()> {
|
||||
if addr & 4095i32 >= 4093i32 {
|
||||
return safe_read16(addr) | safe_read16(addr + 2i32) << 16i32;
|
||||
return Ok(safe_read16(addr)? | safe_read16(addr + 2i32)? << 16i32);
|
||||
}
|
||||
else {
|
||||
return read32s(translate_address_read(addr));
|
||||
return Ok(read32s(translate_address_read(addr)?));
|
||||
};
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn safe_read64s(mut addr: i32) -> reg64 {
|
||||
pub unsafe fn safe_read16_slow_jit(addr: i32) -> i32 {
|
||||
match safe_read16_slow(addr) {
|
||||
Ok(v) => {
|
||||
*page_fault = false;
|
||||
v
|
||||
},
|
||||
Err(()) => {
|
||||
*page_fault = true;
|
||||
-1
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn safe_read32s_slow_jit(addr: i32) -> i32 {
|
||||
match safe_read32s_slow(addr) {
|
||||
Ok(v) => {
|
||||
*page_fault = false;
|
||||
v
|
||||
},
|
||||
Err(()) => {
|
||||
*page_fault = true;
|
||||
-1
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn safe_read64s(mut addr: i32) -> Result<reg64, ()> {
|
||||
let mut addr_phys: i32 = 0;
|
||||
assert_no_cpu_exception();
|
||||
let mut x: reg64 = reg64 { i8_0: [0; 8] };
|
||||
if addr & 4095i32 > 4096i32 - 8i32 {
|
||||
x.u32_0[0usize] = safe_read32s(addr) as u32;
|
||||
x.u32_0[1usize] = safe_read32s(addr + 4i32) as u32
|
||||
x.u32_0[0usize] = safe_read32s(addr)? as u32;
|
||||
x.u32_0[1usize] = safe_read32s(addr + 4i32)? as u32
|
||||
}
|
||||
else {
|
||||
addr_phys = translate_address_read(addr) as i32;
|
||||
addr_phys = translate_address_read(addr)? as i32;
|
||||
x.u64_0[0usize] = read64s(addr_phys as u32) as u64
|
||||
}
|
||||
return x;
|
||||
Ok(x)
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn safe_read128s(mut addr: i32) -> reg128 {
|
||||
pub unsafe extern "C" fn safe_read128s(mut addr: i32) -> Result<reg128, ()> {
|
||||
let mut addr_phys: i32 = 0;
|
||||
assert_no_cpu_exception();
|
||||
let mut x: reg128 = reg128 { i8_0: [0; 16] };
|
||||
if addr & 4095i32 > 4096i32 - 16i32 {
|
||||
x.u64_0[0usize] = safe_read64s(addr).u64_0[0usize];
|
||||
x.u64_0[1usize] = safe_read64s(addr + 8i32).u64_0[0usize]
|
||||
x.u64_0[0usize] = safe_read64s(addr)?.u64_0[0usize];
|
||||
x.u64_0[1usize] = safe_read64s(addr + 8i32)?.u64_0[0usize]
|
||||
}
|
||||
else {
|
||||
addr_phys = translate_address_read(addr) as i32;
|
||||
addr_phys = translate_address_read(addr)? as i32;
|
||||
x = read128(addr_phys as u32)
|
||||
}
|
||||
return x;
|
||||
Ok(x)
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn safe_write8(mut addr: i32, mut value: i32) -> () {
|
||||
pub unsafe extern "C" fn safe_write8(mut addr: i32, mut value: i32) -> Result<(), ()> {
|
||||
assert_no_cpu_exception();
|
||||
write8(translate_address_write(addr), value);
|
||||
write8(translate_address_write(addr)?, value);
|
||||
Ok(())
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn safe_write16(mut address: i32, mut value: i32) -> () {
|
||||
pub unsafe extern "C" fn safe_write16(mut address: i32, mut value: i32) -> Result<(), ()> {
|
||||
let mut base: i32 = (address as u32 >> 12i32) as i32;
|
||||
let mut entry: i32 = *tlb_data.offset(base as isize);
|
||||
let mut info_bits: i32 = entry & 4095i32 & !TLB_GLOBAL;
|
||||
|
@ -2250,26 +2278,30 @@ pub unsafe extern "C" fn safe_write16(mut address: i32, mut value: i32) -> () {
|
|||
dbg_assert!(!jit_page_has_code(phys_address >> 12i32));
|
||||
dbg_assert!(!in_mapped_range(phys_address));
|
||||
*(mem8.offset(phys_address as isize) as *mut u16) = value as u16;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
safe_write16_slow(address, value);
|
||||
return;
|
||||
safe_write16_slow(address, value)?;
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn safe_write16_slow(mut addr: i32, mut value: i32) -> () {
|
||||
pub unsafe extern "C" fn safe_write16_slow(mut addr: i32, mut value: i32) -> Result<(), ()> {
|
||||
assert_no_cpu_exception();
|
||||
let mut phys_low: i32 = translate_address_write(addr) as i32;
|
||||
let mut phys_low: i32 = translate_address_write(addr)? as i32;
|
||||
if addr & 4095i32 == 4095i32 {
|
||||
virt_boundary_write16(phys_low, translate_address_write(addr + 1i32) as i32, value);
|
||||
virt_boundary_write16(
|
||||
phys_low,
|
||||
translate_address_write(addr + 1i32)? as i32,
|
||||
value,
|
||||
);
|
||||
}
|
||||
else {
|
||||
write16(phys_low as u32, value);
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn safe_write32(mut address: i32, mut value: i32) -> () {
|
||||
pub unsafe extern "C" fn safe_write32(mut address: i32, mut value: i32) -> Result<(), ()> {
|
||||
assert_no_cpu_exception();
|
||||
let mut base: i32 = (address as u32 >> 12i32) as i32;
|
||||
let mut entry: i32 = *tlb_data.offset(base as isize);
|
||||
|
@ -2288,7 +2320,6 @@ pub unsafe extern "C" fn safe_write32(mut address: i32, mut value: i32) -> () {
|
|||
dbg_assert!(!jit_page_has_code(phys_address >> 12i32));
|
||||
dbg_assert!(!in_mapped_range(phys_address));
|
||||
*(mem8.offset(phys_address as isize) as *mut i32) = value;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if address & 4095i32 > 4096i32 - 4i32 {
|
||||
|
@ -2312,49 +2343,63 @@ pub unsafe extern "C" fn safe_write32(mut address: i32, mut value: i32) -> () {
|
|||
else {
|
||||
dbg_assert!(0 != 0i32);
|
||||
}
|
||||
safe_write32_slow(address, value);
|
||||
return;
|
||||
safe_write32_slow(address, value)?;
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn safe_write32_slow(mut addr: i32, mut value: i32) -> () {
|
||||
let mut phys_low: i32 = translate_address_write(addr) as i32;
|
||||
pub unsafe extern "C" fn safe_write32_slow(mut addr: i32, mut value: i32) -> Result<(), ()> {
|
||||
let mut phys_low: i32 = translate_address_write(addr)? as i32;
|
||||
if addr & 4095i32 > 4096i32 - 4i32 {
|
||||
virt_boundary_write32(
|
||||
phys_low,
|
||||
(translate_address_write(addr + 3i32 & !3i32) | (addr + 3i32 & 3i32) as u32) as i32,
|
||||
(translate_address_write(addr + 3i32 & !3i32)? | (addr + 3i32 & 3i32) as u32) as i32,
|
||||
value,
|
||||
);
|
||||
}
|
||||
else {
|
||||
write32(phys_low as u32, value);
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn safe_write64(mut addr: i32, mut value: i64) -> () {
|
||||
pub unsafe fn safe_write16_slow_jit(addr: i32, value: i32) {
|
||||
let _ = safe_write16_slow(addr, value);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn safe_write32_slow_jit(addr: i32, value: i32) {
|
||||
let _ = safe_write32_slow(addr, value);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn safe_write64(mut addr: i32, mut value: i64) -> Result<(), ()> {
|
||||
assert_no_cpu_exception();
|
||||
if addr & 4095i32 > 4096i32 - 8i32 {
|
||||
writable_or_pagefault(addr, 8i32);
|
||||
safe_write32(addr, value as i32);
|
||||
safe_write32(addr + 4i32, (value >> 32i32) as i32);
|
||||
writable_or_pagefault(addr, 8i32)?;
|
||||
safe_write32(addr, value as i32).unwrap();
|
||||
safe_write32(addr + 4i32, (value >> 32i32) as i32).unwrap();
|
||||
}
|
||||
else {
|
||||
let mut phys: i32 = translate_address_write(addr) as i32;
|
||||
let mut phys: i32 = translate_address_write(addr)? as i32;
|
||||
write64(phys as u32, value);
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn safe_write128(mut addr: i32, mut value: reg128) -> () {
|
||||
pub unsafe extern "C" fn safe_write128(mut addr: i32, mut value: reg128) -> Result<(), ()> {
|
||||
assert_no_cpu_exception();
|
||||
if addr & 4095i32 > 4096i32 - 16i32 {
|
||||
writable_or_pagefault(addr, 16i32);
|
||||
safe_write64(addr, value.u64_0[0usize] as i64);
|
||||
safe_write64(addr + 8i32, value.u64_0[1usize] as i64);
|
||||
writable_or_pagefault(addr, 16i32)?;
|
||||
safe_write64(addr, value.u64_0[0usize] as i64).unwrap();
|
||||
safe_write64(addr + 8i32, value.u64_0[1usize] as i64).unwrap();
|
||||
}
|
||||
else {
|
||||
let mut phys: i32 = translate_address_write(addr) as i32;
|
||||
let mut phys: i32 = translate_address_write(addr)? as i32;
|
||||
write128(phys as u32, value);
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_reg8_index(mut index: i32) -> i32 {
|
||||
|
@ -2486,14 +2531,14 @@ pub unsafe extern "C" fn task_switch_test_mmx() -> bool {
|
|||
#[no_mangle]
|
||||
pub unsafe extern "C" fn task_switch_test_mmx_void() -> () { task_switch_test_mmx(); }
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn read_moffs() -> i32 {
|
||||
pub unsafe extern "C" fn read_moffs() -> Result<i32, ()> {
|
||||
c_comment!(("read 2 or 4 byte from ip, depending on address size attribute"));
|
||||
if is_asize_32() {
|
||||
return read_imm32s();
|
||||
read_imm32s()
|
||||
}
|
||||
else {
|
||||
return read_imm16();
|
||||
};
|
||||
read_imm16()
|
||||
}
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_real_eip() -> i32 {
|
||||
|
@ -2697,25 +2742,25 @@ pub unsafe extern "C" fn get_valid_global_tlb_entries_count() -> i32 {
|
|||
return result;
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn translate_address_system_read(mut address: i32) -> u32 {
|
||||
pub unsafe extern "C" fn translate_address_system_read(mut address: i32) -> Result<u32, ()> {
|
||||
let mut base: i32 = (address as u32 >> 12i32) as i32;
|
||||
let mut entry: i32 = *tlb_data.offset(base as isize);
|
||||
if 0 != entry & TLB_VALID {
|
||||
return (entry & !4095i32 ^ address) as u32;
|
||||
return Ok((entry & !4095i32 ^ address) as u32);
|
||||
}
|
||||
else {
|
||||
return (do_page_translation(address, 0 != 0i32, 0 != 0i32) | address & 4095i32) as u32;
|
||||
return Ok((do_page_translation(address, 0 != 0i32, 0 != 0i32)? | address & 4095i32) as u32);
|
||||
};
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn translate_address_system_write(mut address: i32) -> u32 {
|
||||
pub unsafe extern "C" fn translate_address_system_write(mut address: i32) -> Result<u32, ()> {
|
||||
let mut base: i32 = (address as u32 >> 12i32) as i32;
|
||||
let mut entry: i32 = *tlb_data.offset(base as isize);
|
||||
if entry & (TLB_VALID | TLB_READONLY) == TLB_VALID {
|
||||
return (entry & !4095i32 ^ address) as u32;
|
||||
return Ok((entry & !4095i32 ^ address) as u32);
|
||||
}
|
||||
else {
|
||||
return (do_page_translation(address, 0 != 1i32, 0 != 0i32) | address & 4095i32) as u32;
|
||||
return Ok((do_page_translation(address, 0 != 1i32, 0 != 0i32)? | address & 4095i32) as u32);
|
||||
};
|
||||
}
|
||||
#[no_mangle]
|
||||
|
|
|
@ -2,24 +2,38 @@ macro_rules! SAFE_READ_WRITE8 {
|
|||
($value:ident, $addr:expr, $instruction:expr) => {{
|
||||
use cpu2::cpu::translate_address_write;
|
||||
use cpu2::memory::{read8, write8};
|
||||
let phys_addr = translate_address_write($addr);
|
||||
let $value = read8(phys_addr);
|
||||
write8(phys_addr, $instruction);
|
||||
match translate_address_write($addr) {
|
||||
Err(()) => {},
|
||||
Ok(phys_addr) => {
|
||||
let $value = read8(phys_addr);
|
||||
write8(phys_addr, $instruction);
|
||||
},
|
||||
}
|
||||
}};
|
||||
}
|
||||
macro_rules! SAFE_READ_WRITE16 {
|
||||
($value:ident, $addr:expr, $instruction:expr) => {{
|
||||
use cpu2::cpu::{translate_address_write, virt_boundary_read16, virt_boundary_write16};
|
||||
use cpu2::memory::{read16, write16};
|
||||
let phys_addr = translate_address_write($addr) as i32;
|
||||
if phys_addr & 0xFFF == 0xFFF {
|
||||
let phys_addr_high = translate_address_write($addr + 1) as i32;
|
||||
let $value = virt_boundary_read16(phys_addr, phys_addr_high);
|
||||
virt_boundary_write16(phys_addr, phys_addr_high, $instruction);
|
||||
}
|
||||
else {
|
||||
let $value = read16(phys_addr as u32);
|
||||
write16(phys_addr as u32, $instruction);
|
||||
match translate_address_write($addr) {
|
||||
Err(()) => {},
|
||||
Ok(phys_addr) => {
|
||||
let phys_addr = phys_addr as i32;
|
||||
if phys_addr & 0xFFF == 0xFFF {
|
||||
match translate_address_write($addr + 1) {
|
||||
Err(()) => {},
|
||||
Ok(phys_addr_high) => {
|
||||
let phys_addr_high = phys_addr_high as i32;
|
||||
let $value = virt_boundary_read16(phys_addr, phys_addr_high);
|
||||
virt_boundary_write16(phys_addr, phys_addr_high, $instruction);
|
||||
},
|
||||
}
|
||||
}
|
||||
else {
|
||||
let $value = read16(phys_addr as u32);
|
||||
write16(phys_addr as u32, $instruction);
|
||||
}
|
||||
},
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
@ -27,15 +41,28 @@ macro_rules! SAFE_READ_WRITE32 {
|
|||
($value:ident, $addr:expr, $instruction:expr) => {{
|
||||
use cpu2::cpu::{translate_address_write, virt_boundary_read32s, virt_boundary_write32};
|
||||
use cpu2::memory::{read32s, write32};
|
||||
let phys_addr = translate_address_write($addr);
|
||||
if phys_addr & 0xFFF >= 0xFFD {
|
||||
let phys_addr_high = translate_address_write($addr + 3 & !3) as i32 | $addr + 3 & 3;
|
||||
let $value = virt_boundary_read32s(phys_addr as i32, phys_addr_high);
|
||||
virt_boundary_write32(phys_addr as i32, phys_addr_high as i32, $instruction);
|
||||
}
|
||||
else {
|
||||
let $value = read32s(phys_addr);
|
||||
write32(phys_addr, $instruction);
|
||||
match translate_address_write($addr) {
|
||||
Err(()) => {},
|
||||
Ok(phys_addr) => {
|
||||
if phys_addr & 0xFFF >= 0xFFD {
|
||||
match translate_address_write($addr + 3 & !3) {
|
||||
Err(()) => {},
|
||||
Ok(phys_addr_high) => {
|
||||
let phys_addr_high = phys_addr_high as i32 | $addr + 3 & 3;
|
||||
let $value = virt_boundary_read32s(phys_addr as i32, phys_addr_high);
|
||||
virt_boundary_write32(
|
||||
phys_addr as i32,
|
||||
phys_addr_high as i32,
|
||||
$instruction,
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
else {
|
||||
let $value = read32s(phys_addr);
|
||||
write32(phys_addr, $instruction);
|
||||
}
|
||||
},
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
|
|
@ -307,30 +307,12 @@ extern "C" {
|
|||
#[no_mangle]
|
||||
static CPU_EXCEPTION_VE: i32;
|
||||
#[no_mangle]
|
||||
fn translate_address_read(address: i32) -> u32;
|
||||
#[no_mangle]
|
||||
fn writable_or_pagefault(addr: i32, size: i32) -> ();
|
||||
#[no_mangle]
|
||||
fn get_seg_cs() -> i32;
|
||||
#[no_mangle]
|
||||
fn get_seg_ss() -> i32;
|
||||
#[no_mangle]
|
||||
fn trigger_gp_non_raising(code: i32) -> ();
|
||||
#[no_mangle]
|
||||
fn safe_read8(addr: i32) -> i32;
|
||||
#[no_mangle]
|
||||
fn safe_read16(addr: i32) -> i32;
|
||||
#[no_mangle]
|
||||
fn safe_read32s(address: i32) -> i32;
|
||||
#[no_mangle]
|
||||
fn safe_write8(addr: i32, value: i32) -> ();
|
||||
#[no_mangle]
|
||||
fn safe_write16(addr: i32, value: i32) -> ();
|
||||
#[no_mangle]
|
||||
fn safe_write32(address: i32, value: i32) -> ();
|
||||
#[no_mangle]
|
||||
fn safe_write128(addr: i32, value: reg128) -> ();
|
||||
#[no_mangle]
|
||||
fn write_reg8(index: i32, value: i32) -> ();
|
||||
#[no_mangle]
|
||||
fn write_reg16(index: i32, value: i32) -> ();
|
||||
|
@ -499,20 +481,6 @@ pub union unnamed {
|
|||
__i: u64,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub union reg64 {
|
||||
i8_0: [i8; 8],
|
||||
i16_0: [i16; 4],
|
||||
i32_0: [i32; 2],
|
||||
i64_0: [i64; 1],
|
||||
u8_0: [u8; 8],
|
||||
u16_0: [u16; 4],
|
||||
u32_0: [u32; 2],
|
||||
u64_0: [u64; 1],
|
||||
f32_0: [f32; 2],
|
||||
f64_0: [f64; 1],
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub union unnamed_0 {
|
||||
|
@ -520,21 +488,6 @@ pub union unnamed_0 {
|
|||
__i: u32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub union reg128 {
|
||||
i8_0: [i8; 16],
|
||||
i16_0: [i16; 8],
|
||||
i32_0: [i32; 4],
|
||||
i64_0: [i64; 2],
|
||||
u8_0: [u8; 16],
|
||||
u16_0: [u16; 8],
|
||||
u32_0: [u32; 4],
|
||||
u64_0: [u64; 2],
|
||||
f32_0: [f32; 4],
|
||||
f64_0: [f64; 2],
|
||||
}
|
||||
|
||||
unsafe extern "C" fn __FLOAT_BITS(mut __f: f32) -> u32 {
|
||||
let mut __u: unnamed_0 = unnamed_0 { __f: 0. };
|
||||
__u.__f = __f;
|
||||
|
@ -1078,105 +1031,159 @@ pub unsafe extern "C" fn adjust_stack_reg(mut adjustment: i32) -> () {
|
|||
*fresh1 = (*fresh1 as i32 + adjustment) as u16
|
||||
};
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push16_ss16(mut imm16: i32) -> () {
|
||||
pub unsafe extern "C" fn push16_ss16(mut imm16: i32) -> Result<(), ()> {
|
||||
let mut sp: i32 = get_seg_ss() + (*reg16.offset(SP as isize) as i32 - 2i32 & 65535i32);
|
||||
safe_write16(sp, imm16);
|
||||
safe_write16(sp, imm16)?;
|
||||
let ref mut fresh2 = *reg16.offset(SP as isize);
|
||||
*fresh2 = (*fresh2 as i32 + -2i32) as u16;
|
||||
Ok(())
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push16_ss32(mut imm16: i32) -> () {
|
||||
pub unsafe extern "C" fn push16_ss32(mut imm16: i32) -> Result<(), ()> {
|
||||
let mut sp: i32 = get_seg_ss() + *reg32s.offset(ESP as isize) - 2i32;
|
||||
safe_write16(sp, imm16);
|
||||
safe_write16(sp, imm16)?;
|
||||
let ref mut fresh3 = *reg32s.offset(ESP as isize);
|
||||
*fresh3 += -2i32;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push16_ss16_jit(mut imm16: i32) {
|
||||
return_on_pagefault!(push16_ss16(imm16))
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push16_ss16_mem(mut addr: i32) -> () { push16_ss16(safe_read16(addr)); }
|
||||
pub unsafe extern "C" fn push16_ss32_jit(mut imm16: i32) {
|
||||
return_on_pagefault!(push16_ss32(imm16))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push16_ss32_mem(mut addr: i32) -> () { push16_ss32(safe_read16(addr)); }
|
||||
pub unsafe extern "C" fn push16_ss16_mem(mut addr: i32) -> Result<(), ()> {
|
||||
push16_ss16(safe_read16(addr)?)
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push16(mut imm16: i32) -> () {
|
||||
pub unsafe extern "C" fn push16_ss32_mem(mut addr: i32) -> Result<(), ()> {
|
||||
push16_ss32(safe_read16(addr)?)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push16_ss16_mem_jit(mut addr: i32) {
|
||||
return_on_pagefault!(push16_ss16(addr))
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push16_ss32_mem_jit(mut addr: i32) {
|
||||
return_on_pagefault!(push16_ss32(addr))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push16(mut imm16: i32) -> Result<(), ()> {
|
||||
if *stack_size_32 {
|
||||
push16_ss32(imm16);
|
||||
push16_ss32(imm16)
|
||||
}
|
||||
else {
|
||||
push16_ss16(imm16);
|
||||
};
|
||||
push16_ss16(imm16)
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push32_ss16(mut imm32: i32) -> () {
|
||||
pub unsafe extern "C" fn push32_ss16(mut imm32: i32) -> Result<(), ()> {
|
||||
let mut new_sp: i32 = *reg16.offset(SP as isize) as i32 - 4i32 & 65535i32;
|
||||
safe_write32(get_seg_ss() + new_sp, imm32);
|
||||
safe_write32(get_seg_ss() + new_sp, imm32)?;
|
||||
*reg16.offset(SP as isize) = new_sp as u16;
|
||||
Ok(())
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push32_ss32(mut imm32: i32) -> () {
|
||||
pub unsafe extern "C" fn push32_ss32(mut imm32: i32) -> Result<(), ()> {
|
||||
let mut new_esp: i32 = *reg32s.offset(ESP as isize) - 4i32;
|
||||
safe_write32(get_seg_ss() + new_esp, imm32);
|
||||
safe_write32(get_seg_ss() + new_esp, imm32)?;
|
||||
*reg32s.offset(ESP as isize) = new_esp;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push32_ss16_jit(mut imm32: i32) {
|
||||
return_on_pagefault!(push32_ss16(imm32))
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push32_ss16_mem(mut addr: i32) -> () { push32_ss16(safe_read32s(addr)); }
|
||||
pub unsafe extern "C" fn push32_ss32_jit(mut imm32: i32) {
|
||||
return_on_pagefault!(push32_ss32(imm32))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push32_ss32_mem(mut addr: i32) -> () { push32_ss32(safe_read32s(addr)); }
|
||||
pub unsafe extern "C" fn push32_ss16_mem(mut addr: i32) -> Result<(), ()> {
|
||||
push32_ss16(safe_read32s(addr)?)
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push32(mut imm32: i32) -> () {
|
||||
pub unsafe extern "C" fn push32_ss32_mem(mut addr: i32) -> Result<(), ()> {
|
||||
push32_ss32(safe_read32s(addr)?)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push32_ss16_mem_jit(mut addr: i32) {
|
||||
return_on_pagefault!(push32_ss16_mem(addr))
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push32_ss32_mem_jit(mut addr: i32) {
|
||||
return_on_pagefault!(push32_ss32_mem(addr))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn push32(mut imm32: i32) -> Result<(), ()> {
|
||||
if *stack_size_32 {
|
||||
push32_ss32(imm32);
|
||||
push32_ss32(imm32)
|
||||
}
|
||||
else {
|
||||
push32_ss16(imm32);
|
||||
};
|
||||
push32_ss16(imm32)
|
||||
}
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pop16() -> i32 {
|
||||
pub unsafe extern "C" fn pop16() -> Result<i32, ()> {
|
||||
if *stack_size_32 {
|
||||
return pop16_ss32();
|
||||
pop16_ss32()
|
||||
}
|
||||
else {
|
||||
return pop16_ss16();
|
||||
};
|
||||
pop16_ss16()
|
||||
}
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pop16_ss16() -> i32 {
|
||||
pub unsafe extern "C" fn pop16_ss16() -> Result<i32, ()> {
|
||||
let mut sp: i32 = get_seg_ss() + *reg16.offset(SP as isize) as i32;
|
||||
let mut result: i32 = safe_read16(sp);
|
||||
let mut result: i32 = safe_read16(sp)?;
|
||||
let ref mut fresh4 = *reg16.offset(SP as isize);
|
||||
*fresh4 = (*fresh4 as i32 + 2i32) as u16;
|
||||
return result;
|
||||
Ok(result)
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pop16_ss32() -> i32 {
|
||||
pub unsafe extern "C" fn pop16_ss32() -> Result<i32, ()> {
|
||||
let mut esp: i32 = get_seg_ss() + *reg32s.offset(ESP as isize);
|
||||
let mut result: i32 = safe_read16(esp);
|
||||
let mut result: i32 = safe_read16(esp)?;
|
||||
let ref mut fresh5 = *reg32s.offset(ESP as isize);
|
||||
*fresh5 += 2i32;
|
||||
return result;
|
||||
Ok(result)
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pop32s() -> i32 {
|
||||
pub unsafe extern "C" fn pop32s() -> Result<i32, ()> {
|
||||
if *stack_size_32 {
|
||||
return pop32s_ss32();
|
||||
pop32s_ss32()
|
||||
}
|
||||
else {
|
||||
return pop32s_ss16();
|
||||
};
|
||||
pop32s_ss16()
|
||||
}
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pop32s_ss16() -> i32 {
|
||||
pub unsafe extern "C" fn pop32s_ss16() -> Result<i32, ()> {
|
||||
let mut sp: i32 = *reg16.offset(SP as isize) as i32;
|
||||
let mut result: i32 = safe_read32s(get_seg_ss() + sp);
|
||||
let mut result: i32 = safe_read32s(get_seg_ss() + sp)?;
|
||||
*reg16.offset(SP as isize) = (sp + 4i32) as u16;
|
||||
return result;
|
||||
Ok(result)
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pop32s_ss32() -> i32 {
|
||||
pub unsafe extern "C" fn pop32s_ss32() -> Result<i32, ()> {
|
||||
let mut esp: i32 = *reg32s.offset(ESP as isize);
|
||||
let mut result: i32 = safe_read32s(get_seg_ss() + esp);
|
||||
let mut result: i32 = safe_read32s(get_seg_ss() + esp)?;
|
||||
*reg32s.offset(ESP as isize) = esp + 4i32;
|
||||
return result;
|
||||
Ok(result)
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pusha16() -> () {
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
#![allow
|
||||
( dead_code , mutable_transmutes , non_camel_case_types , non_snake_case ,
|
||||
non_upper_case_globals , unused_mut )]
|
||||
#![feature ( extern_types , libc )]
|
||||
#![allow(
|
||||
dead_code,
|
||||
mutable_transmutes,
|
||||
non_camel_case_types,
|
||||
non_snake_case,
|
||||
non_upper_case_globals,
|
||||
unused_mut
|
||||
)]
|
||||
#![feature(extern_types, libc)]
|
||||
|
||||
use cpu2::cpu::*;
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
@ -303,14 +310,6 @@ extern "C" {
|
|||
#[no_mangle]
|
||||
static CPU_EXCEPTION_VE: i32;
|
||||
#[no_mangle]
|
||||
fn read_imm8() -> i32;
|
||||
#[no_mangle]
|
||||
fn read_imm8s() -> i32;
|
||||
#[no_mangle]
|
||||
fn read_imm16() -> i32;
|
||||
#[no_mangle]
|
||||
fn read_imm32s() -> i32;
|
||||
#[no_mangle]
|
||||
fn get_seg_prefix(default_segment: i32) -> i32;
|
||||
#[no_mangle]
|
||||
fn get_seg_prefix_ds(offset: i32) -> i32;
|
||||
|
@ -853,181 +852,141 @@ unsafe extern "C" fn __isgreaterequall(mut __x: f64, mut __y: f64) -> i32 {
|
|||
} && __x >= __y) as i32;
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn resolve_modrm16(mut modrm_byte: i32) -> i32 {
|
||||
match modrm_byte {
|
||||
0 | 8 | 16 | 24 | 32 | 40 | 48 | 56 => {
|
||||
return get_seg_prefix_ds(
|
||||
*reg16.offset(BX as isize) as i32 + *reg16.offset(SI as isize) as i32 & 65535i32,
|
||||
)
|
||||
},
|
||||
64 | 72 | 80 | 88 | 96 | 104 | 112 | 120 => {
|
||||
return get_seg_prefix_ds(
|
||||
*reg16.offset(BX as isize) as i32
|
||||
+ *reg16.offset(SI as isize) as i32
|
||||
+ read_imm8s()
|
||||
& 65535i32,
|
||||
)
|
||||
},
|
||||
128 | 136 | 144 | 152 | 160 | 168 | 176 | 184 => {
|
||||
return get_seg_prefix_ds(
|
||||
*reg16.offset(BX as isize) as i32
|
||||
+ *reg16.offset(SI as isize) as i32
|
||||
+ read_imm16()
|
||||
& 65535i32,
|
||||
)
|
||||
},
|
||||
1 | 9 | 17 | 25 | 33 | 41 | 49 | 57 => {
|
||||
return get_seg_prefix_ds(
|
||||
*reg16.offset(BX as isize) as i32 + *reg16.offset(DI as isize) as i32 & 65535i32,
|
||||
)
|
||||
},
|
||||
65 | 73 | 81 | 89 | 97 | 105 | 113 | 121 => {
|
||||
return get_seg_prefix_ds(
|
||||
*reg16.offset(BX as isize) as i32
|
||||
+ *reg16.offset(DI as isize) as i32
|
||||
+ read_imm8s()
|
||||
& 65535i32,
|
||||
)
|
||||
},
|
||||
129 | 137 | 145 | 153 | 161 | 169 | 177 | 185 => {
|
||||
return get_seg_prefix_ds(
|
||||
*reg16.offset(BX as isize) as i32
|
||||
+ *reg16.offset(DI as isize) as i32
|
||||
+ read_imm16()
|
||||
& 65535i32,
|
||||
)
|
||||
},
|
||||
2 | 10 | 18 | 26 | 34 | 42 | 50 | 58 => {
|
||||
return get_seg_prefix_ss(
|
||||
*reg16.offset(BP as isize) as i32 + *reg16.offset(SI as isize) as i32 & 65535i32,
|
||||
)
|
||||
},
|
||||
66 | 74 | 82 | 90 | 98 | 106 | 114 | 122 => {
|
||||
return get_seg_prefix_ss(
|
||||
*reg16.offset(BP as isize) as i32
|
||||
+ *reg16.offset(SI as isize) as i32
|
||||
+ read_imm8s()
|
||||
& 65535i32,
|
||||
)
|
||||
},
|
||||
130 | 138 | 146 | 154 | 162 | 170 | 178 | 186 => {
|
||||
return get_seg_prefix_ss(
|
||||
*reg16.offset(BP as isize) as i32
|
||||
+ *reg16.offset(SI as isize) as i32
|
||||
+ read_imm16()
|
||||
& 65535i32,
|
||||
)
|
||||
},
|
||||
3 | 11 | 19 | 27 | 35 | 43 | 51 | 59 => {
|
||||
return get_seg_prefix_ss(
|
||||
*reg16.offset(BP as isize) as i32 + *reg16.offset(DI as isize) as i32 & 65535i32,
|
||||
)
|
||||
},
|
||||
67 | 75 | 83 | 91 | 99 | 107 | 115 | 123 => {
|
||||
return get_seg_prefix_ss(
|
||||
*reg16.offset(BP as isize) as i32
|
||||
+ *reg16.offset(DI as isize) as i32
|
||||
+ read_imm8s()
|
||||
& 65535i32,
|
||||
)
|
||||
},
|
||||
131 | 139 | 147 | 155 | 163 | 171 | 179 | 187 => {
|
||||
return get_seg_prefix_ss(
|
||||
*reg16.offset(BP as isize) as i32
|
||||
+ *reg16.offset(DI as isize) as i32
|
||||
+ read_imm16()
|
||||
& 65535i32,
|
||||
)
|
||||
},
|
||||
pub unsafe extern "C" fn resolve_modrm16(mut modrm_byte: i32) -> Result<i32, ()> {
|
||||
Ok(match modrm_byte {
|
||||
0 | 8 | 16 | 24 | 32 | 40 | 48 | 56 => get_seg_prefix_ds(
|
||||
*reg16.offset(BX as isize) as i32 + *reg16.offset(SI as isize) as i32 & 65535i32,
|
||||
),
|
||||
64 | 72 | 80 | 88 | 96 | 104 | 112 | 120 => get_seg_prefix_ds(
|
||||
*reg16.offset(BX as isize) as i32 + *reg16.offset(SI as isize) as i32 + read_imm8s()?
|
||||
& 65535i32,
|
||||
),
|
||||
128 | 136 | 144 | 152 | 160 | 168 | 176 | 184 => get_seg_prefix_ds(
|
||||
*reg16.offset(BX as isize) as i32 + *reg16.offset(SI as isize) as i32 + read_imm16()?
|
||||
& 65535i32,
|
||||
),
|
||||
1 | 9 | 17 | 25 | 33 | 41 | 49 | 57 => get_seg_prefix_ds(
|
||||
*reg16.offset(BX as isize) as i32 + *reg16.offset(DI as isize) as i32 & 65535i32,
|
||||
),
|
||||
65 | 73 | 81 | 89 | 97 | 105 | 113 | 121 => get_seg_prefix_ds(
|
||||
*reg16.offset(BX as isize) as i32 + *reg16.offset(DI as isize) as i32 + read_imm8s()?
|
||||
& 65535i32,
|
||||
),
|
||||
129 | 137 | 145 | 153 | 161 | 169 | 177 | 185 => get_seg_prefix_ds(
|
||||
*reg16.offset(BX as isize) as i32 + *reg16.offset(DI as isize) as i32 + read_imm16()?
|
||||
& 65535i32,
|
||||
),
|
||||
2 | 10 | 18 | 26 | 34 | 42 | 50 | 58 => get_seg_prefix_ss(
|
||||
*reg16.offset(BP as isize) as i32 + *reg16.offset(SI as isize) as i32 & 65535i32,
|
||||
),
|
||||
66 | 74 | 82 | 90 | 98 | 106 | 114 | 122 => get_seg_prefix_ss(
|
||||
*reg16.offset(BP as isize) as i32 + *reg16.offset(SI as isize) as i32 + read_imm8s()?
|
||||
& 65535i32,
|
||||
),
|
||||
130 | 138 | 146 | 154 | 162 | 170 | 178 | 186 => get_seg_prefix_ss(
|
||||
*reg16.offset(BP as isize) as i32 + *reg16.offset(SI as isize) as i32 + read_imm16()?
|
||||
& 65535i32,
|
||||
),
|
||||
3 | 11 | 19 | 27 | 35 | 43 | 51 | 59 => get_seg_prefix_ss(
|
||||
*reg16.offset(BP as isize) as i32 + *reg16.offset(DI as isize) as i32 & 65535i32,
|
||||
),
|
||||
67 | 75 | 83 | 91 | 99 | 107 | 115 | 123 => get_seg_prefix_ss(
|
||||
*reg16.offset(BP as isize) as i32 + *reg16.offset(DI as isize) as i32 + read_imm8s()?
|
||||
& 65535i32,
|
||||
),
|
||||
131 | 139 | 147 | 155 | 163 | 171 | 179 | 187 => get_seg_prefix_ss(
|
||||
*reg16.offset(BP as isize) as i32 + *reg16.offset(DI as isize) as i32 + read_imm16()?
|
||||
& 65535i32,
|
||||
),
|
||||
4 | 12 | 20 | 28 | 36 | 44 | 52 | 60 => {
|
||||
return get_seg_prefix_ds(*reg16.offset(SI as isize) as i32 & 65535i32)
|
||||
get_seg_prefix_ds(*reg16.offset(SI as isize) as i32 & 65535i32)
|
||||
},
|
||||
68 | 76 | 84 | 92 | 100 | 108 | 116 | 124 => {
|
||||
return get_seg_prefix_ds(*reg16.offset(SI as isize) as i32 + read_imm8s() & 65535i32)
|
||||
get_seg_prefix_ds(*reg16.offset(SI as isize) as i32 + read_imm8s()? & 65535i32)
|
||||
},
|
||||
132 | 140 | 148 | 156 | 164 | 172 | 180 | 188 => {
|
||||
return get_seg_prefix_ds(*reg16.offset(SI as isize) as i32 + read_imm16() & 65535i32)
|
||||
get_seg_prefix_ds(*reg16.offset(SI as isize) as i32 + read_imm16()? & 65535i32)
|
||||
},
|
||||
5 | 13 | 21 | 29 | 37 | 45 | 53 | 61 => {
|
||||
return get_seg_prefix_ds(*reg16.offset(DI as isize) as i32 & 65535i32)
|
||||
get_seg_prefix_ds(*reg16.offset(DI as isize) as i32 & 65535i32)
|
||||
},
|
||||
69 | 77 | 85 | 93 | 101 | 109 | 117 | 125 => {
|
||||
return get_seg_prefix_ds(*reg16.offset(DI as isize) as i32 + read_imm8s() & 65535i32)
|
||||
get_seg_prefix_ds(*reg16.offset(DI as isize) as i32 + read_imm8s()? & 65535i32)
|
||||
},
|
||||
133 | 141 | 149 | 157 | 165 | 173 | 181 | 189 => {
|
||||
return get_seg_prefix_ds(*reg16.offset(DI as isize) as i32 + read_imm16() & 65535i32)
|
||||
get_seg_prefix_ds(*reg16.offset(DI as isize) as i32 + read_imm16()? & 65535i32)
|
||||
},
|
||||
6 | 14 | 22 | 30 | 38 | 46 | 54 | 62 => return get_seg_prefix_ds(read_imm16()),
|
||||
6 | 14 | 22 | 30 | 38 | 46 | 54 | 62 => get_seg_prefix_ds(read_imm16()?),
|
||||
70 | 78 | 86 | 94 | 102 | 110 | 118 | 126 => {
|
||||
return get_seg_prefix_ss(*reg16.offset(BP as isize) as i32 + read_imm8s() & 65535i32)
|
||||
get_seg_prefix_ss(*reg16.offset(BP as isize) as i32 + read_imm8s()? & 65535i32)
|
||||
},
|
||||
134 | 142 | 150 | 158 | 166 | 174 | 182 | 190 => {
|
||||
return get_seg_prefix_ss(*reg16.offset(BP as isize) as i32 + read_imm16() & 65535i32)
|
||||
get_seg_prefix_ss(*reg16.offset(BP as isize) as i32 + read_imm16()? & 65535i32)
|
||||
},
|
||||
7 | 15 | 23 | 31 | 39 | 47 | 55 | 63 => {
|
||||
return get_seg_prefix_ds(*reg16.offset(BX as isize) as i32 & 65535i32)
|
||||
get_seg_prefix_ds(*reg16.offset(BX as isize) as i32 & 65535i32)
|
||||
},
|
||||
71 | 79 | 87 | 95 | 103 | 111 | 119 | 127 => {
|
||||
return get_seg_prefix_ds(*reg16.offset(BX as isize) as i32 + read_imm8s() & 65535i32)
|
||||
get_seg_prefix_ds(*reg16.offset(BX as isize) as i32 + read_imm8s()? & 65535i32)
|
||||
},
|
||||
135 | 143 | 151 | 159 | 167 | 175 | 183 | 191 => {
|
||||
return get_seg_prefix_ds(*reg16.offset(BX as isize) as i32 + read_imm16() & 65535i32)
|
||||
get_seg_prefix_ds(*reg16.offset(BX as isize) as i32 + read_imm16()? & 65535i32)
|
||||
},
|
||||
_ => {
|
||||
dbg_assert!(0 != 0i32);
|
||||
return 0i32;
|
||||
0i32
|
||||
},
|
||||
};
|
||||
})
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn resolve_modrm32(mut modrm_byte: i32) -> i32 {
|
||||
pub unsafe extern "C" fn resolve_modrm32_(mut modrm_byte: i32) -> Result<i32, ()> {
|
||||
let mut r: u8 = (modrm_byte & 7i32) as u8;
|
||||
dbg_assert!(modrm_byte < 192i32);
|
||||
if r as i32 == 4i32 {
|
||||
Ok(if r as i32 == 4i32 {
|
||||
if modrm_byte < 64i32 {
|
||||
return resolve_sib(0 != 0i32);
|
||||
resolve_sib(0 != 0i32)?
|
||||
}
|
||||
else {
|
||||
return resolve_sib(0 != 1i32) + if modrm_byte < 128i32 {
|
||||
read_imm8s()
|
||||
resolve_sib(0 != 1i32)? + if modrm_byte < 128i32 {
|
||||
read_imm8s()?
|
||||
}
|
||||
else {
|
||||
read_imm32s()
|
||||
};
|
||||
read_imm32s()?
|
||||
}
|
||||
}
|
||||
}
|
||||
else if r as i32 == 5i32 {
|
||||
if modrm_byte < 64i32 {
|
||||
return get_seg_prefix_ds(read_imm32s());
|
||||
get_seg_prefix_ds(read_imm32s()?)
|
||||
}
|
||||
else {
|
||||
return get_seg_prefix_ss(
|
||||
get_seg_prefix_ss(
|
||||
*reg32s.offset(EBP as isize) + if modrm_byte < 128i32 {
|
||||
read_imm8s()
|
||||
read_imm8s()?
|
||||
}
|
||||
else {
|
||||
read_imm32s()
|
||||
read_imm32s()?
|
||||
},
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
else if modrm_byte < 64i32 {
|
||||
return get_seg_prefix_ds(*reg32s.offset(r as isize));
|
||||
get_seg_prefix_ds(*reg32s.offset(r as isize))
|
||||
}
|
||||
else {
|
||||
return get_seg_prefix_ds(
|
||||
get_seg_prefix_ds(
|
||||
*reg32s.offset(r as isize) + if modrm_byte < 128i32 {
|
||||
read_imm8s()
|
||||
read_imm8s()?
|
||||
}
|
||||
else {
|
||||
read_imm32s()
|
||||
read_imm32s()?
|
||||
},
|
||||
);
|
||||
};
|
||||
)
|
||||
})
|
||||
}
|
||||
unsafe extern "C" fn resolve_sib(mut mod_0: bool) -> i32 {
|
||||
unsafe extern "C" fn resolve_sib(mut mod_0: bool) -> Result<i32, ()> {
|
||||
let mut s: u8 = 0;
|
||||
let mut sib_byte: u8 = read_imm8() as u8;
|
||||
let mut sib_byte: u8 = read_imm8()? as u8;
|
||||
let mut r: u8 = (sib_byte as i32 & 7i32) as u8;
|
||||
let mut m: u8 = (sib_byte as i32 >> 3i32 & 7i32) as u8;
|
||||
let mut base: i32 = 0;
|
||||
|
@ -1042,7 +1001,7 @@ unsafe extern "C" fn resolve_sib(mut mod_0: bool) -> i32 {
|
|||
seg = SS
|
||||
}
|
||||
else {
|
||||
base = read_imm32s();
|
||||
base = read_imm32s()?;
|
||||
seg = DS
|
||||
}
|
||||
}
|
||||
|
@ -1058,7 +1017,7 @@ unsafe extern "C" fn resolve_sib(mut mod_0: bool) -> i32 {
|
|||
s = (sib_byte as i32 >> 6i32 & 3i32) as u8;
|
||||
offset = *reg32s.offset(m as isize) << s as i32
|
||||
}
|
||||
return get_seg_prefix(seg) + base + offset;
|
||||
Ok(get_seg_prefix(seg) + base + offset)
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn MODRM_ENTRY() -> i32 { return 0i32; }
|
||||
|
@ -1067,77 +1026,63 @@ pub unsafe extern "C" fn MODRM_ENTRY16() -> i32 { return 0i32; }
|
|||
#[no_mangle]
|
||||
pub unsafe extern "C" fn MODRM_ENTRY32() -> i32 { return 0i32; }
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn resolve_modrm32_(mut modrm_byte: i32) -> i32 {
|
||||
match modrm_byte {
|
||||
0 | 8 | 16 | 24 | 32 | 40 | 48 | 56 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(EAX as isize))
|
||||
},
|
||||
pub unsafe extern "C" fn resolve_modrm32(mut modrm_byte: i32) -> Result<i32, ()> {
|
||||
Ok(match modrm_byte {
|
||||
0 | 8 | 16 | 24 | 32 | 40 | 48 | 56 => get_seg_prefix_ds(*reg32s.offset(EAX as isize)),
|
||||
64 | 72 | 80 | 88 | 96 | 104 | 112 | 120 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(EAX as isize) + read_imm8s())
|
||||
get_seg_prefix_ds(*reg32s.offset(EAX as isize) + read_imm8s()?)
|
||||
},
|
||||
128 | 136 | 144 | 152 | 160 | 168 | 176 | 184 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(EAX as isize) + read_imm32s())
|
||||
},
|
||||
1 | 9 | 17 | 25 | 33 | 41 | 49 | 57 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(ECX as isize))
|
||||
get_seg_prefix_ds(*reg32s.offset(EAX as isize) + read_imm32s()?)
|
||||
},
|
||||
1 | 9 | 17 | 25 | 33 | 41 | 49 | 57 => get_seg_prefix_ds(*reg32s.offset(ECX as isize)),
|
||||
65 | 73 | 81 | 89 | 97 | 105 | 113 | 121 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(ECX as isize) + read_imm8s())
|
||||
get_seg_prefix_ds(*reg32s.offset(ECX as isize) + read_imm8s()?)
|
||||
},
|
||||
129 | 137 | 145 | 153 | 161 | 169 | 177 | 185 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(ECX as isize) + read_imm32s())
|
||||
},
|
||||
2 | 10 | 18 | 26 | 34 | 42 | 50 | 58 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(EDX as isize))
|
||||
get_seg_prefix_ds(*reg32s.offset(ECX as isize) + read_imm32s()?)
|
||||
},
|
||||
2 | 10 | 18 | 26 | 34 | 42 | 50 | 58 => get_seg_prefix_ds(*reg32s.offset(EDX as isize)),
|
||||
66 | 74 | 82 | 90 | 98 | 106 | 114 | 122 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(EDX as isize) + read_imm8s())
|
||||
get_seg_prefix_ds(*reg32s.offset(EDX as isize) + read_imm8s()?)
|
||||
},
|
||||
130 | 138 | 146 | 154 | 162 | 170 | 178 | 186 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(EDX as isize) + read_imm32s())
|
||||
},
|
||||
3 | 11 | 19 | 27 | 35 | 43 | 51 | 59 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(EBX as isize))
|
||||
get_seg_prefix_ds(*reg32s.offset(EDX as isize) + read_imm32s()?)
|
||||
},
|
||||
3 | 11 | 19 | 27 | 35 | 43 | 51 | 59 => get_seg_prefix_ds(*reg32s.offset(EBX as isize)),
|
||||
67 | 75 | 83 | 91 | 99 | 107 | 115 | 123 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(EBX as isize) + read_imm8s())
|
||||
get_seg_prefix_ds(*reg32s.offset(EBX as isize) + read_imm8s()?)
|
||||
},
|
||||
131 | 139 | 147 | 155 | 163 | 171 | 179 | 187 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(EBX as isize) + read_imm32s())
|
||||
get_seg_prefix_ds(*reg32s.offset(EBX as isize) + read_imm32s()?)
|
||||
},
|
||||
4 | 12 | 20 | 28 | 36 | 44 | 52 | 60 => return resolve_sib(0 != 0i32),
|
||||
68 | 76 | 84 | 92 | 100 | 108 | 116 | 124 => return resolve_sib(0 != 1i32) + read_imm8s(),
|
||||
132 | 140 | 148 | 156 | 164 | 172 | 180 | 188 => {
|
||||
return resolve_sib(0 != 1i32) + read_imm32s()
|
||||
},
|
||||
5 | 13 | 21 | 29 | 37 | 45 | 53 | 61 => return get_seg_prefix_ds(read_imm32s()),
|
||||
4 | 12 | 20 | 28 | 36 | 44 | 52 | 60 => resolve_sib(0 != 0i32)?,
|
||||
68 | 76 | 84 | 92 | 100 | 108 | 116 | 124 => resolve_sib(0 != 1i32)? + read_imm8s()?,
|
||||
132 | 140 | 148 | 156 | 164 | 172 | 180 | 188 => resolve_sib(0 != 1i32)? + read_imm32s()?,
|
||||
5 | 13 | 21 | 29 | 37 | 45 | 53 | 61 => get_seg_prefix_ds(read_imm32s()?),
|
||||
69 | 77 | 85 | 93 | 101 | 109 | 117 | 125 => {
|
||||
return get_seg_prefix_ss(*reg32s.offset(EBP as isize) + read_imm8s())
|
||||
get_seg_prefix_ss(*reg32s.offset(EBP as isize) + read_imm8s()?)
|
||||
},
|
||||
133 | 141 | 149 | 157 | 165 | 173 | 181 | 189 => {
|
||||
return get_seg_prefix_ss(*reg32s.offset(EBP as isize) + read_imm32s())
|
||||
},
|
||||
6 | 14 | 22 | 30 | 38 | 46 | 54 | 62 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(ESI as isize))
|
||||
get_seg_prefix_ss(*reg32s.offset(EBP as isize) + read_imm32s()?)
|
||||
},
|
||||
6 | 14 | 22 | 30 | 38 | 46 | 54 | 62 => get_seg_prefix_ds(*reg32s.offset(ESI as isize)),
|
||||
70 | 78 | 86 | 94 | 102 | 110 | 118 | 126 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(ESI as isize) + read_imm8s())
|
||||
get_seg_prefix_ds(*reg32s.offset(ESI as isize) + read_imm8s()?)
|
||||
},
|
||||
134 | 142 | 150 | 158 | 166 | 174 | 182 | 190 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(ESI as isize) + read_imm32s())
|
||||
},
|
||||
7 | 15 | 23 | 31 | 39 | 47 | 55 | 63 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(EDI as isize))
|
||||
get_seg_prefix_ds(*reg32s.offset(ESI as isize) + read_imm32s()?)
|
||||
},
|
||||
7 | 15 | 23 | 31 | 39 | 47 | 55 | 63 => get_seg_prefix_ds(*reg32s.offset(EDI as isize)),
|
||||
71 | 79 | 87 | 95 | 103 | 111 | 119 | 127 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(EDI as isize) + read_imm8s())
|
||||
get_seg_prefix_ds(*reg32s.offset(EDI as isize) + read_imm8s()?)
|
||||
},
|
||||
135 | 143 | 151 | 159 | 167 | 175 | 183 | 191 => {
|
||||
return get_seg_prefix_ds(*reg32s.offset(EDI as isize) + read_imm32s())
|
||||
get_seg_prefix_ds(*reg32s.offset(EDI as isize) + read_imm32s()?)
|
||||
},
|
||||
_ => {
|
||||
dbg_assert!(0 != 0i32);
|
||||
return 0i32;
|
||||
0i32
|
||||
},
|
||||
};
|
||||
})
|
||||
}
|
||||
|
|
43
src/rust/js_api.rs
Normal file
43
src/rust/js_api.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
use cpu2::cpu::{
|
||||
safe_read16, safe_read32s, safe_write16, safe_write32, translate_address_read,
|
||||
translate_address_system_read, translate_address_system_write, writable_or_pagefault,
|
||||
};
|
||||
use cpu2::misc_instr::{pop16, pop32s, push16, push32};
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn safe_read16_js(addr: i32) -> i32 { safe_read16(addr).unwrap() }
|
||||
#[no_mangle]
|
||||
pub unsafe fn safe_read32s_js(addr: i32) -> i32 { safe_read32s(addr).unwrap() }
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn safe_write16_js(addr: i32, value: i32) { safe_write16(addr, value).unwrap() }
|
||||
#[no_mangle]
|
||||
pub unsafe fn safe_write32_js(addr: i32, value: i32) { safe_write32(addr, value).unwrap() }
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn translate_address_read_js(addr: i32) -> u32 { translate_address_read(addr).unwrap() }
|
||||
#[no_mangle]
|
||||
pub unsafe fn translate_address_system_read_js(addr: i32) -> u32 {
|
||||
translate_address_system_read(addr).unwrap()
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe fn translate_address_system_write_js(addr: i32) -> u32 {
|
||||
translate_address_system_write(addr).unwrap()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn writable_or_pagefault_js(addr: i32, size: i32) -> bool {
|
||||
writable_or_pagefault(addr, size).is_ok()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn push16_js(value: i32) { push16(value).unwrap() }
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn push32_js(value: i32) { push32(value).unwrap() }
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn pop16_js() -> i32 { pop16().unwrap() }
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn pop32s_js() -> i32 { pop32s().unwrap() }
|
|
@ -8,9 +8,13 @@ extern crate quickcheck;
|
|||
#[macro_use]
|
||||
mod dbg;
|
||||
|
||||
#[macro_use]
|
||||
mod paging;
|
||||
|
||||
pub mod cpu2;
|
||||
|
||||
pub mod c_api;
|
||||
pub mod js_api;
|
||||
|
||||
mod analysis;
|
||||
mod codegen;
|
||||
|
|
8
src/rust/paging.rs
Normal file
8
src/rust/paging.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
macro_rules! return_on_pagefault {
|
||||
($expr:expr) => {
|
||||
match $expr {
|
||||
Ok(v) => v,
|
||||
Err(()) => return,
|
||||
}
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue