/[gxemul]/trunk/src/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 /trunk/src/bintrans_i386.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (show annotations)
Mon Oct 8 16:18:27 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 84898 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.815 2005/06/27 23:04:35 debug Exp $
20050617	Experimenting some more with netbooting OpenBSD/sgi. Adding
		a hack which allows emulated ethernet networks to be
		distributed across multiple emulator processes.
20050618	Minor updates (documentation, dummy YAMON emulation, etc).
20050620	strcpy/strcat -> strlcpy/strlcat updates.
		Some more progress on evbmips (Malta).
20050621	Adding a section to doc/configfiles.html about ethernet
		emulation across multiple hosts.
		Beginning the work on the ARM translation engine (using the
		dynamic-but-not-binary translation method).
		Fixing a bintrans bug: 0x9fc00000 should always be treated as
		PROM area, just as 0xbfc00000 is.
		Minor progress on Malta emulation (the PCI-ISA bus).
20050622	NetBSD/evbmips can now be installed (using another emulated
		machine) and run (including userland and so on). :-)
		Spliting up the bintrans haddr_entry field into two (one for
		read, one for write). Probably not much of a speed increase,
		though.
		Updating some NetBSD 2.0 -> 2.0.2 in the documentation.
20050623	Minor updates (documentation, the TODO file, etc).
		gzipped kernels are now always automagically gunzipped when
		loaded.
20050624	Adding a dummy Playstation Portable (PSP) mode, just barely
		enough to run Hello World (in weird colors :-).
		Removing the -b command line option; old bintrans is enabled
		by default instead. It makes more sense.
		Trying to finally fix the non-working performance measurement
		thing (instr/second etc).
20050625	Continuing on the essential basics for ARM emulation. Two
		instructions seem to work, a branch and a simple "mov". (The
		mov arguments are not correct yet.) Performance is definitely
		reasonable.
		Various other minor updates.
		Adding the ARM "bl" instruction.
		Adding support for combining multiple ARM instructions into one
		function call. ("mov" + "mov" is the only one implemented so
		far, but it seems to work.)
		Cleaning up some IP32 interrupt things (crime/mace); disabling
		the PS/2 keyboard controller on IP32, so that NetBSD/sgimips
		boots into userland again.
20050626	Finally! NetBSD/sgimips netboots. Adding instructions to
		doc/guestoses.html on how to set up an nfs server etc.
		Various other minor fixes.
		Playstation Portable ".pbp" files can now be used directly.
		(The ELF part of the .pbp is extracted transparently.)
		Converting some sprintf -> snprintf.
		Adding some more instructions to the ARM disassembler.
20050627	More ARM updates. Adding some simple ldr(b), str(b),
		cmps, and conditional branch instructions, enough to run
		a simple Hello World program.
		All ARM instructions are now inlined/generated for all possible
		condition codes.
		Adding add and sub, and more load/store instructions.
		Removing dummy files: cpu_alpha.c, cpu_hppa.c, and cpu_sparc.c.
		Some minor documentation updates; preparing for a 0.3.4
		release. Updating some URLs.

==============  RELEASE 0.3.4  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26