| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| 2 | |
| 3 | #include "qemu/osdep.h" |
| 4 | #include "cpu.h" |
| 5 | #include "qemu/target-info.h" |
| 6 | #include "internals.h" |
| 7 | |
| 8 | |
| 9 | /* Share AArch32 -cpu max features with AArch64. */ |
| 10 | void aa32_max_features(ARMCPU *cpu) |
| 11 | { |
| 12 | uint32_t t; |
| 13 | ARMISARegisters *isar = &cpu->isar; |
| 14 | |
| 15 | /* Add additional features supported by QEMU */ |
| 16 | t = GET_IDREG(isar, ID_ISAR5); |
| 17 | t = FIELD_DP32(t, ID_ISAR5, AES, 2); /* FEAT_PMULL */ |
| 18 | t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); /* FEAT_SHA1 */ |
| 19 | t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); /* FEAT_SHA256 */ |
| 20 | t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); |
| 21 | t = FIELD_DP32(t, ID_ISAR5, RDM, 1); /* FEAT_RDM */ |
| 22 | t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); /* FEAT_FCMA */ |
| 23 | SET_IDREG(isar, ID_ISAR5, t); |
| 24 | |
| 25 | t = GET_IDREG(isar, ID_ISAR6); |
| 26 | t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); /* FEAT_JSCVT */ |
| 27 | t = FIELD_DP32(t, ID_ISAR6, DP, 1); /* Feat_DotProd */ |
| 28 | t = FIELD_DP32(t, ID_ISAR6, FHM, 1); /* FEAT_FHM */ |
| 29 | t = FIELD_DP32(t, ID_ISAR6, SB, 1); /* FEAT_SB */ |
| 30 | t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); /* FEAT_SPECRES */ |
| 31 | t = FIELD_DP32(t, ID_ISAR6, BF16, 1); /* FEAT_AA32BF16 */ |
| 32 | t = FIELD_DP32(t, ID_ISAR6, I8MM, 1); /* FEAT_AA32I8MM */ |
| 33 | SET_IDREG(isar, ID_ISAR6, t); |
| 34 | |
| 35 | t = cpu->isar.mvfr1; |
| 36 | t = FIELD_DP32(t, MVFR1, FPHP, 3); /* FEAT_FP16 */ |
| 37 | t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* FEAT_FP16 */ |
| 38 | cpu->isar.mvfr1 = t; |
| 39 | |
| 40 | t = cpu->isar.mvfr2; |
| 41 | t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ |
| 42 | t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ |
| 43 | cpu->isar.mvfr2 = t; |
| 44 | |
| 45 | FIELD_DP32_IDREG(isar, ID_MMFR3, PAN, 2); /* FEAT_PAN2 */ |
| 46 | |
| 47 | t = GET_IDREG(isar, ID_MMFR4); |
| 48 | t = FIELD_DP32(t, ID_MMFR4, HPDS, 2); /* FEAT_HPDS2 */ |
| 49 | t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ |
| 50 | t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* FEAT_TTCNP */ |
| 51 | t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* FEAT_XNX */ |
| 52 | t = FIELD_DP32(t, ID_MMFR4, EVT, 2); /* FEAT_EVT2 */ |
| 53 | SET_IDREG(isar, ID_MMFR4, t); |
| 54 | |
| 55 | FIELD_DP32_IDREG(isar, ID_MMFR5, ETS, 2); /* FEAT_ETS2 */ |
| 56 | |
| 57 | t = GET_IDREG(isar, ID_PFR0); |
| 58 | t = FIELD_DP32(t, ID_PFR0, CSV2, 2); /* FEAT_CSV2 */ |
| 59 | t = FIELD_DP32(t, ID_PFR0, DIT, 1); /* FEAT_DIT */ |
| 60 | t = FIELD_DP32(t, ID_PFR0, RAS, 1); /* FEAT_RAS */ |
| 61 | SET_IDREG(isar, ID_PFR0, t); |
| 62 | |
| 63 | t = GET_IDREG(isar, ID_PFR2); |
| 64 | t = FIELD_DP32(t, ID_PFR2, CSV3, 1); /* FEAT_CSV3 */ |
| 65 | t = FIELD_DP32(t, ID_PFR2, SSBS, 1); /* FEAT_SSBS */ |
| 66 | SET_IDREG(isar, ID_PFR2, t); |
| 67 | |
| 68 | t = GET_IDREG(isar, ID_DFR0); |
| 69 | t = FIELD_DP32(t, ID_DFR0, COPDBG, 10); /* FEAT_Debugv8p8 */ |
| 70 | t = FIELD_DP32(t, ID_DFR0, COPSDBG, 10); /* FEAT_Debugv8p8 */ |
| 71 | t = FIELD_DP32(t, ID_DFR0, PERFMON, 6); /* FEAT_PMUv3p5 */ |
| 72 | SET_IDREG(isar, ID_DFR0, t); |
| 73 | |
| 74 | /* Debug ID registers. */ |
| 75 | |
| 76 | /* Bit[15] is RES1, Bit[13] and Bits[11:0] are RES0. */ |
| 77 | t = 0x00008000; |
| 78 | t = FIELD_DP32(t, DBGDIDR, SE_IMP, 1); |
| 79 | t = FIELD_DP32(t, DBGDIDR, NSUHD_IMP, 1); |
| 80 | t = FIELD_DP32(t, DBGDIDR, VERSION, 10); /* FEAT_Debugv8p8 */ |
| 81 | t = FIELD_DP32(t, DBGDIDR, CTX_CMPS, 1); |
| 82 | t = FIELD_DP32(t, DBGDIDR, BRPS, 5); |
| 83 | t = FIELD_DP32(t, DBGDIDR, WRPS, 3); |
| 84 | cpu->isar.dbgdidr = t; |
| 85 | |
| 86 | t = 0; |
| 87 | t = FIELD_DP32(t, DBGDEVID, PCSAMPLE, 3); |
| 88 | t = FIELD_DP32(t, DBGDEVID, WPADDRMASK, 1); |
| 89 | t = FIELD_DP32(t, DBGDEVID, BPADDRMASK, 15); |
| 90 | t = FIELD_DP32(t, DBGDEVID, VECTORCATCH, 0); |
| 91 | t = FIELD_DP32(t, DBGDEVID, VIRTEXTNS, 1); |
| 92 | t = FIELD_DP32(t, DBGDEVID, DOUBLELOCK, 1); |
| 93 | t = FIELD_DP32(t, DBGDEVID, AUXREGS, 0); |
| 94 | t = FIELD_DP32(t, DBGDEVID, CIDMASK, 0); |
| 95 | cpu->isar.dbgdevid = t; |
| 96 | |
| 97 | /* Bits[31:4] are RES0. */ |
| 98 | t = 0; |
| 99 | t = FIELD_DP32(t, DBGDEVID1, PCSROFFSET, 2); |
| 100 | cpu->isar.dbgdevid1 = t; |
| 101 | |
| 102 | FIELD_DP32_IDREG(isar, ID_DFR1, HPMN0, 1); /* FEAT_HPMN0 */ |
| 103 | } |
| 104 | |
| 105 | void aarch32_max_v8_tcg_initfn(Object *obj) |
| 106 | { |
| 107 | ARMCPU *cpu = ARM_CPU(obj); |
| 108 | |
| 109 | aarch64_aa32_a57_init(cpu, false); |
| 110 | aa32_max_features(cpu); |
| 111 | #ifdef CONFIG_USER_ONLY |
| 112 | /* |
| 113 | * Break with true ARMv8 and add back old-style VFP short-vector |
| 114 | * support. Only do this for user-mode, where -cpu max is the default, |
| 115 | * so that older v6 and v7 programs are more likely to work without |
| 116 | * adjustment. |
| 117 | */ |
| 118 | cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); |
| 119 | #endif |
| 120 | } |
| 121 | |
| 122 | static void cpu_max_v8_register_type(void) |
| 123 | { |
| 124 | static const ARMCPUInfo max_v8[2] = { |
| 125 | { .name = "max-v8", .initfn = aarch32_max_v8_tcg_initfn }, |
| 126 | { .name = "max-v8", .initfn = aarch64_max_v8_tcg_initfn }, |
| 127 | }; |
| 128 | arm_cpu_register(&max_v8[target_aarch64()]); |
| 129 | } |
| 130 | type_init(cpu_max_v8_register_type) |