1 |
/* |
2 |
* Copyright (C) 2005-2006 Anders Gavare. All rights reserved. |
3 |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
6 |
* |
7 |
* 1. Redistributions of source code must retain the above copyright |
8 |
* notice, this list of conditions and the following disclaimer. |
9 |
* 2. Redistributions in binary form must reproduce the above copyright |
10 |
* notice, this list of conditions and the following disclaimer in the |
11 |
* documentation and/or other materials provided with the distribution. |
12 |
* 3. The name of the author may not be used to endorse or promote products |
13 |
* derived from this software without specific prior written permission. |
14 |
* |
15 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 |
* SUCH DAMAGE. |
26 |
* |
27 |
* |
28 |
* $Id: cpu_x86_instr.c,v 1.13 2006/04/22 18:07:30 debug Exp $ |
29 |
* |
30 |
* x86/amd64 instructions. |
31 |
* |
32 |
* Individual functions should keep track of cpu->n_translated_instrs. |
33 |
* (n_translated_instrs is automatically increased by 1 for each function |
34 |
* call. If no instruction was executed, then it should be decreased. If, say, |
35 |
* 4 instructions were combined into one function and executed, then it should |
36 |
* be increased by 3.) |
37 |
*/ |
38 |
|
39 |
|
40 |
/* |
41 |
* nop: Do nothing. |
42 |
*/ |
43 |
X(nop) |
44 |
{ |
45 |
} |
46 |
|
47 |
|
48 |
/*****************************************************************************/ |
49 |
|
50 |
|
51 |
/* |
52 |
* sti, cli, std, cld, stc, clc: Set/clear flag bits. |
53 |
*/ |
54 |
X(stc) { cpu->cd.x86.rflags |= X86_FLAGS_CF; } |
55 |
X(clc) { cpu->cd.x86.rflags &= ~X86_FLAGS_CF; } |
56 |
X(std) { cpu->cd.x86.rflags |= X86_FLAGS_DF; } |
57 |
X(cld) { cpu->cd.x86.rflags &= ~X86_FLAGS_DF; } |
58 |
X(sti) { cpu->cd.x86.rflags |= X86_FLAGS_IF; } |
59 |
X(cli) { cpu->cd.x86.rflags &= ~X86_FLAGS_IF; } |
60 |
|
61 |
|
62 |
/* |
63 |
* cpuid |
64 |
*/ |
65 |
X(cpuid) |
66 |
{ |
67 |
x86_cpuid(cpu); |
68 |
} |
69 |
|
70 |
|
71 |
/* |
72 |
* inc, dec |
73 |
*/ |
74 |
X(inc_ax) |
75 |
{ |
76 |
MODE_uint_t r = cpu->cd.x86.r[X86_R_AX], r2 = r + 1; |
77 |
cpu->cd.x86.r[X86_R_AX] = (r & ~0xffff) + (r2 & 0xffff); |
78 |
} |
79 |
X(inc_cx) |
80 |
{ |
81 |
MODE_uint_t r = cpu->cd.x86.r[X86_R_CX], r2 = r + 1; |
82 |
cpu->cd.x86.r[X86_R_CX] = (r & ~0xffff) + (r2 & 0xffff); |
83 |
} |
84 |
X(inc_dx) |
85 |
{ |
86 |
MODE_uint_t r = cpu->cd.x86.r[X86_R_DX], r2 = r + 1; |
87 |
cpu->cd.x86.r[X86_R_DX] = (r & ~0xffff) + (r2 & 0xffff); |
88 |
} |
89 |
X(inc_bx) |
90 |
{ |
91 |
MODE_uint_t r = cpu->cd.x86.r[X86_R_BX], r2 = r + 1; |
92 |
cpu->cd.x86.r[X86_R_BX] = (r & ~0xffff) + (r2 & 0xffff); |
93 |
} |
94 |
X(inc_sp) |
95 |
{ |
96 |
MODE_uint_t r = cpu->cd.x86.r[X86_R_SP], r2 = r + 1; |
97 |
cpu->cd.x86.r[X86_R_SP] = (r & ~0xffff) + (r2 & 0xffff); |
98 |
} |
99 |
X(inc_bp) |
100 |
{ |
101 |
MODE_uint_t r = cpu->cd.x86.r[X86_R_BP], r2 = r + 1; |
102 |
cpu->cd.x86.r[X86_R_BP] = (r & ~0xffff) + (r2 & 0xffff); |
103 |
} |
104 |
X(inc_si) |
105 |
{ |
106 |
MODE_uint_t r = cpu->cd.x86.r[X86_R_SI], r2 = r + 1; |
107 |
cpu->cd.x86.r[X86_R_SI] = (r & ~0xffff) + (r2 & 0xffff); |
108 |
} |
109 |
X(inc_di) |
110 |
{ |
111 |
MODE_uint_t r = cpu->cd.x86.r[X86_R_DI], r2 = r + 1; |
112 |
cpu->cd.x86.r[X86_R_DI] = (r & ~0xffff) + (r2 & 0xffff); |
113 |
} |
114 |
X(inc_eax) { cpu->cd.x86.r[X86_R_AX] ++; } |
115 |
X(inc_ecx) { cpu->cd.x86.r[X86_R_CX] ++; } |
116 |
X(inc_edx) { cpu->cd.x86.r[X86_R_DX] ++; } |
117 |
X(inc_ebx) { cpu->cd.x86.r[X86_R_BX] ++; } |
118 |
X(inc_esp) { cpu->cd.x86.r[X86_R_SP] ++; } |
119 |
X(inc_ebp) { cpu->cd.x86.r[X86_R_BP] ++; } |
120 |
X(inc_esi) { cpu->cd.x86.r[X86_R_SI] ++; } |
121 |
X(inc_edi) { cpu->cd.x86.r[X86_R_DI] ++; } |
122 |
|
123 |
|
124 |
/* |
125 |
* mov_reg_imm_8: |
126 |
* |
127 |
* arg[1] = imm8 |
128 |
* arg[2] = pointer to a _byte_ inside an emulated register |
129 |
*/ |
130 |
X(mov_reg_imm_8) |
131 |
{ |
132 |
*((uint8_t *)ic->arg[2]) = ic->arg[1]; |
133 |
} |
134 |
|
135 |
|
136 |
/* |
137 |
* mov_reg_imm_16, _32 |
138 |
*/ |
139 |
X(mov_reg_imm_16) |
140 |
{ |
141 |
reg(ic->arg[2]) &= ~0xffff; |
142 |
reg(ic->arg[2]) |= ic->arg[1]; |
143 |
} |
144 |
X(mov_reg_imm_32) |
145 |
{ |
146 |
reg(ic->arg[2]) = (uint32_t)ic->arg[1]; |
147 |
} |
148 |
|
149 |
|
150 |
/*****************************************************************************/ |
151 |
|
152 |
|
153 |
X(end_of_page) |
154 |
{ |
155 |
/* Update the PC: (offset 0, but on the next page) */ |
156 |
cpu->pc &= ~(X86_IC_ENTRIES_PER_PAGE-1); |
157 |
cpu->pc += X86_IC_ENTRIES_PER_PAGE; |
158 |
|
159 |
/* Find the new physical page and update the translation pointers: */ |
160 |
x86_pc_to_pointers(cpu); |
161 |
|
162 |
/* end_of_page doesn't count as an executed instruction: */ |
163 |
cpu->n_translated_instrs --; |
164 |
} |
165 |
|
166 |
|
167 |
/*****************************************************************************/ |
168 |
|
169 |
|
170 |
#ifdef GET_NEXT_BYTE |
171 |
#undef GET_NEXT_BYTE |
172 |
#endif |
173 |
#ifdef MODE32 |
174 |
#define GET_NEXT_BYTE get_next_byte32 |
175 |
#else |
176 |
#define GET_NEXT_BYTE get_next_byte64 |
177 |
#endif |
178 |
/* Get the next instruction byte; return 1 on success, 0 on failure */ |
179 |
int GET_NEXT_BYTE(struct cpu *cpu, unsigned char *byte, MODE_uint_t addr) |
180 |
{ |
181 |
unsigned char *page; |
182 |
|
183 |
/* Read the instruction word from memory: */ |
184 |
#ifdef MODE32 |
185 |
page = cpu->cd.x86.host_load[addr >> 12]; |
186 |
#else |
187 |
{ |
188 |
const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1; |
189 |
const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1; |
190 |
const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1; |
191 |
uint32_t x1 = (addr >> (64-DYNTRANS_L1N)) & mask1; |
192 |
uint32_t x2 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; |
193 |
uint32_t x3 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N- |
194 |
DYNTRANS_L3N)) & mask3; |
195 |
struct DYNTRANS_L2_64_TABLE *l2 = cpu->cd.x86.l1_64[x1]; |
196 |
struct DYNTRANS_L3_64_TABLE *l3 = l2->l3[x2]; |
197 |
page = l3->host_load[x3]; |
198 |
} |
199 |
#endif |
200 |
|
201 |
if (page != NULL) { |
202 |
/* fatal("TRANSLATION HIT!\n"); */ |
203 |
(*byte) = page[addr & 0xfff]; |
204 |
} else { |
205 |
/* fatal("TRANSLATION MISS!\n"); */ |
206 |
if (!cpu->memory_rw(cpu, cpu->mem, addr, byte, |
207 |
1, MEM_READ, CACHE_INSTRUCTION)) { |
208 |
/* exception occurred, or similar */ |
209 |
return 0; |
210 |
} |
211 |
} |
212 |
|
213 |
return 1; |
214 |
} |
215 |
|
216 |
|
217 |
#ifndef GNB |
218 |
#define GNB { if (len >= sizeof(ib)) \ |
219 |
goto bad; \ |
220 |
if (!GET_NEXT_BYTE(cpu, &ib[len++], addr++)) \ |
221 |
goto gnb_failed; \ |
222 |
} |
223 |
#endif |
224 |
|
225 |
|
226 |
#ifndef GET_OP |
227 |
#define GET_OP opimm = 0; \ |
228 |
{ \ |
229 |
int i; \ |
230 |
for (i=0; i<oplen; i++) { \ |
231 |
GNB; \ |
232 |
opimm |= (ib[len-1] << (i*8)); \ |
233 |
} \ |
234 |
} |
235 |
#endif |
236 |
|
237 |
|
238 |
/* |
239 |
* x86_instr_to_be_translated(): |
240 |
* |
241 |
* Translate an instruction word into an x86_instr_call. ic is filled in with |
242 |
* valid data for the translated instruction, or a "nothing" instruction if |
243 |
* there was a translation failure. The newly translated instruction is then |
244 |
* executed. |
245 |
*/ |
246 |
X(to_be_translated) |
247 |
{ |
248 |
MODE_uint_t addr, orig_addr, low_pc; |
249 |
int main_opcode, secondary_opcode, len, mode16, oplen; |
250 |
uint32_t opimm; |
251 |
unsigned char ib[17]; |
252 |
/* void (*samepage_function)(struct cpu *, struct x86_instr_call *); */ |
253 |
|
254 |
/* Figure out the (virtual) address of the instruction: */ |
255 |
low_pc = ((size_t)ic - (size_t)cpu->cd.x86.cur_ic_page) |
256 |
/ sizeof(struct x86_instr_call); |
257 |
addr = cpu->pc & ~(X86_IC_ENTRIES_PER_PAGE-1); |
258 |
addr += low_pc; |
259 |
cpu->pc = addr; |
260 |
orig_addr = addr; |
261 |
|
262 |
if (!cpu->cd.x86.descr_cache[X86_S_CS].valid) { |
263 |
fatal("x86_cpu_run_instr(): Invalid CS descriptor?\n"); |
264 |
exit(1); |
265 |
} |
266 |
|
267 |
cpu->cd.x86.cursegment = X86_S_CS; |
268 |
cpu->cd.x86.seg_override = 0; |
269 |
|
270 |
|
271 |
#define DYNTRANS_TO_BE_TRANSLATED_HEAD |
272 |
#include "cpu_dyntrans.c" |
273 |
#undef DYNTRANS_TO_BE_TRANSLATED_HEAD |
274 |
|
275 |
|
276 |
/* |
277 |
* Translate the instruction: |
278 |
*/ |
279 |
|
280 |
ic->arg[0] = len = 0; |
281 |
|
282 |
if (LONG_MODE) { |
283 |
fatal("LONG MODE: TODO\n"); |
284 |
goto bad; |
285 |
} |
286 |
|
287 |
mode16 = REAL_MODE; |
288 |
|
289 |
/* Parse prefix bytes, and get the main (first) opcode byte: */ |
290 |
for (;;) { |
291 |
GNB; main_opcode = ib[len - 1]; |
292 |
if (main_opcode == 0x66) { |
293 |
mode16 = !mode16; |
294 |
} else { |
295 |
/* Found a non-prefix byte? Then break. */ |
296 |
break; |
297 |
} |
298 |
} |
299 |
|
300 |
oplen = mode16? sizeof(uint16_t) : sizeof(uint32_t); |
301 |
|
302 |
switch (main_opcode) { |
303 |
|
304 |
case 0x0f: |
305 |
GNB; secondary_opcode = ib[len-1]; |
306 |
switch (secondary_opcode) { |
307 |
|
308 |
case 0xa2: |
309 |
ic->f = instr(cpuid); |
310 |
break; |
311 |
|
312 |
default:fatal("unimplemented 0x0f opcode 0x%02x\n", |
313 |
secondary_opcode); |
314 |
goto bad; |
315 |
} |
316 |
break; |
317 |
|
318 |
case 0x40: /* inc ax etc. */ |
319 |
case 0x41: |
320 |
case 0x42: |
321 |
case 0x43: |
322 |
case 0x44: |
323 |
case 0x45: |
324 |
case 0x46: |
325 |
case 0x47: |
326 |
if (mode16) { |
327 |
switch (main_opcode) { |
328 |
case 0x40: ic->f = instr(inc_ax); break; |
329 |
case 0x41: ic->f = instr(inc_cx); break; |
330 |
case 0x42: ic->f = instr(inc_dx); break; |
331 |
case 0x43: ic->f = instr(inc_bx); break; |
332 |
case 0x44: ic->f = instr(inc_sp); break; |
333 |
case 0x45: ic->f = instr(inc_bp); break; |
334 |
case 0x46: ic->f = instr(inc_si); break; |
335 |
case 0x47: ic->f = instr(inc_di); break; |
336 |
} |
337 |
} else { |
338 |
switch (main_opcode) { |
339 |
case 0x40: ic->f = instr(inc_eax); break; |
340 |
case 0x41: ic->f = instr(inc_ecx); break; |
341 |
case 0x42: ic->f = instr(inc_edx); break; |
342 |
case 0x43: ic->f = instr(inc_ebx); break; |
343 |
case 0x44: ic->f = instr(inc_esp); break; |
344 |
case 0x45: ic->f = instr(inc_ebp); break; |
345 |
case 0x46: ic->f = instr(inc_esi); break; |
346 |
case 0x47: ic->f = instr(inc_edi); break; |
347 |
} |
348 |
} |
349 |
break; |
350 |
|
351 |
case 0x90: /* nop */ |
352 |
ic->f = instr(nop); |
353 |
break; |
354 |
|
355 |
case 0xb0: /* mov al,imm etc. */ |
356 |
case 0xb1: |
357 |
case 0xb2: |
358 |
case 0xb3: |
359 |
case 0xb4: |
360 |
case 0xb5: |
361 |
case 0xb6: |
362 |
case 0xb7: |
363 |
GNB; |
364 |
ic->arg[1] = ib[len - 1]; |
365 |
/* Calculate for little endian first: */ |
366 |
ic->arg[2] = (size_t)&cpu->cd.x86.r[main_opcode & 3]; |
367 |
if (main_opcode >= 0xb4) |
368 |
ic->arg[2] ++; |
369 |
#ifdef HOST_BIG_ENDIAN |
370 |
/* Switch byte order: */ |
371 |
ic->arg[2] = (ic->arg[2] & ~(sizeof(uint64_t)-1)) + |
372 |
sizeof(uint64_t) - 1 - (ic->arg[2] & (sizeof(uint64_t)-1)); |
373 |
#endif |
374 |
ic->f = instr(mov_reg_imm_8); |
375 |
break; |
376 |
|
377 |
case 0xb8: /* mov ax,imm etc. */ |
378 |
case 0xb9: |
379 |
case 0xba: |
380 |
case 0xbb: |
381 |
case 0xbc: |
382 |
case 0xbd: |
383 |
case 0xbe: |
384 |
case 0xbf: |
385 |
GET_OP; |
386 |
ic->arg[1] = opimm; |
387 |
ic->arg[2] = (size_t)&cpu->cd.x86.r[main_opcode - 0xb8]; |
388 |
if (mode16) |
389 |
ic->f = instr(mov_reg_imm_16); |
390 |
else |
391 |
ic->f = instr(mov_reg_imm_32); |
392 |
break; |
393 |
|
394 |
case 0xf8: /* clc */ |
395 |
case 0xf9: /* stc */ |
396 |
case 0xfa: /* cli */ |
397 |
case 0xfb: /* sti */ |
398 |
case 0xfc: /* cld */ |
399 |
case 0xfd: /* std */ |
400 |
switch (main_opcode) { |
401 |
case 0xf8: ic->f = instr(sti); break; |
402 |
case 0xf9: ic->f = instr(stc); break; |
403 |
case 0xfa: ic->f = instr(cli); break; |
404 |
case 0xfb: ic->f = instr(sti); break; |
405 |
case 0xfc: ic->f = instr(cld); break; |
406 |
case 0xfd: ic->f = instr(std); break; |
407 |
} |
408 |
break; |
409 |
|
410 |
default:goto bad; |
411 |
} |
412 |
|
413 |
|
414 |
if (((addr-1) & ~0xfff) != (orig_addr & ~0xfff)) { |
415 |
fatal("Instruction crosses page boundary. TODO\n"); |
416 |
exit(1); |
417 |
} |
418 |
|
419 |
if (len > sizeof(ib)) { |
420 |
fatal("INTERNAL ERROR in cpu_x86_instr.c! len = %i\n", len); |
421 |
exit(1); |
422 |
} |
423 |
|
424 |
ic->arg[0] = len; |
425 |
goto ok; |
426 |
|
427 |
|
428 |
/* We get here if get_next_byte failed (i.e. an excepion occured while |
429 |
crossing a page-boundary...) */ |
430 |
gnb_failed: |
431 |
ic->f = instr(to_be_translated); |
432 |
ic->arg[0] = 0; |
433 |
/* The program counter etc. should already have been updated. */ |
434 |
return; |
435 |
|
436 |
ok: |
437 |
|
438 |
#define DYNTRANS_TO_BE_TRANSLATED_TAIL |
439 |
#include "cpu_dyntrans.c" |
440 |
#undef DYNTRANS_TO_BE_TRANSLATED_TAIL |
441 |
} |
442 |
|