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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 38701 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26