Newer
Older
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* KVM/MIPS: Support for hardware virtualization extensions
*
* Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
* Authors: Yann Le Du <ledu@kymasys.com>
*/
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/preempt.h>
#include <linux/vmalloc.h>
#include <asm/cacheflush.h>
#include <asm/cacheops.h>
#include <asm/cmpxchg.h>
#include <asm/fpu.h>
#include <asm/hazards.h>
#include <asm/inst.h>
#include <asm/mmu_context.h>
#include <asm/r4kcache.h>
#include <asm/time.h>
#include <asm/tlb.h>
#include <asm/tlbex.h>
#include <linux/kvm_host.h>
#include "interrupt.h"
#ifdef CONFIG_CPU_LOONGSON64
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include "trace.h"
/* Pointers to last VCPU loaded on each physical CPU */
static struct kvm_vcpu *last_vcpu[NR_CPUS];
/* Pointers to last VCPU executed on each physical CPU */
static struct kvm_vcpu *last_exec_vcpu[NR_CPUS];
/*
* Number of guest VTLB entries to use, so we can catch inconsistency between
* CPUs.
*/
static unsigned int kvm_vz_guest_vtlb_size;
static inline long kvm_vz_read_gc0_ebase(void)
{
if (sizeof(long) == 8 && cpu_has_ebase_wg)
return read_gc0_ebase_64();
else
return read_gc0_ebase();
}
static inline void kvm_vz_write_gc0_ebase(long v)
{
/*
* First write with WG=1 to write upper bits, then write again in case
* WG should be left at 0.
* write_gc0_ebase_64() is no longer UNDEFINED since R6.
*/
if (sizeof(long) == 8 &&
(cpu_has_mips64r6 || cpu_has_ebase_wg)) {
write_gc0_ebase_64(v | MIPS_EBASE_WG);
write_gc0_ebase_64(v);
} else {
write_gc0_ebase(v | MIPS_EBASE_WG);
write_gc0_ebase(v);
}
}
/*
* These Config bits may be writable by the guest:
* Config: [K23, KU] (!TLB), K0
* Config1: (none)
* Config2: [TU, SU] (impl)
* Config3: ISAOnExc
* Config4: FTLBPageSize
* Config5: K, CV, MSAEn, UFE, FRE, SBRI, UFR
*/
static inline unsigned int kvm_vz_config_guest_wrmask(struct kvm_vcpu *vcpu)
{
return CONF_CM_CMASK;
}
static inline unsigned int kvm_vz_config1_guest_wrmask(struct kvm_vcpu *vcpu)
{
return 0;
}
static inline unsigned int kvm_vz_config2_guest_wrmask(struct kvm_vcpu *vcpu)
{
return 0;
}
static inline unsigned int kvm_vz_config3_guest_wrmask(struct kvm_vcpu *vcpu)
{
return MIPS_CONF3_ISA_OE;
}
static inline unsigned int kvm_vz_config4_guest_wrmask(struct kvm_vcpu *vcpu)
{
/* no need to be exact */
return MIPS_CONF4_VFTLBPAGESIZE;
}
static inline unsigned int kvm_vz_config5_guest_wrmask(struct kvm_vcpu *vcpu)
{
unsigned int mask = MIPS_CONF5_K | MIPS_CONF5_CV | MIPS_CONF5_SBRI;
/* Permit MSAEn changes if MSA supported and enabled */
if (kvm_mips_guest_has_msa(&vcpu->arch))
mask |= MIPS_CONF5_MSAEN;
/*
* Permit guest FPU mode changes if FPU is enabled and the relevant
* feature exists according to FIR register.
*/
if (kvm_mips_guest_has_fpu(&vcpu->arch)) {
if (cpu_has_ufr)
mask |= MIPS_CONF5_UFR;
if (cpu_has_fre)
mask |= MIPS_CONF5_FRE | MIPS_CONF5_UFE;
}
return mask;
}
static inline unsigned int kvm_vz_config6_guest_wrmask(struct kvm_vcpu *vcpu)
{
return MIPS_CONF6_LOONGSON_INTIMER | MIPS_CONF6_LOONGSON_EXTIMER;
}
/*
* VZ optionally allows these additional Config bits to be written by root:
* Config: M, [MT]
* Config1: M, [MMUSize-1, C2, MD, PC, WR, CA], FP
* Config2: M
* Config3: M, MSAP, [BPG], ULRI, [DSP2P, DSPP], CTXTC, [ITL, LPA, VEIC,
* VInt, SP, CDMM, MT, SM, TL]
* Config4: M, [VTLBSizeExt, MMUSizeExt]
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
*/
static inline unsigned int kvm_vz_config_user_wrmask(struct kvm_vcpu *vcpu)
{
return kvm_vz_config_guest_wrmask(vcpu) | MIPS_CONF_M;
}
static inline unsigned int kvm_vz_config1_user_wrmask(struct kvm_vcpu *vcpu)
{
unsigned int mask = kvm_vz_config1_guest_wrmask(vcpu) | MIPS_CONF_M;
/* Permit FPU to be present if FPU is supported */
if (kvm_mips_guest_can_have_fpu(&vcpu->arch))
mask |= MIPS_CONF1_FP;
return mask;
}
static inline unsigned int kvm_vz_config2_user_wrmask(struct kvm_vcpu *vcpu)
{
return kvm_vz_config2_guest_wrmask(vcpu) | MIPS_CONF_M;
}
static inline unsigned int kvm_vz_config3_user_wrmask(struct kvm_vcpu *vcpu)
{
unsigned int mask = kvm_vz_config3_guest_wrmask(vcpu) | MIPS_CONF_M |
MIPS_CONF3_ULRI | MIPS_CONF3_CTXTC;
/* Permit MSA to be present if MSA is supported */
if (kvm_mips_guest_can_have_msa(&vcpu->arch))
mask |= MIPS_CONF3_MSA;
return mask;
}
static inline unsigned int kvm_vz_config4_user_wrmask(struct kvm_vcpu *vcpu)
{
return kvm_vz_config4_guest_wrmask(vcpu) | MIPS_CONF_M;
}
static inline unsigned int kvm_vz_config5_user_wrmask(struct kvm_vcpu *vcpu)
{
return kvm_vz_config5_guest_wrmask(vcpu) | MIPS_CONF5_MRP;
static inline unsigned int kvm_vz_config6_user_wrmask(struct kvm_vcpu *vcpu)
{
return kvm_vz_config6_guest_wrmask(vcpu) |
MIPS_CONF6_LOONGSON_SFBEN | MIPS_CONF6_LOONGSON_FTLBDIS;
}
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
static gpa_t kvm_vz_gva_to_gpa_cb(gva_t gva)
{
/* VZ guest has already converted gva to gpa */
return gva;
}
static void kvm_vz_queue_irq(struct kvm_vcpu *vcpu, unsigned int priority)
{
set_bit(priority, &vcpu->arch.pending_exceptions);
clear_bit(priority, &vcpu->arch.pending_exceptions_clr);
}
static void kvm_vz_dequeue_irq(struct kvm_vcpu *vcpu, unsigned int priority)
{
clear_bit(priority, &vcpu->arch.pending_exceptions);
set_bit(priority, &vcpu->arch.pending_exceptions_clr);
}
static void kvm_vz_queue_timer_int_cb(struct kvm_vcpu *vcpu)
{
/*
* timer expiry is asynchronous to vcpu execution therefore defer guest
* cp0 accesses
*/
kvm_vz_queue_irq(vcpu, MIPS_EXC_INT_TIMER);
}
static void kvm_vz_dequeue_timer_int_cb(struct kvm_vcpu *vcpu)
{
/*
* timer expiry is asynchronous to vcpu execution therefore defer guest
* cp0 accesses
*/
kvm_vz_dequeue_irq(vcpu, MIPS_EXC_INT_TIMER);
}
static void kvm_vz_queue_io_int_cb(struct kvm_vcpu *vcpu,
struct kvm_mips_interrupt *irq)
{
int intr = (int)irq->irq;
/*
* interrupts are asynchronous to vcpu execution therefore defer guest
* cp0 accesses
*/
kvm_vz_queue_irq(vcpu, kvm_irq_to_priority(intr));
}
static void kvm_vz_dequeue_io_int_cb(struct kvm_vcpu *vcpu,
struct kvm_mips_interrupt *irq)
{
int intr = (int)irq->irq;
/*
* interrupts are asynchronous to vcpu execution therefore defer guest
* cp0 accesses
*/
kvm_vz_dequeue_irq(vcpu, kvm_irq_to_priority(-intr));
}
static int kvm_vz_irq_deliver_cb(struct kvm_vcpu *vcpu, unsigned int priority,
u32 cause)
{
u32 irq = (priority < MIPS_EXC_MAX) ?
kvm_priority_to_irq[priority] : 0;
switch (priority) {
case MIPS_EXC_INT_TIMER:
set_gc0_cause(C_TI);
break;
case MIPS_EXC_INT_IO_1:
case MIPS_EXC_INT_IO_2:
case MIPS_EXC_INT_IPI_1:
case MIPS_EXC_INT_IPI_2:
if (cpu_has_guestctl2)
set_c0_guestctl2(irq);
else
set_gc0_cause(irq);
break;
default:
break;
}
clear_bit(priority, &vcpu->arch.pending_exceptions);
return 1;
}
static int kvm_vz_irq_clear_cb(struct kvm_vcpu *vcpu, unsigned int priority,
u32 cause)
{
u32 irq = (priority < MIPS_EXC_MAX) ?
kvm_priority_to_irq[priority] : 0;
switch (priority) {
case MIPS_EXC_INT_TIMER:
/*
* Call to kvm_write_c0_guest_compare() clears Cause.TI in
* kvm_mips_emulate_CP0(). Explicitly clear irq associated with
* Cause.IP[IPTI] if GuestCtl2 virtual interrupt register not
* supported or if not using GuestCtl2 Hardware Clear.
*/
if (cpu_has_guestctl2) {
if (!(read_c0_guestctl2() & (irq << 14)))
clear_c0_guestctl2(irq);
} else {
clear_gc0_cause(irq);
}
break;
case MIPS_EXC_INT_IO_1:
case MIPS_EXC_INT_IO_2:
case MIPS_EXC_INT_IPI_1:
case MIPS_EXC_INT_IPI_2:
/* Clear GuestCtl2.VIP irq if not using Hardware Clear */
if (cpu_has_guestctl2) {
if (!(read_c0_guestctl2() & (irq << 14)))
clear_c0_guestctl2(irq);
} else {
clear_gc0_cause(irq);
}
break;
default:
break;
}
clear_bit(priority, &vcpu->arch.pending_exceptions_clr);
return 1;
}
/*
* VZ guest timer handling.
*/
/**
* kvm_vz_should_use_htimer() - Find whether to use the VZ hard guest timer.
* @vcpu: Virtual CPU.
*
* Returns: true if the VZ GTOffset & real guest CP0_Count should be used
* instead of software emulation of guest timer.
* false otherwise.
*/
static bool kvm_vz_should_use_htimer(struct kvm_vcpu *vcpu)
{
if (kvm_mips_count_disabled(vcpu))
return false;
/* Chosen frequency must match real frequency */
if (mips_hpt_frequency != vcpu->arch.count_hz)
return false;
/* We don't support a CP0_GTOffset with fewer bits than CP0_Count */
if (current_cpu_data.gtoffset_mask != 0xffffffff)
return false;
return true;
}
/**
* _kvm_vz_restore_stimer() - Restore soft timer state.
* @vcpu: Virtual CPU.
* @compare: CP0_Compare register value, restored by caller.
* @cause: CP0_Cause register to restore.
*
* Restore VZ state relating to the soft timer. The hard timer can be enabled
* later.
*/
static void _kvm_vz_restore_stimer(struct kvm_vcpu *vcpu, u32 compare,
u32 cause)
{
/*
* Avoid spurious counter interrupts by setting Guest CP0_Count to just
* after Guest CP0_Compare.
*/
write_c0_gtoffset(compare - read_c0_count());
back_to_back_c0_hazard();
write_gc0_cause(cause);
}
/**
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
* _kvm_vz_restore_htimer() - Restore hard timer state.
* @vcpu: Virtual CPU.
* @compare: CP0_Compare register value, restored by caller.
* @cause: CP0_Cause register to restore.
*
* Restore hard timer Guest.Count & Guest.Cause taking care to preserve the
* value of Guest.CP0_Cause.TI while restoring Guest.CP0_Cause.
*/
static void _kvm_vz_restore_htimer(struct kvm_vcpu *vcpu,
u32 compare, u32 cause)
{
u32 start_count, after_count;
ktime_t freeze_time;
unsigned long flags;
/*
* Freeze the soft-timer and sync the guest CP0_Count with it. We do
* this with interrupts disabled to avoid latency.
*/
local_irq_save(flags);
freeze_time = kvm_mips_freeze_hrtimer(vcpu, &start_count);
write_c0_gtoffset(start_count - read_c0_count());
local_irq_restore(flags);
/* restore guest CP0_Cause, as TI may already be set */
back_to_back_c0_hazard();
write_gc0_cause(cause);
/*
* The above sequence isn't atomic and would result in lost timer
* interrupts if we're not careful. Detect if a timer interrupt is due
* and assert it.
*/
back_to_back_c0_hazard();
after_count = read_gc0_count();
if (after_count - start_count > compare - start_count - 1)
kvm_vz_queue_irq(vcpu, MIPS_EXC_INT_TIMER);
}
/**
* kvm_vz_restore_timer() - Restore timer state.
* @vcpu: Virtual CPU.
*
* Restore soft timer state from saved context.
*/
static void kvm_vz_restore_timer(struct kvm_vcpu *vcpu)
{
struct mips_coproc *cop0 = vcpu->arch.cop0;
u32 cause, compare;
compare = kvm_read_sw_gc0_compare(cop0);
cause = kvm_read_sw_gc0_cause(cop0);
write_gc0_compare(compare);
_kvm_vz_restore_stimer(vcpu, compare, cause);
}
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
/**
* kvm_vz_acquire_htimer() - Switch to hard timer state.
* @vcpu: Virtual CPU.
*
* Restore hard timer state on top of existing soft timer state if possible.
*
* Since hard timer won't remain active over preemption, preemption should be
* disabled by the caller.
*/
void kvm_vz_acquire_htimer(struct kvm_vcpu *vcpu)
{
u32 gctl0;
gctl0 = read_c0_guestctl0();
if (!(gctl0 & MIPS_GCTL0_GT) && kvm_vz_should_use_htimer(vcpu)) {
/* enable guest access to hard timer */
write_c0_guestctl0(gctl0 | MIPS_GCTL0_GT);
_kvm_vz_restore_htimer(vcpu, read_gc0_compare(),
read_gc0_cause());
}
}
/**
* _kvm_vz_save_htimer() - Switch to software emulation of guest timer.
* @vcpu: Virtual CPU.
* @compare: Pointer to write compare value to.
* @cause: Pointer to write cause value to.
*
* Save VZ guest timer state and switch to software emulation of guest CP0
* timer. The hard timer must already be in use, so preemption should be
* disabled.
*/
static void _kvm_vz_save_htimer(struct kvm_vcpu *vcpu,
u32 *out_compare, u32 *out_cause)
{
u32 cause, compare, before_count, end_count;
ktime_t before_time;
compare = read_gc0_compare();
*out_compare = compare;
before_time = ktime_get();
/*
* Record the CP0_Count *prior* to saving CP0_Cause, so we have a time
* at which no pending timer interrupt is missing.
*/
before_count = read_gc0_count();
back_to_back_c0_hazard();
cause = read_gc0_cause();
*out_cause = cause;
/*
* Record a final CP0_Count which we will transfer to the soft-timer.
* This is recorded *after* saving CP0_Cause, so we don't get any timer
* interrupts from just after the final CP0_Count point.
*/
back_to_back_c0_hazard();
end_count = read_gc0_count();
/*
* The above sequence isn't atomic, so we could miss a timer interrupt
* between reading CP0_Cause and end_count. Detect and record any timer
* interrupt due between before_count and end_count.
*/
if (end_count - before_count > compare - before_count - 1)
kvm_vz_queue_irq(vcpu, MIPS_EXC_INT_TIMER);
/*
* Restore soft-timer, ignoring a small amount of negative drift due to
* delay between freeze_hrtimer and setting CP0_GTOffset.
*/
kvm_mips_restore_hrtimer(vcpu, before_time, end_count, -0x10000);
}
/**
* kvm_vz_save_timer() - Save guest timer state.
* @vcpu: Virtual CPU.
*
* Save VZ guest timer state and switch to soft guest timer if hard timer was in
* use.
*/
static void kvm_vz_save_timer(struct kvm_vcpu *vcpu)
{
struct mips_coproc *cop0 = vcpu->arch.cop0;
gctl0 = read_c0_guestctl0();
if (gctl0 & MIPS_GCTL0_GT) {
/* disable guest use of hard timer */
write_c0_guestctl0(gctl0 & ~MIPS_GCTL0_GT);
/* save hard timer state */
_kvm_vz_save_htimer(vcpu, &compare, &cause);
} else {
compare = read_gc0_compare();
cause = read_gc0_cause();
}
/* save timer-related state to VCPU context */
kvm_write_sw_gc0_cause(cop0, cause);
kvm_write_sw_gc0_compare(cop0, compare);
}
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
/**
* kvm_vz_lose_htimer() - Ensure hard guest timer is not in use.
* @vcpu: Virtual CPU.
*
* Transfers the state of the hard guest timer to the soft guest timer, leaving
* guest state intact so it can continue to be used with the soft timer.
*/
void kvm_vz_lose_htimer(struct kvm_vcpu *vcpu)
{
u32 gctl0, compare, cause;
preempt_disable();
gctl0 = read_c0_guestctl0();
if (gctl0 & MIPS_GCTL0_GT) {
/* disable guest use of timer */
write_c0_guestctl0(gctl0 & ~MIPS_GCTL0_GT);
/* switch to soft timer */
_kvm_vz_save_htimer(vcpu, &compare, &cause);
/* leave soft timer in usable state */
_kvm_vz_restore_stimer(vcpu, compare, cause);
}
preempt_enable();
}
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
/**
* is_eva_access() - Find whether an instruction is an EVA memory accessor.
* @inst: 32-bit instruction encoding.
*
* Finds whether @inst encodes an EVA memory access instruction, which would
* indicate that emulation of it should access the user mode address space
* instead of the kernel mode address space. This matters for MUSUK segments
* which are TLB mapped for user mode but unmapped for kernel mode.
*
* Returns: Whether @inst encodes an EVA accessor instruction.
*/
static bool is_eva_access(union mips_instruction inst)
{
if (inst.spec3_format.opcode != spec3_op)
return false;
switch (inst.spec3_format.func) {
case lwle_op:
case lwre_op:
case cachee_op:
case sbe_op:
case she_op:
case sce_op:
case swe_op:
case swle_op:
case swre_op:
case prefe_op:
case lbue_op:
case lhue_op:
case lbe_op:
case lhe_op:
case lle_op:
case lwe_op:
return true;
default:
return false;
}
}
/**
* is_eva_am_mapped() - Find whether an access mode is mapped.
* @vcpu: KVM VCPU state.
* @am: 3-bit encoded access mode.
* @eu: Segment becomes unmapped and uncached when Status.ERL=1.
*
* Decode @am to find whether it encodes a mapped segment for the current VCPU
* state. Where necessary @eu and the actual instruction causing the fault are
* taken into account to make the decision.
*
* Returns: Whether the VCPU faulted on a TLB mapped address.
*/
static bool is_eva_am_mapped(struct kvm_vcpu *vcpu, unsigned int am, bool eu)
{
u32 am_lookup;
int err;
/*
* Interpret access control mode. We assume address errors will already
* have been caught by the guest, leaving us with:
* AM UM SM KM 31..24 23..16
* UK 0 000 Unm 0 0
* MK 1 001 TLB 1
* MSK 2 010 TLB TLB 1
* MUSK 3 011 TLB TLB TLB 1
* MUSUK 4 100 TLB TLB Unm 0 1
* USK 5 101 Unm Unm 0 0
* - 6 110 0 0
* UUSK 7 111 Unm Unm Unm 0 0
*
* We shift a magic value by AM across the sign bit to find if always
* TLB mapped, and if not shift by 8 again to find if it depends on KM.
*/
am_lookup = 0x70080000 << am;
if ((s32)am_lookup < 0) {
/*
* MK, MSK, MUSK
* Always TLB mapped, unless SegCtl.EU && ERL
*/
if (!eu || !(read_gc0_status() & ST0_ERL))
return true;
} else {
am_lookup <<= 8;
if ((s32)am_lookup < 0) {
union mips_instruction inst;
unsigned int status;
u32 *opc;
/*
* MUSUK
* TLB mapped if not in kernel mode
*/
status = read_gc0_status();
if (!(status & (ST0_EXL | ST0_ERL)) &&
(status & ST0_KSU))
return true;
/*
* EVA access instructions in kernel
* mode access user address space.
*/
opc = (u32 *)vcpu->arch.pc;
if (vcpu->arch.host_cp0_cause & CAUSEF_BD)
opc += 1;
err = kvm_get_badinstr(opc, vcpu, &inst.word);
if (!err && is_eva_access(inst))
return true;
}
}
return false;
}
/**
* kvm_vz_gva_to_gpa() - Convert valid GVA to GPA.
* @vcpu: KVM VCPU state.
* @gva: Guest virtual address to convert.
* @gpa: Output guest physical address.
*
* Convert a guest virtual address (GVA) which is valid according to the guest
* context, to a guest physical address (GPA).
*
* Returns: 0 on success.
* -errno on failure.
*/
static int kvm_vz_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva,
unsigned long *gpa)
{
u32 gva32 = gva;
if ((long)gva == (s32)gva32) {
/* Handle canonical 32-bit virtual address */
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
if (cpu_guest_has_segments) {
unsigned long mask, pa;
switch (gva32 >> 29) {
case 0:
case 1: /* CFG5 (1GB) */
segctl = read_gc0_segctl2() >> 16;
mask = (unsigned long)0xfc0000000ull;
break;
case 2:
case 3: /* CFG4 (1GB) */
segctl = read_gc0_segctl2();
mask = (unsigned long)0xfc0000000ull;
break;
case 4: /* CFG3 (512MB) */
segctl = read_gc0_segctl1() >> 16;
mask = (unsigned long)0xfe0000000ull;
break;
case 5: /* CFG2 (512MB) */
segctl = read_gc0_segctl1();
mask = (unsigned long)0xfe0000000ull;
break;
case 6: /* CFG1 (512MB) */
segctl = read_gc0_segctl0() >> 16;
mask = (unsigned long)0xfe0000000ull;
break;
case 7: /* CFG0 (512MB) */
segctl = read_gc0_segctl0();
mask = (unsigned long)0xfe0000000ull;
break;
default:
/*
* GCC 4.9 isn't smart enough to figure out that
* segctl and mask are always initialised.
*/
unreachable();
}
if (is_eva_am_mapped(vcpu, (segctl >> 4) & 0x7,
segctl & 0x0008))
goto tlb_mapped;
/* Unmapped, find guest physical address */
pa = (segctl << 20) & mask;
pa |= gva32 & ~mask;
*gpa = pa;
return 0;
} else if ((s32)gva32 < (s32)0xc0000000) {
/* legacy unmapped KSeg0 or KSeg1 */
*gpa = gva32 & 0x1fffffff;
return 0;
}
#ifdef CONFIG_64BIT
} else if ((gva & 0xc000000000000000) == 0x8000000000000000) {
/* XKPHYS */
if (cpu_guest_has_segments) {
/*
* Each of the 8 regions can be overridden by SegCtl2.XR
* to use SegCtl1.XAM.
*/
segctl = read_gc0_segctl2();
if (segctl & (1ull << (56 + ((gva >> 59) & 0x7)))) {
segctl = read_gc0_segctl1();
if (is_eva_am_mapped(vcpu, (segctl >> 59) & 0x7,
0))
goto tlb_mapped;
}
}
/*
* Traditionally fully unmapped.
* Bits 61:59 specify the CCA, which we can just mask off here.
* Bits 58:PABITS should be zero, but we shouldn't have got here
* if it wasn't.
*/
*gpa = gva & 0x07ffffffffffffff;
return 0;
#endif
}
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
return kvm_vz_guest_tlb_lookup(vcpu, gva, gpa);
}
/**
* kvm_vz_badvaddr_to_gpa() - Convert GVA BadVAddr from root exception to GPA.
* @vcpu: KVM VCPU state.
* @badvaddr: Root BadVAddr.
* @gpa: Output guest physical address.
*
* VZ implementations are permitted to report guest virtual addresses (GVA) in
* BadVAddr on a root exception during guest execution, instead of the more
* convenient guest physical addresses (GPA). When we get a GVA, this function
* converts it to a GPA, taking into account guest segmentation and guest TLB
* state.
*
* Returns: 0 on success.
* -errno on failure.
*/
static int kvm_vz_badvaddr_to_gpa(struct kvm_vcpu *vcpu, unsigned long badvaddr,
unsigned long *gpa)
{
unsigned int gexccode = (vcpu->arch.host_cp0_guestctl0 &
MIPS_GCTL0_GEXC) >> MIPS_GCTL0_GEXC_SHIFT;
/* If BadVAddr is GPA, then all is well in the world */
if (likely(gexccode == MIPS_GCTL0_GEXC_GPA)) {
*gpa = badvaddr;
return 0;
}
/* Otherwise we'd expect it to be GVA ... */
if (WARN(gexccode != MIPS_GCTL0_GEXC_GVA,
"Unexpected gexccode %#x\n", gexccode))
return -EINVAL;
/* ... and we need to perform the GVA->GPA translation in software */
return kvm_vz_gva_to_gpa(vcpu, badvaddr, gpa);
}
static int kvm_trap_vz_no_handler(struct kvm_vcpu *vcpu)
{
u32 *opc = (u32 *) vcpu->arch.pc;
u32 cause = vcpu->arch.host_cp0_cause;
u32 exccode = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE;
unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
u32 inst = 0;
/*
* Fetch the instruction.
*/
if (cause & CAUSEF_BD)
opc += 1;
kvm_get_badinstr(opc, vcpu, &inst);
kvm_err("Exception Code: %d not handled @ PC: %p, inst: 0x%08x BadVaddr: %#lx Status: %#x\n",
exccode, opc, inst, badvaddr,
read_gc0_status());
kvm_arch_vcpu_dump_regs(vcpu);
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
return RESUME_HOST;
}
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
static unsigned long mips_process_maar(unsigned int op, unsigned long val)
{
/* Mask off unused bits */
unsigned long mask = 0xfffff000 | MIPS_MAAR_S | MIPS_MAAR_VL;
if (read_gc0_pagegrain() & PG_ELPA)
mask |= 0x00ffffff00000000ull;
if (cpu_guest_has_mvh)
mask |= MIPS_MAAR_VH;
/* Set or clear VH */
if (op == mtc_op) {
/* clear VH */
val &= ~MIPS_MAAR_VH;
} else if (op == dmtc_op) {
/* set VH to match VL */
val &= ~MIPS_MAAR_VH;
if (val & MIPS_MAAR_VL)
val |= MIPS_MAAR_VH;
}
return val & mask;
}
static void kvm_write_maari(struct kvm_vcpu *vcpu, unsigned long val)
{
struct mips_coproc *cop0 = vcpu->arch.cop0;
val &= MIPS_MAARI_INDEX;
if (val == MIPS_MAARI_INDEX)
kvm_write_sw_gc0_maari(cop0, ARRAY_SIZE(vcpu->arch.maar) - 1);
else if (val < ARRAY_SIZE(vcpu->arch.maar))
kvm_write_sw_gc0_maari(cop0, val);
}
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
static enum emulation_result kvm_vz_gpsi_cop0(union mips_instruction inst,
u32 *opc, u32 cause,
struct kvm_run *run,
struct kvm_vcpu *vcpu)
{
struct mips_coproc *cop0 = vcpu->arch.cop0;
enum emulation_result er = EMULATE_DONE;
u32 rt, rd, sel;
unsigned long curr_pc;
unsigned long val;
/*
* Update PC and hold onto current PC in case there is
* an error and we want to rollback the PC
*/
curr_pc = vcpu->arch.pc;
er = update_pc(vcpu, cause);
if (er == EMULATE_FAIL)
return er;
if (inst.co_format.co) {
switch (inst.co_format.func) {
case wait_op:
er = kvm_mips_emul_wait(vcpu);
break;
default:
er = EMULATE_FAIL;
}
} else {
rt = inst.c0r_format.rt;
rd = inst.c0r_format.rd;
sel = inst.c0r_format.sel;
switch (inst.c0r_format.rs) {
case dmfc_op:
case mfc_op:
#ifdef CONFIG_KVM_MIPS_DEBUG_COP0_COUNTERS
cop0->stat[rd][sel]++;
#endif
if (rd == MIPS_CP0_COUNT &&
sel == 0) { /* Count */
val = kvm_mips_read_count(vcpu);
} else if (rd == MIPS_CP0_COMPARE &&
sel == 0) { /* Compare */
val = read_gc0_compare();
} else if (rd == MIPS_CP0_LLADDR &&
sel == 0) { /* LLAddr */
if (cpu_guest_has_rw_llb)
val = read_gc0_lladdr() &
MIPS_LLADDR_LLB;
else
val = 0;
} else if (rd == MIPS_CP0_LLADDR &&
sel == 1 && /* MAAR */
cpu_guest_has_maar &&
!cpu_guest_has_dyn_maar) {
/* MAARI must be in range */
BUG_ON(kvm_read_sw_gc0_maari(cop0) >=
ARRAY_SIZE(vcpu->arch.maar));
val = vcpu->arch.maar[
kvm_read_sw_gc0_maari(cop0)];
} else if ((rd == MIPS_CP0_PRID &&
(sel == 0 || /* PRid */
sel == 2 || /* CDMMBase */
sel == 3)) || /* CMGCRBase */
(rd == MIPS_CP0_STATUS &&
(sel == 2 || /* SRSCtl */
sel == 3)) || /* SRSMap */
(rd == MIPS_CP0_CONFIG &&
(sel == 6 || /* Config6 */
sel == 7)) || /* Config7 */
(rd == MIPS_CP0_LLADDR &&
(sel == 2) && /* MAARI */
cpu_guest_has_maar &&
!cpu_guest_has_dyn_maar) ||
(rd == MIPS_CP0_ERRCTL &&
(sel == 0))) { /* ErrCtl */
val = cop0->reg[rd][sel];
#ifdef CONFIG_CPU_LOONGSON64
} else if (rd == MIPS_CP0_DIAG &&
(sel == 0)) { /* Diag */
val = cop0->reg[rd][sel];
#endif
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
} else {
val = 0;
er = EMULATE_FAIL;
}
if (er != EMULATE_FAIL) {
/* Sign extend */
if (inst.c0r_format.rs == mfc_op)
val = (int)val;
vcpu->arch.gprs[rt] = val;
}
trace_kvm_hwr(vcpu, (inst.c0r_format.rs == mfc_op) ?
KVM_TRACE_MFC0 : KVM_TRACE_DMFC0,
KVM_TRACE_COP0(rd, sel), val);
break;
case dmtc_op:
case mtc_op:
#ifdef CONFIG_KVM_MIPS_DEBUG_COP0_COUNTERS
cop0->stat[rd][sel]++;
#endif
val = vcpu->arch.gprs[rt];
trace_kvm_hwr(vcpu, (inst.c0r_format.rs == mtc_op) ?
KVM_TRACE_MTC0 : KVM_TRACE_DMTC0,
KVM_TRACE_COP0(rd, sel), val);
if (rd == MIPS_CP0_COUNT &&
sel == 0) { /* Count */
kvm_mips_write_count(vcpu, vcpu->arch.gprs[rt]);
} else if (rd == MIPS_CP0_COMPARE &&
sel == 0) { /* Compare */
kvm_mips_write_compare(vcpu,
vcpu->arch.gprs[rt],
true);
} else if (rd == MIPS_CP0_LLADDR &&
sel == 0) { /* LLAddr */
/*
* P5600 generates GPSI on guest MTC0 LLAddr.
* Only allow the guest to clear LLB.