1228021f0SSong Gao /* SPDX-License-Identifier: GPL-2.0-or-later */
2228021f0SSong Gao /*
3228021f0SSong Gao * QEMU LoongArch CPU
4228021f0SSong Gao *
5228021f0SSong Gao * Copyright (c) 2021 Loongson Technology Corporation Limited
6228021f0SSong Gao */
7228021f0SSong Gao
8228021f0SSong Gao #include "qemu/osdep.h"
9228021f0SSong Gao #include "qemu/log.h"
10228021f0SSong Gao #include "qemu/qemu-print.h"
11228021f0SSong Gao #include "qapi/error.h"
12228021f0SSong Gao #include "qemu/module.h"
13228021f0SSong Gao #include "sysemu/qtest.h"
142d45085aSTianrui Zhao #include "sysemu/tcg.h"
158dcbad51STianrui Zhao #include "sysemu/kvm.h"
168dcbad51STianrui Zhao #include "kvm/kvm_loongarch.h"
17228021f0SSong Gao #include "exec/exec-all.h"
18228021f0SSong Gao #include "cpu.h"
19228021f0SSong Gao #include "internals.h"
20228021f0SSong Gao #include "fpu/softfloat-helpers.h"
21398cecb9SXiaojuan Yang #include "cpu-csr.h"
22c0f6cd9fSPhilippe Mathieu-Daudé #ifndef CONFIG_USER_ONLY
23f84a2aacSXiaojuan Yang #include "sysemu/reset.h"
24c0f6cd9fSPhilippe Mathieu-Daudé #endif
25008a3b16SSong Gao #include "vec.h"
268dcbad51STianrui Zhao #ifdef CONFIG_KVM
278dcbad51STianrui Zhao #include <linux/kvm.h>
288dcbad51STianrui Zhao #endif
292d45085aSTianrui Zhao #ifdef CONFIG_TCG
302d45085aSTianrui Zhao #include "exec/cpu_ldst.h"
312d45085aSTianrui Zhao #include "tcg/tcg.h"
322d45085aSTianrui Zhao #endif
33228021f0SSong Gao
34228021f0SSong Gao const char * const regnames[32] = {
35228021f0SSong Gao "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
36228021f0SSong Gao "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
37228021f0SSong Gao "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
38228021f0SSong Gao "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
39228021f0SSong Gao };
40228021f0SSong Gao
41228021f0SSong Gao const char * const fregnames[32] = {
42228021f0SSong Gao "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
43228021f0SSong Gao "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
44228021f0SSong Gao "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
45228021f0SSong Gao "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
46228021f0SSong Gao };
47228021f0SSong Gao
481590154eSSong Gao struct TypeExcp {
491590154eSSong Gao int32_t exccode;
501590154eSSong Gao const char * const name;
511590154eSSong Gao };
521590154eSSong Gao
531590154eSSong Gao static const struct TypeExcp excp_names[] = {
541590154eSSong Gao {EXCCODE_INT, "Interrupt"},
551590154eSSong Gao {EXCCODE_PIL, "Page invalid exception for load"},
561590154eSSong Gao {EXCCODE_PIS, "Page invalid exception for store"},
571590154eSSong Gao {EXCCODE_PIF, "Page invalid exception for fetch"},
581590154eSSong Gao {EXCCODE_PME, "Page modified exception"},
591590154eSSong Gao {EXCCODE_PNR, "Page Not Readable exception"},
601590154eSSong Gao {EXCCODE_PNX, "Page Not Executable exception"},
611590154eSSong Gao {EXCCODE_PPI, "Page Privilege error"},
621590154eSSong Gao {EXCCODE_ADEF, "Address error for instruction fetch"},
631590154eSSong Gao {EXCCODE_ADEM, "Address error for Memory access"},
641590154eSSong Gao {EXCCODE_SYS, "Syscall"},
651590154eSSong Gao {EXCCODE_BRK, "Break"},
661590154eSSong Gao {EXCCODE_INE, "Instruction Non-Existent"},
671590154eSSong Gao {EXCCODE_IPE, "Instruction privilege error"},
681590154eSSong Gao {EXCCODE_FPD, "Floating Point Disabled"},
691590154eSSong Gao {EXCCODE_FPE, "Floating Point Exception"},
701590154eSSong Gao {EXCCODE_DBP, "Debug breakpoint"},
711590154eSSong Gao {EXCCODE_BCE, "Bound Check Exception"},
721590154eSSong Gao {EXCCODE_SXD, "128 bit vector instructions Disable exception"},
731590154eSSong Gao {EXCCODE_ASXD, "256 bit vector instructions Disable exception"},
741590154eSSong Gao {EXCP_HLT, "EXCP_HLT"},
75228021f0SSong Gao };
76228021f0SSong Gao
loongarch_exception_name(int32_t exception)77228021f0SSong Gao const char *loongarch_exception_name(int32_t exception)
78228021f0SSong Gao {
791590154eSSong Gao int i;
801590154eSSong Gao
811590154eSSong Gao for (i = 0; i < ARRAY_SIZE(excp_names); i++) {
821590154eSSong Gao if (excp_names[i].exccode == exception) {
831590154eSSong Gao return excp_names[i].name;
841590154eSSong Gao }
851590154eSSong Gao }
861590154eSSong Gao return "Unknown";
87228021f0SSong Gao }
88228021f0SSong Gao
do_raise_exception(CPULoongArchState * env,uint32_t exception,uintptr_t pc)89228021f0SSong Gao void G_NORETURN do_raise_exception(CPULoongArchState *env,
90228021f0SSong Gao uint32_t exception,
91228021f0SSong Gao uintptr_t pc)
92228021f0SSong Gao {
93228021f0SSong Gao CPUState *cs = env_cpu(env);
94228021f0SSong Gao
950cbb322fSMichael Tokarev qemu_log_mask(CPU_LOG_INT, "%s: exception: %d (%s)\n",
96228021f0SSong Gao __func__,
97228021f0SSong Gao exception,
98228021f0SSong Gao loongarch_exception_name(exception));
99228021f0SSong Gao cs->exception_index = exception;
100228021f0SSong Gao
101228021f0SSong Gao cpu_loop_exit_restore(cs, pc);
102228021f0SSong Gao }
103228021f0SSong Gao
loongarch_cpu_set_pc(CPUState * cs,vaddr value)104228021f0SSong Gao static void loongarch_cpu_set_pc(CPUState *cs, vaddr value)
105228021f0SSong Gao {
106f3b603b9SPhilippe Mathieu-Daudé set_pc(cpu_env(cs), value);
107228021f0SSong Gao }
108228021f0SSong Gao
loongarch_cpu_get_pc(CPUState * cs)109e4fdf9dfSRichard Henderson static vaddr loongarch_cpu_get_pc(CPUState *cs)
110e4fdf9dfSRichard Henderson {
111f3b603b9SPhilippe Mathieu-Daudé return cpu_env(cs)->pc;
112e4fdf9dfSRichard Henderson }
113e4fdf9dfSRichard Henderson
1140093b9a5SSong Gao #ifndef CONFIG_USER_ONLY
115a8a506c3SXiaojuan Yang #include "hw/loongarch/virt.h"
116a8a506c3SXiaojuan Yang
loongarch_cpu_set_irq(void * opaque,int irq,int level)117f757a2cdSXiaojuan Yang void loongarch_cpu_set_irq(void *opaque, int irq, int level)
118f757a2cdSXiaojuan Yang {
119f757a2cdSXiaojuan Yang LoongArchCPU *cpu = opaque;
120f757a2cdSXiaojuan Yang CPULoongArchState *env = &cpu->env;
121f757a2cdSXiaojuan Yang CPUState *cs = CPU(cpu);
122f757a2cdSXiaojuan Yang
123f757a2cdSXiaojuan Yang if (irq < 0 || irq >= N_IRQS) {
124f757a2cdSXiaojuan Yang return;
125f757a2cdSXiaojuan Yang }
126f757a2cdSXiaojuan Yang
1278dcbad51STianrui Zhao if (kvm_enabled()) {
1288dcbad51STianrui Zhao kvm_loongarch_set_interrupt(cpu, irq, level);
1298dcbad51STianrui Zhao } else if (tcg_enabled()) {
130f757a2cdSXiaojuan Yang env->CSR_ESTAT = deposit64(env->CSR_ESTAT, irq, 1, level != 0);
131f757a2cdSXiaojuan Yang if (FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS)) {
132f757a2cdSXiaojuan Yang cpu_interrupt(cs, CPU_INTERRUPT_HARD);
133f757a2cdSXiaojuan Yang } else {
134f757a2cdSXiaojuan Yang cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
135f757a2cdSXiaojuan Yang }
136f757a2cdSXiaojuan Yang }
1372d45085aSTianrui Zhao }
138f757a2cdSXiaojuan Yang
cpu_loongarch_hw_interrupts_enabled(CPULoongArchState * env)139f757a2cdSXiaojuan Yang static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *env)
140f757a2cdSXiaojuan Yang {
141f757a2cdSXiaojuan Yang bool ret = 0;
142f757a2cdSXiaojuan Yang
143f757a2cdSXiaojuan Yang ret = (FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE) &&
144f757a2cdSXiaojuan Yang !(FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)));
145f757a2cdSXiaojuan Yang
146f757a2cdSXiaojuan Yang return ret;
147f757a2cdSXiaojuan Yang }
148f757a2cdSXiaojuan Yang
149f757a2cdSXiaojuan Yang /* Check if there is pending and not masked out interrupt */
cpu_loongarch_hw_interrupts_pending(CPULoongArchState * env)150f757a2cdSXiaojuan Yang static inline bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env)
151f757a2cdSXiaojuan Yang {
152f757a2cdSXiaojuan Yang uint32_t pending;
153f757a2cdSXiaojuan Yang uint32_t status;
154f757a2cdSXiaojuan Yang
155f757a2cdSXiaojuan Yang pending = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS);
156f757a2cdSXiaojuan Yang status = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE);
157f757a2cdSXiaojuan Yang
15866997c42SMarkus Armbruster return (pending & status) != 0;
159f757a2cdSXiaojuan Yang }
1602d45085aSTianrui Zhao #endif
161f757a2cdSXiaojuan Yang
1622d45085aSTianrui Zhao #ifdef CONFIG_TCG
1632d45085aSTianrui Zhao #ifndef CONFIG_USER_ONLY
loongarch_cpu_do_interrupt(CPUState * cs)164f757a2cdSXiaojuan Yang static void loongarch_cpu_do_interrupt(CPUState *cs)
165f757a2cdSXiaojuan Yang {
166f3b603b9SPhilippe Mathieu-Daudé CPULoongArchState *env = cpu_env(cs);
167f757a2cdSXiaojuan Yang bool update_badinstr = 1;
168f757a2cdSXiaojuan Yang int cause = -1;
169f757a2cdSXiaojuan Yang bool tlbfill = FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR);
170f757a2cdSXiaojuan Yang uint32_t vec_size = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS);
171f757a2cdSXiaojuan Yang
172f757a2cdSXiaojuan Yang if (cs->exception_index != EXCCODE_INT) {
173f757a2cdSXiaojuan Yang qemu_log_mask(CPU_LOG_INT,
174f757a2cdSXiaojuan Yang "%s enter: pc " TARGET_FMT_lx " ERA " TARGET_FMT_lx
1751590154eSSong Gao " TLBRERA " TARGET_FMT_lx " exception: %d (%s)\n",
1761590154eSSong Gao __func__, env->pc, env->CSR_ERA, env->CSR_TLBRERA,
1771590154eSSong Gao cs->exception_index,
1781590154eSSong Gao loongarch_exception_name(cs->exception_index));
179f757a2cdSXiaojuan Yang }
180f757a2cdSXiaojuan Yang
181f757a2cdSXiaojuan Yang switch (cs->exception_index) {
182f757a2cdSXiaojuan Yang case EXCCODE_DBP:
183f757a2cdSXiaojuan Yang env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DCL, 1);
184f757a2cdSXiaojuan Yang env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, ECODE, 0xC);
185f757a2cdSXiaojuan Yang goto set_DERA;
186f757a2cdSXiaojuan Yang set_DERA:
187f757a2cdSXiaojuan Yang env->CSR_DERA = env->pc;
188f757a2cdSXiaojuan Yang env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DST, 1);
1892f6478ffSJiajie Chen set_pc(env, env->CSR_EENTRY + 0x480);
190f757a2cdSXiaojuan Yang break;
191f757a2cdSXiaojuan Yang case EXCCODE_INT:
192f757a2cdSXiaojuan Yang if (FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)) {
193f757a2cdSXiaojuan Yang env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DEI, 1);
194f757a2cdSXiaojuan Yang goto set_DERA;
195f757a2cdSXiaojuan Yang }
196f757a2cdSXiaojuan Yang QEMU_FALLTHROUGH;
197f757a2cdSXiaojuan Yang case EXCCODE_PIF:
1988752b130SSong Gao case EXCCODE_ADEF:
199f757a2cdSXiaojuan Yang cause = cs->exception_index;
200f757a2cdSXiaojuan Yang update_badinstr = 0;
201f757a2cdSXiaojuan Yang break;
202f757a2cdSXiaojuan Yang case EXCCODE_SYS:
203f757a2cdSXiaojuan Yang case EXCCODE_BRK:
2047d552f0eSSong Gao case EXCCODE_INE:
2057d552f0eSSong Gao case EXCCODE_IPE:
2062419978cSRui Wang case EXCCODE_FPD:
2077d552f0eSSong Gao case EXCCODE_FPE:
208a3f3db5cSSong Gao case EXCCODE_SXD:
209b8f1bdf3SSong Gao case EXCCODE_ASXD:
2107d552f0eSSong Gao env->CSR_BADV = env->pc;
2117d552f0eSSong Gao QEMU_FALLTHROUGH;
2122e2ca3c8SSong Gao case EXCCODE_BCE:
2137d552f0eSSong Gao case EXCCODE_ADEM:
214f757a2cdSXiaojuan Yang case EXCCODE_PIL:
215f757a2cdSXiaojuan Yang case EXCCODE_PIS:
216f757a2cdSXiaojuan Yang case EXCCODE_PME:
217f757a2cdSXiaojuan Yang case EXCCODE_PNR:
218f757a2cdSXiaojuan Yang case EXCCODE_PNX:
219f757a2cdSXiaojuan Yang case EXCCODE_PPI:
220f757a2cdSXiaojuan Yang cause = cs->exception_index;
221f757a2cdSXiaojuan Yang break;
222f757a2cdSXiaojuan Yang default:
223e4ad16f4SXiaojuan Yang qemu_log("Error: exception(%d) has not been supported\n",
224e4ad16f4SXiaojuan Yang cs->exception_index);
225f757a2cdSXiaojuan Yang abort();
226f757a2cdSXiaojuan Yang }
227f757a2cdSXiaojuan Yang
228f757a2cdSXiaojuan Yang if (update_badinstr) {
229f757a2cdSXiaojuan Yang env->CSR_BADI = cpu_ldl_code(env, env->pc);
230f757a2cdSXiaojuan Yang }
231f757a2cdSXiaojuan Yang
232f757a2cdSXiaojuan Yang /* Save PLV and IE */
233f757a2cdSXiaojuan Yang if (tlbfill) {
234f757a2cdSXiaojuan Yang env->CSR_TLBRPRMD = FIELD_DP64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV,
235f757a2cdSXiaojuan Yang FIELD_EX64(env->CSR_CRMD,
236f757a2cdSXiaojuan Yang CSR_CRMD, PLV));
237f757a2cdSXiaojuan Yang env->CSR_TLBRPRMD = FIELD_DP64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PIE,
238f757a2cdSXiaojuan Yang FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE));
239f757a2cdSXiaojuan Yang /* set the DA mode */
240f757a2cdSXiaojuan Yang env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1);
241f757a2cdSXiaojuan Yang env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0);
242f757a2cdSXiaojuan Yang env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA,
243f757a2cdSXiaojuan Yang PC, (env->pc >> 2));
244f757a2cdSXiaojuan Yang } else {
245a6b129c8SSong Gao env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, ECODE,
246a6b129c8SSong Gao EXCODE_MCODE(cause));
247a6b129c8SSong Gao env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, ESUBCODE,
248a6b129c8SSong Gao EXCODE_SUBCODE(cause));
249f757a2cdSXiaojuan Yang env->CSR_PRMD = FIELD_DP64(env->CSR_PRMD, CSR_PRMD, PPLV,
250f757a2cdSXiaojuan Yang FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV));
251f757a2cdSXiaojuan Yang env->CSR_PRMD = FIELD_DP64(env->CSR_PRMD, CSR_PRMD, PIE,
252f757a2cdSXiaojuan Yang FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE));
253f757a2cdSXiaojuan Yang env->CSR_ERA = env->pc;
254f757a2cdSXiaojuan Yang }
255f757a2cdSXiaojuan Yang
256f757a2cdSXiaojuan Yang env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0);
257f757a2cdSXiaojuan Yang env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0);
258f757a2cdSXiaojuan Yang
25946233676SXiaojuan Yang if (vec_size) {
26046233676SXiaojuan Yang vec_size = (1 << vec_size) * 4;
26146233676SXiaojuan Yang }
26246233676SXiaojuan Yang
263f757a2cdSXiaojuan Yang if (cs->exception_index == EXCCODE_INT) {
264f757a2cdSXiaojuan Yang /* Interrupt */
265f757a2cdSXiaojuan Yang uint32_t vector = 0;
266f757a2cdSXiaojuan Yang uint32_t pending = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS);
267f757a2cdSXiaojuan Yang pending &= FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE);
268f757a2cdSXiaojuan Yang
269f757a2cdSXiaojuan Yang /* Find the highest-priority interrupt. */
270f757a2cdSXiaojuan Yang vector = 31 - clz32(pending);
2712f6478ffSJiajie Chen set_pc(env, env->CSR_EENTRY + \
2722f6478ffSJiajie Chen (EXCCODE_EXTERNAL_INT + vector) * vec_size);
273f757a2cdSXiaojuan Yang qemu_log_mask(CPU_LOG_INT,
274f757a2cdSXiaojuan Yang "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx
275f757a2cdSXiaojuan Yang " cause %d\n" " A " TARGET_FMT_lx " D "
276f757a2cdSXiaojuan Yang TARGET_FMT_lx " vector = %d ExC " TARGET_FMT_lx "ExS"
277f757a2cdSXiaojuan Yang TARGET_FMT_lx "\n",
278f757a2cdSXiaojuan Yang __func__, env->pc, env->CSR_ERA,
279f757a2cdSXiaojuan Yang cause, env->CSR_BADV, env->CSR_DERA, vector,
280f757a2cdSXiaojuan Yang env->CSR_ECFG, env->CSR_ESTAT);
281f757a2cdSXiaojuan Yang } else {
282f757a2cdSXiaojuan Yang if (tlbfill) {
2832f6478ffSJiajie Chen set_pc(env, env->CSR_TLBRENTRY);
284f757a2cdSXiaojuan Yang } else {
2852f6478ffSJiajie Chen set_pc(env, env->CSR_EENTRY + EXCODE_MCODE(cause) * vec_size);
286f757a2cdSXiaojuan Yang }
287f757a2cdSXiaojuan Yang qemu_log_mask(CPU_LOG_INT,
288f757a2cdSXiaojuan Yang "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx
289f757a2cdSXiaojuan Yang " cause %d%s\n, ESTAT " TARGET_FMT_lx
290f757a2cdSXiaojuan Yang " EXCFG " TARGET_FMT_lx " BADVA " TARGET_FMT_lx
291f757a2cdSXiaojuan Yang "BADI " TARGET_FMT_lx " SYS_NUM " TARGET_FMT_lu
292f757a2cdSXiaojuan Yang " cpu %d asid " TARGET_FMT_lx "\n", __func__, env->pc,
293f757a2cdSXiaojuan Yang tlbfill ? env->CSR_TLBRERA : env->CSR_ERA,
294f757a2cdSXiaojuan Yang cause, tlbfill ? "(refill)" : "", env->CSR_ESTAT,
295f757a2cdSXiaojuan Yang env->CSR_ECFG,
296f757a2cdSXiaojuan Yang tlbfill ? env->CSR_TLBRBADV : env->CSR_BADV,
297f757a2cdSXiaojuan Yang env->CSR_BADI, env->gpr[11], cs->cpu_index,
298f757a2cdSXiaojuan Yang env->CSR_ASID);
299f757a2cdSXiaojuan Yang }
300f757a2cdSXiaojuan Yang cs->exception_index = -1;
301f757a2cdSXiaojuan Yang }
302f757a2cdSXiaojuan Yang
loongarch_cpu_do_transaction_failed(CPUState * cs,hwaddr physaddr,vaddr addr,unsigned size,MMUAccessType access_type,int mmu_idx,MemTxAttrs attrs,MemTxResult response,uintptr_t retaddr)303f757a2cdSXiaojuan Yang static void loongarch_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
304f757a2cdSXiaojuan Yang vaddr addr, unsigned size,
305f757a2cdSXiaojuan Yang MMUAccessType access_type,
306f757a2cdSXiaojuan Yang int mmu_idx, MemTxAttrs attrs,
307f757a2cdSXiaojuan Yang MemTxResult response,
308f757a2cdSXiaojuan Yang uintptr_t retaddr)
309f757a2cdSXiaojuan Yang {
310f3b603b9SPhilippe Mathieu-Daudé CPULoongArchState *env = cpu_env(cs);
311f757a2cdSXiaojuan Yang
312f757a2cdSXiaojuan Yang if (access_type == MMU_INST_FETCH) {
313f757a2cdSXiaojuan Yang do_raise_exception(env, EXCCODE_ADEF, retaddr);
314f757a2cdSXiaojuan Yang } else {
315f757a2cdSXiaojuan Yang do_raise_exception(env, EXCCODE_ADEM, retaddr);
316f757a2cdSXiaojuan Yang }
317f757a2cdSXiaojuan Yang }
318f757a2cdSXiaojuan Yang
loongarch_cpu_exec_interrupt(CPUState * cs,int interrupt_request)319f757a2cdSXiaojuan Yang static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
320f757a2cdSXiaojuan Yang {
321f757a2cdSXiaojuan Yang if (interrupt_request & CPU_INTERRUPT_HARD) {
322f3b603b9SPhilippe Mathieu-Daudé CPULoongArchState *env = cpu_env(cs);
323f757a2cdSXiaojuan Yang
324f757a2cdSXiaojuan Yang if (cpu_loongarch_hw_interrupts_enabled(env) &&
325f757a2cdSXiaojuan Yang cpu_loongarch_hw_interrupts_pending(env)) {
326f757a2cdSXiaojuan Yang /* Raise it */
327f757a2cdSXiaojuan Yang cs->exception_index = EXCCODE_INT;
328f757a2cdSXiaojuan Yang loongarch_cpu_do_interrupt(cs);
329f757a2cdSXiaojuan Yang return true;
330f757a2cdSXiaojuan Yang }
331f757a2cdSXiaojuan Yang }
332f757a2cdSXiaojuan Yang return false;
333f757a2cdSXiaojuan Yang }
3340093b9a5SSong Gao #endif
335f757a2cdSXiaojuan Yang
loongarch_cpu_synchronize_from_tb(CPUState * cs,const TranslationBlock * tb)336228021f0SSong Gao static void loongarch_cpu_synchronize_from_tb(CPUState *cs,
337228021f0SSong Gao const TranslationBlock *tb)
338228021f0SSong Gao {
339b254c342SPhilippe Mathieu-Daudé tcg_debug_assert(!tcg_cflags_has(cs, CF_PCREL));
340f3b603b9SPhilippe Mathieu-Daudé set_pc(cpu_env(cs), tb->pc);
341228021f0SSong Gao }
342ab27940fSRichard Henderson
loongarch_restore_state_to_opc(CPUState * cs,const TranslationBlock * tb,const uint64_t * data)343ab27940fSRichard Henderson static void loongarch_restore_state_to_opc(CPUState *cs,
344ab27940fSRichard Henderson const TranslationBlock *tb,
345ab27940fSRichard Henderson const uint64_t *data)
346ab27940fSRichard Henderson {
347f3b603b9SPhilippe Mathieu-Daudé set_pc(cpu_env(cs), data[0]);
348ab27940fSRichard Henderson }
349228021f0SSong Gao #endif /* CONFIG_TCG */
350228021f0SSong Gao
loongarch_cpu_has_work(CPUState * cs)351f757a2cdSXiaojuan Yang static bool loongarch_cpu_has_work(CPUState *cs)
352f757a2cdSXiaojuan Yang {
3530093b9a5SSong Gao #ifdef CONFIG_USER_ONLY
3540093b9a5SSong Gao return true;
3550093b9a5SSong Gao #else
356f757a2cdSXiaojuan Yang bool has_work = false;
357f757a2cdSXiaojuan Yang
358f757a2cdSXiaojuan Yang if ((cs->interrupt_request & CPU_INTERRUPT_HARD) &&
359f3b603b9SPhilippe Mathieu-Daudé cpu_loongarch_hw_interrupts_pending(cpu_env(cs))) {
360f757a2cdSXiaojuan Yang has_work = true;
361f757a2cdSXiaojuan Yang }
362f757a2cdSXiaojuan Yang
363f757a2cdSXiaojuan Yang return has_work;
3640093b9a5SSong Gao #endif
365f757a2cdSXiaojuan Yang }
366f757a2cdSXiaojuan Yang
loongarch_cpu_mmu_index(CPUState * cs,bool ifetch)367a120d320SRichard Henderson static int loongarch_cpu_mmu_index(CPUState *cs, bool ifetch)
368a72a1b10SRichard Henderson {
369a72a1b10SRichard Henderson CPULoongArchState *env = cpu_env(cs);
370a72a1b10SRichard Henderson
371a72a1b10SRichard Henderson if (FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG)) {
372a72a1b10SRichard Henderson return FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV);
373a72a1b10SRichard Henderson }
3743f262d25SRichard Henderson return MMU_DA_IDX;
375a72a1b10SRichard Henderson }
376a72a1b10SRichard Henderson
loongarch_la464_initfn(Object * obj)377228021f0SSong Gao static void loongarch_la464_initfn(Object *obj)
378228021f0SSong Gao {
379228021f0SSong Gao LoongArchCPU *cpu = LOONGARCH_CPU(obj);
380228021f0SSong Gao CPULoongArchState *env = &cpu->env;
381228021f0SSong Gao int i;
382228021f0SSong Gao
383228021f0SSong Gao for (i = 0; i < 21; i++) {
384228021f0SSong Gao env->cpucfg[i] = 0x0;
385228021f0SSong Gao }
386228021f0SSong Gao
387fda3f15bSXiaojuan Yang cpu->dtb_compatible = "loongarch,Loongson-3A5000";
388228021f0SSong Gao env->cpucfg[0] = 0x14c010; /* PRID */
389228021f0SSong Gao
390228021f0SSong Gao uint32_t data = 0;
391228021f0SSong Gao data = FIELD_DP32(data, CPUCFG1, ARCH, 2);
392228021f0SSong Gao data = FIELD_DP32(data, CPUCFG1, PGMMU, 1);
393228021f0SSong Gao data = FIELD_DP32(data, CPUCFG1, IOCSR, 1);
394228021f0SSong Gao data = FIELD_DP32(data, CPUCFG1, PALEN, 0x2f);
395228021f0SSong Gao data = FIELD_DP32(data, CPUCFG1, VALEN, 0x2f);
396228021f0SSong Gao data = FIELD_DP32(data, CPUCFG1, UAL, 1);
397228021f0SSong Gao data = FIELD_DP32(data, CPUCFG1, RI, 1);
398228021f0SSong Gao data = FIELD_DP32(data, CPUCFG1, EP, 1);
399228021f0SSong Gao data = FIELD_DP32(data, CPUCFG1, RPLV, 1);
400228021f0SSong Gao data = FIELD_DP32(data, CPUCFG1, HP, 1);
401228021f0SSong Gao data = FIELD_DP32(data, CPUCFG1, IOCSR_BRD, 1);
402228021f0SSong Gao env->cpucfg[1] = data;
403228021f0SSong Gao
404228021f0SSong Gao data = 0;
405228021f0SSong Gao data = FIELD_DP32(data, CPUCFG2, FP, 1);
406228021f0SSong Gao data = FIELD_DP32(data, CPUCFG2, FP_SP, 1);
407228021f0SSong Gao data = FIELD_DP32(data, CPUCFG2, FP_DP, 1);
408228021f0SSong Gao data = FIELD_DP32(data, CPUCFG2, FP_VER, 1);
409c6c2fec4SSong Gao data = FIELD_DP32(data, CPUCFG2, LSX, 1),
4102cd81e37SSong Gao data = FIELD_DP32(data, CPUCFG2, LASX, 1),
411228021f0SSong Gao data = FIELD_DP32(data, CPUCFG2, LLFTP, 1);
412228021f0SSong Gao data = FIELD_DP32(data, CPUCFG2, LLFTP_VER, 1);
4130b360727SSong Gao data = FIELD_DP32(data, CPUCFG2, LSPW, 1);
414228021f0SSong Gao data = FIELD_DP32(data, CPUCFG2, LAM, 1);
415228021f0SSong Gao env->cpucfg[2] = data;
416228021f0SSong Gao
417228021f0SSong Gao env->cpucfg[4] = 100 * 1000 * 1000; /* Crystal frequency */
418228021f0SSong Gao
419228021f0SSong Gao data = 0;
420228021f0SSong Gao data = FIELD_DP32(data, CPUCFG5, CC_MUL, 1);
421228021f0SSong Gao data = FIELD_DP32(data, CPUCFG5, CC_DIV, 1);
422228021f0SSong Gao env->cpucfg[5] = data;
423228021f0SSong Gao
424228021f0SSong Gao data = 0;
425228021f0SSong Gao data = FIELD_DP32(data, CPUCFG16, L1_IUPRE, 1);
426228021f0SSong Gao data = FIELD_DP32(data, CPUCFG16, L1_DPRE, 1);
427228021f0SSong Gao data = FIELD_DP32(data, CPUCFG16, L2_IUPRE, 1);
428228021f0SSong Gao data = FIELD_DP32(data, CPUCFG16, L2_IUUNIFY, 1);
429228021f0SSong Gao data = FIELD_DP32(data, CPUCFG16, L2_IUPRIV, 1);
430228021f0SSong Gao data = FIELD_DP32(data, CPUCFG16, L3_IUPRE, 1);
431228021f0SSong Gao data = FIELD_DP32(data, CPUCFG16, L3_IUUNIFY, 1);
432228021f0SSong Gao data = FIELD_DP32(data, CPUCFG16, L3_IUINCL, 1);
433228021f0SSong Gao env->cpucfg[16] = data;
434228021f0SSong Gao
435228021f0SSong Gao data = 0;
436228021f0SSong Gao data = FIELD_DP32(data, CPUCFG17, L1IU_WAYS, 3);
437228021f0SSong Gao data = FIELD_DP32(data, CPUCFG17, L1IU_SETS, 8);
438228021f0SSong Gao data = FIELD_DP32(data, CPUCFG17, L1IU_SIZE, 6);
439228021f0SSong Gao env->cpucfg[17] = data;
440228021f0SSong Gao
441228021f0SSong Gao data = 0;
442228021f0SSong Gao data = FIELD_DP32(data, CPUCFG18, L1D_WAYS, 3);
443228021f0SSong Gao data = FIELD_DP32(data, CPUCFG18, L1D_SETS, 8);
444228021f0SSong Gao data = FIELD_DP32(data, CPUCFG18, L1D_SIZE, 6);
445228021f0SSong Gao env->cpucfg[18] = data;
446228021f0SSong Gao
447228021f0SSong Gao data = 0;
448228021f0SSong Gao data = FIELD_DP32(data, CPUCFG19, L2IU_WAYS, 15);
449228021f0SSong Gao data = FIELD_DP32(data, CPUCFG19, L2IU_SETS, 8);
450228021f0SSong Gao data = FIELD_DP32(data, CPUCFG19, L2IU_SIZE, 6);
451228021f0SSong Gao env->cpucfg[19] = data;
452228021f0SSong Gao
453228021f0SSong Gao data = 0;
454228021f0SSong Gao data = FIELD_DP32(data, CPUCFG20, L3IU_WAYS, 15);
455228021f0SSong Gao data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 14);
456fa90456fSXiaojuan Yang data = FIELD_DP32(data, CPUCFG20, L3IU_SIZE, 6);
457228021f0SSong Gao env->cpucfg[20] = data;
458398cecb9SXiaojuan Yang
459398cecb9SXiaojuan Yang env->CSR_ASID = FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa);
460bba1c36dSSong Gao
461bba1c36dSSong Gao env->CSR_PRCFG1 = FIELD_DP64(env->CSR_PRCFG1, CSR_PRCFG1, SAVE_NUM, 8);
462bba1c36dSSong Gao env->CSR_PRCFG1 = FIELD_DP64(env->CSR_PRCFG1, CSR_PRCFG1, TIMER_BITS, 0x2f);
463bba1c36dSSong Gao env->CSR_PRCFG1 = FIELD_DP64(env->CSR_PRCFG1, CSR_PRCFG1, VSMAX, 7);
464bba1c36dSSong Gao
465bba1c36dSSong Gao env->CSR_PRCFG2 = 0x3ffff000;
466bba1c36dSSong Gao
467bba1c36dSSong Gao env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2);
468bba1c36dSSong Gao env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63);
469bba1c36dSSong Gao env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7);
470bba1c36dSSong Gao env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8);
471bba1c36dSSong Gao
472464136ceSSong Gao loongarch_cpu_post_init(obj);
473228021f0SSong Gao }
474228021f0SSong Gao
loongarch_la132_initfn(Object * obj)475bb8710cfSJiajie Chen static void loongarch_la132_initfn(Object *obj)
476bb8710cfSJiajie Chen {
477bb8710cfSJiajie Chen LoongArchCPU *cpu = LOONGARCH_CPU(obj);
478bb8710cfSJiajie Chen CPULoongArchState *env = &cpu->env;
479bb8710cfSJiajie Chen
480bb8710cfSJiajie Chen int i;
481bb8710cfSJiajie Chen
482bb8710cfSJiajie Chen for (i = 0; i < 21; i++) {
483bb8710cfSJiajie Chen env->cpucfg[i] = 0x0;
484bb8710cfSJiajie Chen }
485bb8710cfSJiajie Chen
486bb8710cfSJiajie Chen cpu->dtb_compatible = "loongarch,Loongson-1C103";
487bb8710cfSJiajie Chen env->cpucfg[0] = 0x148042; /* PRID */
488bb8710cfSJiajie Chen
489bb8710cfSJiajie Chen uint32_t data = 0;
490bb8710cfSJiajie Chen data = FIELD_DP32(data, CPUCFG1, ARCH, 1); /* LA32 */
491bb8710cfSJiajie Chen data = FIELD_DP32(data, CPUCFG1, PGMMU, 1);
492bb8710cfSJiajie Chen data = FIELD_DP32(data, CPUCFG1, IOCSR, 1);
493bb8710cfSJiajie Chen data = FIELD_DP32(data, CPUCFG1, PALEN, 0x1f); /* 32 bits */
494bb8710cfSJiajie Chen data = FIELD_DP32(data, CPUCFG1, VALEN, 0x1f); /* 32 bits */
495bb8710cfSJiajie Chen data = FIELD_DP32(data, CPUCFG1, UAL, 1);
496bb8710cfSJiajie Chen data = FIELD_DP32(data, CPUCFG1, RI, 0);
497bb8710cfSJiajie Chen data = FIELD_DP32(data, CPUCFG1, EP, 0);
498bb8710cfSJiajie Chen data = FIELD_DP32(data, CPUCFG1, RPLV, 0);
499bb8710cfSJiajie Chen data = FIELD_DP32(data, CPUCFG1, HP, 1);
500bb8710cfSJiajie Chen data = FIELD_DP32(data, CPUCFG1, IOCSR_BRD, 1);
501bb8710cfSJiajie Chen env->cpucfg[1] = data;
502bb8710cfSJiajie Chen }
503bb8710cfSJiajie Chen
loongarch_max_initfn(Object * obj)504d6f07732SSong Gao static void loongarch_max_initfn(Object *obj)
505d6f07732SSong Gao {
506d6f07732SSong Gao /* '-cpu max' for TCG: we use cpu la464. */
507d6f07732SSong Gao loongarch_la464_initfn(obj);
508d6f07732SSong Gao }
509d6f07732SSong Gao
loongarch_cpu_reset_hold(Object * obj,ResetType type)510ad80e367SPeter Maydell static void loongarch_cpu_reset_hold(Object *obj, ResetType type)
511228021f0SSong Gao {
512f78b49aeSPeter Maydell CPUState *cs = CPU(obj);
513348802b5SPhilippe Mathieu-Daudé LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(obj);
514f3b603b9SPhilippe Mathieu-Daudé CPULoongArchState *env = cpu_env(cs);
515228021f0SSong Gao
516f78b49aeSPeter Maydell if (lacc->parent_phases.hold) {
517ad80e367SPeter Maydell lacc->parent_phases.hold(obj, type);
518f78b49aeSPeter Maydell }
519228021f0SSong Gao
5206f703a48SBibo Mao #ifdef CONFIG_TCG
521228021f0SSong Gao env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3;
5226f703a48SBibo Mao #endif
523228021f0SSong Gao env->fcsr0 = 0x0;
524228021f0SSong Gao
525398cecb9SXiaojuan Yang int n;
5263ef4b21aSSong Gao /* Set csr registers value after reset, see the manual 6.4. */
527398cecb9SXiaojuan Yang env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0);
528398cecb9SXiaojuan Yang env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0);
529398cecb9SXiaojuan Yang env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1);
530398cecb9SXiaojuan Yang env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0);
5313ef4b21aSSong Gao env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATF, 0);
5323ef4b21aSSong Gao env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATM, 0);
533398cecb9SXiaojuan Yang
534398cecb9SXiaojuan Yang env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, FPE, 0);
535398cecb9SXiaojuan Yang env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, SXE, 0);
536398cecb9SXiaojuan Yang env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, ASXE, 0);
537398cecb9SXiaojuan Yang env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, BTE, 0);
538398cecb9SXiaojuan Yang
539398cecb9SXiaojuan Yang env->CSR_MISC = 0;
540398cecb9SXiaojuan Yang
541398cecb9SXiaojuan Yang env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, VS, 0);
542398cecb9SXiaojuan Yang env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, LIE, 0);
543398cecb9SXiaojuan Yang
544398cecb9SXiaojuan Yang env->CSR_ESTAT = env->CSR_ESTAT & (~MAKE_64BIT_MASK(0, 2));
545398cecb9SXiaojuan Yang env->CSR_RVACFG = FIELD_DP64(env->CSR_RVACFG, CSR_RVACFG, RBITS, 0);
54662784656STianrui Zhao env->CSR_CPUID = cs->cpu_index;
547398cecb9SXiaojuan Yang env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0);
548398cecb9SXiaojuan Yang env->CSR_LLBCTL = FIELD_DP64(env->CSR_LLBCTL, CSR_LLBCTL, KLO, 0);
549398cecb9SXiaojuan Yang env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0);
550398cecb9SXiaojuan Yang env->CSR_MERRCTL = FIELD_DP64(env->CSR_MERRCTL, CSR_MERRCTL, ISMERR, 0);
55162784656STianrui Zhao env->CSR_TID = cs->cpu_index;
552a840d70eSBibo Mao /*
553a840d70eSBibo Mao * Workaround for edk2-stable202408, CSR PGD register is set only if
554a840d70eSBibo Mao * its value is equal to zero for boot cpu, it causes reboot issue.
555a840d70eSBibo Mao *
556a840d70eSBibo Mao * Here clear CSR registers relative with TLB.
557a840d70eSBibo Mao */
558a840d70eSBibo Mao env->CSR_PGDH = 0;
559a840d70eSBibo Mao env->CSR_PGDL = 0;
560a840d70eSBibo Mao env->CSR_PWCL = 0;
561a840d70eSBibo Mao env->CSR_PWCH = 0;
562a840d70eSBibo Mao env->CSR_STLBPS = 0;
563a840d70eSBibo Mao env->CSR_EENTRY = 0;
564a840d70eSBibo Mao env->CSR_TLBRENTRY = 0;
565a840d70eSBibo Mao env->CSR_MERRENTRY = 0;
566398cecb9SXiaojuan Yang
567398cecb9SXiaojuan Yang for (n = 0; n < 4; n++) {
568398cecb9SXiaojuan Yang env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV0, 0);
569398cecb9SXiaojuan Yang env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV1, 0);
570398cecb9SXiaojuan Yang env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV2, 0);
571398cecb9SXiaojuan Yang env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV3, 0);
572398cecb9SXiaojuan Yang }
573398cecb9SXiaojuan Yang
5740093b9a5SSong Gao #ifndef CONFIG_USER_ONLY
575f757a2cdSXiaojuan Yang env->pc = 0x1c000000;
5766f703a48SBibo Mao #ifdef CONFIG_TCG
5773517fb72SSong Gao memset(env->tlb, 0, sizeof(env->tlb));
5786f703a48SBibo Mao #endif
579f8447436STianrui Zhao if (kvm_enabled()) {
580a724f5a8SBibo Mao kvm_arch_reset_vcpu(cs);
581f8447436STianrui Zhao }
5820093b9a5SSong Gao #endif
583f757a2cdSXiaojuan Yang
5842d45085aSTianrui Zhao #ifdef CONFIG_TCG
585d578ca6cSSong Gao restore_fp_status(env);
5862d45085aSTianrui Zhao #endif
587228021f0SSong Gao cs->exception_index = -1;
588228021f0SSong Gao }
589228021f0SSong Gao
loongarch_cpu_disas_set_info(CPUState * s,disassemble_info * info)590228021f0SSong Gao static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info)
591228021f0SSong Gao {
592228021f0SSong Gao info->print_insn = print_insn_loongarch;
593228021f0SSong Gao }
594228021f0SSong Gao
loongarch_cpu_realizefn(DeviceState * dev,Error ** errp)595228021f0SSong Gao static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
596228021f0SSong Gao {
597228021f0SSong Gao CPUState *cs = CPU(dev);
598228021f0SSong Gao LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev);
599228021f0SSong Gao Error *local_err = NULL;
600228021f0SSong Gao
601228021f0SSong Gao cpu_exec_realizefn(cs, &local_err);
602228021f0SSong Gao if (local_err != NULL) {
603228021f0SSong Gao error_propagate(errp, local_err);
604228021f0SSong Gao return;
605228021f0SSong Gao }
606228021f0SSong Gao
607ca61e750SXiaojuan Yang loongarch_cpu_register_gdb_regs_for_features(cs);
608ca61e750SXiaojuan Yang
609228021f0SSong Gao cpu_reset(cs);
610228021f0SSong Gao qemu_init_vcpu(cs);
611228021f0SSong Gao
612228021f0SSong Gao lacc->parent_realize(dev, errp);
613228021f0SSong Gao }
614228021f0SSong Gao
loongarch_get_lsx(Object * obj,Error ** errp)615464136ceSSong Gao static bool loongarch_get_lsx(Object *obj, Error **errp)
616464136ceSSong Gao {
617464136ceSSong Gao LoongArchCPU *cpu = LOONGARCH_CPU(obj);
618464136ceSSong Gao bool ret;
619464136ceSSong Gao
620464136ceSSong Gao if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) {
621464136ceSSong Gao ret = true;
622464136ceSSong Gao } else {
623464136ceSSong Gao ret = false;
624464136ceSSong Gao }
625464136ceSSong Gao return ret;
626464136ceSSong Gao }
627464136ceSSong Gao
loongarch_set_lsx(Object * obj,bool value,Error ** errp)628464136ceSSong Gao static void loongarch_set_lsx(Object *obj, bool value, Error **errp)
629464136ceSSong Gao {
630464136ceSSong Gao LoongArchCPU *cpu = LOONGARCH_CPU(obj);
631464136ceSSong Gao
632464136ceSSong Gao if (value) {
633464136ceSSong Gao cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LSX, 1);
634464136ceSSong Gao } else {
635464136ceSSong Gao cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LSX, 0);
636464136ceSSong Gao cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LASX, 0);
637464136ceSSong Gao }
638464136ceSSong Gao }
639464136ceSSong Gao
loongarch_get_lasx(Object * obj,Error ** errp)640464136ceSSong Gao static bool loongarch_get_lasx(Object *obj, Error **errp)
641464136ceSSong Gao {
642464136ceSSong Gao LoongArchCPU *cpu = LOONGARCH_CPU(obj);
643464136ceSSong Gao bool ret;
644464136ceSSong Gao
645464136ceSSong Gao if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LASX)) {
646464136ceSSong Gao ret = true;
647464136ceSSong Gao } else {
648464136ceSSong Gao ret = false;
649464136ceSSong Gao }
650464136ceSSong Gao return ret;
651464136ceSSong Gao }
652464136ceSSong Gao
loongarch_set_lasx(Object * obj,bool value,Error ** errp)653464136ceSSong Gao static void loongarch_set_lasx(Object *obj, bool value, Error **errp)
654464136ceSSong Gao {
655464136ceSSong Gao LoongArchCPU *cpu = LOONGARCH_CPU(obj);
656464136ceSSong Gao
657464136ceSSong Gao if (value) {
658464136ceSSong Gao if (!FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) {
659464136ceSSong Gao cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LSX, 1);
660464136ceSSong Gao }
661464136ceSSong Gao cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LASX, 1);
662464136ceSSong Gao } else {
663464136ceSSong Gao cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LASX, 0);
664464136ceSSong Gao }
665464136ceSSong Gao }
666464136ceSSong Gao
loongarch_get_lbt(Object * obj,Error ** errp)667c23a53d8SBibo Mao static bool loongarch_get_lbt(Object *obj, Error **errp)
668c23a53d8SBibo Mao {
669c23a53d8SBibo Mao return LOONGARCH_CPU(obj)->lbt != ON_OFF_AUTO_OFF;
670c23a53d8SBibo Mao }
671c23a53d8SBibo Mao
loongarch_set_lbt(Object * obj,bool value,Error ** errp)672c23a53d8SBibo Mao static void loongarch_set_lbt(Object *obj, bool value, Error **errp)
673c23a53d8SBibo Mao {
674c23a53d8SBibo Mao LoongArchCPU *cpu = LOONGARCH_CPU(obj);
675c23a53d8SBibo Mao
676c23a53d8SBibo Mao cpu->lbt = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
677c23a53d8SBibo Mao }
678c23a53d8SBibo Mao
loongarch_get_pmu(Object * obj,Error ** errp)679*6edd2a9bSBibo Mao static bool loongarch_get_pmu(Object *obj, Error **errp)
680*6edd2a9bSBibo Mao {
681*6edd2a9bSBibo Mao return LOONGARCH_CPU(obj)->pmu != ON_OFF_AUTO_OFF;
682*6edd2a9bSBibo Mao }
683*6edd2a9bSBibo Mao
loongarch_set_pmu(Object * obj,bool value,Error ** errp)684*6edd2a9bSBibo Mao static void loongarch_set_pmu(Object *obj, bool value, Error **errp)
685*6edd2a9bSBibo Mao {
686*6edd2a9bSBibo Mao LoongArchCPU *cpu = LOONGARCH_CPU(obj);
687*6edd2a9bSBibo Mao
688*6edd2a9bSBibo Mao cpu->pmu = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
689*6edd2a9bSBibo Mao }
690*6edd2a9bSBibo Mao
loongarch_cpu_post_init(Object * obj)691464136ceSSong Gao void loongarch_cpu_post_init(Object *obj)
692464136ceSSong Gao {
693c23a53d8SBibo Mao LoongArchCPU *cpu = LOONGARCH_CPU(obj);
694c23a53d8SBibo Mao
695464136ceSSong Gao object_property_add_bool(obj, "lsx", loongarch_get_lsx,
696464136ceSSong Gao loongarch_set_lsx);
697464136ceSSong Gao object_property_add_bool(obj, "lasx", loongarch_get_lasx,
698464136ceSSong Gao loongarch_set_lasx);
699c23a53d8SBibo Mao /* lbt is enabled only in kvm mode, not supported in tcg mode */
700c23a53d8SBibo Mao if (kvm_enabled()) {
701c23a53d8SBibo Mao cpu->lbt = ON_OFF_AUTO_AUTO;
702c23a53d8SBibo Mao object_property_add_bool(obj, "lbt", loongarch_get_lbt,
703c23a53d8SBibo Mao loongarch_set_lbt);
704c23a53d8SBibo Mao object_property_set_description(obj, "lbt",
705c23a53d8SBibo Mao "Set off to disable Binary Tranlation.");
706*6edd2a9bSBibo Mao
707*6edd2a9bSBibo Mao cpu->pmu = ON_OFF_AUTO_AUTO;
708*6edd2a9bSBibo Mao object_property_add_bool(obj, "pmu", loongarch_get_pmu,
709*6edd2a9bSBibo Mao loongarch_set_pmu);
710*6edd2a9bSBibo Mao object_property_set_description(obj, "pmu",
711*6edd2a9bSBibo Mao "Set off to performance monitor unit.");
712*6edd2a9bSBibo Mao
713c23a53d8SBibo Mao } else {
714c23a53d8SBibo Mao cpu->lbt = ON_OFF_AUTO_OFF;
715c23a53d8SBibo Mao }
716464136ceSSong Gao }
717464136ceSSong Gao
loongarch_cpu_init(Object * obj)718228021f0SSong Gao static void loongarch_cpu_init(Object *obj)
719228021f0SSong Gao {
7200093b9a5SSong Gao #ifndef CONFIG_USER_ONLY
7218fa08d7eSRichard Henderson LoongArchCPU *cpu = LOONGARCH_CPU(obj);
7228fa08d7eSRichard Henderson
723f757a2cdSXiaojuan Yang qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS);
7242d45085aSTianrui Zhao #ifdef CONFIG_TCG
725dd615fa4SXiaojuan Yang timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL,
726dd615fa4SXiaojuan Yang &loongarch_constant_timer_cb, cpu);
7272d45085aSTianrui Zhao #endif
7280093b9a5SSong Gao #endif
729228021f0SSong Gao }
730228021f0SSong Gao
loongarch_cpu_class_by_name(const char * cpu_model)731228021f0SSong Gao static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)
732228021f0SSong Gao {
733228021f0SSong Gao ObjectClass *oc;
734228021f0SSong Gao
735c254f7afSXiaojuan Yang oc = object_class_by_name(cpu_model);
736c254f7afSXiaojuan Yang if (!oc) {
737c254f7afSXiaojuan Yang g_autofree char *typename
738c254f7afSXiaojuan Yang = g_strdup_printf(LOONGARCH_CPU_TYPE_NAME("%s"), cpu_model);
739228021f0SSong Gao oc = object_class_by_name(typename);
740c254f7afSXiaojuan Yang }
741c254f7afSXiaojuan Yang
742228021f0SSong Gao return oc;
743228021f0SSong Gao }
744228021f0SSong Gao
loongarch_cpu_dump_state(CPUState * cs,FILE * f,int flags)745228021f0SSong Gao void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
746228021f0SSong Gao {
747f3b603b9SPhilippe Mathieu-Daudé CPULoongArchState *env = cpu_env(cs);
748228021f0SSong Gao int i;
749228021f0SSong Gao
750228021f0SSong Gao qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
7516f703a48SBibo Mao qemu_fprintf(f, " FCSR0 0x%08x\n", env->fcsr0);
752228021f0SSong Gao
753228021f0SSong Gao /* gpr */
754228021f0SSong Gao for (i = 0; i < 32; i++) {
755228021f0SSong Gao if ((i & 3) == 0) {
756228021f0SSong Gao qemu_fprintf(f, " GPR%02d:", i);
757228021f0SSong Gao }
758228021f0SSong Gao qemu_fprintf(f, " %s %016" PRIx64, regnames[i], env->gpr[i]);
759228021f0SSong Gao if ((i & 3) == 3) {
760228021f0SSong Gao qemu_fprintf(f, "\n");
761228021f0SSong Gao }
762228021f0SSong Gao }
763228021f0SSong Gao
7647e1c521eSXiaojuan Yang qemu_fprintf(f, "CRMD=%016" PRIx64 "\n", env->CSR_CRMD);
7657e1c521eSXiaojuan Yang qemu_fprintf(f, "PRMD=%016" PRIx64 "\n", env->CSR_PRMD);
7667e1c521eSXiaojuan Yang qemu_fprintf(f, "EUEN=%016" PRIx64 "\n", env->CSR_EUEN);
7677e1c521eSXiaojuan Yang qemu_fprintf(f, "ESTAT=%016" PRIx64 "\n", env->CSR_ESTAT);
7687e1c521eSXiaojuan Yang qemu_fprintf(f, "ERA=%016" PRIx64 "\n", env->CSR_ERA);
7697e1c521eSXiaojuan Yang qemu_fprintf(f, "BADV=%016" PRIx64 "\n", env->CSR_BADV);
7707e1c521eSXiaojuan Yang qemu_fprintf(f, "BADI=%016" PRIx64 "\n", env->CSR_BADI);
7717e1c521eSXiaojuan Yang qemu_fprintf(f, "EENTRY=%016" PRIx64 "\n", env->CSR_EENTRY);
7727e1c521eSXiaojuan Yang qemu_fprintf(f, "PRCFG1=%016" PRIx64 ", PRCFG2=%016" PRIx64 ","
7737e1c521eSXiaojuan Yang " PRCFG3=%016" PRIx64 "\n",
77478f932eaSlanyanzhi env->CSR_PRCFG1, env->CSR_PRCFG2, env->CSR_PRCFG3);
7757e1c521eSXiaojuan Yang qemu_fprintf(f, "TLBRENTRY=%016" PRIx64 "\n", env->CSR_TLBRENTRY);
7767e1c521eSXiaojuan Yang qemu_fprintf(f, "TLBRBADV=%016" PRIx64 "\n", env->CSR_TLBRBADV);
7777e1c521eSXiaojuan Yang qemu_fprintf(f, "TLBRERA=%016" PRIx64 "\n", env->CSR_TLBRERA);
778be45144bSBibo Mao qemu_fprintf(f, "TCFG=%016" PRIx64 "\n", env->CSR_TCFG);
779be45144bSBibo Mao qemu_fprintf(f, "TVAL=%016" PRIx64 "\n", env->CSR_TVAL);
7807e1c521eSXiaojuan Yang
781228021f0SSong Gao /* fpr */
782228021f0SSong Gao if (flags & CPU_DUMP_FPU) {
783228021f0SSong Gao for (i = 0; i < 32; i++) {
78416f5396cSSong Gao qemu_fprintf(f, " %s %016" PRIx64, fregnames[i], env->fpr[i].vreg.D(0));
785228021f0SSong Gao if ((i & 3) == 3) {
786228021f0SSong Gao qemu_fprintf(f, "\n");
787228021f0SSong Gao }
788228021f0SSong Gao }
789228021f0SSong Gao }
790228021f0SSong Gao }
791228021f0SSong Gao
792228021f0SSong Gao #ifdef CONFIG_TCG
793228021f0SSong Gao #include "hw/core/tcg-cpu-ops.h"
794228021f0SSong Gao
7952889fb8bSRichard Henderson static const TCGCPUOps loongarch_tcg_ops = {
796228021f0SSong Gao .initialize = loongarch_translate_init,
797228021f0SSong Gao .synchronize_from_tb = loongarch_cpu_synchronize_from_tb,
798ab27940fSRichard Henderson .restore_state_to_opc = loongarch_restore_state_to_opc,
7997e1c521eSXiaojuan Yang
8000093b9a5SSong Gao #ifndef CONFIG_USER_ONLY
8017e1c521eSXiaojuan Yang .tlb_fill = loongarch_cpu_tlb_fill,
802f757a2cdSXiaojuan Yang .cpu_exec_interrupt = loongarch_cpu_exec_interrupt,
8034f7b1ecbSPeter Maydell .cpu_exec_halt = loongarch_cpu_has_work,
804f757a2cdSXiaojuan Yang .do_interrupt = loongarch_cpu_do_interrupt,
805f757a2cdSXiaojuan Yang .do_transaction_failed = loongarch_cpu_do_transaction_failed,
8060093b9a5SSong Gao #endif
807228021f0SSong Gao };
808228021f0SSong Gao #endif /* CONFIG_TCG */
809228021f0SSong Gao
8100093b9a5SSong Gao #ifndef CONFIG_USER_ONLY
8117e1c521eSXiaojuan Yang #include "hw/core/sysemu-cpu-ops.h"
8127e1c521eSXiaojuan Yang
8137e1c521eSXiaojuan Yang static const struct SysemuCPUOps loongarch_sysemu_ops = {
81432c22cc4SBibo Mao .write_elf64_note = loongarch_cpu_write_elf64_note,
8157e1c521eSXiaojuan Yang .get_phys_page_debug = loongarch_cpu_get_phys_page_debug,
8167e1c521eSXiaojuan Yang };
81714f21f67SBibo Mao
loongarch_cpu_get_arch_id(CPUState * cs)81814f21f67SBibo Mao static int64_t loongarch_cpu_get_arch_id(CPUState *cs)
81914f21f67SBibo Mao {
82014f21f67SBibo Mao LoongArchCPU *cpu = LOONGARCH_CPU(cs);
82114f21f67SBibo Mao
82214f21f67SBibo Mao return cpu->phy_id;
82314f21f67SBibo Mao }
8240093b9a5SSong Gao #endif
8257e1c521eSXiaojuan Yang
loongarch_cpu_class_init(ObjectClass * c,void * data)826228021f0SSong Gao static void loongarch_cpu_class_init(ObjectClass *c, void *data)
827228021f0SSong Gao {
828228021f0SSong Gao LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c);
829228021f0SSong Gao CPUClass *cc = CPU_CLASS(c);
830228021f0SSong Gao DeviceClass *dc = DEVICE_CLASS(c);
831f78b49aeSPeter Maydell ResettableClass *rc = RESETTABLE_CLASS(c);
832228021f0SSong Gao
833228021f0SSong Gao device_class_set_parent_realize(dc, loongarch_cpu_realizefn,
834228021f0SSong Gao &lacc->parent_realize);
835f78b49aeSPeter Maydell resettable_class_set_parent_phases(rc, NULL, loongarch_cpu_reset_hold, NULL,
836f78b49aeSPeter Maydell &lacc->parent_phases);
837228021f0SSong Gao
838228021f0SSong Gao cc->class_by_name = loongarch_cpu_class_by_name;
839f757a2cdSXiaojuan Yang cc->has_work = loongarch_cpu_has_work;
840a72a1b10SRichard Henderson cc->mmu_index = loongarch_cpu_mmu_index;
841228021f0SSong Gao cc->dump_state = loongarch_cpu_dump_state;
842228021f0SSong Gao cc->set_pc = loongarch_cpu_set_pc;
843e4fdf9dfSRichard Henderson cc->get_pc = loongarch_cpu_get_pc;
8440093b9a5SSong Gao #ifndef CONFIG_USER_ONLY
84514f21f67SBibo Mao cc->get_arch_id = loongarch_cpu_get_arch_id;
84667ebd42aSXiaojuan Yang dc->vmsd = &vmstate_loongarch_cpu;
8477e1c521eSXiaojuan Yang cc->sysemu_ops = &loongarch_sysemu_ops;
8480093b9a5SSong Gao #endif
849228021f0SSong Gao cc->disas_set_info = loongarch_cpu_disas_set_info;
850ca61e750SXiaojuan Yang cc->gdb_read_register = loongarch_cpu_gdb_read_register;
851ca61e750SXiaojuan Yang cc->gdb_write_register = loongarch_cpu_gdb_write_register;
852ca61e750SXiaojuan Yang cc->gdb_stop_before_watchpoint = true;
853ca61e750SXiaojuan Yang
854228021f0SSong Gao #ifdef CONFIG_TCG
855228021f0SSong Gao cc->tcg_ops = &loongarch_tcg_ops;
856228021f0SSong Gao #endif
857228021f0SSong Gao }
858228021f0SSong Gao
loongarch32_gdb_arch_name(CPUState * cs)859a6506838SAkihiko Odaki static const gchar *loongarch32_gdb_arch_name(CPUState *cs)
860ebda3036SJiajie Chen {
861a6506838SAkihiko Odaki return "loongarch32";
862ebda3036SJiajie Chen }
863ebda3036SJiajie Chen
loongarch32_cpu_class_init(ObjectClass * c,void * data)8646cbba3e9SJiajie Chen static void loongarch32_cpu_class_init(ObjectClass *c, void *data)
8656cbba3e9SJiajie Chen {
866ebda3036SJiajie Chen CPUClass *cc = CPU_CLASS(c);
867ebda3036SJiajie Chen
868ebda3036SJiajie Chen cc->gdb_core_xml_file = "loongarch-base32.xml";
869ebda3036SJiajie Chen cc->gdb_arch_name = loongarch32_gdb_arch_name;
8706cbba3e9SJiajie Chen }
8716cbba3e9SJiajie Chen
loongarch64_gdb_arch_name(CPUState * cs)872a6506838SAkihiko Odaki static const gchar *loongarch64_gdb_arch_name(CPUState *cs)
873e389358eSPhilippe Mathieu-Daudé {
874a6506838SAkihiko Odaki return "loongarch64";
875e389358eSPhilippe Mathieu-Daudé }
876e389358eSPhilippe Mathieu-Daudé
loongarch64_cpu_class_init(ObjectClass * c,void * data)877e389358eSPhilippe Mathieu-Daudé static void loongarch64_cpu_class_init(ObjectClass *c, void *data)
878e389358eSPhilippe Mathieu-Daudé {
879e389358eSPhilippe Mathieu-Daudé CPUClass *cc = CPU_CLASS(c);
880e389358eSPhilippe Mathieu-Daudé
881e389358eSPhilippe Mathieu-Daudé cc->gdb_core_xml_file = "loongarch-base64.xml";
882e389358eSPhilippe Mathieu-Daudé cc->gdb_arch_name = loongarch64_gdb_arch_name;
883e389358eSPhilippe Mathieu-Daudé }
884e389358eSPhilippe Mathieu-Daudé
885146f2354SPhilippe Mathieu-Daudé #define DEFINE_LOONGARCH_CPU_TYPE(size, model, initfn) \
886228021f0SSong Gao { \
887146f2354SPhilippe Mathieu-Daudé .parent = TYPE_LOONGARCH##size##_CPU, \
888228021f0SSong Gao .instance_init = initfn, \
889228021f0SSong Gao .name = LOONGARCH_CPU_TYPE_NAME(model), \
890228021f0SSong Gao }
891228021f0SSong Gao
892228021f0SSong Gao static const TypeInfo loongarch_cpu_type_infos[] = {
893228021f0SSong Gao {
894228021f0SSong Gao .name = TYPE_LOONGARCH_CPU,
895228021f0SSong Gao .parent = TYPE_CPU,
896228021f0SSong Gao .instance_size = sizeof(LoongArchCPU),
897f669c992SRichard Henderson .instance_align = __alignof(LoongArchCPU),
898228021f0SSong Gao .instance_init = loongarch_cpu_init,
899228021f0SSong Gao
900228021f0SSong Gao .abstract = true,
901228021f0SSong Gao .class_size = sizeof(LoongArchCPUClass),
902228021f0SSong Gao .class_init = loongarch_cpu_class_init,
903228021f0SSong Gao },
904146f2354SPhilippe Mathieu-Daudé {
9056cbba3e9SJiajie Chen .name = TYPE_LOONGARCH32_CPU,
9066cbba3e9SJiajie Chen .parent = TYPE_LOONGARCH_CPU,
9076cbba3e9SJiajie Chen
9086cbba3e9SJiajie Chen .abstract = true,
9096cbba3e9SJiajie Chen .class_init = loongarch32_cpu_class_init,
9106cbba3e9SJiajie Chen },
9116cbba3e9SJiajie Chen {
912146f2354SPhilippe Mathieu-Daudé .name = TYPE_LOONGARCH64_CPU,
913146f2354SPhilippe Mathieu-Daudé .parent = TYPE_LOONGARCH_CPU,
914146f2354SPhilippe Mathieu-Daudé
915146f2354SPhilippe Mathieu-Daudé .abstract = true,
916e389358eSPhilippe Mathieu-Daudé .class_init = loongarch64_cpu_class_init,
917146f2354SPhilippe Mathieu-Daudé },
918146f2354SPhilippe Mathieu-Daudé DEFINE_LOONGARCH_CPU_TYPE(64, "la464", loongarch_la464_initfn),
919bb8710cfSJiajie Chen DEFINE_LOONGARCH_CPU_TYPE(32, "la132", loongarch_la132_initfn),
920d6f07732SSong Gao DEFINE_LOONGARCH_CPU_TYPE(64, "max", loongarch_max_initfn),
921228021f0SSong Gao };
922228021f0SSong Gao
923228021f0SSong Gao DEFINE_TYPES(loongarch_cpu_type_infos)
924