MIPS: Move KVM specific opcodes into asm/inst.h
[linux-drm-fsl-dcu.git] / arch / mips / kvm / trap_emul.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * KVM/MIPS: Deliver/Emulate exceptions to the guest kernel
7  *
8  * Copyright (C) 2012  MIPS Technologies, Inc.  All rights reserved.
9  * Authors: Sanjay Lal <sanjayl@kymasys.com>
10  */
11
12 #include <linux/errno.h>
13 #include <linux/err.h>
14 #include <linux/module.h>
15 #include <linux/vmalloc.h>
16
17 #include <linux/kvm_host.h>
18
19 #include "interrupt.h"
20
21 static gpa_t kvm_trap_emul_gva_to_gpa_cb(gva_t gva)
22 {
23         gpa_t gpa;
24         uint32_t kseg = KSEGX(gva);
25
26         if ((kseg == CKSEG0) || (kseg == CKSEG1))
27                 gpa = CPHYSADDR(gva);
28         else {
29                 kvm_err("%s: cannot find GPA for GVA: %#lx\n", __func__, gva);
30                 kvm_mips_dump_host_tlbs();
31                 gpa = KVM_INVALID_ADDR;
32         }
33
34         kvm_debug("%s: gva %#lx, gpa: %#llx\n", __func__, gva, gpa);
35
36         return gpa;
37 }
38
39 static int kvm_trap_emul_handle_cop_unusable(struct kvm_vcpu *vcpu)
40 {
41         struct mips_coproc *cop0 = vcpu->arch.cop0;
42         struct kvm_run *run = vcpu->run;
43         uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
44         unsigned long cause = vcpu->arch.host_cp0_cause;
45         enum emulation_result er = EMULATE_DONE;
46         int ret = RESUME_GUEST;
47
48         if (((cause & CAUSEF_CE) >> CAUSEB_CE) == 1) {
49                 /* FPU Unusable */
50                 if (!kvm_mips_guest_has_fpu(&vcpu->arch) ||
51                     (kvm_read_c0_guest_status(cop0) & ST0_CU1) == 0) {
52                         /*
53                          * Unusable/no FPU in guest:
54                          * deliver guest COP1 Unusable Exception
55                          */
56                         er = kvm_mips_emulate_fpu_exc(cause, opc, run, vcpu);
57                 } else {
58                         /* Restore FPU state */
59                         kvm_own_fpu(vcpu);
60                         er = EMULATE_DONE;
61                 }
62         } else {
63                 er = kvm_mips_emulate_inst(cause, opc, run, vcpu);
64         }
65
66         switch (er) {
67         case EMULATE_DONE:
68                 ret = RESUME_GUEST;
69                 break;
70
71         case EMULATE_FAIL:
72                 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
73                 ret = RESUME_HOST;
74                 break;
75
76         case EMULATE_WAIT:
77                 run->exit_reason = KVM_EXIT_INTR;
78                 ret = RESUME_HOST;
79                 break;
80
81         default:
82                 BUG();
83         }
84         return ret;
85 }
86
87 static int kvm_trap_emul_handle_tlb_mod(struct kvm_vcpu *vcpu)
88 {
89         struct kvm_run *run = vcpu->run;
90         uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
91         unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
92         unsigned long cause = vcpu->arch.host_cp0_cause;
93         enum emulation_result er = EMULATE_DONE;
94         int ret = RESUME_GUEST;
95
96         if (KVM_GUEST_KSEGX(badvaddr) < KVM_GUEST_KSEG0
97             || KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG23) {
98                 kvm_debug("USER/KSEG23 ADDR TLB MOD fault: cause %#lx, PC: %p, BadVaddr: %#lx\n",
99                           cause, opc, badvaddr);
100                 er = kvm_mips_handle_tlbmod(cause, opc, run, vcpu);
101
102                 if (er == EMULATE_DONE)
103                         ret = RESUME_GUEST;
104                 else {
105                         run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
106                         ret = RESUME_HOST;
107                 }
108         } else if (KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG0) {
109                 /*
110                  * XXXKYMA: The guest kernel does not expect to get this fault
111                  * when we are not using HIGHMEM. Need to address this in a
112                  * HIGHMEM kernel
113                  */
114                 kvm_err("TLB MOD fault not handled, cause %#lx, PC: %p, BadVaddr: %#lx\n",
115                         cause, opc, badvaddr);
116                 kvm_mips_dump_host_tlbs();
117                 kvm_arch_vcpu_dump_regs(vcpu);
118                 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
119                 ret = RESUME_HOST;
120         } else {
121                 kvm_err("Illegal TLB Mod fault address , cause %#lx, PC: %p, BadVaddr: %#lx\n",
122                         cause, opc, badvaddr);
123                 kvm_mips_dump_host_tlbs();
124                 kvm_arch_vcpu_dump_regs(vcpu);
125                 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
126                 ret = RESUME_HOST;
127         }
128         return ret;
129 }
130
131 static int kvm_trap_emul_handle_tlb_st_miss(struct kvm_vcpu *vcpu)
132 {
133         struct kvm_run *run = vcpu->run;
134         uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
135         unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
136         unsigned long cause = vcpu->arch.host_cp0_cause;
137         enum emulation_result er = EMULATE_DONE;
138         int ret = RESUME_GUEST;
139
140         if (((badvaddr & PAGE_MASK) == KVM_GUEST_COMMPAGE_ADDR)
141             && KVM_GUEST_KERNEL_MODE(vcpu)) {
142                 if (kvm_mips_handle_commpage_tlb_fault(badvaddr, vcpu) < 0) {
143                         run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
144                         ret = RESUME_HOST;
145                 }
146         } else if (KVM_GUEST_KSEGX(badvaddr) < KVM_GUEST_KSEG0
147                    || KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG23) {
148                 kvm_debug("USER ADDR TLB LD fault: cause %#lx, PC: %p, BadVaddr: %#lx\n",
149                           cause, opc, badvaddr);
150                 er = kvm_mips_handle_tlbmiss(cause, opc, run, vcpu);
151                 if (er == EMULATE_DONE)
152                         ret = RESUME_GUEST;
153                 else {
154                         run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
155                         ret = RESUME_HOST;
156                 }
157         } else if (KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG0) {
158                 /*
159                  * All KSEG0 faults are handled by KVM, as the guest kernel does
160                  * not expect to ever get them
161                  */
162                 if (kvm_mips_handle_kseg0_tlb_fault
163                     (vcpu->arch.host_cp0_badvaddr, vcpu) < 0) {
164                         run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
165                         ret = RESUME_HOST;
166                 }
167         } else {
168                 kvm_err("Illegal TLB LD fault address , cause %#lx, PC: %p, BadVaddr: %#lx\n",
169                         cause, opc, badvaddr);
170                 kvm_mips_dump_host_tlbs();
171                 kvm_arch_vcpu_dump_regs(vcpu);
172                 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
173                 ret = RESUME_HOST;
174         }
175         return ret;
176 }
177
178 static int kvm_trap_emul_handle_tlb_ld_miss(struct kvm_vcpu *vcpu)
179 {
180         struct kvm_run *run = vcpu->run;
181         uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
182         unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
183         unsigned long cause = vcpu->arch.host_cp0_cause;
184         enum emulation_result er = EMULATE_DONE;
185         int ret = RESUME_GUEST;
186
187         if (((badvaddr & PAGE_MASK) == KVM_GUEST_COMMPAGE_ADDR)
188             && KVM_GUEST_KERNEL_MODE(vcpu)) {
189                 if (kvm_mips_handle_commpage_tlb_fault(badvaddr, vcpu) < 0) {
190                         run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
191                         ret = RESUME_HOST;
192                 }
193         } else if (KVM_GUEST_KSEGX(badvaddr) < KVM_GUEST_KSEG0
194                    || KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG23) {
195                 kvm_debug("USER ADDR TLB ST fault: PC: %#lx, BadVaddr: %#lx\n",
196                           vcpu->arch.pc, badvaddr);
197
198                 /*
199                  * User Address (UA) fault, this could happen if
200                  * (1) TLB entry not present/valid in both Guest and shadow host
201                  *     TLBs, in this case we pass on the fault to the guest
202                  *     kernel and let it handle it.
203                  * (2) TLB entry is present in the Guest TLB but not in the
204                  *     shadow, in this case we inject the TLB from the Guest TLB
205                  *     into the shadow host TLB
206                  */
207
208                 er = kvm_mips_handle_tlbmiss(cause, opc, run, vcpu);
209                 if (er == EMULATE_DONE)
210                         ret = RESUME_GUEST;
211                 else {
212                         run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
213                         ret = RESUME_HOST;
214                 }
215         } else if (KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG0) {
216                 if (kvm_mips_handle_kseg0_tlb_fault
217                     (vcpu->arch.host_cp0_badvaddr, vcpu) < 0) {
218                         run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
219                         ret = RESUME_HOST;
220                 }
221         } else {
222                 kvm_err("Illegal TLB ST fault address , cause %#lx, PC: %p, BadVaddr: %#lx\n",
223                         cause, opc, badvaddr);
224                 kvm_mips_dump_host_tlbs();
225                 kvm_arch_vcpu_dump_regs(vcpu);
226                 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
227                 ret = RESUME_HOST;
228         }
229         return ret;
230 }
231
232 static int kvm_trap_emul_handle_addr_err_st(struct kvm_vcpu *vcpu)
233 {
234         struct kvm_run *run = vcpu->run;
235         uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
236         unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
237         unsigned long cause = vcpu->arch.host_cp0_cause;
238         enum emulation_result er = EMULATE_DONE;
239         int ret = RESUME_GUEST;
240
241         if (KVM_GUEST_KERNEL_MODE(vcpu)
242             && (KSEGX(badvaddr) == CKSEG0 || KSEGX(badvaddr) == CKSEG1)) {
243                 kvm_debug("Emulate Store to MMIO space\n");
244                 er = kvm_mips_emulate_inst(cause, opc, run, vcpu);
245                 if (er == EMULATE_FAIL) {
246                         kvm_err("Emulate Store to MMIO space failed\n");
247                         run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
248                         ret = RESUME_HOST;
249                 } else {
250                         run->exit_reason = KVM_EXIT_MMIO;
251                         ret = RESUME_HOST;
252                 }
253         } else {
254                 kvm_err("Address Error (STORE): cause %#lx, PC: %p, BadVaddr: %#lx\n",
255                         cause, opc, badvaddr);
256                 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
257                 ret = RESUME_HOST;
258         }
259         return ret;
260 }
261
262 static int kvm_trap_emul_handle_addr_err_ld(struct kvm_vcpu *vcpu)
263 {
264         struct kvm_run *run = vcpu->run;
265         uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
266         unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
267         unsigned long cause = vcpu->arch.host_cp0_cause;
268         enum emulation_result er = EMULATE_DONE;
269         int ret = RESUME_GUEST;
270
271         if (KSEGX(badvaddr) == CKSEG0 || KSEGX(badvaddr) == CKSEG1) {
272                 kvm_debug("Emulate Load from MMIO space @ %#lx\n", badvaddr);
273                 er = kvm_mips_emulate_inst(cause, opc, run, vcpu);
274                 if (er == EMULATE_FAIL) {
275                         kvm_err("Emulate Load from MMIO space failed\n");
276                         run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
277                         ret = RESUME_HOST;
278                 } else {
279                         run->exit_reason = KVM_EXIT_MMIO;
280                         ret = RESUME_HOST;
281                 }
282         } else {
283                 kvm_err("Address Error (LOAD): cause %#lx, PC: %p, BadVaddr: %#lx\n",
284                         cause, opc, badvaddr);
285                 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
286                 ret = RESUME_HOST;
287                 er = EMULATE_FAIL;
288         }
289         return ret;
290 }
291
292 static int kvm_trap_emul_handle_syscall(struct kvm_vcpu *vcpu)
293 {
294         struct kvm_run *run = vcpu->run;
295         uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
296         unsigned long cause = vcpu->arch.host_cp0_cause;
297         enum emulation_result er = EMULATE_DONE;
298         int ret = RESUME_GUEST;
299
300         er = kvm_mips_emulate_syscall(cause, opc, run, vcpu);
301         if (er == EMULATE_DONE)
302                 ret = RESUME_GUEST;
303         else {
304                 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
305                 ret = RESUME_HOST;
306         }
307         return ret;
308 }
309
310 static int kvm_trap_emul_handle_res_inst(struct kvm_vcpu *vcpu)
311 {
312         struct kvm_run *run = vcpu->run;
313         uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
314         unsigned long cause = vcpu->arch.host_cp0_cause;
315         enum emulation_result er = EMULATE_DONE;
316         int ret = RESUME_GUEST;
317
318         er = kvm_mips_handle_ri(cause, opc, run, vcpu);
319         if (er == EMULATE_DONE)
320                 ret = RESUME_GUEST;
321         else {
322                 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
323                 ret = RESUME_HOST;
324         }
325         return ret;
326 }
327
328 static int kvm_trap_emul_handle_break(struct kvm_vcpu *vcpu)
329 {
330         struct kvm_run *run = vcpu->run;
331         uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
332         unsigned long cause = vcpu->arch.host_cp0_cause;
333         enum emulation_result er = EMULATE_DONE;
334         int ret = RESUME_GUEST;
335
336         er = kvm_mips_emulate_bp_exc(cause, opc, run, vcpu);
337         if (er == EMULATE_DONE)
338                 ret = RESUME_GUEST;
339         else {
340                 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
341                 ret = RESUME_HOST;
342         }
343         return ret;
344 }
345
346 static int kvm_trap_emul_handle_trap(struct kvm_vcpu *vcpu)
347 {
348         struct kvm_run *run = vcpu->run;
349         uint32_t __user *opc = (uint32_t __user *)vcpu->arch.pc;
350         unsigned long cause = vcpu->arch.host_cp0_cause;
351         enum emulation_result er = EMULATE_DONE;
352         int ret = RESUME_GUEST;
353
354         er = kvm_mips_emulate_trap_exc(cause, opc, run, vcpu);
355         if (er == EMULATE_DONE) {
356                 ret = RESUME_GUEST;
357         } else {
358                 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
359                 ret = RESUME_HOST;
360         }
361         return ret;
362 }
363
364 static int kvm_trap_emul_handle_msa_fpe(struct kvm_vcpu *vcpu)
365 {
366         struct kvm_run *run = vcpu->run;
367         uint32_t __user *opc = (uint32_t __user *)vcpu->arch.pc;
368         unsigned long cause = vcpu->arch.host_cp0_cause;
369         enum emulation_result er = EMULATE_DONE;
370         int ret = RESUME_GUEST;
371
372         er = kvm_mips_emulate_msafpe_exc(cause, opc, run, vcpu);
373         if (er == EMULATE_DONE) {
374                 ret = RESUME_GUEST;
375         } else {
376                 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
377                 ret = RESUME_HOST;
378         }
379         return ret;
380 }
381
382 static int kvm_trap_emul_handle_fpe(struct kvm_vcpu *vcpu)
383 {
384         struct kvm_run *run = vcpu->run;
385         uint32_t __user *opc = (uint32_t __user *)vcpu->arch.pc;
386         unsigned long cause = vcpu->arch.host_cp0_cause;
387         enum emulation_result er = EMULATE_DONE;
388         int ret = RESUME_GUEST;
389
390         er = kvm_mips_emulate_fpe_exc(cause, opc, run, vcpu);
391         if (er == EMULATE_DONE) {
392                 ret = RESUME_GUEST;
393         } else {
394                 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
395                 ret = RESUME_HOST;
396         }
397         return ret;
398 }
399
400 /**
401  * kvm_trap_emul_handle_msa_disabled() - Guest used MSA while disabled in root.
402  * @vcpu:       Virtual CPU context.
403  *
404  * Handle when the guest attempts to use MSA when it is disabled.
405  */
406 static int kvm_trap_emul_handle_msa_disabled(struct kvm_vcpu *vcpu)
407 {
408         struct mips_coproc *cop0 = vcpu->arch.cop0;
409         struct kvm_run *run = vcpu->run;
410         uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
411         unsigned long cause = vcpu->arch.host_cp0_cause;
412         enum emulation_result er = EMULATE_DONE;
413         int ret = RESUME_GUEST;
414
415         if (!kvm_mips_guest_has_msa(&vcpu->arch) ||
416             (kvm_read_c0_guest_status(cop0) & (ST0_CU1 | ST0_FR)) == ST0_CU1) {
417                 /*
418                  * No MSA in guest, or FPU enabled and not in FR=1 mode,
419                  * guest reserved instruction exception
420                  */
421                 er = kvm_mips_emulate_ri_exc(cause, opc, run, vcpu);
422         } else if (!(kvm_read_c0_guest_config5(cop0) & MIPS_CONF5_MSAEN)) {
423                 /* MSA disabled by guest, guest MSA disabled exception */
424                 er = kvm_mips_emulate_msadis_exc(cause, opc, run, vcpu);
425         } else {
426                 /* Restore MSA/FPU state */
427                 kvm_own_msa(vcpu);
428                 er = EMULATE_DONE;
429         }
430
431         switch (er) {
432         case EMULATE_DONE:
433                 ret = RESUME_GUEST;
434                 break;
435
436         case EMULATE_FAIL:
437                 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
438                 ret = RESUME_HOST;
439                 break;
440
441         default:
442                 BUG();
443         }
444         return ret;
445 }
446
447 static int kvm_trap_emul_vm_init(struct kvm *kvm)
448 {
449         return 0;
450 }
451
452 static int kvm_trap_emul_vcpu_init(struct kvm_vcpu *vcpu)
453 {
454         return 0;
455 }
456
457 static int kvm_trap_emul_vcpu_setup(struct kvm_vcpu *vcpu)
458 {
459         struct mips_coproc *cop0 = vcpu->arch.cop0;
460         uint32_t config1;
461         int vcpu_id = vcpu->vcpu_id;
462
463         /*
464          * Arch specific stuff, set up config registers properly so that the
465          * guest will come up as expected, for now we simulate a MIPS 24kc
466          */
467         kvm_write_c0_guest_prid(cop0, 0x00019300);
468         /* Have config1, Cacheable, noncoherent, write-back, write allocate */
469         kvm_write_c0_guest_config(cop0, MIPS_CONF_M | (0x3 << CP0C0_K0) |
470                                   (0x1 << CP0C0_AR) |
471                                   (MMU_TYPE_R4000 << CP0C0_MT));
472
473         /* Read the cache characteristics from the host Config1 Register */
474         config1 = (read_c0_config1() & ~0x7f);
475
476         /* Set up MMU size */
477         config1 &= ~(0x3f << 25);
478         config1 |= ((KVM_MIPS_GUEST_TLB_SIZE - 1) << 25);
479
480         /* We unset some bits that we aren't emulating */
481         config1 &=
482             ~((1 << CP0C1_C2) | (1 << CP0C1_MD) | (1 << CP0C1_PC) |
483               (1 << CP0C1_WR) | (1 << CP0C1_CA));
484         kvm_write_c0_guest_config1(cop0, config1);
485
486         /* Have config3, no tertiary/secondary caches implemented */
487         kvm_write_c0_guest_config2(cop0, MIPS_CONF_M);
488         /* MIPS_CONF_M | (read_c0_config2() & 0xfff) */
489
490         /* Have config4, UserLocal */
491         kvm_write_c0_guest_config3(cop0, MIPS_CONF_M | MIPS_CONF3_ULRI);
492
493         /* Have config5 */
494         kvm_write_c0_guest_config4(cop0, MIPS_CONF_M);
495
496         /* No config6 */
497         kvm_write_c0_guest_config5(cop0, 0);
498
499         /* Set Wait IE/IXMT Ignore in Config7, IAR, AR */
500         kvm_write_c0_guest_config7(cop0, (MIPS_CONF7_WII) | (1 << 10));
501
502         /*
503          * Setup IntCtl defaults, compatibilty mode for timer interrupts (HW5)
504          */
505         kvm_write_c0_guest_intctl(cop0, 0xFC000000);
506
507         /* Put in vcpu id as CPUNum into Ebase Reg to handle SMP Guests */
508         kvm_write_c0_guest_ebase(cop0, KVM_GUEST_KSEG0 | (vcpu_id & 0xFF));
509
510         return 0;
511 }
512
513 static int kvm_trap_emul_get_one_reg(struct kvm_vcpu *vcpu,
514                                      const struct kvm_one_reg *reg,
515                                      s64 *v)
516 {
517         switch (reg->id) {
518         case KVM_REG_MIPS_CP0_COUNT:
519                 *v = kvm_mips_read_count(vcpu);
520                 break;
521         case KVM_REG_MIPS_COUNT_CTL:
522                 *v = vcpu->arch.count_ctl;
523                 break;
524         case KVM_REG_MIPS_COUNT_RESUME:
525                 *v = ktime_to_ns(vcpu->arch.count_resume);
526                 break;
527         case KVM_REG_MIPS_COUNT_HZ:
528                 *v = vcpu->arch.count_hz;
529                 break;
530         default:
531                 return -EINVAL;
532         }
533         return 0;
534 }
535
536 static int kvm_trap_emul_set_one_reg(struct kvm_vcpu *vcpu,
537                                      const struct kvm_one_reg *reg,
538                                      s64 v)
539 {
540         struct mips_coproc *cop0 = vcpu->arch.cop0;
541         int ret = 0;
542         unsigned int cur, change;
543
544         switch (reg->id) {
545         case KVM_REG_MIPS_CP0_COUNT:
546                 kvm_mips_write_count(vcpu, v);
547                 break;
548         case KVM_REG_MIPS_CP0_COMPARE:
549                 kvm_mips_write_compare(vcpu, v);
550                 break;
551         case KVM_REG_MIPS_CP0_CAUSE:
552                 /*
553                  * If the timer is stopped or started (DC bit) it must look
554                  * atomic with changes to the interrupt pending bits (TI, IRQ5).
555                  * A timer interrupt should not happen in between.
556                  */
557                 if ((kvm_read_c0_guest_cause(cop0) ^ v) & CAUSEF_DC) {
558                         if (v & CAUSEF_DC) {
559                                 /* disable timer first */
560                                 kvm_mips_count_disable_cause(vcpu);
561                                 kvm_change_c0_guest_cause(cop0, ~CAUSEF_DC, v);
562                         } else {
563                                 /* enable timer last */
564                                 kvm_change_c0_guest_cause(cop0, ~CAUSEF_DC, v);
565                                 kvm_mips_count_enable_cause(vcpu);
566                         }
567                 } else {
568                         kvm_write_c0_guest_cause(cop0, v);
569                 }
570                 break;
571         case KVM_REG_MIPS_CP0_CONFIG:
572                 /* read-only for now */
573                 break;
574         case KVM_REG_MIPS_CP0_CONFIG1:
575                 cur = kvm_read_c0_guest_config1(cop0);
576                 change = (cur ^ v) & kvm_mips_config1_wrmask(vcpu);
577                 if (change) {
578                         v = cur ^ change;
579                         kvm_write_c0_guest_config1(cop0, v);
580                 }
581                 break;
582         case KVM_REG_MIPS_CP0_CONFIG2:
583                 /* read-only for now */
584                 break;
585         case KVM_REG_MIPS_CP0_CONFIG3:
586                 cur = kvm_read_c0_guest_config3(cop0);
587                 change = (cur ^ v) & kvm_mips_config3_wrmask(vcpu);
588                 if (change) {
589                         v = cur ^ change;
590                         kvm_write_c0_guest_config3(cop0, v);
591                 }
592                 break;
593         case KVM_REG_MIPS_CP0_CONFIG4:
594                 cur = kvm_read_c0_guest_config4(cop0);
595                 change = (cur ^ v) & kvm_mips_config4_wrmask(vcpu);
596                 if (change) {
597                         v = cur ^ change;
598                         kvm_write_c0_guest_config4(cop0, v);
599                 }
600                 break;
601         case KVM_REG_MIPS_CP0_CONFIG5:
602                 cur = kvm_read_c0_guest_config5(cop0);
603                 change = (cur ^ v) & kvm_mips_config5_wrmask(vcpu);
604                 if (change) {
605                         v = cur ^ change;
606                         kvm_write_c0_guest_config5(cop0, v);
607                 }
608                 break;
609         case KVM_REG_MIPS_COUNT_CTL:
610                 ret = kvm_mips_set_count_ctl(vcpu, v);
611                 break;
612         case KVM_REG_MIPS_COUNT_RESUME:
613                 ret = kvm_mips_set_count_resume(vcpu, v);
614                 break;
615         case KVM_REG_MIPS_COUNT_HZ:
616                 ret = kvm_mips_set_count_hz(vcpu, v);
617                 break;
618         default:
619                 return -EINVAL;
620         }
621         return ret;
622 }
623
624 static int kvm_trap_emul_vcpu_get_regs(struct kvm_vcpu *vcpu)
625 {
626         kvm_lose_fpu(vcpu);
627
628         return 0;
629 }
630
631 static int kvm_trap_emul_vcpu_set_regs(struct kvm_vcpu *vcpu)
632 {
633         return 0;
634 }
635
636 static struct kvm_mips_callbacks kvm_trap_emul_callbacks = {
637         /* exit handlers */
638         .handle_cop_unusable = kvm_trap_emul_handle_cop_unusable,
639         .handle_tlb_mod = kvm_trap_emul_handle_tlb_mod,
640         .handle_tlb_st_miss = kvm_trap_emul_handle_tlb_st_miss,
641         .handle_tlb_ld_miss = kvm_trap_emul_handle_tlb_ld_miss,
642         .handle_addr_err_st = kvm_trap_emul_handle_addr_err_st,
643         .handle_addr_err_ld = kvm_trap_emul_handle_addr_err_ld,
644         .handle_syscall = kvm_trap_emul_handle_syscall,
645         .handle_res_inst = kvm_trap_emul_handle_res_inst,
646         .handle_break = kvm_trap_emul_handle_break,
647         .handle_trap = kvm_trap_emul_handle_trap,
648         .handle_msa_fpe = kvm_trap_emul_handle_msa_fpe,
649         .handle_fpe = kvm_trap_emul_handle_fpe,
650         .handle_msa_disabled = kvm_trap_emul_handle_msa_disabled,
651
652         .vm_init = kvm_trap_emul_vm_init,
653         .vcpu_init = kvm_trap_emul_vcpu_init,
654         .vcpu_setup = kvm_trap_emul_vcpu_setup,
655         .gva_to_gpa = kvm_trap_emul_gva_to_gpa_cb,
656         .queue_timer_int = kvm_mips_queue_timer_int_cb,
657         .dequeue_timer_int = kvm_mips_dequeue_timer_int_cb,
658         .queue_io_int = kvm_mips_queue_io_int_cb,
659         .dequeue_io_int = kvm_mips_dequeue_io_int_cb,
660         .irq_deliver = kvm_mips_irq_deliver_cb,
661         .irq_clear = kvm_mips_irq_clear_cb,
662         .get_one_reg = kvm_trap_emul_get_one_reg,
663         .set_one_reg = kvm_trap_emul_set_one_reg,
664         .vcpu_get_regs = kvm_trap_emul_vcpu_get_regs,
665         .vcpu_set_regs = kvm_trap_emul_vcpu_set_regs,
666 };
667
668 int kvm_mips_emulation_init(struct kvm_mips_callbacks **install_callbacks)
669 {
670         *install_callbacks = &kvm_trap_emul_callbacks;
671         return 0;
672 }