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

Contents of /trunk/src/cpu_x86.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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


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

  ViewVC Help
Powered by ViewVC 1.1.26