target/i386: emulate: propagate memory errors on most reads/writes
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>
Mohamed Mediouni committed
Feb 24, 2026 at 00:39 UTC
192d377c98d3d8fcd89b009c56eb4ca32e121744
1 file changed
+88
-31
target/i386/emulate/x86_emu.c
+88
-31
@@ -36,11 +36,14 @@
36
/////////////////////////////////////////////////////////////////////////
37
38
#include "qemu/osdep.h"
39
+#include "qemu/error-report.h"
40
#include "panic.h"
41
#include "x86_decode.h"
42
#include "x86.h"
43
#include "x86_emu.h"
44
#include "x86_flags.h"
45
+#include "x86_mmu.h"
46
+
47
48
#define EXEC_2OP_FLAGS_CMD(env, decode, cmd, FLAGS_FUNC, save_res) \
49
{ \
@@ -175,43 +178,56 @@ void write_val_ext(CPUX86State *env, struct x86_decode_op *decode, target_ulong
178
179
uint8_t *read_mmio(CPUX86State *env, target_ulong ptr, int bytes)
180
{
178
- x86_read_mem(env_cpu(env), env->emu_mmio_buf, ptr, bytes);
181
+ MMUTranslateResult res = x86_read_mem(env_cpu(env), env->emu_mmio_buf, ptr, bytes);
182
+ if (res) {
183
+ if (res == MMU_TRANSLATE_GPA_UNMAPPED) {
184
+ memset(env->emu_mmio_buf, 0xFF, bytes);
185
+ return env->emu_mmio_buf;
186
+ }
187
+ return NULL;
188
+ }
189
return env->emu_mmio_buf;
190
}
191
192
183
-static target_ulong read_val_from_mem(CPUX86State *env, target_long ptr, int size)
193
+static bool read_val_from_mem(CPUX86State *env, target_long ptr, int size, target_ulong* val)
194
{
185
- target_ulong val;
195
uint8_t *mmio_ptr;
196
197
mmio_ptr = read_mmio(env, ptr, size);
198
+ if (mmio_ptr == NULL) {
199
+ return 1;
200
+ }
201
switch (size) {
202
case 1:
191
- val = *(uint8_t *)mmio_ptr;
203
+ *val = *(uint8_t *)mmio_ptr;
204
break;
205
case 2:
194
- val = *(uint16_t *)mmio_ptr;
206
+ *val = *(uint16_t *)mmio_ptr;
207
break;
208
case 4:
197
- val = *(uint32_t *)mmio_ptr;
209
+ *val = *(uint32_t *)mmio_ptr;
210
break;
211
case 8:
200
- val = *(uint64_t *)mmio_ptr;
212
+ *val = *(uint64_t *)mmio_ptr;
213
break;
214
default:
215
VM_PANIC("bad size\n");
216
break;
217
}
206
- return val;
218
+ return 0;
219
}
220
221
target_ulong read_val_ext(CPUX86State *env, struct x86_decode_op *decode, int size)
222
{
223
+ target_ulong val;
224
if (decode->type == X86_VAR_REG) {
225
return read_val_from_reg(decode->regptr, size);
226
} else {
214
- return read_val_from_mem(env, decode->addr, size);
227
+ if (read_val_from_mem(env, decode->addr, size, &val)) {
228
+ error_report("target/i386/emulate: read_val_ext: reading from unmapped address.");
229
+ }
230
+ return val;
231
}
232
}
233
@@ -465,15 +481,17 @@ static inline int get_ZF(CPUX86State *env) {
481
return env->cc_dst ? 0 : CC_Z;
482
}
483
468
-static inline void string_rep(CPUX86State *env, struct x86_decode *decode,
469
- void (*func)(CPUX86State *env,
484
+static inline bool string_rep(CPUX86State *env, struct x86_decode *decode,
485
+ bool (*func)(CPUX86State *env,
486
struct x86_decode *ins), int rep)
487
{
488
target_ulong rcx = read_reg(env, R_ECX, decode->addressing_size);
489
490
while (rcx != 0) {
491
bool is_cmps_or_scas = decode->cmd == X86_DECODE_CMD_CMPS || decode->cmd == X86_DECODE_CMD_SCAS;
476
- func(env, decode);
492
+ if (func(env, decode)) {
493
+ return 1;
494
+ }
495
rcx--;
496
write_reg(env, R_ECX, rcx, decode->addressing_size);
497
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,
501
break;
502
}
503
}
504
+ return 0;
505
}
506
488
-static void exec_ins_single(CPUX86State *env, struct x86_decode *decode)
507
+static bool exec_ins_single(CPUX86State *env, struct x86_decode *decode)
508
{
509
+ MMUTranslateResult res;
510
+
511
target_ulong addr = linear_addr_size(env_cpu(env), RDI(env),
512
decode->addressing_size, R_ES);
513
514
emul_ops->handle_io(env_cpu(env), DX(env), env->emu_mmio_buf, 0,
515
decode->operand_size, 1);
495
- x86_write_mem(env_cpu(env), env->emu_mmio_buf, addr,
516
+ res = x86_write_mem(env_cpu(env), env->emu_mmio_buf, addr,
517
decode->operand_size);
518
+ if (res) {
519
+ return 1;
520
+ }
521
522
string_increment_reg(env, R_EDI, decode);
523
+ return 0;
524
}
525
526
static void exec_ins(CPUX86State *env, struct x86_decode *decode)
527
{
528
+ bool res;
529
if (decode->rep) {
504
- string_rep(env, decode, exec_ins_single, 0);
530
+ res = string_rep(env, decode, exec_ins_single, 0);
531
} else {
506
- exec_ins_single(env, decode);
532
+ res = exec_ins_single(env, decode);
533
}
534
535
+ if (res) {
536
+ return;
537
+ }
538
env->eip += decode->len;
539
}
540
512
-static void exec_outs_single(CPUX86State *env, struct x86_decode *decode)
541
+static bool exec_outs_single(CPUX86State *env, struct x86_decode *decode)
542
{
543
target_ulong addr = decode_linear_addr(env, decode, RSI(env), R_DS);
544
@@ -519,48 +548,64 @@ static void exec_outs_single(CPUX86State *env, struct x86_decode *decode)
548
decode->operand_size, 1);
549
550
string_increment_reg(env, R_ESI, decode);
551
+ return 0;
552
}
553
554
static void exec_outs(CPUX86State *env, struct x86_decode *decode)
555
{
556
+ bool res;
557
if (decode->rep) {
527
- string_rep(env, decode, exec_outs_single, 0);
558
+ res = string_rep(env, decode, exec_outs_single, 0);
559
} else {
529
- exec_outs_single(env, decode);
560
+ res = exec_outs_single(env, decode);
561
}
562
563
+ if (res) {
564
+ return;
565
+ }
566
env->eip += decode->len;
567
}
568
535
-static void exec_movs_single(CPUX86State *env, struct x86_decode *decode)
569
+static bool exec_movs_single(CPUX86State *env, struct x86_decode *decode)
570
{
571
target_ulong src_addr;
572
target_ulong dst_addr;
573
target_ulong val;
574
+ MMUTranslateResult res;
575
576
src_addr = decode_linear_addr(env, decode, RSI(env), R_DS);
577
dst_addr = linear_addr_size(env_cpu(env), RDI(env),
578
decode->addressing_size, R_ES);
579
545
- val = read_val_from_mem(env, src_addr, decode->operand_size);
546
- x86_write_mem(env_cpu(env), &val, dst_addr, decode->operand_size);
580
+ if (read_val_from_mem(env, src_addr, decode->operand_size, &val)) {
581
+ return 1;
582
+ }
583
+ res = x86_write_mem(env_cpu(env), &val, dst_addr, decode->operand_size);
584
+ if (res) {
585
+ return 1;
586
+ }
587
588
string_increment_reg(env, R_ESI, decode);
589
string_increment_reg(env, R_EDI, decode);
590
+ return 0;
591
}
592
593
static void exec_movs(CPUX86State *env, struct x86_decode *decode)
594
{
595
+ bool res;
596
if (decode->rep) {
555
- string_rep(env, decode, exec_movs_single, 0);
597
+ res = string_rep(env, decode, exec_movs_single, 0);
598
} else {
557
- exec_movs_single(env, decode);
599
+ res = exec_movs_single(env, decode);
600
}
601
602
+ if (res) {
603
+ return;
604
+ }
605
env->eip += decode->len;
606
}
607
563
-static void exec_cmps_single(CPUX86State *env, struct x86_decode *decode)
608
+static bool exec_cmps_single(CPUX86State *env, struct x86_decode *decode)
609
{
610
target_ulong src_addr;
611
target_ulong dst_addr;
@@ -570,14 +615,19 @@ static void exec_cmps_single(CPUX86State *env, struct x86_decode *decode)
615
decode->addressing_size, R_ES);
616
617
decode->op[0].type = X86_VAR_IMMEDIATE;
573
- decode->op[0].val = read_val_from_mem(env, src_addr, decode->operand_size);
618
+ if (read_val_from_mem(env, src_addr, decode->operand_size, &decode->op[0].val)) {
619
+ return 1;
620
+ }
621
decode->op[1].type = X86_VAR_IMMEDIATE;
575
- decode->op[1].val = read_val_from_mem(env, dst_addr, decode->operand_size);
622
+ if (read_val_from_mem(env, dst_addr, decode->operand_size, &decode->op[1].val)) {
623
+ return 1;
624
+ }
625
626
EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false);
627
628
string_increment_reg(env, R_ESI, decode);
629
string_increment_reg(env, R_EDI, decode);
630
+ return 0;
631
}
632
633
static void exec_cmps(CPUX86State *env, struct x86_decode *decode)
@@ -591,17 +641,22 @@ static void exec_cmps(CPUX86State *env, struct x86_decode *decode)
641
}
642
643
594
-static void exec_stos_single(CPUX86State *env, struct x86_decode *decode)
644
+static bool exec_stos_single(CPUX86State *env, struct x86_decode *decode)
645
{
646
target_ulong addr;
647
target_ulong val;
648
+ MMUTranslateResult res;
649
650
addr = linear_addr_size(env_cpu(env), RDI(env),
651
decode->addressing_size, R_ES);
652
val = read_reg(env, R_EAX, decode->operand_size);
602
- x86_write_mem(env_cpu(env), &val, addr, decode->operand_size);
653
+ res = x86_write_mem(env_cpu(env), &val, addr, decode->operand_size);
654
+ if (res) {
655
+ return 1;
656
+ }
657
658
string_increment_reg(env, R_EDI, decode);
659
+ return 0;
660
}
661
662
@@ -616,7 +671,7 @@ static void exec_stos(CPUX86State *env, struct x86_decode *decode)
671
env->eip += decode->len;
672
}
673
619
-static void exec_scas_single(CPUX86State *env, struct x86_decode *decode)
674
+static bool exec_scas_single(CPUX86State *env, struct x86_decode *decode)
675
{
676
target_ulong addr;
677
@@ -627,6 +682,7 @@ static void exec_scas_single(CPUX86State *env, struct x86_decode *decode)
682
683
EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false);
684
string_increment_reg(env, R_EDI, decode);
685
+ return 0;
686
}
687
688
static void exec_scas(CPUX86State *env, struct x86_decode *decode)
@@ -642,7 +698,7 @@ static void exec_scas(CPUX86State *env, struct x86_decode *decode)
698
env->eip += decode->len;
699
}
700
645
-static void exec_lods_single(CPUX86State *env, struct x86_decode *decode)
701
+static bool exec_lods_single(CPUX86State *env, struct x86_decode *decode)
702
{
703
target_ulong addr;
704
target_ulong val = 0;
@@ -652,6 +708,7 @@ static void exec_lods_single(CPUX86State *env, struct x86_decode *decode)
708
write_reg(env, R_EAX, val, decode->operand_size);
709
710
string_increment_reg(env, R_ESI, decode);
711
+ return 0;
712
}
713
714
static void exec_lods(CPUX86State *env, struct x86_decode *decode)