qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 2/3] target-arm: Code changes to implement overw


From: Peter Maydell
Subject: Re: [Qemu-devel] [PATCH 2/3] target-arm: Code changes to implement overwrite of tag field on PC load
Date: Thu, 29 Sep 2016 18:24:23 -0700

On 16 September 2016 at 10:34, Thomas Hanson <address@hidden> wrote:
> 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.)

I've cc'd RTH in case he wants to comment on the TCG op sequences
we're generating here.

Same commit message style remarks as patch 1.

> Signed-off-by: Thomas Hanson <address@hidden>
> ---
>  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)

I think it would be better to take a TCGv_i64 here rather than
unsigned int rn (ie have the caller do the cpu_reg(s, rn)).
(You probably don't need that prototype of cpu_reg() above if
you do this, though that's not why it's better.)

> +{

This could use a brief comment explaining the semantics we are
implementing here, something like:

    /* Load the PC from a register.
     *
     * If address tagging is enabled via the TCR TBI bits, then loading
     * an address into the PC will clear out any tag in the it:
     *  + for EL2 and EL3 there is only one TBI bit, and if it is set
     *    then the address is zero-extended, clearing bits [63:56]
     *  + for EL0 and EL1, TBI0 controls addresses with bit 55 == 0
     *    and TBI1 controls addressses with bit 55 == 1.
     *    If the appropriate TBI bit is set for the address then
     *    the address is sign-extended from bit 55 into bits [63:56]
     *
     * We can avoid doing this for relative-branches, because the
     * PC + offset can never overflow into the tag bits (assuming
     * that virtual addresses are less than 56 bits wide, as they
     * are currently), but we must handle it for branch-to-register.
     */

> +    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 */

Rather than "just fix it", we should say "always sign extend from
bit 55 into [63:56]".

> +            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));
> +        }
> +     }
> +

Stray blank line.

> +}
> +
>  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 */

This comment isn't really necessary I think.

> +        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);

I think these two lines would be better in the previous commit.

>      dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
>  #if !defined(CONFIG_USER_ONLY)
>      dc->user = (dc->current_el == 0);
> --
> 1.9.1
>

thanks
-- PMM



reply via email to

[Prev in Thread] Current Thread [Next in Thread]