cpu_dyntrans.cc Source File

Back to the index.

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

Generated on Fri Dec 7 2018 19:52:23 for GXemul by doxygen 1.8.13