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

Annotation of /trunk/src/cpus/cpu_x86.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 24 - (hide annotations)
Mon Oct 8 16:19:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 87347 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1256 2006/06/23 20:43:44 debug Exp $
20060219	Various minor updates. Removing the old MIPS16 skeleton code,
		because it will need to be rewritten for dyntrans anyway.
20060220-22	Removing the non-working dyntrans backend support.
		Continuing on the 64-bit dyntrans virtual memory generalization.
20060223	More work on the 64-bit vm generalization.
20060225	Beginning on MIPS dyntrans load/store instructions.
		Minor PPC updates (64-bit load/store, etc).
		Fixes for the variable-instruction-length framework, some
		minor AVR updates (a simple Hello World program works!).
		Beginning on a skeleton for automatically generating documen-
		tation (for devices etc.).
20060226	PPC updates (adding some more 64-bit instructions, etc).
		AVR updates (more instructions).
		FINALLY found and fixed the zs bug, making NetBSD/macppc
		accept the serial console.
20060301	Adding more AVR instructions.
20060304	Continuing on AVR-related stuff. Beginning on a framework for
		cycle-accurate device emulation. Adding an experimental "PAL
		TV" device (just a dummy so far).
20060305	Adding more AVR instructions.
		Adding a dummy epcom serial controller (for TS7200 emulation).
20060310	Removing the emul() command from configuration files, so only
		net() and machine() are supported.
		Minor progress on the MIPS dyntrans rewrite.
20060311	Continuing on the MIPS dyntrans rewrite (adding more
		instructions, etc).
20060315	Adding more instructions (sllv, srav, srlv, bgtz[l], blez[l],
		beql, bnel, slti[u], various loads and stores).
20060316	Removing the ALWAYS_SIGNEXTEND_32 option, since it was rarely
		used.
		Adding more MIPS dyntrans instructions, and fixing bugs.
20060318	Implementing fast loads/stores for MIPS dyntrans (big/little
		endian, 32-bit and 64-bit modes).
20060320	Making MIPS dyntrans the default configure option; use
		"--enable-oldmips" to use the old bintrans system.
		Adding MIPS dyntrans dmult[u]; minor updates.
20060322	Continuing... adding some more instructions.
		Adding a simple skeleton for demangling C++ "_ZN" symbols.
20060323	Moving src/debugger.c into a new directory (src/debugger/).
20060324	Fixing the hack used to load PPC ELFs (useful for relocated
		Linux/ppc kernels), and adding a dummy G3 machine mode.
20060325-26	Beginning to experiment with GDB remote serial protocol
		connections; adding a -G command line option for selecting
		which TCP port to listen to.
20060330	Beginning a major cleanup to replace things like "0x%016llx"
		with more correct "0x%016"PRIx64, etc.
		Continuing on the GDB remote serial protocol support.
20060331	More cleanup, and some minor GDB remote progress.
20060402	Adding a hack to the configure script, to allow compilation
		on systems that lack PRIx64 etc.
20060406	Removing the temporary FreeBSD/arm hack in dev_ns16550.c and
		replacing it with a better fix from Olivier Houchard.
20060407	A remote debugger (gdb or ddd) can now start and stop the
		emulator using the GDB remote serial protocol, and registers
		and memory can be read. MIPS only for now.
20060408	More GDB progress: single-stepping also works, and also adding
		support for ARM, PowerPC, and Alpha targets.
		Continuing on the delay-slot-across-page-boundary issue.
20060412	Minor update: beginning to add support for the SPARC target
		to the remote GDB functionality.
20060414	Various MIPS updates: adding more instructions for dyntrans
		(eret, add), and making some exceptions work. Fixing a bug
		in dmult[u].
		Implementing the first SPARC instructions (sethi, or).
20060415	Adding "magic trap" instructions so that PROM calls can be
		software emulated in MIPS dyntrans.
		Adding more MIPS dyntrans instructions (ddiv, dadd) and
		fixing another bug in dmult.
20060416	More MIPS dyntrans progress: adding [d]addi, movn, movz, dsllv,
		rfi, an ugly hack for supporting R2000/R3000 style faked caches,
		preliminary interrupt support, and various other updates and
		bugfixes.
20060417	Adding more SPARC instructions (add, sub, sll[x], sra[x],
		srl[x]), and useful SPARC header definitions.
		Adding the first (trivial) x86/AMD64 dyntrans instructions (nop,
		cli/sti, stc/clc, std/cld, simple mov, inc ax). Various other
		x86 updates related to variable instruction length stuff.
		Adding unaligned loads/stores to the MIPS dyntrans mode (but
		still using the pre-dyntrans (slow) imlementation).
20060419	Fixing a MIPS dyntrans exception-in-delay-slot bug.
		Removing the old "show opcode statistics" functionality, since
		it wasn't really useful and isn't implemented for dyntrans.
		Single-stepping (or running with instruction trace) now looks
		ok with dyntrans with delay-slot architectures.
20060420	Minor hacks (removing the -B command line option when compiled
		for non-bintrans, and some other very minor updates).
		Adding (slow) MIPS dyntrans load-linked/store-conditional.
20060422	Applying fixes for bugs discovered by Nils Weller's nwcc
		(static DEC memmap => now per machine, and adding an extern
		keyword in cpu_arm_instr.c).
		Finally found one of the MIPS dyntrans bugs that I've been
		looking for (copy/paste spelling error BIG vs LITTLE endian in
		cpu_mips_instr_loadstore.c for 16-bit fast stores).
		FINALLY found the major MIPS dyntrans bug: slti vs sltiu
		signed/unsigned code in cpu_mips_instr.c. :-)
		Adding more MIPS dyntrans instructions (lwc1, swc1, bgezal[l],
		ctc1, tlt[u], tge[u], tne, beginning on rdhwr).
		NetBSD/hpcmips can now reach userland when using dyntrans :-)
		Adding some more x86 dyntrans instructions.
		Finally removed the old Alpha-specific virtual memory code,
		and replaced it with the generic 64-bit version.
		Beginning to add disassembly support for SPECIAL3 MIPS opcodes.
20060423	Continuing on the delay-slot-across-page-boundary issue;
		adding an end_of_page2 ic slot (like I had planned before, but
		had removed for some reason).
		Adding a quick-and-dirty fallback to legacy coprocessor 1
		code (i.e. skipping dyntrans implementation for now).
		NetBSD/hpcmips and NetBSD/pmax (when running on an emulated
		R4400) can now be installed and run. :-)  (Many bugs left
		to fix, though.)
		Adding more MIPS dyntrans instructions: madd[u], msub[u].
		Cleaning up the SPECIAL2 vs R5900/TX79/C790 "MMI" opcode
		maps somewhat (disassembly and dyntrans instruction decoding).
20060424	Adding an isa_revision field to mips_cpu_types.h, and making
		sure that SPECIAL3 opcodes cause Reserved Instruction
		exceptions on MIPS32/64 revisions lower than 2.
		Adding the SPARC 'ba', 'call', 'jmpl/retl', 'and', and 'xor'
		instructions.
20060425	Removing the -m command line option ("run at most x 
		instructions") and -T ("single_step_on_bad_addr"), because
		they never worked correctly with dyntrans anyway.
		Freshening up the man page.
20060428	Adding more MIPS dyntrans instructions: bltzal[l], idle.
		Enabling MIPS dyntrans compare interrupts.
20060429	FINALLY found the weird dyntrans bug, causing NetBSD etc. to
		behave strangely: some floating point code (conditional
		coprocessor branches) could not be reused from the old
		non-dyntrans code. The "quick-and-dirty fallback" only appeared
		to work. Fixing by implementing bc1* for MIPS dyntrans.
		More MIPS instructions: [d]sub, sdc1, ldc1, dmtc1, dmfc1, cfc0.
		Freshening up MIPS floating point disassembly appearance.
20060430	Continuing on C790/R5900/TX79 disassembly; implementing 128-bit
		"por" and "pextlw".
20060504	Disabling -u (userland emulation) unless compiled as unstable
		development version.
		Beginning on freshening up the testmachine include files,
		to make it easier to reuse those files (placing them in
		src/include/testmachine/), and beginning on a set of "demos"
		or "tutorials" for the testmachine functionality.
		Minor updates to the MIPS GDB remote protocol stub.
		Refreshing doc/experiments.html and gdb_remote.html.
		Enabling Alpha emulation in the stable release configuration,
		even though no guest OSes for Alpha can run yet.
20060505	Adding a generic 'settings' object, which will contain
		references to settable variables (which will later be possible
		to access using the debugger).
20060506	Updating dev_disk and corresponding demo/documentation (and
		switching from SCSI to IDE disk types, so it actually works
		with current test machines :-).
20060510	Adding a -D_LARGEFILE_SOURCE hack for 64-bit Linux hosts,
		so that fseeko() doesn't give a warning.
		Updating the section about how dyntrans works (the "runnable
		IR") in doc/intro.html.
		Instruction updates (some x64=1 checks, some more R5900
		dyntrans stuff: better mul/mult separation from MIPS32/64,
		adding ei and di).
		Updating MIPS cpuregs.h to a newer one (from NetBSD).
		Adding more MIPS dyntrans instructions: deret, ehb.
20060514	Adding disassembly and beginning implementation of SPARC wr
		and wrpr instructions.
20060515	Adding a SUN SPARC machine mode, with dummy SS20 and Ultra1
		machines. Adding the 32-bit "rd psr" instruction.
20060517	Disassembly support for the general SPARC rd instruction.
		Partial implementation of the cmp (subcc) instruction.
		Some other minor updates (making sure that R5900 processors
		start up with the EIE bit enabled, otherwise Linux/playstation2
		receives no interrupts).
20060519	Minor MIPS updates/cleanups.
20060521	Moving the MeshCube machine into evbmips; this seems to work
		reasonably well with a snapshot of a NetBSD MeshCube kernel.
		Cleanup/fix of MIPS config0 register initialization.
20060529	Minor MIPS fixes, including a sign-extension fix to the
		unaligned load/store code, which makes NetBSD/pmax on R3000
		work better with dyntrans. (Ultrix and Linux/DECstation still
		don't work, though.)
20060530	Minor updates to the Alpha machine mode: adding an AlphaBook
		mode, an LCA bus (forwarding accesses to an ISA bus), etc.
20060531	Applying a bugfix for the MIPS dyntrans sc[d] instruction from
		Ondrej Palkovsky. (Many thanks.)
20060601	Minifix to allow ARM immediate msr instruction to not give
		an error for some valid values.
		More Alpha updates.
20060602	Some minor Alpha updates.
20060603	Adding the Alpha cmpbge instruction. NetBSD/alpha prints its
		first boot messages :-) on an emulated Alphabook 1.
20060612	Minor updates; adding a dev_ether.h include file for the
		testmachine ether device. Continuing the hunt for the dyntrans
		bug which makes Linux and Ultrix on DECstation behave
		strangely... FINALLY found it! It seems to be related to
		invalidation of the translation cache, on tlbw{r,i}. There
		also seems to be some remaining interrupt-related problems.
20060614	Correcting the implementation of ldc1/sdc1 for MIPS dyntrans
		(so that it uses 16 32-bit registers if the FR bit in the
		status register is not set).
20060616	REMOVING BINTRANS COMPLETELY!
		Removing the old MIPS interpretation mode.
		Removing the MFHILO_DELAY and instruction delay stuff, because
		they wouldn't work with dyntrans anyway.
20060617	Some documentation updates (adding "NetBSD-archive" to some
		URLs, and new Debian/DECstation installation screenshots).
		Removing the "tracenull" and "enable-caches" configure options.
		Improving MIPS dyntrans performance somewhat (only invalidate
		translations if necessary, on writes to the entryhi register,
		instead of doing it for all cop0 writes).
20060618	More cleanup after the removal of the old MIPS emulation.
		Trying to fix the MIPS dyntrans performance bugs/bottlenecks;
		only semi-successful so far (for R3000).
20060620	Minor update to allow clean compilation again on Tru64/Alpha.
20060622	MIPS cleanup and fixes (removing the pc_last stuff, which
		doesn't make sense with dyntrans anyway, and fixing a cross-
		page-delay-slot-with-exception case in end_of_page).
		Removing the old max_random_cycles_per_chunk stuff, and the
		concept of cycles vs instructions for MIPS emulation.
		FINALLY found and fixed the bug which caused NetBSD/pmax
		clocks to behave strangely (it was a load to the zero register,
		which was treated as a NOP; now it is treated as a load to a
		dummy scratch register).
20060623	Increasing the dyntrans chunk size back to
		N_SAFE_DYNTRANS_LIMIT, instead of N_SAFE_DYNTRANS_LIMIT/2.
		Preparing for a quick release, even though there are known
		bugs, and performance for non-R3000 MIPS emulation is very
		poor. :-/
		Reverting to half the dyntrans chunk size again, because
		NetBSD/cats seemed less stable with full size chunks. :(
		NetBSD/sgimips 3.0 can now run :-)  (With release 0.3.8, only
		NetBSD/sgimips 2.1 worked, not 3.0.)

==============  RELEASE 0.4.0  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26