/[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 28 - (show annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 87369 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

==============  RELEASE 0.4.1  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26