@samitouri / QOSamiQemu / commits / 192d377c98

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)