All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2] target-s390x: fix LOAD MULTIPLE instruction on page boundary
@ 2015-05-26  9:09 Aurelien Jarno
  2015-05-26 16:15 ` Richard Henderson
  0 siblings, 1 reply; 4+ messages in thread
From: Aurelien Jarno @ 2015-05-26  9:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

When consecutive memory locations are on page boundary a page fault
might occur when using the LOAD MULTIPLE instruction. In that case real
hardware doesn't load any register.

This is an important detail in case the base register is in the list
of registers to be loaded. If a page fault occurs this register might be
overwritten and when the instruction is later restarted the wrong
base register value is useD.

Fix this by first loading the first and last value from memory, hence
triggering all possible page faults, and then the remaining registers.

This fixes random segmentation faults seen in the guest.

Cc: Alexander Graf <agraf@suse.de>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-s390x/translate.c | 128 ++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 99 insertions(+), 29 deletions(-)

Changes v1->v2:
- Do the load in two steps: first and last registers, and then the remaining ones

diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index 1819217..23c78e7 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -2434,21 +2434,45 @@ static ExitStatus op_lm32(DisasContext *s, DisasOps *o)
 {
     int r1 = get_field(s->fields, r1);
     int r3 = get_field(s->fields, r3);
-    TCGv_i64 t = tcg_temp_new_i64();
-    TCGv_i64 t4 = tcg_const_i64(4);
+    TCGv_i64 t1, t2;
 
-    while (1) {
-        tcg_gen_qemu_ld32u(t, o->in2, get_mem_index(s));
-        store_reg32_i64(r1, t);
-        if (r1 == r3) {
-            break;
-        }
-        tcg_gen_add_i64(o->in2, o->in2, t4);
+    /* Only one register to read. */
+    t1 = tcg_temp_new_i64();
+    if (unlikely(r1 == r3)) {
+        tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+        store_reg32_i64(r1, t1);
+        tcg_temp_free(t1);
+        return NO_EXIT;
+    }
+
+    /* First load the values of the first and last registers to trigger
+       possible page faults. */
+    t2 = tcg_temp_new_i64();
+    tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+    tcg_gen_addi_i64(t2, o->in2, 4 * ((r3 - r1) & 15));
+    tcg_gen_qemu_ld32u(t2, t2, get_mem_index(s));
+    store_reg32_i64(r1, t1);
+    store_reg32_i64(r3, t2);
+
+    /* Only two registers to read. */
+    if (((r1 + 1) & 15) == r3) {
+        tcg_temp_free(t2);
+        tcg_temp_free(t1);
+        return NO_EXIT;
+    }
+
+    /* Then load the remaining registers. Page fault can't occur. */
+    r3 = (r3 - 1) & 15;
+    tcg_gen_movi_i64(t2, 4);
+    while (r1 != r3) {
         r1 = (r1 + 1) & 15;
+        tcg_gen_add_i64(o->in2, o->in2, t2);
+        tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+        store_reg32_i64(r1, t1);
     }
+    tcg_temp_free(t2);
+    tcg_temp_free(t1);
 
-    tcg_temp_free_i64(t);
-    tcg_temp_free_i64(t4);
     return NO_EXIT;
 }
 
@@ -2456,21 +2480,45 @@ static ExitStatus op_lmh(DisasContext *s, DisasOps *o)
 {
     int r1 = get_field(s->fields, r1);
     int r3 = get_field(s->fields, r3);
-    TCGv_i64 t = tcg_temp_new_i64();
-    TCGv_i64 t4 = tcg_const_i64(4);
+    TCGv_i64 t1, t2;
 
-    while (1) {
-        tcg_gen_qemu_ld32u(t, o->in2, get_mem_index(s));
-        store_reg32h_i64(r1, t);
-        if (r1 == r3) {
-            break;
-        }
-        tcg_gen_add_i64(o->in2, o->in2, t4);
+    /* Only one register to read. */
+    t1 = tcg_temp_new_i64();
+    if (unlikely(r1 == r3)) {
+        tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+        store_reg32h_i64(r1, t1);
+        tcg_temp_free(t1);
+        return NO_EXIT;
+    }
+
+    /* First load the values of the first and last registers to trigger
+       possible page faults. */
+    t2 = tcg_temp_new_i64();
+    tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+    tcg_gen_addi_i64(t2, o->in2, 4 * ((r3 - r1) & 15));
+    tcg_gen_qemu_ld32u(t2, t2, get_mem_index(s));
+    store_reg32h_i64(r1, t1);
+    store_reg32h_i64(r3, t2);
+
+    /* Only two registers to read. */
+    if (((r1 + 1) & 15) == r3) {
+        tcg_temp_free(t2);
+        tcg_temp_free(t1);
+        return NO_EXIT;
+    }
+
+    /* Then load the remaining registers. Page fault can't occur. */
+    r3 = (r3 - 1) & 15;
+    tcg_gen_movi_i64(t2, 4);
+    while (r1 != r3) {
         r1 = (r1 + 1) & 15;
+        tcg_gen_add_i64(o->in2, o->in2, t2);
+        tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+        store_reg32h_i64(r1, t1);
     }
+    tcg_temp_free(t2);
+    tcg_temp_free(t1);
 
-    tcg_temp_free_i64(t);
-    tcg_temp_free_i64(t4);
     return NO_EXIT;
 }
 
@@ -2478,18 +2526,40 @@ static ExitStatus op_lm64(DisasContext *s, DisasOps *o)
 {
     int r1 = get_field(s->fields, r1);
     int r3 = get_field(s->fields, r3);
-    TCGv_i64 t8 = tcg_const_i64(8);
+    TCGv_i64 t1, t2;
 
-    while (1) {
+    /* Only one register to read. */
+    if (unlikely(r1 == r3)) {
         tcg_gen_qemu_ld64(regs[r1], o->in2, get_mem_index(s));
-        if (r1 == r3) {
-            break;
-        }
-        tcg_gen_add_i64(o->in2, o->in2, t8);
+        return NO_EXIT;
+    }
+
+    /* First load the values of the first and last registers to trigger
+       possible page faults. */
+    t1 = tcg_temp_new_i64();
+    t2 = tcg_temp_new_i64();
+    tcg_gen_qemu_ld64(t1, o->in2, get_mem_index(s));
+    tcg_gen_addi_i64(t2, o->in2, 8 * ((r3 - r1) & 15));
+    tcg_gen_qemu_ld64(regs[r3], t2, get_mem_index(s));
+    tcg_gen_mov_i64(regs[r1], t1);
+    tcg_temp_free(t2);
+
+    /* Only two registers to read. */
+    if (((r1 + 1) & 15) == r3) {
+        tcg_temp_free(t1);
+        return NO_EXIT;
+    }
+
+    /* Then load the remaining registers. Page fault can't occur. */
+    r3 = (r3 - 1) & 15;
+    tcg_gen_movi_i64(t1, 8);
+    while (r1 != r3) {
         r1 = (r1 + 1) & 15;
+        tcg_gen_add_i64(o->in2, o->in2, t1);
+        tcg_gen_qemu_ld64(regs[r1], o->in2, get_mem_index(s));
     }
+    tcg_temp_free(t1);
 
-    tcg_temp_free_i64(t8);
     return NO_EXIT;
 }
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [Qemu-devel] [PATCH v2] target-s390x: fix LOAD MULTIPLE instruction on page boundary
  2015-05-26  9:09 [Qemu-devel] [PATCH v2] target-s390x: fix LOAD MULTIPLE instruction on page boundary Aurelien Jarno
@ 2015-05-26 16:15 ` Richard Henderson
  2015-05-26 21:43   ` Alexander Graf
  0 siblings, 1 reply; 4+ messages in thread
From: Richard Henderson @ 2015-05-26 16:15 UTC (permalink / raw)
  To: Aurelien Jarno, qemu-devel; +Cc: Alexander Graf

On 05/26/2015 02:09 AM, Aurelien Jarno wrote:
> This is an important detail in case the base register is in the list
> of registers to be loaded. If a page fault occurs this register might be
> overwritten and when the instruction is later restarted the wrong
> base register value is useD.
> 
> Fix this by first loading the first and last value from memory, hence
> triggering all possible page faults, and then the remaining registers.
> 
> This fixes random segmentation faults seen in the guest.
> 
> Cc: Alexander Graf <agraf@suse.de>
> Cc: Richard Henderson <rth@twiddle.net>
> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
> ---
>  target-s390x/translate.c | 128 ++++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 99 insertions(+), 29 deletions(-)
> 
> Changes v1->v2:
> - Do the load in two steps: first and last registers, and then the remaining ones

Reviewed-by: Richard Henderson <rth@twiddle.net>


r~

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Qemu-devel] [PATCH v2] target-s390x: fix LOAD MULTIPLE instruction on page boundary
  2015-05-26 16:15 ` Richard Henderson
@ 2015-05-26 21:43   ` Alexander Graf
  2015-05-26 22:10     ` Aurelien Jarno
  0 siblings, 1 reply; 4+ messages in thread
From: Alexander Graf @ 2015-05-26 21:43 UTC (permalink / raw)
  To: Richard Henderson, Aurelien Jarno, qemu-devel



On 26.05.15 18:15, Richard Henderson wrote:
> On 05/26/2015 02:09 AM, Aurelien Jarno wrote:
>> This is an important detail in case the base register is in the list
>> of registers to be loaded. If a page fault occurs this register might be
>> overwritten and when the instruction is later restarted the wrong
>> base register value is useD.
>>
>> Fix this by first loading the first and last value from memory, hence
>> triggering all possible page faults, and then the remaining registers.
>>
>> This fixes random segmentation faults seen in the guest.
>>
>> Cc: Alexander Graf <agraf@suse.de>
>> Cc: Richard Henderson <rth@twiddle.net>
>> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
>> ---
>>  target-s390x/translate.c | 128 ++++++++++++++++++++++++++++++++++++-----------
>>  1 file changed, 99 insertions(+), 29 deletions(-)
>>
>> Changes v1->v2:
>> - Do the load in two steps: first and last registers, and then the remaining ones
> 
> Reviewed-by: Richard Henderson <rth@twiddle.net>

Thanks, applied to s390-next.

So what do we do about the other patch set?


Alex

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Qemu-devel] [PATCH v2] target-s390x: fix LOAD MULTIPLE instruction on page boundary
  2015-05-26 21:43   ` Alexander Graf
@ 2015-05-26 22:10     ` Aurelien Jarno
  0 siblings, 0 replies; 4+ messages in thread
From: Aurelien Jarno @ 2015-05-26 22:10 UTC (permalink / raw)
  To: Alexander Graf; +Cc: qemu-devel, Richard Henderson

On 2015-05-26 23:43, Alexander Graf wrote:
> 
> 
> On 26.05.15 18:15, Richard Henderson wrote:
> > On 05/26/2015 02:09 AM, Aurelien Jarno wrote:
> >> This is an important detail in case the base register is in the list
> >> of registers to be loaded. If a page fault occurs this register might be
> >> overwritten and when the instruction is later restarted the wrong
> >> base register value is useD.
> >>
> >> Fix this by first loading the first and last value from memory, hence
> >> triggering all possible page faults, and then the remaining registers.
> >>
> >> This fixes random segmentation faults seen in the guest.
> >>
> >> Cc: Alexander Graf <agraf@suse.de>
> >> Cc: Richard Henderson <rth@twiddle.net>
> >> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
> >> ---
> >>  target-s390x/translate.c | 128 ++++++++++++++++++++++++++++++++++++-----------
> >>  1 file changed, 99 insertions(+), 29 deletions(-)
> >>
> >> Changes v1->v2:
> >> - Do the load in two steps: first and last registers, and then the remaining ones
> > 
> > Reviewed-by: Richard Henderson <rth@twiddle.net>
> 
> Thanks, applied to s390-next.
> 
> So what do we do about the other patch set?

For the other patch set, it seems the best to ignore the STFL/STFLE
part. Patches 01 to 05 and 09 to 10 are still valid, they are just a
collection of bug fixes and improvement not specially linked together.


-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2015-05-26 22:10 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-26  9:09 [Qemu-devel] [PATCH v2] target-s390x: fix LOAD MULTIPLE instruction on page boundary Aurelien Jarno
2015-05-26 16:15 ` Richard Henderson
2015-05-26 21:43   ` Alexander Graf
2015-05-26 22:10     ` Aurelien Jarno

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.