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 at arm.com> --- arch/arm/include/asm/kvm_asm.h | 5 ----- arch/arm/kvm/arm.c | 29 ++++++++++++----------------- arch/arm/kvm/init.S | 5 +++++ arch/arm/kvm/interrupts.S | 12 ++++++++++++ 4 files changed, 29 insertions(+), 22 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 cf9ca42..18c5ba3 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -780,21 +780,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) @@ -802,23 +798,29 @@ 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; + /* Switch from the HYP stub to our own HYP init vector */ cpu_set_vector(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. */ 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"); } /** @@ -899,13 +901,6 @@ static int init_hyp_mode(void) if (err) goto out_free_mappings; - /* - * 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); - return 0; out_free_mappings: free_hyp_pmds(); diff --git a/arch/arm/kvm/init.S b/arch/arm/kvm/init.S index 10ecdf9..8a29b8f 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 @@ -113,6 +114,10 @@ __do_hyp_init: @ Set stack pointer and return to the kernel pop {r0, r1, r2, r12} mov sp, r1 + + @ Set HVBAR to point to the HYP vectors + mcr p15, 4, r2, c12, c0, 0 @ HVBAR + eret .ltorg diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S index eb26870..c79c6a8 100644 --- a/arch/arm/kvm/interrupts.S +++ b/arch/arm/kvm/interrupts.S @@ -710,6 +710,18 @@ 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 + + pop {r0, r1, r2} + mcr p15, 4, r0, c12, c0, 0 @ HVBAR + eret + +host_switch_to_hyp: @ Store lr_usr,spsr (svc cpsr) on bottom of stack mov r1, sp bic r1, r1, #0x0ff -- 1.7.10.3