25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_x86_instr.c,v 1.5 2006/02/09 22:55:20 debug Exp $ |
* $Id: cpu_x86_instr.c,v 1.13 2006/04/22 18:07:30 debug Exp $ |
29 |
* |
* |
30 |
* x86/amd64 instructions. |
* x86/amd64 instructions. |
31 |
* |
* |
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) |
X(end_of_page) |
154 |
{ |
{ |
155 |
/* Update the PC: (offset 0, but on the next page) */ |
/* Update the PC: (offset 0, but on the next page) */ |
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(): |
* x86_instr_to_be_translated(): |
240 |
* |
* |
245 |
*/ |
*/ |
246 |
X(to_be_translated) |
X(to_be_translated) |
247 |
{ |
{ |
248 |
uint64_t addr, low_pc; |
MODE_uint_t addr, orig_addr, low_pc; |
249 |
#ifdef DYNTRANS_BACKEND |
int main_opcode, secondary_opcode, len, mode16, oplen; |
250 |
int simple = 0; |
uint32_t opimm; |
|
#endif |
|
|
unsigned char *page; |
|
|
int main_opcode; |
|
251 |
unsigned char ib[17]; |
unsigned char ib[17]; |
252 |
/* void (*samepage_function)(struct cpu *, struct x86_instr_call *); */ |
/* void (*samepage_function)(struct cpu *, struct x86_instr_call *); */ |
253 |
|
|
257 |
addr = cpu->pc & ~(X86_IC_ENTRIES_PER_PAGE-1); |
addr = cpu->pc & ~(X86_IC_ENTRIES_PER_PAGE-1); |
258 |
addr += low_pc; |
addr += low_pc; |
259 |
cpu->pc = addr; |
cpu->pc = addr; |
260 |
|
orig_addr = addr; |
261 |
|
|
262 |
if (!cpu->cd.x86.descr_cache[X86_S_CS].valid) { |
if (!cpu->cd.x86.descr_cache[X86_S_CS].valid) { |
263 |
fatal("x86_cpu_run_instr(): Invalid CS descriptor?\n"); |
fatal("x86_cpu_run_instr(): Invalid CS descriptor?\n"); |
267 |
cpu->cd.x86.cursegment = X86_S_CS; |
cpu->cd.x86.cursegment = X86_S_CS; |
268 |
cpu->cd.x86.seg_override = 0; |
cpu->cd.x86.seg_override = 0; |
269 |
|
|
|
/* Read the instruction word from memory: */ |
|
|
page = cpu->cd.x86.host_load[addr >> 12]; |
|
|
|
|
|
if (page != NULL) { |
|
|
/* fatal("TRANSLATION HIT!\n"); */ |
|
|
ib[0] = page[addr & 0xfff]; |
|
|
} else { |
|
|
/* fatal("TRANSLATION MISS!\n"); */ |
|
|
if (!cpu->memory_rw(cpu, cpu->mem, addr, &ib[0], |
|
|
1, MEM_READ, CACHE_INSTRUCTION)) { |
|
|
fatal("to_be_translated(): read failed: TODO\n"); |
|
|
goto bad; |
|
|
} |
|
|
} |
|
|
|
|
|
fatal("X86: ib[0] = 0x%02x\n", ib[0]); |
|
|
|
|
270 |
|
|
271 |
#define DYNTRANS_TO_BE_TRANSLATED_HEAD |
#define DYNTRANS_TO_BE_TRANSLATED_HEAD |
272 |
#include "cpu_dyntrans.c" |
#include "cpu_dyntrans.c" |
277 |
* Translate the instruction: |
* Translate the instruction: |
278 |
*/ |
*/ |
279 |
|
|
280 |
|
ic->arg[0] = len = 0; |
281 |
|
|
282 |
/* TODO */ |
if (LONG_MODE) { |
283 |
|
fatal("LONG MODE: TODO\n"); |
284 |
|
goto bad; |
285 |
|
} |
286 |
|
|
287 |
|
mode16 = REAL_MODE; |
288 |
|
|
289 |
main_opcode = ib[0]; |
/* 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) { |
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; |
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 |
#define DYNTRANS_TO_BE_TRANSLATED_TAIL |
439 |
#include "cpu_dyntrans.c" |
#include "cpu_dyntrans.c" |
440 |
#undef DYNTRANS_TO_BE_TRANSLATED_TAIL |
#undef DYNTRANS_TO_BE_TRANSLATED_TAIL |