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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (13 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 86245 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26