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