direct-io.hg

view tools/ioemu/target-i386-dm/helper2.c @ 14411:670aef15eb55

hvm ioemu: Add support for IOREQ_TYPE_XCHG in qemu-dm.

From: Trolle Selander <trolle.selander@gmail.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Fri Mar 16 16:22:29 2007 +0000 (2007-03-16)
parents eedbddf55e51
children 7e431ea834a8
line source
1 /*
2 * i386 helpers (without register variable usage)
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
21 /*
22 * Main cpu loop for handling I/O requests coming from a virtual machine
23 * Copyright 2004, Intel Corporation.
24 * Copyright 2005, International Business Machines Corporation.
25 *
26 * This program is free software; you can redistribute it and/or modify it
27 * under the terms and conditions of the GNU Lesser General Public License,
28 * version 2.1, as published by the Free Software Foundation.
29 *
30 * This program is distributed in the hope it will be useful, but WITHOUT
31 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
32 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
33 * more details.
34 *
35 * You should have received a copy of the GNU Lesser General Public License
36 * along with this program; if not, write to the Free Software Foundation,
37 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA.
38 */
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <inttypes.h>
44 #include <signal.h>
45 #include <assert.h>
47 #include <limits.h>
48 #include <fcntl.h>
50 #include <xenctrl.h>
51 #include <xen/hvm/ioreq.h>
53 #include "cpu.h"
54 #include "exec-all.h"
56 //#define DEBUG_MMU
58 #ifdef USE_CODE_COPY
59 #include <asm/ldt.h>
60 #include <linux/unistd.h>
61 #include <linux/version.h>
63 _syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount)
65 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66)
66 #define modify_ldt_ldt_s user_desc
67 #endif
68 #endif /* USE_CODE_COPY */
70 #include "vl.h"
72 int domid = -1;
73 int vcpus = 1;
75 int xc_handle;
77 shared_iopage_t *shared_page = NULL;
79 #define BUFFER_IO_MAX_DELAY 100
80 buffered_iopage_t *buffered_io_page = NULL;
81 QEMUTimer *buffered_io_timer;
83 /* the evtchn fd for polling */
84 int xce_handle = -1;
86 /* which vcpu we are serving */
87 int send_vcpu = 0;
89 //the evtchn port for polling the notification,
90 #define NR_CPUS 32
91 evtchn_port_t ioreq_local_port[NR_CPUS];
93 CPUX86State *cpu_x86_init(void)
94 {
95 CPUX86State *env;
96 static int inited;
97 int i, rc;
99 env = qemu_mallocz(sizeof(CPUX86State));
100 if (!env)
101 return NULL;
102 cpu_exec_init(env);
104 /* init various static tables */
105 if (!inited) {
106 inited = 1;
108 cpu_single_env = env;
110 xce_handle = xc_evtchn_open();
111 if (xce_handle == -1) {
112 perror("open");
113 return NULL;
114 }
116 /* FIXME: how about if we overflow the page here? */
117 for (i = 0; i < vcpus; i++) {
118 rc = xc_evtchn_bind_interdomain(
119 xce_handle, domid, shared_page->vcpu_iodata[i].vp_eport);
120 if (rc == -1) {
121 fprintf(logfile, "bind interdomain ioctl error %d\n", errno);
122 return NULL;
123 }
124 ioreq_local_port[i] = rc;
125 }
126 }
128 return env;
129 }
131 /* called from main_cpu_reset */
132 void cpu_reset(CPUX86State *env)
133 {
134 int xcHandle;
135 int sts;
137 /* pause domain first, to avoid repeated reboot request*/
138 xc_domain_pause(xc_handle, domid);
140 xcHandle = xc_interface_open();
141 if (xcHandle < 0)
142 fprintf(logfile, "Cannot acquire xenctrl handle\n");
143 else {
144 sts = xc_domain_shutdown(xcHandle, domid, SHUTDOWN_reboot);
145 if (sts != 0)
146 fprintf(logfile,
147 "? xc_domain_shutdown failed to issue reboot, sts %d\n",
148 sts);
149 else
150 fprintf(logfile, "Issued domain %d reboot\n", domid);
151 xc_interface_close(xcHandle);
152 }
153 }
155 void cpu_x86_close(CPUX86State *env)
156 {
157 free(env);
158 }
161 void cpu_dump_state(CPUState *env, FILE *f,
162 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
163 int flags)
164 {
165 }
167 /***********************************************************/
168 /* x86 mmu */
169 /* XXX: add PGE support */
171 void cpu_x86_set_a20(CPUX86State *env, int a20_state)
172 {
173 a20_state = (a20_state != 0);
174 if (a20_state != ((env->a20_mask >> 20) & 1)) {
175 #if defined(DEBUG_MMU)
176 printf("A20 update: a20=%d\n", a20_state);
177 #endif
178 env->a20_mask = 0xffefffff | (a20_state << 20);
179 }
180 }
182 target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
183 {
184 return addr;
185 }
187 //some functions to handle the io req packet
188 void sp_info()
189 {
190 ioreq_t *req;
191 int i;
193 for (i = 0; i < vcpus; i++) {
194 req = &(shared_page->vcpu_iodata[i].vp_ioreq);
195 term_printf("vcpu %d: event port %d\n", i, ioreq_local_port[i]);
196 term_printf(" req state: %x, ptr: %x, addr: %"PRIx64", "
197 "data: %"PRIx64", count: %"PRIx64", size: %"PRIx64"\n",
198 req->state, req->data_is_ptr, req->addr,
199 req->data, req->count, req->size);
200 term_printf(" IO totally occurred on this vcpu: %"PRIx64"\n",
201 req->io_count);
202 }
203 }
205 //get the ioreq packets from share mem
206 static ioreq_t *__cpu_get_ioreq(int vcpu)
207 {
208 ioreq_t *req;
210 req = &(shared_page->vcpu_iodata[vcpu].vp_ioreq);
212 if (req->state != STATE_IOREQ_READY) {
213 fprintf(logfile, "I/O request not ready: "
214 "%x, ptr: %x, port: %"PRIx64", "
215 "data: %"PRIx64", count: %"PRIx64", size: %"PRIx64"\n",
216 req->state, req->data_is_ptr, req->addr,
217 req->data, req->count, req->size);
218 return NULL;
219 }
221 rmb(); /* see IOREQ_READY /then/ read contents of ioreq */
223 req->state = STATE_IOREQ_INPROCESS;
224 return req;
225 }
227 //use poll to get the port notification
228 //ioreq_vec--out,the
229 //retval--the number of ioreq packet
230 static ioreq_t *cpu_get_ioreq(void)
231 {
232 int i;
233 evtchn_port_t port;
235 port = xc_evtchn_pending(xce_handle);
236 if (port != -1) {
237 for ( i = 0; i < vcpus; i++ )
238 if ( ioreq_local_port[i] == port )
239 break;
241 if ( i == vcpus ) {
242 fprintf(logfile, "Fatal error while trying to get io event!\n");
243 exit(1);
244 }
246 // unmask the wanted port again
247 xc_evtchn_unmask(xce_handle, port);
249 //get the io packet from shared memory
250 send_vcpu = i;
251 return __cpu_get_ioreq(i);
252 }
254 //read error or read nothing
255 return NULL;
256 }
258 unsigned long do_inp(CPUState *env, unsigned long addr, unsigned long size)
259 {
260 switch(size) {
261 case 1:
262 return cpu_inb(env, addr);
263 case 2:
264 return cpu_inw(env, addr);
265 case 4:
266 return cpu_inl(env, addr);
267 default:
268 fprintf(logfile, "inp: bad size: %lx %lx\n", addr, size);
269 exit(-1);
270 }
271 }
273 void do_outp(CPUState *env, unsigned long addr,
274 unsigned long size, unsigned long val)
275 {
276 switch(size) {
277 case 1:
278 return cpu_outb(env, addr, val);
279 case 2:
280 return cpu_outw(env, addr, val);
281 case 4:
282 return cpu_outl(env, addr, val);
283 default:
284 fprintf(logfile, "outp: bad size: %lx %lx\n", addr, size);
285 exit(-1);
286 }
287 }
289 extern void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
290 int len, int is_write);
292 static inline void read_physical(uint64_t addr, unsigned long size, void *val)
293 {
294 return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 0);
295 }
297 static inline void write_physical(uint64_t addr, unsigned long size, void *val)
298 {
299 return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 1);
300 }
302 void cpu_ioreq_pio(CPUState *env, ioreq_t *req)
303 {
304 int i, sign;
306 sign = req->df ? -1 : 1;
308 if (req->dir == IOREQ_READ) {
309 if (!req->data_is_ptr) {
310 req->data = do_inp(env, req->addr, req->size);
311 } else {
312 unsigned long tmp;
314 for (i = 0; i < req->count; i++) {
315 tmp = do_inp(env, req->addr, req->size);
316 write_physical((target_phys_addr_t) req->data
317 + (sign * i * req->size),
318 req->size, &tmp);
319 }
320 }
321 } else if (req->dir == IOREQ_WRITE) {
322 if (!req->data_is_ptr) {
323 do_outp(env, req->addr, req->size, req->data);
324 } else {
325 for (i = 0; i < req->count; i++) {
326 unsigned long tmp;
328 read_physical((target_phys_addr_t) req->data
329 + (sign * i * req->size),
330 req->size, &tmp);
331 do_outp(env, req->addr, req->size, tmp);
332 }
333 }
334 }
335 }
337 void cpu_ioreq_move(CPUState *env, ioreq_t *req)
338 {
339 int i, sign;
341 sign = req->df ? -1 : 1;
343 if (!req->data_is_ptr) {
344 if (req->dir == IOREQ_READ) {
345 for (i = 0; i < req->count; i++) {
346 read_physical(req->addr
347 + (sign * i * req->size),
348 req->size, &req->data);
349 }
350 } else if (req->dir == IOREQ_WRITE) {
351 for (i = 0; i < req->count; i++) {
352 write_physical(req->addr
353 + (sign * i * req->size),
354 req->size, &req->data);
355 }
356 }
357 } else {
358 unsigned long tmp;
360 if (req->dir == IOREQ_READ) {
361 for (i = 0; i < req->count; i++) {
362 read_physical(req->addr
363 + (sign * i * req->size),
364 req->size, &tmp);
365 write_physical((target_phys_addr_t )req->data
366 + (sign * i * req->size),
367 req->size, &tmp);
368 }
369 } else if (req->dir == IOREQ_WRITE) {
370 for (i = 0; i < req->count; i++) {
371 read_physical((target_phys_addr_t) req->data
372 + (sign * i * req->size),
373 req->size, &tmp);
374 write_physical(req->addr
375 + (sign * i * req->size),
376 req->size, &tmp);
377 }
378 }
379 }
380 }
382 void cpu_ioreq_and(CPUState *env, ioreq_t *req)
383 {
384 unsigned long tmp1, tmp2;
386 if (req->data_is_ptr != 0)
387 hw_error("expected scalar value");
389 read_physical(req->addr, req->size, &tmp1);
390 if (req->dir == IOREQ_WRITE) {
391 tmp2 = tmp1 & (unsigned long) req->data;
392 write_physical(req->addr, req->size, &tmp2);
393 }
394 req->data = tmp1;
395 }
397 void cpu_ioreq_add(CPUState *env, ioreq_t *req)
398 {
399 unsigned long tmp1, tmp2;
401 if (req->data_is_ptr != 0)
402 hw_error("expected scalar value");
404 read_physical(req->addr, req->size, &tmp1);
405 if (req->dir == IOREQ_WRITE) {
406 tmp2 = tmp1 + (unsigned long) req->data;
407 write_physical(req->addr, req->size, &tmp2);
408 }
409 req->data = tmp1;
410 }
412 void cpu_ioreq_or(CPUState *env, ioreq_t *req)
413 {
414 unsigned long tmp1, tmp2;
416 if (req->data_is_ptr != 0)
417 hw_error("expected scalar value");
419 read_physical(req->addr, req->size, &tmp1);
420 if (req->dir == IOREQ_WRITE) {
421 tmp2 = tmp1 | (unsigned long) req->data;
422 write_physical(req->addr, req->size, &tmp2);
423 }
424 req->data = tmp1;
425 }
427 void cpu_ioreq_xor(CPUState *env, ioreq_t *req)
428 {
429 unsigned long tmp1, tmp2;
431 if (req->data_is_ptr != 0)
432 hw_error("expected scalar value");
434 read_physical(req->addr, req->size, &tmp1);
435 if (req->dir == IOREQ_WRITE) {
436 tmp2 = tmp1 ^ (unsigned long) req->data;
437 write_physical(req->addr, req->size, &tmp2);
438 }
439 req->data = tmp1;
440 }
442 void cpu_ioreq_xchg(CPUState *env, ioreq_t *req)
443 {
444 unsigned long tmp1;
446 if (req->data_is_ptr != 0)
447 hw_error("expected scalar value");
449 read_physical(req->addr, req->size, &tmp1);
450 write_physical(req->addr, req->size, &req->data);
451 req->data = tmp1;
452 }
454 void __handle_ioreq(CPUState *env, ioreq_t *req)
455 {
456 if (!req->data_is_ptr && req->dir == IOREQ_WRITE && req->size != 4)
457 req->data &= (1UL << (8 * req->size)) - 1;
459 switch (req->type) {
460 case IOREQ_TYPE_PIO:
461 cpu_ioreq_pio(env, req);
462 break;
463 case IOREQ_TYPE_COPY:
464 cpu_ioreq_move(env, req);
465 break;
466 case IOREQ_TYPE_AND:
467 cpu_ioreq_and(env, req);
468 break;
469 case IOREQ_TYPE_ADD:
470 cpu_ioreq_add(env, req);
471 break;
472 case IOREQ_TYPE_OR:
473 cpu_ioreq_or(env, req);
474 break;
475 case IOREQ_TYPE_XOR:
476 cpu_ioreq_xor(env, req);
477 break;
478 case IOREQ_TYPE_XCHG:
479 cpu_ioreq_xchg(env, req);
480 break;
481 default:
482 hw_error("Invalid ioreq type 0x%x\n", req->type);
483 }
484 }
486 void __handle_buffered_iopage(CPUState *env)
487 {
488 ioreq_t *req = NULL;
490 if (!buffered_io_page)
491 return;
493 while (buffered_io_page->read_pointer !=
494 buffered_io_page->write_pointer) {
495 req = &buffered_io_page->ioreq[buffered_io_page->read_pointer %
496 IOREQ_BUFFER_SLOT_NUM];
498 __handle_ioreq(env, req);
500 mb();
501 buffered_io_page->read_pointer++;
502 }
503 }
505 void handle_buffered_io(void *opaque)
506 {
507 CPUState *env = opaque;
509 __handle_buffered_iopage(env);
510 qemu_mod_timer(buffered_io_timer, BUFFER_IO_MAX_DELAY +
511 qemu_get_clock(rt_clock));
512 }
514 void cpu_handle_ioreq(void *opaque)
515 {
516 extern int vm_running;
517 extern int shutdown_requested;
518 CPUState *env = opaque;
519 ioreq_t *req = cpu_get_ioreq();
521 handle_buffered_io(env);
522 if (req) {
523 __handle_ioreq(env, req);
525 if (req->state != STATE_IOREQ_INPROCESS) {
526 fprintf(logfile, "Badness in I/O request ... not in service?!: "
527 "%x, ptr: %x, port: %"PRIx64", "
528 "data: %"PRIx64", count: %"PRIx64", size: %"PRIx64"\n",
529 req->state, req->data_is_ptr, req->addr,
530 req->data, req->count, req->size);
531 destroy_hvm_domain();
532 return;
533 }
535 wmb(); /* Update ioreq contents /then/ update state. */
537 /*
538 * We do this before we send the response so that the tools
539 * have the opportunity to pick up on the reset before the
540 * guest resumes and does a hlt with interrupts disabled which
541 * causes Xen to powerdown the domain.
542 */
543 if (vm_running) {
544 if (shutdown_requested) {
545 fprintf(logfile, "shutdown requested in cpu_handle_ioreq\n");
546 destroy_hvm_domain();
547 }
548 if (reset_requested) {
549 fprintf(logfile, "reset requested in cpu_handle_ioreq.\n");
550 qemu_system_reset();
551 reset_requested = 0;
552 }
553 }
555 req->state = STATE_IORESP_READY;
556 xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]);
557 }
558 }
560 int main_loop(void)
561 {
562 extern int vm_running;
563 extern int shutdown_requested;
564 extern int suspend_requested;
565 CPUState *env = cpu_single_env;
566 int evtchn_fd = xc_evtchn_fd(xce_handle);
568 buffered_io_timer = qemu_new_timer(rt_clock, handle_buffered_io,
569 cpu_single_env);
570 qemu_mod_timer(buffered_io_timer, qemu_get_clock(rt_clock));
572 qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, env);
574 while (1) {
575 if (vm_running) {
576 if (shutdown_requested)
577 break;
578 if (reset_requested) {
579 qemu_system_reset();
580 reset_requested = 0;
581 }
582 if (suspend_requested) {
583 fprintf(logfile, "device model received suspend signal!\n");
584 break;
585 }
586 }
588 /* Wait up to 10 msec. */
589 main_loop_wait(10);
590 }
591 if (!suspend_requested)
592 destroy_hvm_domain();
593 else {
594 char qemu_file[20];
595 ioreq_t *req;
596 int rc;
598 sprintf(qemu_file, "/tmp/xen.qemu-dm.%d", domid);
599 xc_domain_pause(xc_handle, domid);
601 /* Pull all outstanding ioreqs through the system */
602 handle_buffered_io(env);
603 main_loop_wait(1); /* For the select() on events */
605 /* Stop the IDE thread */
606 ide_stop_dma_thread();
608 /* Make sure that all outstanding IO responses are handled too */
609 if ( xc_hvm_drain_io(xc_handle, domid) != 0 )
610 {
611 fprintf(stderr, "error clearing ioreq rings (%s)\n",
612 strerror(errno));
613 return -1;
614 }
616 /* Save the device state */
617 if (qemu_savevm(qemu_file) < 0)
618 fprintf(stderr, "qemu save fail.\n");
619 }
621 return 0;
622 }
624 void destroy_hvm_domain(void)
625 {
626 int xcHandle;
627 int sts;
629 xcHandle = xc_interface_open();
630 if (xcHandle < 0)
631 fprintf(logfile, "Cannot acquire xenctrl handle\n");
632 else {
633 sts = xc_domain_shutdown(xcHandle, domid, SHUTDOWN_poweroff);
634 if (sts != 0)
635 fprintf(logfile, "? xc_domain_shutdown failed to issue poweroff, "
636 "sts %d, errno %d\n", sts, errno);
637 else
638 fprintf(logfile, "Issued domain %d poweroff\n", domid);
639 xc_interface_close(xcHandle);
640 }
641 }