xref: /qemu/target/loongarch/kvm/kvm.c (revision b61b9d891305abf8fe37f07280ca5a99a10da6cf)
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);
584*b61b9d89SXianglai Li     int ret = 0;
585*b61b9d89SXianglai Li     uint64_t unused = 0;
586a724f5a8SBibo Mao 
587f8447436STianrui Zhao     env->mp_state = KVM_MP_STATE_RUNNABLE;
588*b61b9d89SXianglai Li     ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_VCPU_RESET, &unused);
589*b61b9d89SXianglai Li     if (ret) {
590*b61b9d89SXianglai Li         error_report("Failed to set KVM_REG_LOONGARCH_VCPU_RESET: %s",
591*b61b9d89SXianglai Li                      strerror(errno));
592*b61b9d89SXianglai Li         exit(EXIT_FAILURE);
593*b61b9d89SXianglai Li     }
594f8447436STianrui Zhao }
595f8447436STianrui Zhao 
596f8447436STianrui Zhao static int kvm_loongarch_get_mpstate(CPUState *cs)
597f8447436STianrui Zhao {
598f8447436STianrui Zhao     int ret = 0;
599f8447436STianrui Zhao     struct kvm_mp_state mp_state;
600f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
601f8447436STianrui Zhao 
602f8447436STianrui Zhao     if (cap_has_mp_state) {
603f8447436STianrui Zhao         ret = kvm_vcpu_ioctl(cs, KVM_GET_MP_STATE, &mp_state);
604f8447436STianrui Zhao         if (ret) {
605f8447436STianrui Zhao             trace_kvm_failed_get_mpstate(strerror(errno));
606f8447436STianrui Zhao             return ret;
607f8447436STianrui Zhao         }
608f8447436STianrui Zhao         env->mp_state = mp_state.mp_state;
609f8447436STianrui Zhao     }
610f8447436STianrui Zhao 
611f8447436STianrui Zhao     return ret;
612f8447436STianrui Zhao }
613f8447436STianrui Zhao 
614f8447436STianrui Zhao static int kvm_loongarch_put_mpstate(CPUState *cs)
615f8447436STianrui Zhao {
616f8447436STianrui Zhao     int ret = 0;
617f8447436STianrui Zhao     struct kvm_mp_state mp_state = {
618f3b603b9SPhilippe Mathieu-Daudé         .mp_state = cpu_env(cs)->mp_state
619f8447436STianrui Zhao     };
620f8447436STianrui Zhao 
621f8447436STianrui Zhao     if (cap_has_mp_state) {
622f8447436STianrui Zhao         ret = kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state);
623f8447436STianrui Zhao         if (ret) {
624f8447436STianrui Zhao             trace_kvm_failed_put_mpstate(strerror(errno));
625f8447436STianrui Zhao         }
626f8447436STianrui Zhao     }
627f8447436STianrui Zhao 
628f8447436STianrui Zhao     return ret;
629f8447436STianrui Zhao }
630f8447436STianrui Zhao 
631f8447436STianrui Zhao static int kvm_loongarch_get_cpucfg(CPUState *cs)
632f8447436STianrui Zhao {
633f8447436STianrui Zhao     int i, ret = 0;
634f8447436STianrui Zhao     uint64_t val;
635f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
636f8447436STianrui Zhao 
637f8447436STianrui Zhao     for (i = 0; i < 21; i++) {
638f8447436STianrui Zhao         ret = kvm_get_one_reg(cs, KVM_IOC_CPUCFG(i), &val);
639f8447436STianrui Zhao         if (ret < 0) {
640f8447436STianrui Zhao             trace_kvm_failed_get_cpucfg(strerror(errno));
641f8447436STianrui Zhao         }
642f8447436STianrui Zhao         env->cpucfg[i] = (uint32_t)val;
643f8447436STianrui Zhao     }
644f8447436STianrui Zhao     return ret;
645f8447436STianrui Zhao }
646f8447436STianrui Zhao 
647fc700996SSong Gao static int kvm_check_cpucfg2(CPUState *cs)
648fc700996SSong Gao {
649fc700996SSong Gao     int ret;
650fc700996SSong Gao     uint64_t val;
651fc700996SSong Gao     struct kvm_device_attr attr = {
652fc700996SSong Gao         .group = KVM_LOONGARCH_VCPU_CPUCFG,
653fc700996SSong Gao         .attr = 2,
654fc700996SSong Gao         .addr = (uint64_t)&val,
655fc700996SSong Gao     };
656f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
657fc700996SSong Gao 
658fc700996SSong Gao     ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr);
659fc700996SSong Gao 
660fc700996SSong Gao     if (!ret) {
661fc700996SSong Gao         kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
662fc700996SSong Gao         env->cpucfg[2] &= val;
663fc700996SSong Gao 
664fc700996SSong Gao         if (FIELD_EX32(env->cpucfg[2], CPUCFG2, FP)) {
665fc700996SSong Gao             /* The FP minimal version is 1. */
666fc700996SSong Gao             env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, FP_VER, 1);
667fc700996SSong Gao         }
668fc700996SSong Gao 
669fc700996SSong Gao         if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LLFTP)) {
670fc700996SSong Gao             /* The LLFTP minimal version is 1. */
671fc700996SSong Gao             env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LLFTP_VER, 1);
672fc700996SSong Gao         }
673fc700996SSong Gao     }
674fc700996SSong Gao 
675fc700996SSong Gao     return ret;
676fc700996SSong Gao }
677fc700996SSong Gao 
678f8447436STianrui Zhao static int kvm_loongarch_put_cpucfg(CPUState *cs)
679f8447436STianrui Zhao {
680f8447436STianrui Zhao     int i, ret = 0;
681f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
682f8447436STianrui Zhao     uint64_t val;
683f8447436STianrui Zhao 
684f8447436STianrui Zhao     for (i = 0; i < 21; i++) {
685f8447436STianrui Zhao 	if (i == 2) {
686fc700996SSong Gao             ret = kvm_check_cpucfg2(cs);
687fc700996SSong Gao             if (ret) {
688fc700996SSong Gao                 return ret;
689f8447436STianrui Zhao             }
690fc700996SSong Gao 	}
691fc700996SSong Gao         val = env->cpucfg[i];
692f8447436STianrui Zhao         ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val);
693f8447436STianrui Zhao         if (ret < 0) {
694f8447436STianrui Zhao             trace_kvm_failed_put_cpucfg(strerror(errno));
695f8447436STianrui Zhao         }
696f8447436STianrui Zhao     }
697f8447436STianrui Zhao     return ret;
698f8447436STianrui Zhao }
699f8447436STianrui Zhao 
700a1676bb3SJulia Suvorova int kvm_arch_get_registers(CPUState *cs, Error **errp)
701537ba9daSTianrui Zhao {
702f8447436STianrui Zhao     int ret;
703f8447436STianrui Zhao 
704f8447436STianrui Zhao     ret = kvm_loongarch_get_regs_core(cs);
705f8447436STianrui Zhao     if (ret) {
706f8447436STianrui Zhao         return ret;
707537ba9daSTianrui Zhao     }
708f8447436STianrui Zhao 
7095872966dSBibo Mao     ret = kvm_loongarch_get_cpucfg(cs);
7105872966dSBibo Mao     if (ret) {
7115872966dSBibo Mao         return ret;
7125872966dSBibo Mao     }
7135872966dSBibo Mao 
714f8447436STianrui Zhao     ret = kvm_loongarch_get_csr(cs);
715f8447436STianrui Zhao     if (ret) {
716f8447436STianrui Zhao         return ret;
717f8447436STianrui Zhao     }
718f8447436STianrui Zhao 
719f8447436STianrui Zhao     ret = kvm_loongarch_get_regs_fp(cs);
720f8447436STianrui Zhao     if (ret) {
721f8447436STianrui Zhao         return ret;
722f8447436STianrui Zhao     }
723f8447436STianrui Zhao 
724a45df286SBibo Mao     ret = kvm_loongarch_get_lbt(cs);
725a45df286SBibo Mao     if (ret) {
726a45df286SBibo Mao         return ret;
727a45df286SBibo Mao     }
728a45df286SBibo Mao 
72947b54e15SBibo Mao     ret = kvm_get_stealtime(cs);
73047b54e15SBibo Mao     if (ret) {
73147b54e15SBibo Mao         return ret;
73247b54e15SBibo Mao     }
73347b54e15SBibo Mao 
734f8447436STianrui Zhao     ret = kvm_loongarch_get_mpstate(cs);
735f8447436STianrui Zhao     return ret;
736f8447436STianrui Zhao }
737f8447436STianrui Zhao 
738a1676bb3SJulia Suvorova int kvm_arch_put_registers(CPUState *cs, int level, Error **errp)
739537ba9daSTianrui Zhao {
740f8447436STianrui Zhao     int ret;
741f8447436STianrui Zhao 
742f8447436STianrui Zhao     ret = kvm_loongarch_put_regs_core(cs);
743f8447436STianrui Zhao     if (ret) {
744f8447436STianrui Zhao         return ret;
745f8447436STianrui Zhao     }
746f8447436STianrui Zhao 
7475872966dSBibo Mao     ret = kvm_loongarch_put_cpucfg(cs);
7485872966dSBibo Mao     if (ret) {
7495872966dSBibo Mao         return ret;
7505872966dSBibo Mao     }
7515872966dSBibo Mao 
75261f6e150SBibo Mao     ret = kvm_loongarch_put_csr(cs, level);
753f8447436STianrui Zhao     if (ret) {
754f8447436STianrui Zhao         return ret;
755f8447436STianrui Zhao     }
756f8447436STianrui Zhao 
757f8447436STianrui Zhao     ret = kvm_loongarch_put_regs_fp(cs);
758f8447436STianrui Zhao     if (ret) {
759f8447436STianrui Zhao         return ret;
760f8447436STianrui Zhao     }
761f8447436STianrui Zhao 
762a45df286SBibo Mao     ret = kvm_loongarch_put_lbt(cs);
763a45df286SBibo Mao     if (ret) {
764a45df286SBibo Mao         return ret;
765a45df286SBibo Mao     }
766a45df286SBibo Mao 
76747b54e15SBibo Mao     if (level >= KVM_PUT_FULL_STATE) {
76847b54e15SBibo Mao         /*
76947b54e15SBibo Mao          * only KVM_PUT_FULL_STATE is required, kvm kernel will clear
77047b54e15SBibo Mao          * guest_addr for KVM_PUT_RESET_STATE
77147b54e15SBibo Mao          */
77247b54e15SBibo Mao         ret = kvm_set_stealtime(cs);
77347b54e15SBibo Mao         if (ret) {
77447b54e15SBibo Mao             return ret;
77547b54e15SBibo Mao         }
77647b54e15SBibo Mao     }
77747b54e15SBibo Mao 
778f8447436STianrui Zhao     ret = kvm_loongarch_put_mpstate(cs);
779f8447436STianrui Zhao     return ret;
780537ba9daSTianrui Zhao }
781537ba9daSTianrui Zhao 
782d11681c9STianrui Zhao static void kvm_loongarch_vm_stage_change(void *opaque, bool running,
783d11681c9STianrui Zhao                                           RunState state)
784d11681c9STianrui Zhao {
785d11681c9STianrui Zhao     int ret;
786d11681c9STianrui Zhao     CPUState *cs = opaque;
787d11681c9STianrui Zhao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
788d11681c9STianrui Zhao 
789d11681c9STianrui Zhao     if (running) {
790d11681c9STianrui Zhao         ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_COUNTER,
791d11681c9STianrui Zhao                               &cpu->kvm_state_counter);
792d11681c9STianrui Zhao         if (ret < 0) {
793d11681c9STianrui Zhao             trace_kvm_failed_put_counter(strerror(errno));
794d11681c9STianrui Zhao         }
795d11681c9STianrui Zhao     } else {
796d11681c9STianrui Zhao         ret = kvm_get_one_reg(cs, KVM_REG_LOONGARCH_COUNTER,
797d11681c9STianrui Zhao                               &cpu->kvm_state_counter);
798d11681c9STianrui Zhao         if (ret < 0) {
799d11681c9STianrui Zhao             trace_kvm_failed_get_counter(strerror(errno));
800d11681c9STianrui Zhao         }
801d11681c9STianrui Zhao     }
802d11681c9STianrui Zhao }
803d11681c9STianrui Zhao 
804c23a53d8SBibo Mao static bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature)
805c23a53d8SBibo Mao {
806c23a53d8SBibo Mao     int ret;
807c23a53d8SBibo Mao     struct kvm_device_attr attr;
808936c3f4dSBibo Mao     uint64_t val;
809c23a53d8SBibo Mao 
810c23a53d8SBibo Mao     switch (feature) {
811936c3f4dSBibo Mao     case LOONGARCH_FEATURE_LSX:
812936c3f4dSBibo Mao         attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
813936c3f4dSBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_LSX;
814936c3f4dSBibo Mao         ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
815936c3f4dSBibo Mao         if (ret == 0) {
816936c3f4dSBibo Mao             return true;
817936c3f4dSBibo Mao         }
818936c3f4dSBibo Mao 
819936c3f4dSBibo Mao         /* Fallback to old kernel detect interface */
820936c3f4dSBibo Mao         val = 0;
821936c3f4dSBibo Mao         attr.group = KVM_LOONGARCH_VCPU_CPUCFG;
822936c3f4dSBibo Mao         /* Cpucfg2 */
823936c3f4dSBibo Mao         attr.attr  = 2;
824936c3f4dSBibo Mao         attr.addr = (uint64_t)&val;
825936c3f4dSBibo Mao         ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr);
826936c3f4dSBibo Mao         if (!ret) {
827936c3f4dSBibo Mao             ret = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
828936c3f4dSBibo Mao             if (ret) {
829936c3f4dSBibo Mao                 return false;
830936c3f4dSBibo Mao             }
831936c3f4dSBibo Mao 
832936c3f4dSBibo Mao             ret = FIELD_EX32((uint32_t)val, CPUCFG2, LSX);
833936c3f4dSBibo Mao             return (ret != 0);
834936c3f4dSBibo Mao         }
835936c3f4dSBibo Mao         return false;
836936c3f4dSBibo Mao 
8375e360dabSBibo Mao     case LOONGARCH_FEATURE_LASX:
8385e360dabSBibo Mao         attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
8395e360dabSBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_LASX;
8405e360dabSBibo Mao         ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
8415e360dabSBibo Mao         if (ret == 0) {
8425e360dabSBibo Mao             return true;
8435e360dabSBibo Mao         }
8445e360dabSBibo Mao 
8455e360dabSBibo Mao         /* Fallback to old kernel detect interface */
8465e360dabSBibo Mao         val = 0;
8475e360dabSBibo Mao         attr.group = KVM_LOONGARCH_VCPU_CPUCFG;
8485e360dabSBibo Mao         /* Cpucfg2 */
8495e360dabSBibo Mao         attr.attr  = 2;
8505e360dabSBibo Mao         attr.addr = (uint64_t)&val;
8515e360dabSBibo Mao         ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr);
8525e360dabSBibo Mao         if (!ret) {
8535e360dabSBibo Mao             ret = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
8545e360dabSBibo Mao             if (ret) {
8555e360dabSBibo Mao                 return false;
8565e360dabSBibo Mao             }
8575e360dabSBibo Mao 
8585e360dabSBibo Mao             ret = FIELD_EX32((uint32_t)val, CPUCFG2, LASX);
8595e360dabSBibo Mao             return (ret != 0);
8605e360dabSBibo Mao         }
8615e360dabSBibo Mao         return false;
8625e360dabSBibo Mao 
863c23a53d8SBibo Mao     case LOONGARCH_FEATURE_LBT:
864c23a53d8SBibo Mao         /*
865c23a53d8SBibo Mao          * Return all if all the LBT features are supported such as:
866c23a53d8SBibo Mao          *  KVM_LOONGARCH_VM_FEAT_X86BT
867c23a53d8SBibo Mao          *  KVM_LOONGARCH_VM_FEAT_ARMBT
868c23a53d8SBibo Mao          *  KVM_LOONGARCH_VM_FEAT_MIPSBT
869c23a53d8SBibo Mao          */
870c23a53d8SBibo Mao         attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
871c23a53d8SBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_X86BT;
872c23a53d8SBibo Mao         ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
873c23a53d8SBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_ARMBT;
874c23a53d8SBibo Mao         ret |= kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
875c23a53d8SBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_MIPSBT;
876c23a53d8SBibo Mao         ret |= kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
877c23a53d8SBibo Mao         return (ret == 0);
8786edd2a9bSBibo Mao 
8796edd2a9bSBibo Mao     case LOONGARCH_FEATURE_PMU:
8806edd2a9bSBibo Mao         attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
8816edd2a9bSBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_PMU;
8826edd2a9bSBibo Mao         ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
8836edd2a9bSBibo Mao         return (ret == 0);
8846edd2a9bSBibo Mao 
885c23a53d8SBibo Mao     default:
886c23a53d8SBibo Mao         return false;
887c23a53d8SBibo Mao     }
8886edd2a9bSBibo Mao 
8896edd2a9bSBibo Mao     return false;
890c23a53d8SBibo Mao }
891c23a53d8SBibo Mao 
892936c3f4dSBibo Mao static int kvm_cpu_check_lsx(CPUState *cs, Error **errp)
893936c3f4dSBibo Mao {
894936c3f4dSBibo Mao     CPULoongArchState *env = cpu_env(cs);
895936c3f4dSBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
896936c3f4dSBibo Mao     bool kvm_supported;
897936c3f4dSBibo Mao 
898936c3f4dSBibo Mao     kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_LSX);
899936c3f4dSBibo Mao     env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LSX, 0);
900936c3f4dSBibo Mao     if (cpu->lsx == ON_OFF_AUTO_ON) {
901936c3f4dSBibo Mao         if (kvm_supported) {
902936c3f4dSBibo Mao             env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LSX, 1);
903936c3f4dSBibo Mao         } else {
904936c3f4dSBibo Mao             error_setg(errp, "'lsx' feature not supported by KVM on this host");
905936c3f4dSBibo Mao             return -ENOTSUP;
906936c3f4dSBibo Mao         }
907936c3f4dSBibo Mao     } else if ((cpu->lsx == ON_OFF_AUTO_AUTO) && kvm_supported) {
908936c3f4dSBibo Mao         env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LSX, 1);
909936c3f4dSBibo Mao     }
910936c3f4dSBibo Mao 
911936c3f4dSBibo Mao     return 0;
912936c3f4dSBibo Mao }
913936c3f4dSBibo Mao 
9145e360dabSBibo Mao static int kvm_cpu_check_lasx(CPUState *cs, Error **errp)
9155e360dabSBibo Mao {
9165e360dabSBibo Mao     CPULoongArchState *env = cpu_env(cs);
9175e360dabSBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
9185e360dabSBibo Mao     bool kvm_supported;
9195e360dabSBibo Mao 
9205e360dabSBibo Mao     kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_LASX);
9215e360dabSBibo Mao     env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LASX, 0);
9225e360dabSBibo Mao     if (cpu->lasx == ON_OFF_AUTO_ON) {
9235e360dabSBibo Mao         if (kvm_supported) {
9245e360dabSBibo Mao             env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LASX, 1);
9255e360dabSBibo Mao         } else {
9265e360dabSBibo Mao             error_setg(errp, "'lasx' feature not supported by KVM on host");
9275e360dabSBibo Mao             return -ENOTSUP;
9285e360dabSBibo Mao         }
9295e360dabSBibo Mao     } else if ((cpu->lasx == ON_OFF_AUTO_AUTO) && kvm_supported) {
9305e360dabSBibo Mao         env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LASX, 1);
9315e360dabSBibo Mao     }
9325e360dabSBibo Mao 
9335e360dabSBibo Mao     return 0;
9345e360dabSBibo Mao }
9355e360dabSBibo Mao 
936c23a53d8SBibo Mao static int kvm_cpu_check_lbt(CPUState *cs, Error **errp)
937c23a53d8SBibo Mao {
938c23a53d8SBibo Mao     CPULoongArchState *env = cpu_env(cs);
939c23a53d8SBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
940c23a53d8SBibo Mao     bool kvm_supported;
941c23a53d8SBibo Mao 
942c23a53d8SBibo Mao     kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_LBT);
943c23a53d8SBibo Mao     if (cpu->lbt == ON_OFF_AUTO_ON) {
944c23a53d8SBibo Mao         if (kvm_supported) {
945c23a53d8SBibo Mao             env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LBT_ALL, 7);
946c23a53d8SBibo Mao         } else {
947c23a53d8SBibo Mao             error_setg(errp, "'lbt' feature not supported by KVM on this host");
948c23a53d8SBibo Mao             return -ENOTSUP;
949c23a53d8SBibo Mao         }
950c23a53d8SBibo Mao     } else if ((cpu->lbt == ON_OFF_AUTO_AUTO) && kvm_supported) {
951c23a53d8SBibo Mao         env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LBT_ALL, 7);
952c23a53d8SBibo Mao     }
953c23a53d8SBibo Mao 
954c23a53d8SBibo Mao     return 0;
955c23a53d8SBibo Mao }
956c23a53d8SBibo Mao 
9576edd2a9bSBibo Mao static int kvm_cpu_check_pmu(CPUState *cs, Error **errp)
9586edd2a9bSBibo Mao {
9596edd2a9bSBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
9606edd2a9bSBibo Mao     CPULoongArchState *env = cpu_env(cs);
9616edd2a9bSBibo Mao     bool kvm_supported;
9626edd2a9bSBibo Mao 
9636edd2a9bSBibo Mao     kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_PMU);
9646edd2a9bSBibo Mao     if (cpu->pmu == ON_OFF_AUTO_ON) {
9656edd2a9bSBibo Mao         if (!kvm_supported) {
9666edd2a9bSBibo Mao             error_setg(errp, "'pmu' feature not supported by KVM on the host");
9676edd2a9bSBibo Mao             return -ENOTSUP;
9686edd2a9bSBibo Mao         }
9696edd2a9bSBibo Mao     } else if (cpu->pmu != ON_OFF_AUTO_AUTO) {
9706edd2a9bSBibo Mao         /* disable pmu if ON_OFF_AUTO_OFF is set */
9716edd2a9bSBibo Mao         kvm_supported = false;
9726edd2a9bSBibo Mao     }
9736edd2a9bSBibo Mao 
9746edd2a9bSBibo Mao     if (kvm_supported) {
9756edd2a9bSBibo Mao         env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMP, 1);
9766edd2a9bSBibo Mao         env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMNUM, 3);
9776edd2a9bSBibo Mao         env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMBITS, 63);
9786edd2a9bSBibo Mao         env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, UPM, 1);
9796edd2a9bSBibo Mao     }
9806edd2a9bSBibo Mao     return 0;
9816edd2a9bSBibo Mao }
9826edd2a9bSBibo Mao 
983537ba9daSTianrui Zhao int kvm_arch_init_vcpu(CPUState *cs)
984537ba9daSTianrui Zhao {
985d38e31efSBibo Mao     uint64_t val;
986c23a53d8SBibo Mao     int ret;
987c23a53d8SBibo Mao     Error *local_err = NULL;
988d38e31efSBibo Mao 
989c23a53d8SBibo Mao     ret = 0;
990d11681c9STianrui Zhao     qemu_add_vm_change_state_handler(kvm_loongarch_vm_stage_change, cs);
991d38e31efSBibo Mao 
992d38e31efSBibo Mao     if (!kvm_get_one_reg(cs, KVM_REG_LOONGARCH_DEBUG_INST, &val)) {
993d38e31efSBibo Mao         brk_insn = val;
994d38e31efSBibo Mao     }
995d38e31efSBibo Mao 
996936c3f4dSBibo Mao     ret = kvm_cpu_check_lsx(cs, &local_err);
997936c3f4dSBibo Mao     if (ret < 0) {
998936c3f4dSBibo Mao         error_report_err(local_err);
999936c3f4dSBibo Mao     }
1000936c3f4dSBibo Mao 
10015e360dabSBibo Mao     ret = kvm_cpu_check_lasx(cs, &local_err);
10025e360dabSBibo Mao     if (ret < 0) {
10035e360dabSBibo Mao         error_report_err(local_err);
10045e360dabSBibo Mao     }
10055e360dabSBibo Mao 
1006c23a53d8SBibo Mao     ret = kvm_cpu_check_lbt(cs, &local_err);
1007c23a53d8SBibo Mao     if (ret < 0) {
1008c23a53d8SBibo Mao         error_report_err(local_err);
1009c23a53d8SBibo Mao     }
10106edd2a9bSBibo Mao 
10116edd2a9bSBibo Mao     ret = kvm_cpu_check_pmu(cs, &local_err);
10126edd2a9bSBibo Mao     if (ret < 0) {
10136edd2a9bSBibo Mao         error_report_err(local_err);
10146edd2a9bSBibo Mao     }
10156edd2a9bSBibo Mao 
1016c23a53d8SBibo Mao     return ret;
1017537ba9daSTianrui Zhao }
1018537ba9daSTianrui Zhao 
1019537ba9daSTianrui Zhao int kvm_arch_destroy_vcpu(CPUState *cs)
1020537ba9daSTianrui Zhao {
1021537ba9daSTianrui Zhao     return 0;
1022537ba9daSTianrui Zhao }
1023537ba9daSTianrui Zhao 
1024537ba9daSTianrui Zhao unsigned long kvm_arch_vcpu_id(CPUState *cs)
1025537ba9daSTianrui Zhao {
1026537ba9daSTianrui Zhao     return cs->cpu_index;
1027537ba9daSTianrui Zhao }
1028537ba9daSTianrui Zhao 
1029537ba9daSTianrui Zhao int kvm_arch_release_virq_post(int virq)
1030537ba9daSTianrui Zhao {
1031537ba9daSTianrui Zhao     return 0;
1032537ba9daSTianrui Zhao }
1033537ba9daSTianrui Zhao 
1034537ba9daSTianrui Zhao int kvm_arch_msi_data_to_gsi(uint32_t data)
1035537ba9daSTianrui Zhao {
1036537ba9daSTianrui Zhao     abort();
1037537ba9daSTianrui Zhao }
1038537ba9daSTianrui Zhao 
1039537ba9daSTianrui Zhao int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
1040537ba9daSTianrui Zhao                              uint64_t address, uint32_t data, PCIDevice *dev)
1041537ba9daSTianrui Zhao {
1042537ba9daSTianrui Zhao     return 0;
1043537ba9daSTianrui Zhao }
1044537ba9daSTianrui Zhao 
1045537ba9daSTianrui Zhao int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
1046537ba9daSTianrui Zhao                                 int vector, PCIDevice *dev)
1047537ba9daSTianrui Zhao {
1048537ba9daSTianrui Zhao     return 0;
1049537ba9daSTianrui Zhao }
1050537ba9daSTianrui Zhao 
1051537ba9daSTianrui Zhao void kvm_arch_init_irq_routing(KVMState *s)
1052537ba9daSTianrui Zhao {
1053537ba9daSTianrui Zhao }
1054537ba9daSTianrui Zhao 
1055537ba9daSTianrui Zhao int kvm_arch_get_default_type(MachineState *ms)
1056537ba9daSTianrui Zhao {
1057537ba9daSTianrui Zhao     return 0;
1058537ba9daSTianrui Zhao }
1059537ba9daSTianrui Zhao 
1060537ba9daSTianrui Zhao int kvm_arch_init(MachineState *ms, KVMState *s)
1061537ba9daSTianrui Zhao {
106241958c99STianrui Zhao     cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
1063537ba9daSTianrui Zhao     return 0;
1064537ba9daSTianrui Zhao }
1065537ba9daSTianrui Zhao 
1066537ba9daSTianrui Zhao int kvm_arch_irqchip_create(KVMState *s)
1067537ba9daSTianrui Zhao {
1068537ba9daSTianrui Zhao     return 0;
1069537ba9daSTianrui Zhao }
1070537ba9daSTianrui Zhao 
1071537ba9daSTianrui Zhao void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
1072537ba9daSTianrui Zhao {
1073537ba9daSTianrui Zhao }
1074537ba9daSTianrui Zhao 
1075537ba9daSTianrui Zhao MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
1076537ba9daSTianrui Zhao {
1077537ba9daSTianrui Zhao     return MEMTXATTRS_UNSPECIFIED;
1078537ba9daSTianrui Zhao }
1079537ba9daSTianrui Zhao 
1080537ba9daSTianrui Zhao int kvm_arch_process_async_events(CPUState *cs)
1081537ba9daSTianrui Zhao {
1082537ba9daSTianrui Zhao     return cs->halted;
1083537ba9daSTianrui Zhao }
1084537ba9daSTianrui Zhao 
1085537ba9daSTianrui Zhao bool kvm_arch_stop_on_emulation_error(CPUState *cs)
1086537ba9daSTianrui Zhao {
1087537ba9daSTianrui Zhao     return true;
1088537ba9daSTianrui Zhao }
1089537ba9daSTianrui Zhao 
1090d38e31efSBibo Mao void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
1091d38e31efSBibo Mao {
1092d38e31efSBibo Mao     if (kvm_sw_breakpoints_active(cpu)) {
1093d38e31efSBibo Mao         dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
1094d38e31efSBibo Mao     }
1095d38e31efSBibo Mao }
1096d38e31efSBibo Mao 
1097d38e31efSBibo Mao int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
1098d38e31efSBibo Mao {
1099d38e31efSBibo Mao     if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
1100d38e31efSBibo Mao         cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) {
1101d38e31efSBibo Mao         error_report("%s failed", __func__);
1102d38e31efSBibo Mao         return -EINVAL;
1103d38e31efSBibo Mao     }
1104d38e31efSBibo Mao     return 0;
1105d38e31efSBibo Mao }
1106d38e31efSBibo Mao 
1107d38e31efSBibo Mao int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
1108d38e31efSBibo Mao {
1109d38e31efSBibo Mao     static uint32_t brk;
1110d38e31efSBibo Mao 
1111d38e31efSBibo Mao     if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk, 4, 0) ||
1112d38e31efSBibo Mao         brk != brk_insn ||
1113d38e31efSBibo Mao         cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) {
1114d38e31efSBibo Mao         error_report("%s failed", __func__);
1115d38e31efSBibo Mao         return -EINVAL;
1116d38e31efSBibo Mao     }
1117d38e31efSBibo Mao     return 0;
1118d38e31efSBibo Mao }
1119d38e31efSBibo Mao 
1120d38e31efSBibo Mao int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type)
1121d38e31efSBibo Mao {
1122d38e31efSBibo Mao     return -ENOSYS;
1123d38e31efSBibo Mao }
1124d38e31efSBibo Mao 
1125d38e31efSBibo Mao int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type)
1126d38e31efSBibo Mao {
1127d38e31efSBibo Mao     return -ENOSYS;
1128d38e31efSBibo Mao }
1129d38e31efSBibo Mao 
1130d38e31efSBibo Mao void kvm_arch_remove_all_hw_breakpoints(void)
1131d38e31efSBibo Mao {
1132d38e31efSBibo Mao }
1133d38e31efSBibo Mao 
1134d38e31efSBibo Mao static bool kvm_loongarch_handle_debug(CPUState *cs, struct kvm_run *run)
1135d38e31efSBibo Mao {
1136d38e31efSBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
1137d38e31efSBibo Mao     CPULoongArchState *env = &cpu->env;
1138d38e31efSBibo Mao 
1139d38e31efSBibo Mao     kvm_cpu_synchronize_state(cs);
1140d38e31efSBibo Mao     if (cs->singlestep_enabled) {
1141d38e31efSBibo Mao         return true;
1142d38e31efSBibo Mao     }
1143d38e31efSBibo Mao 
1144d38e31efSBibo Mao     if (kvm_find_sw_breakpoint(cs, env->pc)) {
1145d38e31efSBibo Mao         return true;
1146d38e31efSBibo Mao     }
1147d38e31efSBibo Mao 
1148d38e31efSBibo Mao     return false;
1149d38e31efSBibo Mao }
1150d38e31efSBibo Mao 
1151537ba9daSTianrui Zhao int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
1152537ba9daSTianrui Zhao {
1153a05a950fSTianrui Zhao     int ret = 0;
1154f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
1155a05a950fSTianrui Zhao     MemTxAttrs attrs = {};
1156a05a950fSTianrui Zhao 
1157a05a950fSTianrui Zhao     attrs.requester_id = env_cpu(env)->cpu_index;
1158a05a950fSTianrui Zhao 
1159a05a950fSTianrui Zhao     trace_kvm_arch_handle_exit(run->exit_reason);
1160a05a950fSTianrui Zhao     switch (run->exit_reason) {
1161a05a950fSTianrui Zhao     case KVM_EXIT_LOONGARCH_IOCSR:
11625e90b8dbSBibo Mao         address_space_rw(env->address_space_iocsr,
1163a05a950fSTianrui Zhao                          run->iocsr_io.phys_addr,
1164a05a950fSTianrui Zhao                          attrs,
1165a05a950fSTianrui Zhao                          run->iocsr_io.data,
1166a05a950fSTianrui Zhao                          run->iocsr_io.len,
1167a05a950fSTianrui Zhao                          run->iocsr_io.is_write);
1168a05a950fSTianrui Zhao         break;
1169d38e31efSBibo Mao 
1170d38e31efSBibo Mao     case KVM_EXIT_DEBUG:
1171d38e31efSBibo Mao         if (kvm_loongarch_handle_debug(cs, run)) {
1172d38e31efSBibo Mao             ret = EXCP_DEBUG;
1173d38e31efSBibo Mao         }
1174d38e31efSBibo Mao         break;
1175d38e31efSBibo Mao 
1176a05a950fSTianrui Zhao     default:
1177a05a950fSTianrui Zhao         ret = -1;
1178a05a950fSTianrui Zhao         warn_report("KVM: unknown exit reason %d", run->exit_reason);
1179a05a950fSTianrui Zhao         break;
1180a05a950fSTianrui Zhao     }
1181a05a950fSTianrui Zhao     return ret;
1182537ba9daSTianrui Zhao }
1183537ba9daSTianrui Zhao 
11848dcbad51STianrui Zhao int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level)
11858dcbad51STianrui Zhao {
11868dcbad51STianrui Zhao     struct kvm_interrupt intr;
11878dcbad51STianrui Zhao     CPUState *cs = CPU(cpu);
11888dcbad51STianrui Zhao 
11898dcbad51STianrui Zhao     if (level) {
11908dcbad51STianrui Zhao         intr.irq = irq;
11918dcbad51STianrui Zhao     } else {
11928dcbad51STianrui Zhao         intr.irq = -irq;
11938dcbad51STianrui Zhao     }
11948dcbad51STianrui Zhao 
11958dcbad51STianrui Zhao     trace_kvm_set_intr(irq, level);
11968dcbad51STianrui Zhao     return kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr);
11978dcbad51STianrui Zhao }
11988dcbad51STianrui Zhao 
1199537ba9daSTianrui Zhao void kvm_arch_accel_class_init(ObjectClass *oc)
1200537ba9daSTianrui Zhao {
1201537ba9daSTianrui Zhao }
1202