debuggers.hg

annotate tools/ioemu/iodev/cpu.cc @ 3680:26a00896163a

bitkeeper revision 1.1159.240.3 (4202bd17uoTYqnlSeqvW9fHjznmCHg)

Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno-xenod/BK/xen-unstable.bk
into labyrinth.cl.cam.ac.uk:/auto/groups/xeno/users/iap10/xeno-clone/xen-unstable.bk
author iap10@labyrinth.cl.cam.ac.uk
date Fri Feb 04 00:08:55 2005 +0000 (2005-02-04)
parents 5e111ac8c357 f89816eaeaad
children d3f0465c034e
rev   line source
iap10@3441 1 /*
iap10@3441 2 * Main cpu loop for handling I/O requests coming from a virtual machine
iap10@3441 3 * Copyright © 2004, Intel Corporation.
iap10@3441 4 *
iap10@3441 5 * This program is free software; you can redistribute it and/or modify it
iap10@3441 6 * under the terms and conditions of the GNU Lesser General Public License,
iap10@3441 7 * version 2.1, as published by the Free Software Foundation.
iap10@3441 8 *
iap10@3441 9 * This program is distributed in the hope it will be useful, but WITHOUT
iap10@3441 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
iap10@3441 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
iap10@3441 12 * more details.
iap10@3441 13 *
iap10@3441 14 * You should have received a copy of the GNU Lesser General Public License
iap10@3441 15 * along with this program; if not, write to the Free Software Foundation,
iap10@3441 16 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA.
iap10@3441 17 */
iap10@3441 18
iap10@3441 19 #include "bochs.h"
iap10@3441 20 #include <cpu/cpu.h>
iap10@3441 21 #ifdef BX_USE_VMX
iap10@3441 22 #include <sys/ioctl.h>
iap10@3441 23 /* According to POSIX 1003.1-2001 */
iap10@3441 24 #include <sys/select.h>
iap10@3441 25
iap10@3441 26 /* According to earlier standards */
iap10@3441 27 #include <sys/time.h>
iap10@3441 28 #include <sys/types.h>
iap10@3441 29 #include <unistd.h>
iap10@3441 30 #include <values.h>
iap10@3441 31 #endif
iap10@3441 32
iap10@3441 33 #define LOG_THIS BX_CPU_THIS_PTR
iap10@3441 34
iap10@3441 35 #ifdef BX_USE_VMX
iap10@3441 36
iap10@3441 37 //the evtchn fd for polling
iap10@3441 38 int evtchn_fd = -1;
iap10@3441 39 //the evtchn port for polling the notification, should be inputed as bochs's parameter
iap10@3441 40 u16 ioreq_port = 0;
iap10@3441 41
iap10@3441 42 void *shared_page = NULL;
iap10@3441 43
iap10@3441 44 //some functions to handle the io req packet
iap10@3441 45
iap10@3441 46 //get the ioreq packets from share mem
iap10@3441 47 ioreq_t* bx_cpu_c::__get_ioreq(void)
iap10@3441 48 {
iap10@3441 49 ioreq_t *req;
iap10@3441 50 req = &((vcpu_iodata_t *) shared_page)->vp_ioreq;
iap10@3441 51 if (req->state == STATE_IOREQ_READY) {
iap10@3441 52 req->state = STATE_IOREQ_INPROCESS;
iap10@3441 53 } else {
iap10@3441 54 BX_INFO(("False I/O requrest ... in-service already: %lx, pvalid: %lx,port: %lx, data: %lx, count: %lx, size: %lx\n", req->state, req->pdata_valid, req->addr, req->u.data, req->count, req->size));
iap10@3441 55 req = NULL;
iap10@3441 56 }
iap10@3441 57
iap10@3441 58 return req;
iap10@3441 59 }
iap10@3441 60
iap10@3441 61 //use poll to get the port notification
iap10@3441 62 //ioreq_vec--out,the
iap10@3441 63 //retval--the number of ioreq packet
iap10@3441 64 ioreq_t* bx_cpu_c::get_ioreq(void)
iap10@3441 65 {
iap10@3441 66 ioreq_t *req;
iap10@3441 67 int rc;
iap10@3441 68 u16 buf[2];
iap10@3441 69 rc = read(evtchn_fd, buf, 2);
iap10@3441 70 if (rc == 2 && buf[0] == ioreq_port){//got only one matched 16bit port index
iap10@3441 71 // unmask the wanted port again
iap10@3441 72 write(evtchn_fd, &ioreq_port, 2);
iap10@3441 73
iap10@3441 74 //get the io packet from shared memory
iap10@3441 75 return __get_ioreq();
iap10@3441 76 }
iap10@3441 77
iap10@3441 78 //read error or read nothing
iap10@3441 79 return NULL;
iap10@3441 80 }
iap10@3441 81
iap10@3441 82 //send the ioreq to device model
iap10@3441 83 void bx_cpu_c::dispatch_ioreq(ioreq_t *req)
iap10@3441 84 {
iap10@3441 85 int ret, i;
iap10@3622 86 int sign;
iap10@3622 87
iap10@3622 88 sign = (req->df) ? -1 : 1;
iap10@3441 89
iap10@3441 90 if ((!req->pdata_valid) && (req->dir == IOREQ_WRITE)) {
iap10@3441 91 if (req->size != 4) {
iap10@3441 92 // Bochs expects higher bits to be 0
iap10@3441 93 req->u.data &= (1UL << (8 * req->size))-1;
iap10@3441 94 }
iap10@3441 95 }
iap10@3441 96 if (req->port_mm == 0){//port io
iap10@3441 97 if(req->dir == IOREQ_READ){//read
iap10@3441 98 if (!req->pdata_valid)
iap10@3441 99 req->u.data = BX_INP(req->addr, req->size);
iap10@3441 100 else {
iap10@3441 101 unsigned long tmp;
iap10@3441 102
iap10@3441 103 for (i = 0; i < req->count; i++) {
iap10@3441 104 tmp = BX_INP(req->addr, req->size);
iap10@3622 105 BX_MEM_WRITE_PHYSICAL((Bit32u) req->u.pdata + (sign * i * req->size),
iap10@3441 106 req->size, &tmp);
iap10@3441 107 }
iap10@3441 108 }
iap10@3441 109 } else if(req->dir == IOREQ_WRITE) {
iap10@3441 110 if (!req->pdata_valid) {
iap10@3441 111 BX_OUTP(req->addr, (Bit32u) req->u.data, req->size);
iap10@3441 112 } else {
iap10@3441 113 for (i = 0; i < req->count; i++) {
iap10@3441 114 unsigned long tmp;
iap10@3441 115
iap10@3622 116 BX_MEM_READ_PHYSICAL((Bit32u) req->u.pdata + (sign * i * req->size), req->size,
iap10@3441 117 &tmp);
iap10@3441 118 BX_OUTP(req->addr, (Bit32u) tmp, req->size);
iap10@3441 119 }
iap10@3441 120 }
iap10@3441 121
iap10@3441 122 }
iap10@3441 123 } else if (req->port_mm == 1){//memory map io
iap10@3441 124 if (!req->pdata_valid) {
iap10@3441 125 if(req->dir == IOREQ_READ){//read
iap10@3441 126 BX_MEM_READ_PHYSICAL(req->addr, req->size, &req->u.data);
iap10@3441 127 } else if(req->dir == IOREQ_WRITE)//write
iap10@3441 128 BX_MEM_WRITE_PHYSICAL(req->addr, req->size, &req->u.data);
iap10@3441 129 } else {
iap10@3441 130 //handle movs
iap10@3441 131 unsigned long tmp;
iap10@3441 132 if (req->dir == IOREQ_READ) {
iap10@3441 133 //BX_INFO(("<READ>addr:%llx, pdata:%llx, size: %x, count: %x\n", req->addr, req->u.pdata, req->size, req->count));
iap10@3441 134 for (i = 0; i < req->count; i++) {
iap10@3622 135 BX_MEM_READ_PHYSICAL(req->addr + (sign * i * req->size), req->size, &tmp);
iap10@3622 136 BX_MEM_WRITE_PHYSICAL((Bit32u) req->u.pdata + (sign * i * req->size), req->size, &tmp);
iap10@3441 137 }
iap10@3441 138 } else if (req->dir == IOREQ_WRITE) {
iap10@3441 139 //BX_INFO(("<WRITE>addr:%llx, pdata:%llx, size: %x, count: %x\n", req->addr, req->u.pdata, req->size, req->count));
iap10@3441 140 for (i = 0; i < req->count; i++) {
iap10@3622 141 BX_MEM_READ_PHYSICAL((Bit32u)req->u.pdata + (sign * i * req->size), req->size, &tmp);
iap10@3622 142 BX_MEM_WRITE_PHYSICAL(req->addr + (sign * i * req->size), req->size, &tmp);
iap10@3441 143 }
iap10@3441 144 }
iap10@3441 145 }
iap10@3441 146 }
iap10@3441 147 req->state = STATE_IORESP_READY;
iap10@3441 148 send_event = 1;
iap10@3441 149 }
iap10@3441 150
iap10@3441 151 void
iap10@3441 152 bx_cpu_c::handle_ioreq(void)
iap10@3441 153 {
iap10@3441 154 ioreq_t *req = get_ioreq();
iap10@3441 155 if (req)
iap10@3441 156 dispatch_ioreq(req);
iap10@3441 157 }
iap10@3441 158
iap10@3441 159 void
iap10@3441 160 bx_cpu_c::timer_handler(void)
iap10@3441 161 {
iap10@3441 162 handle_ioreq();
iap10@3441 163 }
iap10@3441 164
iap10@3441 165 #endif
iap10@3441 166
iap10@3441 167 #define rdtscl(low) \
iap10@3441 168 __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx")
iap10@3441 169
iap10@3441 170 void
iap10@3441 171 bx_cpu_c::cpu_loop(int max_instr_count)
iap10@3441 172 {
iap10@3441 173 Bit8u vector;
iap10@3441 174 fd_set rfds;
iap10@3441 175 unsigned long stime_usec;
iap10@3441 176 struct timeval tv;
iap10@3441 177 int retval;
iap10@3441 178
iap10@3441 179 /* Watch stdin (fd 0) to see when it has input. */
iap10@3441 180 FD_ZERO(&rfds);
iap10@3441 181
iap10@3441 182 while (1) {
iap10@3441 183 unsigned long t1, t2;
iap10@3441 184
iap10@3441 185 /* Wait up to one seconds. */
iap10@3441 186 tv.tv_sec = 0;
iap10@3441 187 tv.tv_usec = 100000;
iap10@3441 188 FD_SET(evtchn_fd, &rfds);
iap10@3441 189
iap10@3441 190 send_event = 0;
iap10@3441 191 rdtscl(t1);
iap10@3441 192 retval = select(evtchn_fd+1, &rfds, NULL, NULL, &tv);
iap10@3441 193 rdtscl(t2);
iap10@3441 194 if (retval == -1) {
iap10@3441 195 perror("select");
iap10@3441 196 return;
iap10@3441 197 }
iap10@3441 198 //stime_usec = 1000000 * (1 - tv.tv_sec) - tv.tv_usec;
iap10@3441 199 if (t2 > t1)
iap10@3441 200 BX_TICKN((t2 - t1) / 2000); // should match ips in bochsrc
iap10@3441 201 else
iap10@3441 202 BX_TICKN((MAXINT - t1 + t2) / 2000); // should match ips in bochsrc
iap10@3441 203 timer_handler();
iap10@3441 204 if (BX_CPU_INTR) {
iap10@3441 205 #if BX_SUPPORT_APIC
iap10@3441 206 if (BX_CPU_THIS_PTR local_apic.INTR)
iap10@3441 207 vector = BX_CPU_THIS_PTR local_apic.acknowledge_int ();
iap10@3441 208 else
iap10@3441 209 vector = DEV_pic_iac(); // may set INTR with next interrupt
iap10@3441 210 #else
iap10@3441 211 // if no local APIC, always acknowledge the PIC.
iap10@3441 212 vector = DEV_pic_iac(); // may set INTR with next interrupt
iap10@3441 213 #endif
iap10@3441 214 interrupt(vector);
iap10@3441 215 }
iap10@3677 216 /* we check DMA after interrupt check*/
iap10@3677 217 while(BX_HRQ){
iap10@3677 218 DEV_dma_raise_hlda();
iap10@3677 219 }
iap10@3441 220
iap10@3441 221 if (send_event) {
iap10@3441 222 int ret;
iap10@3441 223 ret = xc_evtchn_send(xc_handle, ioreq_port);
iap10@3441 224 if (ret == -1) {
iap10@3441 225 BX_ERROR(("evtchn_send failed on port: %d\n", ioreq_port));
iap10@3441 226 }
iap10@3441 227 }
iap10@3441 228 }
iap10@3441 229 }
iap10@3441 230
iap10@3441 231 static __inline__ void set_bit(long nr, volatile void *addr)
iap10@3441 232 {
iap10@3441 233 __asm__ __volatile__( "lock ; "
iap10@3441 234 "btsl %1,%0"
iap10@3441 235 :"=m" ((*(volatile long *)addr))
iap10@3441 236 :"Ir" (nr));
iap10@3441 237
iap10@3441 238 return;
iap10@3441 239 }
iap10@3441 240
iap10@3441 241 void
iap10@3441 242 bx_cpu_c::interrupt(Bit8u vector)
iap10@3441 243 {
iap10@3441 244 unsigned long *intr, tscl;
iap10@3441 245 int ret;
iap10@3441 246
iap10@3441 247 // Send a message on the event channel. Add the vector to the shared mem
iap10@3441 248 // page.
iap10@3441 249
iap10@3441 250 rdtscl(tscl);
iap10@3441 251 BX_INFO(("%lx: injecting vector: %x\n", tscl, vector));
iap10@3441 252 intr = &(((vcpu_iodata_t *) shared_page)->vp_intr[0]);
iap10@3441 253 set_bit(vector, intr);
iap10@3441 254
iap10@3441 255 send_event = 1;
iap10@3441 256 }
iap10@3441 257
iap10@3441 258 void
iap10@3441 259 bx_cpu_c::init(bx_mem_c*)
iap10@3441 260 {
iap10@3441 261 #ifdef BX_USE_VMX
iap10@3441 262 if (evtchn_fd != -1)//the evtchn has been opened by another cpu object
iap10@3441 263 return;
iap10@3441 264
iap10@3441 265 //use nonblock reading not polling, may change in future.
iap10@3441 266 evtchn_fd = open("/dev/xen/evtchn", O_RDWR|O_NONBLOCK);
iap10@3441 267 if (evtchn_fd == -1) {
iap10@3441 268 perror("open");
iap10@3441 269 return;
iap10@3441 270 }
iap10@3441 271
iap10@3441 272 BX_INFO(("listening to port: %d\n", ioreq_port));
iap10@3441 273 /*unmask the wanted port -- bind*/
iap10@3441 274 if (ioctl(evtchn_fd, ('E'<<8)|2, ioreq_port) == -1) {
iap10@3441 275 perror("ioctl");
iap10@3441 276 return;
iap10@3441 277 }
iap10@3441 278
iap10@3441 279 #if 0
iap10@3441 280 //register the reading evtchn function as timer
iap10@3441 281 bx_pc_system.register_timer(this, timer_handler, 1000,//1000 us, may change
iap10@3441 282 1,//continuous timer
iap10@3441 283 1,//active
iap10@3441 284 "cpu reading evtchn handler");
iap10@3441 285 #endif
iap10@3441 286
iap10@3441 287 #endif
iap10@3441 288 }
iap10@3441 289
iap10@3441 290 void
iap10@3441 291 bx_cpu_c::reset(unsigned)
iap10@3441 292 {
iap10@3441 293 }
iap10@3441 294
iap10@3441 295 void
iap10@3441 296 bx_cpu_c::atexit()
iap10@3441 297 {
iap10@3441 298 }
iap10@3441 299
iap10@3441 300 void
iap10@3441 301 bx_cpu_c::set_INTR(unsigned value)
iap10@3441 302 {
iap10@3441 303 BX_CPU_THIS_PTR INTR = value;
iap10@3441 304 }
iap10@3441 305
iap10@3441 306 void
iap10@3441 307 bx_cpu_c::pagingA20Changed()
iap10@3441 308 {
iap10@3441 309 }
iap10@3441 310
iap10@3441 311 bx_cpu_c::bx_cpu_c()
iap10@3441 312 {
iap10@3441 313 }
iap10@3441 314
iap10@3441 315 bx_cpu_c::~bx_cpu_c()
iap10@3441 316 {
iap10@3441 317 }