xref: /linux/arch/arm64/kernel/hyp-stub.S (revision 26fbb4c8c7c3ee9a4c3b4de555a8587b5a19154e)
1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * Hypervisor stub
4 *
5 * Copyright (C) 2012 ARM Ltd.
6 * Author:	Marc Zyngier <marc.zyngier@arm.com>
7 */
8
9#include <linux/init.h>
10#include <linux/linkage.h>
11#include <linux/irqchip/arm-gic-v3.h>
12
13#include <asm/assembler.h>
14#include <asm/kvm_arm.h>
15#include <asm/kvm_asm.h>
16#include <asm/ptrace.h>
17#include <asm/virt.h>
18
19	.text
20	.pushsection	.hyp.text, "ax"
21
22	.align 11
23
24SYM_CODE_START(__hyp_stub_vectors)
25	ventry	el2_sync_invalid		// Synchronous EL2t
26	ventry	el2_irq_invalid			// IRQ EL2t
27	ventry	el2_fiq_invalid			// FIQ EL2t
28	ventry	el2_error_invalid		// Error EL2t
29
30	ventry	el2_sync_invalid		// Synchronous EL2h
31	ventry	el2_irq_invalid			// IRQ EL2h
32	ventry	el2_fiq_invalid			// FIQ EL2h
33	ventry	el2_error_invalid		// Error EL2h
34
35	ventry	el1_sync			// Synchronous 64-bit EL1
36	ventry	el1_irq_invalid			// IRQ 64-bit EL1
37	ventry	el1_fiq_invalid			// FIQ 64-bit EL1
38	ventry	el1_error_invalid		// Error 64-bit EL1
39
40	ventry	el1_sync_invalid		// Synchronous 32-bit EL1
41	ventry	el1_irq_invalid			// IRQ 32-bit EL1
42	ventry	el1_fiq_invalid			// FIQ 32-bit EL1
43	ventry	el1_error_invalid		// Error 32-bit EL1
44SYM_CODE_END(__hyp_stub_vectors)
45
46	.align 11
47
48SYM_CODE_START_LOCAL(el1_sync)
49	cmp	x0, #HVC_SET_VECTORS
50	b.ne	2f
51	msr	vbar_el2, x1
52	b	9f
53
542:	cmp	x0, #HVC_SOFT_RESTART
55	b.ne	3f
56	mov	x0, x2
57	mov	x2, x4
58	mov	x4, x1
59	mov	x1, x3
60	br	x4				// no return
61
623:	cmp	x0, #HVC_RESET_VECTORS
63	beq	9f				// Nothing to reset!
64
65	/* Someone called kvm_call_hyp() against the hyp-stub... */
66	mov_q	x0, HVC_STUB_ERR
67	eret
68
699:	mov	x0, xzr
70	eret
71SYM_CODE_END(el1_sync)
72
73.macro invalid_vector	label
74SYM_CODE_START_LOCAL(\label)
75	b \label
76SYM_CODE_END(\label)
77.endm
78
79	invalid_vector	el2_sync_invalid
80	invalid_vector	el2_irq_invalid
81	invalid_vector	el2_fiq_invalid
82	invalid_vector	el2_error_invalid
83	invalid_vector	el1_sync_invalid
84	invalid_vector	el1_irq_invalid
85	invalid_vector	el1_fiq_invalid
86	invalid_vector	el1_error_invalid
87
88/*
89 * __hyp_set_vectors: Call this after boot to set the initial hypervisor
90 * vectors as part of hypervisor installation.  On an SMP system, this should
91 * be called on each CPU.
92 *
93 * x0 must be the physical address of the new vector table, and must be
94 * 2KB aligned.
95 *
96 * Before calling this, you must check that the stub hypervisor is installed
97 * everywhere, by waiting for any secondary CPUs to be brought up and then
98 * checking that is_hyp_mode_available() is true.
99 *
100 * If not, there is a pre-existing hypervisor, some CPUs failed to boot, or
101 * something else went wrong... in such cases, trying to install a new
102 * hypervisor is unlikely to work as desired.
103 *
104 * When you call into your shiny new hypervisor, sp_el2 will contain junk,
105 * so you will need to set that to something sensible at the new hypervisor's
106 * initialisation entry point.
107 */
108
109SYM_FUNC_START(__hyp_set_vectors)
110	mov	x1, x0
111	mov	x0, #HVC_SET_VECTORS
112	hvc	#0
113	ret
114SYM_FUNC_END(__hyp_set_vectors)
115
116SYM_FUNC_START(__hyp_reset_vectors)
117	mov	x0, #HVC_RESET_VECTORS
118	hvc	#0
119	ret
120SYM_FUNC_END(__hyp_reset_vectors)
121