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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (show annotations)
Mon Oct 8 16:20:10 2007 UTC (11 years, 11 months ago) by dpavlin
File MIME type: text/plain
File size: 87299 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1264 2006/06/25 11:08:04 debug Exp $
20060624	Replacing the error-prone machine type initialization stuff
		with something more reasonable.
		Finally removing the old "cpu_run" kludge; moving around stuff
		in machine.c and emul.c to better suit the dyntrans system.
		Various minor dyntrans cleanups (renaming translate_address to
		translate_v2p, and experimenting with template physpages).
20060625	Removing the speed hack which separated the vph entries into
		two halves (code vs data); things seem a lot more stable now.
		Minor performance hack: R2000/R3000 cache isolation now only
		clears address translations when going into isolation, not
		when going out of it.
		Fixing the MIPS interrupt problems by letting mtc0 immediately
		cause interrupts.

==============  RELEASE 0.4.0.1  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26