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

Contents of /trunk/src/cpu_x86.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6 - (show annotations)
Mon Oct 8 16:18:11 2007 UTC (12 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 154695 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.772 2005/06/04 12:02:16 debug Exp $
20050428	Disabling the "-fmove-all-movables" option in the configure
		script, because it causes the compile to fail on OpenBSD/sgi.
20050502	Minor updates.
20050503	Removing the WRT54G mode (it was bogus anyway), and adding a
		comment about Windows NT for MIPS in doc/experiments.html.
		Minor updates to the x86 instruction decoding.
20050504	Adding some more x86 instructions.
		Adding support for reading files from ISO9660 CDROMs (including
		gzipped files). It's an ugly hack, but it seems to work.
		Various other minor updates (dev_vga.c, pc_bios.c etc).
20050505	Some more x86-related updates.
		Beginning (what I hope will be) a major code cleanup phase.
		"bootris" (an x86 bootsector) runs :-)
20050506	Adding some more x86 instructions.
20050507	tmpnam => mkstemp.
		Working on a hack to allow VGA charcells to be shown even when
		not running with X11.
		Adding more x86 instructions.
20050508	x86 32-bit SIB addressing fix, and more instructions.
20050509	Adding more x86 instructions.
20050510	Minor documentation updates, and other updates (x86 stuff etc.)
20050511	More x86-related updates.
20050513	Various updates, mostly x86-related. (Trying to fix flag 
		calculation, factoring out the ugly shift/rotate code, and
		some other things.)
20050514	Adding support for loading some old i386 a.out executables.
		Finally beginning the cleanup of machine/PROM/bios dependant
		info.
		Some minor documentation updates.
		Trying to clean up ARCBIOS stuff a little.
20050515	Trying to make it possible to actually use more than one disk
		type per machine (floppy, ide, scsi).
		Trying to clean up the kbd vs PROM console stuff. (For PC and
		ARC emulation modes, mostly.)
		Beginning to add an 8259 interrupt controller, and connecting
		it to the x86 emulation.
20050516	The first x86 interrupts seem to work (keyboard stuff).
		Adding a 8253/8254 programmable interval timer skeleton.
		FreeDOS now reaches a command prompt and can be interacted
		with.
20050517	After some bugfixes, MS-DOS also (sometimes) reaches a
		command prompt now.
		Trying to fix the pckbc to work with MS-DOS' keyb.com, but no
		success yet.
20050518	Adding a simple 32-bit x86 MMU skeleton.
20050519	Some more work on the x86 stuff. (Beginning the work on paging,
		and various other fixes).
20050520	More updates. Working on dev_vga (4-bit graphics modes), adding
		40 columns support to the PC bios emulation.
		Trying to add support for resizing windows when switching
		between graphics modes.
20050521	Many more x86-related updates.
20050522	Correcting the initial stack pointer's sign-extension for
		ARCBIOS emulation (thanks to Alec Voropay for noticing the
		error).
		Continuing on the cleanup (ARCBIOS etc).
		dev_vga updates.
20050523	More x86 updates: trying to add some support for protected mode
		interrupts (via gate descriptors) and many other fixes.
		More ARCBIOS cleanup.
		Adding a device flag which indicates that reads cause no
		side-effects. (Useful for the "dump" command in the debugger,
		and other things.)
		Adding support for directly starting up x86 ELFs, skipping the
		bootloader stage. (Most ELFs, however, are not suitable for
		this.)
20050524	Adding simple 32-bit x86 TSS task switching, but no privilege
		level support yet.
		More work on dev_vga. A small "Copper bars" demo works. :-)
		Adding support for Trap Flag (single-step exceptions), at least
		in real mode, and various other x86-related fixes.
20050525	Adding a new disk image prefix (gH;S;) which can be used to
		override the default nr of heads and sectors per track.
20050527	Various bug fixes, more work on the x86 mode (stack change on
		interrupts between different priv.levels), and some minor
		documentation updates.
20050528	Various fixes (x86 stuff).
20050529	More x86 fixes. An OpenBSD/i386 bootfloppy reaches userland
		and can be interacted with (although there are problems with
		key repetition). NetBSD/i386 triggers a serious CISC-related
		problem: instruction fetches across page boundaries, where
		the later part isn't actually part of the instruction.
20050530	Various minor updates. (Documentation updates, etc.)
20050531	Adding some experimental code (experiments/new_test_*) which
		could be useful for dynamic (but not binary) translation in
		the future.
20050602	Adding a dummy ARM skeleton.
		Fixing the pckbc key repetition problem (by adding release
		scancodes for all keypresses).
20050603	Minor updates for the next release.
20050604	Release testing. Minor updates.

==============  RELEASE 0.3.3  ==============

20050604	There'll probably be a 0.3.3.1 release soon, with some very
		very tiny updates.


1 /*
2 * Copyright (C) 2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_x86.c,v 1.161 2005/05/31 06:20:38 debug Exp $
29 *
30 * x86 (and amd64) CPU emulation.
31 *
32 *
33 * TODO: Pretty much everything that has to do with 64-bit and 32-bit modes,
34 * memory translation, flag bits, and so on.
35 *
36 * See http://www.amd.com/us-en/Processors/DevelopWithAMD/
37 * 0,,30_2252_875_7044,00.html for more info on AMD64.
38 *
39 * http://www.cs.ucla.edu/~kohler/class/04f-aos/ref/i386/appa.htm has a
40 * nice overview of the standard i386 opcodes.
41 *
42 * HelpPC (http://members.tripod.com/~oldboard/assembly/) is also useful.
43 */
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <ctype.h>
49
50 #include "misc.h"
51
52
53 #ifndef ENABLE_X86
54
55
56 #include "cpu_x86.h"
57
58 /* (Bogus, when ENABLE_X86 isn't defined.) */
59 int x86_cpu_family_init(struct cpu_family *fp) { return 0; }
60
61
62 #else /* ENABLE_X86 */
63
64
65 #include "cpu.h"
66 #include "cpu_x86.h"
67 #include "devices.h"
68 #include "machine.h"
69 #include "memory.h"
70 #include "symbol.h"
71
72
73 extern volatile int single_step;
74 extern int old_show_trace_tree;
75 extern int old_instruction_trace;
76 extern int old_quiet_mode;
77 extern int quiet_mode;
78
79
80 static struct x86_model models[] = x86_models;
81 static char *reg_names[N_X86_REGS] = x86_reg_names;
82 static char *reg_names_bytes[8] = x86_reg_names_bytes;
83 static char *seg_names[N_X86_SEGS] = x86_seg_names;
84 static char *cond_names[N_X86_CONDS] = x86_cond_names;
85
86 #define REP_REP 1
87 #define REP_REPNE 2
88
89
90 /*
91 * x86_cpu_new():
92 *
93 * Create a new x86 cpu object.
94 */
95 struct cpu *x86_cpu_new(struct memory *mem, struct machine *machine,
96 int cpu_id, char *cpu_type_name)
97 {
98 int i = 0;
99 struct cpu *cpu;
100
101 if (cpu_type_name == NULL)
102 return NULL;
103
104 /* Try to find a match: */
105 while (models[i].model_number != 0) {
106 if (strcasecmp(cpu_type_name, models[i].name) == 0)
107 break;
108 i++;
109 }
110
111 if (models[i].name == NULL)
112 return NULL;
113
114 cpu = malloc(sizeof(struct cpu));
115 if (cpu == NULL) {
116 fprintf(stderr, "out of memory\n");
117 exit(1);
118 }
119
120 memset(cpu, 0, sizeof(struct cpu));
121 cpu->memory_rw = x86_memory_rw;
122 cpu->name = cpu_type_name;
123 cpu->mem = mem;
124 cpu->machine = machine;
125 cpu->cpu_id = cpu_id;
126 cpu->byte_order = EMUL_LITTLE_ENDIAN;
127 cpu->bootstrap_cpu_flag = 0;
128 cpu->running = 0;
129
130 cpu->cd.x86.model = models[i];
131
132 /* Initial startup is in 16-bit real mode: */
133 cpu->pc = 0xfff0;
134
135 /* Initial segments: */
136 cpu->cd.x86.descr_cache[X86_S_CS].valid = 1;
137 cpu->cd.x86.descr_cache[X86_S_CS].default_op_size = 16;
138 cpu->cd.x86.descr_cache[X86_S_CS].access_rights = 0x93;
139 cpu->cd.x86.descr_cache[X86_S_CS].base = 0xf0000; /* ffff0000 */
140 cpu->cd.x86.descr_cache[X86_S_CS].limit = 0xffff;
141 cpu->cd.x86.descr_cache[X86_S_CS].descr_type = DESCR_TYPE_CODE;
142 cpu->cd.x86.descr_cache[X86_S_CS].readable = 1;
143 cpu->cd.x86.descr_cache[X86_S_CS].writable = 1;
144 cpu->cd.x86.descr_cache[X86_S_CS].granularity = 0;
145 cpu->cd.x86.s[X86_S_CS] = 0xf000;
146
147 cpu->cd.x86.idtr = 0;
148 cpu->cd.x86.idtr_limit = 0x3ff;
149
150 cpu->translate_address = translate_address_x86;
151
152 cpu->cd.x86.rflags = 0x0002;
153 if (cpu->cd.x86.model.model_number == X86_MODEL_8086)
154 cpu->cd.x86.rflags |= 0xf000;
155
156 /* Only show name and caches etc for CPU nr 0 (in SMP machines): */
157 if (cpu_id == 0) {
158 debug("%s", cpu->name);
159 }
160
161 return cpu;
162 }
163
164
165 /*
166 * x86_cpu_dumpinfo():
167 */
168 void x86_cpu_dumpinfo(struct cpu *cpu)
169 {
170 debug(", currently in %s mode", PROTECTED_MODE? "protected" : "real");
171 debug("\n");
172 }
173
174
175 /*
176 * x86_cpu_list_available_types():
177 *
178 * Print a list of available x86 CPU types.
179 */
180 void x86_cpu_list_available_types(void)
181 {
182 int i = 0, j;
183
184 while (models[i].model_number != 0) {
185 debug("%s", models[i].name);
186
187 for (j=0; j<10-strlen(models[i].name); j++)
188 debug(" ");
189 i++;
190 if ((i % 6) == 0 || models[i].name == NULL)
191 debug("\n");
192 }
193 }
194
195
196 /*
197 * x86_cpu_register_dump():
198 *
199 * Dump cpu registers in a relatively readable format.
200 * (gprs and coprocs are mostly useful for the MIPS version of this function.)
201 */
202 void x86_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
203 {
204 char *symbol;
205 uint64_t offset;
206 int i, x = cpu->cpu_id;
207
208 if (REAL_MODE) {
209 /* Real-mode: */
210 debug("cpu%i: cs:ip = 0x%04x:0x%04x\n", x,
211 cpu->cd.x86.s[X86_S_CS], (int)cpu->pc);
212
213 debug("cpu%i: ax = 0x%04x bx = 0x%04x cx = 0x%04x dx = "
214 "0x%04x\n", x,
215 (int)cpu->cd.x86.r[X86_R_AX], (int)cpu->cd.x86.r[X86_R_BX],
216 (int)cpu->cd.x86.r[X86_R_CX], (int)cpu->cd.x86.r[X86_R_DX]);
217 debug("cpu%i: si = 0x%04x di = 0x%04x bp = 0x%04x sp = "
218 "0x%04x\n", x,
219 (int)cpu->cd.x86.r[X86_R_SI], (int)cpu->cd.x86.r[X86_R_DI],
220 (int)cpu->cd.x86.r[X86_R_BP], (int)cpu->cd.x86.r[X86_R_SP]);
221
222 debug("cpu%i: ds = 0x%04x es = 0x%04x ss = 0x%04x flags "
223 "= 0x%04x\n", x,
224 (int)cpu->cd.x86.s[X86_S_DS], (int)cpu->cd.x86.s[X86_S_ES],
225 (int)cpu->cd.x86.s[X86_S_SS], (int)cpu->cd.x86.rflags);
226 } else {
227 symbol = get_symbol_name(&cpu->machine->symbol_context,
228 cpu->pc, &offset);
229
230 debug("cpu%i: eip=0x", x);
231 debug("%08x", (int)cpu->pc);
232 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
233
234 debug("cpu%i: eax=0x%08x ebx=0x%08x ecx=0x%08x edx="
235 "0x%08x\n", x,
236 (int)cpu->cd.x86.r[X86_R_AX], (int)cpu->cd.x86.r[X86_R_BX],
237 (int)cpu->cd.x86.r[X86_R_CX], (int)cpu->cd.x86.r[X86_R_DX]);
238 debug("cpu%i: esi=0x%08x edi=0x%08x ebp=0x%08x esp="
239 "0x%08x\n", x,
240 (int)cpu->cd.x86.r[X86_R_SI], (int)cpu->cd.x86.r[X86_R_DI],
241 (int)cpu->cd.x86.r[X86_R_BP], (int)cpu->cd.x86.r[X86_R_SP]);
242 #if 0
243 } else {
244 /* 64-bit */
245 symbol = get_symbol_name(&cpu->machine->symbol_context,
246 cpu->pc, &offset);
247
248 debug("cpu%i: rip = 0x", x);
249 debug("%016llx", (long long)cpu->pc);
250 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
251
252 for (i=0; i<N_X86_REGS; i++) {
253 if ((i & 1) == 0)
254 debug("cpu%i:", x);
255 debug(" r%s = 0x%016llx", reg_names[i],
256 (long long)cpu->cd.x86.r[i]);
257 if ((i & 1) == 1)
258 debug("\n");
259 }
260 #endif
261 }
262
263 if (coprocs != 0) {
264 for (i=0; i<6; i++) {
265 debug("cpu%i: %s=0x%04x (", x, seg_names[i],
266 cpu->cd.x86.s[i]);
267 if (cpu->cd.x86.descr_cache[i].valid) {
268 debug("base=0x%08x, limit=0x%08x, ",
269 (int)cpu->cd.x86.descr_cache[i].base,
270 (int)cpu->cd.x86.descr_cache[i].limit);
271 debug("%s", cpu->cd.x86.descr_cache[i].
272 descr_type==DESCR_TYPE_CODE?"CODE":"DATA");
273 debug(", %i-bit", cpu->cd.x86.descr_cache[i].
274 default_op_size);
275 debug(", %s%s", cpu->cd.x86.descr_cache[i].
276 readable? "R" : "-", cpu->cd.x86.
277 descr_cache[i].writable? "W" : "-");
278 } else
279 debug("invalid");
280 debug(")\n");
281 }
282 debug("cpu%i: gdtr=0x%08llx:0x%04x idtr=0x%08llx:0x%04x "
283 " ldtr=0x%08x:0x%04x\n", x, (long long)cpu->cd.x86.gdtr,
284 (int)cpu->cd.x86.gdtr_limit, (long long)cpu->cd.x86.idtr,
285 (int)cpu->cd.x86.idtr_limit, (long long)cpu->cd.x86.
286 ldtr_base, (int)cpu->cd.x86.ldtr_limit);
287 debug("cpu%i: pic1: irr=0x%02x ier=0x%02x isr=0x%02x "
288 "base=0x%02x\n", x, cpu->machine->md.pc.pic1->irr,
289 cpu->machine->md.pc.pic1->ier,cpu->machine->md.pc.pic1->isr,
290 cpu->machine->md.pc.pic1->irq_base);
291 debug("cpu%i: pic2: irr=0x%02x ier=0x%02x isr=0x%02x "
292 "base=0x%02x\n", x, cpu->machine->md.pc.pic2->irr,
293 cpu->machine->md.pc.pic2->ier,cpu->machine->md.pc.pic2->isr,
294 cpu->machine->md.pc.pic2->irq_base);
295 } else if (PROTECTED_MODE) {
296 /* Protected mode: */
297 debug("cpu%i: cs=0x%04x ds=0x%04x es=0x%04x "
298 "fs=0x%04x gs=0x%04x ss=0x%04x\n", x,
299 (int)cpu->cd.x86.s[X86_S_CS], (int)cpu->cd.x86.s[X86_S_DS],
300 (int)cpu->cd.x86.s[X86_S_ES], (int)cpu->cd.x86.s[X86_S_FS],
301 (int)cpu->cd.x86.s[X86_S_GS], (int)cpu->cd.x86.s[X86_S_SS]);
302 }
303
304 if (PROTECTED_MODE) {
305 /* Protected mode: */
306 debug("cpu%i: cr0=0x%08x cr2=0x%08x cr3=0x%08x eflags="
307 "0x%08x\n", x, (int)cpu->cd.x86.cr[0],
308 (int)cpu->cd.x86.cr[2], (int)cpu->cd.x86.cr[3],
309 (int)cpu->cd.x86.rflags);
310 debug("cpu%i: tr = 0x%04x (base=0x%llx, limit=0x%x)\n",
311 x, (int)cpu->cd.x86.tr, (long long)cpu->cd.x86.tr_base,
312 (int)cpu->cd.x86.tr_limit);
313 }
314 }
315
316
317 /*
318 * x86_cpu_register_match():
319 */
320 void x86_cpu_register_match(struct machine *m, char *name,
321 int writeflag, uint64_t *valuep, int *mr)
322 {
323 int cpunr = 0;
324 int r;
325
326 /* CPU number: TODO */
327
328 if (strcasecmp(name, "pc") == 0 || strcasecmp(name, "rip") == 0) {
329 if (writeflag) {
330 m->cpus[cpunr]->pc = *valuep;
331 m->cpus[cpunr]->cd.x86.halted = 0;
332 } else
333 *valuep = m->cpus[cpunr]->pc;
334 *mr = 1;
335 return;
336 }
337 if (strcasecmp(name, "ip") == 0) {
338 if (writeflag) {
339 m->cpus[cpunr]->pc = (m->cpus[cpunr]->pc & ~0xffff)
340 | (*valuep & 0xffff);
341 m->cpus[cpunr]->cd.x86.halted = 0;
342 } else
343 *valuep = m->cpus[cpunr]->pc & 0xffff;
344 *mr = 1;
345 return;
346 }
347 if (strcasecmp(name, "eip") == 0) {
348 if (writeflag) {
349 m->cpus[cpunr]->pc = *valuep;
350 m->cpus[cpunr]->cd.x86.halted = 0;
351 } else
352 *valuep = m->cpus[cpunr]->pc & 0xffffffffULL;
353 *mr = 1;
354 return;
355 }
356
357 if (strcasecmp(name, "rflags") == 0) {
358 if (writeflag)
359 m->cpus[cpunr]->cd.x86.rflags = *valuep;
360 else
361 *valuep = m->cpus[cpunr]->cd.x86.rflags;
362 *mr = 1;
363 return;
364 }
365 if (strcasecmp(name, "eflags") == 0) {
366 if (writeflag)
367 m->cpus[cpunr]->cd.x86.rflags = (m->cpus[cpunr]->
368 cd.x86.rflags & ~0xffffffffULL) | (*valuep &
369 0xffffffffULL);
370 else
371 *valuep = m->cpus[cpunr]->cd.x86.rflags & 0xffffffffULL;
372 *mr = 1;
373 return;
374 }
375 if (strcasecmp(name, "flags") == 0) {
376 if (writeflag)
377 m->cpus[cpunr]->cd.x86.rflags = (m->cpus[cpunr]->
378 cd.x86.rflags & ~0xffff) | (*valuep & 0xffff);
379 else
380 *valuep = m->cpus[cpunr]->cd.x86.rflags & 0xffff;
381 *mr = 1;
382 return;
383 }
384
385 /* 8-bit low: */
386 for (r=0; r<4; r++)
387 if (strcasecmp(name, reg_names_bytes[r]) == 0) {
388 if (writeflag)
389 m->cpus[cpunr]->cd.x86.r[r] =
390 (m->cpus[cpunr]->cd.x86.r[r] & ~0xff)
391 | (*valuep & 0xff);
392 else
393 *valuep = m->cpus[cpunr]->cd.x86.r[r] & 0xff;
394 *mr = 1;
395 return;
396 }
397
398 /* 8-bit high: */
399 for (r=0; r<4; r++)
400 if (strcasecmp(name, reg_names_bytes[r+4]) == 0) {
401 if (writeflag)
402 m->cpus[cpunr]->cd.x86.r[r] =
403 (m->cpus[cpunr]->cd.x86.r[r] & ~0xff00)
404 | ((*valuep & 0xff) << 8);
405 else
406 *valuep = (m->cpus[cpunr]->cd.x86.r[r] >>
407 8) & 0xff;
408 *mr = 1;
409 return;
410 }
411
412 /* 16-, 32-, 64-bit registers: */
413 for (r=0; r<N_X86_REGS; r++) {
414 /* 16-bit: */
415 if (r<8 && strcasecmp(name, reg_names[r]) == 0) {
416 if (writeflag)
417 m->cpus[cpunr]->cd.x86.r[r] =
418 (m->cpus[cpunr]->cd.x86.r[r] & ~0xffff)
419 | (*valuep & 0xffff);
420 else
421 *valuep = m->cpus[cpunr]->cd.x86.r[r] & 0xffff;
422 *mr = 1;
423 return;
424 }
425
426 /* 32-bit: */
427 if (r<8 && (name[0]=='e' || name[0]=='E') &&
428 strcasecmp(name+1, reg_names[r]) == 0) {
429 if (writeflag)
430 m->cpus[cpunr]->cd.x86.r[r] =
431 *valuep & 0xffffffffULL;
432 else
433 *valuep = m->cpus[cpunr]->cd.x86.r[r] &
434 0xffffffffULL;
435 *mr = 1;
436 return;
437 }
438
439 /* 64-bit: */
440 if ((name[0]=='r' || name[0]=='R') &&
441 strcasecmp(name+1, reg_names[r]) == 0) {
442 if (writeflag)
443 m->cpus[cpunr]->cd.x86.r[r] = *valuep;
444 else
445 *valuep = m->cpus[cpunr]->cd.x86.r[r];
446 *mr = 1;
447 return;
448 }
449 }
450
451 /* segment names: */
452 for (r=0; r<N_X86_SEGS; r++) {
453 if (strcasecmp(name, seg_names[r]) == 0) {
454 if (writeflag)
455 m->cpus[cpunr]->cd.x86.s[r] =
456 (m->cpus[cpunr]->cd.x86.s[r] & ~0xffff)
457 | (*valuep & 0xffff);
458 else
459 *valuep = m->cpus[cpunr]->cd.x86.s[r] & 0xffff;
460 *mr = 1;
461 return;
462 }
463 }
464
465 /* control registers: (TODO: 32- vs 64-bit on AMD64?) */
466 if (strncasecmp(name, "cr", 2) == 0 && atoi(name+2) < N_X86_CREGS ) {
467 int r = atoi(name+2);
468 if (writeflag)
469 m->cpus[cpunr]->cd.x86.cr[r] = *valuep;
470 else
471 *valuep = m->cpus[cpunr]->cd.x86.cr[r];
472 *mr = 1;
473 return;
474 }
475 }
476
477
478 /* Macro which modifies the lower part of a value, or the entire value,
479 depending on 'mode': */
480 #define modify(old,new) ( \
481 mode==16? ( \
482 ((old) & ~0xffff) + ((new) & 0xffff) \
483 ) : ((new) & 0xffffffffULL) )
484
485 /* "volatile" here, because some versions of gcc with -O3 on i386 are buggy */
486 #define HEXPRINT(x,n) { volatile int j; for (j=0; j<(n); j++) \
487 debug("%02x",(x)[j]); }
488 #define HEXSPACES(i) { int j; j = (i)>10? 10:(i); while (j++<10) debug(" "); \
489 debug(" "); }
490 #define SPACES HEXSPACES(ilen)
491
492
493 static uint32_t read_imm_common(unsigned char **instrp, uint64_t *ilenp,
494 int len, int printflag)
495 {
496 uint32_t imm;
497 unsigned char *instr = *instrp;
498
499 if (len == 8)
500 imm = instr[0];
501 else if (len == 16)
502 imm = instr[0] + (instr[1] << 8);
503 else
504 imm = instr[0] + (instr[1] << 8) +
505 (instr[2] << 16) + (instr[3] << 24);
506
507 if (printflag)
508 HEXPRINT(instr, len / 8);
509
510 if (ilenp != NULL)
511 (*ilenp) += len/8;
512
513 (*instrp) += len/8;
514 return imm;
515 }
516
517
518 static uint32_t read_imm_and_print(unsigned char **instrp, uint64_t *ilenp,
519 int mode)
520 {
521 return read_imm_common(instrp, ilenp, mode, 1);
522 }
523
524
525 static uint32_t read_imm(unsigned char **instrp, uint64_t *newpcp,
526 int mode)
527 {
528 return read_imm_common(instrp, newpcp, mode, 0);
529 }
530
531
532 static void print_csip(struct cpu *cpu)
533 {
534 fatal("0x%04x:", cpu->cd.x86.s[X86_S_CS]);
535 if (PROTECTED_MODE)
536 fatal("0x%llx", (long long)cpu->pc);
537 else
538 fatal("0x%04x", (int)cpu->pc);
539 }
540
541
542 /*
543 * x86_cpu_interrupt():
544 *
545 * NOTE: Interacting with the 8259 PIC is done in src/machine.c.
546 */
547 int x86_cpu_interrupt(struct cpu *cpu, uint64_t nr)
548 {
549 if (cpu->machine->md_interrupt != NULL)
550 cpu->machine->md_interrupt(cpu->machine, cpu, nr, 1);
551 else {
552 fatal("x86_cpu_interrupt(): no md_interrupt()?\n");
553 return 1;
554 }
555
556 return 1;
557 }
558
559
560 /*
561 * x86_cpu_interrupt_ack():
562 *
563 * NOTE: Interacting with the 8259 PIC is done in src/machine.c.
564 */
565 int x86_cpu_interrupt_ack(struct cpu *cpu, uint64_t nr)
566 {
567 if (cpu->machine->md_interrupt != NULL)
568 cpu->machine->md_interrupt(cpu->machine, cpu, nr, 0);
569 else {
570 fatal("x86_cpu_interrupt(): no md_interrupt()?\n");
571 return 1;
572 }
573
574 return 1;
575 }
576
577
578 /* (NOTE: Don't use the lowest 3 bits in these defines) */
579 #define RELOAD_TR 0x1000
580 #define RELOAD_LDTR 0x1008
581
582
583 /*
584 * x86_task_switch():
585 *
586 * Save away current state into the current task state segment, and
587 * load the new state from the new task.
588 *
589 * TODO: 16-bit TSS, etc. And clean up all of this :)
590 *
591 * TODO: Link word. AMD64 stuff. And lots more.
592 */
593 void x86_task_switch(struct cpu *cpu, int new_tr, uint64_t *curpc)
594 {
595 unsigned char old_descr[8];
596 unsigned char new_descr[8];
597 uint32_t value, ofs;
598 int i;
599 unsigned char buf[4];
600
601 fatal("x86_task_switch():\n");
602 cpu->pc = *curpc;
603
604 if (!cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr + cpu->cd.x86.tr,
605 old_descr, sizeof(old_descr), MEM_READ, NO_SEGMENTATION)) {
606 fatal("x86_task_switch(): TODO: 1\n");
607 cpu->running = 0;
608 return;
609 }
610
611 /* Check the busy bit, and then clear it: */
612 if (!(old_descr[5] & 0x02)) {
613 fatal("x86_task_switch(): TODO: switching FROM a non-BUSY"
614 " TSS descriptor?\n");
615 cpu->running = 0;
616 return;
617 }
618 old_descr[5] &= ~0x02;
619 if (!cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr + cpu->cd.x86.tr,
620 old_descr, sizeof(old_descr), MEM_WRITE, NO_SEGMENTATION)) {
621 fatal("x86_task_switch(): TODO: could not clear busy bit\n");
622 cpu->running = 0;
623 return;
624 }
625
626 x86_cpu_register_dump(cpu, 1, 1);
627
628 /* Set the task-switched bit in CR0: */
629 cpu->cd.x86.cr[0] |= X86_CR0_TS;
630
631 /* Save away all the old registers: */
632 #define WRITE_VALUE { buf[0]=value; buf[1]=value>>8; buf[2]=value>>16; \
633 buf[3]=value>>24; cpu->memory_rw(cpu, cpu->mem, \
634 cpu->cd.x86.tr_base + ofs, buf, sizeof(buf), MEM_WRITE, \
635 NO_SEGMENTATION); }
636
637 ofs = 0x1c; value = cpu->cd.x86.cr[3]; WRITE_VALUE;
638 ofs = 0x20; value = cpu->pc; WRITE_VALUE;
639 ofs = 0x24; value = cpu->cd.x86.rflags; WRITE_VALUE;
640 for (i=0; i<N_X86_REGS; i++) {
641 ofs = 0x28+i*4; value = cpu->cd.x86.r[i]; WRITE_VALUE;
642 }
643 for (i=0; i<6; i++) {
644 ofs = 0x48+i*4; value = cpu->cd.x86.s[i]; WRITE_VALUE;
645 }
646
647 fatal("-------\n");
648
649 if ((cpu->cd.x86.tr & 0xfffc) == 0) {
650 fatal("TODO: x86_task_switch(): task switch, but old TR"
651 " was 0?\n");
652 cpu->running = 0;
653 return;
654 }
655
656 if (!cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr + new_tr,
657 new_descr, sizeof(new_descr), MEM_READ, NO_SEGMENTATION)) {
658 fatal("x86_task_switch(): TODO: 1\n");
659 cpu->running = 0;
660 return;
661 }
662 if (new_descr[5] & 0x02) {
663 fatal("x86_task_switch(): TODO: switching TO an already BUSY"
664 " TSS descriptor?\n");
665 cpu->running = 0;
666 return;
667 }
668
669 reload_segment_descriptor(cpu, RELOAD_TR, new_tr, NULL);
670
671 if (cpu->cd.x86.tr_limit < 0x67)
672 fatal("WARNING: tr_limit = 0x%x, must be at least 0x67!\n",
673 (int)cpu->cd.x86.tr_limit);
674
675 /* Read new registers: */
676 #define READ_VALUE { cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.tr_base + \
677 ofs, buf, sizeof(buf), MEM_READ, NO_SEGMENTATION); \
678 value = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24); }
679
680 ofs = 0x1c; READ_VALUE; cpu->cd.x86.cr[3] = value;
681 ofs = 0x20; READ_VALUE; cpu->pc = value;
682 ofs = 0x24; READ_VALUE; cpu->cd.x86.rflags = value;
683 for (i=0; i<N_X86_REGS; i++) {
684 ofs = 0x28+i*4; READ_VALUE; cpu->cd.x86.r[i] = value;
685 }
686 for (i=0; i<6; i++) {
687 ofs = 0x48+i*4; READ_VALUE;
688 reload_segment_descriptor(cpu, i, value, NULL);
689 }
690 ofs = 0x60; READ_VALUE; value &= 0xffff;
691 reload_segment_descriptor(cpu, RELOAD_LDTR, value, NULL);
692
693 if ((cpu->cd.x86.s[X86_S_CS] & X86_PL_MASK) !=
694 (cpu->cd.x86.s[X86_S_SS] & X86_PL_MASK))
695 fatal("WARNING: rpl in CS and SS differ!\n");
696
697 if ((cpu->cd.x86.s[X86_S_CS] & X86_PL_MASK) == X86_RING3 &&
698 !(cpu->cd.x86.rflags & X86_FLAGS_IF))
699 fatal("WARNING (?): switching to userland task, but interrupts"
700 " are disabled?\n");
701
702 x86_cpu_register_dump(cpu, 1, 1);
703 fatal("-------\n");
704
705 *curpc = cpu->pc;
706
707 /* cpu->machine->instruction_trace = 1; */
708 /* cpu->running = 0; */
709 }
710
711
712 /*
713 * reload_segment_descriptor():
714 *
715 * Loads base, limit and other settings from the Global Descriptor Table into
716 * segment descriptors.
717 *
718 * This function can also be used to reload the TR (task register).
719 *
720 * And also to do a task switch, or jump into a trap handler etc.
721 * (Perhaps this function should be renamed.)
722 */
723 void reload_segment_descriptor(struct cpu *cpu, int segnr, int selector,
724 uint64_t *curpcp)
725 {
726 int res, i, readable, writable, granularity, descr_type;
727 int segment = 1, rpl, orig_selector = selector;
728 unsigned char descr[8];
729 char *table_name = "GDT";
730 uint64_t base, limit, table_base, table_limit;
731
732 if (segnr > 0x100) /* arbitrary, larger than N_X86_SEGS */
733 segment = 0;
734
735 if (segment && (segnr < 0 || segnr >= N_X86_SEGS)) {
736 fatal("reload_segment_descriptor(): segnr = %i\n", segnr);
737 exit(1);
738 }
739
740 if (segment && REAL_MODE) {
741 /* Real mode: */
742 cpu->cd.x86.descr_cache[segnr].valid = 1;
743 cpu->cd.x86.descr_cache[segnr].default_op_size = 16;
744 cpu->cd.x86.descr_cache[segnr].access_rights = 0x93;
745 cpu->cd.x86.descr_cache[segnr].descr_type =
746 segnr == X86_S_CS? DESCR_TYPE_CODE : DESCR_TYPE_DATA;
747 cpu->cd.x86.descr_cache[segnr].readable = 1;
748 cpu->cd.x86.descr_cache[segnr].writable = 1;
749 cpu->cd.x86.descr_cache[segnr].granularity = 0;
750 cpu->cd.x86.descr_cache[segnr].base = selector << 4;
751 cpu->cd.x86.descr_cache[segnr].limit = 0xffff;
752 cpu->cd.x86.s[segnr] = selector;
753 return;
754 }
755
756 /*
757 * Protected mode: Load the descriptor cache from the GDT.
758 */
759
760 table_base = cpu->cd.x86.gdtr;
761 table_limit = cpu->cd.x86.gdtr_limit;
762 if (selector & 4) {
763 table_name = "LDT";
764 /* fatal("TODO: x86 translation via LDT: 0x%04x\n",
765 selector); */
766 table_base = cpu->cd.x86.ldtr_base;
767 table_limit = cpu->cd.x86.ldtr_limit;
768 }
769
770 /* Special case: Null-descriptor: */
771 if (segment && (selector & ~3) == 0) {
772 cpu->cd.x86.descr_cache[segnr].valid = 0;
773 cpu->cd.x86.s[segnr] = selector;
774 return;
775 }
776
777 rpl = selector & 3;
778
779 /* TODO: check rpl */
780
781 selector &= ~7;
782
783 if (selector + 7 > table_limit) {
784 fatal("TODO: selector 0x%04x outside %s limit (0x%04x)\n",
785 selector, table_name, (int)table_limit);
786 cpu->running = 0;
787 return;
788 }
789
790 res = cpu->memory_rw(cpu, cpu->mem, table_base + selector,
791 descr, sizeof(descr), MEM_READ, NO_SEGMENTATION);
792 if (!res) {
793 fatal("reload_segment_descriptor(): TODO: "
794 "could not read the GDT\n");
795 cpu->running = 0;
796 return;
797 }
798
799 base = descr[2] + (descr[3] << 8) + (descr[4] << 16) +
800 (descr[7] << 24);
801 limit = descr[0] + (descr[1] << 8) + ((descr[6]&15) << 16);
802
803 descr_type = readable = writable = granularity = 0;
804 granularity = (descr[6] & 0x80)? 1 : 0;
805 if (limit == 0) {
806 fatal("WARNING: descriptor limit = 0\n");
807 limit = 0xfffff;
808 }
809 if (granularity)
810 limit = (limit << 12) | 0xfff;
811
812 #if 0
813 printf("base = %llx\n",(long long)base);
814 for (i=0; i<8; i++)
815 fatal(" %02x", descr[i]);
816 #endif
817
818 if (selector != 0x0000 && (descr[5] & 0x80) == 0x00) {
819 fatal("TODO: nonpresent descriptor?\n");
820 goto fail_dump;
821 }
822
823 if (!segment) {
824 switch (segnr) {
825 case RELOAD_TR:
826 /* Check that this is indeed a TSS descriptor: */
827 if ((descr[5] & 0x15) != 0x01) {
828 fatal("TODO: load TR but entry in table is"
829 " not a TSS descriptor?\n");
830 goto fail_dump;
831 }
832
833 /* Reload the task register: */
834 cpu->cd.x86.tr = selector;
835 cpu->cd.x86.tr_base = base;
836 cpu->cd.x86.tr_limit = limit;
837
838 /* Mark the TSS as busy: */
839 descr[5] |= 0x02;
840 res = cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.gdtr +
841 selector, descr, sizeof(descr), MEM_WRITE,
842 NO_SEGMENTATION);
843 break;
844 case RELOAD_LDTR:
845 /* Reload the Local Descriptor Table register: */
846 cpu->cd.x86.ldtr = selector;
847 cpu->cd.x86.ldtr_base = base;
848 cpu->cd.x86.ldtr_limit = limit;
849 break;
850 }
851 return;
852 }
853
854 if ((descr[5] & 0x18) == 0x18) {
855 descr_type = DESCR_TYPE_CODE;
856 readable = descr[5] & 0x02? 1 : 0;
857 if ((descr[5] & 0x98) != 0x98) {
858 fatal("TODO CODE\n");
859 goto fail_dump;
860 }
861 } else if ((descr[5] & 0x18) == 0x10) {
862 descr_type = DESCR_TYPE_DATA;
863 readable = 1;
864 writable = descr[5] & 0x02? 1 : 0;
865 if ((descr[5] & 0x98) != 0x90) {
866 fatal("TODO DATA\n");
867 goto fail_dump;
868 }
869 } else if (segnr == X86_S_CS && (descr[5] & 0x15) == 0x01
870 && curpcp != NULL) {
871 /* TSS */
872 x86_task_switch(cpu, selector, curpcp);
873 return;
874 } else {
875 fatal("TODO: other\n");
876 goto fail_dump;
877 }
878
879 cpu->cd.x86.descr_cache[segnr].valid = 1;
880 cpu->cd.x86.descr_cache[segnr].default_op_size =
881 (descr[6] & 0x40)? 32 : 16;
882 cpu->cd.x86.descr_cache[segnr].access_rights = descr[5];
883 cpu->cd.x86.descr_cache[segnr].descr_type = descr_type;
884 cpu->cd.x86.descr_cache[segnr].readable = readable;
885 cpu->cd.x86.descr_cache[segnr].writable = writable;
886 cpu->cd.x86.descr_cache[segnr].granularity = granularity;
887 cpu->cd.x86.descr_cache[segnr].base = base;
888 cpu->cd.x86.descr_cache[segnr].limit = limit;
889 cpu->cd.x86.s[segnr] = orig_selector;
890 return;
891
892 fail_dump:
893 for (i=0; i<8; i++)
894 fatal(" %02x", descr[i]);
895 cpu->running = 0;
896 }
897
898
899 /*
900 * x86_load():
901 *
902 * Returns same error code as memory_rw().
903 */
904 static int x86_load(struct cpu *cpu, uint64_t addr, uint64_t *data, int len)
905 {
906 unsigned char databuf[8];
907 int res;
908 uint64_t d;
909
910 res = cpu->memory_rw(cpu, cpu->mem, addr, &databuf[0], len,
911 MEM_READ, CACHE_DATA);
912
913 d = databuf[0];
914 if (len > 1) {
915 d += ((uint64_t)databuf[1] << 8);
916 if (len > 2) {
917 d += ((uint64_t)databuf[2] << 16);
918 d += ((uint64_t)databuf[3] << 24);
919 if (len > 4) {
920 d += ((uint64_t)databuf[4] << 32);
921 d += ((uint64_t)databuf[5] << 40);
922 d += ((uint64_t)databuf[6] << 48);
923 d += ((uint64_t)databuf[7] << 56);
924 }
925 }
926 }
927
928 *data = d;
929 return res;
930 }
931
932
933 /*
934 * x86_store():
935 *
936 * Returns same error code as memory_rw().
937 */
938 static int x86_store(struct cpu *cpu, uint64_t addr, uint64_t data, int len)
939 {
940 unsigned char databuf[8];
941
942 /* x86 is always little-endian: */
943 databuf[0] = data;
944 if (len > 1) {
945 databuf[1] = data >> 8;
946 if (len > 2) {
947 databuf[2] = data >> 16;
948 databuf[3] = data >> 24;
949 if (len > 4) {
950 databuf[4] = data >> 32;
951 databuf[5] = data >> 40;
952 databuf[6] = data >> 48;
953 databuf[7] = data >> 56;
954 }
955 }
956 }
957
958 return cpu->memory_rw(cpu, cpu->mem, addr, &databuf[0], len,
959 MEM_WRITE, CACHE_DATA);
960 }
961
962
963 /*
964 * x86_write_cr():
965 *
966 * Write to a control register.
967 */
968 static void x86_write_cr(struct cpu *cpu, int r, uint64_t value)
969 {
970 uint64_t new, tmp;
971
972 switch (r) {
973 case 0: new = cpu->cd.x86.cr[r] = value;
974 /* Warn about unimplemented bits: */
975 tmp = new & ~(X86_CR0_PE | X86_CR0_PG);
976 if (cpu->cd.x86.model.model_number <= X86_MODEL_80386) {
977 if (tmp & X86_CR0_WP)
978 fatal("WARNING: cr0 WP bit set, but this is"
979 " not an 80486 or higher (?)\n");
980 }
981 tmp &= ~X86_CR0_WP;
982 if (tmp != 0)
983 fatal("x86_write_cr(): unimplemented cr0 bits: "
984 "0x%08llx\n", (long long)tmp);
985 break;
986 case 2:
987 case 3: new = cpu->cd.x86.cr[r] = value;
988 break;
989 case 4: new = cpu->cd.x86.cr[r] = value;
990 /* Warn about unimplemented bits: */
991 tmp = new; /* & ~(X86_CR0_PE | X86_CR0_PG); */
992 if (tmp != 0)
993 fatal("x86_write_cr(): unimplemented cr4 bits: "
994 "0x%08llx\n", (long long)tmp);
995 break;
996 default:fatal("x86_write_cr(): write to UNIMPLEMENTED cr%i\n", r);
997 cpu->running = 0;
998 }
999 }
1000
1001
1002 static char *ofs_string(int32_t imm)
1003 {
1004 static char buf[25];
1005 buf[0] = buf[sizeof(buf)-1] = '\0';
1006
1007 if (imm > 32)
1008 sprintf(buf, "+0x%x", imm);
1009 else if (imm > 0)
1010 sprintf(buf, "+%i", imm);
1011 else if (imm < -32)
1012 sprintf(buf, "-0x%x", -imm);
1013 else if (imm < 0)
1014 sprintf(buf, "-%i", -imm);
1015
1016 return buf;
1017 }
1018
1019
1020 static char modrm_r[65];
1021 static char modrm_rm[65];
1022 #define MODRM_READ 0
1023 #define MODRM_WRITE_RM 1
1024 #define MODRM_WRITE_R 2
1025 /* flags: */
1026 #define MODRM_EIGHTBIT 1
1027 #define MODRM_SEG 2
1028 #define MODRM_JUST_GET_ADDR 4
1029 #define MODRM_CR 8
1030 #define MODRM_DR 16
1031 #define MODRM_R_NONEIGHTBIT 32
1032 #define MODRM_RM_16BIT 64
1033
1034
1035 /*
1036 * modrm():
1037 *
1038 * Yuck. I have a feeling that this function will become really ugly.
1039 */
1040 static int modrm(struct cpu *cpu, int writeflag, int mode, int mode67,
1041 int flags, unsigned char **instrp, uint64_t *lenp,
1042 uint64_t *op1p, uint64_t *op2p)
1043 {
1044 uint32_t imm, imm2;
1045 uint64_t addr = 0;
1046 int mod, r, rm, res = 1, z, q = mode/8, sib, s, i, b, immlen;
1047 char *e, *f;
1048 int disasm = (op1p == NULL);
1049
1050 /* e for data, f for addresses */
1051 e = f = "";
1052
1053 if (disasm) {
1054 if (mode == 32)
1055 e = "e";
1056 if (mode == 64)
1057 e = "r";
1058 if (mode67 == 32)
1059 f = "e";
1060 if (mode67 == 64)
1061 f = "r";
1062 modrm_rm[0] = modrm_rm[sizeof(modrm_rm)-1] = '\0';
1063 modrm_r[0] = modrm_r[sizeof(modrm_r)-1] = '\0';
1064 }
1065
1066 immlen = mode67;
1067 if (immlen == 64)
1068 immlen = 32;
1069
1070 imm = read_imm_common(instrp, lenp, 8, disasm);
1071 mod = (imm >> 6) & 3; r = (imm >> 3) & 7; rm = imm & 7;
1072
1073 if (flags & MODRM_EIGHTBIT)
1074 q = 1;
1075
1076 /*
1077 * R/M:
1078 */
1079
1080 switch (mod) {
1081 case 0:
1082 if (disasm) {
1083 if (mode67 >= 32) {
1084 if (rm == 5) {
1085 imm2 = read_imm_common(instrp, lenp,
1086 immlen, disasm);
1087 sprintf(modrm_rm, "[0x%x]", imm2);
1088 } else if (rm == 4) {
1089 char tmp[20];
1090 sib = read_imm_common(instrp, lenp,
1091 8, disasm);
1092 s = 1 << (sib >> 6);
1093 i = (sib >> 3) & 7;
1094 b = sib & 7;
1095 if (b == 5) { /* imm base */
1096 imm2 = read_imm_common(instrp,
1097 lenp, immlen, disasm);
1098 sprintf(tmp, ofs_string(imm2));
1099 } else
1100 sprintf(tmp, "+%s%s", f,
1101 reg_names[b]);
1102 if (i == 4)
1103 sprintf(modrm_rm, "[%s]", tmp);
1104 else if (s == 1)
1105 sprintf(modrm_rm, "[%s%s%s]",
1106 f, reg_names[i], tmp);
1107 else
1108 sprintf(modrm_rm, "[%s%s*%i%s"
1109 "]", f, reg_names[i],
1110 s, tmp);
1111 } else {
1112 sprintf(modrm_rm, "[%s%s]", f,
1113 reg_names[rm]);
1114 }
1115 } else {
1116 switch (rm) {
1117 case 0: sprintf(modrm_rm, "[bx+si]");
1118 break;
1119 case 1: sprintf(modrm_rm, "[bx+di]");
1120 break;
1121 case 2: sprintf(modrm_rm, "[bp+si]");
1122 break;
1123 case 3: sprintf(modrm_rm, "[bp+di]");
1124 break;
1125 case 4: sprintf(modrm_rm, "[si]");
1126 break;
1127 case 5: sprintf(modrm_rm, "[di]");
1128 break;
1129 case 6: imm2 = read_imm_common(instrp, lenp,
1130 immlen, disasm);
1131 sprintf(modrm_rm, "[0x%x]", imm2);
1132 break;
1133 case 7: sprintf(modrm_rm, "[bx]");
1134 break;
1135 }
1136 }
1137 } else {
1138 if (mode67 >= 32) {
1139 if (rm == 5) {
1140 addr = read_imm_common(instrp, lenp,
1141 immlen, disasm);
1142 } else if (rm == 4) {
1143 sib = read_imm_common(instrp, lenp,
1144 8, disasm);
1145 s = 1 << (sib >> 6);
1146 i = (sib >> 3) & 7;
1147 b = sib & 7;
1148 if (b == 4 &&
1149 !cpu->cd.x86.seg_override)
1150 cpu->cd.x86.cursegment=X86_S_SS;
1151 if (b == 5)
1152 addr = read_imm_common(instrp,
1153 lenp, mode67, disasm);
1154 else
1155 addr = cpu->cd.x86.r[b];
1156 if (i != 4)
1157 addr += cpu->cd.x86.r[i] * s;
1158 } else {
1159 addr = cpu->cd.x86.r[rm];
1160 }
1161 } else {
1162 switch (rm) {
1163 case 0: addr = cpu->cd.x86.r[X86_R_BX] +
1164 cpu->cd.x86.r[X86_R_SI]; break;
1165 case 1: addr = cpu->cd.x86.r[X86_R_BX] +
1166 cpu->cd.x86.r[X86_R_DI]; break;
1167 case 2: addr = cpu->cd.x86.r[X86_R_BP] +
1168 cpu->cd.x86.r[X86_R_SI];
1169 if (!cpu->cd.x86.seg_override)
1170 cpu->cd.x86.cursegment=X86_S_SS;
1171 break;
1172 case 3: addr = cpu->cd.x86.r[X86_R_BP] +
1173 cpu->cd.x86.r[X86_R_DI];
1174 if (!cpu->cd.x86.seg_override)
1175 cpu->cd.x86.cursegment=X86_S_SS;
1176 break;
1177 case 4: addr = cpu->cd.x86.r[X86_R_SI]; break;
1178 case 5: addr = cpu->cd.x86.r[X86_R_DI]; break;
1179 case 6: addr = read_imm_common(instrp, lenp,
1180 immlen, disasm); break;
1181 case 7: addr = cpu->cd.x86.r[X86_R_BX]; break;
1182 }
1183 }
1184
1185 if (mode67 == 16)
1186 addr &= 0xffff;
1187 if (mode67 == 32)
1188 addr &= 0xffffffffULL;
1189
1190 switch (writeflag) {
1191 case MODRM_WRITE_RM:
1192 res = x86_store(cpu, addr, *op1p, q);
1193 break;
1194 case MODRM_READ: /* read */
1195 if (flags & MODRM_JUST_GET_ADDR)
1196 *op1p = addr;
1197 else
1198 res = x86_load(cpu, addr, op1p, q);
1199 }
1200 }
1201 break;
1202 case 1:
1203 case 2:
1204 z = (mod == 1)? 8 : immlen;
1205 if (disasm) {
1206 if (mode67 >= 32) {
1207 if (rm == 4) {
1208 sib = read_imm_common(instrp, lenp,
1209 8, disasm);
1210 s = 1 << (sib >> 6);
1211 i = (sib >> 3) & 7;
1212 b = sib & 7;
1213 imm2 = read_imm_common(instrp, lenp,
1214 z, disasm);
1215 if (z == 8) imm2 = (signed char)imm2;
1216 if (i == 4)
1217 sprintf(modrm_rm, "[%s%s%s]",
1218 f, reg_names[b],
1219 ofs_string(imm2));
1220 else if (s == 1)
1221 sprintf(modrm_rm, "[%s%s%s"
1222 "%s%s]", f, reg_names[i],
1223 f, reg_names[b],
1224 ofs_string(imm2));
1225 else
1226 sprintf(modrm_rm, "[%s%s*%i+%s"
1227 "%s%s]", f, reg_names[i], s,
1228 f, reg_names[b],
1229 ofs_string(imm2));
1230 } else {
1231 imm2 = read_imm_common(instrp, lenp,
1232 z, disasm);
1233 if (z == 8) imm2 = (signed char)imm2;
1234 sprintf(modrm_rm, "[%s%s%s]", f,
1235 reg_names[rm], ofs_string(imm2));
1236 }
1237 } else
1238 switch (rm) {
1239 case 0: imm2 = read_imm_common(instrp, lenp, z, disasm);
1240 if (z == 8) imm2 = (signed char)imm2;
1241 sprintf(modrm_rm, "[bx+si%s]",ofs_string(imm2));
1242 break;
1243 case 1: imm2 = read_imm_common(instrp, lenp, z, disasm);
1244 if (z == 8) imm2 = (signed char)imm2;
1245 sprintf(modrm_rm, "[bx+di%s]",ofs_string(imm2));
1246 break;
1247 case 2: imm2 = read_imm_common(instrp, lenp, z, disasm);
1248 if (z == 8) imm2 = (signed char)imm2;
1249 sprintf(modrm_rm, "[bp+si%s]",ofs_string(imm2));
1250 break;
1251 case 3: imm2 = read_imm_common(instrp, lenp, z, disasm);
1252 if (z == 8) imm2 = (signed char)imm2;
1253 sprintf(modrm_rm, "[bp+di%s]",ofs_string(imm2));
1254 break;
1255 case 4: imm2 = read_imm_common(instrp, lenp, z, disasm);
1256 if (z == 8) imm2 = (signed char)imm2;
1257 sprintf(modrm_rm, "[si%s]", ofs_string(imm2));
1258 break;
1259 case 5: imm2 = read_imm_common(instrp, lenp, z, disasm);
1260 if (z == 8) imm2 = (signed char)imm2;
1261 sprintf(modrm_rm, "[di%s]", ofs_string(imm2));
1262 break;
1263 case 6: imm2 = read_imm_common(instrp, lenp, z, disasm);
1264 if (z == 8) imm2 = (signed char)imm2;
1265 sprintf(modrm_rm, "[bp%s]", ofs_string(imm2));
1266 break;
1267 case 7: imm2 = read_imm_common(instrp, lenp, z, disasm);
1268 if (z == 8) imm2 = (signed char)imm2;
1269 sprintf(modrm_rm, "[bx%s]", ofs_string(imm2));
1270 break;
1271 }
1272 } else {
1273 if (mode67 >= 32) {
1274 if (rm == 4) {
1275 sib = read_imm_common(instrp, lenp,
1276 8, disasm);
1277 s = 1 << (sib >> 6);
1278 i = (sib >> 3) & 7;
1279 b = sib & 7;
1280 addr = read_imm_common(instrp, lenp,
1281 z, disasm);
1282 if ((b == 4 || b == 5) &&
1283 !cpu->cd.x86.seg_override)
1284 cpu->cd.x86.cursegment=X86_S_SS;
1285 if (z == 8)
1286 addr = (signed char)addr;
1287 if (i == 4)
1288 addr = cpu->cd.x86.r[b] + addr;
1289 else
1290 addr = cpu->cd.x86.r[i] * s +
1291 cpu->cd.x86.r[b] + addr;
1292 } else {
1293 addr = read_imm_common(instrp, lenp,
1294 z, disasm);
1295 if (z == 8)
1296 addr = (signed char)addr;
1297 addr = cpu->cd.x86.r[rm] + addr;
1298 }
1299 } else {
1300 addr = read_imm_common(instrp, lenp, z, disasm);
1301 if (z == 8)
1302 addr = (signed char)addr;
1303 switch (rm) {
1304 case 0: addr += cpu->cd.x86.r[X86_R_BX]
1305 + cpu->cd.x86.r[X86_R_SI];
1306 break;
1307 case 1: addr += cpu->cd.x86.r[X86_R_BX]
1308 + cpu->cd.x86.r[X86_R_DI];
1309 break;
1310 case 2: addr += cpu->cd.x86.r[X86_R_BP]
1311 + cpu->cd.x86.r[X86_R_SI];
1312 if (!cpu->cd.x86.seg_override)
1313 cpu->cd.x86.cursegment=X86_S_SS;
1314 break;
1315 case 3: addr += cpu->cd.x86.r[X86_R_BP]
1316 + cpu->cd.x86.r[X86_R_DI];
1317 if (!cpu->cd.x86.seg_override)
1318 cpu->cd.x86.cursegment=X86_S_SS;
1319 break;
1320 case 4: addr += cpu->cd.x86.r[X86_R_SI];
1321 break;
1322 case 5: addr += cpu->cd.x86.r[X86_R_DI];
1323 break;
1324 case 6: addr += cpu->cd.x86.r[X86_R_BP];
1325 if (!cpu->cd.x86.seg_override)
1326 cpu->cd.x86.cursegment=X86_S_SS;
1327 break;
1328 case 7: addr += cpu->cd.x86.r[X86_R_BX];
1329 break;
1330 }
1331 }
1332
1333 if (mode67 == 16)
1334 addr &= 0xffff;
1335 if (mode67 == 32)
1336 addr &= 0xffffffffULL;
1337
1338 switch (writeflag) {
1339 case MODRM_WRITE_RM:
1340 res = x86_store(cpu, addr, *op1p, q);
1341 break;
1342 case MODRM_READ: /* read */
1343 if (flags & MODRM_JUST_GET_ADDR)
1344 *op1p = addr;
1345 else
1346 res = x86_load(cpu, addr, op1p, q);
1347 }
1348 }
1349 break;
1350 case 3:
1351 if (flags & MODRM_EIGHTBIT) {
1352 if (disasm) {
1353 strcpy(modrm_rm, reg_names_bytes[rm]);
1354 } else {
1355 switch (writeflag) {
1356 case MODRM_WRITE_RM:
1357 if (rm < 4)
1358 cpu->cd.x86.r[rm] =
1359 (cpu->cd.x86.r[rm] &
1360 ~0xff) | (*op1p & 0xff);
1361 else
1362 cpu->cd.x86.r[rm&3] = (cpu->
1363 cd.x86.r[rm&3] & ~0xff00) |
1364 ((*op1p & 0xff) << 8);
1365 break;
1366 case MODRM_READ:
1367 if (rm < 4)
1368 *op1p = cpu->cd.x86.r[rm] &
1369 0xff;
1370 else
1371 *op1p = (cpu->cd.x86.r[rm&3] &
1372 0xff00) >> 8;
1373 }
1374 }
1375 } else {
1376 if (disasm) {
1377 if (mode == 16 || flags & MODRM_RM_16BIT)
1378 strcpy(modrm_rm, reg_names[rm]);
1379 else
1380 sprintf(modrm_rm, "%s%s", e,
1381 reg_names[rm]);
1382 } else {
1383 switch (writeflag) {
1384 case MODRM_WRITE_RM:
1385 if (mode == 16 ||
1386 flags & MODRM_RM_16BIT)
1387 cpu->cd.x86.r[rm] = (
1388 cpu->cd.x86.r[rm] & ~0xffff)
1389 | (*op1p & 0xffff);
1390 else
1391 cpu->cd.x86.r[rm] =
1392 modify(cpu->cd.x86.r[rm],
1393 *op1p);
1394 break;
1395 case MODRM_READ: /* read */
1396 if (mode == 16 ||
1397 flags & MODRM_RM_16BIT)
1398 *op1p = cpu->cd.x86.r[rm]
1399 & 0xffff;
1400 else
1401 *op1p = cpu->cd.x86.r[rm];
1402 }
1403 }
1404 }
1405 break;
1406 default:
1407 fatal("modrm(): unimplemented mod %i\n", mod);
1408 exit(1);
1409 }
1410
1411
1412 /*
1413 * R:
1414 */
1415
1416 if (flags & MODRM_EIGHTBIT && !(flags & MODRM_R_NONEIGHTBIT)) {
1417 if (disasm) {
1418 strcpy(modrm_r, reg_names_bytes[r]);
1419 } else {
1420 switch (writeflag) {
1421 case MODRM_WRITE_R:
1422 if (r < 4)
1423 cpu->cd.x86.r[r] = (cpu->cd.x86.r[r] &
1424 ~0xff) | (*op2p & 0xff);
1425 else
1426 cpu->cd.x86.r[r&3] = (cpu->cd.x86.r[r&3]
1427 & ~0xff00) | ((*op2p & 0xff) << 8);
1428 break;
1429 case MODRM_READ:
1430 if (r < 4)
1431 *op2p = cpu->cd.x86.r[r] & 0xff;
1432 else
1433 *op2p = (cpu->cd.x86.r[r&3] &
1434 0xff00) >>8;
1435 }
1436 }
1437 } else {
1438 if (disasm) {
1439 if (flags & MODRM_SEG)
1440 strcpy(modrm_r, seg_names[r]);
1441 else if (flags & MODRM_CR)
1442 sprintf(modrm_r, "cr%i", r);
1443 else if (flags & MODRM_DR)
1444 sprintf(modrm_r, "dr%i", r);
1445 else {
1446 if (mode >= 32)
1447 sprintf(modrm_r, "%s%s", e,
1448 reg_names[r]);
1449 else
1450 strcpy(modrm_r, reg_names[r]);
1451 }
1452 } else {
1453 switch (writeflag) {
1454 case MODRM_WRITE_R:
1455 if (flags & MODRM_SEG)
1456 cpu->cd.x86.s[r] = *op2p;
1457 else if (flags & MODRM_CR)
1458 x86_write_cr(cpu, r, *op2p);
1459 else if (flags & MODRM_DR)
1460 cpu->cd.x86.dr[r] = *op2p;
1461 else
1462 cpu->cd.x86.r[r] =
1463 modify(cpu->cd.x86.r[r], *op2p);
1464 break;
1465 case MODRM_READ:
1466 if (flags & MODRM_SEG)
1467 *op2p = cpu->cd.x86.s[r];
1468 else if (flags & MODRM_CR)
1469 *op2p = cpu->cd.x86.cr[r];
1470 else if (flags & MODRM_DR)
1471 *op2p = cpu->cd.x86.dr[r];
1472 else
1473 *op2p = cpu->cd.x86.r[r];
1474 }
1475 }
1476 }
1477
1478 if (!disasm) {
1479 switch (mode) {
1480 case 16:*op1p &= 0xffff; *op2p &= 0xffff; break;
1481 case 32:*op1p &= 0xffffffffULL; *op2p &= 0xffffffffULL; break;
1482 }
1483 }
1484
1485 return res;
1486 }
1487
1488
1489 /*
1490 * x86_cpu_disassemble_instr():
1491 *
1492 * Convert an instruction word into human readable format, for instruction
1493 * tracing.
1494 *
1495 * If running&1 is 1, cpu->pc should be the address of the instruction.
1496 *
1497 * If running&1 is 0, things that depend on the runtime environment (eg.
1498 * register contents) will not be shown, and addr will be used instead of
1499 * cpu->pc for relative addresses.
1500 *
1501 * The rest of running tells us the default (code) operand size.
1502 */
1503 int x86_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr,
1504 int running, uint64_t dumpaddr, int bintrans)
1505 {
1506 int op, rep = 0, lock = 0, n_prefix_bytes = 0;
1507 uint64_t ilen = 0, offset;
1508 uint32_t imm=0, imm2;
1509 int mode = running & ~1;
1510 int mode67;
1511 char *symbol, *mnem = "ERROR", *e = "e", *prefix = NULL;
1512
1513 if (running)
1514 dumpaddr = cpu->pc;
1515
1516 if (mode == 0) {
1517 mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
1518 if (mode == 0) {
1519 fatal("x86_cpu_disassemble_instr(): no mode: TODO\n");
1520 return 1;
1521 }
1522 }
1523
1524 mode67 = mode;
1525
1526 symbol = get_symbol_name(&cpu->machine->symbol_context,
1527 dumpaddr, &offset);
1528 if (symbol != NULL && offset==0)
1529 debug("<%s>\n", symbol);
1530
1531 if (cpu->machine->ncpus > 1 && running)
1532 debug("cpu%i: ", cpu->cpu_id);
1533
1534 if (mode == 32)
1535 debug("%08x: ", (int)dumpaddr);
1536 else if (mode == 64)
1537 debug("%016llx: ", (long long)dumpaddr);
1538 else { /* 16-bit mode */
1539 debug("%04x:%04x ", cpu->cd.x86.s[X86_S_CS],
1540 (int)dumpaddr & 0xffff);
1541 }
1542
1543 /*
1544 * Decode the instruction:
1545 */
1546
1547 /* All instructions are at least 1 byte long: */
1548 HEXPRINT(instr,1);
1549 ilen = 1;
1550
1551 /* Any prefix? */
1552 for (;;) {
1553 if (instr[0] == 0x66) {
1554 if (mode == 16)
1555 mode = 32;
1556 else
1557 mode = 16;
1558 } else if (instr[0] == 0x67) {
1559 if (mode67 == 16)
1560 mode67 = 32;
1561 else
1562 mode67 = 16;
1563 } else if (instr[0] == 0xf2) {
1564 rep = REP_REPNE;
1565 } else if (instr[0] == 0xf3) {
1566 rep = REP_REP;
1567 } else if (instr[0] == 0x26) {
1568 prefix = "es:";
1569 } else if (instr[0] == 0x2e) {
1570 prefix = "cs:";
1571 } else if (instr[0] == 0x36) {
1572 prefix = "ss:";
1573 } else if (instr[0] == 0x3e) {
1574 prefix = "ds:";
1575 } else if (instr[0] == 0x64) {
1576 prefix = "fs:";
1577 } else if (instr[0] == 0x65) {
1578 prefix = "gs:";
1579 } else if (instr[0] == 0xf0) {
1580 lock = 1;
1581 } else
1582 break;
1583
1584 if (++n_prefix_bytes > 4) {
1585 SPACES; debug("more than 4 prefix bytes?\n");
1586 return 4;
1587 }
1588
1589 /* TODO: lock, segment overrides etc */
1590 instr ++; ilen ++;
1591 debug("%02x", instr[0]);
1592 }
1593
1594 if (mode == 16)
1595 e = "";
1596
1597 op = instr[0];
1598 instr ++;
1599
1600 if ((op & 0xf0) <= 0x30 && (op & 7) <= 5) {
1601 switch (op & 0x38) {
1602 case 0x00: mnem = "add"; break;
1603 case 0x08: mnem = "or"; break;
1604 case 0x10: mnem = "adc"; break;
1605 case 0x18: mnem = "sbb"; break;
1606 case 0x20: mnem = "and"; break;
1607 case 0x28: mnem = "sub"; break;
1608 case 0x30: mnem = "xor"; break;
1609 case 0x38: mnem = "cmp"; break;
1610 }
1611 switch (op & 7) {
1612 case 4: imm = read_imm_and_print(&instr, &ilen, 8);
1613 SPACES; debug("%s\tal,0x%02x", mnem, imm);
1614 break;
1615 case 5: imm = read_imm_and_print(&instr, &ilen, mode);
1616 SPACES; debug("%s\t%sax,0x%x", mnem, e, imm);
1617 break;
1618 default:modrm(cpu, MODRM_READ, mode, mode67, op&1? 0 :
1619 MODRM_EIGHTBIT, &instr, &ilen, NULL, NULL);
1620 SPACES; debug("%s\t", mnem);
1621 if (op & 2)
1622 debug("%s,%s", modrm_r, modrm_rm);
1623 else
1624 debug("%s,%s", modrm_rm, modrm_r);
1625 }
1626 } else if (op == 0xf) {
1627 /* "pop cs" on 8086 */
1628 if (cpu->cd.x86.model.model_number == X86_MODEL_8086) {
1629 SPACES; debug("pop\tcs");
1630 } else {
1631 imm = read_imm_and_print(&instr, &ilen, 8);
1632 if (imm == 0x00) {
1633 int subop = (*instr >> 3) & 0x7;
1634 switch (subop) {
1635 case 0: modrm(cpu, MODRM_READ, mode, mode67,
1636 0, &instr, &ilen, NULL, NULL);
1637 SPACES; debug("sldt\t%s", modrm_rm);
1638 break;
1639 case 1: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1640 mode67, 0, &instr, &ilen,
1641 NULL, NULL);
1642 SPACES; debug("str\t%s", modrm_rm);
1643 break;
1644 case 2: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1645 mode67, 0, &instr, &ilen,
1646 NULL, NULL);
1647 SPACES; debug("lldt\t%s", modrm_rm);
1648 break;
1649 case 3: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1650 mode67, 0, &instr, &ilen,
1651 NULL, NULL);
1652 SPACES; debug("ltr\t%s", modrm_rm);
1653 break;
1654 case 4: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1655 mode67, 0, &instr, &ilen,
1656 NULL, NULL);
1657 SPACES; debug("verr\t%s", modrm_rm);
1658 break;
1659 case 5: modrm(cpu, MODRM_READ, 16 /* note:16 */,
1660 mode67, 0, &instr, &ilen,
1661 NULL, NULL);
1662 SPACES; debug("verw\t%s", modrm_rm);
1663 break;
1664 default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1665 "%02x,0x%02x", op, imm, *instr);
1666 }
1667 } else if (imm == 0x01) {
1668 int subop = (*instr >> 3) & 0x7;
1669 switch (subop) {
1670 case 0:
1671 case 1:
1672 case 2:
1673 case 3: modrm(cpu, MODRM_READ, mode, mode67,
1674 0, &instr, &ilen, NULL, NULL);
1675 SPACES; debug("%s%s\t%s",
1676 subop < 2? "s" : "l",
1677 subop&1? "idt" : "gdt", modrm_rm);
1678 break;
1679 case 4:
1680 case 6: if (((*instr >> 3) & 0x7) == 4)
1681 mnem = "smsw";
1682 else
1683 mnem = "lmsw";
1684 modrm(cpu, MODRM_READ, 16, mode67,
1685 0, &instr, &ilen, NULL, NULL);
1686 SPACES; debug("%s\t%s", mnem, modrm_rm);
1687 break;
1688 case 7: modrm(cpu, MODRM_READ, mode,
1689 mode67, 0, &instr, &ilen,
1690 NULL, NULL);
1691 SPACES; debug("invlpg\t%s", modrm_rm);
1692 break;
1693 default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1694 "%02x,0x%02x", op, imm, *instr);
1695 }
1696 } else if (imm == 0x02) {
1697 modrm(cpu, MODRM_READ, mode, mode67,
1698 0, &instr, &ilen, NULL, NULL);
1699 SPACES; debug("lar\t%s,%s", modrm_r, modrm_rm);
1700 } else if (imm == 0x03) {
1701 modrm(cpu, MODRM_READ, mode, mode67,
1702 0, &instr, &ilen, NULL, NULL);
1703 SPACES; debug("lsl\t%s,%s", modrm_r, modrm_rm);
1704 } else if (imm == 0x05) {
1705 SPACES; /* TODO: exactly which models?*/
1706 if (cpu->cd.x86.model.model_number >
1707 X86_MODEL_80486)
1708 debug("syscall");
1709 else
1710 debug("loadall286");
1711 } else if (imm == 0x06) {
1712 SPACES; debug("clts");
1713 } else if (imm == 0x07) {
1714 SPACES; /* TODO: exactly which models?*/
1715 if (cpu->cd.x86.model.model_number >
1716 X86_MODEL_80486)
1717 debug("sysret");
1718 else
1719 debug("loadall");
1720 } else if (imm == 0x08) {
1721 SPACES; debug("invd");
1722 } else if (imm == 0x09) {
1723 SPACES; debug("wbinvd");
1724 } else if (imm == 0x0b) {
1725 SPACES; debug("reserved_0b");
1726 } else if (imm == 0x20 || imm == 0x21) {
1727 modrm(cpu, MODRM_READ, 32 /* note: 32 */,
1728 mode67, imm == 0x20? MODRM_CR : MODRM_DR,
1729 &instr, &ilen, NULL, NULL);
1730 SPACES; debug("mov\t%s,%s", modrm_rm, modrm_r);
1731 } else if (imm == 0x22 || imm == 0x23) {
1732 modrm(cpu, MODRM_READ, 32 /* note: 32 */,
1733 mode67, imm == 0x22? MODRM_CR : MODRM_DR,
1734 &instr, &ilen, NULL, NULL);
1735 SPACES; debug("mov\t%s,%s", modrm_r, modrm_rm);
1736 } else if (imm == 0x30) {
1737 SPACES; debug("wrmsr");
1738 } else if (imm == 0x31) {
1739 SPACES; debug("rdtsc");
1740 } else if (imm == 0x32) {
1741 SPACES; debug("rdmsr");
1742 } else if (imm == 0x33) {
1743 SPACES; debug("rdpmc"); /* http://www
1744 .x86.org/secrets/opcodes/rdpmc.htm */
1745 } else if (imm == 0x34) {
1746 SPACES; debug("sysenter");
1747 } else if (imm == 0x36) {
1748 SPACES; debug("sysexit");
1749 } else if (imm >= 0x40 && imm <= 0x4f) {
1750 modrm(cpu, MODRM_READ, mode, mode67, 0,
1751 &instr, &ilen, NULL, NULL);
1752 op = imm & 0xf;
1753 SPACES; debug("cmov%s%s\t%s,%s", op&1? "n"
1754 : "", cond_names[(op/2) & 0x7],
1755 modrm_r, modrm_rm);
1756 } else if (imm >= 0x80 && imm <= 0x8f) {
1757 op = imm & 0xf;
1758 imm = read_imm_and_print(&instr, &ilen, mode);
1759 imm = dumpaddr + 2 + mode/8 + imm;
1760 SPACES; debug("j%s%s\tnear 0x%x", op&1? "n"
1761 : "", cond_names[(op/2) & 0x7], imm);
1762 } else if (imm >= 0x90 && imm <= 0x9f) {
1763 op = imm;
1764 modrm(cpu, MODRM_READ, mode,
1765 mode67, MODRM_EIGHTBIT, &instr, &ilen,
1766 NULL, NULL);
1767 SPACES; debug("set%s%s\t%s", op&1? "n"
1768 : "", cond_names[(op/2) & 0x7], modrm_rm);
1769 } else if (imm == 0xa0) {
1770 SPACES; debug("push\tfs");
1771 } else if (imm == 0xa1) {
1772 SPACES; debug("pop\tfs");
1773 } else if (imm == 0xa2) {
1774 SPACES; debug("cpuid");
1775 } else if (imm == 0xa3 || imm == 0xab
1776 || imm == 0xb3 || imm == 0xbb) {
1777 modrm(cpu, MODRM_READ, mode, mode67,
1778 0, &instr, &ilen, NULL, NULL);
1779 switch (imm) {
1780 case 0xa3: mnem = "bt"; break;
1781 case 0xab: mnem = "bts"; break;
1782 case 0xb3: mnem = "btr"; break;
1783 case 0xbb: mnem = "btc"; break;
1784 }
1785 SPACES; debug("%s\t%s,%s",
1786 mnem, modrm_rm, modrm_r);
1787 } else if (imm == 0xa4 || imm == 0xa5 ||
1788 imm == 0xac || imm == 0xad) {
1789 modrm(cpu, MODRM_READ, mode, mode67,
1790 0, &instr, &ilen, NULL, NULL);
1791 if (!(imm & 1))
1792 imm2 = read_imm_and_print(&instr,
1793 &ilen, 8);
1794 else
1795 imm2 = 0;
1796 SPACES; debug("sh%sd\t%s,%s,",
1797 imm <= 0xa5? "l" : "r",
1798 modrm_rm, modrm_r);
1799 if (imm & 1)
1800 debug("cl");
1801 else
1802 debug("%i", imm2);
1803 } else if (imm == 0xa8) {
1804 SPACES; debug("push\tgs");
1805 } else if (imm == 0xa9) {
1806 SPACES; debug("pop\tgs");
1807 } else if (imm == 0xaa) {
1808 SPACES; debug("rsm");
1809 } else if (imm == 0xaf) {
1810 modrm(cpu, MODRM_READ, mode, mode67,
1811 0, &instr, &ilen, NULL, NULL);
1812 SPACES; debug("imul\t%s,%s", modrm_r, modrm_rm);
1813 } else if (imm == 0xb0 || imm == 0xb1) {
1814 modrm(cpu, MODRM_READ, mode, mode67,
1815 imm == 0xb0? MODRM_EIGHTBIT : 0,
1816 &instr, &ilen, NULL, NULL);
1817 SPACES; debug("cmpxchg\t%s,%s",
1818 modrm_rm, modrm_r);
1819 } else if (imm == 0xb2 || imm == 0xb4 || imm == 0xb5) {
1820 modrm(cpu, MODRM_READ, mode, mode67, 0,
1821 &instr, &ilen, NULL, NULL);
1822 switch (imm) {
1823 case 0xb2: mnem = "lss"; break;
1824 case 0xb4: mnem = "lfs"; break;
1825 case 0xb5: mnem = "lgs"; break;
1826 }
1827 SPACES; debug("%s\t%s,%s", mnem,
1828 modrm_r, modrm_rm);
1829 } else if (imm == 0xb6 || imm == 0xb7 ||
1830 imm == 0xbe || imm == 0xbf) {
1831 modrm(cpu, MODRM_READ, mode, mode67,
1832 (imm&1)==0? (MODRM_EIGHTBIT |
1833 MODRM_R_NONEIGHTBIT) : MODRM_RM_16BIT,
1834 &instr, &ilen, NULL, NULL);
1835 mnem = "movsx";
1836 if (imm <= 0xb7)
1837 mnem = "movzx";
1838 SPACES; debug("%s\t%s,%s", mnem,
1839 modrm_r, modrm_rm);
1840 } else if (imm == 0xba) {
1841 int subop = (*instr >> 3) & 0x7;
1842 switch (subop) {
1843 case 4: modrm(cpu, MODRM_READ, mode, mode67,
1844 0, &instr, &ilen, NULL, NULL);
1845 imm2 = read_imm_and_print(&instr,
1846 &ilen, 8);
1847 SPACES; debug("bt\t%s,%i",
1848 modrm_rm, imm2);
1849 break;
1850 case 5: modrm(cpu, MODRM_READ, mode, mode67,
1851 0, &instr, &ilen, NULL, NULL);
1852 imm2 = read_imm_and_print(&instr,
1853 &ilen, 8);
1854 SPACES; debug("bts\t%s,%i",
1855 modrm_rm, imm2);
1856 break;
1857 case 6: modrm(cpu, MODRM_READ, mode, mode67,
1858 0, &instr, &ilen, NULL, NULL);
1859 imm2 = read_imm_and_print(&instr,
1860 &ilen, 8);
1861 SPACES; debug("btr\t%s,%i",
1862 modrm_rm, imm2);
1863 break;
1864 case 7: modrm(cpu, MODRM_READ, mode, mode67,
1865 0, &instr, &ilen, NULL, NULL);
1866 imm2 = read_imm_and_print(&instr,
1867 &ilen, 8);
1868 SPACES; debug("btc\t%s,%i",
1869 modrm_rm, imm2);
1870 break;
1871 default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1872 "%02x,0x%02x", op, imm, *instr);
1873 }
1874 } else if (imm == 0xbc || imm == 0xbd) {
1875 modrm(cpu, MODRM_READ, mode, mode67,
1876 0, &instr, &ilen, NULL, NULL);
1877 if (imm == 0xbc)
1878 mnem = "bsf";
1879 else
1880 mnem = "bsr";
1881 SPACES; debug("%s\t%s,%s", mnem, modrm_r,
1882 modrm_rm);
1883 } else if (imm == 0xc0 || imm == 0xc1) {
1884 modrm(cpu, MODRM_READ, mode, mode67,
1885 imm&1? 0 : MODRM_EIGHTBIT,
1886 &instr, &ilen, NULL, NULL);
1887 SPACES; debug("xadd\t%s,%s", modrm_rm, modrm_r);
1888 } else if (imm == 0xc7) {
1889 int subop = (*instr >> 3) & 0x7;
1890 switch (subop) {
1891 case 1: modrm(cpu, MODRM_READ, 64, mode67,
1892 0, &instr, &ilen, NULL, NULL);
1893 SPACES; debug("cmpxchg8b\t%s",modrm_rm);
1894 break;
1895 default:SPACES; debug("UNIMPLEMENTED 0x%02x,0x"
1896 "%02x,0x%02x", op, imm, *instr);
1897 }
1898 } else if (imm >= 0xc8 && imm <= 0xcf) {
1899 SPACES; debug("bswap\te%s", reg_names[imm & 7]);
1900 } else {
1901 SPACES; debug("UNIMPLEMENTED 0x0f,0x%02x", imm);
1902 }
1903 }
1904 } else if (op < 0x20 && (op & 7) == 6) {
1905 SPACES; debug("push\t%s", seg_names[op/8]);
1906 } else if (op < 0x20 && (op & 7) == 7) {
1907 SPACES; debug("pop\t%s", seg_names[op/8]);
1908 } else if (op >= 0x20 && op < 0x40 && (op & 7) == 7) {
1909 SPACES; debug("%sa%s", op < 0x30? "d" : "a",
1910 (op & 0xf)==7? "a" : "s");
1911 } else if (op >= 0x40 && op <= 0x5f) {
1912 switch (op & 0x38) {
1913 case 0x00: mnem = "inc"; break;
1914 case 0x08: mnem = "dec"; break;
1915 case 0x10: mnem = "push"; break;
1916 case 0x18: mnem = "pop"; break;
1917 }
1918 SPACES; debug("%s\t%s%s", mnem, e, reg_names[op & 7]);
1919 } else if (op == 0x60) {
1920 SPACES; debug("pusha%s", mode==16? "" : (mode==32? "d" : "q"));
1921 } else if (op == 0x61) {
1922 SPACES; debug("popa%s", mode==16? "" : (mode==32? "d" : "q"));
1923 } else if (op == 0x62) {
1924 modrm(cpu, MODRM_READ, mode, mode67,
1925 0, &instr, &ilen, NULL, NULL);
1926 SPACES; debug("bound\t%s,%s", modrm_r, modrm_rm);
1927 } else if (op == 0x63) {
1928 modrm(cpu, MODRM_READ, 16, mode67,
1929 0, &instr, &ilen, NULL, NULL);
1930 SPACES; debug("arpl\t%s,%s", modrm_rm, modrm_r);
1931 } else if (op == 0x68) {
1932 imm = read_imm_and_print(&instr, &ilen, mode);
1933 SPACES; debug("push\t%sword 0x%x", mode==32?"d":"", imm);
1934 } else if (op == 0x69 || op == 0x6b) {
1935 modrm(cpu, MODRM_READ, mode, mode67,
1936 0, &instr, &ilen, NULL, NULL);
1937 if (op == 0x69)
1938 imm = read_imm_and_print(&instr, &ilen, mode);
1939 else
1940 imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1941 SPACES; debug("imul\t%s,%s,%i", modrm_r, modrm_rm, imm);
1942 } else if (op == 0x6a) {
1943 imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1944 SPACES; debug("push\tbyte 0x%x", imm);
1945 } else if (op == 0x6c) {
1946 SPACES; debug("insb");
1947 } else if (op == 0x6d) {
1948 SPACES; debug("ins%s", mode==16? "w" : (mode==32? "d" : "q"));
1949 } else if (op == 0x6e) {
1950 SPACES; debug("outsb");
1951 } else if (op == 0x6f) {
1952 SPACES; debug("outs%s", mode==16? "w" : (mode==32? "d" : "q"));
1953 } else if ((op & 0xf0) == 0x70) {
1954 imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1955 imm = dumpaddr + 2 + imm;
1956 SPACES; debug("j%s%s\t0x%x", op&1? "n" : "",
1957 cond_names[(op/2) & 0x7], imm);
1958 } else if (op == 0x80 || op == 0x81) {
1959 switch ((*instr >> 3) & 0x7) {
1960 case 0: mnem = "add"; break;
1961 case 1: mnem = "or"; break;
1962 case 2: mnem = "adc"; break;
1963 case 3: mnem = "sbb"; break;
1964 case 4: mnem = "and"; break;
1965 case 5: mnem = "sub"; break;
1966 case 6: mnem = "xor"; break;
1967 case 7: mnem = "cmp"; break;
1968 default:
1969 SPACES; debug("UNIMPLEMENTED 0x%02x", op);
1970 }
1971 modrm(cpu, MODRM_READ, mode, mode67,
1972 op == 0x80? MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
1973 imm = read_imm_and_print(&instr, &ilen, op==0x80? 8 : mode);
1974 SPACES; debug("%s\t%s,0x%x", mnem, modrm_rm, imm);
1975 } else if (op == 0x83) {
1976 switch ((*instr >> 3) & 0x7) {
1977 case 0: mnem = "add"; break;
1978 case 1: mnem = "or"; break;
1979 case 2: mnem = "adc"; break;
1980 case 3: mnem = "sbb"; break;
1981 case 4: mnem = "and"; break;
1982 case 5: mnem = "sub"; break;
1983 case 6: mnem = "xor"; break;
1984 case 7: mnem = "cmp"; break;
1985 default:
1986 SPACES; debug("UNIMPLEMENTED 0x%02x", op);
1987 }
1988 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, &ilen,
1989 NULL, NULL);
1990 imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
1991 SPACES; debug("%s\t%s,0x%x", mnem, modrm_rm, imm);
1992 } else if (op == 0x84 || op == 0x85) {
1993 modrm(cpu, MODRM_READ, mode, mode67,
1994 op == 0x84? MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
1995 SPACES; debug("test\t%s,%s", modrm_rm, modrm_r);
1996 } else if (op == 0x86 || op == 0x87) {
1997 modrm(cpu, MODRM_READ, mode, mode67, op == 0x86?
1998 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
1999 SPACES; debug("xchg\t%s,%s", modrm_rm, modrm_r);
2000 } else if (op == 0x88 || op == 0x89) {
2001 modrm(cpu, MODRM_READ, mode, mode67, op == 0x88?
2002 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2003 SPACES; debug("mov\t%s,%s", modrm_rm, modrm_r);
2004 } else if (op == 0x8a || op == 0x8b) {
2005 modrm(cpu, MODRM_READ, mode, mode67, op == 0x8a?
2006 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2007 SPACES; debug("mov\t%s,%s", modrm_r, modrm_rm);
2008 } else if (op == 0x8c || op == 0x8e) {
2009 modrm(cpu, MODRM_READ, mode, mode67, MODRM_SEG, &instr, &ilen,
2010 NULL, NULL);
2011 SPACES; debug("mov\t");
2012 if (op == 0x8c)
2013 debug("%s,%s", modrm_rm, modrm_r);
2014 else
2015 debug("%s,%s", modrm_r, modrm_rm);
2016 } else if (op == 0x8d) {
2017 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, &ilen,
2018 NULL, NULL);
2019 SPACES; debug("lea\t%s,%s", modrm_r, modrm_rm);
2020 } else if (op == 0x8f) {
2021 switch ((*instr >> 3) & 0x7) {
2022 case 0: /* POP m16/m32 */
2023 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2024 &ilen, NULL, NULL);
2025 SPACES; debug("pop\t%sword %s", mode == 32? "d" : "",
2026 modrm_rm);
2027 break;
2028 default:
2029 SPACES; debug("UNIMPLEMENTED 0x%02x", op);
2030 }
2031 } else if (op == 0x90) {
2032 SPACES; debug("nop");
2033 } else if (op >= 0x91 && op <= 0x97) {
2034 SPACES; debug("xchg\t%sax,%s%s", e, e, reg_names[op & 7]);
2035 } else if (op == 0x98) {
2036 SPACES; debug("cbw");
2037 } else if (op == 0x99) {
2038 SPACES; debug("cwd");
2039 } else if (op == 0x9a) {
2040 imm = read_imm_and_print(&instr, &ilen, mode);
2041 imm2 = read_imm_and_print(&instr, &ilen, 16);
2042 SPACES; debug("call\t0x%04x:", imm2);
2043 if (mode == 16)
2044 debug("0x%04x", imm);
2045 else
2046 debug("0x%08x", imm);
2047 } else if (op == 0x9b) {
2048 SPACES; debug("wait");
2049 } else if (op == 0x9c) {
2050 SPACES; debug("pushf%s", mode==16? "" : (mode==32? "d" : "q"));
2051 } else if (op == 0x9d) {
2052 SPACES; debug("popf%s", mode==16? "" : (mode==32? "d" : "q"));
2053 } else if (op == 0x9e) {
2054 SPACES; debug("sahf");
2055 } else if (op == 0x9f) {
2056 SPACES; debug("lahf");
2057 } else if (op == 0xa0) {
2058 imm = read_imm_and_print(&instr, &ilen, mode67);
2059 SPACES; debug("mov\tal,[0x%x]", imm);
2060 } else if (op == 0xa1) {
2061 imm = read_imm_and_print(&instr, &ilen, mode67);
2062 SPACES; debug("mov\t%sax,[0x%x]", e, imm);
2063 } else if (op == 0xa2) {
2064 imm = read_imm_and_print(&instr, &ilen, mode67);
2065 SPACES; debug("mov\t[0x%x],al", imm);
2066 } else if (op == 0xa3) {
2067 imm = read_imm_and_print(&instr, &ilen, mode67);
2068 SPACES; debug("mov\t[0x%x],%sax", imm, e);
2069 } else if (op == 0xa4) {
2070 SPACES; debug("movsb");
2071 } else if (op == 0xa5) {
2072 SPACES; debug("movs%s", mode==16? "w" : (mode==32? "d" : "q"));
2073 } else if (op == 0xa6) {
2074 SPACES; debug("cmpsb");
2075 } else if (op == 0xa7) {
2076 SPACES; debug("cmps%s", mode==16? "w" : (mode==32? "d" : "q"));
2077 } else if (op == 0xa8 || op == 0xa9) {
2078 imm = read_imm_and_print(&instr, &ilen, op == 0xa8? 8 : mode);
2079 if (op == 0xa8)
2080 mnem = "al";
2081 else if (mode == 16)
2082 mnem = "ax";
2083 else
2084 mnem = "eax";
2085 SPACES; debug("test\t%s,0x%x", mnem, imm);
2086 } else if (op == 0xaa) {
2087 SPACES; debug("stosb");
2088 } else if (op == 0xab) {
2089 SPACES; debug("stos%s", mode==16? "w" : (mode==32? "d" : "q"));
2090 } else if (op == 0xac) {
2091 SPACES; debug("lodsb");
2092 } else if (op == 0xad) {
2093 SPACES; debug("lods%s", mode==16? "w" : (mode==32? "d" : "q"));
2094 } else if (op == 0xae) {
2095 SPACES; debug("scasb");
2096 } else if (op == 0xaf) {
2097 SPACES; debug("scas%s", mode==16? "w" : (mode==32? "d" : "q"));
2098 } else if (op >= 0xb0 && op <= 0xb7) {
2099 imm = read_imm_and_print(&instr, &ilen, 8);
2100 SPACES; debug("mov\t%s,0x%x", reg_names_bytes[op&7], imm);
2101 } else if (op >= 0xb8 && op <= 0xbf) {
2102 imm = read_imm_and_print(&instr, &ilen, mode);
2103 SPACES; debug("mov\t%s%s,0x%x", e, reg_names[op & 7], imm);
2104 } else if (op == 0xc0 || op == 0xc1) {
2105 switch ((*instr >> 3) & 0x7) {
2106 case 0: mnem = "rol"; break;
2107 case 1: mnem = "ror"; break;
2108 case 2: mnem = "rcl"; break;
2109 case 3: mnem = "rcr"; break;
2110 case 4: mnem = "shl"; break;
2111 case 5: mnem = "shr"; break;
2112 case 6: mnem = "sal"; break;
2113 case 7: mnem = "sar"; break;
2114 }
2115 modrm(cpu, MODRM_READ, mode, mode67, op == 0xc0?
2116 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2117 imm = read_imm_and_print(&instr, &ilen, 8);
2118 SPACES; debug("%s\t%s,%i", mnem, modrm_rm, imm);
2119 } else if (op == 0xc2) {
2120 imm = read_imm_and_print(&instr, &ilen, 16);
2121 SPACES; debug("ret\t0x%x", imm);
2122 } else if (op == 0xc3) {
2123 SPACES; debug("ret");
2124 } else if (op == 0xc4 || op == 0xc5) {
2125 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, &ilen,
2126 NULL, NULL);
2127 switch (op) {
2128 case 0xc4: mnem = "les"; break;
2129 case 0xc5: mnem = "lds"; break;
2130 }
2131 SPACES; debug("%s\t%s,%s", mnem, modrm_r, modrm_rm);
2132 } else if (op == 0xc6 || op == 0xc7) {
2133 switch ((*instr >> 3) & 0x7) {
2134 case 0: modrm(cpu, MODRM_READ, mode, mode67, op == 0xc6?
2135 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2136 imm = read_imm_and_print(&instr, &ilen,
2137 op == 0xc6? 8 : mode);
2138 SPACES; debug("mov\t%s,0x%x", modrm_rm, imm);
2139 break;
2140 default:
2141 SPACES; debug("UNIMPLEMENTED 0x%02x", op);
2142 }
2143 } else if (op == 0xc8) {
2144 imm = read_imm_and_print(&instr, &ilen, 16);
2145 imm2 = read_imm_and_print(&instr, &ilen, 8);
2146 SPACES; debug("enter\t0x%x,%i", imm, imm2);
2147 } else if (op == 0xc9) {
2148 SPACES; debug("leave");
2149 } else if (op == 0xca) {
2150 imm = read_imm_and_print(&instr, &ilen, 16);
2151 SPACES; debug("retf\t0x%x", imm);
2152 } else if (op == 0xcb) {
2153 SPACES; debug("retf");
2154 } else if (op == 0xcc) {
2155 SPACES; debug("int3");
2156 } else if (op == 0xcd) {
2157 imm = read_imm_and_print(&instr, &ilen, 8);
2158 SPACES; debug("int\t0x%x", imm);
2159 } else if (op == 0xce) {
2160 SPACES; debug("into");
2161 } else if (op == 0xcf) {
2162 SPACES; debug("iret");
2163 } else if (op >= 0xd0 && op <= 0xd3) {
2164 int subop = (*instr >> 3) & 0x7;
2165 modrm(cpu, MODRM_READ, mode, mode67, op&1? 0 :
2166 MODRM_EIGHTBIT, &instr, &ilen, NULL, NULL);
2167 switch (subop) {
2168 case 0: mnem = "rol"; break;
2169 case 1: mnem = "ror"; break;
2170 case 2: mnem = "rcl"; break;
2171 case 3: mnem = "rcr"; break;
2172 case 4: mnem = "shl"; break;
2173 case 5: mnem = "shr"; break;
2174 case 6: mnem = "sal"; break;
2175 case 7: mnem = "sar"; break;
2176 }
2177 SPACES; debug("%s\t%s,", mnem, modrm_rm);
2178 if (op <= 0xd1)
2179 debug("1");
2180 else
2181 debug("cl");
2182 } else if (op == 0xd4) {
2183 imm = read_imm_and_print(&instr, &ilen, 8);
2184 SPACES; debug("aam");
2185 if (imm != 10)
2186 debug("\t%i", imm);
2187 } else if (op == 0xd5) {
2188 imm = read_imm_and_print(&instr, &ilen, 8);
2189 SPACES; debug("aad");
2190 if (imm != 10)
2191 debug("\t%i", imm);
2192 } else if (op == 0xd6) {
2193 SPACES; debug("salc"); /* undocumented? */
2194 } else if (op == 0xd7) {
2195 SPACES; debug("xlat");
2196 } else if (op == 0xd9) {
2197 int subop = (*instr >> 3) & 7;
2198 imm = *instr;
2199 if (subop == 5) {
2200 modrm(cpu, MODRM_READ, 16, mode67, 0,
2201 &instr, &ilen, NULL, NULL);
2202 SPACES; debug("fldcw\t%s", modrm_rm);
2203 } else if (subop == 7) {
2204 modrm(cpu, MODRM_READ, 16, mode67, 0,
2205 &instr, &ilen, NULL, NULL);
2206 SPACES; debug("fstcw\t%s", modrm_rm);
2207 } else {
2208 SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2209 }
2210 } else if (op == 0xdb) {
2211 imm = *instr;
2212 if (imm == 0xe2) {
2213 read_imm_and_print(&instr, &ilen, 8);
2214 SPACES; debug("fclex");
2215 } else if (imm == 0xe3) {
2216 read_imm_and_print(&instr, &ilen, 8);
2217 SPACES; debug("finit");
2218 } else if (imm == 0xe4) {
2219 read_imm_and_print(&instr, &ilen, 8);
2220 SPACES; debug("fsetpm");
2221 } else {
2222 SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2223 }
2224 } else if (op == 0xdd) {
2225 int subop = (*instr >> 3) & 7;
2226 imm = *instr;
2227 if (subop == 7) {
2228 modrm(cpu, MODRM_READ, 16, mode67, 0,
2229 &instr, &ilen, NULL, NULL);
2230 SPACES; debug("fstsw\t%s", modrm_rm);
2231 } else {
2232 SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2233 }
2234 } else if (op == 0xdf) {
2235 imm = *instr;
2236 if (imm == 0xe0) {
2237 read_imm_and_print(&instr, &ilen, 8);
2238 SPACES; debug("fstsw\tax");
2239 } else {
2240 SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op, imm);
2241 }
2242 } else if (op == 0xe3) {
2243 imm = read_imm_and_print(&instr, &ilen, 8);
2244 imm = dumpaddr + ilen + (signed char)imm;
2245 if (mode == 16)
2246 mnem = "jcxz";
2247 else
2248 mnem = "jecxz";
2249 SPACES; debug("%s\t0x%x", mnem, imm);
2250 } else if (op == 0xe4) {
2251 imm = read_imm_and_print(&instr, &ilen, 8);
2252 SPACES; debug("in\tal,0x%x", imm);
2253 } else if (op == 0xe5) {
2254 imm = read_imm_and_print(&instr, &ilen, 8);
2255 SPACES; debug("in\t%sax,0x%x", e, imm);
2256 } else if (op == 0xe6) {
2257 imm = read_imm_and_print(&instr, &ilen, 8);
2258 SPACES; debug("out\t0x%x,al", imm);
2259 } else if (op == 0xe7) {
2260 imm = read_imm_and_print(&instr, &ilen, 8);
2261 SPACES; debug("out\t0x%x,%sax", imm, e);
2262 } else if (op == 0xe8 || op == 0xe9) {
2263 imm = read_imm_and_print(&instr, &ilen, mode);
2264 if (mode == 16)
2265 imm = (int16_t)imm;
2266 imm = dumpaddr + ilen + imm;
2267 switch (op) {
2268 case 0xe8: mnem = "call"; break;
2269 case 0xe9: mnem = "jmp"; break;
2270 }
2271 SPACES; debug("%s\t0x%x", mnem, imm);
2272 } else if (op == 0xea) {
2273 imm = read_imm_and_print(&instr, &ilen, mode);
2274 imm2 = read_imm_and_print(&instr, &ilen, 16);
2275 SPACES; debug("jmp\t0x%04x:", imm2);
2276 if (mode == 16)
2277 debug("0x%04x", imm);
2278 else
2279 debug("0x%08x", imm);
2280 } else if ((op >= 0xe0 && op <= 0xe2) || op == 0xeb) {
2281 imm = read_imm_and_print(&instr, &ilen, 8);
2282 imm = dumpaddr + ilen + (signed char)imm;
2283 switch (op) {
2284 case 0xe0: mnem = "loopnz"; break;
2285 case 0xe1: mnem = "loopz"; break;
2286 case 0xe2: mnem = "loop"; break;
2287 case 0xeb: mnem = "jmp"; break;
2288 }
2289 SPACES; debug("%s\t0x%x", mnem, imm);
2290 } else if (op == 0xec) {
2291 SPACES; debug("in\tal,dx");
2292 } else if (op == 0xed) {
2293 SPACES; debug("in\t%sax,dx", e);
2294 } else if (op == 0xee) {
2295 SPACES; debug("out\tdx,al");
2296 } else if (op == 0xef) {
2297 SPACES; debug("out\tdx,%sax", e);
2298 } else if (op == 0xf1) {
2299 SPACES; debug("icebp"); /* undocumented? */
2300 /* http://www.x86.org/secrets/opcodes/icebp.htm */
2301 } else if (op == 0xf4) {
2302 SPACES; debug("hlt");
2303 } else if (op == 0xf5) {
2304 SPACES; debug("cmc");
2305 } else if (op == 0xf8) {
2306 SPACES; debug("clc");
2307 } else if (op == 0xf9) {
2308 SPACES; debug("stc");
2309 } else if (op == 0xfa) {
2310 SPACES; debug("cli");
2311 } else if (op == 0xfb) {
2312 SPACES; debug("sti");
2313 } else if (op == 0xfc) {
2314 SPACES; debug("cld");
2315 } else if (op == 0xfd) {
2316 SPACES; debug("std");
2317 } else if (op == 0xf6 || op == 0xf7) {
2318 switch ((*instr >> 3) & 0x7) {
2319 case 0: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2320 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2321 imm = read_imm_and_print(&instr, &ilen,
2322 op == 0xf6? 8 : mode);
2323 SPACES; debug("test\t%s,0x%x", modrm_rm, imm);
2324 break;
2325 case 2: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2326 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2327 SPACES; debug("not\t%s", modrm_rm);
2328 break;
2329 case 3: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2330 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2331 SPACES; debug("neg\t%s", modrm_rm);
2332 break;
2333 case 4: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2334 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2335 SPACES; debug("mul\t%s", modrm_rm);
2336 break;
2337 case 5: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2338 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2339 SPACES; debug("imul\t%s", modrm_rm);
2340 break;
2341 case 6: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2342 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2343 SPACES; debug("div\t%s", modrm_rm);
2344 break;
2345 case 7: modrm(cpu, MODRM_READ, mode, mode67, op == 0xf6?
2346 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2347 SPACES; debug("idiv\t%s", modrm_rm);
2348 break;
2349 default:
2350 SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op,*instr);
2351 }
2352 } else if (op == 0xfe || op == 0xff) {
2353 /* FE /0 = inc r/m8 */
2354 /* FE /1 = dec r/m8 */
2355 /* FF /2 = call near rm16/32 */
2356 /* FF /3 = call far m16:32 */
2357 /* FF /6 = push r/m16/32 */
2358 switch ((*instr >> 3) & 0x7) {
2359 case 0: modrm(cpu, MODRM_READ, mode, mode67, op == 0xfe?
2360 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2361 SPACES; debug("inc\t%s", modrm_rm);
2362 break;
2363 case 1: modrm(cpu, MODRM_READ, mode, mode67, op == 0xfe?
2364 MODRM_EIGHTBIT : 0, &instr, &ilen, NULL, NULL);
2365 SPACES; debug("dec\t%s", modrm_rm);
2366 break;
2367 case 2: if (op == 0xfe) {
2368 SPACES; debug("UNIMPLEMENTED "
2369 "0x%02x,0x%02x", op,*instr);
2370 } else {
2371 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2372 &ilen, NULL, NULL);
2373 SPACES; debug("call\t%s", modrm_rm);
2374 }
2375 break;
2376 case 3: if (op == 0xfe) {
2377 SPACES; debug("UNIMPLEMENTED "
2378 "0x%02x,0x%02x", op,*instr);
2379 } else {
2380 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2381 &ilen, NULL, NULL);
2382 SPACES; debug("call\tfar %s", modrm_rm);
2383 }
2384 break;
2385 case 4: if (op == 0xfe) {
2386 SPACES; debug("UNIMPLEMENTED "
2387 "0x%02x,0x%02x", op,*instr);
2388 } else {
2389 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2390 &ilen, NULL, NULL);
2391 SPACES; debug("jmp\t%s", modrm_rm);
2392 }
2393 break;
2394 case 5: if (op == 0xfe) {
2395 SPACES; debug("UNIMPLEMENTED "
2396 "0x%02x,0x%02x", op,*instr);
2397 } else {
2398 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2399 &ilen, NULL, NULL);
2400 SPACES; debug("jmp\tfar %s", modrm_rm);
2401 }
2402 break;
2403 case 6: if (op == 0xfe) {
2404 SPACES; debug("UNIMPLEMENTED "
2405 "0x%02x,0x%02x", op,*instr);
2406 } else {
2407 modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
2408 &ilen, NULL, NULL);
2409 SPACES; debug("push\t%sword %s",
2410 mode == 32? "d" : "", modrm_rm);
2411 }
2412 break;
2413 default:
2414 SPACES; debug("UNIMPLEMENTED 0x%02x,0x%02x", op,*instr);
2415 }
2416 } else {
2417 SPACES; debug("UNIMPLEMENTED 0x%02x", op);
2418 }
2419
2420 switch (rep) {
2421 case REP_REP: debug(" (rep)"); break;
2422 case REP_REPNE: debug(" (repne)"); break;
2423 }
2424 if (prefix != NULL)
2425 debug(" (%s)", prefix);
2426 if (lock)
2427 debug(" (lock)");
2428
2429 debug("\n");
2430 return ilen;
2431 }
2432
2433
2434 /*
2435 * x86_cpuid():
2436 *
2437 * TODO: Level 1 and 2 info.
2438 */
2439 static void x86_cpuid(struct cpu *cpu)
2440 {
2441 switch (cpu->cd.x86.r[X86_R_AX]) {
2442 /* Normal CPU id: */
2443 case 0: cpu->cd.x86.r[X86_R_AX] = 2;
2444 /* Intel... */
2445 cpu->cd.x86.r[X86_R_BX] = 0x756e6547; /* "Genu" */
2446 cpu->cd.x86.r[X86_R_DX] = 0x49656e69; /* "ineI" */
2447 cpu->cd.x86.r[X86_R_CX] = 0x6c65746e; /* "ntel" */
2448 /* ... or AMD: */
2449 cpu->cd.x86.r[X86_R_BX] = 0x68747541; /* "Auth" */
2450 cpu->cd.x86.r[X86_R_DX] = 0x69746E65; /* "enti" */
2451 cpu->cd.x86.r[X86_R_CX] = 0x444D4163; /* "cAMD" */
2452 break;
2453 case 1: /* TODO */
2454 cpu->cd.x86.r[X86_R_AX] = 0x0623;
2455 cpu->cd.x86.r[X86_R_BX] = (cpu->cpu_id << 24);
2456 /* TODO: are bits 8..15 the _total_ nr of cpus, or the
2457 cpu id of this one? */
2458 cpu->cd.x86.r[X86_R_CX] = X86_CPUID_ECX_CX16;
2459 cpu->cd.x86.r[X86_R_DX] = X86_CPUID_EDX_CX8 | X86_CPUID_EDX_FPU
2460 | X86_CPUID_EDX_MSR | X86_CPUID_EDX_TSC | X86_CPUID_EDX_MTRR
2461 | X86_CPUID_EDX_CMOV | X86_CPUID_EDX_PSE |
2462 X86_CPUID_EDX_SEP | X86_CPUID_EDX_PGE |
2463 X86_CPUID_EDX_MMX | X86_CPUID_EDX_FXSR;
2464 break;
2465 case 2: /* TODO: actual Cache info */
2466 /* This is just bogus */
2467 cpu->cd.x86.r[X86_R_AX] = 0x03020101;
2468 cpu->cd.x86.r[X86_R_BX] = 0x00000000;
2469 cpu->cd.x86.r[X86_R_CX] = 0x00000000;
2470 cpu->cd.x86.r[X86_R_DX] = 0x06040a42;
2471 break;
2472
2473 /* Extended CPU id: */
2474 case 0x80000000:
2475 cpu->cd.x86.r[X86_R_AX] = 0x80000008;
2476 /* AMD... */
2477 cpu->cd.x86.r[X86_R_BX] = 0x68747541;
2478 cpu->cd.x86.r[X86_R_DX] = 0x444D4163;
2479 cpu->cd.x86.r[X86_R_CX] = 0x69746E65;
2480 break;
2481 case 0x80000001:
2482 cpu->cd.x86.r[X86_R_AX] = 0;
2483 cpu->cd.x86.r[X86_R_BX] = 0;
2484 cpu->cd.x86.r[X86_R_CX] = 0;
2485 cpu->cd.x86.r[X86_R_DX] = (cpu->cd.x86.model.model_number
2486 >= X86_MODEL_AMD64)? X86_CPUID_EXT_EDX_LM : 0;
2487 break;
2488 case 0x80000002:
2489 case 0x80000003:
2490 case 0x80000004:
2491 case 0x80000005:
2492 case 0x80000006:
2493 case 0x80000007:
2494 fatal("[ CPUID 0x%08x ]\n", (int)cpu->cd.x86.r[X86_R_AX]);
2495 cpu->cd.x86.r[X86_R_AX] = 0;
2496 cpu->cd.x86.r[X86_R_BX] = 0;
2497 cpu->cd.x86.r[X86_R_CX] = 0;
2498 cpu->cd.x86.r[X86_R_DX] = 0;
2499 break;
2500 case 0x80000008:
2501 cpu->cd.x86.r[X86_R_AX] = 0x00003028;
2502 cpu->cd.x86.r[X86_R_BX] = 0;
2503 cpu->cd.x86.r[X86_R_CX] = 0;
2504 cpu->cd.x86.r[X86_R_DX] = 0;
2505 break;
2506 default:fatal("x86_cpuid(): unimplemented eax = 0x%x\n",
2507 (int)cpu->cd.x86.r[X86_R_AX]);
2508 cpu->running = 0;
2509 }
2510 }
2511
2512
2513 #define TRANSLATE_ADDRESS translate_address_x86
2514 #include "memory_x86.c"
2515 #undef TRANSLATE_ADDRESS
2516
2517
2518 #define MEMORY_RW x86_memory_rw
2519 #define MEM_X86
2520 #include "memory_rw.c"
2521 #undef MEM_X86
2522 #undef MEMORY_RW
2523
2524
2525 /*
2526 * x86_push():
2527 */
2528 static int x86_push(struct cpu *cpu, uint64_t value, int mode)
2529 {
2530 int res = 1, oldseg;
2531 int ssize = cpu->cd.x86.descr_cache[X86_S_SS].default_op_size;
2532 uint64_t new_esp;
2533 uint64_t old_esp = cpu->cd.x86.r[X86_R_SP];
2534 uint16_t old_ss = cpu->cd.x86.s[X86_S_SS];
2535 uint64_t old_eip = cpu->pc;
2536 uint16_t old_cs = cpu->cd.x86.s[X86_S_CS];
2537
2538 /* TODO: up/down? */
2539 /* TODO: stacksize? */
2540 ssize = mode;
2541
2542 oldseg = cpu->cd.x86.cursegment;
2543 cpu->cd.x86.cursegment = X86_S_SS;
2544 if (ssize == 16)
2545 new_esp = (cpu->cd.x86.r[X86_R_SP] & ~0xffff)
2546 | ((cpu->cd.x86.r[X86_R_SP] - (ssize / 8)) & 0xffff);
2547 else
2548 new_esp = (cpu->cd.x86.r[X86_R_SP] -
2549 (ssize / 8)) & 0xffffffff;
2550 res = x86_store(cpu, new_esp, value, ssize / 8);
2551 if (!res) {
2552 fatal("WARNING: x86_push store failed: cs:eip=0x%04x:0x%08x"
2553 " ss:esp=0x%04x:0x%08x\n", (int)old_cs,
2554 (int)old_eip, (int)old_ss, (int)old_esp);
2555 if ((old_cs & X86_PL_MASK) != X86_RING3)
2556 cpu->running = 0;
2557 } else {
2558 cpu->cd.x86.r[X86_R_SP] = new_esp;
2559 }
2560 cpu->cd.x86.cursegment = oldseg;
2561 return res;
2562 }
2563
2564
2565 /*
2566 * x86_pop():
2567 */
2568 static int x86_pop(struct cpu *cpu, uint64_t *valuep, int mode)
2569 {
2570 int res = 1, oldseg;
2571 int ssize = cpu->cd.x86.descr_cache[X86_S_SS].default_op_size;
2572
2573 /* TODO: up/down? */
2574 /* TODO: stacksize? */
2575 ssize = mode;
2576
2577 oldseg = cpu->cd.x86.cursegment;
2578 cpu->cd.x86.cursegment = X86_S_SS;
2579 res = x86_load(cpu, cpu->cd.x86.r[X86_R_SP], valuep, ssize / 8);
2580 if (!res) {
2581 fatal("WARNING: x86_pop load failed\n");
2582 } else {
2583 if (ssize == 16)
2584 cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] &
2585 ~0xffff) | ((cpu->cd.x86.r[X86_R_SP] + (ssize / 8))
2586 & 0xffff);
2587 else
2588 cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] +
2589 (ssize / 8)) & 0xffffffff;
2590 }
2591 cpu->cd.x86.cursegment = oldseg;
2592 return res;
2593 }
2594
2595
2596 #define INT_TYPE_CALLGATE 1
2597 #define INT_TYPE_INTGATE 2
2598 #define INT_TYPE_TRAPGATE 3
2599 /*
2600 * x86_interrupt():
2601 *
2602 * Read the interrupt descriptor table (or, in real mode, the interrupt
2603 * vector table), push flags/cs/eip, and jump to the interrupt handler.
2604 */
2605 int x86_interrupt(struct cpu *cpu, int nr, int errcode)
2606 {
2607 uint16_t seg, old_cs;
2608 uint32_t ofs;
2609 int res, mode;
2610 unsigned char buf[8];
2611
2612 old_cs = cpu->cd.x86.s[X86_S_CS];
2613
2614 debug("{ x86_interrupt %i }\n", nr);
2615
2616 if (PROTECTED_MODE) {
2617 int i, int_type = 0;
2618
2619 if (nr * 8 > cpu->cd.x86.idtr_limit) {
2620 fatal("TODO: protected mode int 0x%02x outside idtr"
2621 " limit (%i)?\n", nr, (int)cpu->cd.x86.idtr_limit);
2622 cpu->running = 0;
2623 return 0;
2624 }
2625
2626 /* Read the interrupt descriptor: */
2627 res = cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.idtr + nr*8,
2628 buf, 8, MEM_READ, NO_SEGMENTATION);
2629 if (!res) {
2630 fatal("x86_interrupt(): could not read the"
2631 " interrupt descriptor table (prot. mode)\n");
2632 cpu->running = 0;
2633 return 0;
2634 }
2635
2636 if ((buf[5] & 0x17) == 0x04)
2637 int_type = INT_TYPE_CALLGATE;
2638 if ((buf[5] & 0x17) == 0x06)
2639 int_type = INT_TYPE_INTGATE;
2640 if ((buf[5] & 0x17) == 0x07)
2641 int_type = INT_TYPE_TRAPGATE;
2642
2643 if (!int_type) {
2644 fatal("x86_interrupt(): TODO:\n");
2645 for (i=0; i<8; i++)
2646 fatal(" %02x", buf[i]);
2647 fatal("\n");
2648 cpu->running = 0;
2649 return 0;
2650 }
2651
2652 seg = buf[2] + (buf[3] << 8);
2653 ofs = buf[0] + (buf[1] << 8) + (buf[6] << 16) + (buf[7] << 24);
2654
2655 switch (int_type) {
2656 case INT_TYPE_INTGATE:
2657 case INT_TYPE_TRAPGATE:
2658 break;
2659 default:
2660 fatal("INT type: %i, cs:eip = 0x%04x:0x%08x\n",
2661 int_type, (int)seg, (int)ofs);
2662 cpu->running = 0;
2663 return 0;
2664 }
2665
2666 reload_segment_descriptor(cpu, X86_S_CS, seg, &cpu->pc);
2667
2668 /*
2669 * If we're changing privilege level, the we should change
2670 * stack here, and push the old SS:ESP.
2671 */
2672 if ((seg & X86_PL_MASK) < (old_cs & X86_PL_MASK)) {
2673 unsigned char buf[16];
2674 uint16_t new_ss, old_ss;
2675 uint32_t new_esp, old_esp;
2676 int pl;
2677
2678 pl = seg & X86_PL_MASK;
2679
2680 /* Load SSx:ESPx from the Task State Segment: */
2681 if (cpu->cd.x86.tr < 4)
2682 fatal("WARNING: interrupt with stack switch"
2683 ", but task register = 0?\n");
2684
2685 /* fatal("::: old SS:ESP=0x%04x:0x%08x\n",
2686 (int)cpu->cd.x86.s[X86_S_SS],
2687 (int)cpu->cd.x86.r[X86_R_SP]); */
2688
2689 if (!cpu->memory_rw(cpu, cpu->mem, 4 + pl*8 +
2690 cpu->cd.x86.tr_base, buf, sizeof(buf), MEM_READ,
2691 NO_SEGMENTATION)) {
2692 fatal("ERROR: couldn't read tss blah blah\n");
2693 cpu->running = 0;
2694 return 0;
2695 }
2696
2697 new_esp = buf[0] + (buf[1] << 8) +
2698 (buf[2] << 16) + (buf[3] << 24);
2699 new_ss = buf[4] + (buf[5] << 8);
2700
2701 old_ss = cpu->cd.x86.s[X86_S_SS];
2702 old_esp = cpu->cd.x86.r[X86_R_SP];
2703
2704 reload_segment_descriptor(cpu, X86_S_SS, new_ss, NULL);
2705 cpu->cd.x86.r[X86_R_SP] = new_esp;
2706
2707 fatal("::: Switching Stack: new SS:ESP=0x%04x:0x%08x\n",
2708 (int)new_ss, (int)new_esp);
2709
2710 mode = cpu->cd.x86.descr_cache[X86_S_CS].
2711 default_op_size;
2712
2713 if (!x86_push(cpu, old_ss, mode)) {
2714 fatal("TODO: problem adgsadg 1\n");
2715 cpu->running = 0;
2716 }
2717 if (!x86_push(cpu, old_esp, mode)) {
2718 fatal("TODO: problem adgsadg 2\n");
2719 cpu->running = 0;
2720 }
2721 }
2722
2723 /* Push flags, cs, and ip (pc): */
2724 mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
2725 if (!x86_push(cpu, cpu->cd.x86.rflags, mode)) {
2726 fatal("TODO: how to handle this 1 asdf\n");
2727 cpu->running = 0;
2728 }
2729 if (!x86_push(cpu, old_cs, mode)) {
2730 fatal("TODO: how to handle this 2 sdghser\n");
2731 cpu->running = 0;
2732 }
2733 if (!x86_push(cpu, cpu->pc, mode)) {
2734 fatal("TODO: how to handle this 3 we\n");
2735 cpu->running = 0;
2736 }
2737
2738 /* Push error code for some exceptions: */
2739 if ((nr >= 8 && nr <=14) || nr == 17) {
2740 if (!x86_push(cpu, errcode, mode)) {
2741 fatal("x86_interrupt(): TODO: asdgblah\n");
2742 cpu->running = 0;
2743 }
2744 }
2745
2746 /* Only turn off interrupts for Interrupt Gates: */
2747 if (int_type == INT_TYPE_INTGATE)
2748 cpu->cd.x86.rflags &= ~X86_FLAGS_IF;
2749
2750 /* Turn off TF for Interrupt and Trap Gates: */
2751 if (int_type == INT_TYPE_INTGATE ||
2752 int_type == INT_TYPE_TRAPGATE)
2753 cpu->cd.x86.rflags &= ~X86_FLAGS_TF;
2754
2755 goto int_jump;
2756 }
2757
2758 /*
2759 * Real mode:
2760 */
2761 if (nr * 4 > cpu->cd.x86.idtr_limit) {
2762 fatal("TODO: real mode int 0x%02x outside idtr limit ("
2763 "%i)?\n", nr, (int)cpu->cd.x86.idtr_limit);
2764 cpu->running = 0;
2765 return 0;
2766 }
2767 /* Read the interrupt vector: */
2768 res = cpu->memory_rw(cpu, cpu->mem, cpu->cd.x86.idtr + nr*4, buf, 4,
2769 MEM_READ, NO_SEGMENTATION);
2770 if (!res) {
2771 fatal("x86_interrupt(): could not read the"
2772 " interrupt descriptor table\n");
2773 cpu->running = 0;
2774 return 0;
2775 }
2776 ofs = buf[0] + (buf[1] << 8); seg = buf[2] + (buf[3] << 8);
2777
2778 reload_segment_descriptor(cpu, X86_S_CS, seg, &cpu->pc);
2779
2780 /* Push old flags, old cs, and old ip (pc): */
2781 mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
2782
2783 if (!x86_push(cpu, cpu->cd.x86.rflags, mode)) {
2784 fatal("x86_interrupt(): TODO: how to handle this 4\n");
2785 cpu->running = 0;
2786 }
2787 if (!x86_push(cpu, old_cs, mode)) {
2788 fatal("x86_interrupt(): TODO: how to handle this 5\n");
2789 cpu->running = 0;
2790 }
2791 if (!x86_push(cpu, cpu->pc, mode)) {
2792 fatal("x86_interrupt(): TODO: how to handle this 6\n");
2793 cpu->running = 0;
2794 }
2795
2796 /* Turn off interrupts and the Trap Flag, and jump to the interrupt
2797 handler: */
2798 cpu->cd.x86.rflags &= ~(X86_FLAGS_IF | X86_FLAGS_TF);
2799
2800 int_jump:
2801 cpu->pc = ofs;
2802
2803 return 1;
2804 }
2805
2806
2807 #define CALCFLAGS_OP_ADD 1
2808 #define CALCFLAGS_OP_SUB 2
2809 #define CALCFLAGS_OP_XOR 3
2810 /*
2811 * x86_calc_flags():
2812 */
2813 static void x86_calc_flags(struct cpu *cpu, uint64_t a, uint64_t b, int mode,
2814 int op)
2815 {
2816 uint64_t c=0, mask;
2817 int i, count;
2818
2819 if (mode == 8)
2820 mask = 0xff;
2821 else if (mode == 16)
2822 mask = 0xffff;
2823 else if (mode == 32)
2824 mask = 0xffffffffULL;
2825 else if (mode == 64)
2826 mask = 0xffffffffffffffffULL;
2827 else {
2828 fatal("x86_calc_flags(): Bad mode (%i)\n", mode);
2829 return;
2830 }
2831
2832 a &= mask;
2833 b &= mask;
2834
2835 /* CF: */
2836 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
2837 switch (op) {
2838 case CALCFLAGS_OP_ADD:
2839 if (((a + b)&mask) < a && ((a + b)&mask) < b)
2840 cpu->cd.x86.rflags |= X86_FLAGS_CF;
2841 break;
2842 case CALCFLAGS_OP_SUB:
2843 if (a < b)
2844 cpu->cd.x86.rflags |= X86_FLAGS_CF;
2845 break;
2846 case CALCFLAGS_OP_XOR:
2847 break;
2848 }
2849
2850 switch (op) {
2851 case CALCFLAGS_OP_ADD:
2852 c = (a + b) & mask;
2853 break;
2854 case CALCFLAGS_OP_SUB:
2855 c = (a - b) & mask;
2856 break;
2857 case CALCFLAGS_OP_XOR:
2858 c = a;
2859 }
2860
2861 /* ZF: */
2862 cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;
2863 if (c == 0)
2864 cpu->cd.x86.rflags |= X86_FLAGS_ZF;
2865
2866 /* SF: */
2867 cpu->cd.x86.rflags &= ~X86_FLAGS_SF;
2868 if ((mode == 8 && (c & 0x80)) ||
2869 (mode == 16 && (c & 0x8000)) ||
2870 (mode == 32 && (c & 0x80000000ULL)) ||
2871 (mode == 64 && (c & 0x8000000000000000ULL))) {
2872 cpu->cd.x86.rflags |= X86_FLAGS_SF;
2873 }
2874
2875 /* OF: */
2876 cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
2877 switch (op) {
2878 case CALCFLAGS_OP_ADD:
2879 /* TODO */
2880 break;
2881 case CALCFLAGS_OP_SUB:
2882 if (cpu->cd.x86.rflags & X86_FLAGS_SF)
2883 cpu->cd.x86.rflags |= X86_FLAGS_OF;
2884 if (mode == 8 && (int8_t)a < (int8_t)b)
2885 cpu->cd.x86.rflags ^= X86_FLAGS_OF;
2886 if (mode == 16 && (int16_t)a < (int16_t)b)
2887 cpu->cd.x86.rflags ^= X86_FLAGS_OF;
2888 if (mode == 32 && (int32_t)a < (int32_t)b)
2889 cpu->cd.x86.rflags ^= X86_FLAGS_OF;
2890 break;
2891 case CALCFLAGS_OP_XOR:
2892 ;
2893 }
2894
2895 /* AF: */
2896 switch (op) {
2897 case CALCFLAGS_OP_ADD:
2898 if ((a & 0xf) + (b & 0xf) > 15)
2899 cpu->cd.x86.rflags |= X86_FLAGS_AF;
2900 else
2901 cpu->cd.x86.rflags &= ~X86_FLAGS_AF;
2902 break;
2903 case CALCFLAGS_OP_SUB:
2904 if ((b & 0xf) > (a & 0xf))
2905 cpu->cd.x86.rflags |= X86_FLAGS_AF;
2906 else
2907 cpu->cd.x86.rflags &= ~X86_FLAGS_AF;
2908 break;
2909 case CALCFLAGS_OP_XOR:
2910 ;
2911 }
2912
2913 /* PF: (NOTE: Only the lowest 8 bits) */
2914 cpu->cd.x86.rflags &= ~X86_FLAGS_PF;
2915 count = 0;
2916 for (i=0; i<8; i++) {
2917 if (c & 1)
2918 count ++;
2919 c >>= 1;
2920 }
2921 if (!(count&1))
2922 cpu->cd.x86.rflags |= X86_FLAGS_PF;
2923 }
2924
2925
2926 /*
2927 * x86_condition():
2928 *
2929 * Returns 0 or 1 (false or true) depending on flag bits.
2930 */
2931 static int x86_condition(struct cpu *cpu, int op)
2932 {
2933 int success = 0;
2934
2935 switch (op & 0xe) {
2936 case 0x00: /* o */
2937 success = cpu->cd.x86.rflags & X86_FLAGS_OF;
2938 break;
2939 case 0x02: /* c */
2940 success = cpu->cd.x86.rflags & X86_FLAGS_CF;
2941 break;
2942 case 0x04: /* z */
2943 success = cpu->cd.x86.rflags & X86_FLAGS_ZF;
2944 break;
2945 case 0x06: /* be */
2946 success = (cpu->cd.x86.rflags & X86_FLAGS_ZF) ||
2947 (cpu->cd.x86.rflags & X86_FLAGS_CF);
2948 break;
2949 case 0x08: /* s */
2950 success = cpu->cd.x86.rflags & X86_FLAGS_SF;
2951 break;
2952 case 0x0a: /* p */
2953 success = cpu->cd.x86.rflags & X86_FLAGS_PF;
2954 break;
2955 case 0x0c: /* nge */
2956 success = (cpu->cd.x86.rflags & X86_FLAGS_SF? 1 : 0)
2957 != (cpu->cd.x86.rflags & X86_FLAGS_OF? 1 : 0);
2958 break;
2959 case 0x0e: /* ng */
2960 success = (cpu->cd.x86.rflags & X86_FLAGS_SF? 1 : 0)
2961 != (cpu->cd.x86.rflags & X86_FLAGS_OF? 1 : 0);
2962 success |= (cpu->cd.x86.rflags & X86_FLAGS_ZF ? 1 : 0);
2963 break;
2964 }
2965
2966 if (op & 1)
2967 success = !success;
2968
2969 return success? 1 : 0;
2970 }
2971
2972
2973 /*
2974 * x86_shiftrotate():
2975 */
2976 static void x86_shiftrotate(struct cpu *cpu, uint64_t *op1p, int op,
2977 int n, int mode)
2978 {
2979 uint64_t op1 = *op1p;
2980 int cf = -1, oldcf = 0;
2981
2982 n &= 31;
2983 if (mode != 64)
2984 op1 &= (((uint64_t)1 << mode) - 1);
2985
2986 oldcf = cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0;
2987
2988 while (n-- > 0) {
2989 cf = 0;
2990
2991 if (op & 1) { /* right */
2992 if (op1 & 1)
2993 cf = 1;
2994 } else { /* left */
2995 cf = (op1 & ((uint64_t)1 << (mode-1)))? 1 : 0;
2996 }
2997
2998 switch (op) {
2999 case 0: /* rol */
3000 op1 = (op1 << 1) | cf;
3001 break;
3002 case 1: /* ror */
3003 op1 >>= 1;
3004 op1 |= ((uint64_t)cf << (mode - 1));
3005 break;
3006 case 2: /* rcl */
3007 op1 = (op1 << 1) | oldcf;
3008 oldcf = cf;
3009 break;
3010 case 3: /* rcr */
3011 op1 >>= 1;
3012 op1 |= ((uint64_t)oldcf << (mode - 1));
3013 oldcf = cf;
3014 break;
3015 case 4: /* shl */
3016 case 6: /* sal */
3017 op1 <<= 1;
3018 break;
3019 case 5: /* shr */
3020 op1 >>= 1;
3021 break;
3022 case 7: /* sar */
3023 op1 >>= 1;
3024 if (mode == 8 && op1 & 0x40)
3025 op1 |= 0x80;
3026 if (mode == 16 && op1 & 0x4000)
3027 op1 |= 0x8000;
3028 if (mode == 32 && op1 & 0x40000000ULL)
3029 op1 |= 0x80000000ULL;
3030 break;
3031 default:
3032 fatal("x86_shiftrotate(): unimplemented op %i\n", op);
3033 cpu->running = 0;
3034 }
3035 if (mode != 64)
3036 op1 &= (((uint64_t)1 << mode) - 1);
3037 x86_calc_flags(cpu, op1, 0, mode, CALCFLAGS_OP_XOR);
3038 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3039 if (cf)
3040 cpu->cd.x86.rflags |= X86_FLAGS_CF;
3041 }
3042
3043 /* TODO: OF flag */
3044
3045 *op1p = op1;
3046 }
3047
3048
3049 /*
3050 * x86_msr():
3051 *
3052 * This function reads or writes the MSRs (Model Specific Registers).
3053 */
3054 static void x86_msr(struct cpu *cpu, int writeflag)
3055 {
3056 uint32_t regnr = cpu->cd.x86.r[X86_R_CX] & 0xffffffff;
3057 uint64_t odata=0, idata = (cpu->cd.x86.r[X86_R_AX] & 0xffffffff) +
3058 ((cpu->cd.x86.r[X86_R_DX] & 0xffffffff) << 32);
3059
3060 switch (regnr) {
3061 case 0xc0000080: /* AMD64 EFER */
3062 if (writeflag) {
3063 if (cpu->cd.x86.efer & X86_EFER_LME &&
3064 !(idata & X86_EFER_LME))
3065 debug("[ switching FROM 64-bit mode ]\n");
3066 if (!(cpu->cd.x86.efer & X86_EFER_LME) &&
3067 idata & X86_EFER_LME)
3068 debug("[ switching to 64-bit mode ]\n");
3069 cpu->cd.x86.efer = idata;
3070 } else
3071 odata = cpu->cd.x86.efer;
3072 break;
3073 default:fatal("x86_msr: unimplemented MSR 0x%08x\n", (int)regnr);
3074 cpu->running = 0;
3075 }
3076
3077 if (!writeflag) {
3078 cpu->cd.x86.r[X86_R_AX] = odata & 0xffffffff;
3079 cpu->cd.x86.r[X86_R_DX] = (odata >> 32) & 0xffffffff;
3080 }
3081 }
3082
3083
3084 /*
3085 * cause_interrupt():
3086 *
3087 * Read the registers of PIC1 (and possibly PIC2) to find out which interrupt
3088 * has occured.
3089 *
3090 * Returns 1 if an interrupt happened, 0 otherwise (for example if the
3091 * in-service bit of an interrupt was already set).
3092 */
3093 static int cause_interrupt(struct cpu *cpu)
3094 {
3095 int i, irq_nr = -1;
3096
3097 for (i=0; i<8; i++) {
3098 if (cpu->machine->md.pc.pic1->irr &
3099 (~cpu->machine->md.pc.pic1->ier) & (1 << i))
3100 irq_nr = i;
3101 }
3102
3103 if (irq_nr == 2) {
3104 for (i=0; i<8; i++) {
3105 if (cpu->machine->md.pc.pic2->irr &
3106 (~cpu->machine->md.pc.pic2->ier) & (1 << i))
3107 irq_nr = 8+i;
3108 }
3109 }
3110
3111 if (irq_nr == 2) {
3112 fatal("cause_interrupt(): Huh? irq 2 but no secondary irq\n");
3113 cpu->running = 0;
3114 }
3115
3116 /*
3117 * TODO: How about multiple interrupt levels?
3118 */
3119
3120 #if 0
3121 printf("cause1: %i (irr1=%02x ier1=%02x, irr2=%02x ier2=%02x\n", irq_nr,
3122 cpu->machine->md.pc.pic1->irr, cpu->machine->md.pc.pic1->ier,
3123 cpu->machine->md.pc.pic2->irr, cpu->machine->md.pc.pic2->ier);
3124 #endif
3125
3126 /* Set the in-service bit, and calculate actual INT nr: */
3127 if (irq_nr < 8) {
3128 if (cpu->machine->md.pc.pic1->isr & (1 << irq_nr))
3129 return 0;
3130 cpu->machine->md.pc.pic1->isr |= (1 << irq_nr);
3131 irq_nr = cpu->machine->md.pc.pic1->irq_base + irq_nr;
3132 } else {
3133 if (cpu->machine->md.pc.pic2->isr & (1 << (irq_nr & 7)))
3134 return 0;
3135 cpu->machine->md.pc.pic2->isr |= (1 << (irq_nr&7));
3136 irq_nr = cpu->machine->md.pc.pic2->irq_base + (irq_nr & 7);
3137 }
3138
3139 /* printf("cause2: %i\n", irq_nr); */
3140
3141 x86_interrupt(cpu, irq_nr, 0);
3142 cpu->cd.x86.halted = 0;
3143 return 1;
3144 }
3145
3146
3147 /*
3148 * x86_cpu_run_instr():
3149 *
3150 * Execute one instruction on a specific CPU.
3151 *
3152 * Return value is the number of instructions executed during this call,
3153 * 0 if no instruction was executed.
3154 */
3155 int x86_cpu_run_instr(struct emul *emul, struct cpu *cpu)
3156 {
3157 int i, r, rep = 0, op, len, mode, omode, mode67;
3158 int nprefixbytes = 0, success, longmode;
3159 uint32_t imm, imm2;
3160 unsigned char buf[16];
3161 unsigned char *instr = buf, *instr_orig, *really_orig_instr;
3162 uint64_t newpc = cpu->pc;
3163 uint64_t tmp, op1, op2;
3164 int trap_flag_was_set = cpu->cd.x86.rflags & X86_FLAGS_TF;
3165
3166 /* Check PC against breakpoints: */
3167 if (!single_step)
3168 for (i=0; i<cpu->machine->n_breakpoints; i++)
3169 if (cpu->pc == cpu->machine->breakpoint_addr[i]) {
3170 fatal("Breakpoint reached, 0x%04x:0x%llx\n",
3171 cpu->cd.x86.s[X86_S_CS],
3172 (long long)cpu->pc);
3173 single_step = 1;
3174 return 0;
3175 }
3176
3177 if (!cpu->cd.x86.descr_cache[X86_S_CS].valid) {
3178 fatal("x86_cpu_run_instr(): Invalid CS descriptor?\n");
3179 cpu->running = 0;
3180 return 0;
3181 }
3182
3183 longmode = cpu->cd.x86.efer & X86_EFER_LME;
3184 mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size;
3185 omode = mode;
3186 if (mode != 16 && mode != 32) {
3187 fatal("x86_cpu_run_instr(): Invalid CS default op size, %i\n",
3188 mode);
3189 cpu->running = 0;
3190 return 0;
3191 }
3192
3193 if (cpu->cd.x86.interrupt_asserted &&
3194 cpu->cd.x86.rflags & X86_FLAGS_IF) {
3195 if (cause_interrupt(cpu))
3196 return 0;
3197 }
3198
3199 /* 16-bit BIOS emulation: */
3200 if (mode == 16 && ((newpc + (cpu->cd.x86.s[X86_S_CS] << 4)) & 0xff000)
3201 == 0xf8000 && cpu->machine->prom_emulation) {
3202 int addr = (newpc + (cpu->cd.x86.s[X86_S_CS] << 4)) & 0xfff;
3203 if (cpu->machine->instruction_trace)
3204 debug("(PC BIOS emulation, int 0x%02x)\n",
3205 addr >> 4);
3206 pc_bios_emul(cpu);
3207 /* Approximately equivalent to 500 instructions. */
3208 return 500;
3209 }
3210
3211 if (cpu->cd.x86.halted) {
3212 if (!(cpu->cd.x86.rflags & X86_FLAGS_IF)) {
3213 fatal("[ Halting with interrupts disabled. ]\n");
3214 cpu->running = 0;
3215 }
3216 /* Treating this as more than one instruction makes us
3217 wait less for devices. */
3218 return 1000;
3219 }
3220
3221 /* Read an instruction from memory: */
3222 cpu->cd.x86.cursegment = X86_S_CS;
3223 cpu->cd.x86.seg_override = 0;
3224
3225 r = cpu->memory_rw(cpu, cpu->mem, cpu->pc, &buf[0], sizeof(buf),
3226 MEM_READ, CACHE_INSTRUCTION);
3227 if (!r) {
3228 /* This could happen if, for example, there was an
3229 exception while we tried to read the instruction. */
3230 return 0;
3231 }
3232
3233 really_orig_instr = instr; /* Used to display an error message
3234 for unimplemented instructions. */
3235
3236 if (cpu->machine->instruction_trace)
3237 x86_cpu_disassemble_instr(cpu, instr, 1 | omode, 0, 0);
3238
3239 /* For debugging: */
3240 if (instr[0] == 0 && instr[1] == 0 && instr[2] == 0 && instr[3] == 0) {
3241 fatal("WARNING: Running in nothingness?\n");
3242 cpu->running = 0;
3243 return 0;
3244 }
3245
3246 /* All instructions are at least one byte long :-) */
3247 newpc ++;
3248
3249 /* Default is to use the data segment, or the stack segment: */
3250 cpu->cd.x86.cursegment = X86_S_DS;
3251 mode67 = mode;
3252
3253 /* Any prefix? */
3254 for (;;) {
3255 if (longmode && (instr[0] & 0xf0) == 0x40) {
3256 fatal("TODO: REX byte 0x%02x\n", instr[0]);
3257 cpu->running = 0;
3258 } else if (instr[0] == 0x66) {
3259 if (mode == 16)
3260 mode = 32;
3261 else
3262 mode = 16;
3263 } else if (instr[0] == 0x67) {
3264 if (mode67 == 16)
3265 mode67 = 32;
3266 else
3267 mode67 = 16;
3268 } else if (instr[0] == 0x26) {
3269 cpu->cd.x86.cursegment = X86_S_ES;
3270 cpu->cd.x86.seg_override = 1;
3271 } else if (instr[0] == 0x2e) {
3272 cpu->cd.x86.cursegment = X86_S_CS;
3273 cpu->cd.x86.seg_override = 1;
3274 } else if (instr[0] == 0x36) {
3275 cpu->cd.x86.cursegment = X86_S_SS;
3276 cpu->cd.x86.seg_override = 1;
3277 } else if (instr[0] == 0x3e) {
3278 cpu->cd.x86.cursegment = X86_S_DS;
3279 cpu->cd.x86.seg_override = 1;
3280 } else if (instr[0] == 0x64) {
3281 cpu->cd.x86.cursegment = X86_S_FS;
3282 cpu->cd.x86.seg_override = 1;
3283 } else if (instr[0] == 0x65) {
3284 cpu->cd.x86.cursegment = X86_S_GS;
3285 cpu->cd.x86.seg_override = 1;
3286 } else if (instr[0] == 0xf0) {
3287 /* lock */
3288 } else if (instr[0] == 0xf2) {
3289 rep = REP_REPNE;
3290 } else if (instr[0] == 0xf3) {
3291 rep = REP_REP;
3292 } else
3293 break;
3294 instr ++;
3295 newpc ++;
3296 if (++nprefixbytes > 4) {
3297 fatal("x86: too many prefix bytes at ");
3298 print_csip(cpu); fatal("\n");
3299 cpu->running = 0;
3300 return 0;
3301 }
3302 }
3303
3304 op = instr[0];
3305 instr ++;
3306
3307 if ((op & 0xf0) <= 0x30 && (op & 7) <= 5) {
3308 success = 1;
3309 instr_orig = instr;
3310 switch (op & 7) {
3311 case 4: imm = read_imm(&instr, &newpc, 8);
3312 op1 = cpu->cd.x86.r[X86_R_AX] & 0xff;
3313 op2 = (signed char)imm;
3314 mode = 8;
3315 break;
3316 case 5: imm = read_imm(&instr, &newpc, mode);
3317 op1 = cpu->cd.x86.r[X86_R_AX]; op2 = imm;
3318 break;
3319 default:success = modrm(cpu, MODRM_READ, mode, mode67,
3320 op&1? 0 : MODRM_EIGHTBIT, &instr, &newpc,&op1,&op2);
3321 if (!success)
3322 return 0;
3323 }
3324
3325 if ((op & 6) == 2) {
3326 uint64_t tmp = op1; op1 = op2; op2 = tmp;
3327 }
3328
3329 /* printf("op1=0x%x op2=0x%x => ", (int)op1, (int)op2); */
3330
3331 switch (mode) {
3332 case 16: op1 &= 0xffff; op2 &= 0xffff; break;
3333 case 32: op1 &= 0xffffffffULL; op2 &= 0xffffffffULL; break;
3334 }
3335
3336 switch (op & 0x38) {
3337 case 0x00: x86_calc_flags(cpu, op1, op2, !(op & 1)? 8 :
3338 mode, CALCFLAGS_OP_ADD);
3339 op1 = op1 + op2;
3340 break;
3341 case 0x08: op1 = op1 | op2; break;
3342 case 0x10: tmp = op2;
3343 if (cpu->cd.x86.rflags & X86_FLAGS_CF)
3344 tmp ++;
3345 x86_calc_flags(cpu, op1, tmp, !(op & 1)? 8 :
3346 mode, CALCFLAGS_OP_ADD);
3347 op1 = op1 + tmp;
3348 break;
3349 case 0x18: tmp = op2;
3350 if (cpu->cd.x86.rflags & X86_FLAGS_CF)
3351 tmp ++;
3352 x86_calc_flags(cpu, op1, tmp, !(op & 1)? 8 :
3353 mode, CALCFLAGS_OP_SUB);
3354 op1 = op1 - tmp;
3355 break;
3356 case 0x20: op1 = op1 & op2; break;
3357 case 0x28: x86_calc_flags(cpu, op1, op2, !(op & 1)? 8 :
3358 mode, CALCFLAGS_OP_SUB);
3359 op1 = op1 - op2; break;
3360 case 0x30: op1 = op1 ^ op2; break;
3361 case 0x38: x86_calc_flags(cpu, op1, op2, !(op & 1)? 8 :
3362 mode, CALCFLAGS_OP_SUB);
3363 break;
3364 default:
3365 fatal("not yet\n");
3366 exit(1);
3367 }
3368
3369 switch (mode) {
3370 case 16: op1 &= 0xffff; op2 &= 0xffff; break;
3371 case 32: op1 &= 0xffffffffULL; op2 &= 0xffffffffULL; break;
3372 }
3373
3374 /* NOTE: Manual cmp for "sbb, "sub" and "cmp" instructions. */
3375 if ((op & 0x38) != 0x38 && (op & 0x38) != 0x28 &&
3376 (op & 0x38) != 0x18 && (op & 0x38) != 0x00 &&
3377 (op & 0x38) != 0x10)
3378 x86_calc_flags(cpu, op1, 0, !(op & 1)? 8 : mode,
3379 CALCFLAGS_OP_XOR);
3380
3381 /* "and","or","xor" always clears CF and OF: */
3382 if ((op & 0x38) == 0x08 || (op & 0x38) == 0x20 ||
3383 (op & 0x38) == 0x30) {
3384 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3385 cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
3386 }
3387
3388 /* printf("op1=0x%x op2=0x%x\n", (int)op1, (int)op2); */
3389
3390 if ((op & 6) == 2) {
3391 uint64_t tmp = op1; op1 = op2; op2 = tmp;
3392 }
3393
3394 /* Write back the result: (for all cases except CMP) */
3395 if ((op & 0x38) != 0x38) {
3396 switch (op & 7) {
3397 case 4: cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[
3398 X86_R_AX] & ~0xff) | (op1 & 0xff);
3399 break;
3400 case 5: cpu->cd.x86.r[X86_R_AX] = modify(cpu->
3401 cd.x86.r[X86_R_AX], op1);
3402 break;
3403 default:success = modrm(cpu, (op & 6) == 2?
3404 MODRM_WRITE_R : MODRM_WRITE_RM, mode,
3405 mode67, op&1? 0 : MODRM_EIGHTBIT,
3406 &instr_orig, NULL, &op1, &op2);
3407 if (!success)
3408 return 0;
3409 }
3410 }
3411 } else if ((op & 0xf0) < 0x20 && (op & 7) == 6) {
3412 success = x86_push(cpu, cpu->cd.x86.s[op / 8], mode);
3413 if (!success)
3414 return 0;
3415 } else if (op == 0x0f && cpu->cd.x86.model.model_number ==
3416 X86_MODEL_8086) {
3417 uint64_t tmp;
3418 fatal("WARNING: pop cs\n");
3419 if (!x86_pop(cpu, &tmp, mode))
3420 return 0;
3421 reload_segment_descriptor(cpu, X86_S_CS, tmp, &newpc);
3422 } else if (op == 0x0f) {
3423 uint64_t tmp;
3424 unsigned char *instr_orig_2;
3425 int signflag, i;
3426 imm = read_imm(&instr, &newpc, 8);
3427 if (imm >= 0x40 && imm <= 0x4f) { /* CMOVxx */
3428 op = imm & 0xf;
3429 if (!modrm(cpu, MODRM_READ, mode, mode67,
3430 0, &instr, &newpc, &op1, &op2))
3431 return 0;
3432 success = x86_condition(cpu, op);
3433 if (success) {
3434 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3435 MODRM_EIGHTBIT, &instr_orig, NULL,
3436 &op2, &op1))
3437 return 0;
3438 }
3439 } else if (imm >= 0x80 && imm <= 0x8f) {
3440 /* conditional near jump */
3441 op = imm & 0xf;
3442 imm = read_imm(&instr, &newpc, mode);
3443 success = x86_condition(cpu, op);
3444 if (success)
3445 newpc += imm;
3446 } else if (imm >= 0x90 && imm <= 0x9f) {
3447 instr_orig = instr;
3448 if (!modrm(cpu, MODRM_READ, mode, mode67,
3449 MODRM_EIGHTBIT, &instr, &newpc, &op1, &op2))
3450 return 0;
3451 op1 = x86_condition(cpu, imm & 0xf);
3452 if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67,
3453 MODRM_EIGHTBIT, &instr_orig, NULL, &op1, &op2))
3454 return 0;
3455 } else {
3456 int subop;
3457 switch (imm) {
3458 case 0x00:
3459 subop = (*instr >> 3) & 0x7;
3460 switch (subop) {
3461 case 1: /* str */
3462 /* TODO: Check Prot.mode? */
3463 op1 = cpu->cd.x86.tr;
3464 if (!modrm(cpu, MODRM_WRITE_RM, 16,
3465 mode67, 0, &instr, &newpc, &op1,
3466 &op2))
3467 return 0;
3468 break;
3469 case 2: /* lldt */
3470 /* TODO: Check cpl? and Prot.mode */
3471 if (!modrm(cpu, MODRM_READ, 16, mode67,
3472 0, &instr, &newpc, &op1, &op2))
3473 return 0;
3474 reload_segment_descriptor(cpu,
3475 RELOAD_LDTR, op1, &newpc);
3476 break;
3477 case 3: /* ltr */
3478 /* TODO: Check cpl=0 and Prot.mode */
3479 if (!modrm(cpu, MODRM_READ, 16, mode67,
3480 0, &instr, &newpc, &op1, &op2))
3481 return 0;
3482 reload_segment_descriptor(cpu,
3483 RELOAD_TR, op1, &newpc);
3484 break;
3485 default:fatal("UNIMPLEMENTED 0x%02x,0x%02x"
3486 ",0x%02x\n", op, imm, *instr);
3487 quiet_mode = 0;
3488 x86_cpu_disassemble_instr(cpu,
3489 really_orig_instr, 1 | omode, 0, 0);
3490 cpu->running = 0;
3491 }
3492 break;
3493 case 0x01:
3494 subop = (*instr >> 3) & 0x7;
3495 switch (subop) {
3496 case 0: /* sgdt */
3497 case 1: /* sidt */
3498 case 2: /* lgdt */
3499 case 3: /* lidt */
3500 instr_orig = instr;
3501 if (!modrm(cpu, MODRM_READ, mode,
3502 mode67, MODRM_JUST_GET_ADDR, &instr,
3503 &newpc, &op1, &op2))
3504 return 0;
3505 /* TODO/NOTE: how about errors? */
3506 if (subop >= 2) {
3507 x86_load(cpu, op1, &tmp, 2);
3508 x86_load(cpu, op1 + 2, &op2, 4);
3509 if (mode == 16)
3510 op2 &= 0x00ffffffULL;
3511 }
3512 switch (subop) {
3513 case 0: tmp = cpu->cd.x86.gdtr_limit;
3514 op2 = cpu->cd.x86.gdtr;
3515 break;
3516 case 1: tmp = cpu->cd.x86.idtr_limit;
3517 op2 = cpu->cd.x86.idtr;
3518 break;
3519 case 2: cpu->cd.x86.gdtr_limit =
3520 tmp & 0xffff;
3521 cpu->cd.x86.gdtr = op2;
3522 break;
3523 case 3: cpu->cd.x86.idtr_limit =
3524 tmp & 0xffff;
3525 cpu->cd.x86.idtr = op2;
3526 break;
3527 }
3528 if (subop < 2) {
3529 if (mode == 16)
3530 op2 &= 0x00ffffffULL;
3531 x86_store(cpu, op1, tmp, 2);
3532 x86_store(cpu, op1+2, op2, 4);
3533 }
3534 break;
3535 case 4: /* smsw */
3536 case 6: /* lmsw */
3537 instr_orig = instr;
3538 if (!modrm(cpu, MODRM_READ, 16, mode67,
3539 0, &instr, &newpc, &op1, &op2))
3540 return 0;
3541 if (((*instr_orig >> 3) & 0x7) == 4) {
3542 op1 = cpu->cd.x86.cr[0] &0xffff;
3543 if (!modrm(cpu, MODRM_WRITE_RM,
3544 16, mode67, 0, &instr_orig,
3545 NULL, &op1, &op2))
3546 return 0;
3547 } else {
3548 /* lmsw cannot be used to
3549 clear bit 0: */
3550 op1 |= (cpu->cd.x86.cr[0] &
3551 X86_CR0_PE);
3552 x86_write_cr(cpu, 0,
3553 (cpu->cd.x86.cr[0] & ~0xf)
3554 | (op1 & 0xf));
3555 }
3556 break;
3557 case 7: /* invlpg */
3558 modrm(cpu, MODRM_READ, mode,
3559 mode67, MODRM_JUST_GET_ADDR, &instr,
3560 &newpc, &op1, &op2);
3561 /* TODO */
3562 break;
3563 default:fatal("UNIMPLEMENTED 0x%02x,0x%02x"
3564 ",0x%02x\n", op, imm, *instr);
3565 quiet_mode = 0;
3566 x86_cpu_disassemble_instr(cpu,
3567 really_orig_instr, 1 | omode, 0, 0);
3568 cpu->running = 0;
3569 }
3570 break;
3571 case 0x06: /* CLTS */
3572 cpu->cd.x86.cr[0] &= ~X86_CR0_TS;
3573 break;
3574 case 0x08: /* INVD */
3575 /* TODO */
3576 break;
3577 case 0x09: /* WBINVD */
3578 /* TODO */
3579 break;
3580 case 0x0b: /* Reserved */
3581 x86_interrupt(cpu, 6, 0);
3582 return 1;
3583 case 0x20: /* MOV r/m,CRx */
3584 case 0x21: /* MOV r/m,DRx: TODO: is this right? */
3585 instr_orig = instr;
3586 if (!modrm(cpu, MODRM_READ, 32, mode67,
3587 imm==0x20? MODRM_CR : MODRM_DR, &instr,
3588 &newpc, &op1, &op2))
3589 return 0;
3590 op1 = op2;
3591 if (!modrm(cpu, MODRM_WRITE_RM, 32, mode67,
3592 imm==0x20? MODRM_CR : MODRM_DR, &instr_orig,
3593 NULL, &op1, &op2))
3594 return 0;
3595 break;
3596 case 0x22: /* MOV CRx,r/m */
3597 case 0x23: /* MOV DRx,r/m */
3598 instr_orig = instr;
3599 if (!modrm(cpu, MODRM_READ, 32, mode67,
3600 imm==0x22? MODRM_CR : MODRM_DR, &instr,
3601 &newpc, &op1, &op2))
3602 return 0;
3603 op2 = op1;
3604 if (!modrm(cpu, MODRM_WRITE_R, 32, mode67,
3605 imm==0x22? MODRM_CR : MODRM_DR, &instr_orig,
3606 NULL, &op1, &op2))
3607 return 0;
3608 break;
3609 case 0x30: /* WRMSR */
3610 case 0x32: /* RDMSR */
3611 x86_msr(cpu, imm==0x30? 1 : 0);
3612 break;
3613 case 0x31: /* RDTSC */
3614 if (cpu->cd.x86.model.model_number <
3615 X86_MODEL_PENTIUM)
3616 fatal("WARNING: rdtsc usually requires"
3617 " a Pentium. continuing anyway\n");
3618 if (cpu->cd.x86.cr[4] & X86_CR4_TSD)
3619 fatal("WARNING: time stamp disable:"
3620 " TODO\n");
3621 cpu->cd.x86.r[X86_R_DX] = cpu->cd.x86.tsc >> 32;
3622 cpu->cd.x86.r[X86_R_AX] = cpu->cd.x86.tsc
3623 & 0xffffffff;
3624 /* TODO: make this better */
3625 cpu->cd.x86.tsc += 1000;
3626 break;
3627 case 0xa0:
3628 if (!x86_push(cpu, cpu->cd.x86.s[X86_S_FS],
3629 mode))
3630 return 0;
3631 break;
3632 case 0xa1:
3633 if (!x86_pop(cpu, &tmp, mode))
3634 return 0;
3635 reload_segment_descriptor(cpu, X86_S_FS,
3636 tmp, &newpc);
3637 break;
3638 case 0xa2:
3639 if (!(cpu->cd.x86.rflags & X86_FLAGS_ID))
3640 fatal("TODO: ID bit off in flags,"
3641 " but CPUID attempted?\n");
3642 x86_cpuid(cpu);
3643 break;
3644 case 0xa4:
3645 case 0xa5:
3646 case 0xac:
3647 case 0xad:
3648 instr_orig = instr;
3649 if (!modrm(cpu, MODRM_READ, mode, mode67,
3650 0, &instr, &newpc, &op1, &op2))
3651 return 0;
3652 if (imm & 1)
3653 imm2 = cpu->cd.x86.r[X86_R_CX];
3654 else
3655 imm2 = read_imm(&instr, &newpc, 8);
3656 imm2 &= 31;
3657 if (imm <= 0xa5) { /* SHLD */
3658 if (mode == 16) {
3659 op1 <<= 16;
3660 op1 |= (op2 & 0xffff);
3661 } else {
3662 op1 <<= 32;
3663 op1 |= (op2 & 0xffffffff);
3664 }
3665 x86_shiftrotate(cpu, &op1, 4, imm2,
3666 mode == 64? 64 : (mode * 2));
3667 op1 >>= (mode==16? 16 : 32);
3668 } else { /* SHRD */
3669 if (mode == 16) {
3670 op2 <<= 16;
3671 op1 = (op1 & 0xffff) | op2;
3672 } else {
3673 op2 <<= 32;
3674 op1 = (op1 & 0xffffffff) | op2;
3675 }
3676 x86_shiftrotate(cpu, &op1, 5, imm2,
3677 mode == 64? 64 : (mode * 2));
3678 op1 &= (mode==16? 0xffff : 0xffffffff);
3679 }
3680 if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67,
3681 0, &instr_orig, NULL, &op1, &op2))
3682 return 0;
3683 break;
3684 case 0xa8:
3685 if (!x86_push(cpu, cpu->cd.x86.s[X86_S_GS],
3686 mode))
3687 return 0;
3688 break;
3689 case 0xa9:
3690 if (!x86_pop(cpu, &tmp, mode))
3691 return 0;
3692 reload_segment_descriptor(cpu, X86_S_GS,
3693 tmp, &newpc);
3694 break;
3695 case 0xa3: /* BT */
3696 case 0xab: /* BTS */
3697 case 0xb3: /* BTR */
3698 case 0xbb: /* BTC */
3699 instr_orig = instr;
3700 if (!modrm(cpu, MODRM_READ, mode, mode67,
3701 0, &instr, &newpc, &op1, &op2))
3702 return 0;
3703 imm2 = op2 & 31;
3704 if (mode == 16)
3705 imm2 &= 15;
3706 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3707 if (op1 & ((uint64_t)1 << imm2))
3708 cpu->cd.x86.rflags |=
3709 X86_FLAGS_CF;
3710 switch (imm) {
3711 case 0xab:
3712 op1 |= ((uint64_t)1 << imm2);
3713 break;
3714 case 0xb3:
3715 op1 &= ~((uint64_t)1 << imm2);
3716 break;
3717 case 0xbb:
3718 op1 ^= ((uint64_t)1 << imm2);
3719 break;
3720 }
3721 if (imm != 0xa3) {
3722 if (!modrm(cpu, MODRM_WRITE_RM, mode,
3723 mode67, 0, &instr_orig, NULL,
3724 &op1, &op2))
3725 return 0;
3726 }
3727 break;
3728 case 0xaf: /* imul r16/32, rm16/32 */
3729 instr_orig = instr;
3730 if (!modrm(cpu, MODRM_READ, mode, mode67,
3731 0, &instr, &newpc, &op1, &op2))
3732 return 0;
3733 cpu->cd.x86.rflags &= X86_FLAGS_CF;
3734 cpu->cd.x86.rflags &= X86_FLAGS_OF;
3735 if (mode == 16) {
3736 op2 = (int16_t)op1 * (int16_t)op2;
3737 if (op2 >= 0x10000)
3738 cpu->cd.x86.rflags |=
3739 X86_FLAGS_CF | X86_FLAGS_OF;
3740 } else {
3741 op2 = (int32_t)op1 * (int32_t)op2;
3742 if (op2 >= 0x100000000ULL)
3743 cpu->cd.x86.rflags |=
3744 X86_FLAGS_CF | X86_FLAGS_OF;
3745 }
3746 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3747 0, &instr_orig, NULL, &op1, &op2))
3748 return 0;
3749 break;
3750 case 0xb0:
3751 case 0xb1: /* CMPXCHG */
3752 instr_orig = instr;
3753 if (!modrm(cpu, MODRM_READ, mode, mode67,
3754 imm == 0xb0? MODRM_EIGHTBIT : 0,
3755 &instr, &newpc, &op1, &op2))
3756 return 0;
3757 x86_calc_flags(cpu, op1, cpu->cd.x86.r[
3758 X86_R_AX], imm == 0xb0? 8 : mode,
3759 CALCFLAGS_OP_SUB);
3760 if (cpu->cd.x86.rflags & X86_FLAGS_ZF) {
3761 if (!modrm(cpu, MODRM_WRITE_RM, mode,
3762 mode67, imm == 0xb0?
3763 MODRM_EIGHTBIT : 0,
3764 &instr_orig, NULL, &op2, &op1))
3765 return 0;
3766 } else {
3767 if (imm == 0xb0)
3768 cpu->cd.x86.r[X86_R_AX] =
3769 (cpu->cd.x86.r[X86_R_AX] &
3770 ~0xff) | (op1 & 0xff);
3771 else if (mode == 16)
3772 cpu->cd.x86.r[X86_R_AX] =
3773 (cpu->cd.x86.r[X86_R_AX] &
3774 ~0xffff) | (op1 & 0xffff);
3775 else /* 32 bit */
3776 cpu->cd.x86.r[X86_R_AX] = op1;
3777 }
3778 break;
3779 case 0xb2: /* LSS */
3780 case 0xb4: /* LFS */
3781 case 0xb5: /* LGS */
3782 instr_orig = instr;
3783 if (!modrm(cpu, MODRM_READ, mode, mode67,
3784 MODRM_JUST_GET_ADDR, &instr, &newpc,
3785 &op1, &op2))
3786 return 0;
3787 /* op1 is the address to load from */
3788 if (!x86_load(cpu, op1, &tmp, mode/8))
3789 return 0;
3790 op2 = tmp;
3791 if (!x86_load(cpu, op1 + mode/8, &tmp, 2))
3792 return 0;
3793 reload_segment_descriptor(cpu, imm==0xb2?
3794 X86_S_SS:(imm==0xb4?X86_S_FS:X86_S_GS),
3795 tmp, &newpc);
3796 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3797 0, &instr_orig, NULL, &op1, &op2))
3798 return 0;
3799 break;
3800 case 0xb6:
3801 case 0xb7: /* movzx */
3802 case 0xbe:
3803 case 0xbf: /* movsx */
3804 instr_orig = instr;
3805 if (!modrm(cpu, MODRM_READ, mode, mode67,
3806 (imm&1)==0? (MODRM_EIGHTBIT |
3807 MODRM_R_NONEIGHTBIT) : MODRM_RM_16BIT,
3808 &instr, &newpc, &op1, &op2))
3809 return 0;
3810 signflag = 0;
3811 if (imm >= 0xbe)
3812 signflag = 1;
3813 op2 = op1;
3814 if (imm & 1) { /* r32 = r16 */
3815 op2 &= 0xffff;
3816 if (signflag && op2 & 0x8000)
3817 op2 |= 0xffff0000ULL;
3818 } else { /* r(mode) = r8 */
3819 op2 &= 0xff;
3820 if (signflag && op2 & 0x80)
3821 op2 |= 0xffffff00ULL;
3822 }
3823 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3824 (imm&1)==0? (MODRM_EIGHTBIT |
3825 MODRM_R_NONEIGHTBIT) : MODRM_RM_16BIT,
3826 &instr_orig, NULL, &op1, &op2))
3827 return 0;
3828 break;
3829 case 0xba:
3830 subop = (*instr >> 3) & 0x7;
3831 switch (subop) {
3832 case 4: /* BT */
3833 case 5: /* BTS */
3834 case 6: /* BTR */
3835 case 7: /* BTC */
3836 instr_orig = instr;
3837 if (!modrm(cpu, MODRM_READ, mode,
3838 mode67, 0, &instr, &newpc, &op1,
3839 &op2))
3840 return 0;
3841 imm = read_imm(&instr, &newpc, 8);
3842 imm &= 31;
3843 if (mode == 16)
3844 imm &= 15;
3845 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3846 if (op1 & ((uint64_t)1 << imm))
3847 cpu->cd.x86.rflags |=
3848 X86_FLAGS_CF;
3849 switch (subop) {
3850 case 5: op1 |= ((uint64_t)1 << imm);
3851 break;
3852 case 6: op1 &= ~((uint64_t)1 << imm);
3853 break;
3854 case 7: op1 ^= ((uint64_t)1 << imm);
3855 break;
3856 }
3857 if (subop != 4) {
3858 if (!modrm(cpu, MODRM_WRITE_RM,
3859 mode, mode67, 0,
3860 &instr_orig, NULL,
3861 &op1, &op2))
3862 return 0;
3863 }
3864 break;
3865 default:fatal("UNIMPLEMENTED 0x%02x,0x%02x"
3866 ",0x%02x\n", op, imm, *instr);
3867 quiet_mode = 0;
3868 x86_cpu_disassemble_instr(cpu,
3869 really_orig_instr, 1|omode, 0, 0);
3870 cpu->running = 0;
3871 }
3872 break;
3873 case 0xbc: /* bsf */
3874 case 0xbd: /* bsr */
3875 instr_orig = instr;
3876 if (!modrm(cpu, MODRM_READ, mode, mode67,
3877 0, &instr, &newpc, &op1, &op2))
3878 return 0;
3879 cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;
3880 if (op1 == 0)
3881 cpu->cd.x86.rflags |= X86_FLAGS_ZF;
3882 i = mode - 1;
3883 if (imm == 0xbc)
3884 i = 0;
3885 for (;;) {
3886 if (op1 & ((uint64_t)1<<i)) {
3887 op2 = i;
3888 break;
3889 }
3890 if (imm == 0xbc) {
3891 if (++i >= mode)
3892 break;
3893 } else {
3894 if (--i < 0)
3895 break;
3896 }
3897 }
3898 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3899 0, &instr_orig, NULL, &op1, &op2))
3900 return 0;
3901 break;
3902 case 0xc0: /* xadd */
3903 case 0xc1:
3904 instr_orig = instr_orig_2 = instr;
3905 if (!modrm(cpu, MODRM_READ, mode, mode67,
3906 imm == 0xc0? MODRM_EIGHTBIT : 0,
3907 &instr, &newpc, &op1, &op2))
3908 return 0;
3909 tmp = op1; op1 = op2; op2 = tmp;
3910 x86_calc_flags(cpu, op1, op2, imm==0xc0?
3911 8 : mode, CALCFLAGS_OP_ADD);
3912 op1 += op2;
3913 if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67,
3914 imm == 0xc0? MODRM_EIGHTBIT : 0,
3915 &instr_orig, NULL, &op1, &op2))
3916 return 0;
3917 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
3918 imm == 0xc0? MODRM_EIGHTBIT : 0,
3919 &instr_orig_2, NULL, &op1, &op2))
3920 return 0;
3921 break;
3922 case 0xc7:
3923 subop = (*instr >> 3) & 0x7;
3924 switch (subop) {
3925 case 1: /* CMPXCHG8B */
3926 if (!modrm(cpu, MODRM_READ, mode,
3927 mode67, MODRM_JUST_GET_ADDR, &instr,
3928 &newpc, &op1, &op2))
3929 return 0;
3930 if (!x86_load(cpu, op1, &tmp, 8))
3931 return 0;
3932 cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;
3933 if ((tmp >> 32) == (0xffffffffULL &
3934 cpu->cd.x86.r[X86_R_DX]) && (tmp
3935 & 0xffffffffULL) == (0xffffffffULL &
3936 cpu->cd.x86.r[X86_R_AX])) {
3937 cpu->cd.x86.rflags |=
3938 X86_FLAGS_ZF;
3939 tmp = ((cpu->cd.x86.r[X86_R_CX]
3940 & 0xffffffffULL) << 32) |
3941 (cpu->cd.x86.r[X86_R_BX] &
3942 0xffffffffULL);
3943 if (!x86_store(cpu, op1, tmp,8))
3944 return 0;
3945 } else {
3946 cpu->cd.x86.r[X86_R_DX] =
3947 tmp >> 32;
3948 cpu->cd.x86.r[X86_R_AX] =
3949 tmp & 0xffffffffULL;
3950 }
3951 break;
3952 default:fatal("UNIMPLEMENTED 0x%02x,0x%02x"
3953 ",0x%02x\n", op, imm, *instr);
3954 quiet_mode = 0;
3955 x86_cpu_disassemble_instr(cpu,
3956 really_orig_instr, 1|omode, 0, 0);
3957 cpu->running = 0;
3958 }
3959 break;
3960 default:fatal("TODO: 0x0f,0x%02x\n", imm);
3961 quiet_mode = 0;
3962 x86_cpu_disassemble_instr(cpu,
3963 really_orig_instr, 1|omode, 0, 0);
3964 cpu->running = 0;
3965 }
3966 }
3967 } else if ((op & 0xf0) < 0x20 && (op & 7) == 7) {
3968 uint64_t tmp;
3969 success = x86_pop(cpu, &tmp, mode);
3970 if (!success)
3971 return 0;
3972 reload_segment_descriptor(cpu, op/8, tmp, &newpc);
3973 } else if (op == 0x27) { /* DAA */
3974 int a = (cpu->cd.x86.r[X86_R_AX] >> 4) & 0xf;
3975 int b = cpu->cd.x86.r[X86_R_AX] & 0xf;
3976 if (b > 9) {
3977 b -= 10;
3978 a ++;
3979 } else if (cpu->cd.x86.rflags & X86_FLAGS_AF)
3980 b += 6;
3981 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
3982 cpu->cd.x86.rflags &= ~X86_FLAGS_AF;
3983 if (a*10 + b >= 100) {
3984 cpu->cd.x86.rflags |= X86_FLAGS_CF;
3985 cpu->cd.x86.rflags |= X86_FLAGS_AF;
3986 a %= 10;
3987 }
3988 cpu->cd.x86.r[X86_R_AX] &= ~0xff;
3989 cpu->cd.x86.r[X86_R_AX] |= ((a*16 + b) & 0xff);
3990 } else if (op == 0x2f) { /* DAS */
3991 int tmp_al = cpu->cd.x86.r[X86_R_AX] & 0xff;
3992 if ((tmp_al & 0xf) > 9 || cpu->cd.x86.rflags & X86_FLAGS_AF) {
3993 cpu->cd.x86.r[X86_R_AX] &= ~0xff;
3994 cpu->cd.x86.r[X86_R_AX] |= ((tmp_al - 6) & 0xff);
3995 cpu->cd.x86.rflags |= X86_FLAGS_AF;
3996 } else
3997 cpu->cd.x86.rflags &= ~X86_FLAGS_AF;
3998 if (tmp_al > 0x9f || cpu->cd.x86.rflags & X86_FLAGS_CF) {
3999 cpu->cd.x86.r[X86_R_AX] &= ~0xff;
4000 cpu->cd.x86.r[X86_R_AX] |= ((tmp_al - 0x60) & 0xff);
4001 cpu->cd.x86.rflags |= X86_FLAGS_CF;
4002 } else
4003 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4004 x86_calc_flags(cpu, cpu->cd.x86.r[X86_R_AX] & 0xff,
4005 0, 8, CALCFLAGS_OP_XOR);
4006 } else if (op == 0x37) { /* AAA */
4007 int b = cpu->cd.x86.r[X86_R_AX] & 0xf;
4008 if (b > 9) {
4009 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX]
4010 & ~0xff00) | ((cpu->cd.x86.r[X86_R_AX] &
4011 0xff00) + 0x100);
4012 cpu->cd.x86.rflags |= X86_FLAGS_CF | X86_FLAGS_AF;
4013 } else {
4014 cpu->cd.x86.rflags &= ~(X86_FLAGS_CF | X86_FLAGS_AF);
4015 }
4016 cpu->cd.x86.r[X86_R_AX] &= ~0xf0;
4017 } else if (op >= 0x40 && op <= 0x4f) {
4018 int old_cf = cpu->cd.x86.rflags & X86_FLAGS_CF;
4019 if (op < 0x48) {
4020 x86_calc_flags(cpu, cpu->cd.x86.r[op & 7], 1, mode,
4021 CALCFLAGS_OP_ADD);
4022 cpu->cd.x86.r[op & 7] = modify(cpu->cd.x86.r[op & 7],
4023 cpu->cd.x86.r[op & 7] + 1);
4024 } else {
4025 x86_calc_flags(cpu, cpu->cd.x86.r[op & 7], 1, mode,
4026 CALCFLAGS_OP_SUB);
4027 if (mode == 16)
4028 cpu->cd.x86.r[op & 7] = modify(cpu->cd.x86.r[op
4029 & 7], (cpu->cd.x86.r[op & 7] & 0xffff) - 1);
4030 else {
4031 cpu->cd.x86.r[op & 7] --;
4032 cpu->cd.x86.r[op & 7] &= 0xffffffffULL;
4033 }
4034 }
4035 /* preserve CF: */
4036 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4037 cpu->cd.x86.rflags |= old_cf;
4038 } else if (op >= 0x50 && op <= 0x57) {
4039 if (!x86_push(cpu, cpu->cd.x86.r[op & 7], mode))
4040 return 0;
4041 } else if (op >= 0x58 && op <= 0x5f) {
4042 if (!x86_pop(cpu, &tmp, mode))
4043 return 0;
4044 if (mode == 16)
4045 cpu->cd.x86.r[op & 7] = (cpu->cd.x86.r[op & 7] &
4046 ~0xffff) | (tmp & 0xffff);
4047 else
4048 cpu->cd.x86.r[op & 7] = tmp;
4049 } else if (op == 0x60) { /* PUSHA/PUSHAD */
4050 uint64_t r[8];
4051 int i;
4052 for (i=0; i<8; i++)
4053 r[i] = cpu->cd.x86.r[i];
4054 for (i=0; i<8; i++)
4055 if (!x86_push(cpu, r[i], mode)) {
4056 fatal("TODO: failed pusha\n");
4057 cpu->running = 0;
4058 return 0;
4059 }
4060 } else if (op == 0x61) { /* POPA/POPAD */
4061 uint64_t r[8];
4062 int i;
4063 for (i=7; i>=0; i--)
4064 if (!x86_pop(cpu, &r[i], mode)) {
4065 fatal("TODO: failed popa\n");
4066 cpu->running = 0;
4067 return 0;
4068 }
4069 for (i=0; i<8; i++)
4070 if (i != X86_R_SP) {
4071 if (mode == 16)
4072 cpu->cd.x86.r[i] = (cpu->cd.x86.r[i]
4073 & ~0xffff) | (r[i] & 0xffff);
4074 else
4075 cpu->cd.x86.r[i] = r[i];
4076 }
4077 } else if (op == 0x68) { /* PUSH imm16/32 */
4078 uint64_t imm = read_imm(&instr, &newpc, mode);
4079 if (!x86_push(cpu, imm, mode))
4080 return 0;
4081 } else if (op == 0x69 || op == 0x6b) {
4082 instr_orig = instr;
4083 if (!modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
4084 &newpc, &op1, &op2))
4085 return 0;
4086 if (op == 0x69)
4087 imm = read_imm(&instr, &newpc, mode);
4088 else
4089 imm = (signed char)read_imm(&instr, &newpc, 8);
4090 op2 = op1 * imm;
4091 /* TODO: overflow! */
4092 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67, 0,
4093 &instr_orig, NULL, &op1, &op2))
4094 return 0;
4095 } else if (op == 0x6a) { /* PUSH imm8 */
4096 uint64_t imm = (signed char)read_imm(&instr, &newpc, 8);
4097 if (!x86_push(cpu, imm, mode))
4098 return 0;
4099 } else if ((op & 0xf0) == 0x70) {
4100 imm = read_imm(&instr, &newpc, 8);
4101 success = x86_condition(cpu, op);
4102 if (success)
4103 newpc = modify(newpc, newpc + (signed char)imm);
4104 } else if (op == 0x80 || op == 0x81) { /* add/and r/m, imm */
4105 instr_orig = instr;
4106 if (!modrm(cpu, MODRM_READ, mode, mode67, op == 0x80?
4107 MODRM_EIGHTBIT : 0, &instr, &newpc, &op1, &op2))
4108 return 0;
4109 imm = read_imm(&instr, &newpc, op==0x80? 8 : mode);
4110 switch ((*instr_orig >> 3) & 0x7) {
4111 case 0: x86_calc_flags(cpu, op1, imm, op==0x80? 8 : mode,
4112 CALCFLAGS_OP_ADD);
4113 op1 += imm;
4114 break;
4115 case 1: op1 |= imm; break;
4116 case 2: tmp = imm + (cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0);
4117 x86_calc_flags(cpu, op1, tmp, op==0x80? 8 : mode,
4118 CALCFLAGS_OP_ADD);
4119 op1 += tmp;
4120 break;
4121 case 3: tmp = imm + (cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0);
4122 x86_calc_flags(cpu, op1, tmp, op==0x80? 8 : mode,
4123 CALCFLAGS_OP_SUB);
4124 op1 -= tmp;
4125 break;
4126 case 4: op1 &= imm; break;
4127 case 5: x86_calc_flags(cpu, op1, imm, op==0x80? 8 : mode,
4128 CALCFLAGS_OP_SUB);
4129 op1 -= imm; break;
4130 case 6: op1 ^= imm; break;
4131 case 7: x86_calc_flags(cpu, op1, imm, op==0x80? 8 : mode,
4132 CALCFLAGS_OP_SUB); /* cmp */
4133 break;
4134 }
4135
4136 if (((*instr_orig >> 3) & 0x7) != 7) {
4137 if (((*instr_orig >> 3) & 0x7) != 0 &&
4138 ((*instr_orig >> 3) & 0x7) != 2 &&
4139 ((*instr_orig >> 3) & 0x7) != 3 &&
4140 ((*instr_orig >> 3) & 0x7) != 5)
4141 x86_calc_flags(cpu, op1, 0, op==0x80? 8 : mode,
4142 CALCFLAGS_OP_XOR);
4143
4144 /* "and","or","xor" always clears CF and OF: */
4145 if (((*instr_orig >> 3) & 0x7) == 1 ||
4146 ((*instr_orig >> 3) & 0x7) == 4 ||
4147 ((*instr_orig >> 3) & 0x7) == 6) {
4148 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4149 cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
4150 }
4151
4152 if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4153 op == 0x80? MODRM_EIGHTBIT : 0, &instr_orig,
4154 NULL, &op1, &op2))
4155 return 0;
4156 }
4157 } else if (op == 0x83) { /* add/and r/m1632, imm8 */
4158 instr_orig = instr;
4159 if (!modrm(cpu, MODRM_READ, mode, mode67, 0, &instr,
4160 &newpc, &op1, &op2))
4161 return 0;
4162 imm = read_imm(&instr, &newpc, 8);
4163 switch ((*instr_orig >> 3) & 0x7) {
4164 case 0: x86_calc_flags(cpu, op1, (signed char)imm,
4165 mode, CALCFLAGS_OP_ADD);
4166 op1 += (signed char)imm;
4167 break;
4168 case 1: op1 |= (signed char)imm; break;
4169 case 2: tmp = (signed char)imm +
4170 (cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0);
4171 x86_calc_flags(cpu, op1, tmp, mode, CALCFLAGS_OP_ADD);
4172 op1 += tmp;
4173 break;
4174 case 3: tmp = (signed char)imm +
4175 (cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0);
4176 x86_calc_flags(cpu, op1, tmp, mode, CALCFLAGS_OP_SUB);
4177 op1 -= tmp;
4178 break;
4179 case 4: op1 &= (signed char)imm; break;
4180 case 5: x86_calc_flags(cpu, op1, (signed char)imm, mode,
4181 CALCFLAGS_OP_SUB);
4182 op1 -= (signed char)imm; break;
4183 case 6: op1 ^= (signed char)imm; break;
4184 case 7: x86_calc_flags(cpu, op1, (signed char)imm, mode,
4185 CALCFLAGS_OP_SUB);
4186 break;
4187 }
4188 if (((*instr_orig >> 3) & 0x7) != 7) {
4189 if (((*instr_orig >> 3) & 0x7) != 0 &&
4190 ((*instr_orig >> 3) & 0x7) != 2 &&
4191 ((*instr_orig >> 3) & 0x7) != 3 &&
4192 ((*instr_orig >> 3) & 0x7) != 5)
4193 x86_calc_flags(cpu, op1, 0, mode,
4194 CALCFLAGS_OP_XOR);
4195
4196 /* "and","or","xor" always clears CF and OF: */
4197 if (((*instr_orig >> 3) & 0x7) == 1 ||
4198 ((*instr_orig >> 3) & 0x7) == 4 ||
4199 ((*instr_orig >> 3) & 0x7) == 6) {
4200 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4201 cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
4202 }
4203 if (!modrm(cpu, MODRM_WRITE_RM, mode,
4204 mode67, 0, &instr_orig, NULL, &op1, &op2))
4205 return 0;
4206 }
4207 } else if (op == 0x84 || op == 0x85) { /* TEST */
4208 success = modrm(cpu, MODRM_READ, mode, mode67, op == 0x84?
4209 MODRM_EIGHTBIT : 0, &instr, &newpc, &op1, &op2);
4210 if (!success)
4211 return 0;
4212 op1 &= op2;
4213 x86_calc_flags(cpu, op1, 0, op==0x84? 8 : mode,
4214 CALCFLAGS_OP_XOR);
4215 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4216 cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
4217 } else if (op >= 0x86 && op <= 0x87) { /* XCHG */
4218 void *orig2 = instr_orig = instr;
4219 success = modrm(cpu, MODRM_READ, mode, mode67, op&1? 0 :
4220 MODRM_EIGHTBIT, &instr, &newpc, &op1, &op2);
4221 if (!success)
4222 return 0;
4223 /* Note: Update the r/m first, because it may be dependant
4224 on original register values :-) */
4225 success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4226 op == 0x86? MODRM_EIGHTBIT : 0, &instr_orig,
4227 NULL, &op2, &op1);
4228 instr_orig = orig2;
4229 success = modrm(cpu, MODRM_WRITE_R, mode, mode67,
4230 op == 0x86? MODRM_EIGHTBIT : 0, &instr_orig,
4231 NULL, &op2, &op1);
4232 if (!success)
4233 return 0;
4234 } else if (op >= 0x88 && op <= 0x8b) { /* MOV */
4235 instr_orig = instr;
4236 success = modrm(cpu, MODRM_READ, mode, mode67, (op & 1) == 0?
4237 MODRM_EIGHTBIT : 0, &instr, &newpc, &op1, &op2);
4238 if (!success)
4239 return 0;
4240 if (op < 0x8a) {
4241 success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4242 op == 0x88? MODRM_EIGHTBIT : 0, &instr_orig,
4243 NULL, &op2, &op1);
4244 } else {
4245 success = modrm(cpu, MODRM_WRITE_R, mode, mode67,
4246 op == 0x8a? MODRM_EIGHTBIT : 0, &instr_orig,
4247 NULL, &op2, &op1);
4248 }
4249 if (!success)
4250 return 0;
4251 } else if (op == 0x8c || op == 0x8e) { /* MOV seg */
4252 instr_orig = instr;
4253 if (!modrm(cpu, MODRM_READ, 16, mode67, MODRM_SEG,
4254 &instr, &newpc, &op1, &op2))
4255 return 0;
4256 if (op == 0x8c) {
4257 if (!modrm(cpu, MODRM_WRITE_RM, 16, mode67, MODRM_SEG,
4258 &instr_orig, NULL, &op2, &op1))
4259 return 0;
4260 } else {
4261 reload_segment_descriptor(cpu, (*instr_orig >> 3) & 7,
4262 op1 & 0xffff, &newpc);
4263 }
4264 } else if (op == 0x8d) { /* LEA */
4265 instr_orig = instr;
4266 if (!modrm(cpu, MODRM_READ, mode, mode67,
4267 MODRM_JUST_GET_ADDR, &instr, &newpc, &op1, &op2))
4268 return 0;
4269 op2 = op1;
4270 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
4271 0, &instr_orig, NULL, &op1, &op2))
4272 return 0;
4273 } else if (op == 0x8f) {
4274 switch ((*instr >> 3) & 0x7) {
4275 case 0: /* POP m16/m32 */
4276 if (!x86_pop(cpu, &op1, mode))
4277 return 0;
4278 if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4279 0, &instr, &newpc, &op1, &op2))
4280 return 0;
4281 break;
4282 default:
4283 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4284 quiet_mode = 0;
4285 x86_cpu_disassemble_instr(cpu,
4286 really_orig_instr, 1|omode, 0, 0);
4287 cpu->running = 0;
4288 }
4289 } else if (op == 0x90) { /* NOP */
4290 } else if (op >= 0x91 && op <= 0x97) { /* XCHG */
4291 uint64_t tmp;
4292 if (mode == 16) {
4293 tmp = cpu->cd.x86.r[X86_R_AX];
4294 cpu->cd.x86.r[X86_R_AX] = modify(
4295 cpu->cd.x86.r[X86_R_AX], cpu->cd.x86.r[op & 7]);
4296 cpu->cd.x86.r[op & 7] = modify(
4297 cpu->cd.x86.r[op & 7], tmp);
4298 } else {
4299 tmp = cpu->cd.x86.r[X86_R_AX];
4300 cpu->cd.x86.r[X86_R_AX] = cpu->cd.x86.r[op & 7];
4301 cpu->cd.x86.r[op & 7] = tmp;
4302 }
4303 } else if (op == 0x98) { /* CBW/CWDE */
4304 if (mode == 16) {
4305 cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
4306 if (cpu->cd.x86.r[X86_R_AX] & 0x80)
4307 cpu->cd.x86.r[X86_R_AX] |= 0xff00;
4308 } else {
4309 cpu->cd.x86.r[X86_R_AX] &= 0xffff;
4310 if (cpu->cd.x86.r[X86_R_AX] & 0x8000)
4311 cpu->cd.x86.r[X86_R_AX] |= 0xffff0000ULL;
4312 }
4313 } else if (op == 0x99) { /* CWD/CDQ */
4314 if (mode == 16) {
4315 cpu->cd.x86.r[X86_R_DX] &= ~0xffff;
4316 if (cpu->cd.x86.r[X86_R_AX] & 0x8000)
4317 cpu->cd.x86.r[X86_R_DX] |= 0xffff;
4318 } else {
4319 cpu->cd.x86.r[X86_R_DX] = 0;
4320 if (cpu->cd.x86.r[X86_R_AX] & 0x80000000ULL)
4321 cpu->cd.x86.r[X86_R_DX] = 0xffffffff;
4322 }
4323 } else if (op == 0x9a) { /* CALL seg:ofs */
4324 uint16_t old_tr = cpu->cd.x86.tr;
4325 imm = read_imm(&instr, &newpc, mode);
4326 imm2 = read_imm(&instr, &newpc, 16);
4327 if (!x86_push(cpu, cpu->cd.x86.s[X86_S_CS], mode))
4328 return 0;
4329 if (!x86_push(cpu, newpc, mode)) {
4330 fatal("TODO: push failed in CALL seg:ofs\n");
4331 cpu->running = 0;
4332 return 0;
4333 }
4334 reload_segment_descriptor(cpu, X86_S_CS, imm2, &newpc);
4335 if (cpu->cd.x86.tr == old_tr)
4336 newpc = imm;
4337 } else if (op == 0x9b) { /* WAIT */
4338 } else if (op == 0x9c) { /* PUSHF */
4339 if (!x86_push(cpu, cpu->cd.x86.rflags, mode))
4340 return 0;
4341 } else if (op == 0x9d) { /* POPF */
4342 if (!x86_pop(cpu, &tmp, mode))
4343 return 0;
4344 if (mode == 16)
4345 cpu->cd.x86.rflags = (cpu->cd.x86.rflags & ~0xffff)
4346 | (tmp & 0xffff);
4347 else if (mode == 32)
4348 cpu->cd.x86.rflags = (cpu->cd.x86.rflags & ~0xffffffff)
4349 | (tmp & 0xffffffff);
4350 else
4351 cpu->cd.x86.rflags = tmp;
4352 /* TODO: only affect some bits? */
4353 cpu->cd.x86.rflags |= 0x0002;
4354 if (cpu->cd.x86.model.model_number == X86_MODEL_8086)
4355 cpu->cd.x86.rflags |= 0xf000;
4356 /* TODO: all these bits aren't really cleared on a 286: */
4357 if (cpu->cd.x86.model.model_number == X86_MODEL_80286)
4358 cpu->cd.x86.rflags &= ~0xf000;
4359 if (cpu->cd.x86.model.model_number == X86_MODEL_80386)
4360 cpu->cd.x86.rflags &= ~X86_FLAGS_AC;
4361 if (cpu->cd.x86.model.model_number == X86_MODEL_80486)
4362 cpu->cd.x86.rflags &= ~X86_FLAGS_ID;
4363 } else if (op == 0x9e) { /* SAHF */
4364 int mask = (X86_FLAGS_SF | X86_FLAGS_ZF
4365 | X86_FLAGS_AF | X86_FLAGS_PF | X86_FLAGS_CF);
4366 cpu->cd.x86.rflags &= ~mask;
4367 mask &= ((cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff);
4368 cpu->cd.x86.rflags |= mask;
4369 } else if (op == 0x9f) { /* LAHF */
4370 int b = cpu->cd.x86.rflags & (X86_FLAGS_SF | X86_FLAGS_ZF
4371 | X86_FLAGS_AF | X86_FLAGS_PF | X86_FLAGS_CF);
4372 b |= 2;
4373 cpu->cd.x86.r[X86_R_AX] &= ~0xff00;
4374 cpu->cd.x86.r[X86_R_AX] |= (b << 8);
4375 } else if (op == 0xa0) { /* MOV AL,[addr] */
4376 imm = read_imm(&instr, &newpc, mode67);
4377 if (!x86_load(cpu, imm, &tmp, 1))
4378 return 0;
4379 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & ~0xff)
4380 | (tmp & 0xff);
4381 } else if (op == 0xa1) { /* MOV AX,[addr] */
4382 imm = read_imm(&instr, &newpc, mode67);
4383 if (!x86_load(cpu, imm, &tmp, mode/8))
4384 return 0;
4385 cpu->cd.x86.r[X86_R_AX] = modify(cpu->cd.x86.r[X86_R_AX], tmp);
4386 } else if (op == 0xa2) { /* MOV [addr],AL */
4387 imm = read_imm(&instr, &newpc, mode67);
4388 if (!x86_store(cpu, imm, cpu->cd.x86.r[X86_R_AX], 1))
4389 return 0;
4390 } else if (op == 0xa3) { /* MOV [addr],AX */
4391 imm = read_imm(&instr, &newpc, mode67);
4392 if (!x86_store(cpu, imm, cpu->cd.x86.r[X86_R_AX], mode/8))
4393 return 0;
4394 } else if (op == 0xa4 || op == 0xa5 || /* MOVS */
4395 op == 0xa6 || op == 0xa7 || /* CMPS */
4396 op == 0xaa || op == 0xab || /* STOS */
4397 op == 0xac || op == 0xad || /* LODS */
4398 op == 0xae || op == 0xaf) { /* SCAS */
4399 int dir = 1, movs = 0, lods = 0, cmps = 0, stos = 0, scas = 0;
4400 int origcursegment = cpu->cd.x86.cursegment;
4401
4402 len = 1;
4403 if (op & 1)
4404 len = mode / 8;
4405 if (op >= 0xa4 && op <= 0xa5)
4406 movs = 1;
4407 if (op >= 0xa6 && op <= 0xa7)
4408 cmps = 1;
4409 if (op >= 0xaa && op <= 0xab)
4410 stos = 1;
4411 if (op >= 0xac && op <= 0xad)
4412 lods = 1;
4413 if (op >= 0xae && op <= 0xaf)
4414 scas = 1;
4415 if (cpu->cd.x86.rflags & X86_FLAGS_DF)
4416 dir = -1;
4417
4418 do {
4419 uint64_t value;
4420
4421 if (rep) {
4422 /* Abort if [e]cx already 0: */
4423 if (mode == 16 && (cpu->cd.x86.r[X86_R_CX] &
4424 0xffff) == 0)
4425 break;
4426 if (mode != 16 && cpu->cd.x86.r[X86_R_CX] == 0)
4427 break;
4428 }
4429
4430 if (!stos && !scas) {
4431 uint64_t addr = cpu->cd.x86.r[X86_R_SI];
4432 if (mode67 == 16)
4433 addr &= 0xffff;
4434 if (mode67 == 32)
4435 addr &= 0xffffffff;
4436 cpu->cd.x86.cursegment = origcursegment;
4437 if (!x86_load(cpu, addr, &value, len))
4438 return 0;
4439 } else
4440 value = cpu->cd.x86.r[X86_R_AX];
4441 if (lods) {
4442 if (op == 0xac)
4443 cpu->cd.x86.r[X86_R_AX] =
4444 (cpu->cd.x86.r[X86_R_AX] & ~0xff)
4445 | (value & 0xff);
4446 else if (mode == 16)
4447 cpu->cd.x86.r[X86_R_AX] =
4448 (cpu->cd.x86.r[X86_R_AX] & ~0xffff)
4449 | (value & 0xffff);
4450 else
4451 cpu->cd.x86.r[X86_R_AX] = value;
4452 }
4453
4454 if (stos || movs) {
4455 uint64_t addr = cpu->cd.x86.r[X86_R_DI];
4456 if (mode67 == 16)
4457 addr &= 0xffff;
4458 if (mode67 == 32)
4459 addr &= 0xffffffff;
4460 cpu->cd.x86.cursegment = X86_S_ES;
4461 if (!x86_store(cpu, addr, value, len))
4462 return 0;
4463 }
4464 if (cmps || scas) {
4465 uint64_t addr = cpu->cd.x86.r[X86_R_DI];
4466 if (mode67 == 16)
4467 addr &= 0xffff;
4468 if (mode67 == 32)
4469 addr &= 0xffffffff;
4470 cpu->cd.x86.cursegment = X86_S_ES;
4471 if (!x86_load(cpu, addr, &tmp, len))
4472 return 0;
4473
4474 x86_calc_flags(cpu, value, tmp, len*8,
4475 CALCFLAGS_OP_SUB);
4476 }
4477
4478 if (movs || lods || cmps) {
4479 /* Modify esi: */
4480 if (mode67 == 16)
4481 cpu->cd.x86.r[X86_R_SI] =
4482 (cpu->cd.x86.r[X86_R_SI] & ~0xffff)
4483 | ((cpu->cd.x86.r[X86_R_SI]+len*dir)
4484 & 0xffff);
4485 else {
4486 cpu->cd.x86.r[X86_R_SI] += len*dir;
4487 if (mode67 == 32)
4488 cpu->cd.x86.r[X86_R_SI] &=
4489 0xffffffff;
4490 }
4491 }
4492
4493 if (!lods) {
4494 /* Modify edi: */
4495 if (mode67 == 16)
4496 cpu->cd.x86.r[X86_R_DI] =
4497 (cpu->cd.x86.r[X86_R_DI] & ~0xffff)
4498 | ((cpu->cd.x86.r[X86_R_DI]+len*dir)
4499 & 0xffff);
4500 else {
4501 cpu->cd.x86.r[X86_R_DI] += len*dir;
4502 if (mode67 == 32)
4503 cpu->cd.x86.r[X86_R_DI] &=
4504 0xffffffff;
4505 }
4506 }
4507
4508 if (rep) {
4509 /* Decrement ecx: */
4510 if (mode67 == 16)
4511 cpu->cd.x86.r[X86_R_CX] =
4512 (cpu->cd.x86.r[X86_R_CX] & ~0xffff)
4513 | ((cpu->cd.x86.r[X86_R_CX] - 1)
4514 & 0xffff);
4515 else {
4516 cpu->cd.x86.r[X86_R_CX] --;
4517 cpu->cd.x86.r[X86_R_CX] &= 0xffffffff;
4518 }
4519 if (mode67 == 16 && (cpu->cd.x86.r[X86_R_CX] &
4520 0xffff) == 0)
4521 rep = 0;
4522 if (mode67 != 16 &&
4523 cpu->cd.x86.r[X86_R_CX] == 0)
4524 rep = 0;
4525
4526 if (cmps || scas) {
4527 if (rep == REP_REP && !(
4528 cpu->cd.x86.rflags & X86_FLAGS_ZF))
4529 rep = 0;
4530 if (rep == REP_REPNE &&
4531 cpu->cd.x86.rflags & X86_FLAGS_ZF)
4532 rep = 0;
4533 }
4534 }
4535 } while (rep);
4536 } else if (op >= 0xa8 && op <= 0xa9) { /* TEST al/[e]ax,imm */
4537 op1 = cpu->cd.x86.r[X86_R_AX];
4538 op2 = read_imm(&instr, &newpc, op==0xa8? 8 : mode);
4539 op1 &= op2;
4540 x86_calc_flags(cpu, op1, 0, op==0xa8? 8 : mode,
4541 CALCFLAGS_OP_XOR);
4542 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
4543 cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
4544 } else if (op >= 0xb0 && op <= 0xb3) { /* MOV Xl,imm */
4545 imm = read_imm(&instr, &newpc, 8);
4546 cpu->cd.x86.r[op & 3] = (cpu->cd.x86.r[op & 3] & ~0xff)
4547 | (imm & 0xff);
4548 } else if (op >= 0xb4 && op <= 0xb7) { /* MOV Xh,imm */
4549 imm = read_imm(&instr, &newpc, 8);
4550 cpu->cd.x86.r[op & 3] = (cpu->cd.x86.r[op & 3] & ~0xff00)
4551 | ((imm & 0xff) << 8);
4552 } else if (op >= 0xb8 && op <= 0xbf) { /* MOV Xx,imm */
4553 imm = read_imm(&instr, &newpc, mode);
4554 cpu->cd.x86.r[op & 7] = modify(cpu->cd.x86.r[op & 7], imm);
4555 } else if (op == 0xc0 || op == 0xc1) { /* Shift/Rotate */
4556 int n = 1;
4557 instr_orig = instr;
4558 success = modrm(cpu, MODRM_READ, mode, mode67,
4559 op&1? 0 : MODRM_EIGHTBIT, &instr, &newpc, &op1, &op2);
4560 if (!success)
4561 return 0;
4562 n = read_imm(&instr, &newpc, 8);
4563 x86_shiftrotate(cpu, &op1, (*instr_orig >> 3) & 0x7,
4564 n, op&1? mode : 8);
4565 success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4566 op&1? 0 : MODRM_EIGHTBIT, &instr_orig, NULL, &op1, &op2);
4567 if (!success)
4568 return 0;
4569 } else if (op == 0xc2 || op == 0xc3) { /* RET near */
4570 uint64_t popped_pc;
4571 if (!x86_pop(cpu, &popped_pc, mode))
4572 return 0;
4573 if (op == 0xc2) {
4574 imm = read_imm(&instr, &newpc, 16);
4575 cpu->cd.x86.r[X86_R_SP] = modify(cpu->cd.x86.r[
4576 X86_R_SP], cpu->cd.x86.r[X86_R_SP] + imm);
4577 }
4578 newpc = popped_pc;
4579 } else if (op == 0xc4 || op == 0xc5) { /* LDS,LES */
4580 instr_orig = instr;
4581 if (!modrm(cpu, MODRM_READ, mode, mode67,
4582 MODRM_JUST_GET_ADDR, &instr, &newpc, &op1, &op2))
4583 return 0;
4584 /* op1 is the address to load from */
4585 if (!x86_load(cpu, op1, &tmp, mode/8))
4586 return 0;
4587 op2 = tmp;
4588 if (!x86_load(cpu, op1 + mode/8, &tmp, 2))
4589 return 0;
4590 reload_segment_descriptor(cpu, op==0xc4? X86_S_ES:X86_S_DS,
4591 tmp, &newpc);
4592 if (!modrm(cpu, MODRM_WRITE_R, mode, mode67,
4593 0, &instr_orig, NULL, &op1, &op2))
4594 return 0;
4595 } else if (op >= 0xc6 && op <= 0xc7) {
4596 switch ((*instr >> 3) & 0x7) {
4597 case 0: instr_orig = instr; /* MOV r/m, imm */
4598 success = modrm(cpu, MODRM_READ, mode, mode67,
4599 op == 0xc6? MODRM_EIGHTBIT : 0, &instr,
4600 &newpc, &op1, &op2);
4601 if (!success)
4602 return 0;
4603 imm = read_imm(&instr, &newpc, op == 0xc6? 8 : mode);
4604 op1 = imm;
4605 success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4606 op == 0xc6? MODRM_EIGHTBIT : 0, &instr_orig,
4607 NULL, &op1, &op2);
4608 if (!success)
4609 return 0;
4610 break;
4611 default:
4612 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4613 quiet_mode = 0;
4614 x86_cpu_disassemble_instr(cpu,
4615 really_orig_instr, 1|omode, 0, 0);
4616 cpu->running = 0;
4617 }
4618 } else if (op == 0xc8) { /* ENTER */
4619 uint64_t tmp_frame_ptr;
4620 int level;
4621 imm = read_imm(&instr, &newpc, 16);
4622 level = read_imm(&instr, &newpc, 8);
4623 if (!x86_push(cpu, cpu->cd.x86.r[X86_R_BP], mode))
4624 return 0;
4625 tmp_frame_ptr = cpu->cd.x86.r[X86_R_SP];
4626 if (level > 0) {
4627 while (level-- > 1) {
4628 uint64_t tmpword;
4629 cpu->cd.x86.r[X86_R_BP] = modify(
4630 cpu->cd.x86.r[X86_R_BP],
4631 cpu->cd.x86.r[X86_R_BP] - mode/8);
4632 cpu->cd.x86.cursegment = X86_S_SS;
4633 if (!x86_load(cpu, cpu->cd.x86.r[X86_R_BP],
4634 &tmpword, mode/8)) {
4635 fatal("TODO: load error inside"
4636 " ENTER\n");
4637 cpu->running = 0;
4638 return 0;
4639 }
4640 if (!x86_push(cpu, tmpword, mode)) {
4641 fatal("TODO: push error inside"
4642 " ENTER\n");
4643 cpu->running = 0;
4644 return 0;
4645 }
4646 }
4647 if (!x86_push(cpu, tmp_frame_ptr, mode))
4648 return 0;
4649 }
4650 cpu->cd.x86.r[X86_R_BP] = modify(cpu->cd.x86.r[X86_R_BP],
4651 tmp_frame_ptr);
4652 if (mode == 16)
4653 cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] &
4654 ~0xffff) | ((cpu->cd.x86.r[X86_R_SP] & 0xffff)
4655 - imm);
4656 else
4657 cpu->cd.x86.r[X86_R_SP] -= imm;
4658 } else if (op == 0xc9) { /* LEAVE */
4659 cpu->cd.x86.r[X86_R_SP] = cpu->cd.x86.r[X86_R_BP];
4660 if (!x86_pop(cpu, &tmp, mode)) {
4661 fatal("TODO: pop error inside LEAVE\n");
4662 cpu->running = 0;
4663 return 0;
4664 }
4665 cpu->cd.x86.r[X86_R_BP] = tmp;
4666 } else if (op == 0xca || op == 0xcb) { /* RET far */
4667 uint64_t tmp2;
4668 uint16_t old_tr = cpu->cd.x86.tr;
4669 if (op == 0xca)
4670 imm = read_imm(&instr, &newpc, 16);
4671 else
4672 imm = 0;
4673 if (!x86_pop(cpu, &tmp, mode))
4674 return 0;
4675 if (!x86_pop(cpu, &tmp2, mode)) {
4676 fatal("TODO: pop error inside RET\n");
4677 cpu->running = 0;
4678 return 0;
4679 }
4680 cpu->cd.x86.r[X86_R_SP] = modify(cpu->cd.x86.r[X86_R_SP],
4681 cpu->cd.x86.r[X86_R_SP] + imm);
4682 reload_segment_descriptor(cpu, X86_S_CS, tmp2, &newpc);
4683 if (cpu->cd.x86.tr == old_tr)
4684 newpc = tmp;
4685 } else if (op == 0xcc) { /* INT3 */
4686 cpu->pc = newpc;
4687 return x86_interrupt(cpu, 3, 0);
4688 } else if (op == 0xcd) { /* INT */
4689 imm = read_imm(&instr, &newpc, 8);
4690 cpu->pc = newpc;
4691 return x86_interrupt(cpu, imm, 0);
4692 } else if (op == 0xcf) { /* IRET */
4693 uint64_t tmp2, tmp3;
4694 uint16_t old_tr = cpu->cd.x86.tr;
4695 if (!x86_pop(cpu, &tmp, mode))
4696 return 0;
4697 if (!x86_pop(cpu, &tmp2, mode))
4698 return 0;
4699 if (!x86_pop(cpu, &tmp3, mode))
4700 return 0;
4701 debug("{ iret to 0x%04x:0x%08x }\n", (int)tmp2,(int)tmp);
4702 tmp2 &= 0xffff;
4703 /* TODO: only affect some bits? */
4704 if (mode == 16)
4705 cpu->cd.x86.rflags = (cpu->cd.x86.rflags & ~0xffff)
4706 | (tmp3 & 0xffff);
4707 else
4708 cpu->cd.x86.rflags = tmp3;
4709 /*
4710 * In protected mode, if we're switching back from, say, an
4711 * interrupt handler, then we should pop the old ss:esp too:
4712 */
4713 if (PROTECTED_MODE && (tmp2 & X86_PL_MASK) >
4714 (cpu->cd.x86.s[X86_S_CS] & X86_PL_MASK)) {
4715 uint64_t old_ss, old_esp;
4716 if (!x86_pop(cpu, &old_esp, mode))
4717 return 0;
4718 if (!x86_pop(cpu, &old_ss, mode))
4719 return 0;
4720 old_ss &= 0xffff;
4721
4722 printf(": : : BEFORE tmp=%016llx tmp2=%016llx tmp3=%016llx\n",
4723 (long long)tmp, (long long)tmp2, (long long)tmp3);
4724 /* x86_cpu_register_dump(cpu, 1, 1); */
4725
4726 reload_segment_descriptor(cpu, X86_S_SS, old_ss,
4727 &newpc);
4728 cpu->cd.x86.r[X86_R_SP] = old_esp;
4729
4730 /* printf(": : : AFTER\n");
4731 x86_cpu_register_dump(cpu, 1, 1); */
4732
4733 /* AFTER popping ss, check that the pl of
4734 the popped ss is the same as tmp2 (the new
4735 pl in cs)! */
4736 if ((old_ss & X86_PL_MASK) != (tmp2 & X86_PL_MASK))
4737 fatal("WARNING: iret: popped ss' pl = %i,"
4738 " different from cs' pl = %i\n",
4739 (int)(old_ss & X86_PL_MASK),
4740 (int)(tmp2 & X86_PL_MASK));
4741 }
4742 reload_segment_descriptor(cpu, X86_S_CS, tmp2, &newpc);
4743 if (cpu->cd.x86.tr == old_tr)
4744 newpc = tmp;
4745 } else if (op >= 0xd0 && op <= 0xd3) {
4746 int n = 1;
4747 instr_orig = instr;
4748 success = modrm(cpu, MODRM_READ, mode, mode67,
4749 op&1? 0 : MODRM_EIGHTBIT, &instr, &newpc, &op1, &op2);
4750 if (!success)
4751 return 0;
4752 if (op >= 0xd2)
4753 n = cpu->cd.x86.r[X86_R_CX];
4754 x86_shiftrotate(cpu, &op1, (*instr_orig >> 3) & 0x7,
4755 n, op&1? mode : 8);
4756 success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
4757 op&1? 0 : MODRM_EIGHTBIT, &instr_orig, NULL, &op1, &op2);
4758 if (!success)
4759 return 0;
4760 } else if (op == 0xd4) { /* AAM */
4761 int al = cpu->cd.x86.r[X86_R_AX] & 0xff;
4762 /* al should be in the range 0..81 */
4763 int high;
4764 imm = read_imm(&instr, &newpc, 8);
4765 if (imm == 0) {
4766 fatal("[ x86: \"aam 0\" ]\n");
4767 cpu->running = 0;
4768 } else {
4769 high = al / imm;
4770 al %= imm;
4771 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] &
4772 ~0xffff) | al | ((high & 0xff) << 8);
4773 x86_calc_flags(cpu, cpu->cd.x86.r[X86_R_AX],
4774 0, 8, CALCFLAGS_OP_XOR);
4775 }
4776 } else if (op == 0xd5) { /* AAD */
4777 int al = cpu->cd.x86.r[X86_R_AX] & 0xff;
4778 int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff;
4779 imm = read_imm(&instr, &newpc, 8);
4780 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & ~0xffff)
4781 | ((al + 10*ah) & 0xff);
4782 x86_calc_flags(cpu, cpu->cd.x86.r[X86_R_AX],
4783 0, 8, CALCFLAGS_OP_XOR);
4784 } else if (op == 0xd7) { /* XLAT */
4785 uint64_t addr = cpu->cd.x86.r[X86_R_BX];
4786 if (mode == 16)
4787 addr &= 0xffff;
4788 addr += (cpu->cd.x86.r[X86_R_AX] & 0xff);
4789 if (!x86_load(cpu, addr, &tmp, 1))
4790 return 0;
4791 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & ~0xff)
4792 | (tmp & 0xff);
4793 } else if (op == 0xd9) {
4794 int subop = (*instr >> 3) & 7;
4795 imm = *instr;
4796 if (subop == 5) { /* FLDCW mem16 */
4797 if (!modrm(cpu, MODRM_READ, 16, mode67, 0, &instr,
4798 &newpc, &op1, &op2))
4799 return 0;
4800 cpu->cd.x86.fpu_cw = op1;
4801 } else if (subop == 7) { /* FSTCW mem16 */
4802 op1 = cpu->cd.x86.fpu_cw;
4803 if (!modrm(cpu, MODRM_WRITE_RM, 16, mode67, 0, &instr,
4804 &newpc, &op1, &op2))
4805 return 0;
4806 } else {
4807 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4808 quiet_mode = 0;
4809 x86_cpu_disassemble_instr(cpu, really_orig_instr,
4810 1 | omode, 0, 0);
4811 cpu->running = 0;
4812 }
4813 } else if (op == 0xdb) {
4814 imm = *instr;
4815 if (imm == 0xe2) { /* FCLEX */
4816 read_imm(&instr, &newpc, 8);
4817 /* TODO: actually clear exceptions */
4818 } else if (imm == 0xe3) { /* FINIT */
4819 read_imm(&instr, &newpc, 8);
4820 /* TODO: actually init? */
4821 } else if (imm == 0xe4) { /* FSETPM */
4822 read_imm(&instr, &newpc, 8);
4823 } else {
4824 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4825 quiet_mode = 0;
4826 x86_cpu_disassemble_instr(cpu, really_orig_instr,
4827 1 | omode, 0, 0);
4828 cpu->running = 0;
4829 }
4830 } else if (op == 0xdd) {
4831 int subop = (*instr >> 3) & 7;
4832 imm = *instr;
4833 if (subop == 7) { /* FSTSW mem16 */
4834 op1 = cpu->cd.x86.fpu_sw;
4835 if (!modrm(cpu, MODRM_WRITE_RM, 16, mode67, 0, &instr,
4836 &newpc, &op1, &op2))
4837 return 0;
4838 } else {
4839 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4840 quiet_mode = 0;
4841 x86_cpu_disassemble_instr(cpu, really_orig_instr,
4842 1 | omode, 0, 0);
4843 cpu->running = 0;
4844 }
4845 } else if (op == 0xdf) {
4846 imm = *instr;
4847 if (imm == 0xe0) { /* FSTSW */
4848 read_imm(&instr, &newpc, 8);
4849 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] &
4850 ~0xffff) | (cpu->cd.x86.fpu_sw & 0xffff);
4851 } else {
4852 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
4853 quiet_mode = 0;
4854 x86_cpu_disassemble_instr(cpu, really_orig_instr,
4855 1 | omode, 0, 0);
4856 cpu->running = 0;
4857 }
4858 } else if (op == 0xe4 || op == 0xe5 /* IN imm,AL or AX/EAX */
4859 || op == 0x6c || op == 0x6d) { /* INSB or INSW/INSD */
4860 unsigned char databuf[8];
4861 int port_nr, ins = 0, len = 1, dir = 1;
4862 if (op == 0x6c || op == 0x6d) {
4863 port_nr = cpu->cd.x86.r[X86_R_DX] & 0xffff;
4864 ins = 1;
4865 } else
4866 port_nr = read_imm(&instr, &newpc, 8);
4867 if (op & 1)
4868 len = mode/8;
4869 if (cpu->cd.x86.rflags & X86_FLAGS_DF)
4870 dir = -1;
4871 do {
4872 cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE+port_nr,
4873 &databuf[0], len, MEM_READ, CACHE_NONE | PHYSICAL);
4874
4875 if (ins) {
4876 uint64_t addr = cpu->cd.x86.r[X86_R_DI];
4877 uint32_t value = databuf[0] + (databuf[1] << 8)
4878 + (databuf[2] << 16) + (databuf[3] << 24);
4879 if (mode67 == 16)
4880 addr &= 0xffff;
4881 if (mode67 == 32)
4882 addr &= 0xffffffff;
4883 cpu->cd.x86.cursegment = X86_S_ES;
4884 if (!x86_store(cpu, addr, value, len))
4885 return 0;
4886
4887 /* Advance (e)di: */
4888 if (mode67 == 16)
4889 cpu->cd.x86.r[X86_R_DI] =
4890 (cpu->cd.x86.r[X86_R_DI] & ~0xffff)
4891 | ((cpu->cd.x86.r[X86_R_DI]+len*dir)
4892 & 0xffff);
4893 else {
4894 cpu->cd.x86.r[X86_R_DI] += len*dir;
4895 if (mode67 == 32)
4896 cpu->cd.x86.r[X86_R_DI] &=
4897 0xffffffff;
4898 }
4899
4900 if (rep) {
4901 /* Decrement ecx: */
4902 if (mode67 == 16)
4903 cpu->cd.x86.r[X86_R_CX] =
4904 (cpu->cd.x86.r[X86_R_CX] &
4905 ~0xffff) | ((cpu->cd.x86.r[
4906 X86_R_CX] - 1) & 0xffff);
4907 else {
4908 cpu->cd.x86.r[X86_R_CX] --;
4909 cpu->cd.x86.r[X86_R_CX] &=
4910 0xffffffff;
4911 }
4912 if (mode67 == 16 && (cpu->cd.x86.r[
4913 X86_R_CX] & 0xffff) == 0)
4914 rep = 0;
4915 if (mode67 != 16 &&
4916 cpu->cd.x86.r[X86_R_CX] == 0)
4917 rep = 0;
4918 }
4919 } else {
4920 if (len == 1)
4921 cpu->cd.x86.r[X86_R_AX] =
4922 (cpu->cd.x86.r[X86_R_AX] &
4923 ~0xff) | databuf[0];
4924 else if (len == 2)
4925 cpu->cd.x86.r[X86_R_AX] =
4926 (cpu->cd.x86.r[X86_R_AX] & ~0xffff)
4927 | databuf[0] | (databuf[1] << 8);
4928 else if (len == 4)
4929 cpu->cd.x86.r[X86_R_AX] = databuf[0] |
4930 (databuf[1] << 8) | (databuf[2]
4931 << 16) | (databuf[3] << 24);
4932 }
4933 } while (rep);
4934 } else if (op == 0xe6 || op == 0xe7 /* OUT imm,AL or AX/EAX */
4935 || op == 0x6e || op == 0x6f) { /* OUTSB or OUTSW/OUTSD */
4936 unsigned char databuf[8];
4937 int port_nr, outs = 0, len = 1, dir = 1;
4938 if (op == 0x6e || op == 0x6f) {
4939 port_nr = cpu->cd.x86.r[X86_R_DX] & 0xffff;
4940 outs = 1;
4941 } else
4942 port_nr = read_imm(&instr, &newpc, 8);
4943 if (op & 1)
4944 len = mode/8;
4945 if (cpu->cd.x86.rflags & X86_FLAGS_DF)
4946 dir = -1;
4947 do {
4948 if (outs) {
4949 int i;
4950 uint64_t addr = cpu->cd.x86.r[X86_R_DI];
4951 uint64_t value;
4952 if (mode67 == 16)
4953 addr &= 0xffff;
4954 if (mode67 == 32)
4955 addr &= 0xffffffff;
4956 cpu->cd.x86.cursegment = X86_S_ES;
4957 if (!x86_load(cpu, addr, &value, len))
4958 return 0;
4959
4960 /* Advance (e)di: */
4961 if (mode67 == 16)
4962 cpu->cd.x86.r[X86_R_DI] =
4963 (cpu->cd.x86.r[X86_R_DI] & ~0xffff)
4964 | ((cpu->cd.x86.r[X86_R_DI]+len*dir)
4965 & 0xffff);
4966 else {
4967 cpu->cd.x86.r[X86_R_DI] += len*dir;
4968 if (mode67 == 32)
4969 cpu->cd.x86.r[X86_R_DI] &=
4970 0xffffffff;
4971 }
4972
4973 for (i=0; i<8; i++)
4974 databuf[i] = value >> (i*8);
4975
4976 if (rep) {
4977 /* Decrement ecx: */
4978 if (mode67 == 16)
4979 cpu->cd.x86.r[X86_R_CX] =
4980 (cpu->cd.x86.r[X86_R_CX] &
4981 ~0xffff) | ((cpu->cd.x86.r[
4982 X86_R_CX] - 1) & 0xffff);
4983 else {
4984 cpu->cd.x86.r[X86_R_CX] --;
4985 cpu->cd.x86.r[X86_R_CX] &=
4986 0xffffffff;
4987 }
4988 if (mode67 == 16 && (cpu->cd.x86.r[
4989 X86_R_CX] & 0xffff) == 0)
4990 rep = 0;
4991 if (mode67 != 16 &&
4992 cpu->cd.x86.r[X86_R_CX] == 0)
4993 rep = 0;
4994 }
4995 } else {
4996 int i;
4997 for (i=0; i<8; i++)
4998 databuf[i] = cpu->cd.x86.r[X86_R_AX]
4999 >> (i*8);
5000 }
5001
5002 cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE+port_nr,
5003 &databuf[0], len, MEM_WRITE, CACHE_NONE | PHYSICAL);
5004 } while (rep);
5005 } else if (op == 0xe8 || op == 0xe9) { /* CALL/JMP near */
5006 imm = read_imm(&instr, &newpc, mode);
5007 if (mode == 16)
5008 imm = (int16_t)imm;
5009 if (mode == 32)
5010 imm = (int32_t)imm;
5011 if (op == 0xe8) {
5012 if (!x86_push(cpu, newpc, mode))
5013 return 0;
5014 }
5015 newpc += imm;
5016 } else if (op == 0xea) { /* JMP seg:ofs */
5017 uint16_t old_tr = cpu->cd.x86.tr;
5018 imm = read_imm(&instr, &newpc, mode);
5019 imm2 = read_imm(&instr, &newpc, 16);
5020 reload_segment_descriptor(cpu, X86_S_CS, imm2, &newpc);
5021 if (cpu->cd.x86.tr == old_tr)
5022 newpc = imm;
5023 } else if ((op >= 0xe0 && op <= 0xe3) || op == 0xeb) { /* LOOP,JMP */
5024 int perform_jump = 0;
5025 imm = read_imm(&instr, &newpc, 8);
5026 switch (op) {
5027 case 0xe0: /* loopnz */
5028 case 0xe1: /* loopz */
5029 case 0xe2: /* loop */
5030 /* NOTE: address size attribute, not operand size? */
5031 if (mode67 == 16)
5032 cpu->cd.x86.r[X86_R_CX] = (~0xffff &
5033 cpu->cd.x86.r[X86_R_CX]) |
5034 ((cpu->cd.x86.r[X86_R_CX] - 1) & 0xffff);
5035 else
5036 cpu->cd.x86.r[X86_R_CX] --;
5037 if (mode67 == 16 && (cpu->cd.x86.r[X86_R_CX] &
5038 0xffff) != 0)
5039 perform_jump = 1;
5040 if (mode67 == 32 && cpu->cd.x86.r[X86_R_CX] != 0)
5041 perform_jump = 1;
5042 if (op == 0xe0 && cpu->cd.x86.rflags & X86_FLAGS_ZF)
5043 perform_jump = 0;
5044 if (op == 0xe1 && (!cpu->cd.x86.rflags & X86_FLAGS_ZF))
5045 perform_jump = 0;
5046 break;
5047 case 0xe3: /* jcxz/jecxz */
5048 if (mode67 == 16 && (cpu->cd.x86.r[X86_R_CX] & 0xffff)
5049 == 0)
5050 perform_jump = 1;
5051 if (mode67 != 16 && (cpu->cd.x86.r[X86_R_CX] &
5052 0xffffffffULL) == 0)
5053 perform_jump = 1;
5054 break;
5055 case 0xeb: /* jmp */
5056 perform_jump = 1;
5057 break;
5058 }
5059 if (perform_jump)
5060 newpc += (signed char)imm;
5061 } else if (op == 0xec || op == 0xed) { /* IN DX,AL or AX/EAX */
5062 unsigned char databuf[8];
5063 cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE +
5064 (cpu->cd.x86.r[X86_R_DX] & 0xffff), &databuf[0],
5065 op == 0xec? 1 : (mode/8), MEM_READ, CACHE_NONE | PHYSICAL);
5066 if (op == 0xec)
5067 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] &
5068 ~0xff) | databuf[0];
5069 else if (op == 0xed && mode == 16)
5070 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] &
5071 ~0xffff) | databuf[0] | (databuf[1] << 8);
5072 else if (op == 0xed && mode == 32)
5073 cpu->cd.x86.r[X86_R_AX] = databuf[0] |
5074 (databuf[1] << 8) | (databuf[2] << 16) |
5075 (databuf[3] << 24);
5076 } else if (op == 0xee || op == 0xef) { /* OUT DX,AL or AX/EAX */
5077 unsigned char databuf[8];
5078 databuf[0] = cpu->cd.x86.r[X86_R_AX];
5079 if (op == 0xef) {
5080 databuf[1] = cpu->cd.x86.r[X86_R_AX] >> 8;
5081 if (mode >= 32) {
5082 databuf[2] = cpu->cd.x86.r[X86_R_AX] >> 16;
5083 databuf[3] = cpu->cd.x86.r[X86_R_AX] >> 24;
5084 }
5085 }
5086 cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE +
5087 (cpu->cd.x86.r[X86_R_DX] & 0xffff), &databuf[0],
5088 op == 0xee? 1 : (mode/8), MEM_WRITE, CACHE_NONE | PHYSICAL);
5089 } else if (op == 0xf4) { /* HLT */
5090 cpu->cd.x86.halted = 1;
5091 } else if (op == 0xf5) { /* CMC */
5092 cpu->cd.x86.rflags ^= X86_FLAGS_CF;
5093 } else if (op == 0xf8) { /* CLC */
5094 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
5095 } else if (op == 0xf9) { /* STC */
5096 cpu->cd.x86.rflags |= X86_FLAGS_CF;
5097 } else if (op == 0xfa) { /* CLI */
5098 cpu->cd.x86.rflags &= ~X86_FLAGS_IF;
5099 } else if (op == 0xfb) { /* STI */
5100 cpu->cd.x86.rflags |= X86_FLAGS_IF;
5101 } else if (op == 0xfc) { /* CLD */
5102 cpu->cd.x86.rflags &= ~X86_FLAGS_DF;
5103 } else if (op == 0xfd) { /* STD */
5104 cpu->cd.x86.rflags |= X86_FLAGS_DF;
5105 } else if (op == 0xf6 || op == 0xf7) { /* MUL, DIV etc */
5106 uint64_t res;
5107 int unsigned_op = 1;
5108 switch ((*instr >> 3) & 0x7) {
5109 case 0: /* test */
5110 success = modrm(cpu, MODRM_READ, mode, mode67,
5111 op == 0xf6? MODRM_EIGHTBIT : 0, &instr,
5112 &newpc, &op1, &op2);
5113 if (!success)
5114 return 0;
5115 op2 = read_imm(&instr, &newpc, op==0xf6? 8 : mode);
5116 op1 &= op2;
5117 x86_calc_flags(cpu, op1, 0, op==0xf6? 8 : mode,
5118 CALCFLAGS_OP_XOR);
5119 break;
5120 case 2: /* not */
5121 case 3: /* neg */
5122 instr_orig = instr;
5123 success = modrm(cpu, MODRM_READ, mode, mode67,
5124 op == 0xf6? MODRM_EIGHTBIT : 0, &instr,
5125 &newpc, &op1, &op2);
5126 if (!success)
5127 return 0;
5128 switch ((*instr_orig >> 3) & 0x7) {
5129 case 2: op1 ^= 0xffffffffffffffffULL; break;
5130 case 3: x86_calc_flags(cpu, 0, op1,
5131 op == 0xf6? 8 : mode, CALCFLAGS_OP_SUB);
5132 op1 = 0 - op1;
5133 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
5134 if (op1 != 0)
5135 cpu->cd.x86.rflags |= X86_FLAGS_CF;
5136 break;
5137 }
5138 success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
5139 op == 0xf6? MODRM_EIGHTBIT : 0, &instr_orig,
5140 NULL, &op1, &op2);
5141 if (!success)
5142 return 0;
5143 break;
5144 case 5: /* imul */
5145 unsigned_op = 0;
5146 case 4: /* mul */
5147 success = modrm(cpu, MODRM_READ, mode, mode67,
5148 op == 0xf6? MODRM_EIGHTBIT : 0, &instr,
5149 &newpc, &op1, &op2);
5150 if (!success)
5151 return 0;
5152 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
5153 cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
5154 if (op == 0xf6) {
5155 if (unsigned_op)
5156 res = (cpu->cd.x86.r[X86_R_AX] & 0xff)
5157 * (op1 & 0xff);
5158 else
5159 res = (int16_t)(signed char)(cpu->cd.
5160 x86.r[X86_R_AX] & 0xff) * (int16_t)
5161 (signed char)(op1 & 0xff);
5162 cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[
5163 X86_R_AX] & ~0xffff) | (res & 0xffff);
5164 if ((res & 0xffff) >= 0x100)
5165 cpu->cd.x86.rflags |= X86_FLAGS_CF
5166 | X86_FLAGS_OF;
5167 } else if (mode == 16) {
5168 if (unsigned_op)
5169 res = (cpu->cd.x86.r[X86_R_AX] & 0xffff)
5170 * (op1 & 0xffff);
5171 else
5172 res = (int32_t)(int16_t)(cpu->cd.x86.r[
5173 X86_R_AX] & 0xffff) * (int32_t)
5174 (int16_t)(op1 & 0xffff);
5175 cpu->cd.x86.r[X86_R_AX] = modify(cpu->
5176 cd.x86.r[X86_R_AX], res & 0xffff);
5177 cpu->cd.x86.r[X86_R_DX] = modify(cpu->cd.x86
5178 .r[X86_R_DX], (res>>16) & 0xffff);
5179 if ((res & 0xffffffff) >= 0x10000)
5180 cpu->cd.x86.rflags |= X86_FLAGS_CF
5181 | X86_FLAGS_OF;
5182 } else if (mode == 32) {
5183 if (unsigned_op)
5184 res = (cpu->cd.x86.r[X86_R_AX] &
5185 0xffffffff) * (op1 & 0xffffffff);
5186 else
5187 res = (int64_t)(int32_t)(cpu->cd.x86.r[
5188 X86_R_AX] & 0xffffffff) * (int64_t)
5189 (int32_t)(op1 & 0xffffffff);
5190 cpu->cd.x86.r[X86_R_AX] = res & 0xffffffff;
5191 cpu->cd.x86.r[X86_R_DX] = (res >> 32) &
5192 0xffffffff;
5193 if (res >= 0x100000000ULL)
5194 cpu->cd.x86.rflags |= X86_FLAGS_CF
5195 | X86_FLAGS_OF;
5196 }
5197 break;
5198 case 7: /* idiv */
5199 unsigned_op = 0;
5200 case 6: /* div */
5201 success = modrm(cpu, MODRM_READ, mode, mode67,
5202 op == 0xf6? MODRM_EIGHTBIT : 0, &instr,
5203 &newpc, &op1, &op2);
5204 if (!success)
5205 return 0;
5206 if (op1 == 0) {
5207 fatal("TODO: division by zero\n");
5208 cpu->running = 0;
5209 break;
5210 }
5211 if (op == 0xf6) {
5212 int al, ah;
5213 if (unsigned_op) {
5214 al = (cpu->cd.x86.r[X86_R_AX] &
5215 0xffff) / op1;
5216 ah = (cpu->cd.x86.r[X86_R_AX] &
5217 0xffff) % op1;
5218 } else {
5219 al = (int16_t)(cpu->cd.x86.r[
5220 X86_R_AX] & 0xffff) / (int16_t)op1;
5221 ah = (int16_t)(cpu->cd.x86.r[
5222 X86_R_AX] & 0xffff) % (int16_t)op1;
5223 }
5224 cpu->cd.x86.r[X86_R_AX] = modify(
5225 cpu->cd.x86.r[X86_R_AX], (ah<<8) + al);
5226 } else if (mode == 16) {
5227 uint64_t a = (cpu->cd.x86.r[X86_R_AX] & 0xffff)
5228 + ((cpu->cd.x86.r[X86_R_DX] & 0xffff)<<16);
5229 uint32_t ax, dx;
5230 if (unsigned_op) {
5231 ax = a / op1, dx = a % op1;
5232 } else {
5233 ax = (int32_t)a / (int32_t)op1;
5234 dx = (int32_t)a % (int32_t)op1;
5235 }
5236 cpu->cd.x86.r[X86_R_AX] = modify(
5237 cpu->cd.x86.r[X86_R_AX], ax);
5238 cpu->cd.x86.r[X86_R_DX] = modify(
5239 cpu->cd.x86.r[X86_R_DX], dx);
5240 } else if (mode == 32) {
5241 uint64_t a = (cpu->cd.x86.r[X86_R_AX] &
5242 0xffffffffULL) + ((cpu->cd.x86.r[
5243 X86_R_DX] & 0xffffffffULL) << 32);
5244 uint32_t eax, edx;
5245 if (unsigned_op) {
5246 eax = (uint64_t)a / (uint32_t)op1;
5247 edx = (uint64_t)a % (uint32_t)op1;
5248 } else {
5249 eax = (int64_t)a / (int32_t)op1;
5250 edx = (int64_t)a % (int32_t)op1;
5251 }
5252 cpu->cd.x86.r[X86_R_AX] = eax;
5253 cpu->cd.x86.r[X86_R_DX] = edx;
5254 }
5255 break;
5256 default:
5257 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr);
5258 quiet_mode = 0;
5259 x86_cpu_disassemble_instr(cpu,
5260 really_orig_instr, 1|omode, 0, 0);
5261 cpu->running = 0;
5262 }
5263 } else if (op == 0xfe || op == 0xff) { /* INC, DEC etc */
5264 int old_cf;
5265 switch ((*instr >> 3) & 0x7) {
5266 case 0:
5267 case 1: instr_orig = instr;
5268 success = modrm(cpu, MODRM_READ, mode, mode67,
5269 op == 0xfe? MODRM_EIGHTBIT : 0, &instr,
5270 &newpc, &op1, &op2);
5271 if (!success)
5272 return 0;
5273 old_cf = cpu->cd.x86.rflags & X86_FLAGS_CF;
5274 switch ((*instr_orig >> 3) & 0x7) {
5275 case 0: x86_calc_flags(cpu, op1, 1, op==0xfe? 8 : mode,
5276 CALCFLAGS_OP_ADD);
5277 op1 ++;
5278 break; /* inc */
5279 case 1: x86_calc_flags(cpu, op1, 1, op==0xfe? 8 : mode,
5280 CALCFLAGS_OP_SUB);
5281 op1 --;
5282 break; /* dec */
5283 }
5284 success = modrm(cpu, MODRM_WRITE_RM, mode, mode67,
5285 op == 0xfe? MODRM_EIGHTBIT : 0, &instr_orig,
5286 NULL, &op1, &op2);
5287 if (!success)
5288 return 0;
5289 /* preserve CF: */
5290 cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
5291 cpu->cd.x86.rflags |= old_cf;
5292 break;
5293 case 2: if (op == 0xfe) {
5294 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op,
5295 *instr);
5296 quiet_mode = 0;
5297 x86_cpu_disassemble_instr(cpu,
5298 really_orig_instr, 1|omode, 0, 0);
5299 cpu->running = 0;
5300 } else {
5301 success = modrm(cpu, MODRM_READ, mode, mode67,
5302 0, &instr, &newpc, &op1, &op2);
5303 if (!success)
5304 return 0;
5305 /* Push return [E]IP */
5306 if (!x86_push(cpu, newpc, mode))
5307 return 0;
5308 newpc = op1;
5309 }
5310 break;
5311 case 3: if (op == 0xfe) {
5312 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op,
5313 *instr);
5314 quiet_mode = 0;
5315 x86_cpu_disassemble_instr(cpu,
5316 really_orig_instr, 1|omode, 0, 0);
5317 cpu->running = 0;
5318 } else {
5319 uint16_t old_tr = cpu->cd.x86.tr;
5320 uint64_t tmp1, tmp2;
5321 success = modrm(cpu, MODRM_READ, mode, mode67,
5322 MODRM_JUST_GET_ADDR, &instr,
5323 &newpc, &op1, &op2);
5324 if (!success)
5325 return 0;
5326 /* Load a far address from op1: */
5327 if (!x86_load(cpu, op1, &tmp1, mode/8))
5328 return 0;
5329 if (!x86_load(cpu, op1 + (mode/8), &tmp2, 2))
5330 return 0;
5331 /* Push return CS:[E]IP */
5332 if (!x86_push(cpu, cpu->cd.x86.s[X86_S_CS],
5333 mode))
5334 return 0;
5335 if (!x86_push(cpu, newpc, mode)) {
5336 fatal("TODO: push failed, call "
5337 "far indirect?\n");
5338 cpu->running = 0;
5339 return 0;
5340 }
5341 reload_segment_descriptor(cpu, X86_S_CS,
5342 tmp2, &newpc);
5343 if (cpu->cd.x86.tr == old_tr)
5344 newpc = tmp1;
5345 }
5346 break;
5347 case 4: if (op == 0xfe) {
5348 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op,
5349 *instr);
5350 quiet_mode = 0;
5351 x86_cpu_disassemble_instr(cpu,
5352 really_orig_instr, 1|omode, 0, 0);
5353 cpu->running = 0;
5354 } else {
5355 success = modrm(cpu, MODRM_READ, mode, mode67,
5356 0, &instr, &newpc, &op1, &op2);
5357 if (!success)
5358 return 0;
5359 newpc = op1;
5360 }
5361 break;
5362 case 5: if (op == 0xfe) {
5363 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op,
5364 *instr);
5365 quiet_mode = 0;
5366 x86_cpu_disassemble_instr(cpu,
5367 really_orig_instr, 1|omode, 0, 0);
5368 cpu->running = 0;
5369 } else {
5370 uint16_t old_tr = cpu->cd.x86.tr;
5371 uint64_t tmp1, tmp2;
5372 success = modrm(cpu, MODRM_READ, mode, mode67,
5373 MODRM_JUST_GET_ADDR, &instr,
5374 &newpc, &op1, &op2);
5375 if (!success)
5376 return 0;
5377 /* Load a far address from op1: */
5378 if (!x86_load(cpu, op1, &tmp1, mode/8))
5379 return 0;
5380 if (!x86_load(cpu, op1 + (mode/8), &tmp2, 2))
5381 return 0;
5382 reload_segment_descriptor(cpu, X86_S_CS,
5383 tmp2, &newpc);
5384 if (cpu->cd.x86.tr == old_tr)
5385 newpc = tmp1;
5386 }
5387 break;
5388 case 6: if (op == 0xfe) {
5389 fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op,
5390 *instr);
5391 quiet_mode = 0;
5392 x86_cpu_disassemble_instr(cpu,
5393