From patchwork Fri Sep 16 17:34:46 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Hanson X-Patchwork-Id: 670985 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3sbMsK2Fsdz9s2G for ; Sat, 17 Sep 2016 03:36:37 +1000 (AEST) Received: from localhost ([::1]:42861 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bkx3y-0005Nk-Tz for incoming@patchwork.ozlabs.org; Fri, 16 Sep 2016 13:36:34 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37823) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bkx2v-0004e6-50 for qemu-devel@nongnu.org; Fri, 16 Sep 2016 13:35:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bkx2s-0008ET-Hx for qemu-devel@nongnu.org; Fri, 16 Sep 2016 13:35:29 -0400 Received: from g2t2355.austin.hpe.com ([15.233.44.28]:57925) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bkx2s-0008C1-98 for qemu-devel@nongnu.org; Fri, 16 Sep 2016 13:35:26 -0400 Received: from TomH-Z-Workstation.americas.hpqcorp.net (tomh-z-workstation.americas.hpqcorp.net [16.78.178.129]) by g2t2355.austin.hpe.com (Postfix) with ESMTP id E24E071; Fri, 16 Sep 2016 17:35:21 +0000 (UTC) From: Thomas Hanson To: qemu-devel@nongnu.org Date: Fri, 16 Sep 2016 11:34:46 -0600 Message-Id: <1474047287-145701-3-git-send-email-thomas.hanson@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1474047287-145701-1-git-send-email-thomas.hanson@linaro.org> References: <1474047287-145701-1-git-send-email-thomas.hanson@linaro.org> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 15.233.44.28 Subject: [Qemu-devel] [PATCH 2/3] target-arm: Code changes to implement overwrite of tag field on PC load X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: grant.likely@hpe.com, peter.maydell@linaro.org, thomas.hanson@linaro.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" gen_intermediate_code_a64() transfers TBI values from TB->flags to DisasContext structure. disas_uncond_b_reg() calls new function gen_a64_set_pc_reg() to handle BR, BLR and RET instructions. gen_a64_set_pc_reg() implements all of the required checks and overwiting logic to clean up the tag field of an address before loading the PC. Currently only called in one place, but will be used in the future to handle arithmetic overflow cases with 56-bit addresses. (See following patch.) Signed-off-by: Thomas Hanson --- target-arm/translate-a64.c | 67 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index f5e29d2..4d6f951 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -41,6 +41,7 @@ static TCGv_i64 cpu_pc; /* Load/store exclusive handling */ static TCGv_i64 cpu_exclusive_high; +static TCGv_i64 cpu_reg(DisasContext *s, int reg); static const char *regnames[] = { "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", @@ -176,6 +177,58 @@ void gen_a64_set_pc_im(uint64_t val) tcg_gen_movi_i64(cpu_pc, val); } +void gen_a64_set_pc_reg(DisasContext *s, unsigned int rn) +{ + if (s->current_el <= 1) { + /* Test if NEITHER or BOTH TBI values are set. If so, no need to + * examine bit 55 of address, can just generate code. + * If mixed, then test via generated code + */ + if (s->tbi0 && s->tbi1) { + TCGv_i64 tmp_reg = tcg_temp_new_i64(); + /* Both bits set, just fix it */ + tcg_gen_shli_i64(tmp_reg, cpu_reg(s, rn), 8); + tcg_gen_sari_i64(cpu_pc, tmp_reg, 8); + tcg_temp_free_i64(tmp_reg); + } else if (!s->tbi0 && !s->tbi1) { + /* Neither bit set, just load it as-is */ + tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn)); + } else { + TCGv_i64 tcg_tmpval = tcg_temp_new_i64(); + TCGv_i64 tcg_bit55 = tcg_temp_new_i64(); + TCGv_i64 tcg_zero = tcg_const_i64(0); + + tcg_gen_andi_i64(tcg_bit55, cpu_reg(s, rn), (1ull << 55)); + + if (s->tbi0) { + /* tbi0==1, tbi1==0, so 0-fill upper byte if bit 55 = 0 */ + tcg_gen_andi_i64(tcg_tmpval, cpu_reg(s, rn), + 0x00FFFFFFFFFFFFFFull); + tcg_gen_movcond_i64(TCG_COND_EQ, cpu_pc, tcg_bit55, tcg_zero, + tcg_tmpval, cpu_reg(s, rn)); + } else { + /* tbi0==0, tbi1==1, so 1-fill upper byte if bit 55 = 1 */ + tcg_gen_ori_i64(tcg_tmpval, cpu_reg(s, rn), + 0xFF00000000000000ull); + tcg_gen_movcond_i64(TCG_COND_NE, cpu_pc, tcg_bit55, tcg_zero, + tcg_tmpval, cpu_reg(s, rn)); + } + tcg_temp_free_i64(tcg_zero); + tcg_temp_free_i64(tcg_bit55); + tcg_temp_free_i64(tcg_tmpval); + } + } else { /* EL > 1 */ + if (s->tbi0) { + /* Force tag byte to all zero */ + tcg_gen_andi_i64(cpu_pc, cpu_reg(s, rn), 0x00FFFFFFFFFFFFFFull); + } else { + /* Load unmodified address */ + tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn)); + } + } + +} + typedef struct DisasCompare64 { TCGCond cond; TCGv_i64 value; @@ -1691,12 +1744,14 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn) switch (opc) { case 0: /* BR */ - case 2: /* RET */ - tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn)); - break; case 1: /* BLR */ - tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn)); - tcg_gen_movi_i64(cpu_reg(s, 30), s->pc); + case 2: /* RET */ + /* Check for tagged addresses and generate appropriate code */ + gen_a64_set_pc_reg(s, rn); + /* BLR also needs to load return address */ + if (opc == 1) { + tcg_gen_movi_i64(cpu_reg(s, 30), s->pc); + } break; case 4: /* ERET */ if (s->current_el == 0) { @@ -11150,6 +11205,8 @@ void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb) dc->condexec_mask = 0; dc->condexec_cond = 0; dc->mmu_idx = ARM_TBFLAG_MMUIDX(tb->flags); + dc->tbi0 = ARM_TBFLAG_TBI0(tb->flags); + dc->tbi1 = ARM_TBFLAG_TBI1(tb->flags); dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx); #if !defined(CONFIG_USER_ONLY) dc->user = (dc->current_el == 0);