2 * mmio.c: MMIO emulation components.
3 * Copyright (c) 2004, Intel Corporation.
4 * Yaozu Dong (Eddie Dong) (Eddie.dong@intel.com)
5 * Kun Tian (Kevin Tian) (Kevin.tian@intel.com)
7 * Copyright (c) 2007 Intel Corporation KVM support.
8 * Xuefei Xu (Anthony Xu) (anthony.xu@intel.com)
9 * Xiantao Zhang (xiantao.zhang@intel.com)
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms and conditions of the GNU General Public License,
13 * version 2, as published by the Free Software Foundation.
15 * This program is distributed in the hope it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 * You should have received a copy of the GNU General Public License along with
21 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22 * Place - Suite 330, Boston, MA 02111-1307 USA.
26 #include <linux/kvm_host.h>
30 static void vlsapic_write_xtp(struct kvm_vcpu
*v
, uint8_t val
)
38 #define PIB_LOW_HALF(ofst) !(ofst & (1 << 20))
39 #define PIB_OFST_INTA 0x1E0000
40 #define PIB_OFST_XTP 0x1E0008
43 * execute write IPI op.
45 static void vlsapic_write_ipi(struct kvm_vcpu
*vcpu
,
46 uint64_t addr
, uint64_t data
)
48 struct exit_ctl_data
*p
= ¤t_vcpu
->arch
.exit_data
;
53 p
->exit_reason
= EXIT_REASON_IPI
;
54 p
->u
.ipi_data
.addr
.val
= addr
;
55 p
->u
.ipi_data
.data
.val
= data
;
56 vmm_transition(current_vcpu
);
58 local_irq_restore(psr
);
62 void lsapic_write(struct kvm_vcpu
*v
, unsigned long addr
,
63 unsigned long length
, unsigned long val
)
65 addr
&= (PIB_SIZE
- 1);
69 /*panic_domain(NULL, "Undefined write on PIB INTA\n");*/
74 vlsapic_write_xtp(v
, val
);
77 "Undefined write on PIB XTP\n");*/
82 if (PIB_LOW_HALF(addr
)) {
86 "Can't LHF write with size %ld!\n",
90 vlsapic_write_ipi(v
, addr
, val
);
91 } else { /* upper half
92 printk("IPI-UHF write %lx\n",addr);*/
99 unsigned long lsapic_read(struct kvm_vcpu
*v
, unsigned long addr
,
100 unsigned long length
)
104 addr
&= (PIB_SIZE
- 1);
108 if (length
== 1) /* 1 byte load */
109 ; /* There is no i8259, there is no INTA access*/
111 /*panic_domain(NULL,"Undefined read on PIB INTA\n"); */
117 result
= VLSAPIC_XTP(v
);
118 /* printk("read xtp %lx\n", result); */
121 "Undefined read on PIB XTP\n");*/
132 static void mmio_access(struct kvm_vcpu
*vcpu
, u64 src_pa
, u64
*dest
,
133 u16 s
, int ma
, int dir
)
136 struct exit_ctl_data
*p
= &vcpu
->arch
.exit_data
;
139 iot
= __gpfn_is_io(src_pa
>> PAGE_SHIFT
);
143 /*Intercept the acces for PIB range*/
144 if (iot
== GPFN_PIB
) {
146 lsapic_write(vcpu
, src_pa
, s
, *dest
);
148 *dest
= lsapic_read(vcpu
, src_pa
, s
);
151 p
->exit_reason
= EXIT_REASON_MMIO_INSTRUCTION
;
152 p
->u
.ioreq
.addr
= src_pa
;
154 p
->u
.ioreq
.dir
= dir
;
155 if (dir
== IOREQ_WRITE
)
156 p
->u
.ioreq
.data
= *dest
;
157 p
->u
.ioreq
.state
= STATE_IOREQ_READY
;
158 vmm_transition(vcpu
);
160 if (p
->u
.ioreq
.state
== STATE_IORESP_READY
) {
161 if (dir
== IOREQ_READ
)
162 *dest
= p
->u
.ioreq
.data
;
166 local_irq_restore(psr
);
172 inst_type 0:integer 1:floating point
174 #define SL_INTEGER 0 /* store/load interger*/
175 #define SL_FLOATING 1 /* store/load floating*/
177 void emulate_io_inst(struct kvm_vcpu
*vcpu
, u64 padr
, u64 ma
)
179 struct kvm_pt_regs
*regs
;
184 u64 data
, slot1a
, slot1b
, temp
, update_reg
;
188 regs
= vcpu_regs(vcpu
);
190 if (fetch_code(vcpu
, regs
->cr_iip
, &bundle
)) {
191 /* if fetch code fail, return and try again */
194 slot
= ((struct ia64_psr
*)&(regs
->cr_ipsr
))->ri
;
196 inst
.inst
= bundle
.slot0
;
197 else if (slot
== 1) {
198 slot1a
= bundle
.slot1a
;
199 slot1b
= bundle
.slot1b
;
200 inst
.inst
= slot1a
+ (slot1b
<< 18);
201 } else if (slot
== 2)
202 inst
.inst
= bundle
.slot2
;
204 /* Integer Load/Store */
205 if (inst
.M1
.major
== 4 && inst
.M1
.m
== 0 && inst
.M1
.x
== 0) {
206 inst_type
= SL_INTEGER
;
207 size
= (inst
.M1
.x6
& 0x3);
208 if ((inst
.M1
.x6
>> 2) > 0xb) {
211 data
= vcpu_get_gr(vcpu
, inst
.M4
.r2
);
212 } else if ((inst
.M1
.x6
>> 2) < 0xb) {
216 } else if (inst
.M2
.major
== 4 && inst
.M2
.m
== 1 && inst
.M2
.x
== 0) {
217 /* Integer Load + Reg update */
218 inst_type
= SL_INTEGER
;
220 size
= (inst
.M2
.x6
& 0x3);
221 temp
= vcpu_get_gr(vcpu
, inst
.M2
.r3
);
222 update_reg
= vcpu_get_gr(vcpu
, inst
.M2
.r2
);
224 vcpu_set_gr(vcpu
, inst
.M2
.r3
, temp
, 0);
225 } else if (inst
.M3
.major
== 5) {
226 /*Integer Load/Store + Imm update*/
227 inst_type
= SL_INTEGER
;
228 size
= (inst
.M3
.x6
&0x3);
229 if ((inst
.M5
.x6
>> 2) > 0xb) {
232 data
= vcpu_get_gr(vcpu
, inst
.M5
.r2
);
233 temp
= vcpu_get_gr(vcpu
, inst
.M5
.r3
);
234 imm
= (inst
.M5
.s
<< 31) | (inst
.M5
.i
<< 30) |
235 (inst
.M5
.imm7
<< 23);
237 vcpu_set_gr(vcpu
, inst
.M5
.r3
, temp
, 0);
239 } else if ((inst
.M3
.x6
>> 2) < 0xb) {
242 temp
= vcpu_get_gr(vcpu
, inst
.M3
.r3
);
243 imm
= (inst
.M3
.s
<< 31) | (inst
.M3
.i
<< 30) |
244 (inst
.M3
.imm7
<< 23);
246 vcpu_set_gr(vcpu
, inst
.M3
.r3
, temp
, 0);
249 } else if (inst
.M9
.major
== 6 && inst
.M9
.x6
== 0x3B
250 && inst
.M9
.m
== 0 && inst
.M9
.x
== 0) {
251 /* Floating-point spill*/
254 inst_type
= SL_FLOATING
;
256 vcpu_get_fpreg(vcpu
, inst
.M9
.f2
, &v
);
257 /* Write high word. FIXME: this is a kludge! */
258 v
.u
.bits
[1] &= 0x3ffff;
259 mmio_access(vcpu
, padr
+ 8, &v
.u
.bits
[1], 8, ma
, IOREQ_WRITE
);
262 } else if (inst
.M10
.major
== 7 && inst
.M10
.x6
== 0x3B) {
263 /* Floating-point spill + Imm update */
266 inst_type
= SL_FLOATING
;
268 vcpu_get_fpreg(vcpu
, inst
.M10
.f2
, &v
);
269 temp
= vcpu_get_gr(vcpu
, inst
.M10
.r3
);
270 imm
= (inst
.M10
.s
<< 31) | (inst
.M10
.i
<< 30) |
271 (inst
.M10
.imm7
<< 23);
273 vcpu_set_gr(vcpu
, inst
.M10
.r3
, temp
, 0);
275 /* Write high word.FIXME: this is a kludge! */
276 v
.u
.bits
[1] &= 0x3ffff;
277 mmio_access(vcpu
, padr
+ 8, &v
.u
.bits
[1], 8, ma
, IOREQ_WRITE
);
280 } else if (inst
.M10
.major
== 7 && inst
.M10
.x6
== 0x31) {
281 /* Floating-point stf8 + Imm update */
283 inst_type
= SL_FLOATING
;
286 vcpu_get_fpreg(vcpu
, inst
.M10
.f2
, &v
);
287 data
= v
.u
.bits
[0]; /* Significand. */
288 temp
= vcpu_get_gr(vcpu
, inst
.M10
.r3
);
289 imm
= (inst
.M10
.s
<< 31) | (inst
.M10
.i
<< 30) |
290 (inst
.M10
.imm7
<< 23);
292 vcpu_set_gr(vcpu
, inst
.M10
.r3
, temp
, 0);
293 } else if (inst
.M15
.major
== 7 && inst
.M15
.x6
>= 0x2c
294 && inst
.M15
.x6
<= 0x2f) {
295 temp
= vcpu_get_gr(vcpu
, inst
.M15
.r3
);
296 imm
= (inst
.M15
.s
<< 31) | (inst
.M15
.i
<< 30) |
297 (inst
.M15
.imm7
<< 23);
299 vcpu_set_gr(vcpu
, inst
.M15
.r3
, temp
, 0);
301 vcpu_increment_iip(vcpu
);
303 } else if (inst
.M12
.major
== 6 && inst
.M12
.m
== 1
304 && inst
.M12
.x
== 1 && inst
.M12
.x6
== 1) {
305 /* Floating-point Load Pair + Imm ldfp8 M12*/
308 inst_type
= SL_FLOATING
;
311 mmio_access(vcpu
, padr
, &data
, size
, ma
, dir
);
313 v
.u
.bits
[1] = 0x1003E;
314 vcpu_set_fpreg(vcpu
, inst
.M12
.f1
, &v
);
316 mmio_access(vcpu
, padr
, &data
, size
, ma
, dir
);
318 v
.u
.bits
[1] = 0x1003E;
319 vcpu_set_fpreg(vcpu
, inst
.M12
.f2
, &v
);
321 vcpu_set_gr(vcpu
, inst
.M12
.r3
, padr
, 0);
322 vcpu_increment_iip(vcpu
);
330 if (dir
== IOREQ_WRITE
) {
331 mmio_access(vcpu
, padr
, &data
, size
, ma
, dir
);
333 mmio_access(vcpu
, padr
, &data
, size
, ma
, dir
);
334 if (inst_type
== SL_INTEGER
)
335 vcpu_set_gr(vcpu
, inst
.M1
.r1
, data
, 0);
340 vcpu_increment_iip(vcpu
);