From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Cc: richard.henderson@linaro.org
Subject: [PATCH 01/11] target/i386: fix pushed value of EFLAGS.RF
Date: Tue, 4 Jun 2024 09:18:23 +0200 [thread overview]
Message-ID: <20240604071833.962574-2-pbonzini@redhat.com> (raw)
In-Reply-To: <20240604071833.962574-1-pbonzini@redhat.com>
When preparing an exception stack frame for a fault exception, the value
pushed for RF is 1. Take that into account. The same should be true
of interrupts for repeated string instructions, but the situation there
is complicated.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
target/i386/tcg/seg_helper.c | 49 ++++++++++++++++++++++++++++++++----
target/i386/tcg/translate.c | 8 ++++++
2 files changed, 52 insertions(+), 5 deletions(-)
diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c
index 0301459004e..715db1f2326 100644
--- a/target/i386/tcg/seg_helper.c
+++ b/target/i386/tcg/seg_helper.c
@@ -526,6 +526,24 @@ static inline unsigned int get_sp_mask(unsigned int e2)
}
}
+static int exception_is_fault(int intno)
+{
+ switch (intno) {
+ /*
+ * #DB can be both fault- and trap-like, but it never sets RF=1
+ * in the RFLAGS value pushed on the stack.
+ */
+ case EXCP01_DB:
+ case EXCP03_INT3:
+ case EXCP04_INTO:
+ case EXCP08_DBLE:
+ case EXCP12_MCHK:
+ return 0;
+ }
+ /* Everything else including reserved exception is a fault. */
+ return 1;
+}
+
int exception_has_error_code(int intno)
{
switch (intno) {
@@ -605,8 +623,9 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int,
int type, dpl, selector, ss_dpl, cpl;
int has_error_code, new_stack, shift;
uint32_t e1, e2, offset, ss = 0, esp, ss_e1 = 0, ss_e2 = 0;
- uint32_t old_eip, sp_mask;
+ uint32_t old_eip, sp_mask, eflags;
int vm86 = env->eflags & VM_MASK;
+ bool set_rf;
has_error_code = 0;
if (!is_int && !is_hw) {
@@ -614,8 +633,10 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int,
}
if (is_int) {
old_eip = next_eip;
+ set_rf = false;
} else {
old_eip = env->eip;
+ set_rf = exception_is_fault(intno);
}
dt = &env->idt;
@@ -748,6 +769,15 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int,
}
push_size <<= shift;
#endif
+ eflags = cpu_compute_eflags(env);
+ /*
+ * AMD states that code breakpoint #DBs clear RF=0, Intel leaves it
+ * as is. AMD behavior could be implemented in check_hw_breakpoints().
+ */
+ if (set_rf) {
+ eflags |= RF_MASK;
+ }
+
if (shift == 1) {
if (new_stack) {
if (vm86) {
@@ -759,7 +789,7 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int,
PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
PUSHL(ssp, esp, sp_mask, env->regs[R_ESP]);
}
- PUSHL(ssp, esp, sp_mask, cpu_compute_eflags(env));
+ PUSHL(ssp, esp, sp_mask, eflags);
PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
PUSHL(ssp, esp, sp_mask, old_eip);
if (has_error_code) {
@@ -776,7 +806,7 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int,
PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
PUSHW(ssp, esp, sp_mask, env->regs[R_ESP]);
}
- PUSHW(ssp, esp, sp_mask, cpu_compute_eflags(env));
+ PUSHW(ssp, esp, sp_mask, eflags);
PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
PUSHW(ssp, esp, sp_mask, old_eip);
if (has_error_code) {
@@ -868,8 +898,9 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int,
target_ulong ptr;
int type, dpl, selector, cpl, ist;
int has_error_code, new_stack;
- uint32_t e1, e2, e3, ss;
+ uint32_t e1, e2, e3, ss, eflags;
target_ulong old_eip, esp, offset;
+ bool set_rf;
has_error_code = 0;
if (!is_int && !is_hw) {
@@ -877,8 +908,10 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int,
}
if (is_int) {
old_eip = next_eip;
+ set_rf = false;
} else {
old_eip = env->eip;
+ set_rf = exception_is_fault(intno);
}
dt = &env->idt;
@@ -950,9 +983,15 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int,
}
esp &= ~0xfLL; /* align stack */
+ /* See do_interrupt_protected. */
+ eflags = cpu_compute_eflags(env);
+ if (set_rf) {
+ eflags |= RF_MASK;
+ }
+
PUSHQ(esp, env->segs[R_SS].selector);
PUSHQ(esp, env->regs[R_ESP]);
- PUSHQ(esp, cpu_compute_eflags(env));
+ PUSHQ(esp, eflags);
PUSHQ(esp, env->segs[R_CS].selector);
PUSHQ(esp, old_eip);
if (has_error_code) {
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 0486ab69112..d438f8f76f7 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -4630,6 +4630,14 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
* If jmp_opt, we want to handle each string instruction individually.
* For icount also disable repz optimization so that each iteration
* is accounted separately.
+ *
+ * FIXME: this is messy; it makes REP string instructions a lot less
+ * efficient than they should be and it gets in the way of correct
+ * handling of RF (interrupts or traps arriving after any iteration
+ * of a repeated string instruction but the last should set RF to 1).
+ * Perhaps it would be more efficient if REP string instructions were
+ * always at the beginning of the TB, or even their own TB? That
+ * would even allow accounting up to 64k iterations at once for icount.
*/
dc->repz_opt = !dc->jmp_opt && !(cflags & CF_USE_ICOUNT);
--
2.45.1
next prev parent reply other threads:[~2024-06-04 7:19 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-06-04 7:18 [PATCH 00/11] target/i386: fixes for INHIBIT_IRQ, TF and RF Paolo Bonzini
2024-06-04 7:18 ` Paolo Bonzini [this message]
2024-06-04 10:51 ` [PATCH 01/11] target/i386: fix pushed value of EFLAGS.RF Richard Henderson
2024-06-04 7:18 ` [PATCH 02/11] target/i386: fix implementation of ICEBP Paolo Bonzini
2024-06-04 13:50 ` Richard Henderson
2024-06-04 7:18 ` [PATCH 03/11] target/i386: cleanup HLT helpers Paolo Bonzini
2024-06-04 10:54 ` Richard Henderson
2024-06-04 7:18 ` [PATCH 04/11] target/i386: cleanup PAUSE helpers Paolo Bonzini
2024-06-04 10:59 ` Richard Henderson
2024-06-04 14:08 ` Paolo Bonzini
2024-06-04 7:18 ` [PATCH 05/11] target/i386: implement DR7.GD Paolo Bonzini
2024-06-04 13:22 ` Richard Henderson
2024-06-04 7:18 ` [PATCH 06/11] target/i386: disable/enable breakpoints on vmentry/vmexit Paolo Bonzini
2024-06-04 13:24 ` Richard Henderson
2024-06-04 7:18 ` [PATCH 07/11] target/i386: fix INHIBIT_IRQ/TF/RF handling for VMRUN Paolo Bonzini
2024-06-04 13:28 ` Richard Henderson
2024-06-04 7:18 ` [PATCH 08/11] target/i386: fix INHIBIT_IRQ/TF/RF handling for PAUSE Paolo Bonzini
2024-06-04 13:44 ` Richard Henderson
2024-06-04 13:49 ` Richard Henderson
2024-06-04 14:10 ` Paolo Bonzini
2024-06-04 14:14 ` Richard Henderson
2024-06-04 7:18 ` [PATCH 09/11] target/i386: fix TF/RF handling for HLT Paolo Bonzini
2024-06-04 13:46 ` Richard Henderson
2024-06-04 7:18 ` [PATCH 10/11] target/i386: document incorrect semantics of watchpoint following MOV/POP SS Paolo Bonzini
2024-06-04 13:57 ` Richard Henderson
2024-06-04 7:18 ` [PATCH 11/11] target/i386: document use of DISAS_NORETURN Paolo Bonzini
2024-06-04 13:58 ` Richard Henderson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240604071833.962574-2-pbonzini@redhat.com \
--to=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=richard.henderson@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).