[PATCH 3/6] ARM: KVM: Switch HVBAR setting to be HVC-based

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Instead of relying on SMC calls to setup HVBAR, introduce a new
HVC-based API. This of course requires a hypervisor stub to be
installed already. At the moment, this is implemented as part of the
boot wrapper, but will be moved to the kernel itself when it actually
understands being booted in HYP mode.

The kernel now uses "hvc #0xff", with r0 containing the pointer to
the new vectors.

Signed-off-by: Marc Zyngier <marc.zyngier@xxxxxxx>
---
 arch/arm/include/asm/kvm_asm.h |    5 ---
 arch/arm/kvm/arm.c             |   54 +++++++++++++++++++++++++--------------
 arch/arm/kvm/init.S            |   34 +++++++++++++++---------
 arch/arm/kvm/interrupts.S      |   14 ++++++++++
 4 files changed, 69 insertions(+), 38 deletions(-)

diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index e01dfab..a2bf1c5 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -28,11 +28,6 @@
 #define ARM_EXCEPTION_FIQ	  6
 #define ARM_EXCEPTION_HVC	  7
 
-/*
- * SMC Hypervisor API call number
- */
-#define SMCHYP_HVBAR_W 0xfffffff0
-
 #ifndef __ASSEMBLY__
 struct kvm;
 struct kvm_vcpu;
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 390e8b8..da5fc5f 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -39,6 +39,7 @@
 #include <asm/tlbflush.h>
 #include <asm/cacheflush.h>
 #include <asm/cputype.h>
+#include <asm/virt.h>
 #include <asm/kvm_arm.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_mmu.h>
@@ -701,21 +702,17 @@ long kvm_arch_vm_ioctl(struct file *filp,
 static void cpu_set_vector(void *vector)
 {
 	unsigned long vector_ptr;
-	unsigned long smc_hyp_nr;
 
 	vector_ptr = (unsigned long)vector;
-	smc_hyp_nr = SMCHYP_HVBAR_W;
 
 	/*
 	 * Set the HVBAR
 	 */
 	asm volatile (
 		"mov	r0, %[vector_ptr]\n\t"
-		"mov	r7, %[smc_hyp_nr]\n\t"
-		"smc	#0\n\t" : :
-		[vector_ptr] "r" (vector_ptr),
-		[smc_hyp_nr] "r" (smc_hyp_nr) :
-		"r0", "r7");
+		"hvc	#0xff\n\t" : :
+		[vector_ptr] "r" (vector_ptr) :
+		"r0");
 }
 
 static void cpu_init_hyp_mode(void *vector)
@@ -723,25 +720,34 @@ static void cpu_init_hyp_mode(void *vector)
 	unsigned long pgd_ptr;
 	unsigned long hyp_stack_ptr;
 	unsigned long stack_page;
+	unsigned long vector_ptr;
 
-	cpu_set_vector(vector);
+	/* Switch from the HYP stub to our own HYP init vector */
+	__hyp_set_vectors((unsigned long)vector);
 
 	pgd_ptr = virt_to_phys(hyp_pgd);
 	stack_page = __get_cpu_var(kvm_arm_hyp_stack_page);
 	hyp_stack_ptr = stack_page + PAGE_SIZE;
+	vector_ptr = (unsigned long)__kvm_hyp_vector;
 
 	/*
-	 * Call initialization code
+	 * Call initialization code, and switch to the full blown
+	 * HYP code. The init code corrupts r12, so set the clobber
+	 * list accordingly.
 	 */
 	asm volatile (
 		"mov	r0, %[pgd_ptr]\n\t"
 		"mov	r1, %[hyp_stack_ptr]\n\t"
+		"mov	r2, %[vector_ptr]\n\t"
 		"hvc	#0\n\t" : :
 		[pgd_ptr] "r" (pgd_ptr),
-		[hyp_stack_ptr] "r" (hyp_stack_ptr) :
-		"r0", "r1");
+		[hyp_stack_ptr] "r" (hyp_stack_ptr),
+		[vector_ptr] "r" (vector_ptr) :
+		"r0", "r1", "r2", "r12");
 }
 
+static unsigned long hyp_default_vectors;
+
 /**
  * Inits Hyp-mode on all online CPUs
  */
@@ -752,6 +758,12 @@ static int init_hyp_mode(void)
 	int err = 0;
 
 	/*
+	 * It is probably enough to obtain the default on one
+	 * CPU. It's unlikely to be different on the others.
+	 */
+	hyp_default_vectors = __hyp_get_vectors();
+
+	/*
 	 * Allocate stack pages for Hypervisor-mode
 	 */
 	for_each_possible_cpu(cpu) {
@@ -807,13 +819,6 @@ static int init_hyp_mode(void)
 	}
 
 	/*
-	 * Set the HVBAR to the virtual kernel address
-	 */
-	for_each_online_cpu(cpu)
-		smp_call_function_single(cpu, cpu_set_vector,
-					 __kvm_hyp_vector, 1);
-
-	/*
 	 * Map the host VFP structures
 	 */
 	for_each_possible_cpu(cpu) {
@@ -844,6 +849,11 @@ int kvm_arch_init(void *opaque)
 {
 	int err;
 
+	if (!is_hyp_mode_available()) {
+		kvm_err("HYP mode not available\n");
+		return -ENODEV;
+	}
+
 	if (kvm_target_cpu() < 0) {
 		kvm_err("Target CPU (%#08x) not supported!\n", read_cpuid_id());
 		return -ENODEV;
@@ -864,9 +874,13 @@ static void cpu_exit_hyp_mode(void *vector)
 	cpu_set_vector(vector);
 
 	/*
-	 * Disable Hyp-MMU for each cpu
+	 * Disable Hyp-MMU for each cpu, and switch back to the
+	 * default vectors.
 	 */
-	asm volatile ("hvc	#0");
+	asm volatile ("mov	r0, %[vector_ptr]\n\t"
+		      "hvc	#0\n\t" : :
+		      [vector_ptr] "r" (hyp_default_vectors) :
+		      "r0");
 }
 
 static int exit_hyp_mode(void)
diff --git a/arch/arm/kvm/init.S b/arch/arm/kvm/init.S
index 4db26cb..77a8e1f 100644
--- a/arch/arm/kvm/init.S
+++ b/arch/arm/kvm/init.S
@@ -27,6 +27,7 @@
 @    - should be called with:
 @        r0 = Hypervisor pgd pointer
 @        r1 = top of Hyp stack (kernel VA)
+@        r2 = pointer to hyp vectors 
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 	.text
 	.arm
@@ -106,8 +107,12 @@ __do_hyp_init:
 	isb
 
 	@ Set stack pointer and return to the kernel
-	pop	{r0, r1, r2, r12}
+	pop	{r0, r1, r2}
 	mov	sp, r1
+
+	@ Set HVBAR to point to the HYP vectors
+	mcr	p15, 4, r2, c12, c0, 0	@ HVBAR
+
 	eret
 
 	.ltorg
@@ -123,22 +128,25 @@ __kvm_hyp_exit:
 	.globl __kvm_hyp_exit
 
 	@ Hyp-mode exception vector
-	nop
-	nop
-	nop
-	nop
-	nop
-	b	__do_hyp_exit
-	nop
-	nop
+	W(b)	.
+	W(b)	.
+	W(b)	.
+	W(b)	.
+	W(b)	.
+	W(b)	__do_hyp_exit
+	W(b)	.
+	W(b)	.
 
 __do_hyp_exit:
-	@ Clear the MMU and TE bits in the HSCR
-	mrc	p15, 4, sp, c1, c0, 0	@ HSCR
-	bic	sp, sp, #((1 << 30) | (1 << 0))
+	@ Set the next HVBAR (normally the default vectors)
+	mcr	p15, 4, r0, c12, c0, 0	@ HVBAR
+
+	@ Clear the MMU bit in the HSCR
+	mrc	p15, 4, r0, c1, c0, 0	@ HSCR
+	bic	r0, r0, #HSCTLR_M
 
 	isb
-	mcr	p15, 4, sp, c1, c0, 0	@ HSCR
+	mcr	p15, 4, r0, c1, c0, 0	@ HSCR
 	mcr	p15, 4, r0, c8, c7, 0   @ Flush Hyp TLB, r0 ignored
 	isb
 	eret
diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S
index 5816376..4d6cc71 100644
--- a/arch/arm/kvm/interrupts.S
+++ b/arch/arm/kvm/interrupts.S
@@ -637,6 +637,20 @@ hyp_hvc:
 	cmp     r2, #0
 	bne	guest_trap		@ Guest called HVC
 
+	@ HVC came from host. Check if this is a request to
+	@ switch HVBAR to another set of vectors (kvm_exit).
+	lsl	r0, r0, #16
+	lsr	r0, r0, #16
+	cmp	r0, #0xff
+	bne	host_switch_to_hyp	@ Not HVC #0xff
+
+	@ We're switching away from this hypervisor, let's blow the TLBs.
+	pop	{r0, r1, r2}
+	mcr	p15, 4, r0, c12, c0, 0  @ HVBAR
+	mcr	p15, 4, r0, c8, c7, 0   @ Flush Hyp TLB, r0 ignored
+	eret
+
+host_switch_to_hyp:
 	@ Store lr_usr,spsr (svc cpsr) on bottom of stack
 	mov	r1, sp
 	bic	r1, r1, #0x0ff
-- 
1.7.8.6

_______________________________________________
kvmarm mailing list
kvmarm@xxxxxxxxxxxxxxxxxxxxx
https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm


[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux