/[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 6 - (show annotations)
Mon Oct 8 16:18:11 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 36991 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.772 2005/06/04 12:02:16 debug Exp $
20050428	Disabling the "-fmove-all-movables" option in the configure
		script, because it causes the compile to fail on OpenBSD/sgi.
20050502	Minor updates.
20050503	Removing the WRT54G mode (it was bogus anyway), and adding a
		comment about Windows NT for MIPS in doc/experiments.html.
		Minor updates to the x86 instruction decoding.
20050504	Adding some more x86 instructions.
		Adding support for reading files from ISO9660 CDROMs (including
		gzipped files). It's an ugly hack, but it seems to work.
		Various other minor updates (dev_vga.c, pc_bios.c etc).
20050505	Some more x86-related updates.
		Beginning (what I hope will be) a major code cleanup phase.
		"bootris" (an x86 bootsector) runs :-)
20050506	Adding some more x86 instructions.
20050507	tmpnam => mkstemp.
		Working on a hack to allow VGA charcells to be shown even when
		not running with X11.
		Adding more x86 instructions.
20050508	x86 32-bit SIB addressing fix, and more instructions.
20050509	Adding more x86 instructions.
20050510	Minor documentation updates, and other updates (x86 stuff etc.)
20050511	More x86-related updates.
20050513	Various updates, mostly x86-related. (Trying to fix flag 
		calculation, factoring out the ugly shift/rotate code, and
		some other things.)
20050514	Adding support for loading some old i386 a.out executables.
		Finally beginning the cleanup of machine/PROM/bios dependant
		info.
		Some minor documentation updates.
		Trying to clean up ARCBIOS stuff a little.
20050515	Trying to make it possible to actually use more than one disk
		type per machine (floppy, ide, scsi).
		Trying to clean up the kbd vs PROM console stuff. (For PC and
		ARC emulation modes, mostly.)
		Beginning to add an 8259 interrupt controller, and connecting
		it to the x86 emulation.
20050516	The first x86 interrupts seem to work (keyboard stuff).
		Adding a 8253/8254 programmable interval timer skeleton.
		FreeDOS now reaches a command prompt and can be interacted
		with.
20050517	After some bugfixes, MS-DOS also (sometimes) reaches a
		command prompt now.
		Trying to fix the pckbc to work with MS-DOS' keyb.com, but no
		success yet.
20050518	Adding a simple 32-bit x86 MMU skeleton.
20050519	Some more work on the x86 stuff. (Beginning the work on paging,
		and various other fixes).
20050520	More updates. Working on dev_vga (4-bit graphics modes), adding
		40 columns support to the PC bios emulation.
		Trying to add support for resizing windows when switching
		between graphics modes.
20050521	Many more x86-related updates.
20050522	Correcting the initial stack pointer's sign-extension for
		ARCBIOS emulation (thanks to Alec Voropay for noticing the
		error).
		Continuing on the cleanup (ARCBIOS etc).
		dev_vga updates.
20050523	More x86 updates: trying to add some support for protected mode
		interrupts (via gate descriptors) and many other fixes.
		More ARCBIOS cleanup.
		Adding a device flag which indicates that reads cause no
		side-effects. (Useful for the "dump" command in the debugger,
		and other things.)
		Adding support for directly starting up x86 ELFs, skipping the
		bootloader stage. (Most ELFs, however, are not suitable for
		this.)
20050524	Adding simple 32-bit x86 TSS task switching, but no privilege
		level support yet.
		More work on dev_vga. A small "Copper bars" demo works. :-)
		Adding support for Trap Flag (single-step exceptions), at least
		in real mode, and various other x86-related fixes.
20050525	Adding a new disk image prefix (gH;S;) which can be used to
		override the default nr of heads and sectors per track.
20050527	Various bug fixes, more work on the x86 mode (stack change on
		interrupts between different priv.levels), and some minor
		documentation updates.
20050528	Various fixes (x86 stuff).
20050529	More x86 fixes. An OpenBSD/i386 bootfloppy reaches userland
		and can be interacted with (although there are problems with
		key repetition). NetBSD/i386 triggers a serious CISC-related
		problem: instruction fetches across page boundaries, where
		the later part isn't actually part of the instruction.
20050530	Various minor updates. (Documentation updates, etc.)
20050531	Adding some experimental code (experiments/new_test_*) which
		could be useful for dynamic (but not binary) translation in
		the future.
20050602	Adding a dummy ARM skeleton.
		Fixing the pckbc key repetition problem (by adding release
		scancodes for all keypresses).
20050603	Minor updates for the next release.
20050604	Release testing. Minor updates.

==============  RELEASE 0.3.3  ==============

20050604	There'll probably be a 0.3.3.1 release soon, with some very
		very tiny updates.


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.167 2005/05/14 19:47:59 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] != 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] != 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 & 0xfff00000) == 0xbfc00000 &&
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] != 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 *)
988 (((size_t)tbl1->haddr_entry[b]) & ~1);
989 cpu->cd.mips.pc_bintrans_host_4kpage = cpu->cd.mips.pc_last_host_4k_page;
990 cpu->cd.mips.pc_bintrans_paddr = paddr;
991
992 /*
993 printf("C: ");
994 printf("v=%016llx p=%016llx h=%p paddr=%016llx\n",
995 (long long)cpu->cd.mips.pc_last_virtual_page,
996 (long long)cpu->cd.mips.pc_last_physical_page,
997 cpu->cd.mips.pc_last_host_4k_page,(long long)paddr);
998 */
999 goto quick_attempt_translate_again;
1000 }
1001 }
1002 #endif
1003
1004 /* Return. */
1005 }
1006 }
1007
1008 return cpu->cd.mips.bintrans_instructions_executed;
1009 }
1010
1011
1012 /*
1013 * bintrans_attempt_translate():
1014 *
1015 * Attempt to translate a chunk of code, starting at 'paddr'. If successful,
1016 * the code chunk is run.
1017 *
1018 * Returns the number of executed instructions.
1019 */
1020 int bintrans_attempt_translate(struct cpu *cpu, uint64_t paddr)
1021 {
1022 if (cpu->machine->old_bintrans_enable)
1023 return old_bintrans_attempt_translate(cpu, paddr);
1024
1025 /* TODO */
1026 /* printf("bintrans_attempt_translate(): TODO\n"); */
1027
1028 return 0;
1029 }
1030
1031
1032 /*
1033 * old_bintrans_init_cpu():
1034 *
1035 * This must be called for each cpu wishing to use bintrans. This should
1036 * be called after bintrans_init(), but before any other function in this
1037 * module.
1038 */
1039 void old_bintrans_init_cpu(struct cpu *cpu)
1040 {
1041 int i, offset;
1042
1043 cpu->cd.mips.chunk_base_address = cpu->mem->translation_code_chunk_space;
1044 cpu->cd.mips.bintrans_loadstore_32bit = bintrans_loadstore_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->haddr_entry[i] =
1063 (void *)(((size_t)cpu->cd.mips.cache[0]+offset) | 1);
1064 offset = (offset + 4096) % cpu->cd.mips.cache_size[0];
1065 }
1066 cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable->refcount = 1024;
1067
1068 /* Instruction cache: */
1069 offset = 0;
1070 cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable =
1071 zeroed_alloc(sizeof(struct vth32_table));
1072 for (i=0; i<1024; i++) {
1073 cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable->haddr_entry[i] =
1074 (void *)(((size_t)cpu->cd.mips.cache[1]+offset) | 1);
1075 offset = (offset + 4096) % cpu->cd.mips.cache_size[1];
1076 }
1077 cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable->refcount = 1024;
1078
1079 cpu->cd.mips.vaddr_to_hostaddr_table0_kernel =
1080 zeroed_alloc(1024 * sizeof(struct vth32_table *));
1081 cpu->cd.mips.vaddr_to_hostaddr_table0_user =
1082 zeroed_alloc(1024 * sizeof(struct vth32_table *));
1083 cpu->cd.mips.vaddr_to_hostaddr_table0_cacheisol_i =
1084 zeroed_alloc(1024 * sizeof(struct vth32_table *));
1085 cpu->cd.mips.vaddr_to_hostaddr_table0_cacheisol_d =
1086 zeroed_alloc(1024 * sizeof(struct vth32_table *));
1087
1088 for (i=0; i<1024; i++) {
1089 cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[i] = cpu->cd.mips.vaddr_to_hostaddr_nulltable;
1090 cpu->cd.mips.vaddr_to_hostaddr_table0_user[i] = cpu->cd.mips.vaddr_to_hostaddr_nulltable;
1091 cpu->cd.mips.vaddr_to_hostaddr_table0_cacheisol_i[i] = cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable;
1092 cpu->cd.mips.vaddr_to_hostaddr_table0_cacheisol_d[i] = cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable;
1093 }
1094
1095 cpu->cd.mips.vaddr_to_hostaddr_table0 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel;
1096
1097 cpu->mem->bintrans_32bit_only = (cpu->cd.mips.cpu_type.isa_level <= 2
1098 || cpu->cd.mips.cpu_type.isa_level == 32);
1099 }
1100
1101
1102 /*
1103 * bintrans_init_cpu():
1104 *
1105 * This must be called for each cpu wishing to use bintrans. This should
1106 * be called after bintrans_init(), but before any other function in this
1107 * module.
1108 */
1109 void bintrans_init_cpu(struct cpu *cpu)
1110 {
1111 if (cpu->machine->old_bintrans_enable) {
1112 old_bintrans_init_cpu(cpu);
1113 return;
1114 }
1115
1116 /* TODO */
1117 debug("\nbintrans_init_cpu(): New bintrans: TODO");
1118 }
1119
1120
1121 /*
1122 * bintrans_init():
1123 *
1124 * Should be called before any other bintrans_*() function is used.
1125 */
1126 void bintrans_init(struct machine *machine, struct memory *mem)
1127 {
1128 int res, i, n = 1 << BINTRANS_CACHE_N_INDEX_BITS;
1129 size_t s;
1130
1131 mem->translation_page_entry_array = malloc(sizeof(
1132 struct translation_page_entry *) *
1133 (1 << BINTRANS_CACHE_N_INDEX_BITS));
1134 if (mem->translation_page_entry_array == NULL) {
1135 fprintf(stderr, "old_bintrans_init(): out of memory\n");
1136 exit(1);
1137 }
1138
1139 /*
1140 * The entry array must be NULLed, as these are pointers to
1141 * translation page entries.
1142 */
1143 for (i=0; i<n; i++)
1144 mem->translation_page_entry_array[i] = NULL;
1145
1146 /* Allocate the large code chunk space: */
1147 s = machine->bintrans_size + CODE_CHUNK_SPACE_MARGIN;
1148 mem->translation_code_chunk_space = (unsigned char *) mmap(NULL, s,
1149 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
1150
1151 /* If mmap() failed, try malloc(): */
1152 if (mem->translation_code_chunk_space == NULL) {
1153 mem->translation_code_chunk_space = malloc(s);
1154 if (mem->translation_code_chunk_space == NULL) {
1155 fprintf(stderr, "old_bintrans_init(): out of "
1156 "memory (2)\n");
1157 exit(1);
1158 }
1159 }
1160
1161 debug("bintrans: "BACKEND_NAME", %i MB translation cache at %p\n",
1162 (int)(s/1048576), mem->translation_code_chunk_space);
1163
1164 /*
1165 * The translation_code_chunk_space does not need to be zeroed,
1166 * but the pointers to where in the chunk space we are about to
1167 * add new chunks must be initialized to the beginning of the
1168 * chunk space.
1169 */
1170 mem->translation_code_chunk_space_head = 0;
1171
1172 /*
1173 * Some operating systems (for example OpenBSD using the default
1174 * stack protection settings in GCC) don't allow code to be
1175 * dynamically created in memory and executed. This will attempt
1176 * to enable execution of the code chunk space.
1177 *
1178 * NOTE/TODO: A Linux man page for mprotect from 1997 says that
1179 * "POSIX.1b says that mprotect can be used only on regions
1180 * of memory obtained from mmap(2).". If malloc() isn't implemented
1181 * using mmap(), then this could be a problem.
1182 */
1183 res = mprotect((void *)mem->translation_code_chunk_space,
1184 s, PROT_READ | PROT_WRITE | PROT_EXEC);
1185 if (res)
1186 debug("warning: mprotect() failed with errno %i."
1187 " this usually doesn't really matter...\n", errno);
1188
1189 bintrans_backend_init();
1190
1191 if (!machine->old_bintrans_enable) {
1192 debug("bintrans_init(): TODO: New bintrans (?)\n");
1193 }
1194 }
1195
1196
1197 #endif /* BINTRANS */

  ViewVC Help
Powered by ViewVC 1.1.26