Use exit-with-fault block for all faults (#gp, #de, etc.)
This commit is contained in:
parent
aa6de5014c
commit
5da4e192ec
4 changed files with 103 additions and 66 deletions
|
|
@ -583,7 +583,7 @@ fn gen_safe_read(
|
|||
ctx.builder.and_i32();
|
||||
}
|
||||
|
||||
ctx.builder.br_if(ctx.exit_with_pagefault_label);
|
||||
ctx.builder.br_if(ctx.exit_with_fault_label);
|
||||
|
||||
ctx.builder.block_end();
|
||||
|
||||
|
|
@ -688,7 +688,7 @@ pub fn gen_get_phys_eip(ctx: &mut JitContext, address_local: &WasmLocal) {
|
|||
ctx.builder.and_i32();
|
||||
}
|
||||
|
||||
ctx.builder.br_if(ctx.exit_with_pagefault_label);
|
||||
ctx.builder.br_if(ctx.exit_with_fault_label);
|
||||
|
||||
ctx.builder.block_end();
|
||||
|
||||
|
|
@ -799,7 +799,7 @@ fn gen_safe_write(
|
|||
ctx.builder.and_i32();
|
||||
}
|
||||
|
||||
ctx.builder.br_if(ctx.exit_with_pagefault_label);
|
||||
ctx.builder.br_if(ctx.exit_with_fault_label);
|
||||
|
||||
ctx.builder.block_end();
|
||||
|
||||
|
|
@ -939,7 +939,7 @@ pub fn gen_safe_read_write(
|
|||
ctx.builder.and_i32();
|
||||
}
|
||||
|
||||
ctx.builder.br_if(ctx.exit_with_pagefault_label);
|
||||
ctx.builder.br_if(ctx.exit_with_fault_label);
|
||||
|
||||
ctx.builder.block_end();
|
||||
|
||||
|
|
@ -1282,7 +1282,7 @@ pub fn gen_leave(ctx: &mut JitContext, os32: bool) {
|
|||
}
|
||||
|
||||
pub fn gen_task_switch_test(ctx: &mut JitContext) {
|
||||
// generate if(cr[0] & (CR0_EM | CR0_TS)) { task_switch_test_void(); return; }
|
||||
// generate if(cr[0] & (CR0_EM | CR0_TS)) { task_switch_test_jit(); goto exit_with_fault; }
|
||||
let cr0_offset = global_pointers::get_creg_offset(0);
|
||||
|
||||
dbg_assert!(regs::CR0_EM | regs::CR0_TS <= 0xFF);
|
||||
|
|
@ -1291,24 +1291,20 @@ pub fn gen_task_switch_test(ctx: &mut JitContext) {
|
|||
ctx.builder.and_i32();
|
||||
|
||||
ctx.builder.if_void();
|
||||
|
||||
gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
|
||||
|
||||
gen_set_previous_eip_offset_from_eip_with_low_bits(
|
||||
ctx.builder,
|
||||
ctx.start_of_current_instruction as i32 & 0xFFF,
|
||||
);
|
||||
|
||||
gen_move_registers_from_locals_to_memory(ctx);
|
||||
gen_fn0_const(ctx.builder, "task_switch_test_jit");
|
||||
|
||||
ctx.builder.return_();
|
||||
|
||||
{
|
||||
gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
|
||||
gen_fn1_const(
|
||||
ctx.builder,
|
||||
"task_switch_test_jit",
|
||||
ctx.start_of_current_instruction,
|
||||
);
|
||||
ctx.builder.br(ctx.exit_with_fault_label);
|
||||
}
|
||||
ctx.builder.block_end();
|
||||
}
|
||||
|
||||
pub fn gen_task_switch_test_mmx(ctx: &mut JitContext) {
|
||||
// generate if(cr[0] & (CR0_EM | CR0_TS)) { task_switch_test_mmx_void(); return; }
|
||||
// generate if(cr[0] & (CR0_EM | CR0_TS)) { task_switch_test_mmx_jit(); goto exit_with_fault; }
|
||||
let cr0_offset = global_pointers::get_creg_offset(0);
|
||||
|
||||
dbg_assert!(regs::CR0_EM | regs::CR0_TS <= 0xFF);
|
||||
|
|
@ -1317,19 +1313,15 @@ pub fn gen_task_switch_test_mmx(ctx: &mut JitContext) {
|
|||
ctx.builder.and_i32();
|
||||
|
||||
ctx.builder.if_void();
|
||||
|
||||
gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
|
||||
|
||||
gen_set_previous_eip_offset_from_eip_with_low_bits(
|
||||
ctx.builder,
|
||||
ctx.start_of_current_instruction as i32 & 0xFFF,
|
||||
);
|
||||
|
||||
gen_move_registers_from_locals_to_memory(ctx);
|
||||
gen_fn0_const(ctx.builder, "task_switch_test_mmx_jit");
|
||||
|
||||
ctx.builder.return_();
|
||||
|
||||
{
|
||||
gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
|
||||
gen_fn1_const(
|
||||
ctx.builder,
|
||||
"task_switch_test_mmx_jit",
|
||||
ctx.start_of_current_instruction,
|
||||
);
|
||||
ctx.builder.br(ctx.exit_with_fault_label);
|
||||
}
|
||||
ctx.builder.block_end();
|
||||
}
|
||||
|
||||
|
|
@ -1726,36 +1718,34 @@ pub fn gen_fpu_load_i64(ctx: &mut JitContext, modrm_byte: ModrmByte) {
|
|||
}
|
||||
|
||||
pub fn gen_trigger_de(ctx: &mut JitContext) {
|
||||
gen_move_registers_from_locals_to_memory(ctx);
|
||||
gen_set_previous_eip_offset_from_eip_with_low_bits(
|
||||
gen_fn1_const(
|
||||
ctx.builder,
|
||||
ctx.start_of_current_instruction as i32 & 0xFFF,
|
||||
"trigger_de_jit",
|
||||
ctx.start_of_current_instruction,
|
||||
);
|
||||
gen_fn0_const(ctx.builder, "trigger_de");
|
||||
gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
|
||||
ctx.builder.return_();
|
||||
ctx.builder.br(ctx.exit_with_fault_label);
|
||||
}
|
||||
|
||||
pub fn gen_trigger_ud(ctx: &mut JitContext) {
|
||||
gen_move_registers_from_locals_to_memory(ctx);
|
||||
gen_set_previous_eip_offset_from_eip_with_low_bits(
|
||||
gen_fn1_const(
|
||||
ctx.builder,
|
||||
ctx.start_of_current_instruction as i32 & 0xFFF,
|
||||
"trigger_ud_jit",
|
||||
ctx.start_of_current_instruction,
|
||||
);
|
||||
gen_fn0_const(ctx.builder, "trigger_ud");
|
||||
gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
|
||||
ctx.builder.return_();
|
||||
ctx.builder.br(ctx.exit_with_fault_label);
|
||||
}
|
||||
|
||||
pub fn gen_trigger_gp(ctx: &mut JitContext, error_code: u32) {
|
||||
gen_move_registers_from_locals_to_memory(ctx);
|
||||
gen_set_previous_eip_offset_from_eip_with_low_bits(
|
||||
gen_fn2_const(
|
||||
ctx.builder,
|
||||
ctx.start_of_current_instruction as i32 & 0xFFF,
|
||||
"trigger_gp_jit",
|
||||
error_code,
|
||||
ctx.start_of_current_instruction,
|
||||
);
|
||||
gen_fn1_const(ctx.builder, "trigger_gp", error_code);
|
||||
gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
|
||||
ctx.builder.return_();
|
||||
ctx.builder.br(ctx.exit_with_fault_label);
|
||||
}
|
||||
|
||||
pub fn gen_condition_fn(ctx: &mut JitContext, condition: u8) {
|
||||
|
|
|
|||
|
|
@ -258,6 +258,8 @@ pub static mut valid_tlb_entries_count: i32 = 0;
|
|||
|
||||
pub static mut in_jit: bool = false;
|
||||
|
||||
pub static mut jit_fault: Option<(i32, Option<i32>)> = None;
|
||||
|
||||
pub enum LastJump {
|
||||
Interrupt {
|
||||
phys_addr: u32,
|
||||
|
|
@ -1773,11 +1775,11 @@ pub unsafe fn clear_tlb() {
|
|||
/// - safe_{read,write}*_jit call translate_address_{read,write}_jit
|
||||
/// - translate_address_{read,write}_jit do the normal page walk and call this method instead of
|
||||
/// trigger_pagefault when a page fault happens
|
||||
/// - this method prepares a page fault by setting cr2, eip, prefixes and writes the error code
|
||||
/// into page_fault_error_code. This method *doesn't* trigger the interrupt, as registers are
|
||||
/// - this method prepares a page fault by setting cr2, and writes the error code
|
||||
/// into jit_fault. This method *doesn't* trigger the interrupt, as registers are
|
||||
/// still stored in the wasm module
|
||||
/// - back in the wasm module, the generated code detects the page fault, restores the registers
|
||||
/// and finally calls trigger_pagefault_end_jit, which does the interrupt
|
||||
/// and finally calls trigger_fault_end_jit, which does the interrupt
|
||||
pub unsafe fn trigger_pagefault_jit(fault: PageFault) {
|
||||
let write = fault.for_writing;
|
||||
let addr = fault.addr;
|
||||
|
|
@ -1812,12 +1814,48 @@ pub unsafe fn trigger_pagefault_jit(fault: PageFault) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
*page_fault_error_code = (user as i32) << 2 | (write as i32) << 1 | present as i32;
|
||||
let error_code = (user as i32) << 2 | (write as i32) << 1 | present as i32;
|
||||
jit_fault = Some((CPU_EXCEPTION_PF, Some(error_code)));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn trigger_pagefault_end_jit() {
|
||||
call_interrupt_vector(CPU_EXCEPTION_PF, false, Some(*page_fault_error_code));
|
||||
pub unsafe fn trigger_de_jit(start_eip: i32) {
|
||||
dbg_log!("#de in jit mode");
|
||||
*instruction_pointer = *instruction_pointer & !0xFFF | start_eip & 0xFFF;
|
||||
jit_fault = Some((CPU_EXCEPTION_DE, None))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn trigger_ud_jit(start_eip: i32) {
|
||||
dbg_log!("#ud in jit mode");
|
||||
*instruction_pointer = *instruction_pointer & !0xFFF | start_eip & 0xFFF;
|
||||
jit_fault = Some((CPU_EXCEPTION_UD, None))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn trigger_nm_jit(start_eip: i32) {
|
||||
dbg_log!("#nm in jit mode");
|
||||
*instruction_pointer = *instruction_pointer & !0xFFF | start_eip & 0xFFF;
|
||||
jit_fault = Some((CPU_EXCEPTION_NM, None))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn trigger_gp_jit(code: i32, start_eip: i32) {
|
||||
dbg_log!("#gp in jit mode");
|
||||
*instruction_pointer = *instruction_pointer & !0xFFF | start_eip & 0xFFF;
|
||||
jit_fault = Some((CPU_EXCEPTION_GP, Some(code)))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn trigger_fault_end_jit() {
|
||||
let (code, error_code) = jit_fault.unwrap();
|
||||
jit_fault = None;
|
||||
if DEBUG {
|
||||
if cpu_exception_hook(code) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
call_interrupt_vector(code, false, error_code);
|
||||
}
|
||||
|
||||
pub unsafe fn trigger_pagefault(fault: PageFault) {
|
||||
|
|
@ -3246,9 +3284,9 @@ pub unsafe fn set_mxcsr(new_mxcsr: i32) {
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn task_switch_test_jit() {
|
||||
let did_fault = !task_switch_test();
|
||||
dbg_assert!(did_fault);
|
||||
pub unsafe fn task_switch_test_jit(start_eip: i32) {
|
||||
dbg_assert!(0 != *cr & (CR0_EM | CR0_TS));
|
||||
trigger_nm_jit(start_eip);
|
||||
}
|
||||
|
||||
pub unsafe fn task_switch_test_mmx() -> bool {
|
||||
|
|
@ -3269,9 +3307,19 @@ pub unsafe fn task_switch_test_mmx() -> bool {
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn task_switch_test_mmx_jit() {
|
||||
let did_fault = !task_switch_test_mmx();
|
||||
dbg_assert!(did_fault);
|
||||
pub unsafe fn task_switch_test_mmx_jit(start_eip: i32) {
|
||||
if *cr.offset(4) & CR4_OSFXSR == 0 {
|
||||
dbg_log!("Warning: Unimplemented task switch test with cr4.osfxsr=0");
|
||||
}
|
||||
if 0 != *cr & CR0_EM {
|
||||
trigger_ud_jit(start_eip);
|
||||
}
|
||||
else if 0 != *cr & CR0_TS {
|
||||
trigger_nm_jit(start_eip);
|
||||
}
|
||||
else {
|
||||
dbg_assert!(false);
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn read_moffs() -> OrPageFault<i32> {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ pub const flags_changed: *mut i32 = 116 as *mut i32;
|
|||
pub const flags: *mut i32 = 120 as *mut i32;
|
||||
|
||||
pub const page_fault: *mut bool = 540 as *mut bool;
|
||||
pub const page_fault_error_code: *mut i32 = 544 as *mut i32;
|
||||
|
||||
pub const apic_enabled: *mut bool = 548 as *mut bool;
|
||||
pub const acpi_enabled: *mut bool = 552 as *mut bool;
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ pub struct JitContext<'a> {
|
|||
pub register_locals: &'a mut Vec<WasmLocal>,
|
||||
pub start_of_current_instruction: u32,
|
||||
pub main_loop_label: Label,
|
||||
pub exit_with_pagefault_label: Label,
|
||||
pub exit_with_fault_label: Label,
|
||||
pub exit_label: Label,
|
||||
pub our_wasm_table_index: WasmTableIndex,
|
||||
pub basic_block_index_local: &'a WasmLocal,
|
||||
|
|
@ -881,7 +881,7 @@ fn jit_generate_module(
|
|||
let main_loop_label = builder.loop_void();
|
||||
|
||||
builder.block_void(); // for the default case
|
||||
let exit_with_pagefault_label = builder.block_void(); // for the exit-with-pagefault case
|
||||
let exit_with_fault_label = builder.block_void(); // for the exit-with-fault case
|
||||
|
||||
let ctx = &mut JitContext {
|
||||
cpu: &mut cpu,
|
||||
|
|
@ -889,7 +889,7 @@ fn jit_generate_module(
|
|||
register_locals: &mut register_locals,
|
||||
start_of_current_instruction: 0,
|
||||
main_loop_label,
|
||||
exit_with_pagefault_label,
|
||||
exit_with_fault_label,
|
||||
exit_label,
|
||||
our_wasm_table_index: wasm_table_index,
|
||||
basic_block_index_local: &gen_local_state,
|
||||
|
|
@ -921,7 +921,7 @@ fn jit_generate_module(
|
|||
}
|
||||
|
||||
ctx.builder.get_local(&gen_local_state);
|
||||
ctx.builder.brtable_and_cases(basic_blocks.len() as u32 + 1); // plus one for the exit-with-pagefault case
|
||||
ctx.builder.brtable_and_cases(basic_blocks.len() as u32 + 1); // plus one for the exit-with-fault case
|
||||
|
||||
for (i, block) in basic_blocks.iter().enumerate() {
|
||||
// Case [i] will jump after the [i]th block, so we first generate the
|
||||
|
|
@ -1102,10 +1102,10 @@ fn jit_generate_module(
|
|||
}
|
||||
|
||||
{
|
||||
// exit-with-pagefault case
|
||||
// exit-with-fault case
|
||||
ctx.builder.block_end();
|
||||
codegen::gen_move_registers_from_locals_to_memory(ctx);
|
||||
codegen::gen_fn0_const(ctx.builder, "trigger_pagefault_end_jit");
|
||||
codegen::gen_fn0_const(ctx.builder, "trigger_fault_end_jit");
|
||||
ctx.builder.return_();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue