/[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 20 - (hide annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 86242 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26