/[gxemul]/trunk/src/cpu_x86.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/src/cpu_x86.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (hide annotations)
Mon Oct 8 16:18:38 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 86307 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.905 2005/08/16 09:16:24 debug Exp $
20050628	Continuing the work on the ARM translation engine. end_of_page
		works. Experimenting with load/store translation caches
		(virtual -> physical -> host).
20050629	More ARM stuff (memory access translation cache, mostly). This
		might break a lot of stuff elsewhere, probably some MIPS-
		related translation things.
20050630	Many load/stores are now automatically generated and included
		into cpu_arm_instr.c; 1024 functions in total (!).
		Fixes based on feedback from Alec Voropay: only print 8 hex
		digits instead of 16 in some cases when emulating 32-bit
		machines; similar 8 vs 16 digit fix for breakpoint addresses;
		4Kc has 16 TLB entries, not 48; the MIPS config select1
		register is now printed with "reg ,0".
		Also changing many other occurances of 16 vs 8 digit output.
		Adding cache associativity fields to mips_cpu_types.h; updating
		some other cache fields; making the output of
		mips_cpu_dumpinfo() look nicer.
		Generalizing the bintrans stuff for device accesses to also
		work with the new translation system. (This might also break
		some MIPS things.)
		Adding multi-load/store instructions to the ARM disassembler
		and the translator, and some optimizations of various kinds.
20050701	Adding a simple dev_disk (it can read/write sectors from
		disk images).
20050712	Adding dev_ether (a simple ethernet send/receive device).
		Debugger command "ninstrs" for toggling show_nr_of_instructions
		during runtime.
		Removing the framebuffer logo.
20050713	Continuing on dev_ether.
		Adding a dummy cpu_alpha (again).
20050714	More work on cpu_alpha.
20050715	More work on cpu_alpha. Many instructions work, enough to run
		a simple framebuffer fill test (similar to the ARM test).
20050716	More Alpha stuff.
20050717	Minor updates (Alpha stuff).
20050718	Minor updates (Alpha stuff).
20050719	Generalizing some Alpha instructions.
20050720	More Alpha-related updates.
20050721	Continuing on cpu_alpha. Importing rpb.h from NetBSD/alpha.
20050722	Alpha-related updates: userland stuff (Hello World using
		write() compiled statically for FreeBSD/Alpha runs fine), and
		more instructions are now implemented.
20050723	Fixing ldq_u and stq_u.
		Adding more instructions (conditional moves, masks, extracts,
		shifts).
20050724	More FreeBSD/Alpha userland stuff, and adding some more
		instructions (inserts).
20050725	Continuing on the Alpha stuff. (Adding dummy ldt/stt.)
		Adding a -A command line option to turn off alignment checks
		in some cases (for translated code).
		Trying to remove the old bintrans code which updated the pc
		and nr_of_executed_instructions for every instruction.
20050726	Making another attempt att removing the pc/nr of instructions
		code. This time it worked, huge performance increase for
		artificial test code, but performance loss for real-world
		code :-( so I'm scrapping that code for now.
		Tiny performance increase on Alpha (by using ret instead of
		jmp, to play nice with the Alpha's branch prediction) for the
		old MIPS bintrans backend.
20050727	Various minor fixes and cleanups.
20050728	Switching from a 2-level virtual to host/physical translation
		system for ARM emulation, to a 1-level translation.
		Trying to switch from 2-level to 1-level for the MIPS bintrans
		system as well (Alpha only, so far), but there is at least one
		problem: caches and/or how they work with device mappings.
20050730	Doing the 2-level to 1-level conversion for the i386 backend.
		The cache/device bug is still there for R2K/3K :(
		Various other minor updates (Malta etc).
		The mc146818 clock now updates the UIP bit in a way which works
		better with Linux for at least sgimips and Malta emulation.
		Beginning the work on refactoring the dyntrans system.
20050731	Continuing the dyntrans refactoring.
		Fixing a small but serious host alignment bug in memory_rw.
		Adding support for big-endian load/stores to the i386 bintrans
		backend.
		Another minor i386 bintrans backend update: stores from the
		zero register are now one (or two) loads shorter.
		The slt and sltu instructions were incorrectly implemented for
		the i386 backend; only using them for 32-bit mode for now.
20050801	Continuing the dyntrans refactoring.
		Cleanup of the ns16550 serial controller (removing unnecessary
		code).
		Bugfix (memory corruption bug) in dev_gt, and a patch/hack from
		Alec Voropay for Linux/Malta.
20050802	More cleanup/refactoring of the dyntrans subsystem: adding
		phys_page pointers to the lookup tables, for quick jumps
		between translated pages.
		Better fix for the ns16550 device (but still no real FIFO
		functionality).
		Converting cpu_ppc to the new dyntrans system. This means that
		I will have to start from scratch with implementing each
		instruction, and figure out how to implement dual 64/32-bit
		modes etc.
		Removing the URISC CPU family, because it was useless.
20050803	When selecting a machine type, the main type can now be omitted
		if the subtype name is unique. (I.e. -E can be omitted.)
		Fixing a dyntrans/device update bug. (Writes to offset 0 of
		a device could sometimes go unnoticed.)
		Adding an experimental "instruction combination" hack for
		ARM for memset-like byte fill loops.
20050804	Minor progress on cpu_alpha and related things.
		Finally fixing the MIPS dmult/dmultu bugs.
		Fixing some minor TODOs.
20050805	Generalizing the 8259 PIC. It now also works with Cobalt
		and evbmips emulation, in addition to the x86 hack.
		Finally converting the ns16550 device to use devinit.
		Continuing the work on the dyntrans system. Thinking about
		how to add breakpoints.
20050806	More dyntrans updates. Breakpoints seem to work now.
20050807	Minor updates: cpu_alpha and related things; removing
		dev_malta (as it isn't used any more).
		Dyntrans: working on general "show trace tree" support.
		The trace tree stuff now works with both the old MIPS code and
		with newer dyntrans modes. :)
		Continuing on Alpha-related stuff (trying to get *BSD to boot
		a bit further, adding more instructions, etc).
20050808	Adding a dummy IA64 cpu family, and continuing the refactoring
		of the dyntrans system.
		Removing the regression test stuff, because it was more or
		less useless.
		Adding loadlinked/storeconditional type instructions to the
		Alpha emulation. (Needed for Linux/alpha. Not very well tested
		yet.)
20050809	The function call trace tree now prints a per-function nr of
		arguments. (Semi-meaningless, since that data isn't read yet
		from the ELFs; some hardcoded symbols such as memcpy() and
		strlen() work fine, though.)
		More dyntrans refactoring; taking out more of the things that
		are common to all cpu families.
20050810	Working on adding support for "dual mode" for PPC dyntrans
		(i.e. both 64-bit and 32-bit modes).
		(Re)adding some simple PPC instructions.
20050811	Adding a dummy M68K cpu family. The dyntrans system isn't ready
		for variable-length ISAs yet, so it's completely bogus so far.
		Re-adding more PPC instructions.
		Adding a hack to src/file.c which allows OpenBSD/mac68k a.out
		kernels to be loaded.
		Beginning to add PPC loads/stores. So far they only work in
		32-bit mode.
20050812	The configure file option "add_remote" now accepts symbolic
		host names, in addition to numeric IPv4 addresses.
		Re-adding more PPC instructions.
20050814	Continuing to port back more PPC instructions.
		Found and fixed the cache/device write-update bug for 32-bit
		MIPS bintrans. :-)
		Triggered a really weird and annoying bug in Compaq's C
		compiler; ccc sometimes outputs code which loads from an
		address _before_ checking whether the pointer was NULL or not.
		(I'm not sure how to handle this problem.)
20050815	Removing all of the old x86 instruction execution code; adding
		a new (dummy) dyntrans module for x86.
		Taking the first steps to extend the dyntrans system to support
		variable-length instructions.
		Slowly preparing for the next release.
20050816	Adding a dummy SPARC cpu module.
		Minor updates (documentation etc) for the release.

==============  RELEASE 0.3.5  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26