[Android-virt] [PATCH v8 08/15] ARM: KVM: Module unloading support

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

 



Current initialization code relies on the MMU-bit and TE-bit of the
HSCTLR register to be cleared, so to support re-inserting the KVM module
we must clear these bits when unloading the module.

This is going to change in two ways:

First, the init id-map code is going to go away in favor of
section-based id-mapping.

Second, we are not going to use the SMC call in the future, but rather
an HVC instruction to take control of Hyp mode.  We need, however, a
method to setup the original init code again to support module
unloading.  It is useful to add this support at this point since we will (a)
remember to support unloading and (b) benefit from shorter debug cycles.

Signed-off-by: Christoffer Dall <c.dall at virtualopensystems.com>
---
 arch/arm/include/asm/kvm_asm.h |    3 ++
 arch/arm/kvm/arm.c             |   50 ++++++++++++++++++++++++++++++++++++++++
 arch/arm/kvm/exports.c         |    3 ++
 arch/arm/kvm/init.S            |   28 ++++++++++++++++++++++
 4 files changed, 84 insertions(+)

diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index 69afdf3..c2ec131 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -37,6 +37,9 @@ struct kvm_vcpu;
 extern char __kvm_hyp_init[];
 extern char __kvm_hyp_init_end[];
 
+extern char __kvm_hyp_exit[];
+extern char __kvm_hyp_exit_end[];
+
 extern char __kvm_hyp_vector[];
 
 extern char __kvm_hyp_code_start[];
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 4c61d3c..efe130c 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -421,10 +421,60 @@ out_err:
 	return err;
 }
 
+static void cpu_exit_hyp_mode(void *vector)
+{
+	cpu_set_vector(vector);
+
+	/*
+	 * Disable Hyp-MMU for each cpu
+	 */
+	asm volatile ("hvc	#0");
+}
+
+static int exit_hyp_mode(void)
+{
+	phys_addr_t exit_phys_addr, exit_end_phys_addr;
+	int cpu;
+
+	exit_phys_addr = virt_to_phys(__kvm_hyp_exit);
+	exit_end_phys_addr = virt_to_phys(__kvm_hyp_exit_end);
+	BUG_ON(exit_phys_addr & 0x1f);
+
+	/*
+	 * Create identity mapping for the exit code.
+	 */
+	hyp_idmap_add(kvm_hyp_pgd_get(),
+		      (unsigned long)exit_phys_addr,
+		      (unsigned long)exit_end_phys_addr);
+
+	/*
+	 * Execute the exit code on each CPU.
+	 *
+	 * Note: The stack is not mapped yet, so don't do anything else than
+	 * initializing the hypervisor mode on each CPU using a local stack
+	 * space for temporary storage.
+	 */
+	for_each_online_cpu(cpu) {
+		smp_call_function_single(cpu, cpu_exit_hyp_mode,
+					 (void *)(long)exit_phys_addr, 1);
+	}
+
+	/*
+	 * Unmap the identity mapping
+	 */
+	hyp_idmap_del(kvm_hyp_pgd_get(),
+		      (unsigned long)exit_phys_addr,
+		      (unsigned long)exit_end_phys_addr);
+
+	return 0;
+}
+
 void kvm_arch_exit(void)
 {
 	int cpu;
 
+	exit_hyp_mode();
+
 	free_hyp_pmds();
 	for_each_possible_cpu(cpu)
 		free_page(per_cpu(kvm_arm_hyp_stack_page, cpu));
diff --git a/arch/arm/kvm/exports.c b/arch/arm/kvm/exports.c
index 2631609..9bdaf11 100644
--- a/arch/arm/kvm/exports.c
+++ b/arch/arm/kvm/exports.c
@@ -19,6 +19,9 @@
 EXPORT_SYMBOL_GPL(__kvm_hyp_init);
 EXPORT_SYMBOL_GPL(__kvm_hyp_init_end);
 
+EXPORT_SYMBOL_GPL(__kvm_hyp_exit);
+EXPORT_SYMBOL_GPL(__kvm_hyp_exit_end);
+
 EXPORT_SYMBOL_GPL(__kvm_hyp_vector);
 
 EXPORT_SYMBOL_GPL(__kvm_hyp_code_start);
diff --git a/arch/arm/kvm/init.S b/arch/arm/kvm/init.S
index 7800023..c3beb20 100644
--- a/arch/arm/kvm/init.S
+++ b/arch/arm/kvm/init.S
@@ -114,3 +114,31 @@ __do_hyp_init:
 	__kvm_init_sp:
 	.globl __kvm_hyp_init_end
 __kvm_hyp_init_end:
+
+
+	.align 12
+__kvm_hyp_exit:
+	.globl __kvm_hyp_exit
+
+	@ Hyp-mode exception vector
+	nop
+	nop
+	nop
+	nop
+	nop
+	b	__do_hyp_exit
+	nop
+	nop
+
+__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))
+
+	isb
+	mcr	p15, 4, sp, c1, c0, 0	@ HSCR
+	isb
+	eret
+
+	.globl __kvm_hyp_exit_end
+__kvm_hyp_exit_end:



[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