linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v1] Arm64: introduce __hyp_func_call
@ 2014-09-02 14:39 Arun Chandran
  2014-09-02 16:18 ` Geoff Levand
  0 siblings, 1 reply; 2+ messages in thread
From: Arun Chandran @ 2014-09-02 14:39 UTC (permalink / raw)
  To: linux-arm-kernel

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@mvista.com>

---
* It is the codification of idea from "Mark Rutland <mark.rutland@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

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [RFC PATCH v1] Arm64: introduce __hyp_func_call
  2014-09-02 14:39 [RFC PATCH v1] Arm64: introduce __hyp_func_call Arun Chandran
@ 2014-09-02 16:18 ` Geoff Levand
  0 siblings, 0 replies; 2+ messages in thread
From: Geoff Levand @ 2014-09-02 16:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Arun,

On Tue, 2014-09-02 at 20:09 +0530, Arun Chandran wrote:
> 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

I certainly appreciate you trying to help with the kexec work, but I
already have a patch that does something similar to this in my kexec
series [1].

Also, I think we need to consider this change in the context of the
entire solution around how we handle exception level and kexec + KVM.
I'm now working through the details of that, and when I have something I
think is acceptable I'll post the kexec series for review.

[1] https://git.linaro.org/people/geoff.levand/linux-kexec.git

-Geoff

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2014-09-02 16:18 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-09-02 14:39 [RFC PATCH v1] Arm64: introduce __hyp_func_call Arun Chandran
2014-09-02 16:18 ` Geoff Levand

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).