diff mbox series

[1/2] nvic: Handle ARMv6-M SCS reserved registers

Message ID 20180704195812.28798-2-jusual@mail.ru
State New
Headers show
Series nvic: Handle ARMv6-M SCS reserved registers | expand

Commit Message

Cameron Esfahani via July 4, 2018, 7:58 p.m. UTC
Handle SCS reserved registers listed in ARMv6-M ARM D3.6.1.
All reserved registers are RAZ/WI.

Signed-off-by: Julia Suvorova <jusual@mail.ru>
---
 hw/intc/armv7m_nvic.c | 69 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 57 insertions(+), 12 deletions(-)

Comments

Peter Maydell July 5, 2018, 10:54 a.m. UTC | #1
On 4 July 2018 at 20:58, Julia Suvorova <jusual@mail.ru> wrote:
> Handle SCS reserved registers listed in ARMv6-M ARM D3.6.1.
> All reserved registers are RAZ/WI.
>
> Signed-off-by: Julia Suvorova <jusual@mail.ru>
> ---
>  hw/intc/armv7m_nvic.c | 69 +++++++++++++++++++++++++++++++++++--------
>  1 file changed, 57 insertions(+), 12 deletions(-)

Hi; this patch is generally good, but I have a couple of comments
below, and in most (but not all) of these cases we should be
checking the ARM_FEATURE_M_MAIN bit rather than ARM_FEATURE_V7 --
I've annotated which should be which.

> diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
> index aba4510c70..fb61a1d08d 100644
> --- a/hw/intc/armv7m_nvic.c
> +++ b/hw/intc/armv7m_nvic.c
> @@ -865,6 +865,9 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
>          }
>          return val;
>      case 0xd10: /* System Control.  */
> +        if (!arm_feature(&cpu->env, ARM_FEATURE_V7)) {
> +            return 0;
> +        }

This check is correctly on ARM_FEATURE_V7.

Also, I would suggest having the "not in this version" behaviour
for all these checks be "goto bad_offset;" as we do already
for the v8-only registers. This will make the register
RAZ/WI, but it will also log that the guest did something
wrong if the user enables guest-error logging.

>          return cpu->env.v7m.scr[attrs.secure];
>      case 0xd14: /* Configuration Control.  */
>          /* The BFHFNMIGN bit is the only non-banked bit; we
> @@ -986,12 +989,21 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
>          }
>          return val;
>      case 0xd2c: /* Hard Fault Status.  */
> +        if (!arm_feature(&cpu->env, ARM_FEATURE_V7)) {

This one should check ARM_FEATURE_M_MAIN.

> +            return 0;
> +        }
>          return cpu->env.v7m.hfsr;
>      case 0xd30: /* Debug Fault Status.  */
>          return cpu->env.v7m.dfsr;
>      case 0xd34: /* MMFAR MemManage Fault Address */
> +        if (!arm_feature(&cpu->env, ARM_FEATURE_V7)) {
> +            return 0;
> +        }

M_MAIN

>          return cpu->env.v7m.mmfar[attrs.secure];
>      case 0xd38: /* Bus Fault Address.  */
> +        if (!arm_feature(&cpu->env, ARM_FEATURE_V7)) {
> +            return 0;
> +        }

M_MAIN

>          return cpu->env.v7m.bfar;
>      case 0xd3c: /* Aux Fault Status.  */
>          /* TODO: Implement fault status registers.  */
> @@ -1292,8 +1304,10 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
>           * QEMU's implementation ignores SEVONPEND and SLEEPONEXIT, which
>           * is architecturally permitted.
>           */
> -        value &= ~(R_V7M_SCR_SLEEPDEEP_MASK | R_V7M_SCR_SLEEPDEEPS_MASK);
> -        cpu->env.v7m.scr[attrs.secure] = value;
> +        if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
> +            value &= ~(R_V7M_SCR_SLEEPDEEP_MASK | R_V7M_SCR_SLEEPDEEPS_MASK);
> +            cpu->env.v7m.scr[attrs.secure] = value;
> +        }

OK.

As with the readl checks, prefer
   if !arm_feature(...)) {
       goto bad_offset;
   }
   [code for register here]

>          break;
>      case 0xd14: /* Configuration Control.  */
>          /* Enforce RAZ/WI on reserved and must-RAZ/WI bits */
> @@ -1388,16 +1402,22 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
>          nvic_irq_update(s);
>          break;
>      case 0xd2c: /* Hard Fault Status.  */
> -        cpu->env.v7m.hfsr &= ~value; /* W1C */
> +        if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
> +            cpu->env.v7m.hfsr &= ~value; /* W1C */
> +        }

M_MAIN.

>          break;
>      case 0xd30: /* Debug Fault Status.  */
>          cpu->env.v7m.dfsr &= ~value; /* W1C */
>          break;
>      case 0xd34: /* Mem Manage Address.  */
> -        cpu->env.v7m.mmfar[attrs.secure] = value;
> +        if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
> +            cpu->env.v7m.mmfar[attrs.secure] = value;
> +        }

M_MAIN.

>          return;
>      case 0xd38: /* Bus Fault Address.  */
> -        cpu->env.v7m.bfar = value;
> +        if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
> +            cpu->env.v7m.bfar = value;
> +        }

M_MAIN.

>          return;
>      case 0xd3c: /* Aux Fault Status.  */
>          qemu_log_mask(LOG_UNIMP,
> @@ -1624,13 +1644,13 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
>          cpu->env.v7m.sfsr = value;
>          break;
>      case 0xf00: /* Software Triggered Interrupt Register */
> -    {
> -        int excnum = (value & 0x1ff) + NVIC_FIRST_IRQ;
> -        if (excnum < s->num_irq) {
> -            armv7m_nvic_set_pending(s, excnum, false);
> +        if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {

M_MAIN.

> +            int excnum  = (value & 0x1ff) + NVIC_FIRST_IRQ;
> +            if (excnum < s->num_irq) {
> +                armv7m_nvic_set_pending(s, excnum, false);
> +            }
>          }
>          break;
> -    }
>      case 0xf50: /* ICIALLU */
>      case 0xf58: /* ICIMVAU */
>      case 0xf5c: /* DCIMVAC */
> @@ -1775,7 +1795,13 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr,
>              }
>          }
>          break;
> -    case 0xd18 ... 0xd23: /* System Handler Priority (SHPR1, SHPR2, SHPR3) */
> +    case 0xd18: /* System Handler Priority (SHPR1) */
> +        if (!arm_feature(&s->cpu->env, ARM_FEATURE_V7)) {

M_MAIN.

> +            val = 0;
> +            break;
> +        }
> +        /* fall through */
> +    case 0xd1c ... 0xd23: /* System Handler Priority (SHPR2, SHPR3) */
>          val = 0;
>          for (i = 0; i < size; i++) {
>              unsigned hdlidx = (offset - 0xd14) + i;
> @@ -1791,10 +1817,20 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr,
>          /* The BFSR bits [15:8] are shared between security states
>           * and we store them in the NS copy
>           */
> +        if (!arm_feature(&s->cpu->env, ARM_FEATURE_V7)) {

M_MAIN.

> +            val = 0;
> +            break;
> +        };
>          val = s->cpu->env.v7m.cfsr[attrs.secure];
>          val |= s->cpu->env.v7m.cfsr[M_REG_NS] & R_V7M_CFSR_BFSR_MASK;
>          val = extract32(val, (offset - 0xd28) * 8, size * 8);
>          break;
> +    case 0xd40 ... 0xd7c: /* CPUID registers */
> +        if (!arm_feature(&s->cpu->env, ARM_FEATURE_V7)) {
> +            val = 0;
> +            break;
> +        }
> +        goto proceed_to_readl;

Rather than doing this, I would recommend leaving the armv7m_nvic.c
code as it is, and just making sure that the cortex_m0 init function
leaves the cpu_id* registers at zero. Then they will RAZ/WI as
required.

>      case 0xfe0 ... 0xfff: /* ID.  */
>          if (offset & 3) {
>              val = 0;
> @@ -1803,6 +1839,7 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr,
>          }
>          break;
>      default:
> +    proceed_to_readl:
>          if (size == 4) {
>              val = nvic_readl(s, offset, attrs);
>          } else {
> @@ -1882,7 +1919,12 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
>          }
>          nvic_irq_update(s);
>          return MEMTX_OK;
> -    case 0xd18 ... 0xd23: /* System Handler Priority (SHPR1, SHPR2, SHPR3) */
> +    case 0xd18: /* System Handler Priority (SHPR1) */
> +        if (!arm_feature(&s->cpu->env, ARM_FEATURE_V7)) {

M_MAIN.

> +            return MEMTX_OK;
> +        }
> +        /* fall through */
> +    case 0xd1c ... 0xd23: /* System Handler Priority (SHPR2, SHPR3) */
>          for (i = 0; i < size; i++) {
>              unsigned hdlidx = (offset - 0xd14) + i;
>              int newprio = extract32(value, i * 8, 8);
> @@ -1899,6 +1941,9 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
>          /* All bits are W1C, so construct 32 bit value with 0s in
>           * the parts not written by the access size
>           */
> +        if (!arm_feature(&s->cpu->env, ARM_FEATURE_V7)) {
> +            return MEMTX_OK;
> +        }

M_MAIN. Also, this addition has split the comment above it
from the line of code which it is commenting on -- could you
move your check to be above the comment, please?

>          value <<= ((offset - 0xd28) * 8);
>
>          s->cpu->env.v7m.cfsr[attrs.secure] &= ~value;
> --

thanks
-- PMM
Cameron Esfahani via July 5, 2018, 11:25 a.m. UTC | #2
On 05.07.2018 13:54, Peter Maydell wrote:
> On 4 July 2018 at 20:58, Julia Suvorova <jusual@mail.ru> wrote:
>> Handle SCS reserved registers listed in ARMv6-M ARM D3.6.1.
>> All reserved registers are RAZ/WI.
>>
>> Signed-off-by: Julia Suvorova <jusual@mail.ru>
>> ---
>>   hw/intc/armv7m_nvic.c | 69 +++++++++++++++++++++++++++++++++++--------
>>   1 file changed, 57 insertions(+), 12 deletions(-)
> 
> Hi; this patch is generally good, but I have a couple of comments
> below, and in most (but not all) of these cases we should be
> checking the ARM_FEATURE_M_MAIN bit rather than ARM_FEATURE_V7 --
> I've annotated which should be which.

Thank you for the review. I did not dare to set the ARM_FEATURE_M_MAIN,
because I was not completely sure about the v8M behavior in certain cases.
I'll update the code taking into account all the comments, and send v2.

Best regards, Julia Suvorova.
Peter Maydell July 5, 2018, 12:06 p.m. UTC | #3
On 5 July 2018 at 12:25, Julia Suvorova <jusual@mail.ru> wrote:
> Thank you for the review. I did not dare to set the ARM_FEATURE_M_MAIN,
> because I was not completely sure about the v8M behavior in certain cases.
> I'll update the code taking into account all the comments, and send v2.

FWIW, I was working from the v8M Arm ARM, which is downloadable from
https://developer.arm.com/products/architecture/m-profile/docs
-- the descriptions for each register include a "Configurations"
sections which will say if the register is present only if
the main extension is implemented.

thanks
-- PMM
diff mbox series

Patch

diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index aba4510c70..fb61a1d08d 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -865,6 +865,9 @@  static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
         }
         return val;
     case 0xd10: /* System Control.  */
+        if (!arm_feature(&cpu->env, ARM_FEATURE_V7)) {
+            return 0;
+        }
         return cpu->env.v7m.scr[attrs.secure];
     case 0xd14: /* Configuration Control.  */
         /* The BFHFNMIGN bit is the only non-banked bit; we
@@ -986,12 +989,21 @@  static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
         }
         return val;
     case 0xd2c: /* Hard Fault Status.  */
+        if (!arm_feature(&cpu->env, ARM_FEATURE_V7)) {
+            return 0;
+        }
         return cpu->env.v7m.hfsr;
     case 0xd30: /* Debug Fault Status.  */
         return cpu->env.v7m.dfsr;
     case 0xd34: /* MMFAR MemManage Fault Address */
+        if (!arm_feature(&cpu->env, ARM_FEATURE_V7)) {
+            return 0;
+        }
         return cpu->env.v7m.mmfar[attrs.secure];
     case 0xd38: /* Bus Fault Address.  */
+        if (!arm_feature(&cpu->env, ARM_FEATURE_V7)) {
+            return 0;
+        }
         return cpu->env.v7m.bfar;
     case 0xd3c: /* Aux Fault Status.  */
         /* TODO: Implement fault status registers.  */
@@ -1292,8 +1304,10 @@  static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
          * QEMU's implementation ignores SEVONPEND and SLEEPONEXIT, which
          * is architecturally permitted.
          */
-        value &= ~(R_V7M_SCR_SLEEPDEEP_MASK | R_V7M_SCR_SLEEPDEEPS_MASK);
-        cpu->env.v7m.scr[attrs.secure] = value;
+        if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
+            value &= ~(R_V7M_SCR_SLEEPDEEP_MASK | R_V7M_SCR_SLEEPDEEPS_MASK);
+            cpu->env.v7m.scr[attrs.secure] = value;
+        }
         break;
     case 0xd14: /* Configuration Control.  */
         /* Enforce RAZ/WI on reserved and must-RAZ/WI bits */
@@ -1388,16 +1402,22 @@  static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
         nvic_irq_update(s);
         break;
     case 0xd2c: /* Hard Fault Status.  */
-        cpu->env.v7m.hfsr &= ~value; /* W1C */
+        if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
+            cpu->env.v7m.hfsr &= ~value; /* W1C */
+        }
         break;
     case 0xd30: /* Debug Fault Status.  */
         cpu->env.v7m.dfsr &= ~value; /* W1C */
         break;
     case 0xd34: /* Mem Manage Address.  */
-        cpu->env.v7m.mmfar[attrs.secure] = value;
+        if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
+            cpu->env.v7m.mmfar[attrs.secure] = value;
+        }
         return;
     case 0xd38: /* Bus Fault Address.  */
-        cpu->env.v7m.bfar = value;
+        if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
+            cpu->env.v7m.bfar = value;
+        }
         return;
     case 0xd3c: /* Aux Fault Status.  */
         qemu_log_mask(LOG_UNIMP,
@@ -1624,13 +1644,13 @@  static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
         cpu->env.v7m.sfsr = value;
         break;
     case 0xf00: /* Software Triggered Interrupt Register */
-    {
-        int excnum = (value & 0x1ff) + NVIC_FIRST_IRQ;
-        if (excnum < s->num_irq) {
-            armv7m_nvic_set_pending(s, excnum, false);
+        if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
+            int excnum  = (value & 0x1ff) + NVIC_FIRST_IRQ;
+            if (excnum < s->num_irq) {
+                armv7m_nvic_set_pending(s, excnum, false);
+            }
         }
         break;
-    }
     case 0xf50: /* ICIALLU */
     case 0xf58: /* ICIMVAU */
     case 0xf5c: /* DCIMVAC */
@@ -1775,7 +1795,13 @@  static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr,
             }
         }
         break;
-    case 0xd18 ... 0xd23: /* System Handler Priority (SHPR1, SHPR2, SHPR3) */
+    case 0xd18: /* System Handler Priority (SHPR1) */
+        if (!arm_feature(&s->cpu->env, ARM_FEATURE_V7)) {
+            val = 0;
+            break;
+        }
+        /* fall through */
+    case 0xd1c ... 0xd23: /* System Handler Priority (SHPR2, SHPR3) */
         val = 0;
         for (i = 0; i < size; i++) {
             unsigned hdlidx = (offset - 0xd14) + i;
@@ -1791,10 +1817,20 @@  static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr,
         /* The BFSR bits [15:8] are shared between security states
          * and we store them in the NS copy
          */
+        if (!arm_feature(&s->cpu->env, ARM_FEATURE_V7)) {
+            val = 0;
+            break;
+        };
         val = s->cpu->env.v7m.cfsr[attrs.secure];
         val |= s->cpu->env.v7m.cfsr[M_REG_NS] & R_V7M_CFSR_BFSR_MASK;
         val = extract32(val, (offset - 0xd28) * 8, size * 8);
         break;
+    case 0xd40 ... 0xd7c: /* CPUID registers */
+        if (!arm_feature(&s->cpu->env, ARM_FEATURE_V7)) {
+            val = 0;
+            break;
+        }
+        goto proceed_to_readl;
     case 0xfe0 ... 0xfff: /* ID.  */
         if (offset & 3) {
             val = 0;
@@ -1803,6 +1839,7 @@  static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr,
         }
         break;
     default:
+    proceed_to_readl:
         if (size == 4) {
             val = nvic_readl(s, offset, attrs);
         } else {
@@ -1882,7 +1919,12 @@  static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
         }
         nvic_irq_update(s);
         return MEMTX_OK;
-    case 0xd18 ... 0xd23: /* System Handler Priority (SHPR1, SHPR2, SHPR3) */
+    case 0xd18: /* System Handler Priority (SHPR1) */
+        if (!arm_feature(&s->cpu->env, ARM_FEATURE_V7)) {
+            return MEMTX_OK;
+        }
+        /* fall through */
+    case 0xd1c ... 0xd23: /* System Handler Priority (SHPR2, SHPR3) */
         for (i = 0; i < size; i++) {
             unsigned hdlidx = (offset - 0xd14) + i;
             int newprio = extract32(value, i * 8, 8);
@@ -1899,6 +1941,9 @@  static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
         /* All bits are W1C, so construct 32 bit value with 0s in
          * the parts not written by the access size
          */
+        if (!arm_feature(&s->cpu->env, ARM_FEATURE_V7)) {
+            return MEMTX_OK;
+        }
         value <<= ((offset - 0xd28) * 8);
 
         s->cpu->env.v7m.cfsr[attrs.secure] &= ~value;