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

Annotation of /trunk/src/cpu_x86.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (hide annotations)
Mon Oct 8 16:18:00 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 23561 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

==============  RELEASE 0.3.2  ==============


1 dpavlin 4 /*
2     * Copyright (C) 2005 Anders Gavare. All rights reserved.
3     *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28     * $Id: cpu_x86.c,v 1.24 2005/04/20 02:05:56 debug Exp $
29     *
30     * x86 (and amd64) CPU emulation.
31     *
32     *
33     * TODO: Pretty much everything.
34     *
35     * See http://www.amd.com/us-en/Processors/DevelopWithAMD/
36     * 0,,30_2252_875_7044,00.html for more info on AMD64.
37     *
38     * http://www.cs.ucla.edu/~kohler/class/04f-aos/ref/i386/appa.htm has a
39     * nice overview of the standard i386 opcodes.
40     */
41    
42     #include <stdio.h>
43     #include <stdlib.h>
44     #include <string.h>
45     #include <ctype.h>
46    
47     #include "misc.h"
48    
49    
50     #ifndef ENABLE_X86
51    
52    
53     #include "cpu_x86.h"
54    
55    
56     /*
57     * x86_cpu_family_init():
58     *
59     * Bogus, when ENABLE_X86 isn't defined.
60     */
61     int x86_cpu_family_init(struct cpu_family *fp)
62     {
63     return 0;
64     }
65    
66    
67     #else /* ENABLE_X86 */
68    
69    
70     #include "cpu.h"
71     #include "cpu_x86.h"
72     #include "machine.h"
73     #include "memory.h"
74     #include "symbol.h"
75    
76    
77     extern volatile int single_step;
78     extern int old_show_trace_tree;
79     extern int old_instruction_trace;
80     extern int old_quiet_mode;
81     extern int quiet_mode;
82    
83    
84     static struct x86_model models[] = x86_models;
85     static char *reg_names[N_X86_REGS] = x86_reg_names;
86     static char *seg_names[N_X86_SEGS] = x86_seg_names;
87     static char *cond_names[N_X86_CONDS] = x86_cond_names;
88    
89    
90     /*
91     * x86_cpu_new():
92     *
93     * Create a new x86 cpu object.
94     */
95     struct cpu *x86_cpu_new(struct memory *mem, struct machine *machine,
96     int cpu_id, char *cpu_type_name)
97     {
98     int i = 0;
99     struct cpu *cpu;
100    
101     if (cpu_type_name == NULL)
102     return NULL;
103    
104     /* Try to find a match: */
105     while (models[i].model_number != 0) {
106     if (strcasecmp(cpu_type_name, models[i].name) == 0)
107     break;
108     i++;
109     }
110    
111     if (models[i].name == NULL)
112     return NULL;
113    
114     cpu = malloc(sizeof(struct cpu));
115     if (cpu == NULL) {
116     fprintf(stderr, "out of memory\n");
117     exit(1);
118     }
119    
120     memset(cpu, 0, sizeof(struct cpu));
121     cpu->memory_rw = x86_memory_rw;
122     cpu->name = cpu_type_name;
123     cpu->mem = mem;
124     cpu->machine = machine;
125     cpu->cpu_id = cpu_id;
126     cpu->byte_order = EMUL_LITTLE_ENDIAN;
127     cpu->bootstrap_cpu_flag = 0;
128     cpu->running = 0;
129    
130     cpu->cd.x86.model = models[i];
131     cpu->cd.x86.mode = 32;
132     cpu->cd.x86.bits = 32;
133    
134     if (cpu->cd.x86.model.model_number == X86_MODEL_AMD64)
135     cpu->cd.x86.bits = 64;
136    
137     cpu->cd.x86.r[X86_R_SP] = 0xff0;
138    
139     /* Only show name and caches etc for CPU nr 0 (in SMP machines): */
140     if (cpu_id == 0) {
141     debug("%s", cpu->name);
142     }
143    
144     return cpu;
145     }
146    
147    
148     /*
149     * x86_cpu_dumpinfo():
150     */
151     void x86_cpu_dumpinfo(struct cpu *cpu)
152     {
153     debug(" (%i-bit)", cpu->cd.x86.bits);
154     debug(", currently in %i-bit mode", cpu->cd.x86.mode);
155     debug("\n");
156     }
157    
158    
159     /*
160     * x86_cpu_list_available_types():
161     *
162     * Print a list of available x86 CPU types.
163     */
164     void x86_cpu_list_available_types(void)
165     {
166     int i = 0, j;
167    
168     while (models[i].model_number != 0) {
169     debug("%s", models[i].name);
170    
171     for (j=0; j<10-strlen(models[i].name); j++)
172     debug(" ");
173     i++;
174     if ((i % 6) == 0 || models[i].name == NULL)
175     debug("\n");
176     }
177     }
178    
179    
180     /*
181     * x86_cpu_register_dump():
182     *
183     * Dump cpu registers in a relatively readable format.
184     * (gprs and coprocs are mostly useful for the MIPS version of this function.)
185     */
186     void x86_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
187     {
188     char *symbol;
189     uint64_t offset;
190     int i, x = cpu->cpu_id;
191    
192     if (cpu->cd.x86.mode == 16) {
193     debug("cpu%i: cs:ip = 0x%04x:0x%04x\n", x,
194     cpu->cd.x86.s[X86_S_CS], (int)cpu->pc);
195    
196     debug("cpu%i: ax = 0x%04x bx = 0x%04x cx = 0x%04x dx = "
197     "0x%04x\n", x,
198     (int)cpu->cd.x86.r[X86_R_AX], (int)cpu->cd.x86.r[X86_R_BX],
199     (int)cpu->cd.x86.r[X86_R_CX], (int)cpu->cd.x86.r[X86_R_DX]);
200     debug("cpu%i: si = 0x%04x di = 0x%04x bp = 0x%04x sp = "
201     "0x%04x\n", x,
202     (int)cpu->cd.x86.r[X86_R_SI], (int)cpu->cd.x86.r[X86_R_DI],
203     (int)cpu->cd.x86.r[X86_R_BP], (int)cpu->cd.x86.r[X86_R_SP]);
204    
205     debug("cpu%i: ds = 0x%04x es = 0x%04x ss = 0x%04x flags "
206     "= 0x%04x\n", x,
207     (int)cpu->cd.x86.s[X86_S_DS], (int)cpu->cd.x86.s[X86_S_ES],
208     (int)cpu->cd.x86.s[X86_S_SS], (int)cpu->cd.x86.rflags);
209     } else if (cpu->cd.x86.mode == 32) {
210     symbol = get_symbol_name(&cpu->machine->symbol_context,
211     cpu->pc, &offset);
212    
213     debug("cpu%i: eip=0x", x);
214     debug("%08x", (int)cpu->pc);
215     debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
216    
217     debug("cpu%i: eax=0x%08x ebx=0x%08x ecx=0x%08x edx="
218     "0x%08x\n", x,
219     (int)cpu->cd.x86.r[X86_R_AX], (int)cpu->cd.x86.r[X86_R_BX],
220     (int)cpu->cd.x86.r[X86_R_CX], (int)cpu->cd.x86.r[X86_R_DX]);
221     debug("cpu%i: esi=0x%08x edi=0x%08x ebp=0x%08x esp="
222     "0x%08x\n", x,
223     (int)cpu->cd.x86.r[X86_R_SI], (int)cpu->cd.x86.r[X86_R_DI],
224     (int)cpu->cd.x86.r[X86_R_BP], (int)cpu->cd.x86.r[X86_R_SP]);
225     } else {
226     /* 64-bit */
227     symbol = get_symbol_name(&cpu->machine->symbol_context,
228     cpu->pc, &offset);
229    
230     debug("cpu%i: rip = 0x", x);
231     debug("%016llx", (long long)cpu->pc);
232     debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
233    
234     for (i=0; i<N_X86_REGS; i++) {
235     if ((i & 1) == 0)
236     debug("cpu%i:", x);
237     debug(" r%s = 0x%016llx", reg_names[i],
238     (long long)cpu->cd.x86.r[i]);
239     if ((i & 1) == 1)
240     debug("\n");
241     }
242     }
243    
244     if (cpu->cd.x86.mode >= 32) {
245     debug("cpu%i: cs=0x%04x ds=0x%04x es=0x%04x "
246     "fs=0x%04x gs=0x%04x ss=0x%04x\n", x,
247     (int)cpu->cd.x86.s[X86_S_CS], (int)cpu->cd.x86.s[X86_S_DS],
248     (int)cpu->cd.x86.s[X86_S_ES], (int)cpu->cd.x86.s[X86_S_FS],
249     (int)cpu->cd.x86.s[X86_S_GS], (int)cpu->cd.x86.s[X86_S_SS]);
250     }
251    
252     if (cpu->cd.x86.mode == 32) {
253     debug("cpu%i: cr0 = 0x%08x cr3 = 0x%08x eflags = 0x%08x\n",
254     x, (int)cpu->cd.x86.cr[0],
255     (int)cpu->cd.x86.cr[3], (int)cpu->cd.x86.rflags);
256     }
257    
258     if (cpu->cd.x86.mode == 64) {
259     debug("cpu%i: cr0 = 0x%016llx cr3 = 0x%016llx\n", x,
260     "0x%016llx\n", x, (long long)cpu->cd.x86.cr[0], (long long)
261     cpu->cd.x86.cr[3]);
262     debug("cpu%i: rflags = 0x%016llx\n", x,
263     (long long)cpu->cd.x86.rflags);
264     }
265     }
266    
267    
268     /*
269     * x86_cpu_register_match():
270     */
271     void x86_cpu_register_match(struct machine *m, char *name,
272     int writeflag, uint64_t *valuep, int *match_register)
273     {
274     int cpunr = 0;
275    
276     /* CPU number: */
277    
278     /* TODO */
279    
280     /* Register name: */
281     if (strcasecmp(name, "pc") == 0 || strcasecmp(name, "ip") == 0
282     || strcasecmp(name, "eip") == 0) {
283     if (writeflag) {
284     m->cpus[cpunr]->pc = *valuep;
285     } else
286     *valuep = m->cpus[cpunr]->pc;
287     *match_register = 1;
288     }
289    
290     #if 0
291     TODO: regmatch for 64, 32, 16, and 8 bit register names
292     #endif
293     }
294    
295    
296     /* Macro which modifies the lower part of a value, or the entire value,
297     depending on 'mode': */
298     #define modify(old,new) ( \
299     mode==16? ( \
300     ((old) & ~0xffff) + ((new) & 0xffff) \
301     ) : (new) )
302    
303     #define HEXPRINT(x,n) { int j; for (j=0; j<(n); j++) debug("%02x",(x)[j]); }
304     #define HEXSPACES(i) { int j; for (j=0; j<10-(i);j++) debug(" "); debug(" "); }
305     #define SPACES HEXSPACES(ilen)
306    
307    
308     static uint32_t read_imm_common(unsigned char **instrp, int *ilenp,
309     int len, int printflag)
310     {
311     uint32_t imm;
312     unsigned char *instr = *instrp;
313    
314     if (len == 8)
315     imm = instr[0];
316     else if (len == 16)
317     imm = instr[0] + (instr[1] << 8);
318     else
319     imm = instr[0] + (instr[1] << 8) +
320     (instr[2] << 16) + (instr[3] << 24);
321    
322     if (printflag)
323     HEXPRINT(instr, len / 8);
324    
325     (*ilenp) += len/8;
326     (*instrp) += len/8;
327     return imm;
328     }
329    
330    
331     static uint32_t read_imm_and_print(unsigned char **instrp, int *ilenp,
332     int mode)
333     {
334     return read_imm_common(instrp, ilenp, mode, 1);
335     }
336    
337    
338     static uint32_t read_imm(unsigned char **instrp, uint64_t *newpc,
339     int mode)
340     {
341     int x = 0;
342     uint32_t r = read_imm_common(instrp, &x, mode, 0);
343     (*newpc) += x;
344     return r;
345     }
346    
347    
348     static void print_csip(struct cpu *cpu)
349     {
350     if (cpu->cd.x86.mode < 64)
351     fatal("0x%04x:", cpu->cd.x86.s[X86_S_CS]);
352     switch (cpu->cd.x86.mode) {
353     case 16: fatal("0x%04x", (int)cpu->pc); break;
354     case 32: fatal("0x%08x", (int)cpu->pc); break;
355     case 64: fatal("0x%016llx", (long long)cpu->pc); break;
356     }
357     }
358    
359    
360     static char modrm_dst[65];
361     static char modrm_src[65];
362     static void read_modrm(int mode, unsigned char **instrp, int *ilenp)
363     {
364     uint32_t imm = read_imm_and_print(instrp, ilenp, 8);
365     modrm_dst[0] = modrm_dst[64] = '\0';
366     modrm_src[0] = modrm_src[64] = '\0';
367    
368     fatal("read_modrm(): TODO\n");
369    
370     if ((imm & 0xc0) == 0xc0) {
371    
372     } else {
373     fatal("read_modrm(): unimplemented modr/m\n");
374     }
375     }
376    
377    
378     /*
379     * x86_cpu_disassemble_instr():
380     *
381     * Convert an instruction word into human readable format, for instruction
382     * tracing.
383     *
384     * If running is 1, cpu->pc should be the address of the instruction.
385     *
386     * If running is 0, things that depend on the runtime environment (eg.
387     * register contents) will not be shown, and addr will be used instead of
388     * cpu->pc for relative addresses.
389     */
390     int x86_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr,
391     int running, uint64_t dumpaddr, int bintrans)
392     {
393     int ilen = 0, op, rep = 0, n_prefix_bytes = 0;
394     uint64_t offset;
395     uint32_t imm=0, imm2, mode = cpu->cd.x86.mode;
396     char *symbol, *tmp = "ERROR", *mnem = "ERROR", *e = "e",
397     *prefix = NULL;
398    
399     if (running)
400     dumpaddr = cpu->pc;
401    
402     symbol = get_symbol_name(&cpu->machine->symbol_context,
403     dumpaddr, &offset);
404     if (symbol != NULL && offset==0)
405     debug("<%s>\n", symbol);
406    
407     if (cpu->machine->ncpus > 1 && running)
408     debug("cpu%i: ", cpu->cpu_id);
409    
410     if (mode == 32)
411     debug("%08x: ", (int)dumpaddr);
412     else if (mode == 64)
413     debug("%016llx: ", (long long)dumpaddr);
414     else { /* 16-bit mode */
415     if (running)
416     debug("%04x:%04x ", cpu->cd.x86.s[X86_S_CS],
417     (int)dumpaddr);
418     else
419     debug("%08x: ", (int)dumpaddr);
420     }
421    
422     /*
423     * Decode the instruction:
424     */
425    
426     /* All instructions are at least 1 byte long: */
427     HEXPRINT(instr,1);
428     ilen = 1;
429    
430     /* Any prefix? */
431     for (;;) {
432     if (instr[0] == 0x66) {
433     if (mode == 32)
434     mode = 16;
435     else
436     mode = 32;
437     } else if (instr[0] == 0xf3) {
438     rep = 1;
439     } else
440     break;
441    
442     if (++n_prefix_bytes > 4) {
443     SPACES; debug("more than 4 prefix bytes?\n");
444     return 4;
445     }
446    
447     /* TODO: lock, segment overrides etc */
448     instr ++; ilen ++;
449     debug("%02x", instr[0]);
450     }
451    
452     if (mode == 16)
453     e = "";
454    
455     op = instr[0];
456     instr ++;
457    
458     if ((op & 0xf0) <= 0x30 && (op & 7) <= 5) {
459     switch (op & 0x38) {
460     case 0x00: mnem = "add"; break;
461     case 0x08: mnem = "or"; break;
462     case 0x10: mnem = "adc"; break;
463     case 0x18: mnem = "sbb"; break;
464     case 0x20: mnem = "and"; break;
465     case 0x28: mnem = "sub"; break;
466     case 0x30: mnem = "xor"; break;
467     case 0x38: mnem = "cmp"; break;
468     }
469     switch (op & 7) {
470     case 4: imm = read_imm_and_print(&instr, &ilen, 8);
471     SPACES; debug("%s\tal,0x%02x", mnem, imm);
472     break;
473     case 5: imm = read_imm_and_print(&instr, &ilen, mode);
474     SPACES; debug("%s\t%sax,0x%x", mnem, e, imm);
475     break;
476     default:
477     read_modrm(mode, &instr, &ilen);
478     SPACES; debug("%s\t%s,%s", mnem, modrm_dst, modrm_src);
479     }
480     } else if (op == 0xf) {
481     /* "pop cs" on 8086 */
482     if (cpu->cd.x86.model.model_number == X86_MODEL_8086) {
483     SPACES; debug("pop\tcs");
484     } else {
485     SPACES; debug("UNIMPLEMENTED 0x0f");
486     }
487     } else if (op < 0x20 && (op & 7) == 6) {
488     SPACES; debug("push\t%s", seg_names[op/8]);
489     } else if (op < 0x20 && (op & 7) == 7) {
490     SPACES; debug("pop\t%s", seg_names[op/8]);
491     } else if (op >= 0x20 && op < 0x40 && (op & 7) == 7) {
492     SPACES; debug("%sa%s", op < 0x30? "d" : "a",
493     (op & 0xf)==7? "a" : "s");
494     } else if (op >= 0x40 && op <= 0x5f) {
495     switch (op & 0x38) {
496     case 0x00: mnem = "inc"; break;
497     case 0x08: mnem = "dec"; break;
498     case 0x10: mnem = "push"; break;
499     case 0x18: mnem = "pop"; break;
500     }
501     SPACES; debug("%s\t%s%s", mnem, e, reg_names[op & 7]);
502     } else if (op == 0x60) {
503     SPACES; debug("pusha");
504     } else if (op == 0x61) {
505     SPACES; debug("popa");
506     } else if ((op & 0xf0) == 0x70) {
507     imm = (signed char)read_imm_and_print(&instr, &ilen, 8);
508     imm = dumpaddr + 2 + imm;
509     SPACES; debug("j%s%s\t0x%x", op&1? "n" : "",
510     cond_names[(op/2) & 0x7], imm);
511     } else if (op == 0x90) {
512     SPACES; debug("nop");
513     } else if (op >= 0x91 && op <= 0x97) {
514     SPACES; debug("xchg\t%sax,%s%s", e, e, reg_names[op & 7]);
515     } else if (op == 0x98) {
516     SPACES; debug("cbw");
517     } else if (op == 0x99) {
518     SPACES; debug("cwd");
519     } else if (op == 0x9b) {
520     SPACES; debug("wait");
521     } else if (op == 0x9c) {
522     SPACES; debug("pushf");
523     } else if (op == 0x9d) {
524     SPACES; debug("popf");
525     } else if (op == 0x9e) {
526     SPACES; debug("sahf");
527     } else if (op == 0x9f) {
528     SPACES; debug("lahf");
529     } else if (op >= 0xb0 && op <= 0xb7) {
530     imm = read_imm_and_print(&instr, &ilen, 8);
531     switch (op & 7) {
532     case 0: tmp = "al"; break;
533     case 1: tmp = "cl"; break;
534     case 2: tmp = "dl"; break;
535     case 3: tmp = "bl"; break;
536     case 4: tmp = "ah"; break;
537     case 5: tmp = "ch"; break;
538     case 6: tmp = "dh"; break;
539     case 7: tmp = "bh"; break;
540     }
541     SPACES; debug("mov\t%s,0x%x", tmp, imm);
542     } else if (op >= 0xb8 && op <= 0xbf) {
543     imm = read_imm_and_print(&instr, &ilen, mode);
544     SPACES; debug("mov\t%s%s,0x%x", e, reg_names[op & 7], imm);
545     } else if (op == 0xc9) {
546     SPACES; debug("leave");
547     } else if (op == 0xcc) {
548     SPACES; debug("int3");
549     } else if (op == 0xcd) {
550     imm = read_imm_and_print(&instr, &ilen, 8);
551     SPACES; debug("int\t0x%x", imm);
552     } else if (op == 0xce) {
553     SPACES; debug("into");
554     } else if (op == 0xcf) {
555     SPACES; debug("iret");
556     } else if (op == 0xd4) {
557     SPACES; debug("aam");
558     } else if (op == 0xd5) {
559     SPACES; debug("aad");
560     } else if (op == 0xd7) {
561     SPACES; debug("xlat");
562     } else if (op == 0xea) {
563     imm = read_imm_and_print(&instr, &ilen, mode);
564     imm2 = read_imm_and_print(&instr, &ilen, 16);
565     SPACES; debug("jmp\t0x%04x:", imm2);
566     if (mode == 16)
567     debug("0x%04x", imm);
568     else
569     debug("0x%08x", imm);
570     } else if (op == 0xeb) {
571     imm = read_imm_and_print(&instr, &ilen, 8);
572     imm = dumpaddr + ilen + (signed char)imm;
573     SPACES; debug("jmp\t0x%x", imm);
574     } else if (op == 0xf4) {
575     SPACES; debug("hlt");
576     } else if (op == 0xf8) {
577     SPACES; debug("clc");
578     } else if (op == 0xf9) {
579     SPACES; debug("stc");
580     } else if (op == 0xfa) {
581     SPACES; debug("cli");
582     } else if (op == 0xfb) {
583     SPACES; debug("sti");
584     } else if (op == 0xfc) {
585     SPACES; debug("cld");
586     } else if (op == 0xfd) {
587     SPACES; debug("std");
588     } else {
589     SPACES; debug("UNIMPLEMENTED 0x%02x", op);
590     }
591    
592     if (rep)
593     debug(" (rep)");
594     if (prefix != NULL)
595     debug(" (%s)", prefix);
596    
597     debug("\n");
598     return ilen;
599     }
600    
601    
602     #define MEMORY_RW x86_memory_rw
603     #define MEM_X86
604     #include "memory_rw.c"
605     #undef MEM_X86
606     #undef MEMORY_RW
607    
608    
609     /*
610     * x86_load():
611     *
612     * Returns same error code as memory_rw().
613     */
614     static int x86_load(struct cpu *cpu, uint64_t addr, uint64_t *data, int len)
615     {
616     unsigned char databuf[8];
617     int res;
618     uint64_t d;
619    
620     res = cpu->memory_rw(cpu, cpu->mem, addr, &databuf[0], len,
621     MEM_READ, CACHE_DATA);
622    
623     d = databuf[0];
624     if (len > 1) {
625     d += ((uint64_t)databuf[1] << 8);
626     if (len > 2) {
627     d += ((uint64_t)databuf[2] << 16);
628     d += ((uint64_t)databuf[3] << 24);
629     if (len > 4) {
630     d += ((uint64_t)databuf[4] << 32);
631     d += ((uint64_t)databuf[5] << 40);
632     d += ((uint64_t)databuf[6] << 48);
633     d += ((uint64_t)databuf[7] << 56);
634     }
635     }
636     }
637    
638     *data = d;
639     return res;
640     }
641    
642    
643     /*
644     * x86_store():
645     *
646     * Returns same error code as memory_rw().
647     */
648     static int x86_store(struct cpu *cpu, uint64_t addr, uint64_t data, int len)
649     {
650     unsigned char databuf[8];
651    
652     /* x86 is always little-endian: */
653     databuf[0] = data;
654     if (len > 1) {
655     databuf[1] = data >> 8;
656     if (len > 2) {
657     databuf[2] = data >> 16;
658     databuf[3] = data >> 24;
659     if (len > 4) {
660     databuf[4] = data >> 32;
661     databuf[5] = data >> 40;
662     databuf[6] = data >> 48;
663     databuf[7] = data >> 56;
664     }
665     }
666     }
667    
668     return cpu->memory_rw(cpu, cpu->mem, addr, &databuf[0], len,
669     MEM_WRITE, CACHE_DATA);
670     }
671    
672    
673     /*
674     * x86_interrupt():
675     *
676     * NOTE/TODO: Only for 16-bit mode so far.
677     */
678     static int x86_interrupt(struct cpu *cpu, int nr)
679     {
680     uint64_t seg, ofs;
681     const int len = sizeof(uint16_t);
682    
683     if (cpu->cd.x86.mode != 16) {
684     fatal("x86 'int' only implemented for 16-bit so far\n");
685     exit(1);
686     }
687    
688     /* Read the interrupt vector from beginning of RAM: */
689     cpu->cd.x86.cursegment = 0;
690     x86_load(cpu, nr * 4 + 0, &ofs, sizeof(uint16_t));
691     x86_load(cpu, nr * 4 + 2, &seg, sizeof(uint16_t));
692    
693     /* Push flags, cs, and ip (pc): */
694     cpu->cd.x86.cursegment = cpu->cd.x86.s[X86_S_SS];
695     if (x86_store(cpu, cpu->cd.x86.r[X86_R_SP] - len * 1,
696     cpu->cd.x86.rflags, len) != MEMORY_ACCESS_OK)
697     fatal("x86_interrupt(): TODO: how to handle this\n");
698     if (x86_store(cpu, cpu->cd.x86.r[X86_R_SP] - len * 2,
699     cpu->cd.x86.s[X86_S_CS], len) != MEMORY_ACCESS_OK)
700     fatal("x86_interrupt(): TODO: how to handle this\n");
701     if (x86_store(cpu, cpu->cd.x86.r[X86_R_SP] - len * 3, cpu->pc,
702     len) != MEMORY_ACCESS_OK)
703     fatal("x86_interrupt(): TODO: how to handle this\n");
704    
705     cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] & ~0xffff)
706     | ((cpu->cd.x86.r[X86_R_SP] - len*3) & 0xffff);
707    
708     /* TODO: clear the Interrupt Flag? */
709    
710     cpu->cd.x86.s[X86_S_CS] = seg;
711     cpu->pc = ofs;
712    
713     return 1;
714     }
715    
716    
717     /*
718     * x86_cmp():
719     */
720     static void x86_cmp(struct cpu *cpu, uint64_t a, uint64_t b)
721     {
722     if (a == b)
723     cpu->cd.x86.rflags |= X86_FLAGS_ZF;
724     else
725     cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;
726    
727     if (a < b)
728     cpu->cd.x86.rflags |= X86_FLAGS_CF;
729     else
730     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
731    
732     /* TODO: other bits? */
733     }
734    
735    
736     /*
737     * x86_test():
738     */
739     static void x86_test(struct cpu *cpu, uint64_t a, uint64_t b)
740     {
741     a &= b;
742    
743     if (a == 0)
744     cpu->cd.x86.rflags |= X86_FLAGS_ZF;
745     else
746     cpu->cd.x86.rflags &= ~X86_FLAGS_ZF;
747    
748     if ((int32_t)a < 0)
749     cpu->cd.x86.rflags |= X86_FLAGS_SF;
750     else
751     cpu->cd.x86.rflags &= ~X86_FLAGS_SF;
752    
753     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
754     cpu->cd.x86.rflags &= ~X86_FLAGS_OF;
755     /* TODO: PF */
756     }
757    
758    
759     /*
760     * x86_cpu_run_instr():
761     *
762     * Execute one instruction on a specific CPU.
763     *
764     * Return value is the number of instructions executed during this call,
765     * 0 if no instruction was executed.
766     */
767     int x86_cpu_run_instr(struct emul *emul, struct cpu *cpu)
768     {
769     int i, r, rep = 0, op, len, diff, mode = cpu->cd.x86.mode;
770     int mode_addr = mode, nprefixbytes = 0;
771     uint32_t imm, imm2, value;
772     unsigned char buf[16];
773     unsigned char *instr = buf;
774     uint64_t newpc = cpu->pc;
775     unsigned char databuf[8];
776     uint64_t tmp;
777    
778     /* Check PC against breakpoints: */
779     if (!single_step)
780     for (i=0; i<cpu->machine->n_breakpoints; i++)
781     if (cpu->pc == cpu->machine->breakpoint_addr[i]) {
782     fatal("Breakpoint reached, pc=0x%llx",
783     (long long)cpu->pc);
784     single_step = 1;
785     return 0;
786     }
787    
788     /* 16-bit BIOS emulation: */
789     if (mode == 16 && ((newpc + (cpu->cd.x86.s[X86_S_CS] << 4)) & 0xff000)
790     == 0xf8000 && cpu->machine->prom_emulation) {
791     pc_bios_emul(cpu);
792     return 1;
793     }
794    
795     /* Read an instruction from memory: */
796     cpu->cd.x86.cursegment = cpu->cd.x86.s[X86_S_CS];
797    
798     r = cpu->memory_rw(cpu, cpu->mem, cpu->pc, &buf[0], sizeof(buf),
799     MEM_READ, CACHE_INSTRUCTION);
800     if (!r)
801     return 0;
802    
803     if (cpu->machine->instruction_trace)
804     x86_cpu_disassemble_instr(cpu, instr, 1, 0, 0);
805    
806     /* All instructions are at least one byte long :-) */
807     newpc ++;
808    
809     /* Default is to use the data segment, or the stack segment: */
810     cpu->cd.x86.cursegment = cpu->cd.x86.s[X86_S_DS];
811    
812     /* Any prefix? */
813     for (;;) {
814     if (instr[0] == 0x66) {
815     if (mode == 16)
816     mode = 32;
817     else
818     mode = 16;
819     } else if (instr[0] == 0x67) {
820     if (mode_addr == 16)
821     mode_addr = 32;
822     else
823     mode_addr = 16;
824     } else if (instr[0] == 0xf3)
825     rep = 1;
826     else
827     break;
828     /* TODO: repnz, lock etc */
829     instr ++;
830     newpc ++;
831     if (++nprefixbytes > 4) {
832     fatal("x86: too many prefix bytes at ");
833     print_csip(cpu); fatal("\n");
834     cpu->running = 0;
835     return 0;
836     }
837     }
838    
839     op = instr[0];
840     instr ++;
841    
842     if (op >= 0x40 && op <= 0x4f) {
843     if (op < 0x48)
844     cpu->cd.x86.r[op & 7] = modify(cpu->cd.x86.r[op & 7],
845     cpu->cd.x86.r[op & 7] + 1);
846     else
847     cpu->cd.x86.r[op & 7] = modify(cpu->cd.x86.r[op & 7],
848     cpu->cd.x86.r[op & 7] - 1);
849     /* TODO: flags etc */
850     } else if (op == 0x90) { /* NOP */
851     } else if (op >= 0xb8 && op <= 0xbf) {
852     imm = read_imm(&instr, &newpc, mode);
853     cpu->cd.x86.r[op & 7] = imm;
854     } else if (op == 0xcc) { /* INT3 */
855     cpu->pc = newpc;
856     return x86_interrupt(cpu, 3);
857     } else if (op == 0xcd) { /* INT */
858     imm = read_imm(&instr, &newpc, 8);
859     cpu->pc = newpc;
860     return x86_interrupt(cpu, imm);
861     } else if (op == 0xea) { /* JMP seg:ofs */
862     imm = read_imm(&instr, &newpc, mode);
863     imm2 = read_imm(&instr, &newpc, 16);
864     cpu->cd.x86.s[X86_S_CS] = imm2;
865     newpc = modify(cpu->pc, imm);
866     } else if (op == 0xeb) { /* JMP short */
867     imm = read_imm(&instr, &newpc, 8);
868     newpc = modify(newpc, newpc + (signed char)imm);
869     } else if (op == 0xf8) { /* CLC */
870     cpu->cd.x86.rflags &= ~X86_FLAGS_CF;
871     } else if (op == 0xf9) { /* STC */
872     cpu->cd.x86.rflags |= X86_FLAGS_CF;
873     } else if (op == 0xfa) { /* CLI */
874     cpu->cd.x86.rflags &= ~X86_FLAGS_IF;
875     } else if (op == 0xfb) { /* STI */
876     cpu->cd.x86.rflags |= X86_FLAGS_IF;
877     } else if (op == 0xfc) { /* CLD */
878     cpu->cd.x86.rflags &= ~X86_FLAGS_DF;
879     } else if (op == 0xfd) { /* STD */
880     cpu->cd.x86.rflags |= X86_FLAGS_DF;
881     } else {
882     fatal("x86_cpu_run_instr(): unimplemented opcode 0x%02x"
883     " at ", op); print_csip(cpu); fatal("\n");
884     cpu->running = 0;
885     return 0;
886     }
887    
888     cpu->pc = newpc;
889    
890     return 1;
891     }
892    
893    
894     #define CPU_RUN x86_cpu_run
895     #define CPU_RINSTR x86_cpu_run_instr
896     #define CPU_RUN_X86
897     #include "cpu_run.c"
898     #undef CPU_RINSTR
899     #undef CPU_RUN_X86
900     #undef CPU_RUN
901    
902    
903     /*
904     * x86_cpu_family_init():
905     *
906     * Fill in the cpu_family struct for x86.
907     */
908     int x86_cpu_family_init(struct cpu_family *fp)
909     {
910     fp->name = "x86";
911     fp->cpu_new = x86_cpu_new;
912     fp->list_available_types = x86_cpu_list_available_types;
913     fp->register_match = x86_cpu_register_match;
914     fp->disassemble_instr = x86_cpu_disassemble_instr;
915     fp->register_dump = x86_cpu_register_dump;
916     fp->run = x86_cpu_run;
917     fp->dumpinfo = x86_cpu_dumpinfo;
918     /* fp->show_full_statistics = x86_cpu_show_full_statistics; */
919     /* fp->tlbdump = x86_cpu_tlbdump; */
920     /* fp->interrupt = x86_cpu_interrupt; */
921     /* fp->interrupt_ack = x86_cpu_interrupt_ack; */
922     return 1;
923     }
924    
925     #endif /* ENABLE_X86 */

  ViewVC Help
Powered by ViewVC 1.1.26