25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_x86.c,v 1.17 2006/07/16 13:32:26 debug Exp $ |
* $Id: cpu_x86.c,v 1.18 2006/09/23 03:49:02 debug Exp $ |
29 |
* |
* |
30 |
* x86 (and amd64) CPU emulation. |
* x86 (and amd64) CPU emulation. |
31 |
* |
* |
32 |
* |
* |
33 |
* TODO: Pretty much everything that has to do with 64-bit and 32-bit modes, |
* NOTE: I ripped out pretty much everything that had to do with x86 |
34 |
* memory translation, flag bits, and so on. |
* emulation, when doing the transition to dyntrans. This CPU mode |
35 |
|
* hasn't been rewritten yet. |
36 |
* |
* |
37 |
* See http://www.amd.com/us-en/Processors/DevelopWithAMD/ |
* Right now, it is completely bogus. |
|
* 0,,30_2252_875_7044,00.html for more info on AMD64. |
|
|
* |
|
|
* http://www.cs.ucla.edu/~kohler/class/04f-aos/ref/i386/appa.htm has a |
|
|
* nice overview of the standard i386 opcodes. |
|
|
* |
|
|
* HelpPC (http://members.tripod.com/~oldboard/assembly/) is also useful. |
|
38 |
*/ |
*/ |
39 |
|
|
40 |
#include <stdio.h> |
#include <stdio.h> |
47 |
#include "machine.h" |
#include "machine.h" |
48 |
#include "memory.h" |
#include "memory.h" |
49 |
#include "misc.h" |
#include "misc.h" |
50 |
|
#include "settings.h" |
51 |
#include "symbol.h" |
#include "symbol.h" |
52 |
|
|
53 |
#define DYNTRANS_DUALMODE_32 |
#define DYNTRANS_DUALMODE_32 |
|
/* #define DYNTRANS_32 */ |
|
54 |
#define DYNTRANS_VARIABLE_INSTRUCTION_LENGTH |
#define DYNTRANS_VARIABLE_INSTRUCTION_LENGTH |
55 |
#include "tmp_x86_head.c" |
#include "tmp_x86_head.c" |
56 |
|
|
139 |
debug("%s", cpu->name); |
debug("%s", cpu->name); |
140 |
} |
} |
141 |
|
|
142 |
|
/* |
143 |
|
* Add all register names to the settings: |
144 |
|
* |
145 |
|
* Note that the name 'pc' is also added. It equals 64-bit RIP. |
146 |
|
*/ |
147 |
|
CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc); |
148 |
|
|
149 |
|
/* TODO: All of the following: */ |
150 |
|
#if 0 |
151 |
|
if (strcasecmp(name, "pc") == 0 || strcasecmp(name, "rip") == 0) { |
152 |
|
if (strcasecmp(name, "ip") == 0) { |
153 |
|
if (strcasecmp(name, "eip") == 0) { |
154 |
|
if (strcasecmp(name, "rflags") == 0) { |
155 |
|
if (strcasecmp(name, "eflags") == 0) { |
156 |
|
if (strcasecmp(name, "flags") == 0) { |
157 |
|
/* 8-bit low */ |
158 |
|
if (strcasecmp(name, reg_names_bytes[r]) == 0) { |
159 |
|
/* 8-bit high: */ |
160 |
|
for (r=0; r<4; r++) |
161 |
|
if (strcasecmp(name, reg_names_bytes[r+4]) == 0) { |
162 |
|
/* 16-, 32-, 64-bit registers: */ |
163 |
|
for (r=0; r<N_X86_REGS; r++) { |
164 |
|
if (r<8 && strcasecmp(name, reg_names[r]) == 0) { |
165 |
|
/* 32-bit: */ |
166 |
|
if (r<8 && (name[0]=='e' || name[0]=='E') && |
167 |
|
/* 64-bit: */ |
168 |
|
if ((name[0]=='r' || name[0]=='R') && |
169 |
|
strcasecmp(name+1, reg_names[r]) == 0) { |
170 |
|
/* segment names: */ |
171 |
|
for (r=0; r<N_X86_SEGS; r++) { |
172 |
|
if (strcasecmp(name, seg_names[r]) == 0) { |
173 |
|
/* control registers: (TODO: 32- vs 64-bit on AMD64?) */ |
174 |
|
if (strncasecmp(name, "cr", 2) == 0 && atoi(name+2) < N_X86_CREGS ) { |
175 |
|
#endif |
176 |
|
|
177 |
|
|
178 |
return 1; |
return 1; |
179 |
} |
} |
180 |
|
|
341 |
} |
} |
342 |
} |
} |
343 |
|
|
|
|
|
|
/* |
|
|
* x86_cpu_register_match(): |
|
|
*/ |
|
|
void x86_cpu_register_match(struct machine *m, char *name, |
|
|
int writeflag, uint64_t *valuep, int *mr) |
|
|
{ |
|
|
int cpunr = 0; |
|
|
int r; |
|
|
|
|
|
/* CPU number: TODO */ |
|
|
|
|
|
if (strcasecmp(name, "pc") == 0 || strcasecmp(name, "rip") == 0) { |
|
|
if (writeflag) { |
|
|
m->cpus[cpunr]->pc = *valuep; |
|
|
m->cpus[cpunr]->cd.x86.halted = 0; |
|
|
} else |
|
|
*valuep = m->cpus[cpunr]->pc; |
|
|
*mr = 1; |
|
|
return; |
|
|
} |
|
|
if (strcasecmp(name, "ip") == 0) { |
|
|
if (writeflag) { |
|
|
m->cpus[cpunr]->pc = (m->cpus[cpunr]->pc & ~0xffff) |
|
|
| (*valuep & 0xffff); |
|
|
m->cpus[cpunr]->cd.x86.halted = 0; |
|
|
} else |
|
|
*valuep = m->cpus[cpunr]->pc & 0xffff; |
|
|
*mr = 1; |
|
|
return; |
|
|
} |
|
|
if (strcasecmp(name, "eip") == 0) { |
|
|
if (writeflag) { |
|
|
m->cpus[cpunr]->pc = *valuep; |
|
|
m->cpus[cpunr]->cd.x86.halted = 0; |
|
|
} else |
|
|
*valuep = m->cpus[cpunr]->pc & 0xffffffffULL; |
|
|
*mr = 1; |
|
|
return; |
|
|
} |
|
|
|
|
|
if (strcasecmp(name, "rflags") == 0) { |
|
|
if (writeflag) |
|
|
m->cpus[cpunr]->cd.x86.rflags = *valuep; |
|
|
else |
|
|
*valuep = m->cpus[cpunr]->cd.x86.rflags; |
|
|
*mr = 1; |
|
|
return; |
|
|
} |
|
|
if (strcasecmp(name, "eflags") == 0) { |
|
|
if (writeflag) |
|
|
m->cpus[cpunr]->cd.x86.rflags = (m->cpus[cpunr]-> |
|
|
cd.x86.rflags & ~0xffffffffULL) | (*valuep & |
|
|
0xffffffffULL); |
|
|
else |
|
|
*valuep = m->cpus[cpunr]->cd.x86.rflags & 0xffffffffULL; |
|
|
*mr = 1; |
|
|
return; |
|
|
} |
|
|
if (strcasecmp(name, "flags") == 0) { |
|
|
if (writeflag) |
|
|
m->cpus[cpunr]->cd.x86.rflags = (m->cpus[cpunr]-> |
|
|
cd.x86.rflags & ~0xffff) | (*valuep & 0xffff); |
|
|
else |
|
|
*valuep = m->cpus[cpunr]->cd.x86.rflags & 0xffff; |
|
|
*mr = 1; |
|
|
return; |
|
|
} |
|
|
|
|
|
/* 8-bit low: */ |
|
|
for (r=0; r<4; r++) |
|
|
if (strcasecmp(name, reg_names_bytes[r]) == 0) { |
|
|
if (writeflag) |
|
|
m->cpus[cpunr]->cd.x86.r[r] = |
|
|
(m->cpus[cpunr]->cd.x86.r[r] & ~0xff) |
|
|
| (*valuep & 0xff); |
|
|
else |
|
|
*valuep = m->cpus[cpunr]->cd.x86.r[r] & 0xff; |
|
|
*mr = 1; |
|
|
return; |
|
|
} |
|
|
|
|
|
/* 8-bit high: */ |
|
|
for (r=0; r<4; r++) |
|
|
if (strcasecmp(name, reg_names_bytes[r+4]) == 0) { |
|
|
if (writeflag) |
|
|
m->cpus[cpunr]->cd.x86.r[r] = |
|
|
(m->cpus[cpunr]->cd.x86.r[r] & ~0xff00) |
|
|
| ((*valuep & 0xff) << 8); |
|
|
else |
|
|
*valuep = (m->cpus[cpunr]->cd.x86.r[r] >> |
|
|
8) & 0xff; |
|
|
*mr = 1; |
|
|
return; |
|
|
} |
|
|
|
|
|
/* 16-, 32-, 64-bit registers: */ |
|
|
for (r=0; r<N_X86_REGS; r++) { |
|
|
/* 16-bit: */ |
|
|
if (r<8 && strcasecmp(name, reg_names[r]) == 0) { |
|
|
if (writeflag) |
|
|
m->cpus[cpunr]->cd.x86.r[r] = |
|
|
(m->cpus[cpunr]->cd.x86.r[r] & ~0xffff) |
|
|
| (*valuep & 0xffff); |
|
|
else |
|
|
*valuep = m->cpus[cpunr]->cd.x86.r[r] & 0xffff; |
|
|
*mr = 1; |
|
|
return; |
|
|
} |
|
|
|
|
|
/* 32-bit: */ |
|
|
if (r<8 && (name[0]=='e' || name[0]=='E') && |
|
|
strcasecmp(name+1, reg_names[r]) == 0) { |
|
|
if (writeflag) |
|
|
m->cpus[cpunr]->cd.x86.r[r] = |
|
|
*valuep & 0xffffffffULL; |
|
|
else |
|
|
*valuep = m->cpus[cpunr]->cd.x86.r[r] & |
|
|
0xffffffffULL; |
|
|
*mr = 1; |
|
|
return; |
|
|
} |
|
|
|
|
|
/* 64-bit: */ |
|
|
if ((name[0]=='r' || name[0]=='R') && |
|
|
strcasecmp(name+1, reg_names[r]) == 0) { |
|
|
if (writeflag) |
|
|
m->cpus[cpunr]->cd.x86.r[r] = *valuep; |
|
|
else |
|
|
*valuep = m->cpus[cpunr]->cd.x86.r[r]; |
|
|
*mr = 1; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
/* segment names: */ |
|
|
for (r=0; r<N_X86_SEGS; r++) { |
|
|
if (strcasecmp(name, seg_names[r]) == 0) { |
|
|
if (writeflag) |
|
|
m->cpus[cpunr]->cd.x86.s[r] = |
|
|
(m->cpus[cpunr]->cd.x86.s[r] & ~0xffff) |
|
|
| (*valuep & 0xffff); |
|
|
else |
|
|
*valuep = m->cpus[cpunr]->cd.x86.s[r] & 0xffff; |
|
|
*mr = 1; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
/* control registers: (TODO: 32- vs 64-bit on AMD64?) */ |
|
|
if (strncasecmp(name, "cr", 2) == 0 && atoi(name+2) < N_X86_CREGS ) { |
|
|
int r = atoi(name+2); |
|
|
if (writeflag) |
|
|
m->cpus[cpunr]->cd.x86.cr[r] = *valuep; |
|
|
else |
|
|
*valuep = m->cpus[cpunr]->cd.x86.cr[r]; |
|
|
*mr = 1; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
344 |
|
|
345 |
/* Macro which modifies the lower part of a value, or the entire value, |
/* Macro which modifies the lower part of a value, or the entire value, |
346 |
depending on 'mode': */ |
depending on 'mode': */ |