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:
Fabian 2018-08-14 16:07:54 -05:00
parent 11ee22176d
commit a88420910d
10 changed files with 622 additions and 524 deletions

View file

@ -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,
"}",

View file

@ -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, },

View file

@ -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);

View file

@ -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]

View file

@ -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);
}
},
}
}};
}

View file

@ -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() -> () {

View file

@ -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
View 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() }

View file

@ -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
View file

@ -0,0 +1,8 @@
macro_rules! return_on_pagefault {
($expr:expr) => {
match $expr {
Ok(v) => v,
Err(()) => return,
}
};
}