/[gxemul]/trunk/src/cpus/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

Contents of /trunk/src/cpus/cpu_dyntrans.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 44737 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 /*
2 * Copyright (C) 2005-2006 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.54 2006/02/09 22:55:20 debug Exp $
29 *
30 * Common dyntrans routines. Included from cpu_*.c.
31 */
32
33
34 #ifdef DYNTRANS_CPU_RUN_INSTR
35 #if 1 /* IC statistics: */
36 static void gather_statistics(struct cpu *cpu)
37 {
38 struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic;
39 static long long n = 0;
40 static FILE *f = NULL;
41
42 n++;
43 if (n < 100000000)
44 return;
45
46 if (f == NULL) {
47 f = fopen("instruction_call_statistics.raw", "w");
48 if (f == NULL) {
49 fatal("Unable to open statistics file for output.\n");
50 exit(1);
51 }
52 }
53 fwrite(&ic->f, 1, sizeof(void *), f);
54 }
55 #else /* PC statistics: */
56 static void gather_statistics(struct cpu *cpu)
57 {
58 uint64_t a;
59 int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t)
60 cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC);
61 if (low_pc < 0 || low_pc >= DYNTRANS_IC_ENTRIES_PER_PAGE)
62 return;
63
64 #if 0
65 /* Use the physical address: */
66 cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
67 cpu->cd.DYNTRANS_ARCH.cur_ic_page;
68 a = cpu->cd.DYNTRANS_ARCH.cur_physpage->physaddr;
69 #else
70 /* Use the PC (virtual address): */
71 a = cpu->pc;
72 #endif
73
74 a &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
75 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
76 a += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT;
77
78 /*
79 * TODO: Everything below this line should be cleaned up :-)
80 */
81 a &= 0x03ffffff;
82 {
83 static long long *array = NULL;
84 static char *array_16kpage_in_use = NULL;
85 static int n = 0;
86 a >>= DYNTRANS_INSTR_ALIGNMENT_SHIFT;
87 if (array == NULL)
88 array = zeroed_alloc(sizeof(long long) * 16384*1024);
89 if (array_16kpage_in_use == NULL)
90 array_16kpage_in_use = zeroed_alloc(sizeof(char) * 1024);
91 a &= (16384*1024-1);
92 array[a] ++;
93 array_16kpage_in_use[a / 16384] = 1;
94 n++;
95 if ((n & 0x3fffffff) == 0) {
96 FILE *f = fopen("statistics.out", "w");
97 int i, j;
98 printf("Saving statistics... "); fflush(stdout);
99 for (i=0; i<1024; i++)
100 if (array_16kpage_in_use[i]) {
101 for (j=0; j<16384; j++)
102 if (array[i*16384 + j] > 0)
103 fprintf(f, "%lli\t0x%016llx\n",
104 (long long)array[i*16384+j],
105 (long long)((i*16384+j) <<
106 DYNTRANS_INSTR_ALIGNMENT_SHIFT));
107 }
108 fclose(f);
109 printf("n=0x%08x\n", n);
110 }
111 }
112 }
113 #endif /* PC statistics */
114
115 #define S gather_statistics(cpu)
116
117 #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
118 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic; \
119 cpu->cd.DYNTRANS_ARCH.next_ic += ic->arg[0]; \
120 ic->f(cpu, ic);
121 #else
122 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic);
123 #endif
124
125
126 /*
127 * XXX_cpu_run_instr():
128 *
129 * Execute one or more instructions on a specific CPU, using dyntrans.
130 *
131 * Return value is the number of instructions executed during this call,
132 * 0 if no instructions were executed.
133 */
134 int DYNTRANS_CPU_RUN_INSTR(struct emul *emul, struct cpu *cpu)
135 {
136 #ifdef MODE32
137 uint32_t cached_pc;
138 #else
139 uint64_t cached_pc;
140 #endif
141 int low_pc, n_instrs;
142
143 #ifdef DYNTRANS_DUALMODE_32
144 if (cpu->is_32bit)
145 DYNTRANS_PC_TO_POINTERS32(cpu);
146 else
147 #endif
148 DYNTRANS_PC_TO_POINTERS(cpu);
149
150 /*
151 * Interrupt assertion? (This is _below_ the initial PC to pointer
152 * conversion; if the conversion caused an exception of some kind
153 * then interrupts are probably disabled, and the exception will get
154 * priority over device interrupts.)
155 */
156 #ifdef DYNTRANS_ARM
157 if (cpu->cd.arm.irq_asserted && !(cpu->cd.arm.cpsr & ARM_FLAG_I))
158 arm_exception(cpu, ARM_EXCEPTION_IRQ);
159 #endif
160 #ifdef DYNTRANS_PPC
161 if (cpu->cd.ppc.dec_intr_pending && cpu->cd.ppc.msr & PPC_MSR_EE) {
162 ppc_exception(cpu, PPC_EXCEPTION_DEC);
163 cpu->cd.ppc.dec_intr_pending = 0;
164 }
165 if (cpu->cd.ppc.irq_asserted && cpu->cd.ppc.msr & PPC_MSR_EE)
166 ppc_exception(cpu, PPC_EXCEPTION_EI);
167 #endif
168
169 cached_pc = cpu->pc;
170
171 cpu->n_translated_instrs = 0;
172 cpu->running_translated = 1;
173
174 cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
175 cpu->cd.DYNTRANS_ARCH.cur_ic_page;
176
177 if (single_step || cpu->machine->instruction_trace) {
178 /*
179 * Single-step:
180 */
181 struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic
182 #ifndef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
183 ++
184 #endif
185 ;
186 if (cpu->machine->instruction_trace) {
187 #ifdef DYNTRANS_X86
188 unsigned char instr[17];
189 cpu->cd.x86.cursegment = X86_S_CS;
190 cpu->cd.x86.seg_override = 0;
191 #else
192 #ifdef DYNTRANS_M68K
193 unsigned char instr[16]; /* TODO: 16? */
194 #else
195 unsigned char instr[4]; /* General case... */
196 #endif
197 #endif
198 if (!cpu->memory_rw(cpu, cpu->mem, cached_pc, &instr[0],
199 sizeof(instr), MEM_READ, CACHE_INSTRUCTION)) {
200 fatal("XXX_cpu_run_instr(): could not read "
201 "the instruction\n");
202 } else {
203 cpu_disassemble_instr(cpu->machine, cpu,
204 instr, 1, 0, 0);
205 #ifdef DYNTRANS_MIPS
206 /* TODO: generalize, not just MIPS */
207 /* Show the instruction in the delay slot,
208 if any: */
209 fatal("TODO: check for delay slot!\n");
210 #endif
211 }
212 }
213
214 /* When single-stepping, multiple instruction calls cannot
215 be combined into one. This clears all translations: */
216 if (cpu->cd.DYNTRANS_ARCH.cur_physpage->flags & COMBINATIONS) {
217 int i;
218 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
219 cpu->cd.DYNTRANS_ARCH.cur_physpage->ics[i].f =
220 #ifdef DYNTRANS_DUALMODE_32
221 cpu->is_32bit?
222 instr32(to_be_translated) :
223 #endif
224 instr(to_be_translated);
225 fatal("[ Note: The translation of physical page 0x%llx"
226 " contained combinations of instructions; these "
227 "are now flushed because we are single-stepping."
228 " ]\n", (long long)cpu->cd.DYNTRANS_ARCH.
229 cur_physpage->physaddr);
230 cpu->cd.DYNTRANS_ARCH.cur_physpage->flags &=
231 ~(COMBINATIONS | TRANSLATIONS);
232 }
233
234 if (show_opcode_statistics)
235 S;
236
237 /* Execute just one instruction: */
238 ic->f(cpu, ic);
239 n_instrs = 1;
240 } else if (show_opcode_statistics) {
241 /* Gather statistics while executing multiple instructions: */
242 n_instrs = 0;
243 for (;;) {
244 struct DYNTRANS_IC *ic;
245
246 S; I; S; I; S; I; S; I; S; I; S; I;
247 S; I; S; I; S; I; S; I; S; I; S; I;
248 S; I; S; I; S; I; S; I; S; I; S; I;
249 S; I; S; I; S; I; S; I; S; I; S; I;
250
251 n_instrs += 24;
252
253 if (!cpu->running_translated ||
254 n_instrs + cpu->n_translated_instrs >= 16384)
255 break;
256 }
257 } else {
258 /* Execute multiple instructions: */
259 n_instrs = 0;
260 for (;;) {
261 struct DYNTRANS_IC *ic;
262
263 I; I; I; I; I; I; I; I; I; I;
264 I; I; I; I; I; I; I; I; I; I;
265 I; I; I; I; I; I; I; I; I; I;
266 I; I; I; I; I; I; I; I; I; I;
267 I; I; I; I; I; I; I; I; I; I;
268
269 I; I; I; I; I; I; I; I; I; I;
270
271 n_instrs += 60;
272
273 if (!cpu->running_translated ||
274 n_instrs + cpu->n_translated_instrs >= 16384)
275 break;
276 }
277 }
278
279 n_instrs += cpu->n_translated_instrs;
280
281 /* Synchronize the program counter: */
282 low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t)
283 cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC);
284 if (low_pc >= 0 && low_pc < DYNTRANS_IC_ENTRIES_PER_PAGE) {
285 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
286 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
287 cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT);
288 } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE) {
289 /* Switch to next page: */
290 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
291 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
292 cpu->pc += (DYNTRANS_IC_ENTRIES_PER_PAGE <<
293 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
294 } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE + 1) {
295 /* Switch to next page and skip an instruction which was
296 already executed (in a delay slot): */
297 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
298 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
299 cpu->pc += ((DYNTRANS_IC_ENTRIES_PER_PAGE + 1) <<
300 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
301 }
302
303 #ifdef DYNTRANS_PPC
304 /* Update the Decrementer and Time base registers: */
305 {
306 uint32_t old = cpu->cd.ppc.spr[SPR_DEC];
307 cpu->cd.ppc.spr[SPR_DEC] = (uint32_t) (old - n_instrs);
308 if ((old >> 31) == 0 && (cpu->cd.ppc.spr[SPR_DEC] >> 31) == 1
309 && !(cpu->cd.ppc.cpu_type.flags & PPC_NO_DEC))
310 cpu->cd.ppc.dec_intr_pending = 1;
311 old = cpu->cd.ppc.spr[SPR_TBL];
312 cpu->cd.ppc.spr[SPR_TBL] += n_instrs;
313 if ((old >> 31) == 1 && (cpu->cd.ppc.spr[SPR_TBL] >> 31) == 0)
314 cpu->cd.ppc.spr[SPR_TBU] ++;
315 }
316 #endif
317
318 /* Return the nr of instructions executed: */
319 return n_instrs;
320 }
321 #endif /* DYNTRANS_CPU_RUN_INSTR */
322
323
324
325 #ifdef DYNTRANS_FUNCTION_TRACE
326 /*
327 * XXX_cpu_functioncall_trace():
328 *
329 * Without this function, the main trace tree function prints something
330 * like <f()> or <0x1234()> on a function call. It is up to this
331 * function to print the arguments passed.
332 */
333 void DYNTRANS_FUNCTION_TRACE(struct cpu *cpu, uint64_t f, int n_args)
334 {
335 char strbuf[50];
336 char *symbol;
337 uint64_t ot;
338 int x, print_dots = 1, n_args_to_print =
339 #ifdef DYNTRANS_ALPHA
340 6
341 #else
342 #ifdef DYNTRANS_SH
343 8
344 #else
345 4 /* Default value for most archs */
346 #endif
347 #endif
348 ;
349
350 if (n_args >= 0 && n_args <= n_args_to_print) {
351 print_dots = 0;
352 n_args_to_print = n_args;
353 }
354
355 /*
356 * TODO: The type of each argument should be taken from the symbol
357 * table, in some way.
358 *
359 * The code here does a kind of "heuristic guess" regarding what the
360 * argument values might mean. Sometimes the output looks weird, but
361 * usually it looks good enough.
362 *
363 * Print ".." afterwards to show that there might be more arguments
364 * than were passed in register.
365 */
366 for (x=0; x<n_args_to_print; x++) {
367 int64_t d;
368 #ifdef DYNTRANS_X86
369 d = 0; /* TODO */
370 #else
371 /* Args in registers: */
372 d = cpu->cd.DYNTRANS_ARCH.
373 #ifdef DYNTRANS_ALPHA
374 r[ALPHA_A0
375 #endif
376 #ifdef DYNTRANS_ARM
377 r[0
378 #endif
379 #ifdef DYNTRANS_AVR
380 /* TODO: 24,25 = first register, but then
381 they go downwards, ie. 22,23 and so on */
382 r[24
383 #endif
384 #ifdef DYNTRANS_HPPA
385 r[0 /* TODO */
386 #endif
387 #ifdef DYNTRANS_I960
388 r[0 /* TODO */
389 #endif
390 #ifdef DYNTRANS_IA64
391 r[0 /* TODO */
392 #endif
393 #ifdef DYNTRANS_M68K
394 d[0 /* TODO */
395 #endif
396 #ifdef DYNTRANS_MIPS
397 gpr[MIPS_GPR_A0
398 #endif
399 #ifdef DYNTRANS_PPC
400 gpr[3
401 #endif
402 #ifdef DYNTRANS_SH
403 r[2
404 #endif
405 #ifdef DYNTRANS_SPARC
406 r[24
407 #endif
408 + x];
409 #endif
410 symbol = get_symbol_name(&cpu->machine->symbol_context, d, &ot);
411
412 if (d > -256 && d < 256)
413 fatal("%i", (int)d);
414 else if (memory_points_to_string(cpu, cpu->mem, d, 1))
415 fatal("\"%s\"", memory_conv_to_string(cpu,
416 cpu->mem, d, strbuf, sizeof(strbuf)));
417 else if (symbol != NULL && ot == 0)
418 fatal("&%s", symbol);
419 else {
420 if (cpu->is_32bit)
421 fatal("0x%x", (int)d);
422 else
423 fatal("0x%llx", (long long)d);
424 }
425
426 if (x < n_args_to_print - 1)
427 fatal(",");
428 }
429
430 if (print_dots)
431 fatal(",..");
432 }
433 #endif
434
435
436
437 #ifdef DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE
438
439 /* forward declaration of to_be_translated and end_of_page: */
440 static void instr(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
441 static void instr(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
442 #ifdef DYNTRANS_DUALMODE_32
443 static void instr32(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
444 static void instr32(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
445 #endif
446
447 #ifdef DYNTRANS_DELAYSLOT
448 static void instr(end_of_page2)(struct cpu *,struct DYNTRANS_IC *);
449 #ifdef DYNTRANS_DUALMODE_32
450 static void instr32(end_of_page2)(struct cpu *,struct DYNTRANS_IC *);
451 #endif
452 #endif
453
454 /*
455 * XXX_tc_allocate_default_page():
456 *
457 * Create a default page (with just pointers to instr(to_be_translated)
458 * at cpu->translation_cache_cur_ofs.
459 */
460 static void DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE(struct cpu *cpu,
461 uint64_t physaddr)
462 {
463 struct DYNTRANS_TC_PHYSPAGE *ppp;
464 int i;
465
466 /* Create the physpage header: */
467 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
468 + cpu->translation_cache_cur_ofs);
469 ppp->next_ofs = 0;
470 ppp->physaddr = physaddr;
471
472 /* TODO: Is this faster than copying an entire template page? */
473 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
474 ppp->ics[i].f =
475 #ifdef DYNTRANS_DUALMODE_32
476 cpu->is_32bit? instr32(to_be_translated) :
477 #endif
478 instr(to_be_translated);
479
480 ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 0].f =
481 #ifdef DYNTRANS_DUALMODE_32
482 cpu->is_32bit? instr32(end_of_page) :
483 #endif
484 instr(end_of_page);
485
486 #ifdef DYNTRANS_DELAYSLOT
487 ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 1].f =
488 #ifdef DYNTRANS_DUALMODE_32
489 cpu->is_32bit? instr32(end_of_page2) :
490 #endif
491 instr(end_of_page2);
492 #endif
493
494 cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE);
495
496 cpu->translation_cache_cur_ofs --;
497 cpu->translation_cache_cur_ofs |= 63;
498 cpu->translation_cache_cur_ofs ++;
499 }
500 #endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE */
501
502
503
504 #ifdef DYNTRANS_PC_TO_POINTERS_FUNC
505 /*
506 * XXX_pc_to_pointers_generic():
507 *
508 * Generic case. See DYNTRANS_PC_TO_POINTERS_FUNC below.
509 */
510 void DYNTRANS_PC_TO_POINTERS_GENERIC(struct cpu *cpu)
511 {
512 #ifdef MODE32
513 uint32_t
514 #else
515 uint64_t
516 #endif
517 cached_pc, physaddr = 0;
518 uint32_t physpage_ofs;
519 int ok, pagenr, table_index;
520 uint32_t *physpage_entryp;
521 struct DYNTRANS_TC_PHYSPAGE *ppp;
522
523 #ifdef MODE32
524 int index;
525 cached_pc = cpu->pc;
526 index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
527 #else
528 #ifdef DYNTRANS_ALPHA
529 uint32_t a, b;
530 int kernel = 0;
531 struct alpha_vph_page *vph_p;
532 cached_pc = cpu->pc;
533 a = (cached_pc >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
534 b = (cached_pc >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
535 if ((cached_pc >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
536 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
537 kernel = 1;
538 } else
539 vph_p = cpu->cd.alpha.vph_table0[a];
540 #else
541 fatal("Neither alpha nor 32-bit? 3\n");
542 exit(1);
543 #endif
544 #endif
545
546 /* Virtual to physical address translation: */
547 ok = 0;
548 #ifdef MODE32
549 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) {
550 physaddr = cpu->cd.DYNTRANS_ARCH.phys_addr[index];
551 ok = 1;
552 }
553 #else
554 #ifdef DYNTRANS_ALPHA
555 if (vph_p->host_load[b] != NULL) {
556 physaddr = vph_p->phys_addr[b];
557 ok = 1;
558 }
559 #else
560 fatal("Neither alpha nor 32-bit? 4\n");
561 exit(1);
562 #endif
563 #endif
564
565 if (!ok) {
566 uint64_t paddr;
567 if (cpu->translate_address != NULL)
568 ok = cpu->translate_address(cpu, cached_pc,
569 &paddr, FLAG_INSTR);
570 else {
571 paddr = cached_pc;
572 ok = 1;
573 }
574 if (!ok) {
575 /* fatal("TODO: instruction vaddr=>paddr translation"
576 " failed. vaddr=0x%llx\n", (long long)cached_pc);
577 fatal("!! cpu->pc=0x%llx\n", (long long)cpu->pc); */
578
579 ok = cpu->translate_address(cpu, cpu->pc, &paddr,
580 FLAG_INSTR);
581
582 /* printf("EXCEPTION HANDLER: vaddr = 0x%x ==> "
583 "paddr = 0x%x\n", (int)cpu->pc, (int)paddr);
584 fatal("!? cpu->pc=0x%llx\n", (long long)cpu->pc); */
585
586 if (!ok) {
587 fatal("FATAL: could not find physical"
588 " address of the exception handler?");
589 exit(1);
590 }
591 }
592 cached_pc = cpu->pc;
593 #ifdef MODE32
594 index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
595 #endif
596 physaddr = paddr;
597 }
598
599 #ifdef MODE32
600 if (cpu->cd.DYNTRANS_ARCH.host_load[index] == NULL) {
601 unsigned char *host_page = memory_paddr_to_hostaddr(cpu->mem,
602 physaddr, MEM_READ);
603 if (host_page != NULL) {
604 int q = DYNTRANS_PAGESIZE - 1;
605 host_page += (physaddr &
606 ((1 << BITS_PER_MEMBLOCK) - 1) & ~q);
607 cpu->update_translation_table(cpu, cached_pc & ~q,
608 host_page, TLB_CODE, physaddr & ~q);
609 }
610 }
611 #endif
612
613 if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE) {
614 debug("[ dyntrans: resetting the translation cache ]\n");
615 cpu_create_or_reset_tc(cpu);
616 }
617
618 pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr);
619 table_index = PAGENR_TO_TABLE_INDEX(pagenr);
620
621 physpage_entryp = &(((uint32_t *)cpu->translation_cache)[table_index]);
622 physpage_ofs = *physpage_entryp;
623 ppp = NULL;
624
625 /* Traverse the physical page chain: */
626 while (physpage_ofs != 0) {
627 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
628 + physpage_ofs);
629 /* If we found the page in the cache, then we're done: */
630 if (ppp->physaddr == physaddr)
631 break;
632 /* Try the next page in the chain: */
633 physpage_ofs = ppp->next_ofs;
634 }
635
636 /* If the offset is 0 (or ppp is NULL), then we need to create a
637 new "default" empty translation page. */
638
639 if (ppp == NULL) {
640 /* fatal("CREATING page %lli (physaddr 0x%llx), table index "
641 "%i\n", (long long)pagenr, (long long)physaddr,
642 (int)table_index); */
643 *physpage_entryp = physpage_ofs =
644 cpu->translation_cache_cur_ofs;
645
646 /* Allocate a default page, with to_be_translated entries: */
647 DYNTRANS_TC_ALLOCATE(cpu, physaddr);
648
649 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
650 + physpage_ofs);
651 }
652
653 #ifdef MODE32
654 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL)
655 cpu->cd.DYNTRANS_ARCH.phys_page[index] = ppp;
656 #endif
657
658 #ifdef DYNTRANS_ALPHA
659 if (vph_p->host_load[b] != NULL)
660 vph_p->phys_page[b] = ppp;
661 #endif
662
663 #ifdef MODE32
664 /* Small optimization: only mark the physical page as non-writable
665 if it did not contain translations. (Because if it does contain
666 translations, it is already non-writable.) */
667 if (!cpu->cd.DYNTRANS_ARCH.phystranslation[pagenr >> 5] &
668 (1 << (pagenr & 31)))
669 #endif
670 cpu->invalidate_translation_caches(cpu, physaddr,
671 JUST_MARK_AS_NON_WRITABLE | INVALIDATE_PADDR);
672
673 cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
674
675 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
676 DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
677
678 /* printf("cached_pc=0x%016llx pagenr=%lli table_index=%lli, "
679 "physpage_ofs=0x%016llx\n", (long long)cached_pc, (long long)pagenr,
680 (long long)table_index, (long long)physpage_ofs); */
681 }
682
683
684 /*
685 * XXX_pc_to_pointers():
686 *
687 * This function uses the current program counter (a virtual address) to
688 * find out which physical translation page to use, and then sets the current
689 * translation page pointers to that page.
690 *
691 * If there was no translation page for that physical page, then an empty
692 * one is created.
693 *
694 * NOTE: This is the quick lookup version. See
695 * DYNTRANS_PC_TO_POINTERS_GENERIC above for the generic case.
696 */
697 void DYNTRANS_PC_TO_POINTERS_FUNC(struct cpu *cpu)
698 {
699 #ifdef MODE32
700 uint32_t
701 #else
702 uint64_t
703 #endif
704 cached_pc = cpu->pc;
705 struct DYNTRANS_TC_PHYSPAGE *ppp;
706
707 #ifdef MODE32
708 int index;
709 index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
710 ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index];
711 if (ppp != NULL)
712 goto have_it;
713 #else
714 #ifdef DYNTRANS_ALPHA
715 uint32_t a, b;
716 int kernel = 0;
717 struct alpha_vph_page *vph_p;
718 a = (cached_pc >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
719 b = (cached_pc >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
720 if ((cached_pc >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
721 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
722 kernel = 1;
723 } else
724 vph_p = cpu->cd.alpha.vph_table0[a];
725 if (vph_p != cpu->cd.alpha.vph_default_page) {
726 ppp = vph_p->phys_page[b];
727 if (ppp != NULL)
728 goto have_it;
729 }
730 #else
731 fatal("X1: cached_pc=%016llx\n", (long long)cached_pc);
732 /* Temporary, to avoid a compiler warning: */
733 ppp = NULL;
734 fatal("Neither alpha nor 32-bit? 1\n");
735 exit(1);
736 #endif
737 #endif
738
739 DYNTRANS_PC_TO_POINTERS_GENERIC(cpu);
740 return;
741
742 /* Quick return path: */
743 #if defined(MODE32) || defined(DYNTRANS_ALPHA)
744 have_it:
745 cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
746 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
747 DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
748
749 /* printf("cached_pc=0x%016llx pagenr=%lli table_index=%lli, "
750 "physpage_ofs=0x%016llx\n", (long long)cached_pc, (long long)pagenr,
751 (long long)table_index, (long long)physpage_ofs); */
752 #endif
753 }
754 #endif /* DYNTRANS_PC_TO_POINTERS_FUNC */
755
756
757
758 #ifdef DYNTRANS_INVAL_ENTRY
759 /*
760 * XXX_invalidate_tlb_entry():
761 *
762 * Invalidate one translation entry (based on virtual address).
763 *
764 * If the JUST_MARK_AS_NON_WRITABLE flag is set, then the translation entry
765 * is just downgraded to non-writable (ie the host store page is set to
766 * NULL). Otherwise, the entire translation is removed.
767 */
768 static void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu,
769 #ifdef MODE32
770 uint32_t
771 #else
772 uint64_t
773 #endif
774 vaddr_page, int flags)
775 {
776 #ifdef MODE32
777 uint32_t index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
778
779 #ifdef DYNTRANS_ARM
780 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5] &= ~(1 << (index & 31));
781 #endif
782
783 if (flags & JUST_MARK_AS_NON_WRITABLE) {
784 /* printf("JUST MARKING NON-W: vaddr 0x%08x\n",
785 (int)vaddr_page); */
786 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
787 } else {
788 cpu->cd.DYNTRANS_ARCH.host_load[index] = NULL;
789 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
790 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = 0;
791 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
792 cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = 0;
793 }
794 #else
795 /* 2-level: */
796 #ifdef DYNTRANS_ALPHA
797 struct alpha_vph_page *vph_p;
798 uint32_t a, b;
799 int kernel = 0;
800
801 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
802 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
803 if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
804 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
805 kernel = 1;
806 } else
807 vph_p = cpu->cd.alpha.vph_table0[a];
808
809 if (vph_p == cpu->cd.alpha.vph_default_page) {
810 fatal("alpha_invalidate_tlb_entry(): huh? Problem 1.\n");
811 exit(1);
812 }
813
814 if (flags & JUST_MARK_AS_NON_WRITABLE) {
815 vph_p->host_store[b] = NULL;
816 return;
817 }
818 vph_p->host_load[b] = NULL;
819 vph_p->host_store[b] = NULL;
820 vph_p->phys_addr[b] = 0;
821 vph_p->phys_page[b] = NULL;
822 vph_p->refcount --;
823 if (vph_p->refcount < 0) {
824 fatal("alpha_invalidate_tlb_entry(): huh? Problem 2.\n");
825 exit(1);
826 }
827 if (vph_p->refcount == 0) {
828 vph_p->next = cpu->cd.alpha.vph_next_free_page;
829 cpu->cd.alpha.vph_next_free_page = vph_p;
830 if (kernel)
831 cpu->cd.alpha.vph_table0_kernel[a] =
832 cpu->cd.alpha.vph_default_page;
833 else
834 cpu->cd.alpha.vph_table0[a] =
835 cpu->cd.alpha.vph_default_page;
836 }
837 #else /* !DYNTRANS_ALPHA */
838 fatal("Not yet for non-1-level, non-Alpha\n");
839 #endif /* !DYNTRANS_ALPHA */
840 #endif
841 }
842 #endif
843
844
845 #ifdef DYNTRANS_INVALIDATE_TC
846 /*
847 * XXX_invalidate_translation_caches():
848 *
849 * Invalidate all entries matching a specific physical address, a specific
850 * virtual address, or ALL entries.
851 *
852 * flags should be one of
853 * INVALIDATE_PADDR INVALIDATE_VADDR or INVALIDATE_ALL
854 *
855 * In addition, for INVALIDATE_ALL, INVALIDATE_VADDR_UPPER4 may be set and
856 * bit 31..28 of addr are used to select the virtual addresses to invalidate.
857 * (This is useful for PowerPC emulation, when segment registers are updated.)
858 *
859 * In the case when all translations are invalidated, paddr doesn't need
860 * to be supplied.
861 *
862 * NOTE/TODO: When invalidating a virtual address, it is only cleared from
863 * the quick translation array, not from the linear
864 * vph_tlb_entry[] array. Hopefully this is enough anyway.
865 */
866 void DYNTRANS_INVALIDATE_TC(struct cpu *cpu, uint64_t addr, int flags)
867 {
868 int r;
869 #ifdef MODE32
870 uint32_t
871 #else
872 uint64_t
873 #endif
874 addr_page = addr & ~(DYNTRANS_PAGESIZE - 1);
875
876 /* fatal("invalidate(): "); */
877
878 /* Quick case for _one_ virtual addresses: see note above. */
879 if (flags & INVALIDATE_VADDR) {
880 /* fatal("vaddr 0x%08x\n", (int)addr_page); */
881 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, addr_page, flags);
882 return;
883 }
884
885 /* Invalidate everything: */
886 #ifdef DYNTRANS_PPC
887 if (flags & INVALIDATE_ALL && flags & INVALIDATE_VADDR_UPPER4) {
888 /* fatal("all, upper4 (PowerPC segment)\n"); */
889 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
890 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid &&
891 (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page
892 & 0xf0000000) == addr_page) {
893 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd.
894 DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
895 0);
896 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid=0;
897 }
898 }
899 return;
900 }
901 #endif
902 if (flags & INVALIDATE_ALL) {
903 /* fatal("all\n"); */
904 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
905 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
906 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd.
907 DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
908 0);
909 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid=0;
910 }
911 }
912 return;
913 }
914
915 /* Invalidate a physical page: */
916
917 if (!(flags & INVALIDATE_PADDR))
918 fatal("HUH? Invalidate: Not vaddr, all, or paddr?\n");
919
920 /* fatal("addr 0x%08x\n", (int)addr_page); */
921
922 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
923 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && addr_page
924 == cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page) {
925 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
926 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
927 flags);
928 if (flags & JUST_MARK_AS_NON_WRITABLE)
929 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
930 .writeflag = 0;
931 else
932 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
933 .valid = 0;
934 }
935 }
936 }
937 #endif /* DYNTRANS_INVALIDATE_TC */
938
939
940
941 #ifdef DYNTRANS_INVALIDATE_TC_CODE
942 /*
943 * XXX_invalidate_code_translation():
944 *
945 * Invalidate code translations for a specific physical address, a specific
946 * virtual address, or for all entries in the cache.
947 */
948 void DYNTRANS_INVALIDATE_TC_CODE(struct cpu *cpu, uint64_t addr, int flags)
949 {
950 int r;
951 #ifdef MODE32
952 uint32_t
953 #else
954 uint64_t
955 #endif
956 vaddr_page, paddr_page;
957
958 addr &= ~(DYNTRANS_PAGESIZE-1);
959
960 /* printf("DYNTRANS_INVALIDATE_TC_CODE addr=0x%08x flags=%i\n",
961 (int)addr, flags); */
962
963 if (flags & INVALIDATE_PADDR) {
964 int pagenr, table_index;
965 uint32_t physpage_ofs, *physpage_entryp;
966 struct DYNTRANS_TC_PHYSPAGE *ppp, *prev_ppp;
967
968 pagenr = DYNTRANS_ADDR_TO_PAGENR(addr);
969
970 #ifdef MODE32
971 /* If this page isn't marked as having any translations,
972 then return immediately. */
973 if (!(cpu->cd.DYNTRANS_ARCH.phystranslation[pagenr >> 5]
974 & 1 << (pagenr & 31)))
975 return;
976 /* Remove the mark: */
977 cpu->cd.DYNTRANS_ARCH.phystranslation[pagenr >> 5] &=
978 ~ (1 << (pagenr & 31));
979 #endif
980
981 table_index = PAGENR_TO_TABLE_INDEX(pagenr);
982
983 physpage_entryp = &(((uint32_t *)cpu->
984 translation_cache)[table_index]);
985 physpage_ofs = *physpage_entryp;
986 prev_ppp = ppp = NULL;
987
988 /* Traverse the physical page chain: */
989 while (physpage_ofs != 0) {
990 prev_ppp = ppp;
991 ppp = (struct DYNTRANS_TC_PHYSPAGE *)
992 (cpu->translation_cache + physpage_ofs);
993 /* If we found the page in the cache,
994 then we're done: */
995 if (ppp->physaddr == addr)
996 break;
997 /* Try the next page in the chain: */
998 physpage_ofs = ppp->next_ofs;
999 }
1000
1001 if (physpage_ofs == 0)
1002 ppp = NULL;
1003
1004 #if 1
1005 /*
1006 * "Bypass" the page, removing it from the code cache.
1007 *
1008 * NOTE/TODO: This gives _TERRIBLE_ performance with self-
1009 * modifying code, or when a single page is used for both
1010 * code and (writable) data.
1011 */
1012 if (ppp != NULL) {
1013 if (prev_ppp != NULL)
1014 prev_ppp->next_ofs = ppp->next_ofs;
1015 else
1016 *physpage_entryp = ppp->next_ofs;
1017 }
1018 #else
1019 /*
1020 * Instead of removing the page from the code cache, each
1021 * entry can be set to "to_be_translated". This is slow in
1022 * the general case, but in the case of self-modifying code,
1023 * it might be faster since we don't risk wasting cache
1024 * memory as quickly (which would force unnecessary Restarts).
1025 */
1026 if (ppp != NULL) {
1027 /* TODO: Is this faster than copying an entire
1028 template page? */
1029 int i;
1030 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
1031 ppp->ics[i].f =
1032 #ifdef DYNTRANS_DUALMODE_32
1033 cpu->is_32bit? instr32(to_be_translated) :
1034 #endif
1035 instr(to_be_translated);
1036 }
1037 #endif
1038 }
1039
1040 /* Invalidate entries (NOTE: only code entries) in the VPH table: */
1041 for (r = DYNTRANS_MAX_VPH_TLB_ENTRIES/2;
1042 r < DYNTRANS_MAX_VPH_TLB_ENTRIES; r ++) {
1043 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
1044 vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
1045 .vaddr_page & ~(DYNTRANS_PAGESIZE-1);
1046 paddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
1047 .paddr_page & ~(DYNTRANS_PAGESIZE-1);
1048
1049 if (flags & INVALIDATE_ALL ||
1050 (flags & INVALIDATE_PADDR && paddr_page == addr) ||
1051 (flags & INVALIDATE_VADDR && vaddr_page == addr)) {
1052 #ifdef MODE32
1053 uint32_t index =
1054 DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1055 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1056 /* Remove the mark: */
1057 index = DYNTRANS_ADDR_TO_PAGENR(paddr_page);
1058 cpu->cd.DYNTRANS_ARCH.phystranslation[
1059 index >> 5] &= ~ (1 << (index & 31));
1060 #else
1061 /* 2-level: */
1062 #ifdef DYNTRANS_ALPHA
1063 struct alpha_vph_page *vph_p;
1064 uint32_t a, b;
1065 int kernel = 0;
1066
1067 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT)
1068 & (ALPHA_LEVEL0 - 1);
1069 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT)
1070 & (ALPHA_LEVEL1 - 1);
1071 if ((vaddr_page >> ALPHA_TOPSHIFT) ==
1072 ALPHA_TOP_KERNEL) {
1073 vph_p = cpu->cd.alpha.
1074 vph_table0_kernel[a];
1075 kernel = 1;
1076 } else
1077 vph_p = cpu->cd.alpha.vph_table0[a];
1078 vph_p->phys_page[b] = NULL;
1079 #else /* !DYNTRANS_ALPHA */
1080 fatal("Not yet for non-1-level, non-Alpha\n");
1081 #endif /* !DYNTRANS_ALPHA */
1082 #endif
1083 }
1084 }
1085 }
1086 }
1087 #endif /* DYNTRANS_INVALIDATE_TC_CODE */
1088
1089
1090
1091 #ifdef DYNTRANS_UPDATE_TRANSLATION_TABLE
1092 /*
1093 * XXX_update_translation_table():
1094 *
1095 * Update the virtual memory translation tables.
1096 */
1097 void DYNTRANS_UPDATE_TRANSLATION_TABLE(struct cpu *cpu, uint64_t vaddr_page,
1098 unsigned char *host_page, int writeflag, uint64_t paddr_page)
1099 {
1100 #ifndef MODE32
1101 int64_t lowest, highest = -1;
1102 #endif
1103 int found, r, lowest_index, start, end, useraccess = 0;
1104
1105 #ifdef DYNTRANS_ALPHA
1106 uint32_t a, b;
1107 struct alpha_vph_page *vph_p;
1108 int kernel = 0;
1109 /* fatal("update_translation_table(): v=0x%llx, h=%p w=%i"
1110 " p=0x%llx\n", (long long)vaddr_page, host_page, writeflag,
1111 (long long)paddr_page); */
1112 #else
1113 #ifdef MODE32
1114 uint32_t index;
1115 vaddr_page &= 0xffffffffULL;
1116 paddr_page &= 0xffffffffULL;
1117 /* fatal("update_translation_table(): v=0x%x, h=%p w=%i"
1118 " p=0x%x\n", (int)vaddr_page, host_page, writeflag,
1119 (int)paddr_page); */
1120 #else /* !MODE32 */
1121 fatal("Neither 32-bit nor Alpha? 2\n");
1122 exit(1);
1123 #endif
1124 #endif
1125
1126 if (writeflag & MEMORY_USER_ACCESS) {
1127 writeflag &= ~MEMORY_USER_ACCESS;
1128 useraccess = 1;
1129 }
1130
1131 start = 0; end = DYNTRANS_MAX_VPH_TLB_ENTRIES / 2;
1132 #if 1
1133 /* Half of the TLB used for data, half for code: */
1134 if (writeflag & TLB_CODE) {
1135 writeflag &= ~TLB_CODE;
1136 start = end; end = DYNTRANS_MAX_VPH_TLB_ENTRIES;
1137 }
1138 #else
1139 /* Data and code entries are mixed. */
1140 end = DYNTRANS_MAX_VPH_TLB_ENTRIES;
1141 #endif
1142
1143 /* Scan the current TLB entries: */
1144 lowest_index = start;
1145
1146 #ifdef MODE32
1147 /*
1148 * NOTE 1: vaddr_to_tlbindex is one more than the index, so that
1149 * 0 becomes -1, which means a miss.
1150 *
1151 * NOTE 2: When a miss occurs, instead of scanning the entire tlb
1152 * for the entry with the lowest time stamp, just choosing
1153 * one at random will work as well.
1154 */
1155 found = (int)cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[
1156 DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1;
1157 if (found < 0) {
1158 static unsigned int x = 0;
1159 lowest_index = (x % (end-start)) + start;
1160 x ++;
1161 }
1162 #else
1163 lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp;
1164 found = -1;
1165 for (r=start; r<end; r++) {
1166 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) {
1167 lowest = cpu->cd.DYNTRANS_ARCH.
1168 vph_tlb_entry[r].timestamp;
1169 lowest_index = r;
1170 }
1171 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp > highest)
1172 highest = cpu->cd.DYNTRANS_ARCH.
1173 vph_tlb_entry[r].timestamp;
1174 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid &&
1175 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page ==
1176 vaddr_page) {
1177 found = r;
1178 break;
1179 }
1180 }
1181 #endif
1182
1183 if (found < 0) {
1184 /* Create the new TLB entry, overwriting the oldest one: */
1185 r = lowest_index;
1186 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
1187 /* This one has to be invalidated first: */
1188 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
1189 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
1190 0);
1191 }
1192
1193 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid = 1;
1194 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].host_page = host_page;
1195 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page = paddr_page;
1196 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page;
1197 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag =
1198 writeflag & MEM_WRITE;
1199 #ifndef MODE32
1200 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1;
1201 #endif
1202
1203 /* Add the new translation to the table: */
1204 #ifdef DYNTRANS_ALPHA
1205 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
1206 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
1207 if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
1208 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
1209 kernel = 1;
1210 } else
1211 vph_p = cpu->cd.alpha.vph_table0[a];
1212 if (vph_p == cpu->cd.alpha.vph_default_page) {
1213 if (cpu->cd.alpha.vph_next_free_page != NULL) {
1214 if (kernel)
1215 vph_p = cpu->cd.alpha.vph_table0_kernel
1216 [a] = cpu->cd.alpha.
1217 vph_next_free_page;
1218 else
1219 vph_p = cpu->cd.alpha.vph_table0[a] =
1220 cpu->cd.alpha.vph_next_free_page;
1221 cpu->cd.alpha.vph_next_free_page = vph_p->next;
1222 } else {
1223 if (kernel)
1224 vph_p = cpu->cd.alpha.vph_table0_kernel
1225 [a] = malloc(sizeof(struct
1226 alpha_vph_page));
1227 else
1228 vph_p = cpu->cd.alpha.vph_table0[a] =
1229 malloc(sizeof(struct
1230 alpha_vph_page));
1231 memset(vph_p, 0, sizeof(struct alpha_vph_page));
1232 }
1233 }
1234 vph_p->refcount ++;
1235 vph_p->host_load[b] = host_page;
1236 vph_p->host_store[b] = writeflag? host_page : NULL;
1237 vph_p->phys_addr[b] = paddr_page;
1238 vph_p->phys_page[b] = NULL;
1239 #else
1240 #ifdef MODE32
1241 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1242 cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
1243 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1244 writeflag? host_page : NULL;
1245 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
1246 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1247 cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = r + 1;
1248 #ifdef DYNTRANS_ARM
1249 if (useraccess)
1250 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5]
1251 |= 1 << (index & 31);
1252 #endif
1253 #endif /* 32 */
1254 #endif /* !ALPHA */
1255 } else {
1256 /*
1257 * The translation was already in the TLB.
1258 * Writeflag = 0: Do nothing.
1259 * Writeflag = 1: Make sure the page is writable.
1260 * Writeflag = MEM_DOWNGRADE: Downgrade to readonly.
1261 */
1262 r = found;
1263 #ifndef MODE32
1264 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1;
1265 #endif
1266 if (writeflag & MEM_WRITE)
1267 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1;
1268 if (writeflag & MEM_DOWNGRADE)
1269 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 0;
1270 #ifdef DYNTRANS_ALPHA
1271 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
1272 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
1273 if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
1274 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
1275 kernel = 1;
1276 } else
1277 vph_p = cpu->cd.alpha.vph_table0[a];
1278 vph_p->phys_page[b] = NULL;
1279 if (vph_p->phys_addr[b] == paddr_page) {
1280 if (writeflag & MEM_WRITE)
1281 vph_p->host_store[b] = host_page;
1282 if (writeflag & MEM_DOWNGRADE)
1283 vph_p->host_store[b] = NULL;
1284 } else {
1285 /* Change the entire physical/host mapping: */
1286 vph_p->host_load[b] = host_page;
1287 vph_p->host_store[b] = writeflag? host_page : NULL;
1288 vph_p->phys_addr[b] = paddr_page;
1289 }
1290 #else
1291 #ifdef MODE32
1292 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1293 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1294 #ifdef DYNTRANS_ARM
1295 cpu->cd.DYNTRANS_ARCH.is_userpage[index>>5] &= ~(1<<(index&31));
1296 if (useraccess)
1297 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5]
1298 |= 1 << (index & 31);
1299 #endif
1300 if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) {
1301 if (writeflag & MEM_WRITE)
1302 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1303 host_page;
1304 if (writeflag & MEM_DOWNGRADE)
1305 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
1306 } else {
1307 /* Change the entire physical/host mapping: */
1308 cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
1309 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1310 writeflag? host_page : NULL;
1311 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
1312 }
1313 #endif /* 32 */
1314 #endif /* !ALPHA */
1315 }
1316 }
1317 #endif /* DYNTRANS_UPDATE_TRANSLATION_TABLE */
1318
1319
1320 /*****************************************************************************/
1321
1322
1323 #ifdef DYNTRANS_TO_BE_TRANSLATED_HEAD
1324 /*
1325 * Check for breakpoints.
1326 */
1327 if (!single_step_breakpoint) {
1328 #ifdef MODE32
1329 uint32_t curpc = cpu->pc;
1330 #else
1331 uint64_t curpc = cpu->pc;
1332 #endif
1333 int i;
1334 for (i=0; i<cpu->machine->n_breakpoints; i++)
1335 if (curpc ==
1336 #ifdef MODE32
1337 (uint32_t)
1338 #endif
1339 cpu->machine->breakpoint_addr[i]) {
1340 if (!cpu->machine->instruction_trace) {
1341 int old_quiet_mode = quiet_mode;
1342 quiet_mode = 0;
1343 DISASSEMBLE(cpu, ib, 1, 0, 0);
1344 quiet_mode = old_quiet_mode;
1345 }
1346 fatal("BREAKPOINT: pc = 0x%llx\n(The "
1347 "instruction has not yet executed.)\n",
1348 (long long)cpu->pc);
1349 #ifdef DYNTRANS_DELAYSLOT
1350 if (cpu->cd.DYNTRANS_ARCH.delay_slot !=
1351 NOT_DELAYED)
1352 fatal("ERROR! Breakpoint in a delay"
1353 " slot! Not yet supported.\n");
1354 #endif
1355 single_step_breakpoint = 1;
1356 single_step = 1;
1357 goto stop_running_translated;
1358 }
1359 }
1360 #endif /* DYNTRANS_TO_BE_TRANSLATED_HEAD */
1361
1362
1363 /*****************************************************************************/
1364
1365
1366 #ifdef DYNTRANS_TO_BE_TRANSLATED_TAIL
1367 /*
1368 * If we end up here, then an instruction was translated.
1369 * Mark the page as containing a translation.
1370 *
1371 * (Special case for 32-bit mode: set the corresponding bit in the
1372 * phystranslation[] array.)
1373 */
1374 #ifdef MODE32
1375 if (!(cpu->cd.DYNTRANS_ARCH.cur_physpage->flags & TRANSLATIONS)) {
1376 uint32_t index = DYNTRANS_ADDR_TO_PAGENR((uint32_t)addr);
1377 cpu->cd.DYNTRANS_ARCH.phystranslation[index >> 5] |=
1378 (1 << (index & 31));
1379 }
1380 #endif
1381 cpu->cd.DYNTRANS_ARCH.cur_physpage->flags |= TRANSLATIONS;
1382
1383
1384 #ifdef DYNTRANS_BACKEND
1385 /*
1386 * "Empty"/simple native dyntrans backend stuff:
1387 *
1388 * 1) If no translation is currently being done, but the translated
1389 * instruction was simple enough, then let's start making a new
1390 * native translation block.
1391 *
1392 * 2) If a native translation block is currently being constructed,
1393 * but this instruction wasn't simple enough, then end the block
1394 * (without including this instruction).
1395 *
1396 * 3) If a native translation block is currently being constructed,
1397 * and this is a simple instruction, then add it.
1398 */
1399 if (simple && cpu->translation_context.p == NULL &&
1400 dyntrans_backend_enable) {
1401 size_t s = 0;
1402
1403 if (cpu->translation_context.translation_buffer == NULL) {
1404 cpu->translation_context.translation_buffer =
1405 zeroed_alloc(DTB_TRANSLATION_SIZE_MAX +
1406 DTB_TRANSLATION_SIZE_MARGIN);
1407 }
1408
1409 cpu->translation_context.p =
1410 cpu->translation_context.translation_buffer;
1411
1412 cpu->translation_context.ic_page =
1413 cpu->cd.DYNTRANS_ARCH.cur_ic_page;
1414 cpu->translation_context.start_instr_call_index =
1415 ((size_t)ic - (size_t)cpu->cd.DYNTRANS_ARCH.cur_ic_page)
1416 / (sizeof(*ic));
1417
1418 dtb_function_prologue(&cpu->translation_context, &s);
1419 cpu->translation_context.p += s;
1420 cpu->translation_context.n_simple = 0;
1421 }
1422
1423 /* If this is not a continuation of a simple translation, then
1424 stop now! */
1425 if (cpu->translation_context.ic_page != cpu->cd.DYNTRANS_ARCH.
1426 cur_ic_page || ic != &cpu->cd.DYNTRANS_ARCH.cur_ic_page[
1427 cpu->translation_context.start_instr_call_index +
1428 cpu->translation_context.n_simple])
1429 simple = 0;
1430
1431 if (cpu->translation_context.p != NULL && !simple) {
1432 size_t s = 0, total;
1433
1434 if (cpu->translation_context.n_simple > 1) {
1435 dtb_generate_ptr_inc(cpu, &cpu->translation_context,
1436 &s, &cpu->cd.DYNTRANS_ARCH.next_ic,
1437 (cpu->translation_context.n_simple - 1) *
1438 sizeof(*(cpu->cd.DYNTRANS_ARCH.next_ic)));
1439 cpu->translation_context.p += s;
1440 }
1441
1442 dtb_function_epilogue(&cpu->translation_context, &s);
1443 cpu->translation_context.p += s;
1444
1445 cpu_dtb_do_fixups(cpu);
1446 #if 0
1447 {
1448 int i;
1449 unsigned char *addr = cpu->translation_context.translation_buffer;
1450 printf("index = %i\n", cpu->translation_context.start_instr_call_index);
1451 quiet_mode = 0;
1452 for (i=0; i<4*32; i+=4)
1453 alpha_cpu_disassemble_instr(cpu, (unsigned char *)addr + i,
1454 0, i, 0);
1455 }
1456 #endif
1457 total = (size_t)cpu->translation_context.p -
1458 (size_t)cpu->translation_context.translation_buffer;
1459
1460 /* Copy the translated block to the translation cache: */
1461 /* Align first: */
1462 cpu->translation_cache_cur_ofs --;
1463 cpu->translation_cache_cur_ofs |= 31;
1464 cpu->translation_cache_cur_ofs ++;
1465
1466 memcpy(cpu->translation_cache + cpu->translation_cache_cur_ofs,
1467 cpu->translation_context.translation_buffer, total);
1468
1469 /* Set the ic pointer: */
1470 ((struct DYNTRANS_IC *)cpu->translation_context.ic_page)
1471 [cpu->translation_context.start_instr_call_index].f =
1472 (void *)
1473 (cpu->translation_cache + cpu->translation_cache_cur_ofs);
1474
1475 /* Align cur_ofs afterwards as well, just to be safe. */
1476 cpu->translation_cache_cur_ofs += total;
1477 cpu->translation_cache_cur_ofs --;
1478 cpu->translation_cache_cur_ofs |= 31;
1479 cpu->translation_cache_cur_ofs ++;
1480
1481 /* Set the "combined instruction" flag for this page: */
1482 cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
1483 cpu->cd.DYNTRANS_ARCH.cur_ic_page;
1484 cpu->cd.DYNTRANS_ARCH.cur_physpage->flags |= COMBINATIONS;
1485
1486 dtb_host_cacheinvalidate(0,0); /* p , size ... ); */
1487
1488 cpu->translation_context.p = NULL;
1489 }
1490 if (cpu->translation_context.p != NULL) {
1491 size_t s = 0;
1492 dtb_generate_fcall(cpu, &cpu->translation_context,
1493 &s, (size_t)ic->f, (size_t)ic);
1494 cpu->translation_context.p += s;
1495 cpu->translation_context.n_simple ++;
1496 }
1497 #endif /* DYNTRANS_BACKEND */
1498
1499
1500 /*
1501 * Now it is time to check for combinations of instructions that can
1502 * be converted into a single function call.
1503 *
1504 * Note: Single-stepping or instruction tracing doesn't work with
1505 * instruction combination.
1506 */
1507 if (!single_step && !cpu->machine->instruction_trace) {
1508 if (cpu->cd.DYNTRANS_ARCH.combination_check != NULL &&
1509 cpu->machine->speed_tricks)
1510 cpu->cd.DYNTRANS_ARCH.combination_check(cpu, ic,
1511 addr & (DYNTRANS_PAGESIZE - 1));
1512 cpu->cd.DYNTRANS_ARCH.combination_check = NULL;
1513 }
1514
1515 /* ... and finally execute the translated instruction: */
1516 if (single_step_breakpoint) {
1517 /*
1518 * Special case when single-stepping: Execute the translated
1519 * instruction, but then replace it with a "to be translated"
1520 * directly afterwards.
1521 */
1522 single_step_breakpoint = 0;
1523 ic->f(cpu, ic);
1524 ic->f =
1525 #ifdef DYNTRANS_DUALMODE_32
1526 cpu->is_32bit? instr32(to_be_translated) :
1527 #endif
1528 instr(to_be_translated);
1529 } else
1530 ic->f(cpu, ic);
1531
1532 return;
1533
1534
1535 bad: /*
1536 * Nothing was translated. (Unimplemented or illegal instruction.)
1537 */
1538
1539 quiet_mode = 0;
1540 fatal("to_be_translated(): TODO: unimplemented instruction");
1541
1542 if (cpu->machine->instruction_trace)
1543 #ifdef MODE32
1544 fatal(" at 0x%x\n", (int)cpu->pc);
1545 #else
1546 fatal(" at 0x%llx\n", (long long)cpu->pc);
1547 #endif
1548 else {
1549 fatal(":\n");
1550 DISASSEMBLE(cpu, ib, 1, 0, 0);
1551 }
1552
1553 cpu->running = 0;
1554 cpu->dead = 1;
1555 stop_running_translated:
1556 debugger_n_steps_left_before_interaction = 0;
1557 cpu->running_translated = 0;
1558 ic = cpu->cd.DYNTRANS_ARCH.next_ic = &nothing_call;
1559 cpu->cd.DYNTRANS_ARCH.next_ic ++;
1560
1561 /* Execute the "nothing" instruction: */
1562 ic->f(cpu, ic);
1563 #endif /* DYNTRANS_TO_BE_TRANSLATED_TAIL */
1564

  ViewVC Help
Powered by ViewVC 1.1.26