xref: /qemu/target/loongarch/kvm/kvm.c (revision 2698cc7c99b50cf4bb127c56e5c90f7f3cba6f0d)
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>
11620d9bd0SBibo Mao #include "asm-loongarch/kvm_para.h"
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 
86*2698cc7cSBibo Mao static int kvm_set_pv_features(CPUState *cs)
87*2698cc7cSBibo Mao {
88*2698cc7cSBibo Mao     CPULoongArchState *env = cpu_env(cs);
89*2698cc7cSBibo Mao     int err;
90*2698cc7cSBibo Mao     uint64_t val;
91*2698cc7cSBibo Mao     struct kvm_device_attr attr = {
92*2698cc7cSBibo Mao         .group = KVM_LOONGARCH_VCPU_CPUCFG,
93*2698cc7cSBibo Mao         .attr = CPUCFG_KVM_FEATURE,
94*2698cc7cSBibo Mao         .addr = (uint64_t)&val,
95*2698cc7cSBibo Mao     };
96*2698cc7cSBibo Mao 
97*2698cc7cSBibo Mao     err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr);
98*2698cc7cSBibo Mao     if (err) {
99*2698cc7cSBibo Mao         return 0;
100*2698cc7cSBibo Mao     }
101*2698cc7cSBibo Mao 
102*2698cc7cSBibo Mao     val = env->pv_features;
103*2698cc7cSBibo Mao     err = kvm_vcpu_ioctl(cs, KVM_SET_DEVICE_ATTR, attr);
104*2698cc7cSBibo Mao     if (err) {
105*2698cc7cSBibo Mao         error_report("Fail to set pv feature "TARGET_FMT_lx " with error %s",
106*2698cc7cSBibo Mao                       val, strerror(errno));
107*2698cc7cSBibo Mao         return err;
108*2698cc7cSBibo Mao     }
109*2698cc7cSBibo Mao 
110*2698cc7cSBibo Mao     return 0;
111*2698cc7cSBibo Mao }
112*2698cc7cSBibo Mao 
113f8447436STianrui Zhao static int kvm_loongarch_get_regs_core(CPUState *cs)
114f8447436STianrui Zhao {
115f8447436STianrui Zhao     int ret = 0;
116f8447436STianrui Zhao     int i;
117f8447436STianrui Zhao     struct kvm_regs regs;
118f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
119f8447436STianrui Zhao 
120f8447436STianrui Zhao     /* Get the current register set as KVM seems it */
121f8447436STianrui Zhao     ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, &regs);
122f8447436STianrui Zhao     if (ret < 0) {
123f8447436STianrui Zhao         trace_kvm_failed_get_regs_core(strerror(errno));
124f8447436STianrui Zhao         return ret;
125f8447436STianrui Zhao     }
126f8447436STianrui Zhao     /* gpr[0] value is always 0 */
127f8447436STianrui Zhao     env->gpr[0] = 0;
128f8447436STianrui Zhao     for (i = 1; i < 32; i++) {
129f8447436STianrui Zhao         env->gpr[i] = regs.gpr[i];
130f8447436STianrui Zhao     }
131f8447436STianrui Zhao 
132f8447436STianrui Zhao     env->pc = regs.pc;
133f8447436STianrui Zhao     return ret;
134f8447436STianrui Zhao }
135f8447436STianrui Zhao 
136f8447436STianrui Zhao static int kvm_loongarch_put_regs_core(CPUState *cs)
137f8447436STianrui Zhao {
138f8447436STianrui Zhao     int ret = 0;
139f8447436STianrui Zhao     int i;
140f8447436STianrui Zhao     struct kvm_regs regs;
141f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
142f8447436STianrui Zhao 
143f8447436STianrui Zhao     /* Set the registers based on QEMU's view of things */
144f8447436STianrui Zhao     for (i = 0; i < 32; i++) {
145f8447436STianrui Zhao         regs.gpr[i] = env->gpr[i];
146f8447436STianrui Zhao     }
147f8447436STianrui Zhao 
148f8447436STianrui Zhao     regs.pc = env->pc;
149f8447436STianrui Zhao     ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, &regs);
150f8447436STianrui Zhao     if (ret < 0) {
151f8447436STianrui Zhao         trace_kvm_failed_put_regs_core(strerror(errno));
152f8447436STianrui Zhao     }
153f8447436STianrui Zhao 
154f8447436STianrui Zhao     return ret;
155f8447436STianrui Zhao }
156f8447436STianrui Zhao 
157f8447436STianrui Zhao static int kvm_loongarch_get_csr(CPUState *cs)
158f8447436STianrui Zhao {
159f8447436STianrui Zhao     int ret = 0;
160f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
161f8447436STianrui Zhao 
162f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CRMD),
163f8447436STianrui Zhao                            &env->CSR_CRMD);
164f8447436STianrui Zhao 
165f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRMD),
166f8447436STianrui Zhao                            &env->CSR_PRMD);
167f8447436STianrui Zhao 
168f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EUEN),
169f8447436STianrui Zhao                            &env->CSR_EUEN);
170f8447436STianrui Zhao 
171f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MISC),
172f8447436STianrui Zhao                            &env->CSR_MISC);
173f8447436STianrui Zhao 
174f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ECFG),
175f8447436STianrui Zhao                            &env->CSR_ECFG);
176f8447436STianrui Zhao 
177f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ESTAT),
178f8447436STianrui Zhao                            &env->CSR_ESTAT);
179f8447436STianrui Zhao 
180f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ERA),
181f8447436STianrui Zhao                            &env->CSR_ERA);
182f8447436STianrui Zhao 
183f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADV),
184f8447436STianrui Zhao                            &env->CSR_BADV);
185f8447436STianrui Zhao 
186f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADI),
187f8447436STianrui Zhao                            &env->CSR_BADI);
188f8447436STianrui Zhao 
189f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EENTRY),
190f8447436STianrui Zhao                            &env->CSR_EENTRY);
191f8447436STianrui Zhao 
192f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBIDX),
193f8447436STianrui Zhao                            &env->CSR_TLBIDX);
194f8447436STianrui Zhao 
195f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBEHI),
196f8447436STianrui Zhao                            &env->CSR_TLBEHI);
197f8447436STianrui Zhao 
198f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO0),
199f8447436STianrui Zhao                            &env->CSR_TLBELO0);
200f8447436STianrui Zhao 
201f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO1),
202f8447436STianrui Zhao                            &env->CSR_TLBELO1);
203f8447436STianrui Zhao 
204f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ASID),
205f8447436STianrui Zhao                            &env->CSR_ASID);
206f8447436STianrui Zhao 
207f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDL),
208f8447436STianrui Zhao                            &env->CSR_PGDL);
209f8447436STianrui Zhao 
210f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDH),
211f8447436STianrui Zhao                            &env->CSR_PGDH);
212f8447436STianrui Zhao 
213f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGD),
214f8447436STianrui Zhao                            &env->CSR_PGD);
215f8447436STianrui Zhao 
216f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCL),
217f8447436STianrui Zhao                            &env->CSR_PWCL);
218f8447436STianrui Zhao 
219f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCH),
220f8447436STianrui Zhao                            &env->CSR_PWCH);
221f8447436STianrui Zhao 
222f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_STLBPS),
223f8447436STianrui Zhao                            &env->CSR_STLBPS);
224f8447436STianrui Zhao 
225f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_RVACFG),
226f8447436STianrui Zhao                            &env->CSR_RVACFG);
227f8447436STianrui Zhao 
228f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CPUID),
229f8447436STianrui Zhao                            &env->CSR_CPUID);
230f8447436STianrui Zhao 
231f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG1),
232f8447436STianrui Zhao                            &env->CSR_PRCFG1);
233f8447436STianrui Zhao 
234f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG2),
235f8447436STianrui Zhao                            &env->CSR_PRCFG2);
236f8447436STianrui Zhao 
237f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG3),
238f8447436STianrui Zhao                            &env->CSR_PRCFG3);
239f8447436STianrui Zhao 
240f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(0)),
241f8447436STianrui Zhao                            &env->CSR_SAVE[0]);
242f8447436STianrui Zhao 
243f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(1)),
244f8447436STianrui Zhao                            &env->CSR_SAVE[1]);
245f8447436STianrui Zhao 
246f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(2)),
247f8447436STianrui Zhao                            &env->CSR_SAVE[2]);
248f8447436STianrui Zhao 
249f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(3)),
250f8447436STianrui Zhao                            &env->CSR_SAVE[3]);
251f8447436STianrui Zhao 
252f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(4)),
253f8447436STianrui Zhao                            &env->CSR_SAVE[4]);
254f8447436STianrui Zhao 
255f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(5)),
256f8447436STianrui Zhao                            &env->CSR_SAVE[5]);
257f8447436STianrui Zhao 
258f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(6)),
259f8447436STianrui Zhao                            &env->CSR_SAVE[6]);
260f8447436STianrui Zhao 
261f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(7)),
262f8447436STianrui Zhao                            &env->CSR_SAVE[7]);
263f8447436STianrui Zhao 
264f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TID),
265f8447436STianrui Zhao                            &env->CSR_TID);
266f8447436STianrui Zhao 
267f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CNTC),
268f8447436STianrui Zhao                            &env->CSR_CNTC);
269f8447436STianrui Zhao 
270f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TICLR),
271f8447436STianrui Zhao                            &env->CSR_TICLR);
272f8447436STianrui Zhao 
273f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_LLBCTL),
274f8447436STianrui Zhao                            &env->CSR_LLBCTL);
275f8447436STianrui Zhao 
276f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL1),
277f8447436STianrui Zhao                            &env->CSR_IMPCTL1);
278f8447436STianrui Zhao 
279f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL2),
280f8447436STianrui Zhao                            &env->CSR_IMPCTL2);
281f8447436STianrui Zhao 
282f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRENTRY),
283f8447436STianrui Zhao                            &env->CSR_TLBRENTRY);
284f8447436STianrui Zhao 
285f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRBADV),
286f8447436STianrui Zhao                            &env->CSR_TLBRBADV);
287f8447436STianrui Zhao 
288f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRERA),
289f8447436STianrui Zhao                            &env->CSR_TLBRERA);
290f8447436STianrui Zhao 
291f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRSAVE),
292f8447436STianrui Zhao                            &env->CSR_TLBRSAVE);
293f8447436STianrui Zhao 
294f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO0),
295f8447436STianrui Zhao                            &env->CSR_TLBRELO0);
296f8447436STianrui Zhao 
297f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO1),
298f8447436STianrui Zhao                            &env->CSR_TLBRELO1);
299f8447436STianrui Zhao 
300f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBREHI),
301f8447436STianrui Zhao                            &env->CSR_TLBREHI);
302f8447436STianrui Zhao 
303f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRPRMD),
304f8447436STianrui Zhao                            &env->CSR_TLBRPRMD);
305f8447436STianrui Zhao 
306f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(0)),
307f8447436STianrui Zhao                            &env->CSR_DMW[0]);
308f8447436STianrui Zhao 
309f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(1)),
310f8447436STianrui Zhao                            &env->CSR_DMW[1]);
311f8447436STianrui Zhao 
312f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(2)),
313f8447436STianrui Zhao                            &env->CSR_DMW[2]);
314f8447436STianrui Zhao 
315f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(3)),
316f8447436STianrui Zhao                            &env->CSR_DMW[3]);
317f8447436STianrui Zhao 
318f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TVAL),
319f8447436STianrui Zhao                            &env->CSR_TVAL);
320f8447436STianrui Zhao 
321f8447436STianrui Zhao     ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TCFG),
322f8447436STianrui Zhao                            &env->CSR_TCFG);
323f8447436STianrui Zhao 
324f8447436STianrui Zhao     return ret;
325f8447436STianrui Zhao }
326f8447436STianrui Zhao 
32761f6e150SBibo Mao static int kvm_loongarch_put_csr(CPUState *cs, int level)
328f8447436STianrui Zhao {
329f8447436STianrui Zhao     int ret = 0;
330f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
331f8447436STianrui Zhao 
332f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CRMD),
333f8447436STianrui Zhao                            &env->CSR_CRMD);
334f8447436STianrui Zhao 
335f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRMD),
336f8447436STianrui Zhao                            &env->CSR_PRMD);
337f8447436STianrui Zhao 
338f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EUEN),
339f8447436STianrui Zhao                            &env->CSR_EUEN);
340f8447436STianrui Zhao 
341f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MISC),
342f8447436STianrui Zhao                            &env->CSR_MISC);
343f8447436STianrui Zhao 
344f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ECFG),
345f8447436STianrui Zhao                            &env->CSR_ECFG);
346f8447436STianrui Zhao 
347f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ESTAT),
348f8447436STianrui Zhao                            &env->CSR_ESTAT);
349f8447436STianrui Zhao 
350f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ERA),
351f8447436STianrui Zhao                            &env->CSR_ERA);
352f8447436STianrui Zhao 
353f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADV),
354f8447436STianrui Zhao                            &env->CSR_BADV);
355f8447436STianrui Zhao 
356f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADI),
357f8447436STianrui Zhao                            &env->CSR_BADI);
358f8447436STianrui Zhao 
359f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EENTRY),
360f8447436STianrui Zhao                            &env->CSR_EENTRY);
361f8447436STianrui Zhao 
362f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBIDX),
363f8447436STianrui Zhao                            &env->CSR_TLBIDX);
364f8447436STianrui Zhao 
365f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBEHI),
366f8447436STianrui Zhao                            &env->CSR_TLBEHI);
367f8447436STianrui Zhao 
368f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO0),
369f8447436STianrui Zhao                            &env->CSR_TLBELO0);
370f8447436STianrui Zhao 
371f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO1),
372f8447436STianrui Zhao                            &env->CSR_TLBELO1);
373f8447436STianrui Zhao 
374f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ASID),
375f8447436STianrui Zhao                            &env->CSR_ASID);
376f8447436STianrui Zhao 
377f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDL),
378f8447436STianrui Zhao                            &env->CSR_PGDL);
379f8447436STianrui Zhao 
380f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDH),
381f8447436STianrui Zhao                            &env->CSR_PGDH);
382f8447436STianrui Zhao 
383f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGD),
384f8447436STianrui Zhao                            &env->CSR_PGD);
385f8447436STianrui Zhao 
386f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCL),
387f8447436STianrui Zhao                            &env->CSR_PWCL);
388f8447436STianrui Zhao 
389f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCH),
390f8447436STianrui Zhao                            &env->CSR_PWCH);
391f8447436STianrui Zhao 
392f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_STLBPS),
393f8447436STianrui Zhao                            &env->CSR_STLBPS);
394f8447436STianrui Zhao 
395f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_RVACFG),
396f8447436STianrui Zhao                            &env->CSR_RVACFG);
397f8447436STianrui Zhao 
39861f6e150SBibo Mao     /* CPUID is constant after poweron, it should be set only once */
39961f6e150SBibo Mao     if (level >= KVM_PUT_FULL_STATE) {
400f8447436STianrui Zhao         ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CPUID),
401f8447436STianrui Zhao                            &env->CSR_CPUID);
40261f6e150SBibo Mao     }
403f8447436STianrui Zhao 
404f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG1),
405f8447436STianrui Zhao                            &env->CSR_PRCFG1);
406f8447436STianrui Zhao 
407f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG2),
408f8447436STianrui Zhao                            &env->CSR_PRCFG2);
409f8447436STianrui Zhao 
410f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG3),
411f8447436STianrui Zhao                            &env->CSR_PRCFG3);
412f8447436STianrui Zhao 
413f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(0)),
414f8447436STianrui Zhao                            &env->CSR_SAVE[0]);
415f8447436STianrui Zhao 
416f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(1)),
417f8447436STianrui Zhao                            &env->CSR_SAVE[1]);
418f8447436STianrui Zhao 
419f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(2)),
420f8447436STianrui Zhao                            &env->CSR_SAVE[2]);
421f8447436STianrui Zhao 
422f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(3)),
423f8447436STianrui Zhao                            &env->CSR_SAVE[3]);
424f8447436STianrui Zhao 
425f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(4)),
426f8447436STianrui Zhao                            &env->CSR_SAVE[4]);
427f8447436STianrui Zhao 
428f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(5)),
429f8447436STianrui Zhao                            &env->CSR_SAVE[5]);
430f8447436STianrui Zhao 
431f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(6)),
432f8447436STianrui Zhao                            &env->CSR_SAVE[6]);
433f8447436STianrui Zhao 
434f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(7)),
435f8447436STianrui Zhao                            &env->CSR_SAVE[7]);
436f8447436STianrui Zhao 
437f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TID),
438f8447436STianrui Zhao                            &env->CSR_TID);
439f8447436STianrui Zhao 
440f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CNTC),
441f8447436STianrui Zhao                            &env->CSR_CNTC);
442f8447436STianrui Zhao 
443f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TICLR),
444f8447436STianrui Zhao                            &env->CSR_TICLR);
445f8447436STianrui Zhao 
446f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_LLBCTL),
447f8447436STianrui Zhao                            &env->CSR_LLBCTL);
448f8447436STianrui Zhao 
449f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL1),
450f8447436STianrui Zhao                            &env->CSR_IMPCTL1);
451f8447436STianrui Zhao 
452f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL2),
453f8447436STianrui Zhao                            &env->CSR_IMPCTL2);
454f8447436STianrui Zhao 
455f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRENTRY),
456f8447436STianrui Zhao                            &env->CSR_TLBRENTRY);
457f8447436STianrui Zhao 
458f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRBADV),
459f8447436STianrui Zhao                            &env->CSR_TLBRBADV);
460f8447436STianrui Zhao 
461f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRERA),
462f8447436STianrui Zhao                            &env->CSR_TLBRERA);
463f8447436STianrui Zhao 
464f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRSAVE),
465f8447436STianrui Zhao                            &env->CSR_TLBRSAVE);
466f8447436STianrui Zhao 
467f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO0),
468f8447436STianrui Zhao                            &env->CSR_TLBRELO0);
469f8447436STianrui Zhao 
470f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO1),
471f8447436STianrui Zhao                            &env->CSR_TLBRELO1);
472f8447436STianrui Zhao 
473f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBREHI),
474f8447436STianrui Zhao                            &env->CSR_TLBREHI);
475f8447436STianrui Zhao 
476f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRPRMD),
477f8447436STianrui Zhao                            &env->CSR_TLBRPRMD);
478f8447436STianrui Zhao 
479f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(0)),
480f8447436STianrui Zhao                            &env->CSR_DMW[0]);
481f8447436STianrui Zhao 
482f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(1)),
483f8447436STianrui Zhao                            &env->CSR_DMW[1]);
484f8447436STianrui Zhao 
485f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(2)),
486f8447436STianrui Zhao                            &env->CSR_DMW[2]);
487f8447436STianrui Zhao 
488f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(3)),
489f8447436STianrui Zhao                            &env->CSR_DMW[3]);
490f8447436STianrui Zhao     /*
491f8447436STianrui Zhao      * timer cfg must be put at last since it is used to enable
492f8447436STianrui Zhao      * guest timer
493f8447436STianrui Zhao      */
494f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TVAL),
495f8447436STianrui Zhao                            &env->CSR_TVAL);
496f8447436STianrui Zhao 
497f8447436STianrui Zhao     ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TCFG),
498f8447436STianrui Zhao                            &env->CSR_TCFG);
499f8447436STianrui Zhao     return ret;
500f8447436STianrui Zhao }
501f8447436STianrui Zhao 
502f8447436STianrui Zhao static int kvm_loongarch_get_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     ret = kvm_vcpu_ioctl(cs, KVM_GET_FPU, &fpu);
509f8447436STianrui Zhao     if (ret < 0) {
510f8447436STianrui Zhao         trace_kvm_failed_get_fpu(strerror(errno));
511f8447436STianrui Zhao         return ret;
512f8447436STianrui Zhao     }
513f8447436STianrui Zhao 
514f8447436STianrui Zhao     env->fcsr0 = fpu.fcsr;
515f8447436STianrui Zhao     for (i = 0; i < 32; i++) {
516f8447436STianrui Zhao         env->fpr[i].vreg.UD[0] = fpu.fpr[i].val64[0];
51707c08661SSong Gao         env->fpr[i].vreg.UD[1] = fpu.fpr[i].val64[1];
51807c08661SSong Gao         env->fpr[i].vreg.UD[2] = fpu.fpr[i].val64[2];
51907c08661SSong Gao         env->fpr[i].vreg.UD[3] = fpu.fpr[i].val64[3];
520f8447436STianrui Zhao     }
521f8447436STianrui Zhao     for (i = 0; i < 8; i++) {
522f8447436STianrui Zhao         env->cf[i] = fpu.fcc & 0xFF;
523f8447436STianrui Zhao         fpu.fcc = fpu.fcc >> 8;
524f8447436STianrui Zhao     }
525f8447436STianrui Zhao 
526f8447436STianrui Zhao     return ret;
527f8447436STianrui Zhao }
528f8447436STianrui Zhao 
529f8447436STianrui Zhao static int kvm_loongarch_put_regs_fp(CPUState *cs)
530f8447436STianrui Zhao {
531f8447436STianrui Zhao     int ret, i;
532f8447436STianrui Zhao     struct kvm_fpu fpu;
533f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
534f8447436STianrui Zhao 
535f8447436STianrui Zhao     fpu.fcsr = env->fcsr0;
536f8447436STianrui Zhao     fpu.fcc = 0;
537f8447436STianrui Zhao     for (i = 0; i < 32; i++) {
538f8447436STianrui Zhao         fpu.fpr[i].val64[0] = env->fpr[i].vreg.UD[0];
53907c08661SSong Gao         fpu.fpr[i].val64[1] = env->fpr[i].vreg.UD[1];
54007c08661SSong Gao         fpu.fpr[i].val64[2] = env->fpr[i].vreg.UD[2];
54107c08661SSong Gao         fpu.fpr[i].val64[3] = env->fpr[i].vreg.UD[3];
542f8447436STianrui Zhao     }
543f8447436STianrui Zhao 
544f8447436STianrui Zhao     for (i = 0; i < 8; i++) {
545f8447436STianrui Zhao         fpu.fcc |= env->cf[i] << (8 * i);
546f8447436STianrui Zhao     }
547f8447436STianrui Zhao 
548f8447436STianrui Zhao     ret = kvm_vcpu_ioctl(cs, KVM_SET_FPU, &fpu);
549f8447436STianrui Zhao     if (ret < 0) {
550f8447436STianrui Zhao         trace_kvm_failed_put_fpu(strerror(errno));
551f8447436STianrui Zhao     }
552f8447436STianrui Zhao 
553f8447436STianrui Zhao     return ret;
554f8447436STianrui Zhao }
555f8447436STianrui Zhao 
556a45df286SBibo Mao static int kvm_loongarch_put_lbt(CPUState *cs)
557a45df286SBibo Mao {
558a45df286SBibo Mao     CPULoongArchState *env = cpu_env(cs);
559a45df286SBibo Mao     uint64_t val;
560a45df286SBibo Mao     int ret;
561a45df286SBibo Mao 
562a45df286SBibo Mao     /* check whether vm support LBT firstly */
563a45df286SBibo Mao     if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LBT_ALL) != 7) {
564a45df286SBibo Mao         return 0;
565a45df286SBibo Mao     }
566a45df286SBibo Mao 
567a45df286SBibo Mao     /* set six LBT registers including scr0-scr3, eflags, ftop */
568a45df286SBibo Mao     ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR0, &env->lbt.scr0);
569a45df286SBibo Mao     ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR1, &env->lbt.scr1);
570a45df286SBibo Mao     ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR2, &env->lbt.scr2);
571a45df286SBibo Mao     ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR3, &env->lbt.scr3);
572a45df286SBibo Mao     /*
573a45df286SBibo Mao      * Be cautious, KVM_REG_LOONGARCH_LBT_FTOP is defined as 64-bit however
574a45df286SBibo Mao      * lbt.ftop is 32-bit; the same with KVM_REG_LOONGARCH_LBT_EFLAGS register
575a45df286SBibo Mao      */
576a45df286SBibo Mao     val = env->lbt.eflags;
577a45df286SBibo Mao     ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_EFLAGS, &val);
578a45df286SBibo Mao     val = env->lbt.ftop;
579a45df286SBibo Mao     ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_FTOP, &val);
580a45df286SBibo Mao 
581a45df286SBibo Mao     return ret;
582a45df286SBibo Mao }
583a45df286SBibo Mao 
584a45df286SBibo Mao static int kvm_loongarch_get_lbt(CPUState *cs)
585a45df286SBibo Mao {
586a45df286SBibo Mao     CPULoongArchState *env = cpu_env(cs);
587a45df286SBibo Mao     uint64_t val;
588a45df286SBibo Mao     int ret;
589a45df286SBibo Mao 
590a45df286SBibo Mao     /* check whether vm support LBT firstly */
591a45df286SBibo Mao     if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LBT_ALL) != 7) {
592a45df286SBibo Mao         return 0;
593a45df286SBibo Mao     }
594a45df286SBibo Mao 
595a45df286SBibo Mao     /* get six LBT registers including scr0-scr3, eflags, ftop */
596a45df286SBibo Mao     ret = kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR0, &env->lbt.scr0);
597a45df286SBibo Mao     ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR1, &env->lbt.scr1);
598a45df286SBibo Mao     ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR2, &env->lbt.scr2);
599a45df286SBibo Mao     ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR3, &env->lbt.scr3);
600a45df286SBibo Mao     ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_EFLAGS, &val);
601a45df286SBibo Mao     env->lbt.eflags = (uint32_t)val;
602a45df286SBibo Mao     ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_FTOP, &val);
603a45df286SBibo Mao     env->lbt.ftop = (uint32_t)val;
604a45df286SBibo Mao 
605a45df286SBibo Mao     return ret;
606a45df286SBibo Mao }
607a45df286SBibo Mao 
608a724f5a8SBibo Mao void kvm_arch_reset_vcpu(CPUState *cs)
609f8447436STianrui Zhao {
610a724f5a8SBibo Mao     CPULoongArchState *env = cpu_env(cs);
611b61b9d89SXianglai Li     int ret = 0;
612b61b9d89SXianglai Li     uint64_t unused = 0;
613a724f5a8SBibo Mao 
614f8447436STianrui Zhao     env->mp_state = KVM_MP_STATE_RUNNABLE;
615b61b9d89SXianglai Li     ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_VCPU_RESET, &unused);
616b61b9d89SXianglai Li     if (ret) {
617b61b9d89SXianglai Li         error_report("Failed to set KVM_REG_LOONGARCH_VCPU_RESET: %s",
618b61b9d89SXianglai Li                      strerror(errno));
619b61b9d89SXianglai Li         exit(EXIT_FAILURE);
620b61b9d89SXianglai Li     }
621f8447436STianrui Zhao }
622f8447436STianrui Zhao 
623f8447436STianrui Zhao static int kvm_loongarch_get_mpstate(CPUState *cs)
624f8447436STianrui Zhao {
625f8447436STianrui Zhao     int ret = 0;
626f8447436STianrui Zhao     struct kvm_mp_state mp_state;
627f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
628f8447436STianrui Zhao 
629f8447436STianrui Zhao     if (cap_has_mp_state) {
630f8447436STianrui Zhao         ret = kvm_vcpu_ioctl(cs, KVM_GET_MP_STATE, &mp_state);
631f8447436STianrui Zhao         if (ret) {
632f8447436STianrui Zhao             trace_kvm_failed_get_mpstate(strerror(errno));
633f8447436STianrui Zhao             return ret;
634f8447436STianrui Zhao         }
635f8447436STianrui Zhao         env->mp_state = mp_state.mp_state;
636f8447436STianrui Zhao     }
637f8447436STianrui Zhao 
638f8447436STianrui Zhao     return ret;
639f8447436STianrui Zhao }
640f8447436STianrui Zhao 
641f8447436STianrui Zhao static int kvm_loongarch_put_mpstate(CPUState *cs)
642f8447436STianrui Zhao {
643f8447436STianrui Zhao     int ret = 0;
644f8447436STianrui Zhao     struct kvm_mp_state mp_state = {
645f3b603b9SPhilippe Mathieu-Daudé         .mp_state = cpu_env(cs)->mp_state
646f8447436STianrui Zhao     };
647f8447436STianrui Zhao 
648f8447436STianrui Zhao     if (cap_has_mp_state) {
649f8447436STianrui Zhao         ret = kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state);
650f8447436STianrui Zhao         if (ret) {
651f8447436STianrui Zhao             trace_kvm_failed_put_mpstate(strerror(errno));
652f8447436STianrui Zhao         }
653f8447436STianrui Zhao     }
654f8447436STianrui Zhao 
655f8447436STianrui Zhao     return ret;
656f8447436STianrui Zhao }
657f8447436STianrui Zhao 
658f8447436STianrui Zhao static int kvm_loongarch_get_cpucfg(CPUState *cs)
659f8447436STianrui Zhao {
660f8447436STianrui Zhao     int i, ret = 0;
661f8447436STianrui Zhao     uint64_t val;
662f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
663f8447436STianrui Zhao 
664f8447436STianrui Zhao     for (i = 0; i < 21; i++) {
665f8447436STianrui Zhao         ret = kvm_get_one_reg(cs, KVM_IOC_CPUCFG(i), &val);
666f8447436STianrui Zhao         if (ret < 0) {
667f8447436STianrui Zhao             trace_kvm_failed_get_cpucfg(strerror(errno));
668f8447436STianrui Zhao         }
669f8447436STianrui Zhao         env->cpucfg[i] = (uint32_t)val;
670f8447436STianrui Zhao     }
671f8447436STianrui Zhao     return ret;
672f8447436STianrui Zhao }
673f8447436STianrui Zhao 
674fc700996SSong Gao static int kvm_check_cpucfg2(CPUState *cs)
675fc700996SSong Gao {
676fc700996SSong Gao     int ret;
677fc700996SSong Gao     uint64_t val;
678fc700996SSong Gao     struct kvm_device_attr attr = {
679fc700996SSong Gao         .group = KVM_LOONGARCH_VCPU_CPUCFG,
680fc700996SSong Gao         .attr = 2,
681fc700996SSong Gao         .addr = (uint64_t)&val,
682fc700996SSong Gao     };
683f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
684fc700996SSong Gao 
685fc700996SSong Gao     ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr);
686fc700996SSong Gao 
687fc700996SSong Gao     if (!ret) {
688fc700996SSong Gao         kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
689fc700996SSong Gao         env->cpucfg[2] &= val;
690fc700996SSong Gao 
691fc700996SSong Gao         if (FIELD_EX32(env->cpucfg[2], CPUCFG2, FP)) {
692fc700996SSong Gao             /* The FP minimal version is 1. */
693fc700996SSong Gao             env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, FP_VER, 1);
694fc700996SSong Gao         }
695fc700996SSong Gao 
696fc700996SSong Gao         if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LLFTP)) {
697fc700996SSong Gao             /* The LLFTP minimal version is 1. */
698fc700996SSong Gao             env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LLFTP_VER, 1);
699fc700996SSong Gao         }
700fc700996SSong Gao     }
701fc700996SSong Gao 
702fc700996SSong Gao     return ret;
703fc700996SSong Gao }
704fc700996SSong Gao 
705f8447436STianrui Zhao static int kvm_loongarch_put_cpucfg(CPUState *cs)
706f8447436STianrui Zhao {
707f8447436STianrui Zhao     int i, ret = 0;
708f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
709f8447436STianrui Zhao     uint64_t val;
710f8447436STianrui Zhao 
711f8447436STianrui Zhao     for (i = 0; i < 21; i++) {
712f8447436STianrui Zhao 	if (i == 2) {
713fc700996SSong Gao             ret = kvm_check_cpucfg2(cs);
714fc700996SSong Gao             if (ret) {
715fc700996SSong Gao                 return ret;
716f8447436STianrui Zhao             }
717fc700996SSong Gao 	}
718fc700996SSong Gao         val = env->cpucfg[i];
719f8447436STianrui Zhao         ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val);
720f8447436STianrui Zhao         if (ret < 0) {
721f8447436STianrui Zhao             trace_kvm_failed_put_cpucfg(strerror(errno));
722f8447436STianrui Zhao         }
723f8447436STianrui Zhao     }
724f8447436STianrui Zhao     return ret;
725f8447436STianrui Zhao }
726f8447436STianrui Zhao 
727a1676bb3SJulia Suvorova int kvm_arch_get_registers(CPUState *cs, Error **errp)
728537ba9daSTianrui Zhao {
729f8447436STianrui Zhao     int ret;
730f8447436STianrui Zhao 
731f8447436STianrui Zhao     ret = kvm_loongarch_get_regs_core(cs);
732f8447436STianrui Zhao     if (ret) {
733f8447436STianrui Zhao         return ret;
734537ba9daSTianrui Zhao     }
735f8447436STianrui Zhao 
7365872966dSBibo Mao     ret = kvm_loongarch_get_cpucfg(cs);
7375872966dSBibo Mao     if (ret) {
7385872966dSBibo Mao         return ret;
7395872966dSBibo Mao     }
7405872966dSBibo Mao 
741f8447436STianrui Zhao     ret = kvm_loongarch_get_csr(cs);
742f8447436STianrui Zhao     if (ret) {
743f8447436STianrui Zhao         return ret;
744f8447436STianrui Zhao     }
745f8447436STianrui Zhao 
746f8447436STianrui Zhao     ret = kvm_loongarch_get_regs_fp(cs);
747f8447436STianrui Zhao     if (ret) {
748f8447436STianrui Zhao         return ret;
749f8447436STianrui Zhao     }
750f8447436STianrui Zhao 
751a45df286SBibo Mao     ret = kvm_loongarch_get_lbt(cs);
752a45df286SBibo Mao     if (ret) {
753a45df286SBibo Mao         return ret;
754a45df286SBibo Mao     }
755a45df286SBibo Mao 
75647b54e15SBibo Mao     ret = kvm_get_stealtime(cs);
75747b54e15SBibo Mao     if (ret) {
75847b54e15SBibo Mao         return ret;
75947b54e15SBibo Mao     }
76047b54e15SBibo Mao 
761f8447436STianrui Zhao     ret = kvm_loongarch_get_mpstate(cs);
762f8447436STianrui Zhao     return ret;
763f8447436STianrui Zhao }
764f8447436STianrui Zhao 
765a1676bb3SJulia Suvorova int kvm_arch_put_registers(CPUState *cs, int level, Error **errp)
766537ba9daSTianrui Zhao {
767f8447436STianrui Zhao     int ret;
768*2698cc7cSBibo Mao     static int once;
769f8447436STianrui Zhao 
770f8447436STianrui Zhao     ret = kvm_loongarch_put_regs_core(cs);
771f8447436STianrui Zhao     if (ret) {
772f8447436STianrui Zhao         return ret;
773f8447436STianrui Zhao     }
774f8447436STianrui Zhao 
7755872966dSBibo Mao     ret = kvm_loongarch_put_cpucfg(cs);
7765872966dSBibo Mao     if (ret) {
7775872966dSBibo Mao         return ret;
7785872966dSBibo Mao     }
7795872966dSBibo Mao 
78061f6e150SBibo Mao     ret = kvm_loongarch_put_csr(cs, level);
781f8447436STianrui Zhao     if (ret) {
782f8447436STianrui Zhao         return ret;
783f8447436STianrui Zhao     }
784f8447436STianrui Zhao 
785f8447436STianrui Zhao     ret = kvm_loongarch_put_regs_fp(cs);
786f8447436STianrui Zhao     if (ret) {
787f8447436STianrui Zhao         return ret;
788f8447436STianrui Zhao     }
789f8447436STianrui Zhao 
790a45df286SBibo Mao     ret = kvm_loongarch_put_lbt(cs);
791a45df286SBibo Mao     if (ret) {
792a45df286SBibo Mao         return ret;
793a45df286SBibo Mao     }
794a45df286SBibo Mao 
795*2698cc7cSBibo Mao     if (!once) {
796*2698cc7cSBibo Mao         ret = kvm_set_pv_features(cs);
797*2698cc7cSBibo Mao         if (ret) {
798*2698cc7cSBibo Mao             return ret;
799*2698cc7cSBibo Mao         }
800*2698cc7cSBibo Mao         once = 1;
801*2698cc7cSBibo Mao     }
802*2698cc7cSBibo Mao 
80347b54e15SBibo Mao     if (level >= KVM_PUT_FULL_STATE) {
80447b54e15SBibo Mao         /*
80547b54e15SBibo Mao          * only KVM_PUT_FULL_STATE is required, kvm kernel will clear
80647b54e15SBibo Mao          * guest_addr for KVM_PUT_RESET_STATE
80747b54e15SBibo Mao          */
80847b54e15SBibo Mao         ret = kvm_set_stealtime(cs);
80947b54e15SBibo Mao         if (ret) {
81047b54e15SBibo Mao             return ret;
81147b54e15SBibo Mao         }
81247b54e15SBibo Mao     }
81347b54e15SBibo Mao 
814f8447436STianrui Zhao     ret = kvm_loongarch_put_mpstate(cs);
815f8447436STianrui Zhao     return ret;
816537ba9daSTianrui Zhao }
817537ba9daSTianrui Zhao 
818d11681c9STianrui Zhao static void kvm_loongarch_vm_stage_change(void *opaque, bool running,
819d11681c9STianrui Zhao                                           RunState state)
820d11681c9STianrui Zhao {
821d11681c9STianrui Zhao     int ret;
822d11681c9STianrui Zhao     CPUState *cs = opaque;
823d11681c9STianrui Zhao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
824d11681c9STianrui Zhao 
825d11681c9STianrui Zhao     if (running) {
826d11681c9STianrui Zhao         ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_COUNTER,
827d11681c9STianrui Zhao                               &cpu->kvm_state_counter);
828d11681c9STianrui Zhao         if (ret < 0) {
829d11681c9STianrui Zhao             trace_kvm_failed_put_counter(strerror(errno));
830d11681c9STianrui Zhao         }
831d11681c9STianrui Zhao     } else {
832d11681c9STianrui Zhao         ret = kvm_get_one_reg(cs, KVM_REG_LOONGARCH_COUNTER,
833d11681c9STianrui Zhao                               &cpu->kvm_state_counter);
834d11681c9STianrui Zhao         if (ret < 0) {
835d11681c9STianrui Zhao             trace_kvm_failed_get_counter(strerror(errno));
836d11681c9STianrui Zhao         }
837d11681c9STianrui Zhao     }
838d11681c9STianrui Zhao }
839d11681c9STianrui Zhao 
840c23a53d8SBibo Mao static bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature)
841c23a53d8SBibo Mao {
842c23a53d8SBibo Mao     int ret;
843c23a53d8SBibo Mao     struct kvm_device_attr attr;
844936c3f4dSBibo Mao     uint64_t val;
845c23a53d8SBibo Mao 
846c23a53d8SBibo Mao     switch (feature) {
847936c3f4dSBibo Mao     case LOONGARCH_FEATURE_LSX:
848936c3f4dSBibo Mao         attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
849936c3f4dSBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_LSX;
850936c3f4dSBibo Mao         ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
851936c3f4dSBibo Mao         if (ret == 0) {
852936c3f4dSBibo Mao             return true;
853936c3f4dSBibo Mao         }
854936c3f4dSBibo Mao 
855936c3f4dSBibo Mao         /* Fallback to old kernel detect interface */
856936c3f4dSBibo Mao         val = 0;
857936c3f4dSBibo Mao         attr.group = KVM_LOONGARCH_VCPU_CPUCFG;
858936c3f4dSBibo Mao         /* Cpucfg2 */
859936c3f4dSBibo Mao         attr.attr  = 2;
860936c3f4dSBibo Mao         attr.addr = (uint64_t)&val;
861936c3f4dSBibo Mao         ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr);
862936c3f4dSBibo Mao         if (!ret) {
863936c3f4dSBibo Mao             ret = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
864936c3f4dSBibo Mao             if (ret) {
865936c3f4dSBibo Mao                 return false;
866936c3f4dSBibo Mao             }
867936c3f4dSBibo Mao 
868936c3f4dSBibo Mao             ret = FIELD_EX32((uint32_t)val, CPUCFG2, LSX);
869936c3f4dSBibo Mao             return (ret != 0);
870936c3f4dSBibo Mao         }
871936c3f4dSBibo Mao         return false;
872936c3f4dSBibo Mao 
8735e360dabSBibo Mao     case LOONGARCH_FEATURE_LASX:
8745e360dabSBibo Mao         attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
8755e360dabSBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_LASX;
8765e360dabSBibo Mao         ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
8775e360dabSBibo Mao         if (ret == 0) {
8785e360dabSBibo Mao             return true;
8795e360dabSBibo Mao         }
8805e360dabSBibo Mao 
8815e360dabSBibo Mao         /* Fallback to old kernel detect interface */
8825e360dabSBibo Mao         val = 0;
8835e360dabSBibo Mao         attr.group = KVM_LOONGARCH_VCPU_CPUCFG;
8845e360dabSBibo Mao         /* Cpucfg2 */
8855e360dabSBibo Mao         attr.attr  = 2;
8865e360dabSBibo Mao         attr.addr = (uint64_t)&val;
8875e360dabSBibo Mao         ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr);
8885e360dabSBibo Mao         if (!ret) {
8895e360dabSBibo Mao             ret = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
8905e360dabSBibo Mao             if (ret) {
8915e360dabSBibo Mao                 return false;
8925e360dabSBibo Mao             }
8935e360dabSBibo Mao 
8945e360dabSBibo Mao             ret = FIELD_EX32((uint32_t)val, CPUCFG2, LASX);
8955e360dabSBibo Mao             return (ret != 0);
8965e360dabSBibo Mao         }
8975e360dabSBibo Mao         return false;
8985e360dabSBibo Mao 
899c23a53d8SBibo Mao     case LOONGARCH_FEATURE_LBT:
900c23a53d8SBibo Mao         /*
901c23a53d8SBibo Mao          * Return all if all the LBT features are supported such as:
902c23a53d8SBibo Mao          *  KVM_LOONGARCH_VM_FEAT_X86BT
903c23a53d8SBibo Mao          *  KVM_LOONGARCH_VM_FEAT_ARMBT
904c23a53d8SBibo Mao          *  KVM_LOONGARCH_VM_FEAT_MIPSBT
905c23a53d8SBibo Mao          */
906c23a53d8SBibo Mao         attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
907c23a53d8SBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_X86BT;
908c23a53d8SBibo Mao         ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
909c23a53d8SBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_ARMBT;
910c23a53d8SBibo Mao         ret |= kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
911c23a53d8SBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_MIPSBT;
912c23a53d8SBibo Mao         ret |= kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
913c23a53d8SBibo Mao         return (ret == 0);
9146edd2a9bSBibo Mao 
9156edd2a9bSBibo Mao     case LOONGARCH_FEATURE_PMU:
9166edd2a9bSBibo Mao         attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
9176edd2a9bSBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_PMU;
9186edd2a9bSBibo Mao         ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
9196edd2a9bSBibo Mao         return (ret == 0);
9206edd2a9bSBibo Mao 
921620d9bd0SBibo Mao     case LOONGARCH_FEATURE_PV_IPI:
922620d9bd0SBibo Mao         attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
923620d9bd0SBibo Mao         attr.attr = KVM_LOONGARCH_VM_FEAT_PV_IPI;
924620d9bd0SBibo Mao         ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
925620d9bd0SBibo Mao         return (ret == 0);
926620d9bd0SBibo Mao 
927c23a53d8SBibo Mao     default:
928c23a53d8SBibo Mao         return false;
929c23a53d8SBibo Mao     }
9306edd2a9bSBibo Mao 
9316edd2a9bSBibo Mao     return false;
932c23a53d8SBibo Mao }
933c23a53d8SBibo Mao 
934936c3f4dSBibo Mao static int kvm_cpu_check_lsx(CPUState *cs, Error **errp)
935936c3f4dSBibo Mao {
936936c3f4dSBibo Mao     CPULoongArchState *env = cpu_env(cs);
937936c3f4dSBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
938936c3f4dSBibo Mao     bool kvm_supported;
939936c3f4dSBibo Mao 
940936c3f4dSBibo Mao     kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_LSX);
941936c3f4dSBibo Mao     env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LSX, 0);
942936c3f4dSBibo Mao     if (cpu->lsx == ON_OFF_AUTO_ON) {
943936c3f4dSBibo Mao         if (kvm_supported) {
944936c3f4dSBibo Mao             env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LSX, 1);
945936c3f4dSBibo Mao         } else {
946936c3f4dSBibo Mao             error_setg(errp, "'lsx' feature not supported by KVM on this host");
947936c3f4dSBibo Mao             return -ENOTSUP;
948936c3f4dSBibo Mao         }
949936c3f4dSBibo Mao     } else if ((cpu->lsx == ON_OFF_AUTO_AUTO) && kvm_supported) {
950936c3f4dSBibo Mao         env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LSX, 1);
951936c3f4dSBibo Mao     }
952936c3f4dSBibo Mao 
953936c3f4dSBibo Mao     return 0;
954936c3f4dSBibo Mao }
955936c3f4dSBibo Mao 
9565e360dabSBibo Mao static int kvm_cpu_check_lasx(CPUState *cs, Error **errp)
9575e360dabSBibo Mao {
9585e360dabSBibo Mao     CPULoongArchState *env = cpu_env(cs);
9595e360dabSBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
9605e360dabSBibo Mao     bool kvm_supported;
9615e360dabSBibo Mao 
9625e360dabSBibo Mao     kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_LASX);
9635e360dabSBibo Mao     env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LASX, 0);
9645e360dabSBibo Mao     if (cpu->lasx == ON_OFF_AUTO_ON) {
9655e360dabSBibo Mao         if (kvm_supported) {
9665e360dabSBibo Mao             env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LASX, 1);
9675e360dabSBibo Mao         } else {
9685e360dabSBibo Mao             error_setg(errp, "'lasx' feature not supported by KVM on host");
9695e360dabSBibo Mao             return -ENOTSUP;
9705e360dabSBibo Mao         }
9715e360dabSBibo Mao     } else if ((cpu->lasx == ON_OFF_AUTO_AUTO) && kvm_supported) {
9725e360dabSBibo Mao         env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LASX, 1);
9735e360dabSBibo Mao     }
9745e360dabSBibo Mao 
9755e360dabSBibo Mao     return 0;
9765e360dabSBibo Mao }
9775e360dabSBibo Mao 
978c23a53d8SBibo Mao static int kvm_cpu_check_lbt(CPUState *cs, Error **errp)
979c23a53d8SBibo Mao {
980c23a53d8SBibo Mao     CPULoongArchState *env = cpu_env(cs);
981c23a53d8SBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
982c23a53d8SBibo Mao     bool kvm_supported;
983c23a53d8SBibo Mao 
984c23a53d8SBibo Mao     kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_LBT);
985c23a53d8SBibo Mao     if (cpu->lbt == ON_OFF_AUTO_ON) {
986c23a53d8SBibo Mao         if (kvm_supported) {
987c23a53d8SBibo Mao             env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LBT_ALL, 7);
988c23a53d8SBibo Mao         } else {
989c23a53d8SBibo Mao             error_setg(errp, "'lbt' feature not supported by KVM on this host");
990c23a53d8SBibo Mao             return -ENOTSUP;
991c23a53d8SBibo Mao         }
992c23a53d8SBibo Mao     } else if ((cpu->lbt == ON_OFF_AUTO_AUTO) && kvm_supported) {
993c23a53d8SBibo Mao         env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LBT_ALL, 7);
994c23a53d8SBibo Mao     }
995c23a53d8SBibo Mao 
996c23a53d8SBibo Mao     return 0;
997c23a53d8SBibo Mao }
998c23a53d8SBibo Mao 
9996edd2a9bSBibo Mao static int kvm_cpu_check_pmu(CPUState *cs, Error **errp)
10006edd2a9bSBibo Mao {
10016edd2a9bSBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
10026edd2a9bSBibo Mao     CPULoongArchState *env = cpu_env(cs);
10036edd2a9bSBibo Mao     bool kvm_supported;
10046edd2a9bSBibo Mao 
10056edd2a9bSBibo Mao     kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_PMU);
10066edd2a9bSBibo Mao     if (cpu->pmu == ON_OFF_AUTO_ON) {
10076edd2a9bSBibo Mao         if (!kvm_supported) {
10086edd2a9bSBibo Mao             error_setg(errp, "'pmu' feature not supported by KVM on the host");
10096edd2a9bSBibo Mao             return -ENOTSUP;
10106edd2a9bSBibo Mao         }
10116edd2a9bSBibo Mao     } else if (cpu->pmu != ON_OFF_AUTO_AUTO) {
10126edd2a9bSBibo Mao         /* disable pmu if ON_OFF_AUTO_OFF is set */
10136edd2a9bSBibo Mao         kvm_supported = false;
10146edd2a9bSBibo Mao     }
10156edd2a9bSBibo Mao 
10166edd2a9bSBibo Mao     if (kvm_supported) {
10176edd2a9bSBibo Mao         env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMP, 1);
10186edd2a9bSBibo Mao         env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMNUM, 3);
10196edd2a9bSBibo Mao         env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMBITS, 63);
10206edd2a9bSBibo Mao         env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, UPM, 1);
10216edd2a9bSBibo Mao     }
10226edd2a9bSBibo Mao     return 0;
10236edd2a9bSBibo Mao }
10246edd2a9bSBibo Mao 
1025620d9bd0SBibo Mao static int kvm_cpu_check_pv_features(CPUState *cs, Error **errp)
1026620d9bd0SBibo Mao {
1027620d9bd0SBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
1028620d9bd0SBibo Mao     CPULoongArchState *env = cpu_env(cs);
1029620d9bd0SBibo Mao     bool kvm_supported;
1030620d9bd0SBibo Mao 
1031620d9bd0SBibo Mao     kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_PV_IPI);
1032620d9bd0SBibo Mao     if (cpu->kvm_pv_ipi == ON_OFF_AUTO_ON) {
1033620d9bd0SBibo Mao         if (!kvm_supported) {
1034620d9bd0SBibo Mao             error_setg(errp, "'pv_ipi' feature not supported by KVM host");
1035620d9bd0SBibo Mao             return -ENOTSUP;
1036620d9bd0SBibo Mao         }
1037620d9bd0SBibo Mao     } else if (cpu->kvm_pv_ipi != ON_OFF_AUTO_AUTO) {
1038620d9bd0SBibo Mao         kvm_supported = false;
1039620d9bd0SBibo Mao     }
1040620d9bd0SBibo Mao 
1041620d9bd0SBibo Mao     if (kvm_supported) {
1042620d9bd0SBibo Mao         env->pv_features |= BIT(KVM_FEATURE_IPI);
1043620d9bd0SBibo Mao     }
1044620d9bd0SBibo Mao 
1045620d9bd0SBibo Mao     return 0;
1046620d9bd0SBibo Mao }
1047620d9bd0SBibo Mao 
1048537ba9daSTianrui Zhao int kvm_arch_init_vcpu(CPUState *cs)
1049537ba9daSTianrui Zhao {
1050d38e31efSBibo Mao     uint64_t val;
1051c23a53d8SBibo Mao     int ret;
1052c23a53d8SBibo Mao     Error *local_err = NULL;
1053d38e31efSBibo Mao 
1054c23a53d8SBibo Mao     ret = 0;
1055d11681c9STianrui Zhao     qemu_add_vm_change_state_handler(kvm_loongarch_vm_stage_change, cs);
1056d38e31efSBibo Mao 
1057d38e31efSBibo Mao     if (!kvm_get_one_reg(cs, KVM_REG_LOONGARCH_DEBUG_INST, &val)) {
1058d38e31efSBibo Mao         brk_insn = val;
1059d38e31efSBibo Mao     }
1060d38e31efSBibo Mao 
1061936c3f4dSBibo Mao     ret = kvm_cpu_check_lsx(cs, &local_err);
1062936c3f4dSBibo Mao     if (ret < 0) {
1063936c3f4dSBibo Mao         error_report_err(local_err);
1064936c3f4dSBibo Mao     }
1065936c3f4dSBibo Mao 
10665e360dabSBibo Mao     ret = kvm_cpu_check_lasx(cs, &local_err);
10675e360dabSBibo Mao     if (ret < 0) {
10685e360dabSBibo Mao         error_report_err(local_err);
10695e360dabSBibo Mao     }
10705e360dabSBibo Mao 
1071c23a53d8SBibo Mao     ret = kvm_cpu_check_lbt(cs, &local_err);
1072c23a53d8SBibo Mao     if (ret < 0) {
1073c23a53d8SBibo Mao         error_report_err(local_err);
1074c23a53d8SBibo Mao     }
10756edd2a9bSBibo Mao 
10766edd2a9bSBibo Mao     ret = kvm_cpu_check_pmu(cs, &local_err);
10776edd2a9bSBibo Mao     if (ret < 0) {
10786edd2a9bSBibo Mao         error_report_err(local_err);
10796edd2a9bSBibo Mao     }
10806edd2a9bSBibo Mao 
1081620d9bd0SBibo Mao     ret = kvm_cpu_check_pv_features(cs, &local_err);
1082620d9bd0SBibo Mao     if (ret < 0) {
1083620d9bd0SBibo Mao         error_report_err(local_err);
1084620d9bd0SBibo Mao     }
1085620d9bd0SBibo Mao 
1086c23a53d8SBibo Mao     return ret;
1087537ba9daSTianrui Zhao }
1088537ba9daSTianrui Zhao 
1089780a65bdSBibo Mao static bool loongarch_get_lbt(Object *obj, Error **errp)
1090780a65bdSBibo Mao {
1091780a65bdSBibo Mao     return LOONGARCH_CPU(obj)->lbt != ON_OFF_AUTO_OFF;
1092780a65bdSBibo Mao }
1093780a65bdSBibo Mao 
1094780a65bdSBibo Mao static void loongarch_set_lbt(Object *obj, bool value, Error **errp)
1095780a65bdSBibo Mao {
1096780a65bdSBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(obj);
1097780a65bdSBibo Mao 
1098780a65bdSBibo Mao     cpu->lbt = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
1099780a65bdSBibo Mao }
1100780a65bdSBibo Mao 
1101780a65bdSBibo Mao static bool loongarch_get_pmu(Object *obj, Error **errp)
1102780a65bdSBibo Mao {
1103780a65bdSBibo Mao     return LOONGARCH_CPU(obj)->pmu != ON_OFF_AUTO_OFF;
1104780a65bdSBibo Mao }
1105780a65bdSBibo Mao 
1106780a65bdSBibo Mao static void loongarch_set_pmu(Object *obj, bool value, Error **errp)
1107780a65bdSBibo Mao {
1108780a65bdSBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(obj);
1109780a65bdSBibo Mao 
1110780a65bdSBibo Mao     cpu->pmu = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
1111780a65bdSBibo Mao }
1112780a65bdSBibo Mao 
11135b0502c5SBibo Mao static bool kvm_pv_ipi_get(Object *obj, Error **errp)
11145b0502c5SBibo Mao {
11155b0502c5SBibo Mao     return LOONGARCH_CPU(obj)->kvm_pv_ipi != ON_OFF_AUTO_OFF;
11165b0502c5SBibo Mao }
11175b0502c5SBibo Mao 
11185b0502c5SBibo Mao static void kvm_pv_ipi_set(Object *obj, bool value, Error **errp)
11195b0502c5SBibo Mao {
11205b0502c5SBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(obj);
11215b0502c5SBibo Mao 
11225b0502c5SBibo Mao     cpu->kvm_pv_ipi = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
11235b0502c5SBibo Mao }
11245b0502c5SBibo Mao 
11253406b001SBibo Mao void kvm_loongarch_cpu_post_init(LoongArchCPU *cpu)
11263406b001SBibo Mao {
1127780a65bdSBibo Mao     cpu->lbt = ON_OFF_AUTO_AUTO;
1128780a65bdSBibo Mao     object_property_add_bool(OBJECT(cpu), "lbt", loongarch_get_lbt,
1129780a65bdSBibo Mao                              loongarch_set_lbt);
1130780a65bdSBibo Mao     object_property_set_description(OBJECT(cpu), "lbt",
1131780a65bdSBibo Mao                                    "Set off to disable Binary Tranlation.");
1132780a65bdSBibo Mao 
1133780a65bdSBibo Mao     cpu->pmu = ON_OFF_AUTO_AUTO;
1134780a65bdSBibo Mao     object_property_add_bool(OBJECT(cpu), "pmu", loongarch_get_pmu,
1135780a65bdSBibo Mao                              loongarch_set_pmu);
1136780a65bdSBibo Mao     object_property_set_description(OBJECT(cpu), "pmu",
1137780a65bdSBibo Mao                                "Set off to disable performance monitor unit.");
11385b0502c5SBibo Mao 
11395b0502c5SBibo Mao     cpu->kvm_pv_ipi = ON_OFF_AUTO_AUTO;
11405b0502c5SBibo Mao     object_property_add_bool(OBJECT(cpu), "kvm-pv-ipi", kvm_pv_ipi_get,
11415b0502c5SBibo Mao                              kvm_pv_ipi_set);
11425b0502c5SBibo Mao     object_property_set_description(OBJECT(cpu), "kvm-pv-ipi",
11435b0502c5SBibo Mao                                     "Set off to disable KVM paravirt IPI.");
11443406b001SBibo Mao }
11453406b001SBibo Mao 
1146537ba9daSTianrui Zhao int kvm_arch_destroy_vcpu(CPUState *cs)
1147537ba9daSTianrui Zhao {
1148537ba9daSTianrui Zhao     return 0;
1149537ba9daSTianrui Zhao }
1150537ba9daSTianrui Zhao 
1151537ba9daSTianrui Zhao unsigned long kvm_arch_vcpu_id(CPUState *cs)
1152537ba9daSTianrui Zhao {
1153537ba9daSTianrui Zhao     return cs->cpu_index;
1154537ba9daSTianrui Zhao }
1155537ba9daSTianrui Zhao 
1156537ba9daSTianrui Zhao int kvm_arch_release_virq_post(int virq)
1157537ba9daSTianrui Zhao {
1158537ba9daSTianrui Zhao     return 0;
1159537ba9daSTianrui Zhao }
1160537ba9daSTianrui Zhao 
1161537ba9daSTianrui Zhao int kvm_arch_msi_data_to_gsi(uint32_t data)
1162537ba9daSTianrui Zhao {
1163537ba9daSTianrui Zhao     abort();
1164537ba9daSTianrui Zhao }
1165537ba9daSTianrui Zhao 
1166537ba9daSTianrui Zhao int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
1167537ba9daSTianrui Zhao                              uint64_t address, uint32_t data, PCIDevice *dev)
1168537ba9daSTianrui Zhao {
1169537ba9daSTianrui Zhao     return 0;
1170537ba9daSTianrui Zhao }
1171537ba9daSTianrui Zhao 
1172537ba9daSTianrui Zhao int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
1173537ba9daSTianrui Zhao                                 int vector, PCIDevice *dev)
1174537ba9daSTianrui Zhao {
1175537ba9daSTianrui Zhao     return 0;
1176537ba9daSTianrui Zhao }
1177537ba9daSTianrui Zhao 
1178537ba9daSTianrui Zhao void kvm_arch_init_irq_routing(KVMState *s)
1179537ba9daSTianrui Zhao {
1180537ba9daSTianrui Zhao }
1181537ba9daSTianrui Zhao 
1182537ba9daSTianrui Zhao int kvm_arch_get_default_type(MachineState *ms)
1183537ba9daSTianrui Zhao {
1184537ba9daSTianrui Zhao     return 0;
1185537ba9daSTianrui Zhao }
1186537ba9daSTianrui Zhao 
1187537ba9daSTianrui Zhao int kvm_arch_init(MachineState *ms, KVMState *s)
1188537ba9daSTianrui Zhao {
118941958c99STianrui Zhao     cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
1190537ba9daSTianrui Zhao     return 0;
1191537ba9daSTianrui Zhao }
1192537ba9daSTianrui Zhao 
1193537ba9daSTianrui Zhao int kvm_arch_irqchip_create(KVMState *s)
1194537ba9daSTianrui Zhao {
1195537ba9daSTianrui Zhao     return 0;
1196537ba9daSTianrui Zhao }
1197537ba9daSTianrui Zhao 
1198537ba9daSTianrui Zhao void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
1199537ba9daSTianrui Zhao {
1200537ba9daSTianrui Zhao }
1201537ba9daSTianrui Zhao 
1202537ba9daSTianrui Zhao MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
1203537ba9daSTianrui Zhao {
1204537ba9daSTianrui Zhao     return MEMTXATTRS_UNSPECIFIED;
1205537ba9daSTianrui Zhao }
1206537ba9daSTianrui Zhao 
1207537ba9daSTianrui Zhao int kvm_arch_process_async_events(CPUState *cs)
1208537ba9daSTianrui Zhao {
1209537ba9daSTianrui Zhao     return cs->halted;
1210537ba9daSTianrui Zhao }
1211537ba9daSTianrui Zhao 
1212537ba9daSTianrui Zhao bool kvm_arch_stop_on_emulation_error(CPUState *cs)
1213537ba9daSTianrui Zhao {
1214537ba9daSTianrui Zhao     return true;
1215537ba9daSTianrui Zhao }
1216537ba9daSTianrui Zhao 
1217d38e31efSBibo Mao void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
1218d38e31efSBibo Mao {
1219d38e31efSBibo Mao     if (kvm_sw_breakpoints_active(cpu)) {
1220d38e31efSBibo Mao         dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
1221d38e31efSBibo Mao     }
1222d38e31efSBibo Mao }
1223d38e31efSBibo Mao 
1224d38e31efSBibo Mao int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
1225d38e31efSBibo Mao {
1226d38e31efSBibo Mao     if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
1227d38e31efSBibo Mao         cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) {
1228d38e31efSBibo Mao         error_report("%s failed", __func__);
1229d38e31efSBibo Mao         return -EINVAL;
1230d38e31efSBibo Mao     }
1231d38e31efSBibo Mao     return 0;
1232d38e31efSBibo Mao }
1233d38e31efSBibo Mao 
1234d38e31efSBibo Mao int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
1235d38e31efSBibo Mao {
1236d38e31efSBibo Mao     static uint32_t brk;
1237d38e31efSBibo Mao 
1238d38e31efSBibo Mao     if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk, 4, 0) ||
1239d38e31efSBibo Mao         brk != brk_insn ||
1240d38e31efSBibo Mao         cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) {
1241d38e31efSBibo Mao         error_report("%s failed", __func__);
1242d38e31efSBibo Mao         return -EINVAL;
1243d38e31efSBibo Mao     }
1244d38e31efSBibo Mao     return 0;
1245d38e31efSBibo Mao }
1246d38e31efSBibo Mao 
1247d38e31efSBibo Mao int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type)
1248d38e31efSBibo Mao {
1249d38e31efSBibo Mao     return -ENOSYS;
1250d38e31efSBibo Mao }
1251d38e31efSBibo Mao 
1252d38e31efSBibo Mao int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type)
1253d38e31efSBibo Mao {
1254d38e31efSBibo Mao     return -ENOSYS;
1255d38e31efSBibo Mao }
1256d38e31efSBibo Mao 
1257d38e31efSBibo Mao void kvm_arch_remove_all_hw_breakpoints(void)
1258d38e31efSBibo Mao {
1259d38e31efSBibo Mao }
1260d38e31efSBibo Mao 
1261d38e31efSBibo Mao static bool kvm_loongarch_handle_debug(CPUState *cs, struct kvm_run *run)
1262d38e31efSBibo Mao {
1263d38e31efSBibo Mao     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
1264d38e31efSBibo Mao     CPULoongArchState *env = &cpu->env;
1265d38e31efSBibo Mao 
1266d38e31efSBibo Mao     kvm_cpu_synchronize_state(cs);
1267d38e31efSBibo Mao     if (cs->singlestep_enabled) {
1268d38e31efSBibo Mao         return true;
1269d38e31efSBibo Mao     }
1270d38e31efSBibo Mao 
1271d38e31efSBibo Mao     if (kvm_find_sw_breakpoint(cs, env->pc)) {
1272d38e31efSBibo Mao         return true;
1273d38e31efSBibo Mao     }
1274d38e31efSBibo Mao 
1275d38e31efSBibo Mao     return false;
1276d38e31efSBibo Mao }
1277d38e31efSBibo Mao 
1278537ba9daSTianrui Zhao int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
1279537ba9daSTianrui Zhao {
1280a05a950fSTianrui Zhao     int ret = 0;
1281f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
1282a05a950fSTianrui Zhao     MemTxAttrs attrs = {};
1283a05a950fSTianrui Zhao 
1284a05a950fSTianrui Zhao     attrs.requester_id = env_cpu(env)->cpu_index;
1285a05a950fSTianrui Zhao 
1286a05a950fSTianrui Zhao     trace_kvm_arch_handle_exit(run->exit_reason);
1287a05a950fSTianrui Zhao     switch (run->exit_reason) {
1288a05a950fSTianrui Zhao     case KVM_EXIT_LOONGARCH_IOCSR:
12895e90b8dbSBibo Mao         address_space_rw(env->address_space_iocsr,
1290a05a950fSTianrui Zhao                          run->iocsr_io.phys_addr,
1291a05a950fSTianrui Zhao                          attrs,
1292a05a950fSTianrui Zhao                          run->iocsr_io.data,
1293a05a950fSTianrui Zhao                          run->iocsr_io.len,
1294a05a950fSTianrui Zhao                          run->iocsr_io.is_write);
1295a05a950fSTianrui Zhao         break;
1296d38e31efSBibo Mao 
1297d38e31efSBibo Mao     case KVM_EXIT_DEBUG:
1298d38e31efSBibo Mao         if (kvm_loongarch_handle_debug(cs, run)) {
1299d38e31efSBibo Mao             ret = EXCP_DEBUG;
1300d38e31efSBibo Mao         }
1301d38e31efSBibo Mao         break;
1302d38e31efSBibo Mao 
1303a05a950fSTianrui Zhao     default:
1304a05a950fSTianrui Zhao         ret = -1;
1305a05a950fSTianrui Zhao         warn_report("KVM: unknown exit reason %d", run->exit_reason);
1306a05a950fSTianrui Zhao         break;
1307a05a950fSTianrui Zhao     }
1308a05a950fSTianrui Zhao     return ret;
1309537ba9daSTianrui Zhao }
1310537ba9daSTianrui Zhao 
13118dcbad51STianrui Zhao int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level)
13128dcbad51STianrui Zhao {
13138dcbad51STianrui Zhao     struct kvm_interrupt intr;
13148dcbad51STianrui Zhao     CPUState *cs = CPU(cpu);
13158dcbad51STianrui Zhao 
13168dcbad51STianrui Zhao     if (level) {
13178dcbad51STianrui Zhao         intr.irq = irq;
13188dcbad51STianrui Zhao     } else {
13198dcbad51STianrui Zhao         intr.irq = -irq;
13208dcbad51STianrui Zhao     }
13218dcbad51STianrui Zhao 
13228dcbad51STianrui Zhao     trace_kvm_set_intr(irq, level);
13238dcbad51STianrui Zhao     return kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr);
13248dcbad51STianrui Zhao }
13258dcbad51STianrui Zhao 
1326537ba9daSTianrui Zhao void kvm_arch_accel_class_init(ObjectClass *oc)
1327537ba9daSTianrui Zhao {
1328537ba9daSTianrui Zhao }
1329