qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCH] target-arm/translate.c: Handle non-executable p


From: Laurent Desnogues
Subject: Re: [Qemu-devel] [PATCH] target-arm/translate.c: Handle non-executable page-straddling Thumb insns
Date: Sat, 19 Sep 2015 15:41:39 +0200

Hello,

I have two minor comments.

On Sat, Sep 19, 2015 at 3:06 PM, Peter Maydell <address@hidden> wrote:
> When the memory we're trying to translate code from is not executable we have
> to turn this into a guest fault. In order to report the correct PC for this
> fault, and to make sure it is not reported until after any other possible
> faults for instructions earlier in execution, we must terminate TBs at
> the end of a page, in case the next instruction is in a non-executable page.
> This is simple for T16, A32 and A64 instructions, which are always aligned
> to their size. However T32 instructions may be 32-bits but only 16-aligned,
> so they can straddle a page boundary.
>
> Correct the condition that checks whether the next instruction will touch
> the following page, to ensure that if we're 2 bytes before the boundary
> and this insn is T32 then we end the TB.
>
> Reported-by: Pavel Dovgalyuk <address@hidden>
>
> Signed-off-by: Peter Maydell <address@hidden>
> ---
> The other way you could do this would be to check before each 'read halfword'
> in the decoder whether you were going to go off the end of the page, and if
> so roll back anything you'd already generated, but that sounds really painful.
> I'm glad I don't have to fix this bug for x86 :-)
>
>
>  target-arm/translate.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 47 insertions(+), 1 deletion(-)
>
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index 84a21ac..d5cfe84 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -11167,6 +11167,38 @@ undef:
>                         default_exception_el(s));
>  }
>
> +static bool insn_crosses_page(CPUARMState *env, DisasContext *s)
> +{
> +    /* Return true if the insn at dc->pc might cross a page boundary.
> +     * (False positives are OK, false negatives are not.)
> +     */
> +    uint16_t insn;
> +
> +    if ((s->pc & 3) == 0) {
> +        /* At a 4-aligned address we can't be crossing a page */
> +        return false;
> +    }
> +
> +    /* This must be a Thumb insn */
> +    insn = arm_lduw_code(env, s->pc, s->bswap_code);
> +
> +    switch (insn >> 11) {
> +    case 0x1d: /* 0b11101 */
> +    case 0x1e: /* 0b11110 */
> +    case 0x1f: /* 0b11111 */
> +        /* First half of a 32-bit Thumb insn. Thumb-1 cores might
> +         * end up actually treating this as two 16-bit insns (see the
> +         * code at the start of disas_thumb2_insn()) but we don't bother
> +         * to check for that as it is unlikely, and false positives here
> +         * are harmless.
> +         */
> +        return true;
> +    default:
> +        /* 16-bit Thumb insn */
> +        return false;
> +    }

I would have used return (insn >> 11) >= 0x1d instead of a switch.

> +}
> +
>  /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
>     basic block 'tb'. If search_pc is TRUE, also generate PC
>     information for each intermediate instruction. */
> @@ -11183,6 +11215,7 @@ static inline void 
> gen_intermediate_code_internal(ARMCPU *cpu,
>      target_ulong next_page_start;
>      int num_insns;
>      int max_insns;
> +    bool end_of_page;
>
>      /* generate intermediate code */
>
> @@ -11404,11 +11437,24 @@ static inline void 
> gen_intermediate_code_internal(ARMCPU *cpu,
>           * Also stop translation when a page boundary is reached.  This
>           * ensures prefetch aborts occur at the right place.  */
>          num_insns ++;

You could perhaps take the opportunity to remove that whitespace :-)

> +
> +        /* We want to stop the TB if the next insn starts in a new page,
> +         * or if it spans between this page and the next. This means that
> +         * if we're looking at the last halfword in the page we need to
> +         * see if it's a 16-bit Thumb insn (which will fit in this TB)
> +         * or a 32-bit Thumb insn (which won't).
> +         * This is to avoid generating a silly TB with a single 16-bit insn
> +         * in it at the end of this page (which would execute correctly
> +         * but isn't very efficient).
> +         */
> +        end_of_page = (dc->pc >= next_page_start) ||
> +            ((dc->pc >= next_page_start - 3) && insn_crosses_page(env, dc));
> +
>      } while (!dc->is_jmp && !tcg_op_buf_full() &&
>               !cs->singlestep_enabled &&
>               !singlestep &&
>               !dc->ss_active &&
> -             dc->pc < next_page_start &&
> +             !end_of_page &&
>               num_insns < max_insns);
>
>      if (tb->cflags & CF_LAST_IO) {

Except for the two comments and the question, this looks good to me.

Reviewed-by: Laurent Desnogues <address@hidden>


Laurent



reply via email to

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