/[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 14 - (hide annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 38643 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

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

  ViewVC Help
Powered by ViewVC 1.1.26