Use exit-with-fault block for all faults (#gp, #de, etc.)

This commit is contained in:
Fabian 2020-12-31 19:14:33 -06:00
commit 5da4e192ec
4 changed files with 103 additions and 66 deletions

View file

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

View file

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

View file

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

View file

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