[RFC PATCH v1] Arm64: introduce __hyp_func_call

Arun Chandran achandran at mvista.com
Tue Sep 2 07:39:24 PDT 2014


This adds a mechanism to __hyp_stub_vectors to allow a hypercall to
call a function at EL2. It is needed for users who want to
run a part of code with EL2 permissions. The current usecase is for
KVM and kexec.

For kexec we need to move the final CPU up to the mode it started
in before we branch to the new kernel. If we don't do that

* We loose EL2 in the next boot
* Arm64 bootwrapper may not be able to put CPUs at the spin-table
  code. Bootwrapper expects the final jump from kernel to cpu-return-addr
  to be done in EL2.

KVM can use this to set/get VBAR_EL2

Signed-off-by: Arun Chandran <achandran at mvista.com>

---
* It is the codification of idea from "Mark Rutland <mark.rutland at arm.com>"
  http://lists.infradead.org/pipermail/linux-arm-kernel/2014-August/280026.html

* v1
  removed the #define method for __hyp_set/get_vectors
---
---
 arch/arm64/include/asm/virt.h |    2 ++
 arch/arm64/kernel/hyp-stub.S  |   80 +++++++++++++++++++++++++++++++++++------
 2 files changed, 71 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
index 7a5df52..eb98e76 100644
--- a/arch/arm64/include/asm/virt.h
+++ b/arch/arm64/include/asm/virt.h
@@ -37,6 +37,8 @@ extern u32 __boot_cpu_mode[2];
 void __hyp_set_vectors(phys_addr_t phys_vector_base);
 phys_addr_t __hyp_get_vectors(void);
 
+void __hyp_func_call(unsigned long func_addr) __attribute__((noreturn));
+
 /* Reports the availability of HYP mode */
 static inline bool is_hyp_mode_available(void)
 {
diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S
index a272f33..57e519e 100644
--- a/arch/arm64/kernel/hyp-stub.S
+++ b/arch/arm64/kernel/hyp-stub.S
@@ -53,17 +53,24 @@ ENDPROC(__hyp_stub_vectors)
 	.align 11
 
 el1_sync:
-	mrs	x1, esr_el2
-	lsr	x1, x1, #26
-	cmp	x1, #0x16
+	mrs	x5, esr_el2
+	lsr	x5, x5, #26
+	cmp	x5, #0x16
 	b.ne	2f				// Not an HVC trap
-	cbz	x0, 1f
-	msr	vbar_el2, x0			// Set vbar_el2
-	b	2f
-1:	mrs	x0, vbar_el2			// Return vbar_el2
+
+	adr	x5, 3f
+	ldr	x5, [x5]
+	cmp	x5, x7
+	b.ne	1f
+
+	adr	x7, __hyp_func_entry		// EQ-> it is a __hyp_func_entry
+1:	blr	x7 				// Jump to the function
 2:	eret
 ENDPROC(el1_sync)
 
+	.align	3
+3:	.quad	__hyp_func_entry
+
 .macro invalid_vector	label
 \label:
 	b \label
@@ -98,13 +105,64 @@ ENDPROC(\label)
  * When you call into your shiny new hypervisor, sp_el2 will contain junk,
  * so you will need to set that to something sensible at the new hypervisor's
  * initialisation entry point.
+ *
+ * For functions like __hyp_get_vectors, __hyp_set_vectors we
+ * use a two step jumping. After switching mode to EL2 it will first
+ * goto __hyp_func_entry; then address of the next function to
+ * jump to is calculated from the vitrual address contained in x6
  */
 
 ENTRY(__hyp_get_vectors)
-	mov	x0, xzr
-	// fall through
-ENTRY(__hyp_set_vectors)
-	hvc	#0
+	mrs	x5, CurrentEL
+	cmp	x5, #CurrentEL_EL2
+	b.ne	1f
+	mrs	x0, vbar_el2			// Return vbar_el2
+	ret
+1:
+	adr	x6, __hyp_get_vectors
+	adr	x7, __hyp_func_entry
+	mov	x19, x30			// Save lr in x19 / elr_el1??
+	hvc	#0				// Hyp call
+	mov	x30, x19
 	ret
 ENDPROC(__hyp_get_vectors)
+
+ENTRY(__hyp_set_vectors)
+	mrs	x5, CurrentEL
+	cmp	x5, #CurrentEL_EL2
+	b.ne	1f
+	msr	vbar_el2, x0
+	ret
+1:
+	adr	x6, __hyp_set_vectors
+	adr	x7, __hyp_func_entry
+	mov	x19, x30			// Save lr in x19 / elr_el1??
+	hvc	#0				// Hyp call
+	mov	x30, x19
+	ret
 ENDPROC(__hyp_set_vectors)
+
+/*
+ * x5, x7 is used as temporary registers
+ * x6 contains the virtual address of funtion we need to jump into
+ */
+ENTRY(__hyp_func_entry)
+	adr	x5, 1f
+	ldr	x7, [x5]
+	sub	x5, x5, x7
+	add	x6, x6, x5
+
+	br	x6
+ENDPROC(__hyp_func_entry)
+
+	.align	3
+1:	.quad	.
+
+/*
+ * Users like kexec can call this function directly by filling
+ * x7 with the physical address of the funtion to jump into.
+ */
+ENTRY(__hyp_func_call)
+	hvc	#0
+	ret
+ENDPROC(__hyp_func_call)
-- 
1.7.9.5




More information about the linux-arm-kernel mailing list