mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
KVM: MIPS: Implement VZ support
Add the main support for the MIPS Virtualization ASE (A.K.A. VZ) to MIPS KVM. The bulk of this work is in vz.c, with various new state and definitions elsewhere. Enough is implemented to be able to run on a minimal VZ core. Further patches will fill out support for guest features which are optional or can be disabled. Signed-off-by: James Hogan <james.hogan@imgtec.com> Acked-by: Ralf Baechle <ralf@linux-mips.org> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: "Radim Krčmář" <rkrcmar@redhat.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Jonathan Corbet <corbet@lwn.net> Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Cc: linux-doc@vger.kernel.org
This commit is contained in:
parent
ea1bdbf683
commit
c992a4f6a9
@ -2075,6 +2075,7 @@ registers, find a list below:
|
||||
MIPS | KVM_REG_MIPS_CP0_CONTEXT | 64
|
||||
MIPS | KVM_REG_MIPS_CP0_USERLOCAL | 64
|
||||
MIPS | KVM_REG_MIPS_CP0_PAGEMASK | 32
|
||||
MIPS | KVM_REG_MIPS_CP0_PAGEGRAIN | 32
|
||||
MIPS | KVM_REG_MIPS_CP0_WIRED | 32
|
||||
MIPS | KVM_REG_MIPS_CP0_HWRENA | 32
|
||||
MIPS | KVM_REG_MIPS_CP0_BADVADDR | 64
|
||||
@ -2094,6 +2095,7 @@ registers, find a list below:
|
||||
MIPS | KVM_REG_MIPS_CP0_CONFIG4 | 32
|
||||
MIPS | KVM_REG_MIPS_CP0_CONFIG5 | 32
|
||||
MIPS | KVM_REG_MIPS_CP0_CONFIG7 | 32
|
||||
MIPS | KVM_REG_MIPS_CP0_XCONTEXT | 64
|
||||
MIPS | KVM_REG_MIPS_CP0_ERROREPC | 64
|
||||
MIPS | KVM_REG_MIPS_CP0_KSCRATCH1 | 64
|
||||
MIPS | KVM_REG_MIPS_CP0_KSCRATCH2 | 64
|
||||
|
@ -110,6 +110,7 @@ struct cpuinfo_mips {
|
||||
struct guest_info guest;
|
||||
unsigned int gtoffset_mask;
|
||||
unsigned int guestid_mask;
|
||||
unsigned int guestid_cache;
|
||||
} __attribute__((aligned(SMP_CACHE_BYTES)));
|
||||
|
||||
extern struct cpuinfo_mips cpu_data[];
|
||||
|
@ -10,6 +10,7 @@
|
||||
#ifndef __MIPS_KVM_HOST_H__
|
||||
#define __MIPS_KVM_HOST_H__
|
||||
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/interrupt.h>
|
||||
@ -73,6 +74,11 @@
|
||||
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
|
||||
#define KVM_HALT_POLL_NS_DEFAULT 500000
|
||||
|
||||
#ifdef CONFIG_KVM_MIPS_VZ
|
||||
extern unsigned long GUESTID_MASK;
|
||||
extern unsigned long GUESTID_FIRST_VERSION;
|
||||
extern unsigned long GUESTID_VERSION_MASK;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@ -167,6 +173,8 @@ struct kvm_arch_memory_slot {
|
||||
struct kvm_arch {
|
||||
/* Guest physical mm */
|
||||
struct mm_struct gpa_mm;
|
||||
/* Mask of CPUs needing GPA ASID flush */
|
||||
cpumask_t asid_flush_mask;
|
||||
};
|
||||
|
||||
#define N_MIPS_COPROC_REGS 32
|
||||
@ -224,6 +232,11 @@ struct mips_coproc {
|
||||
#define MIPS_CP0_CONFIG4_SEL 4
|
||||
#define MIPS_CP0_CONFIG5_SEL 5
|
||||
|
||||
#define MIPS_CP0_GUESTCTL2 10
|
||||
#define MIPS_CP0_GUESTCTL2_SEL 5
|
||||
#define MIPS_CP0_GTOFFSET 12
|
||||
#define MIPS_CP0_GTOFFSET_SEL 7
|
||||
|
||||
/* Resume Flags */
|
||||
#define RESUME_FLAG_DR (1<<0) /* Reload guest nonvolatile state? */
|
||||
#define RESUME_FLAG_HOST (1<<1) /* Resume host? */
|
||||
@ -356,7 +369,20 @@ struct kvm_vcpu_arch {
|
||||
/* Cache some mmu pages needed inside spinlock regions */
|
||||
struct kvm_mmu_memory_cache mmu_page_cache;
|
||||
|
||||
#ifdef CONFIG_KVM_MIPS_VZ
|
||||
/* vcpu's vzguestid is different on each host cpu in an smp system */
|
||||
u32 vzguestid[NR_CPUS];
|
||||
|
||||
/* wired guest TLB entries */
|
||||
struct kvm_mips_tlb *wired_tlb;
|
||||
unsigned int wired_tlb_limit;
|
||||
unsigned int wired_tlb_used;
|
||||
#endif
|
||||
|
||||
/* Last CPU the VCPU state was loaded on */
|
||||
int last_sched_cpu;
|
||||
/* Last CPU the VCPU actually executed guest code on */
|
||||
int last_exec_cpu;
|
||||
|
||||
/* WAIT executed */
|
||||
int wait;
|
||||
@ -660,6 +686,7 @@ __BUILD_KVM_RW_HW(config4, 32, MIPS_CP0_CONFIG, 4)
|
||||
__BUILD_KVM_RW_HW(config5, 32, MIPS_CP0_CONFIG, 5)
|
||||
__BUILD_KVM_RW_HW(config6, 32, MIPS_CP0_CONFIG, 6)
|
||||
__BUILD_KVM_RW_HW(config7, 32, MIPS_CP0_CONFIG, 7)
|
||||
__BUILD_KVM_RW_HW(xcontext, l, MIPS_CP0_TLB_XCONTEXT, 0)
|
||||
__BUILD_KVM_RW_HW(errorepc, l, MIPS_CP0_ERROR_PC, 0)
|
||||
__BUILD_KVM_RW_HW(kscratch1, l, MIPS_CP0_DESAVE, 2)
|
||||
__BUILD_KVM_RW_HW(kscratch2, l, MIPS_CP0_DESAVE, 3)
|
||||
@ -674,6 +701,14 @@ __BUILD_KVM_SET_HW(status, 32, MIPS_CP0_STATUS, 0)
|
||||
__BUILD_KVM_ATOMIC_HW(cause, 32, MIPS_CP0_CAUSE, 0)
|
||||
__BUILD_KVM_SET_HW(ebase, l, MIPS_CP0_PRID, 1)
|
||||
|
||||
/* Bitwise operations (on saved state) */
|
||||
__BUILD_KVM_SET_SAVED(config, 32, MIPS_CP0_CONFIG, 0)
|
||||
__BUILD_KVM_SET_SAVED(config1, 32, MIPS_CP0_CONFIG, 1)
|
||||
__BUILD_KVM_SET_SAVED(config2, 32, MIPS_CP0_CONFIG, 2)
|
||||
__BUILD_KVM_SET_SAVED(config3, 32, MIPS_CP0_CONFIG, 3)
|
||||
__BUILD_KVM_SET_SAVED(config4, 32, MIPS_CP0_CONFIG, 4)
|
||||
__BUILD_KVM_SET_SAVED(config5, 32, MIPS_CP0_CONFIG, 5)
|
||||
|
||||
/* Helpers */
|
||||
|
||||
static inline bool kvm_mips_guest_can_have_fpu(struct kvm_vcpu_arch *vcpu)
|
||||
@ -786,6 +821,10 @@ u32 kvm_get_user_asid(struct kvm_vcpu *vcpu);
|
||||
|
||||
u32 kvm_get_commpage_asid (struct kvm_vcpu *vcpu);
|
||||
|
||||
#ifdef CONFIG_KVM_MIPS_VZ
|
||||
int kvm_mips_handle_vz_root_tlb_fault(unsigned long badvaddr,
|
||||
struct kvm_vcpu *vcpu, bool write_fault);
|
||||
#endif
|
||||
extern int kvm_mips_handle_kseg0_tlb_fault(unsigned long badbaddr,
|
||||
struct kvm_vcpu *vcpu,
|
||||
bool write_fault);
|
||||
@ -1026,6 +1065,9 @@ enum emulation_result kvm_mips_emulate_load(union mips_instruction inst,
|
||||
struct kvm_run *run,
|
||||
struct kvm_vcpu *vcpu);
|
||||
|
||||
/* COP0 */
|
||||
enum emulation_result kvm_mips_emul_wait(struct kvm_vcpu *vcpu);
|
||||
|
||||
unsigned int kvm_mips_config1_wrmask(struct kvm_vcpu *vcpu);
|
||||
unsigned int kvm_mips_config3_wrmask(struct kvm_vcpu *vcpu);
|
||||
unsigned int kvm_mips_config4_wrmask(struct kvm_vcpu *vcpu);
|
||||
|
@ -70,6 +70,7 @@ EXPORT_SYMBOL(perf_irq);
|
||||
*/
|
||||
|
||||
unsigned int mips_hpt_frequency;
|
||||
EXPORT_SYMBOL_GPL(mips_hpt_frequency);
|
||||
|
||||
/*
|
||||
* This function exists in order to cause an error due to a duplicate
|
||||
|
@ -30,8 +30,13 @@
|
||||
|
||||
#define C_TI (_ULCAST_(1) << 30)
|
||||
|
||||
#ifdef CONFIG_KVM_MIPS_VZ
|
||||
#define KVM_MIPS_IRQ_DELIVER_ALL_AT_ONCE (1)
|
||||
#define KVM_MIPS_IRQ_CLEAR_ALL_AT_ONCE (1)
|
||||
#else
|
||||
#define KVM_MIPS_IRQ_DELIVER_ALL_AT_ONCE (0)
|
||||
#define KVM_MIPS_IRQ_CLEAR_ALL_AT_ONCE (0)
|
||||
#endif
|
||||
|
||||
void kvm_mips_queue_irq(struct kvm_vcpu *vcpu, unsigned int priority);
|
||||
void kvm_mips_dequeue_irq(struct kvm_vcpu *vcpu, unsigned int priority);
|
||||
|
@ -113,7 +113,11 @@ void kvm_arch_check_processor_compat(void *rtn)
|
||||
int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
||||
{
|
||||
switch (type) {
|
||||
#ifdef CONFIG_KVM_MIPS_VZ
|
||||
case KVM_VM_MIPS_VZ:
|
||||
#else
|
||||
case KVM_VM_MIPS_TE:
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
/* Unsupported KVM type */
|
||||
@ -378,6 +382,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
|
||||
|
||||
/* Init */
|
||||
vcpu->arch.last_sched_cpu = -1;
|
||||
vcpu->arch.last_exec_cpu = -1;
|
||||
|
||||
return vcpu;
|
||||
|
||||
|
@ -992,6 +992,22 @@ static pte_t kvm_mips_gpa_pte_to_gva_mapped(pte_t pte, long entrylo)
|
||||
return kvm_mips_gpa_pte_to_gva_unmapped(pte);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KVM_MIPS_VZ
|
||||
int kvm_mips_handle_vz_root_tlb_fault(unsigned long badvaddr,
|
||||
struct kvm_vcpu *vcpu,
|
||||
bool write_fault)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = kvm_mips_map_page(vcpu, badvaddr, write_fault, NULL, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Invalidate this entry in the TLB */
|
||||
return kvm_vz_host_tlb_inv(vcpu, badvaddr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* XXXKYMA: Must be called with interrupts disabled */
|
||||
int kvm_mips_handle_kseg0_tlb_fault(unsigned long badvaddr,
|
||||
struct kvm_vcpu *vcpu,
|
||||
@ -1225,6 +1241,10 @@ int kvm_get_inst(u32 *opc, struct kvm_vcpu *vcpu, u32 *out)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (WARN(IS_ENABLED(CONFIG_KVM_MIPS_VZ),
|
||||
"Expect BadInstr/BadInstrP registers to be used with VZ\n"))
|
||||
return -EINVAL;
|
||||
|
||||
retry:
|
||||
kvm_trap_emul_gva_lockless_begin(vcpu);
|
||||
err = get_user(*out, opc);
|
||||
|
@ -34,6 +34,13 @@
|
||||
#define KVM_GUEST_SP_TLB 1
|
||||
|
||||
#ifdef CONFIG_KVM_MIPS_VZ
|
||||
unsigned long GUESTID_MASK;
|
||||
EXPORT_SYMBOL_GPL(GUESTID_MASK);
|
||||
unsigned long GUESTID_FIRST_VERSION;
|
||||
EXPORT_SYMBOL_GPL(GUESTID_FIRST_VERSION);
|
||||
unsigned long GUESTID_VERSION_MASK;
|
||||
EXPORT_SYMBOL_GPL(GUESTID_VERSION_MASK);
|
||||
|
||||
static u32 kvm_mips_get_root_asid(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct mm_struct *gpa_mm = &vcpu->kvm->arch.gpa_mm;
|
||||
|
@ -286,6 +286,21 @@ TRACE_EVENT(kvm_asid_change,
|
||||
__entry->new_asid)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_guestid_change,
|
||||
TP_PROTO(struct kvm_vcpu *vcpu, unsigned int guestid),
|
||||
TP_ARGS(vcpu, guestid),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, guestid)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->guestid = guestid;
|
||||
),
|
||||
|
||||
TP_printk("GuestID: 0x%02x",
|
||||
__entry->guestid)
|
||||
);
|
||||
|
||||
#endif /* _TRACE_KVM_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
|
2381
arch/mips/kvm/vz.c
Normal file
2381
arch/mips/kvm/vz.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user