Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c992a4f6 authored by James Hogan's avatar James Hogan
Browse files

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: default avatarJames Hogan <james.hogan@imgtec.com>
Acked-by: default avatarRalf 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
parent ea1bdbf6
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -2075,6 +2075,7 @@ registers, find a list below:
  MIPS  | KVM_REG_MIPS_CP0_CONTEXT      | 64
  MIPS  | KVM_REG_MIPS_CP0_CONTEXT      | 64
  MIPS  | KVM_REG_MIPS_CP0_USERLOCAL    | 64
  MIPS  | KVM_REG_MIPS_CP0_USERLOCAL    | 64
  MIPS  | KVM_REG_MIPS_CP0_PAGEMASK     | 32
  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_WIRED        | 32
  MIPS  | KVM_REG_MIPS_CP0_HWRENA       | 32
  MIPS  | KVM_REG_MIPS_CP0_HWRENA       | 32
  MIPS  | KVM_REG_MIPS_CP0_BADVADDR     | 64
  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_CONFIG4      | 32
  MIPS  | KVM_REG_MIPS_CP0_CONFIG5      | 32
  MIPS  | KVM_REG_MIPS_CP0_CONFIG5      | 32
  MIPS  | KVM_REG_MIPS_CP0_CONFIG7      | 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_ERROREPC     | 64
  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH1    | 64
  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH1    | 64
  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH2    | 64
  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH2    | 64
+1 −0
Original line number Original line Diff line number Diff line
@@ -110,6 +110,7 @@ struct cpuinfo_mips {
	struct guest_info	guest;
	struct guest_info	guest;
	unsigned int		gtoffset_mask;
	unsigned int		gtoffset_mask;
	unsigned int		guestid_mask;
	unsigned int		guestid_mask;
	unsigned int		guestid_cache;
} __attribute__((aligned(SMP_CACHE_BYTES)));
} __attribute__((aligned(SMP_CACHE_BYTES)));


extern struct cpuinfo_mips cpu_data[];
extern struct cpuinfo_mips cpu_data[];
+42 −0
Original line number Original line Diff line number Diff line
@@ -10,6 +10,7 @@
#ifndef __MIPS_KVM_HOST_H__
#ifndef __MIPS_KVM_HOST_H__
#define __MIPS_KVM_HOST_H__
#define __MIPS_KVM_HOST_H__


#include <linux/cpumask.h>
#include <linux/mutex.h>
#include <linux/mutex.h>
#include <linux/hrtimer.h>
#include <linux/hrtimer.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
@@ -73,6 +74,11 @@
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
#define KVM_HALT_POLL_NS_DEFAULT 500000
#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 {
struct kvm_arch {
	/* Guest physical mm */
	/* Guest physical mm */
	struct mm_struct gpa_mm;
	struct mm_struct gpa_mm;
	/* Mask of CPUs needing GPA ASID flush */
	cpumask_t asid_flush_mask;
};
};


#define N_MIPS_COPROC_REGS	32
#define N_MIPS_COPROC_REGS	32
@@ -224,6 +232,11 @@ struct mips_coproc {
#define MIPS_CP0_CONFIG4_SEL	4
#define MIPS_CP0_CONFIG4_SEL	4
#define MIPS_CP0_CONFIG5_SEL	5
#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 */
/* Resume Flags */
#define RESUME_FLAG_DR		(1<<0)	/* Reload guest nonvolatile state? */
#define RESUME_FLAG_DR		(1<<0)	/* Reload guest nonvolatile state? */
#define RESUME_FLAG_HOST	(1<<1)	/* Resume host? */
#define RESUME_FLAG_HOST	(1<<1)	/* Resume host? */
@@ -356,7 +369,20 @@ struct kvm_vcpu_arch {
	/* Cache some mmu pages needed inside spinlock regions */
	/* Cache some mmu pages needed inside spinlock regions */
	struct kvm_mmu_memory_cache mmu_page_cache;
	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;
	int last_sched_cpu;
	/* Last CPU the VCPU actually executed guest code on */
	int last_exec_cpu;


	/* WAIT executed */
	/* WAIT executed */
	int wait;
	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(config5,        32, MIPS_CP0_CONFIG,       5)
__BUILD_KVM_RW_HW(config6,        32, MIPS_CP0_CONFIG,       6)
__BUILD_KVM_RW_HW(config6,        32, MIPS_CP0_CONFIG,       6)
__BUILD_KVM_RW_HW(config7,        32, MIPS_CP0_CONFIG,       7)
__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(errorepc,       l,  MIPS_CP0_ERROR_PC,     0)
__BUILD_KVM_RW_HW(kscratch1,      l,  MIPS_CP0_DESAVE,       2)
__BUILD_KVM_RW_HW(kscratch1,      l,  MIPS_CP0_DESAVE,       2)
__BUILD_KVM_RW_HW(kscratch2,      l,  MIPS_CP0_DESAVE,       3)
__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_ATOMIC_HW(cause,      32, MIPS_CP0_CAUSE,        0)
__BUILD_KVM_SET_HW(ebase,         l,  MIPS_CP0_PRID,         1)
__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 */
/* Helpers */


static inline bool kvm_mips_guest_can_have_fpu(struct kvm_vcpu_arch *vcpu)
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);
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,
extern int kvm_mips_handle_kseg0_tlb_fault(unsigned long badbaddr,
					   struct kvm_vcpu *vcpu,
					   struct kvm_vcpu *vcpu,
					   bool write_fault);
					   bool write_fault);
@@ -1026,6 +1065,9 @@ enum emulation_result kvm_mips_emulate_load(union mips_instruction inst,
					    struct kvm_run *run,
					    struct kvm_run *run,
					    struct kvm_vcpu *vcpu);
					    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_config1_wrmask(struct kvm_vcpu *vcpu);
unsigned int kvm_mips_config3_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);
unsigned int kvm_mips_config4_wrmask(struct kvm_vcpu *vcpu);
+1 −0
Original line number Original line Diff line number Diff line
@@ -70,6 +70,7 @@ EXPORT_SYMBOL(perf_irq);
 */
 */


unsigned int mips_hpt_frequency;
unsigned int mips_hpt_frequency;
EXPORT_SYMBOL_GPL(mips_hpt_frequency);


/*
/*
 * This function exists in order to cause an error due to a duplicate
 * This function exists in order to cause an error due to a duplicate
+5 −0
Original line number Original line Diff line number Diff line
@@ -30,8 +30,13 @@


#define C_TI        (_ULCAST_(1) << 30)
#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_DELIVER_ALL_AT_ONCE (0)
#define KVM_MIPS_IRQ_CLEAR_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_queue_irq(struct kvm_vcpu *vcpu, unsigned int priority);
void kvm_mips_dequeue_irq(struct kvm_vcpu *vcpu, unsigned int priority);
void kvm_mips_dequeue_irq(struct kvm_vcpu *vcpu, unsigned int priority);
Loading