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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (hide annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 87369 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

==============  RELEASE 0.4.1  ==============


1 dpavlin 14 /*
2 dpavlin 24 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 dpavlin 14 *
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 28 * $Id: cpu_x86.c,v 1.17 2006/07/16 13:32:26 debug Exp $
29 dpavlin 14 *
30     * x86 (and amd64) CPU emulation.
31     *
32     *
33     * TODO: Pretty much everything that has to do with 64-bit and 32-bit modes,
34     * memory translation, flag bits, and so on.
35     *
36     * See http://www.amd.com/us-en/Processors/DevelopWithAMD/
37     * 0,,30_2252_875_7044,00.html for more info on AMD64.
38     *
39     * http://www.cs.ucla.edu/~kohler/class/04f-aos/ref/i386/appa.htm has a
40     * nice overview of the standard i386 opcodes.
41     *
42     * HelpPC (http://members.tripod.com/~oldboard/assembly/) is also useful.
43     */
44    
45     #include <stdio.h>
46     #include <stdlib.h>
47     #include <string.h>
48     #include <ctype.h>
49    
50     #include "cpu.h"
51     #include "devices.h"
52     #include "machine.h"
53     #include "memory.h"
54     #include "misc.h"
55     #include "symbol.h"
56    
57     #define DYNTRANS_DUALMODE_32
58     /* #define DYNTRANS_32 */
59     #define DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
60     #include "tmp_x86_head.c"
61    
62    
63     static struct x86_model models[] = x86_models;
64     static char *reg_names[N_X86_REGS] = x86_reg_names;
65     static char *reg_names_bytes[8] = x86_reg_names_bytes;
66     static char *seg_names[N_X86_SEGS] = x86_seg_names;
67     static char *cond_names[N_X86_CONDS] = x86_cond_names;
68    
69     #define REP_REP 1
70     #define REP_REPNE 2
71    
72    
73     /*
74     * x86_cpu_new():
75     *
76     * Create a new x86 cpu object.
77     */
78     int x86_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine,
79     int cpu_id, char *cpu_type_name)
80     {
81     int i = 0;
82    
83     /* Try to find a match: */
84     while (models[i].model_number != 0) {
85     if (strcasecmp(cpu_type_name, models[i].name) == 0)
86     break;
87     i++;
88     }
89    
90     if (models[i].name == NULL)
91     return 0;
92    
93     cpu->memory_rw = x86_memory_rw;
94     cpu->byte_order = EMUL_LITTLE_ENDIAN;
95    
96     cpu->cd.x86.model = models[i];
97    
98 dpavlin 26 cpu->translate_v2p = x86_translate_v2p;
99 dpavlin 20
100 dpavlin 14 /* Initial startup is in 16-bit real mode: */
101     cpu->pc = 0xfff0;
102    
103     /* Initial segments: */
104     cpu->cd.x86.descr_cache[X86_S_CS].valid = 1;
105     cpu->cd.x86.descr_cache[X86_S_CS].default_op_size = 16;
106     cpu->cd.x86.descr_cache[X86_S_CS].access_rights = 0x93;
107     cpu->cd.x86.descr_cache[X86_S_CS].base = 0xf0000; /* ffff0000 */
108     cpu->cd.x86.descr_cache[X86_S_CS].limit = 0xffff;
109     cpu->cd.x86.descr_cache[X86_S_CS].descr_type = DESCR_TYPE_CODE;
110     cpu->cd.x86.descr_cache[X86_S_CS].readable = 1;
111     cpu->cd.x86.descr_cache[X86_S_CS].writable = 1;
112     cpu->cd.x86.descr_cache[X86_S_CS].granularity = 0;
113     cpu->cd.x86.s[X86_S_CS] = 0xf000;
114 dpavlin 20 cpu->cd.x86.cursegment = X86_S_CS;
115 dpavlin 14
116     cpu->cd.x86.idtr = 0;
117     cpu->cd.x86.idtr_limit = 0x3ff;
118    
119     cpu->cd.x86.rflags = 0x0002;
120     if (cpu->cd.x86.model.model_number == X86_MODEL_8086)
121     cpu->cd.x86.rflags |= 0xf000;
122    
123 dpavlin 20 cpu->is_32bit = (cpu->cd.x86.model.model_number < X86_MODEL_AMD64)?
124     1 : 0;
125    
126     if (cpu->is_32bit) {
127 dpavlin 28 cpu->run_instr = x8632_run_instr;
128 dpavlin 20 cpu->update_translation_table = x8632_update_translation_table;
129     cpu->invalidate_translation_caches =
130     x8632_invalidate_translation_caches;
131     cpu->invalidate_code_translation =
132     x8632_invalidate_code_translation;
133     } else {
134 dpavlin 28 cpu->run_instr = x86_run_instr;
135 dpavlin 20 cpu->update_translation_table = x86_update_translation_table;
136     cpu->invalidate_translation_caches =
137     x86_invalidate_translation_caches;
138     cpu->invalidate_code_translation =
139     x86_invalidate_code_translation;
140     }
141    
142 dpavlin 14 /* Only show name and caches etc for CPU nr 0 (in SMP machines): */
143     if (cpu_id == 0) {
144     debug("%s", cpu->name);
145     }
146    
147     return 1;
148     }
149    
150    
151     /*
152     * x86_cpu_dumpinfo():
153     */
154     void x86_cpu_dumpinfo(struct cpu *cpu)
155     {
156     debug(", currently in %s mode", PROTECTED_MODE? "protected" : "real");
157     debug("\n");
158     }
159    
160    
161     /*
162     * x86_cpu_list_available_types():
163     *
164     * Print a list of available x86 CPU types.
165     */
166     void x86_cpu_list_available_types(void)
167     {
168     int i = 0, j;
169    
170     while (models[i].model_number != 0) {
171     debug("%s", models[i].name);
172    
173 dpavlin 22 for (j=0; j<10-(int)strlen(models[i].name); j++)
174 dpavlin 14 debug(" ");
175     i++;
176     if ((i % 6) == 0 || models[i].name == NULL)
177     debug("\n");
178     }
179     }
180    
181    
182     /*
183     * x86_cpu_register_dump():
184     *
185     * Dump cpu registers in a relatively readable format.
186     * (gprs and coprocs are mostly useful for the MIPS version of this function.)
187     */
188     void x86_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
189     {
190     char *symbol;
191     uint64_t offset;
192     int i, x = cpu->cpu_id;
193    
194 dpavlin 24 if (LONG_MODE) {
195     /* 64-bit long mode: */
196 dpavlin 14 symbol = get_symbol_name(&cpu->machine->symbol_context,
197     cpu->pc, &offset);
198    
199 dpavlin 24 debug("cpu%i: rip = 0x%016"PRIx64, x, cpu->pc);
200 dpavlin 14 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
201    
202 dpavlin 24 for (i=0; i<N_X86_REGS; i++) {
203     if ((i & 1) == 0)
204     debug("cpu%i:", x);
205     debug(" r%s = 0x%016"PRIx64, reg_names[i],
206     (uint64_t)cpu->cd.x86.r[i]);
207     if ((i & 1) == 1)
208     debug("\n");
209     }
210     } else if (REAL_MODE) {
211     /* 16-bit real-mode: */
212     debug("cpu%i: cs:ip = 0x%04"PRIx16":0x%04"PRIx16"\n", x,
213     cpu->cd.x86.s[X86_S_CS], (uint16_t)cpu->pc);
214    
215     debug("cpu%i: ax = 0x%04"PRIx16" bx = 0x%04"PRIx16
216     " cx = 0x%04"PRIx16" dx = 0x%04"PRIx16"\n", x,
217     (uint16_t)cpu->cd.x86.r[X86_R_AX],
218     (uint16_t)cpu->cd.x86.r[X86_R_BX],
219     (uint16_t)cpu->cd.x86.r[X86_R_CX],
220     (uint16_t)cpu->cd.x86.r[X86_R_DX]);
221     debug("cpu%i: si = 0x%04"PRIx16" di = 0x%04"PRIx16
222     " bp = 0x%04"PRIx16" sp = 0x%04"PRIx16"\n", x,
223     (uint16_t)cpu->cd.x86.r[X86_R_SI],
224     (uint16_t)cpu->cd.x86.r[X86_R_DI],
225     (uint16_t)cpu->cd.x86.r[X86_R_BP],
226     (uint16_t)cpu->cd.x86.r[X86_R_SP]);
227     debug("cpu%i: ds = 0x%04"PRIx16" es = 0x%04"PRIx16
228     " ss = 0x%04"PRIx16" flags = 0x%04"PRIx16"\n", x,
229     (uint16_t)cpu->cd.x86.s[X86_S_DS],
230     (uint16_t)cpu->cd.x86.s[X86_S_ES],
231     (uint16_t)cpu->cd.x86.s[X86_S_SS],
232     (uint16_t)cpu->cd.x86.rflags);
233 dpavlin 14 } else {
234 dpavlin 24 /* 32-bit protected mode: */
235 dpavlin 14 symbol = get_symbol_name(&cpu->machine->symbol_context,
236     cpu->pc, &offset);
237    
238 dpavlin 24 debug("cpu%i: eip=0x%08"PRIx32, x, (uint32_t)cpu->pc);
239 dpavlin 14 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
240    
241 dpavlin 24 debug("cpu%i: eax=0x%08"PRIx32" ebx=0x%08"PRIx32
242     " ecx=0x%08"PRIx32" edx=0x%08"PRIx32"\n", x,
243     (uint32_t)cpu->cd.x86.r[X86_R_AX],
244     (uint32_t)cpu->cd.x86.r[X86_R_BX],
245     (uint32_t)cpu->cd.x86.r[X86_R_CX],
246     (uint32_t)cpu->cd.x86.r[X86_R_DX]);
247     debug("cpu%i: esi=0x%08"PRIx32" edi=0x%08"PRIx32
248     " ebp=0x%08"PRIx32" esp=0x%08"PRIx32"\n", x,
249     (uint32_t)cpu->cd.x86.r[X86_R_SI],
250     (uint32_t)cpu->cd.x86.r[X86_R_DI],
251     (uint32_t)cpu->cd.x86.r[X86_R_BP],
252     (uint32_t)cpu->cd.x86.r[X86_R_SP]);
253 dpavlin 14 }
254    
255     if (coprocs != 0) {
256     for (i=0; i<6; i++) {
257     debug("cpu%i: %s=0x%04x (", x, seg_names[i],
258     cpu->cd.x86.s[i]);
259     if (cpu->cd.x86.descr_cache[i].valid) {
260     debug("base=0x%08x, limit=0x%08x, ",
261     (int)cpu->cd.x86.descr_cache[i].base,
262     (int)cpu->cd.x86.descr_cache[i].limit);
263     debug("%s", cpu->cd.x86.descr_cache[i].
264     descr_type==DESCR_TYPE_CODE?"CODE":"DATA");
265     debug(", %i-bit", cpu->cd.x86.descr_cache[i].
266     default_op_size);
267     debug(", %s%s", cpu->cd.x86.descr_cache[i].
268     readable? "R" : "-", cpu->cd.x86.
269     descr_cache[i].writable? "W" : "-");
270     } else
271     debug("invalid");
272     debug(")\n");
273     }
274     debug("cpu%i: gdtr=0x%08llx:0x%04x idtr=0x%08llx:0x%04x "
275     " ldtr=0x%08x:0x%04x\n", x, (long long)cpu->cd.x86.gdtr,
276     (int)cpu->cd.x86.gdtr_limit, (long long)cpu->cd.x86.idtr,
277     (int)cpu->cd.x86.idtr_limit, (long long)cpu->cd.x86.
278     ldtr_base, (int)cpu->cd.x86.ldtr_limit);
279     debug("cpu%i: pic1: irr=0x%02x ier=0x%02x isr=0x%02x "
280     "base=0x%02x\n", x, cpu->machine->isa_pic_data.pic1->irr,
281     cpu->machine->isa_pic_data.pic1->ier,
282     cpu->machine->isa_pic_data.pic1->isr,
283     cpu->machine->isa_pic_data.pic1->irq_base);
284     debug("cpu%i: pic2: irr=0x%02x ier=0x%02x isr=0x%02x "
285     "base=0x%02x\n", x, cpu->machine->isa_pic_data.pic2->irr,
286     cpu->machine->isa_pic_data.pic2->ier,
287     cpu->machine->isa_pic_data.pic2->isr,
288     cpu->machine->isa_pic_data.pic2->irq_base);
289     } else if (PROTECTED_MODE) {
290     /* Protected mode: */
291 dpavlin 24 debug("cpu%i: cs=0x%04"PRIx16" ds=0x%04"PRIx16" es=0x%04"
292     PRIx16" fs=0x%04"PRIx16" gs=0x%04"PRIx16" ss=0x%04"
293     PRIx16"\n", x, (uint16_t)cpu->cd.x86.s[X86_S_CS],
294     (uint16_t)cpu->cd.x86.s[X86_S_DS],
295     (uint16_t)cpu->cd.x86.s[X86_S_ES],
296     (uint16_t)cpu->cd.x86.s[X86_S_FS],
297     (uint16_t)cpu->cd.x86.s[X86_S_GS],
298     (uint16_t)cpu->cd.x86.s[X86_S_SS]);
299 dpavlin 14 }
300    
301     if (PROTECTED_MODE) {
302     /* Protected mode: */
303 dpavlin 24 debug("cpu%i: cr0=0x%08"PRIx32" cr2=0x%08"PRIx32" cr3=0x%08"
304     PRIx32" eflags=0x%08"PRIx32"\n", x,
305     (uint32_t)cpu->cd.x86.cr[0], (uint32_t)cpu->cd.x86.cr[2],
306     (uint32_t)cpu->cd.x86.cr[3], (uint32_t)cpu->cd.x86.rflags);
307     debug("cpu%i: tr = 0x%04"PRIx16" (base=0x%"PRIx64", limit=0x"
308     PRIx32")\n", x, (uint16_t)cpu->cd.x86.tr, (uint64_t)
309     cpu->cd.x86.tr_base, (uint32_t)cpu->cd.x86.tr_limit);
310 dpavlin 14 }
311     }
312    
313    
314     /*
315     * x86_cpu_register_match():
316     */
317     void x86_cpu_register_match(struct machine *m, char *name,
318     int writeflag, uint64_t *valuep, int *mr)
319     {
320     int cpunr = 0;
321     int r;
322    
323     /* CPU number: TODO */
324    
325     if (strcasecmp(name, "pc") == 0 || strcasecmp(name, "rip") == 0) {
326     if (writeflag) {
327     m->cpus[cpunr]->pc = *valuep;
328     m->cpus[cpunr]->cd.x86.halted = 0;
329     } else
330     *valuep = m->cpus[cpunr]->pc;
331     *mr = 1;
332     return;
333     }
334     if (strcasecmp(name, "ip") == 0) {
335     if (writeflag) {
336     m->cpus[cpunr]->pc = (m->cpus[cpunr]->pc & ~0xffff)
337     | (*valuep & 0xffff);
338     m->cpus[cpunr]->cd.x86.halted = 0;
339     } else
340     *valuep = m->cpus[cpunr]->pc & 0xffff;
341     *mr = 1;
342     return;
343     }
344     if (strcasecmp(name, "eip") == 0) {
345     if (writeflag) {
346     m->cpus[cpunr]->pc = *valuep;
347     m->cpus[cpunr]->cd.x86.halted = 0;
348     } else
349     *valuep = m->cpus[cpunr]->pc & 0xffffffffULL;
350     *mr = 1;
351     return;
352     }
353    
354     if (strcasecmp(name, "rflags") == 0) {
355     if (writeflag)
356     m->cpus[cpunr]->cd.x86.rflags = *valuep;
357     else
358     *valuep = m->cpus[cpunr]->cd.x86.rflags;
359     *mr = 1;
360     return;
361     }
362     if (strcasecmp(name, "eflags") == 0) {
363     if (writeflag)
364     m->cpus[cpunr]->cd.x86.rflags = (m->cpus[cpunr]->
365     cd.x86.rflags & ~0xffffffffULL) | (*valuep &
366     0xffffffffULL);
367     else
368     *valuep = m->cpus[cpunr]->cd.x86.rflags & 0xffffffffULL;
369     *mr = 1;
370     return;
371     }
372     if (strcasecmp(name, "flags") == 0) {
373     if (writeflag)
374     m->cpus[cpunr]->cd.x86.rflags = (m->cpus[cpunr]->
375     cd.x86.rflags & ~0xffff) | (*valuep & 0xffff);
376     else
377     *valuep = m->cpus[cpunr]->cd.x86.rflags & 0xffff;
378     *mr = 1;
379     return;
380     }
381    
382     /* 8-bit low: */
383     for (r=0; r<4; r++)
384     if (strcasecmp(name, reg_names_bytes[r]) == 0) {
385     if (writeflag)
386     m->cpus[cpunr]->cd.x86.r[r] =
387     (m->cpus[cpunr]->cd.x86.r[r] & ~0xff)
388     | (*valuep & 0xff);
389     else
390     *valuep = m->cpus[cpunr]->cd.x86.r[r] & 0xff;
391     *mr = 1;
392     return;
393     }
394    
395     /* 8-bit high: */
396     for (r=0; r<4; r++)
397     if (strcasecmp(name, reg_names_bytes[r+4]) == 0) {
398     if (writeflag)
399     m->cpus[cpunr]->cd.x86.r[r] =
400     (m->cpus[cpunr]->cd.x86.r[r] & ~0xff00)
401     | ((*valuep & 0xff) << 8);
402     else
403     *valuep = (m->cpus[cpunr]->cd.x86.r[r] >>
404     8) & 0xff;
405     *mr = 1;
406     return;
407     }
408    
409     /* 16-, 32-, 64-bit registers: */
410     for (r=0; r<N_X86_REGS; r++) {
411     /* 16-bit: */
412     if (r<8 && strcasecmp(name, reg_names[r]) == 0) {
413     if (writeflag)
414     m->cpus[cpunr]->cd.x86.r[r] =
415     (m->cpus[cpunr]->cd.x86.r[r] & ~0xffff)
416     | (*valuep & 0xffff);
417     else
418     *valuep = m->cpus[cpunr]->cd.x86.r[r] & 0xffff;
419     *mr = 1;
420     return;
421     }
422    
423     /* 32-bit: */
424     if (r<8 && (name[0]=='e' || name[0]=='E') &&
425     strcasecmp(name+1, reg_names[r]) == 0) {
426     if (writeflag)
427     m->cpus[cpunr]->cd.x86.r[r] =
428     *valuep & 0xffffffffULL;
429     else
430     *valuep = m->cpus[cpunr]->cd.x86.r[r] &
431     0xffffffffULL;
432     *mr = 1;
433     return;
434     }
435    
436     /* 64-bit: */
437     if ((name[0]=='r' || name[0]=='R') &&
438     strcasecmp(name+1, reg_names[r]) == 0) {
439     if (writeflag)
440     m->cpus[cpunr]->cd.x86.r[r] = *valuep;
441     else
442     *valuep = m->cpus[cpunr]->cd.x86.r[r];
443     *mr = 1;
444     return;
445     }
446     }
447    
448     /* segment names: */
449     for (r=0; r<N_X86_SEGS; r++) {
450     if (strcasecmp(name, seg_names[r]) == 0) {
451     if (writeflag)
452     m->cpus[cpunr]->cd.x86.s[r] =
453     (m->cpus[cpunr]->cd.x86.s[r] & ~0xffff)
454     | (*valuep & 0xffff);
455     else
456     *valuep = m->cpus[cpunr]->cd.x86.s[r] & 0xffff;
457     *mr = 1;
458     return;
459     }
460     }
461    
462     /* control registers: (TODO: 32- vs 64-bit on AMD64?) */
463     if (strncasecmp(name, "cr", 2) == 0 && atoi(name+2) < N_X86_CREGS ) {
464     int r = atoi(name+2);
465     if (writeflag)
466     m->cpus[cpunr]->cd.x86.cr[r] = *valuep;
467     else
468     *valuep = m->cpus[cpunr]->cd.x86.cr[r];
469     *mr = 1;
470     return;
471     }
472     }
473    
474    
475     /* Macro which modifies the lower part of a value, or the entire value,
476     depending on 'mode': */
477     #define modify(old,new) ( \
478     mode==16? ( \
479     ((old) & ~0xffff) + ((new) & 0xffff) \
480     ) : ((new) & 0xffffffffULL) )
481    
482     /* "volatile" here, because some versions of gcc with -O3 on i386 are buggy */
483     #define HEXPRINT(x,n) { volatile int j; for (j=0; j<(n); j++) \
484     debug("%02x",(x)[j]); }
485     #define HEXSPACES(i) { int j; j = (i)>10? 10:(i); while (j++<10) debug(" "); \
486     debug(" "); }
487     #define SPACES HEXSPACES(ilen)
488    
489    
490     static uint32_t read_imm_common(unsigned char **instrp, uint64_t *ilenp,
491     int len, int printflag)
492     {
493     uint32_t imm;
494     unsigned char *instr = *instrp;
495    
496     if (len == 8)
497     imm = instr[0];
498     else if (len == 16)
499     imm = instr[0] + (instr[1] << 8);
500     else
501     imm = instr[0] + (instr[1] << 8) +
502     (instr[2] << 16) + (instr[3] << 24);
503    
504     if (printflag)
505     HEXPRINT(instr, len / 8);
506    
507     if (ilenp != NULL)
508     (*ilenp) += len/8;
509    
510     (*instrp) += len/8;
511     return imm;
512     }
513    
514    
515     static uint32_t read_imm_and_print(unsigned char **instrp, uint64_t *ilenp,
516     int mode)
517     {
518     return read_imm_common(instrp, ilenp, mode, 1);
519     }
520    
521    
522 dpavlin 22 uint32_t read_imm(unsigned char **instrp, uint64_t *newpcp,
523 dpavlin 14 int mode)
524     {
525     return read_imm_common(instrp, newpcp, mode, 0);
526     }
527    
528    
529 dpavlin 22 void print_csip(struct cpu *cpu)
530 dpavlin 14 {
531     fatal("0x%04x:", cpu->cd.x86.s[X86_S_CS]);
532     if (PROTECTED_MODE)
533     fatal("0x%llx", (long long)cpu->pc);
534     else
535     fatal("0x%04x", (int)cpu->pc);
536     }
537    
538    
539     /*
540 dpavlin 24 * x86_cpu_tlbdump():
541     *
542     * Called from the debugger to dump the TLB in a readable format.
543     * x is the cpu number to dump, or -1 to dump all CPUs.
544     *
545     * If rawflag is nonzero, then the TLB contents isn't formated nicely,
546     * just dumped.
547     */
548     void x86_cpu_tlbdump(struct machine *m, int x, int rawflag)
549     {
550     }
551    
552    
553     /*
554     * x86_cpu_gdb_stub():
555     *
556     * Execute a "remote GDB" command. Returns a newly allocated response string
557     * on success, NULL on failure.
558     */
559     char *x86_cpu_gdb_stub(struct cpu *cpu, char *cmd)
560     {
561     fatal("x86_cpu_gdb_stub(): TODO\n");
562     return NULL;
563     }
564    
565    
566     /*
567 dpavlin 14 * x86_cpu_interrupt():
568     *
569     * NOTE: Interacting with the 8259 PIC is done in src/machine.c.
570     */
571     int x86_cpu_interrupt(struct cpu *cpu, uint64_t nr)
572     {
573     if (cpu->machine->md_interrupt != NULL)
574     cpu->machine->md_interrupt(cpu->machine, cpu, nr, 1);
575     else {
576     fatal("x86_cpu_interrupt(): no md_interrupt()?\n");
577     return 1;
578     }
579    
580     return 1;
581     }
582    
583    
584     /*
585     * x86_cpu_interrupt_ack():
586     *
587     * NOTE: Interacting with the 8259 PIC is done in src/machine.c.
588     */
589     int x86_cpu_interrupt_ack(struct cpu *cpu, uint64_t nr)
590     {
591     if (cpu->machine->md_interrupt != NULL)
592     cpu->machine->md_interrupt(cpu->machine, cpu, nr, 0);
593     else {
594     fatal("x86_cpu_interrupt(): no md_interrupt()?\n");
595     return 1;
596     }
597    
598     return 1;
599     }
600    
601    
602     /* (NOTE: Don't use the lowest 3 bits in these defines) */
603     #define RELOAD_TR 0x1000
604     #define RELOAD_LDTR 0x1008
605    
606    
607     /*
608     * x86_task_switch():
609     *
610     * Save away current state into the current task state segment, and
611     * load the new state from the new task.
612     *
613     * TODO: 16-bit TSS, etc. And clean up all of this :)
614     *
615     * TODO: Link word. AMD64 stuff. And lots more.
616     */
617     void x86_task_switch(struct cpu *cpu, int new_tr, uint64_t *curpc)
618     {
619     unsigned char old_descr[8];
620     unsigned char new_descr[8];
621     uint32_t value, ofs;
622     int i;
623     unsigned char buf[4];
624    
625     fatal("x86_task_switch():\n");
626     cpu->pc = *curpc;
627    
628     if (!cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr + cpu->cd.x86.tr,
629     old_descr, sizeof(old_descr), MEM_READ, NO_SEGMENTATION)) {
630     fatal("x86_task_switch(): TODO: 1\n");
631     cpu->running = 0;
632     return;
633     }
634    
635     /* Check the busy bit, and then clear it: */
636     if (!(old_descr[5] & 0x02)) {
637     fatal("x86_task_switch(): TODO: switching FROM a non-BUSY"
638     " TSS descriptor?\n");
639     cpu->running = 0;
640     return;
641     }
642     old_descr[5] &= ~0x02;
643     if (!cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr + cpu->cd.x86.tr,
644     old_descr, sizeof(old_descr), MEM_WRITE, NO_SEGMENTATION)) {
645     fatal("x86_task_switch(): TODO: could not clear busy bit\n");
646     cpu->running = 0;
647     return;
648     }
649    
650     x86_cpu_register_dump(cpu, 1, 1);
651    
652     /* Set the task-switched bit in CR0: */
653     cpu->cd.x86.cr[0] |= X86_CR0_TS;
654    
655     /* Save away all the old registers: */
656     #define WRITE_VALUE { buf[0]=value; buf[1]=value>>8; buf[2]=value>>16; \
657     buf[3]=value>>24; cpu->memory_rw(cpu, cpu->mem, \
658     cpu->cd.x86.tr_base + ofs, buf, sizeof(buf), MEM_WRITE, \
659     NO_SEGMENTATION); }
660    
661     ofs = 0x1c; value = cpu->cd.x86.cr[3]; WRITE_VALUE;
662     ofs = 0x20; value = cpu->pc; WRITE_VALUE;
663     ofs = 0x24; value = cpu->cd.x86.rflags; WRITE_VALUE;
664     for (i=0; i<N_X86_REGS; i++) {
665     ofs = 0x28+i*4; value = cpu->cd.x86.r[i]; WRITE_VALUE;
666     }
667     for (i=0; i<6; i++) {
668     ofs = 0x48+i*4; value = cpu->cd.x86.s[i]; WRITE_VALUE;
669     }
670    
671     fatal("-------\n");
672    
673     if ((cpu->cd.x86.tr & 0xfffc) == 0) {
674     fatal("TODO: x86_task_switch(): task switch, but old TR"
675     " was 0?\n");
676     cpu->running = 0;
677     return;
678     }
679    
680     if (!cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr + new_tr,
681     new_descr, sizeof(new_descr), MEM_READ, NO_SEGMENTATION)) {
682     fatal("x86_task_switch(): TODO: 1\n");
683     cpu->running = 0;
684     return;
685     }
686     if (new_descr[5] & 0x02) {
687     fatal("x86_task_switch(): TODO: switching TO an already BUSY"
688     " TSS descriptor?\n");
689     cpu->running = 0;
690     return;
691     }
692    
693     reload_segment_descriptor(cpu, RELOAD_TR, new_tr, NULL);
694    
695     if (cpu->cd.x86.tr_limit < 0x67)
696 dpavlin 24 fatal("WARNING: tr_limit = 0x%"PRIx16", must be at least "
697     "0x67!\n", (uint16_t)cpu->cd.x86.tr_limit);
698 dpavlin 14
699     /* Read new registers: */
700     #define READ_VALUE { cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.tr_base + \
701     ofs, buf, sizeof(buf), MEM_READ, NO_SEGMENTATION); \
702     value = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24); }
703    
704     ofs = 0x1c; READ_VALUE; cpu->cd.x86.cr[3] = value;
705     ofs = 0x20; READ_VALUE; cpu->pc = value;
706     ofs = 0x24; READ_VALUE; cpu->cd.x86.rflags = value;
707     for (i=0; i<N_X86_REGS; i++) {
708     ofs = 0x28+i*4; READ_VALUE; cpu->cd.x86.r[i] = value;
709     }
710     for (i=0; i<6; i++) {
711     ofs = 0x48+i*4; READ_VALUE;
712     reload_segment_descriptor(cpu, i, value, NULL);
713     }
714     ofs = 0x60; READ_VALUE; value &= 0xffff;
715     reload_segment_descriptor(cpu, RELOAD_LDTR, value, NULL);
716    
717     if ((cpu->cd.x86.s[X86_S_CS] & X86_PL_MASK) !=
718     (cpu->cd.x86.s[X86_S_SS] & X86_PL_MASK))
719     fatal("WARNING: rpl in CS and SS differ!\n");
720    
721     if ((cpu->cd.x86.s[X86_S_CS] & X86_PL_MASK) == X86_RING3 &&
722     !(cpu->cd.x86.rflags & X86_FLAGS_IF))
723     fatal("WARNING (?): switching to userland task, but interrupts"
724     " are disabled?\n");
725    
726     x86_cpu_register_dump(cpu, 1, 1);
727     fatal("-------\n");
728    
729     *curpc = cpu->pc;
730    
731     /* cpu->machine->instruction_trace = 1; */
732     /* cpu->running = 0; */
733     }
734    
735    
736     /*
737     * reload_segment_descriptor():
738     *
739     * Loads base, limit and other settings from the Global Descriptor Table into
740     * segment descriptors.
741     *
742     * This function can also be used to reload the TR (task register).
743     *
744     * And also to do a task switch, or jump into a trap handler etc.
745     * (Perhaps this function should be renamed.)
746     */
747     void reload_segment_descriptor(struct cpu *cpu, int segnr, int selector,
748     uint64_t *curpcp)
749     {
750     int res, i, readable, writable, granularity, descr_type;
751     int segment = 1, rpl, orig_selector = selector;
752     unsigned char descr[8];
753     char *table_name = "GDT";
754 dpavlin 22 uint64_t base, limit, table_base;
755     int64_t table_limit;
756 dpavlin 14
757     if (segnr > 0x100) /* arbitrary, larger than N_X86_SEGS */
758     segment = 0;
759    
760     if (segment && (segnr < 0 || segnr >= N_X86_SEGS)) {
761     fatal("reload_segment_descriptor(): segnr = %i\n", segnr);
762     exit(1);
763     }
764    
765     if (segment && REAL_MODE) {
766     /* Real mode: */
767     cpu->cd.x86.descr_cache[segnr].valid = 1;
768     cpu->cd.x86.descr_cache[segnr].default_op_size = 16;
769     cpu->cd.x86.descr_cache[segnr].access_rights = 0x93;
770     cpu->cd.x86.descr_cache[segnr].descr_type =
771     segnr == X86_S_CS? DESCR_TYPE_CODE : DESCR_TYPE_DATA;
772     cpu->cd.x86.descr_cache[segnr].readable = 1;
773     cpu->cd.x86.descr_cache[segnr].writable = 1;
774     cpu->cd.x86.descr_cache[segnr].granularity = 0;
775     cpu->cd.x86.descr_cache[segnr].base = selector << 4;
776     cpu->cd.x86.descr_cache[segnr].limit = 0xffff;
777     cpu->cd.x86.s[segnr] = selector;
778     return;
779     }
780    
781     /*
782     * Protected mode: Load the descriptor cache from the GDT.
783     */
784    
785     table_base = cpu->cd.x86.gdtr;
786     table_limit = cpu->cd.x86.gdtr_limit;
787     if (selector & 4) {
788     table_name = "LDT";
789     /* fatal("TODO: x86 translation via LDT: 0x%04x\n",
790     selector); */
791     table_base = cpu->cd.x86.ldtr_base;
792     table_limit = cpu->cd.x86.ldtr_limit;
793     }
794    
795     /* Special case: Null-descriptor: */
796     if (segment && (selector & ~3) == 0) {
797     cpu->cd.x86.descr_cache[segnr].valid = 0;
798     cpu->cd.x86.s[segnr] = selector;
799     return;
800     }
801    
802     rpl = selector & 3;
803    
804     /* TODO: check rpl */
805    
806     selector &= ~7;
807    
808     if (selector + 7 > table_limit) {
809     fatal("TODO: selector 0x%04x outside %s limit (0x%04x)\n",
810     selector, table_name, (int)table_limit);
811     cpu->running = 0;
812     return;
813     }
814    
815     res = cpu->memory_rw(cpu, cpu->mem, table_base + selector,
816     descr, sizeof(descr), MEM_READ, NO_SEGMENTATION);
817     if (!res) {
818     fatal("reload_segment_descriptor(): TODO: "
819     "could not read the GDT\n");
820     cpu->running = 0;
821     return;
822     }
823    
824     base = descr[2] + (descr[3] << 8) + (descr[4] << 16) +
825     (descr[7] << 24);
826     limit = descr[0] + (descr[1] << 8) + ((descr[6]&15) << 16);
827    
828     descr_type = readable = writable = granularity = 0;
829     granularity = (descr[6] & 0x80)? 1 : 0;
830     if (limit == 0) {
831     fatal("WARNING: descriptor limit = 0\n");
832     limit = 0xfffff;
833     }
834     if (granularity)
835     limit = (limit << 12) | 0xfff;
836    
837     #if 0
838     printf("base = %llx\n",(long long)base);
839     for (i=0; i<8; i++)
840     fatal(" %02x", descr[i]);
841     #endif
842    
843     if (selector != 0x0000 && (descr[5] & 0x80) == 0x00) {
844     fatal("TODO: nonpresent descriptor?\n");
845     goto fail_dump;
846     }
847    
848     if (!segment) {
849     switch (segnr) {
850     case RELOAD_TR:
851     /* Check that this is indeed a TSS descriptor: */
852     if ((descr[5] & 0x15) != 0x01) {
853     fatal("TODO: load TR but entry in table is"
854     " not a TSS descriptor?\n");
855     goto fail_dump;
856     }
857    
858     /* Reload the task register: */
859     cpu->cd.x86.tr = selector;
860     cpu->cd.x86.tr_base = base;
861     cpu->cd.x86.tr_limit = limit;
862    
863     /* Mark the TSS as busy: */
864     descr[5] |= 0x02;
865     res = cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr +
866     selector, descr, sizeof(descr), MEM_WRITE,
867     NO_SEGMENTATION);
868     break;
869     case RELOAD_LDTR:
870     /* Reload the Local Descriptor Table register: */
871     cpu->cd.x86.ldtr = selector;
872     cpu->cd.x86.ldtr_base = base;
873     cpu->cd.x86.ldtr_limit = limit;
874     break;
875     }
876     return;
877     }
878    
879     if ((descr[5] & 0x18) == 0x18) {
880     descr_type = DESCR_TYPE_CODE;
881     readable = descr[5] & 0x02? 1 : 0;
882     if ((descr[5] & 0x98) != 0x98) {
883     fatal("TODO CODE\n");
884     goto fail_dump;
885     }
886     } else if ((descr[5] & 0x18) == 0x10) {
887     descr_type = DESCR_TYPE_DATA;
888     readable = 1;
889     writable = descr[5] & 0x02? 1 : 0;
890     if ((descr[5] & 0x98) != 0x90) {
891     fatal("TODO DATA\n");
892     goto fail_dump;
893     }
894     } else if (segnr == X86_S_CS && (descr[5] & 0x15) == 0x01
895     && curpcp != NULL) {
896     /* TSS */
897     x86_task_switch(cpu, selector, curpcp);
898     return;
899     } else {
900     fatal("TODO: other\n");
901     goto fail_dump;
902     }
903    
904     cpu->cd.x86.descr_cache[segnr].valid = 1;
905     cpu->cd.x86.descr_cache[segnr].default_op_size =
906     (descr[6] & 0x40)? 32 : 16;
907     cpu->cd.x86.descr_cache[segnr].access_rights = descr[5];
908     cpu->cd.x86.descr_cache[segnr].descr_type = descr_type;
909     cpu->cd.x86.descr_cache[segnr].readable = readable;
910     cpu->cd.x86.descr_cache[segnr].writable = writable;
911     cpu->cd.x86.descr_cache[segnr].granularity = granularity;
912     cpu->cd.x86.descr_cache[segnr].base = base;
913     cpu->cd.x86.descr_cache[segnr].limit = limit;
914     cpu->cd.x86.s[segnr] = orig_selector;
915     return;
916    
917     fail_dump:
918     for (i=0; i<8; i++)
919     fatal(" %02x", descr[i]);
920     cpu->running = 0;
921     }
922    
923    
924     /*
925     * x86_load():
926     *
927     * Returns same error code as memory_rw().
928     */
929     static int x86_load(struct cpu *cpu, uint64_t addr, uint64_t *data, int len)
930     {
931     unsigned char databuf[8];
932     int res;
933     uint64_t d;
934    
935     res = cpu->memory_rw(cpu, cpu->mem, addr, &databuf[0], len,
936     MEM_READ, CACHE_DATA);
937    
938     d = databuf[0];
939     if (len > 1) {
940     d += ((uint64_t)databuf[1] << 8);
941     if (len > 2) {
942     d += ((uint64_t)databuf[2] << 16);
943     d += ((uint64_t)databuf[3] << 24);
944     if (len > 4) {
945     d += ((uint64_t)databuf[4] << 32);
946     d += ((uint64_t)databuf[5] << 40);
947     d += ((uint64_t)databuf[6] << 48);
948     d += ((uint64_t)databuf[7] << 56);
949     }
950     }
951     }
952    
953     *data = d;
954     return res;
955     }
956    
957    
958     /*
959     * x86_store():
960     *
961     * Returns same error code as memory_rw().
962     */
963     static int x86_store(struct cpu *cpu, uint64_t addr, uint64_t data, int len)
964     {
965     unsigned char databuf[8];
966    
967     /* x86 is always little-endian: */
968     databuf[0] = data;
969     if (len > 1) {
970     databuf[1] = data >> 8;
971     if (len > 2) {
972     databuf[2] = data >> 16;
973     databuf[3] = data >> 24;
974     if (len > 4) {
975     databuf[4] = data >> 32;
976     databuf[5] = data >> 40;
977     databuf[6] = data >> 48;
978     databuf[7] = data >> 56;
979     }
980     }
981     }
982    
983     return cpu->memory_rw(cpu, cpu->mem, addr, &databuf[0], len,
984     MEM_WRITE, CACHE_DATA);
985     }
986    
987    
988     /*
989     * x86_write_cr():
990     *
991     * Write to a control register.
992     */
993     static void x86_write_cr(struct cpu *cpu, int r, uint64_t value)
994     {
995     uint64_t new, tmp;
996    
997     switch (r) {
998     case 0: new = cpu->cd.x86.cr[r] = value;
999     /* Warn about unimplemented bits: */
1000     tmp = new & ~(X86_CR0_PE | X86_CR0_PG);
1001     if (cpu->cd.x86.model.model_number <= X86_MODEL_80386) {
1002     if (tmp & X86_CR0_WP)
1003     fatal("WARNING: cr0 WP bit set, but this is"
1004     " not an 80486 or higher (?)\n");
1005     }
1006     tmp &= ~X86_CR0_WP;
1007     if (tmp != 0)
1008     fatal("x86_write_cr(): unimplemented cr0 bits: "
1009     "0x%08llx\n", (long long)tmp);
1010     break;
1011     case 2:
1012     case 3: new = cpu->cd.x86.cr[r] = value;
1013     break;
1014     case 4: new = cpu->cd.x86.cr[r] = value;
1015     /* Warn about unimplemented bits: */
1016     tmp = new; /* & ~(X86_CR0_PE | X86_CR0_PG); */
1017     if (tmp != 0)
1018     fatal("x86_write_cr(): unimplemented cr4 bits: "
1019     "0x%08llx\n", (long long)tmp);
1020     break;
1021     default:fatal("x86_write_cr(): write to UNIMPLEMENTED cr%i\n", r);
1022     cpu->running = 0;
1023     }
1024     }
1025    
1026    
1027     static char *ofs_string(int32_t imm)
1028     {
1029     static char buf[25];
1030     buf[0] = buf[sizeof(buf)-1] = '\0';
1031    
1032     if (imm > 32)
1033     sprintf(buf, "+0x%x", imm);
1034     else if (imm > 0)
1035     sprintf(buf, "+%i", imm);
1036     else if (imm < -32)
1037     sprintf(buf, "-0x%x", -imm);
1038     else if (imm < 0)
1039     sprintf(buf, "-%i", -imm);
1040    
1041     return buf;
1042     }
1043    
1044    
1045     static char modrm_r[65];
1046     static char modrm_rm[65];
1047     #define MODRM_READ 0
1048     #define MODRM_WRITE_RM 1
1049     #define MODRM_WRITE_R 2
1050     /* flags: */
1051     #define MODRM_EIGHTBIT 1
1052     #define MODRM_SEG 2
1053     #define MODRM_JUST_GET_ADDR 4
1054     #define MODRM_CR 8
1055     #define MODRM_DR 16
1056     #define MODRM_R_NONEIGHTBIT 32
1057     #define MODRM_RM_16BIT 64
1058    
1059    
1060     /*
1061     * modrm():
1062     *
1063     * Yuck. I have a feeling that this function will become really ugly.
1064     */
1065     static int modrm(struct cpu *cpu, int writeflag, int mode, int mode67,
1066     int flags, unsigned char **instrp, uint64_t *lenp,
1067     uint64_t *op1p, uint64_t *op2p)
1068     {
1069     uint32_t imm, imm2;
1070     uint64_t addr = 0;
1071     int mod, r, rm, res = 1, z, q = mode/8, sib, s, i, b, immlen;
1072     char *e, *f;
1073     int disasm = (op1p == NULL);
1074    
1075     /* e for data, f for addresses */
1076     e = f = "";
1077    
1078     if (disasm) {
1079     if (mode == 32)
1080     e = "e";
1081     if (mode == 64)
1082     e = "r";
1083     if (mode67 == 32)
1084     f = "e";
1085     if (mode67 == 64)
1086     f = "r";
1087     modrm_rm[0] = modrm_rm[sizeof(modrm_rm)-1] = '\0';
1088     modrm_r[0] = modrm_r[sizeof(modrm_r)-1] = '\0';
1089     }
1090    
1091     immlen = mode67;
1092     if (immlen == 64)
1093     immlen = 32;
1094    
1095     imm = read_imm_common(instrp, lenp, 8, disasm);
1096     mod = (imm >> 6) & 3; r = (imm >> 3) & 7; rm = imm & 7;
1097    
1098     if (flags & MODRM_EIGHTBIT)
1099     q = 1;
1100    
1101     /*
1102     * R/M:
1103     */
1104    
1105     switch (mod) {
1106     case 0:
1107     if (disasm) {
1108     if (mode67 >= 32) {
1109     if (rm == 5) {
1110     imm2 = read_imm_common(instrp, lenp,
1111     immlen, disasm);
1112     sprintf(modrm_rm, "[0x%x]", imm2);
1113     } else if (rm == 4) {
1114     char tmp[20];
1115     sib = read_imm_common(instrp, lenp,
1116     8, disasm);
1117     s = 1 << (sib >> 6);
1118     i = (sib >> 3) & 7;
1119     b = sib & 7;
1120     if (b == 5) { /* imm base */
1121     imm2 = read_imm_common(instrp,
1122     lenp, immlen, disasm);
1123     sprintf(tmp, ofs_string(imm2));
1124     } else
1125     sprintf(tmp, "+%s%s", f,
1126     reg_names[b]);
1127     if (i == 4)
1128     sprintf(modrm_rm, "[%s]", tmp);
1129     else if (s == 1)
1130     sprintf(modrm_rm, "[%s%s%s]",
1131     f, reg_names[i], tmp);
1132     else
1133     sprintf(modrm_rm, "[%s%s*%i%s"
1134     "]", f, reg_names[i],
1135     s, tmp);
1136     } else {
1137     sprintf(modrm_rm, "[%s%s]", f,
1138     reg_names[rm]);
1139     }
1140     } else {
1141     switch (rm) {
1142     case 0: sprintf(modrm_rm, "[bx+si]");
1143     break;
1144     case 1: sprintf(modrm_rm, "[bx+di]");
1145     break;
1146     case 2: sprintf(modrm_rm, "[bp+si]");
1147     break;
1148     case 3: sprintf(modrm_rm, "[bp+di]");
1149     break;
1150     case 4: sprintf(modrm_rm, "[si]");
1151     break;
1152     case 5: sprintf(modrm_rm, "[di]");
1153     break;
1154     case 6: imm2 = read_imm_common(instrp, lenp,
1155     immlen, disasm);
1156     sprintf(modrm_rm, "[0x%x]", imm2);
1157     break;
1158     case 7: sprintf(modrm_rm, "[bx]");
1159     break;
1160     }
1161     }
1162     } else {
1163     if (mode67 >= 32) {
1164     if (rm == 5) {
1165     addr = read_imm_common(instrp, lenp,
1166     immlen, disasm);
1167     } else if (rm == 4) {
1168     sib = read_imm_common(instrp, lenp,
1169     8, disasm);
1170     s = 1 << (sib >> 6);
1171     i = (sib >> 3) & 7;
1172     b = sib & 7;
1173     if (b == 4 &&
1174     !cpu->cd.x86.seg_override)
1175     cpu->cd.x86.cursegment=X86_S_SS;
1176     if (b == 5)
1177     addr = read_imm_common(instrp,
1178     lenp, mode67, disasm);
1179     else
1180     addr = cpu->cd.x86.r[b];
1181     if (i != 4)
1182     addr += cpu->cd.x86.r[i] * s;
1183     } else {
1184     addr = cpu->cd.x86.r[rm];
1185     }
1186     } else {
1187     switch (rm) {
1188     case 0: addr = cpu->cd.x86.r[X86_R_BX] +
1189     cpu->cd.x86.r[X86_R_SI]; break;
1190     case 1: addr = cpu->cd.x86.r[X86_R_BX] +
1191     cpu->cd.x86.r[X86_R_DI]; break;
1192     case 2: addr = cpu->cd.x86.r[X86_R_BP] +
1193     cpu->cd.x86.r[X86_R_SI];
1194     if (!cpu->cd.x86.seg_override)
1195     cpu->cd.x86.cursegment=X86_S_SS;
1196     break;
1197     case 3: addr = cpu->cd.x86.r[X86_R_BP] +
1198     cpu->cd.x86.r[X86_R_DI];
1199     if (!cpu->cd.x86.seg_override)
1200     cpu->cd.x86.cursegment=X86_S_SS;
1201     break;
1202     case 4: addr = cpu->cd.x86.r[X86_R_SI]; break;
1203     case 5: addr = cpu->cd.x86.r[X86_R_DI]; break;
1204     case 6: addr = read_imm_common(instrp, lenp,
1205     immlen, disasm); break;
1206     case 7: addr = cpu->cd.x86.r[X86_R_BX]; break;
1207     }
1208     }
1209    
1210     if (mode67 == 16)
1211     addr &= 0xffff;
1212     if (mode67 == 32)
1213     addr &= 0xffffffffULL;
1214    
1215     switch (writeflag) {
1216     case MODRM_WRITE_RM:
1217     res = x86_store(cpu, addr, *op1p, q);
1218     break;
1219     case MODRM_READ: /* read */
1220     if (flags & MODRM_JUST_GET_ADDR)
1221     *op1p = addr;
1222     else
1223     res = x86_load(cpu, addr, op1p, q);
1224     }
1225     }
1226     break;
1227     case 1:
1228     case 2:
1229     z = (mod == 1)? 8 : immlen;
1230     if (disasm) {
1231     if (mode67 >= 32) {
1232     if (rm == 4) {
1233     sib = read_imm_common(instrp, lenp,
1234     8, disasm);
1235     s = 1 << (sib >> 6);
1236     i = (sib >> 3) & 7;
1237     b = sib & 7;
1238     imm2 = read_imm_common(instrp, lenp,
1239     z, disasm);
1240     if (z == 8) imm2 = (signed char)imm2;
1241     if (i == 4)
1242     sprintf(modrm_rm, "[%s%s%s]",
1243     f, reg_names[b],
1244     ofs_string(imm2));
1245     else if (s == 1)
1246     sprintf(modrm_rm, "[%s%s%s"
1247     "%s%s]", f, reg_names[i],
1248     f, reg_names[b],
1249     ofs_string(imm2));
1250     else
1251     sprintf(modrm_rm, "[%s%s*%i+%s"
1252     "%s%s]", f, reg_names[i], s,
1253     f, reg_names[b],
1254     ofs_string(imm2));
1255     } else {
1256     imm2 = read_imm_common(instrp, lenp,
1257     z, disasm);
1258     if (z == 8) imm2 = (signed char)imm2;
1259     sprintf(modrm_rm, "[%s%s%s]", f,
1260     reg_names[rm], ofs_string(imm2));
1261     }
1262     } else
1263     switch (rm) {
1264     case 0: imm2 = read_imm_common(instrp, lenp, z, disasm);
1265     if (z == 8) imm2 = (signed char)imm2;
1266     sprintf(modrm_rm, "[bx+si%s]",ofs_string(imm2));
1267     break;
1268     case 1: imm2 = read_imm_common(instrp, lenp, z, disasm);
1269     if (z == 8) imm2 = (signed char)imm2;
1270     sprintf(modrm_rm, "[bx+di%s]",ofs_string(imm2));
1271     break;
1272     case 2: imm2 = read_imm_common(instrp, lenp, z, disasm);
1273     if (z == 8) imm2 = (signed char)imm2;
1274     sprintf(modrm_rm, "[bp+si%s]",ofs_string(imm2));
1275     break;
1276     case 3: imm2 = read_imm_common(instrp, lenp, z, disasm);
1277     if (z == 8) imm2 = (signed char)imm2;
1278     sprintf(modrm_rm, "[bp+di%s]",ofs_string(imm2));
1279     break;
1280     case 4: imm2 = read_imm_common(instrp, lenp, z, disasm);
1281     if (z == 8) imm2 = (signed char)imm2;
1282     sprintf(modrm_rm, "[si%s]", ofs_string(imm2));
1283     break;
1284     case 5: imm2 = read_imm_common(instrp, lenp, z, disasm);
1285     if (z == 8) imm2 = (signed char)imm2;
1286     sprintf(modrm_rm, "[di%s]", ofs_string(imm2));
1287     break;
1288     case 6: imm2 = read_imm_common(instrp, lenp, z, disasm);
1289     if (z == 8) imm2 = (signed char)imm2;
1290     sprintf(modrm_rm, "[bp%s]", ofs_string(imm2));
1291     break;
1292     case 7: imm2 = read_imm_common(instrp, lenp, z, disasm);
1293     if (z == 8) imm2 = (signed char)imm2;
1294     sprintf(modrm_rm, "[bx%s]", ofs_string(imm2));
1295     break;
1296     }
1297     } else {
1298     if (mode67 >= 32) {
1299     if (rm == 4) {
1300     sib = read_imm_common(instrp, lenp,
1301     8, disasm);
1302     s = 1 << (sib >> 6);
1303     i = (sib >> 3) & 7;
1304     b = sib & 7;
1305     addr = read_imm_common(instrp, lenp,
1306     z, disasm);
1307     if ((b == 4 || b == 5) &&
1308     !cpu->cd.x86.seg_override)
1309     cpu->cd.x86.cursegment=X86_S_SS;
1310     if (z == 8)
1311     addr = (signed char)addr;
1312     if (i == 4)
1313     addr = cpu->cd.x86.r[b] + addr;
1314     else
1315     addr = cpu->cd.x86.r[i] * s +
1316     cpu->cd.x86.r[b] + addr;
1317     } else {
1318     addr = read_imm_common(instrp, lenp,
1319     z, disasm);
1320     if (z == 8)
1321     addr = (signed char)addr;
1322     addr = cpu->cd.x86.r[rm] + addr;
1323     }
1324     } else {
1325     addr = read_imm_common(instrp, lenp, z, disasm);
1326     if (z == 8)
1327     addr = (signed char)addr;
1328     switch (rm) {
1329     case 0: addr += cpu->cd.x86.r[X86_R_BX]
1330     + cpu->cd.x86.r[X86_R_SI];
1331     break;
1332     case 1: addr += cpu->cd.x86.r[X86_R_BX]
1333     + cpu->cd.x86.r[X86_R_DI];
1334     break;
1335     case 2: addr += cpu->cd.x86.r[X86_R_BP]
1336     + cpu->cd.x86.r[X86_R_SI];
1337     if (!cpu->cd.x86.seg_override)
1338     cpu->cd.x86.cursegment=X86_S_SS;
1339     break;
1340     case 3: addr += cpu->cd.x86.r[X86_R_BP]
1341     + cpu->cd.x86.r[X86_R_DI];
1342     if (!cpu->cd.x86.seg_override)
1343     cpu->cd.x86.cursegment=X86_S_SS;
1344     break;
1345     case 4: addr += cpu->cd.x86.r[X86_R_SI];
1346     break;
1347     case 5: addr += cpu->cd.x86.r[X86_R_DI];
1348     break;
1349     case 6: addr += cpu->cd.x86.r[X86_R_BP];
1350     if (!cpu->cd.x86.seg_override)
1351     cpu->cd.x86.cursegment=X86_S_SS;
1352     break;
1353     case 7: addr += cpu->cd.x86.r[X86_R_BX];
1354     break;
1355     }
1356     }
1357    
1358     if (mode67 == 16)
1359     addr &= 0xffff;
1360     if (mode67 == 32)
1361     addr &= 0xffffffffULL;
1362    
1363     switch (writeflag) {
1364     case MODRM_WRITE_RM:
1365     res = x86_store(cpu, addr, *op1p, q);
1366     break;
1367     case MODRM_READ: /* read */
1368     if (flags & MODRM_JUST_GET_ADDR)
1369     *op1p = addr;
1370     else
1371     res = x86_load(cpu, addr, op1p, q);
1372     }
1373     }
1374     break;
1375     case 3:
1376     if (flags & MODRM_EIGHTBIT) {
1377     if (disasm) {
1378     strlcpy(modrm_rm, reg_names_bytes[rm],
1379     sizeof(modrm_rm));
1380     } else {
1381     switch (writeflag) {
1382     case MODRM_WRITE_RM:
1383     if (rm < 4)
1384     cpu->cd.x86.r[rm] =
1385     (cpu->cd.x86.r[rm] &
1386     ~0xff) | (*op1p & 0xff);
1387     else
1388     cpu->cd.x86.r[rm&3] = (cpu->
1389     cd.x86.r[rm&3] & ~0xff00) |
1390     ((*op1p & 0xff) << 8);
1391     break;
1392     case MODRM_READ:
1393     if (rm < 4)
1394     *op1p = cpu->cd.x86.r[rm] &
1395     0xff;
1396     else
1397     *op1p = (cpu->cd.x86.r[rm&3] &
1398     0xff00) >> 8;
1399     }
1400     }
1401     } else {
1402     if (disasm) {
1403     if (mode == 16 || flags & MODRM_RM_16BIT)
1404     strlcpy(modrm_rm, reg_names[rm],
1405     sizeof(modrm_rm));
1406     else
1407     sprintf(modrm_rm, "%s%s", e,
1408     reg_names[rm]);
1409     } else {
1410     switch (writeflag) {
1411     case MODRM_WRITE_RM:
1412     if (mode == 16 ||
1413     flags & MODRM_RM_16BIT)
1414     cpu->cd.x86.r[rm] = (
1415     cpu->cd.x86.r[rm] & ~0xffff)
1416     | (*op1p & 0xffff);
1417     else
1418     cpu->cd.x86.r[rm] =
1419     modify(cpu->cd.x86.r[rm],
1420     *op1p);
1421     break;
1422     case MODRM_READ: /* read */
1423     if (mode == 16 ||
1424     flags & MODRM_RM_16BIT)
1425     *op1p = cpu->cd.x86.r[rm]
1426     & 0xffff;
1427     else
1428     *op1p = cpu->cd.x86.r[rm];
1429     }
1430     }
1431     }
1432     break;
1433     default:
1434     fatal("modrm(): unimplemented mod %i\n", mod);
1435     exit(1);
1436     }
1437    
1438    
1439     /*
1440     * R:
1441     */
1442    
1443     if (flags & MODRM_EIGHTBIT && !(flags & MODRM_R_NONEIGHTBIT)) {
1444     if (disasm) {
1445     strlcpy(modrm_r, reg_names_bytes[r],
1446     sizeof(modrm_r));
1447     } else {
1448     switch (writeflag) {
1449     case MODRM_WRITE_R:
1450     if (r < 4)
1451     cpu->cd.x86.r[r] = (cpu->cd.x86.r[r] &
1452     ~0xff) | (*op2p & 0xff);
1453     else
1454     cpu->cd.x86.r[r&3] = (cpu->cd.x86.r[r&3]
1455     & ~0xff00) | ((*op2p & 0xff) << 8);
1456     break;
1457     case MODRM_READ:
1458     if (r < 4)
1459     *op2p = cpu->cd.x86.r[r] & 0xff;
1460     else
1461     *op2p = (cpu->cd.x86.r[r&3] &
1462     0xff00) >>8;
1463     }
1464     }
1465     } else {
1466     if (disasm) {
1467     if (flags & MODRM_SEG)
1468     strlcpy(modrm_r, seg_names[r],
1469     sizeof(modrm_r));
1470     else if (flags & MODRM_CR)
1471     sprintf(modrm_r, "cr%i", r);
1472     else if (flags & MODRM_DR)
1473     sprintf(modrm_r, "dr%i", r);
1474     else {
1475     if (mode >= 32)
1476     sprintf(modrm_r, "%s%s", e,
1477     reg_names[r]);
1478     else
1479     strlcpy(modrm_r, reg_names[r],
1480     sizeof(modrm_r));
1481     }
1482     } else {
1483     switch (writeflag) {
1484     case MODRM_WRITE_R:
1485     if (flags & MODRM_SEG)
1486     cpu->cd.x86.s[r] = *op2p;
1487     else if (flags & MODRM_CR)
1488     x86_write_cr(cpu, r, *op2p);
1489     else if (flags & MODRM_DR)
1490     cpu->cd.x86.dr[r] = *op2p;
1491     else
1492     cpu->cd.x86.r[r] =
1493     modify(cpu->cd.x86.r[r], *op2p);
1494     break;
1495     case MODRM_READ:
1496     if (flags & MODRM_SEG)
1497     *op2p = cpu->cd.x86.s[r];
1498     else if (flags & MODRM_CR)
1499     *op2p = cpu->cd.x86.cr[r];
1500     else if (flags & MODRM_DR)
1501     *op2p = cpu->cd.x86.dr[r];
1502     else
1503     *op2p = cpu->cd.x86.r[r];
1504     }
1505     }
1506     }
1507    
1508     if (!disasm) {
1509     switch (mode) {
1510     case 16:*op1p &= 0xffff; *op2p &= 0xffff; break;
1511     case 32:*op1p &= 0xffffffffULL; *op2p &= 0xffffffffULL; break;
1512     }
1513     }
1514    
1515     return res;
1516     }
1517    
1518    
1519     /*
1520     * x86_cpu_disassemble_instr():
1521     *
1522     * Convert an instruction word into human readable format, for instruction
1523     * tracing.
1524     *
1525     * If running&1 is 1, cpu->pc should be the address of the instruction.
1526     *
1527     * If running&1 is 0, things that depend on the runtime environment (eg.
1528     * register contents) will not be shown, and addr will be used instead of
1529     * cpu->pc for relative addresses.
1530     *
1531     * The rest of running tells us the default (code) operand size.
1532     */
1533     int x86_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr,
1534 dpavlin 24 int running, uint64_t dumpaddr)
1535 dpavlin 14 {
1536     int op, rep = 0, lock = 0, n_prefix_bytes = 0;
1537     uint64_t ilen = 0, offset;
1538     uint32_t imm=0, imm2;
1539     int mode = running & ~1;
1540     int mode67;
1541     char *symbol, *mnem = "ERROR", *e = "e", *prefix = NULL;
1542    
1543     if (running)
1544     dumpaddr = cpu->pc;
1545    
1546     if (mode == 0) {
1547     mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
1548     if (mode == 0) {
1549     fatal("x86_cpu_disassemble_instr(): no mode: TODO\n");
1550     return 1;
1551     }
1552     }
1553    
1554     mode67 = mode;
1555    
1556     symbol = get_symbol_name(&cpu->machine->symbol_context,
1557     dumpaddr, &offset);
1558     if (symbol != NULL && offset==0)
1559     debug("<%s>\n", symbol);
1560    
1561     if (cpu->machine->ncpus > 1 && running)
1562     debug("cpu%i: ", cpu->cpu_id);
1563    
1564     if (mode == 32)
1565     debug("%08x: ", (int)dumpaddr);
1566     else if (mode == 64)
1567     debug("%016llx: ", (long long)dumpaddr);
1568     else { /* 16-bit mode */
1569     debug("%04x:%04x ", cpu->cd.x86.s[X86_S_CS],
1570     (int)dumpaddr & 0xffff);
1571     }
1572    
1573     /*
1574     * Decode the instruction:
1575     */
1576    
1577     /* All instructions are at least 1 byte long: */
1578     HEXPRINT(instr,1);
1579     ilen = 1;
1580    
1581     /* Any prefix? */
1582     for (;;) {
1583     if (instr[0] == 0x66) {
1584     if (mode == 16)
1585     mode = 32;
1586     else
1587     mode = 16;
1588     } else if (instr[0] == 0x67) {
1589     if (mode67 == 16)
1590     mode67 = 32;
1591     else
1592     mode67 = 16;
1593     } else if (instr[0] == 0xf2) {
1594     rep = REP_REPNE;
1595     } else if (instr[0] == 0xf3) {
1596     rep = REP_REP;
1597     } else if (instr[0] == 0x26) {
1598     prefix = "es:";
1599     } else if (instr[0] == 0x2e) {
1600     prefix = "cs:";
1601     } else if (instr[0] == 0x36) {
1602     prefix = "ss:";
1603     } else if (instr[0] == 0x3e) {
1604     prefix = "ds:";
1605     } else if (instr[0] == 0x64) {
1606     prefix = "fs:";
1607     } else if (instr[0] == 0x65) {
1608     prefix = "gs:";
1609     } else if (instr[0] == 0xf0) {
1610     lock = 1;
1611     } else
1612     break;
1613    
1614     if (++n_prefix_bytes > 4) {
1615     SPACES; debug("more than 4 prefix bytes?\n");
1616     return 4;
1617     }
1618    
1619     /* TODO: lock, segment overrides etc */
1620     instr ++; ilen ++;
1621     debug("%02x", instr[0]);
1622     }
1623    
1624     if (mode == 16)
1625     e = "";
1626    
1627     op = instr[0];
1628     instr ++;
1629    
1630     if ((op & 0xf0) <= 0x30 && (op & 7) <= 5) {
1631     switch (op & 0x38) {
1632     case 0x00: mnem = "add"; break;
1633     case 0x08: mnem = "or"; break;
1634     case 0x10: mnem = "adc"; break;
1635     case 0x18: mnem = "sbb"; break;
1636     case 0x20: mnem = "and"; break;
1637     case 0x28: mnem = "sub"; break;
1638     case 0x30: mnem = "xor"; break;
1639     case 0x38: mnem = "cmp"; break;
1640     }
1641     switch (op & 7) {
1642     case 4: imm = read_imm_and_print(&instr, &ilen, 8);
1643     SPACES; debug("%s\tal,0x%02x", mnem, imm);
1644     break;
1645     case 5: imm = read_imm_and_print(&instr, &ilen, mode);
1646     SPACES; debug("%s\t%sax,0x%x", mnem, e, imm);
1647     break;
1648     default:modrm(cpu, MODRM_READ, mode, mode67, op&1? 0 :
1649     MODRM_EIGHTBIT, &instr, &ilen, NULL, NULL);
1650     SPACES; debug("%s\t", mnem);
1651     if (op & 2)
1652     debug("%s,%s", modrm_r, modrm_rm);
1653     else
1654     debug("%s,%s", modrm_rm, modrm_r);
1655     }
1656     } else if (op == 0xf) {
1657     /* "pop cs" on 8086 */
1658     if (cpu->cd.x86.model.model_number == X86_MODEL_8086) {
1659     SPACES; debug("pop\tcs");
1660     } else {
1661     imm = read_imm_and_print(&instr, &ilen, 8);
1662     if (imm == 0x00) {
1663     int subop = (*instr >> 3) & 0x7;
1664     switch (subop) {
1665     case 0: modrm(cpu, MODRM_READ, mode, mode67,
1666     0, &instr, &ilen, NULL, NULL);
1667     SPACES; debug("sldt\t%s", modrm_rm);
1668     break;
1669     case 1: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1670     mode67, 0, &instr, &ilen,
1671     NULL, NULL);
1672     SPACES; debug("str\t%s", modrm_rm);
1673     break;
1674     case 2: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1675     mode67, 0, &instr, &ilen,
1676     NULL, NULL);
1677     SPACES; debug("lldt\t%s", modrm_rm);
1678     break;
1679     case 3: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1680     mode67, 0, &instr, &ilen,
1681     NULL, NULL);
1682     SPACES; debug("ltr\t%s", modrm_rm);
1683     break;
1684     case 4: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1685     mode67, 0, &instr, &ilen,
1686     NULL, NULL);
1687     SPACES; debug("verr\t%s", modrm_rm);
1688     break;
1689     case 5: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1690     mode67, 0, &instr, &ilen,
1691     NULL, NULL);
1692     SPACES; debug("verw\t%s", modrm_rm);
1693     break;
1694     default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1695     "%02x,0x%02x", op, imm, *instr);
1696     }
1697     } else if (imm == 0x01) {
1698     int subop = (*instr >> 3) & 0x7;
1699     switch (subop) {
1700     case 0:
1701     case 1:
1702     case 2:
1703     case 3: modrm(cpu, MODRM_READ, mode, mode67,
1704     0, &instr, &ilen, NULL, NULL);
1705     SPACES; debug("%s%s\t%s",
1706     subop < 2? "s" : "l",
1707     subop&1? "idt" : "gdt", modrm_rm);
1708     break;
1709     case 4:
1710     case 6: if (((*instr >> 3) & 0x7) == 4)
1711     mnem = "smsw";
1712     else
1713     mnem = "lmsw";
1714     modrm(cpu, MODRM_READ, 16, mode67,
1715     0, &instr, &ilen, NULL, NULL);
1716     SPACES; debug("%s\t%s", mnem, modrm_rm);
1717     break;
1718     case 7: modrm(cpu, MODRM_READ, mode,
1719     mode67, 0, &instr, &ilen,
1720     NULL, NULL);
1721     SPACES; debug("invlpg\t%s", modrm_rm);
1722     break;
1723     default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1724     "%02x,0x%02x", op, imm, *instr);
1725     }
1726     } else if (imm == 0x02) {
1727     modrm(cpu, MODRM_READ, mode, mode67,
1728     0, &instr, &ilen, NULL, NULL);
1729     SPACES; debug("lar\t%s,%s", modrm_r, modrm_rm);
1730     } else if (imm == 0x03) {
1731     modrm(cpu, MODRM_READ, mode, mode67,
1732     0, &instr, &ilen, NULL, NULL);
1733     SPACES; debug("lsl\t%s,%s", modrm_r, modrm_rm);
1734     } else if (imm == 0x05) {
1735     SPACES; /* TODO: exactly which models?*/
1736     if (cpu->cd.x86.model.model_number >
1737     X86_MODEL_80486)
1738     debug("syscall");
1739     else
1740     debug("loadall286");
1741     } else if (imm == 0x06) {
1742     SPACES; debug("clts");
1743     } else if (imm == 0x07) {
1744     SPACES; /* TODO: exactly which models?*/
1745     if (cpu->cd.x86.model.model_number >
1746     X86_MODEL_80486)
1747     debug("sysret");
1748     else
1749     debug("loadall");
1750     } else if (imm == 0x08) {
1751     SPACES; debug("invd");
1752     } else if (imm == 0x09) {
1753     SPACES; debug("wbinvd");
1754     } else if (imm == 0x0b) {
1755     SPACES; debug("reserved_0b");
1756     } else if (imm == 0x20 || imm == 0x21) {
1757     modrm(cpu, MODRM_READ, 32 /* note: 32 */,
1758     mode67, imm == 0x20? MODRM_CR : MODRM_DR,
1759     &instr, &ilen, NULL, NULL);
1760     SPACES; debug("mov\t%s,%s", modrm_rm, modrm_r);
1761     } else if (imm == 0x22 || imm == 0x23) {
1762     modrm(cpu, MODRM_READ, 32 /* note: 32 */,
1763     mode67, imm == 0x22? MODRM_CR : MODRM_DR,
1764     &instr, &ilen, NULL, NULL);
1765     SPACES; debug("mov\t%s,%s", modrm_r, modrm_rm);
1766     } else if (imm == 0x30) {
1767     SPACES; debug("wrmsr");
1768     } else if (imm == 0x31) {
1769     SPACES; debug("rdtsc");
1770     } else if (imm == 0x32) {
1771     SPACES; debug("rdmsr");
1772     } else if (imm == 0x33) {
1773     SPACES; debug("rdpmc"); /* http://www
1774     .x86.org/secrets/opcodes/rdpmc.htm */
1775     } else if (imm == 0x34) {
1776     SPACES; debug("sysenter");
1777     } else if (imm == 0x36) {
1778     SPACES; debug("sysexit");
1779     } else if (imm >= 0x40 && imm <= 0x4f) {
1780     modrm(cpu, MODRM_READ, mode, mode67, 0,
1781     &instr, &ilen, NULL, NULL);
1782     op = imm & 0xf;
1783     SPACES; debug("cmov%s%s\t%s,%s", op&1? "n"
1784     : "", cond_names[(op/2) & 0x7],
1785     modrm_r, modrm_rm);
1786     } else if (imm >= 0x80 && imm <= 0x8f) {
1787     op = imm & 0xf;
1788     imm = read_imm_and_print(&instr, &ilen, mode);
1789     imm = dumpaddr + 2 + mode/8 + imm;
1790     SPACES; debug("j%s%s\tnear 0x%x", op&1? "n"
1791     : "", cond_names[(op/2) & 0x7], imm);
1792     } else if (imm >= 0x90 && imm <= 0x9f) {
1793     op = imm;
1794     modrm(cpu, MODRM_READ, mode,
1795     mode67, MODRM_EIGHTBIT, &instr, &ilen,
1796     NULL, NULL);
1797     SPACES; debug("set%s%s\t%s", op&1? "n"
1798     : "", cond_names[(op/2) & 0x7], modrm_rm);
1799     } else if (imm == 0xa0) {
1800     SPACES; debug("push\tfs");
1801     } else if (imm == 0xa1) {
1802     SPACES; debug("pop\tfs");
1803     } else if (imm == 0xa2) {
1804     SPACES; debug("cpuid");
1805     } else if (imm == 0xa3 || imm == 0xab
1806     || imm == 0xb3 || imm == 0xbb) {
1807     modrm(cpu, MODRM_READ, mode, mode67,
1808     0, &instr, &ilen, NULL, NULL);
1809     switch (imm) {
1810     case 0xa3: mnem = "bt"; break;
1811     case 0xab: mnem = "bts"; break;
1812     case 0xb3: mnem = "btr"; break;
1813     case 0xbb: mnem = "btc"; break;
1814     }
1815     SPACES; debug("%s\t%s,%s",
1816     mnem, modrm_rm, modrm_r);
1817     } else if (imm == 0xa4 || imm == 0xa5 ||
1818     imm == 0xac || imm == 0xad) {
1819     modrm(cpu, MODRM_READ, mode, mode67,
1820     0, &instr, &ilen, NULL, NULL);
1821     if (!(imm & 1))
1822     imm2 = read_imm_and_print(&instr,
1823     &ilen, 8);
1824     else
1825     imm2 = 0;
1826     SPACES; debug("sh%sd\t%s,%s,",
1827     imm <= 0xa5? "l" : "r",
1828     modrm_rm, modrm_r);
1829     if (imm & 1)
1830     debug("cl");
1831     else
1832     debug("%i", imm2);
1833     } else if (imm == 0xa8) {
1834     SPACES; debug("push\tgs");
1835     } else if (imm == 0xa9) {
1836     SPACES; debug("pop\tgs");
1837     } else if (imm == 0xaa) {
1838     SPACES; debug("rsm");
1839     } else if (imm == 0xaf) {
1840     modrm(cpu, MODRM_READ, mode, mode67,
1841     0, &instr, &ilen, NULL, NULL);
1842     SPACES; debug("imul\t%s,%s", modrm_r, modrm_rm);
1843     } else if (imm == 0xb0 || imm == 0xb1) {
1844     modrm(cpu, MODRM_READ, mode, mode67,
1845     imm == 0xb0? MODRM_EIGHTBIT : 0,
1846     &instr, &ilen, NULL, NULL);
1847     SPACES; debug("cmpxchg\t%s,%s",
1848     modrm_rm, modrm_r);
1849     } else if (imm == 0xb2 || imm == 0xb4 || imm == 0xb5) {
1850     modrm(cpu, MODRM_READ, mode, mode67, 0,
1851     &instr, &ilen, NULL, NULL);
1852     switch (imm) {
1853     case 0xb2: mnem = "lss"; break;
1854     case 0xb4: mnem = "lfs"; break;
1855     case 0xb5: mnem = "lgs"; break;
1856     }
1857     SPACES; debug("%s\t%s,%s", mnem,
1858     modrm_r, modrm_rm);
1859     } else if (imm == 0xb6 || imm == 0xb7 ||
1860     imm == 0xbe || imm == 0xbf) {
1861     modrm(cpu, MODRM_READ, mode, mode67,
1862     (imm&1)==0? (MODRM_EIGHTBIT |
1863     MODRM_R_NONEIGHTBIT) : MODRM_RM_16BIT,
1864     &instr, &ilen, NULL, NULL);
1865     mnem = "movsx";
1866     if (imm <= 0xb7)
1867     mnem = "movzx";
1868     SPACES; debug("%s\t%s,%s", mnem,
1869     modrm_r, modrm_rm);
1870     } else if (imm == 0xba) {
1871     int subop = (*instr >> 3) & 0x7;
1872     switch (subop) {
1873     case 4: modrm(cpu, MODRM_READ, mode, mode67,
1874     0, &instr, &ilen, NULL, NULL);
1875     imm2 = read_imm_and_print(&instr,
1876     &ilen, 8);
1877     SPACES; debug("bt\t%s,%i",
1878     modrm_rm, imm2);
1879     break;
1880     case 5: modrm(cpu, MODRM_READ, mode, mode67,
1881     0, &instr, &ilen, NULL, NULL);
1882     imm2 = read_imm_and_print(&instr,
1883     &ilen, 8);
1884     SPACES; debug("bts\t%s,%i",
1885     modrm_rm, imm2);
1886     break;
1887     case 6: modrm(cpu, MODRM_READ, mode, mode67,
1888     0, &instr, &ilen, NULL, NULL);
1889     imm2 = read_imm_and_print(&instr,
1890     &ilen, 8);
1891     SPACES; debug("btr\t%s,%i",
1892     modrm_rm, imm2);
1893     break;
1894     case 7: modrm(cpu, MODRM_READ, mode, mode67,
1895     0, &instr, &ilen, NULL, NULL);
1896     imm2 = read_imm_and_print(&instr,
1897     &ilen, 8);
1898     SPACES; debug("btc\t%s,%i",
1899     modrm_rm, imm2);
1900     break;
1901     default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1902     "%02x,0x%02x", op, imm, *instr);
1903     }
1904     } else if (imm == 0xbc || imm == 0xbd) {
1905     modrm(cpu, MODRM_READ, mode, mode67,
1906     0, &instr, &ilen, NULL, NULL);
1907     if (imm == 0xbc)
1908     mnem = "bsf";
1909     else
1910     mnem = "bsr";
1911     SPACES; debug("%s\t%s,%s", mnem, modrm_r,
1912     modrm_rm);
1913     } else if (imm == 0xc0 || imm == 0xc1) {
1914     modrm(cpu, MODRM_READ, mode, mode67,
1915     imm&1? 0 : MODRM_EIGHTBIT,
1916     &instr, &ilen, NULL, NULL);
1917     SPACES; debug("xadd\t%s,%s", modrm_rm, modrm_r);
1918     } else if (imm == 0xc7) {
1919     int subop = (*instr >> 3) & 0x7;
1920     switch (subop) {
1921     case 1: modrm(cpu, MODRM_READ, 64, mode67,
1922     0, &instr, &ilen, NULL, NULL);
1923     SPACES; debug("cmpxchg8b\t%s",modrm_rm);
1924     break;
1925     default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1926     "%02x,0x%02x", op, imm, *instr);
1927     }
1928     } else if (imm >= 0xc8 && imm <= 0xcf) {
1929     SPACES; debug("bswap\te%s", reg_names[imm & 7]);
1930     } else {
1931     SPACES; debug("UNIMPLEMENTED 0x0f,0x%02x", imm);
1932     }
1933     }
1934     } else if (op < 0x20 && (op & 7) == 6) {
1935     SPACES; debug("push\t%s", seg_names[op/8]);
1936     } else if (op < 0x20 && (op & 7) == 7) {
1937     SPACES; debug("pop\t%s", seg_names[op/8]);
1938     } else if (op >= 0x20 && op < 0x40 && (op & 7) == 7) {
1939     SPACES; debug("%sa%s", op < 0x30? "d" : "a",
1940     (op & 0xf)==7? "a" : "s");
1941     } else if (op >= 0x40 && op <= 0x5f) {
1942     switch (op & 0x38) {
1943     case 0x00: mnem = "inc"; break;
1944     case 0x08: mnem = "dec"; break;
1945     case 0x10: mnem = "push"; break;
1946     case 0x18: mnem = "pop"; break;
1947     }
1948     SPACES; debug("%s\t%s%s", mnem, e, reg_names[op & 7]);
1949     } else if (op == 0x60) {
1950     SPACES; debug("pusha%s", mode==16? "" : (mode==32? "d" : "q"));
1951     } else if (op == 0x61) {
1952     SPACES; debug("popa%s", mode==16? "" : (mode==32? "d" : "q"));
1953     } else if (op == 0x62) {
1954     modrm(cpu, MODRM_READ, mode, mode67,
1955     0, &instr, &ilen, NULL, NULL);
1956     SPACES; debug("bound\t%s,%s", modrm_r, modrm_rm);
1957     } else if (op == 0x63) {
1958     modrm(cpu, MODRM_READ, 16, mode67,
1959     0, &instr, &ilen, NULL, NULL);
1960     SPACES; debug("arpl\t%s,%s", modrm_rm, modrm_r);
1961     } else if (op == 0x68) {
1962     imm = read_imm_and_print(&instr, &ilen, mode);
1963     SPACES; debug("push\t%sword 0x%x", mode==32?"d":"", imm);
1964     } else if (op == 0x69 || op == 0x6b) {
1965     modrm(cpu, MODRM_READ, mode, mode67,
1966     0, &instr, &ilen, NULL, NULL);
1967     if (op == 0x69)
1968     imm = read_imm_and_print(&instr, &ilen, mode);
1969     else
1970     imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1971     SPACES; debug("imul\t%s,%s,%i", modrm_r, modrm_rm, imm);
1972     } else if (op == 0x6a) {
1973     imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1974     SPACES; debug("push\tbyte 0x%x", imm);
1975     } else if (op == 0x6c) {
1976     SPACES; debug("insb");
1977     } else if (op == 0x6d) {
1978     SPACES; debug("ins%s", mode==16? "w" : (mode==32? "d" : "q"));
1979     } else if (op == 0x6e) {
1980     SPACES; debug("outsb");
1981     } else if (op == 0x6f) {
1982     SPACES; debug("outs%s", mode==16? "w" : (mode==32? "d" : "q"));
1983     } else if ((op & 0xf0) == 0x70) {
1984     imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1985     imm = dumpaddr + 2 + imm;
1986     SPACES; debug("j%s%s\t0x%x", op&1? "n" : "",
1987     cond_names[(op/2) & 0x7], imm);
1988     } else if (op == 0x80 || op == 0x81) {
1989     switch ((*instr >> 3) & 0x7) {
1990     case 0: mnem = "add"; break;
1991     case 1: mnem = "or"; break;
1992     case 2: mnem = "adc"; break;
1993     case 3: mnem = "sbb"; break;
1994     case 4: mnem = "and"; break;
1995     case 5: mnem = "sub"; break;
1996     case 6: mnem = "xor"; break;
1997     case 7: mnem = "cmp"; break;
1998     default:
1999     SPACES; debug("UNIMPLEMENTED 0x%02x", op);
2000     }
2001     modrm(cpu, MODRM_READ, mode, mode67,
2002     op == 0x80? MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2003     imm = read_imm_and_print(&instr, &ilen, op==0x80? 8 : mode);
2004     SPACES; debug("%s\t%s,0x%x", mnem, modrm_rm, imm);
2005     } else if (op == 0x83) {
2006     switch ((*instr >> 3) & 0x7) {
2007     case 0: mnem = "add"; break;
2008     case 1: mnem = "or"; break;
2009     case 2: mnem = "adc"; break;
2010     case 3: mnem = "sbb"; break;
2011     case 4: mnem = "and"; break;
2012     case 5: mnem = "sub"; break;
2013     case 6: mnem = "xor"; break;
2014     case 7: mnem = "cmp"; break;
2015     default:
2016     SPACES; debug("UNIMPLEMENTED 0x%02x", op);
2017     }
2018     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, &ilen,
2019     NULL, NULL);
2020     imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
2021     SPACES; debug("%s\t%s,0x%x", mnem, modrm_rm, imm);
2022     } else if (op == 0x84 || op == 0x85) {
2023     modrm(cpu, MODRM_READ, mode, mode67,
2024     op == 0x84? MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2025     SPACES; debug("test\t%s,%s", modrm_rm, modrm_r);
2026     } else if (op == 0x86 || op == 0x87) {
2027     modrm(cpu, MODRM_READ, mode, mode67, op == 0x86?
2028     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2029     SPACES; debug("xchg\t%s,%s", modrm_rm, modrm_r);
2030     } else if (op == 0x88 || op == 0x89) {
2031     modrm(cpu, MODRM_READ, mode, mode67, op == 0x88?
2032     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2033     SPACES; debug("mov\t%s,%s", modrm_rm, modrm_r);
2034     } else if (op == 0x8a || op == 0x8b) {
2035     modrm(cpu, MODRM_READ, mode, mode67, op == 0x8a?
2036     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2037     SPACES; debug("mov\t%s,%s", modrm_r, modrm_rm);
2038     } else if (op == 0x8c || op == 0x8e) {
2039     modrm(cpu, MODRM_READ, mode, mode67, MODRM_SEG, &instr, &ilen,
2040     NULL, NULL);
2041     SPACES; debug("mov\t");
2042     if (op == 0x8c)
2043     debug("%s,%s", modrm_rm, modrm_r);
2044     else
2045     debug("%s,%s", modrm_r, modrm_rm);
2046     } else if (op == 0x8d) {
2047     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, &ilen,
2048     NULL, NULL);
2049     SPACES; debug("lea\t%s,%s", modrm_r, modrm_rm);
2050     } else if (op == 0x8f) {
2051     switch ((*instr >> 3) & 0x7) {
2052     case 0: /* POP m16/m32 */
2053     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2054     &ilen, NULL, NULL);
2055     SPACES; debug("pop\t%sword %s", mode == 32? "d" : "",
2056     modrm_rm);
2057     break;
2058     default:
2059     SPACES; debug("UNIMPLEMENTED 0x%02x", op);
2060     }
2061     } else if (op == 0x90) {
2062     SPACES; debug("nop");
2063     } else if (op >= 0x91 && op <= 0x97) {
2064     SPACES; debug("xchg\t%sax,%s%s", e, e, reg_names[op & 7]);
2065     } else if (op == 0x98) {
2066     SPACES; debug("cbw");
2067     } else if (op == 0x99) {
2068     SPACES; debug("cwd");
2069     } else if (op == 0x9a) {
2070     imm = read_imm_and_print(&instr, &ilen, mode);
2071     imm2 = read_imm_and_print(&instr, &ilen, 16);
2072     SPACES; debug("call\t0x%04x:", imm2);
2073     if (mode == 16)
2074     debug("0x%04x", imm);
2075     else
2076     debug("0x%08x", imm);
2077     } else if (op == 0x9b) {
2078     SPACES; debug("wait");
2079     } else if (op == 0x9c) {
2080     SPACES; debug("pushf%s", mode==16? "" : (mode==32? "d" : "q"));
2081     } else if (op == 0x9d) {
2082     SPACES; debug("popf%s", mode==16? "" : (mode==32? "d" : "q"));
2083     } else if (op == 0x9e) {
2084     SPACES; debug("sahf");
2085     } else if (op == 0x9f) {
2086     SPACES; debug("lahf");
2087     } else if (op == 0xa0) {
2088     imm = read_imm_and_print(&instr, &ilen, mode67);
2089     SPACES; debug("mov\tal,[0x%x]", imm);
2090     } else if (op == 0xa1) {
2091     imm = read_imm_and_print(&instr, &ilen, mode67);
2092     SPACES; debug("mov\t%sax,[0x%x]", e, imm);
2093     } else if (op == 0xa2) {
2094     imm = read_imm_and_print(&instr, &ilen, mode67);
2095     SPACES; debug("mov\t[0x%x],al", imm);
2096     } else if (op == 0xa3) {
2097     imm = read_imm_and_print(&instr, &ilen, mode67);
2098     SPACES; debug("mov\t[0x%x],%sax", imm, e);
2099     } else if (op == 0xa4) {
2100     SPACES; debug("movsb");
2101     } else if (op == 0xa5) {
2102     SPACES; debug("movs%s", mode==16? "w" : (mode==32? "d" : "q"));
2103     } else if (op == 0xa6) {
2104     SPACES; debug("cmpsb");
2105     } else if (op == 0xa7) {
2106     SPACES; debug("cmps%s", mode==16? "w" : (mode==32? "d" : "q"));
2107     } else if (op == 0xa8 || op == 0xa9) {
2108     imm = read_imm_and_print(&instr, &ilen, op == 0xa8? 8 : mode);
2109     if (op == 0xa8)
2110     mnem = "al";
2111     else if (mode == 16)
2112     mnem = "ax";
2113     else
2114     mnem = "eax";
2115     SPACES; debug("test\t%s,0x%x", mnem, imm);
2116     } else if (op == 0xaa) {
2117     SPACES; debug("stosb");
2118     } else if (op == 0xab) {
2119     SPACES; debug("stos%s", mode==16? "w" : (mode==32? "d" : "q"));
2120     } else if (op == 0xac) {
2121     SPACES; debug("lodsb");
2122     } else if (op == 0xad) {
2123     SPACES; debug("lods%s", mode==16? "w" : (mode==32? "d" : "q"));
2124     } else if (op == 0xae) {
2125     SPACES; debug("scasb");
2126     } else if (op == 0xaf) {
2127     SPACES; debug("scas%s", mode==16? "w" : (mode==32? "d" : "q"));
2128     } else if (op >= 0xb0 && op <= 0xb7) {
2129     imm = read_imm_and_print(&instr, &ilen, 8);
2130     SPACES; debug("mov\t%s,0x%x", reg_names_bytes[op&7], imm);
2131     } else if (op >= 0xb8 && op <= 0xbf) {
2132     imm = read_imm_and_print(&instr, &ilen, mode);
2133     SPACES; debug("mov\t%s%s,0x%x", e, reg_names[op & 7], imm);
2134     } else if (op == 0xc0 || op == 0xc1) {
2135     switch ((*instr >> 3) & 0x7) {
2136     case 0: mnem = "rol"; break;
2137     case 1: mnem = "ror"; break;
2138     case 2: mnem = "rcl"; break;
2139     case 3: mnem = "rcr"; break;
2140     case 4: mnem = "shl"; break;
2141     case 5: mnem = "shr"; break;
2142     case 6: mnem = "sal"; break;
2143     case 7: mnem = "sar"; break;
2144     }
2145     modrm(cpu, MODRM_READ, mode, mode67, op == 0xc0?
2146     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2147     imm = read_imm_and_print(&instr, &ilen, 8);
2148     SPACES; debug("%s\t%s,%i", mnem, modrm_rm, imm);
2149     } else if (op == 0xc2) {
2150     imm = read_imm_and_print(&instr, &ilen, 16);
2151     SPACES; debug("ret\t0x%x", imm);
2152     } else if (op == 0xc3) {
2153     SPACES; debug("ret");
2154     } else if (op == 0xc4 || op == 0xc5) {
2155     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, &ilen,
2156     NULL, NULL);
2157     switch (op) {
2158     case 0xc4: mnem = "les"; break;
2159     case 0xc5: mnem = "lds"; break;
2160     }
2161     SPACES; debug("%s\t%s,%s", mnem, modrm_r, modrm_rm);
2162     } else if (op == 0xc6 || op == 0xc7) {
2163     switch ((*instr >> 3) & 0x7) {
2164     case 0: modrm(cpu, MODRM_READ, mode, mode67, op == 0xc6?
2165     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2166     imm = read_imm_and_print(&instr, &ilen,
2167     op == 0xc6? 8 : mode);
2168     SPACES; debug("mov\t%s,0x%x", modrm_rm, imm);
2169     break;
2170     default:
2171     SPACES; debug("UNIMPLEMENTED 0x%02x", op);
2172     }
2173     } else if (op == 0xc8) {
2174     imm = read_imm_and_print(&instr, &ilen, 16);
2175     imm2 = read_imm_and_print(&instr, &ilen, 8);
2176     SPACES; debug("enter\t0x%x,%i", imm, imm2);
2177     } else if (op == 0xc9) {
2178     SPACES; debug("leave");
2179     } else if (op == 0xca) {
2180     imm = read_imm_and_print(&instr, &ilen, 16);
2181     SPACES; debug("retf\t0x%x", imm);
2182     } else if (op == 0xcb) {
2183     SPACES; debug("retf");
2184     } else if (op == 0xcc) {
2185     SPACES; debug("int3");
2186     } else if (op == 0xcd) {
2187     imm = read_imm_and_print(&instr, &ilen, 8);
2188     SPACES; debug("int\t0x%x", imm);
2189     } else if (op == 0xce) {
2190     SPACES; debug("into");
2191     } else if (op == 0xcf) {
2192     SPACES; debug("iret");
2193     } else if (op >= 0xd0 && op <= 0xd3) {
2194     int subop = (*instr >> 3) & 0x7;
2195     modrm(cpu, MODRM_READ, mode, mode67, op&1? 0 :
2196     MODRM_EIGHTBIT, &instr, &ilen, NULL, NULL);
2197     switch (subop) {
2198     case 0: mnem = "rol"; break;
2199     case 1: mnem = "ror"; break;
2200     case 2: mnem = "rcl"; break;
2201     case 3: mnem = "rcr"; break;
2202     case 4: mnem = "shl"; break;
2203     case 5: mnem = "shr"; break;
2204     case 6: mnem = "sal"; break;
2205     case 7: mnem = "sar"; break;
2206     }
2207     SPACES; debug("%s\t%s,", mnem, modrm_rm);
2208     if (op <= 0xd1)
2209     debug("1");
2210     else
2211     debug("cl");
2212     } else if (op == 0xd4) {
2213     imm = read_imm_and_print(&instr, &ilen, 8);
2214     SPACES; debug("aam");
2215     if (imm != 10)
2216     debug("\t%i", imm);
2217     } else if (op == 0xd5) {
2218     imm = read_imm_and_print(&instr, &ilen, 8);
2219     SPACES; debug("aad");
2220     if (imm != 10)
2221     debug("\t%i", imm);
2222     } else if (op == 0xd6) {
2223     SPACES; debug("salc"); /* undocumented? */
2224     } else if (op == 0xd7) {
2225     SPACES; debug("xlat");
2226     } else if (op == 0xd9) {
2227     int subop = (*instr >> 3) & 7;
2228     imm = *instr;
2229     if (subop == 5) {
2230     modrm(cpu, MODRM_READ, 16, mode67, 0,
2231     &instr, &ilen, NULL, NULL);
2232     SPACES; debug("fldcw\t%s", modrm_rm);
2233     } else if (subop == 7) {
2234     modrm(cpu, MODRM_READ, 16, mode67, 0,
2235     &instr, &ilen, NULL, NULL);
2236     SPACES; debug("fstcw\t%s", modrm_rm);
2237     } else {
2238     SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2239     }
2240     } else if (op == 0xdb) {
2241     imm = *instr;
2242     if (imm == 0xe2) {
2243     read_imm_and_print(&instr, &ilen, 8);
2244     SPACES; debug("fclex");
2245     } else if (imm == 0xe3) {
2246     read_imm_and_print(&instr, &ilen, 8);
2247     SPACES; debug("finit");
2248     } else if (imm == 0xe4) {
2249     read_imm_and_print(&instr, &ilen, 8);
2250     SPACES; debug("fsetpm");
2251     } else {
2252     SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2253     }
2254     } else if (op == 0xdd) {
2255     int subop = (*instr >> 3) & 7;
2256     imm = *instr;
2257     if (subop == 7) {
2258     modrm(cpu, MODRM_READ, 16, mode67, 0,
2259     &instr, &ilen, NULL, NULL);
2260     SPACES; debug("fstsw\t%s", modrm_rm);
2261     } else {
2262     SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2263     }
2264     } else if (op == 0xdf) {
2265     imm = *instr;
2266     if (imm == 0xe0) {
2267     read_imm_and_print(&instr, &ilen, 8);
2268     SPACES; debug("fstsw\tax");
2269     } else {
2270     SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2271     }
2272     } else if (op == 0xe3) {
2273     imm = read_imm_and_print(&instr, &ilen, 8);
2274     imm = dumpaddr + ilen + (signed char)imm;
2275     if (mode == 16)
2276     mnem = "jcxz";
2277     else
2278     mnem = "jecxz";
2279     SPACES; debug("%s\t0x%x", mnem, imm);
2280     } else if (op == 0xe4) {
2281     imm = read_imm_and_print(&instr, &ilen, 8);
2282     SPACES; debug("in\tal,0x%x", imm);
2283     } else if (op == 0xe5) {
2284     imm = read_imm_and_print(&instr, &ilen, 8);
2285     SPACES; debug("in\t%sax,0x%x", e, imm);
2286     } else if (op == 0xe6) {
2287     imm = read_imm_and_print(&instr, &ilen, 8);
2288     SPACES; debug("out\t0x%x,al", imm);
2289     } else if (op == 0xe7) {
2290     imm = read_imm_and_print(&instr, &ilen, 8);
2291     SPACES; debug("out\t0x%x,%sax", imm, e);
2292     } else if (op == 0xe8 || op == 0xe9) {
2293     imm = read_imm_and_print(&instr, &ilen, mode);
2294     if (mode == 16)
2295     imm = (int16_t)imm;
2296     imm = dumpaddr + ilen + imm;
2297     switch (op) {
2298     case 0xe8: mnem = "call"; break;
2299     case 0xe9: mnem = "jmp"; break;
2300     }
2301     SPACES; debug("%s\t0x%x", mnem, imm);
2302     } else if (op == 0xea) {
2303     imm = read_imm_and_print(&instr, &ilen, mode);
2304     imm2 = read_imm_and_print(&instr, &ilen, 16);
2305     SPACES; debug("jmp\t0x%04x:", imm2);
2306     if (mode == 16)
2307     debug("0x%04x", imm);
2308     else
2309     debug("0x%08x", imm);
2310     } else if ((op >= 0xe0 && op <= 0xe2) || op == 0xeb) {
2311     imm = read_imm_and_print(&instr, &ilen, 8);
2312     imm = dumpaddr + ilen + (signed char)imm;
2313     switch (op) {
2314     case 0xe0: mnem = "loopnz"; break;
2315     case 0xe1: mnem = "loopz"; break;
2316     case 0xe2: mnem = "loop"; break;
2317     case 0xeb: mnem = "jmp"; break;
2318     }
2319     SPACES; debug("%s\t0x%x", mnem, imm);
2320     } else if (op == 0xec) {
2321     SPACES; debug("in\tal,dx");
2322     } else if (op == 0xed) {
2323     SPACES; debug("in\t%sax,dx", e);
2324     } else if (op == 0xee) {
2325     SPACES; debug("out\tdx,al");
2326     } else if (op == 0xef) {
2327     SPACES; debug("out\tdx,%sax", e);
2328     } else if (op == 0xf1) {
2329     SPACES; debug("icebp"); /* undocumented? */
2330     /* http://www.x86.org/secrets/opcodes/icebp.htm */
2331     } else if (op == 0xf4) {
2332     SPACES; debug("hlt");
2333     } else if (op == 0xf5) {
2334     SPACES; debug("cmc");
2335     } else if (op == 0xf8) {
2336     SPACES; debug("clc");
2337     } else if (op == 0xf9) {
2338     SPACES; debug("stc");
2339     } else if (op == 0xfa) {
2340     SPACES; debug("cli");
2341     } else if (op == 0xfb) {
2342     SPACES; debug("sti");
2343     } else if (op == 0xfc) {
2344     SPACES; debug("cld");
2345     } else if (op == 0xfd) {
2346     SPACES; debug("std");
2347     } else if (op == 0xf6 || op == 0xf7) {
2348     switch ((*instr >> 3) & 0x7) {
2349     case 0: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2350     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2351     imm = read_imm_and_print(&instr, &ilen,
2352     op == 0xf6? 8 : mode);
2353     SPACES; debug("test\t%s,0x%x", modrm_rm, imm);
2354     break;
2355     case 2: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2356     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2357     SPACES; debug("not\t%s", modrm_rm);
2358     break;
2359     case 3: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2360     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2361     SPACES; debug("neg\t%s", modrm_rm);
2362     break;
2363     case 4: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2364     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2365     SPACES; debug("mul\t%s", modrm_rm);
2366     break;
2367     case 5: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2368     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2369     SPACES; debug("imul\t%s", modrm_rm);
2370     break;
2371     case 6: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2372     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2373     SPACES; debug("div\t%s", modrm_rm);
2374     break;
2375     case 7: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2376     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2377     SPACES; debug("idiv\t%s", modrm_rm);
2378     break;
2379     default:
2380     SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op,*instr);
2381     }
2382     } else if (op == 0xfe || op == 0xff) {
2383     /* FE /0 = inc r/m8 */
2384     /* FE /1 = dec r/m8 */
2385     /* FF /2 = call near rm16/32 */
2386     /* FF /3 = call far m16:32 */
2387     /* FF /6 = push r/m16/32 */
2388     switch ((*instr >> 3) & 0x7) {
2389     case 0: modrm(cpu, MODRM_READ, mode, mode67, op == 0xfe?
2390     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2391     SPACES; debug("inc\t%s", modrm_rm);
2392     break;
2393     case 1: modrm(cpu, MODRM_READ, mode, mode67, op == 0xfe?
2394     MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2395     SPACES; debug("dec\t%s", modrm_rm);
2396     break;
2397     case 2: if (op == 0xfe) {
2398     SPACES; debug("UNIMPLEMENTED "
2399     "0x%02x,0x%02x", op,*instr);
2400     } else {
2401     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2402     &ilen, NULL, NULL);
2403     SPACES; debug("call\t%s", modrm_rm);
2404     }
2405     break;
2406     case 3: if (op == 0xfe) {
2407     SPACES; debug("UNIMPLEMENTED "
2408     "0x%02x,0x%02x", op,*instr);
2409     } else {
2410     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2411     &ilen, NULL, NULL);
2412     SPACES; debug("call\tfar %s", modrm_rm);
2413     }
2414     break;
2415     case 4: if (op == 0xfe) {
2416     SPACES; debug("UNIMPLEMENTED "
2417     "0x%02x,0x%02x", op,*instr);
2418     } else {
2419     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2420     &ilen, NULL, NULL);
2421     SPACES; debug("jmp\t%s", modrm_rm);
2422     }
2423     break;
2424     case 5: if (op == 0xfe) {
2425     SPACES; debug("UNIMPLEMENTED "
2426     "0x%02x,0x%02x", op,*instr);
2427     } else {
2428     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2429     &ilen, NULL, NULL);
2430     SPACES; debug("jmp\tfar %s", modrm_rm);
2431     }
2432     break;
2433     case 6: if (op == 0xfe) {
2434     SPACES; debug("UNIMPLEMENTED "
2435     "0x%02x,0x%02x", op,*instr);
2436     } else {
2437     modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2438     &ilen, NULL, NULL);
2439     SPACES; debug("push\t%sword %s",
2440     mode == 32? "d" : "", modrm_rm);
2441     }
2442     break;
2443     default:
2444     SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op,*instr);
2445     }
2446     } else {
2447     SPACES; debug("UNIMPLEMENTED 0x%02x", op);
2448     }
2449    
2450     switch (rep) {
2451     case REP_REP: debug(" (rep)"); break;
2452     case REP_REPNE: debug(" (repne)"); break;
2453     }
2454     if (prefix != NULL)
2455     debug(" (%s)", prefix);
2456     if (lock)
2457     debug(" (lock)");
2458    
2459     debug("\n");
2460     return ilen;
2461     }
2462    
2463    
2464    
2465     /*
2466     * x86_cpuid():
2467     *
2468     * TODO: Level 1 and 2 info.
2469     */
2470 dpavlin 22 void x86_cpuid(struct cpu *cpu)
2471 dpavlin 14 {
2472     switch (cpu->cd.x86.r[X86_R_AX]) {
2473     /* Normal CPU id: */
2474     case 0: cpu->cd.x86.r[X86_R_AX] = 2;
2475     /* Intel... */
2476     cpu->cd.x86.r[X86_R_BX] = 0x756e6547; /* "Genu" */
2477     cpu->cd.x86.r[X86_R_DX] = 0x49656e69; /* "ineI" */
2478     cpu->cd.x86.r[X86_R_CX] = 0x6c65746e; /* "ntel" */
2479     /* ... or AMD: */
2480     cpu->cd.x86.r[X86_R_BX] = 0x68747541; /* "Auth" */
2481     cpu->cd.x86.r[X86_R_DX] = 0x69746E65; /* "enti" */
2482     cpu->cd.x86.r[X86_R_CX] = 0x444D4163; /* "cAMD" */
2483     break;
2484     case 1: /* TODO */
2485     cpu->cd.x86.r[X86_R_AX] = 0x0623;
2486     cpu->cd.x86.r[X86_R_BX] = (cpu->cpu_id << 24);
2487     /* TODO: are bits 8..15 the _total_ nr of cpus, or the
2488     cpu id of this one? */
2489     cpu->cd.x86.r[X86_R_CX] = X86_CPUID_ECX_CX16;
2490     cpu->cd.x86.r[X86_R_DX] = X86_CPUID_EDX_CX8 | X86_CPUID_EDX_FPU
2491     | X86_CPUID_EDX_MSR | X86_CPUID_EDX_TSC | X86_CPUID_EDX_MTRR
2492     | X86_CPUID_EDX_CMOV | X86_CPUID_EDX_PSE |
2493     X86_CPUID_EDX_SEP | X86_CPUID_EDX_PGE |
2494     X86_CPUID_EDX_MMX | X86_CPUID_EDX_FXSR;
2495     break;
2496     case 2: /* TODO: actual Cache info */
2497     /* This is just bogus */
2498     cpu->cd.x86.r[X86_R_AX] = 0x03020101;
2499     cpu->cd.x86.r[X86_R_BX] = 0x00000000;
2500     cpu->cd.x86.r[X86_R_CX] = 0x00000000;
2501     cpu->cd.x86.r[X86_R_DX] = 0x06040a42;
2502     break;
2503    
2504     /* Extended CPU id: */
2505     case 0x80000000:
2506     cpu->cd.x86.r[X86_R_AX] = 0x80000008;
2507     /* AMD... */
2508     cpu->cd.x86.r[X86_R_BX] = 0x68747541;
2509     cpu->cd.x86.r[X86_R_DX] = 0x444D4163;
2510     cpu->cd.x86.r[X86_R_CX] = 0x69746E65;
2511     break;
2512     case 0x80000001:
2513     cpu->cd.x86.r[X86_R_AX] = 0;
2514     cpu->cd.x86.r[X86_R_BX] = 0;
2515     cpu->cd.x86.r[X86_R_CX] = 0;
2516     cpu->cd.x86.r[X86_R_DX] = (cpu->cd.x86.model.model_number
2517     >= X86_MODEL_AMD64)? X86_CPUID_EXT_EDX_LM : 0;
2518     break;
2519     case 0x80000002:
2520     case 0x80000003:
2521     case 0x80000004:
2522     case 0x80000005:
2523     case 0x80000006:
2524     case 0x80000007:
2525     fatal("[ CPUID 0x%08x ]\n", (int)cpu->cd.x86.r[X86_R_AX]);
2526     cpu->cd.x86.r[X86_R_AX] = 0;
2527     cpu->cd.x86.r[X86_R_BX] = 0;
2528     cpu->cd.x86.r[X86_R_CX] = 0;
2529     cpu->cd.x86.r[X86_R_DX] = 0;
2530     break;
2531     case 0x80000008:
2532     cpu->cd.x86.r[X86_R_AX] = 0x00003028;
2533     cpu->cd.x86.r[X86_R_BX] = 0;
2534     cpu->cd.x86.r[X86_R_CX] = 0;
2535     cpu->cd.x86.r[X86_R_DX] = 0;
2536     break;
2537     default:fatal("x86_cpuid(): unimplemented eax = 0x%x\n",
2538     (int)cpu->cd.x86.r[X86_R_AX]);
2539     cpu->running = 0;
2540     }
2541     }
2542    
2543    
2544     /*
2545     * x86_push():
2546     */
2547     int x86_push(struct cpu *cpu, uint64_t value, int mode)
2548     {
2549     int res = 1, oldseg;
2550     int ssize = cpu->cd.x86.descr_cache[X86_S_SS].default_op_size;
2551     uint64_t new_esp;
2552     uint64_t old_esp = cpu->cd.x86.r[X86_R_SP];
2553     uint16_t old_ss = cpu->cd.x86.s[X86_S_SS];
2554     uint64_t old_eip = cpu->pc;
2555     uint16_t old_cs = cpu->cd.x86.s[X86_S_CS];
2556    
2557     /* TODO: up/down? */
2558     /* TODO: stacksize? */
2559     ssize = mode;
2560    
2561     oldseg = cpu->cd.x86.cursegment;
2562     cpu->cd.x86.cursegment = X86_S_SS;
2563     if (ssize == 16)
2564     new_esp = (cpu->cd.x86.r[X86_R_SP] & ~0xffff)
2565     | ((cpu->cd.x86.r[X86_R_SP] - (ssize / 8)) & 0xffff);
2566     else
2567     new_esp = (cpu->cd.x86.r[X86_R_SP] -
2568     (ssize / 8)) & 0xffffffff;
2569     res = x86_store(cpu, new_esp, value, ssize / 8);
2570     if (!res) {
2571     fatal("WARNING: x86_push store failed: cs:eip=0x%04x:0x%08x"
2572     " ss:esp=0x%04x:0x%08x\n", (int)old_cs,
2573     (int)old_eip, (int)old_ss, (int)old_esp);
2574     if ((old_cs & X86_PL_MASK) != X86_RING3)
2575     cpu->running = 0;
2576     } else {
2577     cpu->cd.x86.r[X86_R_SP] = new_esp;
2578     }
2579     cpu->cd.x86.cursegment = oldseg;
2580     return res;
2581     }
2582    
2583    
2584     /*
2585     * x86_pop():
2586     */
2587     int x86_pop(struct cpu *cpu, uint64_t *valuep, int mode)
2588     {
2589     int res = 1, oldseg;
2590     int ssize = cpu->cd.x86.descr_cache[X86_S_SS].default_op_size;
2591    
2592     /* TODO: up/down? */
2593     /* TODO: stacksize? */
2594     ssize = mode;
2595    
2596     oldseg = cpu->cd.x86.cursegment;
2597     cpu->cd.x86.cursegment = X86_S_SS;
2598     res = x86_load(cpu, cpu->cd.x86.r[X86_R_SP], valuep, ssize / 8);
2599     if (!res) {
2600     fatal("WARNING: x86_pop load failed\n");
2601     } else {
2602     if (ssize == 16)
2603     cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] &
2604     ~0xffff) | ((cpu->cd.x86.r[X86_R_SP] + (ssize / 8))
2605     & 0xffff);
2606     else
2607     cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] +
2608     (ssize / 8)) & 0xffffffff;
2609     }
2610     cpu->cd.x86.cursegment = oldseg;
2611     return res;
2612     }
2613    
2614    
2615     #define INT_TYPE_CALLGATE 1
2616     #define INT_TYPE_INTGATE 2
2617     #define INT_TYPE_TRAPGATE 3
2618     /*
2619     * x86_interrupt():
2620     *
2621     * Read the interrupt descriptor table (or, in real mode, the interrupt
2622     * vector table), push flags/cs/eip, and jump to the interrupt handler.
2623     */
2624     int x86_interrupt(struct cpu *cpu, int nr, int errcode)
2625     {
2626     uint16_t seg, old_cs;
2627     uint32_t ofs;
2628     int res, mode;
2629     unsigned char buf[8];
2630    
2631     old_cs = cpu->cd.x86.s[X86_S_CS];
2632    
2633     debug("{ x86_interrupt %i }\n", nr);
2634    
2635     if (PROTECTED_MODE) {
2636     int i, int_type = 0;
2637    
2638 dpavlin 22 if (nr * 8 > (int)cpu->cd.x86.idtr_limit) {
2639 dpavlin 14 fatal("TODO: protected mode int 0x%02x outside idtr"
2640     " limit (%i)?\n", nr, (int)cpu->cd.x86.idtr_limit);
2641     cpu->running = 0;
2642     return 0;
2643     }
2644    
2645     /* Read the interrupt descriptor: */
2646     res = cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.idtr + nr*8,
2647     buf, 8, MEM_READ, NO_SEGMENTATION);
2648     if (!res) {
2649     fatal("x86_interrupt(): could not read the"
2650     " interrupt descriptor table (prot. mode)\n");
2651     cpu->running = 0;
2652     return 0;
2653     }
2654    
2655     if ((buf[5] & 0x17) == 0x04)
2656     int_type = INT_TYPE_CALLGATE;
2657     if ((buf[5] & 0x17) == 0x06)
2658     int_type = INT_TYPE_INTGATE;
2659     if ((buf[5] & 0x17) == 0x07)
2660     int_type = INT_TYPE_TRAPGATE;
2661    
2662     if (!int_type) {
2663     fatal("x86_interrupt(): TODO:\n");
2664     for (i=0; i<8; i++)
2665     fatal(" %02x", buf[i]);
2666     fatal("\n");
2667     cpu->running = 0;
2668     return 0;
2669     }
2670    
2671     seg = buf[2] + (buf[3] << 8);
2672     ofs = buf[0] + (buf[1] << 8) + (buf[6] << 16) + (buf[7] << 24);
2673    
2674     switch (int_type) {
2675     case INT_TYPE_INTGATE:
2676     case INT_TYPE_TRAPGATE:
2677     break;
2678     default:
2679     fatal("INT type: %i, cs:eip = 0x%04x:0x%08x\n",
2680     int_type, (int)seg, (int)ofs);
2681     cpu->running = 0;
2682     return 0;
2683     }
2684    
2685     reload_segment_descriptor(cpu, X86_S_CS, seg, &cpu->pc);
2686    
2687     /*
2688     * If we're changing privilege level, the we should change
2689     * stack here, and push the old SS:ESP.
2690     */
2691     if ((seg & X86_PL_MASK) < (old_cs & X86_PL_MASK)) {
2692     unsigned char buf[16];
2693     uint16_t new_ss, old_ss;
2694     uint32_t new_esp, old_esp;
2695     int pl;
2696    
2697     pl = seg & X86_PL_MASK;
2698    
2699     /* Load SSx:ESPx from the Task State Segment: */
2700     if (cpu->cd.x86.tr < 4)
2701     fatal("WARNING: interrupt with stack switch"
2702     ", but task register = 0?\n");
2703    
2704     /* fatal("::: old SS:ESP=0x%04x:0x%08x\n",
2705     (int)cpu->cd.x86.s[X86_S_SS],
2706     (int)cpu->cd.x86.r[X86_R_SP]); */
2707    
2708     if (!cpu->memory_rw(cpu, cpu->mem, 4 + pl*8 +
2709     cpu->cd.x86.tr_base, buf, sizeof(buf), MEM_READ,
2710     NO_SEGMENTATION)) {
2711     fatal("ERROR: couldn't read tss blah blah\n");
2712     cpu->running = 0;
2713     return 0;
2714     }
2715    
2716     new_esp = buf[0] + (buf[1] << 8) +
2717     (buf[2] << 16) + (buf[3] << 24);
2718     new_ss = buf[4] + (buf[5] << 8);
2719    
2720     old_ss = cpu->cd.x86.s[X86_S_SS];
2721     old_esp = cpu->cd.x86.r[X86_R_SP];
2722    
2723     reload_segment_descriptor(cpu, X86_S_SS, new_ss, NULL);
2724     cpu->cd.x86.r[X86_R_SP] = new_esp;
2725    
2726     fatal("::: Switching Stack: new SS:ESP=0x%04x:0x%08x\n",
2727     (int)new_ss, (int)new_esp);
2728    
2729     mode = cpu->cd.x86.descr_cache[X86_S_CS].
2730     default_op_size;
2731    
2732     if (!x86_push(cpu, old_ss, mode)) {
2733     fatal("TODO: problem adgsadg 1\n");
2734     cpu->running = 0;
2735     }
2736     if (!x86_push(cpu, old_esp, mode)) {
2737     fatal("TODO: problem adgsadg 2\n");
2738     cpu->running = 0;
2739     }
2740     }
2741    
2742     /* Push flags, cs, and ip (pc): */
2743     mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
2744     if (!x86_push(cpu, cpu->cd.x86.rflags, mode)) {
2745     fatal("TODO: how to handle this 1 asdf\n");
2746     cpu->running = 0;
2747     }
2748     if (!x86_push(cpu, old_cs, mode)) {
2749     fatal("TODO: how to handle this 2 sdghser\n");
2750     cpu->running = 0;
2751     }
2752     if (!x86_push(cpu, cpu->pc, mode)) {
2753     fatal("TODO: how to handle this 3 we\n");
2754     cpu->running = 0;
2755     }
2756    
2757     /* Push error code for some exceptions: */
2758     if ((nr >= 8 && nr <=14) || nr == 17) {
2759     if (!x86_push(cpu, errcode, mode)) {
2760     fatal("x86_interrupt(): TODO: asdgblah\n");
2761     cpu->running = 0;
2762     }
2763     }
2764    
2765     /* Only turn off interrupts for Interrupt Gates: */
2766     if (int_type == INT_TYPE_INTGATE)
2767     cpu->cd.x86.rflags &= ~X86_FLAGS_IF;
2768    
2769     /* Turn off TF for Interrupt and Trap Gates: */
2770     if (int_type == INT_TYPE_INTGATE ||
2771     int_type == INT_TYPE_TRAPGATE)
2772     cpu->cd.x86.rflags &= ~X86_FLAGS_TF;
2773    
2774     goto int_jump;
2775     }
2776    
2777     /*
2778     * Real mode:
2779     */
2780 dpavlin 22 if (nr * 4 > (int)cpu->cd.x86.idtr_limit) {
2781 dpavlin 14 fatal("TODO: real mode int 0x%02x outside idtr limit ("
2782     "%i)?\n", nr, (int)cpu->cd.x86.idtr_limit);
2783     cpu->running = 0;
2784     return 0;
2785     }
2786     /* Read the interrupt vector: */
2787     res = cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.idtr + nr*4, buf, 4,
2788     MEM_READ, NO_SEGMENTATION);
2789     if (!res) {
2790     fatal("x86_interrupt(): could not read the"
2791     " interrupt descriptor table\n");
2792     cpu->running = 0;
2793     return 0;
2794     }
2795     ofs = buf[0] + (buf[1] << 8); seg = buf[2] + (buf[3] << 8);
2796    
2797     reload_segment_descriptor(cpu, X86_S_CS, seg, &cpu->pc);
2798    
2799     /* Push old flags, old cs, and old ip (pc): */
2800     mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
2801    
2802     if (!x86_push(cpu, cpu->cd.x86.rflags, mode)) {
2803     fatal("x86_interrupt(): TODO: how to handle this 4\n");
2804     cpu->running = 0;
2805     }
2806     if (!x86_push(cpu, old_cs, mode)) {
2807     fatal("x86_interrupt(): TODO: how to handle this 5\n");
2808     cpu->running = 0;
2809     }
2810     if (!x86_push(cpu, cpu->pc, mode)) {
2811     fatal("x86_interrupt(): TODO: how to handle this 6\n");
2812     cpu->running = 0;
2813     }
2814    
2815     /* Turn off interrupts and the Trap Flag, and jump to the interrupt
2816     handler: */
2817     cpu->cd.x86.rflags &= ~(X86_FLAGS_IF | X86_FLAGS_TF);
2818    
2819     int_jump:
2820     cpu->pc = ofs;
2821    
2822     return 1;
2823     }
2824    
2825    
2826     #define CALCFLAGS_OP_ADD 1
2827     #define CALCFLAGS_OP_SUB 2
2828     #define CALCFLAGS_OP_XOR 3
2829     /*
2830     * x86_calc_flags():
2831     */
2832     void x86_calc_flags(struct cpu *cpu, uint64_t a, uint64_t b, int mode,
2833     int op)
2834     {
2835     uint64_t c=0, mask;
2836     int i, count;
2837    
2838     if (mode == 8)
2839     mask = 0xff;
2840     else if (mode == 16)
2841     mask = 0xffff;
2842     else if (mode == 32)
2843     mask = 0xffffffffULL;
2844     else if (mode == 64)
2845     mask = 0xffffffffffffffffULL;
2846     else {
2847     fatal("x86_calc_flags(): Bad mode (%i)\n", mode);
2848     return;
2849     }
2850    
2851     a &= mask;
2852     b &= mask;
2853    
2854     /* CF: */
2855     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
2856     switch (op) {
2857     case CALCFLAGS_OP_ADD:
2858     if (((a + b)&mask) < a && ((a + b)&mask) < b)
2859     cpu->cd.x86.rflags |= X86_FLAGS_CF;
2860     break;
2861     case CALCFLAGS_OP_SUB:
2862     if (a < b)
2863     cpu->cd.x86.rflags |= X86_FLAGS_CF;
2864     break;
2865     case CALCFLAGS_OP_XOR:
2866     break;
2867     }
2868    
2869     switch (op) {
2870     case CALCFLAGS_OP_ADD:
2871     c = (a + b) & mask;
2872     break;
2873     case CALCFLAGS_OP_SUB:
2874     c = (a - b) & mask;
2875     break;
2876     case CALCFLAGS_OP_XOR:
2877     c = a;
2878     }
2879    
2880     /* ZF: */
2881     cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;
2882     if (c == 0)
2883     cpu->cd.x86.rflags |= X86_FLAGS_ZF;
2884    
2885     /* SF: */
2886     cpu->cd.x86.rflags &= ~X86_FLAGS_SF;
2887     if ((mode == 8 && (c & 0x80)) ||
2888     (mode == 16 && (c & 0x8000)) ||
2889     (mode == 32 && (c & 0x80000000ULL)) ||
2890     (mode == 64 && (c & 0x8000000000000000ULL))) {
2891     cpu->cd.x86.rflags |= X86_FLAGS_SF;
2892     }
2893    
2894     /* OF: */
2895     cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
2896     switch (op) {
2897     case CALCFLAGS_OP_ADD:
2898     /* TODO */
2899     break;
2900     case CALCFLAGS_OP_SUB:
2901     if (cpu->cd.x86.rflags & X86_FLAGS_SF)
2902     cpu->cd.x86.rflags |= X86_FLAGS_OF;
2903     if (mode == 8 && (int8_t)a < (int8_t)b)
2904     cpu->cd.x86.rflags ^= X86_FLAGS_OF;
2905     if (mode == 16 && (int16_t)a < (int16_t)b)
2906     cpu->cd.x86.rflags ^= X86_FLAGS_OF;
2907     if (mode == 32 && (int32_t)a < (int32_t)b)
2908     cpu->cd.x86.rflags ^= X86_FLAGS_OF;
2909     break;
2910     case CALCFLAGS_OP_XOR:
2911     ;
2912     }
2913    
2914     /* AF: */
2915     switch (op) {
2916     case CALCFLAGS_OP_ADD:
2917     if ((a & 0xf) + (b & 0xf) > 15)
2918     cpu->cd.x86.rflags |= X86_FLAGS_AF;
2919     else
2920     cpu->cd.x86.rflags &= ~X86_FLAGS_AF;
2921     break;
2922     case CALCFLAGS_OP_SUB:
2923     if ((b & 0xf) > (a & 0xf))
2924     cpu->cd.x86.rflags |= X86_FLAGS_AF;
2925     else
2926     cpu->cd.x86.rflags &= ~X86_FLAGS_AF;
2927     break;
2928     case CALCFLAGS_OP_XOR:
2929     ;
2930     }
2931    
2932     /* PF: (NOTE: Only the lowest 8 bits) */
2933     cpu->cd.x86.rflags &= ~X86_FLAGS_PF;
2934     count = 0;
2935     for (i=0; i<8; i++) {
2936     if (c & 1)
2937     count ++;
2938     c >>= 1;
2939     }
2940     if (!(count&1))
2941     cpu->cd.x86.rflags |= X86_FLAGS_PF;
2942     }
2943    
2944    
2945     /*
2946     * x86_condition():
2947     *
2948     * Returns 0 or 1 (false or true) depending on flag bits.
2949     */
2950     int x86_condition(struct cpu *cpu, int op)
2951     {
2952     int success = 0;
2953    
2954     switch (op & 0xe) {
2955     case 0x00: /* o */
2956     success = cpu->cd.x86.rflags & X86_FLAGS_OF;
2957     break;
2958     case 0x02: /* c */
2959     success = cpu->cd.x86.rflags & X86_FLAGS_CF;
2960     break;
2961     case 0x04: /* z */
2962     success = cpu->cd.x86.rflags & X86_FLAGS_ZF;
2963     break;
2964     case 0x06: /* be */
2965     success = (cpu->cd.x86.rflags & X86_FLAGS_ZF) ||
2966     (cpu->cd.x86.rflags & X86_FLAGS_CF);
2967     break;
2968     case 0x08: /* s */
2969     success = cpu->cd.x86.rflags & X86_FLAGS_SF;
2970     break;
2971     case 0x0a: /* p */
2972     success = cpu->cd.x86.rflags & X86_FLAGS_PF;
2973     break;
2974     case 0x0c: /* nge */
2975     success = (cpu->cd.x86.rflags & X86_FLAGS_SF? 1 : 0)
2976     != (cpu->cd.x86.rflags & X86_FLAGS_OF? 1 : 0);
2977     break;
2978     case 0x0e: /* ng */
2979     success = (cpu->cd.x86.rflags & X86_FLAGS_SF? 1 : 0)
2980     != (cpu->cd.x86.rflags & X86_FLAGS_OF? 1 : 0);
2981     success |= (cpu->cd.x86.rflags & X86_FLAGS_ZF ? 1 : 0);
2982     break;
2983     }
2984    
2985     if (op & 1)
2986     success = !success;
2987    
2988     return success? 1 : 0;
2989     }
2990    
2991    
2992     /*
2993     * x86_shiftrotate():
2994     */
2995     void x86_shiftrotate(struct cpu *cpu, uint64_t *op1p, int op,
2996     int n, int mode)
2997     {
2998     uint64_t op1 = *op1p;
2999     int cf = -1, oldcf = 0;
3000    
3001     n &= 31;
3002     if (mode != 64)
3003     op1 &= (((uint64_t)1 << mode) - 1);
3004    
3005     oldcf = cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0;
3006    
3007     while (n-- > 0) {
3008     cf = 0;
3009    
3010     if (op & 1) { /* right */
3011     if (op1 & 1)
3012     cf = 1;
3013     } else { /* left */
3014     cf = (op1 & ((uint64_t)1 << (mode-1)))? 1 : 0;
3015     }
3016    
3017     switch (op) {
3018     case 0: /* rol */
3019     op1 = (op1 << 1) | cf;
3020     break;
3021     case 1: /* ror */
3022     op1 >>= 1;
3023     op1 |= ((uint64_t)cf << (mode - 1));
3024     break;
3025     case 2: /* rcl */
3026     op1 = (op1 << 1) | oldcf;
3027     oldcf = cf;
3028     break;
3029     case 3: /* rcr */
3030     op1 >>= 1;
3031     op1 |= ((uint64_t)oldcf << (mode - 1));
3032     oldcf = cf;
3033     break;
3034     case 4: /* shl */
3035     case 6: /* sal */
3036     op1 <<= 1;
3037     break;
3038     case 5: /* shr */
3039     op1 >>= 1;
3040     break;
3041     case 7: /* sar */
3042     op1 >>= 1;
3043     if (mode == 8 && op1 & 0x40)
3044     op1 |= 0x80;
3045     if (mode == 16 && op1 & 0x4000)
3046     op1 |= 0x8000;
3047     if (mode == 32 && op1 & 0x40000000ULL)
3048     op1 |= 0x80000000ULL;
3049     break;
3050     default:
3051     fatal("x86_shiftrotate(): unimplemented op %i\n", op);
3052     cpu->running = 0;
3053     }
3054     if (mode != 64)
3055     op1 &= (((uint64_t)1 << mode) - 1);
3056     x86_calc_flags(cpu, op1, 0, mode, CALCFLAGS_OP_XOR);
3057     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3058     if (cf)
3059     cpu->cd.x86.rflags |= X86_FLAGS_CF;
3060     }
3061    
3062     /* TODO: OF flag */
3063    
3064     *op1p = op1;
3065     }
3066    
3067    
3068     /*
3069     * x86_msr():
3070     *
3071     * This function reads or writes the MSRs (Model Specific Registers).
3072     */
3073     void x86_msr(struct cpu *cpu, int writeflag)
3074     {
3075     uint32_t regnr = cpu->cd.x86.r[X86_R_CX] & 0xffffffff;
3076     uint64_t odata=0, idata = (cpu->cd.x86.r[X86_R_AX] & 0xffffffff) +
3077     ((cpu->cd.x86.r[X86_R_DX] & 0xffffffff) << 32);
3078    
3079     switch (regnr) {
3080     case 0xc0000080: /* AMD64 EFER */
3081     if (writeflag) {
3082     if (cpu->cd.x86.efer & X86_EFER_LME &&
3083     !(idata & X86_EFER_LME))
3084     debug("[ switching FROM 64-bit mode ]\n");
3085     if (!(cpu->cd.x86.efer & X86_EFER_LME) &&
3086     idata & X86_EFER_LME)
3087     debug("[ switching to 64-bit mode ]\n");
3088     cpu->cd.x86.efer = idata;
3089     } else
3090     odata = cpu->cd.x86.efer;
3091     break;
3092     default:fatal("x86_msr: unimplemented MSR 0x%08x\n", (int)regnr);
3093     cpu->running = 0;
3094     }
3095    
3096     if (!writeflag) {
3097     cpu->cd.x86.r[X86_R_AX] = odata & 0xffffffff;
3098     cpu->cd.x86.r[X86_R_DX] = (odata >> 32) & 0xffffffff;
3099     }
3100     }
3101    
3102    
3103     /*
3104     * cause_interrupt():
3105     *
3106     * Read the registers of PIC1 (and possibly PIC2) to find out which interrupt
3107     * has occured.
3108     *
3109     * Returns 1 if an interrupt happened, 0 otherwise (for example if the
3110     * in-service bit of an interrupt was already set).
3111     */
3112     int cause_interrupt(struct cpu *cpu)
3113     {
3114     int i, irq_nr = -1;
3115    
3116     for (i=0; i<8; i++) {
3117     if (cpu->machine->isa_pic_data.pic1->irr &
3118     (~cpu->machine->isa_pic_data.pic1->ier) & (1 << i))
3119     irq_nr = i;
3120     }
3121    
3122     if (irq_nr == 2) {
3123     for (i=0; i<8; i++) {
3124     if (cpu->machine->isa_pic_data.pic2->irr &
3125     (~cpu->machine->isa_pic_data.pic2->ier) & (1 << i))
3126     irq_nr = 8+i;
3127     }
3128     }
3129    
3130     if (irq_nr == 2) {
3131     fatal("cause_interrupt(): Huh? irq 2 but no secondary irq\n");
3132     cpu->running = 0;
3133     }
3134    
3135     /*
3136     * TODO: How about multiple interrupt levels?
3137     */
3138    
3139     #if 0
3140     printf("cause1: %i (irr1=%02x ier1=%02x, irr2=%02x ier2=%02x\n", irq_nr,
3141     cpu->machine->isa_pic_data.pic1->irr, cpu->machine->isa_pic_data.pic1->ier,
3142     cpu->machine->isa_pic_data.pic2->irr, cpu->machine->isa_pic_data.pic2->ier);
3143     #endif
3144    
3145     /* Set the in-service bit, and calculate actual INT nr: */
3146     if (irq_nr < 8) {
3147     if (cpu->machine->isa_pic_data.pic1->isr & (1 << irq_nr))
3148     return 0;
3149     cpu->machine->isa_pic_data.pic1->isr |= (1 << irq_nr);
3150     irq_nr = cpu->machine->isa_pic_data.pic1->irq_base + irq_nr;
3151     } else {
3152     if (cpu->machine->isa_pic_data.pic2->isr & (1 << (irq_nr & 7)))
3153     return 0;
3154     cpu->machine->isa_pic_data.pic2->isr |= (1 << (irq_nr&7));
3155     irq_nr = cpu->machine->isa_pic_data.pic2->irq_base +
3156     (irq_nr & 7);
3157     }
3158    
3159     /* printf("cause2: %i\n", irq_nr); */
3160    
3161     x86_interrupt(cpu, irq_nr, 0);
3162     cpu->cd.x86.halted = 0;
3163     return 1;
3164     }
3165    
3166    
3167 dpavlin 26 #define TRANSLATE_ADDRESS x86_translate_v2p
3168 dpavlin 14 #include "memory_x86.c"
3169     #undef TRANSLATE_ADDRESS
3170    
3171    
3172     #include "tmp_x86_tail.c"
3173    

  ViewVC Help
Powered by ViewVC 1.1.26