ia64/xen-unstable

view xen/arch/ia64/vmx/mmio.c @ 10938:bfc69471550e

[IA64] fix a fetch code bug

Fetch code may fail, if there is no corresponding tlb entry
in THASH-VTLB. This patch adds "retry mechanism" to resolve
this issue.

Signed-off-by: Anthony Xu <anthony.xu@intel.com>
author awilliam@xenbuild.aw
date Wed Aug 09 08:01:52 2006 -0600 (2006-08-09)
parents be11edf8964e
children d42e9a6f5378 04e5e80be909
line source
2 /* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
3 /*
4 * mmio.c: MMIO emulation components.
5 * Copyright (c) 2004, Intel Corporation.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 * Place - Suite 330, Boston, MA 02111-1307 USA.
19 *
20 * Yaozu Dong (Eddie Dong) (Eddie.dong@intel.com)
21 * Kun Tian (Kevin Tian) (Kevin.tian@intel.com)
22 */
24 #include <linux/sched.h>
25 #include <asm/tlb.h>
26 #include <asm/vmx_mm_def.h>
27 #include <asm/gcc_intrin.h>
28 #include <linux/interrupt.h>
29 #include <asm/vmx_vcpu.h>
30 #include <asm/bundle.h>
31 #include <asm/types.h>
32 #include <public/hvm/ioreq.h>
33 #include <asm/mm.h>
34 #include <asm/vmx.h>
35 #include <public/event_channel.h>
36 #include <public/arch-ia64.h>
37 #include <linux/event.h>
38 #include <xen/domain.h>
39 /*
40 struct mmio_list *lookup_mmio(u64 gpa, struct mmio_list *mio_base)
41 {
42 int i;
43 for (i=0; mio_base[i].iot != NOT_IO; i++ ) {
44 if ( gpa >= mio_base[i].start && gpa <= mio_base[i].end )
45 return &mio_base[i];
46 }
47 return NULL;
48 }
49 */
51 #define PIB_LOW_HALF(ofst) !(ofst&(1<<20))
52 #define PIB_OFST_INTA 0x1E0000
53 #define PIB_OFST_XTP 0x1E0008
55 static void write_ipi (VCPU *vcpu, uint64_t addr, uint64_t value);
57 static void pib_write(VCPU *vcpu, void *src, uint64_t pib_off, size_t s, int ma)
58 {
59 switch (pib_off) {
60 case PIB_OFST_INTA:
61 panic_domain(NULL,"Undefined write on PIB INTA\n");
62 break;
63 case PIB_OFST_XTP:
64 if ( s == 1 && ma == 4 /* UC */) {
65 vmx_vcpu_get_plat(vcpu)->xtp = *(uint8_t *)src;
66 }
67 else {
68 panic_domain(NULL,"Undefined write on PIB XTP\n");
69 }
70 break;
71 default:
72 if ( PIB_LOW_HALF(pib_off) ) { // lower half
73 if ( s != 8 || ma != 0x4 /* UC */ ) {
74 panic_domain
75 (NULL,"Undefined IPI-LHF write with s %ld, ma %d!\n", s, ma);
76 }
77 else {
78 write_ipi(vcpu, pib_off, *(uint64_t *)src);
79 // TODO for SM-VP
80 }
81 }
82 else { // upper half
83 printf("IPI-UHF write %lx\n",pib_off);
84 panic_domain(NULL,"Not support yet for SM-VP\n");
85 }
86 break;
87 }
88 }
90 static void pib_read(VCPU *vcpu, uint64_t pib_off, void *dest, size_t s, int ma)
91 {
92 switch (pib_off) {
93 case PIB_OFST_INTA:
94 // todo --- emit on processor system bus.
95 if ( s == 1 && ma == 4) { // 1 byte load
96 // TODO: INTA read from IOSAPIC
97 }
98 else {
99 panic_domain(NULL,"Undefined read on PIB INTA\n");
100 }
101 break;
102 case PIB_OFST_XTP:
103 if ( s == 1 && ma == 4) {
104 *((uint8_t*)dest) = vmx_vcpu_get_plat(vcpu)->xtp;
105 }
106 else {
107 panic_domain(NULL,"Undefined read on PIB XTP\n");
108 }
109 break;
110 default:
111 if ( PIB_LOW_HALF(pib_off) ) { // lower half
112 if ( s != 8 || ma != 4 ) {
113 panic_domain(NULL,"Undefined IPI-LHF read!\n");
114 }
115 else {
116 #ifdef IPI_DEBUG
117 printf("IPI-LHF read %lx\n",pib_off);
118 #endif
119 *(uint64_t *)dest = 0; // TODO for SM-VP
120 }
121 }
122 else { // upper half
123 if ( s != 1 || ma != 4 ) {
124 panic_domain(NULL,"Undefined PIB-UHF read!\n");
125 }
126 else {
127 #ifdef IPI_DEBUG
128 printf("IPI-UHF read %lx\n",pib_off);
129 #endif
130 *(uint8_t *)dest = 0; // TODO for SM-VP
131 }
132 }
133 break;
134 }
135 }
137 static void low_mmio_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir)
138 {
139 struct vcpu *v = current;
140 vcpu_iodata_t *vio;
141 ioreq_t *p;
143 vio = get_vio(v->domain, v->vcpu_id);
144 if (vio == 0) {
145 panic_domain(NULL,"bad shared page: %lx", (unsigned long)vio);
146 }
147 p = &vio->vp_ioreq;
148 p->addr = pa;
149 p->size = s;
150 p->count = 1;
151 p->dir = dir;
152 if(dir==IOREQ_WRITE) //write;
153 p->u.data = *val;
154 p->pdata_valid = 0;
155 p->type = 1;
156 p->df = 0;
158 set_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags);
159 p->state = STATE_IOREQ_READY;
160 evtchn_send(iopacket_port(v));
161 vmx_wait_io();
162 if(dir==IOREQ_READ){ //read
163 *val=p->u.data;
164 }
165 return;
166 }
167 #define TO_LEGACY_IO(pa) (((pa)>>12<<2)|((pa)&0x3))
169 static void legacy_io_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir)
170 {
171 struct vcpu *v = current;
172 vcpu_iodata_t *vio;
173 ioreq_t *p;
175 vio = get_vio(v->domain, v->vcpu_id);
176 if (vio == 0) {
177 panic_domain(NULL,"bad shared page\n");
178 }
179 p = &vio->vp_ioreq;
180 p->addr = TO_LEGACY_IO(pa&0x3ffffffUL);
181 p->size = s;
182 p->count = 1;
183 p->dir = dir;
184 if(dir==IOREQ_WRITE) //write;
185 p->u.data = *val;
186 p->pdata_valid = 0;
187 p->type = 0;
188 p->df = 0;
190 set_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags);
191 p->state = STATE_IOREQ_READY;
192 evtchn_send(iopacket_port(v));
194 vmx_wait_io();
195 if(dir==IOREQ_READ){ //read
196 *val=p->u.data;
197 }
198 #ifdef DEBUG_PCI
199 if(dir==IOREQ_WRITE)
200 if(p->addr == 0xcf8UL)
201 printk("Write 0xcf8, with val [0x%lx]\n", p->u.data);
202 else
203 if(p->addr == 0xcfcUL)
204 printk("Read 0xcfc, with val [0x%lx]\n", p->u.data);
205 #endif //DEBUG_PCI
206 return;
207 }
209 extern struct vmx_mmio_handler vioapic_mmio_handler;
210 static void mmio_access(VCPU *vcpu, u64 src_pa, u64 *dest, size_t s, int ma, int dir)
211 {
212 struct virtual_platform_def *v_plat;
213 //mmio_type_t iot;
214 unsigned long iot;
215 struct vmx_mmio_handler *vioapic_handler = &vioapic_mmio_handler;
216 iot=__gpfn_is_io(vcpu->domain, src_pa>>PAGE_SHIFT);
217 v_plat = vmx_vcpu_get_plat(vcpu);
219 switch (iot) {
220 case GPFN_PIB:
221 if(!dir)
222 pib_write(vcpu, dest, src_pa - v_plat->pib_base, s, ma);
223 else
224 pib_read(vcpu, src_pa - v_plat->pib_base, dest, s, ma);
225 break;
226 case GPFN_GFW:
227 break;
228 case GPFN_IOSAPIC:
229 if (!dir)
230 vioapic_handler->write_handler(vcpu, src_pa, s, *dest);
231 else
232 *dest = vioapic_handler->read_handler(vcpu, src_pa, s);
233 break;
234 case GPFN_FRAME_BUFFER:
235 case GPFN_LOW_MMIO:
236 low_mmio_access(vcpu, src_pa, dest, s, dir);
237 break;
238 case GPFN_LEGACY_IO:
239 legacy_io_access(vcpu, src_pa, dest, s, dir);
240 break;
241 default:
242 panic_domain(NULL,"Bad I/O access\n");
243 break;
244 }
245 return;
246 }
248 /*
249 * Read or write data in guest virtual address mode.
250 */
251 /*
252 void
253 memwrite_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s)
254 {
255 uint64_t pa;
257 if (!vtlb->nomap)
258 panic("Normal memory write shouldn't go to this point!");
259 pa = PPN_2_PA(vtlb->ppn);
260 pa += POFFSET((u64)dest, vtlb->ps);
261 mmio_write (vcpu, src, pa, s, vtlb->ma);
262 }
265 void
266 memwrite_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s)
267 {
268 uint64_t pa = (uint64_t)dest;
269 int ma;
271 if ( pa & (1UL <<63) ) {
272 // UC
273 ma = 4;
274 pa <<=1;
275 pa >>=1;
276 }
277 else {
278 // WBL
279 ma = 0; // using WB for WBL
280 }
281 mmio_write (vcpu, src, pa, s, ma);
282 }
284 void
285 memread_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s)
286 {
287 uint64_t pa;
289 if (!vtlb->nomap)
290 panic_domain(NULL,"Normal memory write shouldn't go to this point!");
291 pa = PPN_2_PA(vtlb->ppn);
292 pa += POFFSET((u64)src, vtlb->ps);
294 mmio_read(vcpu, pa, dest, s, vtlb->ma);
295 }
297 void
298 memread_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s)
299 {
300 uint64_t pa = (uint64_t)src;
301 int ma;
303 if ( pa & (1UL <<63) ) {
304 // UC
305 ma = 4;
306 pa <<=1;
307 pa >>=1;
308 }
309 else {
310 // WBL
311 ma = 0; // using WB for WBL
312 }
313 mmio_read(vcpu, pa, dest, s, ma);
314 }
315 */
318 /*
319 * Deliver IPI message. (Only U-VP is supported now)
320 * offset: address offset to IPI space.
321 * value: deliver value.
322 */
323 static void deliver_ipi (VCPU *vcpu, uint64_t dm, uint64_t vector)
324 {
325 #ifdef IPI_DEBUG
326 printf ("deliver_ipi %lx %lx\n",dm,vector);
327 #endif
328 switch ( dm ) {
329 case 0: // INT
330 vmx_vcpu_pend_interrupt (vcpu, vector);
331 break;
332 case 2: // PMI
333 // TODO -- inject guest PMI
334 panic_domain (NULL, "Inject guest PMI!\n");
335 break;
336 case 4: // NMI
337 vmx_vcpu_pend_interrupt (vcpu, 2);
338 break;
339 case 5: // INIT
340 // TODO -- inject guest INIT
341 panic_domain (NULL, "Inject guest INIT!\n");
342 break;
343 case 7: // ExtINT
344 vmx_vcpu_pend_interrupt (vcpu, 0);
345 break;
346 case 1:
347 case 3:
348 case 6:
349 default:
350 panic_domain (NULL, "Deliver reserved IPI!\n");
351 break;
352 }
353 }
355 /*
356 * TODO: Use hash table for the lookup.
357 */
358 static inline VCPU *lid_2_vcpu (struct domain *d, u64 id, u64 eid)
359 {
360 int i;
361 VCPU *vcpu;
362 LID lid;
363 for (i=0; i<MAX_VIRT_CPUS; i++) {
364 vcpu = d->vcpu[i];
365 if (!vcpu)
366 continue;
367 lid.val = VCPU_LID(vcpu);
368 if ( lid.id == id && lid.eid == eid )
369 return vcpu;
370 }
371 return NULL;
372 }
374 /*
375 * execute write IPI op.
376 */
377 static void write_ipi (VCPU *vcpu, uint64_t addr, uint64_t value)
378 {
379 VCPU *targ;
380 struct domain *d=vcpu->domain;
381 targ = lid_2_vcpu(vcpu->domain,
382 ((ipi_a_t)addr).id, ((ipi_a_t)addr).eid);
383 if ( targ == NULL ) panic_domain (NULL,"Unknown IPI cpu\n");
385 if (!test_bit(_VCPUF_initialised, &targ->vcpu_flags)) {
386 struct pt_regs *targ_regs = vcpu_regs (targ);
387 struct vcpu_guest_context c;
389 memset (&c, 0, sizeof (c));
391 if (arch_set_info_guest (targ, &c) != 0) {
392 printf ("arch_boot_vcpu: failure\n");
393 return;
394 }
395 /* First or next rendez-vous: set registers. */
396 vcpu_init_regs (targ);
397 targ_regs->cr_iip = d->arch.sal_data->boot_rdv_ip;
398 targ_regs->r1 = d->arch.sal_data->boot_rdv_r1;
400 if (test_and_clear_bit(_VCPUF_down,&targ->vcpu_flags)) {
401 vcpu_wake(targ);
402 printf ("arch_boot_vcpu: vcpu %d awaken %016lx!\n",
403 targ->vcpu_id, targ_regs->cr_iip);
404 }
405 else
406 printf ("arch_boot_vcpu: huu, already awaken!");
407 }
408 else {
409 int running = test_bit(_VCPUF_running,&targ->vcpu_flags);
410 deliver_ipi (targ, ((ipi_d_t)value).dm,
411 ((ipi_d_t)value).vector);
412 vcpu_unblock(targ);
413 if (running)
414 smp_send_event_check_cpu(targ->processor);
415 }
416 return;
417 }
420 /*
421 dir 1: read 0:write
422 inst_type 0:integer 1:floating point
423 */
424 #define SL_INTEGER 0 // store/load interger
425 #define SL_FLOATING 1 // store/load floating
427 void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma)
428 {
429 REGS *regs;
430 IA64_BUNDLE bundle;
431 int slot, dir=0, inst_type;
432 size_t size;
433 u64 data, value,post_update, slot1a, slot1b, temp;
434 INST64 inst;
435 regs=vcpu_regs(vcpu);
436 if (IA64_RETRY == __vmx_get_domain_bundle(regs->cr_iip, &bundle)) {
437 /* if fetch code fail, return and try again */
438 return;
439 }
440 slot = ((struct ia64_psr *)&(regs->cr_ipsr))->ri;
441 if (!slot) inst.inst = bundle.slot0;
442 else if (slot == 1){
443 slot1a=bundle.slot1a;
444 slot1b=bundle.slot1b;
445 inst.inst =slot1a + (slot1b<<18);
446 }
447 else if (slot == 2) inst.inst = bundle.slot2;
450 // Integer Load/Store
451 if(inst.M1.major==4&&inst.M1.m==0&&inst.M1.x==0){
452 inst_type = SL_INTEGER; //
453 size=(inst.M1.x6&0x3);
454 if((inst.M1.x6>>2)>0xb){ // write
455 dir=IOREQ_WRITE; //write
456 vcpu_get_gr_nat(vcpu,inst.M4.r2,&data);
457 }else if((inst.M1.x6>>2)<0xb){ // read
458 dir=IOREQ_READ;
459 vcpu_get_gr_nat(vcpu,inst.M1.r1,&value);
460 }
461 }
462 // Integer Load + Reg update
463 else if(inst.M2.major==4&&inst.M2.m==1&&inst.M2.x==0){
464 inst_type = SL_INTEGER;
465 dir = IOREQ_READ; //write
466 size = (inst.M2.x6&0x3);
467 vcpu_get_gr_nat(vcpu,inst.M2.r1,&value);
468 vcpu_get_gr_nat(vcpu,inst.M2.r3,&temp);
469 vcpu_get_gr_nat(vcpu,inst.M2.r2,&post_update);
470 temp += post_update;
471 vcpu_set_gr(vcpu,inst.M2.r3,temp,0);
472 }
473 // Integer Load/Store + Imm update
474 else if(inst.M3.major==5){
475 inst_type = SL_INTEGER; //
476 size=(inst.M3.x6&0x3);
477 if((inst.M5.x6>>2)>0xb){ // write
478 dir=IOREQ_WRITE; //write
479 vcpu_get_gr_nat(vcpu,inst.M5.r2,&data);
480 vcpu_get_gr_nat(vcpu,inst.M5.r3,&temp);
481 post_update = (inst.M5.i<<7)+inst.M5.imm7;
482 if(inst.M5.s)
483 temp -= post_update;
484 else
485 temp += post_update;
486 vcpu_set_gr(vcpu,inst.M5.r3,temp,0);
488 }else if((inst.M3.x6>>2)<0xb){ // read
489 dir=IOREQ_READ;
490 vcpu_get_gr_nat(vcpu,inst.M3.r1,&value);
491 vcpu_get_gr_nat(vcpu,inst.M3.r3,&temp);
492 post_update = (inst.M3.i<<7)+inst.M3.imm7;
493 if(inst.M3.s)
494 temp -= post_update;
495 else
496 temp += post_update;
497 vcpu_set_gr(vcpu,inst.M3.r3,temp,0);
499 }
500 }
501 // Floating-point spill
502 else if (inst.M9.major == 6 && inst.M9.x6 == 0x3B &&
503 inst.M9.m == 0 && inst.M9.x == 0) {
504 struct ia64_fpreg v;
506 inst_type = SL_FLOATING;
507 dir = IOREQ_WRITE;
508 vcpu_get_fpreg(vcpu, inst.M9.f2, &v);
509 /* Write high word.
510 FIXME: this is a kludge! */
511 v.u.bits[1] &= 0x3ffff;
512 mmio_access(vcpu, padr + 8, &v.u.bits[1], 8, ma, IOREQ_WRITE);
513 data = v.u.bits[0];
514 size = 3;
515 }
516 // Floating-point spill + Imm update
517 else if(inst.M10.major==7&&inst.M10.x6==0x3B){
518 struct ia64_fpreg v;
519 inst_type=SL_FLOATING;
520 dir=IOREQ_WRITE;
521 vcpu_get_fpreg(vcpu,inst.M10.f2,&v);
522 vcpu_get_gr_nat(vcpu,inst.M10.r3,&temp);
523 post_update = (inst.M10.i<<7)+inst.M10.imm7;
524 if(inst.M10.s)
525 temp -= post_update;
526 else
527 temp += post_update;
528 vcpu_set_gr(vcpu,inst.M10.r3,temp,0);
530 /* Write high word.
531 FIXME: this is a kludge! */
532 v.u.bits[1] &= 0x3ffff;
533 mmio_access(vcpu, padr + 8, &v.u.bits[1], 8, ma, IOREQ_WRITE);
534 data = v.u.bits[0];
535 size = 3;
536 }
537 // Floating-point stf8 + Imm update
538 else if(inst.M10.major==7&&inst.M10.x6==0x31){
539 struct ia64_fpreg v;
540 inst_type=SL_FLOATING;
541 dir=IOREQ_WRITE;
542 size=3;
543 vcpu_get_fpreg(vcpu,inst.M10.f2,&v);
544 data = v.u.bits[0]; /* Significand. */
545 vcpu_get_gr_nat(vcpu,inst.M10.r3,&temp);
546 post_update = (inst.M10.i<<7)+inst.M10.imm7;
547 if(inst.M10.s)
548 temp -= post_update;
549 else
550 temp += post_update;
551 vcpu_set_gr(vcpu,inst.M10.r3,temp,0);
552 }
553 // else if(inst.M6.major==6&&inst.M6.m==0&&inst.M6.x==0&&inst.M6.x6==3){
554 // inst_type=SL_FLOATING; //fp
555 // dir=IOREQ_READ;
556 // size=3; //ldfd
557 // }
558 // lfetch - do not perform accesses.
559 else if(inst.M15.major==7&&inst.M15.x6>=0x2c&&inst.M15.x6<=0x2f){
560 vcpu_get_gr_nat(vcpu,inst.M15.r3,&temp);
561 post_update = (inst.M15.i<<7)+inst.M15.imm7;
562 if(inst.M15.s)
563 temp -= post_update;
564 else
565 temp += post_update;
566 vcpu_set_gr(vcpu,inst.M15.r3,temp,0);
568 vmx_vcpu_increment_iip(vcpu);
569 return;
570 }
571 // Floating-point Load Pair + Imm ldfp8 M12
572 else if(inst.M12.major==6&&inst.M12.m==1&&inst.M12.x==1&&inst.M12.x6==1){
573 struct ia64_fpreg v;
574 inst_type=SL_FLOATING;
575 dir = IOREQ_READ;
576 size = 8; //ldfd
577 mmio_access(vcpu, padr, &data, size, ma, dir);
578 v.u.bits[0]=data;
579 v.u.bits[1]=0x1003E;
580 vcpu_set_fpreg(vcpu,inst.M12.f1,&v);
581 padr += 8;
582 mmio_access(vcpu, padr, &data, size, ma, dir);
583 v.u.bits[0]=data;
584 v.u.bits[1]=0x1003E;
585 vcpu_set_fpreg(vcpu,inst.M12.f2,&v);
586 padr += 8;
587 vcpu_set_gr(vcpu,inst.M12.r3,padr,0);
588 vmx_vcpu_increment_iip(vcpu);
589 return;
590 }
591 else{
592 panic_domain
593 (NULL,"This memory access instr can't be emulated: %lx pc=%lx\n ",
594 inst.inst, regs->cr_iip);
595 }
597 size = 1 << size;
598 if(dir==IOREQ_WRITE){
599 mmio_access(vcpu, padr, &data, size, ma, dir);
600 }else{
601 mmio_access(vcpu, padr, &data, size, ma, dir);
602 if(size==1)
603 data = (value & 0xffffffffffffff00U) | (data & 0xffU);
604 else if(size==2)
605 data = (value & 0xffffffffffff0000U) | (data & 0xffffU);
606 else if(size==4)
607 data = (value & 0xffffffff00000000U) | (data & 0xffffffffU);
609 if(inst_type==SL_INTEGER){ //gp
610 vcpu_set_gr(vcpu,inst.M1.r1,data,0);
611 }else{
612 panic_domain(NULL, "Don't support ldfd now !");
613 /* switch(inst.M6.f1){
615 case 6:
616 regs->f6=(struct ia64_fpreg)data;
617 case 7:
618 regs->f7=(struct ia64_fpreg)data;
619 case 8:
620 regs->f8=(struct ia64_fpreg)data;
621 case 9:
622 regs->f9=(struct ia64_fpreg)data;
623 case 10:
624 regs->f10=(struct ia64_fpreg)data;
625 case 11:
626 regs->f11=(struct ia64_fpreg)data;
627 default :
628 ia64_ldfs(inst.M6.f1,&data);
629 }
630 */
631 }
632 }
633 vmx_vcpu_increment_iip(vcpu);
634 }