Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arm64/kvm/hyp/aarch32.c
26490 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Hyp portion of the (not much of an) Emulation layer for 32bit guests.
4
*
5
* Copyright (C) 2012,2013 - ARM Ltd
6
* Author: Marc Zyngier <[email protected]>
7
*
8
* based on arch/arm/kvm/emulate.c
9
* Copyright (C) 2012 - Virtual Open Systems and Columbia University
10
* Author: Christoffer Dall <[email protected]>
11
*/
12
13
#include <linux/kvm_host.h>
14
#include <asm/kvm_emulate.h>
15
#include <asm/kvm_hyp.h>
16
17
/*
18
* stolen from arch/arm/kernel/opcodes.c
19
*
20
* condition code lookup table
21
* index into the table is test code: EQ, NE, ... LT, GT, AL, NV
22
*
23
* bit position in short is condition code: NZCV
24
*/
25
static const unsigned short cc_map[16] = {
26
0xF0F0, /* EQ == Z set */
27
0x0F0F, /* NE */
28
0xCCCC, /* CS == C set */
29
0x3333, /* CC */
30
0xFF00, /* MI == N set */
31
0x00FF, /* PL */
32
0xAAAA, /* VS == V set */
33
0x5555, /* VC */
34
0x0C0C, /* HI == C set && Z clear */
35
0xF3F3, /* LS == C clear || Z set */
36
0xAA55, /* GE == (N==V) */
37
0x55AA, /* LT == (N!=V) */
38
0x0A05, /* GT == (!Z && (N==V)) */
39
0xF5FA, /* LE == (Z || (N!=V)) */
40
0xFFFF, /* AL always */
41
0 /* NV */
42
};
43
44
/*
45
* Check if a trapped instruction should have been executed or not.
46
*/
47
bool kvm_condition_valid32(const struct kvm_vcpu *vcpu)
48
{
49
unsigned long cpsr;
50
u32 cpsr_cond;
51
int cond;
52
53
/*
54
* These are the exception classes that could fire with a
55
* conditional instruction.
56
*/
57
switch (kvm_vcpu_trap_get_class(vcpu)) {
58
case ESR_ELx_EC_CP15_32:
59
case ESR_ELx_EC_CP15_64:
60
case ESR_ELx_EC_CP14_MR:
61
case ESR_ELx_EC_CP14_LS:
62
case ESR_ELx_EC_FP_ASIMD:
63
case ESR_ELx_EC_CP10_ID:
64
case ESR_ELx_EC_CP14_64:
65
case ESR_ELx_EC_SVC32:
66
break;
67
default:
68
return true;
69
}
70
71
/* Is condition field valid? */
72
cond = kvm_vcpu_get_condition(vcpu);
73
if (cond == 0xE)
74
return true;
75
76
cpsr = *vcpu_cpsr(vcpu);
77
78
if (cond < 0) {
79
/* This can happen in Thumb mode: examine IT state. */
80
unsigned long it;
81
82
it = ((cpsr >> 8) & 0xFC) | ((cpsr >> 25) & 0x3);
83
84
/* it == 0 => unconditional. */
85
if (it == 0)
86
return true;
87
88
/* The cond for this insn works out as the top 4 bits. */
89
cond = (it >> 4);
90
}
91
92
cpsr_cond = cpsr >> 28;
93
94
if (!((cc_map[cond] >> cpsr_cond) & 1))
95
return false;
96
97
return true;
98
}
99
100
/**
101
* kvm_adjust_itstate - adjust ITSTATE when emulating instructions in IT-block
102
* @vcpu: The VCPU pointer
103
*
104
* When exceptions occur while instructions are executed in Thumb IF-THEN
105
* blocks, the ITSTATE field of the CPSR is not advanced (updated), so we have
106
* to do this little bit of work manually. The fields map like this:
107
*
108
* IT[7:0] -> CPSR[26:25],CPSR[15:10]
109
*/
110
static void kvm_adjust_itstate(struct kvm_vcpu *vcpu)
111
{
112
unsigned long itbits, cond;
113
unsigned long cpsr = *vcpu_cpsr(vcpu);
114
bool is_arm = !(cpsr & PSR_AA32_T_BIT);
115
116
if (is_arm || !(cpsr & PSR_AA32_IT_MASK))
117
return;
118
119
cond = (cpsr & 0xe000) >> 13;
120
itbits = (cpsr & 0x1c00) >> (10 - 2);
121
itbits |= (cpsr & (0x3 << 25)) >> 25;
122
123
/* Perform ITAdvance (see page A2-52 in ARM DDI 0406C) */
124
if ((itbits & 0x7) == 0)
125
itbits = cond = 0;
126
else
127
itbits = (itbits << 1) & 0x1f;
128
129
cpsr &= ~PSR_AA32_IT_MASK;
130
cpsr |= cond << 13;
131
cpsr |= (itbits & 0x1c) << (10 - 2);
132
cpsr |= (itbits & 0x3) << 25;
133
*vcpu_cpsr(vcpu) = cpsr;
134
}
135
136
/**
137
* kvm_skip_instr32 - skip a trapped instruction and proceed to the next
138
* @vcpu: The vcpu pointer
139
*/
140
void kvm_skip_instr32(struct kvm_vcpu *vcpu)
141
{
142
u32 pc = *vcpu_pc(vcpu);
143
bool is_thumb;
144
145
is_thumb = !!(*vcpu_cpsr(vcpu) & PSR_AA32_T_BIT);
146
if (is_thumb && !kvm_vcpu_trap_il_is32bit(vcpu))
147
pc += 2;
148
else
149
pc += 4;
150
151
*vcpu_pc(vcpu) = pc;
152
153
kvm_adjust_itstate(vcpu);
154
}
155
156