From 5da4e192ec64bdb0d101c844887ea8082e79f622 Mon Sep 17 00:00:00 2001 From: Fabian Date: Thu, 31 Dec 2020 19:14:33 -0600 Subject: [PATCH] Use exit-with-fault block for all faults (#gp, #de, etc.) --- src/rust/codegen.rs | 84 +++++++++++++++------------------ src/rust/cpu/cpu.rs | 72 +++++++++++++++++++++++----- src/rust/cpu/global_pointers.rs | 1 - src/rust/jit.rs | 12 ++--- 4 files changed, 103 insertions(+), 66 deletions(-) diff --git a/src/rust/codegen.rs b/src/rust/codegen.rs index cfa51322..c71bd3e8 100644 --- a/src/rust/codegen.rs +++ b/src/rust/codegen.rs @@ -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) { diff --git a/src/rust/cpu/cpu.rs b/src/rust/cpu/cpu.rs index 4ef8191a..03b90d5e 100644 --- a/src/rust/cpu/cpu.rs +++ b/src/rust/cpu/cpu.rs @@ -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)> = 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 { diff --git a/src/rust/cpu/global_pointers.rs b/src/rust/cpu/global_pointers.rs index 97d57b70..04396eeb 100644 --- a/src/rust/cpu/global_pointers.rs +++ b/src/rust/cpu/global_pointers.rs @@ -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; diff --git a/src/rust/jit.rs b/src/rust/jit.rs index de357581..7864c7d5 100644 --- a/src/rust/jit.rs +++ b/src/rust/jit.rs @@ -199,7 +199,7 @@ pub struct JitContext<'a> { pub register_locals: &'a mut Vec, 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_(); }