From patchwork Thu May 21 21:32:51 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aurelien Jarno X-Patchwork-Id: 475231 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 558CC140D60 for ; Fri, 22 May 2015 07:33:26 +1000 (AEST) Received: from localhost ([::1]:59557 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YvY5k-0002cJ-8M for incoming@patchwork.ozlabs.org; Thu, 21 May 2015 17:33:24 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:56612) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YvY5K-000209-7n for qemu-devel@nongnu.org; Thu, 21 May 2015 17:32:59 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YvY5J-0006Hb-3L for qemu-devel@nongnu.org; Thu, 21 May 2015 17:32:58 -0400 Received: from hall.aurel32.net ([2001:bc8:30d7:101::1]:51929) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YvY5I-0006HV-Tg for qemu-devel@nongnu.org; Thu, 21 May 2015 17:32:57 -0400 Received: from weber.rr44.fr ([2001:470:d4ed:0:7e05:7ff:fe0d:f152]) by hall.aurel32.net with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.84) (envelope-from ) id 1YvY5G-0002q5-Au; Thu, 21 May 2015 23:32:54 +0200 Received: from aurel32 by weber.rr44.fr with local (Exim 4.85) (envelope-from ) id 1YvY5F-0006sk-FX; Thu, 21 May 2015 23:32:53 +0200 From: Aurelien Jarno To: qemu-devel@nongnu.org Date: Thu, 21 May 2015 23:32:51 +0200 Message-Id: <1432243971-26417-1-git-send-email-aurelien@aurel32.net> X-Mailer: git-send-email 2.1.4 X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2001:bc8:30d7:101::1 Cc: Alexander Graf , Aurelien Jarno , Richard Henderson Subject: [Qemu-devel] [PATCH] target-s390x: fix LOAD MULTIPLE instruction on page boundary X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 all values from memory and then writing them back to the registers. This fixes random segmentation faults seen in the guest. Cc: Alexander Graf Cc: Richard Henderson Signed-off-by: Aurelien Jarno Reviewed-by: Richard Henderson --- target-s390x/translate.c | 56 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 52e106e..ddc78a9 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2436,10 +2436,13 @@ static ExitStatus op_lm32(DisasContext *s, DisasOps *o) int r3 = get_field(s->fields, r3); TCGv_i64 t = tcg_temp_new_i64(); TCGv_i64 t4 = tcg_const_i64(4); + TCGv_i64 tregs[16]; + /* First load all the values from memory. If a page fault occurs the + registers should not be changed. */ while (1) { - tcg_gen_qemu_ld32u(t, o->in2, get_mem_index(s)); - store_reg32_i64(r1, t); + tregs[r1] = tcg_temp_new_i64(); + tcg_gen_qemu_ld32u(tregs[r1], o->in2, get_mem_index(s)); if (r1 == r3) { break; } @@ -2447,6 +2450,18 @@ static ExitStatus op_lm32(DisasContext *s, DisasOps *o) r1 = (r1 + 1) & 15; } + /* When all the values have been loaded, write them back to the + registers. */ + r1 = get_field(s->fields, r1); + while (1) { + store_reg32_i64(r1, tregs[r1]); + tcg_temp_free_i64(tregs[r1]); + if (r1 == r3) { + break; + } + r1 = (r1 + 1) & 15; + } + tcg_temp_free_i64(t); tcg_temp_free_i64(t4); return NO_EXIT; @@ -2458,10 +2473,13 @@ static ExitStatus op_lmh(DisasContext *s, DisasOps *o) int r3 = get_field(s->fields, r3); TCGv_i64 t = tcg_temp_new_i64(); TCGv_i64 t4 = tcg_const_i64(4); + TCGv_i64 tregs[16]; + /* First load all the values from memory. If a page fault occurs the + registers should not be changed. */ while (1) { - tcg_gen_qemu_ld32u(t, o->in2, get_mem_index(s)); - store_reg32h_i64(r1, t); + tregs[r1] = tcg_temp_new_i64(); + tcg_gen_qemu_ld32u(tregs[r1], o->in2, get_mem_index(s)); if (r1 == r3) { break; } @@ -2469,6 +2487,18 @@ static ExitStatus op_lmh(DisasContext *s, DisasOps *o) r1 = (r1 + 1) & 15; } + /* When all the values have been loaded, write them back to the + registers. */ + r1 = get_field(s->fields, r1); + while (1) { + store_reg32h_i64(r1, tregs[r1]); + tcg_temp_free_i64(tregs[r1]); + if (r1 == r3) { + break; + } + r1 = (r1 + 1) & 15; + } + tcg_temp_free_i64(t); tcg_temp_free_i64(t4); return NO_EXIT; @@ -2479,9 +2509,13 @@ 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 tregs[16]; + /* First load all the values from memory. If a page fault occurs the + registers should not be changed. */ while (1) { - tcg_gen_qemu_ld64(regs[r1], o->in2, get_mem_index(s)); + tregs[r1] = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(tregs[r1], o->in2, get_mem_index(s)); if (r1 == r3) { break; } @@ -2489,6 +2523,18 @@ static ExitStatus op_lm64(DisasContext *s, DisasOps *o) r1 = (r1 + 1) & 15; } + /* When all the values have been loaded, write them back to the + registers. */ + r1 = get_field(s->fields, r1); + while (1) { + tcg_gen_mov_i64(regs[r1], tregs[r1]); + tcg_temp_free_i64(tregs[r1]); + if (r1 == r3) { + break; + } + r1 = (r1 + 1) & 15; + } + tcg_temp_free_i64(t8); return NO_EXIT; }