debuggers.hg
annotate xen/arch/x86/vmx_platform.c @ 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
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 | d9cdcc864e90 b66cde79fd78 |
children | d3f0465c034e |
rev | line source |
---|---|
iap10@3607 | 1 /* |
iap10@3607 | 2 * vmx_platform.c: handling x86 platform related MMIO instructions |
iap10@3607 | 3 * Copyright (c) 2004, Intel Corporation. |
iap10@3607 | 4 * |
iap10@3607 | 5 * This program is free software; you can redistribute it and/or modify it |
iap10@3607 | 6 * under the terms and conditions of the GNU General Public License, |
iap10@3607 | 7 * version 2, as published by the Free Software Foundation. |
iap10@3607 | 8 * |
iap10@3607 | 9 * This program is distributed in the hope it will be useful, but WITHOUT |
iap10@3607 | 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
iap10@3607 | 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
iap10@3607 | 12 * more details. |
iap10@3607 | 13 * |
iap10@3607 | 14 * You should have received a copy of the GNU General Public License along with |
iap10@3607 | 15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
iap10@3607 | 16 * Place - Suite 330, Boston, MA 02111-1307 USA. |
iap10@3607 | 17 * |
iap10@3607 | 18 */ |
iap10@3607 | 19 |
iap10@3607 | 20 #include <xen/config.h> |
iap10@3607 | 21 #include <xen/types.h> |
iap10@3607 | 22 #include <xen/mm.h> |
iap10@3607 | 23 #include <asm/shadow.h> |
iap10@3607 | 24 #include <asm/domain_page.h> |
iap10@3607 | 25 #include <asm/page.h> |
iap10@3607 | 26 #include <xen/event.h> |
iap10@3607 | 27 #include <xen/trace.h> |
iap10@3607 | 28 #include <asm/vmx.h> |
iap10@3607 | 29 #include <asm/vmx_platform.h> |
iap10@3607 | 30 #include <public/io/ioreq.h> |
iap10@3607 | 31 |
iap10@3607 | 32 #include <xen/lib.h> |
iap10@3607 | 33 #include <xen/sched.h> |
iap10@3607 | 34 #include <asm/current.h> |
iap10@3607 | 35 |
iap10@3607 | 36 #define DECODE_success 1 |
iap10@3607 | 37 #define DECODE_failure 0 |
iap10@3607 | 38 |
iap10@3607 | 39 #if defined (__x86_64__) |
iap10@3607 | 40 static void store_xen_regs(struct xen_regs *regs) |
iap10@3607 | 41 { |
iap10@3607 | 42 |
iap10@3607 | 43 } |
iap10@3607 | 44 |
iap10@3607 | 45 static long get_reg_value(int size, int index, int seg, struct xen_regs *regs) |
iap10@3607 | 46 { |
iap10@3607 | 47 return 0; |
iap10@3607 | 48 } |
iap10@3607 | 49 #elif defined (__i386__) |
iap10@3607 | 50 static void store_xen_regs(struct xen_regs *regs) |
iap10@3607 | 51 { |
iap10@3607 | 52 __vmread(GUEST_SS_SELECTOR, ®s->ss); |
iap10@3607 | 53 __vmread(GUEST_ESP, ®s->esp); |
iap10@3607 | 54 __vmread(GUEST_EFLAGS, ®s->eflags); |
iap10@3607 | 55 __vmread(GUEST_CS_SELECTOR, ®s->cs); |
iap10@3607 | 56 __vmread(GUEST_EIP, ®s->eip); |
iap10@3607 | 57 } |
iap10@3607 | 58 |
iap10@3607 | 59 static long get_reg_value(int size, int index, int seg, struct xen_regs *regs) |
iap10@3607 | 60 { |
iap10@3607 | 61 /* |
iap10@3607 | 62 * Reference the db_reg[] table |
iap10@3607 | 63 */ |
iap10@3607 | 64 switch (size) { |
iap10@3607 | 65 case BYTE: |
iap10@3607 | 66 switch (index) { |
iap10@3607 | 67 case 0: //%al |
iap10@3607 | 68 return (char)(regs->eax & 0xFF); |
iap10@3607 | 69 case 1: //%cl |
iap10@3607 | 70 return (char)(regs->ecx & 0xFF); |
iap10@3607 | 71 case 2: //%dl |
iap10@3607 | 72 return (char)(regs->edx & 0xFF); |
iap10@3607 | 73 case 3: //%bl |
iap10@3607 | 74 return (char)(regs->ebx & 0xFF); |
iap10@3607 | 75 case 4: //%ah |
iap10@3607 | 76 return (char)((regs->eax & 0xFF00) >> 8); |
iap10@3607 | 77 case 5: //%ch |
iap10@3607 | 78 return (char)((regs->ecx & 0xFF00) >> 8); |
iap10@3607 | 79 case 6: //%dh |
iap10@3607 | 80 return (char)((regs->edx & 0xFF00) >> 8); |
iap10@3607 | 81 case 7: //%bh |
iap10@3607 | 82 return (char)((regs->ebx & 0xFF00) >> 8); |
iap10@3607 | 83 default: |
iap10@3607 | 84 printk("(get_reg_value)size case 0 error\n"); |
iap10@3607 | 85 return -1; |
iap10@3607 | 86 } |
iap10@3607 | 87 case WORD: |
iap10@3607 | 88 switch (index) { |
iap10@3607 | 89 case 0: //%ax |
iap10@3607 | 90 return (short)(regs->eax & 0xFFFF); |
iap10@3607 | 91 case 1: //%cx |
iap10@3607 | 92 return (short)(regs->ecx & 0xFFFF); |
iap10@3607 | 93 case 2: //%dx |
iap10@3607 | 94 return (short)(regs->edx & 0xFFFF); |
iap10@3607 | 95 case 3: //%bx |
iap10@3607 | 96 return (short)(regs->ebx & 0xFFFF); |
iap10@3607 | 97 case 4: //%sp |
iap10@3607 | 98 return (short)(regs->esp & 0xFFFF); |
iap10@3607 | 99 break; |
iap10@3607 | 100 case 5: //%bp |
iap10@3607 | 101 return (short)(regs->ebp & 0xFFFF); |
iap10@3607 | 102 case 6: //%si |
iap10@3607 | 103 return (short)(regs->esi & 0xFFFF); |
iap10@3607 | 104 case 7: //%di |
iap10@3607 | 105 return (short)(regs->edi & 0xFFFF); |
iap10@3607 | 106 default: |
iap10@3607 | 107 printk("(get_reg_value)size case 1 error\n"); |
iap10@3607 | 108 return -1; |
iap10@3607 | 109 } |
iap10@3607 | 110 case LONG: |
iap10@3607 | 111 switch (index) { |
iap10@3607 | 112 case 0: //%eax |
iap10@3607 | 113 return regs->eax; |
iap10@3607 | 114 case 1: //%ecx |
iap10@3607 | 115 return regs->ecx; |
iap10@3607 | 116 case 2: //%edx |
iap10@3607 | 117 return regs->edx; |
iap10@3607 | 118 |
iap10@3607 | 119 case 3: //%ebx |
iap10@3607 | 120 return regs->ebx; |
iap10@3607 | 121 case 4: //%esp |
iap10@3607 | 122 return regs->esp; |
iap10@3607 | 123 case 5: //%ebp |
iap10@3607 | 124 return regs->ebp; |
iap10@3607 | 125 case 6: //%esi |
iap10@3607 | 126 return regs->esi; |
iap10@3607 | 127 case 7: //%edi |
iap10@3607 | 128 return regs->edi; |
iap10@3607 | 129 default: |
iap10@3607 | 130 printk("(get_reg_value)size case 2 error\n"); |
iap10@3607 | 131 return -1; |
iap10@3607 | 132 } |
iap10@3607 | 133 default: |
iap10@3607 | 134 printk("(get_reg_value)size case error\n"); |
iap10@3607 | 135 return -1; |
iap10@3607 | 136 } |
iap10@3607 | 137 } |
iap10@3607 | 138 #endif |
iap10@3607 | 139 |
iap10@3607 | 140 static inline unsigned char *check_prefix(unsigned char *inst, struct instruction *thread_inst) |
iap10@3607 | 141 { |
iap10@3607 | 142 while (1) { |
iap10@3607 | 143 switch (*inst) { |
iap10@3607 | 144 case 0xf3: //REPZ |
iap10@3607 | 145 case 0xf2: //REPNZ |
iap10@3607 | 146 case 0xf0: //LOCK |
iap10@3607 | 147 case 0x2e: //CS |
iap10@3607 | 148 case 0x36: //SS |
iap10@3607 | 149 case 0x3e: //DS |
iap10@3607 | 150 case 0x26: //ES |
iap10@3607 | 151 case 0x64: //FS |
iap10@3607 | 152 case 0x65: //GS |
iap10@3607 | 153 break; |
iap10@3607 | 154 case 0x66: //32bit->16bit |
iap10@3607 | 155 thread_inst->op_size = WORD; |
iap10@3607 | 156 break; |
iap10@3607 | 157 case 0x67: |
iap10@3607 | 158 break; |
iap10@3607 | 159 default: |
iap10@3607 | 160 return inst; |
iap10@3607 | 161 } |
iap10@3607 | 162 inst++; |
iap10@3607 | 163 } |
iap10@3607 | 164 } |
iap10@3607 | 165 |
iap10@3607 | 166 static inline unsigned long get_immediate(const unsigned char *inst, int op_size) |
iap10@3607 | 167 { |
iap10@3607 | 168 int mod, reg, rm; |
iap10@3607 | 169 unsigned long val = 0; |
iap10@3607 | 170 int i; |
iap10@3607 | 171 |
iap10@3607 | 172 mod = (*inst >> 6) & 3; |
iap10@3607 | 173 reg = (*inst >> 3) & 7; |
iap10@3607 | 174 rm = *inst & 7; |
iap10@3607 | 175 |
iap10@3607 | 176 inst++; //skip ModR/M byte |
iap10@3607 | 177 if (mod != 3 && rm == 4) { |
iap10@3607 | 178 inst++; //skip SIB byte |
iap10@3607 | 179 } |
iap10@3607 | 180 |
iap10@3607 | 181 switch(mod) { |
iap10@3607 | 182 case 0: |
iap10@3607 | 183 if (rm == 5) { |
iap10@3607 | 184 inst = inst + 4; //disp32, skip 4 bytes |
iap10@3607 | 185 } |
iap10@3607 | 186 break; |
iap10@3607 | 187 case 1: |
iap10@3607 | 188 inst++; //disp8, skip 1 byte |
iap10@3607 | 189 break; |
iap10@3607 | 190 case 2: |
iap10@3607 | 191 inst = inst + 4; //disp32, skip 4 bytes |
iap10@3607 | 192 } |
iap10@3607 | 193 for (i = 0; i < op_size; i++) { |
iap10@3607 | 194 val |= (*inst++ & 0xff) << (8 * i); |
iap10@3607 | 195 } |
iap10@3607 | 196 |
iap10@3607 | 197 return val; |
iap10@3607 | 198 } |
iap10@3607 | 199 |
iap10@3607 | 200 static inline int get_index(const unsigned char *inst) |
iap10@3607 | 201 { |
iap10@3607 | 202 int mod, reg, rm; |
iap10@3607 | 203 |
iap10@3607 | 204 mod = (*inst >> 6) & 3; |
iap10@3607 | 205 reg = (*inst >> 3) & 7; |
iap10@3607 | 206 rm = *inst & 7; |
iap10@3607 | 207 |
iap10@3607 | 208 //Only one operand in the instruction is register |
iap10@3607 | 209 if (mod == 3) { |
iap10@3607 | 210 return rm; |
iap10@3607 | 211 } else { |
iap10@3607 | 212 return reg; |
iap10@3607 | 213 } |
iap10@3607 | 214 return 0; |
iap10@3607 | 215 } |
iap10@3607 | 216 |
iap10@3607 | 217 static int vmx_decode(const unsigned char *inst, struct instruction *thread_inst) |
iap10@3607 | 218 { |
iap10@3607 | 219 int index; |
iap10@3607 | 220 |
iap10@3607 | 221 switch(*inst) { |
iap10@3607 | 222 case 0x88: |
iap10@3607 | 223 /* mov r8 to m8 */ |
iap10@3607 | 224 thread_inst->op_size = BYTE; |
iap10@3607 | 225 index = get_index((inst + 1)); |
iap10@3607 | 226 thread_inst->operand[0] = mk_operand(BYTE, index, 0, REGISTER); |
iap10@3607 | 227 break; |
iap10@3607 | 228 case 0x89: |
iap10@3607 | 229 /* mov r32/16 to m32/16 */ |
iap10@3607 | 230 index = get_index((inst + 1)); |
iap10@3607 | 231 if (thread_inst->op_size == WORD) { |
iap10@3607 | 232 thread_inst->operand[0] = mk_operand(WORD, index, 0, REGISTER); |
iap10@3607 | 233 } else { |
iap10@3607 | 234 thread_inst->op_size = LONG; |
iap10@3607 | 235 thread_inst->operand[0] = mk_operand(LONG, index, 0, REGISTER); |
iap10@3607 | 236 } |
iap10@3607 | 237 break; |
iap10@3607 | 238 case 0x8a: |
iap10@3607 | 239 /* mov m8 to r8 */ |
iap10@3607 | 240 thread_inst->op_size = BYTE; |
iap10@3607 | 241 index = get_index((inst + 1)); |
iap10@3607 | 242 thread_inst->operand[1] = mk_operand(BYTE, index, 0, REGISTER); |
iap10@3607 | 243 break; |
iap10@3607 | 244 case 0x8b: |
iap10@3607 | 245 /* mov r32/16 to m32/16 */ |
iap10@3607 | 246 index = get_index((inst + 1)); |
iap10@3607 | 247 if (thread_inst->op_size == WORD) { |
iap10@3607 | 248 thread_inst->operand[1] = mk_operand(WORD, index, 0, REGISTER); |
iap10@3607 | 249 } else { |
iap10@3607 | 250 thread_inst->op_size = LONG; |
iap10@3607 | 251 thread_inst->operand[1] = mk_operand(LONG, index, 0, REGISTER); |
iap10@3607 | 252 } |
iap10@3607 | 253 break; |
iap10@3607 | 254 case 0x8c: |
iap10@3607 | 255 case 0x8e: |
iap10@3607 | 256 printk("%x, This opcode hasn't been handled yet!", *inst); |
iap10@3607 | 257 return DECODE_failure; |
iap10@3607 | 258 /* Not handle it yet. */ |
iap10@3607 | 259 |
iap10@3607 | 260 case 0xa0: |
iap10@3607 | 261 /* mov byte to al */ |
iap10@3607 | 262 thread_inst->op_size = BYTE; |
iap10@3607 | 263 thread_inst->operand[1] = mk_operand(BYTE, 0, 0, REGISTER); |
iap10@3607 | 264 break; |
iap10@3607 | 265 case 0xa1: |
iap10@3607 | 266 /* mov word/doubleword to ax/eax */ |
iap10@3607 | 267 if (thread_inst->op_size == WORD) { |
iap10@3607 | 268 thread_inst->operand[1] = mk_operand(WORD, 0, 0, REGISTER); |
iap10@3607 | 269 } else { |
iap10@3607 | 270 thread_inst->op_size = LONG; |
iap10@3607 | 271 thread_inst->operand[1] = mk_operand(LONG, 0, 0, REGISTER); |
iap10@3607 | 272 } |
iap10@3607 | 273 break; |
iap10@3607 | 274 case 0xa2: |
iap10@3607 | 275 /* mov al to (seg:offset) */ |
iap10@3607 | 276 thread_inst->op_size = BYTE; |
iap10@3607 | 277 thread_inst->operand[0] = mk_operand(BYTE, 0, 0, REGISTER); |
iap10@3607 | 278 break; |
iap10@3607 | 279 case 0xa3: |
iap10@3607 | 280 /* mov ax/eax to (seg:offset) */ |
iap10@3607 | 281 if (thread_inst->op_size == WORD) { |
iap10@3607 | 282 thread_inst->operand[0] = mk_operand(WORD, 0, 0, REGISTER); |
iap10@3607 | 283 } else { |
iap10@3607 | 284 thread_inst->op_size = LONG; |
iap10@3607 | 285 thread_inst->operand[0] = mk_operand(LONG, 0, 0, REGISTER); |
iap10@3607 | 286 } |
iap10@3607 | 287 break; |
iap10@3607 | 288 case 0xa4: |
iap10@3607 | 289 /* movsb */ |
iap10@3607 | 290 thread_inst->op_size = BYTE; |
iap10@3607 | 291 strcpy(thread_inst->i_name, "movs"); |
iap10@3607 | 292 |
iap10@3607 | 293 return DECODE_success; |
iap10@3607 | 294 case 0xa5: |
iap10@3607 | 295 /* movsw/movsl */ |
iap10@3607 | 296 if (thread_inst->op_size == WORD) { |
iap10@3607 | 297 } else { |
iap10@3607 | 298 thread_inst->op_size = LONG; |
iap10@3607 | 299 } |
iap10@3607 | 300 |
iap10@3607 | 301 strcpy(thread_inst->i_name, "movs"); |
iap10@3607 | 302 |
iap10@3607 | 303 return DECODE_success; |
iap10@3607 | 304 |
iap10@3607 | 305 case 0xc6: |
iap10@3607 | 306 /* mov imm8 to m8 */ |
iap10@3607 | 307 thread_inst->op_size = BYTE; |
iap10@3607 | 308 thread_inst->operand[0] = mk_operand(BYTE, 0, 0, IMMEDIATE); |
iap10@3607 | 309 thread_inst->immediate = get_immediate((inst+1), thread_inst->op_size); |
iap10@3607 | 310 break; |
iap10@3607 | 311 case 0xc7: |
iap10@3607 | 312 /* mov imm16/32 to m16/32 */ |
iap10@3607 | 313 if (thread_inst->op_size == WORD) { |
iap10@3607 | 314 thread_inst->operand[0] = mk_operand(WORD, 0, 0, IMMEDIATE); |
iap10@3607 | 315 } else { |
iap10@3607 | 316 thread_inst->op_size = LONG; |
iap10@3607 | 317 thread_inst->operand[0] = mk_operand(LONG, 0, 0, IMMEDIATE); |
iap10@3607 | 318 } |
iap10@3607 | 319 thread_inst->immediate = get_immediate((inst+1), thread_inst->op_size); |
iap10@3607 | 320 break; |
iap10@3607 | 321 |
iap10@3607 | 322 case 0x0f: |
iap10@3607 | 323 break; |
iap10@3607 | 324 default: |
iap10@3607 | 325 printk("%x, This opcode hasn't been handled yet!", *inst); |
iap10@3607 | 326 return DECODE_failure; |
iap10@3607 | 327 } |
iap10@3607 | 328 |
iap10@3607 | 329 strcpy(thread_inst->i_name, "mov"); |
iap10@3607 | 330 if (*inst != 0x0f) { |
iap10@3607 | 331 return DECODE_success; |
iap10@3607 | 332 } |
iap10@3607 | 333 |
iap10@3607 | 334 inst++; |
iap10@3607 | 335 switch (*inst) { |
iap10@3607 | 336 |
iap10@3607 | 337 /* movz */ |
iap10@3607 | 338 case 0xb7: |
iap10@3607 | 339 index = get_index((inst + 1)); |
iap10@3607 | 340 thread_inst->operand[1] = mk_operand(LONG, index, 0, REGISTER); |
iap10@3607 | 341 strcpy(thread_inst->i_name, "movzw"); |
iap10@3607 | 342 |
iap10@3607 | 343 return DECODE_success; |
iap10@3607 | 344 default: |
iap10@3607 | 345 printk("0f %x, This opcode hasn't been handled yet!", *inst); |
iap10@3607 | 346 return DECODE_failure; |
iap10@3607 | 347 } |
iap10@3607 | 348 |
iap10@3607 | 349 /* will never reach here */ |
iap10@3607 | 350 return DECODE_failure; |
iap10@3607 | 351 } |
iap10@3607 | 352 |
iap10@3607 | 353 static int inst_copy_from_guest(char *buf, unsigned long guest_eip, int inst_len) |
iap10@3607 | 354 { |
iap10@3607 | 355 unsigned long gpte; |
iap10@3607 | 356 unsigned long mfn; |
iap10@3607 | 357 unsigned long ma; |
iap10@3607 | 358 unsigned char * inst_start; |
iap10@3607 | 359 |
iap10@3607 | 360 if (inst_len > MAX_INST_LEN || inst_len <= 0) { |
iap10@3607 | 361 return 0; |
iap10@3607 | 362 } |
iap10@3607 | 363 |
iap10@3607 | 364 if ((guest_eip & PAGE_MASK) == ((guest_eip + inst_len) & PAGE_MASK)) { |
iap10@3607 | 365 if ( unlikely(__get_user(gpte, (unsigned long *) |
iap10@3607 | 366 &linear_pg_table[guest_eip >> PAGE_SHIFT])) ) |
iap10@3607 | 367 { |
iap10@3607 | 368 printk("inst_copy_from_guest- EXIT: read gpte faulted" ); |
iap10@3607 | 369 return 0; |
iap10@3607 | 370 } |
iap10@3607 | 371 mfn = phys_to_machine_mapping[gpte >> PAGE_SHIFT]; |
iap10@3607 | 372 ma = (mfn << PAGE_SHIFT) | (guest_eip & (PAGE_SIZE - 1)); |
iap10@3607 | 373 inst_start = (unsigned char *)map_domain_mem(ma); |
iap10@3607 | 374 |
iap10@3679 | 375 memcpy(buf, inst_start, inst_len); |
iap10@3607 | 376 unmap_domain_mem(inst_start); |
iap10@3607 | 377 } else { |
iap10@3607 | 378 // Todo: In two page frames |
iap10@3607 | 379 } |
iap10@3607 | 380 |
iap10@3607 | 381 return inst_len; |
iap10@3607 | 382 } |
iap10@3607 | 383 |
iap10@3607 | 384 static void init_instruction(struct instruction *mmio_inst) |
iap10@3607 | 385 { |
iap10@3607 | 386 memset(mmio_inst->i_name, '0', I_NAME_LEN); |
iap10@3607 | 387 mmio_inst->op_size = 0; |
iap10@3607 | 388 mmio_inst->offset = 0; |
iap10@3607 | 389 mmio_inst->immediate = 0; |
iap10@3607 | 390 mmio_inst->seg_sel = 0; |
iap10@3607 | 391 mmio_inst->op_num = 0; |
iap10@3607 | 392 |
iap10@3607 | 393 mmio_inst->operand[0] = 0; |
iap10@3607 | 394 mmio_inst->operand[1] = 0; |
iap10@3607 | 395 mmio_inst->operand[2] = 0; |
iap10@3607 | 396 |
iap10@3607 | 397 mmio_inst->flags = 0; |
iap10@3607 | 398 } |
iap10@3607 | 399 |
iap10@3607 | 400 static int read_from_mmio(struct instruction *inst_p) |
iap10@3607 | 401 { |
iap10@3607 | 402 // Only for mov instruction now!!! |
iap10@3607 | 403 if (inst_p->operand[1] & REGISTER) |
iap10@3607 | 404 return 1; |
iap10@3607 | 405 |
iap10@3607 | 406 return 0; |
iap10@3607 | 407 } |
iap10@3607 | 408 |
iap10@3607 | 409 // dir: 1 read from mmio |
iap10@3607 | 410 // 0 write to mmio |
iap10@3607 | 411 static void send_mmio_req(unsigned long gpa, |
iap10@3607 | 412 struct instruction *inst_p, long value, int dir, int pvalid) |
iap10@3607 | 413 { |
iap10@3607 | 414 struct exec_domain *d = current; |
iap10@3607 | 415 vcpu_iodata_t *vio; |
iap10@3607 | 416 ioreq_t *p; |
iap10@3607 | 417 struct mi_per_cpu_info *mpci_p; |
iap10@3607 | 418 struct xen_regs *inst_decoder_regs; |
iap10@3607 | 419 extern inline unsigned long gva_to_gpa(unsigned long gva); |
iap10@3607 | 420 extern long evtchn_send(int lport); |
iap10@3607 | 421 extern long do_block(void); |
iap10@3607 | 422 |
iap10@3607 | 423 mpci_p = ¤t->thread.arch_vmx.vmx_platform.mpci; |
iap10@3607 | 424 inst_decoder_regs = mpci_p->inst_decoder_regs; |
iap10@3607 | 425 vio = (vcpu_iodata_t *) d->thread.arch_vmx.vmx_platform.shared_page_va; |
iap10@3607 | 426 |
iap10@3607 | 427 if (vio == NULL) { |
iap10@3607 | 428 printk("bad shared page\n"); |
iap10@3607 | 429 domain_crash(); |
iap10@3607 | 430 } |
iap10@3607 | 431 p = &vio->vp_ioreq; |
iap10@3607 | 432 |
iap10@3607 | 433 set_bit(ARCH_VMX_IO_WAIT, &d->thread.arch_vmx.flags); |
iap10@3607 | 434 p->dir = dir; |
iap10@3607 | 435 p->pdata_valid = pvalid; |
iap10@3607 | 436 p->count = 1; |
iap10@3607 | 437 |
iap10@3607 | 438 p->port_mm = 1; |
iap10@3607 | 439 p->size = inst_p->op_size; |
iap10@3607 | 440 p->addr = gpa; |
iap10@3607 | 441 p->u.data = value; |
iap10@3607 | 442 |
iap10@3607 | 443 // p->state = STATE_UPSTREAM_SENDING; |
iap10@3607 | 444 p->state = STATE_IOREQ_READY; |
iap10@3607 | 445 |
iap10@3607 | 446 // Try to use ins/outs' framework |
iap10@3607 | 447 if (pvalid) { |
iap10@3607 | 448 // Handle "movs" |
iap10@3607 | 449 p->u.pdata = (void *) ((p->dir == IOREQ_WRITE) ? |
iap10@3607 | 450 inst_decoder_regs->esi |
iap10@3607 | 451 : inst_decoder_regs->edi); |
iap10@3607 | 452 p->u.pdata = (void *) gva_to_gpa(p->u.data); |
iap10@3607 | 453 p->count = inst_decoder_regs->ecx; |
iap10@3607 | 454 inst_decoder_regs->ecx = 0; |
iap10@3607 | 455 p->df = (inst_decoder_regs->eflags & EF_DF) ? 1 : 0; |
iap10@3607 | 456 } |
iap10@3607 | 457 |
iap10@3607 | 458 evtchn_send(IOPACKET_PORT); |
iap10@3607 | 459 do_block(); |
iap10@3607 | 460 |
iap10@3607 | 461 } |
iap10@3607 | 462 |
iap10@3607 | 463 void handle_mmio(unsigned long va, unsigned long gpte, unsigned long gpa) |
iap10@3607 | 464 { |
iap10@3607 | 465 unsigned long eip; |
iap10@3607 | 466 unsigned long inst_len; |
iap10@3607 | 467 struct mi_per_cpu_info *mpci_p; |
iap10@3607 | 468 struct xen_regs *inst_decoder_regs; |
iap10@3607 | 469 struct instruction mmio_inst; |
iap10@3607 | 470 unsigned char inst[MAX_INST_LEN]; |
iap10@3607 | 471 int ret; |
iap10@3607 | 472 |
iap10@3607 | 473 mpci_p = ¤t->thread.arch_vmx.vmx_platform.mpci; |
iap10@3607 | 474 inst_decoder_regs = mpci_p->inst_decoder_regs; |
iap10@3607 | 475 |
iap10@3607 | 476 __vmread(GUEST_EIP, &eip); |
iap10@3607 | 477 __vmread(INSTRUCTION_LEN, &inst_len); |
iap10@3607 | 478 |
iap10@3607 | 479 memset(inst, '0', MAX_INST_LEN); |
iap10@3607 | 480 ret = inst_copy_from_guest(inst, eip, inst_len); |
iap10@3607 | 481 if (ret != inst_len) { |
iap10@3607 | 482 printk("handle_mmio - EXIT: get guest instruction fault\n"); |
iap10@3607 | 483 domain_crash(); |
iap10@3607 | 484 } |
iap10@3607 | 485 |
iap10@3607 | 486 init_instruction(&mmio_inst); |
iap10@3607 | 487 |
iap10@3607 | 488 if (vmx_decode(check_prefix(inst, &mmio_inst), &mmio_inst) == DECODE_failure) |
iap10@3607 | 489 domain_crash(); |
iap10@3607 | 490 |
iap10@3607 | 491 __vmwrite(GUEST_EIP, eip + inst_len); |
iap10@3607 | 492 store_xen_regs(inst_decoder_regs); |
iap10@3607 | 493 |
iap10@3607 | 494 // Only handle "mov" and "movs" instructions! |
iap10@3607 | 495 if (!strncmp(mmio_inst.i_name, "movzw", 5)) { |
iap10@3607 | 496 long value = 0; |
iap10@3607 | 497 int index; |
iap10@3607 | 498 |
iap10@3607 | 499 if (read_from_mmio(&mmio_inst)) { |
iap10@3607 | 500 // Send the request and waiting for return value. |
iap10@3607 | 501 mpci_p->mmio_target = mmio_inst.operand[1] | WZEROEXTEND; |
iap10@3607 | 502 mmio_inst.op_size = WORD; |
iap10@3607 | 503 send_mmio_req(gpa, &mmio_inst, value, 1, 0); |
iap10@3607 | 504 } else { |
iap10@3607 | 505 // Write to MMIO |
iap10@3607 | 506 if (mmio_inst.operand[0] & IMMEDIATE) { |
iap10@3607 | 507 value = mmio_inst.immediate; |
iap10@3607 | 508 } else if (mmio_inst.operand[0] & REGISTER) { |
iap10@3607 | 509 index = operand_index(mmio_inst.operand[0]); |
iap10@3607 | 510 value = get_reg_value(WORD, index, 0, inst_decoder_regs); |
iap10@3607 | 511 } else { |
iap10@3607 | 512 domain_crash(); |
iap10@3607 | 513 } |
iap10@3607 | 514 mmio_inst.op_size = WORD; |
iap10@3607 | 515 send_mmio_req(gpa, &mmio_inst, value, 0, 0); |
iap10@3607 | 516 return; |
iap10@3607 | 517 } |
iap10@3607 | 518 } |
iap10@3607 | 519 |
iap10@3607 | 520 if (!strncmp(mmio_inst.i_name, "movs", 4)) { |
iap10@3607 | 521 int tmp_dir; |
iap10@3607 | 522 |
iap10@3607 | 523 tmp_dir = ((va == inst_decoder_regs->edi) ? IOREQ_WRITE : IOREQ_READ); |
iap10@3607 | 524 send_mmio_req(gpa, &mmio_inst, 0, tmp_dir, 1); |
iap10@3607 | 525 return; |
iap10@3607 | 526 } |
iap10@3607 | 527 |
iap10@3607 | 528 if (!strncmp(mmio_inst.i_name, "mov", 3)) { |
iap10@3607 | 529 long value = 0; |
iap10@3607 | 530 int size, index; |
iap10@3607 | 531 |
iap10@3607 | 532 if (read_from_mmio(&mmio_inst)) { |
iap10@3607 | 533 // Send the request and waiting for return value. |
iap10@3607 | 534 mpci_p->mmio_target = mmio_inst.operand[1]; |
iap10@3607 | 535 send_mmio_req(gpa, &mmio_inst, value, 1, 0); |
iap10@3607 | 536 } else { |
iap10@3607 | 537 // Write to MMIO |
iap10@3607 | 538 if (mmio_inst.operand[0] & IMMEDIATE) { |
iap10@3607 | 539 value = mmio_inst.immediate; |
iap10@3607 | 540 } else if (mmio_inst.operand[0] & REGISTER) { |
iap10@3607 | 541 size = operand_size(mmio_inst.operand[0]); |
iap10@3607 | 542 index = operand_index(mmio_inst.operand[0]); |
iap10@3607 | 543 value = get_reg_value(size, index, 0, inst_decoder_regs); |
iap10@3607 | 544 } else { |
iap10@3607 | 545 domain_crash(); |
iap10@3607 | 546 } |
iap10@3607 | 547 send_mmio_req(gpa, &mmio_inst, value, 0, 0); |
iap10@3607 | 548 return; |
iap10@3607 | 549 } |
iap10@3607 | 550 domain_crash(); |
iap10@3607 | 551 } |
iap10@3607 | 552 domain_crash(); |
iap10@3607 | 553 } |
iap10@3607 | 554 |