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

Contents of /upstream/0.3.6.2/src/cpus/cpu_x86.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26