/[gxemul]/upstream/0.3.6.1/src/cpus/bintrans_i386.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.3.6.1/src/cpus/bintrans_i386.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 17 - (show annotations)
Mon Oct 8 16:19:05 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 85063 byte(s)
0.3.6.1
1 /*
2 * Copyright (C) 2004-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: bintrans_i386.c,v 1.1 2005/08/29 14:36:41 debug Exp $
29 *
30 * i386 specific code for dynamic binary translation.
31 * See bintrans.c for more information. Included from bintrans.c.
32 *
33 * Translated code uses the following conventions at all time:
34 *
35 * esi points to the cpu struct
36 * edi lowest 32 bits of cpu->pc
37 * ebp contains cpu->bintrans_instructions_executed
38 */
39
40
41 struct cpu dummy_cpu;
42 struct mips_coproc dummy_coproc;
43 struct vth32_table dummy_vth32_table;
44
45
46 /*
47 * bintrans_host_cacheinvalidate()
48 *
49 * Invalidate the host's instruction cache. On i386, this isn't necessary,
50 * so this is an empty function.
51 */
52 static void bintrans_host_cacheinvalidate(unsigned char *p, size_t len)
53 {
54 /* Do nothing. */
55 }
56
57
58 /* offsetof (in stdarg.h) could possibly be used, but I'm not sure
59 if it will take care of the compiler problems... */
60
61 #define ofs_i (((size_t)&dummy_cpu.cd.mips.bintrans_instructions_executed) - ((size_t)&dummy_cpu))
62 #define ofs_pc (((size_t)&dummy_cpu.pc) - ((size_t)&dummy_cpu))
63 #define ofs_pc_last (((size_t)&dummy_cpu.cd.mips.pc_last) - ((size_t)&dummy_cpu))
64 #define ofs_tabl0 (((size_t)&dummy_cpu.cd.mips.vaddr_to_hostaddr_table0) - ((size_t)&dummy_cpu))
65 #define ofs_chunks ((size_t)&dummy_vth32_table.bintrans_chunks[0] - (size_t)&dummy_vth32_table)
66 #define ofs_chunkbase ((size_t)&dummy_cpu.cd.mips.chunk_base_address - (size_t)&dummy_cpu)
67 #define ofs_h_l (((size_t)&dummy_cpu.cd.mips.host_load) - ((size_t)&dummy_cpu))
68 #define ofs_h_s (((size_t)&dummy_cpu.cd.mips.host_store) - ((size_t)&dummy_cpu))
69
70
71 static void (*bintrans_runchunk)(struct cpu *, unsigned char *);
72 static void (*bintrans_jump_to_32bit_pc)(struct cpu *);
73 static void (*bintrans_load_32bit)(struct cpu *);
74 static void (*bintrans_store_32bit)(struct cpu *);
75
76
77 /*
78 * bintrans_write_quickjump():
79 */
80 static void bintrans_write_quickjump(struct memory *mem,
81 unsigned char *quickjump_code, uint32_t chunkoffset)
82 {
83 uint32_t i386_addr;
84 unsigned char *a = quickjump_code;
85
86 i386_addr = chunkoffset + (size_t)mem->translation_code_chunk_space;
87 i386_addr = i386_addr - ((size_t)a + 5);
88
89 /* printf("chunkoffset=%i, %08x %08x %i\n",
90 chunkoffset, i386_addr, a, ofs); */
91
92 *a++ = 0xe9;
93 *a++ = i386_addr;
94 *a++ = i386_addr >> 8;
95 *a++ = i386_addr >> 16;
96 *a++ = i386_addr >> 24;
97 }
98
99
100 /*
101 * bintrans_write_chunkreturn():
102 */
103 static void bintrans_write_chunkreturn(unsigned char **addrp)
104 {
105 unsigned char *a = *addrp;
106 *a++ = 0xc3; /* ret */
107 *addrp = a;
108 }
109
110
111 /*
112 * bintrans_write_chunkreturn_fail():
113 */
114 static void bintrans_write_chunkreturn_fail(unsigned char **addrp)
115 {
116 unsigned char *a = *addrp;
117
118 /* 81 cd 00 00 00 01 orl $0x1000000,%ebp */
119 *a++ = 0x81; *a++ = 0xcd;
120 *a++ = 0; *a++ = 0; *a++ = 0; *a++ = 0x01; /* TODO: not hardcoded */
121
122 *a++ = 0xc3; /* ret */
123 *addrp = a;
124 }
125
126
127 /*
128 * bintrans_write_pc_inc():
129 */
130 static void bintrans_write_pc_inc(unsigned char **addrp)
131 {
132 unsigned char *a = *addrp;
133
134 /* 83 c7 04 add $0x4,%edi */
135 *a++ = 0x83; *a++ = 0xc7; *a++ = 4;
136
137 #if 0
138 if (!bintrans_32bit_only) {
139 int ofs;
140 /* 83 96 zz zz zz zz 00 adcl $0x0,zz(%esi) */
141 ofs = ((size_t)&dummy_cpu.pc) - (size_t)&dummy_cpu;
142 ofs += 4;
143 *a++ = 0x83; *a++ = 0x96;
144 *a++ = ofs & 255;
145 *a++ = (ofs >> 8) & 255;
146 *a++ = (ofs >> 16) & 255;
147 *a++ = (ofs >> 24) & 255;
148 *a++ = 0;
149 }
150 #endif
151
152 /* 45 inc %ebp */
153 *a++ = 0x45;
154
155 *addrp = a;
156 }
157
158
159 /*
160 * load_pc_into_eax_edx():
161 */
162 static void load_pc_into_eax_edx(unsigned char **addrp)
163 {
164 unsigned char *a;
165 a = *addrp;
166
167 /* 89 f8 mov %edi,%eax */
168 *a++ = 0x89; *a++ = 0xf8;
169
170 #if 0
171 if (bintrans_32bit_only) {
172 /* 99 cltd */
173 *a++ = 0x99;
174 } else
175 #endif
176 {
177 int ofs = ((size_t)&dummy_cpu.pc) - (size_t)&dummy_cpu;
178 /* 8b 96 3c 30 00 00 mov 0x303c(%esi),%edx */
179 ofs += 4;
180 *a++ = 0x8b; *a++ = 0x96;
181 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
182 }
183
184 *addrp = a;
185 }
186
187
188 /*
189 * store_eax_edx_into_pc():
190 */
191 static void store_eax_edx_into_pc(unsigned char **addrp)
192 {
193 unsigned char *a;
194 int ofs = ((size_t)&dummy_cpu.pc) - (size_t)&dummy_cpu;
195 a = *addrp;
196
197 /* 89 c7 mov %eax,%edi */
198 *a++ = 0x89; *a++ = 0xc7;
199
200 /* 89 96 3c 30 00 00 mov %edx,0x303c(%esi) */
201 ofs += 4;
202 *a++ = 0x89; *a++ = 0x96;
203 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
204
205 *addrp = a;
206 }
207
208
209 /*
210 * load_into_eax_edx():
211 *
212 * Usage: load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]); etc.
213 */
214 static void load_into_eax_edx(unsigned char **addrp, void *p)
215 {
216 unsigned char *a;
217 int ofs = (size_t)p - (size_t)&dummy_cpu;
218 a = *addrp;
219
220 /* 8b 86 38 30 00 00 mov 0x3038(%esi),%eax */
221 *a++ = 0x8b; *a++ = 0x86;
222 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
223
224 #if 0
225 if (bintrans_32bit_only) {
226 /* 99 cltd */
227 *a++ = 0x99;
228 } else
229 #endif
230 {
231 /* 8b 96 3c 30 00 00 mov 0x303c(%esi),%edx */
232 ofs += 4;
233 *a++ = 0x8b; *a++ = 0x96;
234 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
235 }
236
237 *addrp = a;
238 }
239
240
241 /*
242 * load_into_eax_and_sign_extend_into_edx():
243 *
244 * Usage: load_into_eax_and_sign_extend_into_edx(&a, &dummy_cpu.cd.mips.gpr[rs]); etc.
245 */
246 static void load_into_eax_and_sign_extend_into_edx(unsigned char **addrp, void *p)
247 {
248 unsigned char *a;
249 int ofs = (size_t)p - (size_t)&dummy_cpu;
250 a = *addrp;
251
252 /* 8b 86 38 30 00 00 mov 0x3038(%esi),%eax */
253 *a++ = 0x8b; *a++ = 0x86;
254 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
255
256 /* 99 cltd */
257 *a++ = 0x99;
258
259 *addrp = a;
260 }
261
262
263 /*
264 * load_into_eax_dont_care_about_edx():
265 *
266 * Usage: load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rs]); etc.
267 */
268 static void load_into_eax_dont_care_about_edx(unsigned char **addrp, void *p)
269 {
270 unsigned char *a;
271 int ofs = (size_t)p - (size_t)&dummy_cpu;
272 a = *addrp;
273
274 /* 8b 86 38 30 00 00 mov 0x3038(%esi),%eax */
275 *a++ = 0x8b; *a++ = 0x86;
276 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
277
278 *addrp = a;
279 }
280
281
282 /*
283 * store_eax_edx():
284 *
285 * Usage: store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]); etc.
286 */
287 static void store_eax_edx(unsigned char **addrp, void *p)
288 {
289 unsigned char *a;
290 int ofs = (size_t)p - (size_t)&dummy_cpu;
291 a = *addrp;
292
293 /* 89 86 38 30 00 00 mov %eax,0x3038(%esi) */
294 *a++ = 0x89; *a++ = 0x86;
295 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
296
297 /* 89 96 3c 30 00 00 mov %edx,0x303c(%esi) */
298 ofs += 4;
299 *a++ = 0x89; *a++ = 0x96;
300 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
301
302 *addrp = a;
303 }
304
305
306 /*
307 * bintrans_write_instruction__lui():
308 */
309 static int bintrans_write_instruction__lui(unsigned char **addrp, int rt, int imm)
310 {
311 unsigned char *a;
312
313 a = *addrp;
314 if (rt == 0)
315 goto rt0;
316
317 /* b8 00 00 dc fe mov $0xfedc0000,%eax */
318 *a++ = 0xb8; *a++ = 0; *a++ = 0;
319 *a++ = imm & 255; *a++ = imm >> 8;
320
321 /* 99 cltd */
322 *a++ = 0x99;
323
324 store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
325 *addrp = a;
326
327 rt0:
328 bintrans_write_pc_inc(addrp);
329 return 1;
330 }
331
332
333 /*
334 * bintrans_write_instruction__jr():
335 */
336 static int bintrans_write_instruction__jr(unsigned char **addrp,
337 int rs, int rd, int special)
338 {
339 unsigned char *a;
340 int ofs;
341
342 a = *addrp;
343
344 /*
345 * Perform the jump by setting cpu->delay_slot = TO_BE_DELAYED
346 * and cpu->delay_jmpaddr = gpr[rs].
347 */
348
349 /* c7 86 38 30 00 00 01 00 00 00 movl $0x1,0x3038(%esi) */
350 ofs = ((size_t)&dummy_cpu.cd.mips.delay_slot) - (size_t)&dummy_cpu;
351 *a++ = 0xc7; *a++ = 0x86;
352 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
353 *a++ = TO_BE_DELAYED; *a++ = 0; *a++ = 0; *a++ = 0;
354
355 #if 0
356 if (bintrans_32bit_only)
357 load_into_eax_and_sign_extend_into_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
358 else
359 #endif
360 load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
361
362 store_eax_edx(&a, &dummy_cpu.cd.mips.delay_jmpaddr);
363
364 if (special == SPECIAL_JALR && rd != 0) {
365 /* gpr[rd] = retaddr (pc + 8) */
366
367 #if 0
368 if (bintrans_32bit_only) {
369 load_pc_into_eax_edx(&a);
370 /* 83 c0 08 add $0x8,%eax */
371 *a++ = 0x83; *a++ = 0xc0; *a++ = 0x08;
372 } else
373 #endif
374 {
375 load_pc_into_eax_edx(&a);
376 /* 83 c0 08 add $0x8,%eax */
377 /* 83 d2 00 adc $0x0,%edx */
378 *a++ = 0x83; *a++ = 0xc0; *a++ = 0x08;
379 *a++ = 0x83; *a++ = 0xd2; *a++ = 0x00;
380 }
381
382 store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rd]);
383 }
384
385 *addrp = a;
386 bintrans_write_pc_inc(addrp);
387 return 1;
388 }
389
390
391 /*
392 * bintrans_write_instruction__mfmthilo():
393 */
394 static int bintrans_write_instruction__mfmthilo(unsigned char **addrp,
395 int rd, int from_flag, int hi_flag)
396 {
397 unsigned char *a;
398
399 a = *addrp;
400
401 if (from_flag) {
402 if (rd != 0) {
403 /* mfhi or mflo */
404 if (hi_flag)
405 load_into_eax_edx(&a, &dummy_cpu.cd.mips.hi);
406 else
407 load_into_eax_edx(&a, &dummy_cpu.cd.mips.lo);
408 store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rd]);
409 }
410 } else {
411 /* mthi or mtlo */
412 load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rd]);
413 if (hi_flag)
414 store_eax_edx(&a, &dummy_cpu.cd.mips.hi);
415 else
416 store_eax_edx(&a, &dummy_cpu.cd.mips.lo);
417 }
418
419 *addrp = a;
420 bintrans_write_pc_inc(addrp);
421 return 1;
422 }
423
424
425 /*
426 * bintrans_write_instruction__addiu_etc():
427 */
428 static int bintrans_write_instruction__addiu_etc(
429 struct memory *mem, unsigned char **addrp,
430 int rt, int rs, int imm, int instruction_type)
431 {
432 unsigned char *a;
433 unsigned int uimm;
434
435 /* TODO: overflow detection for ADDI and DADDI */
436 switch (instruction_type) {
437 case HI6_ADDI:
438 case HI6_DADDI:
439 return 0;
440 }
441
442 a = *addrp;
443
444 if (rt == 0)
445 goto rt0;
446
447 uimm = imm & 0xffff;
448
449 if (uimm == 0 && (instruction_type == HI6_ADDIU ||
450 instruction_type == HI6_ADDI)) {
451 load_into_eax_and_sign_extend_into_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
452 store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
453 goto rt0;
454 }
455
456 if (uimm == 0 && (instruction_type == HI6_DADDIU ||
457 instruction_type == HI6_DADDI || instruction_type == HI6_ORI)) {
458 load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
459 store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
460 goto rt0;
461 }
462
463 if (mem->bintrans_32bit_only)
464 load_into_eax_and_sign_extend_into_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
465 else
466 load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
467
468 switch (instruction_type) {
469 case HI6_ADDIU:
470 case HI6_DADDIU:
471 case HI6_ADDI:
472 case HI6_DADDI:
473 if (imm & 0x8000) {
474 /* 05 39 fd ff ff add $0xfffffd39,%eax */
475 /* 83 d2 ff adc $0xffffffff,%edx */
476 *a++ = 0x05; *a++ = uimm; *a++ = uimm >> 8; *a++ = 0xff; *a++ = 0xff;
477 if (instruction_type == HI6_DADDIU) {
478 *a++ = 0x83; *a++ = 0xd2; *a++ = 0xff;
479 }
480 } else {
481 /* 05 c7 02 00 00 add $0x2c7,%eax */
482 /* 83 d2 00 adc $0x0,%edx */
483 *a++ = 0x05; *a++ = uimm; *a++ = uimm >> 8; *a++ = 0; *a++ = 0;
484 if (instruction_type == HI6_DADDIU) {
485 *a++ = 0x83; *a++ = 0xd2; *a++ = 0;
486 }
487 }
488 if (instruction_type == HI6_ADDIU) {
489 /* 99 cltd */
490 *a++ = 0x99;
491 }
492 break;
493 case HI6_ANDI:
494 /* 25 34 12 00 00 and $0x1234,%eax */
495 /* 31 d2 xor %edx,%edx */
496 *a++ = 0x25; *a++ = uimm; *a++ = uimm >> 8; *a++ = 0; *a++ = 0;
497 *a++ = 0x31; *a++ = 0xd2;
498 break;
499 case HI6_ORI:
500 /* 0d 34 12 00 00 or $0x1234,%eax */
501 *a++ = 0xd; *a++ = uimm; *a++ = uimm >> 8; *a++ = 0; *a++ = 0;
502 break;
503 case HI6_XORI:
504 /* 35 34 12 00 00 xor $0x1234,%eax */
505 *a++ = 0x35; *a++ = uimm; *a++ = uimm >> 8; *a++ = 0; *a++ = 0;
506 break;
507 case HI6_SLTIU:
508 /* set if less than, unsigned. (compare edx:eax to ecx:ebx) */
509 /* ecx:ebx = the immediate value */
510 /* bb dc fe ff ff mov $0xfffffedc,%ebx */
511 /* b9 ff ff ff ff mov $0xffffffff,%ecx */
512 /* or */
513 /* 29 c9 sub %ecx,%ecx */
514 #if 0
515 if (bintrans_32bit_only) {
516 /* 99 cltd */
517 *a++ = 0x99;
518 }
519 #endif
520 *a++ = 0xbb; *a++ = uimm; *a++ = uimm >> 8;
521 if (uimm & 0x8000) {
522 *a++ = 0xff; *a++ = 0xff;
523 *a++ = 0xb9; *a++ = 0xff; *a++ = 0xff; *a++ = 0xff; *a++ = 0xff;
524 } else {
525 *a++ = 0; *a++ = 0;
526 *a++ = 0x29; *a++ = 0xc9;
527 }
528
529 /* if edx <= ecx and eax < ebx then 1, else 0. */
530 /* 39 ca cmp %ecx,%edx */
531 /* 77 0b ja <ret0> */
532 /* 39 d8 cmp %ebx,%eax */
533 /* 73 07 jae 58 <ret0> */
534 *a++ = 0x39; *a++ = 0xca;
535 *a++ = 0x77; *a++ = 0x0b;
536 *a++ = 0x39; *a++ = 0xd8;
537 *a++ = 0x73; *a++ = 0x07;
538
539 /* b8 01 00 00 00 mov $0x1,%eax */
540 /* eb 02 jmp <common> */
541 *a++ = 0xb8; *a++ = 1; *a++ = 0; *a++ = 0; *a++ = 0;
542 *a++ = 0xeb; *a++ = 0x02;
543
544 /* ret0: */
545 /* 29 c0 sub %eax,%eax */
546 *a++ = 0x29; *a++ = 0xc0;
547
548 /* common: */
549 /* 99 cltd */
550 *a++ = 0x99;
551 break;
552 case HI6_SLTI:
553 /* set if less than, signed. (compare edx:eax to ecx:ebx) */
554 /* ecx:ebx = the immediate value */
555 /* bb dc fe ff ff mov $0xfffffedc,%ebx */
556 /* b9 ff ff ff ff mov $0xffffffff,%ecx */
557 /* or */
558 /* 29 c9 sub %ecx,%ecx */
559 #if 0
560 if (bintrans_32bit_only) {
561 /* 99 cltd */
562 *a++ = 0x99;
563 }
564 #endif
565 *a++ = 0xbb; *a++ = uimm; *a++ = uimm >> 8;
566 if (uimm & 0x8000) {
567 *a++ = 0xff; *a++ = 0xff;
568 *a++ = 0xb9; *a++ = 0xff; *a++ = 0xff; *a++ = 0xff; *a++ = 0xff;
569 } else {
570 *a++ = 0; *a++ = 0;
571 *a++ = 0x29; *a++ = 0xc9;
572 }
573
574 /* if edx > ecx then 0. */
575 /* if edx < ecx then 1. */
576 /* if eax < ebx then 1, else 0. */
577 /* 39 ca cmp %ecx,%edx */
578 /* 7c 0a jl <ret1> */
579 /* 7f 04 jg <ret0> */
580 /* 39 d8 cmp %ebx,%eax */
581 /* 7c 04 jl <ret1> */
582 *a++ = 0x39; *a++ = 0xca;
583 *a++ = 0x7c; *a++ = 0x0a;
584 *a++ = 0x7f; *a++ = 0x04;
585 *a++ = 0x39; *a++ = 0xd8;
586 *a++ = 0x7c; *a++ = 0x04;
587
588 /* ret0: */
589 /* 29 c0 sub %eax,%eax */
590 /* eb 05 jmp <common> */
591 *a++ = 0x29; *a++ = 0xc0;
592 *a++ = 0xeb; *a++ = 0x05;
593
594 /* ret1: */
595 /* b8 01 00 00 00 mov $0x1,%eax */
596 *a++ = 0xb8; *a++ = 1; *a++ = 0; *a++ = 0; *a++ = 0;
597
598 /* common: */
599 /* 99 cltd */
600 *a++ = 0x99;
601 break;
602 }
603
604 store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
605
606 rt0:
607 *addrp = a;
608 bintrans_write_pc_inc(addrp);
609 return 1;
610 }
611
612
613 /*
614 * bintrans_write_instruction__jal():
615 */
616 static int bintrans_write_instruction__jal(unsigned char **addrp,
617 int imm, int link)
618 {
619 unsigned char *a;
620 uint32_t subimm;
621 int ofs;
622
623 a = *addrp;
624
625 load_pc_into_eax_edx(&a);
626
627 if (link) {
628 /* gpr[31] = pc + 8 */
629 #if 0
630 if (bintrans_32bit_only) {
631 /* 50 push %eax */
632 /* 83 c0 08 add $0x8,%eax */
633 *a++ = 0x50;
634 *a++ = 0x83; *a++ = 0xc0; *a++ = 0x08;
635 } else
636 #endif
637 {
638 /* 50 push %eax */
639 /* 52 push %edx */
640 /* 83 c0 08 add $0x8,%eax */
641 /* 83 d2 00 adc $0x0,%edx */
642 *a++ = 0x50;
643 *a++ = 0x52;
644 *a++ = 0x83; *a++ = 0xc0; *a++ = 0x08;
645 *a++ = 0x83; *a++ = 0xd2; *a++ = 0x00;
646 }
647 store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[31]);
648 #if 0
649 if (bintrans_32bit_only) {
650 /* 58 pop %eax */
651 *a++ = 0x58;
652 } else
653 #endif
654 {
655 /* 5a pop %edx */
656 /* 58 pop %eax */
657 *a++ = 0x5a;
658 *a++ = 0x58;
659 }
660 }
661
662 /* delay_jmpaddr = top 36 bits of pc together with lowest 28 bits of imm*4: */
663 imm *= 4;
664
665 /* Add 4, because the jump is from the delay slot: */
666 /* 83 c0 04 add $0x4,%eax */
667 /* 83 d2 00 adc $0x0,%edx */
668 *a++ = 0x83; *a++ = 0xc0; *a++ = 0x04;
669 *a++ = 0x83; *a++ = 0xd2; *a++ = 0x00;
670
671 /* c1 e8 1c shr $0x1c,%eax */
672 /* c1 e0 1c shl $0x1c,%eax */
673 *a++ = 0xc1; *a++ = 0xe8; *a++ = 0x1c;
674 *a++ = 0xc1; *a++ = 0xe0; *a++ = 0x1c;
675
676 subimm = imm;
677 subimm &= 0x0fffffff;
678
679 /* 0d 78 56 34 12 or $0x12345678,%eax */
680 *a++ = 0x0d; *a++ = subimm; *a++ = subimm >> 8;
681 *a++ = subimm >> 16; *a++ = subimm >> 24;
682
683 store_eax_edx(&a, &dummy_cpu.cd.mips.delay_jmpaddr);
684
685 /* c7 86 38 30 00 00 01 00 00 00 movl $0x1,0x3038(%esi) */
686 ofs = ((size_t)&dummy_cpu.cd.mips.delay_slot) - (size_t)&dummy_cpu;
687 *a++ = 0xc7; *a++ = 0x86;
688 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
689 *a++ = TO_BE_DELAYED; *a++ = 0; *a++ = 0; *a++ = 0;
690
691 *addrp = a;
692 bintrans_write_pc_inc(addrp);
693 return 1;
694 }
695
696
697 /*
698 * bintrans_write_instruction__addu_etc():
699 */
700 static int bintrans_write_instruction__addu_etc(
701 struct memory *mem, unsigned char **addrp,
702 int rd, int rs, int rt, int sa, int instruction_type)
703 {
704 unsigned char *a;
705 int load64 = 0, do_store = 1;
706
707 /* TODO: Not yet */
708 switch (instruction_type) {
709 case SPECIAL_MULT:
710 case SPECIAL_MULTU:
711 case SPECIAL_DIV:
712 case SPECIAL_DIVU:
713 if (rd != 0)
714 return 0;
715 break;
716 case SPECIAL_DSLL:
717 case SPECIAL_DSLL32:
718 case SPECIAL_DSRA:
719 case SPECIAL_DSRA32:
720 case SPECIAL_DSRL:
721 case SPECIAL_DSRL32:
722 case SPECIAL_MOVZ:
723 case SPECIAL_MOVN:
724 bintrans_write_chunkreturn_fail(addrp);
725 return 0;
726 case SPECIAL_SLT:
727 case SPECIAL_SLTU:
728 if (!mem->bintrans_32bit_only) {
729 bintrans_write_chunkreturn_fail(addrp);
730 return 0;
731 }
732 break;
733 }
734
735 switch (instruction_type) {
736 case SPECIAL_DADDU:
737 case SPECIAL_DSUBU:
738 case SPECIAL_OR:
739 case SPECIAL_AND:
740 case SPECIAL_NOR:
741 case SPECIAL_XOR:
742 case SPECIAL_DSLL:
743 case SPECIAL_DSRL:
744 case SPECIAL_DSRA:
745 case SPECIAL_DSLL32:
746 case SPECIAL_DSRL32:
747 case SPECIAL_DSRA32:
748 load64 = 1;
749 }
750
751 switch (instruction_type) {
752 case SPECIAL_MULT:
753 case SPECIAL_MULTU:
754 case SPECIAL_DIV:
755 case SPECIAL_DIVU:
756 break;
757 default:
758 if (rd == 0)
759 goto rd0;
760 }
761
762 a = *addrp;
763
764 if ((instruction_type == SPECIAL_ADDU || instruction_type == SPECIAL_DADDU
765 || instruction_type == SPECIAL_OR) && rt == 0) {
766 if (load64)
767 load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
768 else
769 load_into_eax_and_sign_extend_into_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
770 store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rd]);
771 *addrp = a;
772 goto rd0;
773 }
774
775 /* edx:eax = rs, ecx:ebx = rt */
776 if (load64 && !mem->bintrans_32bit_only) {
777 load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
778 /* 89 c3 mov %eax,%ebx */
779 /* 89 d1 mov %edx,%ecx */
780 *a++ = 0x89; *a++ = 0xc3; *a++ = 0x89; *a++ = 0xd1;
781 load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
782 } else {
783 load_into_eax_and_sign_extend_into_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
784 /* 89 c3 mov %eax,%ebx */
785 /* 89 d1 mov %edx,%ecx */
786 *a++ = 0x89; *a++ = 0xc3; *a++ = 0x89; *a++ = 0xd1;
787 load_into_eax_and_sign_extend_into_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
788 }
789
790 switch (instruction_type) {
791 case SPECIAL_ADDU:
792 /* 01 d8 add %ebx,%eax */
793 /* 99 cltd */
794 *a++ = 0x01; *a++ = 0xd8;
795 *a++ = 0x99;
796 break;
797 case SPECIAL_DADDU:
798 /* 01 d8 add %ebx,%eax */
799 /* 11 ca adc %ecx,%edx */
800 *a++ = 0x01; *a++ = 0xd8;
801 *a++ = 0x11; *a++ = 0xca;
802 break;
803 case SPECIAL_SUBU:
804 /* 29 d8 sub %ebx,%eax */
805 /* 99 cltd */
806 *a++ = 0x29; *a++ = 0xd8;
807 *a++ = 0x99;
808 break;
809 case SPECIAL_DSUBU:
810 /* 29 d8 sub %ebx,%eax */
811 /* 19 ca sbb %ecx,%edx */
812 *a++ = 0x29; *a++ = 0xd8;
813 *a++ = 0x19; *a++ = 0xca;
814 break;
815 case SPECIAL_AND:
816 /* 21 d8 and %ebx,%eax */
817 /* 21 ca and %ecx,%edx */
818 *a++ = 0x21; *a++ = 0xd8;
819 *a++ = 0x21; *a++ = 0xca;
820 break;
821 case SPECIAL_OR:
822 /* 09 d8 or %ebx,%eax */
823 /* 09 ca or %ecx,%edx */
824 *a++ = 0x09; *a++ = 0xd8;
825 *a++ = 0x09; *a++ = 0xca;
826 break;
827 case SPECIAL_NOR:
828 /* 09 d8 or %ebx,%eax */
829 /* 09 ca or %ecx,%edx */
830 /* f7 d0 not %eax */
831 /* f7 d2 not %edx */
832 *a++ = 0x09; *a++ = 0xd8;
833 *a++ = 0x09; *a++ = 0xca;
834 *a++ = 0xf7; *a++ = 0xd0;
835 *a++ = 0xf7; *a++ = 0xd2;
836 break;
837 case SPECIAL_XOR:
838 /* 31 d8 xor %ebx,%eax */
839 /* 31 ca xor %ecx,%edx */
840 *a++ = 0x31; *a++ = 0xd8;
841 *a++ = 0x31; *a++ = 0xca;
842 break;
843 case SPECIAL_SLL:
844 /* 89 d8 mov %ebx,%eax */
845 /* c1 e0 1f shl $0x1f,%eax */
846 /* 99 cltd */
847 *a++ = 0x89; *a++ = 0xd8;
848 if (sa == 1) {
849 *a++ = 0xd1; *a++ = 0xe0;
850 } else {
851 *a++ = 0xc1; *a++ = 0xe0; *a++ = sa;
852 }
853 *a++ = 0x99;
854 break;
855 case SPECIAL_SRA:
856 /* 89 d8 mov %ebx,%eax */
857 /* c1 f8 1f sar $0x1f,%eax */
858 /* 99 cltd */
859 *a++ = 0x89; *a++ = 0xd8;
860 if (sa == 1) {
861 *a++ = 0xd1; *a++ = 0xf8;
862 } else {
863 *a++ = 0xc1; *a++ = 0xf8; *a++ = sa;
864 }
865 *a++ = 0x99;
866 break;
867 case SPECIAL_SRL:
868 /* 89 d8 mov %ebx,%eax */
869 /* c1 e8 1f shr $0x1f,%eax */
870 /* 99 cltd */
871 *a++ = 0x89; *a++ = 0xd8;
872 if (sa == 1) {
873 *a++ = 0xd1; *a++ = 0xe8;
874 } else {
875 *a++ = 0xc1; *a++ = 0xe8; *a++ = sa;
876 }
877 *a++ = 0x99;
878 break;
879 case SPECIAL_SLTU:
880 /* NOTE: 32-bit ONLY! */
881 /* set if less than, unsigned. (compare eax to ebx) */
882 /* 39 d8 cmp %ebx,%eax */
883 /* 73 07 jae 58 <ret0> */
884 *a++ = 0x39; *a++ = 0xd8;
885 *a++ = 0x73; *a++ = 0x07;
886
887 /* b8 01 00 00 00 mov $0x1,%eax */
888 /* eb 02 jmp <common> */
889 *a++ = 0xb8; *a++ = 1; *a++ = 0; *a++ = 0; *a++ = 0;
890 *a++ = 0xeb; *a++ = 0x02;
891
892 /* ret0: */
893 /* 29 c0 sub %eax,%eax */
894 *a++ = 0x29; *a++ = 0xc0;
895
896 /* common: */
897 /* 99 cltd */
898 *a++ = 0x99;
899 break;
900 case SPECIAL_SLT:
901 /* NOTE: 32-bit ONLY! */
902 /* set if less than, signed. (compare eax to ebx) */
903 /* 39 d8 cmp %ebx,%eax */
904 /* 7c 04 jl <ret1> */
905 *a++ = 0x39; *a++ = 0xd8;
906 *a++ = 0x7c; *a++ = 0x04;
907
908 /* ret0: */
909 /* 29 c0 sub %eax,%eax */
910 /* eb 05 jmp <common> */
911 *a++ = 0x29; *a++ = 0xc0;
912 *a++ = 0xeb; *a++ = 0x05;
913
914 /* ret1: */
915 /* b8 01 00 00 00 mov $0x1,%eax */
916 *a++ = 0xb8; *a++ = 1; *a++ = 0; *a++ = 0; *a++ = 0;
917
918 /* common: */
919 /* 99 cltd */
920 *a++ = 0x99;
921 break;
922 case SPECIAL_SLLV:
923 /* rd = rt << (rs&31) (logical) eax = ebx << (eax&31) */
924 /* xchg ebx,eax, then we can do eax = eax << (ebx&31) */
925 /* 93 xchg %eax,%ebx */
926 /* 89 d9 mov %ebx,%ecx */
927 /* 83 e1 1f and $0x1f,%ecx */
928 /* d3 e0 shl %cl,%eax */
929 *a++ = 0x93;
930 *a++ = 0x89; *a++ = 0xd9;
931 *a++ = 0x83; *a++ = 0xe1; *a++ = 0x1f;
932 *a++ = 0xd3; *a++ = 0xe0;
933 /* 99 cltd */
934 *a++ = 0x99;
935 break;
936 case SPECIAL_SRLV:
937 /* rd = rt >> (rs&31) (logical) eax = ebx >> (eax&31) */
938 /* xchg ebx,eax, then we can do eax = eax >> (ebx&31) */
939 /* 93 xchg %eax,%ebx */
940 /* 89 d9 mov %ebx,%ecx */
941 /* 83 e1 1f and $0x1f,%ecx */
942 /* d3 e8 shr %cl,%eax */
943 *a++ = 0x93;
944 *a++ = 0x89; *a++ = 0xd9;
945 *a++ = 0x83; *a++ = 0xe1; *a++ = 0x1f;
946 *a++ = 0xd3; *a++ = 0xe8;
947 /* 99 cltd */
948 *a++ = 0x99;
949 break;
950 case SPECIAL_SRAV:
951 /* rd = rt >> (rs&31) (arithmetic) eax = ebx >> (eax&31) */
952 /* xchg ebx,eax, then we can do eax = eax >> (ebx&31) */
953 /* 93 xchg %eax,%ebx */
954 /* 89 d9 mov %ebx,%ecx */
955 /* 83 e1 1f and $0x1f,%ecx */
956 /* d3 f8 sar %cl,%eax */
957 *a++ = 0x93;
958 *a++ = 0x89; *a++ = 0xd9;
959 *a++ = 0x83; *a++ = 0xe1; *a++ = 0x1f;
960 *a++ = 0xd3; *a++ = 0xf8;
961 /* 99 cltd */
962 *a++ = 0x99;
963 break;
964 case SPECIAL_MULT:
965 case SPECIAL_MULTU:
966 /* 57 push %edi */
967 *a++ = 0x57;
968 if (instruction_type == SPECIAL_MULT) {
969 /* f7 eb imul %ebx */
970 *a++ = 0xf7; *a++ = 0xeb;
971 } else {
972 /* f7 e3 mul %ebx */
973 *a++ = 0xf7; *a++ = 0xe3;
974 }
975 /* here: edx:eax = hi:lo */
976 /* 89 d7 mov %edx,%edi */
977 /* 99 cltd */
978 *a++ = 0x89; *a++ = 0xd7;
979 *a++ = 0x99;
980 /* here: edi=hi, edx:eax = sign-extended lo */
981 store_eax_edx(&a, &dummy_cpu.cd.mips.lo);
982 /* 89 f8 mov %edi,%eax */
983 /* 99 cltd */
984 *a++ = 0x89; *a++ = 0xf8;
985 *a++ = 0x99;
986 /* here: edx:eax = sign-extended hi */
987 store_eax_edx(&a, &dummy_cpu.cd.mips.hi);
988 /* 5f pop %edi */
989 *a++ = 0x5f;
990 do_store = 0;
991 break;
992 case SPECIAL_DIV:
993 case SPECIAL_DIVU:
994 /*
995 * In: edx:eax = rs, ecx:ebx = rt
996 * Out: LO = rs / rt, HI = rs % rt
997 */
998 /* Division by zero on MIPS is undefined, but on
999 i386 it causes an exception, so we'll try to
1000 avoid that. */
1001 *a++ = 0x83; *a++ = 0xfb; *a++ = 0x00; /* cmp $0x0,%ebx */
1002 *a++ = 0x75; *a++ = 0x01; /* jne skip_inc */
1003 *a++ = 0x43; /* inc %ebx */
1004
1005 /* 57 push %edi */
1006 *a++ = 0x57;
1007 if (instruction_type == SPECIAL_DIV) {
1008 *a++ = 0x99; /* cltd */
1009 *a++ = 0xf7; *a++ = 0xfb; /* idiv %ebx */
1010 } else {
1011 *a++ = 0x29; *a++ = 0xd2; /* sub %edx,%edx */
1012 *a++ = 0xf7; *a++ = 0xf3; /* div %ebx */
1013 }
1014 /* here: edx:eax = hi:lo */
1015 /* 89 d7 mov %edx,%edi */
1016 /* 99 cltd */
1017 *a++ = 0x89; *a++ = 0xd7;
1018 *a++ = 0x99;
1019 /* here: edi=hi, edx:eax = sign-extended lo */
1020 store_eax_edx(&a, &dummy_cpu.cd.mips.lo);
1021 /* 89 f8 mov %edi,%eax */
1022 /* 99 cltd */
1023 *a++ = 0x89; *a++ = 0xf8;
1024 *a++ = 0x99;
1025 /* here: edx:eax = sign-extended hi */
1026 store_eax_edx(&a, &dummy_cpu.cd.mips.hi);
1027 /* 5f pop %edi */
1028 *a++ = 0x5f;
1029 do_store = 0;
1030 break;
1031 #if 0
1032 /* TODO: These are from bintrans_alpha.c. Translate them to i386. */
1033
1034 case SPECIAL_DSLL:
1035 *a++ = 0x21; *a++ = 0x17 + ((sa & 7) << 5); *a++ = 0x40 + (sa >> 3); *a++ = 0x48; /* sll t1,sa,t0 */
1036 break;
1037 case SPECIAL_DSLL32:
1038 sa += 32;
1039 *a++ = 0x21; *a++ = 0x17 + ((sa & 7) << 5); *a++ = 0x40 + (sa >> 3); *a++ = 0x48; /* sll t1,sa,t0 */
1040 break;
1041 case SPECIAL_DSRA:
1042 *a++ = 0x81; *a++ = 0x17 + ((sa & 7) << 5); *a++ = 0x40 + (sa >> 3); *a++ = 0x48; /* sra t1,sa,t0 */
1043 break;
1044 case SPECIAL_DSRA32:
1045 sa += 32;
1046 *a++ = 0x81; *a++ = 0x17 + ((sa & 7) << 5); *a++ = 0x40 + (sa >> 3); *a++ = 0x48; /* sra t1,sa,t0 */
1047 break;
1048 case SPECIAL_DSRL:
1049 /* Note: bits of sa are distributed among two different bytes. */
1050 *a++ = 0x81; *a++ = 0x16 + ((sa & 7) << 5); *a++ = 0x40 + (sa >> 3); *a++ = 0x48;
1051 break;
1052 case SPECIAL_DSRL32:
1053 /* Note: bits of sa are distributed among two different bytes. */
1054 sa += 32;
1055 *a++ = 0x81; *a++ = 0x16 + ((sa & 7) << 5); *a++ = 0x40 + (sa >> 3); *a++ = 0x48;
1056 break;
1057 #endif
1058 }
1059
1060 if (do_store)
1061 store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rd]);
1062
1063 *addrp = a;
1064 rd0:
1065 bintrans_write_pc_inc(addrp);
1066 return 1;
1067 }
1068
1069
1070 /*
1071 * bintrans_write_instruction__mfc_mtc():
1072 */
1073 static int bintrans_write_instruction__mfc_mtc(struct memory *mem,
1074 unsigned char **addrp, int coproc_nr, int flag64bit, int rt,
1075 int rd, int mtcflag)
1076 {
1077 unsigned char *a, *failskip;
1078 int ofs;
1079
1080 if (mtcflag && flag64bit) {
1081 /* dmtc */
1082 return 0;
1083 }
1084
1085 /*
1086 * NOTE: Only a few registers are readable without side effects.
1087 */
1088 if (rt == 0 && !mtcflag)
1089 return 0;
1090
1091 if (coproc_nr >= 1)
1092 return 0;
1093
1094 if (rd == COP0_RANDOM || rd == COP0_COUNT)
1095 return 0;
1096
1097 a = *addrp;
1098
1099 /*************************************************************
1100 *
1101 * TODO: Check for kernel mode, or Coproc X usability bit!
1102 *
1103 *************************************************************/
1104
1105 /* 8b 96 3c 30 00 00 mov 0x303c(%esi),%edx */
1106 ofs = ((size_t)&dummy_cpu.cd.mips.coproc[0]) - (size_t)&dummy_cpu;
1107 *a++ = 0x8b; *a++ = 0x96;
1108 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1109
1110 /* here, edx = cpu->coproc[0] */
1111
1112 if (mtcflag) {
1113 /* mtc */
1114
1115 /* TODO: This code only works for mtc0, not dmtc0 */
1116
1117 /* 8b 9a 38 30 00 00 mov 0x3038(%edx),%ebx */
1118 ofs = ((size_t)&dummy_coproc.reg[rd]) - (size_t)&dummy_coproc;
1119 *a++ = 0x8b; *a++ = 0x9a;
1120 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1121
1122 load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
1123
1124 /*
1125 * Here: eax contains the value in register rt,
1126 * ebx contains the coproc register rd value.
1127 *
1128 * In the general case, only allow mtc if it does not
1129 * change the coprocessor register!
1130 */
1131
1132 switch (rd) {
1133
1134 case COP0_INDEX:
1135 break;
1136
1137 case COP0_ENTRYLO0:
1138 case COP0_ENTRYLO1:
1139 /* TODO: Not all bits are writable! */
1140 break;
1141
1142 case COP0_EPC:
1143 break;
1144
1145 case COP0_STATUS:
1146 /* Only allow updates to the status register if
1147 the interrupt enable bits were changed, but no
1148 other bits! */
1149 /* 89 c1 mov %eax,%ecx */
1150 /* 89 da mov %ebx,%edx */
1151 /* 81 e1 00 00 e7 0f and $0x0fe70000,%ecx */
1152 /* 81 e2 00 00 e7 0f and $0x0fe70000,%edx */
1153 /* 39 ca cmp %ecx,%edx */
1154 /* 74 01 je <ok> */
1155 *a++ = 0x89; *a++ = 0xc1;
1156 *a++ = 0x89; *a++ = 0xda;
1157 *a++ = 0x81; *a++ = 0xe1; *a++ = 0x00; *a++ = 0x00;
1158 if (mem->bintrans_32bit_only) {
1159 *a++ = 0xe7; *a++ = 0x0f;
1160 } else {
1161 *a++ = 0xff; *a++ = 0xff;
1162 }
1163 *a++ = 0x81; *a++ = 0xe2; *a++ = 0x00; *a++ = 0x00;
1164 if (mem->bintrans_32bit_only) {
1165 *a++ = 0xe7; *a++ = 0x0f;
1166 } else {
1167 *a++ = 0xff; *a++ = 0xff;
1168 }
1169 *a++ = 0x39; *a++ = 0xca;
1170 *a++ = 0x74; failskip = a; *a++ = 0x00;
1171 bintrans_write_chunkreturn_fail(&a);
1172 *failskip = (size_t)a - (size_t)failskip - 1;
1173
1174 /* Only allow the update if it would NOT cause
1175 an interrupt exception: */
1176
1177 /* 8b 96 3c 30 00 00 mov 0x303c(%esi),%edx */
1178 ofs = ((size_t)&dummy_cpu.cd.mips.coproc[0]) - (size_t)&dummy_cpu;
1179 *a++ = 0x8b; *a++ = 0x96;
1180 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1181
1182 /* 8b 9a 38 30 00 00 mov 0x3038(%edx),%ebx */
1183 ofs = ((size_t)&dummy_coproc.reg[COP0_CAUSE]) - (size_t)&dummy_coproc;
1184 *a++ = 0x8b; *a++ = 0x9a;
1185 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1186
1187 /* 21 c3 and %eax,%ebx */
1188 /* 81 e3 00 ff 00 00 and $0xff00,%ebx */
1189 /* 83 fb 00 cmp $0x0,%ebx */
1190 /* 74 01 je <ok> */
1191 *a++ = 0x21; *a++ = 0xc3;
1192 *a++ = 0x81; *a++ = 0xe3; *a++ = 0x00;
1193 *a++ = 0xff; *a++ = 0x00; *a++ = 0x00;
1194 *a++ = 0x83; *a++ = 0xfb; *a++ = 0x00;
1195 *a++ = 0x74; failskip = a; *a++ = 0x00;
1196 bintrans_write_chunkreturn_fail(&a);
1197 *failskip = (size_t)a - (size_t)failskip - 1;
1198
1199 break;
1200
1201 default:
1202 /* 39 d8 cmp %ebx,%eax */
1203 /* 74 01 je <ok> */
1204 *a++ = 0x39; *a++ = 0xd8;
1205 *a++ = 0x74; failskip = a; *a++ = 0x00;
1206 bintrans_write_chunkreturn_fail(&a);
1207 *failskip = (size_t)a - (size_t)failskip - 1;
1208 }
1209
1210 /* 8b 96 3c 30 00 00 mov 0x303c(%esi),%edx */
1211 ofs = ((size_t)&dummy_cpu.cd.mips.coproc[0]) - (size_t)&dummy_cpu;
1212 *a++ = 0x8b; *a++ = 0x96;
1213 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1214
1215 /* 8d 9a 38 30 00 00 lea 0x3038(%edx),%ebx */
1216 ofs = ((size_t)&dummy_coproc.reg[rd]) - (size_t)&dummy_coproc;
1217 *a++ = 0x8d; *a++ = 0x9a;
1218 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1219
1220 /* Sign-extend eax into edx:eax, and store it in
1221 coprocessor register rd: */
1222 /* 99 cltd */
1223 *a++ = 0x99;
1224
1225 /* 89 03 mov %eax,(%ebx) */
1226 /* 89 53 04 mov %edx,0x4(%ebx) */
1227 *a++ = 0x89; *a++ = 0x03;
1228 *a++ = 0x89; *a++ = 0x53; *a++ = 0x04;
1229 } else {
1230 /* mfc */
1231
1232 /* 8b 82 38 30 00 00 mov 0x3038(%edx),%eax */
1233 ofs = ((size_t)&dummy_coproc.reg[rd]) - (size_t)&dummy_coproc;
1234 *a++ = 0x8b; *a++ = 0x82;
1235 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1236
1237 if (flag64bit) {
1238 /* Load high 32 bits: (note: edx gets overwritten) */
1239 /* 8b 92 3c 30 00 00 mov 0x303c(%edx),%edx */
1240 ofs += 4;
1241 *a++ = 0x8b; *a++ = 0x92;
1242 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1243 } else {
1244 /* 99 cltd */
1245 *a++ = 0x99;
1246 }
1247
1248 store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
1249 }
1250
1251 *addrp = a;
1252 bintrans_write_pc_inc(addrp);
1253 return 1;
1254 }
1255
1256
1257 /*
1258 * bintrans_write_instruction__branch():
1259 */
1260 static int bintrans_write_instruction__branch(unsigned char **addrp,
1261 int instruction_type, int regimm_type, int rt, int rs, int imm)
1262 {
1263 unsigned char *a;
1264 unsigned char *skip1 = NULL, *skip2 = NULL;
1265 int ofs, likely = 0;
1266
1267 switch (instruction_type) {
1268 case HI6_BEQL:
1269 case HI6_BNEL:
1270 case HI6_BLEZL:
1271 case HI6_BGTZL:
1272 likely = 1;
1273 }
1274
1275 /* TODO: See the Alpha backend on how these could be implemented: */
1276 if (likely)
1277 return 0;
1278
1279 a = *addrp;
1280
1281 /*
1282 * edx:eax = gpr[rs]; ecx:ebx = gpr[rt];
1283 *
1284 * Compare for equality (BEQ).
1285 * If the result was zero, then it means equality; perform the
1286 * delayed jump. Otherwise: skip.
1287 */
1288
1289 switch (instruction_type) {
1290 case HI6_BEQ:
1291 case HI6_BNE:
1292 load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
1293 /* 89 c3 mov %eax,%ebx */
1294 /* 89 d1 mov %edx,%ecx */
1295 *a++ = 0x89; *a++ = 0xc3; *a++ = 0x89; *a++ = 0xd1;
1296 }
1297 load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
1298
1299 if (instruction_type == HI6_BEQ && rt != rs) {
1300 /* If rt != rs, then skip. */
1301 /* 39 c3 cmp %eax,%ebx */
1302 /* 75 05 jne 155 <skip> */
1303 /* 39 d1 cmp %edx,%ecx */
1304 /* 75 01 jne 155 <skip> */
1305 *a++ = 0x39; *a++ = 0xc3;
1306 *a++ = 0x75; skip1 = a; *a++ = 0x00;
1307 #if 0
1308 if (!bintrans_32bit_only)
1309 #endif
1310 {
1311 *a++ = 0x39; *a++ = 0xd1;
1312 *a++ = 0x75; skip2 = a; *a++ = 0x00;
1313 }
1314 }
1315
1316 if (instruction_type == HI6_BNE) {
1317 /* If rt != rs, then ok. Otherwise skip. */
1318 #if 0
1319 if (bintrans_32bit_only) {
1320 /* 39 c3 cmp %eax,%ebx */
1321 /* 74 xx je <skip> */
1322 *a++ = 0x39; *a++ = 0xc3;
1323 *a++ = 0x74; skip2 = a; *a++ = 0x00;
1324 } else
1325 #endif
1326 {
1327 /* 39 c3 cmp %eax,%ebx */
1328 /* 75 06 jne 156 <bra> */
1329 /* 39 d1 cmp %edx,%ecx */
1330 /* 75 02 jne 156 <bra> */
1331 /* eb 01 jmp 157 <skip> */
1332 *a++ = 0x39; *a++ = 0xc3;
1333 *a++ = 0x75; *a++ = 0x06;
1334 *a++ = 0x39; *a++ = 0xd1;
1335 *a++ = 0x75; *a++ = 0x02;
1336 *a++ = 0xeb; skip2 = a; *a++ = 0x00;
1337 }
1338 }
1339
1340 if (instruction_type == HI6_BLEZ) {
1341 /* If both eax and edx are zero, then do the branch. */
1342 /* 83 f8 00 cmp $0x0,%eax */
1343 /* 75 07 jne <nott> */
1344 /* 83 fa 00 cmp $0x0,%edx */
1345 /* 75 02 jne 23d <nott> */
1346 /* eb 01 jmp <branch> */
1347 *a++ = 0x83; *a++ = 0xf8; *a++ = 0x00;
1348 *a++ = 0x75; *a++ = 0x07;
1349 *a++ = 0x83; *a++ = 0xfa; *a++ = 0x00;
1350 *a++ = 0x75; *a++ = 0x02;
1351 *a++ = 0xeb; skip1 = a; *a++ = 0x00;
1352
1353 /* If high bit of edx is set, then rs < 0. */
1354 /* f7 c2 00 00 00 80 test $0x80000000,%edx */
1355 /* 74 00 jz skip */
1356 *a++ = 0xf7; *a++ = 0xc2; *a++ = 0; *a++ = 0; *a++ = 0; *a++ = 0x80;
1357 *a++ = 0x74; skip2 = a; *a++ = 0x00;
1358
1359 if (skip1 != NULL)
1360 *skip1 = (size_t)a - (size_t)skip1 - 1;
1361 skip1 = NULL;
1362 }
1363 if (instruction_type == HI6_BGTZ) {
1364 /* If both eax and edx are zero, then skip the branch. */
1365 /* 83 f8 00 cmp $0x0,%eax */
1366 /* 75 07 jne <nott> */
1367 /* 83 fa 00 cmp $0x0,%edx */
1368 /* 75 02 jne 23d <nott> */
1369 /* eb 01 jmp <skip> */
1370 *a++ = 0x83; *a++ = 0xf8; *a++ = 0x00;
1371 *a++ = 0x75; *a++ = 0x07;
1372 *a++ = 0x83; *a++ = 0xfa; *a++ = 0x00;
1373 *a++ = 0x75; *a++ = 0x02;
1374 *a++ = 0xeb; skip1 = a; *a++ = 0x00;
1375
1376 /* If high bit of edx is set, then rs < 0. */
1377 /* f7 c2 00 00 00 80 test $0x80000000,%edx */
1378 /* 75 00 jnz skip */
1379 *a++ = 0xf7; *a++ = 0xc2; *a++ = 0; *a++ = 0; *a++ = 0; *a++ = 0x80;
1380 *a++ = 0x75; skip2 = a; *a++ = 0x00;
1381 }
1382 if (instruction_type == HI6_REGIMM && regimm_type == REGIMM_BLTZ) {
1383 /* If high bit of edx is set, then rs < 0. */
1384 /* f7 c2 00 00 00 80 test $0x80000000,%edx */
1385 /* 74 00 jz skip */
1386 *a++ = 0xf7; *a++ = 0xc2; *a++ = 0; *a++ = 0; *a++ = 0; *a++ = 0x80;
1387 *a++ = 0x74; skip2 = a; *a++ = 0x00;
1388 }
1389 if (instruction_type == HI6_REGIMM && regimm_type == REGIMM_BGEZ) {
1390 /* If high bit of edx is not set, then rs >= 0. */
1391 /* f7 c2 00 00 00 80 test $0x80000000,%edx */
1392 /* 75 00 jnz skip */
1393 *a++ = 0xf7; *a++ = 0xc2; *a++ = 0; *a++ = 0; *a++ = 0; *a++ = 0x80;
1394 *a++ = 0x75; skip2 = a; *a++ = 0x00;
1395 }
1396
1397 /*
1398 * Perform the jump by setting cpu->delay_slot = TO_BE_DELAYED
1399 * and cpu->delay_jmpaddr = pc + 4 + (imm << 2).
1400 */
1401
1402 /* c7 86 38 30 00 00 01 00 00 00 movl $0x1,0x3038(%esi) */
1403 ofs = ((size_t)&dummy_cpu.cd.mips.delay_slot) - (size_t)&dummy_cpu;
1404 *a++ = 0xc7; *a++ = 0x86;
1405 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1406 *a++ = TO_BE_DELAYED; *a++ = 0; *a++ = 0; *a++ = 0;
1407
1408 load_pc_into_eax_edx(&a);
1409
1410 /* 05 78 56 34 12 add $0x12345678,%eax */
1411 /* 83 d2 00 adc $0x0,%edx */
1412 /* or */
1413 /* 83 d2 ff adc $0xffffffff,%edx */
1414 imm = (imm << 2) + 4;
1415 *a++ = 0x05; *a++ = imm; *a++ = imm >> 8; *a++ = imm >> 16; *a++ = imm >> 24;
1416 if (imm >= 0) {
1417 *a++ = 0x83; *a++ = 0xd2; *a++ = 0x00;
1418 } else {
1419 *a++ = 0x83; *a++ = 0xd2; *a++ = 0xff;
1420 }
1421 store_eax_edx(&a, &dummy_cpu.cd.mips.delay_jmpaddr);
1422
1423 if (skip1 != NULL)
1424 *skip1 = (size_t)a - (size_t)skip1 - 1;
1425 if (skip2 != NULL)
1426 *skip2 = (size_t)a - (size_t)skip2 - 1;
1427
1428 *addrp = a;
1429 bintrans_write_pc_inc(addrp);
1430 return 1;
1431 }
1432
1433
1434 /*
1435 * bintrans_write_instruction__delayedbranch():
1436 */
1437 static int bintrans_write_instruction__delayedbranch(struct memory *mem,
1438 unsigned char **addrp, uint32_t *potential_chunk_p, uint32_t *chunks,
1439 int only_care_about_chunk_p, int p, int forward)
1440 {
1441 unsigned char *a, *skip=NULL, *failskip;
1442 int ofs;
1443 uint32_t i386_addr;
1444
1445 a = *addrp;
1446
1447 if (only_care_about_chunk_p)
1448 goto try_chunk_p;
1449
1450 /* Skip all of this if there is no branch: */
1451 ofs = ((size_t)&dummy_cpu.cd.mips.delay_slot) - (size_t)&dummy_cpu;
1452
1453 /* 8b 86 38 30 00 00 mov 0x3038(%esi),%eax */
1454 *a++ = 0x8b; *a++ = 0x86;
1455 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1456
1457 /* 83 f8 00 cmp $0x0,%eax */
1458 /* 74 01 je 16b <skippa> */
1459 *a++ = 0x83; *a++ = 0xf8; *a++ = 0x00;
1460 *a++ = 0x74; skip = a; *a++ = 0;
1461
1462 /*
1463 * Perform the jump by setting cpu->delay_slot = 0
1464 * and pc = cpu->delay_jmpaddr.
1465 */
1466
1467 /* c7 86 38 30 00 00 00 00 00 00 movl $0x0,0x3038(%esi) */
1468 ofs = ((size_t)&dummy_cpu.cd.mips.delay_slot) - (size_t)&dummy_cpu;
1469 *a++ = 0xc7; *a++ = 0x86;
1470 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1471 *a++ = 0; *a++ = 0; *a++ = 0; *a++ = 0;
1472
1473 /* REMEMBER old pc: */
1474 load_pc_into_eax_edx(&a);
1475 /* 89 c3 mov %eax,%ebx */
1476 /* 89 d1 mov %edx,%ecx */
1477 *a++ = 0x89; *a++ = 0xc3;
1478 *a++ = 0x89; *a++ = 0xd1;
1479 load_into_eax_edx(&a, &dummy_cpu.cd.mips.delay_jmpaddr);
1480 store_eax_edx_into_pc(&a);
1481
1482 try_chunk_p:
1483
1484 if (potential_chunk_p == NULL) {
1485 if (mem->bintrans_32bit_only) {
1486 #if 1
1487 /* 8b 86 78 56 34 12 mov 0x12345678(%esi),%eax */
1488 /* ff e0 jmp *%eax */
1489 ofs = ((size_t)&dummy_cpu.cd.mips.bintrans_jump_to_32bit_pc) - (size_t)&dummy_cpu;
1490 *a++ = 0x8b; *a++ = 0x86;
1491 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1492 *a++ = 0xff; *a++ = 0xe0;
1493
1494 #else
1495 /* Don't execute too many instructions. */
1496 /* 81 fd f0 1f 00 00 cmpl $0x1ff0,%ebp */
1497 /* 7c 01 jl <okk> */
1498 /* c3 ret */
1499 *a++ = 0x81; *a++ = 0xfd;
1500 *a++ = (N_SAFE_BINTRANS_LIMIT-1) & 255;
1501 *a++ = ((N_SAFE_BINTRANS_LIMIT-1) >> 8) & 255; *a++ = 0; *a++ = 0;
1502 *a++ = 0x7c; failskip = a; *a++ = 0x01;
1503 bintrans_write_chunkreturn_fail(&a);
1504 *failskip = (size_t)a - (size_t)failskip - 1;
1505
1506 /*
1507 * ebx = ((vaddr >> 22) & 1023) * sizeof(void *)
1508 *
1509 * 89 c3 mov %eax,%ebx
1510 * c1 eb 14 shr $20,%ebx
1511 * 81 e3 fc 0f 00 00 and $0xffc,%ebx
1512 */
1513 *a++ = 0x89; *a++ = 0xc3;
1514 *a++ = 0xc1; *a++ = 0xeb; *a++ = 0x14;
1515 *a++ = 0x81; *a++ = 0xe3; *a++ = 0xfc; *a++ = 0x0f; *a++ = 0; *a++ = 0;
1516
1517 /*
1518 * ecx = vaddr_to_hostaddr_table0
1519 *
1520 * 8b 8e 34 12 00 00 mov 0x1234(%esi),%ecx
1521 */
1522 ofs = ((size_t)&dummy_cpu.cd.mips.vaddr_to_hostaddr_table0) - (size_t)&dummy_cpu;
1523 *a++ = 0x8b; *a++ = 0x8e;
1524 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1525
1526 /*
1527 * ecx = vaddr_to_hostaddr_table0[a]
1528 *
1529 * 8b 0c 19 mov (%ecx,%ebx),%ecx
1530 */
1531 *a++ = 0x8b; *a++ = 0x0c; *a++ = 0x19;
1532
1533 /*
1534 * ebx = ((vaddr >> 12) & 1023) * sizeof(void *)
1535 *
1536 * 89 c3 mov %eax,%ebx
1537 * c1 eb 0a shr $10,%ebx
1538 * 81 e3 fc 0f 00 00 and $0xffc,%ebx
1539 */
1540 *a++ = 0x89; *a++ = 0xc3;
1541 *a++ = 0xc1; *a++ = 0xeb; *a++ = 0x0a;
1542 *a++ = 0x81; *a++ = 0xe3; *a++ = 0xfc; *a++ = 0x0f; *a++ = 0; *a++ = 0;
1543
1544 /*
1545 * ecx = vaddr_to_hostaddr_table0[a][b].cd.mips.chunks
1546 *
1547 * 8b 8c 19 56 34 12 00 mov 0x123456(%ecx,%ebx,1),%ecx
1548 */
1549 ofs = (size_t)&dummy_vth32_table.cd.mips.bintrans_chunks[0]
1550 - (size_t)&dummy_vth32_table;
1551
1552 *a++ = 0x8b; *a++ = 0x8c; *a++ = 0x19;
1553 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1554
1555 /*
1556 * ecx = NULL? Then return with failure.
1557 *
1558 * 83 f9 00 cmp $0x0,%ecx
1559 * 75 01 jne <okzzz>
1560 */
1561 *a++ = 0x83; *a++ = 0xf9; *a++ = 0x00;
1562 *a++ = 0x75; fail = a; *a++ = 0x00;
1563 bintrans_write_chunkreturn(&a);
1564 *fail = (size_t)a - (size_t)fail - 1;
1565
1566 /*
1567 * 25 fc 0f 00 00 and $0xffc,%eax
1568 * 01 c1 add %eax,%ecx
1569 *
1570 * 8b 01 mov (%ecx),%eax
1571 *
1572 * 83 f8 00 cmp $0x0,%eax
1573 * 75 01 jne <ok>
1574 * c3 ret
1575 */
1576 *a++ = 0x25; *a++ = 0xfc; *a++ = 0x0f; *a++ = 0; *a++ = 0;
1577 *a++ = 0x01; *a++ = 0xc1;
1578
1579 *a++ = 0x8b; *a++ = 0x01;
1580
1581 *a++ = 0x83; *a++ = 0xf8; *a++ = 0x00;
1582 *a++ = 0x75; fail = a; *a++ = 0x01;
1583 bintrans_write_chunkreturn(&a);
1584 *fail = (size_t)a - (size_t)fail - 1;
1585
1586 /* 03 86 78 56 34 12 add 0x12345678(%esi),%eax */
1587 /* ff e0 jmp *%eax */
1588 ofs = ((size_t)&dummy_cpu.cd.mips.chunk_base_address) - (size_t)&dummy_cpu;
1589 *a++ = 0x03; *a++ = 0x86;
1590 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1591 *a++ = 0xff; *a++ = 0xe0;
1592 #endif
1593 } else {
1594 /* Not much we can do here if this wasn't to the same physical page... */
1595
1596 /* Don't execute too many instructions. */
1597 /* 81 fd f0 1f 00 00 cmpl $0x1ff0,%ebp */
1598 /* 7c 01 jl <okk> */
1599 /* c3 ret */
1600 *a++ = 0x81; *a++ = 0xfd;
1601 *a++ = (N_SAFE_BINTRANS_LIMIT-1) & 255;
1602 *a++ = ((N_SAFE_BINTRANS_LIMIT-1) >> 8) & 255; *a++ = 0; *a++ = 0;
1603 *a++ = 0x7c; failskip = a; *a++ = 0x01;
1604 bintrans_write_chunkreturn_fail(&a);
1605 *failskip = (size_t)a - (size_t)failskip - 1;
1606
1607 /*
1608 * Compare the old pc (ecx:ebx) and the new pc (edx:eax). If they are on the
1609 * same virtual page (which means that they are on the same physical
1610 * page), then we can check the right chunk pointer, and if it
1611 * is non-NULL, then we can jump there. Otherwise just return.
1612 */
1613
1614 /* Subtract 4 from the old pc first. (This is where the jump originated from.) */
1615 /* 83 eb 04 sub $0x4,%ebx */
1616 /* 83 d9 00 sbb $0x0,%ecx */
1617 *a++ = 0x83; *a++ = 0xeb; *a++ = 0x04;
1618 *a++ = 0x83; *a++ = 0xd9; *a++ = 0x00;
1619
1620 /* 39 d1 cmp %edx,%ecx */
1621 /* 74 01 je 1b9 <ok2> */
1622 /* c3 ret */
1623 *a++ = 0x39; *a++ = 0xd1;
1624 *a++ = 0x74; *a++ = 0x01;
1625 *a++ = 0xc3;
1626
1627 /* Remember new pc: */
1628 /* 89 c1 mov %eax,%ecx */
1629 *a++ = 0x89; *a++ = 0xc1;
1630
1631 /* 81 e3 00 f0 ff ff and $0xfffff000,%ebx */
1632 /* 25 00 f0 ff ff and $0xfffff000,%eax */
1633 *a++ = 0x81; *a++ = 0xe3; *a++ = 0x00; *a++ = 0xf0; *a++ = 0xff; *a++ = 0xff;
1634 *a++ = 0x25; *a++ = 0x00; *a++ = 0xf0; *a++ = 0xff; *a++ = 0xff;
1635
1636 /* 39 c3 cmp %eax,%ebx */
1637 /* 74 01 je <ok1> */
1638 /* c3 ret */
1639 *a++ = 0x39; *a++ = 0xc3;
1640 *a++ = 0x74; *a++ = 0x01;
1641 *a++ = 0xc3;
1642
1643 /* 81 e1 ff 0f 00 00 and $0xfff,%ecx */
1644 *a++ = 0x81; *a++ = 0xe1; *a++ = 0xff; *a++ = 0x0f; *a++ = 0; *a++ = 0;
1645
1646 /* 8b 81 78 56 34 12 mov 0x12345678(%ecx),%eax */
1647 ofs = (size_t)chunks;
1648 *a++ = 0x8b; *a++ = 0x81; *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1649
1650 /* 83 f8 00 cmp $0x0,%eax */
1651 /* 75 01 jne 1cd <okjump> */
1652 /* c3 ret */
1653 *a++ = 0x83; *a++ = 0xf8; *a++ = 0x00;
1654 *a++ = 0x75; *a++ = 0x01;
1655 *a++ = 0xc3;
1656
1657 /* 03 86 78 56 34 12 add 0x12345678(%esi),%eax */
1658 /* ff e0 jmp *%eax */
1659 ofs = ((size_t)&dummy_cpu.cd.mips.chunk_base_address) - (size_t)&dummy_cpu;
1660 *a++ = 0x03; *a++ = 0x86;
1661 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1662 *a++ = 0xff; *a++ = 0xe0;
1663 }
1664 } else {
1665 /*
1666 * Just to make sure that we don't become too unreliant
1667 * on the main program loop, we need to return every once
1668 * in a while (interrupts etc).
1669 *
1670 * Load the "nr of instructions executed" (which is an int)
1671 * and see if it is below a certain threshold. If so, then
1672 * we go on with the fast path (bintrans), otherwise we
1673 * abort by returning.
1674 */
1675 /* 81 fd f0 1f 00 00 cmpl $0x1ff0,%ebp */
1676 /* 7c 01 jl <okk> */
1677 /* c3 ret */
1678 if (!only_care_about_chunk_p && !forward) {
1679 *a++ = 0x81; *a++ = 0xfd;
1680 *a++ = (N_SAFE_BINTRANS_LIMIT-1) & 255;
1681 *a++ = ((N_SAFE_BINTRANS_LIMIT-1) >> 8) & 255; *a++ = 0; *a++ = 0;
1682 *a++ = 0x7c; failskip = a; *a++ = 0x01;
1683 bintrans_write_chunkreturn_fail(&a);
1684 *failskip = (size_t)a - (size_t)failskip - 1;
1685 }
1686
1687 /*
1688 * potential_chunk_p points to an "uint32_t".
1689 * If this value is non-NULL, then it is a piece of i386
1690 * machine language code corresponding to the address
1691 * we're jumping to. Otherwise, those instructions haven't
1692 * been translated yet, so we have to return to the main
1693 * loop. (Actually, we have to add cpu->chunk_base_address.)
1694 *
1695 * Case 1: The value is non-NULL already at translation
1696 * time. Then we can make a direct (fast) native
1697 * i386 jump to the code chunk.
1698 *
1699 * Case 2: The value was NULL at translation time, then we
1700 * have to check during runtime.
1701 */
1702
1703 /* Case 1: */
1704 /* printf("%08x ", *potential_chunk_p); */
1705 i386_addr = *potential_chunk_p +
1706 (size_t)mem->translation_code_chunk_space;
1707 i386_addr = i386_addr - ((size_t)a + 5);
1708 if ((*potential_chunk_p) != 0) {
1709 *a++ = 0xe9;
1710 *a++ = i386_addr;
1711 *a++ = i386_addr >> 8;
1712 *a++ = i386_addr >> 16;
1713 *a++ = i386_addr >> 24;
1714 } else {
1715 /* Case 2: */
1716
1717 bintrans_register_potential_quick_jump(mem, a, p);
1718
1719 i386_addr = (size_t)potential_chunk_p;
1720
1721 /*
1722 * Load the chunk pointer into eax.
1723 * If it is NULL (zero), then skip the following jump.
1724 * Add chunk_base_address to eax, and jump to eax.
1725 */
1726
1727 /* a1 78 56 34 12 mov 0x12345678,%eax */
1728 /* 83 f8 00 cmp $0x0,%eax */
1729 /* 75 01 jne <okaa> */
1730 /* c3 ret */
1731 *a++ = 0xa1;
1732 *a++ = i386_addr; *a++ = i386_addr >> 8;
1733 *a++ = i386_addr >> 16; *a++ = i386_addr >> 24;
1734 *a++ = 0x83; *a++ = 0xf8; *a++ = 0x00;
1735 *a++ = 0x75; *a++ = 0x01;
1736 *a++ = 0xc3;
1737
1738 /* 03 86 78 56 34 12 add 0x12345678(%esi),%eax */
1739 /* ff e0 jmp *%eax */
1740 ofs = ((size_t)&dummy_cpu.cd.mips.chunk_base_address) - (size_t)&dummy_cpu;
1741 *a++ = 0x03; *a++ = 0x86;
1742 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1743 *a++ = 0xff; *a++ = 0xe0;
1744 }
1745 }
1746
1747 if (skip != NULL)
1748 *skip = (size_t)a - (size_t)skip - 1;
1749
1750 *addrp = a;
1751 return 1;
1752 }
1753
1754
1755 /*
1756 * bintrans_write_instruction__loadstore():
1757 */
1758 static int bintrans_write_instruction__loadstore(struct memory *mem,
1759 unsigned char **addrp, int rt, int imm, int rs,
1760 int instruction_type, int bigendian, int do_alignment_check)
1761 {
1762 unsigned char *a, *retfail, *generic64bit, *doloadstore,
1763 *okret0, *okret1, *okret2, *skip;
1764 int ofs, alignment, load=0, unaligned=0;
1765
1766 /* TODO: Not yet: */
1767 if (instruction_type == HI6_LQ_MDMX || instruction_type == HI6_SQ)
1768 return 0;
1769
1770 switch (instruction_type) {
1771 case HI6_LQ_MDMX:
1772 case HI6_LDL:
1773 case HI6_LDR:
1774 case HI6_LD:
1775 case HI6_LWU:
1776 case HI6_LWL:
1777 case HI6_LWR:
1778 case HI6_LW:
1779 case HI6_LHU:
1780 case HI6_LH:
1781 case HI6_LBU:
1782 case HI6_LB:
1783 load = 1;
1784 if (rt == 0)
1785 return 0;
1786 }
1787
1788 switch (instruction_type) {
1789 case HI6_LWL:
1790 case HI6_LWR:
1791 case HI6_LDL:
1792 case HI6_LDR:
1793 case HI6_SWL:
1794 case HI6_SWR:
1795 case HI6_SDL:
1796 case HI6_SDR:
1797 unaligned = 1;
1798 }
1799
1800 /* TODO: Not yet: */
1801 if (bigendian && unaligned)
1802 return 0;
1803
1804 a = *addrp;
1805
1806 if (mem->bintrans_32bit_only)
1807 load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
1808 else
1809 load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
1810
1811 if (imm != 0) {
1812 if (imm & 0x8000) {
1813 /* 05 34 f2 ff ff add $0xfffff234,%eax */
1814 /* 83 d2 ff adc $0xffffffff,%edx */
1815 *a++ = 5;
1816 *a++ = imm; *a++ = imm >> 8; *a++ = 0xff; *a++ = 0xff;
1817 if (!mem->bintrans_32bit_only) {
1818 *a++ = 0x83; *a++ = 0xd2; *a++ = 0xff;
1819 }
1820 } else {
1821 /* 05 34 12 00 00 add $0x1234,%eax */
1822 /* 83 d2 00 adc $0x0,%edx */
1823 *a++ = 5;
1824 *a++ = imm; *a++ = imm >> 8; *a++ = 0; *a++ = 0;
1825 if (!mem->bintrans_32bit_only) {
1826 *a++ = 0x83; *a++ = 0xd2; *a++ = 0;
1827 }
1828 }
1829 }
1830
1831 alignment = 0;
1832 switch (instruction_type) {
1833 case HI6_LQ_MDMX:
1834 case HI6_SQ:
1835 alignment = 15;
1836 break;
1837 case HI6_LD:
1838 case HI6_LDL:
1839 case HI6_LDR:
1840 case HI6_SD:
1841 case HI6_SDL:
1842 case HI6_SDR:
1843 alignment = 7;
1844 break;
1845 case HI6_LW:
1846 case HI6_LWL:
1847 case HI6_LWR:
1848 case HI6_LWU:
1849 case HI6_SW:
1850 case HI6_SWL:
1851 case HI6_SWR:
1852 alignment = 3;
1853 break;
1854 case HI6_LH:
1855 case HI6_LHU:
1856 case HI6_SH:
1857 alignment = 1;
1858 break;
1859 }
1860
1861 if (unaligned) {
1862 /*
1863 * Perform the actual load/store from an
1864 * aligned address.
1865 *
1866 * 83 e0 fc and $0xfffffffc,%eax
1867 */
1868 *a++ = 0x83; *a++ = 0xe0; *a++ = 0xff - alignment;
1869 } else if (alignment > 0 && do_alignment_check) {
1870 unsigned char *alignskip;
1871 /*
1872 * Check alignment:
1873 *
1874 * 89 c3 mov %eax,%ebx
1875 * 83 e3 01 and $0x1,%ebx
1876 * 74 01 jz <ok>
1877 * c3 ret
1878 */
1879 *a++ = 0x89; *a++ = 0xc3;
1880 *a++ = 0x83; *a++ = 0xe3; *a++ = alignment;
1881 *a++ = 0x74; alignskip = a; *a++ = 0x00;
1882 bintrans_write_chunkreturn_fail(&a);
1883 *alignskip = (size_t)a - (size_t)alignskip - 1;
1884 }
1885
1886
1887 /* Here, edx:eax = vaddr */
1888
1889 if (mem->bintrans_32bit_only) {
1890 /* ebx = vaddr >> 12; */
1891 *a++ = 0x89; *a++ = 0xc3; /* mov %eax, %ebx */
1892 *a++ = 0xc1; *a++ = 0xeb; *a++ = 0x0c; /* shr $12, %ebx */
1893
1894 if (load) {
1895 /* ecx = cpu->cd.mips.host_load */
1896 *a++ = 0x8b; *a++ = 0x8e; *a++ = ofs_h_l & 255;
1897 *a++ = (ofs_h_l >> 8) & 255;
1898 *a++ = (ofs_h_l >> 16) & 255; *a++ = (ofs_h_l >> 24) & 255;
1899 } else {
1900 /* ecx = cpu->cd.mips.host_store */
1901 *a++ = 0x8b; *a++ = 0x8e; *a++ = ofs_h_s & 255;
1902 *a++ = (ofs_h_s >> 8) & 255;
1903 *a++ = (ofs_h_s >> 16) & 255; *a++ = (ofs_h_s >> 24) & 255;
1904 }
1905
1906 /* ecx = host_load[a] (or host_store[a]) */
1907 *a++ = 0x8b; *a++ = 0x0c; *a++ = 0x99; /* mov (%ecx,%ebx,4),%ecx */
1908
1909 /*
1910 * ecx = NULL? Then return with failure.
1911 *
1912 * 83 f9 00 cmp $0x0,%ecx
1913 * 75 01 jne <okzzz>
1914 */
1915 *a++ = 0x83; *a++ = 0xf9; *a++ = 0x00;
1916 *a++ = 0x75; retfail = a; *a++ = 0x00;
1917 bintrans_write_chunkreturn_fail(&a); /* ret (and fail) */
1918 *retfail = (size_t)a - (size_t)retfail - 1;
1919
1920 /*
1921 * eax = offset within page = vaddr & 0xfff
1922 * ecx = host address ( = host page + offset)
1923 *
1924 * 25 ff 0f 00 00 and $0xfff,%eax
1925 * 01 c1 add %eax,%ecx
1926 */
1927 *a++ = 0x25; *a++ = 0xff; *a++ = 0x0f; *a++ = 0; *a++ = 0;
1928 *a++ = 0x01; *a++ = 0xc1;
1929 } else {
1930 /*
1931 * If the load/store address has the top 32 bits set to
1932 * 0x00000000 or 0xffffffff, then we can use the 32-bit
1933 * lookup tables:
1934 *
1935
1936 TODO: top 33 bits!!!!!!!
1937
1938 * 83 fa 00 cmp $0x0,%edx
1939 * 74 05 je <ok32>
1940 * 83 fa ff cmp $0xffffffff,%edx
1941 * 75 01 jne <not32>
1942 */
1943 *a++ = 0x83; *a++ = 0xfa; *a++ = 0x00;
1944 *a++ = 0x74; *a++ = 0x05;
1945 *a++ = 0x83; *a++ = 0xfa; *a++ = 0xff;
1946 *a++ = 0x75; generic64bit = a; *a++ = 0x01;
1947
1948 /* Call the quick lookup routine: */
1949 if (load)
1950 ofs = (size_t)bintrans_load_32bit;
1951 else
1952 ofs = (size_t)bintrans_store_32bit;
1953 ofs = ofs - ((size_t)a + 5);
1954 *a++ = 0xe8; *a++ = ofs; *a++ = ofs >> 8;
1955 *a++ = ofs >> 16; *a++ = ofs >> 24;
1956
1957 /*
1958 * ecx = NULL? Then return with failure.
1959 *
1960 * 83 f9 00 cmp $0x0,%ecx
1961 * 75 01 jne <okzzz>
1962 */
1963 *a++ = 0x83; *a++ = 0xf9; *a++ = 0x00;
1964 *a++ = 0x75; retfail = a; *a++ = 0x00;
1965 bintrans_write_chunkreturn_fail(&a); /* ret (and fail) */
1966 *retfail = (size_t)a - (size_t)retfail - 1;
1967
1968 /*
1969 * eax = offset within page = vaddr & 0xfff
1970 * ecx = host address ( = host page + offset)
1971 *
1972 * 25 ff 0f 00 00 and $0xfff,%eax
1973 * 01 c1 add %eax,%ecx
1974 */
1975 *a++ = 0x25; *a++ = 0xff; *a++ = 0x0f; *a++ = 0; *a++ = 0;
1976 *a++ = 0x01; *a++ = 0xc1;
1977
1978 *a++ = 0xeb; doloadstore = a; *a++ = 0x01;
1979
1980
1981 /* TODO: The stuff above is so similar to the pure 32-bit
1982 case that it should be factored out. */
1983
1984
1985 *generic64bit = (size_t)a - (size_t)generic64bit - 1;
1986
1987 /*
1988 * 64-bit generic case:
1989 */
1990
1991 /* push writeflag */
1992 *a++ = 0x6a; *a++ = load? 0 : 1;
1993
1994 /* push vaddr (edx:eax) */
1995 *a++ = 0x52; *a++ = 0x50;
1996
1997 /* push cpu (esi) */
1998 *a++ = 0x56;
1999
2000 /* eax = points to the right function */
2001 ofs = ((size_t)&dummy_cpu.cd.mips.fast_vaddr_to_hostaddr) - (size_t)&dummy_cpu;
2002 *a++ = 0x8b; *a++ = 0x86;
2003 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
2004
2005 /* ff d0 call *%eax */
2006 *a++ = 0xff; *a++ = 0xd0;
2007
2008 /* 83 c4 08 add $0x10,%esp */
2009 *a++ = 0x83; *a++ = 0xc4; *a++ = 0x10;
2010
2011 /* If eax is NULL, then return. */
2012 /* 83 f8 00 cmp $0x0,%eax */
2013 /* 75 01 jne 1cd <okjump> */
2014 /* c3 ret */
2015 *a++ = 0x83; *a++ = 0xf8; *a++ = 0x00;
2016 *a++ = 0x75; retfail = a; *a++ = 0x00;
2017 bintrans_write_chunkreturn_fail(&a); /* ret (and fail) */
2018 *retfail = (size_t)a - (size_t)retfail - 1;
2019
2020 /* 89 c1 mov %eax,%ecx */
2021 *a++ = 0x89; *a++ = 0xc1;
2022
2023 *doloadstore = (size_t)a - (size_t)doloadstore - 1;
2024 }
2025
2026
2027 if (!load) {
2028 if (rt == MIPS_GPR_ZERO) {
2029 switch (alignment) {
2030 case 7: *a++ = 0x31; *a++ = 0xd2; /* edx = 0 */
2031 case 3:
2032 case 1: *a++ = 0x31; *a++ = 0xc0; break; /* eax = 0 */
2033 case 0: *a++ = 0xb0; *a++ = 0x00; break; /* al = 0 */
2034 default:fatal("todo: zero\n"); exit(1);
2035 }
2036 } else {
2037 if (alignment >= 7)
2038 load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
2039 else
2040 load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
2041 }
2042 }
2043
2044 switch (instruction_type) {
2045 case HI6_LD:
2046 if (bigendian) {
2047 /* 8b 11 mov (%ecx),%edx */
2048 /* 8b 41 04 mov 0x4(%ecx),%eax */
2049 /* 0f c8 bswap %eax */
2050 /* 0f ca bswap %edx */
2051 *a++ = 0x8b; *a++ = 0x11;
2052 *a++ = 0x8b; *a++ = 0x41; *a++ = 0x04;
2053 *a++ = 0x0f; *a++ = 0xc8;
2054 *a++ = 0x0f; *a++ = 0xca;
2055 } else {
2056 /* 8b 01 mov (%ecx),%eax */
2057 /* 8b 51 04 mov 0x4(%ecx),%edx */
2058 *a++ = 0x8b; *a++ = 0x01;
2059 *a++ = 0x8b; *a++ = 0x51; *a++ = 0x04;
2060 }
2061 break;
2062 case HI6_LWU:
2063 /* 8b 01 mov (%ecx),%eax */
2064 /* 0f c8 bswap %eax (big endian) */
2065 /* 31 d2 xor %edx,%edx */
2066 *a++ = 0x8b; *a++ = 0x01;
2067 if (bigendian) {
2068 *a++ = 0x0f; *a++ = 0xc8;
2069 }
2070 *a++ = 0x31; *a++ = 0xd2;
2071 break;
2072 case HI6_LW:
2073 /* 8b 01 mov (%ecx),%eax */
2074 /* 0f c8 bswap %eax (big endian) */
2075 /* 99 cltd */
2076 *a++ = 0x8b; *a++ = 0x01;
2077 if (bigendian) {
2078 *a++ = 0x0f; *a++ = 0xc8;
2079 }
2080 *a++ = 0x99;
2081 break;
2082 case HI6_LHU:
2083 /* 31 c0 xor %eax,%eax */
2084 /* 66 8b 01 mov (%ecx),%ax */
2085 /* 86 c4 xchg %al,%ah (big endian) */
2086 /* 99 cltd */
2087 *a++ = 0x31; *a++ = 0xc0;
2088 *a++ = 0x66; *a++ = 0x8b; *a++ = 0x01;
2089 if (bigendian) {
2090 *a++ = 0x86; *a++ = 0xc4;
2091 }
2092 *a++ = 0x99;
2093 break;
2094 case HI6_LH:
2095 /* 66 8b 01 mov (%ecx),%ax */
2096 /* 86 c4 xchg %al,%ah (big endian) */
2097 /* 98 cwtl */
2098 /* 99 cltd */
2099 *a++ = 0x66; *a++ = 0x8b; *a++ = 0x01;
2100 if (bigendian) {
2101 *a++ = 0x86; *a++ = 0xc4;
2102 }
2103 *a++ = 0x98;
2104 *a++ = 0x99;
2105 break;
2106 case HI6_LBU:
2107 /* 31 c0 xor %eax,%eax */
2108 /* 8a 01 mov (%ecx),%al */
2109 /* 99 cltd */
2110 *a++ = 0x31; *a++ = 0xc0;
2111 *a++ = 0x8a; *a++ = 0x01;
2112 *a++ = 0x99;
2113 break;
2114 case HI6_LB:
2115 /* 8a 01 mov (%ecx),%al */
2116 /* 66 98 cbtw */
2117 /* 98 cwtl */
2118 /* 99 cltd */
2119 *a++ = 0x8a; *a++ = 0x01;
2120 *a++ = 0x66; *a++ = 0x98;
2121 *a++ = 0x98;
2122 *a++ = 0x99;
2123 break;
2124
2125 case HI6_LWL:
2126 load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
2127 /* 05 34 f2 ff ff add $0xfffff234,%eax */
2128 *a++ = 5;
2129 *a++ = imm; *a++ = imm >> 8; *a++ = 0xff; *a++ = 0xff;
2130 /* 83 e0 03 and $0x03,%eax */
2131 *a++ = 0x83; *a++ = 0xe0; *a++ = alignment;
2132 /* 89 c3 mov %eax,%ebx */
2133 *a++ = 0x89; *a++ = 0xc3;
2134
2135 load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
2136
2137 /* ALIGNED LOAD: */
2138 /* 8b 11 mov (%ecx),%edx */
2139 *a++ = 0x8b; *a++ = 0x11;
2140
2141 /*
2142 * CASE 0:
2143 * memory = 0x12 0x34 0x56 0x78
2144 * register after lwl: 0x12 0x.. 0x.. 0x..
2145 */
2146 /* 83 fb 00 cmp $0x0,%ebx */
2147 /* 75 01 jne <skip> */
2148 *a++ = 0x83; *a++ = 0xfb; *a++ = 0x00;
2149 *a++ = 0x75; skip = a; *a++ = 0x01;
2150
2151 /* c1 e2 18 shl $0x18,%edx */
2152 /* 25 ff ff ff 00 and $0xffffff,%eax */
2153 /* 09 d0 or %edx,%eax */
2154 *a++ = 0xc1; *a++ = 0xe2; *a++ = 0x18;
2155 *a++ = 0x25; *a++ = 0xff; *a++ = 0xff; *a++ = 0xff; *a++ = 0x00;
2156 *a++ = 0x09; *a++ = 0xd0;
2157
2158 /* eb 00 jmp <okret> */
2159 *a++ = 0xeb; okret0 = a; *a++ = 0;
2160
2161 *skip = (size_t)a - (size_t)skip - 1;
2162
2163 /*
2164 * CASE 1:
2165 * memory = 0x12 0x34 0x56 0x78
2166 * register after lwl: 0x34 0x12 0x.. 0x..
2167 */
2168 /* 83 fb 01 cmp $0x1,%ebx */
2169 /* 75 01 jne <skip> */
2170 *a++ = 0x83; *a++ = 0xfb; *a++ = 0x01;
2171 *a++ = 0x75; skip = a; *a++ = 0x01;
2172
2173 /* c1 e2 10 shl $0x10,%edx */
2174 /* 25 ff ff 00 00 and $0xffff,%eax */
2175 /* 09 d0 or %edx,%eax */
2176 *a++ = 0xc1; *a++ = 0xe2; *a++ = 0x10;
2177 *a++ = 0x25; *a++ = 0xff; *a++ = 0xff; *a++ = 0x00; *a++ = 0x00;
2178 *a++ = 0x09; *a++ = 0xd0;
2179
2180 /* eb 00 jmp <okret> */
2181 *a++ = 0xeb; okret1 = a; *a++ = 0;
2182
2183 *skip = (size_t)a - (size_t)skip - 1;
2184
2185 /*
2186 * CASE 2:
2187 * memory = 0x12 0x34 0x56 0x78
2188 * register after lwl: 0x56 0x34 0x12 0x..
2189 */
2190 /* 83 fb 02 cmp $0x2,%ebx */
2191 /* 75 01 jne <skip> */
2192 *a++ = 0x83; *a++ = 0xfb; *a++ = 0x02;
2193 *a++ = 0x75; skip = a; *a++ = 0x01;
2194
2195 /* c1 e2 08 shl $0x08,%edx */
2196 /* 25 ff 00 00 00 and $0xff,%eax */
2197 /* 09 d0 or %edx,%eax */
2198 *a++ = 0xc1; *a++ = 0xe2; *a++ = 0x08;
2199 *a++ = 0x25; *a++ = 0xff; *a++ = 0x00; *a++ = 0x00; *a++ = 0x00;
2200 *a++ = 0x09; *a++ = 0xd0;
2201
2202 /* eb 00 jmp <okret> */
2203 *a++ = 0xeb; okret2 = a; *a++ = 0;
2204
2205 *skip = (size_t)a - (size_t)skip - 1;
2206
2207 /*
2208 * CASE 3:
2209 * memory = 0x12 0x34 0x56 0x78
2210 * register after lwl: 0x78 0x56 0x34 0x12
2211 */
2212 /* 89 d0 mov %edx,%eax */
2213 *a++ = 0x89; *a++ = 0xd0;
2214
2215 /* okret: */
2216 *okret0 = (size_t)a - (size_t)okret0 - 1;
2217 *okret1 = (size_t)a - (size_t)okret1 - 1;
2218 *okret2 = (size_t)a - (size_t)okret2 - 1;
2219
2220 /* 99 cltd */
2221 *a++ = 0x99;
2222 break;
2223
2224 case HI6_LWR:
2225 load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
2226 /* 05 34 f2 ff ff add $0xfffff234,%eax */
2227 *a++ = 5;
2228 *a++ = imm; *a++ = imm >> 8; *a++ = 0xff; *a++ = 0xff;
2229 /* 83 e0 03 and $0x03,%eax */
2230 *a++ = 0x83; *a++ = 0xe0; *a++ = alignment;
2231 /* 89 c3 mov %eax,%ebx */
2232 *a++ = 0x89; *a++ = 0xc3;
2233
2234 load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
2235
2236 /* ALIGNED LOAD: */
2237 /* 8b 11 mov (%ecx),%edx */
2238 *a++ = 0x8b; *a++ = 0x11;
2239
2240 /*
2241 * CASE 0:
2242 * memory = 0x12 0x34 0x56 0x78
2243 * register after lwr: 0x78 0x56 0x34 0x12
2244 */
2245 /* 83 fb 00 cmp $0x0,%ebx */
2246 /* 75 01 jne <skip> */
2247 *a++ = 0x83; *a++ = 0xfb; *a++ = 0x00;
2248 *a++ = 0x75; skip = a; *a++ = 0x01;
2249
2250 /* 89 d0 mov %edx,%eax */
2251 *a++ = 0x89; *a++ = 0xd0;
2252
2253 /* eb 00 jmp <okret> */
2254 *a++ = 0xeb; okret0 = a; *a++ = 0;
2255
2256 *skip = (size_t)a - (size_t)skip - 1;
2257
2258 /*
2259 * CASE 1:
2260 * memory = 0x12 0x34 0x56 0x78
2261 * register after lwr: 0x.. 0x78 0x56 0x34
2262 */
2263 /* 83 fb 01 cmp $0x1,%ebx */
2264 /* 75 01 jne <skip> */
2265 *a++ = 0x83; *a++ = 0xfb; *a++ = 0x01;
2266 *a++ = 0x75; skip = a; *a++ = 0x01;
2267
2268 /* c1 ea 08 shr $0x8,%edx */
2269 /* 25 00 00 00 ff and $0xff000000,%eax */
2270 /* 09 d0 or %edx,%eax */
2271 *a++ = 0xc1; *a++ = 0xea; *a++ = 0x08;
2272 *a++ = 0x25; *a++ = 0x00; *a++ = 0x00; *a++ = 0x00; *a++ = 0xff;
2273 *a++ = 0x09; *a++ = 0xd0;
2274
2275 /* eb 00 jmp <okret> */
2276 *a++ = 0xeb; okret1 = a; *a++ = 0;
2277
2278 *skip = (size_t)a - (size_t)skip - 1;
2279
2280 /*
2281 * CASE 2:
2282 * memory = 0x12 0x34 0x56 0x78
2283 * register after lwr: 0x.. 0x.. 0x78 0x56
2284 */
2285 /* 83 fb 02 cmp $0x2,%ebx */
2286 /* 75 01 jne <skip> */
2287 *a++ = 0x83; *a++ = 0xfb; *a++ = 0x02;
2288 *a++ = 0x75; skip = a; *a++ = 0x01;
2289
2290 /* c1 ea 10 shr $0x10,%edx */
2291 /* 25 00 00 ff ff and $0xffff0000,%eax */
2292 /* 09 d0 or %edx,%eax */
2293 *a++ = 0xc1; *a++ = 0xea; *a++ = 0x10;
2294 *a++ = 0x25; *a++ = 0x00; *a++ = 0x00; *a++ = 0xff; *a++ = 0xff;
2295 *a++ = 0x09; *a++ = 0xd0;
2296
2297 /* eb 00 jmp <okret> */
2298 *a++ = 0xeb; okret2 = a; *a++ = 0;
2299
2300 *skip = (size_t)a - (size_t)skip - 1;
2301
2302 /*
2303 * CASE 3:
2304 * memory = 0x12 0x34 0x56 0x78
2305 * register after lwr: 0x.. 0x.. 0x.. 0x78
2306 */
2307 /* c1 ea 18 shr $0x18,%edx */
2308 /* 25 00 ff ff ff and $0xffffff00,%eax */
2309 /* 09 d0 or %edx,%eax */
2310 *a++ = 0xc1; *a++ = 0xea; *a++ = 0x18;
2311 *a++ = 0x25; *a++ = 0x00; *a++ = 0xff; *a++ = 0xff; *a++ = 0xff;
2312 *a++ = 0x09; *a++ = 0xd0;
2313
2314 /* okret: */
2315 *okret0 = (size_t)a - (size_t)okret0 - 1;
2316 *okret1 = (size_t)a - (size_t)okret1 - 1;
2317 *okret2 = (size_t)a - (size_t)okret2 - 1;
2318
2319 /* 99 cltd */
2320 *a++ = 0x99;
2321 break;
2322
2323 case HI6_SD:
2324 if (bigendian) {
2325 /* 0f c8 bswap %eax */
2326 /* 0f ca bswap %edx */
2327 /* 89 11 mov %edx,(%ecx) */
2328 /* 89 41 04 mov %eax,0x4(%ecx) */
2329 *a++ = 0x0f; *a++ = 0xc8;
2330 *a++ = 0x0f; *a++ = 0xca;
2331 *a++ = 0x89; *a++ = 0x11;
2332 *a++ = 0x89; *a++ = 0x41; *a++ = 0x04;
2333 } else {
2334 /* 89 01 mov %eax,(%ecx) */
2335 /* 89 51 04 mov %edx,0x4(%ecx) */
2336 *a++ = 0x89; *a++ = 0x01;
2337 *a++ = 0x89; *a++ = 0x51; *a++ = 0x04;
2338 }
2339 break;
2340 case HI6_SW:
2341 /* 0f c8 bswap %eax (big endian) */
2342 if (bigendian) {
2343 *a++ = 0x0f; *a++ = 0xc8;
2344 }
2345 /* 89 01 mov %eax,(%ecx) */
2346 *a++ = 0x89; *a++ = 0x01;
2347 break;
2348 case HI6_SH:
2349 /* 86 c4 xchg %al,%ah (big endian) */
2350 if (bigendian) {
2351 *a++ = 0x86; *a++ = 0xc4;
2352 }
2353 /* 66 89 01 mov %ax,(%ecx) */
2354 *a++ = 0x66; *a++ = 0x89; *a++ = 0x01;
2355 break;
2356 case HI6_SB:
2357 /* 88 01 mov %al,(%ecx) */
2358 *a++ = 0x88; *a++ = 0x01;
2359 break;
2360
2361 case HI6_SWL:
2362 load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
2363 /* 05 34 f2 ff ff add $0xfffff234,%eax */
2364 *a++ = 5;
2365 *a++ = imm; *a++ = imm >> 8; *a++ = 0xff; *a++ = 0xff;
2366 /* 83 e0 03 and $0x03,%eax */
2367 *a++ = 0x83; *a++ = 0xe0; *a++ = alignment;
2368 /* 89 c3 mov %eax,%ebx */
2369 *a++ = 0x89; *a++ = 0xc3;
2370
2371 load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
2372
2373 /* ALIGNED LOAD: */
2374 /* 8b 11 mov (%ecx),%edx */
2375 *a++ = 0x8b; *a++ = 0x11;
2376
2377 /*
2378 * CASE 0:
2379 * memory (edx): 0x12 0x34 0x56 0x78
2380 * register (eax): 0x89abcdef
2381 * mem after swl: 0x89 0x.. 0x.. 0x..
2382 */
2383 /* 83 fb 00 cmp $0x0,%ebx */
2384 /* 75 01 jne <skip> */
2385 *a++ = 0x83; *a++ = 0xfb; *a++ = 0x00;
2386 *a++ = 0x75; skip = a; *a++ = 0x01;
2387
2388 /* 81 e2 00 ff ff ff and $0xffffff00,%edx */
2389 /* c1 e8 18 shr $0x18,%eax */
2390 /* 09 d0 or %edx,%eax */
2391 *a++ = 0x81; *a++ = 0xe2; *a++ = 0x00; *a++ = 0xff; *a++ = 0xff; *a++ = 0xff;
2392 *a++ = 0xc1; *a++ = 0xe8; *a++ = 0x18;
2393 *a++ = 0x09; *a++ = 0xd0;
2394
2395 /* eb 00 jmp <okret> */
2396 *a++ = 0xeb; okret0 = a; *a++ = 0;
2397
2398 *skip = (size_t)a - (size_t)skip - 1;
2399
2400 /*
2401 * CASE 1:
2402 * memory (edx): 0x12 0x34 0x56 0x78
2403 * register (eax): 0x89abcdef
2404 * mem after swl: 0xab 0x89 0x.. 0x..
2405 */
2406 /* 83 fb 01 cmp $0x1,%ebx */
2407 /* 75 01 jne <skip> */
2408 *a++ = 0x83; *a++ = 0xfb; *a++ = 0x01;
2409 *a++ = 0x75; skip = a; *a++ = 0x01;
2410
2411 /* 81 e2 00 00 ff ff and $0xffff0000,%edx */
2412 /* c1 e8 10 shr $0x10,%eax */
2413 /* 09 d0 or %edx,%eax */
2414 *a++ = 0x81; *a++ = 0xe2; *a++ = 0x00; *a++ = 0x00; *a++ = 0xff; *a++ = 0xff;
2415 *a++ = 0xc1; *a++ = 0xe8; *a++ = 0x10;
2416 *a++ = 0x09; *a++ = 0xd0;
2417
2418 /* eb 00 jmp <okret> */
2419 *a++ = 0xeb; okret1 = a; *a++ = 0;
2420
2421 *skip = (size_t)a - (size_t)skip - 1;
2422
2423 /*
2424 * CASE 2:
2425 * memory (edx): 0x12 0x34 0x56 0x78
2426 * register (eax): 0x89abcdef
2427 * mem after swl: 0xcd 0xab 0x89 0x..
2428 */
2429 /* 83 fb 02 cmp $0x2,%ebx */
2430 /* 75 01 jne <skip> */
2431 *a++ = 0x83; *a++ = 0xfb; *a++ = 0x02;
2432 *a++ = 0x75; skip = a; *a++ = 0x01;
2433
2434 /* 81 e2 00 00 00 ff and $0xff000000,%edx */
2435 /* c1 e8 08 shr $0x08,%eax */
2436 /* 09 d0 or %edx,%eax */
2437 *a++ = 0x81; *a++ = 0xe2; *a++ = 0x00; *a++ = 0x00; *a++ = 0x00; *a++ = 0xff;
2438 *a++ = 0xc1; *a++ = 0xe8; *a++ = 0x08;
2439 *a++ = 0x09; *a++ = 0xd0;
2440
2441 /* eb 00 jmp <okret> */
2442 *a++ = 0xeb; okret2 = a; *a++ = 0;
2443
2444 *skip = (size_t)a - (size_t)skip - 1;
2445
2446 /*
2447 * CASE 3:
2448 * memory (edx): 0x12 0x34 0x56 0x78
2449 * register (eax): 0x89abcdef
2450 * mem after swl: 0xef 0xcd 0xab 0x89
2451 */
2452 /* eax = eax :-) */
2453
2454 /* okret: */
2455 *okret0 = (size_t)a - (size_t)okret0 - 1;
2456 *okret1 = (size_t)a - (size_t)okret1 - 1;
2457 *okret2 = (size_t)a - (size_t)okret2 - 1;
2458
2459 /* Store back to memory: */
2460 /* 89 01 mov %eax,(%ecx) */
2461 *a++ = 0x89; *a++ = 0x01;
2462 break;
2463
2464 case HI6_SWR:
2465 load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
2466 /* 05 34 f2 ff ff add $0xfffff234,%eax */
2467 *a++ = 5;
2468 *a++ = imm; *a++ = imm >> 8; *a++ = 0xff; *a++ = 0xff;
2469 /* 83 e0 03 and $0x03,%eax */
2470 *a++ = 0x83; *a++ = 0xe0; *a++ = alignment;
2471 /* 89 c3 mov %eax,%ebx */
2472 *a++ = 0x89; *a++ = 0xc3;
2473
2474 load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
2475
2476 /* ALIGNED LOAD: */
2477 /* 8b 11 mov (%ecx),%edx */
2478 *a++ = 0x8b; *a++ = 0x11;
2479
2480 /*
2481 * CASE 0:
2482 * memory (edx): 0x12 0x34 0x56 0x78
2483 * register (eax): 0x89abcdef
2484 * mem after swr: 0xef 0xcd 0xab 0x89
2485 */
2486 /* 83 fb 00 cmp $0x0,%ebx */
2487 /* 75 01 jne <skip> */
2488 *a++ = 0x83; *a++ = 0xfb; *a++ = 0x00;
2489 *a++ = 0x75; skip = a; *a++ = 0x01;
2490
2491 /* eax = eax, so do nothing */
2492
2493 /* eb 00 jmp <okret> */
2494 *a++ = 0xeb; okret0 = a; *a++ = 0;
2495
2496 *skip = (size_t)a - (size_t)skip - 1;
2497
2498 /*
2499 * CASE 1:
2500 * memory (edx): 0x12 0x34 0x56 0x78
2501 * register (eax): 0x89abcdef
2502 * mem after swr: 0x12 0xef 0xcd 0xab
2503 */
2504 /* 83 fb 01 cmp $0x1,%ebx */
2505 /* 75 01 jne <skip> */
2506 *a++ = 0x83; *a++ = 0xfb; *a++ = 0x01;
2507 *a++ = 0x75; skip = a; *a++ = 0x01;
2508
2509 /* 81 e2 ff 00 00 00 and $0x000000ff,%edx */
2510 /* c1 e0 08 shl $0x08,%eax */
2511 /* 09 d0 or %edx,%eax */
2512 *a++ = 0x81; *a++ = 0xe2; *a++ = 0xff; *a++ = 0x00; *a++ = 0x00; *a++ = 0x00;
2513 *a++ = 0xc1; *a++ = 0xe0; *a++ = 0x08;
2514 *a++ = 0x09; *a++ = 0xd0;
2515
2516 /* eb 00 jmp <okret> */
2517 *a++ = 0xeb; okret1 = a; *a++ = 0;
2518
2519 *skip = (size_t)a - (size_t)skip - 1;
2520
2521 /*
2522 * CASE 2:
2523 * memory (edx): 0x12 0x34 0x56 0x78
2524 * register (eax): 0x89abcdef
2525 * mem after swr: 0x12 0x34 0xef 0xcd
2526 */
2527 /* 83 fb 02 cmp $0x2,%ebx */
2528 /* 75 01 jne <skip> */
2529 *a++ = 0x83; *a++ = 0xfb; *a++ = 0x02;
2530 *a++ = 0x75; skip = a; *a++ = 0x01;
2531
2532 /* 81 e2 ff ff 00 00 and $0x0000ffff,%edx */
2533 /* c1 e0 10 shl $0x10,%eax */
2534 /* 09 d0 or %edx,%eax */
2535 *a++ = 0x81; *a++ = 0xe2; *a++ = 0xff; *a++ = 0xff; *a++ = 0x00; *a++ = 0x00;
2536 *a++ = 0xc1; *a++ = 0xe0; *a++ = 0x10;
2537 *a++ = 0x09; *a++ = 0xd0;
2538
2539 /* eb 00 jmp <okret> */
2540 *a++ = 0xeb; okret2 = a; *a++ = 0;
2541
2542 *skip = (size_t)a - (size_t)skip - 1;
2543
2544 /*
2545 * CASE 3:
2546 * memory (edx): 0x12 0x34 0x56 0x78
2547 * register (eax): 0x89abcdef
2548 * mem after swr: 0x12 0x34 0x56 0xef
2549 */
2550 /* 81 e2 ff ff ff 00 and $0x00ffffff,%edx */
2551 /* c1 e0 18 shl $0x18,%eax */
2552 /* 09 d0 or %edx,%eax */
2553 *a++ = 0x81; *a++ = 0xe2; *a++ = 0xff; *a++ = 0xff; *a++ = 0xff; *a++ = 0x00;
2554 *a++ = 0xc1; *a++ = 0xe0; *a++ = 0x18;
2555 *a++ = 0x09; *a++ = 0xd0;
2556
2557
2558 /* okret: */
2559 *okret0 = (size_t)a - (size_t)okret0 - 1;
2560 *okret1 = (size_t)a - (size_t)okret1 - 1;
2561 *okret2 = (size_t)a - (size_t)okret2 - 1;
2562
2563 /* Store back to memory: */
2564 /* 89 01 mov %eax,(%ecx) */
2565 *a++ = 0x89; *a++ = 0x01;
2566 break;
2567
2568 default:
2569 bintrans_write_chunkreturn_fail(&a); /* ret (and fail) */
2570 }
2571
2572 if (load && rt != 0)
2573 store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
2574
2575 *addrp = a;
2576 bintrans_write_pc_inc(addrp);
2577 return 1;
2578 }
2579
2580
2581 /*
2582 * bintrans_write_instruction__tlb_rfe_etc():
2583 */
2584 static int bintrans_write_instruction__tlb_rfe_etc(unsigned char **addrp,
2585 int itype)
2586 {
2587 unsigned char *a;
2588 int ofs;
2589
2590 switch (itype) {
2591 case CALL_TLBP:
2592 case CALL_TLBR:
2593 case CALL_TLBWR:
2594 case CALL_TLBWI:
2595 case CALL_RFE:
2596 case CALL_ERET:
2597 case CALL_SYSCALL:
2598 case CALL_BREAK:
2599 break;
2600 default:
2601 return 0;
2602 }
2603
2604 a = *addrp;
2605
2606 /* Put back PC into the cpu struct, both as pc and pc_last */
2607 *a++ = 0x89; *a++ = 0xbe; *a++ = ofs_pc&255;
2608 *a++ = (ofs_pc>>8)&255; *a++ = (ofs_pc>>16)&255;
2609 *a++ = (ofs_pc>>24)&255; /* mov %edi,pc(%esi) */
2610
2611 *a++ = 0x89; *a++ = 0xbe; *a++ = ofs_pc_last&255;
2612 *a++ = (ofs_pc_last>>8)&255; *a++ = (ofs_pc_last>>16)&255;
2613 *a++ = (ofs_pc_last>>24)&255; /* mov %edi,pc_last(%esi) */
2614
2615 /* ... and make sure that the high 32 bits are ALSO in pc_last: */
2616 /* 8b 86 38 12 00 00 mov 0x1238(%esi),%eax */
2617 ofs = ofs_pc + 4;
2618 *a++ = 0x8b; *a++ = 0x86; *a++ = ofs&255;
2619 *a++ = (ofs>>8)&255; *a++ = (ofs>>16)&255;
2620 *a++ = (ofs>>24)&255; /* mov %edi,pc(%esi) */
2621
2622 /* 89 86 34 12 00 00 mov %eax,0x1234(%esi) */
2623 ofs = ofs_pc_last + 4;
2624 *a++ = 0x89; *a++ = 0x86; *a++ = ofs&255;
2625 *a++ = (ofs>>8)&255; *a++ = (ofs>>16)&255;
2626 *a++ = (ofs>>24)&255; /* mov %edi,pc(%esi) */
2627
2628 switch (itype) {
2629 case CALL_TLBP:
2630 case CALL_TLBR:
2631 /* push readflag */
2632 *a++ = 0x6a; *a++ = (itype == CALL_TLBR);
2633 ofs = ((size_t)&dummy_cpu.cd.mips.bintrans_fast_tlbpr) - (size_t)&dummy_cpu;
2634 break;
2635 case CALL_TLBWR:
2636 case CALL_TLBWI:
2637 /* push randomflag */
2638 *a++ = 0x6a; *a++ = (itype == CALL_TLBWR);
2639 ofs = ((size_t)&dummy_cpu.cd.mips.bintrans_fast_tlbwri) - (size_t)&dummy_cpu;
2640 break;
2641 case CALL_SYSCALL:
2642 case CALL_BREAK:
2643 /* push randomflag */
2644 *a++ = 0x6a; *a++ = (itype == CALL_BREAK? EXCEPTION_BP : EXCEPTION_SYS);
2645 ofs = ((size_t)&dummy_cpu.cd.mips.bintrans_simple_exception) - (size_t)&dummy_cpu;
2646 break;
2647 case CALL_RFE:
2648 ofs = ((size_t)&dummy_cpu.cd.mips.bintrans_fast_rfe) - (size_t)&dummy_cpu;
2649 break;
2650 case CALL_ERET:
2651 ofs = ((size_t)&dummy_cpu.cd.mips.bintrans_fast_eret) - (size_t)&dummy_cpu;
2652 break;
2653 }
2654
2655 /* push cpu (esi) */
2656 *a++ = 0x56;
2657
2658 /* eax = points to the right function */
2659 *a++ = 0x8b; *a++ = 0x86;
2660 *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
2661
2662 /* ff d0 call *%eax */
2663 *a++ = 0xff; *a++ = 0xd0;
2664
2665 switch (itype) {
2666 case CALL_RFE:
2667 case CALL_ERET:
2668 /* 83 c4 04 add $4,%esp */
2669 *a++ = 0x83; *a++ = 0xc4; *a++ = 4;
2670 break;
2671 default:
2672 /* 83 c4 08 add $8,%esp */
2673 *a++ = 0x83; *a++ = 0xc4; *a++ = 8;
2674 break;
2675 }
2676
2677 /* Load PC from the cpu struct. */
2678 *a++ = 0x8b; *a++ = 0xbe; *a++ = ofs_pc&255;
2679 *a++ = (ofs_pc>>8)&255; *a++ = (ofs_pc>>16)&255;
2680 *a++ = (ofs_pc>>24)&255; /* mov pc(%esi),%edi */
2681
2682 *addrp = a;
2683
2684 switch (itype) {
2685 case CALL_ERET:
2686 case CALL_SYSCALL:
2687 case CALL_BREAK:
2688 break;
2689 default:
2690 bintrans_write_pc_inc(addrp);
2691 }
2692
2693 return 1;
2694 }
2695
2696
2697 /*
2698 * bintrans_backend_init():
2699 *
2700 * This is neccessary for broken GCC 2.x. (For GCC 3.x, this wouldn't be
2701 * neccessary, and the old code would have worked.)
2702 */
2703 static void bintrans_backend_init(void)
2704 {
2705 int size;
2706 unsigned char *p;
2707
2708
2709 /* "runchunk": */
2710 size = 64; /* NOTE: This MUST be enough, or we fail */
2711 p = (unsigned char *)mmap(NULL, size, PROT_READ | PROT_WRITE |
2712 PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
2713
2714 /* If mmap() failed, try malloc(): */
2715 if (p == NULL) {
2716 p = malloc(size);
2717 if (p == NULL) {
2718 fprintf(stderr, "bintrans_backend_init():"
2719 " out of memory\n");
2720 exit(1);
2721 }
2722 }
2723
2724 bintrans_runchunk = (void *)p;
2725
2726 *p++ = 0x57; /* push %edi */
2727 *p++ = 0x56; /* push %esi */
2728 *p++ = 0x55; /* push %ebp */
2729 *p++ = 0x53; /* push %ebx */
2730
2731 /*
2732 * In all translated code, esi points to the cpu struct, and
2733 * ebp is the nr of executed (translated) instructions.
2734 */
2735
2736 /* 0=ebx, 4=ebp, 8=esi, 0xc=edi, 0x10=retaddr, 0x14=arg0, 0x18=arg1 */
2737
2738 /* mov 0x8(%esp,1),%esi */
2739 *p++ = 0x8b; *p++ = 0x74; *p++ = 0x24; *p++ = 0x14;
2740
2741 /* mov nr_instr(%esi),%ebp */
2742 *p++ = 0x8b; *p++ = 0xae; *p++ = ofs_i&255; *p++ = (ofs_i>>8)&255;
2743 *p++ = (ofs_i>>16)&255; *p++ = (ofs_i>>24)&255;
2744
2745 /* mov pc(%esi),%edi */
2746 *p++ = 0x8b; *p++ = 0xbe; *p++ = ofs_pc&255; *p++ = (ofs_pc>>8)&255;
2747 *p++ = (ofs_pc>>16)&255; *p++ = (ofs_pc>>24)&255;
2748
2749 /* call *0x18(%esp,1) */
2750 *p++ = 0xff; *p++ = 0x54; *p++ = 0x24; *p++ = 0x18;
2751
2752 /* mov %ebp,0x1234(%esi) */
2753 *p++ = 0x89; *p++ = 0xae; *p++ = ofs_i&255; *p++ = (ofs_i>>8)&255;
2754 *p++ = (ofs_i>>16)&255; *p++ = (ofs_i>>24)&255;
2755
2756 /* mov %edi,pc(%esi) */
2757 *p++ = 0x89; *p++ = 0xbe; *p++ = ofs_pc&255; *p++ = (ofs_pc>>8)&255;
2758 *p++ = (ofs_pc>>16)&255; *p++ = (ofs_pc>>24)&255;
2759
2760 *p++ = 0x5b; /* pop %ebx */
2761 *p++ = 0x5d; /* pop %ebp */
2762 *p++ = 0x5e; /* pop %esi */
2763 *p++ = 0x5f; /* pop %edi */
2764 *p++ = 0xc3; /* ret */
2765
2766
2767
2768 /* "jump_to_32bit_pc": */
2769 size = 128; /* NOTE: This MUST be enough, or we fail */
2770 p = (unsigned char *)mmap(NULL, size, PROT_READ | PROT_WRITE |
2771 PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
2772
2773 /* If mmap() failed, try malloc(): */
2774 if (p == NULL) {
2775 p = malloc(size);
2776 if (p == NULL) {
2777 fprintf(stderr, "bintrans_backend_init():"
2778 " out of memory\n");
2779 exit(1);
2780 }
2781 }
2782
2783 bintrans_jump_to_32bit_pc = (void *)p;
2784
2785 /* Don't execute too many instructions. */
2786 /* 81 fd f0 1f 00 00 cmpl $0x1ff0,%ebp */
2787 /* 7c 01 jl <okk> */
2788 /* c3 ret */
2789 *p++ = 0x81; *p++ = 0xfd; *p++ = (N_SAFE_BINTRANS_LIMIT-1) & 255;
2790 *p++ = ((N_SAFE_BINTRANS_LIMIT-1) >> 8) & 255; *p++ = 0; *p++ = 0;
2791 *p++ = 0x7c; *p++ = 0x01;
2792 *p++ = 0xc3;
2793
2794 /*
2795 * ebx = ((vaddr >> 22) & 1023) * sizeof(void *)
2796 *
2797 * 89 c3 mov %eax,%ebx
2798 * c1 eb 14 shr $20,%ebx
2799 * 81 e3 fc 0f 00 00 and $0xffc,%ebx
2800 */
2801 *p++ = 0x89; *p++ = 0xc3;
2802 *p++ = 0xc1; *p++ = 0xeb; *p++ = 0x14;
2803 *p++ = 0x81; *p++ = 0xe3; *p++ = 0xfc; *p++ = 0x0f; *p++ = 0; *p++ = 0;
2804
2805 /*
2806 * ecx = vaddr_to_hostaddr_table0
2807 *
2808 * 8b 8e 34 12 00 00 mov 0x1234(%esi),%ecx
2809 */
2810 *p++ = 0x8b; *p++ = 0x8e;
2811 *p++ = ofs_tabl0 & 255; *p++ = (ofs_tabl0 >> 8) & 255;
2812 *p++ = (ofs_tabl0 >> 16) & 255; *p++ = (ofs_tabl0 >> 24) & 255;
2813
2814 /*
2815 * ecx = vaddr_to_hostaddr_table0[a]
2816 *
2817 * 8b 0c 19 mov (%ecx,%ebx),%ecx
2818 */
2819 *p++ = 0x8b; *p++ = 0x0c; *p++ = 0x19;
2820
2821 /*
2822 * ebx = ((vaddr >> 12) & 1023) * sizeof(void *)
2823 *
2824 * 89 c3 mov %eax,%ebx
2825 * c1 eb 0a shr $10,%ebx
2826 * 81 e3 fc 0f 00 00 and $0xffc,%ebx
2827 */
2828 *p++ = 0x89; *p++ = 0xc3;
2829 *p++ = 0xc1; *p++ = 0xeb; *p++ = 0x0a;
2830 *p++ = 0x81; *p++ = 0xe3; *p++ = 0xfc; *p++ = 0x0f; *p++ = 0; *p++ = 0;
2831
2832 /*
2833 * ecx = vaddr_to_hostaddr_table0[a][b].cd.mips.chunks
2834 *
2835 * 8b 8c 19 56 34 12 00 mov 0x123456(%ecx,%ebx,1),%ecx
2836 */
2837 *p++ = 0x8b; *p++ = 0x8c; *p++ = 0x19; *p++ = ofs_chunks & 255;
2838 *p++ = (ofs_chunks >> 8) & 255; *p++ = (ofs_chunks >> 16) & 255;
2839 *p++ = (ofs_chunks >> 24) & 255;
2840
2841 /*
2842 * ecx = NULL? Then return with failure.
2843 *
2844 * 83 f9 00 cmp $0x0,%ecx
2845 * 75 01 jne <okzzz>
2846 */
2847 *p++ = 0x83; *p++ = 0xf9; *p++ = 0x00;
2848 *p++ = 0x75; *p++ = 0x01;
2849 *p++ = 0xc3; /* TODO: failure? */
2850
2851 /*
2852 * 25 fc 0f 00 00 and $0xffc,%eax
2853 * 01 c1 add %eax,%ecx
2854 *
2855 * 8b 01 mov (%ecx),%eax
2856 *
2857 * 83 f8 00 cmp $0x0,%eax
2858 * 75 01 jne <ok>
2859 * c3 ret
2860 */
2861 *p++ = 0x25; *p++ = 0xfc; *p++ = 0x0f; *p++ = 0; *p++ = 0;
2862 *p++ = 0x01; *p++ = 0xc1;
2863
2864 *p++ = 0x8b; *p++ = 0x01;
2865
2866 *p++ = 0x83; *p++ = 0xf8; *p++ = 0x00;
2867 *p++ = 0x75; *p++ = 0x01;
2868 *p++ = 0xc3; /* TODO: failure? */
2869
2870 /* 03 86 78 56 34 12 add 0x12345678(%esi),%eax */
2871 /* ff e0 jmp *%eax */
2872 *p++ = 0x03; *p++ = 0x86; *p++ = ofs_chunkbase & 255;
2873 *p++ = (ofs_chunkbase >> 8) & 255; *p++ = (ofs_chunkbase >> 16) & 255;
2874 *p++ = (ofs_chunkbase >> 24) & 255;
2875 *p++ = 0xff; *p++ = 0xe0;
2876
2877
2878
2879 /* "load_32bit": */
2880 size = 48; /* NOTE: This MUST be enough, or we fail */
2881 p = (unsigned char *)mmap(NULL, size, PROT_READ | PROT_WRITE |
2882 PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
2883
2884 /* If mmap() failed, try malloc(): */
2885 if (p == NULL) {
2886 p = malloc(size);
2887 if (p == NULL) {
2888 fprintf(stderr, "bintrans_backend_init():"
2889 " out of memory\n");
2890 exit(1);
2891 }
2892 }
2893
2894 bintrans_load_32bit = (void *)p;
2895
2896 /* ebx = vaddr >> 12; */
2897 *p++ = 0x89; *p++ = 0xc3; /* mov %eax, %ebx */
2898 *p++ = 0xc1; *p++ = 0xeb; *p++ = 0x0c; /* shr $12, %ebx */
2899
2900 /* ecx = cpu->cd.mips.host_load */
2901 *p++ = 0x8b; *p++ = 0x8e; *p++ = ofs_h_l & 255;
2902 *p++ = (ofs_h_l >> 8) & 255;
2903 *p++ = (ofs_h_l >> 16) & 255; *p++ = (ofs_h_l >> 24) & 255;
2904
2905 /* ecx = host_load[a] */
2906 *p++ = 0x8b; *p++ = 0x0c; *p++ = 0x99; /* mov (%ecx,%ebx,4),%ecx */
2907
2908 /* ret */
2909 *p++ = 0xc3;
2910
2911
2912
2913 /* "store_32bit": */
2914 size = 48; /* NOTE: This MUST be enough, or we fail */
2915 p = (unsigned char *)mmap(NULL, size, PROT_READ | PROT_WRITE |
2916 PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
2917
2918 /* If mmap() failed, try malloc(): */
2919 if (p == NULL) {
2920 p = malloc(size);
2921 if (p == NULL) {
2922 fprintf(stderr, "bintrans_backend_init():"
2923 " out of memory\n");
2924 exit(1);
2925 }
2926 }
2927
2928 bintrans_store_32bit = (void *)p;
2929
2930 /* ebx = vaddr >> 12; */
2931 *p++ = 0x89; *p++ = 0xc3; /* mov %eax, %ebx */
2932 *p++ = 0xc1; *p++ = 0xeb; *p++ = 0x0c; /* shr $12, %ebx */
2933
2934 /* ecx = cpu->cd.mips.host_store */
2935 *p++ = 0x8b; *p++ = 0x8e; *p++ = ofs_h_s & 255;
2936 *p++ = (ofs_h_s >> 8) & 255;
2937 *p++ = (ofs_h_s >> 16) & 255; *p++ = (ofs_h_s >> 24) & 255;
2938
2939 /* ecx = host_store[a] */
2940 *p++ = 0x8b; *p++ = 0x0c; *p++ = 0x99; /* mov (%ecx,%ebx,4),%ecx */
2941
2942 /* ret */
2943 *p++ = 0xc3;
2944 }
2945

  ViewVC Help
Powered by ViewVC 1.1.26