/[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

Annotation of /trunk/src/bintrans.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations)
Mon Oct 8 16:18:27 2007 UTC (16 years, 6 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 dpavlin 2 /*
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 dpavlin 10 * $Id: bintrans.c,v 1.169 2005/06/22 10:12:25 debug Exp $
29 dpavlin 2 *
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 dpavlin 4 void bintrans_restart(struct cpu *cpu) { }
127 dpavlin 2 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 dpavlin 4 * 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 dpavlin 2 * 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 dpavlin 10 if (tbl1->haddr_entry[b*2] != NULL)
316 dpavlin 2 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 dpavlin 4 offset_within_page = (paddr & 0xfff) >> 2;
366 dpavlin 2 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 dpavlin 4 int mask;
371 dpavlin 2
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 dpavlin 4
378     mask = 1 << (offset_within_page & 7);
379 dpavlin 2 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 dpavlin 4 bintrans_restart(cpu);
405 dpavlin 2 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 dpavlin 4 prev_p = p >> 2;
453 dpavlin 2 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 dpavlin 4 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 dpavlin 2 n_translated += translated;
645     break;
646    
647     case HI6_LUI:
648 dpavlin 4 translated = try_to_translate =
649     bintrans_write_instruction__lui(&ca,
650     instr[2] & 31, (instr[1] << 8) + instr[0]);
651 dpavlin 2 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 dpavlin 4 } else
684     try_to_translate = 0;
685 dpavlin 2 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 dpavlin 4 } else
718     try_to_translate = 0;
719 dpavlin 2 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 dpavlin 4 #if 0
795 dpavlin 2 if (stop_after_delayed_branch)
796     try_to_translate = 0;
797 dpavlin 4 #endif
798 dpavlin 2 }
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 dpavlin 4 if (translated && try_to_translate && prev_p < 1023) {
819     int mask = 1 << ((prev_p+1) & 7);
820 dpavlin 2
821 dpavlin 4 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 dpavlin 2
828 dpavlin 4 /* 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 dpavlin 2
837 dpavlin 4 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 dpavlin 2 }
844    
845     p += sizeof(instr);
846 dpavlin 4 prev_p ++;
847 dpavlin 2
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 dpavlin 10 if (tbl1->haddr_entry[b*2] != NULL) {
922 dpavlin 2 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 dpavlin 4 offset_within_page = (paddr & 0xfff) >> 2;
946 dpavlin 2 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 dpavlin 4 int mask;
951 dpavlin 2 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 dpavlin 4 mask = 1 << (offset_within_page & 7);
957 dpavlin 2 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 dpavlin 10 if ((cpu->pc & 0xdff00000) == 0x9fc00000 &&
967 dpavlin 2 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 dpavlin 10 if (ok && tbl1->haddr_entry[b*2] != NULL) {
985 dpavlin 2 cpu->cd.mips.pc_last_virtual_page = cpu->pc & ~0xfff;
986     cpu->cd.mips.pc_last_physical_page = paddr & ~0xfff;
987 dpavlin 10 cpu->cd.mips.pc_last_host_4k_page = (unsigned char *)tbl1->haddr_entry[b*2];
988 dpavlin 2 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 dpavlin 10 cpu->cd.mips.bintrans_load_32bit = bintrans_load_32bit;
1044     cpu->cd.mips.bintrans_store_32bit = bintrans_store_32bit;
1045 dpavlin 2 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 dpavlin 10 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 dpavlin 2 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 dpavlin 10 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 dpavlin 2 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 dpavlin 4
1103     cpu->mem->bintrans_32bit_only = (cpu->cd.mips.cpu_type.isa_level <= 2
1104     || cpu->cd.mips.cpu_type.isa_level == 32);
1105 dpavlin 2 }
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