/[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 44 - (show annotations)
Mon Oct 8 16:22:56 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 52126 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1632 2007/09/11 21:46:35 debug Exp $
20070616	Implementing the MIPS32/64 revision 2 "ror" instruction.
20070617	Adding a struct for each physpage which keeps track of which
		ranges within that page (base offset, length) that are
		continuously translatable. When running with native code
		generation enabled (-b), a range is added after each read-
		ahead loop.
		Experimenting with using the physical program counter sample
		data (implemented 20070608) together with the "translatable
		range" information, to figure out which physical address ranges
		would be worth translating to native code (if the number of
		samples falling within a range is above a certain threshold).
20070618	Adding automagic building of .index comment files for
		src/file/, src/promemul/, src src/useremul/ as well.
		Adding a "has been translated" bit to the ranges, so that only
		not-yet-translated ranges will be sampled.
20070619	Moving src/cpu.c and src/memory_rw.c into src/cpus/,
		src/device.c into src/devices/, and src/machine.c into
		src/machines/.
		Creating a skeleton cc/ld native backend module; beginning on
		the function which will detect cc command line, etc.
20070620	Continuing on the native code generation infrastructure.
20070621	Moving src/x11.c and src/console.c into a new src/console/
		subdir (for everything that is console or framebuffer related).
		Moving src/symbol*.c into a new src/symbol/, which should
		contain anything that is symbol handling related.
20070624	Making the program counter sampling threshold a "settings
		variable" (sampling_threshold), i.e. it can now be changed
		during runtime.
		Switching the RELEASE notes format from plain text to HTML.
		If the TMPDIR environment variable is set, it is used instead
		of "/tmp" for temporary files.
		Continuing on the cc/ld backend: simple .c code is generated,
		the compiler and linker are called, etc.
		Adding detection of host architecture to the configure script
		(again), and adding icache invalidation support (only
		implemented for Alpha hosts so far).
20070625	Simplifying the program counter sampling mechanism.
20070626	Removing the cc/ld native code generation stuff, program
		counter sampling, etc; it would not have worked well in the
		general case.
20070627	Removing everything related to native code generation.
20070629	Removing the (practically unusable) support for multiple
		emulations. (The single emulation allowed now still supports
		multiple simultaneous machines, as before.)
		Beginning on PCCTWO and M88K interrupts.
20070723	Adding a dummy skeleton for emulation of M32R processors.
20070901	Fixing a warning found by "gcc version 4.3.0 20070817
		(experimental)" on amd64.
20070905	Removing some more traces of the old "multiple emulations"
		code.
		Also looking in /usr/local/include and /usr/local/lib for
		X11 libs, when running configure.
20070909	Minor updates to the guest OS install instructions, in
		preparation for the NetBSD 4.0 release.
20070918	More testing of NetBSD 4.0 RC1.

1 /*
2 * Copyright (C) 2005-2007 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.186 2007/07/20 09:03:33 debug Exp $
29 *
30 * Common dyntrans routines. Included from cpu_*.c.
31 *
32 * Note: This might be a bit hard to follow, if you are reading this source
33 * code for the first time. It is basically a hack to implement "templates"
34 * with normal C code, by using suitable defines/macros, and then including
35 * this file.
36 */
37
38
39 #ifndef STATIC_STUFF
40 #define STATIC_STUFF
41 /*
42 * gather_statistics():
43 */
44 static void gather_statistics(struct cpu *cpu)
45 {
46 char ch, buf[60];
47 struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic;
48 int i = 0;
49 uint64_t a;
50 int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t)
51 cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC);
52
53 if (cpu->machine->statistics.file == NULL) {
54 fatal("statistics gathering with no filename set is"
55 " meaningless\n");
56 return;
57 }
58
59 /* low_pc must be within the page! */
60 if (low_pc < 0 || low_pc > DYNTRANS_IC_ENTRIES_PER_PAGE)
61 return;
62
63 buf[0] = '\0';
64
65 while ((ch = cpu->machine->statistics.fields[i]) != '\0') {
66 if (i != 0)
67 strlcat(buf, " ", sizeof(buf));
68
69 switch (ch) {
70 case 'i':
71 snprintf(buf + strlen(buf), sizeof(buf),
72 "%p", (void *)ic->f);
73 break;
74 case 'p':
75 /* Physical program counter address: */
76 cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
77 cpu->cd.DYNTRANS_ARCH.cur_ic_page;
78 a = cpu->cd.DYNTRANS_ARCH.cur_physpage->physaddr;
79 a &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
80 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
81 a += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT;
82 if (cpu->is_32bit)
83 snprintf(buf + strlen(buf), sizeof(buf),
84 "0x%08"PRIx32, (uint32_t)a);
85 else
86 snprintf(buf + strlen(buf), sizeof(buf),
87 "0x%016"PRIx64, (uint64_t)a);
88 break;
89 case 'v':
90 /* Virtual program counter address: */
91 a = cpu->pc;
92 a &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
93 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
94 a += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT;
95 if (cpu->is_32bit)
96 snprintf(buf + strlen(buf), sizeof(buf),
97 "0x%08"PRIx32, (uint32_t)a);
98 else
99 snprintf(buf + strlen(buf), sizeof(buf),
100 "0x%016"PRIx64, (uint64_t)a);
101 break;
102 }
103 i++;
104 }
105
106 fprintf(cpu->machine->statistics.file, "%s\n", buf);
107 }
108
109
110 #define S gather_statistics(cpu)
111
112
113 #if 1
114
115 /* The normal instruction execution core: */
116 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic);
117
118 #else
119
120 /* For heavy debugging: */
121 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; \
122 { \
123 int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - \
124 (size_t)cpu->cd.DYNTRANS_ARCH.cur_ic_page) / \
125 sizeof(struct DYNTRANS_IC); \
126 printf("cur_ic_page=%p ic=%p (low_pc=0x%x)\n", \
127 cpu->cd.DYNTRANS_ARCH.cur_ic_page, \
128 ic, low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT); \
129 } \
130 ic->f(cpu, ic);
131
132 #endif
133
134 /* static long long nr_of_I_calls = 0; */
135
136 /* Temporary hack for finding NULL bugs: */
137 /* #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; \
138 nr_of_I_calls ++; \
139 if (ic->f == NULL) { \
140 int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - \
141 (size_t)cpu->cd.DYNTRANS_ARCH.cur_ic_page) / \
142 sizeof(struct DYNTRANS_IC); \
143 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << \
144 DYNTRANS_INSTR_ALIGNMENT_SHIFT); \
145 cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT);\
146 printf("Crash at %016"PRIx64"\n", cpu->pc); \
147 printf("nr of I calls: %lli\n", nr_of_I_calls); \
148 printf("Next ic = %p\n", cpu->cd. \
149 DYNTRANS_ARCH.next_ic); \
150 printf("cur ic page = %p\n", cpu->cd. \
151 DYNTRANS_ARCH.cur_ic_page); \
152 cpu->running = 0; \
153 return 0; \
154 } \
155 ic->f(cpu, ic); */
156
157 /* Temporary hack for MIPS, to hunt for 32-bit/64-bit sign-extension bugs: */
158 /* #define I { int k; for (k=1; k<=31; k++) \
159 cpu->cd.mips.gpr[k] = (int32_t)cpu->cd.mips.gpr[k];\
160 if (cpu->cd.mips.gpr[0] != 0) { \
161 fatal("NOOOOOO\n"); exit(1); \
162 } \
163 ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic); }
164 */
165 #endif /* STATIC STUFF */
166
167
168
169 #ifdef DYNTRANS_RUN_INSTR_DEF
170 /*
171 * XXX_run_instr():
172 *
173 * Execute one or more instructions on a specific CPU, using dyntrans.
174 * (For dualmode archs, this function is included twice.)
175 *
176 * Return value is the number of instructions executed during this call,
177 * 0 if no instructions were executed.
178 */
179 int DYNTRANS_RUN_INSTR_DEF(struct cpu *cpu)
180 {
181 MODE_uint_t cached_pc;
182 int low_pc, n_instrs;
183
184 /* Ugly... fix this some day. */
185 #ifdef DYNTRANS_DUALMODE_32
186 #ifdef MODE32
187 DYNTRANS_PC_TO_POINTERS32(cpu);
188 #else
189 DYNTRANS_PC_TO_POINTERS(cpu);
190 #endif
191 #else
192 DYNTRANS_PC_TO_POINTERS(cpu);
193 #endif
194
195 /*
196 * Interrupt assertion? (This is _below_ the initial PC to pointer
197 * conversion; if the conversion caused an exception of some kind
198 * then interrupts are probably disabled, and the exception will get
199 * priority over device interrupts.)
200 *
201 * TODO: Turn this into a family-specific function somewhere...
202 */
203 #ifdef DYNTRANS_ARM
204 if (cpu->cd.arm.irq_asserted && !(cpu->cd.arm.cpsr & ARM_FLAG_I))
205 arm_exception(cpu, ARM_EXCEPTION_IRQ);
206 #endif
207 #ifdef DYNTRANS_M88K
208 if (cpu->cd.m88k.irq_asserted &&
209 !(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_IND))
210 m88k_exception(cpu, M88K_EXCEPTION_INTERRUPT, 0);
211 #endif
212 #ifdef DYNTRANS_MIPS
213 {
214 int enabled, mask;
215 int status = cpu->cd.mips.coproc[0]->reg[COP0_STATUS];
216 if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
217 /* R3000: */
218 enabled = status & MIPS_SR_INT_IE;
219 } else {
220 /* R4000 and others: */
221 enabled = (status & STATUS_IE)
222 && !(status & STATUS_EXL) && !(status & STATUS_ERL);
223 /* Special case for R5900/C790/TX79: */
224 if (cpu->cd.mips.cpu_type.rev == MIPS_R5900 &&
225 !(status & R5900_STATUS_EIE))
226 enabled = 0;
227 }
228 mask = status & cpu->cd.mips.coproc[0]->reg[COP0_CAUSE]
229 & STATUS_IM_MASK;
230
231 if (enabled && mask)
232 mips_cpu_exception(cpu, EXCEPTION_INT, 0, 0, 0, 0, 0,0);
233 }
234 #endif
235 #ifdef DYNTRANS_PPC
236 if (cpu->cd.ppc.dec_intr_pending && cpu->cd.ppc.msr & PPC_MSR_EE) {
237 if (!(cpu->cd.ppc.cpu_type.flags & PPC_NO_DEC))
238 ppc_exception(cpu, PPC_EXCEPTION_DEC);
239 cpu->cd.ppc.dec_intr_pending = 0;
240 }
241 if (cpu->cd.ppc.irq_asserted && cpu->cd.ppc.msr & PPC_MSR_EE)
242 ppc_exception(cpu, PPC_EXCEPTION_EI);
243 #endif
244 #ifdef DYNTRANS_SH
245 if (cpu->cd.sh.int_to_assert > 0 && !(cpu->cd.sh.sr & SH_SR_BL)
246 && ((cpu->cd.sh.sr & SH_SR_IMASK) >> SH_SR_IMASK_SHIFT)
247 < cpu->cd.sh.int_level)
248 sh_exception(cpu, 0, cpu->cd.sh.int_to_assert, 0);
249 #endif
250
251 cached_pc = cpu->pc;
252
253 cpu->n_translated_instrs = 0;
254
255 cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
256 cpu->cd.DYNTRANS_ARCH.cur_ic_page;
257
258 if (single_step || cpu->machine->instruction_trace
259 || cpu->machine->register_dump) {
260 /*
261 * Single-step:
262 */
263 struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic;
264 if (cpu->machine->register_dump) {
265 debug("\n");
266 cpu_register_dump(cpu->machine, cpu, 1, 0x1);
267 }
268 if (cpu->machine->instruction_trace) {
269 /* TODO/Note: This must be large enough to hold
270 any instruction for any ISA: */
271 unsigned char instr[1 <<
272 DYNTRANS_INSTR_ALIGNMENT_SHIFT];
273 if (!cpu->memory_rw(cpu, cpu->mem, cached_pc, &instr[0],
274 sizeof(instr), MEM_READ, CACHE_INSTRUCTION)) {
275 fatal("XXX_run_instr(): could not read "
276 "the instruction\n");
277 } else {
278 #ifdef DYNTRANS_DELAYSLOT
279 int len =
280 #endif
281 cpu_disassemble_instr(
282 cpu->machine, cpu, instr, 1, 0);
283 #ifdef DYNTRANS_DELAYSLOT
284 /* Show the instruction in the delay slot,
285 if any: */
286 if (cpu->instruction_has_delayslot == NULL)
287 fatal("WARNING: ihd func not yet"
288 " implemented?\n");
289 else if (cpu->instruction_has_delayslot(cpu,
290 instr)) {
291 int saved_delayslot = cpu->delay_slot;
292 cpu->memory_rw(cpu, cpu->mem, cached_pc
293 + len, &instr[0],
294 sizeof(instr), MEM_READ,
295 CACHE_INSTRUCTION);
296 cpu->delay_slot = DELAYED;
297 cpu->pc += len;
298 cpu_disassemble_instr(cpu->machine,
299 cpu, instr, 1, 0);
300 cpu->delay_slot = saved_delayslot;
301 cpu->pc -= len;
302 }
303 #endif
304 }
305 }
306
307 if (cpu->machine->statistics.enabled)
308 S;
309
310 /* Execute just one instruction: */
311 I;
312
313 n_instrs = 1;
314 } else if (cpu->machine->statistics.enabled) {
315 /* Gather statistics while executing multiple instructions: */
316 n_instrs = 0;
317 for (;;) {
318 struct DYNTRANS_IC *ic;
319
320 S; I; S; I; S; I; S; I; S; I; S; I;
321 S; I; S; I; S; I; S; I; S; I; S; I;
322 S; I; S; I; S; I; S; I; S; I; S; I;
323 S; I; S; I; S; I; S; I; S; I; S; I;
324
325 n_instrs += 24;
326
327 if (n_instrs + cpu->n_translated_instrs >=
328 N_SAFE_DYNTRANS_LIMIT)
329 break;
330 }
331 } else {
332 /*
333 * Execute multiple instructions:
334 *
335 * (This is the core dyntrans loop.)
336 */
337 n_instrs = 0;
338
339 for (;;) {
340 struct DYNTRANS_IC *ic;
341
342 I; I; I; I; I; I; I; I; I; I;
343 I; I; I; I; I; I; I; I; I; I;
344 I; I; I; I; I; I; I; I; I; I;
345 I; I; I; I; I; I; I; I; I; I;
346 I; I; I; I; I; I; I; I; I; I;
347
348 I; I; I; I; I; I; I; I; I; I;
349
350 I; I; I; I; I; I; I; I; I; I;
351 I; I; I; I; I; I; I; I; I; I;
352 I; I; I; I; I; I; I; I; I; I;
353 I; I; I; I; I; I; I; I; I; I;
354 I; I; I; I; I; I; I; I; I; I;
355
356 I; I; I; I; I; I; I; I; I; I;
357
358 cpu->n_translated_instrs += 120;
359 if (cpu->n_translated_instrs >= N_SAFE_DYNTRANS_LIMIT)
360 break;
361 }
362 }
363
364 n_instrs += cpu->n_translated_instrs;
365
366 /* Synchronize the program counter: */
367 low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t)
368 cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC);
369 if (low_pc >= 0 && low_pc < DYNTRANS_IC_ENTRIES_PER_PAGE) {
370 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
371 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
372 cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT);
373 } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE) {
374 /* Switch to next page: */
375 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
376 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
377 cpu->pc += (DYNTRANS_IC_ENTRIES_PER_PAGE <<
378 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
379 } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE + 1) {
380 /* Switch to next page and skip an instruction which was
381 already executed (in a delay slot): */
382 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
383 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
384 cpu->pc += ((DYNTRANS_IC_ENTRIES_PER_PAGE + 1) <<
385 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
386 }
387
388 #ifdef DYNTRANS_MIPS
389 /* Update the count register (on everything except EXC3K): */
390 if (cpu->cd.mips.cpu_type.exc_model != EXC3K) {
391 uint32_t old = cpu->cd.mips.coproc[0]->reg[COP0_COUNT];
392 int32_t diff1 = cpu->cd.mips.coproc[0]->reg[COP0_COMPARE] - old;
393 int32_t diff2;
394 cpu->cd.mips.coproc[0]->reg[COP0_COUNT] =
395 (int32_t) (old + n_instrs);
396 diff2 = cpu->cd.mips.coproc[0]->reg[COP0_COMPARE] -
397 cpu->cd.mips.coproc[0]->reg[COP0_COUNT];
398
399 if (cpu->cd.mips.compare_register_set) {
400 #if 1
401 /* Not yet. TODO */
402 if (cpu->machine->emulated_hz > 0) {
403 if (cpu->cd.mips.compare_interrupts_pending > 0)
404 INTERRUPT_ASSERT(
405 cpu->cd.mips.irq_compare);
406 } else
407 #endif
408 {
409 if (diff1 > 0 && diff2 <= 0)
410 INTERRUPT_ASSERT(
411 cpu->cd.mips.irq_compare);
412 }
413 }
414 }
415 #endif
416 #ifdef DYNTRANS_PPC
417 /* Update the Decrementer and Time base registers: */
418 {
419 uint32_t old = cpu->cd.ppc.spr[SPR_DEC];
420 cpu->cd.ppc.spr[SPR_DEC] = (uint32_t) (old - n_instrs);
421 if ((old >> 31) == 0 && (cpu->cd.ppc.spr[SPR_DEC] >> 31) == 1
422 && !(cpu->cd.ppc.cpu_type.flags & PPC_NO_DEC))
423 cpu->cd.ppc.dec_intr_pending = 1;
424 old = cpu->cd.ppc.spr[SPR_TBL];
425 cpu->cd.ppc.spr[SPR_TBL] += n_instrs;
426 if ((old >> 31) == 1 && (cpu->cd.ppc.spr[SPR_TBL] >> 31) == 0)
427 cpu->cd.ppc.spr[SPR_TBU] ++;
428 }
429 #endif
430
431 cpu->ninstrs += n_instrs;
432
433 /* Return the nr of instructions executed: */
434 return n_instrs;
435 }
436 #endif /* DYNTRANS_RUN_INSTR */
437
438
439
440 #ifdef DYNTRANS_FUNCTION_TRACE_DEF
441 /*
442 * XXX_cpu_functioncall_trace():
443 *
444 * Without this function, the main trace tree function prints something
445 * like <f()> or <0x1234()> on a function call. It is up to this
446 * function to print the arguments passed.
447 */
448 void DYNTRANS_FUNCTION_TRACE_DEF(struct cpu *cpu, uint64_t f, int n_args)
449 {
450 int show_symbolic_function_name = 1;
451 char strbuf[50];
452 char *symbol;
453 uint64_t ot;
454 int x, print_dots = 1, n_args_to_print =
455 #if defined(DYNTRANS_ALPHA) || defined(DYNTRANS_SPARC)
456 6
457 #else
458 #if defined(DYNTRANS_SH) || defined(DYNTRANS_M88K)
459 8 /* Both for 32-bit and 64-bit SuperH, and M88K */
460 #else
461 4 /* Default value for most archs */
462 #endif
463 #endif
464 ;
465
466 if (n_args >= 0 && n_args <= n_args_to_print) {
467 print_dots = 0;
468 n_args_to_print = n_args;
469 }
470
471 #ifdef DYNTRANS_M88K
472 /* Special hack for M88K userspace: */
473 if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE))
474 show_symbolic_function_name = 0;
475 #endif
476
477 /*
478 * TODO: The type of each argument should be taken from the symbol
479 * table, in some way.
480 *
481 * The code here does a kind of "heuristic guess" regarding what the
482 * argument values might mean. Sometimes the output looks weird, but
483 * usually it looks good enough.
484 *
485 * Print ".." afterwards to show that there might be more arguments
486 * than were passed in register.
487 */
488 for (x=0; x<n_args_to_print; x++) {
489 int64_t d = cpu->cd.DYNTRANS_ARCH.
490 #ifdef DYNTRANS_ALPHA
491 r[ALPHA_A0
492 #endif
493 #ifdef DYNTRANS_ARM
494 r[0
495 #endif
496 #ifdef DYNTRANS_AVR
497 /* TODO: 24,25 = first register, but then
498 they go downwards, ie. 22,23 and so on */
499 r[24
500 #endif
501 #ifdef DYNTRANS_MIPS
502 gpr[MIPS_GPR_A0
503 #endif
504 #ifdef DYNTRANS_M32R
505 r[0 /* r0..r3? */
506 #endif
507 #ifdef DYNTRANS_M88K
508 r[2 /* r2..r9 */
509 #endif
510 #ifdef DYNTRANS_PPC
511 gpr[3
512 #endif
513 #ifdef DYNTRANS_SH
514 r[4 /* NetBSD seems to use 4? But 2 seems
515 to be used by other code? TODO */
516 #endif
517 #ifdef DYNTRANS_SPARC
518 r[8 /* o0..o5 */
519 #endif
520 + x];
521
522 symbol = get_symbol_name(&cpu->machine->symbol_context, d, &ot);
523
524 if (d > -256 && d < 256)
525 fatal("%i", (int)d);
526 else if (memory_points_to_string(cpu, cpu->mem, d, 1))
527 fatal("\"%s\"", memory_conv_to_string(cpu,
528 cpu->mem, d, strbuf, sizeof(strbuf)));
529 else if (symbol != NULL && ot == 0 &&
530 show_symbolic_function_name)
531 fatal("&%s", symbol);
532 else {
533 if (cpu->is_32bit)
534 fatal("0x%"PRIx32, (uint32_t)d);
535 else
536 fatal("0x%"PRIx64, (uint64_t)d);
537 }
538
539 if (x < n_args_to_print - 1)
540 fatal(",");
541 }
542
543 if (print_dots)
544 fatal(",..");
545 }
546 #endif /* DYNTRANS_FUNCTION_TRACE_DEF */
547
548
549
550 #ifdef DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE_DEF
551 /*
552 * XXX_tc_allocate_default_page():
553 *
554 * Create a default page (with just pointers to instr(to_be_translated)
555 * at cpu->translation_cache_cur_ofs.
556 */
557 static void DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE_DEF(struct cpu *cpu,
558 uint64_t physaddr)
559 {
560 struct DYNTRANS_TC_PHYSPAGE *ppp;
561
562 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
563 + cpu->translation_cache_cur_ofs);
564
565 /* Copy the entire template page first: */
566 memcpy(ppp, cpu->cd.DYNTRANS_ARCH.physpage_template, sizeof(
567 struct DYNTRANS_TC_PHYSPAGE));
568
569 ppp->physaddr = physaddr & ~(DYNTRANS_PAGESIZE - 1);
570
571 cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE);
572
573 cpu->translation_cache_cur_ofs --;
574 cpu->translation_cache_cur_ofs |= 63;
575 cpu->translation_cache_cur_ofs ++;
576 }
577 #endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE_DEF */
578
579
580
581 #ifdef DYNTRANS_PC_TO_POINTERS_FUNC
582 /*
583 * XXX_pc_to_pointers_generic():
584 *
585 * Generic case. See DYNTRANS_PC_TO_POINTERS_FUNC below.
586 */
587 void DYNTRANS_PC_TO_POINTERS_GENERIC(struct cpu *cpu)
588 {
589 #ifdef MODE32
590 uint32_t
591 #else
592 uint64_t
593 #endif
594 cached_pc = cpu->pc, physaddr = 0;
595 uint32_t physpage_ofs;
596 int ok, pagenr, table_index;
597 uint32_t *physpage_entryp;
598 struct DYNTRANS_TC_PHYSPAGE *ppp;
599
600 #ifdef MODE32
601 int index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
602 #else
603 const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
604 const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
605 const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
606 uint32_t x1, x2, x3;
607 struct DYNTRANS_L2_64_TABLE *l2;
608 struct DYNTRANS_L3_64_TABLE *l3;
609
610 x1 = (cached_pc >> (64-DYNTRANS_L1N)) & mask1;
611 x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
612 x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) & mask3;
613 /* fatal("X3: cached_pc=%016"PRIx64" x1=%x x2=%x x3=%x\n",
614 (uint64_t)cached_pc, (int)x1, (int)x2, (int)x3); */
615 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
616 /* fatal(" l2 = %p\n", l2); */
617 l3 = l2->l3[x2];
618 /* fatal(" l3 = %p\n", l3); */
619 #endif
620
621 /* Virtual to physical address translation: */
622 ok = 0;
623 #ifdef MODE32
624 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) {
625 physaddr = cpu->cd.DYNTRANS_ARCH.phys_addr[index];
626 ok = 1;
627 }
628 #else
629 if (l3->host_load[x3] != NULL) {
630 physaddr = l3->phys_addr[x3];
631 ok = 1;
632 }
633 #endif
634
635 if (!ok) {
636 uint64_t paddr;
637 if (cpu->translate_v2p != NULL) {
638 uint64_t vaddr =
639 #if defined(MODE32) && defined(DYNTRANS_MIPS)
640 /* 32-bit MIPS is _sign_ extend, not zero. */
641 (int32_t)
642 #endif
643 cached_pc;
644 ok = cpu->translate_v2p(
645 cpu, vaddr, &paddr, FLAG_INSTR);
646 } else {
647 paddr = cached_pc;
648 ok = 1;
649 }
650 if (!ok) {
651 /*
652 * The PC is now set to the exception handler.
653 * Try to find the paddr in the translation arrays,
654 * or if that fails, call translate_v2p for the
655 * exception handler.
656 */
657 /* fatal("TODO: instruction vaddr=>paddr translation "
658 "failed. vaddr=0x%"PRIx64"\n", (uint64_t)cached_pc);
659 fatal("!! cpu->pc=0x%"PRIx64"\n", (uint64_t)cpu->pc); */
660
661 /* If there was an exception, the PC has changed.
662 Update cached_pc: */
663 cached_pc = cpu->pc;
664
665 #ifdef MODE32
666 index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
667 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) {
668 paddr = cpu->cd.DYNTRANS_ARCH.phys_addr[index];
669 ok = 1;
670 }
671 #else
672 x1 = (cached_pc >> (64-DYNTRANS_L1N)) & mask1;
673 x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N))
674 & mask2;
675 x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N
676 - DYNTRANS_L3N)) & mask3;
677 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
678 l3 = l2->l3[x2];
679 if (l3->host_load[x3] != NULL) {
680 paddr = l3->phys_addr[x3];
681 ok = 1;
682 }
683 #endif
684
685 if (!ok) {
686 ok = cpu->translate_v2p(cpu, cpu->pc, &paddr,
687 FLAG_INSTR);
688 }
689
690 /* printf("EXCEPTION HANDLER: vaddr = 0x%x ==> "
691 "paddr = 0x%x\n", (int)cpu->pc, (int)paddr);
692 fatal("!? cpu->pc=0x%"PRIx64"\n", (uint64_t)cpu->pc); */
693
694 if (!ok) {
695 fatal("FATAL: could not find physical"
696 " address of the exception handler?");
697 exit(1);
698 }
699 }
700
701 physaddr = paddr;
702 }
703
704 physaddr &= ~(DYNTRANS_PAGESIZE - 1);
705
706 #ifdef MODE32
707 if (cpu->cd.DYNTRANS_ARCH.host_load[index] == NULL) {
708 #else
709 if (l3->host_load[x3] == NULL) {
710 #endif
711 int q = DYNTRANS_PAGESIZE - 1;
712 unsigned char *host_page = memory_paddr_to_hostaddr(cpu->mem,
713 physaddr, MEM_READ);
714 if (host_page != NULL) {
715 cpu->update_translation_table(cpu, cached_pc & ~q,
716 host_page, 0, physaddr);
717 }
718 }
719
720 if (cpu->translation_cache_cur_ofs >= dyntrans_cache_size) {
721 #ifdef UNSTABLE_DEVEL
722 fatal("[ dyntrans: resetting the translation cache ]\n");
723 #endif
724 cpu_create_or_reset_tc(cpu);
725 }
726
727 pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr);
728 table_index = PAGENR_TO_TABLE_INDEX(pagenr);
729
730 physpage_entryp = &(((uint32_t *)cpu->translation_cache)[table_index]);
731 physpage_ofs = *physpage_entryp;
732 ppp = NULL;
733
734 /* Traverse the physical page chain: */
735 while (physpage_ofs != 0) {
736 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
737 + physpage_ofs);
738
739 /* If we found the page in the cache, then we're done: */
740 if (ppp->physaddr == physaddr)
741 break;
742
743 /* Try the next page in the chain: */
744 physpage_ofs = ppp->next_ofs;
745 }
746
747 /*
748 * If the offset is 0, then no translation exists yet for this
749 * physical address. Let's create a new page, and add it first in
750 * the chain.
751 */
752 if (physpage_ofs == 0) {
753 uint32_t previous_first_page_in_chain;
754
755 /* fatal("CREATING page %lli (physaddr 0x%"PRIx64"), table "
756 "index %i\n", (long long)pagenr, (uint64_t)physaddr,
757 (int)table_index); */
758
759 previous_first_page_in_chain = *physpage_entryp;
760
761 /* Insert the new page first in the chain: */
762 *physpage_entryp = physpage_ofs =
763 cpu->translation_cache_cur_ofs;
764
765 /* Allocate a default page, with to_be_translated entries: */
766 DYNTRANS_TC_ALLOCATE(cpu, physaddr);
767
768 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
769 + physpage_ofs);
770
771 /* Point to the other pages in the same chain: */
772 ppp->next_ofs = previous_first_page_in_chain;
773 }
774
775 /* Here, ppp points to a valid physical page struct. */
776
777 #ifdef MODE32
778 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL)
779 cpu->cd.DYNTRANS_ARCH.phys_page[index] = ppp;
780 #else
781 if (l3->host_load[x3] != NULL)
782 l3->phys_page[x3] = ppp;
783 #endif
784
785 /*
786 * If there are no translations yet on this page, then mark it
787 * as non-writable. If there are already translations, then it
788 * should already have been marked as non-writable.
789 */
790 if (ppp->translations_bitmap == 0) {
791 cpu->invalidate_translation_caches(cpu, physaddr,
792 JUST_MARK_AS_NON_WRITABLE | INVALIDATE_PADDR);
793 }
794
795 cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
796
797 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
798 DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
799
800 /* printf("cached_pc=0x%016"PRIx64" pagenr=%lli table_index=%lli, "
801 "physpage_ofs=0x%016"PRIx64"\n", (uint64_t)cached_pc, (long long)
802 pagenr, (long long)table_index, (uint64_t)physpage_ofs); */
803 }
804
805
806 /*
807 * XXX_pc_to_pointers():
808 *
809 * This function uses the current program counter (a virtual address) to
810 * find out which physical translation page to use, and then sets the current
811 * translation page pointers to that page.
812 *
813 * If there was no translation page for that physical page, then an empty
814 * one is created.
815 *
816 * NOTE: This is the quick lookup version. See
817 * DYNTRANS_PC_TO_POINTERS_GENERIC above for the generic case.
818 */
819 void DYNTRANS_PC_TO_POINTERS_FUNC(struct cpu *cpu)
820 {
821 #ifdef MODE32
822 uint32_t
823 #else
824 uint64_t
825 #endif
826 cached_pc = cpu->pc;
827 struct DYNTRANS_TC_PHYSPAGE *ppp;
828
829 #ifdef MODE32
830 int index;
831 index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
832 ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index];
833 if (ppp != NULL)
834 goto have_it;
835 #else
836 const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
837 const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
838 const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
839 uint32_t x1, x2, x3;
840 struct DYNTRANS_L2_64_TABLE *l2;
841 struct DYNTRANS_L3_64_TABLE *l3;
842
843 x1 = (cached_pc >> (64-DYNTRANS_L1N)) & mask1;
844 x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
845 x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) & mask3;
846 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
847 l3 = l2->l3[x2];
848 ppp = l3->phys_page[x3];
849 if (ppp != NULL)
850 goto have_it;
851 #endif
852
853 DYNTRANS_PC_TO_POINTERS_GENERIC(cpu);
854 return;
855
856 /* Quick return path: */
857 have_it:
858 cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
859 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
860 DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
861
862 /* printf("cached_pc=0x%016"PRIx64" pagenr=%lli table_index=%lli, "
863 "physpage_ofs=0x%016"PRIx64"\n", (uint64_t)cached_pc, (long long)
864 pagenr, (long long)table_index, (uint64_t)physpage_ofs); */
865 }
866 #endif /* DYNTRANS_PC_TO_POINTERS_FUNC */
867
868
869
870 #ifdef DYNTRANS_INIT_TABLES
871
872 /* forward declaration of to_be_translated and end_of_page: */
873 static void instr(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
874 static void instr(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
875 #ifdef DYNTRANS_DUALMODE_32
876 static void instr32(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
877 static void instr32(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
878 #endif
879
880 #ifdef DYNTRANS_DUALMODE_32
881 #define TO_BE_TRANSLATED ( cpu->is_32bit? instr32(to_be_translated) : \
882 instr(to_be_translated) )
883 #else
884 #define TO_BE_TRANSLATED ( instr(to_be_translated) )
885 #endif
886
887 #ifdef DYNTRANS_DELAYSLOT
888 static void instr(end_of_page2)(struct cpu *,struct DYNTRANS_IC *);
889 #ifdef DYNTRANS_DUALMODE_32
890 static void instr32(end_of_page2)(struct cpu *,struct DYNTRANS_IC *);
891 #endif
892 #endif
893
894 /*
895 * XXX_init_tables():
896 *
897 * Initializes the default translation page (for newly allocated pages), and
898 * for 64-bit emulation it also initializes 64-bit dummy tables and pointers.
899 */
900 void DYNTRANS_INIT_TABLES(struct cpu *cpu)
901 {
902 #ifndef MODE32
903 struct DYNTRANS_L2_64_TABLE *dummy_l2;
904 struct DYNTRANS_L3_64_TABLE *dummy_l3;
905 int x1, x2;
906 #endif
907 int i;
908 struct DYNTRANS_TC_PHYSPAGE *ppp;
909
910 CHECK_ALLOCATION(ppp = malloc(sizeof(struct DYNTRANS_TC_PHYSPAGE)));
911
912 ppp->next_ofs = 0;
913 ppp->translations_bitmap = 0;
914 ppp->translation_ranges_ofs = 0;
915 /* ppp->physaddr is filled in by the page allocator */
916
917 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
918 ppp->ics[i].f = TO_BE_TRANSLATED;
919
920 /* End-of-page: */
921 ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 0].f =
922 #ifdef DYNTRANS_DUALMODE_32
923 cpu->is_32bit? instr32(end_of_page) :
924 #endif
925 instr(end_of_page);
926
927 /* End-of-page-2, for delay-slot architectures: */
928 #ifdef DYNTRANS_DELAYSLOT
929 ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 1].f =
930 #ifdef DYNTRANS_DUALMODE_32
931 cpu->is_32bit? instr32(end_of_page2) :
932 #endif
933 instr(end_of_page2);
934 #endif
935
936 cpu->cd.DYNTRANS_ARCH.physpage_template = ppp;
937
938
939 /* Prepare 64-bit virtual address translation tables: */
940 #ifndef MODE32
941 if (cpu->is_32bit)
942 return;
943
944 dummy_l2 = zeroed_alloc(sizeof(struct DYNTRANS_L2_64_TABLE));
945 dummy_l3 = zeroed_alloc(sizeof(struct DYNTRANS_L3_64_TABLE));
946
947 cpu->cd.DYNTRANS_ARCH.l2_64_dummy = dummy_l2;
948 cpu->cd.DYNTRANS_ARCH.l3_64_dummy = dummy_l3;
949
950 for (x1 = 0; x1 < (1 << DYNTRANS_L1N); x1 ++)
951 cpu->cd.DYNTRANS_ARCH.l1_64[x1] = dummy_l2;
952
953 for (x2 = 0; x2 < (1 << DYNTRANS_L2N); x2 ++)
954 dummy_l2->l3[x2] = dummy_l3;
955 #endif
956 }
957 #endif /* DYNTRANS_INIT_TABLES */
958
959
960
961 #ifdef DYNTRANS_INVAL_ENTRY
962 /*
963 * XXX_invalidate_tlb_entry():
964 *
965 * Invalidate one translation entry (based on virtual address).
966 *
967 * If the JUST_MARK_AS_NON_WRITABLE flag is set, then the translation entry
968 * is just downgraded to non-writable (ie the host store page is set to
969 * NULL). Otherwise, the entire translation is removed.
970 */
971 static void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu,
972 #ifdef MODE32
973 uint32_t
974 #else
975 uint64_t
976 #endif
977 vaddr_page, int flags)
978 {
979 #ifdef MODE32
980 uint32_t index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
981
982 #ifdef DYNTRANS_ARM
983 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5] &= ~(1 << (index & 31));
984 #endif
985
986 if (flags & JUST_MARK_AS_NON_WRITABLE) {
987 /* printf("JUST MARKING NON-W: vaddr 0x%08x\n",
988 (int)vaddr_page); */
989 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
990 } else {
991 int tlbi = cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index];
992 cpu->cd.DYNTRANS_ARCH.host_load[index] = NULL;
993 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
994 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = 0;
995 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
996 if (tlbi > 0)
997 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[tlbi-1].valid = 0;
998 cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = 0;
999 }
1000 #else
1001 const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
1002 const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
1003 const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
1004 uint32_t x1, x2, x3;
1005 struct DYNTRANS_L2_64_TABLE *l2;
1006 struct DYNTRANS_L3_64_TABLE *l3;
1007
1008 x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1;
1009 x2 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
1010 x3 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N))& mask3;
1011
1012 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1013 if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy)
1014 return;
1015
1016 l3 = l2->l3[x2];
1017 if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy)
1018 return;
1019
1020 if (flags & JUST_MARK_AS_NON_WRITABLE) {
1021 l3->host_store[x3] = NULL;
1022 return;
1023 }
1024
1025 #ifdef BUGHUNT
1026
1027 {
1028 /* Consistency check, for debugging: */
1029 int x1, x1b; // x2, x3;
1030 struct DYNTRANS_L2_64_TABLE *l2;
1031 //struct DYNTRANS_L3_64_TABLE *l3;
1032
1033 for (x1 = 0; x1 <= mask1; x1 ++) {
1034 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1035 if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy)
1036 continue;
1037 /* Make sure that this l2 isn't used more than 1 time! */
1038 for (x1b = 0; x1b <= mask1; x1b ++)
1039 if (x1 != x1b &&
1040 l2 == cpu->cd.DYNTRANS_ARCH.l1_64[x1b]) {
1041 fatal("L2 reuse: %p\n", l2);
1042 exit(1);
1043 }
1044 }
1045 }
1046
1047 /* Count how many pages are actually in use: */
1048 {
1049 int n=0, i;
1050 for (i=0; i<=mask3; i++)
1051 if (l3->vaddr_to_tlbindex[i])
1052 n++;
1053 if (n != l3->refcount) {
1054 printf("Z: %i in use, but refcount = %i!\n", n, l3->refcount);
1055 exit(1);
1056 }
1057
1058 n = 0;
1059 for (i=0; i<=mask3; i++)
1060 if (l3->host_load[i] != NULL)
1061 n++;
1062 if (n != l3->refcount) {
1063 printf("ZHL: %i in use, but refcount = %i!\n", n, l3->refcount);
1064 exit(1);
1065 }
1066 }
1067 #endif
1068
1069 l3->host_load[x3] = NULL;
1070 l3->host_store[x3] = NULL;
1071 l3->phys_addr[x3] = 0;
1072 l3->phys_page[x3] = NULL;
1073 if (l3->vaddr_to_tlbindex[x3] != 0) {
1074 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[
1075 l3->vaddr_to_tlbindex[x3] - 1].valid = 0;
1076 l3->refcount --;
1077 }
1078 l3->vaddr_to_tlbindex[x3] = 0;
1079
1080 if (l3->refcount < 0) {
1081 fatal("xxx_invalidate_tlb_entry(): huh? Refcount bug.\n");
1082 exit(1);
1083 }
1084
1085 if (l3->refcount == 0) {
1086 l3->next = cpu->cd.DYNTRANS_ARCH.next_free_l3;
1087 cpu->cd.DYNTRANS_ARCH.next_free_l3 = l3;
1088 l2->l3[x2] = cpu->cd.DYNTRANS_ARCH.l3_64_dummy;
1089
1090 #ifdef BUGHUNT
1091 /* Make sure that we're placing a CLEAN page on the
1092 freelist: */
1093 {
1094 int i;
1095 for (i=0; i<=mask3; i++)
1096 if (l3->host_load[i] != NULL) {
1097 fatal("TRYING TO RETURN A NON-CLEAN L3 PAGE!\n");
1098 exit(1);
1099 }
1100 }
1101 #endif
1102 l2->refcount --;
1103 if (l2->refcount < 0) {
1104 fatal("xxx_invalidate_tlb_entry(): Refcount bug L2.\n");
1105 exit(1);
1106 }
1107 if (l2->refcount == 0) {
1108 l2->next = cpu->cd.DYNTRANS_ARCH.next_free_l2;
1109 cpu->cd.DYNTRANS_ARCH.next_free_l2 = l2;
1110 cpu->cd.DYNTRANS_ARCH.l1_64[x1] =
1111 cpu->cd.DYNTRANS_ARCH.l2_64_dummy;
1112 }
1113 }
1114 #endif
1115 }
1116 #endif
1117
1118
1119 #ifdef DYNTRANS_INVALIDATE_TC
1120 /*
1121 * XXX_invalidate_translation_caches():
1122 *
1123 * Invalidate all entries matching a specific physical address, a specific
1124 * virtual address, or ALL entries.
1125 *
1126 * flags should be one of
1127 * INVALIDATE_PADDR INVALIDATE_VADDR or INVALIDATE_ALL
1128 *
1129 * In addition, for INVALIDATE_ALL, INVALIDATE_VADDR_UPPER4 may be set and
1130 * bit 31..28 of addr are used to select the virtual addresses to invalidate.
1131 * (This is useful for PowerPC emulation, when segment registers are updated.)
1132 *
1133 * In the case when all translations are invalidated, paddr doesn't need
1134 * to be supplied.
1135 *
1136 * NOTE/TODO: When invalidating a virtual address, it is only cleared from
1137 * the quick translation array, not from the linear
1138 * vph_tlb_entry[] array. Hopefully this is enough anyway.
1139 */
1140 void DYNTRANS_INVALIDATE_TC(struct cpu *cpu, uint64_t addr, int flags)
1141 {
1142 int r;
1143 #ifdef MODE32
1144 uint32_t
1145 #else
1146 uint64_t
1147 #endif
1148 addr_page = addr & ~(DYNTRANS_PAGESIZE - 1);
1149
1150 /* fatal("invalidate(): "); */
1151
1152 /* Quick case for _one_ virtual addresses: see note above. */
1153 if (flags & INVALIDATE_VADDR) {
1154 /* fatal("vaddr 0x%08x\n", (int)addr_page); */
1155 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, addr_page, flags);
1156 return;
1157 }
1158
1159 /* Invalidate everything: */
1160 #ifdef DYNTRANS_PPC
1161 if (flags & INVALIDATE_ALL && flags & INVALIDATE_VADDR_UPPER4) {
1162 /* fatal("all, upper4 (PowerPC segment)\n"); */
1163 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
1164 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid &&
1165 (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page
1166 & 0xf0000000) == addr_page) {
1167 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd.
1168 DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
1169 0);
1170 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid=0;
1171 }
1172 }
1173 return;
1174 }
1175 #endif
1176 if (flags & INVALIDATE_ALL) {
1177 /* fatal("all\n"); */
1178 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
1179 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
1180 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd.
1181 DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
1182 0);
1183 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid=0;
1184 }
1185 }
1186 return;
1187 }
1188
1189 /* Invalidate a physical page: */
1190
1191 if (!(flags & INVALIDATE_PADDR))
1192 fatal("HUH? Invalidate: Not vaddr, all, or paddr?\n");
1193
1194 /* fatal("addr 0x%08x\n", (int)addr_page); */
1195
1196 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
1197 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && addr_page
1198 == cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page) {
1199 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
1200 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
1201 flags);
1202 if (flags & JUST_MARK_AS_NON_WRITABLE)
1203 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
1204 .writeflag = 0;
1205 else
1206 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
1207 .valid = 0;
1208 }
1209 }
1210 }
1211 #endif /* DYNTRANS_INVALIDATE_TC */
1212
1213
1214
1215 #ifdef DYNTRANS_INVALIDATE_TC_CODE
1216 /*
1217 * XXX_invalidate_code_translation():
1218 *
1219 * Invalidate code translations for a specific physical address, a specific
1220 * virtual address, or for all entries in the cache.
1221 */
1222 void DYNTRANS_INVALIDATE_TC_CODE(struct cpu *cpu, uint64_t addr, int flags)
1223 {
1224 int r;
1225 #ifdef MODE32
1226 uint32_t
1227 #else
1228 uint64_t
1229 #endif
1230 vaddr_page, paddr_page;
1231
1232 addr &= ~(DYNTRANS_PAGESIZE-1);
1233
1234 /* printf("DYNTRANS_INVALIDATE_TC_CODE addr=0x%08x flags=%i\n",
1235 (int)addr, flags); */
1236
1237 if (flags & INVALIDATE_PADDR) {
1238 int pagenr, table_index;
1239 uint32_t physpage_ofs, *physpage_entryp;
1240 struct DYNTRANS_TC_PHYSPAGE *ppp, *prev_ppp;
1241
1242 pagenr = DYNTRANS_ADDR_TO_PAGENR(addr);
1243 table_index = PAGENR_TO_TABLE_INDEX(pagenr);
1244
1245 physpage_entryp = &(((uint32_t *)cpu->
1246 translation_cache)[table_index]);
1247 physpage_ofs = *physpage_entryp;
1248
1249 /* Return immediately if there is no code translation
1250 for this page. */
1251 if (physpage_ofs == 0)
1252 return;
1253
1254 prev_ppp = ppp = NULL;
1255
1256 /* Traverse the physical page chain: */
1257 while (physpage_ofs != 0) {
1258 prev_ppp = ppp;
1259 ppp = (struct DYNTRANS_TC_PHYSPAGE *)
1260 (cpu->translation_cache + physpage_ofs);
1261
1262 /* If we found the page in the cache,
1263 then we're done: */
1264 if (ppp->physaddr == addr)
1265 break;
1266
1267 /* Try the next page in the chain: */
1268 physpage_ofs = ppp->next_ofs;
1269 }
1270
1271 /* If there is no translation, there is no need to go
1272 on and try to remove it from the vph_tlb_entry array: */
1273 if (physpage_ofs == 0)
1274 return;
1275
1276 #if 0
1277 /*
1278 * "Bypass" the page, removing it from the code cache.
1279 *
1280 * NOTE/TODO: This gives _TERRIBLE_ performance with self-
1281 * modifying code, or when a single page is used for both
1282 * code and (writable) data.
1283 */
1284 if (ppp != NULL) {
1285 if (prev_ppp != NULL)
1286 prev_ppp->next_ofs = ppp->next_ofs;
1287 else
1288 *physpage_entryp = ppp->next_ofs;
1289 }
1290 #else
1291 /*
1292 * Instead of removing the page from the code cache, each
1293 * entry can be set to "to_be_translated". This is slow in
1294 * the general case, but in the case of self-modifying code,
1295 * it might be faster since we don't risk wasting cache
1296 * memory as quickly (which would force unnecessary Restarts).
1297 */
1298 if (ppp != NULL && ppp->translations_bitmap != 0) {
1299 uint32_t x = ppp->translations_bitmap; /* TODO:
1300 urk Should be same type as the bitmap */
1301 int i, j, n, m;
1302 n = 8 * sizeof(x);
1303 m = DYNTRANS_IC_ENTRIES_PER_PAGE / n;
1304
1305 for (i=0; i<n; i++) {
1306 if (x & 1) {
1307 for (j=0; j<m; j++)
1308 ppp->ics[i*m + j].f =
1309 TO_BE_TRANSLATED;
1310 }
1311
1312 x >>= 1;
1313 }
1314
1315 ppp->translations_bitmap = 0;
1316
1317 /* Clear the list of translatable ranges: */
1318 if (ppp->translation_ranges_ofs != 0) {
1319 struct physpage_ranges *physpage_ranges =
1320 (struct physpage_ranges *)
1321 (cpu->translation_cache +
1322 ppp->translation_ranges_ofs);
1323 physpage_ranges->next_ofs = 0;
1324 physpage_ranges->n_entries_used = 0;
1325 }
1326 }
1327 #endif
1328 }
1329
1330 /* Invalidate entries in the VPH table: */
1331 for (r = 0; r < DYNTRANS_MAX_VPH_TLB_ENTRIES; r ++) {
1332 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
1333 vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
1334 .vaddr_page & ~(DYNTRANS_PAGESIZE-1);
1335 paddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
1336 .paddr_page & ~(DYNTRANS_PAGESIZE-1);
1337
1338 if (flags & INVALIDATE_ALL ||
1339 (flags & INVALIDATE_PADDR && paddr_page == addr) ||
1340 (flags & INVALIDATE_VADDR && vaddr_page == addr)) {
1341 #ifdef MODE32
1342 uint32_t index =
1343 DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1344 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1345 #else
1346 const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
1347 const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
1348 const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
1349 uint32_t x1, x2, x3;
1350 struct DYNTRANS_L2_64_TABLE *l2;
1351 struct DYNTRANS_L3_64_TABLE *l3;
1352
1353 x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1;
1354 x2 = (vaddr_page >> (64-DYNTRANS_L1N -
1355 DYNTRANS_L2N)) & mask2;
1356 x3 = (vaddr_page >> (64-DYNTRANS_L1N -
1357 DYNTRANS_L2N - DYNTRANS_L3N)) & mask3;
1358 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1359 l3 = l2->l3[x2];
1360 l3->phys_page[x3] = NULL;
1361 #endif
1362 }
1363 }
1364 }
1365 }
1366 #endif /* DYNTRANS_INVALIDATE_TC_CODE */
1367
1368
1369
1370 #ifdef DYNTRANS_UPDATE_TRANSLATION_TABLE
1371 /*
1372 * XXX_update_translation_table():
1373 *
1374 * Update the virtual memory translation tables.
1375 */
1376 void DYNTRANS_UPDATE_TRANSLATION_TABLE(struct cpu *cpu, uint64_t vaddr_page,
1377 unsigned char *host_page, int writeflag, uint64_t paddr_page)
1378 {
1379 int found, r, useraccess = 0;
1380
1381 #ifdef MODE32
1382 uint32_t index;
1383 vaddr_page &= 0xffffffffULL;
1384
1385 if (paddr_page > 0xffffffffULL) {
1386 fatal("update_translation_table(): v=0x%016"PRIx64", h=%p w=%i"
1387 " p=0x%016"PRIx64"\n", vaddr_page, host_page, writeflag,
1388 paddr_page);
1389 exit(1);
1390 }
1391
1392 /* fatal("update_translation_table(): v=0x%x, h=%p w=%i"
1393 " p=0x%x\n", (int)vaddr_page, host_page, writeflag,
1394 (int)paddr_page); */
1395 #else /* !MODE32 */
1396 const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1;
1397 const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1;
1398 const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1;
1399 uint32_t x1, x2, x3;
1400 struct DYNTRANS_L2_64_TABLE *l2;
1401 struct DYNTRANS_L3_64_TABLE *l3;
1402
1403 /* fatal("update_translation_table(): v=0x%016"PRIx64", h=%p w=%i"
1404 " p=0x%016"PRIx64"\n", (uint64_t)vaddr_page, host_page, writeflag,
1405 (uint64_t)paddr_page); */
1406 #endif
1407
1408 assert((vaddr_page & (DYNTRANS_PAGESIZE-1)) == 0);
1409 assert((paddr_page & (DYNTRANS_PAGESIZE-1)) == 0);
1410
1411 if (writeflag & MEMORY_USER_ACCESS) {
1412 writeflag &= ~MEMORY_USER_ACCESS;
1413 useraccess = 1;
1414 }
1415
1416 #ifdef DYNTRANS_M88K
1417 /* TODO */
1418 if (useraccess)
1419 return;
1420 #endif
1421
1422 /* Scan the current TLB entries: */
1423
1424 #ifdef MODE32
1425 /*
1426 * NOTE 1: vaddr_to_tlbindex is one more than the index, so that
1427 * 0 becomes -1, which means a miss.
1428 *
1429 * NOTE 2: When a miss occurs, instead of scanning the entire tlb
1430 * for the entry with the lowest time stamp, just choosing
1431 * one at random will work as well.
1432 */
1433 found = (int)cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[
1434 DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1;
1435 #else
1436 x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1;
1437 x2 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
1438 x3 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N))
1439 & mask3;
1440
1441 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1442 if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy)
1443 found = -1;
1444 else {
1445 l3 = l2->l3[x2];
1446 if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy)
1447 found = -1;
1448 else
1449 found = (int)l3->vaddr_to_tlbindex[x3] - 1;
1450 }
1451 #endif
1452
1453 if (found < 0) {
1454 /* Create the new TLB entry, overwriting a "random" entry: */
1455 static unsigned int x = 0;
1456 r = (x++) % DYNTRANS_MAX_VPH_TLB_ENTRIES;
1457
1458 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
1459 /* This one has to be invalidated first: */
1460 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
1461 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
1462 0);
1463 }
1464
1465 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid = 1;
1466 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].host_page = host_page;
1467 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page = paddr_page;
1468 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page;
1469 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag =
1470 writeflag & MEM_WRITE;
1471
1472 /* Add the new translation to the table: */
1473 #ifdef MODE32
1474 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1475 cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
1476 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1477 writeflag? host_page : NULL;
1478 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
1479 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1480 cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = r + 1;
1481 #ifdef DYNTRANS_ARM
1482 if (useraccess)
1483 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5]
1484 |= 1 << (index & 31);
1485 #endif
1486 #else /* !MODE32 */
1487 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1488 if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) {
1489 if (cpu->cd.DYNTRANS_ARCH.next_free_l2 != NULL) {
1490 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1] =
1491 cpu->cd.DYNTRANS_ARCH.next_free_l2;
1492 cpu->cd.DYNTRANS_ARCH.next_free_l2 = l2->next;
1493 } else {
1494 int i;
1495 CHECK_ALLOCATION(l2 =
1496 cpu->cd.DYNTRANS_ARCH.l1_64[x1] = malloc(
1497 sizeof(struct DYNTRANS_L2_64_TABLE)));
1498 l2->refcount = 0;
1499 for (i=0; i<(1 << DYNTRANS_L2N); i++)
1500 l2->l3[i] = cpu->cd.DYNTRANS_ARCH.
1501 l3_64_dummy;
1502 }
1503 if (l2->refcount != 0) {
1504 fatal("Huh? l2 Refcount problem.\n");
1505 exit(1);
1506 }
1507 }
1508 if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) {
1509 fatal("INTERNAL ERROR L2 reuse\n");
1510 exit(1);
1511 }
1512 l3 = l2->l3[x2];
1513 if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy) {
1514 if (cpu->cd.DYNTRANS_ARCH.next_free_l3 != NULL) {
1515 l3 = l2->l3[x2] =
1516 cpu->cd.DYNTRANS_ARCH.next_free_l3;
1517 cpu->cd.DYNTRANS_ARCH.next_free_l3 = l3->next;
1518 } else {
1519 l3 = l2->l3[x2] = zeroed_alloc(sizeof(
1520 struct DYNTRANS_L3_64_TABLE));
1521 }
1522 if (l3->refcount != 0) {
1523 fatal("Huh? l3 Refcount problem.\n");
1524 exit(1);
1525 }
1526 l2->refcount ++;
1527 }
1528 if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy) {
1529 fatal("INTERNAL ERROR L3 reuse\n");
1530 exit(1);
1531 }
1532
1533 l3->host_load[x3] = host_page;
1534 l3->host_store[x3] = writeflag? host_page : NULL;
1535 l3->phys_addr[x3] = paddr_page;
1536 l3->phys_page[x3] = NULL;
1537 l3->vaddr_to_tlbindex[x3] = r + 1;
1538 l3->refcount ++;
1539
1540 #ifdef BUGHUNT
1541 /* Count how many pages are actually in use: */
1542 {
1543 int n=0, i;
1544 for (i=0; i<=mask3; i++)
1545 if (l3->vaddr_to_tlbindex[i])
1546 n++;
1547 if (n != l3->refcount) {
1548 printf("X: %i in use, but refcount = %i!\n", n, l3->refcount);
1549 exit(1);
1550 }
1551
1552 n = 0;
1553 for (i=0; i<=mask3; i++)
1554 if (l3->host_load[i] != NULL)
1555 n++;
1556 if (n != l3->refcount) {
1557 printf("XHL: %i in use, but refcount = %i!\n", n, l3->refcount);
1558 exit(1);
1559 }
1560 }
1561 #endif
1562
1563 #endif /* !MODE32 */
1564 } else {
1565 /*
1566 * The translation was already in the TLB.
1567 * Writeflag = 0: Do nothing.
1568 * Writeflag = 1: Make sure the page is writable.
1569 * Writeflag = MEM_DOWNGRADE: Downgrade to readonly.
1570 */
1571 r = found;
1572 if (writeflag & MEM_WRITE)
1573 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1;
1574 if (writeflag & MEM_DOWNGRADE)
1575 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 0;
1576 #ifdef MODE32
1577 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1578 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1579 #ifdef DYNTRANS_ARM
1580 cpu->cd.DYNTRANS_ARCH.is_userpage[index>>5] &= ~(1<<(index&31));
1581 if (useraccess)
1582 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5]
1583 |= 1 << (index & 31);
1584 #endif
1585 if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) {
1586 if (writeflag & MEM_WRITE)
1587 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1588 host_page;
1589 if (writeflag & MEM_DOWNGRADE)
1590 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
1591 } else {
1592 /* Change the entire physical/host mapping: */
1593 cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
1594 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1595 writeflag? host_page : NULL;
1596 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
1597 }
1598 #else /* !MODE32 */
1599 x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1;
1600 x2 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2;
1601 x3 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N))
1602 & mask3;
1603 l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1];
1604 l3 = l2->l3[x2];
1605 if (l3->phys_addr[x3] == paddr_page) {
1606 if (writeflag & MEM_WRITE)
1607 l3->host_store[x3] = host_page;
1608 if (writeflag & MEM_DOWNGRADE)
1609 l3->host_store[x3] = NULL;
1610 } else {
1611 /* Change the entire physical/host mapping: */
1612 printf("HOST LOAD 2 set to %p\n", host_page);
1613 l3->host_load[x3] = host_page;
1614 l3->host_store[x3] = writeflag? host_page : NULL;
1615 l3->phys_addr[x3] = paddr_page;
1616 }
1617
1618 #ifdef BUGHUNT
1619 /* Count how many pages are actually in use: */
1620 {
1621 int n=0, i;
1622 for (i=0; i<=mask3; i++)
1623 if (l3->vaddr_to_tlbindex[i])
1624 n++;
1625 if (n != l3->refcount) {
1626 printf("Y: %i in use, but refcount = %i!\n", n, l3->refcount);
1627 exit(1);
1628 }
1629
1630 n = 0;
1631 for (i=0; i<=mask3; i++)
1632 if (l3->host_load[i] != NULL)
1633 n++;
1634 if (n != l3->refcount) {
1635 printf("YHL: %i in use, but refcount = %i!\n", n, l3->refcount);
1636 printf("Entry r = %i\n", r);
1637 printf("Valid = %i\n",
1638 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid);
1639 exit(1);
1640 }
1641 }
1642 #endif
1643
1644 #endif /* !MODE32 */
1645 }
1646 }
1647 #endif /* DYNTRANS_UPDATE_TRANSLATION_TABLE */
1648
1649
1650 /*****************************************************************************/
1651
1652
1653 #ifdef DYNTRANS_TO_BE_TRANSLATED_HEAD
1654 /*
1655 * Check for breakpoints.
1656 */
1657 if (!single_step_breakpoint && !cpu->translation_readahead) {
1658 MODE_uint_t curpc = cpu->pc;
1659 int i;
1660 for (i=0; i<cpu->machine->breakpoints.n; i++)
1661 if (curpc == (MODE_uint_t)
1662 cpu->machine->breakpoints.addr[i]) {
1663 if (!cpu->machine->instruction_trace) {
1664 int old_quiet_mode = quiet_mode;
1665 quiet_mode = 0;
1666 DISASSEMBLE(cpu, ib, 1, 0);
1667 quiet_mode = old_quiet_mode;
1668 }
1669 #ifdef MODE32
1670 fatal("BREAKPOINT: pc = 0x%"PRIx32"\n(The "
1671 "instruction has not yet executed.)\n",
1672 (uint32_t)cpu->pc);
1673 #else
1674 fatal("BREAKPOINT: pc = 0x%"PRIx64"\n(The "
1675 "instruction has not yet executed.)\n",
1676 (uint64_t)cpu->pc);
1677 #endif
1678 #ifdef DYNTRANS_DELAYSLOT
1679 if (cpu->delay_slot != NOT_DELAYED)
1680 fatal("ERROR! Breakpoint in a delay"
1681 " slot! Not yet supported.\n");
1682 #endif
1683 single_step_breakpoint = 1;
1684 single_step = ENTER_SINGLE_STEPPING;
1685 goto stop_running_translated;
1686 }
1687 }
1688 #endif /* DYNTRANS_TO_BE_TRANSLATED_HEAD */
1689
1690
1691 /*****************************************************************************/
1692
1693
1694 #ifdef DYNTRANS_TO_BE_TRANSLATED_TAIL
1695 /*
1696 * If we end up here, then an instruction was translated. Let's mark
1697 * the page as containing a translation at this part of the page.
1698 */
1699
1700 /* Make sure cur_physpage is in synch: */
1701 cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
1702 cpu->cd.DYNTRANS_ARCH.cur_ic_page;
1703
1704 {
1705 int x = addr & (DYNTRANS_PAGESIZE - 1);
1706 int addr_per_translation_range = DYNTRANS_PAGESIZE / (8 *
1707 sizeof(cpu->cd.DYNTRANS_ARCH.cur_physpage->
1708 translations_bitmap));
1709 x /= addr_per_translation_range;
1710
1711 cpu->cd.DYNTRANS_ARCH.cur_physpage->
1712 translations_bitmap |= (1 << x);
1713 }
1714
1715
1716 /*
1717 * Now it is time to check for combinations of instructions that can
1718 * be converted into a single function call.
1719 *
1720 * Note: Single-stepping or instruction tracing doesn't work with
1721 * instruction combinations. For architectures with delay slots,
1722 * we also ignore combinations if the delay slot is across a page
1723 * boundary.
1724 */
1725 if (!single_step && !cpu->machine->instruction_trace
1726 #ifdef DYNTRANS_DELAYSLOT
1727 && !in_crosspage_delayslot
1728 #endif
1729 && cpu->cd.DYNTRANS_ARCH.combination_check != NULL
1730 && cpu->machine->allow_instruction_combinations) {
1731 cpu->cd.DYNTRANS_ARCH.combination_check(cpu, ic,
1732 addr & (DYNTRANS_PAGESIZE - 1));
1733 }
1734
1735 cpu->cd.DYNTRANS_ARCH.combination_check = NULL;
1736
1737 /* An additional check, to catch some bugs: */
1738 if (ic->f == TO_BE_TRANSLATED) {
1739 fatal("INTERNAL ERROR: ic->f not set!\n");
1740 goto bad;
1741 }
1742 if (ic->f == NULL) {
1743 fatal("INTERNAL ERROR: ic->f == NULL!\n");
1744 goto bad;
1745 }
1746
1747
1748 /*
1749 * ... and finally execute the translated instruction:
1750 */
1751
1752 /* (Except when doing read-ahead!) */
1753 if (cpu->translation_readahead)
1754 return;
1755
1756 /*
1757 * Special case when single-stepping: Execute the translated
1758 * instruction, but then replace it with a "to be translated"
1759 * directly afterwards.
1760 */
1761 if ((single_step_breakpoint && cpu->delay_slot == NOT_DELAYED)
1762 #ifdef DYNTRANS_DELAYSLOT
1763 || in_crosspage_delayslot
1764 #endif
1765 ) {
1766 single_step_breakpoint = 0;
1767 ic->f(cpu, ic);
1768 ic->f = TO_BE_TRANSLATED;
1769 return;
1770 }
1771
1772 /* Translation read-ahead: */
1773 if (!single_step && !cpu->machine->instruction_trace) {
1774 uint64_t baseaddr = cpu->pc;
1775 uint64_t pagenr = DYNTRANS_ADDR_TO_PAGENR(baseaddr);
1776 int i = 1;
1777
1778 cpu->translation_readahead = MAX_DYNTRANS_READAHEAD;
1779
1780 while (DYNTRANS_ADDR_TO_PAGENR(baseaddr +
1781 (i << DYNTRANS_INSTR_ALIGNMENT_SHIFT)) == pagenr &&
1782 cpu->translation_readahead > 0) {
1783 void (*old_f)(struct cpu *,
1784 struct DYNTRANS_IC *) = ic[i].f;
1785
1786 /* Already translated? Then abort: */
1787 if (old_f != TO_BE_TRANSLATED)
1788 break;
1789
1790 /* Translate the instruction: */
1791 ic[i].f(cpu, ic+i);
1792
1793 /* Translation failed? Then abort. */
1794 if (ic[i].f == old_f)
1795 break;
1796
1797 cpu->translation_readahead --;
1798 ++i;
1799 }
1800
1801 cpu->translation_readahead = 0;
1802 }
1803
1804
1805 /*
1806 * Finally finally :-), execute the instruction.
1807 *
1808 * Note: The instruction might have changed during read-ahead, if
1809 * instruction combinations are used.
1810 */
1811
1812 ic->f(cpu, ic);
1813
1814 return;
1815
1816
1817 bad: /*
1818 * Nothing was translated. (Unimplemented or illegal instruction.)
1819 */
1820
1821 /* Clear the translation, in case it was "half-way" done: */
1822 ic->f = TO_BE_TRANSLATED;
1823
1824 if (cpu->translation_readahead)
1825 return;
1826
1827 quiet_mode = 0;
1828 fatal("to_be_translated(): TODO: unimplemented instruction");
1829
1830 if (cpu->machine->instruction_trace) {
1831 if (cpu->is_32bit)
1832 fatal(" at 0x%"PRIx32"\n", (uint32_t)cpu->pc);
1833 else
1834 fatal(" at 0x%"PRIx64"\n", (uint64_t)cpu->pc);
1835 } else {
1836 fatal(":\n");
1837 DISASSEMBLE(cpu, ib, 1, 0);
1838 }
1839
1840 cpu->running = 0;
1841
1842 /* Note: Single-stepping can jump here. */
1843 stop_running_translated:
1844
1845 debugger_n_steps_left_before_interaction = 0;
1846
1847 ic = cpu->cd.DYNTRANS_ARCH.next_ic = &nothing_call;
1848 cpu->cd.DYNTRANS_ARCH.next_ic ++;
1849
1850 #ifdef DYNTRANS_DELAYSLOT
1851 /* Special hack: If the bad instruction was in a delay slot,
1852 make sure that execution does not continue anyway: */
1853 if (cpu->delay_slot)
1854 cpu->delay_slot |= EXCEPTION_IN_DELAY_SLOT;
1855 #endif
1856
1857 /* Execute the "nothing" instruction: */
1858 ic->f(cpu, ic);
1859
1860 #endif /* DYNTRANS_TO_BE_TRANSLATED_TAIL */
1861

  ViewVC Help
Powered by ViewVC 1.1.26