xref: /openbmc/linux/arch/arm64/kvm/hyp/hyp-entry.S (revision b881cdce77b48bd488f268041f32951bab89bb0f)
1caab277bSThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-only */
22b28162cSMarc Zyngier/*
3e8b22d0fSMarc Zyngier * Copyright (C) 2015-2018 - ARM Ltd
42b28162cSMarc Zyngier * Author: Marc Zyngier <marc.zyngier@arm.com>
52b28162cSMarc Zyngier */
62b28162cSMarc Zyngier
7f72af90cSMarc Zyngier#include <linux/arm-smccc.h>
82b28162cSMarc Zyngier#include <linux/linkage.h>
92b28162cSMarc Zyngier
102b28162cSMarc Zyngier#include <asm/alternative.h>
112b28162cSMarc Zyngier#include <asm/assembler.h>
122b28162cSMarc Zyngier#include <asm/cpufeature.h>
132b28162cSMarc Zyngier#include <asm/kvm_arm.h>
142b28162cSMarc Zyngier#include <asm/kvm_asm.h>
15e8b22d0fSMarc Zyngier#include <asm/mmu.h>
166279017eSWill Deacon#include <asm/spectre.h>
172b28162cSMarc Zyngier
18e9ee186bSJames Morse.macro save_caller_saved_regs_vect
19e9ee186bSJames Morse	/* x0 and x1 were saved in the vector entry */
20e9ee186bSJames Morse	stp	x2, x3,   [sp, #-16]!
21e9ee186bSJames Morse	stp	x4, x5,   [sp, #-16]!
22e9ee186bSJames Morse	stp	x6, x7,   [sp, #-16]!
23e9ee186bSJames Morse	stp	x8, x9,   [sp, #-16]!
24e9ee186bSJames Morse	stp	x10, x11, [sp, #-16]!
25e9ee186bSJames Morse	stp	x12, x13, [sp, #-16]!
26e9ee186bSJames Morse	stp	x14, x15, [sp, #-16]!
27e9ee186bSJames Morse	stp	x16, x17, [sp, #-16]!
28e9ee186bSJames Morse.endm
29e9ee186bSJames Morse
30e9ee186bSJames Morse.macro restore_caller_saved_regs_vect
31e9ee186bSJames Morse	ldp	x16, x17, [sp], #16
32e9ee186bSJames Morse	ldp	x14, x15, [sp], #16
33e9ee186bSJames Morse	ldp	x12, x13, [sp], #16
34e9ee186bSJames Morse	ldp	x10, x11, [sp], #16
35e9ee186bSJames Morse	ldp	x8, x9,   [sp], #16
36e9ee186bSJames Morse	ldp	x6, x7,   [sp], #16
37e9ee186bSJames Morse	ldp	x4, x5,   [sp], #16
38e9ee186bSJames Morse	ldp	x2, x3,   [sp], #16
39e9ee186bSJames Morse	ldp	x0, x1,   [sp], #16
40e9ee186bSJames Morse.endm
41e9ee186bSJames Morse
422b28162cSMarc Zyngier	.text
432b28162cSMarc Zyngier
442b28162cSMarc Zyngierel1_sync:				// Guest trapped into EL2
452b28162cSMarc Zyngier
464464e210SChristoffer Dall	mrs	x0, esr_el2
474464e210SChristoffer Dall	lsr	x0, x0, #ESR_ELx_EC_SHIFT
4868381b2bSShanker Donthineni	cmp	x0, #ESR_ELx_EC_HVC64
49f72af90cSMarc Zyngier	ccmp	x0, #ESR_ELx_EC_HVC32, #4, ne
502b28162cSMarc Zyngier	b.ne	el1_trap
512b28162cSMarc Zyngier
52f72af90cSMarc Zyngier	/*
53f72af90cSMarc Zyngier	 * Fastest possible path for ARM_SMCCC_ARCH_WORKAROUND_1.
54f72af90cSMarc Zyngier	 * The workaround has already been applied on the host,
55f72af90cSMarc Zyngier	 * so let's quickly get back to the guest. We don't bother
56f72af90cSMarc Zyngier	 * restoring x1, as it can be clobbered anyway.
57f72af90cSMarc Zyngier	 */
58f72af90cSMarc Zyngier	ldr	x1, [sp]				// Guest's x0
59f72af90cSMarc Zyngier	eor	w1, w1, #ARM_SMCCC_ARCH_WORKAROUND_1
60b4f18c06SMarc Zyngier	cbz	w1, wa_epilogue
61b4f18c06SMarc Zyngier
62b4f18c06SMarc Zyngier	/* ARM_SMCCC_ARCH_WORKAROUND_2 handling */
63b4f18c06SMarc Zyngier	eor	w1, w1, #(ARM_SMCCC_ARCH_WORKAROUND_1 ^ \
64b4f18c06SMarc Zyngier			  ARM_SMCCC_ARCH_WORKAROUND_2)
65f72af90cSMarc Zyngier	cbnz	w1, el1_trap
66b4f18c06SMarc Zyngier
67b4f18c06SMarc Zyngierwa_epilogue:
68b4f18c06SMarc Zyngier	mov	x0, xzr
69f72af90cSMarc Zyngier	add	sp, sp, #16
70f72af90cSMarc Zyngier	eret
71679db708SWill Deacon	sb
72f72af90cSMarc Zyngier
732b28162cSMarc Zyngierel1_trap:
744464e210SChristoffer Dall	get_vcpu_ptr	x1, x0
7568381b2bSShanker Donthineni	mov	x0, #ARM_EXCEPTION_TRAP
762b28162cSMarc Zyngier	b	__guest_exit
772b28162cSMarc Zyngier
782b28162cSMarc Zyngierel1_irq:
794464e210SChristoffer Dall	get_vcpu_ptr	x1, x0
8068381b2bSShanker Donthineni	mov	x0, #ARM_EXCEPTION_IRQ
812b28162cSMarc Zyngier	b	__guest_exit
822b28162cSMarc Zyngier
831b51e5faSMarc Zyngierel1_error:
844464e210SChristoffer Dall	get_vcpu_ptr	x1, x0
851b51e5faSMarc Zyngier	mov	x0, #ARM_EXCEPTION_EL1_SERROR
861b51e5faSMarc Zyngier	b	__guest_exit
871b51e5faSMarc Zyngier
88e4e11cc0SChristoffer Dallel2_sync:
8988a84cccSJames Morse	/* Check for illegal exception return */
90e4e11cc0SChristoffer Dall	mrs	x0, spsr_el2
9188a84cccSJames Morse	tbnz	x0, #20, 1f
92e4e11cc0SChristoffer Dall
9388a84cccSJames Morse	save_caller_saved_regs_vect
9488a84cccSJames Morse	stp     x29, x30, [sp, #-16]!
9588a84cccSJames Morse	bl	kvm_unexpected_el2_exception
9688a84cccSJames Morse	ldp     x29, x30, [sp], #16
9788a84cccSJames Morse	restore_caller_saved_regs_vect
98e4e11cc0SChristoffer Dall
9988a84cccSJames Morse	eret
10088a84cccSJames Morse
10188a84cccSJames Morse1:
102e4e11cc0SChristoffer Dall	/* Let's attempt a recovery from the illegal exception return */
103e4e11cc0SChristoffer Dall	get_vcpu_ptr	x1, x0
104e4e11cc0SChristoffer Dall	mov	x0, #ARM_EXCEPTION_IL
105e4e11cc0SChristoffer Dall	b	__guest_exit
106e4e11cc0SChristoffer Dall
107e4e11cc0SChristoffer Dall
108395ea79eSMarc Zyngierel2_error:
109e9ee186bSJames Morse	save_caller_saved_regs_vect
110e9ee186bSJames Morse	stp     x29, x30, [sp, #-16]!
1117e80f637SMarc Zyngier
112e9ee186bSJames Morse	bl	kvm_unexpected_el2_exception
113e9ee186bSJames Morse
114e9ee186bSJames Morse	ldp     x29, x30, [sp], #16
115e9ee186bSJames Morse	restore_caller_saved_regs_vect
116e9ee186bSJames Morse
117395ea79eSMarc Zyngier	eret
118679db708SWill Deacon	sb
119395ea79eSMarc Zyngier
1207db21530SAndrew Scull.macro invalid_vector	label, target = __guest_exit_panic
1212b28162cSMarc Zyngier	.align	2
122617a2f39SMark BrownSYM_CODE_START(\label)
1232b28162cSMarc Zyngier	b \target
124617a2f39SMark BrownSYM_CODE_END(\label)
1252b28162cSMarc Zyngier.endm
1262b28162cSMarc Zyngier
1272b28162cSMarc Zyngier	/* None of these should ever happen */
1282b28162cSMarc Zyngier	invalid_vector	el2t_sync_invalid
1292b28162cSMarc Zyngier	invalid_vector	el2t_irq_invalid
1302b28162cSMarc Zyngier	invalid_vector	el2t_fiq_invalid
1312b28162cSMarc Zyngier	invalid_vector	el2t_error_invalid
1322b28162cSMarc Zyngier	invalid_vector	el2h_irq_invalid
1332b28162cSMarc Zyngier	invalid_vector	el2h_fiq_invalid
1342b28162cSMarc Zyngier	invalid_vector	el1_fiq_invalid
1352b28162cSMarc Zyngier
1362b28162cSMarc Zyngier	.ltorg
1372b28162cSMarc Zyngier
1382b28162cSMarc Zyngier	.align 11
1392b28162cSMarc Zyngier
1403dbf100bSJames Morse.macro check_preamble_length start, end
1413dbf100bSJames Morse/* kvm_patch_vector_branch() generates code that jumps over the preamble. */
1423dbf100bSJames Morse.if ((\end-\start) != KVM_VECTOR_PREAMBLE)
1433dbf100bSJames Morse	.error "KVM vector preamble length mismatch"
1443dbf100bSJames Morse.endif
1453dbf100bSJames Morse.endm
1463dbf100bSJames Morse
1477e80f637SMarc Zyngier.macro valid_vect target
1487e80f637SMarc Zyngier	.align 7
1493dbf100bSJames Morse661:
1500e5b9c08SJames Morse	esb
1517e80f637SMarc Zyngier	stp	x0, x1, [sp, #-16]!
1523dbf100bSJames Morse662:
1537e80f637SMarc Zyngier	b	\target
1543dbf100bSJames Morse
1553dbf100bSJames Morsecheck_preamble_length 661b, 662b
1567e80f637SMarc Zyngier.endm
1577e80f637SMarc Zyngier
1587e80f637SMarc Zyngier.macro invalid_vect target
1597e80f637SMarc Zyngier	.align 7
1603dbf100bSJames Morse661:
1610e5b9c08SJames Morse	nop
1627db21530SAndrew Scull	stp	x0, x1, [sp, #-16]!
1633dbf100bSJames Morse662:
16471dcb8beSMarc Zyngier	b	\target
1653dbf100bSJames Morse
1663dbf100bSJames Morsecheck_preamble_length 661b, 662b
1677e80f637SMarc Zyngier.endm
1687e80f637SMarc Zyngier
169617a2f39SMark BrownSYM_CODE_START(__kvm_hyp_vector)
1707e80f637SMarc Zyngier	invalid_vect	el2t_sync_invalid	// Synchronous EL2t
1717e80f637SMarc Zyngier	invalid_vect	el2t_irq_invalid	// IRQ EL2t
1727e80f637SMarc Zyngier	invalid_vect	el2t_fiq_invalid	// FIQ EL2t
1737e80f637SMarc Zyngier	invalid_vect	el2t_error_invalid	// Error EL2t
1742b28162cSMarc Zyngier
175e4e11cc0SChristoffer Dall	valid_vect	el2_sync		// Synchronous EL2h
1767e80f637SMarc Zyngier	invalid_vect	el2h_irq_invalid	// IRQ EL2h
1777e80f637SMarc Zyngier	invalid_vect	el2h_fiq_invalid	// FIQ EL2h
1787e80f637SMarc Zyngier	valid_vect	el2_error		// Error EL2h
1792b28162cSMarc Zyngier
1807e80f637SMarc Zyngier	valid_vect	el1_sync		// Synchronous 64-bit EL1
1817e80f637SMarc Zyngier	valid_vect	el1_irq			// IRQ 64-bit EL1
1827e80f637SMarc Zyngier	invalid_vect	el1_fiq_invalid		// FIQ 64-bit EL1
1837e80f637SMarc Zyngier	valid_vect	el1_error		// Error 64-bit EL1
1842b28162cSMarc Zyngier
1857e80f637SMarc Zyngier	valid_vect	el1_sync		// Synchronous 32-bit EL1
1867e80f637SMarc Zyngier	valid_vect	el1_irq			// IRQ 32-bit EL1
1877e80f637SMarc Zyngier	invalid_vect	el1_fiq_invalid		// FIQ 32-bit EL1
1887e80f637SMarc Zyngier	valid_vect	el1_error		// Error 32-bit EL1
189617a2f39SMark BrownSYM_CODE_END(__kvm_hyp_vector)
190e8b22d0fSMarc Zyngier
191*b881cdceSWill Deacon.macro spectrev2_smccc_wa1_smc
192*b881cdceSWill Deacon	sub	sp, sp, #(8 * 4)
193*b881cdceSWill Deacon	stp	x2, x3, [sp, #(8 * 0)]
194*b881cdceSWill Deacon	stp	x0, x1, [sp, #(8 * 2)]
195*b881cdceSWill Deacon	mov	w0, #ARM_SMCCC_ARCH_WORKAROUND_1
196*b881cdceSWill Deacon	smc	#0
197*b881cdceSWill Deacon	ldp	x2, x3, [sp, #(8 * 0)]
198*b881cdceSWill Deacon	add	sp, sp, #(8 * 2)
199*b881cdceSWill Deacon.endm
200*b881cdceSWill Deacon
201*b881cdceSWill Deacon.macro hyp_ventry	indirect, spectrev2
202e8b22d0fSMarc Zyngier	.align	7
2030e5b9c08SJames Morse1:	esb
204*b881cdceSWill Deacon	.if \spectrev2 != 0
205*b881cdceSWill Deacon	spectrev2_smccc_wa1_smc
206*b881cdceSWill Deacon	.else
207*b881cdceSWill Deacon	stp	x0, x1, [sp, #-16]!
208*b881cdceSWill Deacon	.endif
209*b881cdceSWill Deacon	.if \indirect != 0
210*b881cdceSWill Deacon	alternative_cb  kvm_patch_vector_branch
211e8b22d0fSMarc Zyngier	/*
212*b881cdceSWill Deacon	 * For ARM64_HARDEN_EL2_VECTORS configurations, these NOPs get replaced
213e8b22d0fSMarc Zyngier	 * with:
214e8b22d0fSMarc Zyngier	 *
215e8b22d0fSMarc Zyngier	 * movz	x0, #(addr & 0xffff)
216e8b22d0fSMarc Zyngier	 * movk	x0, #((addr >> 16) & 0xffff), lsl #16
217e8b22d0fSMarc Zyngier	 * movk	x0, #((addr >> 32) & 0xffff), lsl #32
218e8b22d0fSMarc Zyngier	 * br	x0
219e8b22d0fSMarc Zyngier	 *
2203dbf100bSJames Morse	 * Where:
2213dbf100bSJames Morse	 * addr = kern_hyp_va(__kvm_hyp_vector) + vector-offset + KVM_VECTOR_PREAMBLE.
222e8b22d0fSMarc Zyngier	 * See kvm_patch_vector_branch for details.
223e8b22d0fSMarc Zyngier	 */
224*b881cdceSWill Deacon	nop
225e8b22d0fSMarc Zyngier	nop
226e8b22d0fSMarc Zyngier	nop
227e8b22d0fSMarc Zyngier	nop
228e8b22d0fSMarc Zyngier	alternative_cb_end
229*b881cdceSWill Deacon	.endif
230*b881cdceSWill Deacon	b	__kvm_hyp_vector + (1b - 0b + KVM_VECTOR_PREAMBLE)
231e8b22d0fSMarc Zyngier.endm
232e8b22d0fSMarc Zyngier
233*b881cdceSWill Deacon.macro generate_vectors	indirect, spectrev2
234e8b22d0fSMarc Zyngier0:
235e8b22d0fSMarc Zyngier	.rept 16
236*b881cdceSWill Deacon	hyp_ventry	\indirect, \spectrev2
237e8b22d0fSMarc Zyngier	.endr
238e8b22d0fSMarc Zyngier	.org 0b + SZ_2K		// Safety measure
239e8b22d0fSMarc Zyngier.endm
240e8b22d0fSMarc Zyngier
241e8b22d0fSMarc Zyngier	.align	11
2426e52aab9SMark BrownSYM_CODE_START(__bp_harden_hyp_vecs)
243*b881cdceSWill Deacon	generate_vectors indirect = 0, spectrev2 = 0 // HYP_VECTOR_DIRECT
244*b881cdceSWill Deacon	generate_vectors indirect = 0, spectrev2 = 1 // HYP_VECTOR_SPECTRE_DIRECT
245*b881cdceSWill Deacon	generate_vectors indirect = 1, spectrev2 = 0 // HYP_VECTOR_INDIRECT
246*b881cdceSWill Deacon	generate_vectors indirect = 1, spectrev2 = 1 // HYP_VECTOR_SPECTRE_INDIRECT
2476e52aab9SMark Brown1:	.org __bp_harden_hyp_vecs + __BP_HARDEN_HYP_VECS_SZ
2486e52aab9SMark Brown	.org 1b
2496e52aab9SMark BrownSYM_CODE_END(__bp_harden_hyp_vecs)
250