浏览代码

Merge branch 'kvm-mips-fixes' into HEAD

Merge MIPS patches destined to both 4.7 and kvm/next, to avoid
unnecessary conflicts.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Paolo Bonzini 9 年之前
父节点
当前提交
b11c3f5947
共有 5 个文件被更改,包括 27 次插入8 次删除
  1. 2 1
      arch/mips/include/asm/kvm_host.h
  2. 13 6
      arch/mips/kvm/emulate.c
  3. 1 0
      arch/mips/kvm/interrupt.h
  4. 1 0
      arch/mips/kvm/locore.S
  5. 10 1
      arch/mips/kvm/mips.c

+ 2 - 1
arch/mips/include/asm/kvm_host.h

@@ -74,7 +74,7 @@
 #define KVM_GUEST_KUSEG			0x00000000UL
 #define KVM_GUEST_KUSEG			0x00000000UL
 #define KVM_GUEST_KSEG0			0x40000000UL
 #define KVM_GUEST_KSEG0			0x40000000UL
 #define KVM_GUEST_KSEG23		0x60000000UL
 #define KVM_GUEST_KSEG23		0x60000000UL
-#define KVM_GUEST_KSEGX(a)		((_ACAST32_(a)) & 0x60000000)
+#define KVM_GUEST_KSEGX(a)		((_ACAST32_(a)) & 0xe0000000)
 #define KVM_GUEST_CPHYSADDR(a)		((_ACAST32_(a)) & 0x1fffffff)
 #define KVM_GUEST_CPHYSADDR(a)		((_ACAST32_(a)) & 0x1fffffff)
 
 
 #define KVM_GUEST_CKSEG0ADDR(a)		(KVM_GUEST_CPHYSADDR(a) | KVM_GUEST_KSEG0)
 #define KVM_GUEST_CKSEG0ADDR(a)		(KVM_GUEST_CPHYSADDR(a) | KVM_GUEST_KSEG0)
@@ -338,6 +338,7 @@ struct kvm_mips_tlb {
 #define KVM_MIPS_GUEST_TLB_SIZE	64
 #define KVM_MIPS_GUEST_TLB_SIZE	64
 struct kvm_vcpu_arch {
 struct kvm_vcpu_arch {
 	void *host_ebase, *guest_ebase;
 	void *host_ebase, *guest_ebase;
+	int (*vcpu_run)(struct kvm_run *run, struct kvm_vcpu *vcpu);
 	unsigned long host_stack;
 	unsigned long host_stack;
 	unsigned long host_gp;
 	unsigned long host_gp;
 
 

+ 13 - 6
arch/mips/kvm/emulate.c

@@ -1636,6 +1636,7 @@ enum emulation_result kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc,
 		if (index < 0) {
 		if (index < 0) {
 			vcpu->arch.host_cp0_entryhi = (va & VPN2_MASK);
 			vcpu->arch.host_cp0_entryhi = (va & VPN2_MASK);
 			vcpu->arch.host_cp0_badvaddr = va;
 			vcpu->arch.host_cp0_badvaddr = va;
+			vcpu->arch.pc = curr_pc;
 			er = kvm_mips_emulate_tlbmiss_ld(cause, NULL, run,
 			er = kvm_mips_emulate_tlbmiss_ld(cause, NULL, run,
 							 vcpu);
 							 vcpu);
 			preempt_enable();
 			preempt_enable();
@@ -1647,6 +1648,8 @@ enum emulation_result kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc,
 			 * invalid exception to the guest
 			 * invalid exception to the guest
 			 */
 			 */
 			if (!TLB_IS_VALID(*tlb, va)) {
 			if (!TLB_IS_VALID(*tlb, va)) {
+				vcpu->arch.host_cp0_badvaddr = va;
+				vcpu->arch.pc = curr_pc;
 				er = kvm_mips_emulate_tlbinv_ld(cause, NULL,
 				er = kvm_mips_emulate_tlbinv_ld(cause, NULL,
 								run, vcpu);
 								run, vcpu);
 				preempt_enable();
 				preempt_enable();
@@ -1666,7 +1669,7 @@ enum emulation_result kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc,
 			cache, op, base, arch->gprs[base], offset);
 			cache, op, base, arch->gprs[base], offset);
 		er = EMULATE_FAIL;
 		er = EMULATE_FAIL;
 		preempt_enable();
 		preempt_enable();
-		goto dont_update_pc;
+		goto done;
 
 
 	}
 	}
 
 
@@ -1694,16 +1697,20 @@ skip_fault:
 		kvm_err("NO-OP CACHE (cache: %#x, op: %#x, base[%d]: %#lx, offset: %#x\n",
 		kvm_err("NO-OP CACHE (cache: %#x, op: %#x, base[%d]: %#lx, offset: %#x\n",
 			cache, op, base, arch->gprs[base], offset);
 			cache, op, base, arch->gprs[base], offset);
 		er = EMULATE_FAIL;
 		er = EMULATE_FAIL;
-		preempt_enable();
-		goto dont_update_pc;
 	}
 	}
 
 
 	preempt_enable();
 	preempt_enable();
+done:
+	/* Rollback PC only if emulation was unsuccessful */
+	if (er == EMULATE_FAIL)
+		vcpu->arch.pc = curr_pc;
 
 
 dont_update_pc:
 dont_update_pc:
-	/* Rollback PC */
-	vcpu->arch.pc = curr_pc;
-done:
+	/*
+	 * This is for exceptions whose emulation updates the PC, so do not
+	 * overwrite the PC under any circumstances
+	 */
+
 	return er;
 	return er;
 }
 }
 
 

+ 1 - 0
arch/mips/kvm/interrupt.h

@@ -28,6 +28,7 @@
 #define MIPS_EXC_MAX                12
 #define MIPS_EXC_MAX                12
 /* XXXSL More to follow */
 /* XXXSL More to follow */
 
 
+extern char __kvm_mips_vcpu_run_end[];
 extern char mips32_exception[], mips32_exceptionEnd[];
 extern char mips32_exception[], mips32_exceptionEnd[];
 extern char mips32_GuestException[], mips32_GuestExceptionEnd[];
 extern char mips32_GuestException[], mips32_GuestExceptionEnd[];
 
 

+ 1 - 0
arch/mips/kvm/locore.S

@@ -202,6 +202,7 @@ FEXPORT(__kvm_mips_load_k0k1)
 
 
 	/* Jump to guest */
 	/* Jump to guest */
 	eret
 	eret
+EXPORT(__kvm_mips_vcpu_run_end)
 
 
 VECTOR(MIPSX(exception), unknown)
 VECTOR(MIPSX(exception), unknown)
 /* Find out what mode we came from and jump to the proper handler. */
 /* Find out what mode we came from and jump to the proper handler. */

+ 10 - 1
arch/mips/kvm/mips.c

@@ -315,6 +315,15 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
 	memcpy(gebase + offset, mips32_GuestException,
 	memcpy(gebase + offset, mips32_GuestException,
 	       mips32_GuestExceptionEnd - mips32_GuestException);
 	       mips32_GuestExceptionEnd - mips32_GuestException);
 
 
+#ifdef MODULE
+	offset += mips32_GuestExceptionEnd - mips32_GuestException;
+	memcpy(gebase + offset, (char *)__kvm_mips_vcpu_run,
+	       __kvm_mips_vcpu_run_end - (char *)__kvm_mips_vcpu_run);
+	vcpu->arch.vcpu_run = gebase + offset;
+#else
+	vcpu->arch.vcpu_run = __kvm_mips_vcpu_run;
+#endif
+
 	/* Invalidate the icache for these ranges */
 	/* Invalidate the icache for these ranges */
 	local_flush_icache_range((unsigned long)gebase,
 	local_flush_icache_range((unsigned long)gebase,
 				(unsigned long)gebase + ALIGN(size, PAGE_SIZE));
 				(unsigned long)gebase + ALIGN(size, PAGE_SIZE));
@@ -404,7 +413,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	/* Disable hardware page table walking while in guest */
 	/* Disable hardware page table walking while in guest */
 	htw_stop();
 	htw_stop();
 
 
-	r = __kvm_mips_vcpu_run(run, vcpu);
+	r = vcpu->arch.vcpu_run(run, vcpu);
 
 
 	/* Re-enable HTW before enabling interrupts */
 	/* Re-enable HTW before enabling interrupts */
 	htw_start();
 	htw_start();