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@xxxxxxxxxxxxxxxxxxxxxx> --- 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(+) diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h index 77831b1..58d51e3 100644 --- a/arch/arm/include/asm/kvm_asm.h +++ b/arch/arm/include/asm/kvm_asm.h @@ -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[]; diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index dccac7c..63593ee 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -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)); diff --git a/arch/arm/kvm/exports.c b/arch/arm/kvm/exports.c index c432c92..8ebdf07 100644 --- a/arch/arm/kvm/exports.c +++ b/arch/arm/kvm/exports.c @@ -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); diff --git a/arch/arm/kvm/init.S b/arch/arm/kvm/init.S index 7a046fa..4db26cb 100644 --- a/arch/arm/kvm/init.S +++ b/arch/arm/kvm/init.S @@ -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 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html