/[gxemul]/upstream/0.3.3.1/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 /upstream/0.3.3.1/src/cpu_x86.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26