/[gxemul]/upstream/0.3.3.1/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

Annotation of /upstream/0.3.3.1/src/cpu_x86.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26