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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (show annotations)
Mon Oct 8 16:18:27 2007 UTC (12 years, 2 months ago) by dpavlin
File MIME type: text/plain
File size: 37293 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.c,v 1.169 2005/06/22 10:12:25 debug Exp $
29 *
30 * Dynamic binary translation.
31 *
32 *
33 * --------------------------------------------------------------------------
34 *
35 * NOTE: This code needs a lot of updating; much of it is MIPS-specific.
36 *
37 * --------------------------------------------------------------------------
38 *
39 *
40 * This should be documented/commented better. Some of the main concepts are:
41 *
42 * o) Keep a translation cache of a certain number of blocks.
43 *
44 * o) Only translate simple instructions. (For example, the 'tlbwr'
45 * instruction is not actually translated, converted into a call
46 * to C code.)
47 *
48 * o) Translate code in physical ram, not virtual. This will keep
49 * things translated over process switches, and TLB updates.
50 *
51 * o) When the translation cache is "full", then throw away everything
52 * translated so far and restart from scratch. The cache is of a
53 * fixed size, say 24 MB. (This is inspired by a comment in the Qemu
54 * technical documentation: "A 16 MByte cache holds the most recently
55 * used translations. For simplicity, it is completely flushed when
56 * it is full.")
57 *
58 * o) Do not translate over MIPS page boundaries (4 KB).
59 * (TODO: Perhaps it would be possible if we're running in kernel
60 * space? But that would require special checks at the end of
61 * each page.)
62 *
63 * o) If memory is overwritten, any translated block for that page
64 * must be invalidated. (It is removed from the cache so that it
65 * cannot be found on lookups.)
66 *
67 * o) Only run a certain number of instructions, before returning to
68 * the main loop. (This is needed in order to allow devices to
69 * cause interrupts, and so on.)
70 *
71 * o) Check for exceptions inside the block, for those instructions
72 * that require that. Update the program counter by the number
73 * of successfully executed instructions only.
74 *
75 * o) There is no "intermediate representation"; everything is translated
76 * directly from MIPS machine code to target machine code.
77 *
78 * o) Theoretical support for multiple target architectures (Alpha,
79 * i386, sparc, mips :-), ...), but only Alpha and i386 implemented
80 * so far.
81 *
82 * o) Load/stores: TODO: Comment.
83 *
84 * Testing: Running regression tests with and without the binary translator
85 * enabled should obviously result in the exact same results, or something is
86 * wrong.
87 *
88 * The general idea is something like this:
89 *
90 * Check for the current PC (actually: its physical form) in the
91 * translation cache. If it is found, then run the translated code chunk,
92 * otherwise try to translate and then run it.
93 *
94 * A few checks are made though, to make sure that the environment is "safe"
95 * enough; starting inside a delay slot or "nullified" slot is considered
96 * non-safe.
97 */
98
99 #include <errno.h>
100 #include <stdio.h>
101 #include <stdlib.h>
102 #include <string.h>
103 #include <sys/types.h>
104 #include <sys/mman.h>
105
106 #include "bintrans.h"
107 #include "cop0.h"
108 #include "cpu.h"
109 #include "cpu_mips.h"
110 #include "machine.h"
111 #include "memory.h"
112 #include "mips_cpu_types.h"
113 #include "misc.h"
114 #include "opcodes_mips.h"
115
116
117 #ifndef BINTRANS
118
119 /*
120 * No bintrans, then let's supply dummy functions:
121 */
122
123 int bintrans_pc_is_in_cache(struct cpu *cpu, uint64_t pc) { return 0; }
124 void bintrans_invalidate(struct cpu *cpu, uint64_t paddr) { }
125 int bintrans_attempt_translate(struct cpu *cpu, uint64_t paddr) { return 0; }
126 void bintrans_restart(struct cpu *cpu) { }
127 void bintrans_init_cpu(struct cpu *cpu) { }
128 void bintrans_init(struct machine *machine, struct memory *mem)
129 {
130 fatal("\n*** NOT starting bintrans, as gxemul "
131 "was compiled without such support!\n\n");
132 }
133
134 #else
135
136
137 /* Function declaration, should be the same as in bintrans_*.c: */
138
139 static void bintrans_host_cacheinvalidate(unsigned char *p, size_t len);
140 static void bintrans_write_chunkreturn(unsigned char **addrp);
141 static void bintrans_write_chunkreturn_fail(unsigned char **addrp);
142 static void bintrans_write_pc_inc(unsigned char **addrp);
143 static void bintrans_write_quickjump(struct memory *mem,
144 unsigned char *quickjump_code, uint32_t chunkoffset);
145 static int bintrans_write_instruction__addiu_etc(unsigned char **addrp, int rt,
146 int rs, int imm, int instruction_type);
147 static int bintrans_write_instruction__addu_etc(unsigned char **addrp, int rd,
148 int rs, int rt, int sa, int instruction_type);
149 static int bintrans_write_instruction__branch(unsigned char **addrp,
150 int instruction_type, int regimm_type, int rt, int rs, int imm);
151 static int bintrans_write_instruction__jr(unsigned char **addrp, int rs,
152 int rd, int special);
153 static int bintrans_write_instruction__jal(unsigned char **addrp, int imm,
154 int link);
155 static int bintrans_write_instruction__delayedbranch(struct memory *mem,
156 unsigned char **addrp, uint32_t *potential_chunk_p, uint32_t *chunks,
157 int only_care_about_chunk_p, int p, int forward);
158 static int bintrans_write_instruction__loadstore(struct memory *mem,
159 unsigned char **addrp, int rt, int imm, int rs, int instruction_type,
160 int bigendian);
161 static int bintrans_write_instruction__lui(unsigned char **addrp, int rt,
162 int imm);
163 static int bintrans_write_instruction__mfmthilo(unsigned char **addrp, int rd,
164 int from_flag, int hi_flag);
165 static int bintrans_write_instruction__mfc_mtc(struct memory *mem,
166 unsigned char **addrp, int coproc_nr, int flag64bit, int rt, int rd,
167 int mtcflag);
168 static int bintrans_write_instruction__tlb_rfe_etc(unsigned char **addrp,
169 int itype);
170
171 #define CALL_TLBWI 0
172 #define CALL_TLBWR 1
173 #define CALL_TLBP 2
174 #define CALL_TLBR 3
175 #define CALL_RFE 4
176 #define CALL_ERET 5
177 #define CALL_BREAK 6
178 #define CALL_SYSCALL 7
179
180
181 static void bintrans_register_potential_quick_jump(struct memory *mem,
182 unsigned char *a, int p)
183 {
184 /* printf("%02i: a=%016llx p=%i\n", mem->quick_jumps_index, a, p); */
185 mem->quick_jump_host_address[mem->quick_jumps_index] = a;
186 mem->quick_jump_page_offset[mem->quick_jumps_index] = p;
187 mem->quick_jumps_index ++;
188 if (mem->quick_jumps_index > mem->n_quick_jumps)
189 mem->n_quick_jumps = mem->quick_jumps_index;
190 if (mem->quick_jumps_index >= MAX_QUICK_JUMPS)
191 mem->quick_jumps_index = 0;
192 }
193
194
195 /* Include host architecture specific bintrans code: */
196
197 #ifdef ALPHA
198 #define BACKEND_NAME "Alpha"
199 #include "bintrans_alpha.c"
200 #else
201 #ifdef I386
202 #define BACKEND_NAME "i386"
203 #include "bintrans_i386.c"
204 #else
205 #ifdef MIPS
206 #define BACKEND_NAME "MIPS"
207 #include "bintrans_mips.c"
208 #else
209 #ifdef SPARCV9
210 #define BACKEND_NAME "UltraSPARC"
211 #include "bintrans_sparcv9.c"
212 #else
213 #error Unsupported host architecture for bintrans.
214 #endif /* SPARCV9 */
215 #endif /* MIPS */
216 #endif /* I386 */
217 #endif /* ALPHA */
218
219
220 /*
221 * old_bintrans_invalidate():
222 *
223 * Invalidate translations containing a certain physical address.
224 */
225 static void old_bintrans_invalidate(struct cpu *cpu, uint64_t paddr)
226 {
227 int entry_index = PADDR_TO_INDEX(paddr);
228 struct translation_page_entry *tep;
229 #if 0
230 struct translation_page_entry *prev = NULL;
231 #endif
232 uint64_t paddr_page = paddr & ~0xfff;
233
234 tep = cpu->mem->translation_page_entry_array[entry_index];
235 while (tep != NULL) {
236 if (tep->paddr == paddr_page)
237 #if 1
238 break;
239 #else
240 {
241 if (prev == NULL)
242 cpu->mem->translation_page_entry_array[
243 entry_index] = tep->next;
244 else
245 prev->next = tep->next;
246 return;
247 }
248 prev = tep;
249 #endif
250 tep = tep->next;
251 }
252 if (tep == NULL)
253 return;
254
255 if (!tep->page_is_potentially_in_use)
256 return;
257
258 tep->page_is_potentially_in_use = 0;
259 memset(&tep->chunk[0], 0, sizeof(tep->chunk));
260 memset(&tep->flags[0], 0, sizeof(tep->flags));
261 }
262
263
264 /*
265 * bintrans_invalidate():
266 *
267 * Invalidate translations containing a certain physical address.
268 */
269 void bintrans_invalidate(struct cpu *cpu, uint64_t paddr)
270 {
271 if (cpu->machine->old_bintrans_enable) {
272 old_bintrans_invalidate(cpu, paddr);
273 return;
274 }
275
276 /* TODO */
277 /* printf("bintrans_invalidate(): TODO\n"); */
278 }
279
280
281 /*
282 * bintrans_restart():
283 *
284 * Starts over by throwing away the bintrans cache contents.
285 */
286 void bintrans_restart(struct cpu *cpu)
287 {
288 int i, n = 1 << BINTRANS_CACHE_N_INDEX_BITS;
289
290 for (i=0; i<n; i++)
291 cpu->mem->translation_page_entry_array[i] = NULL;
292
293 cpu->mem->translation_code_chunk_space_head = 0;
294 cpu->mem->n_quick_jumps = 0;
295
296 /* debug("bintrans: Starting over!\n"); */
297 clear_all_chunks_from_all_tables(cpu);
298 }
299
300
301 /*
302 * enter_chunks_into_tables():
303 */
304 static void enter_chunks_into_tables(struct cpu *cpu, uint64_t vaddr,
305 uint32_t *chunk0)
306 {
307 int a, b;
308 struct vth32_table *tbl1;
309
310 switch (cpu->cd.mips.cpu_type.mmu_model) {
311 case MMU3K:
312 a = (vaddr >> 22) & 0x3ff;
313 b = (vaddr >> 12) & 0x3ff;
314 tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];
315 if (tbl1->haddr_entry[b*2] != NULL)
316 tbl1->bintrans_chunks[b] = chunk0;
317 break;
318 default:
319 ;
320 }
321 }
322
323
324 /*
325 * old_bintrans_attempt_translate():
326 *
327 * Attempt to translate a chunk of code, starting at 'paddr'. If successful,
328 * the code chunk is run.
329 *
330 * Returns the number of executed instructions.
331 */
332 int old_bintrans_attempt_translate(struct cpu *cpu, uint64_t paddr)
333 {
334 uint64_t paddr_page;
335 int offset_within_page;
336 int entry_index;
337 unsigned char *host_mips_page;
338 unsigned char *ca, *ca_justdid, *ca2;
339 int res, hi6, special6, regimm5;
340 unsigned char instr[4];
341 int old_n_executed;
342 size_t p;
343 int try_to_translate;
344 int n_translated, translated;
345 unsigned char *f;
346 struct translation_page_entry *tep;
347 size_t chunk_len;
348 int rs,rt,rd,sa,imm;
349 uint32_t *potential_chunk_p; /* for branches */
350 int byte_order_cached_bigendian;
351 int delayed_branch, stop_after_delayed_branch;
352 uint64_t delayed_branch_new_p;
353 int prev_p;
354
355
356 /* Abort if the current "environment" isn't safe enough: */
357 if (cpu->cd.mips.delay_slot || cpu->cd.mips.nullify_next ||
358 (paddr & 3) != 0)
359 return cpu->cd.mips.bintrans_instructions_executed;
360
361 byte_order_cached_bigendian = (cpu->byte_order == EMUL_BIG_ENDIAN);
362
363 /* Is this a part of something that is already translated? */
364 paddr_page = paddr & ~0xfff;
365 offset_within_page = (paddr & 0xfff) >> 2;
366 entry_index = PADDR_TO_INDEX(paddr);
367 tep = cpu->mem->translation_page_entry_array[entry_index];
368 while (tep != NULL) {
369 if (tep->paddr == paddr_page) {
370 int mask;
371
372 if (tep->chunk[offset_within_page] != 0) {
373 f = (size_t)tep->chunk[offset_within_page] +
374 cpu->mem->translation_code_chunk_space;
375 goto run_it; /* see further down */
376 }
377
378 mask = 1 << (offset_within_page & 7);
379 if (tep->flags[offset_within_page >> 3] & mask)
380 return cpu->cd.mips.
381 bintrans_instructions_executed;
382 break;
383 }
384 tep = tep->next;
385 }
386
387 #if 1
388 /* printf("A paddr=%016llx\n", (long long)paddr); */
389 /* Sometimes this works. */
390 quick_attempt_translate_again:
391 #endif
392 /*printf("B: ");
393 printf("v=%016llx p=%016llx h=%p paddr=%016llx\n",
394 (long long)cpu->cd.mips.pc_last_virtual_page,
395 (long long)cpu->cd.mips.pc_last_physical_page,
396 cpu->cd.mips.pc_last_host_4k_page,(long long)paddr);
397 */
398 /*
399 * If the chunk space is all used up, we need to start over from
400 * an empty chunk space.
401 */
402 if (cpu->mem->translation_code_chunk_space_head >=
403 cpu->machine->bintrans_size) {
404 bintrans_restart(cpu);
405 tep = NULL;
406 }
407
408
409 host_mips_page = cpu->cd.mips.pc_bintrans_host_4kpage;
410 if (host_mips_page == NULL)
411 return cpu->cd.mips.bintrans_instructions_executed;
412
413
414 if (tep == NULL) {
415 /* Allocate a new translation page entry: */
416 tep = (void *)(size_t) (cpu->mem->translation_code_chunk_space
417 + cpu->mem->translation_code_chunk_space_head);
418 cpu->mem->translation_code_chunk_space_head +=
419 sizeof(struct translation_page_entry);
420
421 /* ... and align again: */
422 cpu->mem->translation_code_chunk_space_head =
423 ((cpu->mem->translation_code_chunk_space_head - 1) | 63)
424 + 1;
425
426 /* Add the entry to the array: */
427 memset(tep, 0, sizeof(struct translation_page_entry));
428 tep->next = cpu->mem->translation_page_entry_array[entry_index];
429 cpu->mem->translation_page_entry_array[entry_index] = tep;
430 tep->paddr = paddr_page;
431 }
432
433 /* printf("translation_page_entry_array[%i] = %p, ofs = %i\n",
434 entry_index, cpu->mem->translation_page_entry_array[entry_index],
435 offset_within_page); */
436
437 /* ca is the "chunk address"; where to start generating a chunk: */
438 ca = cpu->mem->translation_code_chunk_space
439 + cpu->mem->translation_code_chunk_space_head;
440
441
442 /*
443 * Make sure that this page will not be written to by translated
444 * code:
445 */
446 mips_invalidate_translation_caches_paddr(cpu, paddr);
447
448 /*
449 * Try to translate a chunk of code:
450 */
451 p = paddr & 0xfff;
452 prev_p = p >> 2;
453 try_to_translate = 1;
454 n_translated = 0;
455 res = 0;
456 delayed_branch = 0;
457 stop_after_delayed_branch = 0;
458 delayed_branch_new_p = 0;
459 rt = 0;
460 cpu->mem->n_quick_jumps = cpu->mem->quick_jumps_index = 0;
461
462 while (try_to_translate) {
463 ca_justdid = ca;
464 translated = 0;
465
466 /* Read an instruction word from host memory: */
467 *((uint32_t *)&instr[0]) = *((uint32_t *)(host_mips_page + p));
468
469 if (byte_order_cached_bigendian) {
470 int tmp;
471 tmp = instr[0]; instr[0] = instr[3]; instr[3] = tmp;
472 tmp = instr[1]; instr[1] = instr[2]; instr[2] = tmp;
473 }
474
475 hi6 = instr[3] >> 2;
476
477 /* Check for instructions that can be translated: */
478 switch (hi6) {
479
480 case HI6_SPECIAL:
481 special6 = instr[0] & 0x3f;
482 rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);
483 rd = (instr[1] >> 3) & 31;
484 rt = instr[2] & 31;
485 sa = ((instr[1] & 7) << 2) + ((instr[0] >> 6) & 3);
486 switch (special6) {
487 case SPECIAL_JR:
488 case SPECIAL_JALR:
489 translated = try_to_translate =
490 bintrans_write_instruction__jr(&ca, rs, rd,
491 special6);
492 n_translated += translated;
493 delayed_branch = 2;
494 delayed_branch_new_p = -1; /* anything,
495 not within this physical page */
496 if (special6 == SPECIAL_JR)
497 stop_after_delayed_branch = 1;
498 break;
499 case SPECIAL_SYSCALL:
500 case SPECIAL_BREAK:
501 if (cpu->machine->userland_emul != NULL) {
502 int mask = 1 << (prev_p & 7);
503 bintrans_write_chunkreturn_fail(&ca);
504 tep->flags[prev_p >> 3] |= mask;
505 try_to_translate = 0;
506 } else {
507 translated = bintrans_write_instruction__tlb_rfe_etc(&ca,
508 special6 == SPECIAL_BREAK? CALL_BREAK : CALL_SYSCALL);
509 n_translated += translated;
510 try_to_translate = 0;
511 }
512 break;
513 case SPECIAL_ADDU:
514 case SPECIAL_DADDU:
515 case SPECIAL_SUBU:
516 case SPECIAL_DSUBU:
517 case SPECIAL_AND:
518 case SPECIAL_OR:
519 case SPECIAL_NOR:
520 case SPECIAL_XOR:
521 case SPECIAL_SLL:
522 case SPECIAL_SLLV:
523 case SPECIAL_DSLL:
524 case SPECIAL_DSLL32:
525 case SPECIAL_SRA:
526 case SPECIAL_SRAV:
527 case SPECIAL_SRLV:
528 case SPECIAL_SRL:
529 case SPECIAL_DSRA:
530 case SPECIAL_DSRA32:
531 case SPECIAL_DSRL:
532 case SPECIAL_DSRL32:
533 case SPECIAL_SLT:
534 case SPECIAL_SLTU:
535 case SPECIAL_MOVZ:
536 case SPECIAL_MOVN:
537 case SPECIAL_DIV:
538 case SPECIAL_DIVU:
539 case SPECIAL_MULT:
540 case SPECIAL_MULTU:
541 case SPECIAL_SYNC:
542 /* treat SYNC as a nop :-) */
543 if (special6 == SPECIAL_SYNC) {
544 rd = rt = rs = sa = 0;
545 special6 = SPECIAL_SLL;
546 }
547 translated = try_to_translate = bintrans_write_instruction__addu_etc(&ca, rd, rs, rt, sa, special6);
548 n_translated += translated;
549 break;
550 case SPECIAL_MFHI:
551 case SPECIAL_MFLO:
552 case SPECIAL_MTHI:
553 case SPECIAL_MTLO:
554 translated = try_to_translate = bintrans_write_instruction__mfmthilo(&ca,
555 (special6 == SPECIAL_MFHI || special6 == SPECIAL_MFLO)? rd : rs,
556 special6 == SPECIAL_MFHI || special6 == SPECIAL_MFLO,
557 special6 == SPECIAL_MFHI || special6 == SPECIAL_MTHI);
558 n_translated += translated;
559 break;
560 default:
561 /* Untranslatable: */
562 /* TODO: this code should only be in one place */
563 bintrans_write_chunkreturn_fail(&ca);
564 {
565 int mask = 1 << (prev_p & 7);
566 tep->flags[prev_p >> 3] |= mask;
567 }
568 try_to_translate = 0;
569 }
570 break;
571
572 case HI6_REGIMM:
573 regimm5 = instr[2] & 0x1f;
574 switch (regimm5) {
575 case REGIMM_BLTZ:
576 case REGIMM_BGEZ:
577 rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);
578 imm = (instr[1] << 8) + instr[0];
579 if (imm >= 32768)
580 imm -= 65536;
581 translated = try_to_translate = bintrans_write_instruction__branch(&ca, hi6, regimm5, rt, rs, imm);
582 n_translated += translated;
583 delayed_branch = 2;
584 delayed_branch_new_p = p + 4 + 4*imm;
585 break;
586 default:
587 try_to_translate = 0;
588 /* Untranslatable: */
589 /* TODO: this code should only be in one place */
590 bintrans_write_chunkreturn_fail(&ca);
591 {
592 int mask = 1 << (prev_p & 7);
593 tep->flags[prev_p >> 3] |= mask;
594 }
595 try_to_translate = 0;
596 }
597 break;
598
599 case HI6_J:
600 case HI6_JAL:
601 imm = (((instr[3] & 3) << 24) + (instr[2] << 16) +
602 (instr[1] << 8) + instr[0]) & 0x03ffffff;
603 translated = try_to_translate = bintrans_write_instruction__jal(&ca, imm, hi6 == HI6_JAL);
604 n_translated += translated;
605 delayed_branch = 2;
606 delayed_branch_new_p = -1;
607 if (hi6 == HI6_J)
608 stop_after_delayed_branch = 1;
609 break;
610
611 case HI6_BEQ:
612 case HI6_BEQL:
613 case HI6_BNE:
614 case HI6_BNEL:
615 case HI6_BLEZ:
616 case HI6_BLEZL:
617 case HI6_BGTZ:
618 case HI6_BGTZL:
619 rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);
620 rt = instr[2] & 31;
621 imm = (instr[1] << 8) + instr[0];
622 if (imm >= 32768)
623 imm -= 65536;
624 translated = try_to_translate = bintrans_write_instruction__branch(&ca, hi6, 0, rt, rs, imm);
625 n_translated += translated;
626 delayed_branch = 2;
627 delayed_branch_new_p = p + 4 + 4*imm;
628 break;
629
630 case HI6_ADDI:
631 case HI6_ADDIU:
632 case HI6_SLTI:
633 case HI6_SLTIU:
634 case HI6_ANDI:
635 case HI6_ORI:
636 case HI6_XORI:
637 case HI6_DADDI:
638 case HI6_DADDIU:
639 translated = try_to_translate =
640 bintrans_write_instruction__addiu_etc(&ca,
641 instr[2] & 31,
642 ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7),
643 (instr[1] << 8) + instr[0], hi6);
644 n_translated += translated;
645 break;
646
647 case HI6_LUI:
648 translated = try_to_translate =
649 bintrans_write_instruction__lui(&ca,
650 instr[2] & 31, (instr[1] << 8) + instr[0]);
651 n_translated += translated;
652 break;
653
654 case HI6_COP0:
655 switch (instr[3]) {
656 case 0x40:
657 if (instr[0] == 0 && (instr[1]&7)==0) {
658 if ((instr[2] & 0xe0)==0) {
659 /* mfc0: */
660 rt = instr[2] & 31;
661 rd = (instr[1] >> 3) & 31;
662 translated = try_to_translate = bintrans_write_instruction__mfc_mtc(cpu->mem, &ca, 0, 0, rt, rd, 0);
663 n_translated += translated;
664 } else if ((instr[2] & 0xe0)==0x20) {
665 /* dmfc0: */
666 rt = instr[2] & 31;
667 rd = (instr[1] >> 3) & 31;
668 translated = try_to_translate = bintrans_write_instruction__mfc_mtc(cpu->mem, &ca, 0, 1, rt, rd, 0);
669 n_translated += translated;
670 } else if ((instr[2] & 0xe0)==0x80) {
671 /* mtc0: */
672 rt = instr[2] & 31;
673 rd = (instr[1] >> 3) & 31;
674 translated = try_to_translate = bintrans_write_instruction__mfc_mtc(cpu->mem, &ca, 0, 0, rt, rd, 1);
675 n_translated += translated;
676 } else if ((instr[2] & 0xe0)==0xa0) {
677 /* dmtc0: */
678 rt = instr[2] & 31;
679 rd = (instr[1] >> 3) & 31;
680 translated = try_to_translate = bintrans_write_instruction__mfc_mtc(cpu->mem, &ca, 0, 1, rt, rd, 1);
681 n_translated += translated;
682 }
683 } else
684 try_to_translate = 0;
685 break;
686 case 0x42:
687 if (instr[2] == 0x00 && instr[1] == 0x00 && instr[0] == 0x10) {
688 /* rfe: */
689 translated = bintrans_write_instruction__tlb_rfe_etc(&ca, CALL_RFE);
690 n_translated += translated;
691 try_to_translate = 0;
692 } else if (instr[2] == 0x00 && instr[1] == 0x00 && instr[0] == 0x18) {
693 /* eret: */
694 translated = bintrans_write_instruction__tlb_rfe_etc(&ca, CALL_ERET);
695 n_translated += translated;
696 try_to_translate = 0;
697 } else if (instr[2] == 0 && instr[1] == 0 && instr[0] == 2) {
698 /* tlbwi: */
699 translated = try_to_translate = bintrans_write_instruction__tlb_rfe_etc(&ca, CALL_TLBWI);
700 n_translated += translated;
701 } else if (instr[2] == 0 && instr[1] == 0 && instr[0] == 6) {
702 /* tlbwr: */
703 translated = try_to_translate = bintrans_write_instruction__tlb_rfe_etc(&ca, CALL_TLBWR);
704 n_translated += translated;
705 } else if (instr[2] == 0 && instr[1] == 0 && instr[0] == 8) {
706 /* tlbp: */
707 translated = try_to_translate = bintrans_write_instruction__tlb_rfe_etc(&ca, CALL_TLBP);
708 n_translated += translated;
709 } else if (instr[2] == 0 && instr[1] == 0 && instr[0] == 1) {
710 /* tlbr: */
711 translated = try_to_translate = bintrans_write_instruction__tlb_rfe_etc(&ca, CALL_TLBR);
712 n_translated += translated;
713 } else if (instr[2] == 0 && instr[1] == 0 && (instr[0] == 0x21 || instr[0] == 0x22)) {
714 /* standby and suspend on VR41xx etc ==> NOP */
715 translated = try_to_translate = bintrans_write_instruction__addu_etc(&ca, 0, 0, 0, 0, SPECIAL_SLL);
716 n_translated += translated;
717 } else
718 try_to_translate = 0;
719 break;
720 default:
721 try_to_translate = 0;
722 }
723 break;
724
725 #if 0
726 case HI6_LQ_MDMX:
727 #endif
728 case HI6_LD:
729 case HI6_LWU:
730 case HI6_LW:
731 case HI6_LWL:
732 case HI6_LWR:
733 case HI6_LHU:
734 case HI6_LH:
735 case HI6_LBU:
736 case HI6_LB:
737 #if 0
738 case HI6_SQ:
739 #endif
740 case HI6_SD:
741 case HI6_SW:
742 case HI6_SWL:
743 case HI6_SWR:
744 case HI6_SH:
745 case HI6_SB:
746 rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);
747 rt = instr[2] & 31;
748 imm = (instr[1] << 8) + instr[0];
749 if (imm >= 32768)
750 imm -= 65536;
751 translated = try_to_translate = bintrans_write_instruction__loadstore(cpu->mem, &ca, rt, imm, rs, hi6, byte_order_cached_bigendian);
752 n_translated += translated;
753 break;
754
755 case HI6_CACHE:
756 translated = try_to_translate = bintrans_write_instruction__addu_etc(&ca, 0, 0, 0, 0, SPECIAL_SLL);
757 n_translated += translated;
758 break;
759
760 default:
761 /* Untranslatable: */
762 /* TODO: this code should only be in one place */
763 bintrans_write_chunkreturn_fail(&ca);
764 {
765 int mask = 1 << (prev_p & 7);
766 tep->flags[prev_p >> 3] |= mask;
767 }
768 try_to_translate = 0;
769 }
770
771 if (translated && delayed_branch) {
772 delayed_branch --;
773 if (delayed_branch == 0) {
774 int forward;
775
776 /*
777 * p is 0x000 .. 0xffc. If the jump is to
778 * within the same page, then we can use
779 * the same translation page to check if
780 * there already is a translation.
781 */
782 if ((delayed_branch_new_p & ~0xfff) == 0)
783 potential_chunk_p =
784 &tep->chunk[delayed_branch_new_p/4];
785 else
786 potential_chunk_p = NULL;
787
788 forward = delayed_branch_new_p > p;
789
790 bintrans_write_instruction__delayedbranch(
791 cpu->mem, &ca,
792 potential_chunk_p, &tep->chunk[0], 0,
793 delayed_branch_new_p & 0xfff, forward);
794 #if 0
795 if (stop_after_delayed_branch)
796 try_to_translate = 0;
797 #endif
798 }
799 }
800
801 if (translated) {
802 int i;
803
804 if (tep->chunk[prev_p] == 0)
805 tep->chunk[prev_p] = (uint32_t)
806 ((size_t)ca_justdid -
807 (size_t)cpu->mem->translation_code_chunk_space);
808
809 /* Quickjump to the translated instruction from some
810 previous instruction? */
811 for (i=0; i<cpu->mem->n_quick_jumps; i++)
812 if (cpu->mem->quick_jump_page_offset[i] == p)
813 bintrans_write_quickjump(cpu->mem,
814 cpu->mem->quick_jump_host_address[i],
815 tep->chunk[prev_p]);
816 }
817
818 if (translated && try_to_translate && prev_p < 1023) {
819 int mask = 1 << ((prev_p+1) & 7);
820
821 if (tep->flags[(prev_p+1) >> 3] & mask
822 && !delayed_branch) {
823 bintrans_write_chunkreturn_fail(&ca);
824 /* try_to_translate = 0; */
825 break;
826 }
827
828 /* Glue together with previously translated code,
829 if any: */
830 if (tep->chunk[prev_p+1] != 0 && !delayed_branch) {
831 bintrans_write_instruction__delayedbranch(cpu->mem,
832 &ca, &tep->chunk[prev_p+1], NULL, 1, p+4, 1);
833 /* try_to_translate = 0; */
834 break;
835 }
836
837 if (n_translated > 80 && !delayed_branch) {
838 bintrans_write_instruction__delayedbranch(cpu->mem,
839 &ca, &tep->chunk[prev_p+1], NULL, 1, p+4, 1);
840 /* try_to_translate = 0; */
841 break;
842 }
843 }
844
845 p += sizeof(instr);
846 prev_p ++;
847
848 /* If we have reached a different (MIPS) page, then stop translating. */
849 if (p == 0x1000)
850 try_to_translate = 0;
851 }
852
853 tep->page_is_potentially_in_use = 1;
854
855 /* Not enough translated? Then abort. */
856 if (n_translated < 1) {
857 int mask = 1 << (offset_within_page & 7);
858 tep->flags[offset_within_page >> 3] |= mask;
859 return cpu->cd.mips.bintrans_instructions_executed;
860 }
861
862 /* ca2 = ptr to the head of the new code chunk */
863 ca2 = cpu->mem->translation_code_chunk_space +
864 cpu->mem->translation_code_chunk_space_head;
865
866 /* Add return code: */
867 bintrans_write_chunkreturn(&ca);
868
869 /* chunk_len = nr of bytes occupied by the new code chunk */
870 chunk_len = (size_t)ca - (size_t)ca2;
871
872 /* Invalidate the host's instruction cache, if necessary: */
873 bintrans_host_cacheinvalidate(ca2, chunk_len);
874
875 cpu->mem->translation_code_chunk_space_head += chunk_len;
876
877 /* Align the code chunk space: */
878 cpu->mem->translation_code_chunk_space_head =
879 ((cpu->mem->translation_code_chunk_space_head - 1) | 63) + 1;
880
881
882 /* RUN the code chunk: */
883 f = ca2;
884
885 run_it:
886 /* printf("BEFORE: pc=%016llx r31=%016llx\n",
887 (long long)cpu->pc, (long long)cpu->cd.mips.gpr[31]); */
888
889 enter_chunks_into_tables(cpu, cpu->pc, &tep->chunk[0]);
890
891 old_n_executed = cpu->cd.mips.bintrans_instructions_executed;
892
893 bintrans_runchunk(cpu, f);
894
895 /* printf("AFTER: pc=%016llx r31=%016llx\n",
896 (long long)cpu->pc, (long long)cpu->cd.mips.gpr[31]); */
897
898 if (!cpu->cd.mips.delay_slot && !cpu->cd.mips.nullify_next &&
899 cpu->cd.mips.bintrans_instructions_executed < N_SAFE_BINTRANS_LIMIT
900 && (cpu->pc & 3) == 0
901 && cpu->cd.mips.bintrans_instructions_executed != old_n_executed) {
902 int ok = 0, a, b;
903 struct vth32_table *tbl1;
904
905 if (cpu->mem->bintrans_32bit_only ||
906 (cpu->pc & 0xffffffff80000000ULL) == 0 ||
907 (cpu->pc & 0xffffffff80000000ULL) == 0xffffffff80000000ULL) {
908 /* 32-bit special case: */
909 a = (cpu->pc >> 22) & 0x3ff;
910 b = (cpu->pc >> 12) & 0x3ff;
911
912 /* TODO: There is a bug here; if caches are disabled, and
913 for some reason the code jumps to a different page, then
914 this would jump to code in the cache! The fix is
915 to check for cache isolation, and if so, use the
916 kernel table. Otherwise use table0. */
917
918 /* tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a]; */
919
920 tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0[a];
921 if (tbl1->haddr_entry[b*2] != NULL) {
922 paddr = tbl1->paddr_entry[b] | (cpu->pc & 0xfff);
923 ok = 1;
924 }
925 }
926
927 /* General case, or if the special case above failed: */
928 /* (This may cause exceptions.) */
929 if (!ok) {
930 uint64_t old_pc = cpu->cd.mips.pc_last = cpu->pc;
931 ok = cpu->translate_address(cpu, cpu->pc, &paddr, FLAG_INSTR);
932
933 if (!ok && old_pc != cpu->pc) {
934 /* pc is something like ...0080 or ...0000 or so. */
935 paddr = cpu->pc & 0xfff;
936 ok = 1;
937
938 cpu->cd.mips.pc_last_host_4k_page = NULL;
939 cpu->cd.mips.pc_bintrans_host_4kpage = NULL;
940 }
941 }
942
943 if (ok) {
944 paddr_page = paddr & ~0xfff;
945 offset_within_page = (paddr & 0xfff) >> 2;
946 entry_index = PADDR_TO_INDEX(paddr);
947 tep = cpu->mem->translation_page_entry_array[entry_index];
948 while (tep != NULL) {
949 if (tep->paddr == paddr_page) {
950 int mask;
951 if (tep->chunk[offset_within_page] != 0) {
952 f = (size_t)tep->chunk[offset_within_page] +
953 cpu->mem->translation_code_chunk_space;
954 goto run_it;
955 }
956 mask = 1 << (offset_within_page & 7);
957 if (tep->flags[offset_within_page >> 3] & mask)
958 return cpu->cd.mips.bintrans_instructions_executed;
959 break;
960 }
961 tep = tep->next;
962 }
963
964 #if 1
965 /* We have no translation. */
966 if ((cpu->pc & 0xdff00000) == 0x9fc00000 &&
967 cpu->machine->prom_emulation)
968 return cpu->cd.mips.bintrans_instructions_executed;
969
970 /* This special hack might make the time spent
971 in the main cpu_run_instr() lower: */
972 /* TODO: This doesn't seem to work with R4000 etc? */
973 if (cpu->mem->bintrans_32bit_only) {
974 /* || (cpu->pc & 0xffffffff80000000ULL) == 0 ||
975 (cpu->pc & 0xffffffff80000000ULL) == 0xffffffff80000000ULL) { */
976 int ok = 1;
977 /* 32-bit special case: */
978 a = (cpu->pc >> 22) & 0x3ff;
979 b = (cpu->pc >> 12) & 0x3ff;
980 if (cpu->cd.mips.vaddr_to_hostaddr_table0 !=
981 cpu->cd.mips.vaddr_to_hostaddr_table0_kernel)
982 ok = 0;
983 tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];
984 if (ok && tbl1->haddr_entry[b*2] != NULL) {
985 cpu->cd.mips.pc_last_virtual_page = cpu->pc & ~0xfff;
986 cpu->cd.mips.pc_last_physical_page = paddr & ~0xfff;
987 cpu->cd.mips.pc_last_host_4k_page = (unsigned char *)tbl1->haddr_entry[b*2];
988 cpu->cd.mips.pc_bintrans_host_4kpage = cpu->cd.mips.pc_last_host_4k_page;
989 cpu->cd.mips.pc_bintrans_paddr = paddr;
990
991 /*
992 printf("C: ");
993 printf("v=%016llx p=%016llx h=%p paddr=%016llx\n",
994 (long long)cpu->cd.mips.pc_last_virtual_page,
995 (long long)cpu->cd.mips.pc_last_physical_page,
996 cpu->cd.mips.pc_last_host_4k_page,(long long)paddr);
997 */
998 goto quick_attempt_translate_again;
999 }
1000 }
1001 #endif
1002
1003 /* Return. */
1004 }
1005 }
1006
1007 return cpu->cd.mips.bintrans_instructions_executed;
1008 }
1009
1010
1011 /*
1012 * bintrans_attempt_translate():
1013 *
1014 * Attempt to translate a chunk of code, starting at 'paddr'. If successful,
1015 * the code chunk is run.
1016 *
1017 * Returns the number of executed instructions.
1018 */
1019 int bintrans_attempt_translate(struct cpu *cpu, uint64_t paddr)
1020 {
1021 if (cpu->machine->old_bintrans_enable)
1022 return old_bintrans_attempt_translate(cpu, paddr);
1023
1024 /* TODO */
1025 /* printf("bintrans_attempt_translate(): TODO\n"); */
1026
1027 return 0;
1028 }
1029
1030
1031 /*
1032 * old_bintrans_init_cpu():
1033 *
1034 * This must be called for each cpu wishing to use bintrans. This should
1035 * be called after bintrans_init(), but before any other function in this
1036 * module.
1037 */
1038 void old_bintrans_init_cpu(struct cpu *cpu)
1039 {
1040 int i, offset;
1041
1042 cpu->cd.mips.chunk_base_address = cpu->mem->translation_code_chunk_space;
1043 cpu->cd.mips.bintrans_load_32bit = bintrans_load_32bit;
1044 cpu->cd.mips.bintrans_store_32bit = bintrans_store_32bit;
1045 cpu->cd.mips.bintrans_jump_to_32bit_pc = bintrans_jump_to_32bit_pc;
1046 cpu->cd.mips.bintrans_fast_tlbwri = coproc_tlbwri;
1047 cpu->cd.mips.bintrans_fast_tlbpr = coproc_tlbpr;
1048 cpu->cd.mips.bintrans_fast_rfe = coproc_rfe;
1049 cpu->cd.mips.bintrans_fast_eret = coproc_eret;
1050 cpu->cd.mips.bintrans_simple_exception = mips_cpu_cause_simple_exception;
1051 cpu->cd.mips.fast_vaddr_to_hostaddr = fast_vaddr_to_hostaddr;
1052
1053 /* Initialize vaddr->hostaddr translation tables: */
1054 cpu->cd.mips.vaddr_to_hostaddr_nulltable =
1055 zeroed_alloc(sizeof(struct vth32_table));
1056
1057 /* Data cache: */
1058 offset = 0;
1059 cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable =
1060 zeroed_alloc(sizeof(struct vth32_table));
1061 for (i=0; i<1024; i++) {
1062 cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable->
1063 haddr_entry[i*2] = (void *)((size_t)cpu->cd.mips.cache[0]+offset);
1064 cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable->
1065 haddr_entry[i*2+1] = (void *)((size_t)cpu->cd.mips.cache[0]+offset);
1066 offset = (offset + 4096) % cpu->cd.mips.cache_size[0];
1067 }
1068 cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable->refcount = 1024;
1069
1070 /* Instruction cache: */
1071 offset = 0;
1072 cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable =
1073 zeroed_alloc(sizeof(struct vth32_table));
1074 for (i=0; i<1024; i++) {
1075 cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable->
1076 haddr_entry[i*2] =
1077 (void *)((size_t)cpu->cd.mips.cache[1]+offset);
1078 cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable->
1079 haddr_entry[i*2+1] =
1080 (void *)((size_t)cpu->cd.mips.cache[1]+offset);
1081 offset = (offset + 4096) % cpu->cd.mips.cache_size[1];
1082 }
1083 cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable->refcount = 1024;
1084
1085 cpu->cd.mips.vaddr_to_hostaddr_table0_kernel =
1086 zeroed_alloc(1024 * sizeof(struct vth32_table *));
1087 cpu->cd.mips.vaddr_to_hostaddr_table0_user =
1088 zeroed_alloc(1024 * sizeof(struct vth32_table *));
1089 cpu->cd.mips.vaddr_to_hostaddr_table0_cacheisol_i =
1090 zeroed_alloc(1024 * sizeof(struct vth32_table *));
1091 cpu->cd.mips.vaddr_to_hostaddr_table0_cacheisol_d =
1092 zeroed_alloc(1024 * sizeof(struct vth32_table *));
1093
1094 for (i=0; i<1024; i++) {
1095 cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[i] = cpu->cd.mips.vaddr_to_hostaddr_nulltable;
1096 cpu->cd.mips.vaddr_to_hostaddr_table0_user[i] = cpu->cd.mips.vaddr_to_hostaddr_nulltable;
1097 cpu->cd.mips.vaddr_to_hostaddr_table0_cacheisol_i[i] = cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable;
1098 cpu->cd.mips.vaddr_to_hostaddr_table0_cacheisol_d[i] = cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable;
1099 }
1100
1101 cpu->cd.mips.vaddr_to_hostaddr_table0 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel;
1102
1103 cpu->mem->bintrans_32bit_only = (cpu->cd.mips.cpu_type.isa_level <= 2
1104 || cpu->cd.mips.cpu_type.isa_level == 32);
1105 }
1106
1107
1108 /*
1109 * bintrans_init_cpu():
1110 *
1111 * This must be called for each cpu wishing to use bintrans. This should
1112 * be called after bintrans_init(), but before any other function in this
1113 * module.
1114 */
1115 void bintrans_init_cpu(struct cpu *cpu)
1116 {
1117 if (cpu->machine->old_bintrans_enable) {
1118 old_bintrans_init_cpu(cpu);
1119 return;
1120 }
1121
1122 /* TODO */
1123 debug("\nbintrans_init_cpu(): New bintrans: TODO");
1124 }
1125
1126
1127 /*
1128 * bintrans_init():
1129 *
1130 * Should be called before any other bintrans_*() function is used.
1131 */
1132 void bintrans_init(struct machine *machine, struct memory *mem)
1133 {
1134 int res, i, n = 1 << BINTRANS_CACHE_N_INDEX_BITS;
1135 size_t s;
1136
1137 mem->translation_page_entry_array = malloc(sizeof(
1138 struct translation_page_entry *) *
1139 (1 << BINTRANS_CACHE_N_INDEX_BITS));
1140 if (mem->translation_page_entry_array == NULL) {
1141 fprintf(stderr, "old_bintrans_init(): out of memory\n");
1142 exit(1);
1143 }
1144
1145 /*
1146 * The entry array must be NULLed, as these are pointers to
1147 * translation page entries.
1148 */
1149 for (i=0; i<n; i++)
1150 mem->translation_page_entry_array[i] = NULL;
1151
1152 /* Allocate the large code chunk space: */
1153 s = machine->bintrans_size + CODE_CHUNK_SPACE_MARGIN;
1154 mem->translation_code_chunk_space = (unsigned char *) mmap(NULL, s,
1155 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
1156
1157 /* If mmap() failed, try malloc(): */
1158 if (mem->translation_code_chunk_space == NULL) {
1159 mem->translation_code_chunk_space = malloc(s);
1160 if (mem->translation_code_chunk_space == NULL) {
1161 fprintf(stderr, "old_bintrans_init(): out of "
1162 "memory (2)\n");
1163 exit(1);
1164 }
1165 }
1166
1167 debug("bintrans: "BACKEND_NAME", %i MB translation cache at %p\n",
1168 (int)(s/1048576), mem->translation_code_chunk_space);
1169
1170 /*
1171 * The translation_code_chunk_space does not need to be zeroed,
1172 * but the pointers to where in the chunk space we are about to
1173 * add new chunks must be initialized to the beginning of the
1174 * chunk space.
1175 */
1176 mem->translation_code_chunk_space_head = 0;
1177
1178 /*
1179 * Some operating systems (for example OpenBSD using the default
1180 * stack protection settings in GCC) don't allow code to be
1181 * dynamically created in memory and executed. This will attempt
1182 * to enable execution of the code chunk space.
1183 *
1184 * NOTE/TODO: A Linux man page for mprotect from 1997 says that
1185 * "POSIX.1b says that mprotect can be used only on regions
1186 * of memory obtained from mmap(2).". If malloc() isn't implemented
1187 * using mmap(), then this could be a problem.
1188 */
1189 res = mprotect((void *)mem->translation_code_chunk_space,
1190 s, PROT_READ | PROT_WRITE | PROT_EXEC);
1191 if (res)
1192 debug("warning: mprotect() failed with errno %i."
1193 " this usually doesn't really matter...\n", errno);
1194
1195 bintrans_backend_init();
1196
1197 if (!machine->old_bintrans_enable) {
1198 debug("bintrans_init(): TODO: New bintrans (?)\n");
1199 }
1200 }
1201
1202
1203 #endif /* BINTRANS */

  ViewVC Help
Powered by ViewVC 1.1.26