1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <linux/kvm_host.h>
15#include <linux/log2.h>
16#include <asm/mmu_context.h>
17#include <asm/msa.h>
18#include <asm/setup.h>
19#include <asm/tlbex.h>
20#include <asm/uasm.h>
21
22
23#define ZERO 0
24#define AT 1
25#define V0 2
26#define V1 3
27#define A0 4
28#define A1 5
29
30#if _MIPS_SIM == _MIPS_SIM_ABI32
31#define T0 8
32#define T1 9
33#define T2 10
34#define T3 11
35#endif
36
37#if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
38#define T0 12
39#define T1 13
40#define T2 14
41#define T3 15
42#endif
43
44#define S0 16
45#define S1 17
46#define T9 25
47#define K0 26
48#define K1 27
49#define GP 28
50#define SP 29
51#define RA 31
52
53
54#define C0_PWBASE 5, 5
55#define C0_HWRENA 7, 0
56#define C0_BADVADDR 8, 0
57#define C0_BADINSTR 8, 1
58#define C0_BADINSTRP 8, 2
59#define C0_ENTRYHI 10, 0
60#define C0_GUESTCTL1 10, 4
61#define C0_STATUS 12, 0
62#define C0_GUESTCTL0 12, 6
63#define C0_CAUSE 13, 0
64#define C0_EPC 14, 0
65#define C0_EBASE 15, 1
66#define C0_CONFIG5 16, 5
67#define C0_DDATA_LO 28, 3
68#define C0_ERROREPC 30, 0
69
70#define CALLFRAME_SIZ 32
71
72#ifdef CONFIG_64BIT
73#define ST0_KX_IF_64 ST0_KX
74#else
75#define ST0_KX_IF_64 0
76#endif
77
78static unsigned int scratch_vcpu[2] = { C0_DDATA_LO };
79static unsigned int scratch_tmp[2] = { C0_ERROREPC };
80
81enum label_id {
82 label_fpu_1 = 1,
83 label_msa_1,
84 label_return_to_host,
85 label_kernel_asid,
86 label_exit_common,
87};
88
89UASM_L_LA(_fpu_1)
90UASM_L_LA(_msa_1)
91UASM_L_LA(_return_to_host)
92UASM_L_LA(_kernel_asid)
93UASM_L_LA(_exit_common)
94
95static void *kvm_mips_build_enter_guest(void *addr);
96static void *kvm_mips_build_ret_from_exit(void *addr);
97static void *kvm_mips_build_ret_to_guest(void *addr);
98static void *kvm_mips_build_ret_to_host(void *addr);
99
100
101
102
103
104static int c0_kscratch(void)
105{
106 switch (boot_cpu_type()) {
107 case CPU_XLP:
108 case CPU_XLR:
109 return 22;
110 default:
111 return 31;
112 }
113}
114
115
116
117
118
119
120
121
122
123int kvm_mips_entry_setup(void)
124{
125
126
127
128
129 unsigned int kscratch_mask = cpu_data[0].kscratch_mask;
130
131 if (pgd_reg != -1)
132 kscratch_mask &= ~BIT(pgd_reg);
133
134
135 if (kscratch_mask) {
136 scratch_vcpu[0] = c0_kscratch();
137 scratch_vcpu[1] = ffs(kscratch_mask) - 1;
138 kscratch_mask &= ~BIT(scratch_vcpu[1]);
139 }
140
141
142 if (kscratch_mask) {
143 scratch_tmp[0] = c0_kscratch();
144 scratch_tmp[1] = ffs(kscratch_mask) - 1;
145 kscratch_mask &= ~BIT(scratch_tmp[1]);
146 }
147
148 return 0;
149}
150
151static void kvm_mips_build_save_scratch(u32 **p, unsigned int tmp,
152 unsigned int frame)
153{
154
155 UASM_i_MFC0(p, tmp, scratch_vcpu[0], scratch_vcpu[1]);
156 UASM_i_SW(p, tmp, offsetof(struct pt_regs, cp0_epc), frame);
157
158
159 if (scratch_tmp[0] == c0_kscratch()) {
160 UASM_i_MFC0(p, tmp, scratch_tmp[0], scratch_tmp[1]);
161 UASM_i_SW(p, tmp, offsetof(struct pt_regs, cp0_cause), frame);
162 }
163}
164
165static void kvm_mips_build_restore_scratch(u32 **p, unsigned int tmp,
166 unsigned int frame)
167{
168
169
170
171
172 UASM_i_LW(p, tmp, offsetof(struct pt_regs, cp0_epc), frame);
173 UASM_i_MTC0(p, tmp, scratch_vcpu[0], scratch_vcpu[1]);
174
175 if (scratch_tmp[0] == c0_kscratch()) {
176 UASM_i_LW(p, tmp, offsetof(struct pt_regs, cp0_cause), frame);
177 UASM_i_MTC0(p, tmp, scratch_tmp[0], scratch_tmp[1]);
178 }
179}
180
181
182
183
184
185
186
187
188
189static inline void build_set_exc_base(u32 **p, unsigned int reg)
190{
191 if (cpu_has_ebase_wg) {
192
193 uasm_i_ori(p, reg, reg, MIPS_EBASE_WG);
194 UASM_i_MTC0(p, reg, C0_EBASE);
195 } else {
196 uasm_i_mtc0(p, reg, C0_EBASE);
197 }
198}
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214void *kvm_mips_build_vcpu_run(void *addr)
215{
216 u32 *p = addr;
217 unsigned int i;
218
219
220
221
222
223
224
225 UASM_i_ADDIU(&p, K1, SP, -(int)sizeof(struct pt_regs));
226 for (i = 16; i < 32; ++i) {
227 if (i == 24)
228 i = 28;
229 UASM_i_SW(&p, i, offsetof(struct pt_regs, regs[i]), K1);
230 }
231
232
233 uasm_i_mfc0(&p, V0, C0_STATUS);
234 UASM_i_SW(&p, V0, offsetof(struct pt_regs, cp0_status), K1);
235
236
237 kvm_mips_build_save_scratch(&p, V1, K1);
238
239
240 UASM_i_MTC0(&p, A1, scratch_vcpu[0], scratch_vcpu[1]);
241
242
243 UASM_i_ADDIU(&p, K1, A1, offsetof(struct kvm_vcpu, arch));
244
245
246
247
248
249 UASM_i_SW(&p, SP, offsetof(struct kvm_vcpu_arch, host_stack), K1);
250
251
252 UASM_i_SW(&p, GP, offsetof(struct kvm_vcpu_arch, host_gp), K1);
253
254
255
256
257
258 UASM_i_LA(&p, K0, ST0_EXL | KSU_USER | ST0_BEV | ST0_KX_IF_64);
259 uasm_i_mtc0(&p, K0, C0_STATUS);
260 uasm_i_ehb(&p);
261
262
263 UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, guest_ebase), K1);
264 build_set_exc_base(&p, K0);
265
266
267
268
269
270
271 uasm_i_addiu(&p, K0, ZERO, ST0_EXL | KSU_USER | ST0_IE | ST0_KX_IF_64);
272 uasm_i_andi(&p, V0, V0, ST0_IM);
273 uasm_i_or(&p, K0, K0, V0);
274 uasm_i_mtc0(&p, K0, C0_STATUS);
275 uasm_i_ehb(&p);
276
277 p = kvm_mips_build_enter_guest(p);
278
279 return p;
280}
281
282
283
284
285
286
287
288
289
290
291
292static void *kvm_mips_build_enter_guest(void *addr)
293{
294 u32 *p = addr;
295 unsigned int i;
296 struct uasm_label labels[2];
297 struct uasm_reloc relocs[2];
298 struct uasm_label __maybe_unused *l = labels;
299 struct uasm_reloc __maybe_unused *r = relocs;
300
301 memset(labels, 0, sizeof(labels));
302 memset(relocs, 0, sizeof(relocs));
303
304
305 UASM_i_LW(&p, T0, offsetof(struct kvm_vcpu_arch, pc), K1);
306 UASM_i_MTC0(&p, T0, C0_EPC);
307
308#ifdef CONFIG_KVM_MIPS_VZ
309
310 UASM_i_MFC0(&p, K0, c0_kscratch(), pgd_reg);
311 UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu_arch, host_pgd), K1);
312
313
314
315
316
317
318
319
320
321 UASM_i_LW(&p, S0, (int)offsetof(struct kvm_vcpu, kvm) -
322 (int)offsetof(struct kvm_vcpu, arch), K1);
323 UASM_i_LW(&p, A0, offsetof(struct kvm, arch.gpa_mm.pgd), S0);
324 UASM_i_LA(&p, T9, (unsigned long)tlbmiss_handler_setup_pgd);
325 uasm_i_jalr(&p, RA, T9);
326
327 if (cpu_has_htw)
328 UASM_i_MTC0(&p, A0, C0_PWBASE);
329 else
330 uasm_i_nop(&p);
331
332
333 uasm_i_addiu(&p, V1, ZERO, 1);
334 uasm_i_mfc0(&p, K0, C0_GUESTCTL0);
335 uasm_i_ins(&p, K0, V1, MIPS_GCTL0_GM_SHIFT, 1);
336 uasm_i_mtc0(&p, K0, C0_GUESTCTL0);
337
338 if (cpu_has_guestid) {
339
340
341
342
343
344
345 uasm_i_mfc0(&p, T0, C0_GUESTCTL1);
346
347 uasm_i_ext(&p, T1, T0, MIPS_GCTL1_ID_SHIFT,
348 MIPS_GCTL1_ID_WIDTH);
349 uasm_i_ins(&p, T0, T1, MIPS_GCTL1_RID_SHIFT,
350 MIPS_GCTL1_RID_WIDTH);
351 uasm_i_mtc0(&p, T0, C0_GUESTCTL1);
352
353
354 goto skip_asid_restore;
355 }
356
357
358
359
360 UASM_i_MFC0(&p, K0, C0_ENTRYHI);
361 UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu_arch, host_entryhi),
362 K1);
363
364
365 UASM_i_ADDIU(&p, T1, S0,
366 offsetof(struct kvm, arch.gpa_mm.context.asid));
367#else
368
369 UASM_i_LW(&p, T0, offsetof(struct kvm_vcpu_arch, cop0), K1);
370 UASM_i_LW(&p, T0, offsetof(struct mips_coproc, reg[MIPS_CP0_STATUS][0]),
371 T0);
372 uasm_i_andi(&p, T0, T0, KSU_USER | ST0_ERL | ST0_EXL);
373 uasm_i_xori(&p, T0, T0, KSU_USER);
374 uasm_il_bnez(&p, &r, T0, label_kernel_asid);
375 UASM_i_ADDIU(&p, T1, K1, offsetof(struct kvm_vcpu_arch,
376 guest_kernel_mm.context.asid));
377
378 UASM_i_ADDIU(&p, T1, K1, offsetof(struct kvm_vcpu_arch,
379 guest_user_mm.context.asid));
380 uasm_l_kernel_asid(&l, p);
381#endif
382
383
384
385 uasm_i_lw(&p, T2, offsetof(struct thread_info, cpu), GP);
386
387 uasm_i_sll(&p, T2, T2, ilog2(sizeof(long)));
388 UASM_i_ADDU(&p, T3, T1, T2);
389 UASM_i_LW(&p, K0, 0, T3);
390#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE
391
392
393
394
395 uasm_i_addiu(&p, T3, ZERO, sizeof(struct cpuinfo_mips)/sizeof(long));
396 uasm_i_mul(&p, T2, T2, T3);
397
398 UASM_i_LA_mostly(&p, AT, (long)&cpu_data[0].asid_mask);
399 UASM_i_ADDU(&p, AT, AT, T2);
400 UASM_i_LW(&p, T2, uasm_rel_lo((long)&cpu_data[0].asid_mask), AT);
401 uasm_i_and(&p, K0, K0, T2);
402#else
403 uasm_i_andi(&p, K0, K0, MIPS_ENTRYHI_ASID);
404#endif
405
406#ifndef CONFIG_KVM_MIPS_VZ
407
408
409
410
411
412
413 UASM_i_LW(&p, A0, (int)offsetof(struct mm_struct, pgd) -
414 (int)offsetof(struct mm_struct, context.asid), T1);
415
416 UASM_i_LA(&p, T9, (unsigned long)tlbmiss_handler_setup_pgd);
417 uasm_i_jalr(&p, RA, T9);
418 uasm_i_mtc0(&p, K0, C0_ENTRYHI);
419#else
420
421 uasm_i_mtc0(&p, K0, C0_ENTRYHI);
422skip_asid_restore:
423#endif
424 uasm_i_ehb(&p);
425
426
427 uasm_i_mtc0(&p, ZERO, C0_HWRENA);
428
429
430 for (i = 1; i < 32; ++i) {
431
432 if (i == K0 || i == K1)
433 continue;
434 UASM_i_LW(&p, i, offsetof(struct kvm_vcpu_arch, gprs[i]), K1);
435 }
436
437#ifndef CONFIG_CPU_MIPSR6
438
439 UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, hi), K1);
440 uasm_i_mthi(&p, K0);
441
442 UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, lo), K1);
443 uasm_i_mtlo(&p, K0);
444#endif
445
446
447 UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, gprs[K0]), K1);
448 UASM_i_LW(&p, K1, offsetof(struct kvm_vcpu_arch, gprs[K1]), K1);
449
450
451 uasm_i_eret(&p);
452
453 uasm_resolve_relocs(relocs, labels);
454
455 return p;
456}
457
458
459
460
461
462
463
464
465
466
467void *kvm_mips_build_tlb_refill_exception(void *addr, void *handler)
468{
469 u32 *p = addr;
470 struct uasm_label labels[2];
471 struct uasm_reloc relocs[2];
472 struct uasm_label *l = labels;
473 struct uasm_reloc *r = relocs;
474
475 memset(labels, 0, sizeof(labels));
476 memset(relocs, 0, sizeof(relocs));
477
478
479 UASM_i_MTC0(&p, K1, scratch_tmp[0], scratch_tmp[1]);
480
481
482 UASM_i_MFC0(&p, K1, scratch_vcpu[0], scratch_vcpu[1]);
483
484
485 UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu, arch.gprs[K0]), K1);
486
487
488
489
490
491 preempt_disable();
492
493
494
495
496
497
498
499
500
501
502
503
504#ifdef CONFIG_64BIT
505 build_get_pmde64(&p, &l, &r, K0, K1);
506#else
507 build_get_pgde32(&p, K0, K1);
508#endif
509
510
511
512 build_get_ptep(&p, K0, K1);
513 build_update_entries(&p, K0, K1);
514 build_tlb_write_entry(&p, &l, &r, tlb_random);
515
516 preempt_enable();
517
518
519 UASM_i_MFC0(&p, K1, scratch_vcpu[0], scratch_vcpu[1]);
520
521
522 UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu, arch.gprs[K0]), K1);
523 uasm_i_ehb(&p);
524 UASM_i_MFC0(&p, K1, scratch_tmp[0], scratch_tmp[1]);
525
526
527 uasm_i_eret(&p);
528
529 return p;
530}
531
532
533
534
535
536
537
538
539
540
541
542void *kvm_mips_build_exception(void *addr, void *handler)
543{
544 u32 *p = addr;
545 struct uasm_label labels[2];
546 struct uasm_reloc relocs[2];
547 struct uasm_label *l = labels;
548 struct uasm_reloc *r = relocs;
549
550 memset(labels, 0, sizeof(labels));
551 memset(relocs, 0, sizeof(relocs));
552
553
554 UASM_i_MTC0(&p, K1, scratch_tmp[0], scratch_tmp[1]);
555
556
557 UASM_i_MFC0(&p, K1, scratch_vcpu[0], scratch_vcpu[1]);
558 UASM_i_ADDIU(&p, K1, K1, offsetof(struct kvm_vcpu, arch));
559
560
561 UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu_arch, gprs[K0]), K1);
562
563
564 uasm_il_b(&p, &r, label_exit_common);
565 uasm_i_nop(&p);
566
567 uasm_l_exit_common(&l, handler);
568 uasm_resolve_relocs(relocs, labels);
569
570 return p;
571}
572
573
574
575
576
577
578
579
580
581
582
583
584void *kvm_mips_build_exit(void *addr)
585{
586 u32 *p = addr;
587 unsigned int i;
588 struct uasm_label labels[3];
589 struct uasm_reloc relocs[3];
590 struct uasm_label *l = labels;
591 struct uasm_reloc *r = relocs;
592
593 memset(labels, 0, sizeof(labels));
594 memset(relocs, 0, sizeof(relocs));
595
596
597
598
599
600
601
602
603
604
605
606
607 for (i = 0; i < 32; ++i) {
608
609 if (i == K0 || i == K1)
610 continue;
611 UASM_i_SW(&p, i, offsetof(struct kvm_vcpu_arch, gprs[i]), K1);
612 }
613
614#ifndef CONFIG_CPU_MIPSR6
615
616 uasm_i_mfhi(&p, T0);
617 UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, hi), K1);
618
619 uasm_i_mflo(&p, T0);
620 UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, lo), K1);
621#endif
622
623
624 uasm_i_ehb(&p);
625 UASM_i_MFC0(&p, T0, scratch_tmp[0], scratch_tmp[1]);
626 UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, gprs[K1]), K1);
627
628
629
630
631 UASM_i_MFC0(&p, S1, scratch_vcpu[0], scratch_vcpu[1]);
632
633
634 UASM_i_LW(&p, S0, offsetof(struct kvm_vcpu, run), S1);
635
636
637
638
639
640 UASM_i_MFC0(&p, K0, C0_EPC);
641 UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu_arch, pc), K1);
642
643 UASM_i_MFC0(&p, K0, C0_BADVADDR);
644 UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu_arch, host_cp0_badvaddr),
645 K1);
646
647 uasm_i_mfc0(&p, K0, C0_CAUSE);
648 uasm_i_sw(&p, K0, offsetof(struct kvm_vcpu_arch, host_cp0_cause), K1);
649
650 if (cpu_has_badinstr) {
651 uasm_i_mfc0(&p, K0, C0_BADINSTR);
652 uasm_i_sw(&p, K0, offsetof(struct kvm_vcpu_arch,
653 host_cp0_badinstr), K1);
654 }
655
656 if (cpu_has_badinstrp) {
657 uasm_i_mfc0(&p, K0, C0_BADINSTRP);
658 uasm_i_sw(&p, K0, offsetof(struct kvm_vcpu_arch,
659 host_cp0_badinstrp), K1);
660 }
661
662
663
664
665
666 uasm_i_mfc0(&p, V0, C0_STATUS);
667
668 uasm_i_lui(&p, AT, ST0_BEV >> 16);
669 uasm_i_or(&p, K0, V0, AT);
670
671 uasm_i_mtc0(&p, K0, C0_STATUS);
672 uasm_i_ehb(&p);
673
674 UASM_i_LA_mostly(&p, K0, (long)&ebase);
675 UASM_i_LW(&p, K0, uasm_rel_lo((long)&ebase), K0);
676 build_set_exc_base(&p, K0);
677
678 if (raw_cpu_has_fpu) {
679
680
681
682
683 uasm_i_lui(&p, AT, ST0_CU1 >> 16);
684 uasm_i_and(&p, V1, V0, AT);
685 uasm_il_beqz(&p, &r, V1, label_fpu_1);
686 uasm_i_nop(&p);
687 uasm_i_cfc1(&p, T0, 31);
688 uasm_i_sw(&p, T0, offsetof(struct kvm_vcpu_arch, fpu.fcr31),
689 K1);
690 uasm_i_ctc1(&p, ZERO, 31);
691 uasm_l_fpu_1(&l, p);
692 }
693
694 if (cpu_has_msa) {
695
696
697
698
699 uasm_i_mfc0(&p, T0, C0_CONFIG5);
700 uasm_i_ext(&p, T0, T0, 27, 1);
701 uasm_il_beqz(&p, &r, T0, label_msa_1);
702 uasm_i_nop(&p);
703 uasm_i_cfcmsa(&p, T0, MSA_CSR);
704 uasm_i_sw(&p, T0, offsetof(struct kvm_vcpu_arch, fpu.msacsr),
705 K1);
706 uasm_i_ctcmsa(&p, MSA_CSR, ZERO);
707 uasm_l_msa_1(&l, p);
708 }
709
710#ifdef CONFIG_KVM_MIPS_VZ
711
712 if (!cpu_has_guestid) {
713 UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, host_entryhi),
714 K1);
715 UASM_i_MTC0(&p, K0, C0_ENTRYHI);
716 }
717
718
719
720
721
722
723
724 UASM_i_LW(&p, A0,
725 offsetof(struct kvm_vcpu_arch, host_pgd), K1);
726 UASM_i_LA(&p, T9, (unsigned long)tlbmiss_handler_setup_pgd);
727 uasm_i_jalr(&p, RA, T9);
728
729 if (cpu_has_htw)
730 UASM_i_MTC0(&p, A0, C0_PWBASE);
731 else
732 uasm_i_nop(&p);
733
734
735 uasm_i_mfc0(&p, K0, C0_GUESTCTL0);
736 uasm_i_ins(&p, K0, ZERO, MIPS_GCTL0_GM_SHIFT, 1);
737 uasm_i_mtc0(&p, K0, C0_GUESTCTL0);
738
739
740 uasm_i_sw(&p, K0,
741 offsetof(struct kvm_vcpu_arch, host_cp0_guestctl0), K1);
742
743 if (cpu_has_guestid) {
744
745
746
747
748 uasm_i_mfc0(&p, T0, C0_GUESTCTL1);
749
750 uasm_i_ins(&p, T0, ZERO, MIPS_GCTL1_RID_SHIFT,
751 MIPS_GCTL1_RID_WIDTH);
752 uasm_i_mtc0(&p, T0, C0_GUESTCTL1);
753 }
754#endif
755
756
757 uasm_i_addiu(&p, AT, ZERO, ~(ST0_EXL | KSU_USER | ST0_IE));
758 uasm_i_and(&p, V0, V0, AT);
759 uasm_i_lui(&p, AT, ST0_CU0 >> 16);
760 uasm_i_or(&p, V0, V0, AT);
761#ifdef CONFIG_64BIT
762 uasm_i_ori(&p, V0, V0, ST0_SX | ST0_UX);
763#endif
764 uasm_i_mtc0(&p, V0, C0_STATUS);
765 uasm_i_ehb(&p);
766
767
768 UASM_i_LW(&p, GP, offsetof(struct kvm_vcpu_arch, host_gp), K1);
769
770
771 UASM_i_LW(&p, SP, offsetof(struct kvm_vcpu_arch, host_stack), K1);
772
773
774 UASM_i_ADDIU(&p, SP, SP, -(int)sizeof(struct pt_regs));
775
776
777
778
779
780
781
782 kvm_mips_build_restore_scratch(&p, K0, SP);
783
784
785 UASM_i_LA_mostly(&p, K0, (long)&hwrena);
786 uasm_i_lw(&p, K0, uasm_rel_lo((long)&hwrena), K0);
787 uasm_i_mtc0(&p, K0, C0_HWRENA);
788
789
790
791
792
793
794
795 uasm_i_move(&p, A0, S0);
796 uasm_i_move(&p, A1, S1);
797 UASM_i_LA(&p, T9, (unsigned long)kvm_mips_handle_exit);
798 uasm_i_jalr(&p, RA, T9);
799 UASM_i_ADDIU(&p, SP, SP, -CALLFRAME_SIZ);
800
801 uasm_resolve_relocs(relocs, labels);
802
803 p = kvm_mips_build_ret_from_exit(p);
804
805 return p;
806}
807
808
809
810
811
812
813
814
815
816
817static void *kvm_mips_build_ret_from_exit(void *addr)
818{
819 u32 *p = addr;
820 struct uasm_label labels[2];
821 struct uasm_reloc relocs[2];
822 struct uasm_label *l = labels;
823 struct uasm_reloc *r = relocs;
824
825 memset(labels, 0, sizeof(labels));
826 memset(relocs, 0, sizeof(relocs));
827
828
829 uasm_i_di(&p, ZERO);
830 uasm_i_ehb(&p);
831
832
833
834
835
836
837
838 uasm_i_move(&p, K1, S1);
839 UASM_i_ADDIU(&p, K1, K1, offsetof(struct kvm_vcpu, arch));
840
841
842
843
844
845 uasm_i_andi(&p, T0, V0, RESUME_HOST);
846 uasm_il_bnez(&p, &r, T0, label_return_to_host);
847 uasm_i_nop(&p);
848
849 p = kvm_mips_build_ret_to_guest(p);
850
851 uasm_l_return_to_host(&l, p);
852 p = kvm_mips_build_ret_to_host(p);
853
854 uasm_resolve_relocs(relocs, labels);
855
856 return p;
857}
858
859
860
861
862
863
864
865
866
867
868static void *kvm_mips_build_ret_to_guest(void *addr)
869{
870 u32 *p = addr;
871
872
873 UASM_i_MTC0(&p, S1, scratch_vcpu[0], scratch_vcpu[1]);
874
875
876 UASM_i_LW(&p, T0, offsetof(struct kvm_vcpu_arch, guest_ebase), K1);
877
878
879 uasm_i_mfc0(&p, V1, C0_STATUS);
880 uasm_i_lui(&p, AT, ST0_BEV >> 16);
881 uasm_i_or(&p, K0, V1, AT);
882 uasm_i_mtc0(&p, K0, C0_STATUS);
883 uasm_i_ehb(&p);
884 build_set_exc_base(&p, T0);
885
886
887 uasm_i_ori(&p, V1, V1, ST0_EXL | KSU_USER | ST0_IE);
888 UASM_i_LA(&p, AT, ~(ST0_CU0 | ST0_MX | ST0_SX | ST0_UX));
889 uasm_i_and(&p, V1, V1, AT);
890 uasm_i_mtc0(&p, V1, C0_STATUS);
891 uasm_i_ehb(&p);
892
893 p = kvm_mips_build_enter_guest(p);
894
895 return p;
896}
897
898
899
900
901
902
903
904
905
906
907
908static void *kvm_mips_build_ret_to_host(void *addr)
909{
910 u32 *p = addr;
911 unsigned int i;
912
913
914 UASM_i_LW(&p, K1, offsetof(struct kvm_vcpu_arch, host_stack), K1);
915 UASM_i_ADDIU(&p, K1, K1, -(int)sizeof(struct pt_regs));
916
917
918
919
920
921 uasm_i_sra(&p, K0, V0, 2);
922 uasm_i_move(&p, V0, K0);
923
924
925 for (i = 16; i < 31; ++i) {
926 if (i == 24)
927 i = 28;
928 UASM_i_LW(&p, i, offsetof(struct pt_regs, regs[i]), K1);
929 }
930
931
932 UASM_i_LA_mostly(&p, K0, (long)&hwrena);
933 uasm_i_lw(&p, K0, uasm_rel_lo((long)&hwrena), K0);
934 uasm_i_mtc0(&p, K0, C0_HWRENA);
935
936
937 UASM_i_LW(&p, RA, offsetof(struct pt_regs, regs[RA]), K1);
938 uasm_i_jr(&p, RA);
939 uasm_i_nop(&p);
940
941 return p;
942}
943
944