adds emulate_cr_clts
[fkvm-libfkvm.git] / cr.c
blobdbf88ff30554719e7bef1b75a1534a669931968a
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)
47 #define test_repeat_noop() _test_repeat_noop(insn->prefix == insn_rep_zero, \
48 reg_size(), regs)
49 #define test_repeat_tail() _test_repeat_tail(insn->prefix == insn_rep_zero, \
50 reg_size(), regs)
52 static int
53 emulate_cr_mov(kvm_context_t kvm,
54 struct kvm_regs *regs,
55 struct kvm_sregs *sregs,
56 int cr_num,
57 bool is_write,
58 x86_insn_t *insn)
60 uint64_t data;
61 unsigned int dest_size;
62 unsigned int src_size;
63 x86_op_t *dest_op;
64 x86_op_t *src_op;
66 assert(insn->prefix == insn_no_prefix);
67 assert(insn->explicit_count == 2);
69 dest_op = x86_operand_1st(insn);
70 src_op = x86_operand_2nd(insn);
72 dest_size = x86_operand_size(dest_op);
73 src_size = x86_operand_size(src_op);
74 assert(dest_size == src_size);
76 assert(src_op->type == op_register);
77 assert(dest_op->type == op_register);
79 if (is_write) {
80 int src_gp_num;
81 int dest_cr_num;
83 src_gp_num = kvm_reg_from_x86_reg(src_op->data.reg.id);
84 if (src_gp_num == -1)
85 EXIT_ERR_PATH();
87 data = kvm_regs_get(regs, src_gp_num);
88 data = mask_reg(data, dest_size);
90 if (dest_op->data.reg.type != reg_sys)
91 EXIT_ERR_PATH();
92 dest_cr_num = cr_num_from_x86_reg(dest_op->data.reg.id);
93 if (dest_cr_num != cr_num)
94 EXIT_ERR_PATH();
96 switch (dest_cr_num) {
97 case 0: sregs->cr0 = data; break;
98 case 2: sregs->cr2 = data; break;
99 case 3: sregs->cr3 = data; break;
100 case 4: sregs->cr4 = data; break;
101 default: EXIT_ERR_PATH();
104 printf("wrote 0x%" PRIx64 " to CR%d\n", data, dest_cr_num);
106 else {
107 int src_cr_num;
108 int dest_gp_num;
110 if (src_op->data.reg.type != reg_sys)
111 EXIT_ERR_PATH();
112 src_cr_num = cr_num_from_x86_reg(src_op->data.reg.id);
113 if (src_cr_num != cr_num)
114 EXIT_ERR_PATH();
116 switch (src_cr_num) {
117 case 0: data = sregs->cr0; break;
118 case 2: data = sregs->cr2; break;
119 case 3: data = sregs->cr3; break;
120 case 4: data = sregs->cr4; break;
121 default: EXIT_ERR_PATH();
123 data = mask_reg(data, dest_size);
125 dest_gp_num = kvm_reg_from_x86_reg(dest_op->data.reg.id);
126 if (dest_gp_num == -1)
127 EXIT_ERR_PATH();
129 kvm_regs_set(regs, dest_gp_num, data);
132 return 0;
135 static int
136 emulate_cr_lmsw(kvm_context_t kvm,
137 struct kvm_regs *regs,
138 struct kvm_sregs *sregs,
139 x86_insn_t *insn)
141 x86_op_t *src_op;
142 int src_gp_num;
143 uint64_t data;
145 assert(insn->prefix == insn_no_prefix);
146 assert(insn->explicit_count == 1);
148 src_op = x86_operand_1st(insn);
149 assert(x86_operand_size(src_op) == 2);
151 if (src_op->type != op_register)
152 EXIT();
154 src_gp_num = kvm_reg_from_x86_reg(src_op->data.reg.id);
155 if (src_gp_num == -1)
156 EXIT_ERR_PATH();
158 data = kvm_regs_get(regs, src_gp_num);
160 /* from the manual: LMSW can set CR0.PE, but cannot clear it */
161 if ((data & 0x1) == 0 && (sregs->cr0 & 0x1) == 1)
162 EXIT_ERR_PATH();
164 sregs->cr0 = (sregs->cr0 & 0xFFFFFFFFFFFFFFF0) |
165 (data & 0x000000000000000F);
167 return 0;
170 static int
171 emulate_cr_clts(kvm_context_t kvm,
172 struct kvm_regs *regs,
173 struct kvm_sregs *sregs,
174 x86_insn_t *insn)
176 assert(insn->prefix == insn_no_prefix);
177 assert(insn->explicit_count == 0);
179 sregs->cr0 &= ~0x4L;
180 return 0;
184 emulate_cr(kvm_context_t kvm,
185 struct kvm_regs *regs,
186 struct kvm_sregs *sregs,
187 int cr_num,
188 bool is_write)
190 x86_insn_t insn;
191 uint64_t loc, next_rip;
192 unsigned int insn_size;
193 int error = 0;
195 libdisasm_init(reg_size());
197 loc = sregs->cs.base + regs->rip;
198 insn_size = get_x86_insn(loc, &insn);
199 if (insn_size == -1)
200 EXIT_ERR_PATH();
202 printf("rip: %" PRIx64 "\n", regs->rip);
203 printf("loc: %" PRIx64 "\n", loc);
204 next_rip = regs->rip + insn_size;
207 switch (insn.type) {
209 case insn_mov:
210 error = emulate_cr_mov(kvm, regs, sregs, cr_num, is_write, &insn);
211 break;
212 case insn_lmsw:
213 if (!is_write)
214 EXIT_ERR_PATH();
215 error = emulate_cr_lmsw(kvm, regs, sregs, &insn);
216 break;
217 case insn_smsw:
218 if (is_write)
219 EXIT_ERR_PATH();
220 EXIT();
221 break;
222 case insn_clts:
223 if (!is_write)
224 EXIT_ERR_PATH();
225 error = emulate_cr_clts(kvm, regs, sregs, &insn);
226 break;
227 default:
228 printf("insn.type = 0x%x\n", insn.type);
229 EXIT();
232 if (error == 0)
233 regs->rip = next_rip;
235 libdisasm_cleanup();
237 return error;