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

Contents of /upstream/0.4.1/src/cpus/cpu_x86_instr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 29 - (show annotations)
Mon Oct 8 16:20:32 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 11001 byte(s)
0.4.1
1 /*
2 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_x86_instr.c,v 1.13 2006/04/22 18:07:30 debug Exp $
29 *
30 * x86/amd64 instructions.
31 *
32 * Individual functions should keep track of cpu->n_translated_instrs.
33 * (n_translated_instrs is automatically increased by 1 for each function
34 * call. If no instruction was executed, then it should be decreased. If, say,
35 * 4 instructions were combined into one function and executed, then it should
36 * be increased by 3.)
37 */
38
39
40 /*
41 * nop: Do nothing.
42 */
43 X(nop)
44 {
45 }
46
47
48 /*****************************************************************************/
49
50
51 /*
52 * sti, cli, std, cld, stc, clc: Set/clear flag bits.
53 */
54 X(stc) { cpu->cd.x86.rflags |= X86_FLAGS_CF; }
55 X(clc) { cpu->cd.x86.rflags &= ~X86_FLAGS_CF; }
56 X(std) { cpu->cd.x86.rflags |= X86_FLAGS_DF; }
57 X(cld) { cpu->cd.x86.rflags &= ~X86_FLAGS_DF; }
58 X(sti) { cpu->cd.x86.rflags |= X86_FLAGS_IF; }
59 X(cli) { cpu->cd.x86.rflags &= ~X86_FLAGS_IF; }
60
61
62 /*
63 * cpuid
64 */
65 X(cpuid)
66 {
67 x86_cpuid(cpu);
68 }
69
70
71 /*
72 * inc, dec
73 */
74 X(inc_ax)
75 {
76 MODE_uint_t r = cpu->cd.x86.r[X86_R_AX], r2 = r + 1;
77 cpu->cd.x86.r[X86_R_AX] = (r & ~0xffff) + (r2 & 0xffff);
78 }
79 X(inc_cx)
80 {
81 MODE_uint_t r = cpu->cd.x86.r[X86_R_CX], r2 = r + 1;
82 cpu->cd.x86.r[X86_R_CX] = (r & ~0xffff) + (r2 & 0xffff);
83 }
84 X(inc_dx)
85 {
86 MODE_uint_t r = cpu->cd.x86.r[X86_R_DX], r2 = r + 1;
87 cpu->cd.x86.r[X86_R_DX] = (r & ~0xffff) + (r2 & 0xffff);
88 }
89 X(inc_bx)
90 {
91 MODE_uint_t r = cpu->cd.x86.r[X86_R_BX], r2 = r + 1;
92 cpu->cd.x86.r[X86_R_BX] = (r & ~0xffff) + (r2 & 0xffff);
93 }
94 X(inc_sp)
95 {
96 MODE_uint_t r = cpu->cd.x86.r[X86_R_SP], r2 = r + 1;
97 cpu->cd.x86.r[X86_R_SP] = (r & ~0xffff) + (r2 & 0xffff);
98 }
99 X(inc_bp)
100 {
101 MODE_uint_t r = cpu->cd.x86.r[X86_R_BP], r2 = r + 1;
102 cpu->cd.x86.r[X86_R_BP] = (r & ~0xffff) + (r2 & 0xffff);
103 }
104 X(inc_si)
105 {
106 MODE_uint_t r = cpu->cd.x86.r[X86_R_SI], r2 = r + 1;
107 cpu->cd.x86.r[X86_R_SI] = (r & ~0xffff) + (r2 & 0xffff);
108 }
109 X(inc_di)
110 {
111 MODE_uint_t r = cpu->cd.x86.r[X86_R_DI], r2 = r + 1;
112 cpu->cd.x86.r[X86_R_DI] = (r & ~0xffff) + (r2 & 0xffff);
113 }
114 X(inc_eax) { cpu->cd.x86.r[X86_R_AX] ++; }
115 X(inc_ecx) { cpu->cd.x86.r[X86_R_CX] ++; }
116 X(inc_edx) { cpu->cd.x86.r[X86_R_DX] ++; }
117 X(inc_ebx) { cpu->cd.x86.r[X86_R_BX] ++; }
118 X(inc_esp) { cpu->cd.x86.r[X86_R_SP] ++; }
119 X(inc_ebp) { cpu->cd.x86.r[X86_R_BP] ++; }
120 X(inc_esi) { cpu->cd.x86.r[X86_R_SI] ++; }
121 X(inc_edi) { cpu->cd.x86.r[X86_R_DI] ++; }
122
123
124 /*
125 * mov_reg_imm_8:
126 *
127 * arg[1] = imm8
128 * arg[2] = pointer to a _byte_ inside an emulated register
129 */
130 X(mov_reg_imm_8)
131 {
132 *((uint8_t *)ic->arg[2]) = ic->arg[1];
133 }
134
135
136 /*
137 * mov_reg_imm_16, _32
138 */
139 X(mov_reg_imm_16)
140 {
141 reg(ic->arg[2]) &= ~0xffff;
142 reg(ic->arg[2]) |= ic->arg[1];
143 }
144 X(mov_reg_imm_32)
145 {
146 reg(ic->arg[2]) = (uint32_t)ic->arg[1];
147 }
148
149
150 /*****************************************************************************/
151
152
153 X(end_of_page)
154 {
155 /* Update the PC: (offset 0, but on the next page) */
156 cpu->pc &= ~(X86_IC_ENTRIES_PER_PAGE-1);
157 cpu->pc += X86_IC_ENTRIES_PER_PAGE;
158
159 /* Find the new physical page and update the translation pointers: */
160 x86_pc_to_pointers(cpu);
161
162 /* end_of_page doesn't count as an executed instruction: */
163 cpu->n_translated_instrs --;
164 }
165
166
167 /*****************************************************************************/
168
169
170 #ifdef GET_NEXT_BYTE
171 #undef GET_NEXT_BYTE
172 #endif
173 #ifdef MODE32
174 #define GET_NEXT_BYTE get_next_byte32
175 #else
176 #define GET_NEXT_BYTE get_next_byte64
177 #endif
178 /* Get the next instruction byte; return 1 on success, 0 on failure */
179 int GET_NEXT_BYTE(struct cpu *cpu, unsigned char *byte, MODE_uint_t addr)
180 {
181 unsigned char *page;
182
183 /* Read the instruction word from memory: */
184 #ifdef MODE32
185 page = cpu->cd.x86.host_load[addr >> 12];
186 #else
187 {
188 const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
189 const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
190 const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
191 uint32_t x1 = (addr >> (64-DYNTRANS_L1N)) & mask1;
192 uint32_t x2 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
193 uint32_t x3 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N-
194 DYNTRANS_L3N)) & mask3;
195 struct DYNTRANS_L2_64_TABLE *l2 = cpu->cd.x86.l1_64[x1];
196 struct DYNTRANS_L3_64_TABLE *l3 = l2->l3[x2];
197 page = l3->host_load[x3];
198 }
199 #endif
200
201 if (page != NULL) {
202 /* fatal("TRANSLATION HIT!\n"); */
203 (*byte) = page[addr & 0xfff];
204 } else {
205 /* fatal("TRANSLATION MISS!\n"); */
206 if (!cpu->memory_rw(cpu, cpu->mem, addr, byte,
207 1, MEM_READ, CACHE_INSTRUCTION)) {
208 /* exception occurred, or similar */
209 return 0;
210 }
211 }
212
213 return 1;
214 }
215
216
217 #ifndef GNB
218 #define GNB { if (len >= sizeof(ib)) \
219 goto bad; \
220 if (!GET_NEXT_BYTE(cpu, &ib[len++], addr++)) \
221 goto gnb_failed; \
222 }
223 #endif
224
225
226 #ifndef GET_OP
227 #define GET_OP opimm = 0; \
228 { \
229 int i; \
230 for (i=0; i<oplen; i++) { \
231 GNB; \
232 opimm |= (ib[len-1] << (i*8)); \
233 } \
234 }
235 #endif
236
237
238 /*
239 * x86_instr_to_be_translated():
240 *
241 * Translate an instruction word into an x86_instr_call. ic is filled in with
242 * valid data for the translated instruction, or a "nothing" instruction if
243 * there was a translation failure. The newly translated instruction is then
244 * executed.
245 */
246 X(to_be_translated)
247 {
248 MODE_uint_t addr, orig_addr, low_pc;
249 int main_opcode, secondary_opcode, len, mode16, oplen;
250 uint32_t opimm;
251 unsigned char ib[17];
252 /* void (*samepage_function)(struct cpu *, struct x86_instr_call *); */
253
254 /* Figure out the (virtual) address of the instruction: */
255 low_pc = ((size_t)ic - (size_t)cpu->cd.x86.cur_ic_page)
256 / sizeof(struct x86_instr_call);
257 addr = cpu->pc & ~(X86_IC_ENTRIES_PER_PAGE-1);
258 addr += low_pc;
259 cpu->pc = addr;
260 orig_addr = addr;
261
262 if (!cpu->cd.x86.descr_cache[X86_S_CS].valid) {
263 fatal("x86_cpu_run_instr(): Invalid CS descriptor?\n");
264 exit(1);
265 }
266
267 cpu->cd.x86.cursegment = X86_S_CS;
268 cpu->cd.x86.seg_override = 0;
269
270
271 #define DYNTRANS_TO_BE_TRANSLATED_HEAD
272 #include "cpu_dyntrans.c"
273 #undef DYNTRANS_TO_BE_TRANSLATED_HEAD
274
275
276 /*
277 * Translate the instruction:
278 */
279
280 ic->arg[0] = len = 0;
281
282 if (LONG_MODE) {
283 fatal("LONG MODE: TODO\n");
284 goto bad;
285 }
286
287 mode16 = REAL_MODE;
288
289 /* Parse prefix bytes, and get the main (first) opcode byte: */
290 for (;;) {
291 GNB; main_opcode = ib[len - 1];
292 if (main_opcode == 0x66) {
293 mode16 = !mode16;
294 } else {
295 /* Found a non-prefix byte? Then break. */
296 break;
297 }
298 }
299
300 oplen = mode16? sizeof(uint16_t) : sizeof(uint32_t);
301
302 switch (main_opcode) {
303
304 case 0x0f:
305 GNB; secondary_opcode = ib[len-1];
306 switch (secondary_opcode) {
307
308 case 0xa2:
309 ic->f = instr(cpuid);
310 break;
311
312 default:fatal("unimplemented 0x0f opcode 0x%02x\n",
313 secondary_opcode);
314 goto bad;
315 }
316 break;
317
318 case 0x40: /* inc ax etc. */
319 case 0x41:
320 case 0x42:
321 case 0x43:
322 case 0x44:
323 case 0x45:
324 case 0x46:
325 case 0x47:
326 if (mode16) {
327 switch (main_opcode) {
328 case 0x40: ic->f = instr(inc_ax); break;
329 case 0x41: ic->f = instr(inc_cx); break;
330 case 0x42: ic->f = instr(inc_dx); break;
331 case 0x43: ic->f = instr(inc_bx); break;
332 case 0x44: ic->f = instr(inc_sp); break;
333 case 0x45: ic->f = instr(inc_bp); break;
334 case 0x46: ic->f = instr(inc_si); break;
335 case 0x47: ic->f = instr(inc_di); break;
336 }
337 } else {
338 switch (main_opcode) {
339 case 0x40: ic->f = instr(inc_eax); break;
340 case 0x41: ic->f = instr(inc_ecx); break;
341 case 0x42: ic->f = instr(inc_edx); break;
342 case 0x43: ic->f = instr(inc_ebx); break;
343 case 0x44: ic->f = instr(inc_esp); break;
344 case 0x45: ic->f = instr(inc_ebp); break;
345 case 0x46: ic->f = instr(inc_esi); break;
346 case 0x47: ic->f = instr(inc_edi); break;
347 }
348 }
349 break;
350
351 case 0x90: /* nop */
352 ic->f = instr(nop);
353 break;
354
355 case 0xb0: /* mov al,imm etc. */
356 case 0xb1:
357 case 0xb2:
358 case 0xb3:
359 case 0xb4:
360 case 0xb5:
361 case 0xb6:
362 case 0xb7:
363 GNB;
364 ic->arg[1] = ib[len - 1];
365 /* Calculate for little endian first: */
366 ic->arg[2] = (size_t)&cpu->cd.x86.r[main_opcode & 3];
367 if (main_opcode >= 0xb4)
368 ic->arg[2] ++;
369 #ifdef HOST_BIG_ENDIAN
370 /* Switch byte order: */
371 ic->arg[2] = (ic->arg[2] & ~(sizeof(uint64_t)-1)) +
372 sizeof(uint64_t) - 1 - (ic->arg[2] & (sizeof(uint64_t)-1));
373 #endif
374 ic->f = instr(mov_reg_imm_8);
375 break;
376
377 case 0xb8: /* mov ax,imm etc. */
378 case 0xb9:
379 case 0xba:
380 case 0xbb:
381 case 0xbc:
382 case 0xbd:
383 case 0xbe:
384 case 0xbf:
385 GET_OP;
386 ic->arg[1] = opimm;
387 ic->arg[2] = (size_t)&cpu->cd.x86.r[main_opcode - 0xb8];
388 if (mode16)
389 ic->f = instr(mov_reg_imm_16);
390 else
391 ic->f = instr(mov_reg_imm_32);
392 break;
393
394 case 0xf8: /* clc */
395 case 0xf9: /* stc */
396 case 0xfa: /* cli */
397 case 0xfb: /* sti */
398 case 0xfc: /* cld */
399 case 0xfd: /* std */
400 switch (main_opcode) {
401 case 0xf8: ic->f = instr(sti); break;
402 case 0xf9: ic->f = instr(stc); break;
403 case 0xfa: ic->f = instr(cli); break;
404 case 0xfb: ic->f = instr(sti); break;
405 case 0xfc: ic->f = instr(cld); break;
406 case 0xfd: ic->f = instr(std); break;
407 }
408 break;
409
410 default:goto bad;
411 }
412
413
414 if (((addr-1) & ~0xfff) != (orig_addr & ~0xfff)) {
415 fatal("Instruction crosses page boundary. TODO\n");
416 exit(1);
417 }
418
419 if (len > sizeof(ib)) {
420 fatal("INTERNAL ERROR in cpu_x86_instr.c! len = %i\n", len);
421 exit(1);
422 }
423
424 ic->arg[0] = len;
425 goto ok;
426
427
428 /* We get here if get_next_byte failed (i.e. an excepion occured while
429 crossing a page-boundary...) */
430 gnb_failed:
431 ic->f = instr(to_be_translated);
432 ic->arg[0] = 0;
433 /* The program counter etc. should already have been updated. */
434 return;
435
436 ok:
437
438 #define DYNTRANS_TO_BE_TRANSLATED_TAIL
439 #include "cpu_dyntrans.c"
440 #undef DYNTRANS_TO_BE_TRANSLATED_TAIL
441 }
442

  ViewVC Help
Powered by ViewVC 1.1.26