// SPDX-License-Identifier: GPL-2.01/*2* Hyp portion of the (not much of an) Emulation layer for 32bit guests.3*4* Copyright (C) 2012,2013 - ARM Ltd5* Author: Marc Zyngier <[email protected]>6*7* based on arch/arm/kvm/emulate.c8* Copyright (C) 2012 - Virtual Open Systems and Columbia University9* Author: Christoffer Dall <[email protected]>10*/1112#include <linux/kvm_host.h>13#include <asm/kvm_emulate.h>14#include <asm/kvm_hyp.h>1516/*17* stolen from arch/arm/kernel/opcodes.c18*19* condition code lookup table20* index into the table is test code: EQ, NE, ... LT, GT, AL, NV21*22* bit position in short is condition code: NZCV23*/24static const unsigned short cc_map[16] = {250xF0F0, /* EQ == Z set */260x0F0F, /* NE */270xCCCC, /* CS == C set */280x3333, /* CC */290xFF00, /* MI == N set */300x00FF, /* PL */310xAAAA, /* VS == V set */320x5555, /* VC */330x0C0C, /* HI == C set && Z clear */340xF3F3, /* LS == C clear || Z set */350xAA55, /* GE == (N==V) */360x55AA, /* LT == (N!=V) */370x0A05, /* GT == (!Z && (N==V)) */380xF5FA, /* LE == (Z || (N!=V)) */390xFFFF, /* AL always */400 /* NV */41};4243/*44* Check if a trapped instruction should have been executed or not.45*/46bool kvm_condition_valid32(const struct kvm_vcpu *vcpu)47{48unsigned long cpsr;49u32 cpsr_cond;50int cond;5152/*53* These are the exception classes that could fire with a54* conditional instruction.55*/56switch (kvm_vcpu_trap_get_class(vcpu)) {57case ESR_ELx_EC_CP15_32:58case ESR_ELx_EC_CP15_64:59case ESR_ELx_EC_CP14_MR:60case ESR_ELx_EC_CP14_LS:61case ESR_ELx_EC_FP_ASIMD:62case ESR_ELx_EC_CP10_ID:63case ESR_ELx_EC_CP14_64:64case ESR_ELx_EC_SVC32:65break;66default:67return true;68}6970/* Is condition field valid? */71cond = kvm_vcpu_get_condition(vcpu);72if (cond == 0xE)73return true;7475cpsr = *vcpu_cpsr(vcpu);7677if (cond < 0) {78/* This can happen in Thumb mode: examine IT state. */79unsigned long it;8081it = ((cpsr >> 8) & 0xFC) | ((cpsr >> 25) & 0x3);8283/* it == 0 => unconditional. */84if (it == 0)85return true;8687/* The cond for this insn works out as the top 4 bits. */88cond = (it >> 4);89}9091cpsr_cond = cpsr >> 28;9293if (!((cc_map[cond] >> cpsr_cond) & 1))94return false;9596return true;97}9899/**100* kvm_adjust_itstate - adjust ITSTATE when emulating instructions in IT-block101* @vcpu: The VCPU pointer102*103* When exceptions occur while instructions are executed in Thumb IF-THEN104* blocks, the ITSTATE field of the CPSR is not advanced (updated), so we have105* to do this little bit of work manually. The fields map like this:106*107* IT[7:0] -> CPSR[26:25],CPSR[15:10]108*/109static void kvm_adjust_itstate(struct kvm_vcpu *vcpu)110{111unsigned long itbits, cond;112unsigned long cpsr = *vcpu_cpsr(vcpu);113bool is_arm = !(cpsr & PSR_AA32_T_BIT);114115if (is_arm || !(cpsr & PSR_AA32_IT_MASK))116return;117118cond = (cpsr & 0xe000) >> 13;119itbits = (cpsr & 0x1c00) >> (10 - 2);120itbits |= (cpsr & (0x3 << 25)) >> 25;121122/* Perform ITAdvance (see page A2-52 in ARM DDI 0406C) */123if ((itbits & 0x7) == 0)124itbits = cond = 0;125else126itbits = (itbits << 1) & 0x1f;127128cpsr &= ~PSR_AA32_IT_MASK;129cpsr |= cond << 13;130cpsr |= (itbits & 0x1c) << (10 - 2);131cpsr |= (itbits & 0x3) << 25;132*vcpu_cpsr(vcpu) = cpsr;133}134135/**136* kvm_skip_instr32 - skip a trapped instruction and proceed to the next137* @vcpu: The vcpu pointer138*/139void kvm_skip_instr32(struct kvm_vcpu *vcpu)140{141u32 pc = *vcpu_pc(vcpu);142bool is_thumb;143144is_thumb = !!(*vcpu_cpsr(vcpu) & PSR_AA32_T_BIT);145if (is_thumb && !kvm_vcpu_trap_il_is32bit(vcpu))146pc += 2;147else148pc += 4;149150*vcpu_pc(vcpu) = pc;151152kvm_adjust_itstate(vcpu);153}154155156