| 1 | /* |
| 2 | * QEMU ARMv7-M TCG-only CPUs. |
| 3 | * |
| 4 | * Copyright (c) 2012 SUSE LINUX Products GmbH |
| 5 | * |
| 6 | * This code is licensed under the GNU GPL v2 or later. |
| 7 | * |
| 8 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 9 | */ |
| 10 | |
| 11 | #include "qemu/osdep.h" |
| 12 | #include "cpu.h" |
| 13 | #include "accel/tcg/cpu-ops.h" |
| 14 | #include "internals.h" |
| 15 | |
| 16 | #if !defined(CONFIG_USER_ONLY) |
| 17 | |
| 18 | #include "hw/intc/armv7m_nvic.h" |
| 19 | |
| 20 | static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request) |
| 21 | { |
| 22 | ARMCPU *cpu = ARM_CPU(cs); |
| 23 | CPUARMState *env = &cpu->env; |
| 24 | bool ret = false; |
| 25 | |
| 26 | /* |
| 27 | * ARMv7-M interrupt masking works differently than -A or -R. |
| 28 | * There is no FIQ/IRQ distinction. Instead of I and F bits |
| 29 | * masking FIQ and IRQ interrupts, an exception is taken only |
| 30 | * if it is higher priority than the current execution priority |
| 31 | * (which depends on state like BASEPRI, FAULTMASK and the |
| 32 | * currently active exception). |
| 33 | */ |
| 34 | if (interrupt_request & CPU_INTERRUPT_HARD |
| 35 | && (armv7m_nvic_can_take_pending_exception(env->nvic))) { |
| 36 | cs->exception_index = EXCP_IRQ; |
| 37 | cs->cc->tcg_ops->do_interrupt(cs); |
| 38 | ret = true; |
| 39 | } |
| 40 | return ret; |
| 41 | } |
| 42 | |
| 43 | #endif /* !CONFIG_USER_ONLY */ |
| 44 | |
| 45 | static void cortex_m0_initfn(Object *obj) |
| 46 | { |
| 47 | ARMCPU *cpu = ARM_CPU(obj); |
| 48 | ARMISARegisters *isar = &cpu->isar; |
| 49 | set_feature(&cpu->env, ARM_FEATURE_V6); |
| 50 | set_feature(&cpu->env, ARM_FEATURE_M); |
| 51 | |
| 52 | cpu->midr = 0x410cc200; |
| 53 | |
| 54 | /* |
| 55 | * These ID register values are not guest visible, because |
| 56 | * we do not implement the Main Extension. They must be set |
| 57 | * to values corresponding to the Cortex-M0's implemented |
| 58 | * features, because QEMU generally controls its emulation |
| 59 | * by looking at ID register fields. We use the same values as |
| 60 | * for the M3. |
| 61 | */ |
| 62 | SET_IDREG(isar, ID_PFR0, 0x00000030); |
| 63 | SET_IDREG(isar, ID_PFR1, 0x00000200); |
| 64 | SET_IDREG(isar, ID_DFR0, 0x00100000); |
| 65 | SET_IDREG(isar, ID_AFR0, 0x00000000); |
| 66 | SET_IDREG(isar, ID_MMFR0, 0x00000030); |
| 67 | SET_IDREG(isar, ID_MMFR1, 0x00000000); |
| 68 | SET_IDREG(isar, ID_MMFR2, 0x00000000); |
| 69 | SET_IDREG(isar, ID_MMFR3, 0x00000000); |
| 70 | SET_IDREG(isar, ID_ISAR0, 0x01141110); |
| 71 | SET_IDREG(isar, ID_ISAR1, 0x02111000); |
| 72 | SET_IDREG(isar, ID_ISAR2, 0x21112231); |
| 73 | SET_IDREG(isar, ID_ISAR3, 0x01111110); |
| 74 | SET_IDREG(isar, ID_ISAR4, 0x01310102); |
| 75 | SET_IDREG(isar, ID_ISAR5, 0x00000000); |
| 76 | SET_IDREG(isar, ID_ISAR6, 0x00000000); |
| 77 | } |
| 78 | |
| 79 | static void cortex_m3_initfn(Object *obj) |
| 80 | { |
| 81 | ARMCPU *cpu = ARM_CPU(obj); |
| 82 | ARMISARegisters *isar = &cpu->isar; |
| 83 | set_feature(&cpu->env, ARM_FEATURE_V7); |
| 84 | set_feature(&cpu->env, ARM_FEATURE_M); |
| 85 | set_feature(&cpu->env, ARM_FEATURE_M_MAIN); |
| 86 | cpu->midr = 0x410fc231; |
| 87 | cpu->pmsav7_dregion = 8; |
| 88 | SET_IDREG(isar, ID_PFR0, 0x00000030); |
| 89 | SET_IDREG(isar, ID_PFR1, 0x00000200); |
| 90 | SET_IDREG(isar, ID_DFR0, 0x00100000); |
| 91 | SET_IDREG(isar, ID_AFR0, 0x00000000); |
| 92 | SET_IDREG(isar, ID_MMFR0, 0x00000030); |
| 93 | SET_IDREG(isar, ID_MMFR1, 0x00000000); |
| 94 | SET_IDREG(isar, ID_MMFR2, 0x00000000); |
| 95 | SET_IDREG(isar, ID_MMFR3, 0x00000000); |
| 96 | SET_IDREG(isar, ID_ISAR0, 0x01141110); |
| 97 | SET_IDREG(isar, ID_ISAR1, 0x02111000); |
| 98 | SET_IDREG(isar, ID_ISAR2, 0x21112231); |
| 99 | SET_IDREG(isar, ID_ISAR3, 0x01111110); |
| 100 | SET_IDREG(isar, ID_ISAR4, 0x01310102); |
| 101 | SET_IDREG(isar, ID_ISAR5, 0x00000000); |
| 102 | SET_IDREG(isar, ID_ISAR6, 0x00000000); |
| 103 | } |
| 104 | |
| 105 | static void cortex_m4_initfn(Object *obj) |
| 106 | { |
| 107 | ARMCPU *cpu = ARM_CPU(obj); |
| 108 | ARMISARegisters *isar = &cpu->isar; |
| 109 | |
| 110 | set_feature(&cpu->env, ARM_FEATURE_V7); |
| 111 | set_feature(&cpu->env, ARM_FEATURE_M); |
| 112 | set_feature(&cpu->env, ARM_FEATURE_M_MAIN); |
| 113 | set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); |
| 114 | cpu->midr = 0x410fc240; /* r0p0 */ |
| 115 | cpu->pmsav7_dregion = 8; |
| 116 | cpu->isar.mvfr0 = 0x10110021; |
| 117 | cpu->isar.mvfr1 = 0x11000011; |
| 118 | cpu->isar.mvfr2 = 0x00000000; |
| 119 | SET_IDREG(isar, ID_PFR0, 0x00000030); |
| 120 | SET_IDREG(isar, ID_PFR1, 0x00000200); |
| 121 | SET_IDREG(isar, ID_DFR0, 0x00100000); |
| 122 | SET_IDREG(isar, ID_AFR0, 0x00000000); |
| 123 | SET_IDREG(isar, ID_MMFR0, 0x00000030); |
| 124 | SET_IDREG(isar, ID_MMFR1, 0x00000000); |
| 125 | SET_IDREG(isar, ID_MMFR2, 0x00000000); |
| 126 | SET_IDREG(isar, ID_MMFR3, 0x00000000); |
| 127 | SET_IDREG(isar, ID_ISAR0, 0x01141110); |
| 128 | SET_IDREG(isar, ID_ISAR1, 0x02111000); |
| 129 | SET_IDREG(isar, ID_ISAR2, 0x21112231); |
| 130 | SET_IDREG(isar, ID_ISAR3, 0x01111110); |
| 131 | SET_IDREG(isar, ID_ISAR4, 0x01310102); |
| 132 | SET_IDREG(isar, ID_ISAR5, 0x00000000); |
| 133 | SET_IDREG(isar, ID_ISAR6, 0x00000000); |
| 134 | } |
| 135 | |
| 136 | static void cortex_m7_initfn(Object *obj) |
| 137 | { |
| 138 | ARMCPU *cpu = ARM_CPU(obj); |
| 139 | ARMISARegisters *isar = &cpu->isar; |
| 140 | |
| 141 | set_feature(&cpu->env, ARM_FEATURE_V7); |
| 142 | set_feature(&cpu->env, ARM_FEATURE_M); |
| 143 | set_feature(&cpu->env, ARM_FEATURE_M_MAIN); |
| 144 | set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); |
| 145 | cpu->midr = 0x411fc272; /* r1p2 */ |
| 146 | cpu->pmsav7_dregion = 8; |
| 147 | cpu->isar.mvfr0 = 0x10110221; |
| 148 | cpu->isar.mvfr1 = 0x12000011; |
| 149 | cpu->isar.mvfr2 = 0x00000040; |
| 150 | SET_IDREG(isar, ID_PFR0, 0x00000030); |
| 151 | SET_IDREG(isar, ID_PFR1, 0x00000200); |
| 152 | SET_IDREG(isar, ID_DFR0, 0x00100000); |
| 153 | SET_IDREG(isar, ID_AFR0, 0x00000000); |
| 154 | SET_IDREG(isar, ID_MMFR0, 0x00100030); |
| 155 | SET_IDREG(isar, ID_MMFR1, 0x00000000); |
| 156 | SET_IDREG(isar, ID_MMFR2, 0x01000000); |
| 157 | SET_IDREG(isar, ID_MMFR3, 0x00000000); |
| 158 | SET_IDREG(isar, ID_ISAR0, 0x01101110); |
| 159 | SET_IDREG(isar, ID_ISAR1, 0x02112000); |
| 160 | SET_IDREG(isar, ID_ISAR2, 0x20232231); |
| 161 | SET_IDREG(isar, ID_ISAR3, 0x01111131); |
| 162 | SET_IDREG(isar, ID_ISAR4, 0x01310132); |
| 163 | SET_IDREG(isar, ID_ISAR5, 0x00000000); |
| 164 | SET_IDREG(isar, ID_ISAR6, 0x00000000); |
| 165 | } |
| 166 | |
| 167 | static void cortex_m33_initfn(Object *obj) |
| 168 | { |
| 169 | ARMCPU *cpu = ARM_CPU(obj); |
| 170 | ARMISARegisters *isar = &cpu->isar; |
| 171 | |
| 172 | set_feature(&cpu->env, ARM_FEATURE_V8); |
| 173 | set_feature(&cpu->env, ARM_FEATURE_M); |
| 174 | set_feature(&cpu->env, ARM_FEATURE_M_MAIN); |
| 175 | set_feature(&cpu->env, ARM_FEATURE_M_SECURITY); |
| 176 | set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); |
| 177 | cpu->midr = 0x410fd213; /* r0p3 */ |
| 178 | cpu->pmsav7_dregion = 16; |
| 179 | cpu->sau_sregion = 8; |
| 180 | cpu->isar.mvfr0 = 0x10110021; |
| 181 | cpu->isar.mvfr1 = 0x11000011; |
| 182 | cpu->isar.mvfr2 = 0x00000040; |
| 183 | SET_IDREG(isar, ID_PFR0, 0x00000030); |
| 184 | SET_IDREG(isar, ID_PFR1, 0x00000210); |
| 185 | SET_IDREG(isar, ID_DFR0, 0x00200000); |
| 186 | SET_IDREG(isar, ID_AFR0, 0x00000000); |
| 187 | SET_IDREG(isar, ID_MMFR0, 0x00101F40); |
| 188 | SET_IDREG(isar, ID_MMFR1, 0x00000000); |
| 189 | SET_IDREG(isar, ID_MMFR2, 0x01000000); |
| 190 | SET_IDREG(isar, ID_MMFR3, 0x00000000); |
| 191 | SET_IDREG(isar, ID_ISAR0, 0x01101110); |
| 192 | SET_IDREG(isar, ID_ISAR1, 0x02212000); |
| 193 | SET_IDREG(isar, ID_ISAR2, 0x20232232); |
| 194 | SET_IDREG(isar, ID_ISAR3, 0x01111131); |
| 195 | SET_IDREG(isar, ID_ISAR4, 0x01310132); |
| 196 | SET_IDREG(isar, ID_ISAR5, 0x00000000); |
| 197 | SET_IDREG(isar, ID_ISAR6, 0x00000000); |
| 198 | SET_IDREG(isar, CLIDR, 0x00000000); |
| 199 | cpu->ctr = 0x8000c000; |
| 200 | } |
| 201 | |
| 202 | static void cortex_m55_initfn(Object *obj) |
| 203 | { |
| 204 | ARMCPU *cpu = ARM_CPU(obj); |
| 205 | ARMISARegisters *isar = &cpu->isar; |
| 206 | |
| 207 | set_feature(&cpu->env, ARM_FEATURE_V8); |
| 208 | set_feature(&cpu->env, ARM_FEATURE_V8_1M); |
| 209 | set_feature(&cpu->env, ARM_FEATURE_M); |
| 210 | set_feature(&cpu->env, ARM_FEATURE_M_MAIN); |
| 211 | set_feature(&cpu->env, ARM_FEATURE_M_SECURITY); |
| 212 | set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); |
| 213 | cpu->midr = 0x410fd221; /* r0p1 */ |
| 214 | cpu->revidr = 0; |
| 215 | cpu->pmsav7_dregion = 16; |
| 216 | cpu->sau_sregion = 8; |
| 217 | /* These are the MVFR* values for the FPU + full MVE configuration */ |
| 218 | cpu->isar.mvfr0 = 0x10110221; |
| 219 | cpu->isar.mvfr1 = 0x12100211; |
| 220 | cpu->isar.mvfr2 = 0x00000040; |
| 221 | SET_IDREG(isar, ID_PFR0, 0x20000030); |
| 222 | SET_IDREG(isar, ID_PFR1, 0x00000230); |
| 223 | SET_IDREG(isar, ID_DFR0, 0x10200000); |
| 224 | SET_IDREG(isar, ID_AFR0, 0x00000000); |
| 225 | SET_IDREG(isar, ID_MMFR0, 0x00111040); |
| 226 | SET_IDREG(isar, ID_MMFR1, 0x00000000); |
| 227 | SET_IDREG(isar, ID_MMFR2, 0x01000000); |
| 228 | SET_IDREG(isar, ID_MMFR3, 0x00000011); |
| 229 | SET_IDREG(isar, ID_ISAR0, 0x01103110); |
| 230 | SET_IDREG(isar, ID_ISAR1, 0x02212000); |
| 231 | SET_IDREG(isar, ID_ISAR2, 0x20232232); |
| 232 | SET_IDREG(isar, ID_ISAR3, 0x01111131); |
| 233 | SET_IDREG(isar, ID_ISAR4, 0x01310132); |
| 234 | SET_IDREG(isar, ID_ISAR5, 0x00000000); |
| 235 | SET_IDREG(isar, ID_ISAR6, 0x00000000); |
| 236 | SET_IDREG(isar, CLIDR, 0x00000000); /* caches not implemented */ |
| 237 | cpu->ctr = 0x8303c003; |
| 238 | } |
| 239 | |
| 240 | static void cortex_m85_initfn(Object *obj) |
| 241 | { |
| 242 | ARMCPU *cpu = ARM_CPU(obj); |
| 243 | ARMISARegisters *isar = &cpu->isar; |
| 244 | |
| 245 | set_feature(&cpu->env, ARM_FEATURE_V8); |
| 246 | set_feature(&cpu->env, ARM_FEATURE_V8_1M); |
| 247 | set_feature(&cpu->env, ARM_FEATURE_M); |
| 248 | set_feature(&cpu->env, ARM_FEATURE_M_MAIN); |
| 249 | set_feature(&cpu->env, ARM_FEATURE_M_SECURITY); |
| 250 | set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); |
| 251 | cpu->midr = 0x411fd231; /* r1p1 */ |
| 252 | cpu->revidr = 0; |
| 253 | cpu->pmsav7_dregion = 16; |
| 254 | cpu->sau_sregion = 8; |
| 255 | /* These are the MVFR* values for the FPU + full MVE configuration */ |
| 256 | cpu->isar.mvfr0 = 0x10110221; |
| 257 | cpu->isar.mvfr1 = 0x12100211; |
| 258 | cpu->isar.mvfr2 = 0x00000040; |
| 259 | SET_IDREG(isar, ID_PFR0, 0x20000030); |
| 260 | SET_IDREG(isar, ID_PFR1, 0x00000230); |
| 261 | SET_IDREG(isar, ID_DFR0, 0x10200000); |
| 262 | SET_IDREG(isar, ID_AFR0, 0x00000000); |
| 263 | SET_IDREG(isar, ID_MMFR0, 0x00111040); |
| 264 | SET_IDREG(isar, ID_MMFR1, 0x00000000); |
| 265 | SET_IDREG(isar, ID_MMFR2, 0x01000000); |
| 266 | SET_IDREG(isar, ID_MMFR3, 0x00000011); |
| 267 | SET_IDREG(isar, ID_ISAR0, 0x01103110); |
| 268 | SET_IDREG(isar, ID_ISAR1, 0x02212000); |
| 269 | SET_IDREG(isar, ID_ISAR2, 0x20232232); |
| 270 | SET_IDREG(isar, ID_ISAR3, 0x01111131); |
| 271 | SET_IDREG(isar, ID_ISAR4, 0x01310132); |
| 272 | /* |
| 273 | * Real Cortex-M85 CPUs can be configured with or without PACBTI. |
| 274 | * If PACBTI is present then ID_ISAR5[23:20] read as 0b0100, |
| 275 | * indicating that QARMA3 is used. QEMU does not yet implement |
| 276 | * PACBTI emulation for M-profile, so we report as a "no-PACBTI" |
| 277 | * CPU for now. |
| 278 | */ |
| 279 | SET_IDREG(isar, ID_ISAR5, 0x00000000); |
| 280 | SET_IDREG(isar, ID_ISAR6, 0x00000000); |
| 281 | SET_IDREG(isar, CLIDR, 0x00000000); /* caches not implemented */ |
| 282 | cpu->ctr = 0x8303c003; |
| 283 | } |
| 284 | |
| 285 | static const TCGCPUOps arm_v7m_tcg_ops = { |
| 286 | /* ARM processors have a weak memory model */ |
| 287 | .guest_default_memory_order = 0, |
| 288 | .mttcg_supported = true, |
| 289 | |
| 290 | .initialize = arm_translate_init, |
| 291 | .translate_code = arm_translate_code, |
| 292 | .get_tb_cpu_state = arm_get_tb_cpu_state, |
| 293 | .synchronize_from_tb = arm_cpu_synchronize_from_tb, |
| 294 | .debug_excp_handler = arm_debug_excp_handler, |
| 295 | .restore_state_to_opc = arm_restore_state_to_opc, |
| 296 | .mmu_index = arm_cpu_mmu_index, |
| 297 | |
| 298 | #ifdef CONFIG_USER_ONLY |
| 299 | .record_sigsegv = arm_cpu_record_sigsegv, |
| 300 | .record_sigbus = arm_cpu_record_sigbus, |
| 301 | #else |
| 302 | .tlb_fill_align = arm_cpu_tlb_fill_align, |
| 303 | .pointer_wrap = cpu_pointer_wrap_uint32, |
| 304 | .cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt, |
| 305 | .cpu_exec_halt = arm_cpu_exec_halt, |
| 306 | .cpu_exec_reset = cpu_reset, |
| 307 | .do_interrupt = arm_v7m_cpu_do_interrupt, |
| 308 | .do_transaction_failed = arm_cpu_do_transaction_failed, |
| 309 | .do_unaligned_access = arm_cpu_do_unaligned_access, |
| 310 | .adjust_watchpoint_address = arm_adjust_watchpoint_address, |
| 311 | .debug_check_watchpoint = arm_debug_check_watchpoint, |
| 312 | .debug_check_breakpoint = arm_debug_check_breakpoint, |
| 313 | #endif /* !CONFIG_USER_ONLY */ |
| 314 | }; |
| 315 | |
| 316 | static void arm_v7m_class_init(ObjectClass *oc, const void *data) |
| 317 | { |
| 318 | ARMCPUClass *acc = ARM_CPU_CLASS(oc); |
| 319 | CPUClass *cc = CPU_CLASS(oc); |
| 320 | |
| 321 | acc->info = data; |
| 322 | cc->tcg_ops = &arm_v7m_tcg_ops; |
| 323 | } |
| 324 | |
| 325 | static const ARMCPUInfo arm_v7m_cpus[] = { |
| 326 | { .name = "cortex-m0", .initfn = cortex_m0_initfn, |
| 327 | .class_init = arm_v7m_class_init }, |
| 328 | { .name = "cortex-m3", .initfn = cortex_m3_initfn, |
| 329 | .class_init = arm_v7m_class_init }, |
| 330 | { .name = "cortex-m4", .initfn = cortex_m4_initfn, |
| 331 | .class_init = arm_v7m_class_init }, |
| 332 | { .name = "cortex-m7", .initfn = cortex_m7_initfn, |
| 333 | .class_init = arm_v7m_class_init }, |
| 334 | { .name = "cortex-m33", .initfn = cortex_m33_initfn, |
| 335 | .class_init = arm_v7m_class_init }, |
| 336 | { .name = "cortex-m55", .initfn = cortex_m55_initfn, |
| 337 | .class_init = arm_v7m_class_init }, |
| 338 | { .name = "cortex-m85", .initfn = cortex_m85_initfn, |
| 339 | .class_init = arm_v7m_class_init }, |
| 340 | }; |
| 341 | |
| 342 | static void arm_v7m_cpu_register_types(void) |
| 343 | { |
| 344 | size_t i; |
| 345 | |
| 346 | for (i = 0; i < ARRAY_SIZE(arm_v7m_cpus); ++i) { |
| 347 | arm_cpu_register(&arm_v7m_cpus[i]); |
| 348 | } |
| 349 | } |
| 350 | |
| 351 | type_init(arm_v7m_cpu_register_types) |