2 * Copyright (c) 2008 Brent Stephens <brents@rice.edu>
3 * Copyright (c) 2008 Diego Ongaro <diego.ongaro@rice.edu>
4 * Copyright (c) 2008 Oleg Pesok <olegpesok@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 #include "libfkvm-common.h"
46 #define reg_size() _reg_size(regs, sregs)
47 #define test_repeat_noop() _test_repeat_noop(get_repeat_prefix(insn) == insn_rep_zero, \
49 #define test_repeat_tail() _test_repeat_tail(get_repeat_prefix(insn) == insn_rep_zero, \
53 cb_mmio_read(kvm_context_t kvm
,
59 if ((addr
& 0xFFF) + len
- 1 > 0xFFF) {
60 printf("mmio_read over page boundary\n");
63 error
= kvm
->callbacks
->mmio_read(kvm
->opaque
, addr
,
69 cb_mmio_write(kvm_context_t kvm
,
75 if ((addr
& 0xFFF) + len
- 1 > 0xFFF) {
76 printf("mmio_write over page boundary\n");
79 error
= kvm
->callbacks
->mmio_write(kvm
->opaque
, addr
,
85 emulate_mmio_cmp(kvm_context_t kvm
,
86 struct kvm_regs
*regs
,
87 struct kvm_sregs
*sregs
,
95 uint8_t SF
, PF
, CF
, OF
, AF
, ZF
;
99 unsigned int dest_size
;
100 unsigned int src_size
;
104 assert(get_repeat_prefix(insn
) == insn_no_prefix
);
105 assert(insn
->explicit_count
== 2);
107 dest_op
= x86_operand_1st(insn
);
108 src_op
= x86_operand_2nd(insn
);
110 dest_size
= x86_operand_size(dest_op
);
111 src_size
= x86_operand_size(src_op
);
113 assert(dest_size
== src_size
);
115 switch (src_op
->type
) { /* source type */
117 if (dest_op
->type
!= op_expression
)
120 if ((dest_op
->flags
& ~0xFF) == 0)
121 dest_op
->flags
|= op_ds_seg
;
123 source
= get_source_data(regs
, src_op
);
125 dest
= get_memi_address(regs
, sregs
, dest_op
, reg_size());
126 //printf("Destination Address: %" PRIx64 "\n", dest);
127 dest
= kvm_get_phys_addr(dest
);
128 if (dest
!= fault_addr
) {
132 memset(data
, 0, sizeof(data
));
133 cb_mmio_read(kvm
, dest
, data
, dest_size
);
134 dest
= *(uint64_t *)data
;
139 printf("op: %d\n", src_op
->type
);
144 #define SIGN_MASK_64 0x8000000000000000
145 #define SIGN_MASK_32 0x80000000
146 #define SIGN_MASK_16 0x8000
147 #define SIGN_MASK_8 0x80
150 case (1) : sign_mask
= SIGN_MASK_8
;
151 result
= (uint8_t)dest
- (uint8_t)source
;
153 case (4) : sign_mask
= SIGN_MASK_32
;
154 result
= (uint32_t)dest
- (uint32_t)source
;
156 case (8) : sign_mask
= SIGN_MASK_64
;
157 result
= dest
- source
;
160 default : sign_mask
= SIGN_MASK_16
;
161 result
= (uint16_t)dest
- (uint16_t)source
;
165 //printf("The dest is %" PRIx64 "\n", dest);
166 //printf("The src is %" PRIx64 "\n", source);
167 CF
= (dest
< source
);
168 ZF
= (dest
== source
);
169 SF
= (result
& sign_mask
);
170 if ((dest
& sign_mask
) == 0 && (source
& sign_mask
) != 0)
172 else if ((dest
& sign_mask
) != 0 && (source
& sign_mask
) == 0)
177 /* Taken from AMD VOL 3, CMP instruction information */
178 if((int64_t)dest
> (int64_t)source
)
180 else if ((int64_t)dest
< (int64_t)source
)
186 for (i
=0; i
< 8; i
++) {
187 PF
= PF
^ ((result
>> i
) & 1);
190 AF
= ( (dest
& 0x0F) >= (source
& 0x0F) );
192 regs
->rflags
&= ~(CF_MASK
| PF_MASK
| AF_MASK
| ZF_MASK
| SF_MASK
| OF_MASK
);
193 regs
->rflags
|= (CF
) ? CF_MASK
: 0;
194 regs
->rflags
|= (PF
) ? PF_MASK
: 0;
195 regs
->rflags
|= (AF
) ? AF_MASK
: 0;
196 regs
->rflags
|= (ZF
) ? ZF_MASK
: 0;
197 regs
->rflags
|= (SF
) ? SF_MASK
: 0;
198 regs
->rflags
|= (OF
) ? OF_MASK
: 0;
205 emulate_mmio_movs(kvm_context_t kvm
,
206 struct kvm_regs
*regs
,
207 struct kvm_sregs
*sregs
,
211 uint64_t dest_operand
, src_operand
;
218 unsigned int dest_size
;
219 unsigned int src_size
;
225 dest_op
= x86_operand_1st(insn
);
226 src_op
= x86_operand_2nd(insn
);
228 assert(get_repeat_prefix(insn
) == insn_no_prefix
||
229 get_repeat_prefix(insn
) == insn_rep_zero
);
230 assert(insn
->explicit_count
== 2);
232 assert(dest_op
->data
.expression
.index
.id
== 0);
233 assert(src_op
->data
.expression
.index
.id
== 0);
235 assert(dest_op
->type
== op_expression
);
236 assert(src_op
->type
== op_expression
);
238 dest
= &dest_op
->data
.expression
.base
;
239 src
= &src_op
->data
.expression
.base
;
241 reg_idx1
= kvm_reg_from_x86_reg(src
->id
);
242 reg_idx2
= kvm_reg_from_x86_reg(dest
->id
);
244 assert(reg_idx1
== KVM_REG_RSI
);
245 assert(reg_idx2
== KVM_REG_RDI
);
246 assert((dest_op
->flags
& op_es_seg
) == op_es_seg
);
247 assert((src_op
->flags
& op_ds_seg
) == op_ds_seg
);
249 dest_size
= x86_operand_size(dest_op
);
250 src_size
= x86_operand_size(src_op
);
252 assert(dest_size
== src_size
);
254 /* TODO: Can it ever be a segment other than DS
255 if (inst->operands[0].memi.base.segment == SEGMENT_DEFAULT)
256 inst->operands[0].memi.base.segment = SEGMENT_DS;
259 if (test_repeat_noop())
262 dest_operand
= get_memi_address(regs
, sregs
, dest_op
, reg_size());
263 src_operand
= get_memi_address(regs
, sregs
, src_op
, reg_size());
265 //printf("dest_operand: %" PRIx64 "\n", dest_operand);
266 //printf("src_operand: %" PRIx64 "\n", src_operand);
268 if (kvm_get_phys_addr(src_operand
) == fault_addr
) { // Read
269 uint64_t dest_phys_addr
;
270 dest_phys_addr
= kvm_get_phys_addr(dest_operand
);
271 if (dest_phys_addr
== -1)
274 mmio_write
= !kvm_is_containing_region(kvm
,
275 dest_phys_addr
, dest_size
);
277 else if (kvm_get_phys_addr(dest_operand
) == fault_addr
) { // Write
278 uint64_t src_phys_addr
;
279 src_phys_addr
= kvm_get_phys_addr(src_operand
);
280 if (src_phys_addr
== -1)
283 mmio_read
= !kvm_is_containing_region(kvm
,
284 src_phys_addr
, src_size
);
289 /* TODO: what if we keep on writing past the page boundary due
294 uint64_t src_phys_addr
;
295 src_phys_addr
= kvm_get_phys_addr(src_operand
);
296 if (src_phys_addr
== -1)
298 error
= cb_mmio_read(kvm
,
304 cpu_virtual_memory_rw(src_operand
, data
,
309 uint64_t dest_phys_addr
;
310 dest_phys_addr
= kvm_get_phys_addr(dest_operand
);
311 if (dest_phys_addr
== -1)
313 error
= cb_mmio_write(kvm
,
319 cpu_virtual_memory_rw(dest_operand
, data
,
326 if ((regs
->rflags
& RFLAGS_DF_MASK
) != 0) {
327 regs
->rsi
-= dest_size
;
328 regs
->rdi
-= dest_size
;
329 src_operand
-= dest_size
;
330 dest_operand
-= dest_size
;
333 regs
->rsi
+= dest_size
;
334 regs
->rdi
+= dest_size
;
335 src_operand
+= dest_size
;
336 dest_operand
+= dest_size
;
339 } while (test_repeat_tail());
345 emulate_mmio_stos(kvm_context_t kvm
,
346 struct kvm_regs
*regs
,
347 struct kvm_sregs
*sregs
,
351 uint64_t dest_operand
;
353 uint8_t source_data
[8];
357 unsigned int dest_size
;
358 unsigned int src_size
;
363 dest_op
= x86_operand_1st(insn
);
364 src_op
= x86_operand_2nd(insn
);
366 assert(insn
->explicit_count
== 2);
368 assert(dest_op
->type
== op_expression
);
369 assert((dest_op
->flags
& op_es_seg
) == op_es_seg
);
370 assert(dest_op
->data
.expression
.index
.id
== 0);
371 assert(src_op
->type
== op_register
);
373 dest
= &dest_op
->data
.expression
.base
;
375 reg_idx1
= kvm_reg_from_x86_reg(dest
->id
);
376 reg_idx2
= kvm_reg_from_x86_reg(src_op
->data
.reg
.id
);
377 assert(reg_idx1
== KVM_REG_RDI
);
378 assert(reg_idx2
== KVM_REG_RAX
);
380 dest_size
= x86_operand_size(dest_op
);
381 src_size
= x86_operand_size(src_op
);
383 assert(dest_size
== src_size
);
385 assert(get_repeat_prefix(insn
) == insn_no_prefix
||
386 get_repeat_prefix(insn
) == insn_rep_zero
);
388 if (test_repeat_noop())
391 dest_operand
= get_memi_address(regs
, sregs
, dest_op
, reg_size());
392 source
= mask_reg(regs
->rax
, reg_size());
394 //printf("dest_operand: %" PRIx64 "\n", dest_operand);
395 //printf("source: %" PRIx64 "\n", source);
397 if (kvm_get_phys_addr(dest_operand
) != fault_addr
)
400 /* TODO: what if we keep on writing past the page boundary due
403 *(uint64_t*) source_data
= source
;
407 uint64_t dest_phys_addr
;
408 dest_phys_addr
= kvm_get_phys_addr(dest_operand
);
409 if (dest_phys_addr
== -1)
412 error
= cb_mmio_write(kvm
, dest_phys_addr
, source_data
, dest_size
);
416 if ((regs
->rflags
& RFLAGS_DF_MASK
) != 0) {
417 regs
->rdi
-= dest_size
;
418 dest_operand
-= dest_size
;
421 regs
->rdi
+= dest_size
;
422 dest_operand
+= dest_size
;
425 } while (test_repeat_tail());
431 emulate_mmio_mov(kvm_context_t kvm
,
432 struct kvm_regs
*regs
,
433 struct kvm_sregs
*sregs
,
441 unsigned int dest_size
;
442 unsigned int src_size
;
446 assert(get_repeat_prefix(insn
) == insn_no_prefix
);
447 assert(insn
->explicit_count
== 2);
449 dest_op
= x86_operand_1st(insn
);
450 src_op
= x86_operand_2nd(insn
);
452 dest_size
= x86_operand_size(dest_op
);
453 src_size
= x86_operand_size(src_op
);
455 if (strcmp(insn
->mnemonic
, "movzx") == 0)
457 else if (strcmp(insn
->mnemonic
, "movsx") == 0)
460 assert(dest_size
== src_size
);
462 switch (src_op
->type
) { /* source type */
465 if ((dest_op
->type
!= op_expression
) &&
466 (dest_op
->type
!= op_offset
))
469 if ((dest_op
->flags
& ~0xFF) == 0)
470 dest_op
->flags
|= op_ds_seg
;
472 *(uint64_t*) data
= get_source_data(regs
, src_op
);
474 dest
= get_memi_address(regs
, sregs
, dest_op
, reg_size());
475 //printf("Destination Address: %" PRIx64 "\n", dest);
477 dest
= kvm_get_phys_addr(dest
);
479 if (dest
!= fault_addr
) {
483 error
= cb_mmio_write(kvm
, dest
, data
, dest_size
);
491 if (dest_op
->type
!= op_register
)
493 if ((src_op
->flags
& ~0xFF) == 0)
494 src_op
->flags
|= op_ds_seg
;
496 source
= get_memi_address(regs
, sregs
, src_op
, reg_size());
497 printf("source = %016" PRIx64
" -> %016" PRIx64
"\n",
499 kvm_get_phys_addr(source
));
500 printf("fault_addr = %016" PRIx64
" -> %016" PRIx64
"\n",
502 kvm_get_phys_addr(fault_addr
));
504 source
= kvm_get_phys_addr(source
);
506 if (source
!= fault_addr
) {
507 printf("eax: 0x%" PRIx64
"\n", regs
->rax
);
511 error
= cb_mmio_read(kvm
, source
, data
, src_size
);
515 dest
= *(uint64_t*) data
;
516 dest
= mask_reg(dest
, reg_size());
518 kvm_reg_from_x86_reg(dest_op
->data
.reg
.id
),
524 printf("op: %d\n", src_op
->type
);
532 emulate_mmio_xchg(kvm_context_t kvm
,
533 struct kvm_regs
*regs
,
534 struct kvm_sregs
*sregs
,
540 unsigned int mem_size
;
541 unsigned int reg_size
;
547 assert(get_repeat_prefix(insn
) == insn_no_prefix
);
548 assert(insn
->explicit_count
== 2);
550 mem_op
= x86_operand_1st(insn
);
551 reg_op
= x86_operand_2nd(insn
);
553 assert(mem_op
->type
== op_expression
);
554 assert(reg_op
->type
== op_register
);
556 mem_size
= x86_operand_size(mem_op
);
557 reg_size
= x86_operand_size(reg_op
);
558 assert(reg_size
== mem_size
);
561 reg_data
= get_source_data(regs
, reg_op
);
563 if ((mem_op
->flags
& ~0xFF) == 0)
564 mem_op
->flags
|= op_ds_seg
;
565 mem_addr
= get_memi_address(regs
, sregs
, mem_op
, reg_size());
566 mem_addr
= kvm_get_phys_addr(mem_addr
);
567 if (mem_addr
!= fault_addr
)
569 error
= cb_mmio_read(kvm
, mem_addr
, (uint8_t*) &mem_data
, mem_size
);
583 kvm_reg_from_x86_reg(reg_op
->data
.reg
.id
),
585 error
= cb_mmio_write(kvm
, mem_addr
, (uint8_t*) &mem_data
, mem_size
);
594 emulate_mmio(kvm_context_t kvm
,
595 struct kvm_regs
*regs
,
596 struct kvm_sregs
*sregs
,
600 uint64_t loc
, next_rip
;
601 unsigned int insn_size
;
605 libdisasm_init(reg_size());
607 loc
= sregs
->cs
.base
+ regs
->rip
;
608 insn_size
= get_x86_insn(loc
, &insn
);
612 //printf("rip: %" PRIx64 "\n", regs->rip);
613 //printf("loc: %" PRIx64 "\n", loc);
614 next_rip
= regs
->rip
+ insn_size
;
617 //printf("Number of args: %d\n", (int)insn.explicit_count);
620 op
= x86_operand_1st(&insn
);
621 printf("Dest Type = %d\n", op
->type
);
622 op
= x86_operand_2nd(&insn
);
623 printf("Src Type = %d\n", op
->type
);
624 op
= x86_operand_3rd(&insn
);
626 printf("Type = %d\n", op
->type
);
628 printf("Op was null\n");
634 error
= emulate_mmio_movs(kvm
, regs
, sregs
, fault_addr
, &insn
);
637 error
= emulate_mmio_stos(kvm
, regs
, sregs
, fault_addr
, &insn
);
640 error
= emulate_mmio_mov(kvm
, regs
, sregs
, fault_addr
, &insn
);
643 error
= emulate_mmio_cmp(kvm
, regs
, sregs
, fault_addr
, &insn
);
646 error
= emulate_mmio_xchg(kvm
, regs
, sregs
, fault_addr
, &insn
);
649 printf("MMIO %s insn.type=%d\n", insn
.mnemonic
, insn
.type
);
654 regs
->rip
= next_rip
;