/[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 (12 years, 5 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);