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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (show annotations)
Mon Oct 8 16:18:56 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 31309 byte(s)
0.3.6
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.19 2005/10/07 22:10:51 debug Exp $
29 *
30 * Common dyntrans routines. Included from cpu_*.c.
31 */
32
33
34 #ifdef DYNTRANS_CPU_RUN_INSTR
35 /*
36 * XXX_cpu_run_instr():
37 *
38 * Execute one or more instructions on a specific CPU, using dyntrans.
39 *
40 * Return value is the number of instructions executed during this call,
41 * 0 if no instructions were executed.
42 */
43 int DYNTRANS_CPU_RUN_INSTR(struct emul *emul, struct cpu *cpu)
44 {
45 #ifdef MODE32
46 uint32_t cached_pc;
47 #else
48 uint64_t cached_pc;
49 #endif
50 int low_pc, n_instrs;
51
52 #ifdef DYNTRANS_DUALMODE_32
53 if (cpu->is_32bit)
54 DYNTRANS_PC_TO_POINTERS32(cpu);
55 else
56 #endif
57 DYNTRANS_PC_TO_POINTERS(cpu);
58
59 /*
60 * Interrupt assertion? (This is _below_ the initial PC to pointer
61 * conversion; if the conversion caused an exception of some kind
62 * then interrupts are probably disabled, and the exception will get
63 * priority over device interrupts.)
64 */
65 #ifdef DYNTRANS_ARM
66 if (cpu->cd.arm.irq_asserted && !(cpu->cd.arm.cpsr & ARM_FLAG_I))
67 arm_exception(cpu, ARM_EXCEPTION_IRQ);
68 #endif
69
70 cached_pc = cpu->pc;
71
72 cpu->n_translated_instrs = 0;
73 cpu->running_translated = 1;
74
75 if (single_step || cpu->machine->instruction_trace) {
76 /*
77 * Single-step:
78 */
79 struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic
80 #ifndef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
81 ++
82 #endif
83 ;
84 if (cpu->machine->instruction_trace) {
85 #ifdef DYNTRANS_X86
86 unsigned char instr[17];
87 cpu->cd.x86.cursegment = X86_S_CS;
88 cpu->cd.x86.seg_override = 0;
89 #else
90 #ifdef DYNTRANS_M68K
91 unsigned char instr[16]; /* TODO: 16? */
92 #else
93 unsigned char instr[4]; /* General case... */
94 #endif
95 #endif
96 if (!cpu->memory_rw(cpu, cpu->mem, cached_pc, &instr[0],
97 sizeof(instr), MEM_READ, CACHE_INSTRUCTION)) {
98 fatal("XXX_cpu_run_instr(): could not read "
99 "the instruction\n");
100 } else
101 cpu_disassemble_instr(cpu->machine, cpu,
102 instr, 1, 0, 0);
103 }
104
105 /* When single-stepping, multiple instruction calls cannot
106 be combined into one. This clears all translations: */
107 if (cpu->cd.DYNTRANS_ARCH.cur_physpage->flags & COMBINATIONS) {
108 int i;
109 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
110 cpu->cd.DYNTRANS_ARCH.cur_physpage->ics[i].f =
111 #ifdef DYNTRANS_DUALMODE_32
112 cpu->is_32bit?
113 instr32(to_be_translated) :
114 #endif
115 instr(to_be_translated);
116 fatal("[ Note: The translation of physical page 0x%llx"
117 " contained combinations of instructions; these "
118 "are now flushed because we are single-stepping."
119 " ]\n", (long long)cpu->cd.DYNTRANS_ARCH.
120 cur_physpage->physaddr);
121 cpu->cd.DYNTRANS_ARCH.cur_physpage->flags &=
122 ~(COMBINATIONS | TRANSLATIONS);
123 }
124
125 /* Execute just one instruction: */
126 ic->f(cpu, ic);
127 n_instrs = 1;
128 } else {
129 /* Execute multiple instructions: */
130 n_instrs = 0;
131 for (;;) {
132 struct DYNTRANS_IC *ic;
133
134 #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
135 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic; ic->f(cpu, ic);
136 #else
137 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic);
138 #endif
139
140 I; I; I; I; I; I; I; I; I; I;
141 I; I; I; I; I; I; I; I; I; I;
142 I; I; I; I; I; I; I; I; I; I;
143 I; I; I; I; I; I; I; I; I; I;
144 I; I; I; I; I; I; I; I; I; I;
145
146 I; I; I; I; I; I; I; I; I; I;
147 I; I; I; I; I; I; I; I; I; I;
148 I; I; I; I; I; I; I; I; I; I;
149 I; I; I; I; I; I; I; I; I; I;
150 I; I; I; I; I; I; I; I; I; I;
151
152 I; I; I; I; I; I; I; I; I; I;
153 I; I; I; I; I; I; I; I; I; I;
154
155 n_instrs += 120;
156
157 if (!cpu->running_translated ||
158 n_instrs + cpu->n_translated_instrs >= 16384)
159 break;
160 }
161 }
162
163
164 /*
165 * Update the program counter and return the correct number of
166 * executed instructions:
167 */
168 low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t)
169 cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC);
170
171 if (low_pc >= 0 && low_pc < DYNTRANS_IC_ENTRIES_PER_PAGE) {
172 #ifdef DYNTRANS_ARM
173 cpu->cd.arm.r[ARM_PC] &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1)<<2);
174 cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
175 cpu->pc = cpu->cd.arm.r[ARM_PC];
176 #else
177 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
178 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
179 cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT);
180 #endif
181 } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE) {
182 /* Switch to next page: */
183 #ifdef DYNTRANS_ARM
184 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << 2);
185 cpu->cd.arm.r[ARM_PC] += (ARM_IC_ENTRIES_PER_PAGE << 2);
186 cpu->pc = cpu->cd.arm.r[ARM_PC];
187 #else
188 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
189 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
190 cpu->pc += (DYNTRANS_IC_ENTRIES_PER_PAGE <<
191 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
192 #endif
193 } else {
194 /* debug("debug: Outside a page (This is actually ok)\n"); */
195 }
196
197 return n_instrs + cpu->n_translated_instrs;
198 }
199 #endif /* DYNTRANS_CPU_RUN_INSTR */
200
201
202
203 #ifdef DYNTRANS_FUNCTION_TRACE
204 /*
205 * XXX_cpu_functioncall_trace():
206 *
207 * Without this function, the main trace tree function prints something
208 * like <f()> or <0x1234()> on a function call. It is up to this
209 * function to print the arguments passed.
210 */
211 void DYNTRANS_FUNCTION_TRACE(struct cpu *cpu, uint64_t f, int n_args)
212 {
213 char strbuf[50];
214 char *symbol;
215 uint64_t ot;
216 int x, print_dots = 1, n_args_to_print =
217 #ifdef DYNTRANS_ALPHA
218 6
219 #else
220 #ifdef DYNTRANS_SH
221 8
222 #else
223 4 /* Default value for most archs */
224 #endif
225 #endif
226 ;
227
228 if (n_args >= 0 && n_args <= n_args_to_print) {
229 print_dots = 0;
230 n_args_to_print = n_args;
231 }
232
233 /*
234 * TODO: The type of each argument should be taken from the symbol
235 * table, in some way.
236 *
237 * The code here does a kind of "heuristic guess" regarding what the
238 * argument values might mean. Sometimes the output looks weird, but
239 * usually it looks good enough.
240 *
241 * Print ".." afterwards to show that there might be more arguments
242 * than were passed in register.
243 */
244 for (x=0; x<n_args_to_print; x++) {
245 int64_t d;
246 #ifdef DYNTRANS_X86
247 d = 0; /* TODO */
248 #else
249 /* Args in registers: */
250 d = cpu->cd.DYNTRANS_ARCH.
251 #ifdef DYNTRANS_ALPHA
252 r[ALPHA_A0
253 #endif
254 #ifdef DYNTRANS_ARM
255 r[0
256 #endif
257 #ifdef DYNTRANS_AVR
258 /* TODO: 24,25 = first register, but then
259 they go downwards, ie. 22,23 and so on */
260 r[24
261 #endif
262 #ifdef DYNTRANS_HPPA
263 r[0 /* TODO */
264 #endif
265 #ifdef DYNTRANS_I960
266 r[0 /* TODO */
267 #endif
268 #ifdef DYNTRANS_IA64
269 r[0 /* TODO */
270 #endif
271 #ifdef DYNTRANS_M68K
272 d[0 /* TODO */
273 #endif
274 #ifdef DYNTRANS_MIPS
275 gpr[MIPS_GPR_A0
276 #endif
277 #ifdef DYNTRANS_PPC
278 gpr[3
279 #endif
280 #ifdef DYNTRANS_SH
281 r[2
282 #endif
283 #ifdef DYNTRANS_SPARC
284 r_i[0
285 #endif
286 + x];
287 #endif
288 symbol = get_symbol_name(&cpu->machine->symbol_context, d, &ot);
289
290 if (d > -256 && d < 256)
291 fatal("%i", (int)d);
292 else if (memory_points_to_string(cpu, cpu->mem, d, 1))
293 fatal("\"%s\"", memory_conv_to_string(cpu,
294 cpu->mem, d, strbuf, sizeof(strbuf)));
295 else if (symbol != NULL && ot == 0)
296 fatal("&%s", symbol);
297 else {
298 if (cpu->is_32bit)
299 fatal("0x%x", (int)d);
300 else
301 fatal("0x%llx", (long long)d);
302 }
303
304 if (x < n_args_to_print - 1)
305 fatal(",");
306 }
307
308 if (print_dots)
309 fatal(",..");
310 }
311 #endif
312
313
314
315 #ifdef DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE
316 /* forward declaration of to_be_translated and end_of_page: */
317 static void instr(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
318 static void instr(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
319 #ifdef DYNTRANS_DUALMODE_32
320 static void instr32(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
321 static void instr32(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
322 #endif
323 /*
324 * XXX_tc_allocate_default_page():
325 *
326 * Create a default page (with just pointers to instr(to_be_translated)
327 * at cpu->translation_cache_cur_ofs.
328 */
329 static void DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE(struct cpu *cpu,
330 uint64_t physaddr)
331 {
332 struct DYNTRANS_TC_PHYSPAGE *ppp;
333 int i;
334
335 /* Create the physpage header: */
336 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
337 + cpu->translation_cache_cur_ofs);
338 ppp->next_ofs = 0;
339 ppp->physaddr = physaddr;
340
341 /* TODO: Is this faster than copying an entire template page? */
342 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
343 ppp->ics[i].f =
344 #ifdef DYNTRANS_DUALMODE_32
345 cpu->is_32bit? instr32(to_be_translated) :
346 #endif
347 instr(to_be_translated);
348
349 ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE].f =
350 #ifdef DYNTRANS_DUALMODE_32
351 cpu->is_32bit? instr32(end_of_page) :
352 #endif
353 instr(end_of_page);
354
355 cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE);
356 }
357 #endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE */
358
359
360
361 #ifdef DYNTRANS_PC_TO_POINTERS_FUNC
362 /*
363 * XXX_pc_to_pointers_generic():
364 *
365 * Generic case. See DYNTRANS_PC_TO_POINTERS_FUNC below.
366 */
367 void DYNTRANS_PC_TO_POINTERS_GENERIC(struct cpu *cpu)
368 {
369 #ifdef MODE32
370 uint32_t
371 #else
372 uint64_t
373 #endif
374 cached_pc, physaddr;
375 uint32_t physpage_ofs;
376 int ok, pagenr, table_index;
377 uint32_t *physpage_entryp;
378 struct DYNTRANS_TC_PHYSPAGE *ppp;
379
380 #ifdef MODE32
381 int index;
382 cached_pc = cpu->pc;
383 index = cached_pc >> 12;
384 #else
385 #ifdef DYNTRANS_ALPHA
386 uint32_t a, b;
387 int kernel = 0;
388 struct alpha_vph_page *vph_p;
389 cached_pc = cpu->pc;
390 a = (cached_pc >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
391 b = (cached_pc >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
392 if ((cached_pc >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
393 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
394 kernel = 1;
395 } else
396 vph_p = cpu->cd.alpha.vph_table0[a];
397 #else
398 #ifdef DYNTRANS_IA64
399 fatal("IA64 todo\n");
400 #else
401 fatal("Neither alpha, ia64, nor 32-bit? 3\n");
402 exit(1);
403 #endif
404 #endif
405 #endif
406
407 /* Virtual to physical address translation: */
408 ok = 0;
409 #ifdef MODE32
410 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) {
411 physaddr = cpu->cd.DYNTRANS_ARCH.phys_addr[index];
412 ok = 1;
413 }
414 #else
415 #ifdef DYNTRANS_ALPHA
416 if (vph_p->host_load[b] != NULL) {
417 physaddr = vph_p->phys_addr[b];
418 ok = 1;
419 }
420 #else
421 #ifdef DYNTRANS_IA64
422 fatal("IA64 todo\n");
423 #else
424 fatal("Neither alpha, ia64, nor 32-bit? 4\n");
425 exit(1);
426 #endif
427 #endif
428 #endif
429
430 if (!ok) {
431 uint64_t paddr;
432 if (cpu->translate_address != NULL)
433 ok = cpu->translate_address(cpu, cached_pc,
434 &paddr, FLAG_INSTR);
435 else {
436 paddr = cached_pc;
437 ok = 1;
438 }
439 if (!ok) {
440 /*
441 fatal("TODO: instruction vaddr=>paddr translation"
442 " failed. vaddr=0x%llx\n", (long long)cached_pc);
443 fatal("!! cpu->pc=0x%llx arm_pc=0x%x\n", (long long)cpu->pc,
444 cpu->cd.arm.r[ARM_PC]);
445 */
446 ok = cpu->translate_address(cpu, cpu->pc, &paddr,
447 FLAG_INSTR);
448 /*
449 printf("EXCEPTION HANDLER: vaddr = 0x%x ==> paddr = 0x%x\n",
450 (int)cpu->pc, (int)paddr);
451 fatal("!? cpu->pc=0x%llx arm_pc=0x%x\n", (long long)cpu->pc,
452 cpu->cd.arm.r[ARM_PC]);
453 */
454 if (!ok) {
455 fatal("FATAL: could not find physical"
456 " address of the exception handler?");
457 exit(1);
458 }
459 }
460 cached_pc = cpu->pc;
461 physaddr = paddr;
462 }
463
464 if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE)
465 cpu_create_or_reset_tc(cpu);
466
467 pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr);
468 table_index = PAGENR_TO_TABLE_INDEX(pagenr);
469
470 physpage_entryp = &(((uint32_t *)cpu->translation_cache)[table_index]);
471 physpage_ofs = *physpage_entryp;
472 ppp = NULL;
473
474 /* Traverse the physical page chain: */
475 while (physpage_ofs != 0) {
476 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
477 + physpage_ofs);
478 /* If we found the page in the cache, then we're done: */
479 if (ppp->physaddr == physaddr)
480 break;
481 /* Try the next page in the chain: */
482 physpage_ofs = ppp->next_ofs;
483 }
484
485 /* If the offset is 0 (or ppp is NULL), then we need to create a
486 new "default" empty translation page. */
487
488 if (ppp == NULL) {
489 /* fatal("CREATING page %lli (physaddr 0x%llx), table index "
490 "%i\n", (long long)pagenr, (long long)physaddr,
491 (int)table_index); */
492 *physpage_entryp = physpage_ofs =
493 cpu->translation_cache_cur_ofs;
494
495 /* Allocate a default page, with to_be_translated entries: */
496 DYNTRANS_TC_ALLOCATE(cpu, physaddr);
497
498 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
499 + physpage_ofs);
500 }
501
502 #ifdef MODE32
503 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL)
504 cpu->cd.DYNTRANS_ARCH.phys_page[index] = ppp;
505 #endif
506
507 #ifdef DYNTRANS_ALPHA
508 if (vph_p->host_load[b] != NULL)
509 vph_p->phys_page[b] = ppp;
510 #endif
511
512 cpu->invalidate_translation_caches_paddr(cpu, physaddr,
513 JUST_MARK_AS_NON_WRITABLE);
514
515 cpu->cd.DYNTRANS_ARCH.cur_physpage = ppp;
516 cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
517 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
518 DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
519
520 /* printf("cached_pc=0x%016llx pagenr=%lli table_index=%lli, "
521 "physpage_ofs=0x%016llx\n", (long long)cached_pc, (long long)pagenr,
522 (long long)table_index, (long long)physpage_ofs); */
523 }
524
525
526 /*
527 * XXX_pc_to_pointers():
528 *
529 * This function uses the current program counter (a virtual address) to
530 * find out which physical translation page to use, and then sets the current
531 * translation page pointers to that page.
532 *
533 * If there was no translation page for that physical page, then an empty
534 * one is created.
535 *
536 * NOTE: This is the quick lookup version. See
537 * DYNTRANS_PC_TO_POINTERS_GENERIC above for the generic case.
538 */
539 void DYNTRANS_PC_TO_POINTERS_FUNC(struct cpu *cpu)
540 {
541 #ifdef MODE32
542 uint32_t
543 #else
544 uint64_t
545 #endif
546 cached_pc;
547 struct DYNTRANS_TC_PHYSPAGE *ppp;
548
549 #ifdef MODE32
550 int index;
551 cached_pc = cpu->pc;
552 index = cached_pc >> 12;
553 ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index];
554 if (ppp != NULL)
555 goto have_it;
556 #else
557 #ifdef DYNTRANS_ALPHA
558 uint32_t a, b;
559 int kernel = 0;
560 struct alpha_vph_page *vph_p;
561 cached_pc = cpu->pc;
562 a = (cached_pc >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
563 b = (cached_pc >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
564 if ((cached_pc >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
565 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
566 kernel = 1;
567 } else
568 vph_p = cpu->cd.alpha.vph_table0[a];
569 if (vph_p != cpu->cd.alpha.vph_default_page) {
570 ppp = vph_p->phys_page[b];
571 if (ppp != NULL)
572 goto have_it;
573 }
574 #else
575 #ifdef DYNTRANS_IA64
576 fatal("IA64 todo\n");
577 #else
578 fatal("Neither alpha, ia64, nor 32-bit? 1\n");
579 { char *p = (char *) 0; *p = 0; }
580 exit(1);
581 #endif
582 #endif
583 #endif
584
585 DYNTRANS_PC_TO_POINTERS_GENERIC(cpu);
586 return;
587
588 /* Quick return path: */
589 have_it:
590 cpu->cd.DYNTRANS_ARCH.cur_physpage = ppp;
591 cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
592 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
593 DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
594
595 /* printf("cached_pc=0x%016llx pagenr=%lli table_index=%lli, "
596 "physpage_ofs=0x%016llx\n", (long long)cached_pc, (long long)pagenr,
597 (long long)table_index, (long long)physpage_ofs); */
598 }
599 #endif /* DYNTRANS_PC_TO_POINTERS_FUNC */
600
601
602
603 #ifdef DYNTRANS_INVAL_ENTRY
604 /*
605 * XXX_invalidate_tlb_entry():
606 *
607 * Invalidate one translation entry (based on virtual address).
608 *
609 * If the JUST_MARK_AS_NON_WRITABLE flag is set, then the translation entry
610 * is just downgraded to non-writable (ie the host store page is set to
611 * NULL). Otherwise, the entire translation is removed.
612 */
613 void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu,
614 #ifdef MODE32
615 uint32_t
616 #else
617 uint64_t
618 #endif
619 vaddr_page, int flags)
620 {
621 #ifdef MODE32
622 uint32_t index = vaddr_page >> 12;
623
624 if (flags & JUST_MARK_AS_NON_WRITABLE) {
625 /* printf("JUST MARKING NON-W: vaddr 0x%08x\n",
626 (int)vaddr_page); */
627 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
628 } else {
629 cpu->cd.DYNTRANS_ARCH.host_load[index] = NULL;
630 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
631 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = 0;
632 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
633 }
634 #else
635 /* 2-level: */
636 #ifdef DYNTRANS_ALPHA
637 struct alpha_vph_page *vph_p;
638 uint32_t a, b;
639 int kernel = 0;
640
641 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
642 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
643 if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
644 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
645 kernel = 1;
646 } else
647 vph_p = cpu->cd.alpha.vph_table0[a];
648
649 if (vph_p == cpu->cd.alpha.vph_default_page) {
650 fatal("alpha_invalidate_tlb_entry(): huh? Problem 1.\n");
651 exit(1);
652 }
653
654 if (flags & JUST_MARK_AS_NON_WRITABLE) {
655 vph_p->host_store[b] = NULL;
656 return;
657 }
658 vph_p->host_load[b] = NULL;
659 vph_p->host_store[b] = NULL;
660 vph_p->phys_addr[b] = 0;
661 vph_p->phys_page[b] = NULL;
662 vph_p->refcount --;
663 if (vph_p->refcount < 0) {
664 fatal("alpha_invalidate_tlb_entry(): huh? Problem 2.\n");
665 exit(1);
666 }
667 if (vph_p->refcount == 0) {
668 vph_p->next = cpu->cd.alpha.vph_next_free_page;
669 cpu->cd.alpha.vph_next_free_page = vph_p;
670 if (kernel)
671 cpu->cd.alpha.vph_table0_kernel[a] =
672 cpu->cd.alpha.vph_default_page;
673 else
674 cpu->cd.alpha.vph_table0[a] =
675 cpu->cd.alpha.vph_default_page;
676 }
677 #else /* !DYNTRANS_ALPHA */
678 #ifdef DYNTRANS_IA64
679 fatal("IA64: blah blah TODO\n");
680 #else
681 fatal("Not yet for non-1-level, non-Alpha, non-ia64\n");
682 #endif /* !DYNTRANS_IA64 */
683 #endif /* !DYNTRANS_ALPHA */
684 #endif
685 }
686 #endif
687
688
689 #ifdef DYNTRANS_INVALIDATE_TC_PADDR
690 /*
691 * XXX_invalidate_translation_caches_paddr():
692 *
693 * Invalidate all entries matching a specific physical address, a specific
694 * virtual address, or ALL entries.
695 *
696 * flags should be one of
697 * INVALIDATE_PADDR INVALIDATE_VADDR or INVALIDATE_ALL
698 *
699 * In the case when all translations are invalidated, paddr doesn't need
700 * to be supplied.
701 *
702 * NOTE/TODO: Poorly choosen name for this function, as it can
703 * invalidate based on virtual address as well.
704 */
705 void DYNTRANS_INVALIDATE_TC_PADDR(struct cpu *cpu, uint64_t paddr, int flags)
706 {
707 int r;
708 #ifdef MODE32
709 uint32_t
710 #else
711 uint64_t
712 #endif
713 addr_page = paddr & ~(DYNTRANS_PAGESIZE - 1);
714
715 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
716 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && (
717 (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page ==
718 addr_page && flags & INVALIDATE_PADDR) ||
719 (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page ==
720 addr_page && flags & INVALIDATE_VADDR) ||
721 flags & INVALIDATE_ALL) ) {
722 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
723 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
724 flags);
725 if (flags & JUST_MARK_AS_NON_WRITABLE)
726 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
727 .writeflag = 0;
728 else
729 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
730 .valid = 0;
731 }
732 }
733 }
734 #endif /* DYNTRANS_INVALIDATE_TC_PADDR */
735
736
737
738 #ifdef DYNTRANS_INVALIDATE_TC_CODE
739 /*
740 * XXX_invalidate_code_translation():
741 *
742 * Invalidate code translations for a specific physical address, a specific
743 * virtual address, or for all entries in the cache.
744 */
745 void DYNTRANS_INVALIDATE_TC_CODE(struct cpu *cpu, uint64_t addr, int flags)
746 {
747 int r;
748 #ifdef MODE_32
749 uint32_t
750 #else
751 uint64_t
752 #endif
753 vaddr_page, paddr_page;
754
755 addr &= ~(DYNTRANS_PAGESIZE-1);
756
757 /* printf("DYNTRANS_INVALIDATE_TC_CODE addr=0x%08x flags=%i\n",
758 (int)addr, flags); */
759
760 if (flags & INVALIDATE_PADDR) {
761 int pagenr, table_index;
762 uint32_t physpage_ofs, *physpage_entryp;
763 struct DYNTRANS_TC_PHYSPAGE *ppp;
764
765 pagenr = DYNTRANS_ADDR_TO_PAGENR(addr);
766 table_index = PAGENR_TO_TABLE_INDEX(pagenr);
767
768 physpage_entryp = &(((uint32_t *)cpu->
769 translation_cache)[table_index]);
770 physpage_ofs = *physpage_entryp;
771 ppp = NULL;
772
773 /* Traverse the physical page chain: */
774 while (physpage_ofs != 0) {
775 ppp = (struct DYNTRANS_TC_PHYSPAGE *)
776 (cpu->translation_cache + physpage_ofs);
777 /* If we found the page in the cache,
778 then we're done: */
779 if (ppp->physaddr == addr)
780 break;
781 /* Try the next page in the chain: */
782 physpage_ofs = ppp->next_ofs;
783 }
784
785 /* If the page was found, then we should invalidate all
786 code translations: */
787 if (ppp != NULL) {
788 /* TODO: Is this faster than copying an entire
789 template page? */
790 int i;
791 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
792 ppp->ics[i].f =
793 #ifdef DYNTRANS_DUALMODE_32
794 cpu->is_32bit? instr32(to_be_translated) :
795 #endif
796 instr(to_be_translated);
797 }
798 }
799
800 /* Invalidate entries in the VPH table: */
801 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
802 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
803 vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
804 .vaddr_page & ~(DYNTRANS_PAGESIZE-1);
805 paddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
806 .paddr_page & ~(DYNTRANS_PAGESIZE-1);
807
808 if (flags & INVALIDATE_ALL ||
809 (flags & INVALIDATE_PADDR && paddr_page == addr) ||
810 (flags & INVALIDATE_VADDR && vaddr_page == addr)) {
811 #ifdef MODE32
812 uint32_t index = vaddr_page >> 12;
813 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
814 #else
815 /* 2-level: */
816 #ifdef DYNTRANS_ALPHA
817 struct alpha_vph_page *vph_p;
818 uint32_t a, b;
819 int kernel = 0;
820
821 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT)
822 & (ALPHA_LEVEL0 - 1);
823 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT)
824 & (ALPHA_LEVEL1 - 1);
825 if ((vaddr_page >> ALPHA_TOPSHIFT) ==
826 ALPHA_TOP_KERNEL) {
827 vph_p = cpu->cd.alpha.
828 vph_table0_kernel[a];
829 kernel = 1;
830 } else
831 vph_p = cpu->cd.alpha.vph_table0[a];
832 vph_p->phys_page[b] = NULL;
833 #else /* !DYNTRANS_ALPHA */
834 #ifdef DYNTRANS_IA64
835 fatal("IA64: blah yo yo TODO\n");
836 #else
837 fatal("Not yet for non-1-level, non-Alpha, "
838 "non-ia64\n");
839 #endif /* !DYNTRANS_IA64 */
840 #endif /* !DYNTRANS_ALPHA */
841 #endif
842 }
843 }
844 }
845 }
846 #endif /* DYNTRANS_INVALIDATE_TC_CODE */
847
848
849
850 #ifdef DYNTRANS_UPDATE_TRANSLATION_TABLE
851 /*
852 * XXX_update_translation_table():
853 *
854 * Update the virtual memory translation tables.
855 */
856 void DYNTRANS_UPDATE_TRANSLATION_TABLE(struct cpu *cpu, uint64_t vaddr_page,
857 unsigned char *host_page, int writeflag, uint64_t paddr_page)
858 {
859 int64_t lowest, highest = -1;
860 int found, r, lowest_index;
861
862 #ifdef DYNTRANS_ALPHA
863 uint32_t a, b;
864 struct alpha_vph_page *vph_p;
865 int kernel = 0;
866 /* fatal("update_translation_table(): v=0x%llx, h=%p w=%i"
867 " p=0x%llx\n", (long long)vaddr_page, host_page, writeflag,
868 (long long)paddr_page); */
869 #else
870 #ifdef MODE32
871 uint32_t index;
872 vaddr_page &= 0xffffffffULL;
873 paddr_page &= 0xffffffffULL;
874 /* fatal("update_translation_table(): v=0x%x, h=%p w=%i"
875 " p=0x%x\n", (int)vaddr_page, host_page, writeflag,
876 (int)paddr_page); */
877 #else /* !MODE32 */
878 #ifdef DYNTRANS_IA64
879 fatal("IA64 update todo\n");
880 #else
881 fatal("Neither 32-bit, IA64, nor Alpha? 2\n");
882 exit(1);
883 #endif
884 #endif
885 #endif
886
887 /* Scan the current TLB entries: */
888 found = -1; lowest_index = 0;
889 lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp;
890 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
891 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) {
892 lowest = cpu->cd.DYNTRANS_ARCH.
893 vph_tlb_entry[r].timestamp;
894 lowest_index = r;
895 }
896 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp > highest)
897 highest = cpu->cd.DYNTRANS_ARCH.
898 vph_tlb_entry[r].timestamp;
899 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid &&
900 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page ==
901 vaddr_page) {
902 found = r;
903 break;
904 }
905 }
906
907 if (found < 0) {
908 /* Create the new TLB entry, overwriting the oldest one: */
909 r = lowest_index;
910 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
911 /* This one has to be invalidated first: */
912 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
913 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page,
914 0);
915 }
916
917 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid = 1;
918 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].host_page = host_page;
919 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page = paddr_page;
920 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page;
921 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = writeflag;
922 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1;
923
924 /* Add the new translation to the table: */
925 #ifdef DYNTRANS_ALPHA
926 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
927 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
928 if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
929 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
930 kernel = 1;
931 } else
932 vph_p = cpu->cd.alpha.vph_table0[a];
933 if (vph_p == cpu->cd.alpha.vph_default_page) {
934 if (cpu->cd.alpha.vph_next_free_page != NULL) {
935 if (kernel)
936 vph_p = cpu->cd.alpha.vph_table0_kernel
937 [a] = cpu->cd.alpha.
938 vph_next_free_page;
939 else
940 vph_p = cpu->cd.alpha.vph_table0[a] =
941 cpu->cd.alpha.vph_next_free_page;
942 cpu->cd.alpha.vph_next_free_page = vph_p->next;
943 } else {
944 if (kernel)
945 vph_p = cpu->cd.alpha.vph_table0_kernel
946 [a] = malloc(sizeof(struct
947 alpha_vph_page));
948 else
949 vph_p = cpu->cd.alpha.vph_table0[a] =
950 malloc(sizeof(struct
951 alpha_vph_page));
952 memset(vph_p, 0, sizeof(struct alpha_vph_page));
953 }
954 }
955 vph_p->refcount ++;
956 vph_p->host_load[b] = host_page;
957 vph_p->host_store[b] = writeflag? host_page : NULL;
958 vph_p->phys_addr[b] = paddr_page;
959 vph_p->phys_page[b] = NULL;
960 #else
961 #ifdef MODE32
962 index = vaddr_page >> 12;
963 cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
964 cpu->cd.DYNTRANS_ARCH.host_store[index] =
965 writeflag? host_page : NULL;
966 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
967 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
968 #endif /* 32 */
969 #endif /* !ALPHA */
970 } else {
971 /*
972 * The translation was already in the TLB.
973 * Writeflag = 0: Do nothing.
974 * Writeflag = 1: Make sure the page is writable.
975 * Writeflag = -1: Downgrade to readonly.
976 */
977 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[found].timestamp =
978 highest + 1;
979 if (writeflag == 1)
980 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1;
981 if (writeflag == -1)
982 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 0;
983 #ifdef DYNTRANS_ALPHA
984 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
985 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
986 if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
987 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
988 kernel = 1;
989 } else
990 vph_p = cpu->cd.alpha.vph_table0[a];
991 vph_p->phys_page[b] = NULL;
992 if (vph_p->phys_addr[b] == paddr_page) {
993 if (writeflag == 1)
994 vph_p->host_store[b] = host_page;
995 if (writeflag == -1)
996 vph_p->host_store[b] = NULL;
997 } else {
998 /* Change the entire physical/host mapping: */
999 vph_p->host_load[b] = host_page;
1000 vph_p->host_store[b] = writeflag? host_page : NULL;
1001 vph_p->phys_addr[b] = paddr_page;
1002 }
1003 #else
1004 #ifdef MODE32
1005 index = vaddr_page >> 12;
1006 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
1007 if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) {
1008 if (writeflag == 1)
1009 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1010 host_page;
1011 if (writeflag == -1)
1012 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
1013 } else {
1014 /* Change the entire physical/host mapping: */
1015 cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
1016 cpu->cd.DYNTRANS_ARCH.host_store[index] =
1017 writeflag? host_page : NULL;
1018 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
1019 }
1020 #endif /* 32 */
1021 #endif /* !ALPHA */
1022 }
1023 }
1024 #endif /* DYNTRANS_UPDATE_TRANSLATION_TABLE */
1025
1026
1027 /*****************************************************************************/
1028
1029
1030 #ifdef DYNTRANS_TO_BE_TRANSLATED_HEAD
1031 /*
1032 * Check for breakpoints.
1033 */
1034 if (!single_step_breakpoint) {
1035 #ifdef MODE32
1036 uint32_t curpc = cpu->pc;
1037 #else
1038 uint64_t curpc = cpu->pc;
1039 #endif
1040 int i;
1041 for (i=0; i<cpu->machine->n_breakpoints; i++)
1042 if (curpc ==
1043 #ifdef MODE32
1044 (uint32_t)
1045 #endif
1046 cpu->machine->breakpoint_addr[i]) {
1047 if (!cpu->machine->instruction_trace) {
1048 int old_quiet_mode = quiet_mode;
1049 quiet_mode = 0;
1050 DISASSEMBLE(cpu, ib, 1, 0, 0);
1051 quiet_mode = old_quiet_mode;
1052 }
1053 fatal("BREAKPOINT: pc = 0x%llx\n(The "
1054 "instruction has not yet executed.)\n",
1055 (long long)cpu->pc);
1056 single_step_breakpoint = 1;
1057 single_step = 1;
1058 goto stop_running_translated;
1059 }
1060 }
1061 #endif /* DYNTRANS_TO_BE_TRANSLATED_HEAD */
1062
1063
1064 /*****************************************************************************/
1065
1066
1067 #ifdef DYNTRANS_TO_BE_TRANSLATED_TAIL
1068 /*
1069 * If we end up here, then an instruction was translated.
1070 */
1071 translated;
1072
1073 /*
1074 * Now it is time to check for combinations of instructions that can
1075 * be converted into a single function call.
1076 *
1077 * Note: Single-stepping or instruction tracing doesn't work with
1078 * instruction combination.
1079 */
1080 if (!single_step && !cpu->machine->instruction_trace)
1081 COMBINE_INSTRUCTIONS(cpu, ic, addr);
1082
1083 /* ... and finally execute the translated instruction: */
1084 if (single_step_breakpoint) {
1085 /*
1086 * Special case when single-stepping: Execute the translated
1087 * instruction, but then replace it with a "to be translated"
1088 * directly afterwards.
1089 */
1090 single_step_breakpoint = 0;
1091 ic->f(cpu, ic);
1092 ic->f =
1093 #ifdef DYNTRANS_DUALMODE_32
1094 cpu->is_32bit? instr32(to_be_translated) :
1095 #endif
1096 instr(to_be_translated);
1097 } else
1098 ic->f(cpu, ic);
1099
1100 return;
1101
1102
1103 bad: /*
1104 * Nothing was translated. (Unimplemented or illegal instruction.)
1105 */
1106
1107 quiet_mode = 0;
1108 fatal("to_be_translated(): TODO: unimplemented instruction");
1109
1110 if (cpu->machine->instruction_trace)
1111 #ifdef MODE32
1112 fatal(" at 0x%x\n", (int)cpu->pc);
1113 #else
1114 fatal(" at 0x%llx\n", (long long)cpu->pc);
1115 #endif
1116 else {
1117 fatal(":\n");
1118 DISASSEMBLE(cpu, ib, 1, 0, 0);
1119 }
1120
1121 cpu->running = 0;
1122 cpu->dead = 1;
1123 stop_running_translated:
1124 debugger_n_steps_left_before_interaction = 0;
1125 cpu->running_translated = 0;
1126 ic = cpu->cd.DYNTRANS_ARCH.next_ic = &nothing_call;
1127 cpu->cd.DYNTRANS_ARCH.next_ic ++;
1128
1129 /* Execute the "nothing" instruction: */
1130 ic->f(cpu, ic);
1131 #endif /* DYNTRANS_TO_BE_TRANSLATED_TAIL */
1132

  ViewVC Help
Powered by ViewVC 1.1.26