summary refs log tree commit diff stats
path: root/target-arm/op_helper.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-03-16 17:43:37 +0000
committerPeter Maydell <peter.maydell@linaro.org>2016-03-16 17:43:37 +0000
commitd1f8764099022bc1173f2413331b26d4ff609a0c (patch)
tree5dd25667e072bf580983ac1d0ad54a31b0b083f9 /target-arm/op_helper.c
parent0ebc03bc065329eaefb6493f5fa7df08df528f2a (diff)
parentfec44a8c70e23f0f8433a28e824ce6dae4de8cde (diff)
downloadfocaccia-qemu-d1f8764099022bc1173f2413331b26d4ff609a0c.tar.gz
focaccia-qemu-d1f8764099022bc1173f2413331b26d4ff609a0c.zip
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20160316-1' into staging
target-arm queue:
 * loader: Fix incorrect parameter name in load_image_mr()
 * Implement MRS (banked) and MSR (banked) instructions
 * virt: Implement versioning for machine model
 * i.MX: some initial patches preparing for i.MX6 support
 * new ASPEED AST2400 SoC and palmetto-bmc machine
 * bcm2835: add some more raspi2 devices
 * sd: fix segfault running "info qtree"

# gpg: Signature made Wed 16 Mar 2016 17:42:43 GMT using RSA key ID 14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>"
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>"

* remotes/pmaydell/tags/pull-target-arm-20160316-1: (21 commits)
  sd: Fix "info qtree" on boards with SD cards
  bcm2835_dma: add emulation of Raspberry Pi DMA controller
  bcm2835_property: implement framebuffer control/configuration properties
  bcm2835_fb: add framebuffer device for Raspberry Pi
  bcm2835_aux: add emulation of BCM2835 AUX (aka UART1) block
  bcm2835_peripherals: enable sdhci pending-insert quirk for raspberry pi
  hw/arm: Add palmetto-bmc machine
  hw/arm: Add ASPEED AST2400 SoC model
  hw/intc: Add (new) ASPEED VIC device model
  hw/timer: Add ASPEED timer device model
  i.MX: Add missing descriptions in devices.
  i.MX: Add i.MX6 CCM and ANALOG device.
  i.MX: Add the CLK_IPG_HIGH clock
  i.MX: Remove CCM useless clock computation handling.
  i.MX: Rename CCM NOCLK to CLK_NONE for naming consistency.
  i.MX: Allow GPT timer to rollover.
  arm: virt: Move machine class init code to the abstract machine type
  arm: virt: Add an abstract ARM virt machine type
  target-arm: Fix translation level on early translation faults
  target-arm: Implement MRS (banked) and MSR (banked) instructions
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-arm/op_helper.c')
-rw-r--r--target-arm/op_helper.c120
1 files changed, 120 insertions, 0 deletions
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 92fde0a68c..d626ff1a20 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -494,6 +494,126 @@ uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
     }
 }
 
+static void msr_mrs_banked_exc_checks(CPUARMState *env, uint32_t tgtmode,
+                                      uint32_t regno)
+{
+    /* Raise an exception if the requested access is one of the UNPREDICTABLE
+     * cases; otherwise return. This broadly corresponds to the pseudocode
+     * BankedRegisterAccessValid() and SPSRAccessValid(),
+     * except that we have already handled some cases at translate time.
+     */
+    int curmode = env->uncached_cpsr & CPSR_M;
+
+    if (curmode == tgtmode) {
+        goto undef;
+    }
+
+    if (tgtmode == ARM_CPU_MODE_USR) {
+        switch (regno) {
+        case 8 ... 12:
+            if (curmode != ARM_CPU_MODE_FIQ) {
+                goto undef;
+            }
+            break;
+        case 13:
+            if (curmode == ARM_CPU_MODE_SYS) {
+                goto undef;
+            }
+            break;
+        case 14:
+            if (curmode == ARM_CPU_MODE_HYP || curmode == ARM_CPU_MODE_SYS) {
+                goto undef;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+
+    if (tgtmode == ARM_CPU_MODE_HYP) {
+        switch (regno) {
+        case 17: /* ELR_Hyp */
+            if (curmode != ARM_CPU_MODE_HYP && curmode != ARM_CPU_MODE_MON) {
+                goto undef;
+            }
+            break;
+        default:
+            if (curmode != ARM_CPU_MODE_MON) {
+                goto undef;
+            }
+            break;
+        }
+    }
+
+    return;
+
+undef:
+    raise_exception(env, EXCP_UDEF, syn_uncategorized(),
+                    exception_target_el(env));
+}
+
+void HELPER(msr_banked)(CPUARMState *env, uint32_t value, uint32_t tgtmode,
+                        uint32_t regno)
+{
+    msr_mrs_banked_exc_checks(env, tgtmode, regno);
+
+    switch (regno) {
+    case 16: /* SPSRs */
+        env->banked_spsr[bank_number(tgtmode)] = value;
+        break;
+    case 17: /* ELR_Hyp */
+        env->elr_el[2] = value;
+        break;
+    case 13:
+        env->banked_r13[bank_number(tgtmode)] = value;
+        break;
+    case 14:
+        env->banked_r14[bank_number(tgtmode)] = value;
+        break;
+    case 8 ... 12:
+        switch (tgtmode) {
+        case ARM_CPU_MODE_USR:
+            env->usr_regs[regno - 8] = value;
+            break;
+        case ARM_CPU_MODE_FIQ:
+            env->fiq_regs[regno - 8] = value;
+            break;
+        default:
+            g_assert_not_reached();
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+uint32_t HELPER(mrs_banked)(CPUARMState *env, uint32_t tgtmode, uint32_t regno)
+{
+    msr_mrs_banked_exc_checks(env, tgtmode, regno);
+
+    switch (regno) {
+    case 16: /* SPSRs */
+        return env->banked_spsr[bank_number(tgtmode)];
+    case 17: /* ELR_Hyp */
+        return env->elr_el[2];
+    case 13:
+        return env->banked_r13[bank_number(tgtmode)];
+    case 14:
+        return env->banked_r14[bank_number(tgtmode)];
+    case 8 ... 12:
+        switch (tgtmode) {
+        case ARM_CPU_MODE_USR:
+            return env->usr_regs[regno - 8];
+        case ARM_CPU_MODE_FIQ:
+            return env->fiq_regs[regno - 8];
+        default:
+            g_assert_not_reached();
+        }
+    default:
+        g_assert_not_reached();
+    }
+}
+
 void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
                                  uint32_t isread)
 {