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

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

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


1 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 6 * $Id: bintrans.c,v 1.167 2005/05/14 19:47:59 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     if (tbl1->haddr_entry[b] != NULL)
316     tbl1->bintrans_chunks[b] = chunk0;
317     break;
318     default:
319     ;
320     }
321     }
322    
323    
324     /*
325     * old_bintrans_attempt_translate():
326     *
327     * Attempt to translate a chunk of code, starting at 'paddr'. If successful,
328     * the code chunk is run.
329     *
330     * Returns the number of executed instructions.
331     */
332     int old_bintrans_attempt_translate(struct cpu *cpu, uint64_t paddr)
333     {
334     uint64_t paddr_page;
335     int offset_within_page;
336     int entry_index;
337     unsigned char *host_mips_page;
338     unsigned char *ca, *ca_justdid, *ca2;
339     int res, hi6, special6, regimm5;
340     unsigned char instr[4];
341     int old_n_executed;
342     size_t p;
343     int try_to_translate;
344     int n_translated, translated;
345     unsigned char *f;
346     struct translation_page_entry *tep;
347     size_t chunk_len;
348     int rs,rt,rd,sa,imm;
349     uint32_t *potential_chunk_p; /* for branches */
350     int byte_order_cached_bigendian;
351     int delayed_branch, stop_after_delayed_branch;
352     uint64_t delayed_branch_new_p;
353     int prev_p;
354    
355    
356     /* Abort if the current "environment" isn't safe enough: */
357     if (cpu->cd.mips.delay_slot || cpu->cd.mips.nullify_next ||
358     (paddr & 3) != 0)
359     return cpu->cd.mips.bintrans_instructions_executed;
360    
361     byte_order_cached_bigendian = (cpu->byte_order == EMUL_BIG_ENDIAN);
362    
363     /* Is this a part of something that is already translated? */
364     paddr_page = paddr & ~0xfff;
365 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     if (tbl1->haddr_entry[b] != NULL) {
922     paddr = tbl1->paddr_entry[b] | (cpu->pc & 0xfff);
923     ok = 1;
924     }
925     }
926    
927     /* General case, or if the special case above failed: */
928     /* (This may cause exceptions.) */
929     if (!ok) {
930     uint64_t old_pc = cpu->cd.mips.pc_last = cpu->pc;
931     ok = cpu->translate_address(cpu, cpu->pc, &paddr, FLAG_INSTR);
932    
933     if (!ok && old_pc != cpu->pc) {
934     /* pc is something like ...0080 or ...0000 or so. */
935     paddr = cpu->pc & 0xfff;
936     ok = 1;
937    
938     cpu->cd.mips.pc_last_host_4k_page = NULL;
939     cpu->cd.mips.pc_bintrans_host_4kpage = NULL;
940     }
941     }
942    
943     if (ok) {
944     paddr_page = paddr & ~0xfff;
945 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     if ((cpu->pc & 0xfff00000) == 0xbfc00000 &&
967     cpu->machine->prom_emulation)
968     return cpu->cd.mips.bintrans_instructions_executed;
969    
970     /* This special hack might make the time spent
971     in the main cpu_run_instr() lower: */
972     /* TODO: This doesn't seem to work with R4000 etc? */
973     if (cpu->mem->bintrans_32bit_only) {
974     /* || (cpu->pc & 0xffffffff80000000ULL) == 0 ||
975     (cpu->pc & 0xffffffff80000000ULL) == 0xffffffff80000000ULL) { */
976     int ok = 1;
977     /* 32-bit special case: */
978     a = (cpu->pc >> 22) & 0x3ff;
979     b = (cpu->pc >> 12) & 0x3ff;
980     if (cpu->cd.mips.vaddr_to_hostaddr_table0 !=
981     cpu->cd.mips.vaddr_to_hostaddr_table0_kernel)
982     ok = 0;
983     tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];
984     if (ok && tbl1->haddr_entry[b] != NULL) {
985     cpu->cd.mips.pc_last_virtual_page = cpu->pc & ~0xfff;
986     cpu->cd.mips.pc_last_physical_page = paddr & ~0xfff;
987     cpu->cd.mips.pc_last_host_4k_page = (unsigned char *)
988     (((size_t)tbl1->haddr_entry[b]) & ~1);
989     cpu->cd.mips.pc_bintrans_host_4kpage = cpu->cd.mips.pc_last_host_4k_page;
990     cpu->cd.mips.pc_bintrans_paddr = paddr;
991    
992     /*
993     printf("C: ");
994     printf("v=%016llx p=%016llx h=%p paddr=%016llx\n",
995     (long long)cpu->cd.mips.pc_last_virtual_page,
996     (long long)cpu->cd.mips.pc_last_physical_page,
997     cpu->cd.mips.pc_last_host_4k_page,(long long)paddr);
998     */
999     goto quick_attempt_translate_again;
1000     }
1001     }
1002     #endif
1003    
1004     /* Return. */
1005     }
1006     }
1007    
1008     return cpu->cd.mips.bintrans_instructions_executed;
1009     }
1010    
1011    
1012     /*
1013     * bintrans_attempt_translate():
1014     *
1015     * Attempt to translate a chunk of code, starting at 'paddr'. If successful,
1016     * the code chunk is run.
1017     *
1018     * Returns the number of executed instructions.
1019     */
1020     int bintrans_attempt_translate(struct cpu *cpu, uint64_t paddr)
1021     {
1022     if (cpu->machine->old_bintrans_enable)
1023     return old_bintrans_attempt_translate(cpu, paddr);
1024    
1025     /* TODO */
1026     /* printf("bintrans_attempt_translate(): TODO\n"); */
1027    
1028     return 0;
1029     }
1030    
1031    
1032     /*
1033     * old_bintrans_init_cpu():
1034     *
1035     * This must be called for each cpu wishing to use bintrans. This should
1036     * be called after bintrans_init(), but before any other function in this
1037     * module.
1038     */
1039     void old_bintrans_init_cpu(struct cpu *cpu)
1040     {
1041     int i, offset;
1042    
1043     cpu->cd.mips.chunk_base_address = cpu->mem->translation_code_chunk_space;
1044     cpu->cd.mips.bintrans_loadstore_32bit = bintrans_loadstore_32bit;
1045     cpu->cd.mips.bintrans_jump_to_32bit_pc = bintrans_jump_to_32bit_pc;
1046     cpu->cd.mips.bintrans_fast_tlbwri = coproc_tlbwri;
1047     cpu->cd.mips.bintrans_fast_tlbpr = coproc_tlbpr;
1048     cpu->cd.mips.bintrans_fast_rfe = coproc_rfe;
1049     cpu->cd.mips.bintrans_fast_eret = coproc_eret;
1050     cpu->cd.mips.bintrans_simple_exception = mips_cpu_cause_simple_exception;
1051     cpu->cd.mips.fast_vaddr_to_hostaddr = fast_vaddr_to_hostaddr;
1052    
1053     /* Initialize vaddr->hostaddr translation tables: */
1054     cpu->cd.mips.vaddr_to_hostaddr_nulltable =
1055     zeroed_alloc(sizeof(struct vth32_table));
1056    
1057     /* Data cache: */
1058     offset = 0;
1059     cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable =
1060     zeroed_alloc(sizeof(struct vth32_table));
1061     for (i=0; i<1024; i++) {
1062     cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable->haddr_entry[i] =
1063     (void *)(((size_t)cpu->cd.mips.cache[0]+offset) | 1);
1064     offset = (offset + 4096) % cpu->cd.mips.cache_size[0];
1065     }
1066     cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable->refcount = 1024;
1067    
1068     /* Instruction cache: */
1069     offset = 0;
1070     cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable =
1071     zeroed_alloc(sizeof(struct vth32_table));
1072     for (i=0; i<1024; i++) {
1073     cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable->haddr_entry[i] =
1074     (void *)(((size_t)cpu->cd.mips.cache[1]+offset) | 1);
1075     offset = (offset + 4096) % cpu->cd.mips.cache_size[1];
1076     }
1077     cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable->refcount = 1024;
1078    
1079     cpu->cd.mips.vaddr_to_hostaddr_table0_kernel =
1080     zeroed_alloc(1024 * sizeof(struct vth32_table *));
1081     cpu->cd.mips.vaddr_to_hostaddr_table0_user =
1082     zeroed_alloc(1024 * sizeof(struct vth32_table *));
1083     cpu->cd.mips.vaddr_to_hostaddr_table0_cacheisol_i =
1084     zeroed_alloc(1024 * sizeof(struct vth32_table *));
1085     cpu->cd.mips.vaddr_to_hostaddr_table0_cacheisol_d =
1086     zeroed_alloc(1024 * sizeof(struct vth32_table *));
1087    
1088     for (i=0; i<1024; i++) {
1089     cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[i] = cpu->cd.mips.vaddr_to_hostaddr_nulltable;
1090     cpu->cd.mips.vaddr_to_hostaddr_table0_user[i] = cpu->cd.mips.vaddr_to_hostaddr_nulltable;
1091     cpu->cd.mips.vaddr_to_hostaddr_table0_cacheisol_i[i] = cpu->cd.mips.vaddr_to_hostaddr_r2k3k_icachetable;
1092     cpu->cd.mips.vaddr_to_hostaddr_table0_cacheisol_d[i] = cpu->cd.mips.vaddr_to_hostaddr_r2k3k_dcachetable;
1093     }
1094    
1095     cpu->cd.mips.vaddr_to_hostaddr_table0 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel;
1096 dpavlin 4
1097     cpu->mem->bintrans_32bit_only = (cpu->cd.mips.cpu_type.isa_level <= 2
1098     || cpu->cd.mips.cpu_type.isa_level == 32);
1099 dpavlin 2 }
1100    
1101    
1102     /*
1103     * bintrans_init_cpu():
1104     *
1105     * This must be called for each cpu wishing to use bintrans. This should
1106     * be called after bintrans_init(), but before any other function in this
1107     * module.
1108     */
1109     void bintrans_init_cpu(struct cpu *cpu)
1110     {
1111     if (cpu->machine->old_bintrans_enable) {
1112     old_bintrans_init_cpu(cpu);
1113     return;
1114     }
1115    
1116     /* TODO */
1117     debug("\nbintrans_init_cpu(): New bintrans: TODO");
1118     }
1119    
1120    
1121     /*
1122     * bintrans_init():
1123     *
1124     * Should be called before any other bintrans_*() function is used.
1125     */
1126     void bintrans_init(struct machine *machine, struct memory *mem)
1127     {
1128     int res, i, n = 1 << BINTRANS_CACHE_N_INDEX_BITS;
1129     size_t s;
1130    
1131     mem->translation_page_entry_array = malloc(sizeof(
1132     struct translation_page_entry *) *
1133     (1 << BINTRANS_CACHE_N_INDEX_BITS));
1134     if (mem->translation_page_entry_array == NULL) {
1135     fprintf(stderr, "old_bintrans_init(): out of memory\n");
1136     exit(1);
1137     }
1138    
1139     /*
1140     * The entry array must be NULLed, as these are pointers to
1141     * translation page entries.
1142     */
1143     for (i=0; i<n; i++)
1144     mem->translation_page_entry_array[i] = NULL;
1145    
1146     /* Allocate the large code chunk space: */
1147     s = machine->bintrans_size + CODE_CHUNK_SPACE_MARGIN;
1148     mem->translation_code_chunk_space = (unsigned char *) mmap(NULL, s,
1149     PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
1150    
1151     /* If mmap() failed, try malloc(): */
1152     if (mem->translation_code_chunk_space == NULL) {
1153     mem->translation_code_chunk_space = malloc(s);
1154     if (mem->translation_code_chunk_space == NULL) {
1155     fprintf(stderr, "old_bintrans_init(): out of "
1156     "memory (2)\n");
1157     exit(1);
1158     }
1159     }
1160    
1161     debug("bintrans: "BACKEND_NAME", %i MB translation cache at %p\n",
1162     (int)(s/1048576), mem->translation_code_chunk_space);
1163    
1164     /*
1165     * The translation_code_chunk_space does not need to be zeroed,
1166     * but the pointers to where in the chunk space we are about to
1167     * add new chunks must be initialized to the beginning of the
1168     * chunk space.
1169     */
1170     mem->translation_code_chunk_space_head = 0;
1171    
1172     /*
1173     * Some operating systems (for example OpenBSD using the default
1174     * stack protection settings in GCC) don't allow code to be
1175     * dynamically created in memory and executed. This will attempt
1176     * to enable execution of the code chunk space.
1177     *
1178     * NOTE/TODO: A Linux man page for mprotect from 1997 says that
1179     * "POSIX.1b says that mprotect can be used only on regions
1180     * of memory obtained from mmap(2).". If malloc() isn't implemented
1181     * using mmap(), then this could be a problem.
1182     */
1183     res = mprotect((void *)mem->translation_code_chunk_space,
1184     s, PROT_READ | PROT_WRITE | PROT_EXEC);
1185     if (res)
1186     debug("warning: mprotect() failed with errno %i."
1187     " this usually doesn't really matter...\n", errno);
1188    
1189     bintrans_backend_init();
1190    
1191     if (!machine->old_bintrans_enable) {
1192     debug("bintrans_init(): TODO: New bintrans (?)\n");
1193     }
1194     }
1195    
1196    
1197     #endif /* BINTRANS */

  ViewVC Help
Powered by ViewVC 1.1.26