debuggers.hg

view xen/arch/x86/vmx_platform.c @ 3607:cd26f113b1b1

bitkeeper revision 1.1159.231.12 (41f97ef6r1c2TDcgR-o8jFV1IWm5dA)

Lean decoder for MMIO instructions.

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