debuggers.hg

view xen/arch/x86/vmx_platform.c @ 3755:ea98f0bb6510

bitkeeper revision 1.1159.212.127 (4208b02bTdSR4AVYRg8diDkKZmIVUg)

General shadow code cleanup.

Fixed compilation problems when SHADOW_DEBUG is enabled.
Fixed compilation problems when CONFIG_VMX is undefined.

Simplified l1pte_write_fault and l1pte_read_fault.
Name change: spfn => smfn (shadow machine frame numbers).

In general, the terms pfn and gpfn now refer to pages in the
guest's idea of physical frames (which diffs for full shadow
guests). mfn always refers to a machine frame number.

One bug fix for check_pagetable():
If we're using writable page tables
along with shadow mode, don't check the currently writable page table
page -- check its snapshot instead.

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