/[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 6 - (hide annotations)
Mon Oct 8 16:18:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 154695 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.772 2005/06/04 12:02:16 debug Exp $
20050428	Disabling the "-fmove-all-movables" option in the configure
		script, because it causes the compile to fail on OpenBSD/sgi.
20050502	Minor updates.
20050503	Removing the WRT54G mode (it was bogus anyway), and adding a
		comment about Windows NT for MIPS in doc/experiments.html.
		Minor updates to the x86 instruction decoding.
20050504	Adding some more x86 instructions.
		Adding support for reading files from ISO9660 CDROMs (including
		gzipped files). It's an ugly hack, but it seems to work.
		Various other minor updates (dev_vga.c, pc_bios.c etc).
20050505	Some more x86-related updates.
		Beginning (what I hope will be) a major code cleanup phase.
		"bootris" (an x86 bootsector) runs :-)
20050506	Adding some more x86 instructions.
20050507	tmpnam => mkstemp.
		Working on a hack to allow VGA charcells to be shown even when
		not running with X11.
		Adding more x86 instructions.
20050508	x86 32-bit SIB addressing fix, and more instructions.
20050509	Adding more x86 instructions.
20050510	Minor documentation updates, and other updates (x86 stuff etc.)
20050511	More x86-related updates.
20050513	Various updates, mostly x86-related. (Trying to fix flag 
		calculation, factoring out the ugly shift/rotate code, and
		some other things.)
20050514	Adding support for loading some old i386 a.out executables.
		Finally beginning the cleanup of machine/PROM/bios dependant
		info.
		Some minor documentation updates.
		Trying to clean up ARCBIOS stuff a little.
20050515	Trying to make it possible to actually use more than one disk
		type per machine (floppy, ide, scsi).
		Trying to clean up the kbd vs PROM console stuff. (For PC and
		ARC emulation modes, mostly.)
		Beginning to add an 8259 interrupt controller, and connecting
		it to the x86 emulation.
20050516	The first x86 interrupts seem to work (keyboard stuff).
		Adding a 8253/8254 programmable interval timer skeleton.
		FreeDOS now reaches a command prompt and can be interacted
		with.
20050517	After some bugfixes, MS-DOS also (sometimes) reaches a
		command prompt now.
		Trying to fix the pckbc to work with MS-DOS' keyb.com, but no
		success yet.
20050518	Adding a simple 32-bit x86 MMU skeleton.
20050519	Some more work on the x86 stuff. (Beginning the work on paging,
		and various other fixes).
20050520	More updates. Working on dev_vga (4-bit graphics modes), adding
		40 columns support to the PC bios emulation.
		Trying to add support for resizing windows when switching
		between graphics modes.
20050521	Many more x86-related updates.
20050522	Correcting the initial stack pointer's sign-extension for
		ARCBIOS emulation (thanks to Alec Voropay for noticing the
		error).
		Continuing on the cleanup (ARCBIOS etc).
		dev_vga updates.
20050523	More x86 updates: trying to add some support for protected mode
		interrupts (via gate descriptors) and many other fixes.
		More ARCBIOS cleanup.
		Adding a device flag which indicates that reads cause no
		side-effects. (Useful for the "dump" command in the debugger,
		and other things.)
		Adding support for directly starting up x86 ELFs, skipping the
		bootloader stage. (Most ELFs, however, are not suitable for
		this.)
20050524	Adding simple 32-bit x86 TSS task switching, but no privilege
		level support yet.
		More work on dev_vga. A small "Copper bars" demo works. :-)
		Adding support for Trap Flag (single-step exceptions), at least
		in real mode, and various other x86-related fixes.
20050525	Adding a new disk image prefix (gH;S;) which can be used to
		override the default nr of heads and sectors per track.
20050527	Various bug fixes, more work on the x86 mode (stack change on
		interrupts between different priv.levels), and some minor
		documentation updates.
20050528	Various fixes (x86 stuff).
20050529	More x86 fixes. An OpenBSD/i386 bootfloppy reaches userland
		and can be interacted with (although there are problems with
		key repetition). NetBSD/i386 triggers a serious CISC-related
		problem: instruction fetches across page boundaries, where
		the later part isn't actually part of the instruction.
20050530	Various minor updates. (Documentation updates, etc.)
20050531	Adding some experimental code (experiments/new_test_*) which
		could be useful for dynamic (but not binary) translation in
		the future.
20050602	Adding a dummy ARM skeleton.
		Fixing the pckbc key repetition problem (by adding release
		scancodes for all keypresses).
20050603	Minor updates for the next release.
20050604	Release testing. Minor updates.

==============  RELEASE 0.3.3  ==============

20050604	There'll probably be a 0.3.3.1 release soon, with some very
		very tiny updates.


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

  ViewVC Help
Powered by ViewVC 1.1.26