Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/powerpc/kvm/44x_emulate.c
10817 views
1
/*
2
* This program is free software; you can redistribute it and/or modify
3
* it under the terms of the GNU General Public License, version 2, as
4
* published by the Free Software Foundation.
5
*
6
* This program is distributed in the hope that it will be useful,
7
* but WITHOUT ANY WARRANTY; without even the implied warranty of
8
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9
* GNU General Public License for more details.
10
*
11
* You should have received a copy of the GNU General Public License
12
* along with this program; if not, write to the Free Software
13
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
14
*
15
* Copyright IBM Corp. 2008
16
*
17
* Authors: Hollis Blanchard <[email protected]>
18
*/
19
20
#include <asm/kvm_ppc.h>
21
#include <asm/dcr.h>
22
#include <asm/dcr-regs.h>
23
#include <asm/disassemble.h>
24
#include <asm/kvm_44x.h>
25
#include "timing.h"
26
27
#include "booke.h"
28
#include "44x_tlb.h"
29
30
#define XOP_MFDCR 323
31
#define XOP_MTDCR 451
32
#define XOP_TLBSX 914
33
#define XOP_ICCCI 966
34
#define XOP_TLBWE 978
35
36
int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
37
unsigned int inst, int *advance)
38
{
39
int emulated = EMULATE_DONE;
40
int dcrn;
41
int ra;
42
int rb;
43
int rc;
44
int rs;
45
int rt;
46
int ws;
47
48
switch (get_op(inst)) {
49
case 31:
50
switch (get_xop(inst)) {
51
52
case XOP_MFDCR:
53
dcrn = get_dcrn(inst);
54
rt = get_rt(inst);
55
56
/* The guest may access CPR0 registers to determine the timebase
57
* frequency, and it must know the real host frequency because it
58
* can directly access the timebase registers.
59
*
60
* It would be possible to emulate those accesses in userspace,
61
* but userspace can really only figure out the end frequency.
62
* We could decompose that into the factors that compute it, but
63
* that's tricky math, and it's easier to just report the real
64
* CPR0 values.
65
*/
66
switch (dcrn) {
67
case DCRN_CPR0_CONFIG_ADDR:
68
kvmppc_set_gpr(vcpu, rt, vcpu->arch.cpr0_cfgaddr);
69
break;
70
case DCRN_CPR0_CONFIG_DATA:
71
local_irq_disable();
72
mtdcr(DCRN_CPR0_CONFIG_ADDR,
73
vcpu->arch.cpr0_cfgaddr);
74
kvmppc_set_gpr(vcpu, rt,
75
mfdcr(DCRN_CPR0_CONFIG_DATA));
76
local_irq_enable();
77
break;
78
default:
79
run->dcr.dcrn = dcrn;
80
run->dcr.data = 0;
81
run->dcr.is_write = 0;
82
vcpu->arch.io_gpr = rt;
83
vcpu->arch.dcr_needed = 1;
84
kvmppc_account_exit(vcpu, DCR_EXITS);
85
emulated = EMULATE_DO_DCR;
86
}
87
88
break;
89
90
case XOP_MTDCR:
91
dcrn = get_dcrn(inst);
92
rs = get_rs(inst);
93
94
/* emulate some access in kernel */
95
switch (dcrn) {
96
case DCRN_CPR0_CONFIG_ADDR:
97
vcpu->arch.cpr0_cfgaddr = kvmppc_get_gpr(vcpu, rs);
98
break;
99
default:
100
run->dcr.dcrn = dcrn;
101
run->dcr.data = kvmppc_get_gpr(vcpu, rs);
102
run->dcr.is_write = 1;
103
vcpu->arch.dcr_needed = 1;
104
kvmppc_account_exit(vcpu, DCR_EXITS);
105
emulated = EMULATE_DO_DCR;
106
}
107
108
break;
109
110
case XOP_TLBWE:
111
ra = get_ra(inst);
112
rs = get_rs(inst);
113
ws = get_ws(inst);
114
emulated = kvmppc_44x_emul_tlbwe(vcpu, ra, rs, ws);
115
break;
116
117
case XOP_TLBSX:
118
rt = get_rt(inst);
119
ra = get_ra(inst);
120
rb = get_rb(inst);
121
rc = get_rc(inst);
122
emulated = kvmppc_44x_emul_tlbsx(vcpu, rt, ra, rb, rc);
123
break;
124
125
case XOP_ICCCI:
126
break;
127
128
default:
129
emulated = EMULATE_FAIL;
130
}
131
132
break;
133
134
default:
135
emulated = EMULATE_FAIL;
136
}
137
138
if (emulated == EMULATE_FAIL)
139
emulated = kvmppc_booke_emulate_op(run, vcpu, inst, advance);
140
141
return emulated;
142
}
143
144
int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
145
{
146
int emulated = EMULATE_DONE;
147
148
switch (sprn) {
149
case SPRN_PID:
150
kvmppc_set_pid(vcpu, kvmppc_get_gpr(vcpu, rs)); break;
151
case SPRN_MMUCR:
152
vcpu->arch.mmucr = kvmppc_get_gpr(vcpu, rs); break;
153
case SPRN_CCR0:
154
vcpu->arch.ccr0 = kvmppc_get_gpr(vcpu, rs); break;
155
case SPRN_CCR1:
156
vcpu->arch.ccr1 = kvmppc_get_gpr(vcpu, rs); break;
157
default:
158
emulated = kvmppc_booke_emulate_mtspr(vcpu, sprn, rs);
159
}
160
161
return emulated;
162
}
163
164
int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
165
{
166
int emulated = EMULATE_DONE;
167
168
switch (sprn) {
169
case SPRN_PID:
170
kvmppc_set_gpr(vcpu, rt, vcpu->arch.pid); break;
171
case SPRN_MMUCR:
172
kvmppc_set_gpr(vcpu, rt, vcpu->arch.mmucr); break;
173
case SPRN_CCR0:
174
kvmppc_set_gpr(vcpu, rt, vcpu->arch.ccr0); break;
175
case SPRN_CCR1:
176
kvmppc_set_gpr(vcpu, rt, vcpu->arch.ccr1); break;
177
default:
178
emulated = kvmppc_booke_emulate_mfspr(vcpu, sprn, rt);
179
}
180
181
return emulated;
182
}
183
184
185