ia64/xen-unstable

view tools/ioemu/target-i386-dm/helper2.c @ 6433:0610add7c3fe

merge?
author cl349@firebug.cl.cam.ac.uk
date Thu Aug 25 16:27:04 2005 +0000 (2005-08-25)
parents b54144915ae6 6e899a3840b2
children b4b3f6be5226
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 *
25 * This program is free software; you can redistribute it and/or modify it
26 * under the terms and conditions of the GNU Lesser General Public License,
27 * version 2.1, as published by the Free Software Foundation.
28 *
29 * This program is distributed in the hope it will be useful, but WITHOUT
30 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
31 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
32 * more details.
33 *
34 * You should have received a copy of the GNU Lesser General Public License
35 * along with this program; if not, write to the Free Software Foundation,
36 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA.
37 */
38 #include <stdarg.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <inttypes.h>
43 #include <signal.h>
44 #include <assert.h>
46 #include <limits.h>
47 #include <fcntl.h>
48 #include <sys/ioctl.h>
50 #include "xenctrl.h"
51 #include <io/ioreq.h>
53 #include "cpu.h"
54 #include "exec-all.h"
55 #include "vl.h"
57 shared_iopage_t *shared_page = NULL;
58 extern int reset_requested;
60 CPUX86State *cpu_86_init(void)
61 {
62 CPUX86State *env;
63 static int inited;
65 cpu_exec_init();
67 env = malloc(sizeof(CPUX86State));
68 if (!env)
69 return NULL;
70 memset(env, 0, sizeof(CPUX86State));
71 /* init various static tables */
72 if (!inited) {
73 inited = 1;
74 }
75 cpu_single_env = env;
76 cpu_reset(env);
77 return env;
78 }
80 /* NOTE: must be called outside the CPU execute loop */
81 void cpu_reset(CPUX86State *env)
82 {
83 }
85 void cpu_x86_close(CPUX86State *env)
86 {
87 free(env);
88 }
91 void cpu_dump_state(CPUState *env, FILE *f,
92 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
93 int flags)
94 {
95 }
97 /***********************************************************/
98 /* x86 mmu */
99 /* XXX: add PGE support */
101 void cpu_x86_set_a20(CPUX86State *env, int a20_state)
102 {
103 a20_state = (a20_state != 0);
104 if (a20_state != ((env->a20_mask >> 20) & 1)) {
105 #if defined(DEBUG_MMU)
106 printf("A20 update: a20=%d\n", a20_state);
107 #endif
108 env->a20_mask = 0xffefffff | (a20_state << 20);
109 }
110 }
112 target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
113 {
114 return addr;
115 }
117 //the evtchn fd for polling
118 int evtchn_fd = -1;
119 //the evtchn port for polling the notification, should be inputed as bochs's parameter
120 u16 ioreq_port = 0;
122 //some functions to handle the io req packet
123 void
124 sp_info()
125 {
126 ioreq_t *req;
128 req = &(shared_page->vcpu_iodata[0].vp_ioreq);
129 term_printf("event port: %d\n", shared_page->sp_global.eport);
130 term_printf("req state: %x, pvalid: %x, addr: %llx, data: %llx, count: %llx, size: %llx\n", req->state, req->pdata_valid, req->addr, req->u.data, req->count, req->size);
131 }
133 //get the ioreq packets from share mem
134 ioreq_t* __cpu_get_ioreq(void)
135 {
136 ioreq_t *req;
138 req = &(shared_page->vcpu_iodata[0].vp_ioreq);
139 if (req->state == STATE_IOREQ_READY) {
140 req->state = STATE_IOREQ_INPROCESS;
141 } else {
142 fprintf(logfile, "False I/O request ... in-service already: %x, pvalid: %x,port: %llx, data: %llx, count: %llx, size: %llx\n", req->state, req->pdata_valid, req->addr, req->u.data, req->count, req->size);
143 req = NULL;
144 }
146 return req;
147 }
149 //use poll to get the port notification
150 //ioreq_vec--out,the
151 //retval--the number of ioreq packet
152 ioreq_t* cpu_get_ioreq(void)
153 {
154 int rc;
155 u16 buf[2];
156 rc = read(evtchn_fd, buf, 2);
157 if (rc == 2 && buf[0] == ioreq_port){//got only one matched 16bit port index
158 // unmask the wanted port again
159 write(evtchn_fd, &ioreq_port, 2);
161 //get the io packet from shared memory
162 return __cpu_get_ioreq();
163 }
165 //read error or read nothing
166 return NULL;
167 }
169 unsigned long
170 do_inp(CPUState *env, unsigned long addr, unsigned long size)
171 {
172 switch(size) {
173 case 1:
174 return cpu_inb(env, addr);
175 case 2:
176 return cpu_inw(env, addr);
177 case 4:
178 return cpu_inl(env, addr);
179 default:
180 fprintf(logfile, "inp: bad size: %lx %lx\n", addr, size);
181 exit(-1);
182 }
183 }
185 void
186 do_outp(CPUState *env, unsigned long addr, unsigned long size,
187 unsigned long val)
188 {
189 switch(size) {
190 case 1:
191 return cpu_outb(env, addr, val);
192 case 2:
193 return cpu_outw(env, addr, val);
194 case 4:
195 return cpu_outl(env, addr, val);
196 default:
197 fprintf(logfile, "outp: bad size: %lx %lx\n", addr, size);
198 exit(-1);
199 }
200 }
202 extern void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
203 int len, int is_write);
205 static inline void
206 read_physical(target_phys_addr_t addr, unsigned long size, void *val)
207 {
208 return cpu_physical_memory_rw(addr, val, size, 0);
209 }
211 static inline void
212 write_physical(target_phys_addr_t addr, unsigned long size, void *val)
213 {
214 return cpu_physical_memory_rw(addr, val, size, 1);
215 }
217 //send the ioreq to device model
218 void cpu_dispatch_ioreq(CPUState *env, ioreq_t *req)
219 {
220 int i;
221 int sign;
223 sign = (req->df) ? -1 : 1;
225 if ((!req->pdata_valid) && (req->dir == IOREQ_WRITE)) {
226 if (req->size != 4) {
227 // Bochs expects higher bits to be 0
228 req->u.data &= (1UL << (8 * req->size))-1;
229 }
230 }
232 if (req->port_mm == 0){//port io
233 if(req->dir == IOREQ_READ){//read
234 if (!req->pdata_valid) {
235 req->u.data = do_inp(env, req->addr, req->size);
236 } else {
237 unsigned long tmp;
239 for (i = 0; i < req->count; i++) {
240 tmp = do_inp(env, req->addr, req->size);
241 write_physical((target_phys_addr_t)req->u.pdata + (sign * i * req->size),
242 req->size, &tmp);
243 }
244 }
245 } else if(req->dir == IOREQ_WRITE) {
246 if (!req->pdata_valid) {
247 do_outp(env, req->addr, req->size, req->u.data);
248 } else {
249 for (i = 0; i < req->count; i++) {
250 unsigned long tmp;
252 read_physical((target_phys_addr_t)req->u.pdata + (sign * i * req->size), req->size,
253 &tmp);
254 do_outp(env, req->addr, req->size, tmp);
255 }
256 }
258 }
259 } else if (req->port_mm == 1){//memory map io
260 if (!req->pdata_valid) {
261 //handle stos
262 if(req->dir == IOREQ_READ) { //read
263 for (i = 0; i < req->count; i++) {
264 read_physical((target_phys_addr_t)req->addr + (sign * i * req->size), req->size, &req->u.data);
265 }
266 } else if(req->dir == IOREQ_WRITE) { //write
267 for (i = 0; i < req->count; i++) {
268 write_physical((target_phys_addr_t)req->addr + (sign * i * req->size), req->size, &req->u.data);
269 }
270 }
271 } else {
272 //handle movs
273 unsigned long tmp;
274 if (req->dir == IOREQ_READ) {
275 for (i = 0; i < req->count; i++) {
276 read_physical((target_phys_addr_t)req->addr + (sign * i * req->size), req->size, &tmp);
277 write_physical((target_phys_addr_t)req->u.pdata + (sign * i * req->size), req->size, &tmp);
278 }
279 } else if (req->dir == IOREQ_WRITE) {
280 for (i = 0; i < req->count; i++) {
281 read_physical((target_phys_addr_t)req->u.pdata + (sign * i * req->size), req->size, &tmp);
282 write_physical((target_phys_addr_t)req->addr + (sign * i * req->size), req->size, &tmp);
283 }
284 }
285 }
286 }
287 /* No state change if state = STATE_IORESP_HOOK */
288 if (req->state == STATE_IOREQ_INPROCESS)
289 req->state = STATE_IORESP_READY;
290 env->send_event = 1;
291 }
293 void
294 cpu_handle_ioreq(CPUState *env)
295 {
296 ioreq_t *req = cpu_get_ioreq();
297 if (req)
298 cpu_dispatch_ioreq(env, req);
299 }
301 void
302 cpu_timer_handler(CPUState *env)
303 {
304 cpu_handle_ioreq(env);
305 }
307 int xc_handle;
309 static __inline__ void atomic_set_bit(long nr, volatile void *addr)
310 {
311 __asm__ __volatile__(
312 "lock ; bts %1,%0"
313 :"=m" (*(volatile long *)addr)
314 :"dIr" (nr));
315 }
317 void
318 do_interrupt(CPUState *env, int vector)
319 {
320 unsigned long *intr;
322 // Send a message on the event channel. Add the vector to the shared mem
323 // page.
324 intr = &(shared_page->sp_global.pic_intr[0]);
325 atomic_set_bit(vector, intr);
326 if (loglevel & CPU_LOG_INT)
327 fprintf(logfile, "injecting vector: %x\n", vector);
328 env->send_event = 1;
329 }
331 void
332 destroy_vmx_domain(void)
333 {
334 extern int domid;
335 extern FILE* logfile;
336 char destroy_cmd[20];
337 sprintf(destroy_cmd, "xm destroy %d", domid);
338 if (system(destroy_cmd) == -1)
339 fprintf(logfile, "%s failed.!\n", destroy_cmd);
340 }
342 int main_loop(void)
343 {
344 int vector;
345 fd_set rfds;
346 struct timeval tv;
347 extern CPUState *global_env;
348 extern int vm_running;
349 extern int shutdown_requested;
350 CPUState *env = global_env;
351 int retval;
352 extern void main_loop_wait(int);
354 /* Watch stdin (fd 0) to see when it has input. */
355 FD_ZERO(&rfds);
357 while (1) {
358 if (vm_running) {
359 if (shutdown_requested) {
360 break;
361 }
362 if (reset_requested){
363 qemu_system_reset();
364 reset_requested = 0;
365 }
366 }
368 /* Wait up to one seconds. */
369 tv.tv_sec = 0;
370 tv.tv_usec = 100000;
371 FD_SET(evtchn_fd, &rfds);
373 env->send_event = 0;
374 retval = select(evtchn_fd+1, &rfds, NULL, NULL, &tv);
375 if (retval == -1) {
376 perror("select");
377 return 0;
378 }
380 #if __WORDSIZE == 32
381 #define ULONGLONG_MAX 0xffffffffffffffffULL
382 #else
383 #define ULONGLONG_MAX ULONG_MAX
384 #endif
386 main_loop_wait(0);
387 #ifdef APIC_SUPPORT
388 ioapic_update_EOI();
389 #endif
390 cpu_timer_handler(env);
391 if (env->interrupt_request & CPU_INTERRUPT_HARD) {
392 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
393 vector = cpu_get_pic_interrupt(env);
394 do_interrupt(env, vector);
395 }
396 #ifdef APIC_SUPPORT
397 if (ioapic_has_intr())
398 do_ioapic();
399 #endif
400 if (env->send_event) {
401 int ret;
402 ret = xc_evtchn_send(xc_handle, ioreq_port);
403 if (ret == -1) {
404 fprintf(logfile, "evtchn_send failed on port: %d\n", ioreq_port);
405 }
406 }
407 }
408 destroy_vmx_domain();
409 return 0;
410 }
412 static void
413 qemu_vmx_reset(void *unused)
414 {
415 char cmd[255];
416 extern int domid;
418 /* pause domain first, to avoid repeated reboot request*/
419 xc_domain_pause (xc_handle, domid);
421 sprintf(cmd,"xm shutdown -R %d", domid);
422 system (cmd);
423 }
425 CPUState *
426 cpu_init()
427 {
428 CPUX86State *env;
430 cpu_exec_init();
431 qemu_register_reset(qemu_vmx_reset, NULL);
432 env = malloc(sizeof(CPUX86State));
433 if (!env)
434 return NULL;
435 memset(env, 0, sizeof(CPUX86State));
437 cpu_single_env = env;
439 if (evtchn_fd != -1)//the evtchn has been opened by another cpu object
440 return NULL;
442 //use nonblock reading not polling, may change in future.
443 evtchn_fd = open("/dev/xen/evtchn", O_RDWR|O_NONBLOCK);
444 if (evtchn_fd == -1) {
445 perror("open");
446 return NULL;
447 }
449 fprintf(logfile, "listening to port: %d\n", ioreq_port);
450 /*unmask the wanted port -- bind*/
451 if (ioctl(evtchn_fd, ('E'<<8)|2, ioreq_port) == -1) {
452 perror("ioctl");
453 return NULL;
454 }
456 return env;
457 }