/[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 10 - (show annotations)
Mon Oct 8 16:18:27 2007 UTC (12 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 154404 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.815 2005/06/27 23:04:35 debug Exp $
20050617	Experimenting some more with netbooting OpenBSD/sgi. Adding
		a hack which allows emulated ethernet networks to be
		distributed across multiple emulator processes.
20050618	Minor updates (documentation, dummy YAMON emulation, etc).
20050620	strcpy/strcat -> strlcpy/strlcat updates.
		Some more progress on evbmips (Malta).
20050621	Adding a section to doc/configfiles.html about ethernet
		emulation across multiple hosts.
		Beginning the work on the ARM translation engine (using the
		dynamic-but-not-binary translation method).
		Fixing a bintrans bug: 0x9fc00000 should always be treated as
		PROM area, just as 0xbfc00000 is.
		Minor progress on Malta emulation (the PCI-ISA bus).
20050622	NetBSD/evbmips can now be installed (using another emulated
		machine) and run (including userland and so on). :-)
		Spliting up the bintrans haddr_entry field into two (one for
		read, one for write). Probably not much of a speed increase,
		though.
		Updating some NetBSD 2.0 -> 2.0.2 in the documentation.
20050623	Minor updates (documentation, the TODO file, etc).
		gzipped kernels are now always automagically gunzipped when
		loaded.
20050624	Adding a dummy Playstation Portable (PSP) mode, just barely
		enough to run Hello World (in weird colors :-).
		Removing the -b command line option; old bintrans is enabled
		by default instead. It makes more sense.
		Trying to finally fix the non-working performance measurement
		thing (instr/second etc).
20050625	Continuing on the essential basics for ARM emulation. Two
		instructions seem to work, a branch and a simple "mov". (The
		mov arguments are not correct yet.) Performance is definitely
		reasonable.
		Various other minor updates.
		Adding the ARM "bl" instruction.
		Adding support for combining multiple ARM instructions into one
		function call. ("mov" + "mov" is the only one implemented so
		far, but it seems to work.)
		Cleaning up some IP32 interrupt things (crime/mace); disabling
		the PS/2 keyboard controller on IP32, so that NetBSD/sgimips
		boots into userland again.
20050626	Finally! NetBSD/sgimips netboots. Adding instructions to
		doc/guestoses.html on how to set up an nfs server etc.
		Various other minor fixes.
		Playstation Portable ".pbp" files can now be used directly.
		(The ELF part of the .pbp is extracted transparently.)
		Converting some sprintf -> snprintf.
		Adding some more instructions to the ARM disassembler.
20050627	More ARM updates. Adding some simple ldr(b), str(b),
		cmps, and conditional branch instructions, enough to run
		a simple Hello World program.
		All ARM instructions are now inlined/generated for all possible
		condition codes.
		Adding add and sub, and more load/store instructions.
		Removing dummy files: cpu_alpha.c, cpu_hppa.c, and cpu_sparc.c.
		Some minor documentation updates; preparing for a 0.3.4
		release. Updating some URLs.

==============  RELEASE 0.3.4  ==============


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