xref: /openbmc/linux/arch/arm64/kvm/hyp/hyp-entry.S (revision 53fd5b6487e4438049a5da5e36dfb8edcf1fd789)
12b28162cSMarc Zyngier/*
22b28162cSMarc Zyngier * Copyright (C) 2015 - ARM Ltd
32b28162cSMarc Zyngier * Author: Marc Zyngier <marc.zyngier@arm.com>
42b28162cSMarc Zyngier *
52b28162cSMarc Zyngier * This program is free software; you can redistribute it and/or modify
62b28162cSMarc Zyngier * it under the terms of the GNU General Public License version 2 as
72b28162cSMarc Zyngier * published by the Free Software Foundation.
82b28162cSMarc Zyngier *
92b28162cSMarc Zyngier * This program is distributed in the hope that it will be useful,
102b28162cSMarc Zyngier * but WITHOUT ANY WARRANTY; without even the implied warranty of
112b28162cSMarc Zyngier * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
122b28162cSMarc Zyngier * GNU General Public License for more details.
132b28162cSMarc Zyngier *
142b28162cSMarc Zyngier * You should have received a copy of the GNU General Public License
152b28162cSMarc Zyngier * along with this program.  If not, see <http://www.gnu.org/licenses/>.
162b28162cSMarc Zyngier */
172b28162cSMarc Zyngier
182b28162cSMarc Zyngier#include <linux/linkage.h>
192b28162cSMarc Zyngier
202b28162cSMarc Zyngier#include <asm/alternative.h>
212b28162cSMarc Zyngier#include <asm/assembler.h>
222b28162cSMarc Zyngier#include <asm/asm-offsets.h>
232b28162cSMarc Zyngier#include <asm/cpufeature.h>
242b28162cSMarc Zyngier#include <asm/kvm_arm.h>
252b28162cSMarc Zyngier#include <asm/kvm_asm.h>
262b28162cSMarc Zyngier#include <asm/kvm_mmu.h>
272b28162cSMarc Zyngier
282b28162cSMarc Zyngier	.text
292b28162cSMarc Zyngier	.pushsection	.hyp.text, "ax"
302b28162cSMarc Zyngier
312b28162cSMarc Zyngier.macro	save_x0_to_x3
322b28162cSMarc Zyngier	stp	x0, x1, [sp, #-16]!
332b28162cSMarc Zyngier	stp	x2, x3, [sp, #-16]!
342b28162cSMarc Zyngier.endm
352b28162cSMarc Zyngier
362b28162cSMarc Zyngier.macro	restore_x0_to_x3
372b28162cSMarc Zyngier	ldp	x2, x3, [sp], #16
382b28162cSMarc Zyngier	ldp	x0, x1, [sp], #16
392b28162cSMarc Zyngier.endm
402b28162cSMarc Zyngier
412b28162cSMarc Zyngierel1_sync:				// Guest trapped into EL2
422b28162cSMarc Zyngier	save_x0_to_x3
432b28162cSMarc Zyngier
442b28162cSMarc Zyngier	mrs	x1, esr_el2
452b28162cSMarc Zyngier	lsr	x2, x1, #ESR_ELx_EC_SHIFT
462b28162cSMarc Zyngier
472b28162cSMarc Zyngier	cmp	x2, #ESR_ELx_EC_HVC64
482b28162cSMarc Zyngier	b.ne	el1_trap
492b28162cSMarc Zyngier
502b28162cSMarc Zyngier	mrs	x3, vttbr_el2		// If vttbr is valid, the 64bit guest
512b28162cSMarc Zyngier	cbnz	x3, el1_trap		// called HVC
522b28162cSMarc Zyngier
532b28162cSMarc Zyngier	/* Here, we're pretty sure the host called HVC. */
542b28162cSMarc Zyngier	restore_x0_to_x3
552b28162cSMarc Zyngier
562b28162cSMarc Zyngier	/* Check for __hyp_get_vectors */
572b28162cSMarc Zyngier	cbnz	x0, 1f
582b28162cSMarc Zyngier	mrs	x0, vbar_el2
592b28162cSMarc Zyngier	b	2f
602b28162cSMarc Zyngier
612b28162cSMarc Zyngier1:	stp	lr, xzr, [sp, #-16]!
622b28162cSMarc Zyngier
632b28162cSMarc Zyngier	/*
642b28162cSMarc Zyngier	 * Compute the function address in EL2, and shuffle the parameters.
652b28162cSMarc Zyngier	 */
662b28162cSMarc Zyngier	kern_hyp_va	x0
672b28162cSMarc Zyngier	mov	lr, x0
682b28162cSMarc Zyngier	mov	x0, x1
692b28162cSMarc Zyngier	mov	x1, x2
702b28162cSMarc Zyngier	mov	x2, x3
712b28162cSMarc Zyngier	blr	lr
722b28162cSMarc Zyngier
732b28162cSMarc Zyngier	ldp	lr, xzr, [sp], #16
742b28162cSMarc Zyngier2:	eret
752b28162cSMarc Zyngier
762b28162cSMarc Zyngierel1_trap:
772b28162cSMarc Zyngier	/*
782b28162cSMarc Zyngier	 * x1: ESR
792b28162cSMarc Zyngier	 * x2: ESR_EC
802b28162cSMarc Zyngier	 */
812b28162cSMarc Zyngier
822b28162cSMarc Zyngier	/* Guest accessed VFP/SIMD registers, save host, restore Guest */
832b28162cSMarc Zyngier	cmp	x2, #ESR_ELx_EC_FP_ASIMD
842b28162cSMarc Zyngier	b.eq	__fpsimd_guest_restore
852b28162cSMarc Zyngier
862b28162cSMarc Zyngier	cmp	x2, #ESR_ELx_EC_DABT_LOW
872b28162cSMarc Zyngier	mov	x0, #ESR_ELx_EC_IABT_LOW
882b28162cSMarc Zyngier	ccmp	x2, x0, #4, ne
892b28162cSMarc Zyngier	b.ne	1f		// Not an abort we care about
902b28162cSMarc Zyngier
912b28162cSMarc Zyngier	/* This is an abort. Check for permission fault */
922b28162cSMarc Zyngieralternative_if_not ARM64_WORKAROUND_834220
932b28162cSMarc Zyngier	and	x2, x1, #ESR_ELx_FSC_TYPE
942b28162cSMarc Zyngier	cmp	x2, #FSC_PERM
952b28162cSMarc Zyngier	b.ne	1f		// Not a permission fault
962b28162cSMarc Zyngieralternative_else
972b28162cSMarc Zyngier	nop			// Use the permission fault path to
982b28162cSMarc Zyngier	nop			// check for a valid S1 translation,
992b28162cSMarc Zyngier	nop			// regardless of the ESR value.
1002b28162cSMarc Zyngieralternative_endif
1012b28162cSMarc Zyngier
1022b28162cSMarc Zyngier	/*
1032b28162cSMarc Zyngier	 * Check for Stage-1 page table walk, which is guaranteed
1042b28162cSMarc Zyngier	 * to give a valid HPFAR_EL2.
1052b28162cSMarc Zyngier	 */
1062b28162cSMarc Zyngier	tbnz	x1, #7, 1f	// S1PTW is set
1072b28162cSMarc Zyngier
1082b28162cSMarc Zyngier	/* Preserve PAR_EL1 */
1092b28162cSMarc Zyngier	mrs	x3, par_el1
1102b28162cSMarc Zyngier	stp	x3, xzr, [sp, #-16]!
1112b28162cSMarc Zyngier
1122b28162cSMarc Zyngier	/*
1132b28162cSMarc Zyngier	 * Permission fault, HPFAR_EL2 is invalid.
1142b28162cSMarc Zyngier	 * Resolve the IPA the hard way using the guest VA.
1152b28162cSMarc Zyngier	 * Stage-1 translation already validated the memory access rights.
1162b28162cSMarc Zyngier	 * As such, we can use the EL1 translation regime, and don't have
1172b28162cSMarc Zyngier	 * to distinguish between EL0 and EL1 access.
1182b28162cSMarc Zyngier	 */
1192b28162cSMarc Zyngier	mrs	x2, far_el2
1202b28162cSMarc Zyngier	at	s1e1r, x2
1212b28162cSMarc Zyngier	isb
1222b28162cSMarc Zyngier
1232b28162cSMarc Zyngier	/* Read result */
1242b28162cSMarc Zyngier	mrs	x3, par_el1
1252b28162cSMarc Zyngier	ldp	x0, xzr, [sp], #16	// Restore PAR_EL1 from the stack
1262b28162cSMarc Zyngier	msr	par_el1, x0
1272b28162cSMarc Zyngier	tbnz	x3, #0, 3f		// Bail out if we failed the translation
1282b28162cSMarc Zyngier	ubfx	x3, x3, #12, #36	// Extract IPA
1292b28162cSMarc Zyngier	lsl	x3, x3, #4		// and present it like HPFAR
1302b28162cSMarc Zyngier	b	2f
1312b28162cSMarc Zyngier
1322b28162cSMarc Zyngier1:	mrs	x3, hpfar_el2
1332b28162cSMarc Zyngier	mrs	x2, far_el2
1342b28162cSMarc Zyngier
1352b28162cSMarc Zyngier2:	mrs	x0, tpidr_el2
1362b28162cSMarc Zyngier	str	w1, [x0, #VCPU_ESR_EL2]
1372b28162cSMarc Zyngier	str	x2, [x0, #VCPU_FAR_EL2]
1382b28162cSMarc Zyngier	str	x3, [x0, #VCPU_HPFAR_EL2]
1392b28162cSMarc Zyngier
1402b28162cSMarc Zyngier	mov	x1, #ARM_EXCEPTION_TRAP
1412b28162cSMarc Zyngier	b	__guest_exit
1422b28162cSMarc Zyngier
1432b28162cSMarc Zyngier	/*
1442b28162cSMarc Zyngier	 * Translation failed. Just return to the guest and
1452b28162cSMarc Zyngier	 * let it fault again. Another CPU is probably playing
1462b28162cSMarc Zyngier	 * behind our back.
1472b28162cSMarc Zyngier	 */
1482b28162cSMarc Zyngier3:	restore_x0_to_x3
1492b28162cSMarc Zyngier
1502b28162cSMarc Zyngier	eret
1512b28162cSMarc Zyngier
1522b28162cSMarc Zyngierel1_irq:
1532b28162cSMarc Zyngier	save_x0_to_x3
1542b28162cSMarc Zyngier	mrs	x0, tpidr_el2
1552b28162cSMarc Zyngier	mov	x1, #ARM_EXCEPTION_IRQ
1562b28162cSMarc Zyngier	b	__guest_exit
1572b28162cSMarc Zyngier
158*53fd5b64SMarc ZyngierENTRY(__hyp_do_panic)
159*53fd5b64SMarc Zyngier	mov	lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
160*53fd5b64SMarc Zyngier		      PSR_MODE_EL1h)
161*53fd5b64SMarc Zyngier	msr	spsr_el2, lr
162*53fd5b64SMarc Zyngier	ldr	lr, =panic
163*53fd5b64SMarc Zyngier	msr	elr_el2, lr
164*53fd5b64SMarc Zyngier	eret
165*53fd5b64SMarc ZyngierENDPROC(__hyp_do_panic)
166*53fd5b64SMarc Zyngier
167*53fd5b64SMarc Zyngier.macro invalid_vector	label, target = __hyp_panic
1682b28162cSMarc Zyngier	.align	2
1692b28162cSMarc Zyngier\label:
1702b28162cSMarc Zyngier	b \target
1712b28162cSMarc ZyngierENDPROC(\label)
1722b28162cSMarc Zyngier.endm
1732b28162cSMarc Zyngier
1742b28162cSMarc Zyngier	/* None of these should ever happen */
1752b28162cSMarc Zyngier	invalid_vector	el2t_sync_invalid
1762b28162cSMarc Zyngier	invalid_vector	el2t_irq_invalid
1772b28162cSMarc Zyngier	invalid_vector	el2t_fiq_invalid
1782b28162cSMarc Zyngier	invalid_vector	el2t_error_invalid
1792b28162cSMarc Zyngier	invalid_vector	el2h_sync_invalid
1802b28162cSMarc Zyngier	invalid_vector	el2h_irq_invalid
1812b28162cSMarc Zyngier	invalid_vector	el2h_fiq_invalid
1822b28162cSMarc Zyngier	invalid_vector	el2h_error_invalid
1832b28162cSMarc Zyngier	invalid_vector	el1_sync_invalid
1842b28162cSMarc Zyngier	invalid_vector	el1_irq_invalid
1852b28162cSMarc Zyngier	invalid_vector	el1_fiq_invalid
1862b28162cSMarc Zyngier	invalid_vector	el1_error_invalid
1872b28162cSMarc Zyngier
1882b28162cSMarc Zyngier	.ltorg
1892b28162cSMarc Zyngier
1902b28162cSMarc Zyngier	.align 11
1912b28162cSMarc Zyngier
1922b28162cSMarc ZyngierENTRY(__hyp_vector)
1932b28162cSMarc Zyngier	ventry	el2t_sync_invalid		// Synchronous EL2t
1942b28162cSMarc Zyngier	ventry	el2t_irq_invalid		// IRQ EL2t
1952b28162cSMarc Zyngier	ventry	el2t_fiq_invalid		// FIQ EL2t
1962b28162cSMarc Zyngier	ventry	el2t_error_invalid		// Error EL2t
1972b28162cSMarc Zyngier
1982b28162cSMarc Zyngier	ventry	el2h_sync_invalid		// Synchronous EL2h
1992b28162cSMarc Zyngier	ventry	el2h_irq_invalid		// IRQ EL2h
2002b28162cSMarc Zyngier	ventry	el2h_fiq_invalid		// FIQ EL2h
2012b28162cSMarc Zyngier	ventry	el2h_error_invalid		// Error EL2h
2022b28162cSMarc Zyngier
2032b28162cSMarc Zyngier	ventry	el1_sync			// Synchronous 64-bit EL1
2042b28162cSMarc Zyngier	ventry	el1_irq				// IRQ 64-bit EL1
2052b28162cSMarc Zyngier	ventry	el1_fiq_invalid			// FIQ 64-bit EL1
2062b28162cSMarc Zyngier	ventry	el1_error_invalid		// Error 64-bit EL1
2072b28162cSMarc Zyngier
2082b28162cSMarc Zyngier	ventry	el1_sync			// Synchronous 32-bit EL1
2092b28162cSMarc Zyngier	ventry	el1_irq				// IRQ 32-bit EL1
2102b28162cSMarc Zyngier	ventry	el1_fiq_invalid			// FIQ 32-bit EL1
2112b28162cSMarc Zyngier	ventry	el1_error_invalid		// Error 32-bit EL1
2122b28162cSMarc ZyngierENDPROC(__hyp_vector)
213