/[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

Annotation of /trunk/src/cpus/cpu_x86.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (hide annotations)
Mon Oct 8 16:20:10 2007 UTC (12 years, 9 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 dpavlin 14 /*
2 dpavlin 24 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 dpavlin 14 *
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 dpavlin 26 * $Id: cpu_x86.c,v 1.16 2006/06/24 21:47:23 debug Exp $
29 dpavlin 14 *
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 dpavlin 26 cpu->translate_v2p = x86_translate_v2p;
99 dpavlin 20
100 dpavlin 14 /* 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 dpavlin 20 cpu->cd.x86.cursegment = X86_S_CS;
115 dpavlin 14
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 dpavlin 20 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 dpavlin 14 /* 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 dpavlin 22 for (j=0; j<10-(int)strlen(models[i].name); j++)
172 dpavlin 14 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 dpavlin 24 if (LONG_MODE) {
193     /* 64-bit long mode: */
194 dpavlin 14 symbol = get_symbol_name(&cpu->machine->symbol_context,
195     cpu->pc, &offset);
196    
197 dpavlin 24 debug("cpu%i: rip = 0x%016"PRIx64, x, cpu->pc);
198 dpavlin 14 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
199    
200 dpavlin 24 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 dpavlin 14 } else {
232 dpavlin 24 /* 32-bit protected mode: */
233 dpavlin 14 symbol = get_symbol_name(&cpu->machine->symbol_context,
234     cpu->pc, &offset);
235    
236 dpavlin 24 debug("cpu%i: eip=0x%08"PRIx32, x, (uint32_t)cpu->pc);
237 dpavlin 14 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
238    
239 dpavlin 24 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 dpavlin 14 }
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 dpavlin 24 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 dpavlin 14 }
298    
299     if (PROTECTED_MODE) {
300     /* Protected mode: */
301 dpavlin 24 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 dpavlin 14 }
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 dpavlin 22 uint32_t read_imm(unsigned char **instrp, uint64_t *newpcp,
521 dpavlin 14 int mode)
522     {
523     return read_imm_common(instrp, newpcp, mode, 0);
524     }
525    
526    
527 dpavlin 22 void print_csip(struct cpu *cpu)
528 dpavlin 14 {
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 dpavlin 24 * 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 dpavlin 14 * 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 dpavlin 24 fatal("WARNING: tr_limit = 0x%"PRIx16", must be at least "
695     "0x67!\n", (uint16_t)cpu->cd.x86.tr_limit);
696 dpavlin 14
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 dpavlin 22 uint64_t base, limit, table_base;
753     int64_t table_limit;
754 dpavlin 14
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 dpavlin 24 int running, uint64_t dumpaddr)
1533 dpavlin 14 {
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 dpavlin 22 void x86_cpuid(struct cpu *cpu)
2469 dpavlin 14 {
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 dpavlin 22 if (nr * 8 > (int)cpu->cd.x86.idtr_limit) {
2637 dpavlin 14 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 dpavlin 22 if (nr * 4 > (int)cpu->cd.x86.idtr_limit) {
2779 dpavlin 14 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 dpavlin 26 #define TRANSLATE_ADDRESS x86_translate_v2p
3166 dpavlin 14 #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