direct-io.hg

view xen/arch/ia64/vmx/mmio.c @ 14153:a9d246105752

Accelerate IDE PIO on HVM/IA64 [3/3]

Add a bufferring mechanism for IDE PIO in a hypervisor.

Signed-off-by: Kouya Shimura <kouya@jp.fujitsu.com>
author kfraser@localhost.localdomain
date Tue Feb 27 15:34:55 2007 +0000 (2007-02-27)
parents db72b85b81bb
children 4ca4374eabd5
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 <xen/mm.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/vmx.h>
34 #include <public/event_channel.h>
35 #include <public/xen.h>
36 #include <linux/event.h>
37 #include <xen/domain.h>
38 #include <asm/viosapic.h>
39 #include <asm/vlsapic.h>
41 #define HVM_BUFFERED_IO_RANGE_NR 1
43 struct hvm_buffered_io_range {
44 unsigned long start_addr;
45 unsigned long length;
46 };
48 static struct hvm_buffered_io_range buffered_stdvga_range = {0xA0000, 0x20000};
49 static struct hvm_buffered_io_range
50 *hvm_buffered_io_ranges[HVM_BUFFERED_IO_RANGE_NR] =
51 {
52 &buffered_stdvga_range
53 };
55 int hvm_buffered_io_intercept(ioreq_t *p)
56 {
57 struct vcpu *v = current;
58 spinlock_t *buffered_io_lock;
59 buffered_iopage_t *buffered_iopage =
60 (buffered_iopage_t *)(v->domain->arch.hvm_domain.buffered_io_va);
61 unsigned long tmp_write_pointer = 0;
62 int i;
64 /* ignore READ ioreq_t! */
65 if ( p->dir == IOREQ_READ )
66 return 0;
68 for ( i = 0; i < HVM_BUFFERED_IO_RANGE_NR; i++ ) {
69 if ( p->addr >= hvm_buffered_io_ranges[i]->start_addr &&
70 p->addr + p->size - 1 < hvm_buffered_io_ranges[i]->start_addr +
71 hvm_buffered_io_ranges[i]->length )
72 break;
73 }
75 if ( i == HVM_BUFFERED_IO_RANGE_NR )
76 return 0;
78 buffered_io_lock = &v->domain->arch.hvm_domain.buffered_io_lock;
79 spin_lock(buffered_io_lock);
81 if ( buffered_iopage->write_pointer - buffered_iopage->read_pointer ==
82 (unsigned long)IOREQ_BUFFER_SLOT_NUM ) {
83 /* the queue is full.
84 * send the iopacket through the normal path.
85 * NOTE: The arithimetic operation could handle the situation for
86 * write_pointer overflow.
87 */
88 spin_unlock(buffered_io_lock);
89 return 0;
90 }
92 tmp_write_pointer = buffered_iopage->write_pointer % IOREQ_BUFFER_SLOT_NUM;
94 memcpy(&buffered_iopage->ioreq[tmp_write_pointer], p, sizeof(ioreq_t));
96 /*make the ioreq_t visible before write_pointer*/
97 wmb();
98 buffered_iopage->write_pointer++;
100 spin_unlock(buffered_io_lock);
102 return 1;
103 }
106 static void low_mmio_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir)
107 {
108 struct vcpu *v = current;
109 vcpu_iodata_t *vio;
110 ioreq_t *p;
112 vio = get_vio(v->domain, v->vcpu_id);
113 if (vio == 0) {
114 panic_domain(NULL,"bad shared page: %lx", (unsigned long)vio);
115 }
116 p = &vio->vp_ioreq;
117 p->addr = pa;
118 p->size = s;
119 p->count = 1;
120 p->dir = dir;
121 if(dir==IOREQ_WRITE) //write;
122 p->data = *val;
123 p->data_is_ptr = 0;
124 p->type = 1;
125 p->df = 0;
127 p->io_count++;
128 if(hvm_buffered_io_intercept(p)){
129 p->state = STATE_IORESP_READY;
130 vmx_io_assist(v);
131 return ;
132 }else
133 vmx_send_assist_req(v);
134 if(dir==IOREQ_READ){ //read
135 *val=p->data;
136 }
137 return;
138 }
140 int vmx_ide_pio_intercept(ioreq_t *p, u64 *val)
141 {
142 struct buffered_piopage *pio_page =
143 (void *)(current->domain->arch.hvm_domain.buffered_pio_va);
144 struct pio_buffer *piobuf;
145 uint32_t pointer, page_offset;
147 if (p->addr == 0x1F0)
148 piobuf = &pio_page->pio[PIO_BUFFER_IDE_PRIMARY];
149 else if (p->addr == 0x170)
150 piobuf = &pio_page->pio[PIO_BUFFER_IDE_SECONDARY];
151 else
152 return 0;
154 if (p->size != 2 && p->size != 4)
155 return 0;
157 pointer = piobuf->pointer;
158 page_offset = piobuf->page_offset;
160 /* sanity check */
161 if (page_offset + pointer < offsetof(struct buffered_piopage, buffer))
162 return 0;
163 if (page_offset + piobuf->data_end > PAGE_SIZE)
164 return 0;
166 if (pointer + p->size < piobuf->data_end) {
167 uint8_t *bufp = (uint8_t *)pio_page + page_offset + pointer;
168 if (p->dir == IOREQ_WRITE) {
169 if (likely(p->size == 4 && (((long)bufp & 3) == 0)))
170 *(uint32_t *)bufp = *val;
171 else
172 memcpy(bufp, val, p->size);
173 } else {
174 if (likely(p->size == 4 && (((long)bufp & 3) == 0))) {
175 *val = *(uint32_t *)bufp;
176 } else {
177 *val = 0;
178 memcpy(val, bufp, p->size);
179 }
180 }
181 piobuf->pointer += p->size;
182 p->state = STATE_IORESP_READY;
183 vmx_io_assist(current);
184 return 1;
185 }
186 return 0;
187 }
189 #define TO_LEGACY_IO(pa) (((pa)>>12<<2)|((pa)&0x3))
191 static void legacy_io_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir)
192 {
193 struct vcpu *v = current;
194 vcpu_iodata_t *vio;
195 ioreq_t *p;
197 vio = get_vio(v->domain, v->vcpu_id);
198 if (vio == 0) {
199 panic_domain(NULL,"bad shared page\n");
200 }
201 p = &vio->vp_ioreq;
202 p->addr = TO_LEGACY_IO(pa&0x3ffffffUL);
203 p->size = s;
204 p->count = 1;
205 p->dir = dir;
206 if(dir==IOREQ_WRITE) //write;
207 p->data = *val;
208 p->data_is_ptr = 0;
209 p->type = 0;
210 p->df = 0;
212 p->io_count++;
214 if (vmx_ide_pio_intercept(p, val))
215 return;
217 vmx_send_assist_req(v);
218 if(dir==IOREQ_READ){ //read
219 *val=p->data;
220 }
221 #ifdef DEBUG_PCI
222 if(dir==IOREQ_WRITE)
223 if(p->addr == 0xcf8UL)
224 printk("Write 0xcf8, with val [0x%lx]\n", p->data);
225 else
226 if(p->addr == 0xcfcUL)
227 printk("Read 0xcfc, with val [0x%lx]\n", p->data);
228 #endif //DEBUG_PCI
229 return;
230 }
232 static void mmio_access(VCPU *vcpu, u64 src_pa, u64 *dest, size_t s, int ma, int dir)
233 {
234 struct virtual_platform_def *v_plat;
235 //mmio_type_t iot;
236 unsigned long iot;
237 iot=__gpfn_is_io(vcpu->domain, src_pa>>PAGE_SHIFT);
238 v_plat = vmx_vcpu_get_plat(vcpu);
240 perfc_incra(vmx_mmio_access, iot >> 56);
241 switch (iot) {
242 case GPFN_PIB:
243 if (ma != 4)
244 panic_domain(NULL, "Access PIB not with UC attribute\n");
246 if (!dir)
247 vlsapic_write(vcpu, src_pa, s, *dest);
248 else
249 *dest = vlsapic_read(vcpu, src_pa, s);
250 break;
251 case GPFN_GFW:
252 break;
253 case GPFN_IOSAPIC:
254 if (!dir)
255 viosapic_write(vcpu, src_pa, s, *dest);
256 else
257 *dest = viosapic_read(vcpu, src_pa, s);
258 break;
259 case GPFN_FRAME_BUFFER:
260 case GPFN_LOW_MMIO:
261 low_mmio_access(vcpu, src_pa, dest, s, dir);
262 break;
263 case GPFN_LEGACY_IO:
264 legacy_io_access(vcpu, src_pa, dest, s, dir);
265 break;
266 default:
267 panic_domain(NULL,"Bad I/O access\n");
268 break;
269 }
270 return;
271 }
273 /*
274 dir 1: read 0:write
275 inst_type 0:integer 1:floating point
276 */
277 #define SL_INTEGER 0 // store/load interger
278 #define SL_FLOATING 1 // store/load floating
280 void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma)
281 {
282 REGS *regs;
283 IA64_BUNDLE bundle;
284 int slot, dir=0, inst_type;
285 size_t size;
286 u64 data, post_update, slot1a, slot1b, temp;
287 INST64 inst;
288 regs=vcpu_regs(vcpu);
289 if (IA64_RETRY == __vmx_get_domain_bundle(regs->cr_iip, &bundle)) {
290 /* if fetch code fail, return and try again */
291 return;
292 }
293 slot = ((struct ia64_psr *)&(regs->cr_ipsr))->ri;
294 if (!slot) inst.inst = bundle.slot0;
295 else if (slot == 1){
296 slot1a=bundle.slot1a;
297 slot1b=bundle.slot1b;
298 inst.inst =slot1a + (slot1b<<18);
299 }
300 else if (slot == 2) inst.inst = bundle.slot2;
303 // Integer Load/Store
304 if(inst.M1.major==4&&inst.M1.m==0&&inst.M1.x==0){
305 inst_type = SL_INTEGER; //
306 size=(inst.M1.x6&0x3);
307 if((inst.M1.x6>>2)>0xb){ // write
308 dir=IOREQ_WRITE; //write
309 vcpu_get_gr_nat(vcpu,inst.M4.r2,&data);
310 }else if((inst.M1.x6>>2)<0xb){ // read
311 dir=IOREQ_READ;
312 }
313 }
314 // Integer Load + Reg update
315 else if(inst.M2.major==4&&inst.M2.m==1&&inst.M2.x==0){
316 inst_type = SL_INTEGER;
317 dir = IOREQ_READ; //write
318 size = (inst.M2.x6&0x3);
319 vcpu_get_gr_nat(vcpu,inst.M2.r3,&temp);
320 vcpu_get_gr_nat(vcpu,inst.M2.r2,&post_update);
321 temp += post_update;
322 vcpu_set_gr(vcpu,inst.M2.r3,temp,0);
323 }
324 // Integer Load/Store + Imm update
325 else if(inst.M3.major==5){
326 inst_type = SL_INTEGER; //
327 size=(inst.M3.x6&0x3);
328 if((inst.M5.x6>>2)>0xb){ // write
329 dir=IOREQ_WRITE; //write
330 vcpu_get_gr_nat(vcpu,inst.M5.r2,&data);
331 vcpu_get_gr_nat(vcpu,inst.M5.r3,&temp);
332 post_update = (inst.M5.i<<7)+inst.M5.imm7;
333 if(inst.M5.s)
334 temp -= post_update;
335 else
336 temp += post_update;
337 vcpu_set_gr(vcpu,inst.M5.r3,temp,0);
339 }else if((inst.M3.x6>>2)<0xb){ // read
340 dir=IOREQ_READ;
341 vcpu_get_gr_nat(vcpu,inst.M3.r3,&temp);
342 post_update = (inst.M3.i<<7)+inst.M3.imm7;
343 if(inst.M3.s)
344 temp -= post_update;
345 else
346 temp += post_update;
347 vcpu_set_gr(vcpu,inst.M3.r3,temp,0);
349 }
350 }
351 // Floating-point spill
352 else if (inst.M9.major == 6 && inst.M9.x6 == 0x3B &&
353 inst.M9.m == 0 && inst.M9.x == 0) {
354 struct ia64_fpreg v;
356 inst_type = SL_FLOATING;
357 dir = IOREQ_WRITE;
358 vcpu_get_fpreg(vcpu, inst.M9.f2, &v);
359 /* Write high word.
360 FIXME: this is a kludge! */
361 v.u.bits[1] &= 0x3ffff;
362 mmio_access(vcpu, padr + 8, &v.u.bits[1], 8, ma, IOREQ_WRITE);
363 data = v.u.bits[0];
364 size = 3;
365 }
366 // Floating-point spill + Imm update
367 else if(inst.M10.major==7&&inst.M10.x6==0x3B){
368 struct ia64_fpreg v;
369 inst_type=SL_FLOATING;
370 dir=IOREQ_WRITE;
371 vcpu_get_fpreg(vcpu,inst.M10.f2,&v);
372 vcpu_get_gr_nat(vcpu,inst.M10.r3,&temp);
373 post_update = (inst.M10.i<<7)+inst.M10.imm7;
374 if(inst.M10.s)
375 temp -= post_update;
376 else
377 temp += post_update;
378 vcpu_set_gr(vcpu,inst.M10.r3,temp,0);
380 /* Write high word.
381 FIXME: this is a kludge! */
382 v.u.bits[1] &= 0x3ffff;
383 mmio_access(vcpu, padr + 8, &v.u.bits[1], 8, ma, IOREQ_WRITE);
384 data = v.u.bits[0];
385 size = 3;
386 }
387 // Floating-point stf8 + Imm update
388 else if(inst.M10.major==7&&inst.M10.x6==0x31){
389 struct ia64_fpreg v;
390 inst_type=SL_FLOATING;
391 dir=IOREQ_WRITE;
392 size=3;
393 vcpu_get_fpreg(vcpu,inst.M10.f2,&v);
394 data = v.u.bits[0]; /* Significand. */
395 vcpu_get_gr_nat(vcpu,inst.M10.r3,&temp);
396 post_update = (inst.M10.i<<7)+inst.M10.imm7;
397 if(inst.M10.s)
398 temp -= post_update;
399 else
400 temp += post_update;
401 vcpu_set_gr(vcpu,inst.M10.r3,temp,0);
402 }
403 // else if(inst.M6.major==6&&inst.M6.m==0&&inst.M6.x==0&&inst.M6.x6==3){
404 // inst_type=SL_FLOATING; //fp
405 // dir=IOREQ_READ;
406 // size=3; //ldfd
407 // }
408 // lfetch - do not perform accesses.
409 else if(inst.M15.major==7&&inst.M15.x6>=0x2c&&inst.M15.x6<=0x2f){
410 vcpu_get_gr_nat(vcpu,inst.M15.r3,&temp);
411 post_update = (inst.M15.i<<7)+inst.M15.imm7;
412 if(inst.M15.s)
413 temp -= post_update;
414 else
415 temp += post_update;
416 vcpu_set_gr(vcpu,inst.M15.r3,temp,0);
418 vcpu_increment_iip(vcpu);
419 return;
420 }
421 // Floating-point Load Pair + Imm ldfp8 M12
422 else if(inst.M12.major==6&&inst.M12.m==1&&inst.M12.x==1&&inst.M12.x6==1){
423 struct ia64_fpreg v;
424 inst_type=SL_FLOATING;
425 dir = IOREQ_READ;
426 size = 8; //ldfd
427 mmio_access(vcpu, padr, &data, size, ma, dir);
428 v.u.bits[0]=data;
429 v.u.bits[1]=0x1003E;
430 vcpu_set_fpreg(vcpu,inst.M12.f1,&v);
431 padr += 8;
432 mmio_access(vcpu, padr, &data, size, ma, dir);
433 v.u.bits[0]=data;
434 v.u.bits[1]=0x1003E;
435 vcpu_set_fpreg(vcpu,inst.M12.f2,&v);
436 padr += 8;
437 vcpu_set_gr(vcpu,inst.M12.r3,padr,0);
438 vcpu_increment_iip(vcpu);
439 return;
440 }
441 else{
442 panic_domain
443 (NULL,"This memory access instr can't be emulated: %lx pc=%lx\n ",
444 inst.inst, regs->cr_iip);
445 }
447 size = 1 << size;
448 if(dir==IOREQ_WRITE){
449 mmio_access(vcpu, padr, &data, size, ma, dir);
450 }else{
451 mmio_access(vcpu, padr, &data, size, ma, dir);
452 if(inst_type==SL_INTEGER){ //gp
453 vcpu_set_gr(vcpu,inst.M1.r1,data,0);
454 }else{
455 panic_domain(NULL, "Don't support ldfd now !");
456 /* switch(inst.M6.f1){
458 case 6:
459 regs->f6=(struct ia64_fpreg)data;
460 case 7:
461 regs->f7=(struct ia64_fpreg)data;
462 case 8:
463 regs->f8=(struct ia64_fpreg)data;
464 case 9:
465 regs->f9=(struct ia64_fpreg)data;
466 case 10:
467 regs->f10=(struct ia64_fpreg)data;
468 case 11:
469 regs->f11=(struct ia64_fpreg)data;
470 default :
471 ia64_ldfs(inst.M6.f1,&data);
472 }
473 */
474 }
475 }
476 vcpu_increment_iip(vcpu);
477 }