/[gxemul]/trunk/src/cpus/bintrans.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/src/cpus/bintrans.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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


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

  ViewVC Help
Powered by ViewVC 1.1.26