/[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 14 - (hide annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 86207 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

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

  ViewVC Help
Powered by ViewVC 1.1.26