xref: /qemu/target/loongarch/kvm/kvm.c (revision 5e360dabedb1ab1f15cce27a134ccbe4b8e18424)
1537ba9daSTianrui Zhao /* SPDX-License-Identifier: GPL-2.0-or-later */
2537ba9daSTianrui Zhao /*
3537ba9daSTianrui Zhao  * QEMU LoongArch KVM
4537ba9daSTianrui Zhao  *
5537ba9daSTianrui Zhao  * Copyright (c) 2023 Loongson Technology Corporation Limited
6537ba9daSTianrui Zhao  */
7537ba9daSTianrui Zhao 
8537ba9daSTianrui Zhao #include "qemu/osdep.h"
9537ba9daSTianrui Zhao #include <sys/ioctl.h>
10537ba9daSTianrui Zhao #include <linux/kvm.h>
11537ba9daSTianrui Zhao 
12c23a53d8SBibo Mao #include "qapi/error.h"
13537ba9daSTianrui Zhao #include "qemu/timer.h"
14537ba9daSTianrui Zhao #include "qemu/error-report.h"
15537ba9daSTianrui Zhao #include "qemu/main-loop.h"
1632cad1ffSPhilippe Mathieu-Daudé #include "system/system.h"
1732cad1ffSPhilippe Mathieu-Daudé #include "system/kvm.h"
1832cad1ffSPhilippe Mathieu-Daudé #include "system/kvm_int.h"
19537ba9daSTianrui Zhao #include "hw/pci/pci.h"
20537ba9daSTianrui Zhao #include "exec/memattrs.h"
21537ba9daSTianrui Zhao #include "exec/address-spaces.h"
22537ba9daSTianrui Zhao #include "hw/boards.h"
23537ba9daSTianrui Zhao #include "hw/irq.h"
24537ba9daSTianrui Zhao #include "qemu/log.h"
25537ba9daSTianrui Zhao #include "hw/loader.h"
2632cad1ffSPhilippe Mathieu-Daudé #include "system/runstate.h"
27537ba9daSTianrui Zhao #include "cpu-csr.h"
28537ba9daSTianrui Zhao #include "kvm_loongarch.h"
29f8447436STianrui Zhao #include "trace.h"
30537ba9daSTianrui Zhao 
31537ba9daSTianrui Zhao static bool cap_has_mp_state;
32d38e31efSBibo Mao static unsigned int brk_insn;
33537ba9daSTianrui Zhao const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
34537ba9daSTianrui Zhao     KVM_CAP_LAST_INFO
35537ba9daSTianrui Zhao };
36537ba9daSTianrui Zhao 
3747b54e15SBibo Mao static int kvm_get_stealtime(CPUState *cs)
3847b54e15SBibo Mao {
3947b54e15SBibo Mao     CPULoongArchState *env = cpu_env(cs);
4047b54e15SBibo Mao     int err;
4147b54e15SBibo Mao     struct kvm_device_attr attr = {
4247b54e15SBibo Mao         .group = KVM_LOONGARCH_VCPU_PVTIME_CTRL,
4347b54e15SBibo Mao         .attr = KVM_LOONGARCH_VCPU_PVTIME_GPA,
4447b54e15SBibo Mao         .addr = (uint64_t)&env->stealtime.guest_addr,
4547b54e15SBibo Mao     };
4647b54e15SBibo Mao 
4747b54e15SBibo Mao     err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr);
4847b54e15SBibo Mao     if (err) {
4947b54e15SBibo Mao         return 0;
5047b54e15SBibo Mao     }
5147b54e15SBibo Mao 
5247b54e15SBibo Mao     err = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, attr);
5347b54e15SBibo Mao     if (err) {
5447b54e15SBibo Mao         error_report("PVTIME: KVM_GET_DEVICE_ATTR: %s", strerror(errno));
5547b54e15SBibo Mao         return err;
5647b54e15SBibo Mao     }
5747b54e15SBibo Mao 
5847b54e15SBibo Mao     return 0;
5947b54e15SBibo Mao }
6047b54e15SBibo Mao 
6147b54e15SBibo Mao static int kvm_set_stealtime(CPUState *cs)
6247b54e15SBibo Mao {
6347b54e15SBibo Mao     CPULoongArchState *env = cpu_env(cs);
6447b54e15SBibo Mao     int err;
6547b54e15SBibo Mao     struct kvm_device_attr attr = {
6647b54e15SBibo Mao         .group = KVM_LOONGARCH_VCPU_PVTIME_CTRL,
6747b54e15SBibo Mao         .attr = KVM_LOONGARCH_VCPU_PVTIME_GPA,
6847b54e15SBibo Mao         .addr = (uint64_t)&env->stealtime.guest_addr,
6947b54e15SBibo Mao     };
7047b54e15SBibo Mao 
7147b54e15SBibo Mao     err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr);
7247b54e15SBibo Mao     if (err) {
7347b54e15SBibo Mao         return 0;
7447b54e15SBibo Mao     }
7547b54e15SBibo Mao 
7647b54e15SBibo Mao     err = kvm_vcpu_ioctl(cs, KVM_SET_DEVICE_ATTR, attr);
7747b54e15SBibo Mao     if (err) {
7847b54e15SBibo Mao         error_report("PVTIME: KVM_SET_DEVICE_ATTR %s with gpa "TARGET_FMT_lx,
7947b54e15SBibo Mao                       strerror(errno), env->stealtime.guest_addr);
8047b54e15SBibo Mao         return err;
8147b54e15SBibo Mao     }
8247b54e15SBibo Mao 
8347b54e15SBibo Mao     return 0;
8447b54e15SBibo Mao }
8547b54e15SBibo Mao 
86f8447436STianrui Zhao static int kvm_loongarch_get_regs_core(CPUState *cs)
87f8447436STianrui Zhao {
88f8447436STianrui Zhao     int ret = 0;
89f8447436STianrui Zhao     int i;
90f8447436STianrui Zhao     struct kvm_regs regs;
91f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
92f8447436STianrui Zhao 
93f8447436STianrui Zhao     /* Get the current register set as KVM seems it */
94f8447436STianrui Zhao     ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, &regs);
95f8447436STianrui Zhao     if (ret < 0) {
96f8447436STianrui Zhao         trace_kvm_failed_get_regs_core(strerror(errno));
97f8447436STianrui Zhao         return ret;
98f8447436STianrui Zhao     }
99f8447436STianrui Zhao     /* gpr[0] value is always 0 */
100f8447436STianrui Zhao     env->gpr[0] = 0;
101f8447436STianrui Zhao     for (i = 1; i < 32; i++) {
102f8447436STianrui Zhao         env->gpr[i] = regs.gpr[i];
103f8447436STianrui Zhao     }
104f8447436STianrui Zhao 
105f8447436STianrui Zhao     env->pc = regs.pc;
106f8447436STianrui Zhao     return ret;
107f8447436STianrui Zhao }
108f8447436STianrui Zhao 
109f8447436STianrui Zhao static int kvm_loongarch_put_regs_core(CPUState *cs)
110f8447436STianrui Zhao {
111f8447436STianrui Zhao     int ret = 0;
112f8447436STianrui Zhao     int i;
113f8447436STianrui Zhao     struct kvm_regs regs;
114f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
115f8447436STianrui Zhao 
116f8447436STianrui Zhao     /* Set the registers based on QEMU's view of things */
117f8447436STianrui Zhao     for (i = 0; i < 32; i++) {
118f8447436STianrui Zhao         regs.gpr[i] = env->gpr[i];
119f8447436STianrui Zhao     }
120f8447436STianrui Zhao 
121f8447436STianrui Zhao     regs.pc = env->pc;
122f8447436STianrui Zhao     ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, &regs);
123f8447436STianrui Zhao     if (ret < 0) {
124f8447436STianrui Zhao         trace_kvm_failed_put_regs_core(strerror(errno));
125f8447436STianrui Zhao     }
126f8447436STianrui Zhao 
127f8447436STianrui Zhao     return ret;
128f8447436STianrui Zhao }
129f8447436STianrui Zhao 
130f8447436STianrui Zhao static int kvm_loongarch_get_csr(CPUState *cs)
131f8447436STianrui Zhao {
132f8447436STianrui Zhao     int ret = 0;
133f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
134f8447436STianrui Zhao 
135f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CRMD),
136f8447436STianrui Zhao                            &env->CSR_CRMD);
137f8447436STianrui Zhao 
138f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRMD),
139f8447436STianrui Zhao                            &env->CSR_PRMD);
140f8447436STianrui Zhao 
141f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EUEN),
142f8447436STianrui Zhao                            &env->CSR_EUEN);
143f8447436STianrui Zhao 
144f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MISC),
145f8447436STianrui Zhao                            &env->CSR_MISC);
146f8447436STianrui Zhao 
147f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ECFG),
148f8447436STianrui Zhao                            &env->CSR_ECFG);
149f8447436STianrui Zhao 
150f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ESTAT),
151f8447436STianrui Zhao                            &env->CSR_ESTAT);
152f8447436STianrui Zhao 
153f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ERA),
154f8447436STianrui Zhao                            &env->CSR_ERA);
155f8447436STianrui Zhao 
156f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADV),
157f8447436STianrui Zhao                            &env->CSR_BADV);
158f8447436STianrui Zhao 
159f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADI),
160f8447436STianrui Zhao                            &env->CSR_BADI);
161f8447436STianrui Zhao 
162f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EENTRY),
163f8447436STianrui Zhao                            &env->CSR_EENTRY);
164f8447436STianrui Zhao 
165f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBIDX),
166f8447436STianrui Zhao                            &env->CSR_TLBIDX);
167f8447436STianrui Zhao 
168f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBEHI),
169f8447436STianrui Zhao                            &env->CSR_TLBEHI);
170f8447436STianrui Zhao 
171f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO0),
172f8447436STianrui Zhao                            &env->CSR_TLBELO0);
173f8447436STianrui Zhao 
174f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO1),
175f8447436STianrui Zhao                            &env->CSR_TLBELO1);
176f8447436STianrui Zhao 
177f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ASID),
178f8447436STianrui Zhao                            &env->CSR_ASID);
179f8447436STianrui Zhao 
180f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDL),
181f8447436STianrui Zhao                            &env->CSR_PGDL);
182f8447436STianrui Zhao 
183f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDH),
184f8447436STianrui Zhao                            &env->CSR_PGDH);
185f8447436STianrui Zhao 
186f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGD),
187f8447436STianrui Zhao                            &env->CSR_PGD);
188f8447436STianrui Zhao 
189f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCL),
190f8447436STianrui Zhao                            &env->CSR_PWCL);
191f8447436STianrui Zhao 
192f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCH),
193f8447436STianrui Zhao                            &env->CSR_PWCH);
194f8447436STianrui Zhao 
195f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_STLBPS),
196f8447436STianrui Zhao                            &env->CSR_STLBPS);
197f8447436STianrui Zhao 
198f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_RVACFG),
199f8447436STianrui Zhao                            &env->CSR_RVACFG);
200f8447436STianrui Zhao 
201f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CPUID),
202f8447436STianrui Zhao                            &env->CSR_CPUID);
203f8447436STianrui Zhao 
204f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG1),
205f8447436STianrui Zhao                            &env->CSR_PRCFG1);
206f8447436STianrui Zhao 
207f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG2),
208f8447436STianrui Zhao                            &env->CSR_PRCFG2);
209f8447436STianrui Zhao 
210f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG3),
211f8447436STianrui Zhao                            &env->CSR_PRCFG3);
212f8447436STianrui Zhao 
213f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(0)),
214f8447436STianrui Zhao                            &env->CSR_SAVE[0]);
215f8447436STianrui Zhao 
216f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(1)),
217f8447436STianrui Zhao                            &env->CSR_SAVE[1]);
218f8447436STianrui Zhao 
219f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(2)),
220f8447436STianrui Zhao                            &env->CSR_SAVE[2]);
221f8447436STianrui Zhao 
222f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(3)),
223f8447436STianrui Zhao                            &env->CSR_SAVE[3]);
224f8447436STianrui Zhao 
225f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(4)),
226f8447436STianrui Zhao                            &env->CSR_SAVE[4]);
227f8447436STianrui Zhao 
228f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(5)),
229f8447436STianrui Zhao                            &env->CSR_SAVE[5]);
230f8447436STianrui Zhao 
231f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(6)),
232f8447436STianrui Zhao                            &env->CSR_SAVE[6]);
233f8447436STianrui Zhao 
234f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(7)),
235f8447436STianrui Zhao                            &env->CSR_SAVE[7]);
236f8447436STianrui Zhao 
237f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TID),
238f8447436STianrui Zhao                            &env->CSR_TID);
239f8447436STianrui Zhao 
240f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CNTC),
241f8447436STianrui Zhao                            &env->CSR_CNTC);
242f8447436STianrui Zhao 
243f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TICLR),
244f8447436STianrui Zhao                            &env->CSR_TICLR);
245f8447436STianrui Zhao 
246f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_LLBCTL),
247f8447436STianrui Zhao                            &env->CSR_LLBCTL);
248f8447436STianrui Zhao 
249f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL1),
250f8447436STianrui Zhao                            &env->CSR_IMPCTL1);
251f8447436STianrui Zhao 
252f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL2),
253f8447436STianrui Zhao                            &env->CSR_IMPCTL2);
254f8447436STianrui Zhao 
255f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRENTRY),
256f8447436STianrui Zhao                            &env->CSR_TLBRENTRY);
257f8447436STianrui Zhao 
258f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRBADV),
259f8447436STianrui Zhao                            &env->CSR_TLBRBADV);
260f8447436STianrui Zhao 
261f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRERA),
262f8447436STianrui Zhao                            &env->CSR_TLBRERA);
263f8447436STianrui Zhao 
264f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRSAVE),
265f8447436STianrui Zhao                            &env->CSR_TLBRSAVE);
266f8447436STianrui Zhao 
267f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO0),
268f8447436STianrui Zhao                            &env->CSR_TLBRELO0);
269f8447436STianrui Zhao 
270f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO1),
271f8447436STianrui Zhao                            &env->CSR_TLBRELO1);
272f8447436STianrui Zhao 
273f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBREHI),
274f8447436STianrui Zhao                            &env->CSR_TLBREHI);
275f8447436STianrui Zhao 
276f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRPRMD),
277f8447436STianrui Zhao                            &env->CSR_TLBRPRMD);
278f8447436STianrui Zhao 
279f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(0)),
280f8447436STianrui Zhao                            &env->CSR_DMW[0]);
281f8447436STianrui Zhao 
282f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(1)),
283f8447436STianrui Zhao                            &env->CSR_DMW[1]);
284f8447436STianrui Zhao 
285f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(2)),
286f8447436STianrui Zhao                            &env->CSR_DMW[2]);
287f8447436STianrui Zhao 
288f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(3)),
289f8447436STianrui Zhao                            &env->CSR_DMW[3]);
290f8447436STianrui Zhao 
291f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TVAL),
292f8447436STianrui Zhao                            &env->CSR_TVAL);
293f8447436STianrui Zhao 
294f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TCFG),
295f8447436STianrui Zhao                            &env->CSR_TCFG);
296f8447436STianrui Zhao 
297f8447436STianrui Zhao     return ret;
298f8447436STianrui Zhao }
299f8447436STianrui Zhao 
30061f6e150SBibo Mao static int kvm_loongarch_put_csr(CPUState *cs, int level)
301f8447436STianrui Zhao {
302f8447436STianrui Zhao     int ret = 0;
303f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
304f8447436STianrui Zhao 
305f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CRMD),
306f8447436STianrui Zhao                            &env->CSR_CRMD);
307f8447436STianrui Zhao 
308f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRMD),
309f8447436STianrui Zhao                            &env->CSR_PRMD);
310f8447436STianrui Zhao 
311f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EUEN),
312f8447436STianrui Zhao                            &env->CSR_EUEN);
313f8447436STianrui Zhao 
314f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MISC),
315f8447436STianrui Zhao                            &env->CSR_MISC);
316f8447436STianrui Zhao 
317f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ECFG),
318f8447436STianrui Zhao                            &env->CSR_ECFG);
319f8447436STianrui Zhao 
320f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ESTAT),
321f8447436STianrui Zhao                            &env->CSR_ESTAT);
322f8447436STianrui Zhao 
323f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ERA),
324f8447436STianrui Zhao                            &env->CSR_ERA);
325f8447436STianrui Zhao 
326f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADV),
327f8447436STianrui Zhao                            &env->CSR_BADV);
328f8447436STianrui Zhao 
329f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADI),
330f8447436STianrui Zhao                            &env->CSR_BADI);
331f8447436STianrui Zhao 
332f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EENTRY),
333f8447436STianrui Zhao                            &env->CSR_EENTRY);
334f8447436STianrui Zhao 
335f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBIDX),
336f8447436STianrui Zhao                            &env->CSR_TLBIDX);
337f8447436STianrui Zhao 
338f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBEHI),
339f8447436STianrui Zhao                            &env->CSR_TLBEHI);
340f8447436STianrui Zhao 
341f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO0),
342f8447436STianrui Zhao                            &env->CSR_TLBELO0);
343f8447436STianrui Zhao 
344f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO1),
345f8447436STianrui Zhao                            &env->CSR_TLBELO1);
346f8447436STianrui Zhao 
347f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ASID),
348f8447436STianrui Zhao                            &env->CSR_ASID);
349f8447436STianrui Zhao 
350f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDL),
351f8447436STianrui Zhao                            &env->CSR_PGDL);
352f8447436STianrui Zhao 
353f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDH),
354f8447436STianrui Zhao                            &env->CSR_PGDH);
355f8447436STianrui Zhao 
356f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGD),
357f8447436STianrui Zhao                            &env->CSR_PGD);
358f8447436STianrui Zhao 
359f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCL),
360f8447436STianrui Zhao                            &env->CSR_PWCL);
361f8447436STianrui Zhao 
362f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCH),
363f8447436STianrui Zhao                            &env->CSR_PWCH);
364f8447436STianrui Zhao 
365f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_STLBPS),
366f8447436STianrui Zhao                            &env->CSR_STLBPS);
367f8447436STianrui Zhao 
368f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_RVACFG),
369f8447436STianrui Zhao                            &env->CSR_RVACFG);
370f8447436STianrui Zhao 
37161f6e150SBibo Mao     /* CPUID is constant after poweron, it should be set only once */
37261f6e150SBibo Mao     if (level >= KVM_PUT_FULL_STATE) {
373f8447436STianrui Zhao         ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CPUID),
374f8447436STianrui Zhao                            &env->CSR_CPUID);
37561f6e150SBibo Mao     }
376f8447436STianrui Zhao 
377f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG1),
378f8447436STianrui Zhao                            &env->CSR_PRCFG1);
379f8447436STianrui Zhao 
380f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG2),
381f8447436STianrui Zhao                            &env->CSR_PRCFG2);
382f8447436STianrui Zhao 
383f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG3),
384f8447436STianrui Zhao                            &env->CSR_PRCFG3);
385f8447436STianrui Zhao 
386f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(0)),
387f8447436STianrui Zhao                            &env->CSR_SAVE[0]);
388f8447436STianrui Zhao 
389f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(1)),
390f8447436STianrui Zhao                            &env->CSR_SAVE[1]);
391f8447436STianrui Zhao 
392f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(2)),
393f8447436STianrui Zhao                            &env->CSR_SAVE[2]);
394f8447436STianrui Zhao 
395f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(3)),
396f8447436STianrui Zhao                            &env->CSR_SAVE[3]);
397f8447436STianrui Zhao 
398f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(4)),
399f8447436STianrui Zhao                            &env->CSR_SAVE[4]);
400f8447436STianrui Zhao 
401f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(5)),
402f8447436STianrui Zhao                            &env->CSR_SAVE[5]);
403f8447436STianrui Zhao 
404f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(6)),
405f8447436STianrui Zhao                            &env->CSR_SAVE[6]);
406f8447436STianrui Zhao 
407f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(7)),
408f8447436STianrui Zhao                            &env->CSR_SAVE[7]);
409f8447436STianrui Zhao 
410f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TID),
411f8447436STianrui Zhao                            &env->CSR_TID);
412f8447436STianrui Zhao 
413f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CNTC),
414f8447436STianrui Zhao                            &env->CSR_CNTC);
415f8447436STianrui Zhao 
416f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TICLR),
417f8447436STianrui Zhao                            &env->CSR_TICLR);
418f8447436STianrui Zhao 
419f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_LLBCTL),
420f8447436STianrui Zhao                            &env->CSR_LLBCTL);
421f8447436STianrui Zhao 
422f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL1),
423f8447436STianrui Zhao                            &env->CSR_IMPCTL1);
424f8447436STianrui Zhao 
425f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL2),
426f8447436STianrui Zhao                            &env->CSR_IMPCTL2);
427f8447436STianrui Zhao 
428f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRENTRY),
429f8447436STianrui Zhao                            &env->CSR_TLBRENTRY);
430f8447436STianrui Zhao 
431f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRBADV),
432f8447436STianrui Zhao                            &env->CSR_TLBRBADV);
433f8447436STianrui Zhao 
434f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRERA),
435f8447436STianrui Zhao                            &env->CSR_TLBRERA);
436f8447436STianrui Zhao 
437f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRSAVE),
438f8447436STianrui Zhao                            &env->CSR_TLBRSAVE);
439f8447436STianrui Zhao 
440f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO0),
441f8447436STianrui Zhao                            &env->CSR_TLBRELO0);
442f8447436STianrui Zhao 
443f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO1),
444f8447436STianrui Zhao                            &env->CSR_TLBRELO1);
445f8447436STianrui Zhao 
446f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBREHI),
447f8447436STianrui Zhao                            &env->CSR_TLBREHI);
448f8447436STianrui Zhao 
449f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRPRMD),
450f8447436STianrui Zhao                            &env->CSR_TLBRPRMD);
451f8447436STianrui Zhao 
452f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(0)),
453f8447436STianrui Zhao                            &env->CSR_DMW[0]);
454f8447436STianrui Zhao 
455f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(1)),
456f8447436STianrui Zhao                            &env->CSR_DMW[1]);
457f8447436STianrui Zhao 
458f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(2)),
459f8447436STianrui Zhao                            &env->CSR_DMW[2]);
460f8447436STianrui Zhao 
461f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(3)),
462f8447436STianrui Zhao                            &env->CSR_DMW[3]);
463f8447436STianrui Zhao     /*
464f8447436STianrui Zhao      * timer cfg must be put at last since it is used to enable
465f8447436STianrui Zhao      * guest timer
466f8447436STianrui Zhao      */
467f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TVAL),
468f8447436STianrui Zhao                            &env->CSR_TVAL);
469f8447436STianrui Zhao 
470f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TCFG),
471f8447436STianrui Zhao                            &env->CSR_TCFG);
472f8447436STianrui Zhao     return ret;
473f8447436STianrui Zhao }
474f8447436STianrui Zhao 
475f8447436STianrui Zhao static int kvm_loongarch_get_regs_fp(CPUState *cs)
476f8447436STianrui Zhao {
477f8447436STianrui Zhao     int ret, i;
478f8447436STianrui Zhao     struct kvm_fpu fpu;
479f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
480f8447436STianrui Zhao 
481f8447436STianrui Zhao     ret = kvm_vcpu_ioctl(cs, KVM_GET_FPU, &fpu);
482f8447436STianrui Zhao     if (ret < 0) {
483f8447436STianrui Zhao         trace_kvm_failed_get_fpu(strerror(errno));
484f8447436STianrui Zhao         return ret;
485f8447436STianrui Zhao     }
486f8447436STianrui Zhao 
487f8447436STianrui Zhao     env->fcsr0 = fpu.fcsr;
488f8447436STianrui Zhao     for (i = 0; i < 32; i++) {
489f8447436STianrui Zhao         env->fpr[i].vreg.UD[0] = fpu.fpr[i].val64[0];
49007c08661SSong Gao         env->fpr[i].vreg.UD[1] = fpu.fpr[i].val64[1];
49107c08661SSong Gao         env->fpr[i].vreg.UD[2] = fpu.fpr[i].val64[2];
49207c08661SSong Gao         env->fpr[i].vreg.UD[3] = fpu.fpr[i].val64[3];
493f8447436STianrui Zhao     }
494f8447436STianrui Zhao     for (i = 0; i < 8; i++) {
495f8447436STianrui Zhao         env->cf[i] = fpu.fcc & 0xFF;
496f8447436STianrui Zhao         fpu.fcc = fpu.fcc >> 8;
497f8447436STianrui Zhao     }
498f8447436STianrui Zhao 
499f8447436STianrui Zhao     return ret;
500f8447436STianrui Zhao }
501f8447436STianrui Zhao 
502f8447436STianrui Zhao static int kvm_loongarch_put_regs_fp(CPUState *cs)
503f8447436STianrui Zhao {
504f8447436STianrui Zhao     int ret, i;
505f8447436STianrui Zhao     struct kvm_fpu fpu;
506f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
507f8447436STianrui Zhao 
508f8447436STianrui Zhao     fpu.fcsr = env->fcsr0;
509f8447436STianrui Zhao     fpu.fcc = 0;
510f8447436STianrui Zhao     for (i = 0; i < 32; i++) {
511f8447436STianrui Zhao         fpu.fpr[i].val64[0] = env->fpr[i].vreg.UD[0];
51207c08661SSong Gao         fpu.fpr[i].val64[1] = env->fpr[i].vreg.UD[1];
51307c08661SSong Gao         fpu.fpr[i].val64[2] = env->fpr[i].vreg.UD[2];
51407c08661SSong Gao         fpu.fpr[i].val64[3] = env->fpr[i].vreg.UD[3];
515f8447436STianrui Zhao     }
516f8447436STianrui Zhao 
517f8447436STianrui Zhao     for (i = 0; i < 8; i++) {
518f8447436STianrui Zhao         fpu.fcc |= env->cf[i] << (8 * i);
519f8447436STianrui Zhao     }
520f8447436STianrui Zhao 
521f8447436STianrui Zhao     ret = kvm_vcpu_ioctl(cs, KVM_SET_FPU, &fpu);
522f8447436STianrui Zhao     if (ret < 0) {
523f8447436STianrui Zhao         trace_kvm_failed_put_fpu(strerror(errno));
524f8447436STianrui Zhao     }
525f8447436STianrui Zhao 
526f8447436STianrui Zhao     return ret;
527f8447436STianrui Zhao }
528f8447436STianrui Zhao 
529a45df286SBibo Mao static int kvm_loongarch_put_lbt(CPUState *cs)
530a45df286SBibo Mao {
531a45df286SBibo Mao     CPULoongArchState *env = cpu_env(cs);
532a45df286SBibo Mao     uint64_t val;
533a45df286SBibo Mao     int ret;
534a45df286SBibo Mao 
535a45df286SBibo Mao     /* check whether vm support LBT firstly */
536a45df286SBibo Mao     if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LBT_ALL) != 7) {
537a45df286SBibo Mao         return 0;
538a45df286SBibo Mao     }
539a45df286SBibo Mao 
540a45df286SBibo Mao     /* set six LBT registers including scr0-scr3, eflags, ftop */
541a45df286SBibo Mao     ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR0, &env->lbt.scr0);
542a45df286SBibo Mao     ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR1, &env->lbt.scr1);
543a45df286SBibo Mao     ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR2, &env->lbt.scr2);
544a45df286SBibo Mao     ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR3, &env->lbt.scr3);
545a45df286SBibo Mao     /*
546a45df286SBibo Mao      * Be cautious, KVM_REG_LOONGARCH_LBT_FTOP is defined as 64-bit however
547a45df286SBibo Mao      * lbt.ftop is 32-bit; the same with KVM_REG_LOONGARCH_LBT_EFLAGS register
548a45df286SBibo Mao      */
549a45df286SBibo Mao     val = env->lbt.eflags;
550a45df286SBibo Mao     ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_EFLAGS, &val);
551a45df286SBibo Mao     val = env->lbt.ftop;
552a45df286SBibo Mao     ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_FTOP, &val);
553a45df286SBibo Mao 
554a45df286SBibo Mao     return ret;
555a45df286SBibo Mao }
556a45df286SBibo Mao 
557a45df286SBibo Mao static int kvm_loongarch_get_lbt(CPUState *cs)
558a45df286SBibo Mao {
559a45df286SBibo Mao     CPULoongArchState *env = cpu_env(cs);
560a45df286SBibo Mao     uint64_t val;
561a45df286SBibo Mao     int ret;
562a45df286SBibo Mao 
563a45df286SBibo Mao     /* check whether vm support LBT firstly */
564a45df286SBibo Mao     if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LBT_ALL) != 7) {
565a45df286SBibo Mao         return 0;
566a45df286SBibo Mao     }
567a45df286SBibo Mao 
568a45df286SBibo Mao     /* get six LBT registers including scr0-scr3, eflags, ftop */
569a45df286SBibo Mao     ret = kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR0, &env->lbt.scr0);
570a45df286SBibo Mao     ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR1, &env->lbt.scr1);
571a45df286SBibo Mao     ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR2, &env->lbt.scr2);
572a45df286SBibo Mao     ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR3, &env->lbt.scr3);
573a45df286SBibo Mao     ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_EFLAGS, &val);
574a45df286SBibo Mao     env->lbt.eflags = (uint32_t)val;
575a45df286SBibo Mao     ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_FTOP, &val);
576a45df286SBibo Mao     env->lbt.ftop = (uint32_t)val;
577a45df286SBibo Mao 
578a45df286SBibo Mao     return ret;
579a45df286SBibo Mao }
580a45df286SBibo Mao 
581a724f5a8SBibo Mao void kvm_arch_reset_vcpu(CPUState *cs)
582f8447436STianrui Zhao {
583a724f5a8SBibo Mao     CPULoongArchState *env = cpu_env(cs);
584a724f5a8SBibo Mao 
585f8447436STianrui Zhao     env->mp_state = KVM_MP_STATE_RUNNABLE;
586a724f5a8SBibo Mao     kvm_set_one_reg(cs, KVM_REG_LOONGARCH_VCPU_RESET, 0);
587f8447436STianrui Zhao }
588f8447436STianrui Zhao 
589f8447436STianrui Zhao static int kvm_loongarch_get_mpstate(CPUState *cs)
590f8447436STianrui Zhao {
591f8447436STianrui Zhao     int ret = 0;
592f8447436STianrui Zhao     struct kvm_mp_state mp_state;
593f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
594f8447436STianrui Zhao 
595f8447436STianrui Zhao     if (cap_has_mp_state) {
596f8447436STianrui Zhao         ret = kvm_vcpu_ioctl(cs, KVM_GET_MP_STATE, &mp_state);
597f8447436STianrui Zhao         if (ret) {
598f8447436STianrui Zhao             trace_kvm_failed_get_mpstate(strerror(errno));
599f8447436STianrui Zhao             return ret;
600f8447436STianrui Zhao         }
601f8447436STianrui Zhao         env->mp_state = mp_state.mp_state;
602f8447436STianrui Zhao     }
603f8447436STianrui Zhao 
604f8447436STianrui Zhao     return ret;
605f8447436STianrui Zhao }
606f8447436STianrui Zhao 
607f8447436STianrui Zhao static int kvm_loongarch_put_mpstate(CPUState *cs)
608f8447436STianrui Zhao {
609f8447436STianrui Zhao     int ret = 0;
610f8447436STianrui Zhao     struct kvm_mp_state mp_state = {
611f3b603b9SPhilippe Mathieu-Daudé         .mp_state = cpu_env(cs)->mp_state
612f8447436STianrui Zhao     };
613f8447436STianrui Zhao 
614f8447436STianrui Zhao     if (cap_has_mp_state) {
615f8447436STianrui Zhao         ret = kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state);
616f8447436STianrui Zhao         if (ret) {
617f8447436STianrui Zhao             trace_kvm_failed_put_mpstate(strerror(errno));
618f8447436STianrui Zhao         }
619f8447436STianrui Zhao     }
620f8447436STianrui Zhao 
621f8447436STianrui Zhao     return ret;
622f8447436STianrui Zhao }
623f8447436STianrui Zhao 
624f8447436STianrui Zhao static int kvm_loongarch_get_cpucfg(CPUState *cs)
625f8447436STianrui Zhao {
626f8447436STianrui Zhao     int i, ret = 0;
627f8447436STianrui Zhao     uint64_t val;
628f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
629f8447436STianrui Zhao 
630f8447436STianrui Zhao     for (i = 0; i < 21; i++) {
631f8447436STianrui Zhao         ret = kvm_get_one_reg(cs, KVM_IOC_CPUCFG(i), &val);
632f8447436STianrui Zhao         if (ret < 0) {
633f8447436STianrui Zhao             trace_kvm_failed_get_cpucfg(strerror(errno));
634f8447436STianrui Zhao         }
635f8447436STianrui Zhao         env->cpucfg[i] = (uint32_t)val;
636f8447436STianrui Zhao     }
637f8447436STianrui Zhao     return ret;
638f8447436STianrui Zhao }
639f8447436STianrui Zhao 
640fc700996SSong Gao static int kvm_check_cpucfg2(CPUState *cs)
641fc700996SSong Gao {
642fc700996SSong Gao     int ret;
643fc700996SSong Gao     uint64_t val;
644fc700996SSong Gao     struct kvm_device_attr attr = {
645fc700996SSong Gao         .group = KVM_LOONGARCH_VCPU_CPUCFG,
646fc700996SSong Gao         .attr = 2,
647fc700996SSong Gao         .addr = (uint64_t)&val,
648fc700996SSong Gao     };
649f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
650fc700996SSong Gao 
651fc700996SSong Gao     ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr);
652fc700996SSong Gao 
653fc700996SSong Gao     if (!ret) {
654fc700996SSong Gao         kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
655fc700996SSong Gao         env->cpucfg[2] &= val;
656fc700996SSong Gao 
657fc700996SSong Gao         if (FIELD_EX32(env->cpucfg[2], CPUCFG2, FP)) {
658fc700996SSong Gao             /* The FP minimal version is 1. */
659fc700996SSong Gao             env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, FP_VER, 1);
660fc700996SSong Gao         }
661fc700996SSong Gao 
662fc700996SSong Gao         if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LLFTP)) {
663fc700996SSong Gao             /* The LLFTP minimal version is 1. */
664fc700996SSong Gao             env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LLFTP_VER, 1);
665fc700996SSong Gao         }
666fc700996SSong Gao     }
667fc700996SSong Gao 
668fc700996SSong Gao     return ret;
669fc700996SSong Gao }
670fc700996SSong Gao 
671f8447436STianrui Zhao static int kvm_loongarch_put_cpucfg(CPUState *cs)
672f8447436STianrui Zhao {
673f8447436STianrui Zhao     int i, ret = 0;
674f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
675f8447436STianrui Zhao     uint64_t val;
676f8447436STianrui Zhao 
677f8447436STianrui Zhao     for (i = 0; i < 21; i++) {
678f8447436STianrui Zhao 	if (i == 2) {
679fc700996SSong Gao             ret = kvm_check_cpucfg2(cs);
680fc700996SSong Gao             if (ret) {
681fc700996SSong Gao                 return ret;
682f8447436STianrui Zhao             }
683fc700996SSong Gao 	}
684fc700996SSong Gao         val = env->cpucfg[i];
685f8447436STianrui Zhao         ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val);
686f8447436STianrui Zhao         if (ret < 0) {
687f8447436STianrui Zhao             trace_kvm_failed_put_cpucfg(strerror(errno));
688f8447436STianrui Zhao         }
689f8447436STianrui Zhao     }
690f8447436STianrui Zhao     return ret;
691f8447436STianrui Zhao }
692f8447436STianrui Zhao 
693a1676bb3SJulia Suvorova int kvm_arch_get_registers(CPUState *cs, Error **errp)
694537ba9daSTianrui Zhao {
695f8447436STianrui Zhao     int ret;
696f8447436STianrui Zhao 
697f8447436STianrui Zhao     ret = kvm_loongarch_get_regs_core(cs);
698f8447436STianrui Zhao     if (ret) {
699f8447436STianrui Zhao         return ret;
700537ba9daSTianrui Zhao     }
701f8447436STianrui Zhao 
7025872966dSBibo Mao     ret = kvm_loongarch_get_cpucfg(cs);
7035872966dSBibo Mao     if (ret) {
7045872966dSBibo Mao         return ret;
7055872966dSBibo Mao     }
7065872966dSBibo Mao 
707f8447436STianrui Zhao     ret = kvm_loongarch_get_csr(cs);
708f8447436STianrui Zhao     if (ret) {
709f8447436STianrui Zhao         return ret;
710f8447436STianrui Zhao     }
711f8447436STianrui Zhao 
712f8447436STianrui Zhao     ret = kvm_loongarch_get_regs_fp(cs);
713f8447436STianrui Zhao     if (ret) {
714f8447436STianrui Zhao         return ret;
715f8447436STianrui Zhao     }
716f8447436STianrui Zhao 
717a45df286SBibo Mao     ret = kvm_loongarch_get_lbt(cs);
718a45df286SBibo Mao     if (ret) {
719a45df286SBibo Mao         return ret;
720a45df286SBibo Mao     }
721a45df286SBibo Mao 
72247b54e15SBibo Mao     ret = kvm_get_stealtime(cs);
72347b54e15SBibo Mao     if (ret) {
72447b54e15SBibo Mao         return ret;
72547b54e15SBibo Mao     }
72647b54e15SBibo Mao 
727f8447436STianrui Zhao     ret = kvm_loongarch_get_mpstate(cs);
728f8447436STianrui Zhao     return ret;
729f8447436STianrui Zhao }
730f8447436STianrui Zhao 
731a1676bb3SJulia Suvorova int kvm_arch_put_registers(CPUState *cs, int level, Error **errp)
732537ba9daSTianrui Zhao {
733f8447436STianrui Zhao     int ret;
734f8447436STianrui Zhao 
735f8447436STianrui Zhao     ret = kvm_loongarch_put_regs_core(cs);
736f8447436STianrui Zhao     if (ret) {
737f8447436STianrui Zhao         return ret;
738f8447436STianrui Zhao     }
739f8447436STianrui Zhao 
7405872966dSBibo Mao     ret = kvm_loongarch_put_cpucfg(cs);
7415872966dSBibo Mao     if (ret) {
7425872966dSBibo Mao         return ret;
7435872966dSBibo Mao     }
7445872966dSBibo Mao 
74561f6e150SBibo Mao     ret = kvm_loongarch_put_csr(cs, level);
746f8447436STianrui Zhao     if (ret) {
747f8447436STianrui Zhao         return ret;
748f8447436STianrui Zhao     }
749f8447436STianrui Zhao 
750f8447436STianrui Zhao     ret = kvm_loongarch_put_regs_fp(cs);
751f8447436STianrui Zhao     if (ret) {
752f8447436STianrui Zhao         return ret;
753f8447436STianrui Zhao     }
754f8447436STianrui Zhao 
755a45df286SBibo Mao     ret = kvm_loongarch_put_lbt(cs);
756a45df286SBibo Mao     if (ret) {
757a45df286SBibo Mao         return ret;
758a45df286SBibo Mao     }
759a45df286SBibo Mao 
76047b54e15SBibo Mao     if (level >= KVM_PUT_FULL_STATE) {
76147b54e15SBibo Mao         /*
76247b54e15SBibo Mao          * only KVM_PUT_FULL_STATE is required, kvm kernel will clear
76347b54e15SBibo Mao          * guest_addr for KVM_PUT_RESET_STATE
76447b54e15SBibo Mao          */
76547b54e15SBibo Mao         ret = kvm_set_stealtime(cs);
76647b54e15SBibo Mao         if (ret) {
76747b54e15SBibo Mao             return ret;
76847b54e15SBibo Mao         }
76947b54e15SBibo Mao     }
77047b54e15SBibo Mao 
771f8447436STianrui Zhao     ret = kvm_loongarch_put_mpstate(cs);
772f8447436STianrui Zhao     return ret;
773537ba9daSTianrui Zhao }
774537ba9daSTianrui Zhao 
775d11681c9STianrui Zhao static void kvm_loongarch_vm_stage_change(void *opaque, bool running,
776d11681c9STianrui Zhao                                           RunState state)
777d11681c9STianrui Zhao {
778d11681c9STianrui Zhao     int ret;
779d11681c9STianrui Zhao     CPUState *cs = opaque;
780d11681c9STianrui Zhao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
781d11681c9STianrui Zhao 
782d11681c9STianrui Zhao     if (running) {
783d11681c9STianrui Zhao         ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_COUNTER,
784d11681c9STianrui Zhao                               &cpu->kvm_state_counter);
785d11681c9STianrui Zhao         if (ret < 0) {
786d11681c9STianrui Zhao             trace_kvm_failed_put_counter(strerror(errno));
787d11681c9STianrui Zhao         }
788d11681c9STianrui Zhao     } else {
789d11681c9STianrui Zhao         ret = kvm_get_one_reg(cs, KVM_REG_LOONGARCH_COUNTER,
790d11681c9STianrui Zhao                               &cpu->kvm_state_counter);
791d11681c9STianrui Zhao         if (ret < 0) {
792d11681c9STianrui Zhao             trace_kvm_failed_get_counter(strerror(errno));
793d11681c9STianrui Zhao         }
794d11681c9STianrui Zhao     }
795d11681c9STianrui Zhao }
796d11681c9STianrui Zhao 
797c23a53d8SBibo Mao static bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature)
798c23a53d8SBibo Mao {
799c23a53d8SBibo Mao     int ret;
800c23a53d8SBibo Mao     struct kvm_device_attr attr;
801936c3f4dSBibo Mao     uint64_t val;
802c23a53d8SBibo Mao 
803c23a53d8SBibo Mao     switch (feature) {
804936c3f4dSBibo Mao     case LOONGARCH_FEATURE_LSX:
805936c3f4dSBibo Mao         attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
806936c3f4dSBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_LSX;
807936c3f4dSBibo Mao         ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
808936c3f4dSBibo Mao         if (ret == 0) {
809936c3f4dSBibo Mao             return true;
810936c3f4dSBibo Mao         }
811936c3f4dSBibo Mao 
812936c3f4dSBibo Mao         /* Fallback to old kernel detect interface */
813936c3f4dSBibo Mao         val = 0;
814936c3f4dSBibo Mao         attr.group = KVM_LOONGARCH_VCPU_CPUCFG;
815936c3f4dSBibo Mao         /* Cpucfg2 */
816936c3f4dSBibo Mao         attr.attr  = 2;
817936c3f4dSBibo Mao         attr.addr = (uint64_t)&val;
818936c3f4dSBibo Mao         ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr);
819936c3f4dSBibo Mao         if (!ret) {
820936c3f4dSBibo Mao             ret = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
821936c3f4dSBibo Mao             if (ret) {
822936c3f4dSBibo Mao                 return false;
823936c3f4dSBibo Mao             }
824936c3f4dSBibo Mao 
825936c3f4dSBibo Mao             ret = FIELD_EX32((uint32_t)val, CPUCFG2, LSX);
826936c3f4dSBibo Mao             return (ret != 0);
827936c3f4dSBibo Mao         }
828936c3f4dSBibo Mao         return false;
829936c3f4dSBibo Mao 
830*5e360dabSBibo Mao     case LOONGARCH_FEATURE_LASX:
831*5e360dabSBibo Mao         attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
832*5e360dabSBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_LASX;
833*5e360dabSBibo Mao         ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
834*5e360dabSBibo Mao         if (ret == 0) {
835*5e360dabSBibo Mao             return true;
836*5e360dabSBibo Mao         }
837*5e360dabSBibo Mao 
838*5e360dabSBibo Mao         /* Fallback to old kernel detect interface */
839*5e360dabSBibo Mao         val = 0;
840*5e360dabSBibo Mao         attr.group = KVM_LOONGARCH_VCPU_CPUCFG;
841*5e360dabSBibo Mao         /* Cpucfg2 */
842*5e360dabSBibo Mao         attr.attr  = 2;
843*5e360dabSBibo Mao         attr.addr = (uint64_t)&val;
844*5e360dabSBibo Mao         ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr);
845*5e360dabSBibo Mao         if (!ret) {
846*5e360dabSBibo Mao             ret = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
847*5e360dabSBibo Mao             if (ret) {
848*5e360dabSBibo Mao                 return false;
849*5e360dabSBibo Mao             }
850*5e360dabSBibo Mao 
851*5e360dabSBibo Mao             ret = FIELD_EX32((uint32_t)val, CPUCFG2, LASX);
852*5e360dabSBibo Mao             return (ret != 0);
853*5e360dabSBibo Mao         }
854*5e360dabSBibo Mao         return false;
855*5e360dabSBibo Mao 
856c23a53d8SBibo Mao     case LOONGARCH_FEATURE_LBT:
857c23a53d8SBibo Mao         /*
858c23a53d8SBibo Mao          * Return all if all the LBT features are supported such as:
859c23a53d8SBibo Mao          *  KVM_LOONGARCH_VM_FEAT_X86BT
860c23a53d8SBibo Mao          *  KVM_LOONGARCH_VM_FEAT_ARMBT
861c23a53d8SBibo Mao          *  KVM_LOONGARCH_VM_FEAT_MIPSBT
862c23a53d8SBibo Mao          */
863c23a53d8SBibo Mao         attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
864c23a53d8SBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_X86BT;
865c23a53d8SBibo Mao         ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
866c23a53d8SBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_ARMBT;
867c23a53d8SBibo Mao         ret |= kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
868c23a53d8SBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_MIPSBT;
869c23a53d8SBibo Mao         ret |= kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
870c23a53d8SBibo Mao         return (ret == 0);
8716edd2a9bSBibo Mao 
8726edd2a9bSBibo Mao     case LOONGARCH_FEATURE_PMU:
8736edd2a9bSBibo Mao         attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
8746edd2a9bSBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_PMU;
8756edd2a9bSBibo Mao         ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
8766edd2a9bSBibo Mao         return (ret == 0);
8776edd2a9bSBibo Mao 
878c23a53d8SBibo Mao     default:
879c23a53d8SBibo Mao         return false;
880c23a53d8SBibo Mao     }
8816edd2a9bSBibo Mao 
8826edd2a9bSBibo Mao     return false;
883c23a53d8SBibo Mao }
884c23a53d8SBibo Mao 
885936c3f4dSBibo Mao static int kvm_cpu_check_lsx(CPUState *cs, Error **errp)
886936c3f4dSBibo Mao {
887936c3f4dSBibo Mao     CPULoongArchState *env = cpu_env(cs);
888936c3f4dSBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
889936c3f4dSBibo Mao     bool kvm_supported;
890936c3f4dSBibo Mao 
891936c3f4dSBibo Mao     kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_LSX);
892936c3f4dSBibo Mao     env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LSX, 0);
893936c3f4dSBibo Mao     if (cpu->lsx == ON_OFF_AUTO_ON) {
894936c3f4dSBibo Mao         if (kvm_supported) {
895936c3f4dSBibo Mao             env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LSX, 1);
896936c3f4dSBibo Mao         } else {
897936c3f4dSBibo Mao             error_setg(errp, "'lsx' feature not supported by KVM on this host");
898936c3f4dSBibo Mao             return -ENOTSUP;
899936c3f4dSBibo Mao         }
900936c3f4dSBibo Mao     } else if ((cpu->lsx == ON_OFF_AUTO_AUTO) && kvm_supported) {
901936c3f4dSBibo Mao         env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LSX, 1);
902936c3f4dSBibo Mao     }
903936c3f4dSBibo Mao 
904936c3f4dSBibo Mao     return 0;
905936c3f4dSBibo Mao }
906936c3f4dSBibo Mao 
907*5e360dabSBibo Mao static int kvm_cpu_check_lasx(CPUState *cs, Error **errp)
908*5e360dabSBibo Mao {
909*5e360dabSBibo Mao     CPULoongArchState *env = cpu_env(cs);
910*5e360dabSBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
911*5e360dabSBibo Mao     bool kvm_supported;
912*5e360dabSBibo Mao 
913*5e360dabSBibo Mao     kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_LASX);
914*5e360dabSBibo Mao     env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LASX, 0);
915*5e360dabSBibo Mao     if (cpu->lasx == ON_OFF_AUTO_ON) {
916*5e360dabSBibo Mao         if (kvm_supported) {
917*5e360dabSBibo Mao             env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LASX, 1);
918*5e360dabSBibo Mao         } else {
919*5e360dabSBibo Mao             error_setg(errp, "'lasx' feature not supported by KVM on host");
920*5e360dabSBibo Mao             return -ENOTSUP;
921*5e360dabSBibo Mao         }
922*5e360dabSBibo Mao     } else if ((cpu->lasx == ON_OFF_AUTO_AUTO) && kvm_supported) {
923*5e360dabSBibo Mao         env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LASX, 1);
924*5e360dabSBibo Mao     }
925*5e360dabSBibo Mao 
926*5e360dabSBibo Mao     return 0;
927*5e360dabSBibo Mao }
928*5e360dabSBibo Mao 
929c23a53d8SBibo Mao static int kvm_cpu_check_lbt(CPUState *cs, Error **errp)
930c23a53d8SBibo Mao {
931c23a53d8SBibo Mao     CPULoongArchState *env = cpu_env(cs);
932c23a53d8SBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
933c23a53d8SBibo Mao     bool kvm_supported;
934c23a53d8SBibo Mao 
935c23a53d8SBibo Mao     kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_LBT);
936c23a53d8SBibo Mao     if (cpu->lbt == ON_OFF_AUTO_ON) {
937c23a53d8SBibo Mao         if (kvm_supported) {
938c23a53d8SBibo Mao             env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LBT_ALL, 7);
939c23a53d8SBibo Mao         } else {
940c23a53d8SBibo Mao             error_setg(errp, "'lbt' feature not supported by KVM on this host");
941c23a53d8SBibo Mao             return -ENOTSUP;
942c23a53d8SBibo Mao         }
943c23a53d8SBibo Mao     } else if ((cpu->lbt == ON_OFF_AUTO_AUTO) && kvm_supported) {
944c23a53d8SBibo Mao         env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LBT_ALL, 7);
945c23a53d8SBibo Mao     }
946c23a53d8SBibo Mao 
947c23a53d8SBibo Mao     return 0;
948c23a53d8SBibo Mao }
949c23a53d8SBibo Mao 
9506edd2a9bSBibo Mao static int kvm_cpu_check_pmu(CPUState *cs, Error **errp)
9516edd2a9bSBibo Mao {
9526edd2a9bSBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
9536edd2a9bSBibo Mao     CPULoongArchState *env = cpu_env(cs);
9546edd2a9bSBibo Mao     bool kvm_supported;
9556edd2a9bSBibo Mao 
9566edd2a9bSBibo Mao     kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_PMU);
9576edd2a9bSBibo Mao     if (cpu->pmu == ON_OFF_AUTO_ON) {
9586edd2a9bSBibo Mao         if (!kvm_supported) {
9596edd2a9bSBibo Mao             error_setg(errp, "'pmu' feature not supported by KVM on the host");
9606edd2a9bSBibo Mao             return -ENOTSUP;
9616edd2a9bSBibo Mao         }
9626edd2a9bSBibo Mao     } else if (cpu->pmu != ON_OFF_AUTO_AUTO) {
9636edd2a9bSBibo Mao         /* disable pmu if ON_OFF_AUTO_OFF is set */
9646edd2a9bSBibo Mao         kvm_supported = false;
9656edd2a9bSBibo Mao     }
9666edd2a9bSBibo Mao 
9676edd2a9bSBibo Mao     if (kvm_supported) {
9686edd2a9bSBibo Mao         env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMP, 1);
9696edd2a9bSBibo Mao         env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMNUM, 3);
9706edd2a9bSBibo Mao         env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMBITS, 63);
9716edd2a9bSBibo Mao         env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, UPM, 1);
9726edd2a9bSBibo Mao     }
9736edd2a9bSBibo Mao     return 0;
9746edd2a9bSBibo Mao }
9756edd2a9bSBibo Mao 
976537ba9daSTianrui Zhao int kvm_arch_init_vcpu(CPUState *cs)
977537ba9daSTianrui Zhao {
978d38e31efSBibo Mao     uint64_t val;
979c23a53d8SBibo Mao     int ret;
980c23a53d8SBibo Mao     Error *local_err = NULL;
981d38e31efSBibo Mao 
982c23a53d8SBibo Mao     ret = 0;
983d11681c9STianrui Zhao     qemu_add_vm_change_state_handler(kvm_loongarch_vm_stage_change, cs);
984d38e31efSBibo Mao 
985d38e31efSBibo Mao     if (!kvm_get_one_reg(cs, KVM_REG_LOONGARCH_DEBUG_INST, &val)) {
986d38e31efSBibo Mao         brk_insn = val;
987d38e31efSBibo Mao     }
988d38e31efSBibo Mao 
989936c3f4dSBibo Mao     ret = kvm_cpu_check_lsx(cs, &local_err);
990936c3f4dSBibo Mao     if (ret < 0) {
991936c3f4dSBibo Mao         error_report_err(local_err);
992936c3f4dSBibo Mao     }
993936c3f4dSBibo Mao 
994*5e360dabSBibo Mao     ret = kvm_cpu_check_lasx(cs, &local_err);
995*5e360dabSBibo Mao     if (ret < 0) {
996*5e360dabSBibo Mao         error_report_err(local_err);
997*5e360dabSBibo Mao     }
998*5e360dabSBibo Mao 
999c23a53d8SBibo Mao     ret = kvm_cpu_check_lbt(cs, &local_err);
1000c23a53d8SBibo Mao     if (ret < 0) {
1001c23a53d8SBibo Mao         error_report_err(local_err);
1002c23a53d8SBibo Mao     }
10036edd2a9bSBibo Mao 
10046edd2a9bSBibo Mao     ret = kvm_cpu_check_pmu(cs, &local_err);
10056edd2a9bSBibo Mao     if (ret < 0) {
10066edd2a9bSBibo Mao         error_report_err(local_err);
10076edd2a9bSBibo Mao     }
10086edd2a9bSBibo Mao 
1009c23a53d8SBibo Mao     return ret;
1010537ba9daSTianrui Zhao }
1011537ba9daSTianrui Zhao 
1012537ba9daSTianrui Zhao int kvm_arch_destroy_vcpu(CPUState *cs)
1013537ba9daSTianrui Zhao {
1014537ba9daSTianrui Zhao     return 0;
1015537ba9daSTianrui Zhao }
1016537ba9daSTianrui Zhao 
1017537ba9daSTianrui Zhao unsigned long kvm_arch_vcpu_id(CPUState *cs)
1018537ba9daSTianrui Zhao {
1019537ba9daSTianrui Zhao     return cs->cpu_index;
1020537ba9daSTianrui Zhao }
1021537ba9daSTianrui Zhao 
1022537ba9daSTianrui Zhao int kvm_arch_release_virq_post(int virq)
1023537ba9daSTianrui Zhao {
1024537ba9daSTianrui Zhao     return 0;
1025537ba9daSTianrui Zhao }
1026537ba9daSTianrui Zhao 
1027537ba9daSTianrui Zhao int kvm_arch_msi_data_to_gsi(uint32_t data)
1028537ba9daSTianrui Zhao {
1029537ba9daSTianrui Zhao     abort();
1030537ba9daSTianrui Zhao }
1031537ba9daSTianrui Zhao 
1032537ba9daSTianrui Zhao int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
1033537ba9daSTianrui Zhao                              uint64_t address, uint32_t data, PCIDevice *dev)
1034537ba9daSTianrui Zhao {
1035537ba9daSTianrui Zhao     return 0;
1036537ba9daSTianrui Zhao }
1037537ba9daSTianrui Zhao 
1038537ba9daSTianrui Zhao int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
1039537ba9daSTianrui Zhao                                 int vector, PCIDevice *dev)
1040537ba9daSTianrui Zhao {
1041537ba9daSTianrui Zhao     return 0;
1042537ba9daSTianrui Zhao }
1043537ba9daSTianrui Zhao 
1044537ba9daSTianrui Zhao void kvm_arch_init_irq_routing(KVMState *s)
1045537ba9daSTianrui Zhao {
1046537ba9daSTianrui Zhao }
1047537ba9daSTianrui Zhao 
1048537ba9daSTianrui Zhao int kvm_arch_get_default_type(MachineState *ms)
1049537ba9daSTianrui Zhao {
1050537ba9daSTianrui Zhao     return 0;
1051537ba9daSTianrui Zhao }
1052537ba9daSTianrui Zhao 
1053537ba9daSTianrui Zhao int kvm_arch_init(MachineState *ms, KVMState *s)
1054537ba9daSTianrui Zhao {
105541958c99STianrui Zhao     cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
1056537ba9daSTianrui Zhao     return 0;
1057537ba9daSTianrui Zhao }
1058537ba9daSTianrui Zhao 
1059537ba9daSTianrui Zhao int kvm_arch_irqchip_create(KVMState *s)
1060537ba9daSTianrui Zhao {
1061537ba9daSTianrui Zhao     return 0;
1062537ba9daSTianrui Zhao }
1063537ba9daSTianrui Zhao 
1064537ba9daSTianrui Zhao void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
1065537ba9daSTianrui Zhao {
1066537ba9daSTianrui Zhao }
1067537ba9daSTianrui Zhao 
1068537ba9daSTianrui Zhao MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
1069537ba9daSTianrui Zhao {
1070537ba9daSTianrui Zhao     return MEMTXATTRS_UNSPECIFIED;
1071537ba9daSTianrui Zhao }
1072537ba9daSTianrui Zhao 
1073537ba9daSTianrui Zhao int kvm_arch_process_async_events(CPUState *cs)
1074537ba9daSTianrui Zhao {
1075537ba9daSTianrui Zhao     return cs->halted;
1076537ba9daSTianrui Zhao }
1077537ba9daSTianrui Zhao 
1078537ba9daSTianrui Zhao bool kvm_arch_stop_on_emulation_error(CPUState *cs)
1079537ba9daSTianrui Zhao {
1080537ba9daSTianrui Zhao     return true;
1081537ba9daSTianrui Zhao }
1082537ba9daSTianrui Zhao 
1083d38e31efSBibo Mao void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
1084d38e31efSBibo Mao {
1085d38e31efSBibo Mao     if (kvm_sw_breakpoints_active(cpu)) {
1086d38e31efSBibo Mao         dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
1087d38e31efSBibo Mao     }
1088d38e31efSBibo Mao }
1089d38e31efSBibo Mao 
1090d38e31efSBibo Mao int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
1091d38e31efSBibo Mao {
1092d38e31efSBibo Mao     if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
1093d38e31efSBibo Mao         cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) {
1094d38e31efSBibo Mao         error_report("%s failed", __func__);
1095d38e31efSBibo Mao         return -EINVAL;
1096d38e31efSBibo Mao     }
1097d38e31efSBibo Mao     return 0;
1098d38e31efSBibo Mao }
1099d38e31efSBibo Mao 
1100d38e31efSBibo Mao int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
1101d38e31efSBibo Mao {
1102d38e31efSBibo Mao     static uint32_t brk;
1103d38e31efSBibo Mao 
1104d38e31efSBibo Mao     if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk, 4, 0) ||
1105d38e31efSBibo Mao         brk != brk_insn ||
1106d38e31efSBibo Mao         cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) {
1107d38e31efSBibo Mao         error_report("%s failed", __func__);
1108d38e31efSBibo Mao         return -EINVAL;
1109d38e31efSBibo Mao     }
1110d38e31efSBibo Mao     return 0;
1111d38e31efSBibo Mao }
1112d38e31efSBibo Mao 
1113d38e31efSBibo Mao int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type)
1114d38e31efSBibo Mao {
1115d38e31efSBibo Mao     return -ENOSYS;
1116d38e31efSBibo Mao }
1117d38e31efSBibo Mao 
1118d38e31efSBibo Mao int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type)
1119d38e31efSBibo Mao {
1120d38e31efSBibo Mao     return -ENOSYS;
1121d38e31efSBibo Mao }
1122d38e31efSBibo Mao 
1123d38e31efSBibo Mao void kvm_arch_remove_all_hw_breakpoints(void)
1124d38e31efSBibo Mao {
1125d38e31efSBibo Mao }
1126d38e31efSBibo Mao 
1127d38e31efSBibo Mao static bool kvm_loongarch_handle_debug(CPUState *cs, struct kvm_run *run)
1128d38e31efSBibo Mao {
1129d38e31efSBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
1130d38e31efSBibo Mao     CPULoongArchState *env = &cpu->env;
1131d38e31efSBibo Mao 
1132d38e31efSBibo Mao     kvm_cpu_synchronize_state(cs);
1133d38e31efSBibo Mao     if (cs->singlestep_enabled) {
1134d38e31efSBibo Mao         return true;
1135d38e31efSBibo Mao     }
1136d38e31efSBibo Mao 
1137d38e31efSBibo Mao     if (kvm_find_sw_breakpoint(cs, env->pc)) {
1138d38e31efSBibo Mao         return true;
1139d38e31efSBibo Mao     }
1140d38e31efSBibo Mao 
1141d38e31efSBibo Mao     return false;
1142d38e31efSBibo Mao }
1143d38e31efSBibo Mao 
1144537ba9daSTianrui Zhao int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
1145537ba9daSTianrui Zhao {
1146a05a950fSTianrui Zhao     int ret = 0;
1147f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
1148a05a950fSTianrui Zhao     MemTxAttrs attrs = {};
1149a05a950fSTianrui Zhao 
1150a05a950fSTianrui Zhao     attrs.requester_id = env_cpu(env)->cpu_index;
1151a05a950fSTianrui Zhao 
1152a05a950fSTianrui Zhao     trace_kvm_arch_handle_exit(run->exit_reason);
1153a05a950fSTianrui Zhao     switch (run->exit_reason) {
1154a05a950fSTianrui Zhao     case KVM_EXIT_LOONGARCH_IOCSR:
11555e90b8dbSBibo Mao         address_space_rw(env->address_space_iocsr,
1156a05a950fSTianrui Zhao                          run->iocsr_io.phys_addr,
1157a05a950fSTianrui Zhao                          attrs,
1158a05a950fSTianrui Zhao                          run->iocsr_io.data,
1159a05a950fSTianrui Zhao                          run->iocsr_io.len,
1160a05a950fSTianrui Zhao                          run->iocsr_io.is_write);
1161a05a950fSTianrui Zhao         break;
1162d38e31efSBibo Mao 
1163d38e31efSBibo Mao     case KVM_EXIT_DEBUG:
1164d38e31efSBibo Mao         if (kvm_loongarch_handle_debug(cs, run)) {
1165d38e31efSBibo Mao             ret = EXCP_DEBUG;
1166d38e31efSBibo Mao         }
1167d38e31efSBibo Mao         break;
1168d38e31efSBibo Mao 
1169a05a950fSTianrui Zhao     default:
1170a05a950fSTianrui Zhao         ret = -1;
1171a05a950fSTianrui Zhao         warn_report("KVM: unknown exit reason %d", run->exit_reason);
1172a05a950fSTianrui Zhao         break;
1173a05a950fSTianrui Zhao     }
1174a05a950fSTianrui Zhao     return ret;
1175537ba9daSTianrui Zhao }
1176537ba9daSTianrui Zhao 
11778dcbad51STianrui Zhao int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level)
11788dcbad51STianrui Zhao {
11798dcbad51STianrui Zhao     struct kvm_interrupt intr;
11808dcbad51STianrui Zhao     CPUState *cs = CPU(cpu);
11818dcbad51STianrui Zhao 
11828dcbad51STianrui Zhao     if (level) {
11838dcbad51STianrui Zhao         intr.irq = irq;
11848dcbad51STianrui Zhao     } else {
11858dcbad51STianrui Zhao         intr.irq = -irq;
11868dcbad51STianrui Zhao     }
11878dcbad51STianrui Zhao 
11888dcbad51STianrui Zhao     trace_kvm_set_intr(irq, level);
11898dcbad51STianrui Zhao     return kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr);
11908dcbad51STianrui Zhao }
11918dcbad51STianrui Zhao 
1192537ba9daSTianrui Zhao void kvm_arch_accel_class_init(ObjectClass *oc)
1193537ba9daSTianrui Zhao {
1194537ba9daSTianrui Zhao }
1195