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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (hide annotations)
Mon Oct 8 16:18:38 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 24450 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.905 2005/08/16 09:16:24 debug Exp $
20050628	Continuing the work on the ARM translation engine. end_of_page
		works. Experimenting with load/store translation caches
		(virtual -> physical -> host).
20050629	More ARM stuff (memory access translation cache, mostly). This
		might break a lot of stuff elsewhere, probably some MIPS-
		related translation things.
20050630	Many load/stores are now automatically generated and included
		into cpu_arm_instr.c; 1024 functions in total (!).
		Fixes based on feedback from Alec Voropay: only print 8 hex
		digits instead of 16 in some cases when emulating 32-bit
		machines; similar 8 vs 16 digit fix for breakpoint addresses;
		4Kc has 16 TLB entries, not 48; the MIPS config select1
		register is now printed with "reg ,0".
		Also changing many other occurances of 16 vs 8 digit output.
		Adding cache associativity fields to mips_cpu_types.h; updating
		some other cache fields; making the output of
		mips_cpu_dumpinfo() look nicer.
		Generalizing the bintrans stuff for device accesses to also
		work with the new translation system. (This might also break
		some MIPS things.)
		Adding multi-load/store instructions to the ARM disassembler
		and the translator, and some optimizations of various kinds.
20050701	Adding a simple dev_disk (it can read/write sectors from
		disk images).
20050712	Adding dev_ether (a simple ethernet send/receive device).
		Debugger command "ninstrs" for toggling show_nr_of_instructions
		during runtime.
		Removing the framebuffer logo.
20050713	Continuing on dev_ether.
		Adding a dummy cpu_alpha (again).
20050714	More work on cpu_alpha.
20050715	More work on cpu_alpha. Many instructions work, enough to run
		a simple framebuffer fill test (similar to the ARM test).
20050716	More Alpha stuff.
20050717	Minor updates (Alpha stuff).
20050718	Minor updates (Alpha stuff).
20050719	Generalizing some Alpha instructions.
20050720	More Alpha-related updates.
20050721	Continuing on cpu_alpha. Importing rpb.h from NetBSD/alpha.
20050722	Alpha-related updates: userland stuff (Hello World using
		write() compiled statically for FreeBSD/Alpha runs fine), and
		more instructions are now implemented.
20050723	Fixing ldq_u and stq_u.
		Adding more instructions (conditional moves, masks, extracts,
		shifts).
20050724	More FreeBSD/Alpha userland stuff, and adding some more
		instructions (inserts).
20050725	Continuing on the Alpha stuff. (Adding dummy ldt/stt.)
		Adding a -A command line option to turn off alignment checks
		in some cases (for translated code).
		Trying to remove the old bintrans code which updated the pc
		and nr_of_executed_instructions for every instruction.
20050726	Making another attempt att removing the pc/nr of instructions
		code. This time it worked, huge performance increase for
		artificial test code, but performance loss for real-world
		code :-( so I'm scrapping that code for now.
		Tiny performance increase on Alpha (by using ret instead of
		jmp, to play nice with the Alpha's branch prediction) for the
		old MIPS bintrans backend.
20050727	Various minor fixes and cleanups.
20050728	Switching from a 2-level virtual to host/physical translation
		system for ARM emulation, to a 1-level translation.
		Trying to switch from 2-level to 1-level for the MIPS bintrans
		system as well (Alpha only, so far), but there is at least one
		problem: caches and/or how they work with device mappings.
20050730	Doing the 2-level to 1-level conversion for the i386 backend.
		The cache/device bug is still there for R2K/3K :(
		Various other minor updates (Malta etc).
		The mc146818 clock now updates the UIP bit in a way which works
		better with Linux for at least sgimips and Malta emulation.
		Beginning the work on refactoring the dyntrans system.
20050731	Continuing the dyntrans refactoring.
		Fixing a small but serious host alignment bug in memory_rw.
		Adding support for big-endian load/stores to the i386 bintrans
		backend.
		Another minor i386 bintrans backend update: stores from the
		zero register are now one (or two) loads shorter.
		The slt and sltu instructions were incorrectly implemented for
		the i386 backend; only using them for 32-bit mode for now.
20050801	Continuing the dyntrans refactoring.
		Cleanup of the ns16550 serial controller (removing unnecessary
		code).
		Bugfix (memory corruption bug) in dev_gt, and a patch/hack from
		Alec Voropay for Linux/Malta.
20050802	More cleanup/refactoring of the dyntrans subsystem: adding
		phys_page pointers to the lookup tables, for quick jumps
		between translated pages.
		Better fix for the ns16550 device (but still no real FIFO
		functionality).
		Converting cpu_ppc to the new dyntrans system. This means that
		I will have to start from scratch with implementing each
		instruction, and figure out how to implement dual 64/32-bit
		modes etc.
		Removing the URISC CPU family, because it was useless.
20050803	When selecting a machine type, the main type can now be omitted
		if the subtype name is unique. (I.e. -E can be omitted.)
		Fixing a dyntrans/device update bug. (Writes to offset 0 of
		a device could sometimes go unnoticed.)
		Adding an experimental "instruction combination" hack for
		ARM for memset-like byte fill loops.
20050804	Minor progress on cpu_alpha and related things.
		Finally fixing the MIPS dmult/dmultu bugs.
		Fixing some minor TODOs.
20050805	Generalizing the 8259 PIC. It now also works with Cobalt
		and evbmips emulation, in addition to the x86 hack.
		Finally converting the ns16550 device to use devinit.
		Continuing the work on the dyntrans system. Thinking about
		how to add breakpoints.
20050806	More dyntrans updates. Breakpoints seem to work now.
20050807	Minor updates: cpu_alpha and related things; removing
		dev_malta (as it isn't used any more).
		Dyntrans: working on general "show trace tree" support.
		The trace tree stuff now works with both the old MIPS code and
		with newer dyntrans modes. :)
		Continuing on Alpha-related stuff (trying to get *BSD to boot
		a bit further, adding more instructions, etc).
20050808	Adding a dummy IA64 cpu family, and continuing the refactoring
		of the dyntrans system.
		Removing the regression test stuff, because it was more or
		less useless.
		Adding loadlinked/storeconditional type instructions to the
		Alpha emulation. (Needed for Linux/alpha. Not very well tested
		yet.)
20050809	The function call trace tree now prints a per-function nr of
		arguments. (Semi-meaningless, since that data isn't read yet
		from the ELFs; some hardcoded symbols such as memcpy() and
		strlen() work fine, though.)
		More dyntrans refactoring; taking out more of the things that
		are common to all cpu families.
20050810	Working on adding support for "dual mode" for PPC dyntrans
		(i.e. both 64-bit and 32-bit modes).
		(Re)adding some simple PPC instructions.
20050811	Adding a dummy M68K cpu family. The dyntrans system isn't ready
		for variable-length ISAs yet, so it's completely bogus so far.
		Re-adding more PPC instructions.
		Adding a hack to src/file.c which allows OpenBSD/mac68k a.out
		kernels to be loaded.
		Beginning to add PPC loads/stores. So far they only work in
		32-bit mode.
20050812	The configure file option "add_remote" now accepts symbolic
		host names, in addition to numeric IPv4 addresses.
		Re-adding more PPC instructions.
20050814	Continuing to port back more PPC instructions.
		Found and fixed the cache/device write-update bug for 32-bit
		MIPS bintrans. :-)
		Triggered a really weird and annoying bug in Compaq's C
		compiler; ccc sometimes outputs code which loads from an
		address _before_ checking whether the pointer was NULL or not.
		(I'm not sure how to handle this problem.)
20050815	Removing all of the old x86 instruction execution code; adding
		a new (dummy) dyntrans module for x86.
		Taking the first steps to extend the dyntrans system to support
		variable-length instructions.
		Slowly preparing for the next release.
20050816	Adding a dummy SPARC cpu module.
		Minor updates (documentation etc) for the release.

==============  RELEASE 0.3.5  ==============


1 dpavlin 12 /*
2     * Copyright (C) 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: cpu_dyntrans.c,v 1.29 2005/08/16 05:37:10 debug Exp $
29     *
30     * Common dyntrans routines. Included from cpu_*.c.
31     */
32    
33    
34     #ifdef DYNTRANS_CPU_RUN_INSTR
35     /*
36     * XXX_cpu_run_instr():
37     *
38     * Execute one or more instructions on a specific CPU, using dyntrans.
39     *
40     * Return value is the number of instructions executed during this call,
41     * 0 if no instructions were executed.
42     */
43     int DYNTRANS_CPU_RUN_INSTR(struct emul *emul, struct cpu *cpu)
44     {
45     #ifdef DYNTRANS_ARM
46     uint32_t cached_pc;
47     #else
48     uint64_t cached_pc;
49     #endif
50     int low_pc, n_instrs;
51    
52     DYNTRANS_PC_TO_POINTERS(cpu);
53    
54     #ifdef DYNTRANS_ARM
55     cached_pc = cpu->cd.arm.r[ARM_PC] & ~3;
56     #else
57     cached_pc = cpu->pc & ~3;
58     #endif
59    
60     cpu->n_translated_instrs = 0;
61     cpu->running_translated = 1;
62    
63     if (single_step || cpu->machine->instruction_trace) {
64     /*
65     * Single-step:
66     */
67     struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic
68     #ifndef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
69     ++
70     #endif
71     ;
72     if (cpu->machine->instruction_trace) {
73     #ifdef DYNTRANS_X86
74     unsigned char instr[17];
75     cpu->cd.x86.cursegment = X86_S_CS;
76     cpu->cd.x86.seg_override = 0;
77     #else
78     #ifdef DYNTRANS_M68K
79     unsigned char instr[16]; /* TODO: 16? */
80     #else
81     unsigned char instr[4]; /* General case... */
82     #endif
83     #endif
84     if (!cpu->memory_rw(cpu, cpu->mem, cached_pc, &instr[0],
85     sizeof(instr), MEM_READ, CACHE_INSTRUCTION)) {
86     fatal("XXX_cpu_run_instr(): could not read "
87     "the instruction\n");
88     } else
89     cpu_disassemble_instr(cpu->machine, cpu,
90     instr, 1, 0, 0);
91     }
92    
93     /* When single-stepping, multiple instruction calls cannot
94     be combined into one. This clears all translations: */
95     if (cpu->cd.DYNTRANS_ARCH.cur_physpage->flags & COMBINATIONS) {
96     int i;
97     for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
98     cpu->cd.DYNTRANS_ARCH.cur_physpage->ics[i].f =
99     #ifdef DYNTRANS_DUALMODE_32
100     cpu->is_32bit?
101     instr32(to_be_translated) :
102     #endif
103     instr(to_be_translated);
104     fatal("[ Note: The translation of physical page 0x%llx"
105     " contained combinations of instructions; these "
106     "are now flushed because we are single-stepping."
107     " ]\n", (long long)cpu->cd.DYNTRANS_ARCH.
108     cur_physpage->physaddr);
109     cpu->cd.DYNTRANS_ARCH.cur_physpage->flags &=
110     ~(COMBINATIONS | TRANSLATIONS);
111     }
112    
113     /* Execute just one instruction: */
114     ic->f(cpu, ic);
115     n_instrs = 1;
116     } else {
117     /* Execute multiple instructions: */
118     n_instrs = 0;
119     for (;;) {
120     struct DYNTRANS_IC *ic;
121    
122     #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
123     #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic; ic->f(cpu, ic);
124     #else
125     #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic);
126     #endif
127     I; I; I; I; I; I; I; I; I; I;
128     I; I; I; I; I; I; I; I; I; I;
129     I; I; I; I; I; I; I; I; I; I;
130     I; I; I; I; I; I; I; I; I; I;
131     I; I; I; I; I; I; I; I; I; I;
132    
133     I; I; I; I; I; I; I; I; I; I;
134     I; I; I; I; I; I; I; I; I; I;
135     I; I; I; I; I; I; I; I; I; I;
136     I; I; I; I; I; I; I; I; I; I;
137     I; I; I; I; I; I; I; I; I; I;
138    
139     I; I; I; I; I; I; I; I; I; I;
140     I; I; I; I; I; I; I; I; I; I;
141    
142     n_instrs += 120;
143    
144     if (!cpu->running_translated ||
145     n_instrs + cpu->n_translated_instrs >= 16384)
146     break;
147     }
148     }
149    
150    
151     /*
152     * Update the program counter and return the correct number of
153     * executed instructions:
154     */
155     low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t)
156     cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC);
157    
158     if (low_pc >= 0 && low_pc < DYNTRANS_IC_ENTRIES_PER_PAGE) {
159     #ifdef DYNTRANS_ARM
160     cpu->cd.arm.r[ARM_PC] &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1)<<2);
161     cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
162     cpu->pc = cpu->cd.arm.r[ARM_PC];
163     #else
164     cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
165     DYNTRANS_INSTR_ALIGNMENT_SHIFT);
166     cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT);
167     #endif
168     } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE) {
169     /* Switch to next page: */
170     #ifdef DYNTRANS_ARM
171     cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << 2);
172     cpu->cd.arm.r[ARM_PC] += (ARM_IC_ENTRIES_PER_PAGE << 2);
173     cpu->pc = cpu->cd.arm.r[ARM_PC];
174     #else
175     cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
176     DYNTRANS_INSTR_ALIGNMENT_SHIFT);
177     cpu->pc += (DYNTRANS_IC_ENTRIES_PER_PAGE <<
178     DYNTRANS_INSTR_ALIGNMENT_SHIFT);
179     #endif
180     } else {
181     /* debug("debug: Outside a page (This is actually ok)\n"); */
182     }
183    
184     return n_instrs + cpu->n_translated_instrs;
185     }
186     #endif /* DYNTRANS_CPU_RUN_INSTR */
187    
188    
189    
190     #ifdef DYNTRANS_FUNCTION_TRACE
191     /*
192     * XXX_cpu_functioncall_trace():
193     *
194     * Without this function, the main trace tree function prints something
195     * like <f()> or <0x1234()> on a function call. It is up to this
196     * function to print the arguments passed.
197     */
198     void DYNTRANS_FUNCTION_TRACE(struct cpu *cpu, uint64_t f, int n_args)
199     {
200     char strbuf[50];
201     char *symbol;
202     uint64_t ot;
203     int x, print_dots = 1, n_args_to_print =
204     #ifdef DYNTRANS_ALPHA
205     6
206     #else
207     4 /* Most non-Alpha archs */
208     #endif
209     ;
210    
211     if (n_args >= 0 && n_args <= n_args_to_print) {
212     print_dots = 0;
213     n_args_to_print = n_args;
214     }
215    
216     /*
217     * TODO: The type of each argument should be taken from the symbol
218     * table, in some way.
219     *
220     * The code here does a kind of "heuristic guess" regarding what the
221     * argument values might mean. Sometimes the output looks weird, but
222     * usually it looks good enough.
223     *
224     * Print ".." afterwards to show that there might be more arguments
225     * than were passed in register.
226     */
227     for (x=0; x<n_args_to_print; x++) {
228     int64_t d;
229     #ifdef DYNTRANS_X86
230     d = 0; /* TODO */
231     #else
232     /* Args in registers: */
233     d = cpu->cd.DYNTRANS_ARCH.
234     #ifdef DYNTRANS_ALPHA
235     r[ALPHA_A0
236     #endif
237     #ifdef DYNTRANS_ARM
238     r[0
239     #endif
240     #ifdef DYNTRANS_IA64
241     r[0 /* TODO */
242     #endif
243     #ifdef DYNTRANS_M68K
244     d[0 /* TODO */
245     #endif
246     #ifdef DYNTRANS_MIPS
247     gpr[MIPS_GPR_A0
248     #endif
249     #ifdef DYNTRANS_PPC
250     gpr[3
251     #endif
252     #ifdef DYNTRANS_SPARC
253     r_i[0
254     #endif
255     + x];
256     #endif
257     symbol = get_symbol_name(&cpu->machine->symbol_context, d, &ot);
258    
259     if (d > -256 && d < 256)
260     fatal("%i", (int)d);
261     else if (memory_points_to_string(cpu, cpu->mem, d, 1))
262     fatal("\"%s\"", memory_conv_to_string(cpu,
263     cpu->mem, d, strbuf, sizeof(strbuf)));
264     else if (symbol != NULL && ot == 0)
265     fatal("&%s", symbol);
266     else {
267     if (cpu->is_32bit)
268     fatal("0x%x", (int)d);
269     else
270     fatal("0x%llx", (long long)d);
271     }
272    
273     if (x < n_args_to_print - 1)
274     fatal(",");
275     }
276    
277     if (print_dots)
278     fatal(",..");
279     }
280     #endif
281    
282    
283    
284     #ifdef DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE
285     /* forward declaration of to_be_translated and end_of_page: */
286     static void instr(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
287     static void instr(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
288     #ifdef DYNTRANS_DUALMODE_32
289     static void instr32(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
290     #endif
291     /*
292     * XXX_tc_allocate_default_page():
293     *
294     * Create a default page (with just pointers to instr(to_be_translated)
295     * at cpu->translation_cache_cur_ofs.
296     */
297     static void DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE(struct cpu *cpu,
298     uint64_t physaddr)
299     {
300     struct DYNTRANS_TC_PHYSPAGE *ppp;
301     int i;
302    
303     /* Create the physpage header: */
304     ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
305     + cpu->translation_cache_cur_ofs);
306     ppp->next_ofs = 0;
307     ppp->physaddr = physaddr;
308    
309     /* TODO: Is this faster than copying an entire template page? */
310    
311     for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
312     ppp->ics[i].f =
313     #ifdef DYNTRANS_DUALMODE_32
314     cpu->is_32bit? instr32(to_be_translated) :
315     #endif
316     instr(to_be_translated);
317    
318     ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE].f = instr(end_of_page);
319    
320     cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE);
321     }
322     #endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE */
323    
324    
325    
326     #ifdef DYNTRANS_PC_TO_POINTERS_FUNC
327     /*
328     * XXX_pc_to_pointers():
329     *
330     * This function uses the current program counter (a virtual address) to
331     * find out which physical translation page to use, and then sets the current
332     * translation page pointers to that page.
333     *
334     * If there was no translation page for that physical page, then an empty
335     * one is created.
336     */
337     void DYNTRANS_PC_TO_POINTERS_FUNC(struct cpu *cpu)
338     {
339     #ifdef DYNTRANS_32
340     uint32_t
341     #else
342     uint64_t
343     #endif
344     cached_pc, physaddr, physpage_ofs;
345     int pagenr, table_index;
346     uint32_t *physpage_entryp;
347     struct DYNTRANS_TC_PHYSPAGE *ppp;
348    
349     #ifdef DYNTRANS_32
350     int index;
351     cached_pc = cpu->pc;
352     index = cached_pc >> 12;
353     ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index];
354     if (ppp != NULL)
355     goto have_it;
356     #else
357     #ifdef DYNTRANS_ALPHA
358     uint32_t a, b;
359     int kernel = 0;
360     struct alpha_vph_page *vph_p;
361     cached_pc = cpu->pc;
362     a = (cached_pc >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
363     b = (cached_pc >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
364     if ((cached_pc >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
365     vph_p = cpu->cd.alpha.vph_table0_kernel[a];
366     kernel = 1;
367     } else
368     vph_p = cpu->cd.alpha.vph_table0[a];
369     if (vph_p != cpu->cd.alpha.vph_default_page) {
370     ppp = vph_p->phys_page[b];
371     if (ppp != NULL)
372     goto have_it;
373     }
374     #else
375     #ifdef DYNTRANS_IA64
376     fatal("IA64 todo\n");
377     #else
378     #error Neither alpha, ia64, nor 32-bit?
379     #endif
380     #endif
381     #endif
382    
383     /*
384     * TODO: virtual to physical address translation
385     */
386     physaddr = cached_pc & ~( ((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
387     DYNTRANS_INSTR_ALIGNMENT_SHIFT) |
388     ((1 << DYNTRANS_INSTR_ALIGNMENT_SHIFT)-1) );
389    
390     if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE)
391     cpu_create_or_reset_tc(cpu);
392    
393     pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr);
394     table_index = PAGENR_TO_TABLE_INDEX(pagenr);
395    
396     physpage_entryp = &(((uint32_t *)cpu->translation_cache)[table_index]);
397     physpage_ofs = *physpage_entryp;
398     ppp = NULL;
399    
400     /* Traverse the physical page chain: */
401     while (physpage_ofs != 0) {
402     ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
403     + physpage_ofs);
404     /* If we found the page in the cache, then we're done: */
405     if (ppp->physaddr == physaddr)
406     break;
407     /* Try the next page in the chain: */
408     physpage_ofs = ppp->next_ofs;
409     }
410    
411     /* If the offset is 0 (or ppp is NULL), then we need to create a
412     new "default" empty translation page. */
413    
414     if (ppp == NULL) {
415     /* fatal("CREATING page %lli (physaddr 0x%llx), table index "
416     "%i\n", (long long)pagenr, (long long)physaddr,
417     (int)table_index); */
418     *physpage_entryp = physpage_ofs =
419     cpu->translation_cache_cur_ofs;
420    
421     /* Allocate a default page, with to_be_translated entries: */
422     DYNTRANS_TC_ALLOCATE(cpu, physaddr);
423    
424     ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
425     + physpage_ofs);
426     }
427    
428     #ifdef DYNTRANS_32
429     if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL)
430     cpu->cd.DYNTRANS_ARCH.phys_page[index] = ppp;
431     #endif
432    
433     #ifdef DYNTRANS_ALPHA
434     if (vph_p->host_load[b] != NULL)
435     vph_p->phys_page[b] = ppp;
436     #endif
437    
438     have_it:
439     cpu->cd.DYNTRANS_ARCH.cur_physpage = ppp;
440     cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
441     cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
442     DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
443    
444     /* printf("cached_pc=0x%016llx pagenr=%lli table_index=%lli, "
445     "physpage_ofs=0x%016llx\n", (long long)cached_pc, (long long)pagenr,
446     (long long)table_index, (long long)physpage_ofs); */
447     }
448     #endif /* DYNTRANS_PC_TO_POINTERS_FUNC */
449    
450    
451    
452     #ifdef DYNTRANS_INVAL_ENTRY
453     /*
454     * XXX_invalidate_tlb_entry():
455     *
456     * Invalidate one translation entry (based on virtual address).
457     */
458     void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu,
459     #ifdef DYNTRANS_32
460     uint32_t
461     #else
462     uint64_t
463     #endif
464     vaddr_page)
465     {
466     #ifdef DYNTRANS_1LEVEL
467     uint32_t index = vaddr_page >> 12;
468     cpu->cd.DYNTRANS_ARCH.host_load[index] = NULL;
469     cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
470     cpu->cd.DYNTRANS_ARCH.phys_addr[index] = 0;
471     cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
472     #else
473     /* 2-level: */
474     #ifdef DYNTRANS_ALPHA
475     struct alpha_vph_page *vph_p;
476     uint32_t a, b;
477     int kernel = 0;
478    
479     a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
480     b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
481     if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
482     vph_p = cpu->cd.alpha.vph_table0_kernel[a];
483     kernel = 1;
484     } else
485     vph_p = cpu->cd.alpha.vph_table0[a];
486    
487     if (vph_p == cpu->cd.alpha.vph_default_page) {
488     fatal("alpha_invalidate_tlb_entry(): huh? Problem 1.\n");
489     exit(1);
490     }
491    
492     vph_p->host_load[b] = NULL;
493     vph_p->host_store[b] = NULL;
494     vph_p->phys_addr[b] = 0;
495     vph_p->phys_page[b] = NULL;
496     vph_p->refcount --;
497     if (vph_p->refcount < 0) {
498     fatal("alpha_invalidate_tlb_entry(): huh? Problem 2.\n");
499     exit(1);
500     }
501     if (vph_p->refcount == 0) {
502     vph_p->next = cpu->cd.alpha.vph_next_free_page;
503     cpu->cd.alpha.vph_next_free_page = vph_p;
504     if (kernel)
505     cpu->cd.alpha.vph_table0_kernel[a] =
506     cpu->cd.alpha.vph_default_page;
507     else
508     cpu->cd.alpha.vph_table0[a] =
509     cpu->cd.alpha.vph_default_page;
510     }
511     #else /* !DYNTRANS_ALPHA */
512     #ifdef DYNTRANS_IA64
513     fatal("IA64: blah blah TODO\n");
514     #else
515     #error Not yet for non-1-level, non-Alpha, non-ia64
516     #endif /* !DYNTRANS_IA64 */
517     #endif /* !DYNTRANS_ALPHA */
518     #endif
519     }
520     #endif
521    
522    
523     #ifdef DYNTRANS_INVALIDATE_TC_PADDR
524     /*
525     * XXX_invalidate_translation_caches_paddr():
526     *
527     * Invalidate all entries matching a specific physical address.
528     */
529     void DYNTRANS_INVALIDATE_TC_PADDR(struct cpu *cpu, uint64_t paddr)
530     {
531     int r;
532     #ifdef DYNTRANS_32
533     uint32_t
534     #else
535     uint64_t
536     #endif
537     paddr_page = paddr &
538     #ifdef DYNTRANS_8K
539     ~0x1fff
540     #else
541     ~0xfff
542     #endif
543     ;
544    
545     for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
546     if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid &&
547     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page ==
548     paddr_page) {
549     DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
550     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page);
551     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid = 0;
552     }
553     }
554     }
555     #endif /* DYNTRANS_INVALIDATE_TC_PADDR */
556    
557    
558    
559     #ifdef DYNTRANS_INVALIDATE_TC_CODE
560     /*
561     * XXX_invalidate_code_translation_caches():
562     *
563     * Invalidate all entries matching a specific virtual address.
564     */
565     void DYNTRANS_INVALIDATE_TC_CODE(struct cpu *cpu)
566     {
567     int r;
568     #ifdef DYNTRANS_32
569     uint32_t
570     #else
571     uint64_t
572     #endif
573     vaddr_page;
574    
575     for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
576     if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
577     vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
578     .vaddr_page & ~(DYNTRANS_PAGESIZE-1);
579     #ifdef DYNTRANS_1LEVEL
580     {
581     uint32_t index = vaddr_page >> 12;
582     cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
583     }
584     #else
585     {
586     /* 2-level: */
587     #ifdef DYNTRANS_ALPHA
588     struct alpha_vph_page *vph_p;
589     uint32_t a, b;
590     int kernel = 0;
591    
592     a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
593     b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
594     if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
595     vph_p = cpu->cd.alpha.vph_table0_kernel[a];
596     kernel = 1;
597     } else
598     vph_p = cpu->cd.alpha.vph_table0[a];
599     vph_p->phys_page[b] = NULL;
600     #else /* !DYNTRANS_ALPHA */
601     #ifdef DYNTRANS_IA64
602     fatal("IA64: blah yo yo TODO\n");
603     #else
604     #error Not yet for non-Alpha, non-1Level, non-ia64
605     #endif /* !DYNTRANS_IA64 */
606     #endif /* !DYNTRANS_ALPHA */
607     }
608     #endif
609     }
610     }
611     }
612     #endif /* DYNTRANS_INVALIDATE_TC_CODE */
613    
614    
615    
616     #ifdef DYNTRANS_UPDATE_TRANSLATION_TABLE
617     /*
618     * XXX_update_translation_table():
619     *
620     * Update the virtual memory translation tables.
621     */
622     void DYNTRANS_UPDATE_TRANSLATION_TABLE(struct cpu *cpu, uint64_t vaddr_page,
623     unsigned char *host_page, int writeflag, uint64_t paddr_page)
624     {
625     int64_t lowest, highest = -1;
626     int found, r, lowest_index;
627    
628     #ifdef DYNTRANS_ALPHA
629     uint32_t a, b;
630     struct alpha_vph_page *vph_p;
631     int kernel = 0;
632     /* fatal("update_translation_table(): v=0x%llx, h=%p w=%i"
633     " p=0x%llx\n", (long long)vaddr_page, host_page, writeflag,
634     (long long)paddr_page); */
635     #else
636     #ifdef DYNTRANS_32
637     uint32_t index;
638     vaddr_page &= 0xffffffffULL;
639     paddr_page &= 0xffffffffULL;
640     /* fatal("update_translation_table(): v=0x%x, h=%p w=%i"
641     " p=0x%x\n", (int)vaddr_page, host_page, writeflag,
642     (int)paddr_page); */
643     #else /* !DYNTRANS_32 */
644     #ifdef DYNTRANS_IA64
645     fatal("IA64 update todo\n");
646     #else
647     #error Neither 32-bit, IA64, nor Alpha?
648     #endif
649     #endif
650     #endif
651    
652     /* Scan the current TLB entries: */
653     found = -1; lowest_index = 0;
654     lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp;
655     for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
656     if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) {
657     lowest = cpu->cd.DYNTRANS_ARCH.
658     vph_tlb_entry[r].timestamp;
659     lowest_index = r;
660     }
661     if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp > highest)
662     highest = cpu->cd.DYNTRANS_ARCH.
663     vph_tlb_entry[r].timestamp;
664     if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid &&
665     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page ==
666     vaddr_page) {
667     found = r;
668     break;
669     }
670     }
671    
672     if (found < 0) {
673     /* Create the new TLB entry, overwriting the oldest one: */
674     r = lowest_index;
675     if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
676     /* This one has to be invalidated first: */
677     DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
678     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page);
679     }
680    
681     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid = 1;
682     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].host_page = host_page;
683     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page = paddr_page;
684     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page;
685     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = writeflag;
686     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1;
687    
688     /* Add the new translation to the table: */
689     #ifdef DYNTRANS_ALPHA
690     a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
691     b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
692     if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
693     vph_p = cpu->cd.alpha.vph_table0_kernel[a];
694     kernel = 1;
695     } else
696     vph_p = cpu->cd.alpha.vph_table0[a];
697     if (vph_p == cpu->cd.alpha.vph_default_page) {
698     if (cpu->cd.alpha.vph_next_free_page != NULL) {
699     if (kernel)
700     vph_p = cpu->cd.alpha.vph_table0_kernel
701     [a] = cpu->cd.alpha.
702     vph_next_free_page;
703     else
704     vph_p = cpu->cd.alpha.vph_table0[a] =
705     cpu->cd.alpha.vph_next_free_page;
706     cpu->cd.alpha.vph_next_free_page = vph_p->next;
707     } else {
708     if (kernel)
709     vph_p = cpu->cd.alpha.vph_table0_kernel
710     [a] = malloc(sizeof(struct
711     alpha_vph_page));
712     else
713     vph_p = cpu->cd.alpha.vph_table0[a] =
714     malloc(sizeof(struct
715     alpha_vph_page));
716     memset(vph_p, 0, sizeof(struct alpha_vph_page));
717     }
718     }
719     vph_p->refcount ++;
720     vph_p->host_load[b] = host_page;
721     vph_p->host_store[b] = writeflag? host_page : NULL;
722     vph_p->phys_addr[b] = paddr_page;
723     vph_p->phys_page[b] = NULL;
724     #else
725     #ifdef DYNTRANS_32
726     index = vaddr_page >> 12;
727     cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
728     cpu->cd.DYNTRANS_ARCH.host_store[index] =
729     writeflag? host_page : NULL;
730     cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
731     cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;;
732     #endif /* 32 */
733     #endif /* !ALPHA */
734     } else {
735     /*
736     * The translation was already in the TLB.
737     * Writeflag = 0: Do nothing.
738     * Writeflag = 1: Make sure the page is writable.
739     * Writeflag = -1: Downgrade to readonly.
740     */
741     #ifdef DYNTRANS_ALPHA
742     a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
743     b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
744     if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
745     vph_p = cpu->cd.alpha.vph_table0_kernel[a];
746     kernel = 1;
747     } else
748     vph_p = cpu->cd.alpha.vph_table0[a];
749     cpu->cd.alpha.vph_tlb_entry[found].timestamp = highest + 1;
750     if (vph_p->phys_addr[b] == paddr_page) {
751     if (writeflag == 1)
752     vph_p->host_store[b] = host_page;
753     if (writeflag == -1)
754     vph_p->host_store[b] = NULL;
755     } else {
756     /* Change the entire physical/host mapping: */
757     vph_p->host_load[b] = host_page;
758     vph_p->host_store[b] = writeflag? host_page : NULL;
759     vph_p->phys_addr[b] = paddr_page;
760     }
761     #else
762     #ifdef DYNTRANS_32
763     index = vaddr_page >> 12;
764     cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[found].timestamp =
765     highest + 1;
766     if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) {
767     if (writeflag == 1)
768     cpu->cd.DYNTRANS_ARCH.host_store[index] =
769     host_page;
770     if (writeflag == -1)
771     cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
772     } else {
773     /* Change the entire physical/host mapping: */
774     cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
775     cpu->cd.DYNTRANS_ARCH.host_store[index] =
776     writeflag? host_page : NULL;
777     cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
778     }
779     #endif /* 32 */
780     #endif /* !ALPHA */
781     }
782     }
783     #endif /* DYNTRANS_UPDATE_TRANSLATION_TABLE */
784    
785    
786    
787     #ifdef DYNTRANS_TO_BE_TRANSLATED_HEAD
788     /*
789     * Check for breakpoints.
790     */
791     if (!single_step_breakpoint) {
792     int i;
793     for (i=0; i<cpu->machine->n_breakpoints; i++)
794     if (cpu->pc == cpu->machine->breakpoint_addr[i]) {
795     if (!cpu->machine->instruction_trace) {
796     int old_quiet_mode = quiet_mode;
797     quiet_mode = 0;
798     DISASSEMBLE(cpu, ib, 1, 0, 0);
799     quiet_mode = old_quiet_mode;
800     }
801     fatal("BREAKPOINT: pc = 0x%llx\n(The "
802     "instruction has not yet executed.)\n",
803     (long long)cpu->pc);
804     single_step_breakpoint = 1;
805     single_step = 1;
806     goto stop_running_translated;
807     }
808     }
809     #endif /* DYNTRANS_TO_BE_TRANSLATED_HEAD */
810    
811    
812    
813     #ifdef DYNTRANS_TO_BE_TRANSLATED_TAIL
814     /*
815     * If we end up here, then an instruction was translated.
816     */
817     translated;
818    
819     /*
820     * Now it is time to check for combinations of instructions that can
821     * be converted into a single function call.
822     *
823     * Note: Single-stepping or instruction tracing doesn't work with
824     * instruction combination.
825     */
826     if (!single_step && !cpu->machine->instruction_trace)
827     COMBINE_INSTRUCTIONS(cpu, ic, addr);
828    
829     /* ... and finally execute the translated instruction: */
830     if (single_step_breakpoint) {
831     /*
832     * Special case when single-stepping: Execute the translated
833     * instruction, but then replace it with a "to be translated"
834     * directly afterwards.
835     */
836     single_step_breakpoint = 0;
837     ic->f(cpu, ic);
838     ic->f =
839     #ifdef DYNTRANS_DUALMODE_32
840     cpu->is_32bit? instr32(to_be_translated) :
841     #endif
842     instr(to_be_translated);
843     } else
844     ic->f(cpu, ic);
845    
846     return;
847    
848    
849     bad: /*
850     * Nothing was translated. (Unimplemented or illegal instruction.)
851     */
852    
853     quiet_mode = 0;
854     fatal("to_be_translated(): TODO: unimplemented instruction");
855    
856     if (cpu->machine->instruction_trace)
857     #ifdef DYNTRANS_32
858     fatal(" at 0x%x\n", (int)cpu->pc);
859     #else
860     fatal(" at 0x%llx\n", (long long)cpu->pc);
861     #endif
862     else {
863     fatal(":\n");
864     DISASSEMBLE(cpu, ib, 1, 0, 0);
865     }
866    
867     cpu->running = 0;
868     cpu->dead = 1;
869     stop_running_translated:
870     debugger_n_steps_left_before_interaction = 0;
871     cpu->running_translated = 0;
872     ic = cpu->cd.DYNTRANS_ARCH.next_ic = &nothing_call;
873     cpu->cd.DYNTRANS_ARCH.next_ic ++;
874    
875     /* Execute the "nothing" instruction: */
876     ic->f(cpu, ic);
877     #endif /* DYNTRANS_TO_BE_TRANSLATED_TAIL */
878    

  ViewVC Help
Powered by ViewVC 1.1.26