/[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 18 - (show annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 37289 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


1 /*
2 * Copyright (C) 2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_dyntrans.c,v 1.27 2005/10/27 14:01:13 debug Exp $
29 *
30 * Common dyntrans routines. Included from cpu_*.c.
31 */
32
33
34 #ifdef DYNTRANS_CPU_RUN_INSTR
35 static void gather_statistics(struct cpu *cpu)
36 {
37 uint64_t a;
38 int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t)
39 cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC);
40 if (low_pc < 0 || low_pc >= DYNTRANS_IC_ENTRIES_PER_PAGE)
41 return;
42
43 #if 1
44 /* Use the physical address: */
45 cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
46 cpu->cd.DYNTRANS_ARCH.cur_ic_page;
47 a = cpu->cd.DYNTRANS_ARCH.cur_physpage->physaddr;
48 #else
49 /* Use the PC (virtual address): */
50 a = cpu->pc;
51 #endif
52
53 a &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
54 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
55 a += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT;
56
57 /*
58 * TODO: Everything below this line should be cleaned up :-)
59 */
60 a &= 0x03ffffff;
61 {
62 static long long *array = NULL;
63 static char *array_16kpage_in_use = NULL;
64 static int n = 0;
65 a >>= DYNTRANS_INSTR_ALIGNMENT_SHIFT;
66 if (array == NULL)
67 array = zeroed_alloc(sizeof(long long) * 16384*1024);
68 if (array_16kpage_in_use == NULL)
69 array_16kpage_in_use = zeroed_alloc(sizeof(char) * 1024);
70 a &= (16384*1024-1);
71 array[a] ++;
72 array_16kpage_in_use[a / 16384] = 1;
73 n++;
74 if ((n & 0x3fffffff) == 0) {
75 FILE *f = fopen("statistics.out", "w");
76 int i, j;
77 printf("Saving statistics... "); fflush(stdout);
78 for (i=0; i<1024; i++)
79 if (array_16kpage_in_use[i]) {
80 for (j=0; j<16384; j++)
81 if (array[i*16384 + j] > 0)
82 fprintf(f, "%lli\t0x%016llx\n",
83 (long long)array[i*16384+j],
84 (long long)((i*16384+j) <<
85 DYNTRANS_INSTR_ALIGNMENT_SHIFT));
86 }
87 fclose(f);
88 printf("n=0x%08x\n", n);
89 }
90 }
91 }
92
93
94 #define S gather_statistics(cpu)
95
96 #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
97 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic; ic->f(cpu, ic);
98 #else
99 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic);
100 #endif
101
102
103 /*
104 * XXX_cpu_run_instr():
105 *
106 * Execute one or more instructions on a specific CPU, using dyntrans.
107 *
108 * Return value is the number of instructions executed during this call,
109 * 0 if no instructions were executed.
110 */
111 int DYNTRANS_CPU_RUN_INSTR(struct emul *emul, struct cpu *cpu)
112 {
113 #ifdef MODE32
114 uint32_t cached_pc;
115 #else
116 uint64_t cached_pc;
117 #endif
118 int low_pc, n_instrs;
119
120 #ifdef DYNTRANS_DUALMODE_32
121 if (cpu->is_32bit)
122 DYNTRANS_PC_TO_POINTERS32(cpu);
123 else
124 #endif
125 DYNTRANS_PC_TO_POINTERS(cpu);
126
127 /*
128 * Interrupt assertion? (This is _below_ the initial PC to pointer
129 * conversion; if the conversion caused an exception of some kind
130 * then interrupts are probably disabled, and the exception will get
131 * priority over device interrupts.)
132 */
133 #ifdef DYNTRANS_ARM
134 if (cpu->cd.arm.irq_asserted && !(cpu->cd.arm.cpsr & ARM_FLAG_I))
135 arm_exception(cpu, ARM_EXCEPTION_IRQ);
136 #endif
137
138 cached_pc = cpu->pc;
139
140 cpu->n_translated_instrs = 0;
141 cpu->running_translated = 1;
142
143 cpu->cd.DYNTRANS_ARCH.cur_physpage = (void *)
144 cpu->cd.DYNTRANS_ARCH.cur_ic_page;
145
146 if (single_step || cpu->machine->instruction_trace) {
147 /*
148 * Single-step:
149 */
150 struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic
151 #ifndef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
152 ++
153 #endif
154 ;
155 if (cpu->machine->instruction_trace) {
156 #ifdef DYNTRANS_X86
157 unsigned char instr[17];
158 cpu->cd.x86.cursegment = X86_S_CS;
159 cpu->cd.x86.seg_override = 0;
160 #else
161 #ifdef DYNTRANS_M68K
162 unsigned char instr[16]; /* TODO: 16? */
163 #else
164 unsigned char instr[4]; /* General case... */
165 #endif
166 #endif
167 if (!cpu->memory_rw(cpu, cpu->mem, cached_pc, &instr[0],
168 sizeof(instr), MEM_READ, CACHE_INSTRUCTION)) {
169 fatal("XXX_cpu_run_instr(): could not read "
170 "the instruction\n");
171 } else
172 cpu_disassemble_instr(cpu->machine, cpu,
173 instr, 1, 0, 0);
174 }
175
176 /* When single-stepping, multiple instruction calls cannot
177 be combined into one. This clears all translations: */
178 if (cpu->cd.DYNTRANS_ARCH.cur_physpage->flags & COMBINATIONS) {
179 int i;
180 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
181 cpu->cd.DYNTRANS_ARCH.cur_physpage->ics[i].f =
182 #ifdef DYNTRANS_DUALMODE_32
183 cpu->is_32bit?
184 instr32(to_be_translated) :
185 #endif
186 instr(to_be_translated);
187 fatal("[ Note: The translation of physical page 0x%llx"
188 " contained combinations of instructions; these "
189 "are now flushed because we are single-stepping."
190 " ]\n", (long long)cpu->cd.DYNTRANS_ARCH.
191 cur_physpage->physaddr);
192 cpu->cd.DYNTRANS_ARCH.cur_physpage->flags &=
193 ~(COMBINATIONS | TRANSLATIONS);
194 }
195
196 if (show_opcode_statistics)
197 S;
198
199 /* Execute just one instruction: */
200 ic->f(cpu, ic);
201 n_instrs = 1;
202 } else if (show_opcode_statistics) {
203 /* Gather statistics while executing multiple instructions: */
204 n_instrs = 0;
205 for (;;) {
206 struct DYNTRANS_IC *ic;
207
208 S; I; S; I; S; I; S; I; S; I; S; I;
209 S; I; S; I; S; I; S; I; S; I; S; I;
210 S; I; S; I; S; I; S; I; S; I; S; I;
211 S; I; S; I; S; I; S; I; S; I; S; I;
212
213 n_instrs += 24;
214
215 if (!cpu->running_translated ||
216 n_instrs + cpu->n_translated_instrs >= 16384)
217 break;
218 }
219 } else {
220 /* Execute multiple instructions: */
221 n_instrs = 0;
222 for (;;) {
223 struct DYNTRANS_IC *ic;
224
225 I; I; I; I; I; I; I; I; I; I;
226 I; I; I; I; I; I; I; I; I; I;
227 I; I; I; I; I; I; I; I; I; I;
228 I; I; I; I; I; I; I; I; I; I;
229 I; I; I; I; I; I; I; I; I; I;
230
231 I; I; I; I; I; I; I; I; I; I;
232
233 n_instrs += 60;
234
235 if (!cpu->running_translated ||
236 n_instrs + cpu->n_translated_instrs >= 16384)
237 break;
238 }
239 }
240
241
242 /*
243 * Update the program counter and return the correct number of
244 * executed instructions:
245 */
246 low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t)
247 cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC);
248
249 if (low_pc >= 0 && low_pc < DYNTRANS_IC_ENTRIES_PER_PAGE) {
250 #ifdef DYNTRANS_ARM
251 cpu->cd.arm.r[ARM_PC] &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1)<<2);
252 cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
253 cpu->pc = cpu->cd.arm.r[ARM_PC];
254 #else
255 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
256 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
257 cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT);
258 #endif
259 } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE) {
260 /* Switch to next page: */
261 #ifdef DYNTRANS_ARM
262 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << 2);
263 cpu->cd.arm.r[ARM_PC] += (ARM_IC_ENTRIES_PER_PAGE << 2);
264 cpu->pc = cpu->cd.arm.r[ARM_PC];
265 #else
266 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
267 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
268 cpu->pc += (DYNTRANS_IC_ENTRIES_PER_PAGE <<
269 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
270 #endif
271 } else {
272 /* debug("debug: Outside a page (This is actually ok)\n"); */
273 }
274
275 return n_instrs + cpu->n_translated_instrs;
276 }
277 #endif /* DYNTRANS_CPU_RUN_INSTR */
278
279
280
281 #ifdef DYNTRANS_FUNCTION_TRACE
282 /*
283 * XXX_cpu_functioncall_trace():
284 *
285 * Without this function, the main trace tree function prints something
286 * like <f()> or <0x1234()> on a function call. It is up to this
287 * function to print the arguments passed.
288 */
289 void DYNTRANS_FUNCTION_TRACE(struct cpu *cpu, uint64_t f, int n_args)
290 {
291 char strbuf[50];
292 char *symbol;
293 uint64_t ot;
294 int x, print_dots = 1, n_args_to_print =
295 #ifdef DYNTRANS_ALPHA
296 6
297 #else
298 #ifdef DYNTRANS_SH
299 8
300 #else
301 4 /* Default value for most archs */
302 #endif
303 #endif
304 ;
305
306 if (n_args >= 0 && n_args <= n_args_to_print) {
307 print_dots = 0;
308 n_args_to_print = n_args;
309 }
310
311 /*
312 * TODO: The type of each argument should be taken from the symbol
313 * table, in some way.
314 *
315 * The code here does a kind of "heuristic guess" regarding what the
316 * argument values might mean. Sometimes the output looks weird, but
317 * usually it looks good enough.
318 *
319 * Print ".." afterwards to show that there might be more arguments
320 * than were passed in register.
321 */
322 for (x=0; x<n_args_to_print; x++) {
323 int64_t d;
324 #ifdef DYNTRANS_X86
325 d = 0; /* TODO */
326 #else
327 /* Args in registers: */
328 d = cpu->cd.DYNTRANS_ARCH.
329 #ifdef DYNTRANS_ALPHA
330 r[ALPHA_A0
331 #endif
332 #ifdef DYNTRANS_ARM
333 r[0
334 #endif
335 #ifdef DYNTRANS_AVR
336 /* TODO: 24,25 = first register, but then
337 they go downwards, ie. 22,23 and so on */
338 r[24
339 #endif
340 #ifdef DYNTRANS_HPPA
341 r[0 /* TODO */
342 #endif
343 #ifdef DYNTRANS_I960
344 r[0 /* TODO */
345 #endif
346 #ifdef DYNTRANS_IA64
347 r[0 /* TODO */
348 #endif
349 #ifdef DYNTRANS_M68K
350 d[0 /* TODO */
351 #endif
352 #ifdef DYNTRANS_MIPS
353 gpr[MIPS_GPR_A0
354 #endif
355 #ifdef DYNTRANS_PPC
356 gpr[3
357 #endif
358 #ifdef DYNTRANS_SH
359 r[2
360 #endif
361 #ifdef DYNTRANS_SPARC
362 r_i[0
363 #endif
364 + x];
365 #endif
366 symbol = get_symbol_name(&cpu->machine->symbol_context, d, &ot);
367
368 if (d > -256 && d < 256)
369 fatal("%i", (int)d);
370 else if (memory_points_to_string(cpu, cpu->mem, d, 1))
371 fatal("\"%s\"", memory_conv_to_string(cpu,
372 cpu->mem, d, strbuf, sizeof(strbuf)));
373 else if (symbol != NULL && ot == 0)
374 fatal("&%s", symbol);
375 else {
376 if (cpu->is_32bit)
377 fatal("0x%x", (int)d);
378 else
379 fatal("0x%llx", (long long)d);
380 }
381
382 if (x < n_args_to_print - 1)
383 fatal(",");
384 }
385
386 if (print_dots)
387 fatal(",..");
388 }
389 #endif
390
391
392
393 #ifdef DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE
394 /* forward declaration of to_be_translated and end_of_page: */
395 static void instr(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
396 static void instr(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
397 #ifdef DYNTRANS_DUALMODE_32
398 static void instr32(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
399 static void instr32(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
400 #endif
401 /*
402 * XXX_tc_allocate_default_page():
403 *
404 * Create a default page (with just pointers to instr(to_be_translated)
405 * at cpu->translation_cache_cur_ofs.
406 */
407 static void DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE(struct cpu *cpu,
408 uint64_t physaddr)
409 {
410 struct DYNTRANS_TC_PHYSPAGE *ppp;
411 int i;
412
413 /* Create the physpage header: */
414 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
415 + cpu->translation_cache_cur_ofs);
416 ppp->next_ofs = 0;
417 ppp->physaddr = physaddr;
418
419 /* TODO: Is this faster than copying an entire template page? */
420 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
421 ppp->ics[i].f =
422 #ifdef DYNTRANS_DUALMODE_32
423 cpu->is_32bit? instr32(to_be_translated) :
424 #endif
425 instr(to_be_translated);
426
427 ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE].f =
428 #ifdef DYNTRANS_DUALMODE_32
429 cpu->is_32bit? instr32(end_of_page) :
430 #endif
431 instr(end_of_page);
432
433 cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE);
434
435 cpu->translation_cache_cur_ofs --;
436 cpu->translation_cache_cur_ofs |= 63;
437 cpu->translation_cache_cur_ofs ++;
438 }
439 #endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE */
440
441
442
443 #ifdef DYNTRANS_PC_TO_POINTERS_FUNC
444 /*
445 * XXX_pc_to_pointers_generic():
446 *
447 * Generic case. See DYNTRANS_PC_TO_POINTERS_FUNC below.
448 */
449 void DYNTRANS_PC_TO_POINTERS_GENERIC(struct cpu *cpu)
450 {
451 #ifdef MODE32
452 uint32_t
453 #else
454 uint64_t
455 #endif
456 cached_pc, physaddr;
457 uint32_t physpage_ofs;
458 int ok, pagenr, table_index;
459 uint32_t *physpage_entryp;
460 struct DYNTRANS_TC_PHYSPAGE *ppp;
461
462 #ifdef MODE32
463 int index;
464 cached_pc = cpu->pc;
465 index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
466 #else
467 #ifdef DYNTRANS_ALPHA
468 uint32_t a, b;
469 int kernel = 0;
470 struct alpha_vph_page *vph_p;
471 cached_pc = cpu->pc;
472 a = (cached_pc >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
473 b = (cached_pc >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
474 if ((cached_pc >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
475 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
476 kernel = 1;
477 } else
478 vph_p = cpu->cd.alpha.vph_table0[a];
479 #else
480 #ifdef DYNTRANS_IA64
481 fatal("IA64 todo\n");
482 #else
483 fatal("Neither alpha, ia64, nor 32-bit? 3\n");
484 exit(1);
485 #endif
486 #endif
487 #endif
488
489 /* Virtual to physical address translation: */
490 ok = 0;
491 #ifdef MODE32
492 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) {
493 physaddr = cpu->cd.DYNTRANS_ARCH.phys_addr[index];
494 ok = 1;
495 }
496 #else
497 #ifdef DYNTRANS_ALPHA
498 if (vph_p->host_load[b] != NULL) {
499 physaddr = vph_p->phys_addr[b];
500 ok = 1;
501 }
502 #else
503 #ifdef DYNTRANS_IA64
504 fatal("IA64 todo\n");
505 #else
506 fatal("Neither alpha, ia64, nor 32-bit? 4\n");
507 exit(1);
508 #endif
509 #endif
510 #endif
511
512 if (!ok) {
513 uint64_t paddr;
514 if (cpu->translate_address != NULL)
515 ok = cpu->translate_address(cpu, cached_pc,
516 &paddr, FLAG_INSTR);
517 else {
518 paddr = cached_pc;
519 ok = 1;
520 }
521 if (!ok) {
522 /*
523 fatal("TODO: instruction vaddr=>paddr translation"
524 " failed. vaddr=0x%llx\n", (long long)cached_pc);
525 fatal("!! cpu->pc=0x%llx arm_pc=0x%x\n", (long long)cpu->pc,
526 cpu->cd.arm.r[ARM_PC]);
527 */
528 ok = cpu->translate_address(cpu, cpu->pc, &paddr,
529 FLAG_INSTR);
530 /*
531 printf("EXCEPTION HANDLER: vaddr = 0x%x ==> paddr = 0x%x\n",
532 (int)cpu->pc, (int)paddr);
533 fatal("!? cpu->pc=0x%llx arm_pc=0x%x\n", (long long)cpu->pc,
534 cpu->cd.arm.r[ARM_PC]);
535 */
536 if (!ok) {
537 fatal("FATAL: could not find physical"
538 " address of the exception handler?");
539 exit(1);
540 }
541 }
542 cached_pc = cpu->pc;
543 #ifdef MODE32
544 index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
545 #endif
546 physaddr = paddr;
547 }
548
549 #ifdef MODE32
550 if (cpu->cd.DYNTRANS_ARCH.host_load[index] == NULL) {
551 unsigned char *host_page = memory_paddr_to_hostaddr(cpu->mem,
552 physaddr, MEM_READ);
553 if (host_page != NULL) {
554 int q = DYNTRANS_PAGESIZE - 1;
555 host_page += (physaddr &
556 ((1 << BITS_PER_MEMBLOCK) - 1) & ~q);
557 cpu->update_translation_table(cpu, cached_pc & ~q,
558 host_page, TLB_CODE, physaddr & ~q);
559 }
560 }
561 #endif
562
563 if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE) {
564 fatal("[ dyntrans: resetting the translation cache ]\n");
565 cpu_create_or_reset_tc(cpu);
566 }
567
568 pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr);
569 table_index = PAGENR_TO_TABLE_INDEX(pagenr);
570
571 physpage_entryp = &(((uint32_t *)cpu->translation_cache)[table_index]);
572 physpage_ofs = *physpage_entryp;
573 ppp = NULL;
574
575 /* Traverse the physical page chain: */
576 while (physpage_ofs != 0) {
577 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
578 + physpage_ofs);
579 /* If we found the page in the cache, then we're done: */
580 if (ppp->physaddr == physaddr)
581 break;
582 /* Try the next page in the chain: */
583 physpage_ofs = ppp->next_ofs;
584 }
585
586 /* If the offset is 0 (or ppp is NULL), then we need to create a
587 new "default" empty translation page. */
588
589 if (ppp == NULL) {
590 /* fatal("CREATING page %lli (physaddr 0x%llx), table index "
591 "%i\n", (long long)pagenr, (long long)physaddr,
592 (int)table_index); */
593 *physpage_entryp = physpage_ofs =
594 cpu->translation_cache_cur_ofs;
595
596 /* Allocate a default page, with to_be_translated entries: */
597 DYNTRANS_TC_ALLOCATE(cpu, physaddr);
598
599 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
600 + physpage_ofs);
601 }
602
603 #ifdef MODE32
604 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL)
605 cpu->cd.DYNTRANS_ARCH.phys_page[index] = ppp;
606 #endif
607
608 #ifdef DYNTRANS_ALPHA
609 if (vph_p->host_load[b] != NULL)
610 vph_p->phys_page[b] = ppp;
611 #endif
612
613 cpu->invalidate_translation_caches(cpu, physaddr,
614 JUST_MARK_AS_NON_WRITABLE | INVALIDATE_PADDR);
615
616 /* cpu->cd.DYNTRANS_ARCH.cur_physpage = ppp; */
617 cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
618
619 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
620 DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
621
622 /* printf("cached_pc=0x%016llx pagenr=%lli table_index=%lli, "
623 "physpage_ofs=0x%016llx\n", (long long)cached_pc, (long long)pagenr,
624 (long long)table_index, (long long)physpage_ofs); */
625 }
626
627
628 /*
629 * XXX_pc_to_pointers():
630 *
631 * This function uses the current program counter (a virtual address) to
632 * find out which physical translation page to use, and then sets the current
633 * translation page pointers to that page.
634 *
635 * If there was no translation page for that physical page, then an empty
636 * one is created.
637 *
638 * NOTE: This is the quick lookup version. See
639 * DYNTRANS_PC_TO_POINTERS_GENERIC above for the generic case.
640 */
641 void DYNTRANS_PC_TO_POINTERS_FUNC(struct cpu *cpu)
642 {
643 #ifdef MODE32
644 uint32_t
645 #else
646 uint64_t
647 #endif
648 cached_pc;
649 struct DYNTRANS_TC_PHYSPAGE *ppp;
650
651 #ifdef MODE32
652 int index;
653 cached_pc = cpu->pc;
654 index = DYNTRANS_ADDR_TO_PAGENR(cached_pc);
655 ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index];
656 if (ppp != NULL)
657 goto have_it;
658 #else
659 #ifdef DYNTRANS_ALPHA
660 uint32_t a, b;
661 int kernel = 0;
662 struct alpha_vph_page *vph_p;
663 cached_pc = cpu->pc;
664 a = (cached_pc >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
665 b = (cached_pc >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
666 if ((cached_pc >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
667 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
668 kernel = 1;
669 } else
670 vph_p = cpu->cd.alpha.vph_table0[a];
671 if (vph_p != cpu->cd.alpha.vph_default_page) {
672 ppp = vph_p->phys_page[b];
673 if (ppp != NULL)
674 goto have_it;
675 }
676 #else
677 #ifdef DYNTRANS_IA64
678 fatal("IA64 todo\n");
679 #else
680 fatal("Neither alpha, ia64, nor 32-bit? 1\n");
681 { char *p = (char *) 0; *p = 0; }
682 exit(1);
683 #endif
684 #endif
685 #endif
686
687 DYNTRANS_PC_TO_POINTERS_GENERIC(cpu);
688 return;
689
690 /* Quick return path: */
691 have_it:
692 /* cpu->cd.DYNTRANS_ARCH.cur_physpage = ppp; */
693 cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
694 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
695 DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
696
697 /* printf("cached_pc=0x%016llx pagenr=%lli table_index=%lli, "
698 "physpage_ofs=0x%016llx\n", (long long)cached_pc, (long long)pagenr,
699 (long long)table_index, (long long)physpage_ofs); */
700 }
701 #endif /* DYNTRANS_PC_TO_POINTERS_FUNC */
702
703
704
705 #ifdef DYNTRANS_INVAL_ENTRY
706 /*
707 * XXX_invalidate_tlb_entry():
708 *
709 * Invalidate one translation entry (based on virtual address).
710 *
711 * If the JUST_MARK_AS_NON_WRITABLE flag is set, then the translation entry
712 * is just downgraded to non-writable (ie the host store page is set to
713 * NULL). Otherwise, the entire translation is removed.
714 */
715 static void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu,
716 #ifdef MODE32
717 uint32_t
718 #else
719 uint64_t
720 #endif
721 vaddr_page, int flags)
722 {
723 #ifdef MODE32
724 uint32_t index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
725
726 #ifdef DYNTRANS_ARM
727 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 3] &= ~(1 << (index & 7));
728 #endif
729
730 if (flags & JUST_MARK_AS_NON_WRITABLE) {
731 /* printf("JUST MARKING NON-W: vaddr 0x%08x\n",
732 (int)vaddr_page); */
733 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
734 } else {
735 cpu->cd.DYNTRANS_ARCH.host_load[index] = NULL;
736 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
737 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = 0;
738 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
739 cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = 0;
740 }
741 #else
742 /* 2-level: */
743 #ifdef DYNTRANS_ALPHA
744 struct alpha_vph_page *vph_p;
745 uint32_t a, b;
746 int kernel = 0;
747
748 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
749 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
750 if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
751 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
752 kernel = 1;
753 } else
754 vph_p = cpu->cd.alpha.vph_table0[a];
755
756 if (vph_p == cpu->cd.alpha.vph_default_page) {
757 fatal("alpha_invalidate_tlb_entry(): huh? Problem 1.\n");
758 exit(1);
759 }
760
761 if (flags & JUST_MARK_AS_NON_WRITABLE) {
762 vph_p->host_store[b] = NULL;
763 return;
764 }
765 vph_p->host_load[b] = NULL;
766 vph_p->host_store[b] = NULL;
767 vph_p->phys_addr[b] = 0;
768 vph_p->phys_page[b] = NULL;
769 vph_p->refcount --;
770 if (vph_p->refcount < 0) {
771 fatal("alpha_invalidate_tlb_entry(): huh? Problem 2.\n");
772 exit(1);
773 }
774 if (vph_p->refcount == 0) {
775 vph_p->next = cpu->cd.alpha.vph_next_free_page;
776 cpu->cd.alpha.vph_next_free_page = vph_p;
777 if (kernel)
778 cpu->cd.alpha.vph_table0_kernel[a] =
779 cpu->cd.alpha.vph_default_page;
780 else
781 cpu->cd.alpha.vph_table0[a] =
782 cpu->cd.alpha.vph_default_page;
783 }
784 #else /* !DYNTRANS_ALPHA */
785 #ifdef DYNTRANS_IA64
786 fatal("IA64: blah blah TODO\n");
787 #else
788 fatal("Not yet for non-1-level, non-Alpha, non-ia64\n");
789 #endif /* !DYNTRANS_IA64 */
790 #endif /* !DYNTRANS_ALPHA */
791 #endif
792 }
793 #endif
794
795
796 #ifdef DYNTRANS_INVALIDATE_TC
797 /*
798 * XXX_invalidate_translation_caches():
799 *
800 * Invalidate all entries matching a specific physical address, a specific
801 * virtual address, or ALL entries.
802 *
803 * flags should be one of
804 * INVALIDATE_PADDR INVALIDATE_VADDR or INVALIDATE_ALL
805 *
806 * In the case when all translations are invalidated, paddr doesn't need
807 * to be supplied.
808 *
809 * NOTE/TODO: When invalidating a virtual address, it is only cleared from
810 * the quick translation array, not from the linear
811 * vph_tlb_entry[] array. Hopefully this is enough anyway.
812 */
813 void DYNTRANS_INVALIDATE_TC(struct cpu *cpu, uint64_t paddr, int flags)
814 {
815 int r;
816 #ifdef MODE32
817 uint32_t
818 #else
819 uint64_t
820 #endif
821 addr_page = paddr & ~(DYNTRANS_PAGESIZE - 1);
822
823 /* Quick case for virtual addresses: see note above. */
824 if (flags & INVALIDATE_VADDR) {
825 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, addr_page, flags);
826 return;
827 }
828
829 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
830 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && (
831 (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page ==
832 addr_page && flags & INVALIDATE_PADDR) ||
833 flags & INVALIDATE_ALL) ) {
834 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
835 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
836 flags);
837 if (flags & JUST_MARK_AS_NON_WRITABLE)
838 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
839 .writeflag = 0;
840 else
841 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
842 .valid = 0;
843 }
844 }
845 }
846 #endif /* DYNTRANS_INVALIDATE_TC */
847
848
849
850 #ifdef DYNTRANS_INVALIDATE_TC_CODE
851 /*
852 * XXX_invalidate_code_translation():
853 *
854 * Invalidate code translations for a specific physical address, a specific
855 * virtual address, or for all entries in the cache.
856 */
857 void DYNTRANS_INVALIDATE_TC_CODE(struct cpu *cpu, uint64_t addr, int flags)
858 {
859 int r;
860 #ifdef MODE32
861 uint32_t
862 #else
863 uint64_t
864 #endif
865 vaddr_page, paddr_page;
866
867 addr &= ~(DYNTRANS_PAGESIZE-1);
868
869 /* printf("DYNTRANS_INVALIDATE_TC_CODE addr=0x%08x flags=%i\n",
870 (int)addr, flags); */
871
872 if (flags & INVALIDATE_PADDR) {
873 int pagenr, table_index;
874 uint32_t physpage_ofs, *physpage_entryp;
875 struct DYNTRANS_TC_PHYSPAGE *ppp, *prev_ppp;
876
877 pagenr = DYNTRANS_ADDR_TO_PAGENR(addr);
878
879 #ifdef MODE32
880 /* If this page isn't marked as having any translations,
881 then return immediately. */
882 if (!(cpu->cd.DYNTRANS_ARCH.phystranslation[pagenr >> 5]
883 & 1 << (pagenr & 31)))
884 return;
885 /* Remove the mark: */
886 cpu->cd.DYNTRANS_ARCH.phystranslation[pagenr >> 5] &=
887 ~ (1 << (pagenr & 31));
888 #endif
889
890 table_index = PAGENR_TO_TABLE_INDEX(pagenr);
891
892 physpage_entryp = &(((uint32_t *)cpu->
893 translation_cache)[table_index]);
894 physpage_ofs = *physpage_entryp;
895 prev_ppp = ppp = NULL;
896
897 /* Traverse the physical page chain: */
898 while (physpage_ofs != 0) {
899 prev_ppp = ppp;
900 ppp = (struct DYNTRANS_TC_PHYSPAGE *)
901 (cpu->translation_cache + physpage_ofs);
902 /* If we found the page in the cache,
903 then we're done: */
904 if (ppp->physaddr == addr)
905 break;
906 /* Try the next page in the chain: */
907 physpage_ofs = ppp->next_ofs;
908 }
909
910 if (physpage_ofs == 0)
911 ppp = NULL;
912
913 #if 1
914 /*
915 * "Bypass" the page, removing it from the code cache.
916 *
917 * NOTE/TODO: This gives _TERRIBLE_ performance with self-
918 * modifying code, or when a single page is used for both
919 * code and (writable) data.
920 */
921 if (ppp != NULL) {
922 if (prev_ppp != NULL)
923 prev_ppp->next_ofs = ppp->next_ofs;
924 else
925 *physpage_entryp = ppp->next_ofs;
926 }
927 #else
928 /*
929 * Instead of removing the page from the code cache, each
930 * entry can be set to "to_be_translated". This is slow in
931 * the general case, but in the case of self-modifying code,
932 * it might be faster since we don't risk wasting cache
933 * memory as quickly (which would force unnecessary Restarts).
934 */
935 if (ppp != NULL) {
936 /* TODO: Is this faster than copying an entire
937 template page? */
938 int i;
939 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
940 ppp->ics[i].f =
941 #ifdef DYNTRANS_DUALMODE_32
942 cpu->is_32bit? instr32(to_be_translated) :
943 #endif
944 instr(to_be_translated);
945 }
946 #endif
947 }
948
949 /* Invalidate entries (NOTE: only code entries) in the VPH table: */
950 for (r = DYNTRANS_MAX_VPH_TLB_ENTRIES/2;
951 r < DYNTRANS_MAX_VPH_TLB_ENTRIES; r ++) {
952 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
953 vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
954 .vaddr_page & ~(DYNTRANS_PAGESIZE-1);
955 paddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
956 .paddr_page & ~(DYNTRANS_PAGESIZE-1);
957
958 if (flags & INVALIDATE_ALL ||
959 (flags & INVALIDATE_PADDR && paddr_page == addr) ||
960 (flags & INVALIDATE_VADDR && vaddr_page == addr)) {
961 #ifdef MODE32
962 uint32_t index =
963 DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
964 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
965 /* Remove the mark: */
966 index = DYNTRANS_ADDR_TO_PAGENR(paddr_page);
967 cpu->cd.DYNTRANS_ARCH.phystranslation[
968 index >> 5] &= ~ (1 << (index & 31));
969 #else
970 /* 2-level: */
971 #ifdef DYNTRANS_ALPHA
972 struct alpha_vph_page *vph_p;
973 uint32_t a, b;
974 int kernel = 0;
975
976 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT)
977 & (ALPHA_LEVEL0 - 1);
978 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT)
979 & (ALPHA_LEVEL1 - 1);
980 if ((vaddr_page >> ALPHA_TOPSHIFT) ==
981 ALPHA_TOP_KERNEL) {
982 vph_p = cpu->cd.alpha.
983 vph_table0_kernel[a];
984 kernel = 1;
985 } else
986 vph_p = cpu->cd.alpha.vph_table0[a];
987 vph_p->phys_page[b] = NULL;
988 #else /* !DYNTRANS_ALPHA */
989 #ifdef DYNTRANS_IA64
990 fatal("IA64: blah yo yo TODO\n");
991 #else
992 fatal("Not yet for non-1-level, non-Alpha, "
993 "non-ia64\n");
994 #endif /* !DYNTRANS_IA64 */
995 #endif /* !DYNTRANS_ALPHA */
996 #endif
997 }
998 }
999 }
1000 }
1001 #endif /* DYNTRANS_INVALIDATE_TC_CODE */
1002
1003
1004
1005 #ifdef DYNTRANS_UPDATE_TRANSLATION_TABLE
1006 /*
1007 * XXX_update_translation_table():
1008 *
1009 * Update the virtual memory translation tables.
1010 */
1011 void DYNTRANS_UPDATE_TRANSLATION_TABLE(struct cpu *cpu, uint64_t vaddr_page,
1012 unsigned char *host_page, int writeflag, uint64_t paddr_page)
1013 {
1014 int64_t lowest, highest = -1;
1015 int found, r, lowest_index, start, end, useraccess = 0;
1016
1017 #ifdef DYNTRANS_ALPHA
1018 uint32_t a, b;
1019 struct alpha_vph_page *vph_p;
1020 int kernel = 0;
1021 /* fatal("update_translation_table(): v=0x%llx, h=%p w=%i"
1022 " p=0x%llx\n", (long long)vaddr_page, host_page, writeflag,
1023 (long long)paddr_page); */
1024 #else
1025 #ifdef MODE32
1026 uint32_t index;
1027 vaddr_page &= 0xffffffffULL;
1028 paddr_page &= 0xffffffffULL;
1029 /* fatal("update_translation_table(): v=0x%x, h=%p w=%i"
1030 " p=0x%x\n", (int)vaddr_page, host_page, writeflag,
1031 (int)paddr_page); */
1032 #else /* !MODE32 */
1033 #ifdef DYNTRANS_IA64
1034 fatal("IA64 update todo\n");
1035 #else
1036 fatal("Neither 32-bit, IA64, nor Alpha? 2\n");
1037 exit(1);
1038 #endif
1039 #endif
1040 #endif
1041
1042 if (writeflag & MEMORY_USER_ACCESS) {
1043 writeflag &= ~MEMORY_USER_ACCESS;
1044 useraccess = 1;
1045 }
1046
1047 start = 0; end = DYNTRANS_MAX_VPH_TLB_ENTRIES / 2;
1048 #if 1
1049 /* Half of the TLB used for data, half for code: */
1050 if (writeflag & TLB_CODE) {
1051 writeflag &= ~TLB_CODE;
1052 start = end; end = DYNTRANS_MAX_VPH_TLB_ENTRIES;
1053 }
1054 #else
1055 /* Data and code entries are mixed. */
1056 end = DYNTRANS_MAX_VPH_TLB_ENTRIES;
1057 #endif
1058
1059 /* Scan the current TLB entries: */
1060 found = -1; lowest_index = start;
1061 lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp;
1062
1063 #ifdef MODE32
1064 /* NOTE: vaddr_to_tlbindex is one more than the index, so that
1065 0 becomes -1, which means a miss. */
1066 found = cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[
1067 DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1;
1068 if (found < 0)
1069 lowest_index = (random() % (end-start)) + start;
1070 if (0)
1071 #endif
1072
1073 for (r=start; r<end; r++) {
1074 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) {
1075 lowest = cpu->cd.DYNTRANS_ARCH.
1076 vph_tlb_entry[r].timestamp;
1077 lowest_index = r;
1078 }
1079 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp > highest)
1080 highest = cpu->cd.DYNTRANS_ARCH.
1081 vph_tlb_entry[r].timestamp;
1082 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid &&
1083 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page ==
1084 vaddr_page) {
1085 found = r;
1086 break;
1087 }
1088 }
1089
1090 if (found < 0) {
1091 /* Create the new TLB entry, overwriting the oldest one: */
1092 r = lowest_index;
1093 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
1094 /* This one has to be invalidated first: */
1095 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
1096 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
1097 0);
1098 }
1099
1100 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid = 1;
1101 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].host_page = host_page;
1102 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page = paddr_page;
1103 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page;
1104 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = writeflag;
1105 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1;
1106
1107 /* Add the new translation to the table: */
1108 #ifdef DYNTRANS_ALPHA
1109 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
1110 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
1111 if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
1112 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
1113 kernel = 1;
1114 } else
1115 vph_p = cpu->cd.alpha.vph_table0[a];
1116 if (vph_p == cpu->cd.alpha.vph_default_page) {
1117 if (cpu->cd.alpha.vph_next_free_page != NULL) {
1118 if (kernel)
1119 vph_p = cpu->cd.alpha.vph_table0_kernel
1120 [a] = cpu->cd.alpha.
1121 vph_next_free_page;
1122 else
1123 vph_p = cpu->cd.alpha.vph_table0[a] =
1124 cpu->cd.alpha.vph_next_free_page;
1125 cpu->cd.alpha.vph_next_free_page = vph_p->next;
1126 } else {
1127 if (kernel)
1128 vph_p = cpu->cd.alpha.vph_table0_kernel
1129 [a] = malloc(sizeof(struct
1130 alpha_vph_page));
1131 else
1132 vph_p = cpu->cd.alpha.vph_table0[a] =
1133 malloc(sizeof(struct
1134 alpha_vph_page));
1135 memset(vph_p, 0, sizeof(struct alpha_vph_page));
1136 }
1137 }
1138 vph_p->refcount ++;
1139 vph_p->host_load[b] = host_page;
1140 vph_p->host_store[b] = writeflag? host_page : NULL;
1141 vph_p->phys_addr[b] = paddr_page;
1142 vph_p->phys_page[b] = NULL;
1143 #else
1144 #ifdef MODE32
1145 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1146 cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
1147 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1148 writeflag? host_page : NULL;
1149 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
1150 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1151 cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = r + 1;
1152 #ifdef DYNTRANS_ARM
1153 if (useraccess)
1154 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 3]
1155 |= 1 << (index & 7);
1156 #endif
1157 #endif /* 32 */
1158 #endif /* !ALPHA */
1159 } else {
1160 /*
1161 * The translation was already in the TLB.
1162 * Writeflag = 0: Do nothing.
1163 * Writeflag = 1: Make sure the page is writable.
1164 * Writeflag = -1: Downgrade to readonly.
1165 */
1166 r = found;
1167 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1;
1168 if (writeflag == 1)
1169 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1;
1170 if (writeflag == -1)
1171 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 0;
1172 #ifdef DYNTRANS_ALPHA
1173 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
1174 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
1175 if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
1176 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
1177 kernel = 1;
1178 } else
1179 vph_p = cpu->cd.alpha.vph_table0[a];
1180 vph_p->phys_page[b] = NULL;
1181 if (vph_p->phys_addr[b] == paddr_page) {
1182 if (writeflag == 1)
1183 vph_p->host_store[b] = host_page;
1184 if (writeflag == -1)
1185 vph_p->host_store[b] = NULL;
1186 } else {
1187 /* Change the entire physical/host mapping: */
1188 vph_p->host_load[b] = host_page;
1189 vph_p->host_store[b] = writeflag? host_page : NULL;
1190 vph_p->phys_addr[b] = paddr_page;
1191 }
1192 #else
1193 #ifdef MODE32
1194 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page);
1195 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1196 #ifdef DYNTRANS_ARM
1197 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 3]&=~(1<<(index&7));
1198 if (useraccess)
1199 cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 3]
1200 |= 1 << (index & 7);
1201 #endif
1202 if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) {
1203 if (writeflag == 1)
1204 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1205 host_page;
1206 if (writeflag == -1)
1207 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
1208 } else {
1209 /* Change the entire physical/host mapping: */
1210 cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
1211 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1212 writeflag? host_page : NULL;
1213 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
1214 }
1215 #endif /* 32 */
1216 #endif /* !ALPHA */
1217 }
1218 }
1219 #endif /* DYNTRANS_UPDATE_TRANSLATION_TABLE */
1220
1221
1222 /*****************************************************************************/
1223
1224
1225 #ifdef DYNTRANS_TO_BE_TRANSLATED_HEAD
1226 /*
1227 * Check for breakpoints.
1228 */
1229 if (!single_step_breakpoint) {
1230 #ifdef MODE32
1231 uint32_t curpc = cpu->pc;
1232 #else
1233 uint64_t curpc = cpu->pc;
1234 #endif
1235 int i;
1236 for (i=0; i<cpu->machine->n_breakpoints; i++)
1237 if (curpc ==
1238 #ifdef MODE32
1239 (uint32_t)
1240 #endif
1241 cpu->machine->breakpoint_addr[i]) {
1242 if (!cpu->machine->instruction_trace) {
1243 int old_quiet_mode = quiet_mode;
1244 quiet_mode = 0;
1245 DISASSEMBLE(cpu, ib, 1, 0, 0);
1246 quiet_mode = old_quiet_mode;
1247 }
1248 fatal("BREAKPOINT: pc = 0x%llx\n(The "
1249 "instruction has not yet executed.)\n",
1250 (long long)cpu->pc);
1251 single_step_breakpoint = 1;
1252 single_step = 1;
1253 goto stop_running_translated;
1254 }
1255 }
1256 #endif /* DYNTRANS_TO_BE_TRANSLATED_HEAD */
1257
1258
1259 /*****************************************************************************/
1260
1261
1262 #ifdef DYNTRANS_TO_BE_TRANSLATED_TAIL
1263 /*
1264 * If we end up here, then an instruction was translated.
1265 * Mark the page as containing a translation.
1266 *
1267 * (Special case for 32-bit mode: set the corresponding bit in the
1268 * phystranslation[] array.)
1269 */
1270 #ifdef MODE32
1271 if (!(cpu->cd.DYNTRANS_ARCH.cur_physpage->flags & TRANSLATIONS)) {
1272 uint32_t index = DYNTRANS_ADDR_TO_PAGENR(addr);
1273 cpu->cd.DYNTRANS_ARCH.phystranslation[index >> 5] |=
1274 (1 << (index & 31));
1275 }
1276 #endif
1277 cpu->cd.DYNTRANS_ARCH.cur_physpage->flags |= TRANSLATIONS;
1278
1279
1280 /*
1281 * Now it is time to check for combinations of instructions that can
1282 * be converted into a single function call.
1283 *
1284 * Note: Single-stepping or instruction tracing doesn't work with
1285 * instruction combination.
1286 */
1287 if (!single_step && !cpu->machine->instruction_trace) {
1288 if (cpu->combination_check != NULL &&
1289 cpu->machine->speed_tricks)
1290 cpu->combination_check(cpu, ic,
1291 addr & (DYNTRANS_PAGESIZE - 1));
1292 cpu->combination_check = NULL;
1293 }
1294
1295 /* ... and finally execute the translated instruction: */
1296 if (single_step_breakpoint) {
1297 /*
1298 * Special case when single-stepping: Execute the translated
1299 * instruction, but then replace it with a "to be translated"
1300 * directly afterwards.
1301 */
1302 single_step_breakpoint = 0;
1303 ic->f(cpu, ic);
1304 ic->f =
1305 #ifdef DYNTRANS_DUALMODE_32
1306 cpu->is_32bit? instr32(to_be_translated) :
1307 #endif
1308 instr(to_be_translated);
1309 } else
1310 ic->f(cpu, ic);
1311
1312 return;
1313
1314
1315 bad: /*
1316 * Nothing was translated. (Unimplemented or illegal instruction.)
1317 */
1318
1319 quiet_mode = 0;
1320 fatal("to_be_translated(): TODO: unimplemented instruction");
1321
1322 if (cpu->machine->instruction_trace)
1323 #ifdef MODE32
1324 fatal(" at 0x%x\n", (int)cpu->pc);
1325 #else
1326 fatal(" at 0x%llx\n", (long long)cpu->pc);
1327 #endif
1328 else {
1329 fatal(":\n");
1330 DISASSEMBLE(cpu, ib, 1, 0, 0);
1331 }
1332
1333 cpu->running = 0;
1334 cpu->dead = 1;
1335 stop_running_translated:
1336 debugger_n_steps_left_before_interaction = 0;
1337 cpu->running_translated = 0;
1338 ic = cpu->cd.DYNTRANS_ARCH.next_ic = &nothing_call;
1339 cpu->cd.DYNTRANS_ARCH.next_ic ++;
1340
1341 /* Execute the "nothing" instruction: */
1342 ic->f(cpu, ic);
1343 #endif /* DYNTRANS_TO_BE_TRANSLATED_TAIL */
1344

  ViewVC Help
Powered by ViewVC 1.1.26