]> git.proxmox.com Git - mirror_qemu.git/blame - target/mips/cpu.c
Merge tag 'qga-pull-2024-01-30' of https://github.com/kostyanf14/qemu into staging
[mirror_qemu.git] / target / mips / cpu.c
CommitLineData
0f71a709
AF
1/*
2 * QEMU MIPS CPU
3 *
4 * Copyright (c) 2012 SUSE LINUX Products GmbH
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see
18 * <http://www.gnu.org/licenses/lgpl-2.1.html>
19 */
20
c684822a 21#include "qemu/osdep.h"
8a6359f9 22#include "qemu/cutils.h"
c20cf02b 23#include "qemu/qemu-print.h"
cc37d98b 24#include "qemu/error-report.h"
da34e65c 25#include "qapi/error.h"
0f71a709 26#include "cpu.h"
26aa3d9a 27#include "internal.h"
14c03ab9 28#include "kvm_mips.h"
0b8fa32f 29#include "qemu/module.h"
14c03ab9 30#include "sysemu/kvm.h"
8a6359f9 31#include "sysemu/qtest.h"
63c91552 32#include "exec/exec-all.h"
d0bec217 33#include "hw/qdev-properties.h"
a0713e85 34#include "hw/qdev-clock.h"
6b5fe137 35#include "semihosting/semihost.h"
03e4d95c 36#include "fpu_helper.h"
0f71a709 37
06106772 38const char regnames[32][3] = {
adbf1be3
PMD
39 "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
40 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
41 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
42 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
43};
44
4d169b9c
PMD
45static void fpu_dump_fpr(fpr_t *fpr, FILE *f, bool is_fpu64)
46{
47 if (is_fpu64) {
48 qemu_fprintf(f, "w:%08x d:%016" PRIx64 " fd:%13g fs:%13g psu: %13g\n",
49 fpr->w[FP_ENDIAN_IDX], fpr->d,
50 (double)fpr->fd,
51 (double)fpr->fs[FP_ENDIAN_IDX],
52 (double)fpr->fs[!FP_ENDIAN_IDX]);
53 } else {
54 fpr_t tmp;
55
56 tmp.w[FP_ENDIAN_IDX] = fpr->w[FP_ENDIAN_IDX];
57 tmp.w[!FP_ENDIAN_IDX] = (fpr + 1)->w[FP_ENDIAN_IDX];
58 qemu_fprintf(f, "w:%08x d:%016" PRIx64 " fd:%13g fs:%13g psu:%13g\n",
59 tmp.w[FP_ENDIAN_IDX], tmp.d,
60 (double)tmp.fd,
61 (double)tmp.fs[FP_ENDIAN_IDX],
62 (double)tmp.fs[!FP_ENDIAN_IDX]);
63 }
64}
65
4f14ce4b
PMD
66static void fpu_dump_state(CPUMIPSState *env, FILE *f, int flags)
67{
68 int i;
4d169b9c 69 bool is_fpu64 = !!(env->hflags & MIPS_HFLAG_F64);
4f14ce4b
PMD
70
71 qemu_fprintf(f,
72 "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%02x\n",
73 env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64,
74 get_float_exception_flags(&env->active_fpu.fp_status));
75 for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) {
76 qemu_fprintf(f, "%3s: ", fregnames[i]);
4d169b9c 77 fpu_dump_fpr(&env->active_fpu.fpr[i], f, is_fpu64);
4f14ce4b 78 }
4f14ce4b
PMD
79}
80
81static void mips_cpu_dump_state(CPUState *cs, FILE *f, int flags)
82{
83 MIPSCPU *cpu = MIPS_CPU(cs);
84 CPUMIPSState *env = &cpu->env;
85 int i;
86
87 qemu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx
88 " LO=0x" TARGET_FMT_lx " ds %04x "
89 TARGET_FMT_lx " " TARGET_FMT_ld "\n",
90 env->active_tc.PC, env->active_tc.HI[0], env->active_tc.LO[0],
91 env->hflags, env->btarget, env->bcond);
92 for (i = 0; i < 32; i++) {
93 if ((i & 3) == 0) {
94 qemu_fprintf(f, "GPR%02d:", i);
95 }
96 qemu_fprintf(f, " %s " TARGET_FMT_lx,
97 regnames[i], env->active_tc.gpr[i]);
98 if ((i & 3) == 3) {
99 qemu_fprintf(f, "\n");
100 }
101 }
102
103 qemu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x"
104 TARGET_FMT_lx "\n",
105 env->CP0_Status, env->CP0_Cause, env->CP0_EPC);
106 qemu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%016"
107 PRIx64 "\n",
108 env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
109 qemu_fprintf(f, " Config2 0x%08x Config3 0x%08x\n",
110 env->CP0_Config2, env->CP0_Config3);
111 qemu_fprintf(f, " Config4 0x%08x Config5 0x%08x\n",
112 env->CP0_Config4, env->CP0_Config5);
113 if ((flags & CPU_DUMP_FPU) && (env->hflags & MIPS_HFLAG_FPU)) {
114 fpu_dump_state(env, f, flags);
115 }
116}
117
e9927723
PMD
118void cpu_set_exception_base(int vp_index, target_ulong address)
119{
120 MIPSCPU *vp = MIPS_CPU(qemu_get_cpu(vp_index));
121 vp->env.exception_base = address;
122}
123
f45748f1
AF
124static void mips_cpu_set_pc(CPUState *cs, vaddr value)
125{
126 MIPSCPU *cpu = MIPS_CPU(cs);
f45748f1 127
533fc64f 128 mips_env_set_pc(&cpu->env, value);
f45748f1
AF
129}
130
e4fdf9df
RH
131static vaddr mips_cpu_get_pc(CPUState *cs)
132{
133 MIPSCPU *cpu = MIPS_CPU(cs);
134
135 return cpu->env.active_tc.PC;
136}
137
8c2e1b00
AF
138static bool mips_cpu_has_work(CPUState *cs)
139{
140 MIPSCPU *cpu = MIPS_CPU(cs);
141 CPUMIPSState *env = &cpu->env;
142 bool has_work = false;
143
cf02a116
AM
144 /*
145 * Prior to MIPS Release 6 it is implementation dependent if non-enabled
146 * interrupts wake-up the CPU, however most of the implementations only
36b84f85
MN
147 * check for interrupts that can be taken. For pre-release 6 CPUs,
148 * check for CP0 Config7 'Wait IE ignore' bit.
cf02a116 149 */
8c2e1b00
AF
150 if ((cs->interrupt_request & CPU_INTERRUPT_HARD) &&
151 cpu_mips_hw_interrupts_pending(env)) {
7540a43a 152 if (cpu_mips_hw_interrupts_enabled(env) ||
36b84f85 153 (env->CP0_Config7 & (1 << CP0C7_WII)) ||
2e211e0a 154 (env->insn_flags & ISA_MIPS_R6)) {
71ca034a
LA
155 has_work = true;
156 }
8c2e1b00
AF
157 }
158
159 /* MIPS-MT has the ability to halt the CPU. */
17c2c320 160 if (ase_mt_available(env)) {
cf02a116
AM
161 /*
162 * The QEMU model will issue an _WAKE request whenever the CPUs
163 * should be woken up.
164 */
8c2e1b00
AF
165 if (cs->interrupt_request & CPU_INTERRUPT_WAKE) {
166 has_work = true;
167 }
168
169 if (!mips_vpe_active(env)) {
170 has_work = false;
171 }
172 }
01bc435b
YK
173 /* MIPS Release 6 has the ability to halt the CPU. */
174 if (env->CP0_Config5 & (1 << CP0C5_VP)) {
175 if (cs->interrupt_request & CPU_INTERRUPT_WAKE) {
176 has_work = true;
177 }
178 if (!mips_vp_active(env)) {
179 has_work = false;
180 }
181 }
8c2e1b00
AF
182 return has_work;
183}
184
0dc351ca 185#include "cpu-defs.c.inc"
c20cf02b 186
c08dfb7a 187static void mips_cpu_reset_hold(Object *obj)
c20cf02b 188{
c08dfb7a 189 CPUState *cs = CPU(obj);
9bcd41d4
PMD
190 MIPSCPU *cpu = MIPS_CPU(cs);
191 MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(cpu);
192 CPUMIPSState *env = &cpu->env;
193
c08dfb7a
PM
194 if (mcc->parent_phases.hold) {
195 mcc->parent_phases.hold(obj);
196 }
9bcd41d4
PMD
197
198 memset(env, 0, offsetof(CPUMIPSState, end_reset_fields));
c20cf02b
PMD
199
200 /* Reset registers to their default values */
201 env->CP0_PRid = env->cpu_model->CP0_PRid;
202 env->CP0_Config0 = env->cpu_model->CP0_Config0;
ee3eb3a7 203#if TARGET_BIG_ENDIAN
c20cf02b
PMD
204 env->CP0_Config0 |= (1 << CP0C0_BE);
205#endif
206 env->CP0_Config1 = env->cpu_model->CP0_Config1;
207 env->CP0_Config2 = env->cpu_model->CP0_Config2;
208 env->CP0_Config3 = env->cpu_model->CP0_Config3;
209 env->CP0_Config4 = env->cpu_model->CP0_Config4;
210 env->CP0_Config4_rw_bitmask = env->cpu_model->CP0_Config4_rw_bitmask;
211 env->CP0_Config5 = env->cpu_model->CP0_Config5;
212 env->CP0_Config5_rw_bitmask = env->cpu_model->CP0_Config5_rw_bitmask;
213 env->CP0_Config6 = env->cpu_model->CP0_Config6;
214 env->CP0_Config6_rw_bitmask = env->cpu_model->CP0_Config6_rw_bitmask;
215 env->CP0_Config7 = env->cpu_model->CP0_Config7;
216 env->CP0_Config7_rw_bitmask = env->cpu_model->CP0_Config7_rw_bitmask;
217 env->CP0_LLAddr_rw_bitmask = env->cpu_model->CP0_LLAddr_rw_bitmask
218 << env->cpu_model->CP0_LLAddr_shift;
219 env->CP0_LLAddr_shift = env->cpu_model->CP0_LLAddr_shift;
220 env->SYNCI_Step = env->cpu_model->SYNCI_Step;
221 env->CCRes = env->cpu_model->CCRes;
222 env->CP0_Status_rw_bitmask = env->cpu_model->CP0_Status_rw_bitmask;
223 env->CP0_TCStatus_rw_bitmask = env->cpu_model->CP0_TCStatus_rw_bitmask;
224 env->CP0_SRSCtl = env->cpu_model->CP0_SRSCtl;
225 env->current_tc = 0;
226 env->SEGBITS = env->cpu_model->SEGBITS;
227 env->SEGMask = (target_ulong)((1ULL << env->cpu_model->SEGBITS) - 1);
228#if defined(TARGET_MIPS64)
229 if (env->cpu_model->insn_flags & ISA_MIPS3) {
230 env->SEGMask |= 3ULL << 62;
231 }
232#endif
233 env->PABITS = env->cpu_model->PABITS;
234 env->CP0_SRSConf0_rw_bitmask = env->cpu_model->CP0_SRSConf0_rw_bitmask;
235 env->CP0_SRSConf0 = env->cpu_model->CP0_SRSConf0;
236 env->CP0_SRSConf1_rw_bitmask = env->cpu_model->CP0_SRSConf1_rw_bitmask;
237 env->CP0_SRSConf1 = env->cpu_model->CP0_SRSConf1;
238 env->CP0_SRSConf2_rw_bitmask = env->cpu_model->CP0_SRSConf2_rw_bitmask;
239 env->CP0_SRSConf2 = env->cpu_model->CP0_SRSConf2;
240 env->CP0_SRSConf3_rw_bitmask = env->cpu_model->CP0_SRSConf3_rw_bitmask;
241 env->CP0_SRSConf3 = env->cpu_model->CP0_SRSConf3;
242 env->CP0_SRSConf4_rw_bitmask = env->cpu_model->CP0_SRSConf4_rw_bitmask;
243 env->CP0_SRSConf4 = env->cpu_model->CP0_SRSConf4;
244 env->CP0_PageGrain_rw_bitmask = env->cpu_model->CP0_PageGrain_rw_bitmask;
245 env->CP0_PageGrain = env->cpu_model->CP0_PageGrain;
246 env->CP0_EBaseWG_rw_bitmask = env->cpu_model->CP0_EBaseWG_rw_bitmask;
03afdc28
JY
247 env->lcsr_cpucfg1 = env->cpu_model->lcsr_cpucfg1;
248 env->lcsr_cpucfg2 = env->cpu_model->lcsr_cpucfg2;
c20cf02b
PMD
249 env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0;
250 env->active_fpu.fcr31_rw_bitmask = env->cpu_model->CP1_fcr31_rw_bitmask;
251 env->active_fpu.fcr31 = env->cpu_model->CP1_fcr31;
252 env->msair = env->cpu_model->MSAIR;
253 env->insn_flags = env->cpu_model->insn_flags;
254
255#if defined(CONFIG_USER_ONLY)
256 env->CP0_Status = (MIPS_HFLAG_UM << CP0St_KSU);
257# ifdef TARGET_MIPS64
258 /* Enable 64-bit register mode. */
259 env->CP0_Status |= (1 << CP0St_PX);
260# endif
261# ifdef TARGET_ABI_MIPSN64
262 /* Enable 64-bit address mode. */
263 env->CP0_Status |= (1 << CP0St_UX);
264# endif
265 /*
266 * Enable access to the CPUNum, SYNCI_Step, CC, and CCRes RDHWR
267 * hardware registers.
268 */
269 env->CP0_HWREna |= 0x0000000F;
270 if (env->CP0_Config1 & (1 << CP0C1_FP)) {
271 env->CP0_Status |= (1 << CP0St_CU1);
272 }
273 if (env->CP0_Config3 & (1 << CP0C3_DSPP)) {
274 env->CP0_Status |= (1 << CP0St_MX);
275 }
276# if defined(TARGET_MIPS64)
277 /* For MIPS64, init FR bit to 1 if FPU unit is there and bit is writable. */
278 if ((env->CP0_Config1 & (1 << CP0C1_FP)) &&
279 (env->CP0_Status_rw_bitmask & (1 << CP0St_FR))) {
280 env->CP0_Status |= (1 << CP0St_FR);
281 }
282# endif
283#else /* !CONFIG_USER_ONLY */
284 if (env->hflags & MIPS_HFLAG_BMASK) {
285 /*
286 * If the exception was raised from a delay slot,
287 * come back to the jump.
288 */
289 env->CP0_ErrorEPC = (env->active_tc.PC
290 - (env->hflags & MIPS_HFLAG_B16 ? 2 : 4));
291 } else {
292 env->CP0_ErrorEPC = env->active_tc.PC;
293 }
294 env->active_tc.PC = env->exception_base;
295 env->CP0_Random = env->tlb->nb_tlb - 1;
296 env->tlb->tlb_in_use = env->tlb->nb_tlb;
297 env->CP0_Wired = 0;
298 env->CP0_GlobalNumber = (cs->cpu_index & 0xFF) << CP0GN_VPId;
a8448735 299 env->CP0_EBase = KSEG0_BASE | (cs->cpu_index & 0x3FF);
c20cf02b
PMD
300 if (env->CP0_Config3 & (1 << CP0C3_CMGCR)) {
301 env->CP0_CMGCRBase = 0x1fbf8000 >> 4;
302 }
303 env->CP0_EntryHi_ASID_mask = (env->CP0_Config5 & (1 << CP0C5_MI)) ?
304 0x0 : (env->CP0_Config4 & (1 << CP0C4_AE)) ? 0x3ff : 0xff;
305 env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL);
8063db0f
JY
306 if (env->insn_flags & INSN_LOONGSON2F) {
307 /* Loongson-2F has those bits hardcoded to 1 */
308 env->CP0_Status |= (1 << CP0St_KX) | (1 << CP0St_SX) |
309 (1 << CP0St_UX);
310 }
311
c20cf02b
PMD
312 /*
313 * Vectored interrupts not implemented, timer on int 7,
314 * no performance counters.
315 */
316 env->CP0_IntCtl = 0xe0000000;
317 {
318 int i;
319
320 for (i = 0; i < 7; i++) {
321 env->CP0_WatchLo[i] = 0;
a6bc80f7 322 env->CP0_WatchHi[i] = 1 << CP0WH_M;
c20cf02b
PMD
323 }
324 env->CP0_WatchLo[7] = 0;
325 env->CP0_WatchHi[7] = 0;
326 }
327 /* Count register increments in debug mode, EJTAG version 1 */
328 env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
329
330 cpu_mips_store_count(env, 1);
331
332 if (ase_mt_available(env)) {
333 int i;
334
335 /* Only TC0 on VPE 0 starts as active. */
336 for (i = 0; i < ARRAY_SIZE(env->tcs); i++) {
337 env->tcs[i].CP0_TCBind = cs->cpu_index << CP0TCBd_CurVPE;
338 env->tcs[i].CP0_TCHalt = 1;
339 }
340 env->active_tc.CP0_TCHalt = 1;
341 cs->halted = 1;
342
343 if (cs->cpu_index == 0) {
344 /* VPE0 starts up enabled. */
345 env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
346 env->CP0_VPEConf0 |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
347
348 /* TC0 starts up unhalted. */
349 cs->halted = 0;
350 env->active_tc.CP0_TCHalt = 0;
351 env->tcs[0].CP0_TCHalt = 0;
352 /* With thread 0 active. */
353 env->active_tc.CP0_TCStatus = (1 << CP0TCSt_A);
354 env->tcs[0].CP0_TCStatus = (1 << CP0TCSt_A);
355 }
356 }
357
358 /*
359 * Configure default legacy segmentation control. We use this regardless of
360 * whether segmentation control is presented to the guest.
361 */
362 /* KSeg3 (seg0 0xE0000000..0xFFFFFFFF) */
363 env->CP0_SegCtl0 = (CP0SC_AM_MK << CP0SC_AM);
364 /* KSeg2 (seg1 0xC0000000..0xDFFFFFFF) */
365 env->CP0_SegCtl0 |= ((CP0SC_AM_MSK << CP0SC_AM)) << 16;
366 /* KSeg1 (seg2 0xA0000000..0x9FFFFFFF) */
367 env->CP0_SegCtl1 = (0 << CP0SC_PA) | (CP0SC_AM_UK << CP0SC_AM) |
368 (2 << CP0SC_C);
369 /* KSeg0 (seg3 0x80000000..0x9FFFFFFF) */
370 env->CP0_SegCtl1 |= ((0 << CP0SC_PA) | (CP0SC_AM_UK << CP0SC_AM) |
371 (3 << CP0SC_C)) << 16;
372 /* USeg (seg4 0x40000000..0x7FFFFFFF) */
373 env->CP0_SegCtl2 = (2 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) |
374 (1 << CP0SC_EU) | (2 << CP0SC_C);
375 /* USeg (seg5 0x00000000..0x3FFFFFFF) */
376 env->CP0_SegCtl2 |= ((0 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) |
377 (1 << CP0SC_EU) | (2 << CP0SC_C)) << 16;
378 /* XKPhys (note, SegCtl2.XR = 0, so XAM won't be used) */
379 env->CP0_SegCtl1 |= (CP0SC_AM_UK << CP0SC1_XAM);
380#endif /* !CONFIG_USER_ONLY */
2e211e0a 381 if ((env->insn_flags & ISA_MIPS_R6) &&
c20cf02b
PMD
382 (env->active_fpu.fcr0 & (1 << FCR0_F64))) {
383 /* Status.FR = 0 mode in 64-bit FPU not allowed in R6 */
384 env->CP0_Status |= (1 << CP0St_FR);
385 }
386
2e211e0a 387 if (env->insn_flags & ISA_MIPS_R6) {
c20cf02b
PMD
388 /* PTW = 1 */
389 env->CP0_PWSize = 0x40;
390 /* GDI = 12 */
391 /* UDI = 12 */
392 /* MDI = 12 */
393 /* PRI = 12 */
394 /* PTEI = 2 */
395 env->CP0_PWField = 0x0C30C302;
396 } else {
397 /* GDI = 0 */
398 /* UDI = 0 */
399 /* MDI = 0 */
400 /* PRI = 0 */
401 /* PTEI = 2 */
402 env->CP0_PWField = 0x02;
403 }
404
405 if (env->CP0_Config3 & (1 << CP0C3_ISA) & (1 << (CP0C3_ISA + 1))) {
406 /* microMIPS on reset when Config3.ISA is 3 */
407 env->hflags |= MIPS_HFLAG_M16;
408 }
409
72f31f60 410 msa_reset(env);
c20cf02b
PMD
411
412 compute_hflags(env);
413 restore_fp_status(env);
414 restore_pamask(env);
415 cs->exception_index = EXCP_NONE;
416
417 if (semihosting_get_argc()) {
418 /* UHI interface can be used to obtain argc and argv */
419 env->active_tc.gpr[4] = -1;
420 }
14c03ab9
JH
421
422#ifndef CONFIG_USER_ONLY
423 if (kvm_enabled()) {
424 kvm_mips_reset_vcpu(cpu);
425 }
426#endif
0f71a709
AF
427}
428
cf02a116
AM
429static void mips_cpu_disas_set_info(CPUState *s, disassemble_info *info)
430{
89a955e8
AM
431 MIPSCPU *cpu = MIPS_CPU(s);
432 CPUMIPSState *env = &cpu->env;
433
434 if (!(env->insn_flags & ISA_NANOMIPS32)) {
ee3eb3a7 435#if TARGET_BIG_ENDIAN
89a955e8 436 info->print_insn = print_insn_big_mips;
63a946c7 437#else
89a955e8 438 info->print_insn = print_insn_little_mips;
63a946c7 439#endif
89a955e8 440 } else {
89a955e8 441 info->print_insn = print_insn_nanomips;
89a955e8 442 }
63a946c7
PC
443}
444
d225b512 445/*
d0bec217 446 * Since commit 6af0bf9c7c3 this model assumes a CPU clocked at 200MHz.
d225b512
PMD
447 */
448#define CPU_FREQ_HZ_DEFAULT 200000000
d225b512
PMD
449
450static void mips_cp0_period_set(MIPSCPU *cpu)
451{
452 CPUMIPSState *env = &cpu->env;
453
b263688d
JY
454 clock_set_mul_div(cpu->count_div, env->cpu_model->CCRes, 1);
455 clock_set_source(cpu->count_div, cpu->clock);
456 clock_set_source(env->count_clock, cpu->count_div);
d225b512
PMD
457}
458
c1caf1d9
AF
459static void mips_cpu_realizefn(DeviceState *dev, Error **errp)
460{
14a10fc3 461 CPUState *cs = CPU(dev);
df4dc102 462 MIPSCPU *cpu = MIPS_CPU(dev);
7b884bf5 463 CPUMIPSState *env = &cpu->env;
c1caf1d9 464 MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(dev);
ce5b1bbf
LV
465 Error *local_err = NULL;
466
a0713e85 467 if (!clock_get(cpu->clock)) {
8a6359f9
PMD
468#ifndef CONFIG_USER_ONLY
469 if (!qtest_enabled()) {
470 g_autofree char *cpu_freq_str = freq_to_str(CPU_FREQ_HZ_DEFAULT);
471
472 warn_report("CPU input clock is not connected to any output clock, "
473 "using default frequency of %s.", cpu_freq_str);
474 }
475#endif
a0713e85
PMD
476 /* Initialize the frequency in case the clock remains unconnected. */
477 clock_set_hz(cpu->clock, CPU_FREQ_HZ_DEFAULT);
478 }
d225b512
PMD
479 mips_cp0_period_set(cpu);
480
ce5b1bbf
LV
481 cpu_exec_realizefn(cs, &local_err);
482 if (local_err != NULL) {
483 error_propagate(errp, local_err);
484 return;
485 }
c1caf1d9 486
7b884bf5
PMD
487 env->exception_base = (int32_t)0xBFC00000;
488
c2842017 489#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
7b884bf5
PMD
490 mmu_init(env, env->cpu_model);
491#endif
492 fpu_init(env, env->cpu_model);
493 mvp_init(env);
df4dc102 494
14a10fc3
AF
495 cpu_reset(cs);
496 qemu_init_vcpu(cs);
c1caf1d9
AF
497
498 mcc->parent_realize(dev, errp);
499}
500
5b0c40f7
AF
501static void mips_cpu_initfn(Object *obj)
502{
503 MIPSCPU *cpu = MIPS_CPU(obj);
504 CPUMIPSState *env = &cpu->env;
41da212c 505 MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(obj);
5b0c40f7 506
5ee0abed 507 cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu, 0);
b263688d
JY
508 cpu->count_div = clock_new(OBJECT(obj), "clk-div-count");
509 env->count_clock = clock_new(OBJECT(obj), "clk-count");
41da212c 510 env->cpu_model = mcc->cpu_def;
03afdc28
JY
511#ifndef CONFIG_USER_ONLY
512 if (mcc->cpu_def->lcsr_cpucfg2 & (1 << CPUCFG2_LCSRP)) {
513 memory_region_init_io(&env->iocsr.mr, OBJECT(cpu), NULL,
514 env, "iocsr", UINT64_MAX);
515 address_space_init(&env->iocsr.as,
516 &env->iocsr.mr, "IOCSR");
517 }
518#endif
5b0c40f7
AF
519}
520
41da212c
IM
521static char *mips_cpu_type_name(const char *cpu_model)
522{
a7519f2b 523 return g_strdup_printf(MIPS_CPU_TYPE_NAME("%s"), cpu_model);
41da212c
IM
524}
525
526static ObjectClass *mips_cpu_class_by_name(const char *cpu_model)
527{
528 ObjectClass *oc;
529 char *typename;
530
41da212c
IM
531 typename = mips_cpu_type_name(cpu_model);
532 oc = object_class_by_name(typename);
533 g_free(typename);
534 return oc;
535}
536
8b80bd28
PMD
537#ifndef CONFIG_USER_ONLY
538#include "hw/core/sysemu-cpu-ops.h"
539
540static const struct SysemuCPUOps mips_sysemu_ops = {
08928c6d 541 .get_phys_page_debug = mips_cpu_get_phys_page_debug,
feece4d0 542 .legacy_vmsd = &vmstate_mips_cpu,
8b80bd28
PMD
543};
544#endif
545
78271684
CF
546#ifdef CONFIG_TCG
547#include "hw/core/tcg-cpu-ops.h"
548/*
549 * NB: cannot be const, as some elements are changed for specific
550 * mips hardware (see hw/mips/jazz.c).
551 */
1764ad70 552static const TCGCPUOps mips_tcg_ops = {
78271684
CF
553 .initialize = mips_tcg_init,
554 .synchronize_from_tb = mips_cpu_synchronize_from_tb,
3766855c 555 .restore_state_to_opc = mips_restore_state_to_opc,
78271684
CF
556
557#if !defined(CONFIG_USER_ONLY)
52d4899b 558 .tlb_fill = mips_cpu_tlb_fill,
6eb66e08 559 .cpu_exec_interrupt = mips_cpu_exec_interrupt,
78271684
CF
560 .do_interrupt = mips_cpu_do_interrupt,
561 .do_transaction_failed = mips_cpu_do_transaction_failed,
562 .do_unaligned_access = mips_cpu_do_unaligned_access,
95ab7c22 563 .io_recompile_replay_branch = mips_io_recompile_replay_branch,
78271684
CF
564#endif /* !CONFIG_USER_ONLY */
565};
566#endif /* CONFIG_TCG */
567
0f71a709
AF
568static void mips_cpu_class_init(ObjectClass *c, void *data)
569{
570 MIPSCPUClass *mcc = MIPS_CPU_CLASS(c);
571 CPUClass *cc = CPU_CLASS(c);
c1caf1d9 572 DeviceClass *dc = DEVICE_CLASS(c);
c08dfb7a 573 ResettableClass *rc = RESETTABLE_CLASS(c);
c1caf1d9 574
bf853881
PMD
575 device_class_set_parent_realize(dc, mips_cpu_realizefn,
576 &mcc->parent_realize);
c08dfb7a
PM
577 resettable_class_set_parent_phases(rc, NULL, mips_cpu_reset_hold, NULL,
578 &mcc->parent_phases);
97a8ea5a 579
41da212c 580 cc->class_by_name = mips_cpu_class_by_name;
8c2e1b00 581 cc->has_work = mips_cpu_has_work;
878096ee 582 cc->dump_state = mips_cpu_dump_state;
f45748f1 583 cc->set_pc = mips_cpu_set_pc;
e4fdf9df 584 cc->get_pc = mips_cpu_get_pc;
5b50e790
AF
585 cc->gdb_read_register = mips_cpu_gdb_read_register;
586 cc->gdb_write_register = mips_cpu_gdb_write_register;
931d019f 587#ifndef CONFIG_USER_ONLY
8b80bd28 588 cc->sysemu_ops = &mips_sysemu_ops;
00b941e5 589#endif
63a946c7 590 cc->disas_set_info = mips_cpu_disas_set_info;
a0e372f0 591 cc->gdb_num_core_regs = 73;
2472b6c0 592 cc->gdb_stop_before_watchpoint = true;
78271684
CF
593#ifdef CONFIG_TCG
594 cc->tcg_ops = &mips_tcg_ops;
595#endif /* CONFIG_TCG */
0f71a709
AF
596}
597
598static const TypeInfo mips_cpu_type_info = {
599 .name = TYPE_MIPS_CPU,
600 .parent = TYPE_CPU,
601 .instance_size = sizeof(MIPSCPU),
f669c992 602 .instance_align = __alignof(MIPSCPU),
5b0c40f7 603 .instance_init = mips_cpu_initfn,
41da212c 604 .abstract = true,
0f71a709
AF
605 .class_size = sizeof(MIPSCPUClass),
606 .class_init = mips_cpu_class_init,
607};
608
41da212c
IM
609static void mips_cpu_cpudef_class_init(ObjectClass *oc, void *data)
610{
611 MIPSCPUClass *mcc = MIPS_CPU_CLASS(oc);
612 mcc->cpu_def = data;
613}
614
615static void mips_register_cpudef_type(const struct mips_def_t *def)
616{
617 char *typename = mips_cpu_type_name(def->name);
618 TypeInfo ti = {
619 .name = typename,
620 .parent = TYPE_MIPS_CPU,
621 .class_init = mips_cpu_cpudef_class_init,
622 .class_data = (void *)def,
623 };
624
625 type_register(&ti);
626 g_free(typename);
627}
628
0f71a709
AF
629static void mips_cpu_register_types(void)
630{
41da212c
IM
631 int i;
632
0f71a709 633 type_register_static(&mips_cpu_type_info);
41da212c
IM
634 for (i = 0; i < mips_defs_number; i++) {
635 mips_register_cpudef_type(&mips_defs[i]);
636 }
0f71a709
AF
637}
638
639type_init(mips_cpu_register_types)
7aaab96a
PMD
640
641/* Could be used by generic CPU object */
642MIPSCPU *mips_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk)
643{
644 DeviceState *cpu;
645
646 cpu = DEVICE(object_new(cpu_type));
647 qdev_connect_clock_in(cpu, "clk-in", cpu_refclk);
648 qdev_realize(cpu, NULL, &error_abort);
649
650 return MIPS_CPU(cpu);
651}
df6adb68
PMD
652
653bool cpu_supports_isa(const CPUMIPSState *env, uint64_t isa_mask)
654{
655 return (env->cpu_model->insn_flags & isa_mask) != 0;
656}
ffa657ee
PMD
657
658bool cpu_type_supports_isa(const char *cpu_type, uint64_t isa)
659{
660 const MIPSCPUClass *mcc = MIPS_CPU_CLASS(object_class_by_name(cpu_type));
661 return (mcc->cpu_def->insn_flags & isa) != 0;
662}
663
664bool cpu_type_supports_cps_smp(const char *cpu_type)
665{
666 const MIPSCPUClass *mcc = MIPS_CPU_CLASS(object_class_by_name(cpu_type));
667 return (mcc->cpu_def->CP0_Config3 & (1 << CP0C3_CMGCR)) != 0;
668}