mask repeat prefix out of insn prefix
[fkvm-libfkvm.git] / ioio.c
blobafda12294cc5b2e0353fff912613c6c132238b06
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>
40 #include "libkvm.h"
41 #include "libfkvm-common.h"
42 #include "disasm.h"
44 #define reg_size() _reg_size(regs, sregs)
45 #define test_repeat_noop() _test_repeat_noop(rep && string, \
46 reg_size(), regs)
47 #define test_repeat_tail() _test_repeat_tail(rep && string, \
48 reg_size(), regs)
50 /* TODO: check return value for kvm->callbacks->in* */
51 static int
52 emulate_ioio_in(kvm_context_t kvm,
53 struct kvm_regs *regs,
54 struct kvm_sregs *sregs,
55 uint16_t port,
56 size_t size,
57 bool rep,
58 bool string)
60 uint32_t data = 0;
62 if (test_repeat_noop())
63 return 0;
65 do {
66 switch (size) {
67 case 1:
68 kvm->callbacks->inb(kvm->opaque,
69 port,
70 (uint8_t*) &data);
71 break;
72 case 2:
73 kvm->callbacks->inw(kvm->opaque,
74 port,
75 (uint16_t*) &data);
76 break;
77 case 4:
78 kvm->callbacks->inl(kvm->opaque,
79 port,
80 (uint32_t*) &data);
81 break;
83 if (!string) {
84 regs->rax = data;
86 else {
87 regs->rdi = mask_reg(regs->rdi, reg_size());
89 /* TODO: es limit check */
90 cpu_virtual_memory_rw(sregs->es.base + regs->rdi,
91 (uint8_t*) &data,
92 size,
93 1);
95 if ((regs->rflags & RFLAGS_DF_MASK) != 0)
96 regs->rdi -= size;
97 else
98 regs->rdi += size;
100 } while (test_repeat_tail());
102 return 0;
105 /* TODO: check return value for kvm->callbacks->in* */
106 static int
107 emulate_ioio_out(kvm_context_t kvm,
108 struct kvm_regs *regs,
109 struct kvm_sregs *sregs,
110 uint16_t port,
111 size_t size,
112 bool rep,
113 bool string)
115 uint32_t data = 0;
117 if (test_repeat_noop())
118 return 0;
120 do {
121 if (!string) {
122 data = regs->rax;
124 else {
125 /* SVM won't tell us whether there's a SEG prefix,
126 * so we need to decode the instruction */
127 struct kvm_segment *segment = &sregs->ds;
128 x86_insn_t insn;
129 unsigned int insn_size;
131 libdisasm_init(reg_size());
132 insn_size = get_x86_insn(sregs->cs.base + regs->rip, &insn);
133 if (insn_size == -1)
134 EXIT_ERR_PATH();
135 segment = kvm_seg_from_x86_op(sregs, x86_operand_2nd(&insn));
136 libdisasm_cleanup();
138 regs->rsi = mask_reg(regs->rsi, reg_size());
140 /* TODO: segment limit check */
141 cpu_virtual_memory_rw(segment->base + regs->rsi,
142 (uint8_t*) &data,
143 size,
146 if ((regs->rflags & RFLAGS_DF_MASK) != 0)
147 regs->rsi -= size;
148 else
149 regs->rsi += size;
151 switch (size) {
152 case 1:
153 kvm->callbacks->outb(kvm->opaque,
154 port,
155 (uint8_t) data);
156 break;
157 case 2:
158 kvm->callbacks->outw(kvm->opaque,
159 port,
160 (uint16_t) data);
161 break;
162 case 4:
163 kvm->callbacks->outl(kvm->opaque,
164 port,
165 (uint32_t) data);
166 break;
168 } while (test_repeat_tail());
170 return 0;
174 emulate_ioio(kvm_context_t kvm,
175 struct kvm_regs *regs,
176 struct kvm_sregs *sregs,
177 uint16_t port,
178 size_t size,
179 bool rep,
180 bool string,
181 bool in)
183 switch (size) {
184 case 1:
185 case 2:
186 case 4:
187 break;
188 default:
189 printf("emulate_ioio: invalid size (%u)\n", (int) size);
190 EXIT_ERR_PATH();
191 return -1;
194 if (in) {
195 return emulate_ioio_in(kvm, regs, sregs,
196 port, size, rep, string);
198 else {
199 return emulate_ioio_out(kvm, regs, sregs,
200 port, size, rep, string);