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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 19 - (show annotations)
Mon Oct 8 16:19:16 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 37289 byte(s)
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