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)
49 emulate_cr_mov(kvm_context_t kvm
,
50 struct kvm_regs
*regs
,
51 struct kvm_sregs
*sregs
,
57 unsigned int dest_size
;
58 unsigned int src_size
;
62 assert(get_repeat_prefix(insn
) == insn_no_prefix
);
63 assert(insn
->explicit_count
== 2);
65 dest_op
= x86_operand_1st(insn
);
66 src_op
= x86_operand_2nd(insn
);
68 dest_size
= x86_operand_size(dest_op
);
69 src_size
= x86_operand_size(src_op
);
70 assert(dest_size
== src_size
);
72 assert(src_op
->type
== op_register
);
73 assert(dest_op
->type
== op_register
);
79 src_gp_num
= kvm_reg_from_x86_reg(src_op
->data
.reg
.id
);
83 data
= kvm_regs_get(regs
, src_gp_num
);
84 data
= mask_reg(data
, dest_size
);
86 if (dest_op
->data
.reg
.type
!= reg_sys
)
88 dest_cr_num
= cr_num_from_x86_reg(dest_op
->data
.reg
.id
);
89 if (dest_cr_num
!= cr_num
)
92 switch (dest_cr_num
) {
93 case 0: sregs
->cr0
= data
; break;
94 case 2: sregs
->cr2
= data
; break;
95 case 3: sregs
->cr3
= data
; break;
96 case 4: sregs
->cr4
= data
; break;
97 default: EXIT_ERR_PATH();
100 printf("wrote 0x%" PRIx64
" to CR%d\n", data
, dest_cr_num
);
106 if (src_op
->data
.reg
.type
!= reg_sys
)
108 src_cr_num
= cr_num_from_x86_reg(src_op
->data
.reg
.id
);
109 if (src_cr_num
!= cr_num
)
112 switch (src_cr_num
) {
113 case 0: data
= sregs
->cr0
; break;
114 case 2: data
= sregs
->cr2
; break;
115 case 3: data
= sregs
->cr3
; break;
116 case 4: data
= sregs
->cr4
; break;
117 default: EXIT_ERR_PATH();
119 data
= mask_reg(data
, dest_size
);
121 dest_gp_num
= kvm_reg_from_x86_reg(dest_op
->data
.reg
.id
);
122 if (dest_gp_num
== -1)
125 kvm_regs_set(regs
, dest_gp_num
, data
);
132 emulate_cr_lmsw(kvm_context_t kvm
,
133 struct kvm_regs
*regs
,
134 struct kvm_sregs
*sregs
,
141 assert(get_repeat_prefix(insn
) == insn_no_prefix
);
142 assert(insn
->explicit_count
== 1);
144 src_op
= x86_operand_1st(insn
);
145 assert(x86_operand_size(src_op
) == 2);
147 if (src_op
->type
!= op_register
)
150 src_gp_num
= kvm_reg_from_x86_reg(src_op
->data
.reg
.id
);
151 if (src_gp_num
== -1)
154 data
= kvm_regs_get(regs
, src_gp_num
);
156 /* from the manual: LMSW can set CR0.PE, but cannot clear it */
157 if ((data
& 0x1) == 0 && (sregs
->cr0
& 0x1) == 1)
160 sregs
->cr0
= (sregs
->cr0
& 0xFFFFFFFFFFFFFFF0) |
161 (data
& 0x000000000000000F);
167 emulate_cr_smsw(kvm_context_t kvm
,
168 struct kvm_regs
*regs
,
169 struct kvm_sregs
*sregs
,
177 assert(get_repeat_prefix(insn
) == insn_no_prefix
);
178 assert(insn
->explicit_count
== 1);
180 dest_op
= x86_operand_1st(insn
);
182 if (dest_op
->type
!= op_register
)
185 dest_gp_num
= kvm_reg_from_x86_reg(dest_op
->data
.reg
.id
);
186 if (dest_gp_num
== -1)
189 dest_data
= kvm_regs_get(regs
, dest_gp_num
);
190 switch (x86_operand_size(dest_op
)) {
192 data
= (sregs
->cr0
& 0x000000000000FFFF) |
193 (dest_data
& 0xFFFFFFFFFFFF0000);
196 data
= (sregs
->cr0
& 0x00000000FFFFFFFF) |
197 (dest_data
& 0xFFFFFFFF00000000);
200 data
= (sregs
->cr0
& 0xFFFFFFFFFFFFFFFF) |
201 (dest_data
& 0x0000000000000000);
207 kvm_regs_set(regs
, dest_gp_num
, data
);
213 emulate_cr_clts(kvm_context_t kvm
,
214 struct kvm_regs
*regs
,
215 struct kvm_sregs
*sregs
,
218 assert(get_repeat_prefix(insn
) == insn_no_prefix
);
219 assert(insn
->explicit_count
== 0);
226 emulate_cr(kvm_context_t kvm
,
227 struct kvm_regs
*regs
,
228 struct kvm_sregs
*sregs
,
233 uint64_t loc
, next_rip
;
234 unsigned int insn_size
;
237 libdisasm_init(reg_size());
239 loc
= sregs
->cs
.base
+ regs
->rip
;
240 insn_size
= get_x86_insn(loc
, &insn
);
244 printf("rip: %" PRIx64
"\n", regs
->rip
);
245 printf("loc: %" PRIx64
"\n", loc
);
246 next_rip
= regs
->rip
+ insn_size
;
252 error
= emulate_cr_mov(kvm
, regs
, sregs
, cr_num
, is_write
, &insn
);
257 error
= emulate_cr_lmsw(kvm
, regs
, sregs
, &insn
);
262 error
= emulate_cr_smsw(kvm
, regs
, sregs
, &insn
);
267 error
= emulate_cr_clts(kvm
, regs
, sregs
, &insn
);
270 printf("insn.type = 0x%x\n", insn
.type
);
275 regs
->rip
= next_rip
;