xref: /openbmc/linux/arch/arm64/kvm/hyp/aarch32.c (revision ba2929159000dc7015cc01cdf7bb72542e19952a)
19ed24f4bSMarc Zyngier // SPDX-License-Identifier: GPL-2.0
29ed24f4bSMarc Zyngier /*
39ed24f4bSMarc Zyngier  * Hyp portion of the (not much of an) Emulation layer for 32bit guests.
49ed24f4bSMarc Zyngier  *
59ed24f4bSMarc Zyngier  * Copyright (C) 2012,2013 - ARM Ltd
69ed24f4bSMarc Zyngier  * Author: Marc Zyngier <marc.zyngier@arm.com>
79ed24f4bSMarc Zyngier  *
89ed24f4bSMarc Zyngier  * based on arch/arm/kvm/emulate.c
99ed24f4bSMarc Zyngier  * Copyright (C) 2012 - Virtual Open Systems and Columbia University
109ed24f4bSMarc Zyngier  * Author: Christoffer Dall <c.dall@virtualopensystems.com>
119ed24f4bSMarc Zyngier  */
129ed24f4bSMarc Zyngier 
139ed24f4bSMarc Zyngier #include <linux/kvm_host.h>
149ed24f4bSMarc Zyngier #include <asm/kvm_emulate.h>
159ed24f4bSMarc Zyngier #include <asm/kvm_hyp.h>
169ed24f4bSMarc Zyngier 
179ed24f4bSMarc Zyngier /*
189ed24f4bSMarc Zyngier  * stolen from arch/arm/kernel/opcodes.c
199ed24f4bSMarc Zyngier  *
209ed24f4bSMarc Zyngier  * condition code lookup table
219ed24f4bSMarc Zyngier  * index into the table is test code: EQ, NE, ... LT, GT, AL, NV
229ed24f4bSMarc Zyngier  *
239ed24f4bSMarc Zyngier  * bit position in short is condition code: NZCV
249ed24f4bSMarc Zyngier  */
259ed24f4bSMarc Zyngier static const unsigned short cc_map[16] = {
269ed24f4bSMarc Zyngier 	0xF0F0,			/* EQ == Z set            */
279ed24f4bSMarc Zyngier 	0x0F0F,			/* NE                     */
289ed24f4bSMarc Zyngier 	0xCCCC,			/* CS == C set            */
299ed24f4bSMarc Zyngier 	0x3333,			/* CC                     */
309ed24f4bSMarc Zyngier 	0xFF00,			/* MI == N set            */
319ed24f4bSMarc Zyngier 	0x00FF,			/* PL                     */
329ed24f4bSMarc Zyngier 	0xAAAA,			/* VS == V set            */
339ed24f4bSMarc Zyngier 	0x5555,			/* VC                     */
349ed24f4bSMarc Zyngier 	0x0C0C,			/* HI == C set && Z clear */
359ed24f4bSMarc Zyngier 	0xF3F3,			/* LS == C clear || Z set */
369ed24f4bSMarc Zyngier 	0xAA55,			/* GE == (N==V)           */
379ed24f4bSMarc Zyngier 	0x55AA,			/* LT == (N!=V)           */
389ed24f4bSMarc Zyngier 	0x0A05,			/* GT == (!Z && (N==V))   */
399ed24f4bSMarc Zyngier 	0xF5FA,			/* LE == (Z || (N!=V))    */
409ed24f4bSMarc Zyngier 	0xFFFF,			/* AL always              */
419ed24f4bSMarc Zyngier 	0			/* NV                     */
429ed24f4bSMarc Zyngier };
439ed24f4bSMarc Zyngier 
449ed24f4bSMarc Zyngier /*
459ed24f4bSMarc Zyngier  * Check if a trapped instruction should have been executed or not.
469ed24f4bSMarc Zyngier  */
kvm_condition_valid32(const struct kvm_vcpu * vcpu)47c50cb043SDavid Brazdil bool kvm_condition_valid32(const struct kvm_vcpu *vcpu)
489ed24f4bSMarc Zyngier {
499ed24f4bSMarc Zyngier 	unsigned long cpsr;
509ed24f4bSMarc Zyngier 	u32 cpsr_cond;
519ed24f4bSMarc Zyngier 	int cond;
529ed24f4bSMarc Zyngier 
53*93ca96f0SMarc Zyngier 	/*
54*93ca96f0SMarc Zyngier 	 * These are the exception classes that could fire with a
55*93ca96f0SMarc Zyngier 	 * conditional instruction.
56*93ca96f0SMarc Zyngier 	 */
57*93ca96f0SMarc Zyngier 	switch (kvm_vcpu_trap_get_class(vcpu)) {
58*93ca96f0SMarc Zyngier 	case ESR_ELx_EC_CP15_32:
59*93ca96f0SMarc Zyngier 	case ESR_ELx_EC_CP15_64:
60*93ca96f0SMarc Zyngier 	case ESR_ELx_EC_CP14_MR:
61*93ca96f0SMarc Zyngier 	case ESR_ELx_EC_CP14_LS:
62*93ca96f0SMarc Zyngier 	case ESR_ELx_EC_FP_ASIMD:
63*93ca96f0SMarc Zyngier 	case ESR_ELx_EC_CP10_ID:
64*93ca96f0SMarc Zyngier 	case ESR_ELx_EC_CP14_64:
65*93ca96f0SMarc Zyngier 	case ESR_ELx_EC_SVC32:
66*93ca96f0SMarc Zyngier 		break;
67*93ca96f0SMarc Zyngier 	default:
689ed24f4bSMarc Zyngier 		return true;
69*93ca96f0SMarc Zyngier 	}
709ed24f4bSMarc Zyngier 
719ed24f4bSMarc Zyngier 	/* Is condition field valid? */
729ed24f4bSMarc Zyngier 	cond = kvm_vcpu_get_condition(vcpu);
739ed24f4bSMarc Zyngier 	if (cond == 0xE)
749ed24f4bSMarc Zyngier 		return true;
759ed24f4bSMarc Zyngier 
769ed24f4bSMarc Zyngier 	cpsr = *vcpu_cpsr(vcpu);
779ed24f4bSMarc Zyngier 
789ed24f4bSMarc Zyngier 	if (cond < 0) {
799ed24f4bSMarc Zyngier 		/* This can happen in Thumb mode: examine IT state. */
809ed24f4bSMarc Zyngier 		unsigned long it;
819ed24f4bSMarc Zyngier 
829ed24f4bSMarc Zyngier 		it = ((cpsr >> 8) & 0xFC) | ((cpsr >> 25) & 0x3);
839ed24f4bSMarc Zyngier 
849ed24f4bSMarc Zyngier 		/* it == 0 => unconditional. */
859ed24f4bSMarc Zyngier 		if (it == 0)
869ed24f4bSMarc Zyngier 			return true;
879ed24f4bSMarc Zyngier 
889ed24f4bSMarc Zyngier 		/* The cond for this insn works out as the top 4 bits. */
899ed24f4bSMarc Zyngier 		cond = (it >> 4);
909ed24f4bSMarc Zyngier 	}
919ed24f4bSMarc Zyngier 
929ed24f4bSMarc Zyngier 	cpsr_cond = cpsr >> 28;
939ed24f4bSMarc Zyngier 
949ed24f4bSMarc Zyngier 	if (!((cc_map[cond] >> cpsr_cond) & 1))
959ed24f4bSMarc Zyngier 		return false;
969ed24f4bSMarc Zyngier 
979ed24f4bSMarc Zyngier 	return true;
989ed24f4bSMarc Zyngier }
999ed24f4bSMarc Zyngier 
1009ed24f4bSMarc Zyngier /**
1019ed24f4bSMarc Zyngier  * adjust_itstate - adjust ITSTATE when emulating instructions in IT-block
1029ed24f4bSMarc Zyngier  * @vcpu:	The VCPU pointer
1039ed24f4bSMarc Zyngier  *
1049ed24f4bSMarc Zyngier  * When exceptions occur while instructions are executed in Thumb IF-THEN
1059ed24f4bSMarc Zyngier  * blocks, the ITSTATE field of the CPSR is not advanced (updated), so we have
1069ed24f4bSMarc Zyngier  * to do this little bit of work manually. The fields map like this:
1079ed24f4bSMarc Zyngier  *
1089ed24f4bSMarc Zyngier  * IT[7:0] -> CPSR[26:25],CPSR[15:10]
1099ed24f4bSMarc Zyngier  */
kvm_adjust_itstate(struct kvm_vcpu * vcpu)110c50cb043SDavid Brazdil static void kvm_adjust_itstate(struct kvm_vcpu *vcpu)
1119ed24f4bSMarc Zyngier {
1129ed24f4bSMarc Zyngier 	unsigned long itbits, cond;
1139ed24f4bSMarc Zyngier 	unsigned long cpsr = *vcpu_cpsr(vcpu);
1149ed24f4bSMarc Zyngier 	bool is_arm = !(cpsr & PSR_AA32_T_BIT);
1159ed24f4bSMarc Zyngier 
1169ed24f4bSMarc Zyngier 	if (is_arm || !(cpsr & PSR_AA32_IT_MASK))
1179ed24f4bSMarc Zyngier 		return;
1189ed24f4bSMarc Zyngier 
1199ed24f4bSMarc Zyngier 	cond = (cpsr & 0xe000) >> 13;
1209ed24f4bSMarc Zyngier 	itbits = (cpsr & 0x1c00) >> (10 - 2);
1219ed24f4bSMarc Zyngier 	itbits |= (cpsr & (0x3 << 25)) >> 25;
1229ed24f4bSMarc Zyngier 
1239ed24f4bSMarc Zyngier 	/* Perform ITAdvance (see page A2-52 in ARM DDI 0406C) */
1249ed24f4bSMarc Zyngier 	if ((itbits & 0x7) == 0)
1259ed24f4bSMarc Zyngier 		itbits = cond = 0;
1269ed24f4bSMarc Zyngier 	else
1279ed24f4bSMarc Zyngier 		itbits = (itbits << 1) & 0x1f;
1289ed24f4bSMarc Zyngier 
1299ed24f4bSMarc Zyngier 	cpsr &= ~PSR_AA32_IT_MASK;
1309ed24f4bSMarc Zyngier 	cpsr |= cond << 13;
1319ed24f4bSMarc Zyngier 	cpsr |= (itbits & 0x1c) << (10 - 2);
1329ed24f4bSMarc Zyngier 	cpsr |= (itbits & 0x3) << 25;
1339ed24f4bSMarc Zyngier 	*vcpu_cpsr(vcpu) = cpsr;
1349ed24f4bSMarc Zyngier }
1359ed24f4bSMarc Zyngier 
1369ed24f4bSMarc Zyngier /**
1379ed24f4bSMarc Zyngier  * kvm_skip_instr - skip a trapped instruction and proceed to the next
1389ed24f4bSMarc Zyngier  * @vcpu: The vcpu pointer
1399ed24f4bSMarc Zyngier  */
kvm_skip_instr32(struct kvm_vcpu * vcpu)1406ddbc281SMarc Zyngier void kvm_skip_instr32(struct kvm_vcpu *vcpu)
1419ed24f4bSMarc Zyngier {
1429ed24f4bSMarc Zyngier 	u32 pc = *vcpu_pc(vcpu);
1439ed24f4bSMarc Zyngier 	bool is_thumb;
1449ed24f4bSMarc Zyngier 
1459ed24f4bSMarc Zyngier 	is_thumb = !!(*vcpu_cpsr(vcpu) & PSR_AA32_T_BIT);
1466ddbc281SMarc Zyngier 	if (is_thumb && !kvm_vcpu_trap_il_is32bit(vcpu))
1479ed24f4bSMarc Zyngier 		pc += 2;
1489ed24f4bSMarc Zyngier 	else
1499ed24f4bSMarc Zyngier 		pc += 4;
1509ed24f4bSMarc Zyngier 
1519ed24f4bSMarc Zyngier 	*vcpu_pc(vcpu) = pc;
1529ed24f4bSMarc Zyngier 
1539ed24f4bSMarc Zyngier 	kvm_adjust_itstate(vcpu);
1549ed24f4bSMarc Zyngier }
155