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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 13 - (show annotations)
Mon Oct 8 16:18:43 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 24450 byte(s)
0.3.5
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.29 2005/08/16 05:37:10 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 DYNTRANS_ARM
46 uint32_t cached_pc;
47 #else
48 uint64_t cached_pc;
49 #endif
50 int low_pc, n_instrs;
51
52 DYNTRANS_PC_TO_POINTERS(cpu);
53
54 #ifdef DYNTRANS_ARM
55 cached_pc = cpu->cd.arm.r[ARM_PC] & ~3;
56 #else
57 cached_pc = cpu->pc & ~3;
58 #endif
59
60 cpu->n_translated_instrs = 0;
61 cpu->running_translated = 1;
62
63 if (single_step || cpu->machine->instruction_trace) {
64 /*
65 * Single-step:
66 */
67 struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic
68 #ifndef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
69 ++
70 #endif
71 ;
72 if (cpu->machine->instruction_trace) {
73 #ifdef DYNTRANS_X86
74 unsigned char instr[17];
75 cpu->cd.x86.cursegment = X86_S_CS;
76 cpu->cd.x86.seg_override = 0;
77 #else
78 #ifdef DYNTRANS_M68K
79 unsigned char instr[16]; /* TODO: 16? */
80 #else
81 unsigned char instr[4]; /* General case... */
82 #endif
83 #endif
84 if (!cpu->memory_rw(cpu, cpu->mem, cached_pc, &instr[0],
85 sizeof(instr), MEM_READ, CACHE_INSTRUCTION)) {
86 fatal("XXX_cpu_run_instr(): could not read "
87 "the instruction\n");
88 } else
89 cpu_disassemble_instr(cpu->machine, cpu,
90 instr, 1, 0, 0);
91 }
92
93 /* When single-stepping, multiple instruction calls cannot
94 be combined into one. This clears all translations: */
95 if (cpu->cd.DYNTRANS_ARCH.cur_physpage->flags & COMBINATIONS) {
96 int i;
97 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
98 cpu->cd.DYNTRANS_ARCH.cur_physpage->ics[i].f =
99 #ifdef DYNTRANS_DUALMODE_32
100 cpu->is_32bit?
101 instr32(to_be_translated) :
102 #endif
103 instr(to_be_translated);
104 fatal("[ Note: The translation of physical page 0x%llx"
105 " contained combinations of instructions; these "
106 "are now flushed because we are single-stepping."
107 " ]\n", (long long)cpu->cd.DYNTRANS_ARCH.
108 cur_physpage->physaddr);
109 cpu->cd.DYNTRANS_ARCH.cur_physpage->flags &=
110 ~(COMBINATIONS | TRANSLATIONS);
111 }
112
113 /* Execute just one instruction: */
114 ic->f(cpu, ic);
115 n_instrs = 1;
116 } else {
117 /* Execute multiple instructions: */
118 n_instrs = 0;
119 for (;;) {
120 struct DYNTRANS_IC *ic;
121
122 #ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
123 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic; ic->f(cpu, ic);
124 #else
125 #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic);
126 #endif
127 I; I; I; I; I; I; I; I; I; I;
128 I; I; I; I; I; I; I; I; I; I;
129 I; I; I; I; I; I; I; I; I; I;
130 I; I; I; I; I; I; I; I; I; I;
131 I; I; I; I; I; I; I; I; I; I;
132
133 I; I; I; I; I; I; I; I; I; I;
134 I; I; I; I; I; I; I; I; I; I;
135 I; I; I; I; I; I; I; I; I; I;
136 I; I; I; I; I; I; I; I; I; I;
137 I; I; I; I; I; I; I; I; I; I;
138
139 I; I; I; I; I; I; I; I; I; I;
140 I; I; I; I; I; I; I; I; I; I;
141
142 n_instrs += 120;
143
144 if (!cpu->running_translated ||
145 n_instrs + cpu->n_translated_instrs >= 16384)
146 break;
147 }
148 }
149
150
151 /*
152 * Update the program counter and return the correct number of
153 * executed instructions:
154 */
155 low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t)
156 cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC);
157
158 if (low_pc >= 0 && low_pc < DYNTRANS_IC_ENTRIES_PER_PAGE) {
159 #ifdef DYNTRANS_ARM
160 cpu->cd.arm.r[ARM_PC] &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1)<<2);
161 cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
162 cpu->pc = cpu->cd.arm.r[ARM_PC];
163 #else
164 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
165 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
166 cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT);
167 #endif
168 } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE) {
169 /* Switch to next page: */
170 #ifdef DYNTRANS_ARM
171 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << 2);
172 cpu->cd.arm.r[ARM_PC] += (ARM_IC_ENTRIES_PER_PAGE << 2);
173 cpu->pc = cpu->cd.arm.r[ARM_PC];
174 #else
175 cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
176 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
177 cpu->pc += (DYNTRANS_IC_ENTRIES_PER_PAGE <<
178 DYNTRANS_INSTR_ALIGNMENT_SHIFT);
179 #endif
180 } else {
181 /* debug("debug: Outside a page (This is actually ok)\n"); */
182 }
183
184 return n_instrs + cpu->n_translated_instrs;
185 }
186 #endif /* DYNTRANS_CPU_RUN_INSTR */
187
188
189
190 #ifdef DYNTRANS_FUNCTION_TRACE
191 /*
192 * XXX_cpu_functioncall_trace():
193 *
194 * Without this function, the main trace tree function prints something
195 * like <f()> or <0x1234()> on a function call. It is up to this
196 * function to print the arguments passed.
197 */
198 void DYNTRANS_FUNCTION_TRACE(struct cpu *cpu, uint64_t f, int n_args)
199 {
200 char strbuf[50];
201 char *symbol;
202 uint64_t ot;
203 int x, print_dots = 1, n_args_to_print =
204 #ifdef DYNTRANS_ALPHA
205 6
206 #else
207 4 /* Most non-Alpha archs */
208 #endif
209 ;
210
211 if (n_args >= 0 && n_args <= n_args_to_print) {
212 print_dots = 0;
213 n_args_to_print = n_args;
214 }
215
216 /*
217 * TODO: The type of each argument should be taken from the symbol
218 * table, in some way.
219 *
220 * The code here does a kind of "heuristic guess" regarding what the
221 * argument values might mean. Sometimes the output looks weird, but
222 * usually it looks good enough.
223 *
224 * Print ".." afterwards to show that there might be more arguments
225 * than were passed in register.
226 */
227 for (x=0; x<n_args_to_print; x++) {
228 int64_t d;
229 #ifdef DYNTRANS_X86
230 d = 0; /* TODO */
231 #else
232 /* Args in registers: */
233 d = cpu->cd.DYNTRANS_ARCH.
234 #ifdef DYNTRANS_ALPHA
235 r[ALPHA_A0
236 #endif
237 #ifdef DYNTRANS_ARM
238 r[0
239 #endif
240 #ifdef DYNTRANS_IA64
241 r[0 /* TODO */
242 #endif
243 #ifdef DYNTRANS_M68K
244 d[0 /* TODO */
245 #endif
246 #ifdef DYNTRANS_MIPS
247 gpr[MIPS_GPR_A0
248 #endif
249 #ifdef DYNTRANS_PPC
250 gpr[3
251 #endif
252 #ifdef DYNTRANS_SPARC
253 r_i[0
254 #endif
255 + x];
256 #endif
257 symbol = get_symbol_name(&cpu->machine->symbol_context, d, &ot);
258
259 if (d > -256 && d < 256)
260 fatal("%i", (int)d);
261 else if (memory_points_to_string(cpu, cpu->mem, d, 1))
262 fatal("\"%s\"", memory_conv_to_string(cpu,
263 cpu->mem, d, strbuf, sizeof(strbuf)));
264 else if (symbol != NULL && ot == 0)
265 fatal("&%s", symbol);
266 else {
267 if (cpu->is_32bit)
268 fatal("0x%x", (int)d);
269 else
270 fatal("0x%llx", (long long)d);
271 }
272
273 if (x < n_args_to_print - 1)
274 fatal(",");
275 }
276
277 if (print_dots)
278 fatal(",..");
279 }
280 #endif
281
282
283
284 #ifdef DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE
285 /* forward declaration of to_be_translated and end_of_page: */
286 static void instr(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
287 static void instr(end_of_page)(struct cpu *,struct DYNTRANS_IC *);
288 #ifdef DYNTRANS_DUALMODE_32
289 static void instr32(to_be_translated)(struct cpu *, struct DYNTRANS_IC *);
290 #endif
291 /*
292 * XXX_tc_allocate_default_page():
293 *
294 * Create a default page (with just pointers to instr(to_be_translated)
295 * at cpu->translation_cache_cur_ofs.
296 */
297 static void DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE(struct cpu *cpu,
298 uint64_t physaddr)
299 {
300 struct DYNTRANS_TC_PHYSPAGE *ppp;
301 int i;
302
303 /* Create the physpage header: */
304 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
305 + cpu->translation_cache_cur_ofs);
306 ppp->next_ofs = 0;
307 ppp->physaddr = physaddr;
308
309 /* TODO: Is this faster than copying an entire template page? */
310
311 for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++)
312 ppp->ics[i].f =
313 #ifdef DYNTRANS_DUALMODE_32
314 cpu->is_32bit? instr32(to_be_translated) :
315 #endif
316 instr(to_be_translated);
317
318 ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE].f = instr(end_of_page);
319
320 cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE);
321 }
322 #endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE */
323
324
325
326 #ifdef DYNTRANS_PC_TO_POINTERS_FUNC
327 /*
328 * XXX_pc_to_pointers():
329 *
330 * This function uses the current program counter (a virtual address) to
331 * find out which physical translation page to use, and then sets the current
332 * translation page pointers to that page.
333 *
334 * If there was no translation page for that physical page, then an empty
335 * one is created.
336 */
337 void DYNTRANS_PC_TO_POINTERS_FUNC(struct cpu *cpu)
338 {
339 #ifdef DYNTRANS_32
340 uint32_t
341 #else
342 uint64_t
343 #endif
344 cached_pc, physaddr, physpage_ofs;
345 int pagenr, table_index;
346 uint32_t *physpage_entryp;
347 struct DYNTRANS_TC_PHYSPAGE *ppp;
348
349 #ifdef DYNTRANS_32
350 int index;
351 cached_pc = cpu->pc;
352 index = cached_pc >> 12;
353 ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index];
354 if (ppp != NULL)
355 goto have_it;
356 #else
357 #ifdef DYNTRANS_ALPHA
358 uint32_t a, b;
359 int kernel = 0;
360 struct alpha_vph_page *vph_p;
361 cached_pc = cpu->pc;
362 a = (cached_pc >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
363 b = (cached_pc >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
364 if ((cached_pc >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
365 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
366 kernel = 1;
367 } else
368 vph_p = cpu->cd.alpha.vph_table0[a];
369 if (vph_p != cpu->cd.alpha.vph_default_page) {
370 ppp = vph_p->phys_page[b];
371 if (ppp != NULL)
372 goto have_it;
373 }
374 #else
375 #ifdef DYNTRANS_IA64
376 fatal("IA64 todo\n");
377 #else
378 #error Neither alpha, ia64, nor 32-bit?
379 #endif
380 #endif
381 #endif
382
383 /*
384 * TODO: virtual to physical address translation
385 */
386 physaddr = cached_pc & ~( ((DYNTRANS_IC_ENTRIES_PER_PAGE-1) <<
387 DYNTRANS_INSTR_ALIGNMENT_SHIFT) |
388 ((1 << DYNTRANS_INSTR_ALIGNMENT_SHIFT)-1) );
389
390 if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE)
391 cpu_create_or_reset_tc(cpu);
392
393 pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr);
394 table_index = PAGENR_TO_TABLE_INDEX(pagenr);
395
396 physpage_entryp = &(((uint32_t *)cpu->translation_cache)[table_index]);
397 physpage_ofs = *physpage_entryp;
398 ppp = NULL;
399
400 /* Traverse the physical page chain: */
401 while (physpage_ofs != 0) {
402 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
403 + physpage_ofs);
404 /* If we found the page in the cache, then we're done: */
405 if (ppp->physaddr == physaddr)
406 break;
407 /* Try the next page in the chain: */
408 physpage_ofs = ppp->next_ofs;
409 }
410
411 /* If the offset is 0 (or ppp is NULL), then we need to create a
412 new "default" empty translation page. */
413
414 if (ppp == NULL) {
415 /* fatal("CREATING page %lli (physaddr 0x%llx), table index "
416 "%i\n", (long long)pagenr, (long long)physaddr,
417 (int)table_index); */
418 *physpage_entryp = physpage_ofs =
419 cpu->translation_cache_cur_ofs;
420
421 /* Allocate a default page, with to_be_translated entries: */
422 DYNTRANS_TC_ALLOCATE(cpu, physaddr);
423
424 ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache
425 + physpage_ofs);
426 }
427
428 #ifdef DYNTRANS_32
429 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL)
430 cpu->cd.DYNTRANS_ARCH.phys_page[index] = ppp;
431 #endif
432
433 #ifdef DYNTRANS_ALPHA
434 if (vph_p->host_load[b] != NULL)
435 vph_p->phys_page[b] = ppp;
436 #endif
437
438 have_it:
439 cpu->cd.DYNTRANS_ARCH.cur_physpage = ppp;
440 cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0];
441 cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page +
442 DYNTRANS_PC_TO_IC_ENTRY(cached_pc);
443
444 /* printf("cached_pc=0x%016llx pagenr=%lli table_index=%lli, "
445 "physpage_ofs=0x%016llx\n", (long long)cached_pc, (long long)pagenr,
446 (long long)table_index, (long long)physpage_ofs); */
447 }
448 #endif /* DYNTRANS_PC_TO_POINTERS_FUNC */
449
450
451
452 #ifdef DYNTRANS_INVAL_ENTRY
453 /*
454 * XXX_invalidate_tlb_entry():
455 *
456 * Invalidate one translation entry (based on virtual address).
457 */
458 void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu,
459 #ifdef DYNTRANS_32
460 uint32_t
461 #else
462 uint64_t
463 #endif
464 vaddr_page)
465 {
466 #ifdef DYNTRANS_1LEVEL
467 uint32_t index = vaddr_page >> 12;
468 cpu->cd.DYNTRANS_ARCH.host_load[index] = NULL;
469 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
470 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = 0;
471 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
472 #else
473 /* 2-level: */
474 #ifdef DYNTRANS_ALPHA
475 struct alpha_vph_page *vph_p;
476 uint32_t a, b;
477 int kernel = 0;
478
479 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
480 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
481 if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
482 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
483 kernel = 1;
484 } else
485 vph_p = cpu->cd.alpha.vph_table0[a];
486
487 if (vph_p == cpu->cd.alpha.vph_default_page) {
488 fatal("alpha_invalidate_tlb_entry(): huh? Problem 1.\n");
489 exit(1);
490 }
491
492 vph_p->host_load[b] = NULL;
493 vph_p->host_store[b] = NULL;
494 vph_p->phys_addr[b] = 0;
495 vph_p->phys_page[b] = NULL;
496 vph_p->refcount --;
497 if (vph_p->refcount < 0) {
498 fatal("alpha_invalidate_tlb_entry(): huh? Problem 2.\n");
499 exit(1);
500 }
501 if (vph_p->refcount == 0) {
502 vph_p->next = cpu->cd.alpha.vph_next_free_page;
503 cpu->cd.alpha.vph_next_free_page = vph_p;
504 if (kernel)
505 cpu->cd.alpha.vph_table0_kernel[a] =
506 cpu->cd.alpha.vph_default_page;
507 else
508 cpu->cd.alpha.vph_table0[a] =
509 cpu->cd.alpha.vph_default_page;
510 }
511 #else /* !DYNTRANS_ALPHA */
512 #ifdef DYNTRANS_IA64
513 fatal("IA64: blah blah TODO\n");
514 #else
515 #error Not yet for non-1-level, non-Alpha, non-ia64
516 #endif /* !DYNTRANS_IA64 */
517 #endif /* !DYNTRANS_ALPHA */
518 #endif
519 }
520 #endif
521
522
523 #ifdef DYNTRANS_INVALIDATE_TC_PADDR
524 /*
525 * XXX_invalidate_translation_caches_paddr():
526 *
527 * Invalidate all entries matching a specific physical address.
528 */
529 void DYNTRANS_INVALIDATE_TC_PADDR(struct cpu *cpu, uint64_t paddr)
530 {
531 int r;
532 #ifdef DYNTRANS_32
533 uint32_t
534 #else
535 uint64_t
536 #endif
537 paddr_page = paddr &
538 #ifdef DYNTRANS_8K
539 ~0x1fff
540 #else
541 ~0xfff
542 #endif
543 ;
544
545 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
546 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid &&
547 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page ==
548 paddr_page) {
549 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
550 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page);
551 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid = 0;
552 }
553 }
554 }
555 #endif /* DYNTRANS_INVALIDATE_TC_PADDR */
556
557
558
559 #ifdef DYNTRANS_INVALIDATE_TC_CODE
560 /*
561 * XXX_invalidate_code_translation_caches():
562 *
563 * Invalidate all entries matching a specific virtual address.
564 */
565 void DYNTRANS_INVALIDATE_TC_CODE(struct cpu *cpu)
566 {
567 int r;
568 #ifdef DYNTRANS_32
569 uint32_t
570 #else
571 uint64_t
572 #endif
573 vaddr_page;
574
575 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
576 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
577 vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r]
578 .vaddr_page & ~(DYNTRANS_PAGESIZE-1);
579 #ifdef DYNTRANS_1LEVEL
580 {
581 uint32_t index = vaddr_page >> 12;
582 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;
583 }
584 #else
585 {
586 /* 2-level: */
587 #ifdef DYNTRANS_ALPHA
588 struct alpha_vph_page *vph_p;
589 uint32_t a, b;
590 int kernel = 0;
591
592 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
593 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
594 if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
595 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
596 kernel = 1;
597 } else
598 vph_p = cpu->cd.alpha.vph_table0[a];
599 vph_p->phys_page[b] = NULL;
600 #else /* !DYNTRANS_ALPHA */
601 #ifdef DYNTRANS_IA64
602 fatal("IA64: blah yo yo TODO\n");
603 #else
604 #error Not yet for non-Alpha, non-1Level, non-ia64
605 #endif /* !DYNTRANS_IA64 */
606 #endif /* !DYNTRANS_ALPHA */
607 }
608 #endif
609 }
610 }
611 }
612 #endif /* DYNTRANS_INVALIDATE_TC_CODE */
613
614
615
616 #ifdef DYNTRANS_UPDATE_TRANSLATION_TABLE
617 /*
618 * XXX_update_translation_table():
619 *
620 * Update the virtual memory translation tables.
621 */
622 void DYNTRANS_UPDATE_TRANSLATION_TABLE(struct cpu *cpu, uint64_t vaddr_page,
623 unsigned char *host_page, int writeflag, uint64_t paddr_page)
624 {
625 int64_t lowest, highest = -1;
626 int found, r, lowest_index;
627
628 #ifdef DYNTRANS_ALPHA
629 uint32_t a, b;
630 struct alpha_vph_page *vph_p;
631 int kernel = 0;
632 /* fatal("update_translation_table(): v=0x%llx, h=%p w=%i"
633 " p=0x%llx\n", (long long)vaddr_page, host_page, writeflag,
634 (long long)paddr_page); */
635 #else
636 #ifdef DYNTRANS_32
637 uint32_t index;
638 vaddr_page &= 0xffffffffULL;
639 paddr_page &= 0xffffffffULL;
640 /* fatal("update_translation_table(): v=0x%x, h=%p w=%i"
641 " p=0x%x\n", (int)vaddr_page, host_page, writeflag,
642 (int)paddr_page); */
643 #else /* !DYNTRANS_32 */
644 #ifdef DYNTRANS_IA64
645 fatal("IA64 update todo\n");
646 #else
647 #error Neither 32-bit, IA64, nor Alpha?
648 #endif
649 #endif
650 #endif
651
652 /* Scan the current TLB entries: */
653 found = -1; lowest_index = 0;
654 lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp;
655 for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) {
656 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) {
657 lowest = cpu->cd.DYNTRANS_ARCH.
658 vph_tlb_entry[r].timestamp;
659 lowest_index = r;
660 }
661 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp > highest)
662 highest = cpu->cd.DYNTRANS_ARCH.
663 vph_tlb_entry[r].timestamp;
664 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid &&
665 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page ==
666 vaddr_page) {
667 found = r;
668 break;
669 }
670 }
671
672 if (found < 0) {
673 /* Create the new TLB entry, overwriting the oldest one: */
674 r = lowest_index;
675 if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) {
676 /* This one has to be invalidated first: */
677 DYNTRANS_INVALIDATE_TLB_ENTRY(cpu,
678 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page);
679 }
680
681 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid = 1;
682 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].host_page = host_page;
683 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page = paddr_page;
684 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page;
685 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = writeflag;
686 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp = highest + 1;
687
688 /* Add the new translation to the table: */
689 #ifdef DYNTRANS_ALPHA
690 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
691 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
692 if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
693 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
694 kernel = 1;
695 } else
696 vph_p = cpu->cd.alpha.vph_table0[a];
697 if (vph_p == cpu->cd.alpha.vph_default_page) {
698 if (cpu->cd.alpha.vph_next_free_page != NULL) {
699 if (kernel)
700 vph_p = cpu->cd.alpha.vph_table0_kernel
701 [a] = cpu->cd.alpha.
702 vph_next_free_page;
703 else
704 vph_p = cpu->cd.alpha.vph_table0[a] =
705 cpu->cd.alpha.vph_next_free_page;
706 cpu->cd.alpha.vph_next_free_page = vph_p->next;
707 } else {
708 if (kernel)
709 vph_p = cpu->cd.alpha.vph_table0_kernel
710 [a] = malloc(sizeof(struct
711 alpha_vph_page));
712 else
713 vph_p = cpu->cd.alpha.vph_table0[a] =
714 malloc(sizeof(struct
715 alpha_vph_page));
716 memset(vph_p, 0, sizeof(struct alpha_vph_page));
717 }
718 }
719 vph_p->refcount ++;
720 vph_p->host_load[b] = host_page;
721 vph_p->host_store[b] = writeflag? host_page : NULL;
722 vph_p->phys_addr[b] = paddr_page;
723 vph_p->phys_page[b] = NULL;
724 #else
725 #ifdef DYNTRANS_32
726 index = vaddr_page >> 12;
727 cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
728 cpu->cd.DYNTRANS_ARCH.host_store[index] =
729 writeflag? host_page : NULL;
730 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
731 cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL;;
732 #endif /* 32 */
733 #endif /* !ALPHA */
734 } else {
735 /*
736 * The translation was already in the TLB.
737 * Writeflag = 0: Do nothing.
738 * Writeflag = 1: Make sure the page is writable.
739 * Writeflag = -1: Downgrade to readonly.
740 */
741 #ifdef DYNTRANS_ALPHA
742 a = (vaddr_page >> ALPHA_LEVEL0_SHIFT) & (ALPHA_LEVEL0 - 1);
743 b = (vaddr_page >> ALPHA_LEVEL1_SHIFT) & (ALPHA_LEVEL1 - 1);
744 if ((vaddr_page >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) {
745 vph_p = cpu->cd.alpha.vph_table0_kernel[a];
746 kernel = 1;
747 } else
748 vph_p = cpu->cd.alpha.vph_table0[a];
749 cpu->cd.alpha.vph_tlb_entry[found].timestamp = highest + 1;
750 if (vph_p->phys_addr[b] == paddr_page) {
751 if (writeflag == 1)
752 vph_p->host_store[b] = host_page;
753 if (writeflag == -1)
754 vph_p->host_store[b] = NULL;
755 } else {
756 /* Change the entire physical/host mapping: */
757 vph_p->host_load[b] = host_page;
758 vph_p->host_store[b] = writeflag? host_page : NULL;
759 vph_p->phys_addr[b] = paddr_page;
760 }
761 #else
762 #ifdef DYNTRANS_32
763 index = vaddr_page >> 12;
764 cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[found].timestamp =
765 highest + 1;
766 if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) {
767 if (writeflag == 1)
768 cpu->cd.DYNTRANS_ARCH.host_store[index] =
769 host_page;
770 if (writeflag == -1)
771 cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL;
772 } else {
773 /* Change the entire physical/host mapping: */
774 cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page;
775 cpu->cd.DYNTRANS_ARCH.host_store[index] =
776 writeflag? host_page : NULL;
777 cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page;
778 }
779 #endif /* 32 */
780 #endif /* !ALPHA */
781 }
782 }
783 #endif /* DYNTRANS_UPDATE_TRANSLATION_TABLE */
784
785
786
787 #ifdef DYNTRANS_TO_BE_TRANSLATED_HEAD
788 /*
789 * Check for breakpoints.
790 */
791 if (!single_step_breakpoint) {
792 int i;
793 for (i=0; i<cpu->machine->n_breakpoints; i++)
794 if (cpu->pc == cpu->machine->breakpoint_addr[i]) {
795 if (!cpu->machine->instruction_trace) {
796 int old_quiet_mode = quiet_mode;
797 quiet_mode = 0;
798 DISASSEMBLE(cpu, ib, 1, 0, 0);
799 quiet_mode = old_quiet_mode;
800 }
801 fatal("BREAKPOINT: pc = 0x%llx\n(The "
802 "instruction has not yet executed.)\n",
803 (long long)cpu->pc);
804 single_step_breakpoint = 1;
805 single_step = 1;
806 goto stop_running_translated;
807 }
808 }
809 #endif /* DYNTRANS_TO_BE_TRANSLATED_HEAD */
810
811
812
813 #ifdef DYNTRANS_TO_BE_TRANSLATED_TAIL
814 /*
815 * If we end up here, then an instruction was translated.
816 */
817 translated;
818
819 /*
820 * Now it is time to check for combinations of instructions that can
821 * be converted into a single function call.
822 *
823 * Note: Single-stepping or instruction tracing doesn't work with
824 * instruction combination.
825 */
826 if (!single_step && !cpu->machine->instruction_trace)
827 COMBINE_INSTRUCTIONS(cpu, ic, addr);
828
829 /* ... and finally execute the translated instruction: */
830 if (single_step_breakpoint) {
831 /*
832 * Special case when single-stepping: Execute the translated
833 * instruction, but then replace it with a "to be translated"
834 * directly afterwards.
835 */
836 single_step_breakpoint = 0;
837 ic->f(cpu, ic);
838 ic->f =
839 #ifdef DYNTRANS_DUALMODE_32
840 cpu->is_32bit? instr32(to_be_translated) :
841 #endif
842 instr(to_be_translated);
843 } else
844 ic->f(cpu, ic);
845
846 return;
847
848
849 bad: /*
850 * Nothing was translated. (Unimplemented or illegal instruction.)
851 */
852
853 quiet_mode = 0;
854 fatal("to_be_translated(): TODO: unimplemented instruction");
855
856 if (cpu->machine->instruction_trace)
857 #ifdef DYNTRANS_32
858 fatal(" at 0x%x\n", (int)cpu->pc);
859 #else
860 fatal(" at 0x%llx\n", (long long)cpu->pc);
861 #endif
862 else {
863 fatal(":\n");
864 DISASSEMBLE(cpu, ib, 1, 0, 0);
865 }
866
867 cpu->running = 0;
868 cpu->dead = 1;
869 stop_running_translated:
870 debugger_n_steps_left_before_interaction = 0;
871 cpu->running_translated = 0;
872 ic = cpu->cd.DYNTRANS_ARCH.next_ic = &nothing_call;
873 cpu->cd.DYNTRANS_ARCH.next_ic ++;
874
875 /* Execute the "nothing" instruction: */
876 ic->f(cpu, ic);
877 #endif /* DYNTRANS_TO_BE_TRANSLATED_TAIL */
878

  ViewVC Help
Powered by ViewVC 1.1.26