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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26