Merge tag 'kvm-arm-for-3.13-3' of git://git.linaro.org/people/cdall/linux-kvm-arm...
[cascardo/linux.git] / arch / powerpc / kvm / 44x_emulate.c
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 <hollisb@us.ibm.com>
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_MFDCRX  259
31 #define XOP_MFDCR   323
32 #define XOP_MTDCRX  387
33 #define XOP_MTDCR   451
34 #define XOP_TLBSX   914
35 #define XOP_ICCCI   966
36 #define XOP_TLBWE   978
37
38 static int emulate_mtdcr(struct kvm_vcpu *vcpu, int rs, int dcrn)
39 {
40         /* emulate some access in kernel */
41         switch (dcrn) {
42         case DCRN_CPR0_CONFIG_ADDR:
43                 vcpu->arch.cpr0_cfgaddr = kvmppc_get_gpr(vcpu, rs);
44                 return EMULATE_DONE;
45         default:
46                 vcpu->run->dcr.dcrn = dcrn;
47                 vcpu->run->dcr.data = kvmppc_get_gpr(vcpu, rs);
48                 vcpu->run->dcr.is_write = 1;
49                 vcpu->arch.dcr_is_write = 1;
50                 vcpu->arch.dcr_needed = 1;
51                 kvmppc_account_exit(vcpu, DCR_EXITS);
52                 return EMULATE_DO_DCR;
53         }
54 }
55
56 static int emulate_mfdcr(struct kvm_vcpu *vcpu, int rt, int dcrn)
57 {
58         /* The guest may access CPR0 registers to determine the timebase
59          * frequency, and it must know the real host frequency because it
60          * can directly access the timebase registers.
61          *
62          * It would be possible to emulate those accesses in userspace,
63          * but userspace can really only figure out the end frequency.
64          * We could decompose that into the factors that compute it, but
65          * that's tricky math, and it's easier to just report the real
66          * CPR0 values.
67          */
68         switch (dcrn) {
69         case DCRN_CPR0_CONFIG_ADDR:
70                 kvmppc_set_gpr(vcpu, rt, vcpu->arch.cpr0_cfgaddr);
71                 break;
72         case DCRN_CPR0_CONFIG_DATA:
73                 local_irq_disable();
74                 mtdcr(DCRN_CPR0_CONFIG_ADDR,
75                           vcpu->arch.cpr0_cfgaddr);
76                 kvmppc_set_gpr(vcpu, rt,
77                                mfdcr(DCRN_CPR0_CONFIG_DATA));
78                 local_irq_enable();
79                 break;
80         default:
81                 vcpu->run->dcr.dcrn = dcrn;
82                 vcpu->run->dcr.data =  0;
83                 vcpu->run->dcr.is_write = 0;
84                 vcpu->arch.dcr_is_write = 0;
85                 vcpu->arch.io_gpr = rt;
86                 vcpu->arch.dcr_needed = 1;
87                 kvmppc_account_exit(vcpu, DCR_EXITS);
88                 return EMULATE_DO_DCR;
89         }
90
91         return EMULATE_DONE;
92 }
93
94 int kvmppc_core_emulate_op_44x(struct kvm_run *run, struct kvm_vcpu *vcpu,
95                                unsigned int inst, int *advance)
96 {
97         int emulated = EMULATE_DONE;
98         int dcrn = get_dcrn(inst);
99         int ra = get_ra(inst);
100         int rb = get_rb(inst);
101         int rc = get_rc(inst);
102         int rs = get_rs(inst);
103         int rt = get_rt(inst);
104         int ws = get_ws(inst);
105
106         switch (get_op(inst)) {
107         case 31:
108                 switch (get_xop(inst)) {
109
110                 case XOP_MFDCR:
111                         emulated = emulate_mfdcr(vcpu, rt, dcrn);
112                         break;
113
114                 case XOP_MFDCRX:
115                         emulated = emulate_mfdcr(vcpu, rt,
116                                         kvmppc_get_gpr(vcpu, ra));
117                         break;
118
119                 case XOP_MTDCR:
120                         emulated = emulate_mtdcr(vcpu, rs, dcrn);
121                         break;
122
123                 case XOP_MTDCRX:
124                         emulated = emulate_mtdcr(vcpu, rs,
125                                         kvmppc_get_gpr(vcpu, ra));
126                         break;
127
128                 case XOP_TLBWE:
129                         emulated = kvmppc_44x_emul_tlbwe(vcpu, ra, rs, ws);
130                         break;
131
132                 case XOP_TLBSX:
133                         emulated = kvmppc_44x_emul_tlbsx(vcpu, rt, ra, rb, rc);
134                         break;
135
136                 case XOP_ICCCI:
137                         break;
138
139                 default:
140                         emulated = EMULATE_FAIL;
141                 }
142
143                 break;
144
145         default:
146                 emulated = EMULATE_FAIL;
147         }
148
149         if (emulated == EMULATE_FAIL)
150                 emulated = kvmppc_booke_emulate_op(run, vcpu, inst, advance);
151
152         return emulated;
153 }
154
155 int kvmppc_core_emulate_mtspr_44x(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
156 {
157         int emulated = EMULATE_DONE;
158
159         switch (sprn) {
160         case SPRN_PID:
161                 kvmppc_set_pid(vcpu, spr_val); break;
162         case SPRN_MMUCR:
163                 vcpu->arch.mmucr = spr_val; break;
164         case SPRN_CCR0:
165                 vcpu->arch.ccr0 = spr_val; break;
166         case SPRN_CCR1:
167                 vcpu->arch.ccr1 = spr_val; break;
168         default:
169                 emulated = kvmppc_booke_emulate_mtspr(vcpu, sprn, spr_val);
170         }
171
172         return emulated;
173 }
174
175 int kvmppc_core_emulate_mfspr_44x(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
176 {
177         int emulated = EMULATE_DONE;
178
179         switch (sprn) {
180         case SPRN_PID:
181                 *spr_val = vcpu->arch.pid; break;
182         case SPRN_MMUCR:
183                 *spr_val = vcpu->arch.mmucr; break;
184         case SPRN_CCR0:
185                 *spr_val = vcpu->arch.ccr0; break;
186         case SPRN_CCR1:
187                 *spr_val = vcpu->arch.ccr1; break;
188         default:
189                 emulated = kvmppc_booke_emulate_mfspr(vcpu, sprn, spr_val);
190         }
191
192         return emulated;
193 }
194