The final Rust porting
This commit contains the final changes requires for porting all C code to Rust and from emscripten to llvm: - tools/wasm-patch-indirect-function-table.js: A script that rewrites the wasm generated by llvm to remove the table limit - tools/rust-lld-wrapper: A wrapper around rust-lld that removes arguments forced by rustc that break compilation for us - src/rust/cpu2/Makefile: A monstrosity to postprocess c2rust's output - gen/generate_interpreter.js: Ported to produce Rust instead of C - src/rust/*: A few functions and macros to connect the old Rust code and the new Rust code - src/*.js: Removes the loading of the old emscripten wasm module and adapts imports and exports from emscripten to llvm
This commit is contained in:
parent
6de0bb374b
commit
01061dc4b6
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -21,6 +21,9 @@ package-lock.json
|
|||
profile*.json
|
||||
Cargo.lock
|
||||
build-head
|
||||
src/rust/gen/interpreter.rs
|
||||
src/rust/gen/interpreter0f_16.rs
|
||||
src/rust/gen/interpreter0f_32.rs
|
||||
src/rust/gen/analyzer.rs
|
||||
src/rust/gen/analyzer0f_16.rs
|
||||
src/rust/gen/analyzer0f_32.rs
|
||||
|
|
|
@ -12,8 +12,11 @@ path = "src/rust/lib.rs"
|
|||
|
||||
[profile.dev]
|
||||
lto = false
|
||||
opt-level=2
|
||||
# XXX: 2 -> removes debug information in later rust verions
|
||||
# 0 -> requires more imports that are optimised away
|
||||
opt-level = 2
|
||||
panic = "abort"
|
||||
overflow-checks = false
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
|
45
Makefile
45
Makefile
|
@ -5,7 +5,7 @@ NASM_TEST_DIR=./tests/nasm
|
|||
COVERAGE_DIR=./tests/coverage
|
||||
|
||||
INSTRUCTION_TABLES=src/rust/gen/jit.rs src/rust/gen/jit0f_16.rs src/rust/gen/jit0f_32.rs \
|
||||
build/interpreter.c build/interpreter0f_16.c build/interpreter0f_32.c \
|
||||
src/rust/gen/interpreter.rs src/rust/gen/interpreter0f_16.rs src/rust/gen/interpreter0f_32.rs \
|
||||
src/rust/gen/analyzer.rs src/rust/gen/analyzer0f_16.rs src/rust/gen/analyzer0f_32.rs \
|
||||
|
||||
# Only the dependencies common to both generate_{jit,interpreter}.js
|
||||
|
@ -102,7 +102,9 @@ CC_FLAGS=\
|
|||
|
||||
CARGO_FLAGS=\
|
||||
--target wasm32-unknown-unknown \
|
||||
-- -Clink-args="--import-memory" \
|
||||
-- \
|
||||
-C linker=tools/rust-lld-wrapper \
|
||||
-C link-args="--import-table --global-base=142606336" \
|
||||
--verbose
|
||||
|
||||
CORE_FILES=const.js config.js io.js main.js lib.js coverage.js ide.js pci.js floppy.js \
|
||||
|
@ -116,6 +118,7 @@ BROWSER_FILES=screen.js \
|
|||
network.js lib.js starter.js worker_bus.js dummy_screen.js print_stats.js
|
||||
|
||||
RUST_FILES=$(shell find src/rust/ -name '*.rs') \
|
||||
src/rust/gen/interpreter.rs src/rust/gen/interpreter0f_16.rs src/rust/gen/interpreter0f_32.rs \
|
||||
src/rust/gen/jit.rs src/rust/gen/jit0f_16.rs src/rust/gen/jit0f_32.rs \
|
||||
src/rust/gen/analyzer.rs src/rust/gen/analyzer0f_16.rs src/rust/gen/analyzer0f_32.rs
|
||||
|
||||
|
@ -183,11 +186,11 @@ src/rust/gen/jit0f_16.rs: $(JIT_DEPENDENCIES)
|
|||
src/rust/gen/jit0f_32.rs: $(JIT_DEPENDENCIES)
|
||||
./gen/generate_jit.js --output-dir build/ --table jit0f_32
|
||||
|
||||
build/interpreter.c: $(INTERPRETER_DEPENDENCIES)
|
||||
src/rust/gen/interpreter.rs: $(INTERPRETER_DEPENDENCIES)
|
||||
./gen/generate_interpreter.js --output-dir build/ --table interpreter
|
||||
build/interpreter0f_16.c: $(INTERPRETER_DEPENDENCIES)
|
||||
src/rust/gen/interpreter0f_16.rs: $(INTERPRETER_DEPENDENCIES)
|
||||
./gen/generate_interpreter.js --output-dir build/ --table interpreter0f_16
|
||||
build/interpreter0f_32.c: $(INTERPRETER_DEPENDENCIES)
|
||||
src/rust/gen/interpreter0f_32.rs: $(INTERPRETER_DEPENDENCIES)
|
||||
./gen/generate_interpreter.js --output-dir build/ --table interpreter0f_32
|
||||
|
||||
src/rust/gen/analyzer.rs: $(ANALYZER_DEPENDENCIES)
|
||||
|
@ -200,38 +203,38 @@ src/rust/gen/analyzer0f_32.rs: $(ANALYZER_DEPENDENCIES)
|
|||
build/v86.wasm: src/native/*.c src/native/*.h src/native/profiler/* src/native/*.ll $(INSTRUCTION_TABLES)
|
||||
mkdir -p build
|
||||
-ls -lh build/v86.wasm
|
||||
emcc src/native/*.c src/native/profiler/*.c src/native/*.ll \
|
||||
$(CC_FLAGS) \
|
||||
-DDEBUG=false \
|
||||
-DNDEBUG \
|
||||
-O3 \
|
||||
--llvm-opts 3 \
|
||||
--llvm-lto 3 \
|
||||
-o build/v86.wasm
|
||||
#emcc src/native/*.c src/native/profiler/*.c src/native/*.ll \
|
||||
# $(CC_FLAGS) \
|
||||
# -DDEBUG=false \
|
||||
# -DNDEBUG \
|
||||
# -O3 \
|
||||
# --llvm-opts 3 \
|
||||
# --llvm-lto 3 \
|
||||
# -o build/v86.wasm
|
||||
ls -lh build/v86.wasm
|
||||
|
||||
build/v86-debug.wasm: src/native/*.c src/native/*.h src/native/profiler/* src/native/*.ll $(INSTRUCTION_TABLES)
|
||||
mkdir -p build/coverage
|
||||
-ls -lh build/v86-debug.wasm
|
||||
emcc src/native/*.c src/native/profiler/*.c src/native/*.ll \
|
||||
$(CC_FLAGS) \
|
||||
$(CC_COVERAGE_FLAGS) \
|
||||
-Os \
|
||||
-o build/v86-debug.wasm
|
||||
ls -lh build/v86-debug.wasm
|
||||
#emcc src/native/*.c src/native/profiler/*.c src/native/*.ll \
|
||||
# $(CC_FLAGS) \
|
||||
# $(CC_COVERAGE_FLAGS) \
|
||||
# -Os \
|
||||
# -o build/v86-debug.wasm
|
||||
#ls -lh build/v86-debug.wasm
|
||||
|
||||
build/v86oxide.wasm: $(RUST_FILES) Cargo.toml
|
||||
mkdir -p build/
|
||||
-ls -lh build/v86oxide.wasm
|
||||
cargo +nightly rustc --release $(CARGO_FLAGS)
|
||||
cp build/wasm32-unknown-unknown/release/v86oxide.wasm build/v86oxide.wasm
|
||||
./tools/wasm-patch-indirect-function-table.js < build/wasm32-unknown-unknown/release/v86oxide.wasm > build/v86oxide.wasm
|
||||
ls -lh build/v86oxide.wasm
|
||||
|
||||
build/v86oxide-debug.wasm: $(RUST_FILES) Cargo.toml
|
||||
mkdir -p build/
|
||||
-ls -lh build/v86oxide-debug.wasm
|
||||
cargo +nightly rustc $(CARGO_FLAGS)
|
||||
cp build/wasm32-unknown-unknown/debug/v86oxide.wasm build/v86oxide-debug.wasm
|
||||
./tools/wasm-patch-indirect-function-table.js < build/wasm32-unknown-unknown/debug/v86oxide.wasm > build/v86oxide-debug.wasm
|
||||
ls -lh build/v86oxide-debug.wasm
|
||||
|
||||
clean:
|
||||
|
|
|
@ -3,7 +3,7 @@ FROM ttt43ttt/emscripten
|
|||
RUN \
|
||||
dpkg --add-architecture i386 && \
|
||||
apt-get update -qq && \
|
||||
apt-get install -y clang-tidy gcc-multilib nasm gdb unzip openjdk-8-jre wget python qemu-system-x86 && \
|
||||
apt-get install -y clang-tidy gcc-multilib nasm gdb unzip openjdk-8-jre wget python python3 qemu-system-x86 && \
|
||||
wget https://nodejs.org/dist/v8.9.4/node-v8.9.4-linux-x64.tar.xz && \
|
||||
tar xfv node-v8.9.4-linux-x64.tar.xz && \
|
||||
rm node-v8.9.4-linux-x64.tar.xz && \
|
||||
|
@ -12,5 +12,6 @@ RUN \
|
|||
rm ./rustup.sh && \
|
||||
export PATH="$HOME/.cargo/bin:$PATH" && \
|
||||
rustup toolchain install nightly && \
|
||||
rustup default nightly && \
|
||||
rustup target add wasm32-unknown-unknown --toolchain nightly && \
|
||||
rustup component add rustfmt-preview --toolchain nightly
|
||||
|
|
|
@ -4,11 +4,10 @@
|
|||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const x86_table = require("./x86_table");
|
||||
const c_ast = require("./c_ast");
|
||||
const { hex, mkdirpSync, get_switch_value, get_switch_exist, finalize_table } = require("./util");
|
||||
const rust_ast = require("./rust_ast");
|
||||
const { hex, mkdirpSync, get_switch_value, get_switch_exist, finalize_table_rust } = require("./util");
|
||||
|
||||
const OUT_DIR = get_switch_value("--output-dir") ||
|
||||
path.join(__dirname, "..", "build");
|
||||
const OUT_DIR = path.join(__dirname, "..", "src/rust/gen/");
|
||||
|
||||
mkdirpSync(OUT_DIR);
|
||||
|
||||
|
@ -125,7 +124,7 @@ function gen_instruction_body(encodings, size)
|
|||
|
||||
if(encoding.e)
|
||||
{
|
||||
code.push("int32_t modrm_byte = read_imm8();");
|
||||
code.push("let modrm_byte = read_imm8();");
|
||||
}
|
||||
|
||||
if(has_66.length || has_F2.length || has_F3.length)
|
||||
|
@ -134,28 +133,28 @@ function gen_instruction_body(encodings, size)
|
|||
|
||||
if(has_66.length) {
|
||||
const body = gen_instruction_body_after_prefix(has_66, size);
|
||||
if_blocks.push({ condition: "prefixes_ & PREFIX_66", body, });
|
||||
if_blocks.push({ condition: "prefixes_ & PREFIX_66 != 0", body, });
|
||||
}
|
||||
if(has_F2.length) {
|
||||
const body = gen_instruction_body_after_prefix(has_F2, size);
|
||||
if_blocks.push({ condition: "prefixes_ & PREFIX_F2", body, });
|
||||
if_blocks.push({ condition: "prefixes_ & PREFIX_F2 != 0", body, });
|
||||
}
|
||||
if(has_F3.length) {
|
||||
const body = gen_instruction_body_after_prefix(has_F3, size);
|
||||
if_blocks.push({ condition: "prefixes_ & PREFIX_F3", body, });
|
||||
if_blocks.push({ condition: "prefixes_ & PREFIX_F3 != 0", body, });
|
||||
}
|
||||
|
||||
const check_prefixes = encoding.sse ? "(PREFIX_66 | PREFIX_F2 | PREFIX_F3)" : "(PREFIX_F2 | PREFIX_F3)";
|
||||
|
||||
const else_block = {
|
||||
body: [].concat(
|
||||
"dbg_assert((prefixes_ & " + check_prefixes + ") == 0);",
|
||||
"dbg_assert!((prefixes_ & " + check_prefixes + ") == 0);",
|
||||
gen_instruction_body_after_prefix(no_prefix, size)
|
||||
)
|
||||
};
|
||||
|
||||
return [].concat(
|
||||
"int32_t prefixes_ = *prefixes;",
|
||||
"let prefixes_ = *prefixes as i32;",
|
||||
code,
|
||||
{
|
||||
type: "if-else",
|
||||
|
@ -206,7 +205,7 @@ function gen_instruction_body_after_prefix(encodings, size)
|
|||
|
||||
default_case: {
|
||||
body: [
|
||||
"assert(false);",
|
||||
"assert!(false);",
|
||||
"trigger_ud();",
|
||||
],
|
||||
}
|
||||
|
@ -366,6 +365,7 @@ function gen_table()
|
|||
console.assert(encoding && encoding.length);
|
||||
|
||||
let opcode_hex = hex(opcode, 2);
|
||||
let opcode_high_hex = hex(opcode | 0x100, 2);
|
||||
|
||||
if(encoding[0].os)
|
||||
{
|
||||
|
@ -374,14 +374,14 @@ function gen_table()
|
|||
body: gen_instruction_body(encoding, 16),
|
||||
});
|
||||
cases.push({
|
||||
conditions: [`0x${opcode_hex}|0x100`],
|
||||
conditions: [`0x${opcode_high_hex}`],
|
||||
body: gen_instruction_body(encoding, 32),
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
cases.push({
|
||||
conditions: [`0x${opcode_hex}`, `0x${opcode_hex}|0x100`],
|
||||
conditions: [`0x${opcode_hex}`, `0x${opcode_high_hex}`],
|
||||
body: gen_instruction_body(encoding, undefined),
|
||||
});
|
||||
}
|
||||
|
@ -391,15 +391,28 @@ function gen_table()
|
|||
condition: "opcode",
|
||||
cases,
|
||||
default_case: {
|
||||
body: ["assert(false);"]
|
||||
body: ["assert!(false);"]
|
||||
},
|
||||
};
|
||||
if(to_generate.interpreter)
|
||||
{
|
||||
finalize_table(
|
||||
const code = [
|
||||
"use cpu2::cpu::*;",
|
||||
"use cpu2::instructions::*;",
|
||||
"use cpu2::instructions_0f::*;",
|
||||
"use cpu2::modrm::*;",
|
||||
"use cpu2::global_pointers::*;",
|
||||
|
||||
"#[cfg_attr(rustfmt, rustfmt_skip)]",
|
||||
"pub unsafe fn run(opcode: u32) {",
|
||||
table,
|
||||
"}",
|
||||
];
|
||||
|
||||
finalize_table_rust(
|
||||
OUT_DIR,
|
||||
"interpreter",
|
||||
c_ast.print_syntax_tree([table]).join("\n") + "\n"
|
||||
"interpreter.rs",
|
||||
rust_ast.print_syntax_tree([].concat(code)).join("\n") + "\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -440,7 +453,7 @@ function gen_table()
|
|||
condition: "opcode",
|
||||
cases: cases0f_16,
|
||||
default_case: {
|
||||
body: ["assert(false);"]
|
||||
body: ["assert!(false);"]
|
||||
},
|
||||
};
|
||||
const table0f_32 = {
|
||||
|
@ -448,25 +461,51 @@ function gen_table()
|
|||
condition: "opcode",
|
||||
cases: cases0f_32,
|
||||
default_case: {
|
||||
body: ["assert(false);"]
|
||||
body: ["assert!(false);"]
|
||||
},
|
||||
};
|
||||
|
||||
if(to_generate.interpreter0f_16)
|
||||
{
|
||||
finalize_table(
|
||||
const code = [
|
||||
"use cpu2::cpu::*;",
|
||||
"use cpu2::instructions::*;",
|
||||
"use cpu2::instructions_0f::*;",
|
||||
"use cpu2::modrm::*;",
|
||||
"use cpu2::global_pointers::*;",
|
||||
|
||||
"#[cfg_attr(rustfmt, rustfmt_skip)]",
|
||||
"pub unsafe fn run(opcode: u8) {",
|
||||
table0f_16,
|
||||
"}",
|
||||
];
|
||||
|
||||
finalize_table_rust(
|
||||
OUT_DIR,
|
||||
"interpreter0f_16",
|
||||
c_ast.print_syntax_tree([table0f_16]).join("\n") + "\n"
|
||||
"interpreter0f_16.rs",
|
||||
rust_ast.print_syntax_tree([].concat(code)).join("\n") + "\n"
|
||||
);
|
||||
}
|
||||
|
||||
if(to_generate.interpreter0f_32)
|
||||
{
|
||||
finalize_table(
|
||||
const code = [
|
||||
"use cpu2::cpu::*;",
|
||||
"use cpu2::instructions::*;",
|
||||
"use cpu2::instructions_0f::*;",
|
||||
"use cpu2::modrm::*;",
|
||||
"use cpu2::global_pointers::*;",
|
||||
|
||||
"#[cfg_attr(rustfmt, rustfmt_skip)]",
|
||||
"pub unsafe fn run(opcode: u8) {",
|
||||
table0f_32,
|
||||
"}",
|
||||
];
|
||||
|
||||
finalize_table_rust(
|
||||
OUT_DIR,
|
||||
"interpreter0f_32",
|
||||
c_ast.print_syntax_tree([table0f_32]).join("\n") + "\n"
|
||||
"interpreter0f_32.rs",
|
||||
rust_ast.print_syntax_tree([].concat(code)).join("\n") + "\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ function SerialAdapter(element, bus)
|
|||
this.update_timer = setTimeout(() => {
|
||||
this.update_timer = undefined;
|
||||
var now = Date.now();
|
||||
dbg_assert(now - this.last_update >= 16);
|
||||
dbg_assert(now - this.last_update >= 15);
|
||||
this.last_update = now;
|
||||
this.render();
|
||||
}, 16 - delta);
|
||||
|
|
|
@ -94,21 +94,22 @@ function V86Starter(options)
|
|||
this.emulator_bus = bus[1];
|
||||
var emulator;
|
||||
var cpu;
|
||||
var mem;
|
||||
var mem8;
|
||||
var v86oxide;
|
||||
const coverage_logger = new CoverageLogger();
|
||||
|
||||
if(coverage_logger.ENABLED)
|
||||
{
|
||||
this.bus.register("emulator-stopped", function()
|
||||
{
|
||||
coverage_logger.dump_to_files();
|
||||
}, this);
|
||||
}
|
||||
//if(coverage_logger.ENABLED)
|
||||
//{
|
||||
// this.bus.register("emulator-stopped", function()
|
||||
// {
|
||||
// coverage_logger.dump_to_files();
|
||||
// }, this);
|
||||
//}
|
||||
|
||||
const wasm_table = new WebAssembly.Table({ element: "anyfunc", initial: 0x10000 + 0x100 });
|
||||
|
||||
var wasm_shared_funcs = {
|
||||
"___assert_fail": (condition, file, line, fun) => {
|
||||
const memory = mem8;
|
||||
"__assert_fail": (condition, file, line, fun) => {
|
||||
const memory = new Uint8Array(v86oxide.exports.memory.buffer);
|
||||
|
||||
function read_string(memory, offset)
|
||||
{
|
||||
|
@ -130,88 +131,90 @@ function V86Starter(options)
|
|||
|
||||
dbg_assert(false);
|
||||
},
|
||||
"_throw_cpu_exception": () => {
|
||||
"throw_cpu_exception": () => {
|
||||
throw MAGIC_CPU_EXCEPTION;
|
||||
},
|
||||
"_cpu_exception_hook": (n) => {
|
||||
"cpu_exception_hook": (n) => {
|
||||
return this["cpu_exception_hook"] && this["cpu_exception_hook"](n);
|
||||
},
|
||||
"_hlt_op": function() { return cpu.hlt_op(); },
|
||||
"hlt_op": function() { return cpu.hlt_op(); },
|
||||
"abort": function() { dbg_assert(false); },
|
||||
"__dbg_trace": function() { return dbg_trace(); },
|
||||
"_logop": function(eip, op) { return cpu.debug.logop(eip, op); },
|
||||
"_undefined_instruction": function() { return cpu.undefined_instruction.apply(cpu, arguments); },
|
||||
"_unimplemented_sse": function() { return cpu.unimplemented_sse(); },
|
||||
"_microtick": v86.microtick,
|
||||
"_get_rand_int": function() { return v86util.get_rand_int(); },
|
||||
"_has_rand_int": function() { return v86util.has_rand_int(); },
|
||||
"_printf": function(format_string_offset, stack_top) {
|
||||
"_dbg_trace": function() { return dbg_trace(); },
|
||||
"logop": function(eip, op) { return cpu.debug.logop(eip, op); },
|
||||
"undefined_instruction": function() { return cpu.undefined_instruction.apply(cpu, arguments); },
|
||||
"unimplemented_sse": function() { return cpu.unimplemented_sse(); },
|
||||
"microtick": v86.microtick,
|
||||
"get_rand_int": function() { return v86util.get_rand_int(); },
|
||||
"has_rand_int": function() { return v86util.has_rand_int(); },
|
||||
"printf": function(format_string_offset, stack_top) {
|
||||
dbg_assert(arguments.length === 2);
|
||||
dbg_log_wasm(mem, format_string_offset, stack_top);
|
||||
dbg_log_wasm(v86oxide.exports.memory.buffer, format_string_offset, stack_top);
|
||||
},
|
||||
"_memcpy_large": function(dest, source, length) {
|
||||
"memcpy_large": function(dest, source, length) {
|
||||
const mem8 = new Uint8Array(v86oxide.exports.memory.buffer);
|
||||
mem8.set(mem8.subarray(source, source + length), dest);
|
||||
return dest;
|
||||
},
|
||||
"_memcpy": function(dest, source, length) {
|
||||
"memcpy": function(dest, source, length) {
|
||||
const mem8 = new Uint8Array(v86oxide.exports.memory.buffer);
|
||||
mem8.set(mem8.subarray(source, source + length), dest);
|
||||
return dest;
|
||||
},
|
||||
|
||||
"_call_interrupt_vector": function(interrupt_nr, is_software_int, has_error_code, error_code) {
|
||||
"call_interrupt_vector": function(interrupt_nr, is_software_int, has_error_code, error_code) {
|
||||
cpu.call_interrupt_vector(interrupt_nr, is_software_int, !!has_error_code, error_code);
|
||||
},
|
||||
"_far_jump": function(eip, selector, is_call) { return cpu.far_jump(eip, selector, !!is_call); },
|
||||
"_far_return": function(eip, selector, stack_adjust) { return cpu.far_return(eip, selector, stack_adjust); },
|
||||
"_switch_seg": function(reg, selector) { return cpu.switch_seg(reg, selector); },
|
||||
"_iret16": function() { return cpu.iret16(); },
|
||||
"_iret32": function() { return cpu.iret32(); },
|
||||
"_handle_irqs": function() { return cpu.handle_irqs(); },
|
||||
"far_jump": function(eip, selector, is_call) { return cpu.far_jump(eip, selector, !!is_call); },
|
||||
"far_return": function(eip, selector, stack_adjust) { return cpu.far_return(eip, selector, stack_adjust); },
|
||||
"switch_seg": function(reg, selector) { return cpu.switch_seg(reg, selector); },
|
||||
"iret16": function() { return cpu.iret16(); },
|
||||
"iret32": function() { return cpu.iret32(); },
|
||||
"handle_irqs": function() { return cpu.handle_irqs(); },
|
||||
|
||||
"_io_port_read8": function(addr) { return cpu.io.port_read8(addr); },
|
||||
"_io_port_read16": function(addr) { return cpu.io.port_read16(addr); },
|
||||
"_io_port_read32": function(addr) { return cpu.io.port_read32(addr); },
|
||||
"_io_port_write8": function(addr, value) { cpu.io.port_write8(addr, value); },
|
||||
"_io_port_write16": function(addr, value) { cpu.io.port_write16(addr, value); },
|
||||
"_io_port_write32": function(addr, value) { cpu.io.port_write32(addr, value); },
|
||||
"io_port_read8": function(addr) { return cpu.io.port_read8(addr); },
|
||||
"io_port_read16": function(addr) { return cpu.io.port_read16(addr); },
|
||||
"io_port_read32": function(addr) { return cpu.io.port_read32(addr); },
|
||||
"io_port_write8": function(addr, value) { cpu.io.port_write8(addr, value); },
|
||||
"io_port_write16": function(addr, value) { cpu.io.port_write16(addr, value); },
|
||||
"io_port_write32": function(addr, value) { cpu.io.port_write32(addr, value); },
|
||||
|
||||
"_mmap_read8": function(addr) { return cpu.mmap_read8(addr); },
|
||||
"_mmap_read16": function(addr) { return cpu.mmap_read16(addr); },
|
||||
"_mmap_read32": function(addr) { return cpu.mmap_read32(addr); },
|
||||
"_mmap_write8": function(addr, value) { return cpu.mmap_write8(addr, value); },
|
||||
"_mmap_write16": function(addr, value) { return cpu.mmap_write16(addr, value); },
|
||||
"_mmap_write32": function(addr, value) { return cpu.mmap_write32(addr, value); },
|
||||
"_mmap_write128": function(addr, value0, value1, value2, value3) { return cpu.mmap_write128(addr, value0, value1, value2, value3); },
|
||||
"mmap_read8": function(addr) { return cpu.mmap_read8(addr); },
|
||||
"mmap_read16": function(addr) { return cpu.mmap_read16(addr); },
|
||||
"mmap_read32": function(addr) { return cpu.mmap_read32(addr); },
|
||||
"mmap_write8": function(addr, value) { return cpu.mmap_write8(addr, value); },
|
||||
"mmap_write16": function(addr, value) { return cpu.mmap_write16(addr, value); },
|
||||
"mmap_write32": function(addr, value) { return cpu.mmap_write32(addr, value); },
|
||||
"mmap_write128": function(addr, value0, value1, value2, value3) { return cpu.mmap_write128(addr, value0, value1, value2, value3); },
|
||||
|
||||
"_int_log2": function(val) { return v86util.int_log2(val); },
|
||||
"int_log2": function(val) { return v86util.int_log2(val); },
|
||||
|
||||
"_popa16": function() { return cpu.popa16.apply(cpu, arguments); },
|
||||
"_popa32": function() { return cpu.popa32.apply(cpu, arguments); },
|
||||
"_arpl": function() { return cpu.arpl.apply(cpu, arguments); },
|
||||
"popa16": function() { return cpu.popa16.apply(cpu, arguments); },
|
||||
"popa32": function() { return cpu.popa32.apply(cpu, arguments); },
|
||||
"arpl": function() { return cpu.arpl.apply(cpu, arguments); },
|
||||
|
||||
"_bswap": function() { return cpu.bswap.apply(cpu, arguments); },
|
||||
"bswap": function() { return cpu.bswap.apply(cpu, arguments); },
|
||||
|
||||
"_lar": function() { return cpu.lar.apply(cpu, arguments); },
|
||||
"_lsl": function() { return cpu.lsl.apply(cpu, arguments); },
|
||||
"_verw": function() { return cpu.verw.apply(cpu, arguments); },
|
||||
"_verr": function() { return cpu.verr.apply(cpu, arguments); },
|
||||
"lar": function() { return cpu.lar.apply(cpu, arguments); },
|
||||
"lsl": function() { return cpu.lsl.apply(cpu, arguments); },
|
||||
"verw": function() { return cpu.verw.apply(cpu, arguments); },
|
||||
"verr": function() { return cpu.verr.apply(cpu, arguments); },
|
||||
|
||||
"_cpl_changed": function() { return cpu.cpl_changed.apply(cpu, arguments); },
|
||||
"_set_cr0": function() { return cpu.set_cr0.apply(cpu, arguments); },
|
||||
"_update_cs_size": function() { return cpu.update_cs_size.apply(cpu, arguments); },
|
||||
"_cpuid": function() { return cpu.cpuid.apply(cpu, arguments); },
|
||||
"cpl_changed": function() { return cpu.cpl_changed.apply(cpu, arguments); },
|
||||
"set_cr0": function() { return cpu.set_cr0.apply(cpu, arguments); },
|
||||
"update_cs_size": function() { return cpu.update_cs_size.apply(cpu, arguments); },
|
||||
"cpuid": function() { return cpu.cpuid.apply(cpu, arguments); },
|
||||
|
||||
"_load_ldt": function() { return cpu.load_ldt.apply(cpu, arguments); },
|
||||
"_load_tr": function() { return cpu.load_tr.apply(cpu, arguments); },
|
||||
"load_ldt": function() { return cpu.load_ldt.apply(cpu, arguments); },
|
||||
"load_tr": function() { return cpu.load_tr.apply(cpu, arguments); },
|
||||
|
||||
"_lss16": function() { return cpu.lss16.apply(cpu, arguments); },
|
||||
"_lss32": function() { return cpu.lss32.apply(cpu, arguments); },
|
||||
"_enter16": function() { return cpu.enter16.apply(cpu, arguments); },
|
||||
"_enter32": function() { return cpu.enter32.apply(cpu, arguments); },
|
||||
"lss16": function() { return cpu.lss16.apply(cpu, arguments); },
|
||||
"lss32": function() { return cpu.lss32.apply(cpu, arguments); },
|
||||
"enter16": function() { return cpu.enter16.apply(cpu, arguments); },
|
||||
"enter32": function() { return cpu.enter32.apply(cpu, arguments); },
|
||||
|
||||
"_test_privileges_for_io": function() { return cpu.test_privileges_for_io.apply(cpu, arguments); },
|
||||
"test_privileges_for_io": function() { return cpu.test_privileges_for_io.apply(cpu, arguments); },
|
||||
|
||||
"_convert_f64_to_i32": function(f) {
|
||||
"convert_f64_to_i32": function(f) {
|
||||
// implemented here due to emscripten bug
|
||||
if(!(f <= 0x7FFFFFFF && f >= -0x80000000))
|
||||
{
|
||||
|
@ -220,30 +223,37 @@ function V86Starter(options)
|
|||
|
||||
return f | 0;
|
||||
},
|
||||
"_get_time": Date.now,
|
||||
"get_time": Date.now,
|
||||
|
||||
"_coverage_log": (fn_name_offset, num_blocks, visited_block) => {
|
||||
coverage_logger.log(fn_name_offset, num_blocks, visited_block);
|
||||
"coverage_log": (fn_name_offset, num_blocks, visited_block) => {
|
||||
//coverage_logger.log(fn_name_offset, num_blocks, visited_block);
|
||||
},
|
||||
|
||||
// see https://github.com/kripken/emscripten/blob/incoming/src/library.js
|
||||
"_atan2": Math.atan2,
|
||||
"_sin": Math.sin,
|
||||
"_cos": Math.cos,
|
||||
"_tan": Math.tan,
|
||||
"_trunc": Math.trunc,
|
||||
"_fmod": (x, y) => x % y,
|
||||
"_llvm_exp2_f64": (x) => Math.pow(2, x),
|
||||
"_log": Math.log,
|
||||
"_round": Math.round,
|
||||
"_ldexp": function(x, exp) {
|
||||
"atan2": Math.atan2,
|
||||
"sin": Math.sin,
|
||||
"cos": Math.cos,
|
||||
"tan": Math.tan,
|
||||
"trunc": Math.trunc,
|
||||
"fmod": (x, y) => x % y,
|
||||
"llvm_exp2_f64": (x) => Math.pow(2, x),
|
||||
"log": Math.log,
|
||||
"round": Math.round,
|
||||
"ldexp": function(x, exp) {
|
||||
return x * Math.pow(2, exp);
|
||||
},
|
||||
"_llvm_round_f64": function(d) {
|
||||
"llvm_round_f64": function(d) {
|
||||
d = +d;
|
||||
return d >= +0 ? +Math.floor(d + 0.5) : +Math.ceil(d - 0.5);
|
||||
},
|
||||
"_llvm_trunc_f64": Math.trunc,
|
||||
"llvm_trunc_f64": Math.trunc,
|
||||
|
||||
"log_from_wasm": function(offset, len) {
|
||||
const str = v86util.read_sized_string_from_mem(v86oxide.exports.memory, offset, len);
|
||||
dbg_log(str, LOG_CPU);
|
||||
},
|
||||
"codegen_finalize": (wasm_table_index, start, end, first_opcode, state_flags) => cpu.codegen_finalize(wasm_table_index, start, end, first_opcode, state_flags),
|
||||
"__indirect_function_table": wasm_table,
|
||||
};
|
||||
|
||||
const wasm_globals = {
|
||||
|
@ -251,25 +261,16 @@ function V86Starter(options)
|
|||
"NaN": NaN,
|
||||
};
|
||||
|
||||
const v86oxide_mem = new WebAssembly.Memory({ "initial": 250 });
|
||||
const v86oxide_externs = {
|
||||
"memory": v86oxide_mem,
|
||||
"log_from_wasm": function(offset, len) {
|
||||
const str = v86util.read_sized_string_from_mem(v86oxide_mem, offset, len);
|
||||
dbg_log(str, LOG_CPU);
|
||||
},
|
||||
"abort": function() {
|
||||
dbg_assert(false);
|
||||
},
|
||||
|
||||
"read8": addr => cpu.read8(addr),
|
||||
"read16": addr => cpu.read16(addr),
|
||||
"read32": addr => cpu.read32s(addr),
|
||||
"tlb_set_has_code": (page, has_code) => cpu.wm.exports["_tlb_set_has_code"](page, has_code),
|
||||
"check_tlb_invariants": () => cpu.wm.exports["_check_tlb_invariants"](),
|
||||
"codegen_finalize": (wasm_table_index, start, end, first_opcode, state_flags) => cpu.codegen_finalize(wasm_table_index, start, end, first_opcode, state_flags),
|
||||
"profiler_stat_increment": (name) => cpu.wm.exports["_profiler_stat_increment"](name),
|
||||
};
|
||||
//const v86oxide_mem = new WebAssembly.Memory({ "initial": 250 });
|
||||
//const v86oxide_externs = {
|
||||
// "memory": v86oxide_mem,
|
||||
// "read8": addr => cpu.read8(addr),
|
||||
// "read16": addr => cpu.read16(addr),
|
||||
// "read32": addr => cpu.read32s(addr),
|
||||
// "tlb_set_has_code": (page, has_code) => cpu.wm.exports["_tlb_set_has_code"](page, has_code),
|
||||
// "check_tlb_invariants": () => cpu.wm.exports["_check_tlb_invariants"](),
|
||||
// "profiler_stat_increment": (name) => cpu.wm.exports["_profiler_stat_increment"](name),
|
||||
//};
|
||||
|
||||
let wasm_file = DEBUG ? "v86-debug.wasm" : "v86.wasm";
|
||||
let v86oxide_bin = DEBUG ? "v86oxide-debug.wasm" : "v86oxide.wasm";
|
||||
|
@ -304,28 +305,38 @@ function V86Starter(options)
|
|||
"jit_dirty_cache",
|
||||
];
|
||||
|
||||
v86util.minimal_load_wasm(v86oxide_bin, { "env": v86oxide_externs }, (v86oxide) => {
|
||||
for(const fn_name of v86oxide_exports)
|
||||
{
|
||||
dbg_assert(typeof v86oxide.exports[fn_name] === "function", `Function ${fn_name} not found in v86oxide exports`);
|
||||
wasm_shared_funcs[`_${fn_name}`] = v86oxide.exports[fn_name];
|
||||
}
|
||||
v86util.minimal_load_wasm(v86oxide_bin, { "env": wasm_shared_funcs }, (v86oxide_) => {
|
||||
v86oxide = v86oxide_;
|
||||
//for(const fn_name of v86oxide_exports)
|
||||
//{
|
||||
// dbg_assert(typeof v86oxide.exports[fn_name] === "function", `Function ${fn_name} not found in v86oxide exports`);
|
||||
// wasm_shared_funcs[`_${fn_name}`] = v86oxide.exports[fn_name];
|
||||
//}
|
||||
v86oxide.exports["rust_setup"]();
|
||||
|
||||
//v86oxide.exports[WASM_EXPORT_TABLE_NAME].grow(WASM_TABLE_SIZE);
|
||||
|
||||
const wm = v86oxide;
|
||||
|
||||
//mem = v86oxide.exports.memory.buffer;
|
||||
//mem8 = new Uint8Array(mem);
|
||||
emulator = this.v86 = new v86(this.emulator_bus, wm, v86oxide, coverage_logger);
|
||||
cpu = emulator.cpu;
|
||||
|
||||
//XXX: fix indentation break
|
||||
|
||||
v86util.load_wasm(
|
||||
wasm_file,
|
||||
{ "env": wasm_shared_funcs, "global" : wasm_globals },
|
||||
options["memory_size"] + GUEST_MEMORY_START,
|
||||
WASM_TABLE_SIZE,
|
||||
wm => {
|
||||
mem = wm.memory.buffer;
|
||||
mem8 = new Uint8Array(mem);
|
||||
wm.instance.exports["__post_instantiate"]();
|
||||
coverage_logger.init(wm);
|
||||
emulator = this.v86 = new v86(this.emulator_bus, wm, v86oxide, coverage_logger);
|
||||
cpu = emulator.cpu;
|
||||
//v86util.load_wasm(
|
||||
// wasm_file,
|
||||
// { "env": wasm_shared_funcs, "global" : wasm_globals },
|
||||
// options["memory_size"] + GUEST_MEMORY_START,
|
||||
// WASM_TABLE_SIZE,
|
||||
// wm => {
|
||||
// mem = wm.memory.buffer;
|
||||
// mem8 = new Uint8Array(mem);
|
||||
// wm.instance.exports["__post_instantiate"]();
|
||||
// coverage_logger.init(wm);
|
||||
// emulator = this.v86 = new v86(this.emulator_bus, wm, v86oxide, coverage_logger);
|
||||
// cpu = emulator.cpu;
|
||||
|
||||
// XXX: Leaving unindented to minimize diff; still a part of the cb to load_wasm!
|
||||
this.bus.register("emulator-stopped", function()
|
||||
|
@ -671,7 +682,7 @@ function V86Starter(options)
|
|||
}.bind(this), 0);
|
||||
}
|
||||
|
||||
});
|
||||
//});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -362,7 +362,7 @@ var WASM_TABLE_SIZE = 0x10000;
|
|||
var JIT_CACHE_ARRAY_SIZE = 0x40000;
|
||||
|
||||
/** @const */
|
||||
const WASM_EXPORT_TABLE_NAME = "table";
|
||||
const WASM_EXPORT_TABLE_NAME = "__indirect_function_table";
|
||||
|
||||
|
||||
/** @const */
|
||||
|
|
289
src/cpu.js
289
src/cpu.js
|
@ -19,46 +19,64 @@ function CPU(bus, wm, v86oxide, coverage_logger)
|
|||
this.wasm_patch(wm);
|
||||
this.create_jit_imports();
|
||||
|
||||
this.memory_size = new Uint32Array(wm.memory.buffer, 812, 1);
|
||||
const memory = v86oxide.instance.exports.memory;
|
||||
|
||||
Object.defineProperty(this, "memory_size", { get: () => { return new Uint32Array(memory.buffer, 812, 1); } });
|
||||
if(false) this.memory_size = new Uint32Array(memory.buffer, 812, 1);
|
||||
|
||||
// Note: Currently unused (degrades performance and not required by any OS
|
||||
// that we support)
|
||||
this.a20_enabled = new Int32Array(wm.memory.buffer, 552, 1);
|
||||
if(false) this.a20_enabled = new Int32Array(memory.buffer, 552, 1);
|
||||
Object.defineProperty(this, "a20_enabled", { get: () => { return new Int32Array(memory.buffer, 552, 1); } });
|
||||
this.a20_enabled[0] = +true;
|
||||
|
||||
this.mem_page_infos = undefined;
|
||||
if(false) this.mem8 = new Uint8Array(0);
|
||||
if(false) this.mem16 = new Uint16Array(this.mem8.buffer);
|
||||
if(false) this.mem32s = new Int32Array(this.mem8.buffer);
|
||||
|
||||
this.mem8 = new Uint8Array(0);
|
||||
this.mem16 = new Uint16Array(this.mem8.buffer);
|
||||
this.mem32s = new Int32Array(this.mem8.buffer);
|
||||
Object.defineProperty(this, "mem8", { get: () => { return new Uint8Array(memory.buffer, GUEST_MEMORY_START, this.memory_size[0]); } });
|
||||
Object.defineProperty(this, "mem16", { get: () => { return new Uint16Array(memory.buffer, GUEST_MEMORY_START, this.memory_size[0] >> 1); } });
|
||||
Object.defineProperty(this, "mem32s", { get: () => { return new Int32Array(memory.buffer, GUEST_MEMORY_START, this.memory_size[0] >> 2); } });
|
||||
|
||||
this.segment_is_null = new Uint8Array(wm.memory.buffer, 724, 8);
|
||||
this.segment_offsets = new Int32Array(wm.memory.buffer, 736, 8);
|
||||
this.segment_limits = new Uint32Array(wm.memory.buffer, 768, 8);
|
||||
//this.segment_infos = [];
|
||||
if(false) this.segment_is_null = new Uint8Array(memory.buffer, 724, 8);
|
||||
Object.defineProperty(this, "segment_is_null", { get: () => { return new Uint8Array(memory.buffer, 724, 8); } });
|
||||
|
||||
if(false) this.segment_offsets = new Int32Array(memory.buffer, 736, 8);
|
||||
Object.defineProperty(this, "segment_offsets", { get: () => { return new Int32Array(memory.buffer, 736, 8); } });
|
||||
|
||||
if(false) this.segment_limits = new Uint32Array(memory.buffer, 768, 8);
|
||||
Object.defineProperty(this, "segment_limits", { get: () => { return new Uint32Array(memory.buffer, 768, 8); } });
|
||||
|
||||
/**
|
||||
* Wheter or not in protected mode
|
||||
*/
|
||||
this.protected_mode = new Int32Array(wm.memory.buffer, 800, 1);
|
||||
if(false) this.protected_mode = new Int32Array(memory.buffer, 800, 1);
|
||||
Object.defineProperty(this, "protected_mode", { get: () => { return new Int32Array(memory.buffer, 800, 1); } });
|
||||
|
||||
this.idtr_size = new Int32Array(wm.memory.buffer, 564, 1);
|
||||
this.idtr_offset = new Int32Array(wm.memory.buffer, 568, 1);
|
||||
if(false) this.idtr_size = new Int32Array(memory.buffer, 564, 1);
|
||||
if(false) this.idtr_offset = new Int32Array(memory.buffer, 568, 1);
|
||||
Object.defineProperty(this, "idtr_size", { get: () => { return new Int32Array(memory.buffer, 564, 1); } });
|
||||
Object.defineProperty(this, "idtr_offset", { get: () => { return new Int32Array(memory.buffer, 568, 1); } });
|
||||
|
||||
/**
|
||||
* global descriptor table register
|
||||
*/
|
||||
this.gdtr_size = new Int32Array(wm.memory.buffer, 572, 1);
|
||||
this.gdtr_offset = new Int32Array(wm.memory.buffer, 576, 1);
|
||||
if(false) this.gdtr_size = new Int32Array(memory.buffer, 572, 1);
|
||||
if(false) this.gdtr_offset = new Int32Array(memory.buffer, 576, 1);
|
||||
|
||||
Object.defineProperty(this, "gdtr_size", { get: () => { return new Int32Array(memory.buffer, 572, 1); } });
|
||||
Object.defineProperty(this, "gdtr_offset", { get: () => { return new Int32Array(memory.buffer, 576, 1); } });
|
||||
|
||||
this.tss_size_32 = false;
|
||||
|
||||
/*
|
||||
* whether or not a page fault occured
|
||||
*/
|
||||
this.page_fault = new Uint32Array(wm.memory.buffer, 540, 8);
|
||||
if(false) this.page_fault = new Uint32Array(memory.buffer, 540, 8);
|
||||
Object.defineProperty(this, "page_fault", { get: () => { return new Uint32Array(memory.buffer, 540, 8); } });
|
||||
|
||||
this.cr = new Int32Array(wm.memory.buffer, 580, 8);
|
||||
if(false) this.cr = new Int32Array(memory.buffer, 580, 8);
|
||||
Object.defineProperty(this, "cr", { get: () => { return new Int32Array(memory.buffer, 580, 8); } });
|
||||
|
||||
/** @type {number} */
|
||||
this.cr[0] = 0;
|
||||
|
@ -70,62 +88,76 @@ function CPU(bus, wm, v86oxide, coverage_logger)
|
|||
this.cr[4] = 0;
|
||||
|
||||
// current privilege level
|
||||
this.cpl = new Int32Array(wm.memory.buffer, 612, 1);
|
||||
if(false) this.cpl = new Int32Array(memory.buffer, 612, 1);
|
||||
Object.defineProperty(this, "cpl", { get: () => { return new Int32Array(memory.buffer, 612, 1); } });
|
||||
|
||||
// current operand/address size
|
||||
this.is_32 = new Int32Array(wm.memory.buffer, 804, 1);
|
||||
if(false) this.is_32 = new Int32Array(memory.buffer, 804, 1);
|
||||
Object.defineProperty(this, "is_32", { get: () => { return new Int32Array(memory.buffer, 804, 1); } });
|
||||
|
||||
this.stack_size_32 = new Int32Array(wm.memory.buffer, 808, 1);
|
||||
if(false) this.stack_size_32 = new Int32Array(memory.buffer, 808, 1);
|
||||
Object.defineProperty(this, "stack_size_32", { get: () => { return new Int32Array(memory.buffer, 808, 1); } });
|
||||
|
||||
/**
|
||||
* Was the last instruction a hlt?
|
||||
*/
|
||||
this.in_hlt = new Uint8Array(wm.memory.buffer, 616, 1);
|
||||
if(false) this.in_hlt = new Uint8Array(memory.buffer, 616, 1);
|
||||
Object.defineProperty(this, "in_hlt", { get: () => { return new Uint8Array(memory.buffer, 616, 1); } });
|
||||
|
||||
this.last_virt_eip = new Int32Array(wm.memory.buffer, 620, 1);
|
||||
this.last_virt_eip = new Int32Array(memory.buffer, 620, 1);
|
||||
|
||||
this.eip_phys = new Int32Array(wm.memory.buffer, 624, 1);
|
||||
this.eip_phys = new Int32Array(memory.buffer, 624, 1);
|
||||
|
||||
this.last_virt_esp = new Int32Array(wm.memory.buffer, 628, 1);
|
||||
this.last_virt_esp = new Int32Array(memory.buffer, 628, 1);
|
||||
|
||||
this.esp_phys = new Int32Array(wm.memory.buffer, 632, 1);
|
||||
this.esp_phys = new Int32Array(memory.buffer, 632, 1);
|
||||
|
||||
|
||||
this.sysenter_cs = new Int32Array(wm.memory.buffer, 636, 1);
|
||||
this.sysenter_cs = new Int32Array(memory.buffer, 636, 1);
|
||||
|
||||
this.sysenter_esp = new Int32Array(wm.memory.buffer, 640, 1);
|
||||
this.sysenter_esp = new Int32Array(memory.buffer, 640, 1);
|
||||
|
||||
this.sysenter_eip = new Int32Array(wm.memory.buffer, 644, 1);
|
||||
this.sysenter_eip = new Int32Array(memory.buffer, 644, 1);
|
||||
|
||||
this.prefixes = new Int32Array(wm.memory.buffer, 648, 1);
|
||||
if(false) this.prefixes = new Int32Array(memory.buffer, 648, 1);
|
||||
Object.defineProperty(this, "prefixes", { get: () => { return new Int32Array(memory.buffer, 648, 1); } });
|
||||
|
||||
this.flags = new Int32Array(wm.memory.buffer, 536, 1);
|
||||
if(false) this.flags = new Int32Array(memory.buffer, 536, 1);
|
||||
Object.defineProperty(this, "flags", { get: () => { return new Int32Array(memory.buffer, 536, 1); } });
|
||||
|
||||
/**
|
||||
* bitmap of flags which are not updated in the flags variable
|
||||
* changed by arithmetic instructions, so only relevant to arithmetic flags
|
||||
*/
|
||||
this.flags_changed = new Int32Array(wm.memory.buffer, 532, 1);
|
||||
if(false) this.flags_changed = new Int32Array(memory.buffer, 532, 1);
|
||||
Object.defineProperty(this, "flags_changed", { get: () => { return new Int32Array(memory.buffer, 532, 1); } });
|
||||
|
||||
/**
|
||||
* the last 2 operators and the result and size of the last arithmetic operation
|
||||
*/
|
||||
this.last_op1 = new Int32Array(wm.memory.buffer, 512, 1);
|
||||
this.last_op2 = new Int32Array(wm.memory.buffer, 516, 1);
|
||||
this.last_op_size = new Int32Array(wm.memory.buffer, 520, 1);
|
||||
if(false) this.last_op1 = new Int32Array(memory.buffer, 512, 1);
|
||||
Object.defineProperty(this, "last_op1", { get: () => { return new Int32Array(memory.buffer, 512, 1); } });
|
||||
if(false) this.last_op2 = new Int32Array(memory.buffer, 516, 1);
|
||||
Object.defineProperty(this, "last_op2", { get: () => { return new Int32Array(memory.buffer, 516, 1); } });
|
||||
if(false) this.last_op_size = new Int32Array(memory.buffer, 520, 1);
|
||||
Object.defineProperty(this, "last_op_size", { get: () => { return new Int32Array(memory.buffer, 520, 1); } });
|
||||
|
||||
this.last_add_result = new Int32Array(wm.memory.buffer, 524, 1);
|
||||
if(false) this.last_add_result = new Int32Array(memory.buffer, 524, 1);
|
||||
Object.defineProperty(this, "last_add_result", { get: () => { return new Int32Array(memory.buffer, 524, 1); } });
|
||||
|
||||
this.last_result = new Int32Array(wm.memory.buffer, 528, 1);
|
||||
if(false) this.last_result = new Int32Array(memory.buffer, 528, 1);
|
||||
Object.defineProperty(this, "last_result", { get: () => { return new Int32Array(memory.buffer, 528, 1); } });
|
||||
|
||||
this.current_tsc = new Uint32Array(wm.memory.buffer, 956, 2); // 64 bit
|
||||
this.current_tsc = new Uint32Array(memory.buffer, 956, 2); // 64 bit
|
||||
|
||||
/** @type {!Object} */
|
||||
this.devices = {};
|
||||
|
||||
this.instruction_pointer = new Int32Array(wm.memory.buffer, 556, 1);
|
||||
if(false) this.instruction_pointer = new Int32Array(memory.buffer, 556, 1);
|
||||
Object.defineProperty(this, "instruction_pointer", { get: () => { return new Int32Array(memory.buffer, 556, 1); } });
|
||||
|
||||
this.previous_ip = new Int32Array(wm.memory.buffer, 560, 1);
|
||||
if(false) this.previous_ip = new Int32Array(memory.buffer, 560, 1);
|
||||
Object.defineProperty(this, "previous_ip", { get: () => { return new Int32Array(memory.buffer, 560, 1); } });
|
||||
|
||||
this.apic_enabled = true;
|
||||
|
||||
|
@ -144,56 +176,64 @@ function CPU(bus, wm, v86oxide, coverage_logger)
|
|||
vga: null,
|
||||
};
|
||||
|
||||
this.timestamp_counter = new Uint32Array(wm.memory.buffer, 664, 1);
|
||||
Object.defineProperty(this, "timestamp_counter", { get: () => { return new Int32Array(memory.buffer, 664, 1); } });
|
||||
if(false) this.timestamp_counter = new Uint32Array(memory.buffer, 664, 1);
|
||||
|
||||
// registers
|
||||
this.reg32s = new Int32Array(wm.memory.buffer, 4, 8);
|
||||
this.reg32 = new Uint32Array(this.reg32s.buffer, 4, 8);
|
||||
this.reg16s = new Int16Array(this.reg32s.buffer, 4, 16);
|
||||
this.reg16 = new Uint16Array(this.reg32s.buffer, 4, 16);
|
||||
this.reg8s = new Int8Array(this.reg32s.buffer, 4, 32);
|
||||
this.reg8 = new Uint8Array(this.reg32s.buffer, 4, 32);
|
||||
if(false) this.reg32s = new Int32Array(memory.buffer, 4, 8);
|
||||
if(false) this.reg32 = new Uint32Array(this.reg32s.buffer, 4, 8);
|
||||
if(false) this.reg16s = new Int16Array(this.reg32s.buffer, 4, 16);
|
||||
if(false) this.reg16 = new Uint16Array(this.reg32s.buffer, 4, 16);
|
||||
if(false) this.reg8s = new Int8Array(this.reg32s.buffer, 4, 32);
|
||||
if(false) this.reg8 = new Uint8Array(this.reg32s.buffer, 4, 32);
|
||||
Object.defineProperty(this, "reg32s", { get: () => { return new Int32Array(memory.buffer, 4, 8); } });
|
||||
Object.defineProperty(this, "reg32", { get: () => { return new Uint32Array(memory.buffer, 4, 8); } });
|
||||
Object.defineProperty(this, "reg16s", { get: () => { return new Int16Array(memory.buffer, 4, 16); } });
|
||||
Object.defineProperty(this, "reg16", { get: () => { return new Uint16Array(memory.buffer, 4, 16); } });
|
||||
Object.defineProperty(this, "reg8s", { get: () => { return new Int8Array(memory.buffer, 4, 32); } });
|
||||
Object.defineProperty(this, "reg8", { get: () => { return new Uint8Array(memory.buffer, 4, 32); } });
|
||||
|
||||
// Why no Float80Array :-(
|
||||
this.fpu_st = new Float64Array(wm.memory.buffer, 968, 8);
|
||||
this.fpu_st = new Float64Array(memory.buffer, 968, 8);
|
||||
|
||||
this.fpu_stack_empty = new Int32Array(wm.memory.buffer, 816, 1);
|
||||
this.fpu_stack_empty = new Int32Array(memory.buffer, 816, 1);
|
||||
this.fpu_stack_empty[0] = 0xff;
|
||||
this.fpu_stack_ptr = new Uint32Array(wm.memory.buffer, 1032, 1);
|
||||
this.fpu_stack_ptr = new Uint32Array(memory.buffer, 1032, 1);
|
||||
this.fpu_stack_ptr[0] = 0;
|
||||
|
||||
this.fpu_control_word = new Int32Array(wm.memory.buffer, 1036, 1);
|
||||
this.fpu_control_word = new Int32Array(memory.buffer, 1036, 1);
|
||||
this.fpu_control_word[0] = 0x37F;
|
||||
this.fpu_status_word = new Int32Array(wm.memory.buffer, 1040, 1);
|
||||
this.fpu_status_word = new Int32Array(memory.buffer, 1040, 1);
|
||||
this.fpu_status_word[0] = 0;
|
||||
this.fpu_ip = new Int32Array(wm.memory.buffer, 1048, 1);
|
||||
this.fpu_ip = new Int32Array(memory.buffer, 1048, 1);
|
||||
this.fpu_ip[0] = 0;
|
||||
this.fpu_ip_selector = new Int32Array(wm.memory.buffer, 1052, 1);
|
||||
this.fpu_ip_selector = new Int32Array(memory.buffer, 1052, 1);
|
||||
this.fpu_ip_selector[0] = 0;
|
||||
this.fpu_opcode = new Int32Array(wm.memory.buffer, 1044, 1);
|
||||
this.fpu_opcode = new Int32Array(memory.buffer, 1044, 1);
|
||||
this.fpu_opcode[0] = 0;
|
||||
this.fpu_dp = new Int32Array(wm.memory.buffer, 1056, 1);
|
||||
this.fpu_dp = new Int32Array(memory.buffer, 1056, 1);
|
||||
this.fpu_dp[0] = 0;
|
||||
this.fpu_dp_selector = new Int32Array(wm.memory.buffer, 1060, 1);
|
||||
this.fpu_dp_selector = new Int32Array(memory.buffer, 1060, 1);
|
||||
this.fpu_dp_selector[0] = 0;
|
||||
|
||||
// mm0-mm7 split up into 32 bit pairs
|
||||
this.reg_mmxs = new Int32Array(wm.memory.buffer, 1064, 16);
|
||||
this.reg_mmxs = new Int32Array(memory.buffer, 1064, 16);
|
||||
this.reg_mmx = new Uint32Array(this.reg_mmxs.buffer, 1064, 16);
|
||||
this.reg_mmx8s = new Int8Array(this.reg_mmxs.buffer, 1064, 64);
|
||||
this.reg_mmx8 = new Uint8Array(this.reg_mmxs.buffer, 1064, 64);
|
||||
|
||||
this.reg_xmm32s = new Int32Array(wm.memory.buffer, 828, 8 * 4);
|
||||
this.reg_xmm32s = new Int32Array(memory.buffer, 828, 8 * 4);
|
||||
|
||||
this.mxcsr = new Int32Array(wm.memory.buffer, 824, 1);
|
||||
this.mxcsr = new Int32Array(memory.buffer, 824, 1);
|
||||
|
||||
// segment registers, tr and ldtr
|
||||
this.sreg = new Uint16Array(wm.memory.buffer, 668, 8);
|
||||
if(false) this.sreg = new Uint16Array(memory.buffer, 668, 8);
|
||||
Object.defineProperty(this, "sreg", { get: () => { return new Uint16Array(memory.buffer, 668, 8); } });
|
||||
|
||||
// debug registers
|
||||
this.dreg = new Int32Array(wm.memory.buffer, 684, 8);
|
||||
this.dreg = new Int32Array(memory.buffer, 684, 8);
|
||||
|
||||
this.fw_value = new Int32Array(wm.memory.buffer, 720, 1);
|
||||
this.fw_value = new Int32Array(memory.buffer, 720, 1);
|
||||
|
||||
this.io = undefined;
|
||||
|
||||
|
@ -213,7 +253,7 @@ CPU.prototype.wasmgen_get_module_code = function()
|
|||
const ptr = this.jit_get_op_ptr();
|
||||
const len = this.jit_get_op_len();
|
||||
|
||||
const output_buffer_view = new Uint8Array(this.v86oxide.memory.buffer, ptr, len);
|
||||
const output_buffer_view = new Uint8Array(this.v86oxide.instance.exports.memory.buffer, ptr, len);
|
||||
return output_buffer_view;
|
||||
};
|
||||
|
||||
|
@ -228,18 +268,21 @@ CPU.prototype.create_jit_imports = function()
|
|||
}
|
||||
|
||||
// put all imports that don't change on the prototype
|
||||
JITImports.prototype["m"] = this.wm.memory;
|
||||
JITImports.prototype["m"] = this.v86oxide.memory;
|
||||
|
||||
const exports = this.wm.instance.exports;
|
||||
const exports = this.v86oxide.instance.exports;
|
||||
|
||||
JITImports.prototype["m"] = exports["memory"];
|
||||
|
||||
for(let name of Object.keys(exports))
|
||||
{
|
||||
if(name[0] !== "_")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//if(name[0] !== "_")
|
||||
//{
|
||||
// continue;
|
||||
//}
|
||||
|
||||
JITImports.prototype[name.slice(1)] = exports[name];
|
||||
//JITImports.prototype[name.slice(1)] = exports[name];
|
||||
JITImports.prototype[name] = exports[name];
|
||||
}
|
||||
|
||||
this.jit_imports = new JITImports();
|
||||
|
@ -247,56 +290,57 @@ CPU.prototype.create_jit_imports = function()
|
|||
|
||||
CPU.prototype.wasm_patch = function(wm)
|
||||
{
|
||||
this.getiopl = this.wm.exports["_getiopl"];
|
||||
this.vm86_mode = this.wm.exports["_vm86_mode"];
|
||||
this.get_eflags = this.wm.exports["_get_eflags"];
|
||||
this.update_eflags = this.wm.exports["_update_eflags"];
|
||||
this.getiopl = this.v86oxide.exports["getiopl"];
|
||||
this.vm86_mode = this.v86oxide.exports["vm86_mode"];
|
||||
this.get_eflags = this.v86oxide.exports["get_eflags"];
|
||||
this.update_eflags = this.v86oxide.exports["update_eflags"];
|
||||
|
||||
this.trigger_gp_non_raising = this.wm.exports["_trigger_gp_non_raising"];
|
||||
this.trigger_ud = this.wm.exports["_trigger_ud"];
|
||||
this.trigger_np = this.wm.exports["_trigger_np"];
|
||||
this.trigger_ss = this.wm.exports["_trigger_ss"];
|
||||
this.trigger_gp_non_raising = this.v86oxide.exports["trigger_gp_non_raising"];
|
||||
this.trigger_ud = this.v86oxide.exports["trigger_ud"];
|
||||
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.cycle_internal = this.wm.exports["_cycle_internal"];
|
||||
//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.cycle_internal = this.v86oxide.exports["cycle_internal"];
|
||||
|
||||
this.read8 = this.wm.exports["_read8"];
|
||||
this.read16 = this.wm.exports["_read16"];
|
||||
this.read32s = this.wm.exports["_read32s"];
|
||||
this.write8 = this.wm.exports["_write8"];
|
||||
this.write16 = this.wm.exports["_write16"];
|
||||
this.write32 = this.wm.exports["_write32"];
|
||||
this.in_mapped_range = this.wm.exports["_in_mapped_range"];
|
||||
this.read8 = this.v86oxide.exports["read8"];
|
||||
this.read16 = this.v86oxide.exports["read16"];
|
||||
this.read32s = this.v86oxide.exports["read32s"];
|
||||
this.write8 = this.v86oxide.exports["write8"];
|
||||
this.write16 = this.v86oxide.exports["write16"];
|
||||
this.write32 = this.v86oxide.exports["write32"];
|
||||
this.in_mapped_range = this.v86oxide.exports["in_mapped_range"];
|
||||
|
||||
this.push16 = this.wm.exports["_push16"];
|
||||
this.push32 = this.wm.exports["_push32"];
|
||||
this.pop16 = this.wm.exports["_pop16"];
|
||||
this.pop32s = this.wm.exports["_pop32s"];
|
||||
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.set_stack_reg = this.wm.exports["_set_stack_reg"];
|
||||
this.set_stack_reg = this.v86oxide.exports["set_stack_reg"];
|
||||
|
||||
this.translate_address_read = this.wm.exports["_translate_address_read"];
|
||||
this.translate_address_system_read = this.wm.exports["_translate_address_system_read"];
|
||||
this.translate_address_system_write = this.wm.exports["_translate_address_system_write"];
|
||||
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.get_seg = this.wm.exports["_get_seg"];
|
||||
this.adjust_stack_reg = this.wm.exports["_adjust_stack_reg"];
|
||||
this.get_real_eip = this.wm.exports["_get_real_eip"];
|
||||
this.get_stack_pointer = this.wm.exports["_get_stack_pointer"];
|
||||
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.wm.exports["_writable_or_pagefault"];
|
||||
this.safe_write32 = this.wm.exports["_safe_write32"];
|
||||
this.safe_read32s = this.wm.exports["_safe_read32s"];
|
||||
this.safe_write16 = this.wm.exports["_safe_write16"];
|
||||
this.safe_read16 = this.wm.exports["_safe_read16"];
|
||||
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.clear_tlb = this.wm.exports["_clear_tlb"];
|
||||
this.full_clear_tlb = this.wm.exports["_full_clear_tlb"];
|
||||
this.clear_tlb = this.v86oxide.exports["clear_tlb"];
|
||||
this.full_clear_tlb = this.v86oxide.exports["full_clear_tlb"];
|
||||
|
||||
this.set_tsc = this.wm.exports["_set_tsc"];
|
||||
this.store_current_tsc = this.wm.exports["_store_current_tsc"];
|
||||
this.set_tsc = this.v86oxide.exports["set_tsc"];
|
||||
this.store_current_tsc = this.v86oxide.exports["store_current_tsc"];
|
||||
|
||||
this.pack_current_state_flags = this.wm.exports["_pack_current_state_flags"];
|
||||
this.pack_current_state_flags = this.v86oxide.exports["pack_current_state_flags"];
|
||||
|
||||
this.jit_force_generate_unsafe = this.v86oxide.exports["jit_force_generate_unsafe"];
|
||||
this.jit_empty_cache = this.v86oxide.exports["jit_empty_cache"];
|
||||
|
@ -317,7 +361,7 @@ CPU.prototype.jit_force_generate = function(addr)
|
|||
CPU.prototype.jit_clear_func = function(index)
|
||||
{
|
||||
dbg_assert(index >= 0 && index < WASM_TABLE_SIZE);
|
||||
this.wm.imports.env[WASM_EXPORT_TABLE_NAME].set(index, null);
|
||||
this.wm.imports.env[WASM_EXPORT_TABLE_NAME + 0x100].set(index, null);
|
||||
};
|
||||
|
||||
CPU.prototype.get_state = function()
|
||||
|
@ -670,11 +714,11 @@ CPU.prototype.create_memory = function(size)
|
|||
|
||||
this.memory_size[0] = size;
|
||||
|
||||
var buffer = this.wm.memory.buffer;
|
||||
//var buffer = this.wm.memory.buffer;
|
||||
|
||||
this.mem8 = new Uint8Array(buffer, GUEST_MEMORY_START, size);
|
||||
this.mem16 = new Uint16Array(buffer, GUEST_MEMORY_START, size >> 1);
|
||||
this.mem32s = new Int32Array(buffer, GUEST_MEMORY_START, size >> 2);
|
||||
//this.mem8 = new Uint8Array(buffer, GUEST_MEMORY_START, size);
|
||||
//this.mem16 = new Uint16Array(buffer, GUEST_MEMORY_START, size >> 1);
|
||||
//this.mem32s = new Int32Array(buffer, GUEST_MEMORY_START, size >> 2);
|
||||
};
|
||||
|
||||
CPU.prototype.init = function(settings, device_bus)
|
||||
|
@ -833,7 +877,7 @@ CPU.prototype.init = function(settings, device_bus)
|
|||
this.debug.init();
|
||||
}
|
||||
|
||||
this.wm.exports["_profiler_init"]();
|
||||
//this.wm.exports["_profiler_init"]();
|
||||
};
|
||||
|
||||
CPU.prototype.load_multiboot = function(buffer)
|
||||
|
@ -1142,7 +1186,7 @@ CPU.prototype.load_bios = function()
|
|||
|
||||
CPU.prototype.do_run = function()
|
||||
{
|
||||
this.wm.exports["_profiler_stat_increment_do_run"]();
|
||||
//this.wm.exports["_profiler_stat_increment_do_run"]();
|
||||
|
||||
/** @type {number} */
|
||||
var start = v86.microtick();
|
||||
|
@ -1179,7 +1223,7 @@ let do_many_cycles_total = 0;
|
|||
CPU.prototype.do_many_cycles = function()
|
||||
{
|
||||
// Capture the total time we were executing instructions
|
||||
this.coverage_logger.log_start();
|
||||
//this.coverage_logger.log_start();
|
||||
|
||||
if(ENABLE_PROFILER)
|
||||
{
|
||||
|
@ -1200,7 +1244,7 @@ CPU.prototype.do_many_cycles = function()
|
|||
do_many_cycles_count++;
|
||||
}
|
||||
|
||||
this.coverage_logger.log_end();
|
||||
//this.coverage_logger.log_end();
|
||||
};
|
||||
|
||||
/** @export */
|
||||
|
@ -1284,7 +1328,7 @@ CPU.prototype.codegen_finalize = function(wasm_table_index, start, end, first_op
|
|||
first_opcode, state_flags);
|
||||
|
||||
// The following will throw if f isn't an exported function
|
||||
this.wm.imports["env"][WASM_EXPORT_TABLE_NAME].set(wasm_table_index, f);
|
||||
this.wm.imports["env"][WASM_EXPORT_TABLE_NAME].set(wasm_table_index + 0x100, f);
|
||||
|
||||
if(this.test_hook_did_finalize_wasm)
|
||||
{
|
||||
|
@ -1346,7 +1390,7 @@ CPU.prototype.dump_function_code = function(block_ptr, count)
|
|||
|
||||
const SIZEOF_BASIC_BLOCK_IN_DWORDS = 7;
|
||||
|
||||
const mem32 = new Int32Array(this.wm.memory.buffer);
|
||||
const mem32 = new Int32Array(this.v86oxide.instance.exports.memory.buffer);
|
||||
|
||||
dbg_assert((block_ptr & 3) === 0);
|
||||
|
||||
|
@ -1463,11 +1507,12 @@ CPU.prototype.jit_clear_cache = function()
|
|||
{
|
||||
this.jit_empty_cache();
|
||||
|
||||
const table = this.wm.imports["env"][WASM_EXPORT_TABLE_NAME];
|
||||
const table = this.wm.exports[WASM_EXPORT_TABLE_NAME] || this.wm.imports["env"][WASM_EXPORT_TABLE_NAME];
|
||||
const offset = 0x100;
|
||||
|
||||
for(let i = 0; i < WASM_TABLE_SIZE; i++)
|
||||
{
|
||||
table.set(i, null);
|
||||
table.set(offset + i, null);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ mod unsafe_cpu {
|
|||
pub fn tlb_set_has_code(physical_page: u32, has_code: bool);
|
||||
pub fn read8(addr: u32) -> u8;
|
||||
pub fn read16(addr: u32) -> u16;
|
||||
pub fn read32(addr: u32) -> u32;
|
||||
pub fn read32s(addr: u32) -> u32;
|
||||
pub fn check_tlb_invariants();
|
||||
|
||||
pub fn codegen_finalize(
|
||||
|
@ -29,7 +29,7 @@ pub enum BitSize {
|
|||
|
||||
pub fn read8(addr: u32) -> u8 { unsafe { unsafe_cpu::read8(addr) } }
|
||||
pub fn read16(addr: u32) -> u16 { unsafe { unsafe_cpu::read16(addr) } }
|
||||
pub fn read32(addr: u32) -> u32 { unsafe { unsafe_cpu::read32(addr) } }
|
||||
pub fn read32(addr: u32) -> u32 { unsafe { unsafe_cpu::read32s(addr) } }
|
||||
|
||||
pub fn tlb_set_has_code(physical_page: Page, has_code: bool) {
|
||||
unsafe { unsafe_cpu::tlb_set_has_code(physical_page.to_u32(), has_code) }
|
||||
|
|
86
src/rust/cpu2/Makefile
Normal file
86
src/rust/cpu2/Makefile
Normal file
|
@ -0,0 +1,86 @@
|
|||
ALL:= arith.rs cpu.rs fpu.rs instructions_0f.rs instructions.rs \
|
||||
memory.rs misc_instr.rs modrm.rs shared.rs sse_instr.rs string.rs \
|
||||
global_pointers.rs profiler.rs
|
||||
|
||||
all: $(ALL)
|
||||
|
||||
profiler.rs: profiler/profiler.rs
|
||||
cp profiler/profiler.rs profiler.rs
|
||||
|
||||
%.rs:
|
||||
#citrus --api=rust $< -I ../../native/ ../../native/profiler/ > $@.tmp
|
||||
#cat import-prefix $@.tmp | grep -v cpu2::$(basename $@):: > $@
|
||||
#rm $@.tmp
|
||||
#sed -i 's/assert(/assert!(/' $@
|
||||
#sed -i 's/dbg_assert(/dbg_assert!(/' $@
|
||||
#sed -i 's/dbg_log(/dbg_log!(/' $@
|
||||
#sed -i 's/%x/{:x}/g' $@
|
||||
#sed -i 's/%d/{}/g' $@
|
||||
#sed -i '/:.*= ()/d' $@
|
||||
#sed -i 's/!= 0 != 0//' $@
|
||||
#sed -i 's/fn(,/fn(i32,/' $@
|
||||
#sed -i 's/is_32 != 0/is_32/' $@
|
||||
#sed -i 's/SAFE_READ_WRITE8/SAFE_READ_WRITE8!/' $@
|
||||
#sed -i 's/SAFE_READ_WRITE16/SAFE_READ_WRITE16!/' $@
|
||||
#sed -i 's/SAFE_READ_WRITE32/SAFE_READ_WRITE32!/' $@
|
||||
#sed -i 's/pub fn SAFE_READ_WRITE8!();//' $@
|
||||
#sed -i 's/pub fn SAFE_READ_WRITE16!();//' $@
|
||||
#sed -i 's/pub fn SAFE_READ_WRITE32!();//' $@
|
||||
|
||||
cp ~/DL/c2rust/scripts/v86/src/native/$@ $@
|
||||
#cat import-prefix $@.tmp | grep -v cpu2::$(basename $@):: > $@
|
||||
#cat $@.tmp | grep -v cpu2::$(basename $@):: > $@
|
||||
-rm $@.tmp
|
||||
sed -i 's/assert(/assert_c!(/' $@
|
||||
#sed -i 's/dbg_assert(/dbg_assert!(/' $@
|
||||
sed -i 's/dbg_log(/dbg_log_c!(/' $@
|
||||
#sed -i 's/pub unsafe extern "C" fn assert_c!() -> () { }//' $@
|
||||
#sed -i 's/pub unsafe extern "C" fn dbg_assert_c!() -> () { }//' $@
|
||||
#sed -i 's/pub unsafe extern "C" fn dbg_log_c!() -> () { }//' $@
|
||||
|
||||
sed -i 's/fn assert_c!() -> ();//' $@
|
||||
sed -i 's/fn dbg_assert_c!() -> ();//' $@
|
||||
sed -i 's/fn dbg_log_c!() -> ();//' $@
|
||||
|
||||
sed -i 's/fn assert_c!/fn assert_c/' $@
|
||||
sed -i 's/fn dbg_assert_c!/fn dbg_assert_c/' $@
|
||||
sed -i 's/fn dbg_log_c!/fn dbg_log_c/' $@
|
||||
|
||||
sed -i 's/libc::c_char/i8/g' $@
|
||||
sed -i 's/libc::c_double/f64/g' $@
|
||||
sed -i 's/libc::c_float/f32/g' $@
|
||||
sed -i 's/libc::c_int/i32/g' $@
|
||||
sed -i 's/libc::c_longlong/i64/g' $@
|
||||
sed -i 's/libc::c_long/i64/g' $@
|
||||
sed -i 's/libc::c_schar/i8/g' $@
|
||||
sed -i 's/libc::c_short/i16/g' $@
|
||||
sed -i 's/libc::c_uchar/u8/g' $@
|
||||
sed -i 's/libc::c_uint/u32/g' $@
|
||||
sed -i 's/libc::c_ulonglong/u64/g' $@
|
||||
sed -i 's/libc::c_ulong/u64/g' $@
|
||||
sed -i 's/libc::c_ushort/u16/g' $@
|
||||
|
||||
sed -i 's/SAFE_READ_WRITE8/SAFE_READ_WRITE8!/' $@
|
||||
sed -i 's/SAFE_READ_WRITE16/SAFE_READ_WRITE16!/' $@
|
||||
sed -i 's/SAFE_READ_WRITE32/SAFE_READ_WRITE32!/' $@
|
||||
sed -i 's/fn SAFE_READ_WRITE8!() -> ();//' $@
|
||||
sed -i 's/fn SAFE_READ_WRITE16!() -> ();//' $@
|
||||
sed -i 's/fn SAFE_READ_WRITE32!() -> ();//' $@
|
||||
|
||||
sed -i 's/pub type _IO_FILE;//' $@
|
||||
sed -i 's/pub type FILE = _IO_FILE;//' $@
|
||||
sed -i ':a;N;$$!ba;s/#\[no_mangle]\n static stdin: \*mut FILE;//' $@
|
||||
sed -i ':a;N;$$!ba;s/#\[no_mangle]\n static stdout: \*mut FILE;//' $@
|
||||
sed -i ':a;N;$$!ba;s/#\[no_mangle]\n static stderr: \*mut FILE;//' $@
|
||||
|
||||
sed -i ':a;N;$$!ba;s/#\[no_mangle]\n static mut ___: int32_t;//' $@
|
||||
|
||||
sed -i 's/SAFE_READ_WRITE8!(/SAFE_READ_WRITE8!(___, /' $@
|
||||
sed -i 's/SAFE_READ_WRITE16!(/SAFE_READ_WRITE16!(___, /' $@
|
||||
sed -i 's/SAFE_READ_WRITE32!(/SAFE_READ_WRITE32!(___, /' $@
|
||||
|
||||
sed -i 's/extern crate libc;//' $@
|
||||
|
||||
clean:
|
||||
-rm $(ALL)
|
||||
-rm profiler/profiler.rs
|
46
src/rust/cpu2/imports.rs
Normal file
46
src/rust/cpu2/imports.rs
Normal file
|
@ -0,0 +1,46 @@
|
|||
#[no_mangle]
|
||||
pub unsafe extern "C" fn run_instruction(opcode: u32) { ::gen::interpreter::run(opcode) }
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn run_instruction0f_16(opcode: u32) {
|
||||
::gen::interpreter0f_16::run(opcode as u8)
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn run_instruction0f_32(opcode: u32) {
|
||||
::gen::interpreter0f_32::run(opcode as u8)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn sqrt(x: f64) -> f64 { x.sqrt() }
|
||||
|
||||
#[no_mangle]
|
||||
pub fn sqrtf(x: f32) -> f32 { x.sqrt() }
|
||||
|
||||
#[no_mangle]
|
||||
pub fn profiler_stat_increment(stat: u32) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn profiler_stat_increment_by(stat: u32, by: u32) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn call_indirect1(f: fn(u16), x: u16) { f(x); }
|
||||
|
||||
macro_rules! dbg_assert_c {
|
||||
($fmt:expr) => {
|
||||
dbg_assert!($fmt != 0);
|
||||
};
|
||||
($fmt:expr, $($arg:tt)*) => {
|
||||
dbg_assert!($fmt != 0, $arg);
|
||||
};
|
||||
}
|
||||
macro_rules! dbg_log_c {
|
||||
($fmt:expr) => {};
|
||||
($fmt:expr, $($arg:tt)*) => {};
|
||||
}
|
||||
macro_rules! assert_c {
|
||||
($fmt:expr) => {
|
||||
assert!($fmt != 0);
|
||||
};
|
||||
($fmt:expr, $($arg:tt)*) => {
|
||||
assert!($fmt != 0, $arg);
|
||||
};
|
||||
}
|
41
src/rust/cpu2/instruction_helpers.rs
Normal file
41
src/rust/cpu2/instruction_helpers.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
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);
|
||||
}};
|
||||
}
|
||||
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);
|
||||
}
|
||||
}};
|
||||
}
|
||||
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);
|
||||
}
|
||||
}};
|
||||
}
|
20
src/rust/cpu2/mod.rs
Normal file
20
src/rust/cpu2/mod.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
#![allow(unused_assignments, unused_variables, unused_unsafe)]
|
||||
|
||||
#[macro_use]
|
||||
pub mod imports;
|
||||
|
||||
#[macro_use]
|
||||
mod instruction_helpers;
|
||||
|
||||
pub mod arith;
|
||||
pub mod cpu;
|
||||
pub mod fpu;
|
||||
pub mod global_pointers;
|
||||
pub mod instructions;
|
||||
pub mod instructions_0f;
|
||||
pub mod memory;
|
||||
pub mod misc_instr;
|
||||
pub mod modrm;
|
||||
pub mod shared;
|
||||
pub mod sse_instr;
|
||||
pub mod string;
|
|
@ -45,6 +45,7 @@ macro_rules! dbg_assert {
|
|||
column!(),
|
||||
stringify!($cond),
|
||||
));
|
||||
#[allow(unused_unsafe)]
|
||||
unsafe {
|
||||
abort();
|
||||
}
|
||||
|
@ -61,6 +62,7 @@ macro_rules! dbg_assert {
|
|||
stringify!($cond),
|
||||
$desc,
|
||||
));
|
||||
#[allow(unused_unsafe)]
|
||||
unsafe {
|
||||
abort();
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
pub mod interpreter;
|
||||
pub mod interpreter0f_16;
|
||||
pub mod interpreter0f_32;
|
||||
|
||||
pub mod jit;
|
||||
pub mod jit0f_16;
|
||||
pub mod jit0f_32;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#![feature(const_fn)]
|
||||
#![feature(extern_types)]
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
|
@ -7,7 +8,7 @@ extern crate quickcheck;
|
|||
#[macro_use]
|
||||
mod dbg;
|
||||
|
||||
mod cpu2;
|
||||
pub mod cpu2;
|
||||
|
||||
pub mod c_api;
|
||||
|
||||
|
|
38
tools/rust-lld-wrapper
Executable file
38
tools/rust-lld-wrapper
Executable file
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# A wrapper for rust-lld that removes certain arguments inserted by rustc that
|
||||
# we'd like to override
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
from os import path
|
||||
|
||||
def main():
|
||||
args = sys.argv[1:]
|
||||
|
||||
# filter out args inserted by rustc
|
||||
TO_REMOVE = {"--stack-first"}
|
||||
args = list(filter(lambda arg: arg not in TO_REMOVE, args))
|
||||
|
||||
lld = find_rust_lld()
|
||||
|
||||
result = subprocess.run([lld] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
result.check_returncode()
|
||||
|
||||
print(result.stderr, file=sys.stderr)
|
||||
print(result.stdout)
|
||||
|
||||
def find_rust_lld():
|
||||
which = subprocess.run(["rustup", "which", "rustc"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
which.check_returncode()
|
||||
|
||||
rustc_path = which.stdout.decode("utf8").strip()
|
||||
assert path.basename(rustc_path) == "rustc"
|
||||
|
||||
bin_path = path.dirname(rustc_path)
|
||||
rust_lld_path = path.join(bin_path, "../lib/rustlib/x86_64-unknown-linux-gnu/bin/rust-lld")
|
||||
|
||||
assert path.isfile(rust_lld_path)
|
||||
return rust_lld_path
|
||||
|
||||
main()
|
184
tools/wasm-patch-indirect-function-table.js
Executable file
184
tools/wasm-patch-indirect-function-table.js
Executable file
|
@ -0,0 +1,184 @@
|
|||
#!/usr/bin/env node
|
||||
"use strict";
|
||||
|
||||
// Read a wasm module in binary format from stdin, find table import entries, i.e.:
|
||||
//
|
||||
// (import "env" "table" (table (;0;) <initial> <maximum> anyfunc))
|
||||
//
|
||||
// Remove the <maximum> and write the patched wasm module to stdout.
|
||||
|
||||
process.on("unhandledRejection", exn => { throw exn; });
|
||||
|
||||
const fs = require("fs");
|
||||
|
||||
const SECTION_IMPORT = 2;
|
||||
|
||||
const IMPORT_KIND_FUNCTION = 0;
|
||||
const IMPORT_KIND_TABLE = 1;
|
||||
const IMPORT_KIND_MEMORY = 2;
|
||||
const IMPORT_KIND_GLOBAL = 3;
|
||||
|
||||
function main()
|
||||
{
|
||||
const wasm = fs.readFileSync("/dev/stdin");
|
||||
const view = new DataView(wasm.buffer);
|
||||
var ptr = 0;
|
||||
|
||||
// magic
|
||||
console.assert(view.getUint32(ptr, true) === 0x6d736100);
|
||||
ptr += 4;
|
||||
|
||||
// version
|
||||
console.assert(view.getUint32(ptr, true) === 1);
|
||||
ptr += 4;
|
||||
|
||||
while(ptr < view.byteLength)
|
||||
{
|
||||
const section_id = view.getUint8(ptr);
|
||||
ptr++;
|
||||
var { ptr, value: size } = read_leb_u32(ptr, view);
|
||||
const section_end = ptr + size;
|
||||
|
||||
if(section_id === SECTION_IMPORT)
|
||||
{
|
||||
patch_import_section(ptr, view);
|
||||
}
|
||||
|
||||
ptr = section_end;
|
||||
}
|
||||
|
||||
// sanity check
|
||||
const module = new WebAssembly.Module(view.buffer);
|
||||
|
||||
process.stdout.write(wasm);
|
||||
}
|
||||
|
||||
function patch_import_section(ptr, view)
|
||||
{
|
||||
var { ptr, value: section_entry_count } = read_leb_u32(ptr, view);
|
||||
|
||||
for(let i = 0; i < section_entry_count; i++)
|
||||
{
|
||||
var { ptr, value: module_str_length } = read_leb_u32(ptr, view);
|
||||
ptr += module_str_length;
|
||||
var { ptr, value: field_str_length } = read_leb_u32(ptr, view);
|
||||
ptr += field_str_length;
|
||||
|
||||
const kind = view.getUint8(ptr);
|
||||
ptr++;
|
||||
|
||||
if(kind === IMPORT_KIND_FUNCTION)
|
||||
{
|
||||
var { ptr, value: function_signature_index } = read_leb_u32(ptr, view);
|
||||
}
|
||||
else if(kind === IMPORT_KIND_TABLE)
|
||||
{
|
||||
const table_offset = ptr;
|
||||
var { ptr, value: table_element_type } = read_leb_u32(ptr, view);
|
||||
console.assert(table_element_type === 0x70);
|
||||
|
||||
const maximum_present = new Uint8Array(view.buffer, ptr, 1);
|
||||
console.assert(maximum_present[0] === 0 || maximum_present[0] === 1);
|
||||
ptr++;
|
||||
|
||||
var { ptr, value: initial_table_size, leb_view: initial_table_size_view } = read_leb_u32(ptr, view);
|
||||
|
||||
if(maximum_present[0])
|
||||
{
|
||||
var { ptr, value: maximum_table_size, leb_view: maximum_table_size_view } = read_leb_u32(ptr, view);
|
||||
}
|
||||
else
|
||||
{
|
||||
maximum_table_size = -1;
|
||||
}
|
||||
|
||||
console.error(`Found table import at offset` +
|
||||
` ${table_offset}` +
|
||||
` maximum_present=${maximum_present[0]}` +
|
||||
` initial=${initial_table_size}` +
|
||||
` maximum=${maximum_table_size}`);
|
||||
|
||||
if(maximum_present[0])
|
||||
{
|
||||
patch_maximum_limit(maximum_present, initial_table_size_view, maximum_table_size_view);
|
||||
console.error("Patched!");
|
||||
}
|
||||
else
|
||||
{
|
||||
console.error("No maximum present, skipped");
|
||||
}
|
||||
}
|
||||
else if(kind === IMPORT_KIND_MEMORY)
|
||||
{
|
||||
const maximum_present = view.getUint8(ptr);
|
||||
console.assert(maximum_present === 0 || maximum_present === 1);
|
||||
ptr++;
|
||||
|
||||
var { ptr, value: initial_memory_size } = read_leb_u32(ptr, view);
|
||||
|
||||
if(maximum_present)
|
||||
{
|
||||
var { ptr, value: maximum_memory_size } = read_leb_u32(ptr, view);
|
||||
}
|
||||
}
|
||||
else if(kind === IMPORT_KIND_GLOBAL)
|
||||
{
|
||||
const content_type = view.getUint8(ptr);
|
||||
ptr++;
|
||||
const mutability = view.getUint8(ptr);
|
||||
console.assert(mutability === 0 || mutability === 1);
|
||||
ptr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
console.assert(false, `Unexpected import kind: 0x${kind.toString(16)} at offset ${ptr - 1}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function patch_maximum_limit(maximum_present, initial_size, maximum_size)
|
||||
{
|
||||
// clear the maximum present bit
|
||||
maximum_present[0] = 0;
|
||||
|
||||
// set the highest bit of the initial size, in order to use it to pad the existing maximum size bytes
|
||||
const last_byte_initial_size = initial_size[initial_size.length - 1];
|
||||
console.assert((last_byte_initial_size & 0x80) === 0);
|
||||
initial_size[initial_size.length - 1] = last_byte_initial_size | 0x80;
|
||||
|
||||
for(let i = 0; i < maximum_size.length - 1; i++)
|
||||
{
|
||||
// pad maximum value with 0x80 bytes
|
||||
maximum_size[i] = 0x80;
|
||||
}
|
||||
|
||||
// pad the last byte of the maximum value with 0x00
|
||||
maximum_size[maximum_size.length - 1] = 0x00;
|
||||
}
|
||||
|
||||
function read_leb_u32(ptr, view)
|
||||
{
|
||||
let value = 0;
|
||||
let byte_length = 0;
|
||||
|
||||
while(true)
|
||||
{
|
||||
let byte = view.getUint8(ptr++);
|
||||
|
||||
value |= (byte & 0x7f) << (byte_length * 7);
|
||||
byte_length++;
|
||||
|
||||
if((byte & 0x80) === 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
console.assert(byte_length <= 4);
|
||||
|
||||
const leb_view = new Uint8Array(view.buffer, ptr - byte_length, byte_length);
|
||||
|
||||
return { ptr, value, leb_view };
|
||||
}
|
||||
|
||||
main();
|
Loading…
Reference in a new issue