qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Peter Maydell <peter.maydell@linaro.org>
To: Michael Davidsaver <mdavidsaver@gmail.com>
Cc: Peter Crosthwaite <crosthwaitepeter@gmail.com>,
	qemu-arm <qemu-arm@nongnu.org>,
	QEMU Developers <qemu-devel@nongnu.org>
Subject: Re: [Qemu-devel] [PATCH v2 12/26] armv7m: check exception return consistency
Date: Thu, 17 Dec 2015 19:26:12 +0000	[thread overview]
Message-ID: <CAFEAcA-dYHJDc5YsneK63ubTHfrrf7RfpV23+r8VbE77X6yKyA@mail.gmail.com> (raw)
In-Reply-To: <1449101933-24928-13-git-send-email-mdavidsaver@gmail.com>

On 3 December 2015 at 00:18, Michael Davidsaver <mdavidsaver@gmail.com> wrote:
> Detect use of reserved exception return codes
> and return to thread mode from nested
> exception handler.
>
> Also check consistency between NVIC and CPU
> wrt. the active exception.
> ---
>  hw/intc/armv7m_nvic.c |  7 +++-
>  target-arm/cpu.h      |  2 +-
>  target-arm/helper.c   | 95 ++++++++++++++++++++++++++++++++++++++++++++++-----
>  3 files changed, 94 insertions(+), 10 deletions(-)
>
> diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
> index 619c320..7d261ae 100644
> --- a/hw/intc/armv7m_nvic.c
> +++ b/hw/intc/armv7m_nvic.c
> @@ -396,7 +396,7 @@ void armv7m_nvic_acknowledge_irq(void *opaque)
>      assert(env->v7m.exception > 0); /* spurious exception? */
>  }
>
> -void armv7m_nvic_complete_irq(void *opaque, int irq)
> +bool armv7m_nvic_complete_irq(void *opaque, int irq)
>  {
>      NVICState *s = (NVICState *)opaque;
>      VecInfo *vec;
> @@ -406,12 +406,17 @@ void armv7m_nvic_complete_irq(void *opaque, int irq)
>
>      vec = &s->vectors[irq];
>
> +    if (!vec->active) {
> +        return true;
> +    }
> +
>      vec->active = 0;
>      vec->pending = vec->level;
>      assert(!vec->level || irq >= 16);
>
>      nvic_irq_update(s);
>      DPRINTF(0, "EOI %d\n", irq);
> +    return false;
>  }
>
>  /* Only called for external interrupt (vector>=16) */
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 4262efc..b98ef89 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -1043,7 +1043,7 @@ void armv7m_nvic_set_pending(void *opaque, int irq);
>  bool armv7m_nvic_is_active(void *opaque, int irq);
>  int armv7m_nvic_get_active_prio(void *opaque);
>  void armv7m_nvic_acknowledge_irq(void *opaque);
> -void armv7m_nvic_complete_irq(void *opaque, int irq);
> +bool armv7m_nvic_complete_irq(void *opaque, int irq);

A brief comment here describing what the return value means would be nice.

>
>  /* Interface for defining coprocessor registers.
>   * Registers are defined in tables of arm_cp_reginfo structs
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index b6ec761..f7e496d 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -5375,18 +5375,65 @@ static void switch_v7m_sp(CPUARMState *env, int process)
>
>  static void do_v7m_exception_exit(CPUARMState *env)
>  {
> +    unsigned ufault = 0;
>      uint32_t type;
>      uint32_t xpsr;
>
> -    type = env->regs[15];
> +    if (env->v7m.exception == 0) {
> +        hw_error("Return from exception w/o active exception.  Logic error.");

Should this just be an assert(), or can the guest provoke this?

> +    }
> +
>      if (env->v7m.exception != ARMV7M_EXCP_NMI) {
>          /* Auto-clear FAULTMASK on return from other than NMI */
>          env->daif &= ~PSTATE_F;
>      }
> -    if (env->v7m.exception != 0) {
> -        armv7m_nvic_complete_irq(env->nvic, env->v7m.exception);
> +
> +    if (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception)) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "Requesting return from exception "
> +                      "from inactive exception %d\n",
> +                      env->v7m.exception);
> +        ufault = 1;
> +    }
> +    env->v7m.exception = -42; /* spoil, will be unstacked below */

I don't really like this. If you're going to do it please at least
use a symbolic constant rather than hardcoding -42.

> +    env->v7m.exception_prio = armv7m_nvic_get_active_prio(env->nvic);
> +
> +    type = env->regs[15] & 0xf;
> +    /* QEMU seems to clear the LSB at some point. */
> +    type |= 1;

This is a rather vague comment. The LSB of regs[15] is always
clear because Thumb PCs are 2-aligned. We don't ever store the
"Thumb mode" bit in regs[15] (and the hardware doesn't either).

> +
> +    switch (type) {
> +    case 0x1: /* Return to Handler mode */
> +        if (env->v7m.exception_prio == 0x100) {
> +            qemu_log_mask(LOG_GUEST_ERROR, "Requesting return from exception "
> +                          "to Handler mode not allowed at base level of "
> +                          "activation");
> +            ufault = 1;

What is this test? None of the listed integrity checks in section
B1.5.8 of the v7M ARM ARM or the ExceptionReturn pseudocode cehck
the priority of the currently executing exception.

> +        }
> +        break;
> +    case 0x9: /* Return to Thread mode w/ Main stack */
> +    case 0xd: /* Return to Thread mode w/ Process stack */
> +        if (env->v7m.exception_prio != 0x100) {
> +            /* Attempt to return to Thread mode
> +             * from nested handler while NONBASETHRDENA not set.
> +             */
> +            qemu_log_mask(LOG_GUEST_ERROR, "Nested exception return to %d w/"
> +                          " Thread mode while NONBASETHRDENA not set\n",
> +                          env->v7m.exception);

The error message and the comment talk about NONBASETHRDENA, but
the code isn't testing it. Also, you have nothing corresponding
to what the pseudocode NestedActivation variable is tracking
(ie is there a single active exception currently).

> +            ufault = 1;
> +        }
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR, "Exception return w/ reserved code"
> +                                       " %02x\n", (unsigned)type);
> +        ufault = 1;
>      }
>
> +    /* TODO? if ufault==1 ARM calls for entering exception handler
> +     * directly w/o popping stack.
> +     * We pop anyway since the active UsageFault will push on entry
> +     * which should happen before execution resumes?
> +     */

There is a distinction if SP is currently pointing at an invalid
address -- if you try to unstack and stack again then that will
fault and the guest can see the difference. This is a corner case
that I'm happy with us just marking as TODO for the moment though.
(Also I think there may be a difference if we have a pending NMI
at this point, but I haven't thought that through.)

> +
>      /* Switch to the target stack.  */
>      switch_v7m_sp(env, (type & 4) != 0);
>      /* Pop registers.  */
> @@ -5409,14 +5456,46 @@ static void do_v7m_exception_exit(CPUARMState *env)
>      }
>      xpsr = v7m_pop(env);
>      xpsr_write(env, xpsr, 0xfffffdff);
> +
> +    assert(env->v7m.exception!=-42);
> +
>      /* Undo stack alignment.  */
>      if (xpsr & 0x200)
>          env->regs[13] |= 4;
> -    /* ??? The exception return type specifies Thread/Handler mode.  However
> -       this is also implied by the xPSR value. Not sure what to do
> -       if there is a mismatch.  */
> -    /* ??? Likewise for mismatches between the CONTROL register and the stack
> -       pointer.  */
> +
> +    if (!ufault) {
> +        /* consistency check between NVIC and guest stack */
> +        if (env->v7m.exception == 0 && env->v7m.exception_prio != 0x100) {
> +            ufault = 1;
> +            qemu_log_mask(LOG_GUEST_ERROR, "Can't Unstacked to thread mode "
> +                          "with active exception\n");
> +            env->v7m.exception_prio = 0x100;
> +
> +        } else if (env->v7m.exception != 0 &&
> +                   !armv7m_nvic_is_active(env->nvic, env->v7m.exception))
> +        {
> +            ufault = 1;
> +            qemu_log_mask(LOG_GUEST_ERROR, "Unstacked exception %d is not "
> +                          "active\n", env->v7m.exception);
> +        } else  if (env->v7m.exception != 0
> +                    && env->v7m.exception_prio == 0x100) {
> +            hw_error("logic error at exception exit\n");
> +        }
> +        /* ARM calls for PushStack() here, which should happen
> +         * went we return with a pending exception

"when"

> +         */
> +    }
> +
> +    if (ufault) {
> +        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
> +        env->v7m.cfsr |= 1<<18; /* INVPC */
> +    }
> +
> +    /* Ensure that priority is consistent.  Clear for Thread mode
> +     * and set for Handler mode
> +     */
> +    assert((env->v7m.exception == 0 && env->v7m.exception_prio > 0xff)
> +           || (env->v7m.exception != 0 && env->v7m.exception_prio <= 0xff));
>  }
>
>  static

thanks
-- PMM

  reply	other threads:[~2015-12-17 19:26 UTC|newest]

Thread overview: 56+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-03  0:18 [Qemu-devel] [PATCH v2 00/26] armv7m: exception handling, MPU, and more Michael Davidsaver
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 01/26] armv7m: MRS/MSR handle unprivileged access Michael Davidsaver
2015-12-17 13:10   ` Peter Maydell
2017-01-12 14:14     ` Peter Maydell
2017-01-12 16:33       ` Michael Davidsaver
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 02/26] armv7m: Undo armv7m.hack Michael Davidsaver
2015-12-17 15:38   ` Peter Maydell
2015-12-27 20:22     ` Michael Davidsaver
2015-12-28 18:36       ` Peter Maydell
2015-12-28  1:55     ` Michael Davidsaver
2015-12-28 18:27       ` Peter Maydell
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 03/26] armv7m: Explicit error for bad vector table Michael Davidsaver
2015-12-17 13:25   ` Peter Maydell
2015-12-27 20:43     ` Michael Davidsaver
2015-12-28 18:38       ` Peter Maydell
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 04/26] armv7m: additional cpu state for exception handling Michael Davidsaver
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 05/26] armv7m: add armv7m_excp_running_prio() Michael Davidsaver
2015-12-17 14:36   ` Peter Maydell
2015-12-27 20:56     ` Michael Davidsaver
2015-12-28 18:41       ` Peter Maydell
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 06/26] armv7m: fix I and F flag handling Michael Davidsaver
2015-12-17 14:39   ` Peter Maydell
2015-12-17 15:18     ` Peter Maydell
2015-12-28  1:59       ` Michael Davidsaver
2015-12-28 18:43         ` [Qemu-devel] [Qemu-arm] " Peter Maydell
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 07/26] armv7m: simpler/faster exception start Michael Davidsaver
2015-12-17 15:39   ` Peter Maydell
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 08/26] armv7m: rewrite NVIC Michael Davidsaver
2015-12-17 18:49   ` Peter Maydell
2015-12-19 19:08   ` Christopher Friedt
2015-12-19 19:45     ` Christopher Friedt
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 09/26] armv7m: implement CFSR, HFSR, BFAR, and MMFAR Michael Davidsaver
2015-12-17 19:04   ` Peter Maydell
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 10/26] armv7m: auto-clear FAULTMASK Michael Davidsaver
2015-12-17 19:07   ` Peter Maydell
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 11/26] arm: gic: Remove references to NVIC Michael Davidsaver
2015-12-17 19:08   ` Peter Maydell
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 12/26] armv7m: check exception return consistency Michael Davidsaver
2015-12-17 19:26   ` Peter Maydell [this message]
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 13/26] armv7m: implement CCR Michael Davidsaver
2015-12-17 19:31   ` Peter Maydell
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 14/26] armv7m: prevent unprivileged write to STIR Michael Davidsaver
2015-12-17 19:33   ` Peter Maydell
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 15/26] armv7m: add MPU to cortex-m3 and cortex-m4 Michael Davidsaver
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 16/26] armv7m: add some mpu debugging prints Michael Davidsaver
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 17/26] armv7m: mpu background miss is perm fault Michael Davidsaver
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 18/26] armv7m: update base region policy Michael Davidsaver
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 19/26] armv7m: mpu not allowed to map exception return codes Michael Davidsaver
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 20/26] armv7m: observable initial register state Michael Davidsaver
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 21/26] armv7m: CONTROL<1> handling Michael Davidsaver
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 22/26] armv7m: priority field mask Michael Davidsaver
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 23/26] qom: add cpu_generic_init_unrealized() Michael Davidsaver
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 24/26] armv7m: split armv7m_init in two parts Michael Davidsaver
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 25/26] armv7m: remove extra cpu_reset() Michael Davidsaver
2015-12-03  0:18 ` [Qemu-devel] [PATCH v2 26/26] armv7m: decide whether faults are MemManage or BusFault Michael Davidsaver
2015-12-17 19:38 ` [Qemu-devel] [PATCH v2 00/26] armv7m: exception handling, MPU, and more Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAFEAcA-dYHJDc5YsneK63ubTHfrrf7RfpV23+r8VbE77X6yKyA@mail.gmail.com \
    --to=peter.maydell@linaro.org \
    --cc=crosthwaitepeter@gmail.com \
    --cc=mdavidsaver@gmail.com \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).