/[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 22 - (hide annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 86245 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26