]> git.proxmox.com Git - qemu.git/blobdiff - target-arm/helper.c
Merge remote-tracking branch 'sstabellini/compile-xs' into staging
[qemu.git] / target-arm / helper.c
index 00934cdf3761ff9fb194f8ce45f3de619f4a3bf9..23099236adc9d56872c437d9159d32b90ee7a5a6 100644 (file)
@@ -193,6 +193,9 @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = {
     { .name = "ILOCKDOWN", .cp = 15, .crn = 9, .crm = 0, .opc1 = 0, .opc2 = 1,
       .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c9_insn),
       .resetvalue = 0 },
+    /* v6 doesn't have the cache ID registers but Linux reads them anyway */
+    { .name = "DUMMY", .cp = 15, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = CP_ANY,
+      .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
     REGINFO_SENTINEL
 };
 
@@ -322,6 +325,21 @@ static int pmintenclr_write(CPUARMState *env, const ARMCPRegInfo *ri,
     return 0;
 }
 
+static int ccsidr_read(CPUARMState *env, const ARMCPRegInfo *ri,
+                       uint64_t *value)
+{
+    ARMCPU *cpu = arm_env_get_cpu(env);
+    *value = cpu->ccsidr[env->cp15.c0_cssel];
+    return 0;
+}
+
+static int csselr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                        uint64_t value)
+{
+    env->cp15.c0_cssel = value & 0xf;
+    return 0;
+}
+
 static const ARMCPRegInfo v7_cp_reginfo[] = {
     /* DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped
      * debug components
@@ -392,6 +410,16 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
     { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
       .resetvalue = 0, },
+    { .name = "CCSIDR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0,
+      .access = PL1_R, .readfn = ccsidr_read },
+    { .name = "CSSELR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 2, .opc2 = 0,
+      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c0_cssel),
+      .writefn = csselr_write, .resetvalue = 0 },
+    /* Auxiliary ID register: this actually has an IMPDEF value but for now
+     * just RAZ for all cores:
+     */
+    { .name = "AIDR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 7,
+      .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
     REGINFO_SENTINEL
 };
 
@@ -782,6 +810,19 @@ static const ARMCPRegInfo cache_block_ops_cp_reginfo[] = {
     /* We never have a a block transfer operation in progress */
     { .name = "BXSR", .cp = 15, .crn = 7, .crm = 12, .opc1 = 0, .opc2 = 4,
       .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 },
+    /* The cache ops themselves: these all NOP for QEMU */
+    { .name = "IICR", .cp = 15, .crm = 5, .opc1 = 0,
+      .access = PL1_W, .type = ARM_CP_NOP|ARM_CP_64BIT },
+    { .name = "IDCR", .cp = 15, .crm = 6, .opc1 = 0,
+      .access = PL1_W, .type = ARM_CP_NOP|ARM_CP_64BIT },
+    { .name = "CDCR", .cp = 15, .crm = 12, .opc1 = 0,
+      .access = PL0_W, .type = ARM_CP_NOP|ARM_CP_64BIT },
+    { .name = "PIR", .cp = 15, .crm = 12, .opc1 = 1,
+      .access = PL0_W, .type = ARM_CP_NOP|ARM_CP_64BIT },
+    { .name = "PDR", .cp = 15, .crm = 12, .opc1 = 2,
+      .access = PL0_W, .type = ARM_CP_NOP|ARM_CP_64BIT },
+    { .name = "CIDCR", .cp = 15, .crm = 14, .opc1 = 0,
+      .access = PL1_W, .type = ARM_CP_NOP|ARM_CP_64BIT },
     REGINFO_SENTINEL
 };
 
@@ -805,6 +846,31 @@ static const ARMCPRegInfo strongarm_cp_reginfo[] = {
     REGINFO_SENTINEL
 };
 
+static int mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri,
+                      uint64_t *value)
+{
+    uint32_t mpidr = env->cpu_index;
+    /* We don't support setting cluster ID ([8..11])
+     * so these bits always RAZ.
+     */
+    if (arm_feature(env, ARM_FEATURE_V7MP)) {
+        mpidr |= (1 << 31);
+        /* Cores which are uniprocessor (non-coherent)
+         * but still implement the MP extensions set
+         * bit 30. (For instance, A9UP.) However we do
+         * not currently model any of those cores.
+         */
+    }
+    *value = mpidr;
+    return 0;
+}
+
+static const ARMCPRegInfo mpidr_cp_reginfo[] = {
+    { .name = "MPIDR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 5,
+      .access = PL1_R, .readfn = mpidr_read },
+    REGINFO_SENTINEL
+};
+
 static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 {
     env->cp15.c1_sys = value;
@@ -825,6 +891,60 @@ void register_cp_regs_for_features(ARMCPU *cpu)
 
     define_arm_cp_regs(cpu, cp_reginfo);
     if (arm_feature(env, ARM_FEATURE_V6)) {
+        /* The ID registers all have impdef reset values */
+        ARMCPRegInfo v6_idregs[] = {
+            { .name = "ID_PFR0", .cp = 15, .crn = 0, .crm = 1,
+              .opc1 = 0, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST,
+              .resetvalue = cpu->id_pfr0 },
+            { .name = "ID_PFR1", .cp = 15, .crn = 0, .crm = 1,
+              .opc1 = 0, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST,
+              .resetvalue = cpu->id_pfr1 },
+            { .name = "ID_DFR0", .cp = 15, .crn = 0, .crm = 1,
+              .opc1 = 0, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST,
+              .resetvalue = cpu->id_dfr0 },
+            { .name = "ID_AFR0", .cp = 15, .crn = 0, .crm = 1,
+              .opc1 = 0, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST,
+              .resetvalue = cpu->id_afr0 },
+            { .name = "ID_MMFR0", .cp = 15, .crn = 0, .crm = 1,
+              .opc1 = 0, .opc2 = 4, .access = PL1_R, .type = ARM_CP_CONST,
+              .resetvalue = cpu->id_mmfr0 },
+            { .name = "ID_MMFR1", .cp = 15, .crn = 0, .crm = 1,
+              .opc1 = 0, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST,
+              .resetvalue = cpu->id_mmfr1 },
+            { .name = "ID_MMFR2", .cp = 15, .crn = 0, .crm = 1,
+              .opc1 = 0, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST,
+              .resetvalue = cpu->id_mmfr2 },
+            { .name = "ID_MMFR3", .cp = 15, .crn = 0, .crm = 1,
+              .opc1 = 0, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST,
+              .resetvalue = cpu->id_mmfr3 },
+            { .name = "ID_ISAR0", .cp = 15, .crn = 0, .crm = 2,
+              .opc1 = 0, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST,
+              .resetvalue = cpu->id_isar0 },
+            { .name = "ID_ISAR1", .cp = 15, .crn = 0, .crm = 2,
+              .opc1 = 0, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST,
+              .resetvalue = cpu->id_isar1 },
+            { .name = "ID_ISAR2", .cp = 15, .crn = 0, .crm = 2,
+              .opc1 = 0, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST,
+              .resetvalue = cpu->id_isar2 },
+            { .name = "ID_ISAR3", .cp = 15, .crn = 0, .crm = 2,
+              .opc1 = 0, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST,
+              .resetvalue = cpu->id_isar3 },
+            { .name = "ID_ISAR4", .cp = 15, .crn = 0, .crm = 2,
+              .opc1 = 0, .opc2 = 4, .access = PL1_R, .type = ARM_CP_CONST,
+              .resetvalue = cpu->id_isar4 },
+            { .name = "ID_ISAR5", .cp = 15, .crn = 0, .crm = 2,
+              .opc1 = 0, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST,
+              .resetvalue = cpu->id_isar5 },
+            /* 6..7 are as yet unallocated and must RAZ */
+            { .name = "ID_ISAR6", .cp = 15, .crn = 0, .crm = 2,
+              .opc1 = 0, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST,
+              .resetvalue = 0 },
+            { .name = "ID_ISAR7", .cp = 15, .crn = 0, .crm = 2,
+              .opc1 = 0, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST,
+              .resetvalue = 0 },
+            REGINFO_SENTINEL
+        };
+        define_arm_cp_regs(cpu, v6_idregs);
         define_arm_cp_regs(cpu, v6_cp_reginfo);
     } else {
         define_arm_cp_regs(cpu, not_v6_cp_reginfo);
@@ -842,7 +962,12 @@ void register_cp_regs_for_features(ARMCPU *cpu)
             .fieldoffset = offsetof(CPUARMState, cp15.c9_pmcr),
             .readfn = pmreg_read, .writefn = pmcr_write
         };
+        ARMCPRegInfo clidr = {
+            .name = "CLIDR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 1,
+            .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->clidr
+        };
         define_one_arm_cp_reg(cpu, &pmcr);
+        define_one_arm_cp_reg(cpu, &clidr);
         define_arm_cp_regs(cpu, v7_cp_reginfo);
     } else {
         define_arm_cp_regs(cpu, not_v7_cp_reginfo);
@@ -888,6 +1013,77 @@ void register_cp_regs_for_features(ARMCPU *cpu)
     if (arm_feature(env, ARM_FEATURE_DUMMY_C15_REGS)) {
         define_arm_cp_regs(cpu, dummy_c15_cp_reginfo);
     }
+    if (arm_feature(env, ARM_FEATURE_MPIDR)) {
+        define_arm_cp_regs(cpu, mpidr_cp_reginfo);
+    }
+    /* Slightly awkwardly, the OMAP and StrongARM cores need all of
+     * cp15 crn=0 to be writes-ignored, whereas for other cores they should
+     * be read-only (ie write causes UNDEF exception).
+     */
+    {
+        ARMCPRegInfo id_cp_reginfo[] = {
+            /* Note that the MIDR isn't a simple constant register because
+             * of the TI925 behaviour where writes to another register can
+             * cause the MIDR value to change.
+             */
+            { .name = "MIDR",
+              .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0,
+              .access = PL1_R, .resetvalue = cpu->midr,
+              .writefn = arm_cp_write_ignore,
+              .fieldoffset = offsetof(CPUARMState, cp15.c0_cpuid) },
+            { .name = "CTR",
+              .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 1,
+              .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->ctr },
+            { .name = "TCMTR",
+              .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 2,
+              .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
+            { .name = "TLBTR",
+              .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 3,
+              .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
+            /* crn = 0 op1 = 0 crm = 3..7 : currently unassigned; we RAZ. */
+            { .name = "DUMMY",
+              .cp = 15, .crn = 0, .crm = 3, .opc1 = 0, .opc2 = CP_ANY,
+              .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
+            { .name = "DUMMY",
+              .cp = 15, .crn = 0, .crm = 4, .opc1 = 0, .opc2 = CP_ANY,
+              .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
+            { .name = "DUMMY",
+              .cp = 15, .crn = 0, .crm = 5, .opc1 = 0, .opc2 = CP_ANY,
+              .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
+            { .name = "DUMMY",
+              .cp = 15, .crn = 0, .crm = 6, .opc1 = 0, .opc2 = CP_ANY,
+              .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
+            { .name = "DUMMY",
+              .cp = 15, .crn = 0, .crm = 7, .opc1 = 0, .opc2 = CP_ANY,
+              .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
+            REGINFO_SENTINEL
+        };
+        ARMCPRegInfo crn0_wi_reginfo = {
+            .name = "CRN0_WI", .cp = 15, .crn = 0, .crm = CP_ANY,
+            .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_W,
+            .type = ARM_CP_NOP | ARM_CP_OVERRIDE
+        };
+        if (arm_feature(env, ARM_FEATURE_OMAPCP) ||
+            arm_feature(env, ARM_FEATURE_STRONGARM)) {
+            ARMCPRegInfo *r;
+            /* Register the blanket "writes ignored" value first to cover the
+             * whole space. Then define the specific ID registers, but update
+             * their access field to allow write access, so that they ignore
+             * writes rather than causing them to UNDEF.
+             */
+            define_one_arm_cp_reg(cpu, &crn0_wi_reginfo);
+            for (r = id_cp_reginfo; r->type != ARM_CP_SENTINEL; r++) {
+                r->access = PL1_RW;
+                define_one_arm_cp_reg(cpu, r);
+            }
+        } else {
+            /* Just register the standard ID registers (read-only, meaning
+             * that writes will UNDEF).
+             */
+            define_arm_cp_regs(cpu, id_cp_reginfo);
+        }
+    }
+
     if (arm_feature(env, ARM_FEATURE_AUXCR)) {
         ARMCPRegInfo auxcr = {
             .name = "AUXCR", .cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 1,
@@ -1245,16 +1441,6 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
     return 1;
 }
 
-void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val)
-{
-    cpu_abort(env, "cp15 insn %08x\n", insn);
-}
-
-uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn)
-{
-    cpu_abort(env, "cp15 insn %08x\n", insn);
-}
-
 /* These should probably raise undefined insn exceptions.  */
 void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
 {
@@ -1981,141 +2167,6 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUARMState *env, target_ulong addr)
     return phys_addr;
 }
 
-void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val)
-{
-    int op1;
-    int op2;
-    int crm;
-
-    op1 = (insn >> 21) & 7;
-    op2 = (insn >> 5) & 7;
-    crm = insn & 0xf;
-    switch ((insn >> 16) & 0xf) {
-    case 0:
-        /* ID codes.  */
-        if (arm_feature(env, ARM_FEATURE_XSCALE))
-            break;
-        if (arm_feature(env, ARM_FEATURE_OMAPCP))
-            break;
-        if (arm_feature(env, ARM_FEATURE_V7)
-                && op1 == 2 && crm == 0 && op2 == 0) {
-            env->cp15.c0_cssel = val & 0xf;
-            break;
-        }
-        goto bad_reg;
-    case 4: /* Reserved.  */
-        goto bad_reg;
-    case 12: /* Reserved.  */
-        goto bad_reg;
-    }
-    return;
-bad_reg:
-    /* ??? For debugging only.  Should raise illegal instruction exception.  */
-    cpu_abort(env, "Unimplemented cp15 register write (c%d, c%d, {%d, %d})\n",
-              (insn >> 16) & 0xf, crm, op1, op2);
-}
-
-uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn)
-{
-    int op1;
-    int op2;
-    int crm;
-
-    op1 = (insn >> 21) & 7;
-    op2 = (insn >> 5) & 7;
-    crm = insn & 0xf;
-    switch ((insn >> 16) & 0xf) {
-    case 0: /* ID codes.  */
-        switch (op1) {
-        case 0:
-            switch (crm) {
-            case 0:
-                switch (op2) {
-                case 0: /* Device ID.  */
-                    return env->cp15.c0_cpuid;
-                case 1: /* Cache Type.  */
-                   return env->cp15.c0_cachetype;
-                case 2: /* TCM status.  */
-                    return 0;
-                case 3: /* TLB type register.  */
-                    return 0; /* No lockable TLB entries.  */
-                case 5: /* MPIDR */
-                    /* The MPIDR was standardised in v7; prior to
-                     * this it was implemented only in the 11MPCore.
-                     * For all other pre-v7 cores it does not exist.
-                     */
-                    if (arm_feature(env, ARM_FEATURE_V7) ||
-                        ARM_CPUID(env) == ARM_CPUID_ARM11MPCORE) {
-                        int mpidr = env->cpu_index;
-                        /* We don't support setting cluster ID ([8..11])
-                         * so these bits always RAZ.
-                         */
-                        if (arm_feature(env, ARM_FEATURE_V7MP)) {
-                            mpidr |= (1 << 31);
-                            /* Cores which are uniprocessor (non-coherent)
-                             * but still implement the MP extensions set
-                             * bit 30. (For instance, A9UP.) However we do
-                             * not currently model any of those cores.
-                             */
-                        }
-                        return mpidr;
-                    }
-                    /* otherwise fall through to the unimplemented-reg case */
-                default:
-                    goto bad_reg;
-                }
-            case 1:
-                if (!arm_feature(env, ARM_FEATURE_V6))
-                    goto bad_reg;
-                return env->cp15.c0_c1[op2];
-            case 2:
-                if (!arm_feature(env, ARM_FEATURE_V6))
-                    goto bad_reg;
-                return env->cp15.c0_c2[op2];
-            case 3: case 4: case 5: case 6: case 7:
-                return 0;
-            default:
-                goto bad_reg;
-            }
-        case 1:
-            /* These registers aren't documented on arm11 cores.  However
-               Linux looks at them anyway.  */
-            if (!arm_feature(env, ARM_FEATURE_V6))
-                goto bad_reg;
-            if (crm != 0)
-                goto bad_reg;
-            if (!arm_feature(env, ARM_FEATURE_V7))
-                return 0;
-
-            switch (op2) {
-            case 0:
-                return env->cp15.c0_ccsid[env->cp15.c0_cssel];
-            case 1:
-                return env->cp15.c0_clid;
-            case 7:
-                return 0;
-            }
-            goto bad_reg;
-        case 2:
-            if (op2 != 0 || crm != 0)
-                goto bad_reg;
-            return env->cp15.c0_cssel;
-        default:
-            goto bad_reg;
-        }
-    case 4: /* Reserved.  */
-        goto bad_reg;
-    case 11: /* TCM DMA control.  */
-    case 12: /* Reserved.  */
-        goto bad_reg;
-    }
-bad_reg:
-    /* ??? For debugging only.  Should raise illegal instruction exception.  */
-    cpu_abort(env, "Unimplemented cp15 register read (c%d, c%d, {%d, %d})\n",
-              (insn >> 16) & 0xf, crm, op1, op2);
-    return 0;
-}
-
 void HELPER(set_r13_banked)(CPUARMState *env, uint32_t mode, uint32_t val)
 {
     if ((env->uncached_cpsr & CPSR_M) == mode) {