/[gxemul]/trunk/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 /trunk/src/cpu_x86.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations)
Mon Oct 8 16:18:27 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 154404 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.815 2005/06/27 23:04:35 debug Exp $
20050617	Experimenting some more with netbooting OpenBSD/sgi. Adding
		a hack which allows emulated ethernet networks to be
		distributed across multiple emulator processes.
20050618	Minor updates (documentation, dummy YAMON emulation, etc).
20050620	strcpy/strcat -> strlcpy/strlcat updates.
		Some more progress on evbmips (Malta).
20050621	Adding a section to doc/configfiles.html about ethernet
		emulation across multiple hosts.
		Beginning the work on the ARM translation engine (using the
		dynamic-but-not-binary translation method).
		Fixing a bintrans bug: 0x9fc00000 should always be treated as
		PROM area, just as 0xbfc00000 is.
		Minor progress on Malta emulation (the PCI-ISA bus).
20050622	NetBSD/evbmips can now be installed (using another emulated
		machine) and run (including userland and so on). :-)
		Spliting up the bintrans haddr_entry field into two (one for
		read, one for write). Probably not much of a speed increase,
		though.
		Updating some NetBSD 2.0 -> 2.0.2 in the documentation.
20050623	Minor updates (documentation, the TODO file, etc).
		gzipped kernels are now always automagically gunzipped when
		loaded.
20050624	Adding a dummy Playstation Portable (PSP) mode, just barely
		enough to run Hello World (in weird colors :-).
		Removing the -b command line option; old bintrans is enabled
		by default instead. It makes more sense.
		Trying to finally fix the non-working performance measurement
		thing (instr/second etc).
20050625	Continuing on the essential basics for ARM emulation. Two
		instructions seem to work, a branch and a simple "mov". (The
		mov arguments are not correct yet.) Performance is definitely
		reasonable.
		Various other minor updates.
		Adding the ARM "bl" instruction.
		Adding support for combining multiple ARM instructions into one
		function call. ("mov" + "mov" is the only one implemented so
		far, but it seems to work.)
		Cleaning up some IP32 interrupt things (crime/mace); disabling
		the PS/2 keyboard controller on IP32, so that NetBSD/sgimips
		boots into userland again.
20050626	Finally! NetBSD/sgimips netboots. Adding instructions to
		doc/guestoses.html on how to set up an nfs server etc.
		Various other minor fixes.
		Playstation Portable ".pbp" files can now be used directly.
		(The ELF part of the .pbp is extracted transparently.)
		Converting some sprintf -> snprintf.
		Adding some more instructions to the ARM disassembler.
20050627	More ARM updates. Adding some simple ldr(b), str(b),
		cmps, and conditional branch instructions, enough to run
		a simple Hello World program.
		All ARM instructions are now inlined/generated for all possible
		condition codes.
		Adding add and sub, and more load/store instructions.
		Removing dummy files: cpu_alpha.c, cpu_hppa.c, and cpu_sparc.c.
		Some minor documentation updates; preparing for a 0.3.4
		release. Updating some URLs.

==============  RELEASE 0.3.4  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26