Use that to not bump RIP for those cases. Warn on read/write from/to unmapped MMIO, but not consider that as an exception. For reads, return 0xFF(s) as the register value in that case.
Leaves a coverage gap for read_val_ext(), to be handled in a later commit. Signed-off-by: Mohamed Mediouni <[email protected]> --- target/i386/emulate/x86_emu.c | 119 +++++++++++++++++++++++++--------- 1 file changed, 88 insertions(+), 31 deletions(-) diff --git a/target/i386/emulate/x86_emu.c b/target/i386/emulate/x86_emu.c index 3aedd638a1..ec6bc798a4 100644 --- a/target/i386/emulate/x86_emu.c +++ b/target/i386/emulate/x86_emu.c @@ -36,11 +36,14 @@ ///////////////////////////////////////////////////////////////////////// #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "panic.h" #include "x86_decode.h" #include "x86.h" #include "x86_emu.h" #include "x86_flags.h" +#include "x86_mmu.h" + #define EXEC_2OP_FLAGS_CMD(env, decode, cmd, FLAGS_FUNC, save_res) \ { \ @@ -175,43 +178,56 @@ void write_val_ext(CPUX86State *env, struct x86_decode_op *decode, target_ulong uint8_t *read_mmio(CPUX86State *env, target_ulong ptr, int bytes) { - x86_read_mem(env_cpu(env), env->emu_mmio_buf, ptr, bytes); + MMUTranslateResult res = x86_read_mem(env_cpu(env), env->emu_mmio_buf, ptr, bytes); + if (res) { + if (res == MMU_TRANSLATE_GPA_UNMAPPED) { + memset(env->emu_mmio_buf, 0xFF, bytes); + return env->emu_mmio_buf; + } + return NULL; + } return env->emu_mmio_buf; } -static target_ulong read_val_from_mem(CPUX86State *env, target_long ptr, int size) +static bool read_val_from_mem(CPUX86State *env, target_long ptr, int size, target_ulong* val) { - target_ulong val; uint8_t *mmio_ptr; mmio_ptr = read_mmio(env, ptr, size); + if (mmio_ptr == NULL) { + return 1; + } switch (size) { case 1: - val = *(uint8_t *)mmio_ptr; + *val = *(uint8_t *)mmio_ptr; break; case 2: - val = *(uint16_t *)mmio_ptr; + *val = *(uint16_t *)mmio_ptr; break; case 4: - val = *(uint32_t *)mmio_ptr; + *val = *(uint32_t *)mmio_ptr; break; case 8: - val = *(uint64_t *)mmio_ptr; + *val = *(uint64_t *)mmio_ptr; break; default: VM_PANIC("bad size\n"); break; } - return val; + return 0; } target_ulong read_val_ext(CPUX86State *env, struct x86_decode_op *decode, int size) { + target_ulong val; if (decode->type == X86_VAR_REG) { return read_val_from_reg(decode->regptr, size); } else { - return read_val_from_mem(env, decode->addr, size); + if (read_val_from_mem(env, decode->addr, size, &val)) { + error_report("target/i386/emulate: read_val_ext: reading from unmapped address."); + } + return val; } } @@ -465,15 +481,17 @@ static inline int get_ZF(CPUX86State *env) { return env->cc_dst ? 0 : CC_Z; } -static inline void string_rep(CPUX86State *env, struct x86_decode *decode, - void (*func)(CPUX86State *env, +static inline bool string_rep(CPUX86State *env, struct x86_decode *decode, + bool (*func)(CPUX86State *env, struct x86_decode *ins), int rep) { target_ulong rcx = read_reg(env, R_ECX, decode->addressing_size); while (rcx != 0) { bool is_cmps_or_scas = decode->cmd == X86_DECODE_CMD_CMPS || decode->cmd == X86_DECODE_CMD_SCAS; - func(env, decode); + if (func(env, decode)) { + return 1; + } rcx--; write_reg(env, R_ECX, rcx, decode->addressing_size); if ((PREFIX_REP == rep) && !get_ZF(env) && is_cmps_or_scas) { @@ -483,33 +501,44 @@ static inline void string_rep(CPUX86State *env, struct x86_decode *decode, break; } } + return 0; } -static void exec_ins_single(CPUX86State *env, struct x86_decode *decode) +static bool exec_ins_single(CPUX86State *env, struct x86_decode *decode) { + MMUTranslateResult res; + target_ulong addr = linear_addr_size(env_cpu(env), RDI(env), decode->addressing_size, R_ES); emul_ops->handle_io(env_cpu(env), DX(env), env->emu_mmio_buf, 0, decode->operand_size, 1); - x86_write_mem(env_cpu(env), env->emu_mmio_buf, addr, + res = x86_write_mem(env_cpu(env), env->emu_mmio_buf, addr, decode->operand_size); + if (res) { + return 1; + } string_increment_reg(env, R_EDI, decode); + return 0; } static void exec_ins(CPUX86State *env, struct x86_decode *decode) { + bool res; if (decode->rep) { - string_rep(env, decode, exec_ins_single, 0); + res = string_rep(env, decode, exec_ins_single, 0); } else { - exec_ins_single(env, decode); + res = exec_ins_single(env, decode); } + if (res) { + return; + } env->eip += decode->len; } -static void exec_outs_single(CPUX86State *env, struct x86_decode *decode) +static bool exec_outs_single(CPUX86State *env, struct x86_decode *decode) { target_ulong addr = decode_linear_addr(env, decode, RSI(env), R_DS); @@ -519,48 +548,64 @@ static void exec_outs_single(CPUX86State *env, struct x86_decode *decode) decode->operand_size, 1); string_increment_reg(env, R_ESI, decode); + return 0; } static void exec_outs(CPUX86State *env, struct x86_decode *decode) { + bool res; if (decode->rep) { - string_rep(env, decode, exec_outs_single, 0); + res = string_rep(env, decode, exec_outs_single, 0); } else { - exec_outs_single(env, decode); + res = exec_outs_single(env, decode); } + if (res) { + return; + } env->eip += decode->len; } -static void exec_movs_single(CPUX86State *env, struct x86_decode *decode) +static bool exec_movs_single(CPUX86State *env, struct x86_decode *decode) { target_ulong src_addr; target_ulong dst_addr; target_ulong val; + MMUTranslateResult res; src_addr = decode_linear_addr(env, decode, RSI(env), R_DS); dst_addr = linear_addr_size(env_cpu(env), RDI(env), decode->addressing_size, R_ES); - val = read_val_from_mem(env, src_addr, decode->operand_size); - x86_write_mem(env_cpu(env), &val, dst_addr, decode->operand_size); + if (read_val_from_mem(env, src_addr, decode->operand_size, &val)) { + return 1; + } + res = x86_write_mem(env_cpu(env), &val, dst_addr, decode->operand_size); + if (res) { + return 1; + } string_increment_reg(env, R_ESI, decode); string_increment_reg(env, R_EDI, decode); + return 0; } static void exec_movs(CPUX86State *env, struct x86_decode *decode) { + bool res; if (decode->rep) { - string_rep(env, decode, exec_movs_single, 0); + res = string_rep(env, decode, exec_movs_single, 0); } else { - exec_movs_single(env, decode); + res = exec_movs_single(env, decode); } + if (res) { + return; + } env->eip += decode->len; } -static void exec_cmps_single(CPUX86State *env, struct x86_decode *decode) +static bool exec_cmps_single(CPUX86State *env, struct x86_decode *decode) { target_ulong src_addr; target_ulong dst_addr; @@ -570,14 +615,19 @@ static void exec_cmps_single(CPUX86State *env, struct x86_decode *decode) decode->addressing_size, R_ES); decode->op[0].type = X86_VAR_IMMEDIATE; - decode->op[0].val = read_val_from_mem(env, src_addr, decode->operand_size); + if (read_val_from_mem(env, src_addr, decode->operand_size, &decode->op[0].val)) { + return 1; + } decode->op[1].type = X86_VAR_IMMEDIATE; - decode->op[1].val = read_val_from_mem(env, dst_addr, decode->operand_size); + if (read_val_from_mem(env, dst_addr, decode->operand_size, &decode->op[1].val)) { + return 1; + } EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); string_increment_reg(env, R_ESI, decode); string_increment_reg(env, R_EDI, decode); + return 0; } static void exec_cmps(CPUX86State *env, struct x86_decode *decode) @@ -591,17 +641,22 @@ static void exec_cmps(CPUX86State *env, struct x86_decode *decode) } -static void exec_stos_single(CPUX86State *env, struct x86_decode *decode) +static bool exec_stos_single(CPUX86State *env, struct x86_decode *decode) { target_ulong addr; target_ulong val; + MMUTranslateResult res; addr = linear_addr_size(env_cpu(env), RDI(env), decode->addressing_size, R_ES); val = read_reg(env, R_EAX, decode->operand_size); - x86_write_mem(env_cpu(env), &val, addr, decode->operand_size); + res = x86_write_mem(env_cpu(env), &val, addr, decode->operand_size); + if (res) { + return 1; + } string_increment_reg(env, R_EDI, decode); + return 0; } @@ -616,7 +671,7 @@ static void exec_stos(CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -static void exec_scas_single(CPUX86State *env, struct x86_decode *decode) +static bool exec_scas_single(CPUX86State *env, struct x86_decode *decode) { target_ulong addr; @@ -627,6 +682,7 @@ static void exec_scas_single(CPUX86State *env, struct x86_decode *decode) EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); string_increment_reg(env, R_EDI, decode); + return 0; } static void exec_scas(CPUX86State *env, struct x86_decode *decode) @@ -642,7 +698,7 @@ static void exec_scas(CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -static void exec_lods_single(CPUX86State *env, struct x86_decode *decode) +static bool exec_lods_single(CPUX86State *env, struct x86_decode *decode) { target_ulong addr; target_ulong val = 0; @@ -652,6 +708,7 @@ static void exec_lods_single(CPUX86State *env, struct x86_decode *decode) write_reg(env, R_EAX, val, decode->operand_size); string_increment_reg(env, R_ESI, decode); + return 0; } static void exec_lods(CPUX86State *env, struct x86_decode *decode) -- 2.50.1 (Apple Git-155)
