mask repeat prefix out of insn prefix
[fkvm-libfkvm.git] / cr.c
blob30b8347689430e2293b9f59e92f5d94a55ada9db
1 /*-
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>
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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
26 * SUCH DAMAGE.
29 #define FKVM_INTERNAL
30 #include <sys/fkvm.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <inttypes.h>
39 #include <assert.h>
40 #include <libdis.h>
42 #include "libkvm.h"
43 #include "libfkvm-common.h"
44 #include "disasm.h"
46 #define reg_size() _reg_size(regs, sregs)
48 static int
49 emulate_cr_mov(kvm_context_t kvm,
50 struct kvm_regs *regs,
51 struct kvm_sregs *sregs,
52 int cr_num,
53 bool is_write,
54 x86_insn_t *insn)
56 uint64_t data;
57 unsigned int dest_size;
58 unsigned int src_size;
59 x86_op_t *dest_op;
60 x86_op_t *src_op;
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);
75 if (is_write) {
76 int src_gp_num;
77 int dest_cr_num;
79 src_gp_num = kvm_reg_from_x86_reg(src_op->data.reg.id);
80 if (src_gp_num == -1)
81 EXIT_ERR_PATH();
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)
87 EXIT_ERR_PATH();
88 dest_cr_num = cr_num_from_x86_reg(dest_op->data.reg.id);
89 if (dest_cr_num != cr_num)
90 EXIT_ERR_PATH();
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);
102 else {
103 int src_cr_num;
104 int dest_gp_num;
106 if (src_op->data.reg.type != reg_sys)
107 EXIT_ERR_PATH();
108 src_cr_num = cr_num_from_x86_reg(src_op->data.reg.id);
109 if (src_cr_num != cr_num)
110 EXIT_ERR_PATH();
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)
123 EXIT_ERR_PATH();
125 kvm_regs_set(regs, dest_gp_num, data);
128 return 0;
131 static int
132 emulate_cr_lmsw(kvm_context_t kvm,
133 struct kvm_regs *regs,
134 struct kvm_sregs *sregs,
135 x86_insn_t *insn)
137 x86_op_t *src_op;
138 int src_gp_num;
139 uint64_t data;
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)
148 EXIT();
150 src_gp_num = kvm_reg_from_x86_reg(src_op->data.reg.id);
151 if (src_gp_num == -1)
152 EXIT_ERR_PATH();
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)
158 EXIT_ERR_PATH();
160 sregs->cr0 = (sregs->cr0 & 0xFFFFFFFFFFFFFFF0) |
161 (data & 0x000000000000000F);
163 return 0;
166 static int
167 emulate_cr_smsw(kvm_context_t kvm,
168 struct kvm_regs *regs,
169 struct kvm_sregs *sregs,
170 x86_insn_t *insn)
172 x86_op_t *dest_op;
173 int dest_gp_num;
174 uint64_t dest_data;
175 uint64_t data;
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)
183 EXIT();
185 dest_gp_num = kvm_reg_from_x86_reg(dest_op->data.reg.id);
186 if (dest_gp_num == -1)
187 EXIT_ERR_PATH();
189 dest_data = kvm_regs_get(regs, dest_gp_num);
190 switch (x86_operand_size(dest_op)) {
191 case 2:
192 data = (sregs->cr0 & 0x000000000000FFFF) |
193 (dest_data & 0xFFFFFFFFFFFF0000);
194 break;
195 case 4:
196 data = (sregs->cr0 & 0x00000000FFFFFFFF) |
197 (dest_data & 0xFFFFFFFF00000000);
198 break;
199 case 8:
200 data = (sregs->cr0 & 0xFFFFFFFFFFFFFFFF) |
201 (dest_data & 0x0000000000000000);
202 break;
203 default:
204 EXIT_ERR_PATH();
207 kvm_regs_set(regs, dest_gp_num, data);
208 return 0;
212 static int
213 emulate_cr_clts(kvm_context_t kvm,
214 struct kvm_regs *regs,
215 struct kvm_sregs *sregs,
216 x86_insn_t *insn)
218 assert(get_repeat_prefix(insn) == insn_no_prefix);
219 assert(insn->explicit_count == 0);
221 sregs->cr0 &= ~0x4L;
222 return 0;
226 emulate_cr(kvm_context_t kvm,
227 struct kvm_regs *regs,
228 struct kvm_sregs *sregs,
229 int cr_num,
230 bool is_write)
232 x86_insn_t insn;
233 uint64_t loc, next_rip;
234 unsigned int insn_size;
235 int error = 0;
237 libdisasm_init(reg_size());
239 loc = sregs->cs.base + regs->rip;
240 insn_size = get_x86_insn(loc, &insn);
241 if (insn_size == -1)
242 EXIT_ERR_PATH();
244 printf("rip: %" PRIx64 "\n", regs->rip);
245 printf("loc: %" PRIx64 "\n", loc);
246 next_rip = regs->rip + insn_size;
249 switch (insn.type) {
251 case insn_mov:
252 error = emulate_cr_mov(kvm, regs, sregs, cr_num, is_write, &insn);
253 break;
254 case insn_lmsw:
255 if (!is_write)
256 EXIT_ERR_PATH();
257 error = emulate_cr_lmsw(kvm, regs, sregs, &insn);
258 break;
259 case insn_smsw:
260 if (is_write)
261 EXIT_ERR_PATH();
262 error = emulate_cr_smsw(kvm, regs, sregs, &insn);
263 break;
264 case insn_clts:
265 if (!is_write)
266 EXIT_ERR_PATH();
267 error = emulate_cr_clts(kvm, regs, sregs, &insn);
268 break;
269 default:
270 printf("insn.type = 0x%x\n", insn.type);
271 EXIT();
274 if (error == 0)
275 regs->rip = next_rip;
277 libdisasm_cleanup();
279 return error;