/[gxemul]/upstream/0.3.4/src/cpu_x86.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/0.3.4/src/cpu_x86.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11 - (show annotations)
Mon Oct 8 16:18:31 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 154404 byte(s)
0.3.4
1 /*
2 * Copyright (C) 2005 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.c,v 1.163 2005/06/26 22:23:42 debug Exp $
29 *
30 * x86 (and amd64) CPU emulation.
31 *
32 *
33 * TODO: Pretty much everything that has to do with 64-bit and 32-bit modes,
34 * memory translation, flag bits, and so on.
35 *
36 * See http://www.amd.com/us-en/Processors/DevelopWithAMD/
37 * 0,,30_2252_875_7044,00.html for more info on AMD64.
38 *
39 * http://www.cs.ucla.edu/~kohler/class/04f-aos/ref/i386/appa.htm has a
40 * nice overview of the standard i386 opcodes.
41 *
42 * HelpPC (http://members.tripod.com/~oldboard/assembly/) is also useful.
43 */
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <ctype.h>
49
50 #include "misc.h"
51
52
53 #ifndef ENABLE_X86
54
55
56 #include "cpu_x86.h"
57
58 /* (Bogus, when ENABLE_X86 isn't defined.) */
59 int x86_cpu_family_init(struct cpu_family *fp) { return 0; }
60
61
62 #else /* ENABLE_X86 */
63
64
65 #include "cpu.h"
66 #include "cpu_x86.h"
67 #include "devices.h"
68 #include "machine.h"
69 #include "memory.h"
70 #include "symbol.h"
71
72
73 extern volatile int single_step;
74 extern int old_show_trace_tree;
75 extern int old_instruction_trace;
76 extern int old_quiet_mode;
77 extern int quiet_mode;
78
79
80 static struct x86_model models[] = x86_models;
81 static char *reg_names[N_X86_REGS] = x86_reg_names;
82 static char *reg_names_bytes[8] = x86_reg_names_bytes;
83 static char *seg_names[N_X86_SEGS] = x86_seg_names;
84 static char *cond_names[N_X86_CONDS] = x86_cond_names;
85
86 #define REP_REP 1
87 #define REP_REPNE 2
88
89
90 /*
91 * x86_cpu_new():
92 *
93 * Create a new x86 cpu object.
94 */
95 int x86_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine,
96 int cpu_id, char *cpu_type_name)
97 {
98 int i = 0;
99
100 /* Try to find a match: */
101 while (models[i].model_number != 0) {
102 if (strcasecmp(cpu_type_name, models[i].name) == 0)
103 break;
104 i++;
105 }
106
107 if (models[i].name == NULL)
108 return 0;
109
110 cpu->memory_rw = x86_memory_rw;
111 cpu->byte_order = EMUL_LITTLE_ENDIAN;
112
113 cpu->cd.x86.model = models[i];
114
115 /* Initial startup is in 16-bit real mode: */
116 cpu->pc = 0xfff0;
117
118 /* Initial segments: */
119 cpu->cd.x86.descr_cache[X86_S_CS].valid = 1;
120 cpu->cd.x86.descr_cache[X86_S_CS].default_op_size = 16;
121 cpu->cd.x86.descr_cache[X86_S_CS].access_rights = 0x93;
122 cpu->cd.x86.descr_cache[X86_S_CS].base = 0xf0000; /* ffff0000 */
123 cpu->cd.x86.descr_cache[X86_S_CS].limit = 0xffff;
124 cpu->cd.x86.descr_cache[X86_S_CS].descr_type = DESCR_TYPE_CODE;
125 cpu->cd.x86.descr_cache[X86_S_CS].readable = 1;
126 cpu->cd.x86.descr_cache[X86_S_CS].writable = 1;
127 cpu->cd.x86.descr_cache[X86_S_CS].granularity = 0;
128 cpu->cd.x86.s[X86_S_CS] = 0xf000;
129
130 cpu->cd.x86.idtr = 0;
131 cpu->cd.x86.idtr_limit = 0x3ff;
132
133 cpu->translate_address = translate_address_x86;
134
135 cpu->cd.x86.rflags = 0x0002;
136 if (cpu->cd.x86.model.model_number == X86_MODEL_8086)
137 cpu->cd.x86.rflags |= 0xf000;
138
139 /* Only show name and caches etc for CPU nr 0 (in SMP machines): */
140 if (cpu_id == 0) {
141 debug("%s", cpu->name);
142 }
143
144 return 1;
145 }
146
147
148 /*
149 * x86_cpu_dumpinfo():
150 */
151 void x86_cpu_dumpinfo(struct cpu *cpu)
152 {
153 debug(", currently in %s mode", PROTECTED_MODE? "protected" : "real");
154 debug("\n");
155 }
156
157
158 /*
159 * x86_cpu_list_available_types():
160 *
161 * Print a list of available x86 CPU types.
162 */
163 void x86_cpu_list_available_types(void)
164 {
165 int i = 0, j;
166
167 while (models[i].model_number != 0) {
168 debug("%s", models[i].name);
169
170 for (j=0; j<10-strlen(models[i].name); j++)
171 debug(" ");
172 i++;
173 if ((i % 6) == 0 || models[i].name == NULL)
174 debug("\n");
175 }
176 }
177
178
179 /*
180 * x86_cpu_register_dump():
181 *
182 * Dump cpu registers in a relatively readable format.
183 * (gprs and coprocs are mostly useful for the MIPS version of this function.)
184 */
185 void x86_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
186 {
187 char *symbol;
188 uint64_t offset;
189 int i, x = cpu->cpu_id;
190
191 if (REAL_MODE) {
192 /* Real-mode: */
193 debug("cpu%i: cs:ip = 0x%04x:0x%04x\n", x,
194 cpu->cd.x86.s[X86_S_CS], (int)cpu->pc);
195
196 debug("cpu%i: ax = 0x%04x bx = 0x%04x cx = 0x%04x dx = "
197 "0x%04x\n", x,
198 (int)cpu->cd.x86.r[X86_R_AX], (int)cpu->cd.x86.r[X86_R_BX],
199 (int)cpu->cd.x86.r[X86_R_CX], (int)cpu->cd.x86.r[X86_R_DX]);
200 debug("cpu%i: si = 0x%04x di = 0x%04x bp = 0x%04x sp = "
201 "0x%04x\n", x,
202 (int)cpu->cd.x86.r[X86_R_SI], (int)cpu->cd.x86.r[X86_R_DI],
203 (int)cpu->cd.x86.r[X86_R_BP], (int)cpu->cd.x86.r[X86_R_SP]);
204
205 debug("cpu%i: ds = 0x%04x es = 0x%04x ss = 0x%04x flags "
206 "= 0x%04x\n", x,
207 (int)cpu->cd.x86.s[X86_S_DS], (int)cpu->cd.x86.s[X86_S_ES],
208 (int)cpu->cd.x86.s[X86_S_SS], (int)cpu->cd.x86.rflags);
209 } else {
210 symbol = get_symbol_name(&cpu->machine->symbol_context,
211 cpu->pc, &offset);
212
213 debug("cpu%i: eip=0x", x);
214 debug("%08x", (int)cpu->pc);
215 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
216
217 debug("cpu%i: eax=0x%08x ebx=0x%08x ecx=0x%08x edx="
218 "0x%08x\n", x,
219 (int)cpu->cd.x86.r[X86_R_AX], (int)cpu->cd.x86.r[X86_R_BX],
220 (int)cpu->cd.x86.r[X86_R_CX], (int)cpu->cd.x86.r[X86_R_DX]);
221 debug("cpu%i: esi=0x%08x edi=0x%08x ebp=0x%08x esp="
222 "0x%08x\n", x,
223 (int)cpu->cd.x86.r[X86_R_SI], (int)cpu->cd.x86.r[X86_R_DI],
224 (int)cpu->cd.x86.r[X86_R_BP], (int)cpu->cd.x86.r[X86_R_SP]);
225 #if 0
226 } else {
227 /* 64-bit */
228 symbol = get_symbol_name(&cpu->machine->symbol_context,
229 cpu->pc, &offset);
230
231 debug("cpu%i: rip = 0x", x);
232 debug("%016llx", (long long)cpu->pc);
233 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
234
235 for (i=0; i<N_X86_REGS; i++) {
236 if ((i & 1) == 0)
237 debug("cpu%i:", x);
238 debug(" r%s = 0x%016llx", reg_names[i],
239 (long long)cpu->cd.x86.r[i]);
240 if ((i & 1) == 1)
241 debug("\n");
242 }
243 #endif
244 }
245
246 if (coprocs != 0) {
247 for (i=0; i<6; i++) {
248 debug("cpu%i: %s=0x%04x (", x, seg_names[i],
249 cpu->cd.x86.s[i]);
250 if (cpu->cd.x86.descr_cache[i].valid) {
251 debug("base=0x%08x, limit=0x%08x, ",
252 (int)cpu->cd.x86.descr_cache[i].base,
253 (int)cpu->cd.x86.descr_cache[i].limit);
254 debug("%s", cpu->cd.x86.descr_cache[i].
255 descr_type==DESCR_TYPE_CODE?"CODE":"DATA");
256 debug(", %i-bit", cpu->cd.x86.descr_cache[i].
257 default_op_size);
258 debug(", %s%s", cpu->cd.x86.descr_cache[i].
259 readable? "R" : "-", cpu->cd.x86.
260 descr_cache[i].writable? "W" : "-");
261 } else
262 debug("invalid");
263 debug(")\n");
264 }
265 debug("cpu%i: gdtr=0x%08llx:0x%04x idtr=0x%08llx:0x%04x "
266 " ldtr=0x%08x:0x%04x\n", x, (long long)cpu->cd.x86.gdtr,
267 (int)cpu->cd.x86.gdtr_limit, (long long)cpu->cd.x86.idtr,
268 (int)cpu->cd.x86.idtr_limit, (long long)cpu->cd.x86.
269 ldtr_base, (int)cpu->cd.x86.ldtr_limit);
270 debug("cpu%i: pic1: irr=0x%02x ier=0x%02x isr=0x%02x "
271 "base=0x%02x\n", x, cpu->machine->md.pc.pic1->irr,
272 cpu->machine->md.pc.pic1->ier,cpu->machine->md.pc.pic1->isr,
273 cpu->machine->md.pc.pic1->irq_base);
274 debug("cpu%i: pic2: irr=0x%02x ier=0x%02x isr=0x%02x "
275 "base=0x%02x\n", x, cpu->machine->md.pc.pic2->irr,
276 cpu->machine->md.pc.pic2->ier,cpu->machine->md.pc.pic2->isr,
277 cpu->machine->md.pc.pic2->irq_base);
278 } else if (PROTECTED_MODE) {
279 /* Protected mode: */
280 debug("cpu%i: cs=0x%04x ds=0x%04x es=0x%04x "
281 "fs=0x%04x gs=0x%04x ss=0x%04x\n", x,
282 (int)cpu->cd.x86.s[X86_S_CS], (int)cpu->cd.x86.s[X86_S_DS],
283 (int)cpu->cd.x86.s[X86_S_ES], (int)cpu->cd.x86.s[X86_S_FS],
284 (int)cpu->cd.x86.s[X86_S_GS], (int)cpu->cd.x86.s[X86_S_SS]);
285 }
286
287 if (PROTECTED_MODE) {
288 /* Protected mode: */
289 debug("cpu%i: cr0=0x%08x cr2=0x%08x cr3=0x%08x eflags="
290 "0x%08x\n", x, (int)cpu->cd.x86.cr[0],
291 (int)cpu->cd.x86.cr[2], (int)cpu->cd.x86.cr[3],
292 (int)cpu->cd.x86.rflags);
293 debug("cpu%i: tr = 0x%04x (base=0x%llx, limit=0x%x)\n",
294 x, (int)cpu->cd.x86.tr, (long long)cpu->cd.x86.tr_base,
295 (int)cpu->cd.x86.tr_limit);
296 }
297 }
298
299
300 /*
301 * x86_cpu_register_match():
302 */
303 void x86_cpu_register_match(struct machine *m, char *name,
304 int writeflag, uint64_t *valuep, int *mr)
305 {
306 int cpunr = 0;
307 int r;
308
309 /* CPU number: TODO */
310
311 if (strcasecmp(name, "pc") == 0 || strcasecmp(name, "rip") == 0) {
312 if (writeflag) {
313 m->cpus[cpunr]->pc = *valuep;
314 m->cpus[cpunr]->cd.x86.halted = 0;
315 } else
316 *valuep = m->cpus[cpunr]->pc;
317 *mr = 1;
318 return;
319 }
320 if (strcasecmp(name, "ip") == 0) {
321 if (writeflag) {
322 m->cpus[cpunr]->pc = (m->cpus[cpunr]->pc & ~0xffff)
323 | (*valuep & 0xffff);
324 m->cpus[cpunr]->cd.x86.halted = 0;
325 } else
326 *valuep = m->cpus[cpunr]->pc & 0xffff;
327 *mr = 1;
328 return;
329 }
330 if (strcasecmp(name, "eip") == 0) {
331 if (writeflag) {
332 m->cpus[cpunr]->pc = *valuep;
333 m->cpus[cpunr]->cd.x86.halted = 0;
334 } else
335 *valuep = m->cpus[cpunr]->pc & 0xffffffffULL;
336 *mr = 1;
337 return;
338 }
339
340 if (strcasecmp(name, "rflags") == 0) {
341 if (writeflag)
342 m->cpus[cpunr]->cd.x86.rflags = *valuep;
343 else
344 *valuep = m->cpus[cpunr]->cd.x86.rflags;
345 *mr = 1;
346 return;
347 }
348 if (strcasecmp(name, "eflags") == 0) {
349 if (writeflag)
350 m->cpus[cpunr]->cd.x86.rflags = (m->cpus[cpunr]->
351 cd.x86.rflags & ~0xffffffffULL) | (*valuep &
352 0xffffffffULL);
353 else
354 *valuep = m->cpus[cpunr]->cd.x86.rflags & 0xffffffffULL;
355 *mr = 1;
356 return;
357 }
358 if (strcasecmp(name, "flags") == 0) {
359 if (writeflag)
360 m->cpus[cpunr]->cd.x86.rflags = (m->cpus[cpunr]->
361 cd.x86.rflags & ~0xffff) | (*valuep & 0xffff);
362 else
363 *valuep = m->cpus[cpunr]->cd.x86.rflags & 0xffff;
364 *mr = 1;
365 return;
366 }
367
368 /* 8-bit low: */
369 for (r=0; r<4; r++)
370 if (strcasecmp(name, reg_names_bytes[r]) == 0) {
371 if (writeflag)
372 m->cpus[cpunr]->cd.x86.r[r] =
373 (m->cpus[cpunr]->cd.x86.r[r] & ~0xff)
374 | (*valuep & 0xff);
375 else
376 *valuep = m->cpus[cpunr]->cd.x86.r[r] & 0xff;
377 *mr = 1;
378 return;
379 }
380
381 /* 8-bit high: */
382 for (r=0; r<4; r++)
383 if (strcasecmp(name, reg_names_bytes[r+4]) == 0) {
384 if (writeflag)
385 m->cpus[cpunr]->cd.x86.r[r] =
386 (m->cpus[cpunr]->cd.x86.r[r] & ~0xff00)
387 | ((*valuep & 0xff) << 8);
388 else
389 *valuep = (m->cpus[cpunr]->cd.x86.r[r] >>
390 8) & 0xff;
391 *mr = 1;
392 return;
393 }
394
395 /* 16-, 32-, 64-bit registers: */
396 for (r=0; r<N_X86_REGS; r++) {
397 /* 16-bit: */
398 if (r<8 && strcasecmp(name, reg_names[r]) == 0) {
399 if (writeflag)
400 m->cpus[cpunr]->cd.x86.r[r] =
401 (m->cpus[cpunr]->cd.x86.r[r] & ~0xffff)
402 | (*valuep & 0xffff);
403 else
404 *valuep = m->cpus[cpunr]->cd.x86.r[r] & 0xffff;
405 *mr = 1;
406 return;
407 }
408
409 /* 32-bit: */
410 if (r<8 && (name[0]=='e' || name[0]=='E') &&
411 strcasecmp(name+1, reg_names[r]) == 0) {
412 if (writeflag)
413 m->cpus[cpunr]->cd.x86.r[r] =
414 *valuep & 0xffffffffULL;
415 else
416 *valuep = m->cpus[cpunr]->cd.x86.r[r] &
417 0xffffffffULL;
418 *mr = 1;
419 return;
420 }
421
422 /* 64-bit: */
423 if ((name[0]=='r' || name[0]=='R') &&
424 strcasecmp(name+1, reg_names[r]) == 0) {
425 if (writeflag)
426 m->cpus[cpunr]->cd.x86.r[r] = *valuep;
427 else
428 *valuep = m->cpus[cpunr]->cd.x86.r[r];
429 *mr = 1;
430 return;
431 }
432 }
433
434 /* segment names: */
435 for (r=0; r<N_X86_SEGS; r++) {
436 if (strcasecmp(name, seg_names[r]) == 0) {
437 if (writeflag)
438 m->cpus[cpunr]->cd.x86.s[r] =
439 (m->cpus[cpunr]->cd.x86.s[r] & ~0xffff)
440 | (*valuep & 0xffff);
441 else
442 *valuep = m->cpus[cpunr]->cd.x86.s[r] & 0xffff;
443 *mr = 1;
444 return;
445 }
446 }
447
448 /* control registers: (TODO: 32- vs 64-bit on AMD64?) */
449 if (strncasecmp(name, "cr", 2) == 0 && atoi(name+2) < N_X86_CREGS ) {
450 int r = atoi(name+2);
451 if (writeflag)
452 m->cpus[cpunr]->cd.x86.cr[r] = *valuep;
453 else
454 *valuep = m->cpus[cpunr]->cd.x86.cr[r];
455 *mr = 1;
456 return;
457 }
458 }
459
460
461 /* Macro which modifies the lower part of a value, or the entire value,
462 depending on 'mode': */
463 #define modify(old,new) ( \
464 mode==16? ( \
465 ((old) & ~0xffff) + ((new) & 0xffff) \
466 ) : ((new) & 0xffffffffULL) )
467
468 /* "volatile" here, because some versions of gcc with -O3 on i386 are buggy */
469 #define HEXPRINT(x,n) { volatile int j; for (j=0; j<(n); j++) \
470 debug("%02x",(x)[j]); }
471 #define HEXSPACES(i) { int j; j = (i)>10? 10:(i); while (j++<10) debug(" "); \
472 debug(" "); }
473 #define SPACES HEXSPACES(ilen)
474
475
476 static uint32_t read_imm_common(unsigned char **instrp, uint64_t *ilenp,
477 int len, int printflag)
478 {
479 uint32_t imm;
480 unsigned char *instr = *instrp;
481
482 if (len == 8)
483 imm = instr[0];
484 else if (len == 16)
485 imm = instr[0] + (instr[1] << 8);
486 else
487 imm = instr[0] + (instr[1] << 8) +
488 (instr[2] << 16) + (instr[3] << 24);
489
490 if (printflag)
491 HEXPRINT(instr, len / 8);
492
493 if (ilenp != NULL)
494 (*ilenp) += len/8;
495
496 (*instrp) += len/8;
497 return imm;
498 }
499
500
501 static uint32_t read_imm_and_print(unsigned char **instrp, uint64_t *ilenp,
502 int mode)
503 {
504 return read_imm_common(instrp, ilenp, mode, 1);
505 }
506
507
508 static uint32_t read_imm(unsigned char **instrp, uint64_t *newpcp,
509 int mode)
510 {
511 return read_imm_common(instrp, newpcp, mode, 0);
512 }
513
514
515 static void print_csip(struct cpu *cpu)
516 {
517 fatal("0x%04x:", cpu->cd.x86.s[X86_S_CS]);
518 if (PROTECTED_MODE)
519 fatal("0x%llx", (long long)cpu->pc);
520 else
521 fatal("0x%04x", (int)cpu->pc);
522 }
523
524
525 /*
526 * x86_cpu_interrupt():
527 *
528 * NOTE: Interacting with the 8259 PIC is done in src/machine.c.
529 */
530 int x86_cpu_interrupt(struct cpu *cpu, uint64_t nr)
531 {
532 if (cpu->machine->md_interrupt != NULL)
533 cpu->machine->md_interrupt(cpu->machine, cpu, nr, 1);
534 else {
535 fatal("x86_cpu_interrupt(): no md_interrupt()?\n");
536 return 1;
537 }
538
539 return 1;
540 }
541
542
543 /*
544 * x86_cpu_interrupt_ack():
545 *
546 * NOTE: Interacting with the 8259 PIC is done in src/machine.c.
547 */
548 int x86_cpu_interrupt_ack(struct cpu *cpu, uint64_t nr)
549 {
550 if (cpu->machine->md_interrupt != NULL)
551 cpu->machine->md_interrupt(cpu->machine, cpu, nr, 0);
552 else {
553 fatal("x86_cpu_interrupt(): no md_interrupt()?\n");
554 return 1;
555 }
556
557 return 1;
558 }
559
560
561 /* (NOTE: Don't use the lowest 3 bits in these defines) */
562 #define RELOAD_TR 0x1000
563 #define RELOAD_LDTR 0x1008
564
565
566 /*
567 * x86_task_switch():
568 *
569 * Save away current state into the current task state segment, and
570 * load the new state from the new task.
571 *
572 * TODO: 16-bit TSS, etc. And clean up all of this :)
573 *
574 * TODO: Link word. AMD64 stuff. And lots more.
575 */
576 void x86_task_switch(struct cpu *cpu, int new_tr, uint64_t *curpc)
577 {
578 unsigned char old_descr[8];
579 unsigned char new_descr[8];
580 uint32_t value, ofs;
581 int i;
582 unsigned char buf[4];
583
584 fatal("x86_task_switch():\n");
585 cpu->pc = *curpc;
586
587 if (!cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr + cpu->cd.x86.tr,
588 old_descr, sizeof(old_descr), MEM_READ, NO_SEGMENTATION)) {
589 fatal("x86_task_switch(): TODO: 1\n");
590 cpu->running = 0;
591 return;
592 }
593
594 /* Check the busy bit, and then clear it: */
595 if (!(old_descr[5] & 0x02)) {
596 fatal("x86_task_switch(): TODO: switching FROM a non-BUSY"
597 " TSS descriptor?\n");
598 cpu->running = 0;
599 return;
600 }
601 old_descr[5] &= ~0x02;
602 if (!cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr + cpu->cd.x86.tr,
603 old_descr, sizeof(old_descr), MEM_WRITE, NO_SEGMENTATION)) {
604 fatal("x86_task_switch(): TODO: could not clear busy bit\n");
605 cpu->running = 0;
606 return;
607 }
608
609 x86_cpu_register_dump(cpu, 1, 1);
610
611 /* Set the task-switched bit in CR0: */
612 cpu->cd.x86.cr[0] |= X86_CR0_TS;
613
614 /* Save away all the old registers: */
615 #define WRITE_VALUE { buf[0]=value; buf[1]=value>>8; buf[2]=value>>16; \
616 buf[3]=value>>24; cpu->memory_rw(cpu, cpu->mem, \
617 cpu->cd.x86.tr_base + ofs, buf, sizeof(buf), MEM_WRITE, \
618 NO_SEGMENTATION); }
619
620 ofs = 0x1c; value = cpu->cd.x86.cr[3]; WRITE_VALUE;
621 ofs = 0x20; value = cpu->pc; WRITE_VALUE;
622 ofs = 0x24; value = cpu->cd.x86.rflags; WRITE_VALUE;
623 for (i=0; i<N_X86_REGS; i++) {
624 ofs = 0x28+i*4; value = cpu->cd.x86.r[i]; WRITE_VALUE;
625 }
626 for (i=0; i<6; i++) {
627 ofs = 0x48+i*4; value = cpu->cd.x86.s[i]; WRITE_VALUE;
628 }
629
630 fatal("-------\n");
631
632 if ((cpu->cd.x86.tr & 0xfffc) == 0) {
633 fatal("TODO: x86_task_switch(): task switch, but old TR"
634 " was 0?\n");
635 cpu->running = 0;
636 return;
637 }
638
639 if (!cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr + new_tr,
640 new_descr, sizeof(new_descr), MEM_READ, NO_SEGMENTATION)) {
641 fatal("x86_task_switch(): TODO: 1\n");
642 cpu->running = 0;
643 return;
644 }
645 if (new_descr[5] & 0x02) {
646 fatal("x86_task_switch(): TODO: switching TO an already BUSY"
647 " TSS descriptor?\n");
648 cpu->running = 0;
649 return;
650 }
651
652 reload_segment_descriptor(cpu, RELOAD_TR, new_tr, NULL);
653
654 if (cpu->cd.x86.tr_limit < 0x67)
655 fatal("WARNING: tr_limit = 0x%x, must be at least 0x67!\n",
656 (int)cpu->cd.x86.tr_limit);
657
658 /* Read new registers: */
659 #define READ_VALUE { cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.tr_base + \
660 ofs, buf, sizeof(buf), MEM_READ, NO_SEGMENTATION); \
661 value = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24); }
662
663 ofs = 0x1c; READ_VALUE; cpu->cd.x86.cr[3] = value;
664 ofs = 0x20; READ_VALUE; cpu->pc = value;
665 ofs = 0x24; READ_VALUE; cpu->cd.x86.rflags = value;
666 for (i=0; i<N_X86_REGS; i++) {
667 ofs = 0x28+i*4; READ_VALUE; cpu->cd.x86.r[i] = value;
668 }
669 for (i=0; i<6; i++) {
670 ofs = 0x48+i*4; READ_VALUE;
671 reload_segment_descriptor(cpu, i, value, NULL);
672 }
673 ofs = 0x60; READ_VALUE; value &= 0xffff;
674 reload_segment_descriptor(cpu, RELOAD_LDTR, value, NULL);
675
676 if ((cpu->cd.x86.s[X86_S_CS] & X86_PL_MASK) !=
677 (cpu->cd.x86.s[X86_S_SS] & X86_PL_MASK))
678 fatal("WARNING: rpl in CS and SS differ!\n");
679
680 if ((cpu->cd.x86.s[X86_S_CS] & X86_PL_MASK) == X86_RING3 &&
681 !(cpu->cd.x86.rflags & X86_FLAGS_IF))
682 fatal("WARNING (?): switching to userland task, but interrupts"
683 " are disabled?\n");
684
685 x86_cpu_register_dump(cpu, 1, 1);
686 fatal("-------\n");
687
688 *curpc = cpu->pc;
689
690 /* cpu->machine->instruction_trace = 1; */
691 /* cpu->running = 0; */
692 }
693
694
695 /*
696 * reload_segment_descriptor():
697 *
698 * Loads base, limit and other settings from the Global Descriptor Table into
699 * segment descriptors.
700 *
701 * This function can also be used to reload the TR (task register).
702 *
703 * And also to do a task switch, or jump into a trap handler etc.
704 * (Perhaps this function should be renamed.)
705 */
706 void reload_segment_descriptor(struct cpu *cpu, int segnr, int selector,
707 uint64_t *curpcp)
708 {
709 int res, i, readable, writable, granularity, descr_type;
710 int segment = 1, rpl, orig_selector = selector;
711 unsigned char descr[8];
712 char *table_name = "GDT";
713 uint64_t base, limit, table_base, table_limit;
714
715 if (segnr > 0x100) /* arbitrary, larger than N_X86_SEGS */
716 segment = 0;
717
718 if (segment && (segnr < 0 || segnr >= N_X86_SEGS)) {
719 fatal("reload_segment_descriptor(): segnr = %i\n", segnr);
720 exit(1);
721 }
722
723 if (segment && REAL_MODE) {
724 /* Real mode: */
725 cpu->cd.x86.descr_cache[segnr].valid = 1;
726 cpu->cd.x86.descr_cache[segnr].default_op_size = 16;
727 cpu->cd.x86.descr_cache[segnr].access_rights = 0x93;
728 cpu->cd.x86.descr_cache[segnr].descr_type =
729 segnr == X86_S_CS? DESCR_TYPE_CODE : DESCR_TYPE_DATA;
730 cpu->cd.x86.descr_cache[segnr].readable = 1;
731 cpu->cd.x86.descr_cache[segnr].writable = 1;
732 cpu->cd.x86.descr_cache[segnr].granularity = 0;
733 cpu->cd.x86.descr_cache[segnr].base = selector << 4;
734 cpu->cd.x86.descr_cache[segnr].limit = 0xffff;
735 cpu->cd.x86.s[segnr] = selector;
736 return;
737 }
738
739 /*
740 * Protected mode: Load the descriptor cache from the GDT.
741 */
742
743 table_base = cpu->cd.x86.gdtr;
744 table_limit = cpu->cd.x86.gdtr_limit;
745 if (selector & 4) {
746 table_name = "LDT";
747 /* fatal("TODO: x86 translation via LDT: 0x%04x\n",
748 selector); */
749 table_base = cpu->cd.x86.ldtr_base;
750 table_limit = cpu->cd.x86.ldtr_limit;
751 }
752
753 /* Special case: Null-descriptor: */
754 if (segment && (selector & ~3) == 0) {
755 cpu->cd.x86.descr_cache[segnr].valid = 0;
756 cpu->cd.x86.s[segnr] = selector;
757 return;
758 }
759
760 rpl = selector & 3;
761
762 /* TODO: check rpl */
763
764 selector &= ~7;
765
766 if (selector + 7 > table_limit) {
767 fatal("TODO: selector 0x%04x outside %s limit (0x%04x)\n",
768 selector, table_name, (int)table_limit);
769 cpu->running = 0;
770 return;
771 }
772
773 res = cpu->memory_rw(cpu, cpu->mem, table_base + selector,
774 descr, sizeof(descr), MEM_READ, NO_SEGMENTATION);
775 if (!res) {
776 fatal("reload_segment_descriptor(): TODO: "
777 "could not read the GDT\n");
778 cpu->running = 0;
779 return;
780 }
781
782 base = descr[2] + (descr[3] << 8) + (descr[4] << 16) +
783 (descr[7] << 24);
784 limit = descr[0] + (descr[1] << 8) + ((descr[6]&15) << 16);
785
786 descr_type = readable = writable = granularity = 0;
787 granularity = (descr[6] & 0x80)? 1 : 0;
788 if (limit == 0) {
789 fatal("WARNING: descriptor limit = 0\n");
790 limit = 0xfffff;
791 }
792 if (granularity)
793 limit = (limit << 12) | 0xfff;
794
795 #if 0
796 printf("base = %llx\n",(long long)base);
797 for (i=0; i<8; i++)
798 fatal(" %02x", descr[i]);
799 #endif
800
801 if (selector != 0x0000 && (descr[5] & 0x80) == 0x00) {
802 fatal("TODO: nonpresent descriptor?\n");
803 goto fail_dump;
804 }
805
806 if (!segment) {
807 switch (segnr) {
808 case RELOAD_TR:
809 /* Check that this is indeed a TSS descriptor: */
810 if ((descr[5] & 0x15) != 0x01) {
811 fatal("TODO: load TR but entry in table is"
812 " not a TSS descriptor?\n");
813 goto fail_dump;
814 }
815
816 /* Reload the task register: */
817 cpu->cd.x86.tr = selector;
818 cpu->cd.x86.tr_base = base;
819 cpu->cd.x86.tr_limit = limit;
820
821 /* Mark the TSS as busy: */
822 descr[5] |= 0x02;
823 res = cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr +
824 selector, descr, sizeof(descr), MEM_WRITE,
825 NO_SEGMENTATION);
826 break;
827 case RELOAD_LDTR:
828 /* Reload the Local Descriptor Table register: */
829 cpu->cd.x86.ldtr = selector;
830 cpu->cd.x86.ldtr_base = base;
831 cpu->cd.x86.ldtr_limit = limit;
832 break;
833 }
834 return;
835 }
836
837 if ((descr[5] & 0x18) == 0x18) {
838 descr_type = DESCR_TYPE_CODE;
839 readable = descr[5] & 0x02? 1 : 0;
840 if ((descr[5] & 0x98) != 0x98) {
841 fatal("TODO CODE\n");
842 goto fail_dump;
843 }
844 } else if ((descr[5] & 0x18) == 0x10) {
845 descr_type = DESCR_TYPE_DATA;
846 readable = 1;
847 writable = descr[5] & 0x02? 1 : 0;
848 if ((descr[5] & 0x98) != 0x90) {
849 fatal("TODO DATA\n");
850 goto fail_dump;
851 }
852 } else if (segnr == X86_S_CS && (descr[5] & 0x15) == 0x01
853 && curpcp != NULL) {
854 /* TSS */
855 x86_task_switch(cpu, selector, curpcp);
856 return;
857 } else {
858 fatal("TODO: other\n");
859 goto fail_dump;
860 }
861
862 cpu->cd.x86.descr_cache[segnr].valid = 1;
863 cpu->cd.x86.descr_cache[segnr].default_op_size =
864 (descr[6] & 0x40)? 32 : 16;
865 cpu->cd.x86.descr_cache[segnr].access_rights = descr[5];
866 cpu->cd.x86.descr_cache[segnr].descr_type = descr_type;
867 cpu->cd.x86.descr_cache[segnr].readable = readable;
868 cpu->cd.x86.descr_cache[segnr].writable = writable;
869 cpu->cd.x86.descr_cache[segnr].granularity = granularity;
870 cpu->cd.x86.descr_cache[segnr].base = base;
871 cpu->cd.x86.descr_cache[segnr].limit = limit;
872 cpu->cd.x86.s[segnr] = orig_selector;
873 return;
874
875 fail_dump:
876 for (i=0; i<8; i++)
877 fatal(" %02x", descr[i]);
878 cpu->running = 0;
879 }
880
881
882 /*
883 * x86_load():
884 *
885 * Returns same error code as memory_rw().
886 */
887 static int x86_load(struct cpu *cpu, uint64_t addr, uint64_t *data, int len)
888 {
889 unsigned char databuf[8];
890 int res;
891 uint64_t d;
892
893 res = cpu->memory_rw(cpu, cpu->mem, addr, &databuf[0], len,
894 MEM_READ, CACHE_DATA);
895
896 d = databuf[0];
897 if (len > 1) {
898 d += ((uint64_t)databuf[1] << 8);
899 if (len > 2) {
900 d += ((uint64_t)databuf[2] << 16);
901 d += ((uint64_t)databuf[3] << 24);
902 if (len > 4) {
903 d += ((uint64_t)databuf[4] << 32);
904 d += ((uint64_t)databuf[5] << 40);
905 d += ((uint64_t)databuf[6] << 48);
906 d += ((uint64_t)databuf[7] << 56);
907 }
908 }
909 }
910
911 *data = d;
912 return res;
913 }
914
915
916 /*
917 * x86_store():
918 *
919 * Returns same error code as memory_rw().
920 */
921 static int x86_store(struct cpu *cpu, uint64_t addr, uint64_t data, int len)
922 {
923 unsigned char databuf[8];
924
925 /* x86 is always little-endian: */
926 databuf[0] = data;
927 if (len > 1) {
928 databuf[1] = data >> 8;
929 if (len > 2) {
930 databuf[2] = data >> 16;
931 databuf[3] = data >> 24;
932 if (len > 4) {
933 databuf[4] = data >> 32;
934 databuf[5] = data >> 40;
935 databuf[6] = data >> 48;
936 databuf[7] = data >> 56;
937 }
938 }
939 }
940
941 return cpu->memory_rw(cpu, cpu->mem, addr, &databuf[0], len,
942 MEM_WRITE, CACHE_DATA);
943 }
944
945
946 /*
947 * x86_write_cr():
948 *
949 * Write to a control register.
950 */
951 static void x86_write_cr(struct cpu *cpu, int r, uint64_t value)
952 {
953 uint64_t new, tmp;
954
955 switch (r) {
956 case 0: new = cpu->cd.x86.cr[r] = value;
957 /* Warn about unimplemented bits: */
958 tmp = new & ~(X86_CR0_PE | X86_CR0_PG);
959 if (cpu->cd.x86.model.model_number <= X86_MODEL_80386) {
960 if (tmp & X86_CR0_WP)
961 fatal("WARNING: cr0 WP bit set, but this is"
962 " not an 80486 or higher (?)\n");
963 }
964 tmp &= ~X86_CR0_WP;
965 if (tmp != 0)
966 fatal("x86_write_cr(): unimplemented cr0 bits: "
967 "0x%08llx\n", (long long)tmp);
968 break;
969 case 2:
970 case 3: new = cpu->cd.x86.cr[r] = value;
971 break;
972 case 4: new = cpu->cd.x86.cr[r] = value;
973 /* Warn about unimplemented bits: */
974 tmp = new; /* & ~(X86_CR0_PE | X86_CR0_PG); */
975 if (tmp != 0)
976 fatal("x86_write_cr(): unimplemented cr4 bits: "
977 "0x%08llx\n", (long long)tmp);
978 break;
979 default:fatal("x86_write_cr(): write to UNIMPLEMENTED cr%i\n", r);
980 cpu->running = 0;
981 }
982 }
983
984
985 static char *ofs_string(int32_t imm)
986 {
987 static char buf[25];
988 buf[0] = buf[sizeof(buf)-1] = '\0';
989
990 if (imm > 32)
991 sprintf(buf, "+0x%x", imm);
992 else if (imm > 0)
993 sprintf(buf, "+%i", imm);
994 else if (imm < -32)
995 sprintf(buf, "-0x%x", -imm);
996 else if (imm < 0)
997 sprintf(buf, "-%i", -imm);
998
999 return buf;
1000 }
1001
1002
1003 static char modrm_r[65];
1004 static char modrm_rm[65];
1005 #define MODRM_READ 0
1006 #define MODRM_WRITE_RM 1
1007 #define MODRM_WRITE_R 2
1008 /* flags: */
1009 #define MODRM_EIGHTBIT 1
1010 #define MODRM_SEG 2
1011 #define MODRM_JUST_GET_ADDR 4
1012 #define MODRM_CR 8
1013 #define MODRM_DR 16
1014 #define MODRM_R_NONEIGHTBIT 32
1015 #define MODRM_RM_16BIT 64
1016
1017
1018 /*
1019 * modrm():
1020 *
1021 * Yuck. I have a feeling that this function will become really ugly.
1022 */
1023 static int modrm(struct cpu *cpu, int writeflag, int mode, int mode67,
1024 int flags, unsigned char **instrp, uint64_t *lenp,
1025 uint64_t *op1p, uint64_t *op2p)
1026 {
1027 uint32_t imm, imm2;
1028 uint64_t addr = 0;
1029 int mod, r, rm, res = 1, z, q = mode/8, sib, s, i, b, immlen;
1030 char *e, *f;
1031 int disasm = (op1p == NULL);
1032
1033 /* e for data, f for addresses */
1034 e = f = "";
1035
1036 if (disasm) {
1037 if (mode == 32)
1038 e = "e";
1039 if (mode == 64)
1040 e = "r";
1041 if (mode67 == 32)
1042 f = "e";
1043 if (mode67 == 64)
1044 f = "r";
1045 modrm_rm[0] = modrm_rm[sizeof(modrm_rm)-1] = '\0';
1046 modrm_r[0] = modrm_r[sizeof(modrm_r)-1] = '\0';
1047 }
1048
1049 immlen = mode67;
1050 if (immlen == 64)
1051 immlen = 32;
1052
1053 imm = read_imm_common(instrp, lenp, 8, disasm);
1054 mod = (imm >> 6) & 3; r = (imm >> 3) & 7; rm = imm & 7;
1055
1056 if (flags & MODRM_EIGHTBIT)
1057 q = 1;
1058
1059 /*
1060 * R/M:
1061 */
1062
1063 switch (mod) {
1064 case 0:
1065 if (disasm) {
1066 if (mode67 >= 32) {
1067 if (rm == 5) {
1068 imm2 = read_imm_common(instrp, lenp,
1069 immlen, disasm);
1070 sprintf(modrm_rm, "[0x%x]", imm2);
1071 } else if (rm == 4) {
1072 char tmp[20];
1073 sib = read_imm_common(instrp, lenp,
1074 8, disasm);
1075 s = 1 << (sib >> 6);
1076 i = (sib >> 3) & 7;
1077 b = sib & 7;
1078 if (b == 5) { /* imm base */
1079 imm2 = read_imm_common(instrp,
1080 lenp, immlen, disasm);
1081 sprintf(tmp, ofs_string(imm2));
1082 } else
1083 sprintf(tmp, "+%s%s", f,
1084 reg_names[b]);
1085 if (i == 4)
1086 sprintf(modrm_rm, "[%s]", tmp);
1087 else if (s == 1)
1088 sprintf(modrm_rm, "[%s%s%s]",
1089 f, reg_names[i], tmp);
1090 else
1091 sprintf(modrm_rm, "[%s%s*%i%s"
1092 "]", f, reg_names[i],
1093 s, tmp);
1094 } else {
1095 sprintf(modrm_rm, "[%s%s]", f,
1096 reg_names[rm]);
1097 }
1098 } else {
1099 switch (rm) {
1100 case 0: sprintf(modrm_rm, "[bx+si]");
1101 break;
1102 case 1: sprintf(modrm_rm, "[bx+di]");
1103 break;
1104 case 2: sprintf(modrm_rm, "[bp+si]");
1105 break;
1106 case 3: sprintf(modrm_rm, "[bp+di]");
1107 break;
1108 case 4: sprintf(modrm_rm, "[si]");
1109 break;
1110 case 5: sprintf(modrm_rm, "[di]");
1111 break;
1112 case 6: imm2 = read_imm_common(instrp, lenp,
1113 immlen, disasm);
1114 sprintf(modrm_rm, "[0x%x]", imm2);
1115 break;
1116 case 7: sprintf(modrm_rm, "[bx]");
1117 break;
1118 }
1119 }
1120 } else {
1121 if (mode67 >= 32) {
1122 if (rm == 5) {
1123 addr = read_imm_common(instrp, lenp,
1124 immlen, disasm);
1125 } else if (rm == 4) {
1126 sib = read_imm_common(instrp, lenp,
1127 8, disasm);
1128 s = 1 << (sib >> 6);
1129 i = (sib >> 3) & 7;
1130 b = sib & 7;
1131 if (b == 4 &&
1132 !cpu->cd.x86.seg_override)
1133 cpu->cd.x86.cursegment=X86_S_SS;
1134 if (b == 5)
1135 addr = read_imm_common(instrp,
1136 lenp, mode67, disasm);
1137 else
1138 addr = cpu->cd.x86.r[b];
1139 if (i != 4)
1140 addr += cpu->cd.x86.r[i] * s;
1141 } else {
1142 addr = cpu->cd.x86.r[rm];
1143 }
1144 } else {
1145 switch (rm) {
1146 case 0: addr = cpu->cd.x86.r[X86_R_BX] +
1147 cpu->cd.x86.r[X86_R_SI]; break;
1148 case 1: addr = cpu->cd.x86.r[X86_R_BX] +
1149 cpu->cd.x86.r[X86_R_DI]; break;
1150 case 2: addr = cpu->cd.x86.r[X86_R_BP] +
1151 cpu->cd.x86.r[X86_R_SI];
1152 if (!cpu->cd.x86.seg_override)
1153 cpu->cd.x86.cursegment=X86_S_SS;
1154 break;
1155 case 3: addr = cpu->cd.x86.r[X86_R_BP] +
1156 cpu->cd.x86.r[X86_R_DI];
1157 if (!cpu->cd.x86.seg_override)
1158 cpu->cd.x86.cursegment=X86_S_SS;
1159 break;
1160 case 4: addr = cpu->cd.x86.r[X86_R_SI]; break;
1161 case 5: addr = cpu->cd.x86.r[X86_R_DI]; break;
1162 case 6: addr = read_imm_common(instrp, lenp,
1163 immlen, disasm); break;
1164 case 7: addr = cpu->cd.x86.r[X86_R_BX]; break;
1165 }
1166 }
1167
1168 if (mode67 == 16)
1169 addr &= 0xffff;
1170 if (mode67 == 32)
1171 addr &= 0xffffffffULL;
1172
1173 switch (writeflag) {
1174 case MODRM_WRITE_RM:
1175 res = x86_store(cpu, addr, *op1p, q);
1176 break;
1177 case MODRM_READ: /* read */
1178 if (flags & MODRM_JUST_GET_ADDR)
1179 *op1p = addr;
1180 else
1181 res = x86_load(cpu, addr, op1p, q);
1182 }
1183 }
1184 break;
1185 case 1:
1186 case 2:
1187 z = (mod == 1)? 8 : immlen;
1188 if (disasm) {
1189 if (mode67 >= 32) {
1190 if (rm == 4) {
1191 sib = read_imm_common(instrp, lenp,
1192 8, disasm);
1193 s = 1 << (sib >> 6);
1194 i = (sib >> 3) & 7;
1195 b = sib & 7;
1196 imm2 = read_imm_common(instrp, lenp,
1197 z, disasm);
1198 if (z == 8) imm2 = (signed char)imm2;
1199 if (i == 4)
1200 sprintf(modrm_rm, "[%s%s%s]",
1201 f, reg_names[b],
1202 ofs_string(imm2));
1203 else if (s == 1)
1204 sprintf(modrm_rm, "[%s%s%s"
1205 "%s%s]", f, reg_names[i],
1206 f, reg_names[b],
1207 ofs_string(imm2));
1208 else
1209 sprintf(modrm_rm, "[%s%s*%i+%s"
1210 "%s%s]", f, reg_names[i], s,
1211 f, reg_names[b],
1212 ofs_string(imm2));
1213 } else {
1214 imm2 = read_imm_common(instrp, lenp,
1215 z, disasm);
1216 if (z == 8) imm2 = (signed char)imm2;
1217 sprintf(modrm_rm, "[%s%s%s]", f,
1218 reg_names[rm], ofs_string(imm2));
1219 }
1220 } else
1221 switch (rm) {
1222 case 0: imm2 = read_imm_common(instrp, lenp, z, disasm);
1223 if (z == 8) imm2 = (signed char)imm2;
1224 sprintf(modrm_rm, "[bx+si%s]",ofs_string(imm2));
1225 break;
1226 case 1: imm2 = read_imm_common(instrp, lenp, z, disasm);
1227 if (z == 8) imm2 = (signed char)imm2;
1228 sprintf(modrm_rm, "[bx+di%s]",ofs_string(imm2));
1229 break;
1230 case 2: imm2 = read_imm_common(instrp, lenp, z, disasm);
1231 if (z == 8) imm2 = (signed char)imm2;
1232 sprintf(modrm_rm, "[bp+si%s]",ofs_string(imm2));
1233 break;
1234 case 3: imm2 = read_imm_common(instrp, lenp, z, disasm);
1235 if (z == 8) imm2 = (signed char)imm2;
1236 sprintf(modrm_rm, "[bp+di%s]",ofs_string(imm2));
1237 break;
1238 case 4: imm2 = read_imm_common(instrp, lenp, z, disasm);
1239 if (z == 8) imm2 = (signed char)imm2;
1240 sprintf(modrm_rm, "[si%s]", ofs_string(imm2));
1241 break;
1242 case 5: imm2 = read_imm_common(instrp, lenp, z, disasm);
1243 if (z == 8) imm2 = (signed char)imm2;
1244 sprintf(modrm_rm, "[di%s]", ofs_string(imm2));
1245 break;
1246 case 6: imm2 = read_imm_common(instrp, lenp, z, disasm);
1247 if (z == 8) imm2 = (signed char)imm2;
1248 sprintf(modrm_rm, "[bp%s]", ofs_string(imm2));
1249 break;
1250 case 7: imm2 = read_imm_common(instrp, lenp, z, disasm);
1251 if (z == 8) imm2 = (signed char)imm2;
1252 sprintf(modrm_rm, "[bx%s]", ofs_string(imm2));
1253 break;
1254 }
1255 } else {
1256 if (mode67 >= 32) {
1257 if (rm == 4) {
1258 sib = read_imm_common(instrp, lenp,
1259 8, disasm);
1260 s = 1 << (sib >> 6);
1261 i = (sib >> 3) & 7;
1262 b = sib & 7;
1263 addr = read_imm_common(instrp, lenp,
1264 z, disasm);
1265 if ((b == 4 || b == 5) &&
1266 !cpu->cd.x86.seg_override)
1267 cpu->cd.x86.cursegment=X86_S_SS;
1268 if (z == 8)
1269 addr = (signed char)addr;
1270 if (i == 4)
1271 addr = cpu->cd.x86.r[b] + addr;
1272 else
1273 addr = cpu->cd.x86.r[i] * s +
1274 cpu->cd.x86.r[b] + addr;
1275 } else {
1276 addr = read_imm_common(instrp, lenp,
1277 z, disasm);
1278 if (z == 8)
1279 addr = (signed char)addr;
1280 addr = cpu->cd.x86.r[rm] + addr;
1281 }
1282 } else {
1283 addr = read_imm_common(instrp, lenp, z, disasm);
1284 if (z == 8)
1285 addr = (signed char)addr;
1286 switch (rm) {
1287 case 0: addr += cpu->cd.x86.r[X86_R_BX]
1288 + cpu->cd.x86.r[X86_R_SI];
1289 break;
1290 case 1: addr += cpu->cd.x86.r[X86_R_BX]
1291 + cpu->cd.x86.r[X86_R_DI];
1292 break;
1293 case 2: addr += cpu->cd.x86.r[X86_R_BP]
1294 + cpu->cd.x86.r[X86_R_SI];
1295 if (!cpu->cd.x86.seg_override)
1296 cpu->cd.x86.cursegment=X86_S_SS;
1297 break;
1298 case 3: addr += cpu->cd.x86.r[X86_R_BP]
1299 + cpu->cd.x86.r[X86_R_DI];
1300 if (!cpu->cd.x86.seg_override)
1301 cpu->cd.x86.cursegment=X86_S_SS;
1302 break;
1303 case 4: addr += cpu->cd.x86.r[X86_R_SI];
1304 break;
1305 case 5: addr += cpu->cd.x86.r[X86_R_DI];
1306 break;
1307 case 6: addr += cpu->cd.x86.r[X86_R_BP];
1308 if (!cpu->cd.x86.seg_override)
1309 cpu->cd.x86.cursegment=X86_S_SS;
1310 break;
1311 case 7: addr += cpu->cd.x86.r[X86_R_BX];
1312 break;
1313 }
1314 }
1315
1316 if (mode67 == 16)
1317 addr &= 0xffff;
1318 if (mode67 == 32)
1319 addr &= 0xffffffffULL;
1320
1321 switch (writeflag) {
1322 case MODRM_WRITE_RM:
1323 res = x86_store(cpu, addr, *op1p, q);
1324 break;
1325 case MODRM_READ: /* read */
1326 if (flags & MODRM_JUST_GET_ADDR)
1327 *op1p = addr;
1328 else
1329 res = x86_load(cpu, addr, op1p, q);
1330 }
1331 }
1332 break;
1333 case 3:
1334 if (flags & MODRM_EIGHTBIT) {
1335 if (disasm) {
1336 strlcpy(modrm_rm, reg_names_bytes[rm],
1337 sizeof(modrm_rm));
1338 } else {
1339 switch (writeflag) {
1340 case MODRM_WRITE_RM:
1341 if (rm < 4)
1342 cpu->cd.x86.r[rm] =
1343 (cpu->cd.x86.r[rm] &
1344 ~0xff) | (*op1p & 0xff);
1345 else
1346 cpu->cd.x86.r[rm&3] = (cpu->
1347 cd.x86.r[rm&3] & ~0xff00) |
1348 ((*op1p & 0xff) << 8);
1349 break;
1350 case MODRM_READ:
1351 if (rm < 4)
1352 *op1p = cpu->cd.x86.r[rm] &
1353 0xff;
1354 else
1355 *op1p = (cpu->cd.x86.r[rm&3] &
1356 0xff00) >> 8;
1357 }
1358 }
1359 } else {
1360 if (disasm) {
1361 if (mode == 16 || flags & MODRM_RM_16BIT)
1362 strlcpy(modrm_rm, reg_names[rm],
1363 sizeof(modrm_rm));
1364 else
1365 sprintf(modrm_rm, "%s%s", e,
1366 reg_names[rm]);
1367 } else {
1368 switch (writeflag) {
1369 case MODRM_WRITE_RM:
1370 if (mode == 16 ||
1371 flags & MODRM_RM_16BIT)
1372 cpu->cd.x86.r[rm] = (
1373 cpu->cd.x86.r[rm] & ~0xffff)
1374 | (*op1p & 0xffff);
1375 else
1376 cpu->cd.x86.r[rm] =
1377 modify(cpu->cd.x86.r[rm],
1378 *op1p);
1379 break;
1380 case MODRM_READ: /* read */
1381 if (mode == 16 ||
1382 flags & MODRM_RM_16BIT)
1383 *op1p = cpu->cd.x86.r[rm]
1384 & 0xffff;
1385 else
1386 *op1p = cpu->cd.x86.r[rm];
1387 }
1388 }
1389 }
1390 break;
1391 default:
1392 fatal("modrm(): unimplemented mod %i\n", mod);
1393 exit(1);
1394 }
1395
1396
1397 /*
1398 * R:
1399 */
1400
1401 if (flags & MODRM_EIGHTBIT && !(flags & MODRM_R_NONEIGHTBIT)) {
1402 if (disasm) {
1403 strlcpy(modrm_r, reg_names_bytes[r],
1404 sizeof(modrm_r));
1405 } else {
1406 switch (writeflag) {
1407 case MODRM_WRITE_R:
1408 if (r < 4)
1409 cpu->cd.x86.r[r] = (cpu->cd.x86.r[r] &
1410 ~0xff) | (*op2p & 0xff);
1411 else
1412 cpu->cd.x86.r[r&3] = (cpu->cd.x86.r[r&3]
1413 & ~0xff00) | ((*op2p & 0xff) << 8);
1414 break;
1415 case MODRM_READ:
1416 if (r < 4)
1417 *op2p = cpu->cd.x86.r[r] & 0xff;
1418 else
1419 *op2p = (cpu->cd.x86.r[r&3] &
1420 0xff00) >>8;
1421 }
1422 }
1423 } else {
1424 if (disasm) {
1425 if (flags & MODRM_SEG)
1426 strlcpy(modrm_r, seg_names[r],
1427 sizeof(modrm_r));
1428 else if (flags & MODRM_CR)
1429 sprintf(modrm_r, "cr%i", r);
1430 else if (flags & MODRM_DR)
1431 sprintf(modrm_r, "dr%i", r);
1432 else {
1433 if (mode >= 32)
1434 sprintf(modrm_r, "%s%s", e,
1435 reg_names[r]);
1436 else
1437 strlcpy(modrm_r, reg_names[r],
1438 sizeof(modrm_r));
1439 }
1440 } else {
1441 switch (writeflag) {
1442 case MODRM_WRITE_R:
1443 if (flags & MODRM_SEG)
1444 cpu->cd.x86.s[r] = *op2p;
1445 else if (flags & MODRM_CR)
1446 x86_write_cr(cpu, r, *op2p);
1447 else if (flags & MODRM_DR)
1448 cpu->cd.x86.dr[r] = *op2p;
1449 else
1450 cpu->cd.x86.r[r] =
1451 modify(cpu->cd.x86.r[r], *op2p);
1452 break;
1453 case MODRM_READ:
1454 if (flags & MODRM_SEG)
1455 *op2p = cpu->cd.x86.s[r];
1456 else if (flags & MODRM_CR)
1457 *op2p = cpu->cd.x86.cr[r];
1458 else if (flags & MODRM_DR)
1459 *op2p = cpu->cd.x86.dr[r];
1460 else
1461 *op2p = cpu->cd.x86.r[r];
1462 }
1463 }
1464 }
1465
1466 if (!disasm) {
1467 switch (mode) {
1468 case 16:*op1p &= 0xffff; *op2p &= 0xffff; break;
1469 case 32:*op1p &= 0xffffffffULL; *op2p &= 0xffffffffULL; break;
1470 }
1471 }
1472
1473 return res;
1474 }
1475
1476
1477 /*
1478 * x86_cpu_disassemble_instr():
1479 *
1480 * Convert an instruction word into human readable format, for instruction
1481 * tracing.
1482 *
1483 * If running&1 is 1, cpu->pc should be the address of the instruction.
1484 *
1485 * If running&1 is 0, things that depend on the runtime environment (eg.
1486 * register contents) will not be shown, and addr will be used instead of
1487 * cpu->pc for relative addresses.
1488 *
1489 * The rest of running tells us the default (code) operand size.
1490 */
1491 int x86_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr,
1492 int running, uint64_t dumpaddr, int bintrans)
1493 {
1494 int op, rep = 0, lock = 0, n_prefix_bytes = 0;
1495 uint64_t ilen = 0, offset;
1496 uint32_t imm=0, imm2;
1497 int mode = running & ~1;
1498 int mode67;
1499 char *symbol, *mnem = "ERROR", *e = "e", *prefix = NULL;
1500
1501 if (running)
1502 dumpaddr = cpu->pc;
1503
1504 if (mode == 0) {
1505 mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
1506 if (mode == 0) {
1507 fatal("x86_cpu_disassemble_instr(): no mode: TODO\n");
1508 return 1;
1509 }
1510 }
1511
1512 mode67 = mode;
1513
1514 symbol = get_symbol_name(&cpu->machine->symbol_context,
1515 dumpaddr, &offset);
1516 if (symbol != NULL && offset==0)
1517 debug("<%s>\n", symbol);
1518
1519 if (cpu->machine->ncpus > 1 && running)
1520 debug("cpu%i: ", cpu->cpu_id);
1521
1522 if (mode == 32)
1523 debug("%08x: ", (int)dumpaddr);
1524 else if (mode == 64)
1525 debug("%016llx: ", (long long)dumpaddr);
1526 else { /* 16-bit mode */
1527 debug("%04x:%04x ", cpu->cd.x86.s[X86_S_CS],
1528 (int)dumpaddr & 0xffff);
1529 }
1530
1531 /*
1532 * Decode the instruction:
1533 */
1534
1535 /* All instructions are at least 1 byte long: */
1536 HEXPRINT(instr,1);
1537 ilen = 1;
1538
1539 /* Any prefix? */
1540 for (;;) {
1541 if (instr[0] == 0x66) {
1542 if (mode == 16)
1543 mode = 32;
1544 else
1545 mode = 16;
1546 } else if (instr[0] == 0x67) {
1547 if (mode67 == 16)
1548 mode67 = 32;
1549 else
1550 mode67 = 16;
1551 } else if (instr[0] == 0xf2) {
1552 rep = REP_REPNE;
1553 } else if (instr[0] == 0xf3) {
1554 rep = REP_REP;
1555 } else if (instr[0] == 0x26) {
1556 prefix = "es:";
1557 } else if (instr[0] == 0x2e) {
1558 prefix = "cs:";
1559 } else if (instr[0] == 0x36) {
1560 prefix = "ss:";
1561 } else if (instr[0] == 0x3e) {
1562 prefix = "ds:";
1563 } else if (instr[0] == 0x64) {
1564 prefix = "fs:";
1565 } else if (instr[0] == 0x65) {
1566 prefix = "gs:";
1567 } else if (instr[0] == 0xf0) {
1568 lock = 1;
1569 } else
1570 break;
1571
1572 if (++n_prefix_bytes > 4) {
1573 SPACES; debug("more than 4 prefix bytes?\n");
1574 return 4;
1575 }
1576
1577 /* TODO: lock, segment overrides etc */
1578 instr ++; ilen ++;
1579 debug("%02x", instr[0]);
1580 }
1581
1582 if (mode == 16)
1583 e = "";
1584
1585 op = instr[0];
1586 instr ++;
1587
1588 if ((op & 0xf0) <= 0x30 && (op & 7) <= 5) {
1589 switch (op & 0x38) {
1590 case 0x00: mnem = "add"; break;
1591 case 0x08: mnem = "or"; break;
1592 case 0x10: mnem = "adc"; break;
1593 case 0x18: mnem = "sbb"; break;
1594 case 0x20: mnem = "and"; break;
1595 case 0x28: mnem = "sub"; break;
1596 case 0x30: mnem = "xor"; break;
1597 case 0x38: mnem = "cmp"; break;
1598 }
1599 switch (op & 7) {
1600 case 4: imm = read_imm_and_print(&instr, &ilen, 8);
1601 SPACES; debug("%s\tal,0x%02x", mnem, imm);
1602 break;
1603 case 5: imm = read_imm_and_print(&instr, &ilen, mode);
1604 SPACES; debug("%s\t%sax,0x%x", mnem, e, imm);
1605 break;
1606 default:modrm(cpu, MODRM_READ, mode, mode67, op&1? 0 :
1607 MODRM_EIGHTBIT, &instr, &ilen, NULL, NULL);
1608 SPACES; debug("%s\t", mnem);
1609 if (op & 2)
1610 debug("%s,%s", modrm_r, modrm_rm);
1611 else
1612 debug("%s,%s", modrm_rm, modrm_r);
1613 }
1614 } else if (op == 0xf) {
1615 /* "pop cs" on 8086 */
1616 if (cpu->cd.x86.model.model_number == X86_MODEL_8086) {
1617 SPACES; debug("pop\tcs");
1618 } else {
1619 imm = read_imm_and_print(&instr, &ilen, 8);
1620 if (imm == 0x00) {
1621 int subop = (*instr >> 3) & 0x7;
1622 switch (subop) {
1623 case 0: modrm(cpu, MODRM_READ, mode, mode67,
1624 0, &instr, &ilen, NULL, NULL);
1625 SPACES; debug("sldt\t%s", modrm_rm);
1626 break;
1627 case 1: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1628 mode67, 0, &instr, &ilen,
1629 NULL, NULL);
1630 SPACES; debug("str\t%s", modrm_rm);
1631 break;
1632 case 2: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1633 mode67, 0, &instr, &ilen,
1634 NULL, NULL);
1635 SPACES; debug("lldt\t%s", modrm_rm);
1636 break;
1637 case 3: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1638 mode67, 0, &instr, &ilen,
1639 NULL, NULL);
1640 SPACES; debug("ltr\t%s", modrm_rm);
1641 break;
1642 case 4: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1643 mode67, 0, &instr, &ilen,
1644 NULL, NULL);
1645 SPACES; debug("verr\t%s", modrm_rm);
1646 break;
1647 case 5: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1648 mode67, 0, &instr, &ilen,
1649 NULL, NULL);
1650 SPACES; debug("verw\t%s", modrm_rm);
1651 break;
1652 default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1653 "%02x,0x%02x", op, imm, *instr);
1654 }
1655 } else if (imm == 0x01) {
1656 int subop = (*instr >> 3) & 0x7;
1657 switch (subop) {
1658 case 0:
1659 case 1:
1660 case 2:
1661 case 3: modrm(cpu, MODRM_READ, mode, mode67,
1662 0, &instr, &ilen, NULL, NULL);
1663 SPACES; debug("%s%s\t%s",
1664 subop < 2? "s" : "l",
1665 subop&1? "idt" : "gdt", modrm_rm);
1666 break;
1667 case 4:
1668 case 6: if (((*instr >> 3) & 0x7) == 4)
1669 mnem = "smsw";
1670 else
1671 mnem = "lmsw";
1672 modrm(cpu, MODRM_READ, 16, mode67,
1673 0, &instr, &ilen, NULL, NULL);
1674 SPACES; debug("%s\t%s", mnem, modrm_rm);
1675 break;
1676 case 7: modrm(cpu, MODRM_READ, mode,
1677 mode67, 0, &instr, &ilen,
1678 NULL, NULL);
1679 SPACES; debug("invlpg\t%s", modrm_rm);
1680 break;
1681 default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1682 "%02x,0x%02x", op, imm, *instr);
1683 }
1684 } else if (imm == 0x02) {
1685 modrm(cpu, MODRM_READ, mode, mode67,
1686 0, &instr, &ilen, NULL, NULL);
1687 SPACES; debug("lar\t%s,%s", modrm_r, modrm_rm);
1688 } else if (imm == 0x03) {
1689 modrm(cpu, MODRM_READ, mode, mode67,
1690 0, &instr, &ilen, NULL, NULL);
1691 SPACES; debug("lsl\t%s,%s", modrm_r, modrm_rm);
1692 } else if (imm == 0x05) {
1693 SPACES; /* TODO: exactly which models?*/
1694 if (cpu->cd.x86.model.model_number >
1695 X86_MODEL_80486)
1696 debug("syscall");
1697 else
1698 debug("loadall286");
1699 } else if (imm == 0x06) {
1700 SPACES; debug("clts");
1701 } else if (imm == 0x07) {
1702 SPACES; /* TODO: exactly which models?*/
1703 if (cpu->cd.x86.model.model_number >
1704 X86_MODEL_80486)
1705 debug("sysret");
1706 else
1707 debug("loadall");
1708 } else if (imm == 0x08) {
1709 SPACES; debug("invd");
1710 } else if (imm == 0x09) {
1711 SPACES; debug("wbinvd");
1712 } else if (imm == 0x0b) {
1713 SPACES; debug("reserved_0b");
1714 } else if (imm == 0x20 || imm == 0x21) {
1715 modrm(cpu, MODRM_READ, 32 /* note: 32 */,
1716 mode67, imm == 0x20? MODRM_CR : MODRM_DR,
1717 &instr, &ilen, NULL, NULL);
1718 SPACES; debug("mov\t%s,%s", modrm_rm, modrm_r);
1719 } else if (imm == 0x22 || imm == 0x23) {
1720 modrm(cpu, MODRM_READ, 32 /* note: 32 */,
1721 mode67, imm == 0x22? MODRM_CR : MODRM_DR,
1722 &instr, &ilen, NULL, NULL);
1723 SPACES; debug("mov\t%s,%s", modrm_r, modrm_rm);
1724 } else if (imm == 0x30) {
1725 SPACES; debug("wrmsr");
1726 } else if (imm == 0x31) {
1727 SPACES; debug("rdtsc");
1728 } else if (imm == 0x32) {
1729 SPACES; debug("rdmsr");
1730 } else if (imm == 0x33) {
1731 SPACES; debug("rdpmc"); /* http://www
1732 .x86.org/secrets/opcodes/rdpmc.htm */
1733 } else if (imm == 0x34) {
1734 SPACES; debug("sysenter");
1735 } else if (imm == 0x36) {
1736 SPACES; debug("sysexit");
1737 } else if (imm >= 0x40 && imm <= 0x4f) {
1738 modrm(cpu, MODRM_READ, mode, mode67, 0,
1739 &instr, &ilen, NULL, NULL);
1740 op = imm & 0xf;
1741 SPACES; debug("cmov%s%s\t%s,%s", op&1? "n"
1742 : "", cond_names[(op/2) & 0x7],
1743 modrm_r, modrm_rm);
1744 } else if (imm >= 0x80 && imm <= 0x8f) {
1745 op = imm & 0xf;
1746 imm = read_imm_and_print(&instr, &ilen, mode);
1747 imm = dumpaddr + 2 + mode/8 + imm;
1748 SPACES; debug("j%s%s\tnear 0x%x", op&1? "n"
1749 : "", cond_names[(op/2) & 0x7], imm);
1750 } else if (imm >= 0x90 && imm <= 0x9f) {
1751 op = imm;
1752 modrm(cpu, MODRM_READ, mode,
1753 mode67, MODRM_EIGHTBIT, &instr, &ilen,
1754 NULL, NULL);
1755 SPACES; debug("set%s%s\t%s", op&1? "n"
1756 : "", cond_names[(op/2) & 0x7], modrm_rm);
1757 } else if (imm == 0xa0) {
1758 SPACES; debug("push\tfs");
1759 } else if (imm == 0xa1) {
1760 SPACES; debug("pop\tfs");
1761 } else if (imm == 0xa2) {
1762 SPACES; debug("cpuid");
1763 } else if (imm == 0xa3 || imm == 0xab
1764 || imm == 0xb3 || imm == 0xbb) {
1765 modrm(cpu, MODRM_READ, mode, mode67,
1766 0, &instr, &ilen, NULL, NULL);
1767 switch (imm) {
1768 case 0xa3: mnem = "bt"; break;
1769 case 0xab: mnem = "bts"; break;
1770 case 0xb3: mnem = "btr"; break;
1771 case 0xbb: mnem = "btc"; break;
1772 }
1773 SPACES; debug("%s\t%s,%s",
1774 mnem, modrm_rm, modrm_r);
1775 } else if (imm == 0xa4 || imm == 0xa5 ||
1776 imm == 0xac || imm == 0xad) {
1777 modrm(cpu, MODRM_READ, mode, mode67,
1778 0, &instr, &ilen, NULL, NULL);
1779 if (!(imm & 1))
1780 imm2 = read_imm_and_print(&instr,
1781 &ilen, 8);
1782 else
1783 imm2 = 0;
1784 SPACES; debug("sh%sd\t%s,%s,",
1785 imm <= 0xa5? "l" : "r",
1786 modrm_rm, modrm_r);
1787 if (imm & 1)
1788 debug("cl");
1789 else
1790 debug("%i", imm2);
1791 } else if (imm == 0xa8) {
1792 SPACES; debug("push\tgs");
1793 } else if (imm == 0xa9) {
1794 SPACES; debug("pop\tgs");
1795 } else if (imm == 0xaa) {
1796 SPACES; debug("rsm");
1797 } else if (imm == 0xaf) {
1798 modrm(cpu, MODRM_READ, mode, mode67,
1799 0, &instr, &ilen, NULL, NULL);
1800 SPACES; debug("imul\t%s,%s", modrm_r, modrm_rm);
1801 } else if (imm == 0xb0 || imm == 0xb1) {
1802 modrm(cpu, MODRM_READ, mode, mode67,
1803 imm == 0xb0? MODRM_EIGHTBIT : 0,
1804 &instr, &ilen, NULL, NULL);
1805 SPACES; debug("cmpxchg\t%s,%s",
1806 modrm_rm, modrm_r);
1807 } else if (imm == 0xb2 || imm == 0xb4 || imm == 0xb5) {
1808 modrm(cpu, MODRM_READ, mode, mode67, 0,
1809 &instr, &ilen, NULL, NULL);
1810 switch (imm) {
1811 case 0xb2: mnem = "lss"; break;
1812 case 0xb4: mnem = "lfs"; break;
1813 case 0xb5: mnem = "lgs"; break;
1814 }
1815 SPACES; debug("%s\t%s,%s", mnem,
1816 modrm_r, modrm_rm);
1817 } else if (imm == 0xb6 || imm == 0xb7 ||
1818 imm == 0xbe || imm == 0xbf) {
1819 modrm(cpu, MODRM_READ, mode, mode67,
1820 (imm&1)==0? (MODRM_EIGHTBIT |
1821 MODRM_R_NONEIGHTBIT) : MODRM_RM_16BIT,
1822 &instr, &ilen, NULL, NULL);
1823 mnem = "movsx";
1824 if (imm <= 0xb7)
1825 mnem = "movzx";
1826 SPACES; debug("%s\t%s,%s", mnem,
1827 modrm_r, modrm_rm);
1828 } else if (imm == 0xba) {
1829 int subop = (*instr >> 3) & 0x7;
1830 switch (subop) {
1831 case 4: modrm(cpu, MODRM_READ, mode, mode67,
1832 0, &instr, &ilen, NULL, NULL);
1833 imm2 = read_imm_and_print(&instr,
1834 &ilen, 8);
1835 SPACES; debug("bt\t%s,%i",
1836 modrm_rm, imm2);
1837 break;
1838 case 5: modrm(cpu, MODRM_READ, mode, mode67,
1839 0, &instr, &ilen, NULL, NULL);
1840 imm2 = read_imm_and_print(&instr,
1841 &ilen, 8);
1842 SPACES; debug("bts\t%s,%i",
1843 modrm_rm, imm2);
1844 break;
1845 case 6: modrm(cpu, MODRM_READ, mode, mode67,
1846 0, &instr, &ilen, NULL, NULL);
1847 imm2 = read_imm_and_print(&instr,
1848 &ilen, 8);
1849 SPACES; debug("btr\t%s,%i",
1850 modrm_rm, imm2);
1851 break;
1852 case 7: modrm(cpu, MODRM_READ, mode, mode67,
1853 0, &instr, &ilen, NULL, NULL);
1854 imm2 = read_imm_and_print(&instr,
1855 &ilen, 8);
1856 SPACES; debug("btc\t%s,%i",
1857 modrm_rm, imm2);
1858 break;
1859 default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1860 "%02x,0x%02x", op, imm, *instr);
1861 }
1862 } else if (imm == 0xbc || imm == 0xbd) {
1863 modrm(cpu, MODRM_READ, mode, mode67,
1864 0, &instr, &ilen, NULL, NULL);
1865 if (imm == 0xbc)
1866 mnem = "bsf";
1867 else
1868 mnem = "bsr";
1869 SPACES; debug("%s\t%s,%s", mnem, modrm_r,
1870 modrm_rm);
1871 } else if (imm == 0xc0 || imm == 0xc1) {
1872 modrm(cpu, MODRM_READ, mode, mode67,
1873 imm&1? 0 : MODRM_EIGHTBIT,
1874 &instr, &ilen, NULL, NULL);
1875 SPACES; debug("xadd\t%s,%s", modrm_rm, modrm_r);
1876 } else if (imm == 0xc7) {
1877 int subop = (*instr >> 3) & 0x7;
1878 switch (subop) {
1879 case 1: modrm(cpu, MODRM_READ, 64, mode67,
1880 0, &instr, &ilen, NULL, NULL);
1881 SPACES; debug("cmpxchg8b\t%s",modrm_rm);
1882 break;
1883 default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1884 "%02x,0x%02x", op, imm, *instr);
1885 }
1886 } else if (imm >= 0xc8 && imm <= 0xcf) {
1887 SPACES; debug("bswap\te%s", reg_names[imm & 7]);
1888 } else {
1889 SPACES; debug("UNIMPLEMENTED 0x0f,0x%02x", imm);
1890 }
1891 }
1892 } else if (op < 0x20 && (op & 7) == 6) {
1893 SPACES; debug("push\t%s", seg_names[op/8]);
1894 } else if (op < 0x20 && (op & 7) == 7) {
1895 SPACES; debug("pop\t%s", seg_names[op/8]);
1896 } else if (op >= 0x20 && op < 0x40 && (op & 7) == 7) {
1897 SPACES; debug("%sa%s", op < 0x30? "d" : "a",
1898 (op & 0xf)==7? "a" : "s");
1899 } else if (op >= 0x40 && op <= 0x5f) {
1900 switch (op & 0x38) {
1901 case 0x00: mnem = "inc"; break;
1902 case 0x08: mnem = "dec"; break;
1903 case 0x10: mnem = "push"; break;
1904 case 0x18: mnem = "pop"; break;
1905 }
1906 SPACES; debug("%s\t%s%s", mnem, e, reg_names[op & 7]);
1907 } else if (op == 0x60) {
1908 SPACES; debug("pusha%s", mode==16? "" : (mode==32? "d" : "q"));
1909 } else if (op == 0x61) {
1910 SPACES; debug("popa%s", mode==16? "" : (mode==32? "d" : "q"));
1911 } else if (op == 0x62) {
1912 modrm(cpu, MODRM_READ, mode, mode67,
1913 0, &instr, &ilen, NULL, NULL);
1914 SPACES; debug("bound\t%s,%s", modrm_r, modrm_rm);
1915 } else if (op == 0x63) {
1916 modrm(cpu, MODRM_READ, 16, mode67,
1917 0, &instr, &ilen, NULL, NULL);
1918 SPACES; debug("arpl\t%s,%s", modrm_rm, modrm_r);
1919 } else if (op == 0x68) {
1920 imm = read_imm_and_print(&instr, &ilen, mode);
1921 SPACES; debug("push\t%sword 0x%x", mode==32?"d":"", imm);
1922 } else if (op == 0x69 || op == 0x6b) {
1923 modrm(cpu, MODRM_READ, mode, mode67,
1924 0, &instr, &ilen, NULL, NULL);
1925 if (op == 0x69)
1926 imm = read_imm_and_print(&instr, &ilen, mode);
1927 else
1928 imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1929 SPACES; debug("imul\t%s,%s,%i", modrm_r, modrm_rm, imm);
1930 } else if (op == 0x6a) {
1931 imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1932 SPACES; debug("push\tbyte 0x%x", imm);
1933 } else if (op == 0x6c) {
1934 SPACES; debug("insb");
1935 } else if (op == 0x6d) {
1936 SPACES; debug("ins%s", mode==16? "w" : (mode==32? "d" : "q"));
1937 } else if (op == 0x6e) {
1938 SPACES; debug("outsb");
1939 } else if (op == 0x6f) {
1940 SPACES; debug("outs%s", mode==16? "w" : (mode==32? "d" : "q"));
1941 } else if ((op & 0xf0) == 0x70) {
1942 imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1943 imm = dumpaddr + 2 + imm;
1944 SPACES; debug("j%s%s\t0x%x", op&1? "n" : "",
1945 cond_names[(op/2) & 0x7], imm);
1946 } else if (op == 0x80 || op == 0x81) {
1947 switch ((*instr >> 3) & 0x7) {
1948 case 0: mnem = "add"; break;
1949 case 1: mnem = "or"; break;
1950 case 2: mnem = "adc"; break;
1951 case 3: mnem = "sbb"; break;
1952 case 4: mnem = "and"; break;
1953 case 5: mnem = "sub"; break;
1954 case 6: mnem = "xor"; break;
1955 case 7: mnem = "cmp"; break;
1956 default:
1957 SPACES; debug("UNIMPLEMENTED 0x%02x", op);
1958 }
1959 modrm(cpu, MODRM_READ, mode, mode67,
1960 op == 0x80? MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
1961 imm = read_imm_and_print(&instr, &ilen, op==0x80? 8 : mode);
1962 SPACES; debug("%s\t%s,0x%x", mnem, modrm_rm, imm);
1963 } else if (op == 0x83) {
1964 switch ((*instr >> 3) & 0x7) {
1965 case 0: mnem = "add"; break;
1966 case 1: mnem = "or"; break;
1967 case 2: mnem = "adc"; break;
1968 case 3: mnem = "sbb"; break;
1969 case 4: mnem = "and"; break;
1970 case 5: mnem = "sub"; break;
1971 case 6: mnem = "xor"; break;
1972 case 7: mnem = "cmp"; break;
1973 default:
1974 SPACES; debug("UNIMPLEMENTED 0x%02x", op);
1975 }
1976 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, &ilen,
1977 NULL, NULL);
1978 imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1979 SPACES; debug("%s\t%s,0x%x", mnem, modrm_rm, imm);
1980 } else if (op == 0x84 || op == 0x85) {
1981 modrm(cpu, MODRM_READ, mode, mode67,
1982 op == 0x84? MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
1983 SPACES; debug("test\t%s,%s", modrm_rm, modrm_r);
1984 } else if (op == 0x86 || op == 0x87) {
1985 modrm(cpu, MODRM_READ, mode, mode67, op == 0x86?
1986 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
1987 SPACES; debug("xchg\t%s,%s", modrm_rm, modrm_r);
1988 } else if (op == 0x88 || op == 0x89) {
1989 modrm(cpu, MODRM_READ, mode, mode67, op == 0x88?
1990 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
1991 SPACES; debug("mov\t%s,%s", modrm_rm, modrm_r);
1992 } else if (op == 0x8a || op == 0x8b) {
1993 modrm(cpu, MODRM_READ, mode, mode67, op == 0x8a?
1994 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
1995 SPACES; debug("mov\t%s,%s", modrm_r, modrm_rm);
1996 } else if (op == 0x8c || op == 0x8e) {
1997 modrm(cpu, MODRM_READ, mode, mode67, MODRM_SEG, &instr, &ilen,
1998 NULL, NULL);
1999 SPACES; debug("mov\t");
2000 if (op == 0x8c)
2001 debug("%s,%s", modrm_rm, modrm_r);
2002 else
2003 debug("%s,%s", modrm_r, modrm_rm);
2004 } else if (op == 0x8d) {
2005 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, &ilen,
2006 NULL, NULL);
2007 SPACES; debug("lea\t%s,%s", modrm_r, modrm_rm);
2008 } else if (op == 0x8f) {
2009 switch ((*instr >> 3) & 0x7) {
2010 case 0: /* POP m16/m32 */
2011 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2012 &ilen, NULL, NULL);
2013 SPACES; debug("pop\t%sword %s", mode == 32? "d" : "",
2014 modrm_rm);
2015 break;
2016 default:
2017 SPACES; debug("UNIMPLEMENTED 0x%02x", op);
2018 }
2019 } else if (op == 0x90) {
2020 SPACES; debug("nop");
2021 } else if (op >= 0x91 && op <= 0x97) {
2022 SPACES; debug("xchg\t%sax,%s%s", e, e, reg_names[op & 7]);
2023 } else if (op == 0x98) {
2024 SPACES; debug("cbw");
2025 } else if (op == 0x99) {
2026 SPACES; debug("cwd");
2027 } else if (op == 0x9a) {
2028 imm = read_imm_and_print(&instr, &ilen, mode);
2029 imm2 = read_imm_and_print(&instr, &ilen, 16);
2030 SPACES; debug("call\t0x%04x:", imm2);
2031 if (mode == 16)
2032 debug("0x%04x", imm);
2033 else
2034 debug("0x%08x", imm);
2035 } else if (op == 0x9b) {
2036 SPACES; debug("wait");
2037 } else if (op == 0x9c) {
2038 SPACES; debug("pushf%s", mode==16? "" : (mode==32? "d" : "q"));
2039 } else if (op == 0x9d) {
2040 SPACES; debug("popf%s", mode==16? "" : (mode==32? "d" : "q"));
2041 } else if (op == 0x9e) {
2042 SPACES; debug("sahf");
2043 } else if (op == 0x9f) {
2044 SPACES; debug("lahf");
2045 } else if (op == 0xa0) {
2046 imm = read_imm_and_print(&instr, &ilen, mode67);
2047 SPACES; debug("mov\tal,[0x%x]", imm);
2048 } else if (op == 0xa1) {
2049 imm = read_imm_and_print(&instr, &ilen, mode67);
2050 SPACES; debug("mov\t%sax,[0x%x]", e, imm);
2051 } else if (op == 0xa2) {
2052 imm = read_imm_and_print(&instr, &ilen, mode67);
2053 SPACES; debug("mov\t[0x%x],al", imm);
2054 } else if (op == 0xa3) {
2055 imm = read_imm_and_print(&instr, &ilen, mode67);
2056 SPACES; debug("mov\t[0x%x],%sax", imm, e);
2057 } else if (op == 0xa4) {
2058 SPACES; debug("movsb");
2059 } else if (op == 0xa5) {
2060 SPACES; debug("movs%s", mode==16? "w" : (mode==32? "d" : "q"));
2061 } else if (op == 0xa6) {
2062 SPACES; debug("cmpsb");
2063 } else if (op == 0xa7) {
2064 SPACES; debug("cmps%s", mode==16? "w" : (mode==32? "d" : "q"));
2065 } else if (op == 0xa8 || op == 0xa9) {
2066 imm = read_imm_and_print(&instr, &ilen, op == 0xa8? 8 : mode);
2067 if (op == 0xa8)
2068 mnem = "al";
2069 else if (mode == 16)
2070 mnem = "ax";
2071 else
2072 mnem = "eax";
2073 SPACES; debug("test\t%s,0x%x", mnem, imm);
2074 } else if (op == 0xaa) {
2075 SPACES; debug("stosb");
2076 } else if (op == 0xab) {
2077 SPACES; debug("stos%s", mode==16? "w" : (mode==32? "d" : "q"));
2078 } else if (op == 0xac) {
2079 SPACES; debug("lodsb");
2080 } else if (op == 0xad) {
2081 SPACES; debug("lods%s", mode==16? "w" : (mode==32? "d" : "q"));
2082 } else if (op == 0xae) {
2083 SPACES; debug("scasb");
2084 } else if (op == 0xaf) {
2085 SPACES; debug("scas%s", mode==16? "w" : (mode==32? "d" : "q"));
2086 } else if (op >= 0xb0 && op <= 0xb7) {
2087 imm = read_imm_and_print(&instr, &ilen, 8);
2088 SPACES; debug("mov\t%s,0x%x", reg_names_bytes[op&7], imm);
2089 } else if (op >= 0xb8 && op <= 0xbf) {
2090 imm = read_imm_and_print(&instr, &ilen, mode);
2091 SPACES; debug("mov\t%s%s,0x%x", e, reg_names[op & 7], imm);
2092 } else if (op == 0xc0 || op == 0xc1) {
2093 switch ((*instr >> 3) & 0x7) {
2094 case 0: mnem = "rol"; break;
2095 case 1: mnem = "ror"; break;
2096 case 2: mnem = "rcl"; break;
2097 case 3: mnem = "rcr"; break;
2098 case 4: mnem = "shl"; break;
2099 case 5: mnem = "shr"; break;
2100 case 6: mnem = "sal"; break;
2101 case 7: mnem = "sar"; break;
2102 }
2103 modrm(cpu, MODRM_READ, mode, mode67, op == 0xc0?
2104 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2105 imm = read_imm_and_print(&instr, &ilen, 8);
2106 SPACES; debug("%s\t%s,%i", mnem, modrm_rm, imm);
2107 } else if (op == 0xc2) {
2108 imm = read_imm_and_print(&instr, &ilen, 16);
2109 SPACES; debug("ret\t0x%x", imm);
2110 } else if (op == 0xc3) {
2111 SPACES; debug("ret");
2112 } else if (op == 0xc4 || op == 0xc5) {
2113 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, &ilen,
2114 NULL, NULL);
2115 switch (op) {
2116 case 0xc4: mnem = "les"; break;
2117 case 0xc5: mnem = "lds"; break;
2118 }
2119 SPACES; debug("%s\t%s,%s", mnem, modrm_r, modrm_rm);
2120 } else if (op == 0xc6 || op == 0xc7) {
2121 switch ((*instr >> 3) & 0x7) {
2122 case 0: modrm(cpu, MODRM_READ, mode, mode67, op == 0xc6?
2123 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2124 imm = read_imm_and_print(&instr, &ilen,
2125 op == 0xc6? 8 : mode);
2126 SPACES; debug("mov\t%s,0x%x", modrm_rm, imm);
2127 break;
2128 default:
2129 SPACES; debug("UNIMPLEMENTED 0x%02x", op);
2130 }
2131 } else if (op == 0xc8) {
2132 imm = read_imm_and_print(&instr, &ilen, 16);
2133 imm2 = read_imm_and_print(&instr, &ilen, 8);
2134 SPACES; debug("enter\t0x%x,%i", imm, imm2);
2135 } else if (op == 0xc9) {
2136 SPACES; debug("leave");
2137 } else if (op == 0xca) {
2138 imm = read_imm_and_print(&instr, &ilen, 16);
2139 SPACES; debug("retf\t0x%x", imm);
2140 } else if (op == 0xcb) {
2141 SPACES; debug("retf");
2142 } else if (op == 0xcc) {
2143 SPACES; debug("int3");
2144 } else if (op == 0xcd) {
2145 imm = read_imm_and_print(&instr, &ilen, 8);
2146 SPACES; debug("int\t0x%x", imm);
2147 } else if (op == 0xce) {
2148 SPACES; debug("into");
2149 } else if (op == 0xcf) {
2150 SPACES; debug("iret");
2151 } else if (op >= 0xd0 && op <= 0xd3) {
2152 int subop = (*instr >> 3) & 0x7;
2153 modrm(cpu, MODRM_READ, mode, mode67, op&1? 0 :
2154 MODRM_EIGHTBIT, &instr, &ilen, NULL, NULL);
2155 switch (subop) {
2156 case 0: mnem = "rol"; break;
2157 case 1: mnem = "ror"; break;
2158 case 2: mnem = "rcl"; break;
2159 case 3: mnem = "rcr"; break;
2160 case 4: mnem = "shl"; break;
2161 case 5: mnem = "shr"; break;
2162 case 6: mnem = "sal"; break;
2163 case 7: mnem = "sar"; break;
2164 }
2165 SPACES; debug("%s\t%s,", mnem, modrm_rm);
2166 if (op <= 0xd1)
2167 debug("1");
2168 else
2169 debug("cl");
2170 } else if (op == 0xd4) {
2171 imm = read_imm_and_print(&instr, &ilen, 8);
2172 SPACES; debug("aam");
2173 if (imm != 10)
2174 debug("\t%i", imm);
2175 } else if (op == 0xd5) {
2176 imm = read_imm_and_print(&instr, &ilen, 8);
2177 SPACES; debug("aad");
2178 if (imm != 10)
2179 debug("\t%i", imm);
2180 } else if (op == 0xd6) {
2181 SPACES; debug("salc"); /* undocumented? */
2182 } else if (op == 0xd7) {
2183 SPACES; debug("xlat");
2184 } else if (op == 0xd9) {
2185 int subop = (*instr >> 3) & 7;
2186 imm = *instr;
2187 if (subop == 5) {
2188 modrm(cpu, MODRM_READ, 16, mode67, 0,
2189 &instr, &ilen, NULL, NULL);
2190 SPACES; debug("fldcw\t%s", modrm_rm);
2191 } else if (subop == 7) {
2192 modrm(cpu, MODRM_READ, 16, mode67, 0,
2193 &instr, &ilen, NULL, NULL);
2194 SPACES; debug("fstcw\t%s", modrm_rm);
2195 } else {
2196 SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2197 }
2198 } else if (op == 0xdb) {
2199 imm = *instr;
2200 if (imm == 0xe2) {
2201 read_imm_and_print(&instr, &ilen, 8);
2202 SPACES; debug("fclex");
2203 } else if (imm == 0xe3) {
2204 read_imm_and_print(&instr, &ilen, 8);
2205 SPACES; debug("finit");
2206 } else if (imm == 0xe4) {
2207 read_imm_and_print(&instr, &ilen, 8);
2208 SPACES; debug("fsetpm");
2209 } else {
2210 SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2211 }
2212 } else if (op == 0xdd) {
2213 int subop = (*instr >> 3) & 7;
2214 imm = *instr;
2215 if (subop == 7) {
2216 modrm(cpu, MODRM_READ, 16, mode67, 0,
2217 &instr, &ilen, NULL, NULL);
2218 SPACES; debug("fstsw\t%s", modrm_rm);
2219 } else {
2220 SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2221 }
2222 } else if (op == 0xdf) {
2223 imm = *instr;
2224 if (imm == 0xe0) {
2225 read_imm_and_print(&instr, &ilen, 8);
2226 SPACES; debug("fstsw\tax");
2227 } else {
2228 SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2229 }
2230 } else if (op == 0xe3) {
2231 imm = read_imm_and_print(&instr, &ilen, 8);
2232 imm = dumpaddr + ilen + (signed char)imm;
2233 if (mode == 16)
2234 mnem = "jcxz";
2235 else
2236 mnem = "jecxz";
2237 SPACES; debug("%s\t0x%x", mnem, imm);
2238 } else if (op == 0xe4) {
2239 imm = read_imm_and_print(&instr, &ilen, 8);
2240 SPACES; debug("in\tal,0x%x", imm);
2241 } else if (op == 0xe5) {
2242 imm = read_imm_and_print(&instr, &ilen, 8);
2243 SPACES; debug("in\t%sax,0x%x", e, imm);
2244 } else if (op == 0xe6) {
2245 imm = read_imm_and_print(&instr, &ilen, 8);
2246 SPACES; debug("out\t0x%x,al", imm);
2247 } else if (op == 0xe7) {
2248 imm = read_imm_and_print(&instr, &ilen, 8);
2249 SPACES; debug("out\t0x%x,%sax", imm, e);
2250 } else if (op == 0xe8 || op == 0xe9) {
2251 imm = read_imm_and_print(&instr, &ilen, mode);
2252 if (mode == 16)
2253 imm = (int16_t)imm;
2254 imm = dumpaddr + ilen + imm;
2255 switch (op) {
2256 case 0xe8: mnem = "call"; break;
2257 case 0xe9: mnem = "jmp"; break;
2258 }
2259 SPACES; debug("%s\t0x%x", mnem, imm);
2260 } else if (op == 0xea) {
2261 imm = read_imm_and_print(&instr, &ilen, mode);
2262 imm2 = read_imm_and_print(&instr, &ilen, 16);
2263 SPACES; debug("jmp\t0x%04x:", imm2);
2264 if (mode == 16)
2265 debug("0x%04x", imm);
2266 else
2267 debug("0x%08x", imm);
2268 } else if ((op >= 0xe0 && op <= 0xe2) || op == 0xeb) {
2269 imm = read_imm_and_print(&instr, &ilen, 8);
2270 imm = dumpaddr + ilen + (signed char)imm;
2271 switch (op) {
2272 case 0xe0: mnem = "loopnz"; break;
2273 case 0xe1: mnem = "loopz"; break;
2274 case 0xe2: mnem = "loop"; break;
2275 case 0xeb: mnem = "jmp"; break;
2276 }
2277 SPACES; debug("%s\t0x%x", mnem, imm);
2278 } else if (op == 0xec) {
2279 SPACES; debug("in\tal,dx");
2280 } else if (op == 0xed) {
2281 SPACES; debug("in\t%sax,dx", e);
2282 } else if (op == 0xee) {
2283 SPACES; debug("out\tdx,al");
2284 } else if (op == 0xef) {
2285 SPACES; debug("out\tdx,%sax", e);
2286 } else if (op == 0xf1) {
2287 SPACES; debug("icebp"); /* undocumented? */
2288 /* http://www.x86.org/secrets/opcodes/icebp.htm */
2289 } else if (op == 0xf4) {
2290 SPACES; debug("hlt");
2291 } else if (op == 0xf5) {
2292 SPACES; debug("cmc");
2293 } else if (op == 0xf8) {
2294 SPACES; debug("clc");
2295 } else if (op == 0xf9) {
2296 SPACES; debug("stc");
2297 } else if (op == 0xfa) {
2298 SPACES; debug("cli");
2299 } else if (op == 0xfb) {
2300 SPACES; debug("sti");
2301 } else if (op == 0xfc) {
2302 SPACES; debug("cld");
2303 } else if (op == 0xfd) {
2304 SPACES; debug("std");
2305 } else if (op == 0xf6 || op == 0xf7) {
2306 switch ((*instr >> 3) & 0x7) {
2307 case 0: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2308 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2309 imm = read_imm_and_print(&instr, &ilen,
2310 op == 0xf6? 8 : mode);
2311 SPACES; debug("test\t%s,0x%x", modrm_rm, imm);
2312 break;
2313 case 2: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2314 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2315 SPACES; debug("not\t%s", modrm_rm);
2316 break;
2317 case 3: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2318 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2319 SPACES; debug("neg\t%s", modrm_rm);
2320 break;
2321 case 4: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2322 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2323 SPACES; debug("mul\t%s", modrm_rm);
2324 break;
2325 case 5: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2326 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2327 SPACES; debug("imul\t%s", modrm_rm);
2328 break;
2329 case 6: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2330 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2331 SPACES; debug("div\t%s", modrm_rm);
2332 break;
2333 case 7: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2334 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2335 SPACES; debug("idiv\t%s", modrm_rm);
2336 break;
2337 default:
2338 SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op,*instr);
2339 }
2340 } else if (op == 0xfe || op == 0xff) {
2341 /* FE /0 = inc r/m8 */
2342 /* FE /1 = dec r/m8 */
2343 /* FF /2 = call near rm16/32 */
2344 /* FF /3 = call far m16:32 */
2345 /* FF /6 = push r/m16/32 */
2346 switch ((*instr >> 3) & 0x7) {
2347 case 0: modrm(cpu, MODRM_READ, mode, mode67, op == 0xfe?
2348 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2349 SPACES; debug("inc\t%s", modrm_rm);
2350 break;
2351 case 1: modrm(cpu, MODRM_READ, mode, mode67, op == 0xfe?
2352 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2353 SPACES; debug("dec\t%s", modrm_rm);
2354 break;
2355 case 2: if (op == 0xfe) {
2356 SPACES; debug("UNIMPLEMENTED "
2357 "0x%02x,0x%02x", op,*instr);
2358 } else {
2359 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2360 &ilen, NULL, NULL);
2361 SPACES; debug("call\t%s", modrm_rm);
2362 }
2363 break;
2364 case 3: if (op == 0xfe) {
2365 SPACES; debug("UNIMPLEMENTED "
2366 "0x%02x,0x%02x", op,*instr);
2367 } else {
2368 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2369 &ilen, NULL, NULL);
2370 SPACES; debug("call\tfar %s", modrm_rm);
2371 }
2372 break;
2373 case 4: if (op == 0xfe) {
2374 SPACES; debug("UNIMPLEMENTED "
2375 "0x%02x,0x%02x", op,*instr);
2376 } else {
2377 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2378 &ilen, NULL, NULL);
2379 SPACES; debug("jmp\t%s", modrm_rm);
2380 }
2381 break;
2382 case 5: if (op == 0xfe) {
2383 SPACES; debug("UNIMPLEMENTED "
2384 "0x%02x,0x%02x", op,*instr);
2385 } else {
2386 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2387 &ilen, NULL, NULL);
2388 SPACES; debug("jmp\tfar %s", modrm_rm);
2389 }
2390 break;
2391 case 6: if (op == 0xfe) {
2392 SPACES; debug("UNIMPLEMENTED "
2393 "0x%02x,0x%02x", op,*instr);
2394 } else {
2395 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2396 &ilen, NULL, NULL);
2397 SPACES; debug("push\t%sword %s",
2398 mode == 32? "d" : "", modrm_rm);
2399 }
2400 break;
2401 default:
2402 SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op,*instr);
2403 }
2404 } else {
2405 SPACES; debug("UNIMPLEMENTED 0x%02x", op);
2406 }
2407
2408 switch (rep) {
2409 case REP_REP: debug(" (rep)"); break;
2410 case REP_REPNE: debug(" (repne)"); break;
2411 }
2412 if (prefix != NULL)
2413 debug(" (%s)", prefix);
2414 if (lock)
2415 debug(" (lock)");
2416
2417 debug("\n");
2418 return ilen;
2419 }
2420
2421
2422 /*
2423 * x86_cpuid():
2424 *
2425 * TODO: Level 1 and 2 info.
2426 */
2427 static void x86_cpuid(struct cpu *cpu)
2428 {
2429 switch (cpu->cd.x86.r[X86_R_AX]) {
2430 /* Normal CPU id: */
2431 case 0: cpu->cd.x86.r[X86_R_AX] = 2;
2432 /* Intel... */
2433 cpu->cd.x86.r[X86_R_BX] = 0x756e6547; /* "Genu" */
2434 cpu->cd.x86.r[X86_R_DX] = 0x49656e69; /* "ineI" */
2435 cpu->cd.x86.r[X86_R_CX] = 0x6c65746e; /* "ntel" */
2436 /* ... or AMD: */
2437 cpu->cd.x86.r[X86_R_BX] = 0x68747541; /* "Auth" */
2438 cpu->cd.x86.r[X86_R_DX] = 0x69746E65; /* "enti" */
2439 cpu->cd.x86.r[X86_R_CX] = 0x444D4163; /* "cAMD" */
2440 break;
2441 case 1: /* TODO */
2442 cpu->cd.x86.r[X86_R_AX] = 0x0623;
2443 cpu->cd.x86.r[X86_R_BX] = (cpu->cpu_id << 24);
2444 /* TODO: are bits 8..15 the _total_ nr of cpus, or the
2445 cpu id of this one? */
2446 cpu->cd.x86.r[X86_R_CX] = X86_CPUID_ECX_CX16;
2447 cpu->cd.x86.r[X86_R_DX] = X86_CPUID_EDX_CX8 | X86_CPUID_EDX_FPU
2448 | X86_CPUID_EDX_MSR | X86_CPUID_EDX_TSC | X86_CPUID_EDX_MTRR
2449 | X86_CPUID_EDX_CMOV | X86_CPUID_EDX_PSE |
2450 X86_CPUID_EDX_SEP | X86_CPUID_EDX_PGE |
2451 X86_CPUID_EDX_MMX | X86_CPUID_EDX_FXSR;
2452 break;
2453 case 2: /* TODO: actual Cache info */
2454 /* This is just bogus */
2455 cpu->cd.x86.r[X86_R_AX] = 0x03020101;
2456 cpu->cd.x86.r[X86_R_BX] = 0x00000000;
2457 cpu->cd.x86.r[X86_R_CX] = 0x00000000;
2458 cpu->cd.x86.r[X86_R_DX] = 0x06040a42;
2459 break;
2460
2461 /* Extended CPU id: */
2462 case 0x80000000:
2463 cpu->cd.x86.r[X86_R_AX] = 0x80000008;
2464 /* AMD... */
2465 cpu->cd.x86.r[X86_R_BX] = 0x68747541;
2466 cpu->cd.x86.r[X86_R_DX] = 0x444D4163;
2467 cpu->cd.x86.r[X86_R_CX] = 0x69746E65;
2468 break;
2469 case 0x80000001:
2470 cpu->cd.x86.r[X86_R_AX] = 0;
2471 cpu->cd.x86.r[X86_R_BX] = 0;
2472 cpu->cd.x86.r[X86_R_CX] = 0;
2473 cpu->cd.x86.r[X86_R_DX] = (cpu->cd.x86.model.model_number
2474 >= X86_MODEL_AMD64)? X86_CPUID_EXT_EDX_LM : 0;
2475 break;
2476 case 0x80000002:
2477 case 0x80000003:
2478 case 0x80000004:
2479 case 0x80000005:
2480 case 0x80000006:
2481 case 0x80000007:
2482 fatal("[ CPUID 0x%08x ]\n", (int)cpu->cd.x86.r[X86_R_AX]);
2483 cpu->cd.x86.r[X86_R_AX] = 0;
2484 cpu->cd.x86.r[X86_R_BX] = 0;
2485 cpu->cd.x86.r[X86_R_CX] = 0;
2486 cpu->cd.x86.r[X86_R_DX] = 0;
2487 break;
2488 case 0x80000008:
2489 cpu->cd.x86.r[X86_R_AX] = 0x00003028;
2490 cpu->cd.x86.r[X86_R_BX] = 0;
2491 cpu->cd.x86.r[X86_R_CX] = 0;
2492 cpu->cd.x86.r[X86_R_DX] = 0;
2493 break;
2494 default:fatal("x86_cpuid(): unimplemented eax = 0x%x\n",
2495 (int)cpu->cd.x86.r[X86_R_AX]);
2496 cpu->running = 0;
2497 }
2498 }
2499
2500
2501 #define TRANSLATE_ADDRESS translate_address_x86
2502 #include "memory_x86.c"
2503 #undef TRANSLATE_ADDRESS
2504
2505
2506 #define MEMORY_RW x86_memory_rw
2507 #define MEM_X86
2508 #include "memory_rw.c"
2509 #undef MEM_X86
2510 #undef MEMORY_RW
2511
2512
2513 /*
2514 * x86_push():
2515 */
2516 static int x86_push(struct cpu *cpu, uint64_t value, int mode)
2517 {
2518 int res = 1, oldseg;
2519 int ssize = cpu->cd.x86.descr_cache[X86_S_SS].default_op_size;
2520 uint64_t new_esp;
2521 uint64_t old_esp = cpu->cd.x86.r[X86_R_SP];
2522 uint16_t old_ss = cpu->cd.x86.s[X86_S_SS];
2523 uint64_t old_eip = cpu->pc;
2524 uint16_t old_cs = cpu->cd.x86.s[X86_S_CS];
2525
2526 /* TODO: up/down? */
2527 /* TODO: stacksize? */
2528 ssize = mode;
2529
2530 oldseg = cpu->cd.x86.cursegment;
2531 cpu->cd.x86.cursegment = X86_S_SS;
2532 if (ssize == 16)
2533 new_esp = (cpu->cd.x86.r[X86_R_SP] & ~0xffff)
2534 | ((cpu->cd.x86.r[X86_R_SP] - (ssize / 8)) & 0xffff);
2535 else
2536 new_esp = (cpu->cd.x86.r[X86_R_SP] -
2537 (ssize / 8)) & 0xffffffff;
2538 res = x86_store(cpu, new_esp, value, ssize / 8);
2539 if (!res) {
2540 fatal("WARNING: x86_push store failed: cs:eip=0x%04x:0x%08x"
2541 " ss:esp=0x%04x:0x%08x\n", (int)old_cs,
2542 (int)old_eip, (int)old_ss, (int)old_esp);
2543 if ((old_cs & X86_PL_MASK) != X86_RING3)
2544 cpu->running = 0;
2545 } else {
2546 cpu->cd.x86.r[X86_R_SP] = new_esp;
2547 }
2548 cpu->cd.x86.cursegment = oldseg;
2549 return res;
2550 }
2551
2552
2553 /*
2554 * x86_pop():
2555 */
2556 static int x86_pop(struct cpu *cpu, uint64_t *valuep, int mode)
2557 {
2558 int res = 1, oldseg;
2559 int ssize = cpu->cd.x86.descr_cache[X86_S_SS].default_op_size;
2560
2561 /* TODO: up/down? */
2562 /* TODO: stacksize? */
2563 ssize = mode;
2564
2565 oldseg = cpu->cd.x86.cursegment;
2566 cpu->cd.x86.cursegment = X86_S_SS;
2567 res = x86_load(cpu, cpu->cd.x86.r[X86_R_SP], valuep, ssize / 8);
2568 if (!res) {
2569 fatal("WARNING: x86_pop load failed\n");
2570 } else {
2571 if (ssize == 16)
2572 cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] &
2573 ~0xffff) | ((cpu->cd.x86.r[X86_R_SP] + (ssize / 8))
2574 & 0xffff);
2575 else
2576 cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] +
2577 (ssize / 8)) & 0xffffffff;
2578 }
2579 cpu->cd.x86.cursegment = oldseg;
2580 return res;
2581 }
2582
2583
2584 #define INT_TYPE_CALLGATE 1
2585 #define INT_TYPE_INTGATE 2
2586 #define INT_TYPE_TRAPGATE 3
2587 /*
2588 * x86_interrupt():
2589 *
2590 * Read the interrupt descriptor table (or, in real mode, the interrupt
2591 * vector table), push flags/cs/eip, and jump to the interrupt handler.
2592 */
2593 int x86_interrupt(struct cpu *cpu, int nr, int errcode)
2594 {
2595 uint16_t seg, old_cs;
2596 uint32_t ofs;
2597 int res, mode;
2598 unsigned char buf[8];
2599
2600 old_cs = cpu->cd.x86.s[X86_S_CS];
2601
2602 debug("{ x86_interrupt %i }\n", nr);
2603
2604 if (PROTECTED_MODE) {
2605 int i, int_type = 0;
2606
2607 if (nr * 8 > cpu->cd.x86.idtr_limit) {
2608 fatal("TODO: protected mode int 0x%02x outside idtr"
2609 " limit (%i)?\n", nr, (int)cpu->cd.x86.idtr_limit);
2610 cpu->running = 0;
2611 return 0;
2612 }
2613
2614 /* Read the interrupt descriptor: */
2615 res = cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.idtr + nr*8,
2616 buf, 8, MEM_READ, NO_SEGMENTATION);
2617 if (!res) {
2618 fatal("x86_interrupt(): could not read the"
2619 " interrupt descriptor table (prot. mode)\n");
2620 cpu->running = 0;
2621 return 0;
2622 }
2623
2624 if ((buf[5] & 0x17) == 0x04)
2625 int_type = INT_TYPE_CALLGATE;
2626 if ((buf[5] & 0x17) == 0x06)
2627 int_type = INT_TYPE_INTGATE;
2628 if ((buf[5] & 0x17) == 0x07)
2629 int_type = INT_TYPE_TRAPGATE;
2630
2631 if (!int_type) {
2632 fatal("x86_interrupt(): TODO:\n");
2633 for (i=0; i<8; i++)
2634 fatal(" %02x", buf[i]);
2635 fatal("\n");
2636 cpu->running = 0;
2637 return 0;
2638 }
2639
2640 seg = buf[2] + (buf[3] << 8);
2641 ofs = buf[0] + (buf[1] << 8) + (buf[6] << 16) + (buf[7] << 24);
2642
2643 switch (int_type) {
2644 case INT_TYPE_INTGATE:
2645 case INT_TYPE_TRAPGATE:
2646 break;
2647 default:
2648 fatal("INT type: %i, cs:eip = 0x%04x:0x%08x\n",
2649 int_type, (int)seg, (int)ofs);
2650 cpu->running = 0;
2651 return 0;
2652 }
2653
2654 reload_segment_descriptor(cpu, X86_S_CS, seg, &cpu->pc);
2655
2656 /*
2657 * If we're changing privilege level, the we should change
2658 * stack here, and push the old SS:ESP.
2659 */
2660 if ((seg & X86_PL_MASK) < (old_cs & X86_PL_MASK)) {
2661 unsigned char buf[16];
2662 uint16_t new_ss, old_ss;
2663 uint32_t new_esp, old_esp;
2664 int pl;
2665
2666 pl = seg & X86_PL_MASK;
2667
2668 /* Load SSx:ESPx from the Task State Segment: */
2669 if (cpu->cd.x86.tr < 4)
2670 fatal("WARNING: interrupt with stack switch"
2671 ", but task register = 0?\n");
2672
2673 /* fatal("::: old SS:ESP=0x%04x:0x%08x\n",
2674 (int)cpu->cd.x86.s[X86_S_SS],
2675 (int)cpu->cd.x86.r[X86_R_SP]); */
2676
2677 if (!cpu->memory_rw(cpu, cpu->mem, 4 + pl*8 +
2678 cpu->cd.x86.tr_base, buf, sizeof(buf), MEM_READ,
2679 NO_SEGMENTATION)) {
2680 fatal("ERROR: couldn't read tss blah blah\n");
2681 cpu->running = 0;
2682 return 0;
2683 }
2684
2685 new_esp = buf[0] + (buf[1] << 8) +
2686 (buf[2] << 16) + (buf[3] << 24);
2687 new_ss = buf[4] + (buf[5] << 8);
2688
2689 old_ss = cpu->cd.x86.s[X86_S_SS];
2690 old_esp = cpu->cd.x86.r[X86_R_SP];
2691
2692 reload_segment_descriptor(cpu, X86_S_SS, new_ss, NULL);
2693 cpu->cd.x86.r[X86_R_SP] = new_esp;
2694
2695 fatal("::: Switching Stack: new SS:ESP=0x%04x:0x%08x\n",
2696 (int)new_ss, (int)new_esp);
2697
2698 mode = cpu->cd.x86.descr_cache[X86_S_CS].
2699 default_op_size;
2700
2701 if (!x86_push(cpu, old_ss, mode)) {
2702 fatal("TODO: problem adgsadg 1\n");
2703 cpu->running = 0;
2704 }
2705 if (!x86_push(cpu, old_esp, mode)) {
2706 fatal("TODO: problem adgsadg 2\n");
2707 cpu->running = 0;
2708 }
2709 }
2710
2711 /* Push flags, cs, and ip (pc): */
2712 mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
2713 if (!x86_push(cpu, cpu->cd.x86.rflags, mode)) {
2714 fatal("TODO: how to handle this 1 asdf\n");
2715 cpu->running = 0;
2716 }
2717 if (!x86_push(cpu, old_cs, mode)) {
2718 fatal("TODO: how to handle this 2 sdghser\n");
2719 cpu->running = 0;
2720 }
2721 if (!x86_push(cpu, cpu->pc, mode)) {
2722 fatal("TODO: how to handle this 3 we\n");
2723 cpu->running = 0;
2724 }
2725
2726 /* Push error code for some exceptions: */
2727 if ((nr >= 8 && nr <=14) || nr == 17) {
2728 if (!x86_push(cpu, errcode, mode)) {
2729 fatal("x86_interrupt(): TODO: asdgblah\n");
2730 cpu->running = 0;
2731 }
2732 }
2733
2734 /* Only turn off interrupts for Interrupt Gates: */
2735 if (int_type == INT_TYPE_INTGATE)
2736 cpu->cd.x86.rflags &= ~X86_FLAGS_IF;
2737
2738 /* Turn off TF for Interrupt and Trap Gates: */
2739 if (int_type == INT_TYPE_INTGATE ||
2740 int_type == INT_TYPE_TRAPGATE)
2741 cpu->cd.x86.rflags &= ~X86_FLAGS_TF;
2742
2743 goto int_jump;
2744 }
2745
2746 /*
2747 * Real mode:
2748 */
2749 if (nr * 4 > cpu->cd.x86.idtr_limit) {
2750 fatal("TODO: real mode int 0x%02x outside idtr limit ("
2751 "%i)?\n", nr, (int)cpu->cd.x86.idtr_limit);
2752 cpu->running = 0;
2753 return 0;
2754 }
2755 /* Read the interrupt vector: */
2756 res = cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.idtr + nr*4, buf, 4,
2757 MEM_READ, NO_SEGMENTATION);
2758 if (!res) {
2759 fatal("x86_interrupt(): could not read the"
2760 " interrupt descriptor table\n");
2761 cpu->running = 0;
2762 return 0;
2763 }
2764 ofs = buf[0] + (buf[1] << 8); seg = buf[2] + (buf[3] << 8);
2765
2766 reload_segment_descriptor(cpu, X86_S_CS, seg, &cpu->pc);
2767
2768 /* Push old flags, old cs, and old ip (pc): */
2769 mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
2770
2771 if (!x86_push(cpu, cpu->cd.x86.rflags, mode)) {
2772 fatal("x86_interrupt(): TODO: how to handle this 4\n");
2773 cpu->running = 0;
2774 }
2775 if (!x86_push(cpu, old_cs, mode)) {
2776 fatal("x86_interrupt(): TODO: how to handle this 5\n");
2777 cpu->running = 0;
2778 }
2779 if (!x86_push(cpu, cpu->pc, mode)) {
2780 fatal("x86_interrupt(): TODO: how to handle this 6\n");
2781 cpu->running = 0;
2782 }
2783
2784 /* Turn off interrupts and the Trap Flag, and jump to the interrupt
2785 handler: */
2786 cpu->cd.x86.rflags &= ~(X86_FLAGS_IF | X86_FLAGS_TF);
2787
2788 int_jump:
2789 cpu->pc = ofs;
2790
2791 return 1;
2792 }
2793
2794
2795 #define CALCFLAGS_OP_ADD 1
2796 #define CALCFLAGS_OP_SUB 2
2797 #define CALCFLAGS_OP_XOR 3
2798 /*
2799 * x86_calc_flags():
2800 */
2801 static void x86_calc_flags(struct cpu *cpu, uint64_t a, uint64_t b, int mode,
2802 int op)
2803 {
2804 uint64_t c=0, mask;
2805 int i, count;
2806
2807 if (mode == 8)
2808 mask = 0xff;
2809 else if (mode == 16)
2810 mask = 0xffff;
2811 else if (mode == 32)
2812 mask = 0xffffffffULL;
2813 else if (mode == 64)
2814 mask = 0xffffffffffffffffULL;
2815 else {
2816 fatal("x86_calc_flags(): Bad mode (%i)\n", mode);
2817 return;
2818 }
2819
2820 a &= mask;
2821 b &= mask;
2822
2823 /* CF: */
2824 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
2825 switch (op) {
2826 case CALCFLAGS_OP_ADD:
2827 if (((a + b)&mask) < a && ((a + b)&mask) < b)
2828 cpu->cd.x86.rflags |= X86_FLAGS_CF;
2829 break;
2830 case CALCFLAGS_OP_SUB:
2831 if (a < b)
2832 cpu->cd.x86.rflags |= X86_FLAGS_CF;
2833 break;
2834 case CALCFLAGS_OP_XOR:
2835 break;
2836 }
2837
2838 switch (op) {
2839 case CALCFLAGS_OP_ADD:
2840 c = (a + b) & mask;
2841 break;
2842 case CALCFLAGS_OP_SUB:
2843 c = (a - b) & mask;
2844 break;
2845 case CALCFLAGS_OP_XOR:
2846 c = a;
2847 }
2848
2849 /* ZF: */
2850 cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;
2851 if (c == 0)
2852 cpu->cd.x86.rflags |= X86_FLAGS_ZF;
2853
2854 /* SF: */
2855 cpu->cd.x86.rflags &= ~X86_FLAGS_SF;
2856 if ((mode == 8 && (c & 0x80)) ||
2857 (mode == 16 && (c & 0x8000)) ||
2858 (mode == 32 && (c & 0x80000000ULL)) ||
2859 (mode == 64 && (c & 0x8000000000000000ULL))) {
2860 cpu->cd.x86.rflags |= X86_FLAGS_SF;
2861 }
2862
2863 /* OF: */
2864 cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
2865 switch (op) {
2866 case CALCFLAGS_OP_ADD:
2867 /* TODO */
2868 break;
2869 case CALCFLAGS_OP_SUB:
2870 if (cpu->cd.x86.rflags & X86_FLAGS_SF)
2871 cpu->cd.x86.rflags |= X86_FLAGS_OF;
2872 if (mode == 8 && (int8_t)a < (int8_t)b)
2873 cpu->cd.x86.rflags ^= X86_FLAGS_OF;
2874 if (mode == 16 && (int16_t)a < (int16_t)b)
2875 cpu->cd.x86.rflags ^= X86_FLAGS_OF;
2876 if (mode == 32 && (int32_t)a < (int32_t)b)
2877 cpu->cd.x86.rflags ^= X86_FLAGS_OF;
2878 break;
2879 case CALCFLAGS_OP_XOR:
2880 ;
2881 }
2882
2883 /* AF: */
2884 switch (op) {
2885 case CALCFLAGS_OP_ADD:
2886 if ((a & 0xf) + (b & 0xf) > 15)
2887 cpu->cd.x86.rflags |= X86_FLAGS_AF;
2888 else
2889 cpu->cd.x86.rflags &= ~X86_FLAGS_AF;
2890 break;
2891 case CALCFLAGS_OP_SUB:
2892 if ((b & 0xf) > (a & 0xf))
2893 cpu->cd.x86.rflags |= X86_FLAGS_AF;
2894 else
2895 cpu->cd.x86.rflags &= ~X86_FLAGS_AF;
2896 break;
2897 case CALCFLAGS_OP_XOR:
2898 ;
2899 }
2900
2901 /* PF: (NOTE: Only the lowest 8 bits) */
2902 cpu->cd.x86.rflags &= ~X86_FLAGS_PF;
2903 count = 0;
2904 for (i=0; i<8; i++) {
2905 if (c & 1)
2906 count ++;
2907 c >>= 1;
2908 }
2909 if (!(count&1))
2910 cpu->cd.x86.rflags |= X86_FLAGS_PF;
2911 }
2912
2913
2914 /*
2915 * x86_condition():
2916 *
2917 * Returns 0 or 1 (false or true) depending on flag bits.
2918 */
2919 static int x86_condition(struct cpu *cpu, int op)
2920 {
2921 int success = 0;
2922
2923 switch (op & 0xe) {
2924 case 0x00: /* o */
2925 success = cpu->cd.x86.rflags & X86_FLAGS_OF;
2926 break;
2927 case 0x02: /* c */
2928 success = cpu->cd.x86.rflags & X86_FLAGS_CF;
2929 break;
2930 case 0x04: /* z */
2931 success = cpu->cd.x86.rflags & X86_FLAGS_ZF;
2932 break;
2933 case 0x06: /* be */
2934 success = (cpu->cd.x86.rflags & X86_FLAGS_ZF) ||
2935 (cpu->cd.x86.rflags & X86_FLAGS_CF);
2936 break;
2937 case 0x08: /* s */
2938 success = cpu->cd.x86.rflags & X86_FLAGS_SF;
2939 break;
2940 case 0x0a: /* p */
2941 success = cpu->cd.x86.rflags & X86_FLAGS_PF;
2942 break;
2943 case 0x0c: /* nge */
2944 success = (cpu->cd.x86.rflags & X86_FLAGS_SF? 1 : 0)
2945 != (cpu->cd.x86.rflags & X86_FLAGS_OF? 1 : 0);
2946 break;
2947 case 0x0e: /* ng */
2948 success = (cpu->cd.x86.rflags & X86_FLAGS_SF? 1 : 0)
2949 != (cpu->cd.x86.rflags & X86_FLAGS_OF? 1 : 0);
2950 success |= (cpu->cd.x86.rflags & X86_FLAGS_ZF ? 1 : 0);
2951 break;
2952 }
2953
2954 if (op & 1)
2955 success = !success;
2956
2957 return success? 1 : 0;
2958 }
2959
2960
2961 /*
2962 * x86_shiftrotate():
2963 */
2964 static void x86_shiftrotate(struct cpu *cpu, uint64_t *op1p, int op,
2965 int n, int mode)
2966 {
2967 uint64_t op1 = *op1p;
2968 int cf = -1, oldcf = 0;
2969
2970 n &= 31;
2971 if (mode != 64)
2972 op1 &= (((uint64_t)1 << mode) - 1);
2973
2974 oldcf = cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0;
2975
2976 while (n-- > 0) {
2977 cf = 0;
2978
2979 if (op & 1) { /* right */
2980 if (op1 & 1)
2981 cf = 1;
2982 } else { /* left */
2983 cf = (op1 & ((uint64_t)1 << (mode-1)))? 1 : 0;
2984 }
2985
2986 switch (op) {
2987 case 0: /* rol */
2988 op1 = (op1 << 1) | cf;
2989 break;
2990 case 1: /* ror */
2991 op1 >>= 1;
2992 op1 |= ((uint64_t)cf << (mode - 1));
2993 break;
2994 case 2: /* rcl */
2995 op1 = (op1 << 1) | oldcf;
2996 oldcf = cf;
2997 break;
2998 case 3: /* rcr */
2999 op1 >>= 1;
3000 op1 |= ((uint64_t)oldcf << (mode - 1));
3001 oldcf = cf;
3002 break;
3003 case 4: /* shl */
3004 case 6: /* sal */
3005 op1 <<= 1;
3006 break;
3007 case 5: /* shr */
3008 op1 >>= 1;
3009 break;
3010 case 7: /* sar */
3011 op1 >>= 1;
3012 if (mode == 8 && op1 & 0x40)
3013 op1 |= 0x80;
3014 if (mode == 16 && op1 & 0x4000)
3015 op1 |= 0x8000;
3016 if (mode == 32 && op1 & 0x40000000ULL)
3017 op1 |= 0x80000000ULL;
3018 break;
3019 default:
3020 fatal("x86_shiftrotate(): unimplemented op %i\n", op);
3021 cpu->running = 0;
3022 }
3023 if (mode != 64)
3024 op1 &= (((uint64_t)1 << mode) - 1);
3025 x86_calc_flags(cpu, op1, 0, mode, CALCFLAGS_OP_XOR);
3026 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3027 if (cf)
3028 cpu->cd.x86.rflags |= X86_FLAGS_CF;
3029 }
3030
3031 /* TODO: OF flag */
3032
3033 *op1p = op1;
3034 }
3035
3036
3037 /*
3038 * x86_msr():
3039 *
3040 * This function reads or writes the MSRs (Model Specific Registers).
3041 */
3042 static void x86_msr(struct cpu *cpu, int writeflag)
3043 {
3044 uint32_t regnr = cpu->cd.x86.r[X86_R_CX] & 0xffffffff;
3045 uint64_t odata=0, idata = (cpu->cd.x86.r[X86_R_AX] & 0xffffffff) +
3046 ((cpu->cd.x86.r[X86_R_DX] & 0xffffffff) << 32);
3047
3048 switch (regnr) {
3049 case 0xc0000080: /* AMD64 EFER */
3050 if (writeflag) {
3051 if (cpu->cd.x86.efer & X86_EFER_LME &&
3052 !(idata & X86_EFER_LME))
3053 debug("[ switching FROM 64-bit mode ]\n");
3054 if (!(cpu->cd.x86.efer & X86_EFER_LME) &&
3055 idata & X86_EFER_LME)
3056 debug("[ switching to 64-bit mode ]\n");
3057 cpu->cd.x86.efer = idata;
3058 } else
3059 odata = cpu->cd.x86.efer;
3060 break;
3061 default:fatal("x86_msr: unimplemented MSR 0x%08x\n", (int)regnr);
3062 cpu->running = 0;
3063 }
3064
3065 if (!writeflag) {
3066 cpu->cd.x86.r[X86_R_AX] = odata & 0xffffffff;
3067 cpu->cd.x86.r[X86_R_DX] = (odata >> 32) & 0xffffffff;
3068 }
3069 }
3070
3071
3072 /*
3073 * cause_interrupt():
3074 *
3075 * Read the registers of PIC1 (and possibly PIC2) to find out which interrupt
3076 * has occured.
3077 *
3078 * Returns 1 if an interrupt happened, 0 otherwise (for example if the
3079 * in-service bit of an interrupt was already set).
3080 */
3081 static int cause_interrupt(struct cpu *cpu)
3082 {
3083 int i, irq_nr = -1;
3084
3085 for (i=0; i<8; i++) {
3086 if (cpu->machine->md.pc.pic1->irr &
3087 (~cpu->machine->md.pc.pic1->ier) & (1 << i))
3088 irq_nr = i;
3089 }
3090
3091 if (irq_nr == 2) {
3092 for (i=0; i<8; i++) {
3093 if (cpu->machine->md.pc.pic2->irr &
3094 (~cpu->machine->md.pc.pic2->ier) & (1 << i))
3095 irq_nr = 8+i;
3096 }
3097 }
3098
3099 if (irq_nr == 2) {
3100 fatal("cause_interrupt(): Huh? irq 2 but no secondary irq\n");
3101 cpu->running = 0;
3102 }
3103
3104 /*
3105 * TODO: How about multiple interrupt levels?
3106 */
3107
3108 #if 0
3109 printf("cause1: %i (irr1=%02x ier1=%02x, irr2=%02x ier2=%02x\n", irq_nr,
3110 cpu->machine->md.pc.pic1->irr, cpu->machine->md.pc.pic1->ier,
3111 cpu->machine->md.pc.pic2->irr, cpu->machine->md.pc.pic2->ier);
3112 #endif
3113
3114 /* Set the in-service bit, and calculate actual INT nr: */
3115 if (irq_nr < 8) {
3116 if (cpu->machine->md.pc.pic1->isr & (1 << irq_nr))
3117 return 0;
3118 cpu->machine->md.pc.pic1->isr |= (1 << irq_nr);
3119 irq_nr = cpu->machine->md.pc.pic1->irq_base + irq_nr;
3120 } else {
3121 if (cpu->machine->md.pc.pic2->isr & (1 << (irq_nr & 7)))
3122 return 0;
3123 cpu->machine->md.pc.pic2->isr |= (1 << (irq_nr&7));
3124 irq_nr = cpu->machine->md.pc.pic2->irq_base + (irq_nr & 7);
3125 }
3126
3127 /* printf("cause2: %i\n", irq_nr); */
3128
3129 x86_interrupt(cpu, irq_nr, 0);
3130 cpu->cd.x86.halted = 0;
3131 return 1;
3132 }
3133
3134
3135 /*
3136 * x86_cpu_run_instr():
3137 *
3138 * Execute one instruction on a specific CPU.
3139 *
3140 * Return value is the number of instructions executed during this call,
3141 * 0 if no instruction was executed.
3142 */
3143 int x86_cpu_run_instr(struct emul *emul, struct cpu *cpu)
3144 {
3145 int i, r, rep = 0, op, len, mode, omode, mode67;
3146 int nprefixbytes = 0, success, longmode;
3147 uint32_t imm, imm2;
3148 unsigned char buf[16];
3149 unsigned char *instr = buf, *instr_orig, *really_orig_instr;
3150 uint64_t newpc = cpu->pc;
3151 uint64_t tmp, op1, op2;
3152 int trap_flag_was_set = cpu->cd.x86.rflags & X86_FLAGS_TF;
3153
3154 /* Check PC against breakpoints: */
3155 if (!single_step)
3156 for (i=0; i<cpu->machine->n_breakpoints; i++)
3157 if (cpu->pc == cpu->machine->breakpoint_addr[i]) {
3158 fatal("Breakpoint reached, 0x%04x:0x%llx\n",
3159 cpu->cd.x86.s[X86_S_CS],
3160 (long long)cpu->pc);
3161 single_step = 1;
3162 return 0;
3163 }
3164
3165 if (!cpu->cd.x86.descr_cache[X86_S_CS].valid) {
3166 fatal("x86_cpu_run_instr(): Invalid CS descriptor?\n");
3167 cpu->running = 0;
3168 return 0;
3169 }
3170
3171 longmode = cpu->cd.x86.efer & X86_EFER_LME;
3172 mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
3173 omode = mode;
3174 if (mode != 16 && mode != 32) {
3175 fatal("x86_cpu_run_instr(): Invalid CS default op size, %i\n",
3176 mode);
3177 cpu->running = 0;
3178 return 0;
3179 }
3180
3181 if (cpu->cd.x86.interrupt_asserted &&
3182 cpu->cd.x86.rflags & X86_FLAGS_IF) {
3183 if (cause_interrupt(cpu))
3184 return 0;
3185 }
3186
3187 /* 16-bit BIOS emulation: */
3188 if (mode == 16 && ((newpc + (cpu->cd.x86.s[X86_S_CS] << 4)) & 0xff000)
3189 == 0xf8000 && cpu->machine->prom_emulation) {
3190 int addr = (newpc + (cpu->cd.x86.s[X86_S_CS] << 4)) & 0xfff;
3191 if (cpu->machine->instruction_trace)
3192 debug("(PC BIOS emulation, int 0x%02x)\n",
3193 addr >> 4);
3194 pc_bios_emul(cpu);
3195 /* Approximately equivalent to 500 instructions. */
3196 return 500;
3197 }
3198
3199 if (cpu->cd.x86.halted) {
3200 if (!(cpu->cd.x86.rflags & X86_FLAGS_IF)) {
3201 fatal("[ Halting with interrupts disabled. ]\n");
3202 cpu->running = 0;
3203 }
3204 /* Treating this as more than one instruction makes us
3205 wait less for devices. */
3206 return 1000;
3207 }
3208
3209 /* Read an instruction from memory: */
3210 cpu->cd.x86.cursegment = X86_S_CS;
3211 cpu->cd.x86.seg_override = 0;
3212
3213 r = cpu->memory_rw(cpu, cpu->mem, cpu->pc, &buf[0], sizeof(buf),
3214 MEM_READ, CACHE_INSTRUCTION);
3215 if (!r) {
3216 /* This could happen if, for example, there was an
3217 exception while we tried to read the instruction. */
3218 return 0;
3219 }
3220
3221 really_orig_instr = instr; /* Used to display an error message
3222 for unimplemented instructions. */
3223
3224 if (cpu->machine->instruction_trace)
3225 x86_cpu_disassemble_instr(cpu, instr, 1 | omode, 0, 0);
3226
3227 /* For debugging: */
3228 if (instr[0] == 0 && instr[1] == 0 && instr[2] == 0 && instr[3] == 0) {
3229 fatal("WARNING: Running in nothingness?\n");
3230 cpu->running = 0;
3231 return 0;
3232 }
3233
3234 /* All instructions are at least one byte long :-) */
3235 newpc ++;
3236
3237 /* Default is to use the data segment, or the stack segment: */
3238 cpu->cd.x86.cursegment = X86_S_DS;
3239 mode67 = mode;
3240
3241 /* Any prefix? */
3242 for (;;) {
3243 if (longmode && (instr[0] & 0xf0) == 0x40) {
3244 fatal("TODO: REX byte 0x%02x\n", instr[0]);
3245 cpu->running = 0;
3246 } else if (instr[0] == 0x66) {
3247 if (mode == 16)
3248 mode = 32;
3249 else
3250 mode = 16;
3251 } else if (instr[0] == 0x67) {
3252 if (mode67 == 16)
3253 mode67 = 32;
3254 else
3255 mode67 = 16;
3256 } else if (instr[0] == 0x26) {
3257 cpu->cd.x86.cursegment = X86_S_ES;
3258 cpu->cd.x86.seg_override = 1;
3259 } else if (instr[0] == 0x2e) {
3260 cpu->cd.x86.cursegment = X86_S_CS;
3261 cpu->cd.x86.seg_override = 1;
3262 } else if (instr[0] == 0x36) {
3263 cpu->cd.x86.cursegment = X86_S_SS;
3264 cpu->cd.x86.seg_override = 1;
3265 } else if (instr[0] == 0x3e) {
3266 cpu->cd.x86.cursegment = X86_S_DS;
3267 cpu->cd.x86.seg_override = 1;
3268 } else if (instr[0] == 0x64) {
3269 cpu->cd.x86.cursegment = X86_S_FS;
3270 cpu->cd.x86.seg_override = 1;
3271 } else if (instr[0] == 0x65) {
3272 cpu->cd.x86.cursegment = X86_S_GS;
3273 cpu->cd.x86.seg_override = 1;
3274 } else if (instr[0] == 0xf0) {
3275 /* lock */
3276 } else if (instr[0] == 0xf2) {
3277 rep = REP_REPNE;
3278 } else if (instr[0] == 0xf3) {
3279 rep = REP_REP;
3280 } else
3281 break;
3282 instr ++;
3283 newpc ++;
3284 if (++nprefixbytes > 4) {
3285 fatal("x86: too many prefix bytes at ");
3286 print_csip(cpu); fatal("\n");
3287 cpu->running = 0;
3288 return 0;
3289 }
3290 }
3291
3292 op = instr[0];
3293 instr ++;
3294
3295 if ((op & 0xf0) <= 0x30 && (op & 7) <= 5) {
3296 success = 1;
3297 instr_orig = instr;
3298 switch (op & 7) {
3299 case 4: imm = read_imm(&instr, &newpc, 8);
3300 op1 = cpu->cd.x86.r[X86_R_AX] & 0xff;
3301 op2 = (signed char)imm;
3302 mode = 8;
3303 break;
3304 case 5: imm = read_imm(&instr, &newpc, mode);
3305 op1 = cpu->cd.x86.r[X86_R_AX]; op2 = imm;
3306 break;
3307 default:success = modrm(cpu, MODRM_READ, mode, mode67,
3308 op&1? 0 : MODRM_EIGHTBIT, &instr, &newpc,&op1,&op2);
3309 if (!success)
3310 return 0;
3311 }
3312
3313 if ((op & 6) == 2) {
3314 uint64_t tmp = op1; op1 = op2; op2 = tmp;
3315 }
3316
3317 /* printf("op1=0x%x op2=0x%x => ", (int)op1, (int)op2); */
3318
3319 switch (mode) {
3320 case 16: op1 &= 0xffff; op2 &= 0xffff; break;
3321 case 32: op1 &= 0xffffffffULL; op2 &= 0xffffffffULL; break;
3322 }
3323
3324 switch (op & 0x38) {
3325 case 0x00: x86_calc_flags(cpu, op1, op2, !(op & 1)? 8 :
3326 mode, CALCFLAGS_OP_ADD);
3327 op1 = op1 + op2;
3328 break;
3329 case 0x08: op1 = op1 | op2; break;
3330 case 0x10: tmp = op2;
3331 if (cpu->cd.x86.rflags & X86_FLAGS_CF)
3332 tmp ++;
3333 x86_calc_flags(cpu, op1, tmp, !(op & 1)? 8 :
3334 mode, CALCFLAGS_OP_ADD);
3335 op1 = op1 + tmp;
3336 break;
3337 case 0x18: tmp = op2;
3338 if (cpu->cd.x86.rflags & X86_FLAGS_CF)
3339 tmp ++;
3340 x86_calc_flags(cpu, op1, tmp, !(op & 1)? 8 :
3341 mode, CALCFLAGS_OP_SUB);
3342 op1 = op1 - tmp;
3343 break;
3344 case 0x20: op1 = op1 & op2; break;
3345 case 0x28: x86_calc_flags(cpu, op1, op2, !(op & 1)? 8 :
3346 mode, CALCFLAGS_OP_SUB);
3347 op1 = op1 - op2; break;
3348 case 0x30: op1 = op1 ^ op2; break;
3349 case 0x38: x86_calc_flags(cpu, op1, op2, !(op & 1)? 8 :
3350 mode, CALCFLAGS_OP_SUB);
3351 break;
3352 default:
3353 fatal("not yet\n");
3354 exit(1);
3355 }
3356
3357 switch (mode) {
3358 case 16: op1 &= 0xffff; op2 &= 0xffff; break;
3359 case 32: op1 &= 0xffffffffULL; op2 &= 0xffffffffULL; break;
3360 }
3361
3362 /* NOTE: Manual cmp for "sbb, "sub" and "cmp" instructions. */
3363 if ((op & 0x38) != 0x38 && (op & 0x38) != 0x28 &&
3364 (op & 0x38) != 0x18 && (op & 0x38) != 0x00 &&
3365 (op & 0x38) != 0x10)
3366 x86_calc_flags(cpu, op1, 0, !(op & 1)? 8 : mode,
3367 CALCFLAGS_OP_XOR);
3368
3369 /* "and","or","xor" always clears CF and OF: */
3370 if ((op & 0x38) == 0x08 || (op & 0x38) == 0x20 ||
3371 (op & 0x38) == 0x30) {
3372 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3373 cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
3374 }
3375
3376 /* printf("op1=0x%x op2=0x%x\n", (int)op1, (int)op2); */
3377
3378 if ((op & 6) == 2) {
3379 uint64_t tmp = op1; op1 = op2; op2 = tmp;
3380 }
3381
3382 /* Write back the result: (for all cases except CMP) */
3383 if ((op & 0x38) != 0x38) {
3384 switch (op & 7) {
3385 case 4: cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[
3386 X86_R_AX] & ~0xff) | (op1 & 0xff);
3387 break;
3388 case 5: cpu->cd.x86.r[X86_R_AX] = modify(cpu->
3389 cd.x86.r[X86_R_AX], op1);
3390 break;
3391 default:success = modrm(cpu, (op & 6) == 2?
3392 MODRM_WRITE_R : MODRM_WRITE_RM, mode,
3393 mode67, op&1? 0 : MODRM_EIGHTBIT,
3394 &instr_orig, NULL, &op1, &op2);
3395 if (!success)
3396 return 0;
3397 }
3398 }
3399 } else if ((op & 0xf0) < 0x20 && (op & 7) == 6) {
3400 success = x86_push(cpu, cpu->cd.x86.s[op / 8], mode);
3401 if (!success)
3402 return 0;
3403 } else if (op == 0x0f && cpu->cd.x86.model.model_number ==
3404 X86_MODEL_8086) {
3405 uint64_t tmp;
3406 fatal("WARNING: pop cs\n");
3407 if (!x86_pop(cpu, &tmp, mode))
3408 return 0;
3409 reload_segment_descriptor(cpu, X86_S_CS, tmp, &newpc);
3410 } else if (op == 0x0f) {
3411 uint64_t tmp;
3412 unsigned char *instr_orig_2;
3413 int signflag, i;
3414 imm = read_imm(&instr, &newpc, 8);
3415 if (imm >= 0x40 && imm <= 0x4f) { /* CMOVxx */
3416 op = imm & 0xf;
3417 if (!modrm(cpu, MODRM_READ, mode, mode67,
3418 0, &instr, &newpc, &op1, &op2))
3419 return 0;
3420 success = x86_condition(cpu, op);
3421 if (success) {
3422 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3423 MODRM_EIGHTBIT, &instr_orig, NULL,
3424 &op2, &op1))
3425 return 0;
3426 }
3427 } else if (imm >= 0x80 && imm <= 0x8f) {
3428 /* conditional near jump */
3429 op = imm & 0xf;
3430 imm = read_imm(&instr, &newpc, mode);
3431 success = x86_condition(cpu, op);
3432 if (success)
3433 newpc += imm;
3434 } else if (imm >= 0x90 && imm <= 0x9f) {
3435 instr_orig = instr;
3436 if (!modrm(cpu, MODRM_READ, mode, mode67,
3437 MODRM_EIGHTBIT, &instr, &newpc, &op1, &op2))
3438 return 0;
3439 op1 = x86_condition(cpu, imm & 0xf);
3440 if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67,
3441 MODRM_EIGHTBIT, &instr_orig, NULL, &op1, &op2))
3442 return 0;
3443 } else {
3444 int subop;
3445 switch (imm) {
3446 case 0x00:
3447 subop = (*instr >> 3) & 0x7;
3448 switch (subop) {
3449 case 1: /* str */
3450 /* TODO: Check Prot.mode? */
3451 op1 = cpu->cd.x86.tr;
3452 if (!modrm(cpu, MODRM_WRITE_RM, 16,
3453 mode67, 0, &instr, &newpc, &op1,
3454 &op2))
3455 return 0;
3456 break;
3457 case 2: /* lldt */
3458 /* TODO: Check cpl? and Prot.mode */
3459 if (!modrm(cpu, MODRM_READ, 16, mode67,
3460 0, &instr, &newpc, &op1, &op2))
3461 return 0;
3462 reload_segment_descriptor(cpu,
3463 RELOAD_LDTR, op1, &newpc);
3464 break;
3465 case 3: /* ltr */
3466 /* TODO: Check cpl=0 and Prot.mode */
3467 if (!modrm(cpu, MODRM_READ, 16, mode67,
3468 0, &instr, &newpc, &op1, &op2))
3469 return 0;
3470 reload_segment_descriptor(cpu,
3471 RELOAD_TR, op1, &newpc);
3472 break;
3473 default:fatal("UNIMPLEMENTED 0x%02x,0x%02x"
3474 ",0x%02x\n", op, imm, *instr);
3475 quiet_mode = 0;
3476 x86_cpu_disassemble_instr(cpu,
3477 really_orig_instr, 1 | omode, 0, 0);
3478 cpu->running = 0;
3479 }
3480 break;
3481 case 0x01:
3482 subop = (*instr >> 3) & 0x7;
3483 switch (subop) {
3484 case 0: /* sgdt */
3485 case 1: /* sidt */
3486 case 2: /* lgdt */
3487 case 3: /* lidt */
3488 instr_orig = instr;
3489 if (!modrm(cpu, MODRM_READ, mode,
3490 mode67, MODRM_JUST_GET_ADDR, &instr,
3491 &newpc, &op1, &op2))
3492 return 0;
3493 /* TODO/NOTE: how about errors? */
3494 if (subop >= 2) {
3495 x86_load(cpu, op1, &tmp, 2);
3496 x86_load(cpu, op1 + 2, &op2, 4);
3497 if (mode == 16)
3498 op2 &= 0x00ffffffULL;
3499 }
3500 switch (subop) {
3501 case 0: tmp = cpu->cd.x86.gdtr_limit;
3502 op2 = cpu->cd.x86.gdtr;
3503 break;
3504 case 1: tmp = cpu->cd.x86.idtr_limit;
3505 op2 = cpu->cd.x86.idtr;
3506 break;
3507 case 2: cpu->cd.x86.gdtr_limit =
3508 tmp & 0xffff;
3509 cpu->cd.x86.gdtr = op2;
3510 break;
3511 case 3: cpu->cd.x86.idtr_limit =
3512 tmp & 0xffff;
3513 cpu->cd.x86.idtr = op2;
3514 break;
3515 }
3516 if (subop < 2) {
3517 if (mode == 16)
3518 op2 &= 0x00ffffffULL;
3519 x86_store(cpu, op1, tmp, 2);
3520 x86_store(cpu, op1+2, op2, 4);
3521 }
3522 break;
3523 case 4: /* smsw */
3524 case 6: /* lmsw */
3525 instr_orig = instr;
3526 if (!modrm(cpu, MODRM_READ, 16, mode67,
3527 0, &instr, &newpc, &op1, &op2))
3528 return 0;
3529 if (((*instr_orig >> 3) & 0x7) == 4) {
3530 op1 = cpu->cd.x86.cr[0] &0xffff;
3531 if (!modrm(cpu, MODRM_WRITE_RM,
3532 16, mode67, 0, &instr_orig,
3533 NULL, &op1, &op2))
3534 return 0;
3535 } else {
3536 /* lmsw cannot be used to
3537 clear bit 0: */
3538 op1 |= (cpu->cd.x86.cr[0] &
3539 X86_CR0_PE);
3540 x86_write_cr(cpu, 0,
3541 (cpu->cd.x86.cr[0] & ~0xf)
3542 | (op1 & 0xf));
3543 }
3544 break;
3545 case 7: /* invlpg */
3546 modrm(cpu, MODRM_READ, mode,
3547 mode67, MODRM_JUST_GET_ADDR, &instr,
3548 &newpc, &op1, &op2);
3549 /* TODO */
3550 break;
3551 default:fatal("UNIMPLEMENTED 0x%02x,0x%02x"
3552 ",0x%02x\n", op, imm, *instr);
3553 quiet_mode = 0;
3554 x86_cpu_disassemble_instr(cpu,
3555 really_orig_instr, 1 | omode, 0, 0);
3556 cpu->running = 0;
3557 }
3558 break;
3559 case 0x06: /* CLTS */
3560 cpu->cd.x86.cr[0] &= ~X86_CR0_TS;
3561 break;
3562 case 0x08: /* INVD */
3563 /* TODO */
3564 break;
3565 case 0x09: /* WBINVD */
3566 /* TODO */
3567 break;
3568 case 0x0b: /* Reserved */
3569 x86_interrupt(cpu, 6, 0);
3570 return 1;
3571 case 0x20: /* MOV r/m,CRx */
3572 case 0x21: /* MOV r/m,DRx: TODO: is this right? */
3573 instr_orig = instr;
3574 if (!modrm(cpu, MODRM_READ, 32, mode67,
3575 imm==0x20? MODRM_CR : MODRM_DR, &instr,
3576 &newpc, &op1, &op2))
3577 return 0;
3578 op1 = op2;
3579 if (!modrm(cpu, MODRM_WRITE_RM, 32, mode67,
3580 imm==0x20? MODRM_CR : MODRM_DR, &instr_orig,
3581 NULL, &op1, &op2))
3582 return 0;
3583 break;
3584 case 0x22: /* MOV CRx,r/m */
3585 case 0x23: /* MOV DRx,r/m */
3586 instr_orig = instr;
3587 if (!modrm(cpu, MODRM_READ, 32, mode67,
3588 imm==0x22? MODRM_CR : MODRM_DR, &instr,
3589 &newpc, &op1, &op2))
3590 return 0;
3591 op2 = op1;
3592 if (!modrm(cpu, MODRM_WRITE_R, 32, mode67,
3593 imm==0x22? MODRM_CR : MODRM_DR, &instr_orig,
3594 NULL, &op1, &op2))
3595 return 0;
3596 break;
3597 case 0x30: /* WRMSR */
3598 case 0x32: /* RDMSR */
3599 x86_msr(cpu, imm==0x30? 1 : 0);
3600 break;
3601 case 0x31: /* RDTSC */
3602 if (cpu->cd.x86.model.model_number <
3603 X86_MODEL_PENTIUM)
3604 fatal("WARNING: rdtsc usually requires"
3605 " a Pentium. continuing anyway\n");
3606 if (cpu->cd.x86.cr[4] & X86_CR4_TSD)
3607 fatal("WARNING: time stamp disable:"
3608 " TODO\n");
3609 cpu->cd.x86.r[X86_R_DX] = cpu->cd.x86.tsc >> 32;
3610 cpu->cd.x86.r[X86_R_AX] = cpu->cd.x86.tsc
3611 & 0xffffffff;
3612 /* TODO: make this better */
3613 cpu->cd.x86.tsc += 1000;
3614 break;
3615 case 0xa0:
3616 if (!x86_push(cpu, cpu->cd.x86.s[X86_S_FS],
3617 mode))
3618 return 0;
3619 break;
3620 case 0xa1:
3621 if (!x86_pop(cpu, &tmp, mode))
3622 return 0;
3623 reload_segment_descriptor(cpu, X86_S_FS,
3624 tmp, &newpc);
3625 break;
3626 case 0xa2:
3627 if (!(cpu->cd.x86.rflags & X86_FLAGS_ID))
3628 fatal("TODO: ID bit off in flags,"
3629 " but CPUID attempted?\n");
3630 x86_cpuid(cpu);
3631 break;
3632 case 0xa4:
3633 case 0xa5:
3634 case 0xac:
3635 case 0xad:
3636 instr_orig = instr;
3637 if (!modrm(cpu, MODRM_READ, mode, mode67,
3638 0, &instr, &newpc, &op1, &op2))
3639 return 0;
3640 if (imm & 1)
3641 imm2 = cpu->cd.x86.r[X86_R_CX];
3642 else
3643 imm2 = read_imm(&instr, &newpc, 8);
3644 imm2 &= 31;
3645 if (imm <= 0xa5) { /* SHLD */
3646 if (mode == 16) {
3647 op1 <<= 16;
3648 op1 |= (op2 & 0xffff);
3649 } else {
3650 op1 <<= 32;
3651 op1 |= (op2 & 0xffffffff);
3652 }
3653 x86_shiftrotate(cpu, &op1, 4, imm2,
3654 mode == 64? 64 : (mode * 2));
3655 op1 >>= (mode==16? 16 : 32);
3656 } else { /* SHRD */
3657 if (mode == 16) {
3658 op2 <<= 16;
3659 op1 = (op1 & 0xffff) | op2;
3660 } else {
3661 op2 <<= 32;
3662 op1 = (op1 & 0xffffffff) | op2;
3663 }
3664 x86_shiftrotate(cpu, &op1, 5, imm2,
3665 mode == 64? 64 : (mode * 2));
3666 op1 &= (mode==16? 0xffff : 0xffffffff);
3667 }
3668 if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67,
3669 0, &instr_orig, NULL, &op1, &op2))
3670 return 0;
3671 break;
3672 case 0xa8:
3673 if (!x86_push(cpu, cpu->cd.x86.s[X86_S_GS],
3674 mode))
3675 return 0;
3676 break;
3677 case 0xa9:
3678 if (!x86_pop(cpu, &tmp, mode))
3679 return 0;
3680 reload_segment_descriptor(cpu, X86_S_GS,
3681 tmp, &newpc);
3682 break;
3683 case 0xa3: /* BT */
3684 case 0xab: /* BTS */
3685 case 0xb3: /* BTR */
3686 case 0xbb: /* BTC */
3687 instr_orig = instr;
3688 if (!modrm(cpu, MODRM_READ, mode, mode67,
3689 0, &instr, &newpc, &op1, &op2))
3690 return 0;
3691 imm2 = op2 & 31;
3692 if (mode == 16)
3693 imm2 &= 15;
3694 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3695 if (op1 & ((uint64_t)1 << imm2))
3696 cpu->cd.x86.rflags |=
3697 X86_FLAGS_CF;
3698 switch (imm) {
3699 case 0xab:
3700 op1 |= ((uint64_t)1 << imm2);
3701 break;
3702 case 0xb3:
3703 op1 &= ~((uint64_t)1 << imm2);
3704 break;
3705 case 0xbb:
3706 op1 ^= ((uint64_t)1 << imm2);
3707 break;
3708 }
3709 if (imm != 0xa3) {
3710 if (!modrm(cpu, MODRM_WRITE_RM, mode,
3711 mode67, 0, &instr_orig, NULL,
3712 &op1, &op2))
3713 return 0;
3714 }
3715 break;
3716 case 0xaf: /* imul r16/32, rm16/32 */
3717 instr_orig = instr;
3718 if (!modrm(cpu, MODRM_READ, mode, mode67,
3719 0, &instr, &newpc, &op1, &op2))
3720 return 0;
3721 cpu->cd.x86.rflags &= X86_FLAGS_CF;
3722 cpu->cd.x86.rflags &= X86_FLAGS_OF;
3723 if (mode == 16) {
3724 op2 = (int16_t)op1 * (int16_t)op2;
3725 if (op2 >= 0x10000)
3726 cpu->cd.x86.rflags |=
3727 X86_FLAGS_CF | X86_FLAGS_OF;
3728 } else {
3729 op2 = (int32_t)op1 * (int32_t)op2;
3730 if (op2 >= 0x100000000ULL)
3731 cpu->cd.x86.rflags |=
3732 X86_FLAGS_CF | X86_FLAGS_OF;
3733 }
3734 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3735 0, &instr_orig, NULL, &op1, &op2))
3736 return 0;
3737 break;
3738 case 0xb0:
3739 case 0xb1: /* CMPXCHG */
3740 instr_orig = instr;
3741 if (!modrm(cpu, MODRM_READ, mode, mode67,
3742 imm == 0xb0? MODRM_EIGHTBIT : 0,
3743 &instr, &newpc, &op1, &op2))
3744 return 0;
3745 x86_calc_flags(cpu, op1, cpu->cd.x86.r[
3746 X86_R_AX], imm == 0xb0? 8 : mode,
3747 CALCFLAGS_OP_SUB);
3748 if (cpu->cd.x86.rflags & X86_FLAGS_ZF) {
3749 if (!modrm(cpu, MODRM_WRITE_RM, mode,
3750 mode67, imm == 0xb0?
3751 MODRM_EIGHTBIT : 0,
3752 &instr_orig, NULL, &op2, &op1))
3753 return 0;
3754 } else {
3755 if (imm == 0xb0)
3756 cpu->cd.x86.r[X86_R_AX] =
3757 (cpu->cd.x86.r[X86_R_AX] &
3758 ~0xff) | (op1 & 0xff);
3759 else if (mode == 16)
3760 cpu->cd.x86.r[X86_R_AX] =
3761 (cpu->cd.x86.r[X86_R_AX] &
3762 ~0xffff) | (op1 & 0xffff);
3763 else /* 32 bit */
3764 cpu->cd.x86.r[X86_R_AX] = op1;
3765 }
3766 break;
3767 case 0xb2: /* LSS */
3768 case 0xb4: /* LFS */
3769 case 0xb5: /* LGS */
3770 instr_orig = instr;
3771 if (!modrm(cpu, MODRM_READ, mode, mode67,
3772 MODRM_JUST_GET_ADDR, &instr, &newpc,
3773 &op1, &op2))
3774 return 0;
3775 /* op1 is the address to load from */
3776 if (!x86_load(cpu, op1, &tmp, mode/8))
3777 return 0;
3778 op2 = tmp;
3779 if (!x86_load(cpu, op1 + mode/8, &tmp, 2))
3780 return 0;
3781 reload_segment_descriptor(cpu, imm==0xb2?
3782 X86_S_SS:(imm==0xb4?X86_S_FS:X86_S_GS),
3783 tmp, &newpc);
3784 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3785 0, &instr_orig, NULL, &op1, &op2))
3786 return 0;
3787 break;
3788 case 0xb6:
3789 case 0xb7: /* movzx */
3790 case 0xbe:
3791 case 0xbf: /* movsx */
3792 instr_orig = instr;
3793 if (!modrm(cpu, MODRM_READ, mode, mode67,
3794 (imm&1)==0? (MODRM_EIGHTBIT |
3795 MODRM_R_NONEIGHTBIT) : MODRM_RM_16BIT,
3796 &instr, &newpc, &op1, &op2))
3797 return 0;
3798 signflag = 0;
3799 if (imm >= 0xbe)
3800 signflag = 1;
3801 op2 = op1;
3802 if (imm & 1) { /* r32 = r16 */
3803 op2 &= 0xffff;
3804 if (signflag && op2 & 0x8000)
3805 op2 |= 0xffff0000ULL;
3806 } else { /* r(mode) = r8 */
3807 op2 &= 0xff;
3808 if (signflag && op2 & 0x80)
3809 op2 |= 0xffffff00ULL;
3810 }
3811 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3812 (imm&1)==0? (MODRM_EIGHTBIT |
3813 MODRM_R_NONEIGHTBIT) : MODRM_RM_16BIT,
3814 &instr_orig, NULL, &op1, &op2))
3815 return 0;
3816 break;
3817 case 0xba:
3818 subop = (*instr >> 3) & 0x7;
3819 switch (subop) {
3820 case 4: /* BT */
3821 case 5: /* BTS */
3822 case 6: /* BTR */
3823 case 7: /* BTC */
3824 instr_orig = instr;
3825 if (!modrm(cpu, MODRM_READ, mode,
3826 mode67, 0, &instr, &newpc, &op1,
3827 &op2))
3828 return 0;
3829 imm = read_imm(&instr, &newpc, 8);
3830 imm &= 31;
3831 if (mode == 16)
3832 imm &= 15;
3833 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3834 if (op1 & ((uint64_t)1 << imm))
3835 cpu->cd.x86.rflags |=
3836 X86_FLAGS_CF;
3837 switch (subop) {
3838 case 5: op1 |= ((uint64_t)1 << imm);
3839 break;
3840 case 6: op1 &= ~((uint64_t)1 << imm);
3841 break;
3842 case 7: op1 ^= ((uint64_t)1 << imm);
3843 break;
3844 }
3845 if (subop != 4) {
3846 if (!modrm(cpu, MODRM_WRITE_RM,
3847 mode, mode67, 0,
3848 &instr_orig, NULL,
3849 &op1, &op2))
3850 return 0;
3851 }
3852 break;
3853 default:fatal("UNIMPLEMENTED 0x%02x,0x%02x"
3854 ",0x%02x\n", op, imm, *instr);
3855 quiet_mode = 0;
3856 x86_cpu_disassemble_instr(cpu,
3857 really_orig_instr, 1|omode, 0, 0);
3858 cpu->running = 0;
3859 }
3860 break;
3861 case 0xbc: /* bsf */
3862 case 0xbd: /* bsr */
3863 instr_orig = instr;
3864 if (!modrm(cpu, MODRM_READ, mode, mode67,
3865 0, &instr, &newpc, &op1, &op2))
3866 return 0;
3867 cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;
3868 if (op1 == 0)
3869 cpu->cd.x86.rflags |= X86_FLAGS_ZF;
3870 i = mode - 1;
3871 if (imm == 0xbc)
3872 i = 0;
3873 for (;;) {
3874 if (op1 & ((uint64_t)1<<i)) {
3875 op2 = i;
3876 break;
3877 }
3878 if (imm == 0xbc) {
3879 if (++i >= mode)
3880 break;
3881 } else {
3882 if (--i < 0)
3883 break;
3884 }
3885 }
3886 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3887 0, &instr_orig, NULL, &op1, &op2))
3888 return 0;
3889 break;
3890 case 0xc0: /* xadd */
3891 case 0xc1:
3892 instr_orig = instr_orig_2 = instr;
3893 if (!modrm(cpu, MODRM_READ, mode, mode67,
3894 imm == 0xc0? MODRM_EIGHTBIT : 0,
3895 &instr, &newpc, &op1, &op2))
3896 return 0;
3897 tmp = op1; op1 = op2; op2 = tmp;
3898 x86_calc_flags(cpu, op1, op2, imm==0xc0?
3899 8 : mode, CALCFLAGS_OP_ADD);
3900 op1 += op2;
3901 if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67,
3902 imm == 0xc0? MODRM_EIGHTBIT : 0,
3903 &instr_orig, NULL, &op1, &op2))
3904 return 0;
3905 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3906 imm == 0xc0? MODRM_EIGHTBIT : 0,
3907 &instr_orig_2, NULL, &op1, &op2))
3908 return 0;
3909 break;
3910 case 0xc7:
3911 subop = (*instr >> 3) & 0x7;
3912 switch (subop) {
3913 case 1: /* CMPXCHG8B */
3914 if (!modrm(cpu, MODRM_READ, mode,
3915 mode67, MODRM_JUST_GET_ADDR, &instr,
3916 &newpc, &op1, &op2))
3917 return 0;
3918 if (!x86_load(cpu, op1, &tmp, 8))
3919 return 0;
3920 cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;
3921 if ((tmp >> 32) == (0xffffffffULL &
3922 cpu->cd.x86.r[X86_R_DX]) && (tmp
3923 & 0xffffffffULL) == (0xffffffffULL &
3924 cpu->cd.x86.r[X86_R_AX])) {
3925 cpu->cd.x86.rflags |=
3926 X86_FLAGS_ZF;
3927 tmp = ((cpu->cd.x86.r[X86_R_CX]
3928 & 0xffffffffULL) << 32) |
3929 (cpu->cd.x86.r[X86_R_BX] &
3930 0xffffffffULL);
3931 if (!x86_store(cpu, op1, tmp,8))
3932 return 0;
3933 } else {
3934 cpu->cd.x86.r[X86_R_DX] =
3935 tmp >> 32;
3936 cpu->cd.x86.r[X86_R_AX] =
3937 tmp & 0xffffffffULL;
3938 }
3939 break;
3940 default:fatal("UNIMPLEMENTED 0x%02x,0x%02x"
3941 ",0x%02x\n", op, imm, *instr);
3942 quiet_mode = 0;
3943 x86_cpu_disassemble_instr(cpu,
3944 really_orig_instr, 1|omode, 0, 0);
3945 cpu->running = 0;
3946 }
3947 break;
3948 default:fatal("TODO: 0x0f,0x%02x\n", imm);
3949 quiet_mode = 0;
3950 x86_cpu_disassemble_instr(cpu,
3951 really_orig_instr, 1|omode, 0, 0);
3952 cpu->running = 0;
3953 }
3954 }
3955 } else if ((op & 0xf0) < 0x20 && (op & 7) == 7) {
3956 uint64_t tmp;
3957 success = x86_pop(cpu, &tmp, mode);
3958 if (!success)
3959 return 0;
3960 reload_segment_descriptor(cpu, op/8, tmp, &newpc);
3961 } else if (op == 0x27) { /* DAA */
3962 int a = (cpu->cd.x86.r[X86_R_AX] >> 4) & 0xf;
3963 int b = cpu->cd.x86.r[X86_R_AX] & 0xf;
3964 if (b > 9) {
3965 b -= 10;
3966 a ++;
3967 } else if (cpu->cd.x86.rflags & X86_FLAGS_AF)
3968 b += 6;
3969 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3970 cpu->cd.x86.rflags &= ~X86_FLAGS_AF;
3971 if (a*10 + b >= 100) {
3972 cpu->cd.x86.rflags |= X86_FLAGS_CF;
3973 cpu->cd.x86.rflags |= X86_FLAGS_AF;
3974 a %= 10;
3975 }
3976 cpu->cd.x86.r[X86_R_AX] &= ~0xff;
3977 cpu->cd.x86.r[X86_R_AX] |= ((a*16 + b) & 0xff);
3978 } else if (op == 0x2f) { /* DAS */
3979 int tmp_al = cpu->cd.x86.r[X86_R_AX] & 0xff;
3980 if ((tmp_al & 0xf) > 9 || cpu->cd.x86.rflags & X86_FLAGS_AF) {
3981 cpu->cd.x86.r[X86_R_AX] &= ~0xff;
3982 cpu->cd.x86.r[X86_R_AX] |= ((tmp_al - 6) & 0xff);
3983 cpu->cd.x86.rflags |= X86_FLAGS_AF;
3984 } else
3985 cpu->cd.x86.rflags &= ~X86_FLAGS_AF;
3986 if (tmp_al > 0x9f || cpu->cd.x86.rflags & X86_FLAGS_CF) {
3987 cpu->cd.x86.r[X86_R_AX] &= ~0xff;
3988 cpu->cd.x86.r[X86_R_AX] |= ((tmp_al - 0x60) & 0xff);
3989 cpu->cd.x86.rflags |= X86_FLAGS_CF;
3990 } else
3991 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3992 x86_calc_flags(cpu, cpu->cd.x86.r[X86_R_AX] & 0xff,
3993 0, 8, CALCFLAGS_OP_XOR);
3994 } else if (op == 0x37) { /* AAA */
3995 int b = cpu->cd.x86.r[X86_R_AX] & 0xf;
3996 if (b > 9) {
3997 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX]
3998 & ~0xff00) | ((cpu->cd.x86.r[X86_R_AX] &
3999 0xff00) + 0x100);
4000 cpu->cd.x86.rflags |= X86_FLAGS_CF | X86_FLAGS_AF;
4001 } else {
4002 cpu->cd.x86.rflags &= ~(X86_FLAGS_CF | X86_FLAGS_AF);
4003 }
4004 cpu->cd.x86.r[X86_R_AX] &= ~0xf0;
4005 } else if (op >= 0x40 && op <= 0x4f) {
4006 int old_cf = cpu->cd.x86.rflags & X86_FLAGS_CF;
4007 if (op < 0x48) {
4008 x86_calc_flags(cpu, cpu->cd.x86.r[op & 7], 1, mode,
4009 CALCFLAGS_OP_ADD);
4010 cpu->cd.x86.r[op & 7] = modify(cpu->cd.x86.r[op & 7],
4011 cpu->cd.x86.r[op & 7] + 1);
4012 } else {
4013 x86_calc_flags(cpu, cpu->cd.x86.r[op & 7], 1, mode,
4014 CALCFLAGS_OP_SUB);
4015 if (mode == 16)
4016 cpu->cd.x86.r[op & 7] = modify(cpu->cd.x86.r[op
4017 & 7], (cpu->cd.x86.r[op & 7] & 0xffff) - 1);
4018 else {
4019 cpu->cd.x86.r[op & 7] --;
4020 cpu->cd.x86.r[op & 7] &= 0xffffffffULL;
4021 }
4022 }
4023 /* preserve CF: */
4024 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4025 cpu->cd.x86.rflags |= old_cf;
4026 } else if (op >= 0x50 && op <= 0x57) {
4027 if (!x86_push(cpu, cpu->cd.x86.r[op & 7], mode))
4028 return 0;
4029 } else if (op >= 0x58 && op <= 0x5f) {
4030 if (!x86_pop(cpu, &tmp, mode))
4031 return 0;
4032 if (mode == 16)
4033 cpu->cd.x86.r[op & 7] = (cpu->cd.x86.r[op & 7] &
4034 ~0xffff) | (tmp & 0xffff);
4035 else
4036 cpu->cd.x86.r[op & 7] = tmp;
4037 } else if (op == 0x60) { /* PUSHA/PUSHAD */
4038 uint64_t r[8];
4039 int i;
4040 for (i=0; i<8; i++)
4041 r[i] = cpu->cd.x86.r[i];
4042 for (i=0; i<8; i++)
4043 if (!x86_push(cpu, r[i], mode)) {
4044 fatal("TODO: failed pusha\n");
4045 cpu->running = 0;
4046 return 0;
4047 }
4048 } else if (op == 0x61) { /* POPA/POPAD */
4049 uint64_t r[8];
4050 int i;
4051 for (i=7; i>=0; i--)
4052 if (!x86_pop(cpu, &r[i], mode)) {
4053 fatal("TODO: failed popa\n");
4054 cpu->running = 0;
4055 return 0;
4056 }
4057 for (i=0; i<8; i++)
4058 if (i != X86_R_SP) {
4059 if (mode == 16)
4060 cpu->cd.x86.r[i] = (cpu->cd.x86.r[i]
4061 & ~0xffff) | (r[i] & 0xffff);
4062 else
4063 cpu->cd.x86.r[i] = r[i];
4064 }
4065 } else if (op == 0x68) { /* PUSH imm16/32 */
4066 uint64_t imm = read_imm(&instr, &newpc, mode);
4067 if (!x86_push(cpu, imm, mode))
4068 return 0;
4069 } else if (op == 0x69 || op == 0x6b) {
4070 instr_orig = instr;
4071 if (!modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
4072 &newpc, &op1, &op2))
4073 return 0;
4074 if (op == 0x69)
4075 imm = read_imm(&instr, &newpc, mode);
4076 else
4077 imm = (signed char)read_imm(&instr, &newpc, 8);
4078 op2 = op1 * imm;
4079 /* TODO: overflow! */
4080 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67, 0,
4081 &instr_orig, NULL, &op1, &op2))
4082 return 0;
4083 } else if (op == 0x6a) { /* PUSH imm8 */
4084 uint64_t imm = (signed char)read_imm(&instr, &newpc, 8);
4085 if (!x86_push(cpu, imm, mode))
4086 return 0;
4087 } else if ((op & 0xf0) == 0x70) {
4088 imm = read_imm(&instr, &newpc, 8);
4089 success = x86_condition(cpu, op);
4090 if (success)
4091 newpc = modify(newpc, newpc + (signed char)imm);
4092 } else if (op == 0x80 || op == 0x81) { /* add/and r/m, imm */
4093 instr_orig = instr;
4094 if (!modrm(cpu, MODRM_READ, mode, mode67, op == 0x80?
4095 MODRM_EIGHTBIT : 0, &instr, &newpc, &op1, &op2))
4096 return 0;
4097 imm = read_imm(&instr, &newpc, op==0x80? 8 : mode);
4098 switch ((*instr_orig >> 3) & 0x7) {
4099 case 0: x86_calc_flags(cpu, op1, imm, op==0x80? 8 : mode,
4100 CALCFLAGS_OP_ADD);
4101 op1 += imm;
4102 break;
4103 case 1: op1 |= imm; break;
4104 case 2: tmp = imm + (cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0);
4105 x86_calc_flags(cpu, op1, tmp, op==0x80? 8 : mode,
4106 CALCFLAGS_OP_ADD);
4107 op1 += tmp;
4108 break;
4109 case 3: tmp = imm + (cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0);
4110 x86_calc_flags(cpu, op1, tmp, op==0x80? 8 : mode,
4111 CALCFLAGS_OP_SUB);
4112 op1 -= tmp;
4113 break;
4114 case 4: op1 &= imm; break;
4115 case 5: x86_calc_flags(cpu, op1, imm, op==0x80? 8 : mode,
4116 CALCFLAGS_OP_SUB);
4117 op1 -= imm; break;
4118 case 6: op1 ^= imm; break;
4119 case 7: x86_calc_flags(cpu, op1, imm, op==0x80? 8 : mode,
4120 CALCFLAGS_OP_SUB); /* cmp */
4121 break;
4122 }
4123
4124 if (((*instr_orig >> 3) & 0x7) != 7) {
4125 if (((*instr_orig >> 3) & 0x7) != 0 &&
4126 ((*instr_orig >> 3) & 0x7) != 2 &&
4127 ((*instr_orig >> 3) & 0x7) != 3 &&
4128 ((*instr_orig >> 3) & 0x7) != 5)
4129 x86_calc_flags(cpu, op1, 0, op==0x80? 8 : mode,
4130 CALCFLAGS_OP_XOR);
4131
4132 /* "and","or","xor" always clears CF and OF: */
4133 if (((*instr_orig >> 3) & 0x7) == 1 ||
4134 ((*instr_orig >> 3) & 0x7) == 4 ||
4135 ((*instr_orig >> 3) & 0x7) == 6) {
4136 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4137 cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
4138 }
4139
4140 if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4141 op == 0x80? MODRM_EIGHTBIT : 0, &instr_orig,
4142 NULL, &op1, &op2))
4143 return 0;
4144 }
4145 } else if (op == 0x83) { /* add/and r/m1632, imm8 */
4146 instr_orig = instr;
4147 if (!modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
4148 &newpc, &op1, &op2))
4149 return 0;
4150 imm = read_imm(&instr, &newpc, 8);
4151 switch ((*instr_orig >> 3) & 0x7) {
4152 case 0: x86_calc_flags(cpu, op1, (signed char)imm,
4153 mode, CALCFLAGS_OP_ADD);
4154 op1 += (signed char)imm;
4155 break;
4156 case 1: op1 |= (signed char)imm; break;
4157 case 2: tmp = (signed char)imm +
4158 (cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0);
4159 x86_calc_flags(cpu, op1, tmp, mode, CALCFLAGS_OP_ADD);
4160 op1 += tmp;
4161 break;
4162 case 3: tmp = (signed char)imm +
4163 (cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0);
4164 x86_calc_flags(cpu, op1, tmp, mode, CALCFLAGS_OP_SUB);
4165 op1 -= tmp;
4166 break;
4167 case 4: op1 &= (signed char)imm; break;
4168 case 5: x86_calc_flags(cpu, op1, (signed char)imm, mode,
4169 CALCFLAGS_OP_SUB);
4170 op1 -= (signed char)imm; break;
4171 case 6: op1 ^= (signed char)imm; break;
4172 case 7: x86_calc_flags(cpu, op1, (signed char)imm, mode,
4173 CALCFLAGS_OP_SUB);
4174 break;
4175 }
4176 if (((*instr_orig >> 3) & 0x7) != 7) {
4177 if (((*instr_orig >> 3) & 0x7) != 0 &&
4178 ((*instr_orig >> 3) & 0x7) != 2 &&
4179 ((*instr_orig >> 3) & 0x7) != 3 &&
4180 ((*instr_orig >> 3) & 0x7) != 5)
4181 x86_calc_flags(cpu, op1, 0, mode,
4182 CALCFLAGS_OP_XOR);
4183
4184 /* "and","or","xor" always clears CF and OF: */
4185 if (((*instr_orig >> 3) & 0x7) == 1 ||
4186 ((*instr_orig >> 3) & 0x7) == 4 ||
4187 ((*instr_orig >> 3) & 0x7) == 6) {
4188 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4189 cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
4190 }
4191 if (!modrm(cpu, MODRM_WRITE_RM, mode,
4192 mode67, 0, &instr_orig, NULL, &op1, &op2))
4193 return 0;
4194 }
4195 } else if (op == 0x84 || op == 0x85) { /* TEST */
4196 success = modrm(cpu, MODRM_READ, mode, mode67, op == 0x84?
4197 MODRM_EIGHTBIT : 0, &instr, &newpc, &op1, &op2);
4198 if (!success)
4199 return 0;
4200 op1 &= op2;
4201 x86_calc_flags(cpu, op1, 0, op==0x84? 8 : mode,
4202 CALCFLAGS_OP_XOR);
4203 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4204 cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
4205 } else if (op >= 0x86 && op <= 0x87) { /* XCHG */
4206 void *orig2 = instr_orig = instr;
4207 success = modrm(cpu, MODRM_READ, mode, mode67, op&1? 0 :
4208 MODRM_EIGHTBIT, &instr, &newpc, &op1, &op2);
4209 if (!success)
4210 return 0;
4211 /* Note: Update the r/m first, because it may be dependant
4212 on original register values :-) */
4213 success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4214 op == 0x86? MODRM_EIGHTBIT : 0, &instr_orig,
4215 NULL, &op2, &op1);
4216 instr_orig = orig2;
4217 success = modrm(cpu, MODRM_WRITE_R, mode, mode67,
4218 op == 0x86? MODRM_EIGHTBIT : 0, &instr_orig,
4219 NULL, &op2, &op1);
4220 if (!success)
4221 return 0;
4222 } else if (op >= 0x88 && op <= 0x8b) { /* MOV */
4223 instr_orig = instr;
4224 success = modrm(cpu, MODRM_READ, mode, mode67, (op & 1) == 0?
4225 MODRM_EIGHTBIT : 0, &instr, &newpc, &op1, &op2);
4226 if (!success)
4227 return 0;
4228 if (op < 0x8a) {
4229 success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4230 op == 0x88? MODRM_EIGHTBIT : 0, &instr_orig,
4231 NULL, &op2, &op1);
4232 } else {
4233 success = modrm(cpu, MODRM_WRITE_R, mode, mode67,
4234 op == 0x8a? MODRM_EIGHTBIT : 0, &instr_orig,
4235 NULL, &op2, &op1);
4236 }
4237 if (!success)
4238 return 0;
4239 } else if (op == 0x8c || op == 0x8e) { /* MOV seg */
4240 instr_orig = instr;
4241 if (!modrm(cpu, MODRM_READ, 16, mode67, MODRM_SEG,
4242 &instr, &newpc, &op1, &op2))
4243 return 0;
4244 if (op == 0x8c) {
4245 if (!modrm(cpu, MODRM_WRITE_RM, 16, mode67, MODRM_SEG,
4246 &instr_orig, NULL, &op2, &op1))
4247 return 0;
4248 } else {
4249 reload_segment_descriptor(cpu, (*instr_orig >> 3) & 7,
4250 op1 & 0xffff, &newpc);
4251 }
4252 } else if (op == 0x8d) { /* LEA */
4253 instr_orig = instr;
4254 if (!modrm(cpu, MODRM_READ, mode, mode67,
4255 MODRM_JUST_GET_ADDR, &instr, &newpc, &op1, &op2))
4256 return 0;
4257 op2 = op1;
4258 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
4259 0, &instr_orig, NULL, &op1, &op2))
4260 return 0;
4261 } else if (op == 0x8f) {
4262 switch ((*instr >> 3) & 0x7) {
4263 case 0: /* POP m16/m32 */
4264 if (!x86_pop(cpu, &op1, mode))
4265 return 0;
4266 if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4267 0, &instr, &newpc, &op1, &op2))
4268 return 0;
4269 break;
4270 default:
4271 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4272 quiet_mode = 0;
4273 x86_cpu_disassemble_instr(cpu,
4274 really_orig_instr, 1|omode, 0, 0);
4275 cpu->running = 0;
4276 }
4277 } else if (op == 0x90) { /* NOP */
4278 } else if (op >= 0x91 && op <= 0x97) { /* XCHG */
4279 uint64_t tmp;
4280 if (mode == 16) {
4281 tmp = cpu->cd.x86.r[X86_R_AX];
4282 cpu->cd.x86.r[X86_R_AX] = modify(
4283 cpu->cd.x86.r[X86_R_AX], cpu->cd.x86.r[op & 7]);
4284 cpu->cd.x86.r[op & 7] = modify(
4285 cpu->cd.x86.r[op & 7], tmp);
4286 } else {
4287 tmp = cpu->cd.x86.r[X86_R_AX];
4288 cpu->cd.x86.r[X86_R_AX] = cpu->cd.x86.r[op & 7];
4289 cpu->cd.x86.r[op & 7] = tmp;
4290 }
4291 } else if (op == 0x98) { /* CBW/CWDE */
4292 if (mode == 16) {
4293 cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
4294 if (cpu->cd.x86.r[X86_R_AX] & 0x80)
4295 cpu->cd.x86.r[X86_R_AX] |= 0xff00;
4296 } else {
4297 cpu->cd.x86.r[X86_R_AX] &= 0xffff;
4298 if (cpu->cd.x86.r[X86_R_AX] & 0x8000)
4299 cpu->cd.x86.r[X86_R_AX] |= 0xffff0000ULL;
4300 }
4301 } else if (op == 0x99) { /* CWD/CDQ */
4302 if (mode == 16) {
4303 cpu->cd.x86.r[X86_R_DX] &= ~0xffff;
4304 if (cpu->cd.x86.r[X86_R_AX] & 0x8000)
4305 cpu->cd.x86.r[X86_R_DX] |= 0xffff;
4306 } else {
4307 cpu->cd.x86.r[X86_R_DX] = 0;
4308 if (cpu->cd.x86.r[X86_R_AX] & 0x80000000ULL)
4309 cpu->cd.x86.r[X86_R_DX] = 0xffffffff;
4310 }
4311 } else if (op == 0x9a) { /* CALL seg:ofs */
4312 uint16_t old_tr = cpu->cd.x86.tr;
4313 imm = read_imm(&instr, &newpc, mode);
4314 imm2 = read_imm(&instr, &newpc, 16);
4315 if (!x86_push(cpu, cpu->cd.x86.s[X86_S_CS], mode))
4316 return 0;
4317 if (!x86_push(cpu, newpc, mode)) {
4318 fatal("TODO: push failed in CALL seg:ofs\n");
4319 cpu->running = 0;
4320 return 0;
4321 }
4322 reload_segment_descriptor(cpu, X86_S_CS, imm2, &newpc);
4323 if (cpu->cd.x86.tr == old_tr)
4324 newpc = imm;
4325 } else if (op == 0x9b) { /* WAIT */
4326 } else if (op == 0x9c) { /* PUSHF */
4327 if (!x86_push(cpu, cpu->cd.x86.rflags, mode))
4328 return 0;
4329 } else if (op == 0x9d) { /* POPF */
4330 if (!x86_pop(cpu, &tmp, mode))
4331 return 0;
4332 if (mode == 16)
4333 cpu->cd.x86.rflags = (cpu->cd.x86.rflags & ~0xffff)
4334 | (tmp & 0xffff);
4335 else if (mode == 32)
4336 cpu->cd.x86.rflags = (cpu->cd.x86.rflags & ~0xffffffff)
4337 | (tmp & 0xffffffff);
4338 else
4339 cpu->cd.x86.rflags = tmp;
4340 /* TODO: only affect some bits? */
4341 cpu->cd.x86.rflags |= 0x0002;
4342 if (cpu->cd.x86.model.model_number == X86_MODEL_8086)
4343 cpu->cd.x86.rflags |= 0xf000;
4344 /* TODO: all these bits aren't really cleared on a 286: */
4345 if (cpu->cd.x86.model.model_number == X86_MODEL_80286)
4346 cpu->cd.x86.rflags &= ~0xf000;
4347 if (cpu->cd.x86.model.model_number == X86_MODEL_80386)
4348 cpu->cd.x86.rflags &= ~X86_FLAGS_AC;
4349 if (cpu->cd.x86.model.model_number == X86_MODEL_80486)
4350 cpu->cd.x86.rflags &= ~X86_FLAGS_ID;
4351 } else if (op == 0x9e) { /* SAHF */
4352 int mask = (X86_FLAGS_SF | X86_FLAGS_ZF
4353 | X86_FLAGS_AF | X86_FLAGS_PF | X86_FLAGS_CF);
4354 cpu->cd.x86.rflags &= ~mask;
4355 mask &= ((cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff);
4356 cpu->cd.x86.rflags |= mask;
4357 } else if (op == 0x9f) { /* LAHF */
4358 int b = cpu->cd.x86.rflags & (X86_FLAGS_SF | X86_FLAGS_ZF
4359 | X86_FLAGS_AF | X86_FLAGS_PF | X86_FLAGS_CF);
4360 b |= 2;
4361 cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
4362 cpu->cd.x86.r[X86_R_AX] |= (b << 8);
4363 } else if (op == 0xa0) { /* MOV AL,[addr] */
4364 imm = read_imm(&instr, &newpc, mode67);
4365 if (!x86_load(cpu, imm, &tmp, 1))
4366 return 0;
4367 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & ~0xff)
4368 | (tmp & 0xff);
4369 } else if (op == 0xa1) { /* MOV AX,[addr] */
4370 imm = read_imm(&instr, &newpc, mode67);
4371 if (!x86_load(cpu, imm, &tmp, mode/8))
4372 return 0;
4373 cpu->cd.x86.r[X86_R_AX] = modify(cpu->cd.x86.r[X86_R_AX], tmp);
4374 } else if (op == 0xa2) { /* MOV [addr],AL */
4375 imm = read_imm(&instr, &newpc, mode67);
4376 if (!x86_store(cpu, imm, cpu->cd.x86.r[X86_R_AX], 1))
4377 return 0;
4378 } else if (op == 0xa3) { /* MOV [addr],AX */
4379 imm = read_imm(&instr, &newpc, mode67);
4380 if (!x86_store(cpu, imm, cpu->cd.x86.r[X86_R_AX], mode/8))
4381 return 0;
4382 } else if (op == 0xa4 || op == 0xa5 || /* MOVS */
4383 op == 0xa6 || op == 0xa7 || /* CMPS */
4384 op == 0xaa || op == 0xab || /* STOS */
4385 op == 0xac || op == 0xad || /* LODS */
4386 op == 0xae || op == 0xaf) { /* SCAS */
4387 int dir = 1, movs = 0, lods = 0, cmps = 0, stos = 0, scas = 0;
4388 int origcursegment = cpu->cd.x86.cursegment;
4389
4390 len = 1;
4391 if (op & 1)
4392 len = mode / 8;
4393 if (op >= 0xa4 && op <= 0xa5)
4394 movs = 1;
4395 if (op >= 0xa6 && op <= 0xa7)
4396 cmps = 1;
4397 if (op >= 0xaa && op <= 0xab)
4398 stos = 1;
4399 if (op >= 0xac && op <= 0xad)
4400 lods = 1;
4401 if (op >= 0xae && op <= 0xaf)
4402 scas = 1;
4403 if (cpu->cd.x86.rflags & X86_FLAGS_DF)
4404 dir = -1;
4405
4406 do {
4407 uint64_t value;
4408
4409 if (rep) {
4410 /* Abort if [e]cx already 0: */
4411 if (mode == 16 && (cpu->cd.x86.r[X86_R_CX] &
4412 0xffff) == 0)
4413 break;
4414 if (mode != 16 && cpu->cd.x86.r[X86_R_CX] == 0)
4415 break;
4416 }
4417
4418 if (!stos && !scas) {
4419 uint64_t addr = cpu->cd.x86.r[X86_R_SI];
4420 if (mode67 == 16)
4421 addr &= 0xffff;
4422 if (mode67 == 32)
4423 addr &= 0xffffffff;
4424 cpu->cd.x86.cursegment = origcursegment;
4425 if (!x86_load(cpu, addr, &value, len))
4426 return 0;
4427 } else
4428 value = cpu->cd.x86.r[X86_R_AX];
4429 if (lods) {
4430 if (op == 0xac)
4431 cpu->cd.x86.r[X86_R_AX] =
4432 (cpu->cd.x86.r[X86_R_AX] & ~0xff)
4433 | (value & 0xff);
4434 else if (mode == 16)
4435 cpu->cd.x86.r[X86_R_AX] =
4436 (cpu->cd.x86.r[X86_R_AX] & ~0xffff)
4437 | (value & 0xffff);
4438 else
4439 cpu->cd.x86.r[X86_R_AX] = value;
4440 }
4441
4442 if (stos || movs) {
4443 uint64_t addr = cpu->cd.x86.r[X86_R_DI];
4444 if (mode67 == 16)
4445 addr &= 0xffff;
4446 if (mode67 == 32)
4447 addr &= 0xffffffff;
4448 cpu->cd.x86.cursegment = X86_S_ES;
4449 if (!x86_store(cpu, addr, value, len))
4450 return 0;
4451 }
4452 if (cmps || scas) {
4453 uint64_t addr = cpu->cd.x86.r[X86_R_DI];
4454 if (mode67 == 16)
4455 addr &= 0xffff;
4456 if (mode67 == 32)
4457 addr &= 0xffffffff;
4458 cpu->cd.x86.cursegment = X86_S_ES;
4459 if (!x86_load(cpu, addr, &tmp, len))
4460 return 0;
4461
4462 x86_calc_flags(cpu, value, tmp, len*8,
4463 CALCFLAGS_OP_SUB);
4464 }
4465
4466 if (movs || lods || cmps) {
4467 /* Modify esi: */
4468 if (mode67 == 16)
4469 cpu->cd.x86.r[X86_R_SI] =
4470 (cpu->cd.x86.r[X86_R_SI] & ~0xffff)
4471 | ((cpu->cd.x86.r[X86_R_SI]+len*dir)
4472 & 0xffff);
4473 else {
4474 cpu->cd.x86.r[X86_R_SI] += len*dir;
4475 if (mode67 == 32)
4476 cpu->cd.x86.r[X86_R_SI] &=
4477 0xffffffff;
4478 }
4479 }
4480
4481 if (!lods) {
4482 /* Modify edi: */
4483 if (mode67 == 16)
4484 cpu->cd.x86.r[X86_R_DI] =
4485 (cpu->cd.x86.r[X86_R_DI] & ~0xffff)
4486 | ((cpu->cd.x86.r[X86_R_DI]+len*dir)
4487 & 0xffff);
4488 else {
4489 cpu->cd.x86.r[X86_R_DI] += len*dir;
4490 if (mode67 == 32)
4491 cpu->cd.x86.r[X86_R_DI] &=
4492 0xffffffff;
4493 }
4494 }
4495
4496 if (rep) {
4497 /* Decrement ecx: */
4498 if (mode67 == 16)
4499 cpu->cd.x86.r[X86_R_CX] =
4500 (cpu->cd.x86.r[X86_R_CX] & ~0xffff)
4501 | ((cpu->cd.x86.r[X86_R_CX] - 1)
4502 & 0xffff);
4503 else {
4504 cpu->cd.x86.r[X86_R_CX] --;
4505 cpu->cd.x86.r[X86_R_CX] &= 0xffffffff;
4506 }
4507 if (mode67 == 16 && (cpu->cd.x86.r[X86_R_CX] &
4508 0xffff) == 0)
4509 rep = 0;
4510 if (mode67 != 16 &&
4511 cpu->cd.x86.r[X86_R_CX] == 0)
4512 rep = 0;
4513
4514 if (cmps || scas) {
4515 if (rep == REP_REP && !(
4516 cpu->cd.x86.rflags & X86_FLAGS_ZF))
4517 rep = 0;
4518 if (rep == REP_REPNE &&
4519 cpu->cd.x86.rflags & X86_FLAGS_ZF)
4520 rep = 0;
4521 }
4522 }
4523 } while (rep);
4524 } else if (op >= 0xa8 && op <= 0xa9) { /* TEST al/[e]ax,imm */
4525 op1 = cpu->cd.x86.r[X86_R_AX];
4526 op2 = read_imm(&instr, &newpc, op==0xa8? 8 : mode);
4527 op1 &= op2;
4528 x86_calc_flags(cpu, op1, 0, op==0xa8? 8 : mode,
4529 CALCFLAGS_OP_XOR);
4530 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4531 cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
4532 } else if (op >= 0xb0 && op <= 0xb3) { /* MOV Xl,imm */
4533 imm = read_imm(&instr, &newpc, 8);
4534 cpu->cd.x86.r[op & 3] = (cpu->cd.x86.r[op & 3] & ~0xff)
4535 | (imm & 0xff);
4536 } else if (op >= 0xb4 && op <= 0xb7) { /* MOV Xh,imm */
4537 imm = read_imm(&instr, &newpc, 8);
4538 cpu->cd.x86.r[op & 3] = (cpu->cd.x86.r[op & 3] & ~0xff00)
4539 | ((imm & 0xff) << 8);
4540 } else if (op >= 0xb8 && op <= 0xbf) { /* MOV Xx,imm */
4541 imm = read_imm(&instr, &newpc, mode);
4542 cpu->cd.x86.r[op & 7] = modify(cpu->cd.x86.r[op & 7], imm);
4543 } else if (op == 0xc0 || op == 0xc1) { /* Shift/Rotate */
4544 int n = 1;
4545 instr_orig = instr;
4546 success = modrm(cpu, MODRM_READ, mode, mode67,
4547 op&1? 0 : MODRM_EIGHTBIT, &instr, &newpc, &op1, &op2);
4548 if (!success)
4549 return 0;
4550 n = read_imm(&instr, &newpc, 8);
4551 x86_shiftrotate(cpu, &op1, (*instr_orig >> 3) & 0x7,
4552 n, op&1? mode : 8);
4553 success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4554 op&1? 0 : MODRM_EIGHTBIT, &instr_orig, NULL, &op1, &op2);
4555 if (!success)
4556 return 0;
4557 } else if (op == 0xc2 || op == 0xc3) { /* RET near */
4558 uint64_t popped_pc;
4559 if (!x86_pop(cpu, &popped_pc, mode))
4560 return 0;
4561 if (op == 0xc2) {
4562 imm = read_imm(&instr, &newpc, 16);
4563 cpu->cd.x86.r[X86_R_SP] = modify(cpu->cd.x86.r[
4564 X86_R_SP], cpu->cd.x86.r[X86_R_SP] + imm);
4565 }
4566 newpc = popped_pc;
4567 } else if (op == 0xc4 || op == 0xc5) { /* LDS,LES */
4568 instr_orig = instr;
4569 if (!modrm(cpu, MODRM_READ, mode, mode67,
4570 MODRM_JUST_GET_ADDR, &instr, &newpc, &op1, &op2))
4571 return 0;
4572 /* op1 is the address to load from */
4573 if (!x86_load(cpu, op1, &tmp, mode/8))
4574 return 0;
4575 op2 = tmp;
4576 if (!x86_load(cpu, op1 + mode/8, &tmp, 2))
4577 return 0;
4578 reload_segment_descriptor(cpu, op==0xc4? X86_S_ES:X86_S_DS,
4579 tmp, &newpc);
4580 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
4581 0, &instr_orig, NULL, &op1, &op2))
4582 return 0;
4583 } else if (op >= 0xc6 && op <= 0xc7) {
4584 switch ((*instr >> 3) & 0x7) {
4585 case 0: instr_orig = instr; /* MOV r/m, imm */
4586 success = modrm(cpu, MODRM_READ, mode, mode67,
4587 op == 0xc6? MODRM_EIGHTBIT : 0, &instr,
4588 &newpc, &op1, &op2);
4589 if (!success)
4590 return 0;
4591 imm = read_imm(&instr, &newpc, op == 0xc6? 8 : mode);
4592 op1 = imm;
4593 success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4594 op == 0xc6? MODRM_EIGHTBIT : 0, &instr_orig,
4595 NULL, &op1, &op2);
4596 if (!success)
4597 return 0;
4598 break;
4599 default:
4600 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4601 quiet_mode = 0;
4602 x86_cpu_disassemble_instr(cpu,
4603 really_orig_instr, 1|omode, 0, 0);
4604 cpu->running = 0;
4605 }
4606 } else if (op == 0xc8) { /* ENTER */
4607 uint64_t tmp_frame_ptr;
4608 int level;
4609 imm = read_imm(&instr, &newpc, 16);
4610 level = read_imm(&instr, &newpc, 8);
4611 if (!x86_push(cpu, cpu->cd.x86.r[X86_R_BP], mode))
4612 return 0;
4613 tmp_frame_ptr = cpu->cd.x86.r[X86_R_SP];
4614 if (level > 0) {
4615 while (level-- > 1) {
4616 uint64_t tmpword;
4617 cpu->cd.x86.r[X86_R_BP] = modify(
4618 cpu->cd.x86.r[X86_R_BP],
4619 cpu->cd.x86.r[X86_R_BP] - mode/8);
4620 cpu->cd.x86.cursegment = X86_S_SS;
4621 if (!x86_load(cpu, cpu->cd.x86.r[X86_R_BP],
4622 &tmpword, mode/8)) {
4623 fatal("TODO: load error inside"
4624 " ENTER\n");
4625 cpu->running = 0;
4626 return 0;
4627 }
4628 if (!x86_push(cpu, tmpword, mode)) {
4629 fatal("TODO: push error inside"
4630 " ENTER\n");
4631 cpu->running = 0;
4632 return 0;
4633 }
4634 }
4635 if (!x86_push(cpu, tmp_frame_ptr, mode))
4636 return 0;
4637 }
4638 cpu->cd.x86.r[X86_R_BP] = modify(cpu->cd.x86.r[X86_R_BP],
4639 tmp_frame_ptr);
4640 if (mode == 16)
4641 cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] &
4642 ~0xffff) | ((cpu->cd.x86.r[X86_R_SP] & 0xffff)
4643 - imm);
4644 else
4645 cpu->cd.x86.r[X86_R_SP] -= imm;
4646 } else if (op == 0xc9) { /* LEAVE */
4647 cpu->cd.x86.r[X86_R_SP] = cpu->cd.x86.r[X86_R_BP];
4648 if (!x86_pop(cpu, &tmp, mode)) {
4649 fatal("TODO: pop error inside LEAVE\n");
4650 cpu->running = 0;
4651 return 0;
4652 }
4653 cpu->cd.x86.r[X86_R_BP] = tmp;
4654 } else if (op == 0xca || op == 0xcb) { /* RET far */
4655 uint64_t tmp2;
4656 uint16_t old_tr = cpu->cd.x86.tr;
4657 if (op == 0xca)
4658 imm = read_imm(&instr, &newpc, 16);
4659 else
4660 imm = 0;
4661 if (!x86_pop(cpu, &tmp, mode))
4662 return 0;
4663 if (!x86_pop(cpu, &tmp2, mode)) {
4664 fatal("TODO: pop error inside RET\n");
4665 cpu->running = 0;
4666 return 0;
4667 }
4668 cpu->cd.x86.r[X86_R_SP] = modify(cpu->cd.x86.r[X86_R_SP],
4669 cpu->cd.x86.r[X86_R_SP] + imm);
4670 reload_segment_descriptor(cpu, X86_S_CS, tmp2, &newpc);
4671 if (cpu->cd.x86.tr == old_tr)
4672 newpc = tmp;
4673 } else if (op == 0xcc) { /* INT3 */
4674 cpu->pc = newpc;
4675 return x86_interrupt(cpu, 3, 0);
4676 } else if (op == 0xcd) { /* INT */
4677 imm = read_imm(&instr, &newpc, 8);
4678 cpu->pc = newpc;
4679 return x86_interrupt(cpu, imm, 0);
4680 } else if (op == 0xcf) { /* IRET */
4681 uint64_t tmp2, tmp3;
4682 uint16_t old_tr = cpu->cd.x86.tr;
4683 if (!x86_pop(cpu, &tmp, mode))
4684 return 0;
4685 if (!x86_pop(cpu, &tmp2, mode))
4686 return 0;
4687 if (!x86_pop(cpu, &tmp3, mode))
4688 return 0;
4689 debug("{ iret to 0x%04x:0x%08x }\n", (int)tmp2,(int)tmp);
4690 tmp2 &= 0xffff;
4691 /* TODO: only affect some bits? */
4692 if (mode == 16)
4693 cpu->cd.x86.rflags = (cpu->cd.x86.rflags & ~0xffff)
4694 | (tmp3 & 0xffff);
4695 else
4696 cpu->cd.x86.rflags = tmp3;
4697 /*
4698 * In protected mode, if we're switching back from, say, an
4699 * interrupt handler, then we should pop the old ss:esp too:
4700 */
4701 if (PROTECTED_MODE && (tmp2 & X86_PL_MASK) >
4702 (cpu->cd.x86.s[X86_S_CS] & X86_PL_MASK)) {
4703 uint64_t old_ss, old_esp;
4704 if (!x86_pop(cpu, &old_esp, mode))
4705 return 0;
4706 if (!x86_pop(cpu, &old_ss, mode))
4707 return 0;
4708 old_ss &= 0xffff;
4709
4710 printf(": : : BEFORE tmp=%016llx tmp2=%016llx tmp3=%016llx\n",
4711 (long long)tmp, (long long)tmp2, (long long)tmp3);
4712 /* x86_cpu_register_dump(cpu, 1, 1); */
4713
4714 reload_segment_descriptor(cpu, X86_S_SS, old_ss,
4715 &newpc);
4716 cpu->cd.x86.r[X86_R_SP] = old_esp;
4717
4718 /* printf(": : : AFTER\n");
4719 x86_cpu_register_dump(cpu, 1, 1); */
4720
4721 /* AFTER popping ss, check that the pl of
4722 the popped ss is the same as tmp2 (the new
4723 pl in cs)! */
4724 if ((old_ss & X86_PL_MASK) != (tmp2 & X86_PL_MASK))
4725 fatal("WARNING: iret: popped ss' pl = %i,"
4726 " different from cs' pl = %i\n",
4727 (int)(old_ss & X86_PL_MASK),
4728 (int)(tmp2 & X86_PL_MASK));
4729 }
4730 reload_segment_descriptor(cpu, X86_S_CS, tmp2, &newpc);
4731 if (cpu->cd.x86.tr == old_tr)
4732 newpc = tmp;
4733 } else if (op >= 0xd0 && op <= 0xd3) {
4734 int n = 1;
4735 instr_orig = instr;
4736 success = modrm(cpu, MODRM_READ, mode, mode67,
4737 op&1? 0 : MODRM_EIGHTBIT, &instr, &newpc, &op1, &op2);
4738 if (!success)
4739 return 0;
4740 if (op >= 0xd2)
4741 n = cpu->cd.x86.r[X86_R_CX];
4742 x86_shiftrotate(cpu, &op1, (*instr_orig >> 3) & 0x7,
4743 n, op&1? mode : 8);
4744 success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4745 op&1? 0 : MODRM_EIGHTBIT, &instr_orig, NULL, &op1, &op2);
4746 if (!success)
4747 return 0;
4748 } else if (op == 0xd4) { /* AAM */
4749 int al = cpu->cd.x86.r[X86_R_AX] & 0xff;
4750 /* al should be in the range 0..81 */
4751 int high;
4752 imm = read_imm(&instr, &newpc, 8);
4753 if (imm == 0) {
4754 fatal("[ x86: \"aam 0\" ]\n");
4755 cpu->running = 0;
4756 } else {
4757 high = al / imm;
4758 al %= imm;
4759 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] &
4760 ~0xffff) | al | ((high & 0xff) << 8);
4761 x86_calc_flags(cpu, cpu->cd.x86.r[X86_R_AX],
4762 0, 8, CALCFLAGS_OP_XOR);
4763 }
4764 } else if (op == 0xd5) { /* AAD */
4765 int al = cpu->cd.x86.r[X86_R_AX] & 0xff;
4766 int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
4767 imm = read_imm(&instr, &newpc, 8);
4768 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & ~0xffff)
4769 | ((al + 10*ah) & 0xff);
4770 x86_calc_flags(cpu, cpu->cd.x86.r[X86_R_AX],
4771 0, 8, CALCFLAGS_OP_XOR);
4772 } else if (op == 0xd7) { /* XLAT */
4773 uint64_t addr = cpu->cd.x86.r[X86_R_BX];
4774 if (mode == 16)
4775 addr &= 0xffff;
4776 addr += (cpu->cd.x86.r[X86_R_AX] & 0xff);
4777 if (!x86_load(cpu, addr, &tmp, 1))
4778 return 0;
4779 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & ~0xff)
4780 | (tmp & 0xff);
4781 } else if (op == 0xd9) {
4782 int subop = (*instr >> 3) & 7;
4783 imm = *instr;
4784 if (subop == 5) { /* FLDCW mem16 */
4785 if (!modrm(cpu, MODRM_READ, 16, mode67, 0, &instr,
4786 &newpc, &op1, &op2))
4787 return 0;
4788 cpu->cd.x86.fpu_cw = op1;
4789 } else if (subop == 7) { /* FSTCW mem16 */
4790 op1 = cpu->cd.x86.fpu_cw;
4791 if (!modrm(cpu, MODRM_WRITE_RM, 16, mode67, 0, &instr,
4792 &newpc, &op1, &op2))
4793 return 0;
4794 } else {
4795 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4796 quiet_mode = 0;
4797 x86_cpu_disassemble_instr(cpu, really_orig_instr,
4798 1 | omode, 0, 0);
4799 cpu->running = 0;
4800 }
4801 } else if (op == 0xdb) {
4802 imm = *instr;
4803 if (imm == 0xe2) { /* FCLEX */
4804 read_imm(&instr, &newpc, 8);
4805 /* TODO: actually clear exceptions */
4806 } else if (imm == 0xe3) { /* FINIT */
4807 read_imm(&instr, &newpc, 8);
4808 /* TODO: actually init? */
4809 } else if (imm == 0xe4) { /* FSETPM */
4810 read_imm(&instr, &newpc, 8);
4811 } else {
4812 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4813 quiet_mode = 0;
4814 x86_cpu_disassemble_instr(cpu, really_orig_instr,
4815 1 | omode, 0, 0);
4816 cpu->running = 0;
4817 }
4818 } else if (op == 0xdd) {
4819 int subop = (*instr >> 3) & 7;
4820 imm = *instr;
4821 if (subop == 7) { /* FSTSW mem16 */
4822 op1 = cpu->cd.x86.fpu_sw;
4823 if (!modrm(cpu, MODRM_WRITE_RM, 16, mode67, 0, &instr,
4824 &newpc, &op1, &op2))
4825 return 0;
4826 } else {
4827 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4828 quiet_mode = 0;
4829 x86_cpu_disassemble_instr(cpu, really_orig_instr,
4830 1 | omode, 0, 0);
4831 cpu->running = 0;
4832 }
4833 } else if (op == 0xdf) {
4834 imm = *instr;
4835 if (imm == 0xe0) { /* FSTSW */
4836 read_imm(&instr, &newpc, 8);
4837 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] &
4838 ~0xffff) | (cpu->cd.x86.fpu_sw & 0xffff);
4839 } else {
4840 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4841 quiet_mode = 0;
4842 x86_cpu_disassemble_instr(cpu, really_orig_instr,
4843 1 | omode, 0, 0);
4844 cpu->running = 0;
4845 }
4846 } else if (op == 0xe4 || op == 0xe5 /* IN imm,AL or AX/EAX */
4847 || op == 0x6c || op == 0x6d) { /* INSB or INSW/INSD */
4848 unsigned char databuf[8];
4849 int port_nr, ins = 0, len = 1, dir = 1;
4850 if (op == 0x6c || op == 0x6d) {
4851 port_nr = cpu->cd.x86.r[X86_R_DX] & 0xffff;
4852 ins = 1;
4853 } else
4854 port_nr = read_imm(&instr, &newpc, 8);
4855 if (op & 1)
4856 len = mode/8;
4857 if (cpu->cd.x86.rflags & X86_FLAGS_DF)
4858 dir = -1;
4859 do {
4860 cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE+port_nr,
4861 &databuf[0], len, MEM_READ, CACHE_NONE | PHYSICAL);
4862
4863 if (ins) {
4864 uint64_t addr = cpu->cd.x86.r[X86_R_DI];
4865 uint32_t value = databuf[0] + (databuf[1] << 8)
4866 + (databuf[2] << 16) + (databuf[3] << 24);
4867 if (mode67 == 16)
4868 addr &= 0xffff;
4869 if (mode67 == 32)
4870 addr &= 0xffffffff;
4871 cpu->cd.x86.cursegment = X86_S_ES;
4872 if (!x86_store(cpu, addr, value, len))
4873 return 0;
4874
4875 /* Advance (e)di: */
4876 if (mode67 == 16)
4877 cpu->cd.x86.r[X86_R_DI] =
4878 (cpu->cd.x86.r[X86_R_DI] & ~0xffff)
4879 | ((cpu->cd.x86.r[X86_R_DI]+len*dir)
4880 & 0xffff);
4881 else {
4882 cpu->cd.x86.r[X86_R_DI] += len*dir;
4883 if (mode67 == 32)
4884 cpu->cd.x86.r[X86_R_DI] &=
4885 0xffffffff;
4886 }
4887
4888 if (rep) {
4889 /* Decrement ecx: */
4890 if (mode67 == 16)
4891 cpu->cd.x86.r[X86_R_CX] =
4892 (cpu->cd.x86.r[X86_R_CX] &
4893 ~0xffff) | ((cpu->cd.x86.r[
4894 X86_R_CX] - 1) & 0xffff);
4895 else {
4896 cpu->cd.x86.r[X86_R_CX] --;
4897 cpu->cd.x86.r[X86_R_CX] &=
4898 0xffffffff;
4899 }
4900 if (mode67 == 16 && (cpu->cd.x86.r[
4901 X86_R_CX] & 0xffff) == 0)
4902 rep = 0;
4903 if (mode67 != 16 &&
4904 cpu->cd.x86.r[X86_R_CX] == 0)
4905 rep = 0;
4906 }
4907 } else {
4908 if (len == 1)
4909 cpu->cd.x86.r[X86_R_AX] =
4910 (cpu->cd.x86.r[X86_R_AX] &
4911 ~0xff) | databuf[0];
4912 else if (len == 2)
4913 cpu->cd.x86.r[X86_R_AX] =
4914 (cpu->cd.x86.r[X86_R_AX] & ~0xffff)
4915 | databuf[0] | (databuf[1] << 8);
4916 else if (len == 4)
4917 cpu->cd.x86.r[X86_R_AX] = databuf[0] |
4918 (databuf[1] << 8) | (databuf[2]
4919 << 16) | (databuf[3] << 24);
4920 }
4921 } while (rep);
4922 } else if (op == 0xe6 || op == 0xe7 /* OUT imm,AL or AX/EAX */
4923 || op == 0x6e || op == 0x6f) { /* OUTSB or OUTSW/OUTSD */
4924 unsigned char databuf[8];
4925 int port_nr, outs = 0, len = 1, dir = 1;
4926 if (op == 0x6e || op == 0x6f) {
4927 port_nr = cpu->cd.x86.r[X86_R_DX] & 0xffff;
4928 outs = 1;
4929 } else
4930 port_nr = read_imm(&instr, &newpc, 8);
4931 if (op & 1)
4932 len = mode/8;
4933 if (cpu->cd.x86.rflags & X86_FLAGS_DF)
4934 dir = -1;
4935 do {
4936 if (outs) {
4937 int i;
4938 uint64_t addr = cpu->cd.x86.r[X86_R_DI];
4939 uint64_t value;
4940 if (mode67 == 16)
4941 addr &= 0xffff;
4942 if (mode67 == 32)
4943 addr &= 0xffffffff;
4944 cpu->cd.x86.cursegment = X86_S_ES;
4945 if (!x86_load(cpu, addr, &value, len))
4946 return 0;
4947
4948 /* Advance (e)di: */
4949 if (mode67 == 16)
4950 cpu->cd.x86.r[X86_R_DI] =
4951 (cpu->cd.x86.r[X86_R_DI] & ~0xffff)
4952 | ((cpu->cd.x86.r[X86_R_DI]+len*dir)
4953 & 0xffff);
4954 else {
4955 cpu->cd.x86.r[X86_R_DI] += len*dir;
4956 if (mode67 == 32)
4957 cpu->cd.x86.r[X86_R_DI] &=
4958 0xffffffff;
4959 }
4960
4961 for (i=0; i<8; i++)
4962 databuf[i] = value >> (i*8);
4963
4964 if (rep) {
4965 /* Decrement ecx: */
4966 if (mode67 == 16)
4967 cpu->cd.x86.r[X86_R_CX] =
4968 (cpu->cd.x86.r[X86_R_CX] &
4969 ~0xffff) | ((cpu->cd.x86.r[
4970 X86_R_CX] - 1) & 0xffff);
4971 else {
4972 cpu->cd.x86.r[X86_R_CX] --;
4973 cpu->cd.x86.r[X86_R_CX] &=
4974 0xffffffff;
4975 }
4976 if (mode67 == 16 && (cpu->cd.x86.r[
4977 X86_R_CX] & 0xffff) == 0)
4978 rep = 0;
4979 if (mode67 != 16 &&
4980 cpu->cd.x86.r[X86_R_CX] == 0)
4981 rep = 0;
4982 }
4983 } else {
4984 int i;
4985 for (i=0; i<8; i++)
4986 databuf[i] = cpu->cd.x86.r[X86_R_AX]
4987 >> (i*8);
4988 }
4989
4990 cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE+port_nr,
4991 &databuf[0], len, MEM_WRITE, CACHE_NONE | PHYSICAL);
4992 } while (rep);
4993 } else if (op == 0xe8 || op == 0xe9) { /* CALL/JMP near */
4994 imm = read_imm(&instr, &newpc, mode);
4995 if (mode == 16)
4996 imm = (int16_t)imm;
4997 if (mode == 32)
4998 imm = (int32_t)imm;
4999 if (op == 0xe8) {
5000 if (!x86_push(cpu, newpc, mode))
5001 return 0;
5002 }
5003 newpc += imm;
5004 } else if (op == 0xea) { /* JMP seg:ofs */
5005 uint16_t old_tr = cpu->cd.x86.tr;
5006 imm = read_imm(&instr, &newpc, mode);
5007 imm2 = read_imm(&instr, &newpc, 16);
5008 reload_segment_descriptor(cpu, X86_S_CS, imm2, &newpc);
5009 if (cpu->cd.x86.tr == old_tr)
5010 newpc = imm;
5011 } else if ((op >= 0xe0 && op <= 0xe3) || op == 0xeb) { /* LOOP,JMP */
5012 int perform_jump = 0;
5013 imm = read_imm(&instr, &newpc, 8);
5014 switch (op) {
5015 case 0xe0: /* loopnz */
5016 case 0xe1: /* loopz */
5017 case 0xe2: /* loop */
5018 /* NOTE: address size attribute, not operand size? */
5019 if (mode67 == 16)
5020 cpu->cd.x86.r[X86_R_CX] = (~0xffff &
5021 cpu->cd.x86.r[X86_R_CX]) |
5022 ((cpu->cd.x86.r[X86_R_CX] - 1) & 0xffff);
5023 else
5024 cpu->cd.x86.r[X86_R_CX] --;
5025 if (mode67 == 16 && (cpu->cd.x86.r[X86_R_CX] &
5026 0xffff) != 0)
5027 perform_jump = 1;
5028 if (mode67 == 32 && cpu->cd.x86.r[X86_R_CX] != 0)
5029 perform_jump = 1;
5030 if (op == 0xe0 && cpu->cd.x86.rflags & X86_FLAGS_ZF)
5031 perform_jump = 0;
5032 if (op == 0xe1 && (!cpu->cd.x86.rflags & X86_FLAGS_ZF))
5033 perform_jump = 0;
5034 break;
5035 case 0xe3: /* jcxz/jecxz */
5036 if (mode67 == 16 && (cpu->cd.x86.r[X86_R_CX] & 0xffff)
5037 == 0)
5038 perform_jump = 1;
5039 if (mode67 != 16 && (cpu->cd.x86.r[X86_R_CX] &
5040 0xffffffffULL) == 0)
5041 perform_jump = 1;
5042 break;
5043 case 0xeb: /* jmp */
5044 perform_jump = 1;
5045 break;
5046 }
5047 if (perform_jump)
5048 newpc += (signed char)imm;
5049 } else if (op == 0xec || op == 0xed) { /* IN DX,AL or AX/EAX */
5050 unsigned char databuf[8];
5051 cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE +
5052 (cpu->cd.x86.r[X86_R_DX] & 0xffff), &databuf[0],
5053 op == 0xec? 1 : (mode/8), MEM_READ, CACHE_NONE | PHYSICAL);
5054 if (op == 0xec)
5055 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] &
5056 ~0xff) | databuf[0];
5057 else if (op == 0xed && mode == 16)
5058 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] &
5059 ~0xffff) | databuf[0] | (databuf[1] << 8);
5060 else if (op == 0xed && mode == 32)
5061 cpu->cd.x86.r[X86_R_AX] = databuf[0] |
5062 (databuf[1] << 8) | (databuf[2] << 16) |
5063 (databuf[3] << 24);
5064 } else if (op == 0xee || op == 0xef) { /* OUT DX,AL or AX/EAX */
5065 unsigned char databuf[8];
5066 databuf[0] = cpu->cd.x86.r[X86_R_AX];
5067 if (op == 0xef) {
5068 databuf[1] = cpu->cd.x86.r[X86_R_AX] >> 8;
5069 if (mode >= 32) {
5070 databuf[2] = cpu->cd.x86.r[X86_R_AX] >> 16;
5071 databuf[3] = cpu->cd.x86.r[X86_R_AX] >> 24;
5072 }
5073 }
5074 cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE +
5075 (cpu->cd.x86.r[X86_R_DX] & 0xffff), &databuf[0],
5076 op == 0xee? 1 : (mode/8), MEM_WRITE, CACHE_NONE | PHYSICAL);
5077 } else if (op == 0xf4) { /* HLT */
5078 cpu->cd.x86.halted = 1;
5079 } else if (op == 0xf5) { /* CMC */
5080 cpu->cd.x86.rflags ^= X86_FLAGS_CF;
5081 } else if (op == 0xf8) { /* CLC */
5082 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
5083 } else if (op == 0xf9) { /* STC */
5084 cpu->cd.x86.rflags |= X86_FLAGS_CF;
5085 } else if (op == 0xfa) { /* CLI */
5086 cpu->cd.x86.rflags &= ~X86_FLAGS_IF;
5087 } else if (op == 0xfb) { /* STI */
5088 cpu->cd.x86.rflags |= X86_FLAGS_IF;
5089 } else if (op == 0xfc) { /* CLD */
5090 cpu->cd.x86.rflags &= ~X86_FLAGS_DF;
5091 } else if (op == 0xfd) { /* STD */
5092 cpu->cd.x86.rflags |= X86_FLAGS_DF;
5093 } else if (op == 0xf6 || op == 0xf7) { /* MUL, DIV etc */
5094 uint64_t res;
5095 int unsigned_op = 1;
5096 switch ((*instr >> 3) & 0x7) {
5097 case 0: /* test */
5098 success = modrm(cpu, MODRM_READ, mode, mode67,
5099 op == 0xf6? MODRM_EIGHTBIT : 0, &instr,
5100 &newpc, &op1, &op2);
5101 if (!success)
5102 return 0;
5103 op2 = read_imm(&instr, &newpc, op==0xf6? 8 : mode);
5104 op1 &= op2;
5105 x86_calc_flags(cpu, op1, 0, op==0xf6? 8 : mode,
5106 CALCFLAGS_OP_XOR);
5107 break;
5108 case 2: /* not */
5109 case 3: /* neg */
5110 instr_orig = instr;
5111 success = modrm(cpu, MODRM_READ, mode, mode67,
5112 op == 0xf6? MODRM_EIGHTBIT : 0, &instr,
5113 &newpc, &op1, &op2);
5114 if (!success)
5115 return 0;
5116 switch ((*instr_orig >> 3) & 0x7) {
5117 case 2: op1 ^= 0xffffffffffffffffULL; break;
5118 case 3: x86_calc_flags(cpu, 0, op1,
5119 op == 0xf6? 8 : mode, CALCFLAGS_OP_SUB);
5120 op1 = 0 - op1;
5121 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
5122 if (op1 != 0)
5123 cpu->cd.x86.rflags |= X86_FLAGS_CF;
5124 break;
5125 }
5126 success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
5127 op == 0xf6? MODRM_EIGHTBIT : 0, &instr_orig,
5128 NULL, &op1, &op2);
5129 if (!success)
5130 return 0;
5131 break;
5132 case 5: /* imul */
5133 unsigned_op = 0;
5134 case 4: /* mul */
5135 success = modrm(cpu, MODRM_READ, mode, mode67,
5136 op == 0xf6? MODRM_EIGHTBIT : 0, &instr,
5137 &newpc, &op1, &op2);
5138 if (!success)
5139 return 0;
5140 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
5141 cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
5142 if (op == 0xf6) {
5143 if (unsigned_op)
5144 res = (cpu->cd.x86.r[X86_R_AX] & 0xff)
5145 * (op1 & 0xff);
5146 else
5147 res = (int16_t)(signed char)(cpu->cd.
5148 x86.r[X86_R_AX] & 0xff) * (int16_t)
5149 (signed char)(op1 & 0xff);
5150 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[
5151 X86_R_AX] & ~0xffff) | (res & 0xffff);
5152 if ((res & 0xffff) >= 0x100)
5153 cpu->cd.x86.rflags |= X86_FLAGS_CF
5154 | X86_FLAGS_OF;
5155 } else if (mode == 16) {
5156 if (unsigned_op)
5157 res = (cpu->cd.x86.r[X86_R_AX] & 0xffff)
5158 * (op1 & 0xffff);
5159 else
5160 res = (int32_t)(int16_t)(cpu->cd.x86.r[
5161 X86_R_AX] & 0xffff) * (int32_t)
5162 (int16_t)(op1 & 0xffff);
5163 cpu->cd.x86.r[X86_R_AX] = modify(cpu->
5164 cd.x86.r[X86_R_AX], res & 0xffff);
5165 cpu->cd.x86.r[X86_R_DX] = modify(cpu->cd.x86
5166 .r[X86_R_DX], (res>>16) & 0xffff);
5167 if ((res & 0xffffffff) >= 0x10000)
5168 cpu->cd.x86.rflags |= X86_FLAGS_CF
5169 | X86_FLAGS_OF;
5170 } else if (mode == 32) {
5171 if (unsigned_op)
5172 res = (cpu->cd.x86.r[X86_R_AX] &
5173 0xffffffff) * (op1 & 0xffffffff);
5174 else
5175 res = (int64_t)(int32_t)(cpu->cd.x86.r[
5176 X86_R_AX] & 0xffffffff) * (int64_t)
5177 (int32_t)(op1 & 0xffffffff);
5178 cpu->cd.x86.r[X86_R_AX] = res & 0xffffffff;
5179 cpu->cd.x86.r[X86_R_DX] = (res >> 32) &
5180 0xffffffff;
5181 if (res >= 0x100000000ULL)
5182 cpu->cd.x86.rflags |= X86_FLAGS_CF
5183 | X86_FLAGS_OF;
5184 }
5185 break;
5186 case 7: /* idiv */
5187 unsigned_op = 0;
5188 case 6: /* div */
5189 success = modrm(cpu, MODRM_READ, mode, mode67,
5190 op == 0xf6? MODRM_EIGHTBIT : 0, &instr,
5191 &newpc, &op1, &op2);
5192 if (!success)
5193 return 0;
5194 if (op1 == 0) {
5195 fatal("TODO: division by zero\n");
5196 cpu->running = 0;
5197 break;
5198 }
5199 if (op == 0xf6) {
5200 int al, ah;
5201 if (unsigned_op) {
5202 al = (cpu->cd.x86.r[X86_R_AX] &
5203 0xffff) / op1;
5204 ah = (cpu->cd.x86.r[X86_R_AX] &
5205 0xffff) % op1;
5206 } else {
5207 al = (int16_t)(cpu->cd.x86.r[
5208 X86_R_AX] & 0xffff) / (int16_t)op1;
5209 ah = (int16_t)(cpu->cd.x86.r[
5210 X86_R_AX] & 0xffff) % (int16_t)op1;
5211 }
5212 cpu->cd.x86.r[X86_R_AX] = modify(
5213 cpu->cd.x86.r[X86_R_AX], (ah<<8) + al);
5214 } else if (mode == 16) {
5215 uint64_t a = (cpu->cd.x86.r[X86_R_AX] & 0xffff)
5216 + ((cpu->cd.x86.r[X86_R_DX] & 0xffff)<<16);
5217 uint32_t ax, dx;
5218 if (unsigned_op) {
5219 ax = a / op1, dx = a % op1;
5220 } else {
5221 ax = (int32_t)a / (int32_t)op1;
5222 dx = (int32_t)a % (int32_t)op1;
5223 }
5224 cpu->cd.x86.r[X86_R_AX] = modify(
5225 cpu->cd.x86.r[X86_R_AX], ax);
5226 cpu->cd.x86.r[X86_R_DX] = modify(
5227 cpu->cd.x86.r[X86_R_DX], dx);
5228 } else if (mode == 32) {
5229 uint64_t a = (cpu->cd.x86.r[X86_R_AX] &
5230 0xffffffffULL) + ((cpu->cd.x86.r[
5231 X86_R_DX] & 0xffffffffULL) << 32);
5232 uint32_t eax, edx;
5233 if (unsigned_op) {
5234 eax = (uint64_t)a / (uint32_t)op1;
5235 edx = (uint64_t)a % (uint32_t)op1;
5236 } else {
5237 eax = (int64_t)a / (int32_t)op1;
5238 edx = (int64_t)a % (int32_t)op1;
5239 }
5240 cpu->cd.x86.r[X86_R_AX] = eax;
5241 cpu->cd.x86.r[X86_R_DX] = edx;
5242 }
5243 break;
5244 default:
5245 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
5246 quiet_mode = 0;
5247 x86_cpu_disassemble_instr(cpu,
5248 really_orig_instr, 1|omode, 0, 0);
5249 cpu->running = 0;
5250 }
5251 } else if (op == 0xfe || op == 0xff) { /* INC, DEC etc */
5252 int old_cf;
5253 switch ((*instr >> 3) & 0x7) {
5254 case 0:
5255 case 1: instr_orig = instr;
5256 success = modrm(cpu, MODRM_READ, mode, mode67,
5257 op == 0xfe? MODRM_EIGHTBIT : 0, &instr,
5258 &newpc, &op1, &op2);
5259 if (!success)
5260 return 0;
5261 old_cf = cpu->cd.x86.rflags & X86_FLAGS_CF;
5262 switch ((*instr_orig >> 3) & 0x7) {
5263 case 0: x86_calc_flags(cpu, op1, 1, op==0xfe? 8 : mode,
5264 CALCFLAGS_OP_ADD);
5265 op1 ++;
5266 break; /* inc */
5267 case 1: x86_calc_flags(cpu, op1, 1, op==0xfe? 8 : mode,
5268 CALCFLAGS_OP_SUB);
5269 op1 --;
5270 break; /* dec */
5271 }
5272 success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
5273 op == 0xfe? MODRM_EIGHTBIT : 0, &instr_orig,
5274 NULL, &op1, &op2);
5275 if (!success)
5276 return 0;
5277 /* preserve CF: */
5278 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
5279 cpu->cd.x86.rflags |= old_cf;
5280 break;
5281 case 2: if (op == 0xfe) {
5282 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op,
5283 *instr);
5284 quiet_mode = 0;
5285 x86_cpu_disassemble_instr(cpu,
5286 really_orig_instr, 1|omode, 0, 0);
5287 cpu->running = 0;
5288 } else {
5289 success = modrm(cpu, MODRM_READ, mode, mode67,
5290 0, &instr, &newpc, &op1, &op2);
5291 if (!success)
5292 return 0;
5293 /* Push return [E]IP */
5294 if (!x86_push(cpu, newpc, mode))
5295 return 0;
5296 newpc = op1;
5297 }
5298 break;
5299 case 3: if (op == 0xfe) {
5300 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op,
5301 *instr);
5302 quiet_mode = 0;
5303 x86_cpu_disassemble_instr(cpu,
5304 really_orig_instr, 1|omode, 0, 0);
5305 cpu->running = 0;
5306 } else {
5307 uint16_t old_tr = cpu->cd.x86.tr;
5308 uint64_t tmp1, tmp2;
5309 success = modrm(cpu, MODRM_READ, mode, mode67,
5310 MODRM_JUST_GET_ADDR, &instr,
5311 &newpc, &op1, &op2);
5312 if (!success)
5313 return 0;
5314 /* Load a far address from op1: */
5315 if (!x86_load(cpu, op1, &tmp1, mode/8))
5316 return 0;
5317 if (!x86_load(cpu, op1 + (mode/8), &tmp2, 2))
5318 return 0;
5319 /* Push return CS:[E]IP */
5320 if (!x86_push(cpu, cpu->cd.x86.s[X86_S_CS],
5321 mode))
5322 return 0;
5323 if (!x86_push(cpu, newpc, mode)) {
5324 fatal("TODO: push failed, call "
5325 "far indirect?\n");
5326 cpu->running = 0;
5327 return 0;
5328 }
5329 reload_segment_descriptor(cpu, X86_S_CS,
5330 tmp2, &newpc);
5331 if (cpu->cd.x86.tr == old_tr)
5332 newpc = tmp1;
5333 }
5334 break;
5335 case 4: if (op == 0xfe) {
5336 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op,
5337 *instr);
5338 quiet_mode = 0;
5339 x86_cpu_disassemble_instr(cpu,
5340 really_orig_instr, 1|omode, 0, 0);
5341 cpu->running = 0;
5342 } else {
5343 success = modrm(cpu, MODRM_READ, mode, mode67,
5344 0, &instr, &newpc, &op1, &op2);
5345 if (!success)
5346 return 0;
5347 newpc = op1;
5348 }
5349 break;
5350 case 5: if (op == 0xfe) {
5351 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op,
5352 *instr);
5353 quiet_mode = 0;
5354 x86_cpu_disassemble_instr(cpu,
5355 really_orig_instr, 1|omode, 0, 0);
5356 cpu->running = 0;
5357 } else {
5358 uint16_t old_tr = cpu->cd.x86.tr;
5359 uint64_t tmp1, tmp2;
5360 success = modrm(cpu, MODRM_READ, mode, mode67,
5361 MODRM_JUST_GET_ADDR, &instr,
5362 &newpc, &op1, &op2);
5363 if (!success)
5364 return 0;
5365 /* Load a far address from op1: */
5366 if (!x86_load(cpu, op1, &tmp1, mode/8))
5367 return 0;
5368 if (!x86_load(cpu, op1 + (mode/8), &tmp2, 2))
5369 return 0;
5370 reload_segment_descriptor(cpu, X86_S_CS,
5371 tmp2, &newpc);
5372 if (cpu->cd.x86.tr == old_tr)
5373 newpc = tmp1;
5374 }
5375 break;
5376 case 6: if (op == 0xfe) {
5377 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op,
5378 *instr);
5379 quiet_mode = 0;
5380 x86_cpu_disassemble_instr(cpu,
5381 really_orig_instr, 1|omode, 0, 0);
5382 cpu->running = 0;
5383 } else {
5384 instr_orig = instr;
5385 success = modrm(cpu, MODRM_READ, mode, mode67,
5386 0, &instr, &newpc, &op1, &op2);
5387 if (!success)
5388 return 0;
5389 if (!x86_push(cpu, op1, mode))
5390 return 0;
5391 }
5392 break;
5393 default:
5394 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
5395 quiet_mode = 0;
5396 x86_cpu_disassemble_instr(cpu,
5397 really_orig_instr, 1|omode, 0, 0);
5398 cpu->running = 0;
5399 }
5400 } else {
5401 fatal("x86_cpu_run_instr(): unimplemented opcode 0x%02x"
5402 " at ", op); print_csip(cpu); fatal("\n");
5403 quiet_mode = 0;
5404 x86_cpu_disassemble_instr(cpu,
5405 really_orig_instr, 1|omode, 0, 0);
5406 cpu->running = 0;
5407 return 0;
5408 }
5409
5410 /* Wrap-around and update [E]IP: */
5411 cpu->pc = newpc & (((uint64_t)1 << (cpu->cd.x86.descr_cache[
5412 X86_S_CS].default_op_size)) - 1);
5413
5414 if (trap_flag_was_set) {
5415 if (REAL_MODE) {
5416 x86_interrupt(cpu, 1, 0);
5417 } else {
5418 fatal("TRAP flag in protected mode?\n");
5419 cpu->running = 0;
5420 }
5421 }
5422
5423 return 1;
5424 }
5425
5426
5427 #define CPU_RUN x86_cpu_run
5428 #define CPU_RINSTR x86_cpu_run_instr
5429 #define CPU_RUN_X86
5430 #include "cpu_run.c"
5431 #undef CPU_RINSTR
5432 #undef CPU_RUN_X86
5433 #undef CPU_RUN
5434
5435
5436 /*
5437 * x86_cpu_family_init():
5438 *
5439 * Fill in the cpu_family struct for x86.
5440 */
5441 int x86_cpu_family_init(struct cpu_family *fp)
5442 {
5443 fp->name = "x86";
5444 fp->cpu_new = x86_cpu_new;
5445 fp->list_available_types = x86_cpu_list_available_types;
5446 fp->register_match = x86_cpu_register_match;
5447 fp->disassemble_instr = x86_cpu_disassemble_instr;
5448 fp->register_dump = x86_cpu_register_dump;
5449 fp->run = x86_cpu_run;
5450 fp->dumpinfo = x86_cpu_dumpinfo;
5451 /* fp->show_full_statistics = x86_cpu_show_full_statistics; */
5452 /* fp->tlbdump = x86_cpu_tlbdump; */
5453 fp->interrupt = x86_cpu_interrupt;
5454 fp->interrupt_ack = x86_cpu_interrupt_ack;
5455 return 1;
5456 }
5457
5458 #endif /* ENABLE_X86 */

  ViewVC Help
Powered by ViewVC 1.1.26