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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26