]>
Commit | Line | Data |
---|---|---|
d14d42f1 PM |
1 | /* |
2 | * QEMU AArch64 CPU | |
3 | * | |
4 | * Copyright (c) 2013 Linaro Ltd | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version 2 | |
9 | * of the License, or (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, see | |
18 | * <http://www.gnu.org/licenses/gpl-2.0.html> | |
19 | */ | |
20 | ||
74c21bd0 | 21 | #include "qemu/osdep.h" |
da34e65c | 22 | #include "qapi/error.h" |
d14d42f1 | 23 | #include "cpu.h" |
0b8fa32f | 24 | #include "qemu/module.h" |
d14d42f1 PM |
25 | #if !defined(CONFIG_USER_ONLY) |
26 | #include "hw/loader.h" | |
27 | #endif | |
d14d42f1 | 28 | #include "sysemu/kvm.h" |
bab52d4b | 29 | #include "kvm_arm.h" |
adf92eab | 30 | #include "qapi/visitor.h" |
d14d42f1 PM |
31 | |
32 | static inline void set_feature(CPUARMState *env, int feature) | |
33 | { | |
34 | env->features |= 1ULL << feature; | |
35 | } | |
36 | ||
fb8d6c24 GB |
37 | static inline void unset_feature(CPUARMState *env, int feature) |
38 | { | |
39 | env->features &= ~(1ULL << feature); | |
40 | } | |
41 | ||
377a44ec | 42 | #ifndef CONFIG_USER_ONLY |
ee804264 | 43 | static uint64_t a57_a53_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) |
377a44ec | 44 | { |
2fc0cc0e | 45 | ARMCPU *cpu = env_archcpu(env); |
f9a69711 AF |
46 | |
47 | /* Number of cores is in [25:24]; otherwise we RAZ */ | |
48 | return (cpu->core_count - 1) << 24; | |
377a44ec PM |
49 | } |
50 | #endif | |
51 | ||
f11b452b | 52 | static const ARMCPRegInfo cortex_a72_a57_a53_cp_reginfo[] = { |
377a44ec PM |
53 | #ifndef CONFIG_USER_ONLY |
54 | { .name = "L2CTLR_EL1", .state = ARM_CP_STATE_AA64, | |
55 | .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 2, | |
ee804264 | 56 | .access = PL1_RW, .readfn = a57_a53_l2ctlr_read, |
377a44ec PM |
57 | .writefn = arm_cp_write_ignore }, |
58 | { .name = "L2CTLR", | |
59 | .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 2, | |
ee804264 | 60 | .access = PL1_RW, .readfn = a57_a53_l2ctlr_read, |
377a44ec PM |
61 | .writefn = arm_cp_write_ignore }, |
62 | #endif | |
63 | { .name = "L2ECTLR_EL1", .state = ARM_CP_STATE_AA64, | |
64 | .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 3, | |
65 | .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, | |
66 | { .name = "L2ECTLR", | |
67 | .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 3, | |
68 | .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, | |
69 | { .name = "L2ACTLR", .state = ARM_CP_STATE_BOTH, | |
70 | .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 0, .opc2 = 0, | |
71 | .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, | |
72 | { .name = "CPUACTLR_EL1", .state = ARM_CP_STATE_AA64, | |
73 | .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 0, | |
74 | .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, | |
75 | { .name = "CPUACTLR", | |
76 | .cp = 15, .opc1 = 0, .crm = 15, | |
77 | .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, | |
78 | { .name = "CPUECTLR_EL1", .state = ARM_CP_STATE_AA64, | |
79 | .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 1, | |
80 | .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, | |
81 | { .name = "CPUECTLR", | |
82 | .cp = 15, .opc1 = 1, .crm = 15, | |
83 | .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, | |
84 | { .name = "CPUMERRSR_EL1", .state = ARM_CP_STATE_AA64, | |
85 | .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 2, | |
86 | .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, | |
87 | { .name = "CPUMERRSR", | |
88 | .cp = 15, .opc1 = 2, .crm = 15, | |
89 | .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, | |
90 | { .name = "L2MERRSR_EL1", .state = ARM_CP_STATE_AA64, | |
91 | .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 3, | |
92 | .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, | |
93 | { .name = "L2MERRSR", | |
94 | .cp = 15, .opc1 = 3, .crm = 15, | |
95 | .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 }, | |
96 | REGINFO_SENTINEL | |
97 | }; | |
98 | ||
cb1fa941 PM |
99 | static void aarch64_a57_initfn(Object *obj) |
100 | { | |
101 | ARMCPU *cpu = ARM_CPU(obj); | |
102 | ||
0458b7b5 | 103 | cpu->dtb_compatible = "arm,cortex-a57"; |
cb1fa941 | 104 | set_feature(&cpu->env, ARM_FEATURE_V8); |
cb1fa941 PM |
105 | set_feature(&cpu->env, ARM_FEATURE_NEON); |
106 | set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); | |
107 | set_feature(&cpu->env, ARM_FEATURE_AARCH64); | |
f318cec6 | 108 | set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); |
c25bd18a | 109 | set_feature(&cpu->env, ARM_FEATURE_EL2); |
3ad901bc | 110 | set_feature(&cpu->env, ARM_FEATURE_EL3); |
929e754d | 111 | set_feature(&cpu->env, ARM_FEATURE_PMU); |
cb1fa941 PM |
112 | cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57; |
113 | cpu->midr = 0x411fd070; | |
13b72b2b | 114 | cpu->revidr = 0x00000000; |
cb1fa941 | 115 | cpu->reset_fpsid = 0x41034070; |
47576b94 RH |
116 | cpu->isar.mvfr0 = 0x10110222; |
117 | cpu->isar.mvfr1 = 0x12111111; | |
118 | cpu->isar.mvfr2 = 0x00000043; | |
cb1fa941 PM |
119 | cpu->ctr = 0x8444c004; |
120 | cpu->reset_sctlr = 0x00c50838; | |
121 | cpu->id_pfr0 = 0x00000131; | |
122 | cpu->id_pfr1 = 0x00011011; | |
a6179538 | 123 | cpu->isar.id_dfr0 = 0x03010066; |
cb1fa941 | 124 | cpu->id_afr0 = 0x00000000; |
10054016 PM |
125 | cpu->isar.id_mmfr0 = 0x10101105; |
126 | cpu->isar.id_mmfr1 = 0x40000000; | |
127 | cpu->isar.id_mmfr2 = 0x01260000; | |
128 | cpu->isar.id_mmfr3 = 0x02102211; | |
47576b94 RH |
129 | cpu->isar.id_isar0 = 0x02101110; |
130 | cpu->isar.id_isar1 = 0x13112111; | |
131 | cpu->isar.id_isar2 = 0x21232042; | |
132 | cpu->isar.id_isar3 = 0x01112131; | |
133 | cpu->isar.id_isar4 = 0x00011142; | |
134 | cpu->isar.id_isar5 = 0x00011121; | |
135 | cpu->isar.id_isar6 = 0; | |
136 | cpu->isar.id_aa64pfr0 = 0x00002222; | |
2a609df8 | 137 | cpu->isar.id_aa64dfr0 = 0x10305106; |
47576b94 | 138 | cpu->isar.id_aa64isar0 = 0x00011120; |
3dc91ddb | 139 | cpu->isar.id_aa64mmfr0 = 0x00001124; |
4426d361 | 140 | cpu->isar.dbgdidr = 0x3516d000; |
cb1fa941 PM |
141 | cpu->clidr = 0x0a200023; |
142 | cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ | |
143 | cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ | |
144 | cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */ | |
145 | cpu->dcz_blocksize = 4; /* 64 bytes */ | |
e45868a3 PM |
146 | cpu->gic_num_lrs = 4; |
147 | cpu->gic_vpribits = 5; | |
148 | cpu->gic_vprebits = 5; | |
f11b452b | 149 | define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); |
cb1fa941 PM |
150 | } |
151 | ||
e3531026 PC |
152 | static void aarch64_a53_initfn(Object *obj) |
153 | { | |
154 | ARMCPU *cpu = ARM_CPU(obj); | |
155 | ||
156 | cpu->dtb_compatible = "arm,cortex-a53"; | |
157 | set_feature(&cpu->env, ARM_FEATURE_V8); | |
e3531026 PC |
158 | set_feature(&cpu->env, ARM_FEATURE_NEON); |
159 | set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); | |
160 | set_feature(&cpu->env, ARM_FEATURE_AARCH64); | |
161 | set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); | |
c25bd18a | 162 | set_feature(&cpu->env, ARM_FEATURE_EL2); |
3ad901bc | 163 | set_feature(&cpu->env, ARM_FEATURE_EL3); |
929e754d | 164 | set_feature(&cpu->env, ARM_FEATURE_PMU); |
7525465e | 165 | cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53; |
e3531026 | 166 | cpu->midr = 0x410fd034; |
13b72b2b | 167 | cpu->revidr = 0x00000000; |
e3531026 | 168 | cpu->reset_fpsid = 0x41034070; |
47576b94 RH |
169 | cpu->isar.mvfr0 = 0x10110222; |
170 | cpu->isar.mvfr1 = 0x12111111; | |
171 | cpu->isar.mvfr2 = 0x00000043; | |
e3531026 PC |
172 | cpu->ctr = 0x84448004; /* L1Ip = VIPT */ |
173 | cpu->reset_sctlr = 0x00c50838; | |
174 | cpu->id_pfr0 = 0x00000131; | |
175 | cpu->id_pfr1 = 0x00011011; | |
a6179538 | 176 | cpu->isar.id_dfr0 = 0x03010066; |
e3531026 | 177 | cpu->id_afr0 = 0x00000000; |
10054016 PM |
178 | cpu->isar.id_mmfr0 = 0x10101105; |
179 | cpu->isar.id_mmfr1 = 0x40000000; | |
180 | cpu->isar.id_mmfr2 = 0x01260000; | |
181 | cpu->isar.id_mmfr3 = 0x02102211; | |
47576b94 RH |
182 | cpu->isar.id_isar0 = 0x02101110; |
183 | cpu->isar.id_isar1 = 0x13112111; | |
184 | cpu->isar.id_isar2 = 0x21232042; | |
185 | cpu->isar.id_isar3 = 0x01112131; | |
186 | cpu->isar.id_isar4 = 0x00011142; | |
187 | cpu->isar.id_isar5 = 0x00011121; | |
188 | cpu->isar.id_isar6 = 0; | |
189 | cpu->isar.id_aa64pfr0 = 0x00002222; | |
2a609df8 | 190 | cpu->isar.id_aa64dfr0 = 0x10305106; |
47576b94 | 191 | cpu->isar.id_aa64isar0 = 0x00011120; |
3dc91ddb | 192 | cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */ |
4426d361 | 193 | cpu->isar.dbgdidr = 0x3516d000; |
e3531026 PC |
194 | cpu->clidr = 0x0a200023; |
195 | cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ | |
196 | cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */ | |
197 | cpu->ccsidr[2] = 0x707fe07a; /* 1024KB L2 cache */ | |
198 | cpu->dcz_blocksize = 4; /* 64 bytes */ | |
e45868a3 PM |
199 | cpu->gic_num_lrs = 4; |
200 | cpu->gic_vpribits = 5; | |
201 | cpu->gic_vprebits = 5; | |
f11b452b EI |
202 | define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); |
203 | } | |
204 | ||
205 | static void aarch64_a72_initfn(Object *obj) | |
206 | { | |
207 | ARMCPU *cpu = ARM_CPU(obj); | |
208 | ||
209 | cpu->dtb_compatible = "arm,cortex-a72"; | |
210 | set_feature(&cpu->env, ARM_FEATURE_V8); | |
f11b452b EI |
211 | set_feature(&cpu->env, ARM_FEATURE_NEON); |
212 | set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); | |
213 | set_feature(&cpu->env, ARM_FEATURE_AARCH64); | |
214 | set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); | |
f11b452b EI |
215 | set_feature(&cpu->env, ARM_FEATURE_EL2); |
216 | set_feature(&cpu->env, ARM_FEATURE_EL3); | |
217 | set_feature(&cpu->env, ARM_FEATURE_PMU); | |
218 | cpu->midr = 0x410fd083; | |
219 | cpu->revidr = 0x00000000; | |
220 | cpu->reset_fpsid = 0x41034080; | |
47576b94 RH |
221 | cpu->isar.mvfr0 = 0x10110222; |
222 | cpu->isar.mvfr1 = 0x12111111; | |
223 | cpu->isar.mvfr2 = 0x00000043; | |
f11b452b EI |
224 | cpu->ctr = 0x8444c004; |
225 | cpu->reset_sctlr = 0x00c50838; | |
226 | cpu->id_pfr0 = 0x00000131; | |
227 | cpu->id_pfr1 = 0x00011011; | |
a6179538 | 228 | cpu->isar.id_dfr0 = 0x03010066; |
f11b452b | 229 | cpu->id_afr0 = 0x00000000; |
10054016 PM |
230 | cpu->isar.id_mmfr0 = 0x10201105; |
231 | cpu->isar.id_mmfr1 = 0x40000000; | |
232 | cpu->isar.id_mmfr2 = 0x01260000; | |
233 | cpu->isar.id_mmfr3 = 0x02102211; | |
47576b94 RH |
234 | cpu->isar.id_isar0 = 0x02101110; |
235 | cpu->isar.id_isar1 = 0x13112111; | |
236 | cpu->isar.id_isar2 = 0x21232042; | |
237 | cpu->isar.id_isar3 = 0x01112131; | |
238 | cpu->isar.id_isar4 = 0x00011142; | |
239 | cpu->isar.id_isar5 = 0x00011121; | |
240 | cpu->isar.id_aa64pfr0 = 0x00002222; | |
2a609df8 | 241 | cpu->isar.id_aa64dfr0 = 0x10305106; |
47576b94 | 242 | cpu->isar.id_aa64isar0 = 0x00011120; |
3dc91ddb | 243 | cpu->isar.id_aa64mmfr0 = 0x00001124; |
4426d361 | 244 | cpu->isar.dbgdidr = 0x3516d000; |
f11b452b EI |
245 | cpu->clidr = 0x0a200023; |
246 | cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ | |
247 | cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ | |
248 | cpu->ccsidr[2] = 0x707fe07a; /* 1MB L2 cache */ | |
249 | cpu->dcz_blocksize = 4; /* 64 bytes */ | |
250 | cpu->gic_num_lrs = 4; | |
251 | cpu->gic_vpribits = 5; | |
252 | cpu->gic_vprebits = 5; | |
253 | define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); | |
e3531026 PC |
254 | } |
255 | ||
0df9142d AJ |
256 | void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) |
257 | { | |
258 | /* | |
259 | * If any vector lengths are explicitly enabled with sve<N> properties, | |
260 | * then all other lengths are implicitly disabled. If sve-max-vq is | |
261 | * specified then it is the same as explicitly enabling all lengths | |
262 | * up to and including the specified maximum, which means all larger | |
263 | * lengths will be implicitly disabled. If no sve<N> properties | |
264 | * are enabled and sve-max-vq is not specified, then all lengths not | |
265 | * explicitly disabled will be enabled. Additionally, all power-of-two | |
266 | * vector lengths less than the maximum enabled length will be | |
267 | * automatically enabled and all vector lengths larger than the largest | |
268 | * disabled power-of-two vector length will be automatically disabled. | |
269 | * Errors are generated if the user provided input that interferes with | |
270 | * any of the above. Finally, if SVE is not disabled, then at least one | |
271 | * vector length must be enabled. | |
272 | */ | |
6fa8a379 | 273 | DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ); |
0df9142d AJ |
274 | DECLARE_BITMAP(tmp, ARM_MAX_VQ); |
275 | uint32_t vq, max_vq = 0; | |
276 | ||
6fa8a379 AJ |
277 | /* Collect the set of vector lengths supported by KVM. */ |
278 | bitmap_zero(kvm_supported, ARM_MAX_VQ); | |
279 | if (kvm_enabled() && kvm_arm_sve_supported(CPU(cpu))) { | |
280 | kvm_arm_sve_get_vls(CPU(cpu), kvm_supported); | |
281 | } else if (kvm_enabled()) { | |
282 | assert(!cpu_isar_feature(aa64_sve, cpu)); | |
283 | } | |
284 | ||
0df9142d AJ |
285 | /* |
286 | * Process explicit sve<N> properties. | |
287 | * From the properties, sve_vq_map<N> implies sve_vq_init<N>. | |
288 | * Check first for any sve<N> enabled. | |
289 | */ | |
290 | if (!bitmap_empty(cpu->sve_vq_map, ARM_MAX_VQ)) { | |
291 | max_vq = find_last_bit(cpu->sve_vq_map, ARM_MAX_VQ) + 1; | |
292 | ||
293 | if (cpu->sve_max_vq && max_vq > cpu->sve_max_vq) { | |
294 | error_setg(errp, "cannot enable sve%d", max_vq * 128); | |
295 | error_append_hint(errp, "sve%d is larger than the maximum vector " | |
296 | "length, sve-max-vq=%d (%d bits)\n", | |
297 | max_vq * 128, cpu->sve_max_vq, | |
298 | cpu->sve_max_vq * 128); | |
299 | return; | |
300 | } | |
301 | ||
6fa8a379 AJ |
302 | if (kvm_enabled()) { |
303 | /* | |
304 | * For KVM we have to automatically enable all supported unitialized | |
305 | * lengths, even when the smaller lengths are not all powers-of-two. | |
306 | */ | |
307 | bitmap_andnot(tmp, kvm_supported, cpu->sve_vq_init, max_vq); | |
308 | bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq); | |
309 | } else { | |
310 | /* Propagate enabled bits down through required powers-of-two. */ | |
311 | for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) { | |
312 | if (!test_bit(vq - 1, cpu->sve_vq_init)) { | |
313 | set_bit(vq - 1, cpu->sve_vq_map); | |
314 | } | |
0df9142d AJ |
315 | } |
316 | } | |
317 | } else if (cpu->sve_max_vq == 0) { | |
318 | /* | |
319 | * No explicit bits enabled, and no implicit bits from sve-max-vq. | |
320 | */ | |
321 | if (!cpu_isar_feature(aa64_sve, cpu)) { | |
322 | /* SVE is disabled and so are all vector lengths. Good. */ | |
323 | return; | |
324 | } | |
325 | ||
6fa8a379 AJ |
326 | if (kvm_enabled()) { |
327 | /* Disabling a supported length disables all larger lengths. */ | |
328 | for (vq = 1; vq <= ARM_MAX_VQ; ++vq) { | |
329 | if (test_bit(vq - 1, cpu->sve_vq_init) && | |
330 | test_bit(vq - 1, kvm_supported)) { | |
331 | break; | |
332 | } | |
333 | } | |
334 | max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ; | |
335 | bitmap_andnot(cpu->sve_vq_map, kvm_supported, | |
336 | cpu->sve_vq_init, max_vq); | |
337 | if (max_vq == 0 || bitmap_empty(cpu->sve_vq_map, max_vq)) { | |
338 | error_setg(errp, "cannot disable sve%d", vq * 128); | |
339 | error_append_hint(errp, "Disabling sve%d results in all " | |
340 | "vector lengths being disabled.\n", | |
341 | vq * 128); | |
342 | error_append_hint(errp, "With SVE enabled, at least one " | |
343 | "vector length must be enabled.\n"); | |
344 | return; | |
345 | } | |
346 | } else { | |
347 | /* Disabling a power-of-two disables all larger lengths. */ | |
348 | if (test_bit(0, cpu->sve_vq_init)) { | |
349 | error_setg(errp, "cannot disable sve128"); | |
350 | error_append_hint(errp, "Disabling sve128 results in all " | |
351 | "vector lengths being disabled.\n"); | |
352 | error_append_hint(errp, "With SVE enabled, at least one " | |
353 | "vector length must be enabled.\n"); | |
354 | return; | |
355 | } | |
356 | for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) { | |
357 | if (test_bit(vq - 1, cpu->sve_vq_init)) { | |
358 | break; | |
359 | } | |
0df9142d | 360 | } |
6fa8a379 AJ |
361 | max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ; |
362 | bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq); | |
0df9142d | 363 | } |
0df9142d | 364 | |
0df9142d AJ |
365 | max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1; |
366 | } | |
367 | ||
368 | /* | |
369 | * Process the sve-max-vq property. | |
370 | * Note that we know from the above that no bit above | |
371 | * sve-max-vq is currently set. | |
372 | */ | |
373 | if (cpu->sve_max_vq != 0) { | |
374 | max_vq = cpu->sve_max_vq; | |
375 | ||
376 | if (!test_bit(max_vq - 1, cpu->sve_vq_map) && | |
377 | test_bit(max_vq - 1, cpu->sve_vq_init)) { | |
378 | error_setg(errp, "cannot disable sve%d", max_vq * 128); | |
379 | error_append_hint(errp, "The maximum vector length must be " | |
380 | "enabled, sve-max-vq=%d (%d bits)\n", | |
381 | max_vq, max_vq * 128); | |
382 | return; | |
383 | } | |
384 | ||
385 | /* Set all bits not explicitly set within sve-max-vq. */ | |
386 | bitmap_complement(tmp, cpu->sve_vq_init, max_vq); | |
387 | bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq); | |
388 | } | |
389 | ||
390 | /* | |
391 | * We should know what max-vq is now. Also, as we're done | |
392 | * manipulating sve-vq-map, we ensure any bits above max-vq | |
393 | * are clear, just in case anybody looks. | |
394 | */ | |
395 | assert(max_vq != 0); | |
396 | bitmap_clear(cpu->sve_vq_map, max_vq, ARM_MAX_VQ - max_vq); | |
397 | ||
6fa8a379 AJ |
398 | if (kvm_enabled()) { |
399 | /* Ensure the set of lengths matches what KVM supports. */ | |
400 | bitmap_xor(tmp, cpu->sve_vq_map, kvm_supported, max_vq); | |
401 | if (!bitmap_empty(tmp, max_vq)) { | |
402 | vq = find_last_bit(tmp, max_vq) + 1; | |
403 | if (test_bit(vq - 1, cpu->sve_vq_map)) { | |
404 | if (cpu->sve_max_vq) { | |
405 | error_setg(errp, "cannot set sve-max-vq=%d", | |
406 | cpu->sve_max_vq); | |
407 | error_append_hint(errp, "This KVM host does not support " | |
408 | "the vector length %d-bits.\n", | |
409 | vq * 128); | |
410 | error_append_hint(errp, "It may not be possible to use " | |
411 | "sve-max-vq with this KVM host. Try " | |
412 | "using only sve<N> properties.\n"); | |
413 | } else { | |
414 | error_setg(errp, "cannot enable sve%d", vq * 128); | |
415 | error_append_hint(errp, "This KVM host does not support " | |
416 | "the vector length %d-bits.\n", | |
417 | vq * 128); | |
418 | } | |
419 | } else { | |
420 | error_setg(errp, "cannot disable sve%d", vq * 128); | |
421 | error_append_hint(errp, "The KVM host requires all " | |
422 | "supported vector lengths smaller " | |
423 | "than %d bits to also be enabled.\n", | |
424 | max_vq * 128); | |
425 | } | |
0df9142d AJ |
426 | return; |
427 | } | |
6fa8a379 AJ |
428 | } else { |
429 | /* Ensure all required powers-of-two are enabled. */ | |
430 | for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) { | |
431 | if (!test_bit(vq - 1, cpu->sve_vq_map)) { | |
432 | error_setg(errp, "cannot disable sve%d", vq * 128); | |
433 | error_append_hint(errp, "sve%d is required as it " | |
434 | "is a power-of-two length smaller than " | |
435 | "the maximum, sve%d\n", | |
436 | vq * 128, max_vq * 128); | |
437 | return; | |
438 | } | |
439 | } | |
0df9142d AJ |
440 | } |
441 | ||
442 | /* | |
443 | * Now that we validated all our vector lengths, the only question | |
444 | * left to answer is if we even want SVE at all. | |
445 | */ | |
446 | if (!cpu_isar_feature(aa64_sve, cpu)) { | |
447 | error_setg(errp, "cannot enable sve%d", max_vq * 128); | |
448 | error_append_hint(errp, "SVE must be enabled to enable vector " | |
449 | "lengths.\n"); | |
450 | error_append_hint(errp, "Add sve=on to the CPU property list.\n"); | |
451 | return; | |
452 | } | |
453 | ||
454 | /* From now on sve_max_vq is the actual maximum supported length. */ | |
455 | cpu->sve_max_vq = max_vq; | |
456 | } | |
457 | ||
73234775 AJ |
458 | static void cpu_max_get_sve_max_vq(Object *obj, Visitor *v, const char *name, |
459 | void *opaque, Error **errp) | |
adf92eab RH |
460 | { |
461 | ARMCPU *cpu = ARM_CPU(obj); | |
73234775 AJ |
462 | uint32_t value; |
463 | ||
464 | /* All vector lengths are disabled when SVE is off. */ | |
465 | if (!cpu_isar_feature(aa64_sve, cpu)) { | |
466 | value = 0; | |
467 | } else { | |
468 | value = cpu->sve_max_vq; | |
469 | } | |
470 | visit_type_uint32(v, name, &value, errp); | |
adf92eab RH |
471 | } |
472 | ||
73234775 AJ |
473 | static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name, |
474 | void *opaque, Error **errp) | |
adf92eab RH |
475 | { |
476 | ARMCPU *cpu = ARM_CPU(obj); | |
477 | Error *err = NULL; | |
6fa8a379 AJ |
478 | uint32_t max_vq; |
479 | ||
480 | visit_type_uint32(v, name, &max_vq, &err); | |
481 | if (err) { | |
482 | error_propagate(errp, err); | |
483 | return; | |
484 | } | |
adf92eab | 485 | |
6fa8a379 AJ |
486 | if (kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) { |
487 | error_setg(errp, "cannot set sve-max-vq"); | |
488 | error_append_hint(errp, "SVE not supported by KVM on this host\n"); | |
489 | return; | |
490 | } | |
adf92eab | 491 | |
6fa8a379 AJ |
492 | if (max_vq == 0 || max_vq > ARM_MAX_VQ) { |
493 | error_setg(errp, "unsupported SVE vector length"); | |
494 | error_append_hint(errp, "Valid sve-max-vq in range [1-%d]\n", | |
adf92eab | 495 | ARM_MAX_VQ); |
6fa8a379 | 496 | return; |
adf92eab | 497 | } |
6fa8a379 AJ |
498 | |
499 | cpu->sve_max_vq = max_vq; | |
adf92eab RH |
500 | } |
501 | ||
0df9142d AJ |
502 | static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name, |
503 | void *opaque, Error **errp) | |
504 | { | |
505 | ARMCPU *cpu = ARM_CPU(obj); | |
506 | uint32_t vq = atoi(&name[3]) / 128; | |
507 | bool value; | |
508 | ||
509 | /* All vector lengths are disabled when SVE is off. */ | |
510 | if (!cpu_isar_feature(aa64_sve, cpu)) { | |
511 | value = false; | |
512 | } else { | |
513 | value = test_bit(vq - 1, cpu->sve_vq_map); | |
514 | } | |
515 | visit_type_bool(v, name, &value, errp); | |
516 | } | |
517 | ||
518 | static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name, | |
519 | void *opaque, Error **errp) | |
520 | { | |
521 | ARMCPU *cpu = ARM_CPU(obj); | |
522 | uint32_t vq = atoi(&name[3]) / 128; | |
523 | Error *err = NULL; | |
524 | bool value; | |
525 | ||
526 | visit_type_bool(v, name, &value, &err); | |
527 | if (err) { | |
528 | error_propagate(errp, err); | |
529 | return; | |
530 | } | |
531 | ||
6fa8a379 AJ |
532 | if (value && kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) { |
533 | error_setg(errp, "cannot enable %s", name); | |
534 | error_append_hint(errp, "SVE not supported by KVM on this host\n"); | |
535 | return; | |
536 | } | |
537 | ||
0df9142d AJ |
538 | if (value) { |
539 | set_bit(vq - 1, cpu->sve_vq_map); | |
540 | } else { | |
541 | clear_bit(vq - 1, cpu->sve_vq_map); | |
542 | } | |
543 | set_bit(vq - 1, cpu->sve_vq_init); | |
544 | } | |
545 | ||
73234775 AJ |
546 | static void cpu_arm_get_sve(Object *obj, Visitor *v, const char *name, |
547 | void *opaque, Error **errp) | |
548 | { | |
549 | ARMCPU *cpu = ARM_CPU(obj); | |
550 | bool value = cpu_isar_feature(aa64_sve, cpu); | |
551 | ||
552 | visit_type_bool(v, name, &value, errp); | |
553 | } | |
554 | ||
555 | static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name, | |
556 | void *opaque, Error **errp) | |
557 | { | |
558 | ARMCPU *cpu = ARM_CPU(obj); | |
559 | Error *err = NULL; | |
560 | bool value; | |
561 | uint64_t t; | |
562 | ||
563 | visit_type_bool(v, name, &value, &err); | |
564 | if (err) { | |
565 | error_propagate(errp, err); | |
566 | return; | |
567 | } | |
568 | ||
14e99e0f AJ |
569 | if (value && kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) { |
570 | error_setg(errp, "'sve' feature not supported by KVM on this host"); | |
571 | return; | |
572 | } | |
573 | ||
73234775 AJ |
574 | t = cpu->isar.id_aa64pfr0; |
575 | t = FIELD_DP64(t, ID_AA64PFR0, SVE, value); | |
576 | cpu->isar.id_aa64pfr0 = t; | |
577 | } | |
578 | ||
87014c6b AJ |
579 | void aarch64_add_sve_properties(Object *obj) |
580 | { | |
581 | uint32_t vq; | |
582 | ||
583 | object_property_add(obj, "sve", "bool", cpu_arm_get_sve, | |
584 | cpu_arm_set_sve, NULL, NULL, &error_fatal); | |
585 | ||
586 | for (vq = 1; vq <= ARM_MAX_VQ; ++vq) { | |
587 | char name[8]; | |
588 | sprintf(name, "sve%d", vq * 128); | |
589 | object_property_add(obj, name, "bool", cpu_arm_get_sve_vq, | |
590 | cpu_arm_set_sve_vq, NULL, NULL, &error_fatal); | |
591 | } | |
592 | } | |
593 | ||
bab52d4b PM |
594 | /* -cpu max: if KVM is enabled, like -cpu host (best possible with this host); |
595 | * otherwise, a CPU with as many features enabled as our emulation supports. | |
596 | * The version of '-cpu max' for qemu-system-arm is defined in cpu.c; | |
597 | * this only needs to handle 64 bits. | |
598 | */ | |
599 | static void aarch64_max_initfn(Object *obj) | |
600 | { | |
601 | ARMCPU *cpu = ARM_CPU(obj); | |
602 | ||
603 | if (kvm_enabled()) { | |
604 | kvm_arm_set_cpu_features_from_host(cpu); | |
dea101a1 | 605 | kvm_arm_add_vcpu_properties(obj); |
bab52d4b | 606 | } else { |
87014c6b | 607 | uint64_t t; |
962fcbf2 | 608 | uint32_t u; |
bab52d4b | 609 | aarch64_a57_initfn(obj); |
962fcbf2 | 610 | |
2bd5f41c AB |
611 | /* |
612 | * Reset MIDR so the guest doesn't mistake our 'max' CPU type for a real | |
613 | * one and try to apply errata workarounds or use impdef features we | |
614 | * don't provide. | |
615 | * An IMPLEMENTER field of 0 means "reserved for software use"; | |
616 | * ARCHITECTURE must be 0xf indicating "v7 or later, check ID registers | |
617 | * to see which features are present"; | |
618 | * the VARIANT, PARTNUM and REVISION fields are all implementation | |
619 | * defined and we choose to define PARTNUM just in case guest | |
620 | * code needs to distinguish this QEMU CPU from other software | |
621 | * implementations, though this shouldn't be needed. | |
622 | */ | |
623 | t = FIELD_DP64(0, MIDR_EL1, IMPLEMENTER, 0); | |
624 | t = FIELD_DP64(t, MIDR_EL1, ARCHITECTURE, 0xf); | |
625 | t = FIELD_DP64(t, MIDR_EL1, PARTNUM, 'Q'); | |
626 | t = FIELD_DP64(t, MIDR_EL1, VARIANT, 0); | |
627 | t = FIELD_DP64(t, MIDR_EL1, REVISION, 0); | |
628 | cpu->midr = t; | |
629 | ||
962fcbf2 RH |
630 | t = cpu->isar.id_aa64isar0; |
631 | t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* AES + PMULL */ | |
632 | t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); | |
633 | t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* SHA512 */ | |
634 | t = FIELD_DP64(t, ID_AA64ISAR0, CRC32, 1); | |
635 | t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 2); | |
636 | t = FIELD_DP64(t, ID_AA64ISAR0, RDM, 1); | |
637 | t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 1); | |
638 | t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); | |
639 | t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 1); | |
640 | t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1); | |
991c0599 | 641 | t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1); |
5ef84f11 | 642 | t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* v8.5-CondM */ |
de390645 | 643 | t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1); |
962fcbf2 RH |
644 | cpu->isar.id_aa64isar0 = t; |
645 | ||
646 | t = cpu->isar.id_aa64isar1; | |
0d57b499 | 647 | t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2); |
6c1f6f27 | 648 | t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); |
962fcbf2 | 649 | t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); |
1ce32e47 RH |
650 | t = FIELD_DP64(t, ID_AA64ISAR1, APA, 1); /* PAuth, architected only */ |
651 | t = FIELD_DP64(t, ID_AA64ISAR1, API, 0); | |
652 | t = FIELD_DP64(t, ID_AA64ISAR1, GPA, 1); | |
653 | t = FIELD_DP64(t, ID_AA64ISAR1, GPI, 0); | |
9888bd1e | 654 | t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); |
cb570bd3 | 655 | t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); |
6bea2563 | 656 | t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); |
a1229109 | 657 | t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* ARMv8.4-RCPC */ |
962fcbf2 RH |
658 | cpu->isar.id_aa64isar1 = t; |
659 | ||
cd208a1c RH |
660 | t = cpu->isar.id_aa64pfr0; |
661 | t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); | |
5763190f RH |
662 | t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); |
663 | t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); | |
cd208a1c RH |
664 | cpu->isar.id_aa64pfr0 = t; |
665 | ||
a15daafa RH |
666 | t = cpu->isar.id_aa64pfr1; |
667 | t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); | |
668 | cpu->isar.id_aa64pfr1 = t; | |
669 | ||
037c13c5 RH |
670 | t = cpu->isar.id_aa64mmfr1; |
671 | t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* HPD */ | |
2d7137c1 | 672 | t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); |
cd3f80ab | 673 | t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1); |
e0fe7309 | 674 | t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* ATS1E1 */ |
dc7a88d0 | 675 | t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* VMID16 */ |
037c13c5 RH |
676 | cpu->isar.id_aa64mmfr1 = t; |
677 | ||
e11f0eb6 RH |
678 | t = cpu->isar.id_aa64mmfr2; |
679 | t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); | |
41a4bf1f | 680 | t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* TTCNP */ |
e11f0eb6 RH |
681 | cpu->isar.id_aa64mmfr2 = t; |
682 | ||
962fcbf2 RH |
683 | /* Replicate the same data to the 32-bit id registers. */ |
684 | u = cpu->isar.id_isar5; | |
685 | u = FIELD_DP32(u, ID_ISAR5, AES, 2); /* AES + PMULL */ | |
686 | u = FIELD_DP32(u, ID_ISAR5, SHA1, 1); | |
687 | u = FIELD_DP32(u, ID_ISAR5, SHA2, 1); | |
688 | u = FIELD_DP32(u, ID_ISAR5, CRC32, 1); | |
689 | u = FIELD_DP32(u, ID_ISAR5, RDM, 1); | |
690 | u = FIELD_DP32(u, ID_ISAR5, VCMA, 1); | |
691 | cpu->isar.id_isar5 = u; | |
692 | ||
693 | u = cpu->isar.id_isar6; | |
6c1f6f27 | 694 | u = FIELD_DP32(u, ID_ISAR6, JSCVT, 1); |
962fcbf2 | 695 | u = FIELD_DP32(u, ID_ISAR6, DP, 1); |
991c0599 | 696 | u = FIELD_DP32(u, ID_ISAR6, FHM, 1); |
9888bd1e | 697 | u = FIELD_DP32(u, ID_ISAR6, SB, 1); |
cb570bd3 | 698 | u = FIELD_DP32(u, ID_ISAR6, SPECRES, 1); |
962fcbf2 RH |
699 | cpu->isar.id_isar6 = u; |
700 | ||
10054016 | 701 | u = cpu->isar.id_mmfr3; |
e0fe7309 | 702 | u = FIELD_DP32(u, ID_MMFR3, PAN, 2); /* ATS1E1 */ |
10054016 | 703 | cpu->isar.id_mmfr3 = u; |
e0fe7309 | 704 | |
f6287c24 | 705 | u = cpu->isar.id_mmfr4; |
dac65ba1 | 706 | u = FIELD_DP32(u, ID_MMFR4, HPDS, 1); /* AA32HPD */ |
f6287c24 | 707 | u = FIELD_DP32(u, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ |
41a4bf1f | 708 | u = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */ |
f6287c24 PM |
709 | cpu->isar.id_mmfr4 = u; |
710 | ||
3bec7844 PM |
711 | u = cpu->isar.id_aa64dfr0; |
712 | u = FIELD_DP64(u, ID_AA64DFR0, PMUVER, 5); /* v8.4-PMU */ | |
713 | cpu->isar.id_aa64dfr0 = u; | |
714 | ||
715 | u = cpu->isar.id_dfr0; | |
716 | u = FIELD_DP32(u, ID_DFR0, PERFMON, 5); /* v8.4-PMU */ | |
717 | cpu->isar.id_dfr0 = u; | |
718 | ||
5763190f RH |
719 | /* |
720 | * FIXME: We do not yet support ARMv8.2-fp16 for AArch32 yet, | |
721 | * so do not set MVFR1.FPHP. Strictly speaking this is not legal, | |
722 | * but it is also not legal to enable SVE without support for FP16, | |
723 | * and enabling SVE in system mode is more useful in the short term. | |
a0032cc5 | 724 | */ |
5763190f RH |
725 | |
726 | #ifdef CONFIG_USER_ONLY | |
a0032cc5 PM |
727 | /* For usermode -cpu max we can use a larger and more efficient DCZ |
728 | * blocksize since we don't have to follow what the hardware does. | |
bab52d4b | 729 | */ |
a0032cc5 PM |
730 | cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */ |
731 | cpu->dcz_blocksize = 7; /* 512 bytes */ | |
732 | #endif | |
bab52d4b | 733 | } |
14e99e0f | 734 | |
87014c6b | 735 | aarch64_add_sve_properties(obj); |
6fa8a379 AJ |
736 | object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq, |
737 | cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal); | |
bab52d4b PM |
738 | } |
739 | ||
51e5ef45 | 740 | struct ARMCPUInfo { |
d14d42f1 PM |
741 | const char *name; |
742 | void (*initfn)(Object *obj); | |
743 | void (*class_init)(ObjectClass *oc, void *data); | |
51e5ef45 | 744 | }; |
d14d42f1 PM |
745 | |
746 | static const ARMCPUInfo aarch64_cpus[] = { | |
cb1fa941 | 747 | { .name = "cortex-a57", .initfn = aarch64_a57_initfn }, |
e3531026 | 748 | { .name = "cortex-a53", .initfn = aarch64_a53_initfn }, |
f11b452b | 749 | { .name = "cortex-a72", .initfn = aarch64_a72_initfn }, |
bab52d4b | 750 | { .name = "max", .initfn = aarch64_max_initfn }, |
83e6813a | 751 | { .name = NULL } |
d14d42f1 PM |
752 | }; |
753 | ||
fb8d6c24 GB |
754 | static bool aarch64_cpu_get_aarch64(Object *obj, Error **errp) |
755 | { | |
756 | ARMCPU *cpu = ARM_CPU(obj); | |
757 | ||
758 | return arm_feature(&cpu->env, ARM_FEATURE_AARCH64); | |
759 | } | |
760 | ||
761 | static void aarch64_cpu_set_aarch64(Object *obj, bool value, Error **errp) | |
762 | { | |
763 | ARMCPU *cpu = ARM_CPU(obj); | |
764 | ||
765 | /* At this time, this property is only allowed if KVM is enabled. This | |
766 | * restriction allows us to avoid fixing up functionality that assumes a | |
767 | * uniform execution state like do_interrupt. | |
768 | */ | |
fb8d6c24 | 769 | if (value == false) { |
b9e758f0 AJ |
770 | if (!kvm_enabled() || !kvm_arm_aarch32_supported(CPU(cpu))) { |
771 | error_setg(errp, "'aarch64' feature cannot be disabled " | |
772 | "unless KVM is enabled and 32-bit EL1 " | |
773 | "is supported"); | |
774 | return; | |
775 | } | |
fb8d6c24 GB |
776 | unset_feature(&cpu->env, ARM_FEATURE_AARCH64); |
777 | } else { | |
778 | set_feature(&cpu->env, ARM_FEATURE_AARCH64); | |
779 | } | |
780 | } | |
781 | ||
d14d42f1 PM |
782 | static void aarch64_cpu_initfn(Object *obj) |
783 | { | |
fb8d6c24 GB |
784 | object_property_add_bool(obj, "aarch64", aarch64_cpu_get_aarch64, |
785 | aarch64_cpu_set_aarch64, NULL); | |
786 | object_property_set_description(obj, "aarch64", | |
787 | "Set on/off to enable/disable aarch64 " | |
788 | "execution state ", | |
789 | NULL); | |
d14d42f1 PM |
790 | } |
791 | ||
792 | static void aarch64_cpu_finalizefn(Object *obj) | |
793 | { | |
794 | } | |
795 | ||
b3820e6c DH |
796 | static gchar *aarch64_gdb_arch_name(CPUState *cs) |
797 | { | |
798 | return g_strdup("aarch64"); | |
799 | } | |
800 | ||
d14d42f1 PM |
801 | static void aarch64_cpu_class_init(ObjectClass *oc, void *data) |
802 | { | |
14ade10f AG |
803 | CPUClass *cc = CPU_CLASS(oc); |
804 | ||
e8925712 | 805 | cc->cpu_exec_interrupt = arm_cpu_exec_interrupt; |
96c04212 AG |
806 | cc->gdb_read_register = aarch64_cpu_gdb_read_register; |
807 | cc->gdb_write_register = aarch64_cpu_gdb_write_register; | |
808 | cc->gdb_num_core_regs = 34; | |
809 | cc->gdb_core_xml_file = "aarch64-core.xml"; | |
b3820e6c | 810 | cc->gdb_arch_name = aarch64_gdb_arch_name; |
d14d42f1 PM |
811 | } |
812 | ||
51e5ef45 MAL |
813 | static void aarch64_cpu_instance_init(Object *obj) |
814 | { | |
815 | ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj); | |
816 | ||
817 | acc->info->initfn(obj); | |
818 | arm_cpu_post_init(obj); | |
819 | } | |
820 | ||
821 | static void cpu_register_class_init(ObjectClass *oc, void *data) | |
822 | { | |
823 | ARMCPUClass *acc = ARM_CPU_CLASS(oc); | |
824 | ||
825 | acc->info = data; | |
826 | } | |
827 | ||
d14d42f1 PM |
828 | static void aarch64_cpu_register(const ARMCPUInfo *info) |
829 | { | |
830 | TypeInfo type_info = { | |
831 | .parent = TYPE_AARCH64_CPU, | |
832 | .instance_size = sizeof(ARMCPU), | |
51e5ef45 | 833 | .instance_init = aarch64_cpu_instance_init, |
d14d42f1 | 834 | .class_size = sizeof(ARMCPUClass), |
51e5ef45 MAL |
835 | .class_init = info->class_init ?: cpu_register_class_init, |
836 | .class_data = (void *)info, | |
d14d42f1 PM |
837 | }; |
838 | ||
839 | type_info.name = g_strdup_printf("%s-" TYPE_ARM_CPU, info->name); | |
840 | type_register(&type_info); | |
841 | g_free((void *)type_info.name); | |
842 | } | |
843 | ||
844 | static const TypeInfo aarch64_cpu_type_info = { | |
845 | .name = TYPE_AARCH64_CPU, | |
846 | .parent = TYPE_ARM_CPU, | |
847 | .instance_size = sizeof(ARMCPU), | |
848 | .instance_init = aarch64_cpu_initfn, | |
849 | .instance_finalize = aarch64_cpu_finalizefn, | |
850 | .abstract = true, | |
851 | .class_size = sizeof(AArch64CPUClass), | |
852 | .class_init = aarch64_cpu_class_init, | |
853 | }; | |
854 | ||
855 | static void aarch64_cpu_register_types(void) | |
856 | { | |
83e6813a | 857 | const ARMCPUInfo *info = aarch64_cpus; |
d14d42f1 PM |
858 | |
859 | type_register_static(&aarch64_cpu_type_info); | |
83e6813a PM |
860 | |
861 | while (info->name) { | |
862 | aarch64_cpu_register(info); | |
863 | info++; | |
d14d42f1 PM |
864 | } |
865 | } | |
866 | ||
867 | type_init(aarch64_cpu_register_types) |