[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 10/34] target-s390x: fix LOAD MULTIPLE instruction on
From: |
Alexander Graf |
Subject: |
[Qemu-devel] [PULL 10/34] target-s390x: fix LOAD MULTIPLE instruction on page boundary |
Date: |
Fri, 5 Jun 2015 01:41:40 +0200 |
From: Aurelien Jarno <address@hidden>
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.
Signed-off-by: Aurelien Jarno <address@hidden>
Reviewed-by: Richard Henderson <address@hidden>
Signed-off-by: Alexander Graf <address@hidden>
---
target-s390x/translate.c | 128 ++++++++++++++++++++++++++++++++++++-----------
1 file changed, 99 insertions(+), 29 deletions(-)
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index 0c6d1f6..63885f8 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -2440,21 +2440,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;
}
@@ -2462,21 +2486,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;
}
@@ -2484,18 +2532,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;
}
--
1.7.12.4
- [Qemu-devel] [PULL 30/34] target-s390x: add a cpu_mmu_idx_to_asc function, (continued)
- [Qemu-devel] [PULL 30/34] target-s390x: add a cpu_mmu_idx_to_asc function, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 12/34] target-s390x: fix MMU index computation, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 11/34] target-s390x: fix PSW value on dynamical exception from helpers, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 15/34] target-s390x: detect tininess before rounding for FP operations, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 03/34] target-s390x: optimize (negative-) abs computation, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 01/34] target-s390x: fix CC computation for EX instruction, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 24/34] target-s390x: implement TRANSLATE AND TEST instruction, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 13/34] target-s390x: define default NaN values, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 33/34] target-s390x: fix MVC instruction when areas overlap, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 22/34] target-s390x: move SET DFP ROUNDING MODE to the correct facility, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 10/34] target-s390x: fix LOAD MULTIPLE instruction on page boundary,
Alexander Graf <=
- [Qemu-devel] [PULL 18/34] target-s390x: fix exception for invalid operation code, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 27/34] target-s390x: implement miscellaneous-instruction-extensions facility, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 23/34] target-s390x: implement LOAD FP INTEGER instructions, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 21/34] target-s390x: move STORE CLOCK FAST to the correct facility, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 32/34] target-s390x: use softmmu functions for mvcp/mvcs, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 19/34] target-s390x: fix CLGIT instruction, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 34/34] target-s390x: Only access allocated storage keys, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 17/34] target-s390x: implement LAY and LAEY instructions, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 29/34] target-s390x: implement high-word facility, Alexander Graf, 2015/06/04
- [Qemu-devel] [PULL 26/34] target-s390x: implement LPDFR and LNDFR instructions, Alexander Graf, 2015/06/04