/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 24 - (show 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 /*
2 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_x86.c,v 1.15 2006/06/16 18:31:26 debug Exp $
29 *
30 * x86 (and amd64) CPU emulation.
31 *
32 *
33 * TODO: Pretty much everything that has to do with 64-bit and 32-bit modes,
34 * memory translation, flag bits, and so on.
35 *
36 * See http://www.amd.com/us-en/Processors/DevelopWithAMD/
37 * 0,,30_2252_875_7044,00.html for more info on AMD64.
38 *
39 * http://www.cs.ucla.edu/~kohler/class/04f-aos/ref/i386/appa.htm has a
40 * nice overview of the standard i386 opcodes.
41 *
42 * HelpPC (http://members.tripod.com/~oldboard/assembly/) is also useful.
43 */
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <ctype.h>
49
50 #include "cpu.h"
51 #include "devices.h"
52 #include "machine.h"
53 #include "memory.h"
54 #include "misc.h"
55 #include "symbol.h"
56
57 #define DYNTRANS_DUALMODE_32
58 /* #define DYNTRANS_32 */
59 #define DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
60 #include "tmp_x86_head.c"
61
62
63 static struct x86_model models[] = x86_models;
64 static char *reg_names[N_X86_REGS] = x86_reg_names;
65 static char *reg_names_bytes[8] = x86_reg_names_bytes;
66 static char *seg_names[N_X86_SEGS] = x86_seg_names;
67 static char *cond_names[N_X86_CONDS] = x86_cond_names;
68
69 #define REP_REP 1
70 #define REP_REPNE 2
71
72
73 /*
74 * x86_cpu_new():
75 *
76 * Create a new x86 cpu object.
77 */
78 int x86_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine,
79 int cpu_id, char *cpu_type_name)
80 {
81 int i = 0;
82
83 /* Try to find a match: */
84 while (models[i].model_number != 0) {
85 if (strcasecmp(cpu_type_name, models[i].name) == 0)
86 break;
87 i++;
88 }
89
90 if (models[i].name == NULL)
91 return 0;
92
93 cpu->memory_rw = x86_memory_rw;
94 cpu->byte_order = EMUL_LITTLE_ENDIAN;
95
96 cpu->cd.x86.model = models[i];
97
98 cpu->translate_address = x86_translate_address;
99
100 /* 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 cpu->cd.x86.cursegment = X86_S_CS;
115
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 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 /* 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 x86_init_64bit_dummy_tables(cpu);
146
147 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 for (j=0; j<10-(int)strlen(models[i].name); j++)
174 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 if (LONG_MODE) {
195 /* 64-bit long mode: */
196 symbol = get_symbol_name(&cpu->machine->symbol_context,
197 cpu->pc, &offset);
198
199 debug("cpu%i: rip = 0x%016"PRIx64, x, cpu->pc);
200 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
201
202 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 } else {
234 /* 32-bit protected mode: */
235 symbol = get_symbol_name(&cpu->machine->symbol_context,
236 cpu->pc, &offset);
237
238 debug("cpu%i: eip=0x%08"PRIx32, x, (uint32_t)cpu->pc);
239 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
240
241 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 }
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 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 }
300
301 if (PROTECTED_MODE) {
302 /* Protected mode: */
303 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 }
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 uint32_t read_imm(unsigned char **instrp, uint64_t *newpcp,
523 int mode)
524 {
525 return read_imm_common(instrp, newpcp, mode, 0);
526 }
527
528
529 void print_csip(struct cpu *cpu)
530 {
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 * 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 * 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 fatal("WARNING: tr_limit = 0x%"PRIx16", must be at least "
697 "0x67!\n", (uint16_t)cpu->cd.x86.tr_limit);
698
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 uint64_t base, limit, table_base;
755 int64_t table_limit;
756
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 int running, uint64_t dumpaddr)
1535 {
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 void x86_cpuid(struct cpu *cpu)
2471 {
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 if (nr * 8 > (int)cpu->cd.x86.idtr_limit) {
2639 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 if (nr * 4 > (int)cpu->cd.x86.idtr_limit) {
2781 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