@@ -39,6 +39,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[];
@@ -423,10 +423,52 @@ 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;
+ int cpu;
+
+ /*
+ * TODO: flush Hyp TLB in case idmap code overlaps.
+ * Note that we should do this in the monitor code when switching the
+ * HVBAR, but this is going away and should be rather done in the Hyp
+ * mode change of HVBAR.
+ */
+ hyp_idmap_setup();
+ exit_phys_addr = virt_to_phys(__kvm_hyp_exit);
+ BUG_ON(exit_phys_addr & 0x1f);
+
+ /*
+ * 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);
+ }
+
+ 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));
@@ -22,6 +22,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);
@@ -118,4 +118,32 @@ __do_hyp_init:
.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
+ mcr p15, 4, r0, c8, c7, 0 @ Flush Hyp TLB, r0 ignored
+ isb
+ eret
+
+ .globl __kvm_hyp_exit_end
+__kvm_hyp_exit_end:
+
.popsection
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 when we support booting the kernel in Hyp mode and get rid of the SMC call, in that we will have to issue an HVC call with a parameter instead. Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com> --- arch/arm/include/asm/kvm_asm.h | 3 +++ arch/arm/kvm/arm.c | 42 ++++++++++++++++++++++++++++++++++++++++ arch/arm/kvm/exports.c | 3 +++ arch/arm/kvm/init.S | 28 +++++++++++++++++++++++++++ 4 files changed, 76 insertions(+) -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html