From: Mohamed Mediouni <mohamed@unpredictable.fr>
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 <mohamed@unpredictable.fr>
Link: https://lore.kernel.org/r/20260223233950.96076-25-mohamed@unpredictable.fr
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
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 3aedd638a10..ec6bc798a42 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.53.0