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