25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_dyntrans.c,v 1.99 2006/06/23 20:43:44 debug Exp $ |
* $Id: cpu_dyntrans.c,v 1.104 2006/06/25 00:15:44 debug Exp $ |
29 |
* |
* |
30 |
* Common dyntrans routines. Included from cpu_*.c. |
* Common dyntrans routines. Included from cpu_*.c. |
31 |
*/ |
*/ |
187 |
*/ |
*/ |
188 |
int show_opcode_statistics = 0; |
int show_opcode_statistics = 0; |
189 |
|
|
190 |
#ifdef DYNTRANS_DUALMODE_32 |
#ifdef MODE32 |
|
uint64_t cached_pc; |
|
|
#else |
|
191 |
uint32_t cached_pc; |
uint32_t cached_pc; |
192 |
|
#else |
193 |
|
uint64_t cached_pc; |
194 |
#endif |
#endif |
195 |
int low_pc, n_instrs; |
int low_pc, n_instrs; |
196 |
|
|
358 |
|
|
359 |
if (!cpu->running_translated || |
if (!cpu->running_translated || |
360 |
n_instrs + cpu->n_translated_instrs >= |
n_instrs + cpu->n_translated_instrs >= |
361 |
N_SAFE_DYNTRANS_LIMIT / 2) |
N_SAFE_DYNTRANS_LIMIT) |
362 |
break; |
break; |
363 |
} |
} |
364 |
} else if (show_opcode_statistics) { |
} else if (show_opcode_statistics) { |
376 |
|
|
377 |
if (!cpu->running_translated || |
if (!cpu->running_translated || |
378 |
n_instrs + cpu->n_translated_instrs >= |
n_instrs + cpu->n_translated_instrs >= |
379 |
N_SAFE_DYNTRANS_LIMIT / 2) |
N_SAFE_DYNTRANS_LIMIT) |
380 |
break; |
break; |
381 |
} |
} |
382 |
} else { |
} else { |
397 |
|
|
398 |
if (!cpu->running_translated || |
if (!cpu->running_translated || |
399 |
n_instrs + cpu->n_translated_instrs >= |
n_instrs + cpu->n_translated_instrs >= |
400 |
N_SAFE_DYNTRANS_LIMIT / 2) |
N_SAFE_DYNTRANS_LIMIT) |
401 |
break; |
break; |
402 |
} |
} |
403 |
} |
} |
575 |
|
|
576 |
|
|
577 |
#ifdef DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE |
#ifdef DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE |
|
|
|
|
/* forward declaration of to_be_translated and end_of_page: */ |
|
|
static void instr(to_be_translated)(struct cpu *, struct DYNTRANS_IC *); |
|
|
static void instr(end_of_page)(struct cpu *,struct DYNTRANS_IC *); |
|
|
#ifdef DYNTRANS_DUALMODE_32 |
|
|
static void instr32(to_be_translated)(struct cpu *, struct DYNTRANS_IC *); |
|
|
static void instr32(end_of_page)(struct cpu *,struct DYNTRANS_IC *); |
|
|
#endif |
|
|
|
|
|
#ifdef DYNTRANS_DELAYSLOT |
|
|
static void instr(end_of_page2)(struct cpu *,struct DYNTRANS_IC *); |
|
|
#ifdef DYNTRANS_DUALMODE_32 |
|
|
static void instr32(end_of_page2)(struct cpu *,struct DYNTRANS_IC *); |
|
|
#endif |
|
|
#endif |
|
|
|
|
578 |
/* |
/* |
579 |
* XXX_tc_allocate_default_page(): |
* XXX_tc_allocate_default_page(): |
580 |
* |
* |
585 |
uint64_t physaddr) |
uint64_t physaddr) |
586 |
{ |
{ |
587 |
struct DYNTRANS_TC_PHYSPAGE *ppp; |
struct DYNTRANS_TC_PHYSPAGE *ppp; |
|
int i; |
|
588 |
|
|
|
/* Create the physpage header: */ |
|
589 |
ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache |
ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache |
590 |
+ cpu->translation_cache_cur_ofs); |
+ cpu->translation_cache_cur_ofs); |
|
ppp->next_ofs = 0; |
|
|
ppp->physaddr = physaddr; |
|
|
|
|
|
/* TODO: Is this faster than copying an entire template page? */ |
|
|
for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++) { |
|
|
ppp->ics[i].f = |
|
|
#ifdef DYNTRANS_DUALMODE_32 |
|
|
cpu->is_32bit? instr32(to_be_translated) : |
|
|
#endif |
|
|
instr(to_be_translated); |
|
|
#ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH |
|
|
ppp->ics[i].arg[0] = 0; |
|
|
#endif |
|
|
} |
|
|
|
|
|
/* End-of-page: */ |
|
|
ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 0].f = |
|
|
#ifdef DYNTRANS_DUALMODE_32 |
|
|
cpu->is_32bit? instr32(end_of_page) : |
|
|
#endif |
|
|
instr(end_of_page); |
|
591 |
|
|
592 |
#ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH |
/* Copy the entire template page first: */ |
593 |
ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 0].arg[0] = 0; |
memcpy(ppp, cpu->cd.DYNTRANS_ARCH.physpage_template, sizeof( |
594 |
#endif |
struct DYNTRANS_TC_PHYSPAGE)); |
595 |
|
|
596 |
/* End-of-page-2, for delay-slot architectures: */ |
ppp->physaddr = physaddr & ~(DYNTRANS_PAGESIZE - 1); |
|
#ifdef DYNTRANS_DELAYSLOT |
|
|
ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 1].f = |
|
|
#ifdef DYNTRANS_DUALMODE_32 |
|
|
cpu->is_32bit? instr32(end_of_page2) : |
|
|
#endif |
|
|
instr(end_of_page2); |
|
|
#endif |
|
597 |
|
|
598 |
cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE); |
cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE); |
599 |
|
|
600 |
cpu->translation_cache_cur_ofs --; |
cpu->translation_cache_cur_ofs --; |
601 |
cpu->translation_cache_cur_ofs |= 63; |
cpu->translation_cache_cur_ofs |= 127; |
602 |
cpu->translation_cache_cur_ofs ++; |
cpu->translation_cache_cur_ofs ++; |
603 |
} |
} |
604 |
#endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE */ |
#endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE */ |
661 |
|
|
662 |
if (!ok) { |
if (!ok) { |
663 |
uint64_t paddr; |
uint64_t paddr; |
664 |
if (cpu->translate_address != NULL) |
if (cpu->translate_v2p != NULL) { |
665 |
ok = cpu->translate_address(cpu, cached_pc, |
ok = cpu->translate_v2p( |
666 |
&paddr, FLAG_INSTR); |
cpu, cached_pc, &paddr, FLAG_INSTR); |
667 |
else { |
} else { |
668 |
paddr = cached_pc; |
paddr = cached_pc; |
669 |
ok = 1; |
ok = 1; |
670 |
} |
} |
673 |
"failed. vaddr=0x%"PRIx64"\n", (uint64_t)cached_pc); |
"failed. vaddr=0x%"PRIx64"\n", (uint64_t)cached_pc); |
674 |
fatal("!! cpu->pc=0x%"PRIx64"\n", (uint64_t)cpu->pc); */ |
fatal("!! cpu->pc=0x%"PRIx64"\n", (uint64_t)cpu->pc); */ |
675 |
|
|
676 |
ok = cpu->translate_address(cpu, cpu->pc, &paddr, |
ok = cpu->translate_v2p(cpu, cpu->pc, &paddr, |
677 |
FLAG_INSTR); |
FLAG_INSTR); |
678 |
|
|
679 |
/* printf("EXCEPTION HANDLER: vaddr = 0x%x ==> " |
/* printf("EXCEPTION HANDLER: vaddr = 0x%x ==> " |
715 |
host_page += (physaddr & |
host_page += (physaddr & |
716 |
((1 << BITS_PER_MEMBLOCK) - 1) & ~q); |
((1 << BITS_PER_MEMBLOCK) - 1) & ~q); |
717 |
cpu->update_translation_table(cpu, cached_pc & ~q, |
cpu->update_translation_table(cpu, cached_pc & ~q, |
718 |
host_page, TLB_CODE, physaddr & ~q); |
host_page, 0, physaddr & ~q); |
719 |
#ifndef MODE32 |
#ifndef MODE32 |
720 |
/* Recalculate l2 and l3, since they might have |
/* Recalculate l2 and l3, since they might have |
721 |
changed now: */ |
changed now: */ |
726 |
} |
} |
727 |
|
|
728 |
if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE) { |
if (cpu->translation_cache_cur_ofs >= DYNTRANS_CACHE_SIZE) { |
729 |
debug("[ dyntrans: resetting the translation cache ]\n"); |
#ifdef UNSTABLE_DEVEL |
730 |
|
fatal("[ dyntrans: resetting the translation cache ]\n"); |
731 |
|
#endif |
732 |
cpu_create_or_reset_tc(cpu); |
cpu_create_or_reset_tc(cpu); |
733 |
} |
} |
734 |
|
|
735 |
|
physaddr &= ~(DYNTRANS_PAGESIZE - 1); |
736 |
|
|
737 |
pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr); |
pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr); |
738 |
table_index = PAGENR_TO_TABLE_INDEX(pagenr); |
table_index = PAGENR_TO_TABLE_INDEX(pagenr); |
739 |
|
|
745 |
while (physpage_ofs != 0) { |
while (physpage_ofs != 0) { |
746 |
ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache |
ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache |
747 |
+ physpage_ofs); |
+ physpage_ofs); |
748 |
|
|
749 |
/* If we found the page in the cache, then we're done: */ |
/* If we found the page in the cache, then we're done: */ |
750 |
if (DYNTRANS_ADDR_TO_PAGENR(ppp->physaddr) == pagenr) |
if (ppp->physaddr == physaddr) |
751 |
break; |
break; |
752 |
|
|
753 |
/* Try the next page in the chain: */ |
/* Try the next page in the chain: */ |
754 |
physpage_ofs = ppp->next_ofs; |
physpage_ofs = ppp->next_ofs; |
755 |
} |
} |
864 |
|
|
865 |
|
|
866 |
|
|
867 |
#ifdef DYNTRANS_INIT_64BIT_DUMMY_TABLES |
#ifdef DYNTRANS_INIT_TABLES |
868 |
|
|
869 |
|
/* forward declaration of to_be_translated and end_of_page: */ |
870 |
|
static void instr(to_be_translated)(struct cpu *, struct DYNTRANS_IC *); |
871 |
|
static void instr(end_of_page)(struct cpu *,struct DYNTRANS_IC *); |
872 |
|
#ifdef DYNTRANS_DUALMODE_32 |
873 |
|
static void instr32(to_be_translated)(struct cpu *, struct DYNTRANS_IC *); |
874 |
|
static void instr32(end_of_page)(struct cpu *,struct DYNTRANS_IC *); |
875 |
|
#endif |
876 |
|
|
877 |
|
#ifdef DYNTRANS_DELAYSLOT |
878 |
|
static void instr(end_of_page2)(struct cpu *,struct DYNTRANS_IC *); |
879 |
|
#ifdef DYNTRANS_DUALMODE_32 |
880 |
|
static void instr32(end_of_page2)(struct cpu *,struct DYNTRANS_IC *); |
881 |
|
#endif |
882 |
|
#endif |
883 |
|
|
884 |
/* |
/* |
885 |
* XXX_init_64bit_dummy_tables(): |
* XXX_init_tables(): |
886 |
* |
* |
887 |
* Initializes 64-bit dummy tables and pointers. |
* Initializes the default translation page (for newly allocated pages), and |
888 |
|
* for 64-bit emulation it also initializes 64-bit dummy tables and pointers. |
889 |
*/ |
*/ |
890 |
void DYNTRANS_INIT_64BIT_DUMMY_TABLES(struct cpu *cpu) |
void DYNTRANS_INIT_TABLES(struct cpu *cpu) |
891 |
{ |
{ |
892 |
|
#ifndef MODE32 |
893 |
struct DYNTRANS_L2_64_TABLE *dummy_l2; |
struct DYNTRANS_L2_64_TABLE *dummy_l2; |
894 |
struct DYNTRANS_L3_64_TABLE *dummy_l3; |
struct DYNTRANS_L3_64_TABLE *dummy_l3; |
895 |
int x1, x2; |
int x1, x2; |
896 |
|
#endif |
897 |
|
int i; |
898 |
|
struct DYNTRANS_TC_PHYSPAGE *ppp = malloc(sizeof( |
899 |
|
struct DYNTRANS_TC_PHYSPAGE)); |
900 |
|
|
901 |
|
if (ppp == NULL) { |
902 |
|
fprintf(stderr, "out of memory\n"); |
903 |
|
exit(1); |
904 |
|
} |
905 |
|
|
906 |
|
ppp->next_ofs = 0; |
907 |
|
/* ppp->physaddr is filled in by the page allocator */ |
908 |
|
|
909 |
|
for (i=0; i<DYNTRANS_IC_ENTRIES_PER_PAGE; i++) { |
910 |
|
ppp->ics[i].f = |
911 |
|
#ifdef DYNTRANS_DUALMODE_32 |
912 |
|
cpu->is_32bit? instr32(to_be_translated) : |
913 |
|
#endif |
914 |
|
instr(to_be_translated); |
915 |
|
#ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH |
916 |
|
ppp->ics[i].arg[0] = 0; |
917 |
|
#endif |
918 |
|
} |
919 |
|
|
920 |
|
/* End-of-page: */ |
921 |
|
ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 0].f = |
922 |
|
#ifdef DYNTRANS_DUALMODE_32 |
923 |
|
cpu->is_32bit? instr32(end_of_page) : |
924 |
|
#endif |
925 |
|
instr(end_of_page); |
926 |
|
|
927 |
|
#ifdef DYNTRANS_VARIABLE_INSTRUCTION_LENGTH |
928 |
|
ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 0].arg[0] = 0; |
929 |
|
#endif |
930 |
|
|
931 |
|
/* End-of-page-2, for delay-slot architectures: */ |
932 |
|
#ifdef DYNTRANS_DELAYSLOT |
933 |
|
ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 1].f = |
934 |
|
#ifdef DYNTRANS_DUALMODE_32 |
935 |
|
cpu->is_32bit? instr32(end_of_page2) : |
936 |
|
#endif |
937 |
|
instr(end_of_page2); |
938 |
|
#endif |
939 |
|
|
940 |
|
cpu->cd.DYNTRANS_ARCH.physpage_template = ppp; |
941 |
|
|
942 |
|
|
943 |
|
/* Prepare 64-bit virtual address translation tables: */ |
944 |
|
#ifndef MODE32 |
945 |
if (cpu->is_32bit) |
if (cpu->is_32bit) |
946 |
return; |
return; |
947 |
|
|
956 |
|
|
957 |
for (x2 = 0; x2 < (1 << DYNTRANS_L2N); x2 ++) |
for (x2 = 0; x2 < (1 << DYNTRANS_L2N); x2 ++) |
958 |
dummy_l2->l3[x2] = dummy_l3; |
dummy_l2->l3[x2] = dummy_l3; |
959 |
|
#endif |
960 |
} |
} |
961 |
#endif /* DYNTRANS_INIT_64BIT_DUMMY_TABLES */ |
#endif /* DYNTRANS_INIT_TABLES */ |
962 |
|
|
963 |
|
|
964 |
|
|
1204 |
prev_ppp = ppp; |
prev_ppp = ppp; |
1205 |
ppp = (struct DYNTRANS_TC_PHYSPAGE *) |
ppp = (struct DYNTRANS_TC_PHYSPAGE *) |
1206 |
(cpu->translation_cache + physpage_ofs); |
(cpu->translation_cache + physpage_ofs); |
1207 |
|
|
1208 |
/* If we found the page in the cache, |
/* If we found the page in the cache, |
1209 |
then we're done: */ |
then we're done: */ |
1210 |
if (ppp->physaddr == addr) |
if (ppp->physaddr == addr) |
1211 |
break; |
break; |
1212 |
|
|
1213 |
/* Try the next page in the chain: */ |
/* Try the next page in the chain: */ |
1214 |
physpage_ofs = ppp->next_ofs; |
physpage_ofs = ppp->next_ofs; |
1215 |
} |
} |
1253 |
#endif |
#endif |
1254 |
} |
} |
1255 |
|
|
1256 |
/* Invalidate entries (NOTE: only code entries) in the VPH table: */ |
/* Invalidate entries in the VPH table: */ |
1257 |
for (r = DYNTRANS_MAX_VPH_TLB_ENTRIES/2; |
for (r = 0; r < DYNTRANS_MAX_VPH_TLB_ENTRIES; r ++) { |
|
r < DYNTRANS_MAX_VPH_TLB_ENTRIES; r ++) { |
|
1258 |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) { |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) { |
1259 |
vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r] |
vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r] |
1260 |
.vaddr_page & ~(DYNTRANS_PAGESIZE-1); |
.vaddr_page & ~(DYNTRANS_PAGESIZE-1); |
1309 |
#ifndef MODE32 |
#ifndef MODE32 |
1310 |
int64_t lowest, highest = -1; |
int64_t lowest, highest = -1; |
1311 |
#endif |
#endif |
1312 |
int found, r, lowest_index, start, end, useraccess = 0; |
int found, r, lowest_index, useraccess = 0; |
1313 |
|
|
1314 |
#ifdef MODE32 |
#ifdef MODE32 |
1315 |
uint32_t index; |
uint32_t index; |
1330 |
(uint64_t)paddr_page); */ |
(uint64_t)paddr_page); */ |
1331 |
#endif |
#endif |
1332 |
|
|
1333 |
|
assert((vaddr_page & (DYNTRANS_PAGESIZE-1)) == 0); |
1334 |
|
assert((paddr_page & (DYNTRANS_PAGESIZE-1)) == 0); |
1335 |
|
|
1336 |
if (writeflag & MEMORY_USER_ACCESS) { |
if (writeflag & MEMORY_USER_ACCESS) { |
1337 |
writeflag &= ~MEMORY_USER_ACCESS; |
writeflag &= ~MEMORY_USER_ACCESS; |
1338 |
useraccess = 1; |
useraccess = 1; |
1339 |
} |
} |
1340 |
|
|
|
start = 0; end = DYNTRANS_MAX_VPH_TLB_ENTRIES / 2; |
|
|
#if 1 |
|
|
/* Half of the TLB used for data, half for code: */ |
|
|
if (writeflag & TLB_CODE) { |
|
|
writeflag &= ~TLB_CODE; |
|
|
start = end; end = DYNTRANS_MAX_VPH_TLB_ENTRIES; |
|
|
} |
|
|
#else |
|
|
/* Data and code entries are mixed. */ |
|
|
end = DYNTRANS_MAX_VPH_TLB_ENTRIES; |
|
|
#endif |
|
|
|
|
1341 |
/* Scan the current TLB entries: */ |
/* Scan the current TLB entries: */ |
1342 |
lowest_index = start; |
lowest_index = 0; |
1343 |
|
|
1344 |
#ifdef MODE32 |
#ifdef MODE32 |
1345 |
/* |
/* |
1354 |
DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1; |
DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1; |
1355 |
if (found < 0) { |
if (found < 0) { |
1356 |
static unsigned int x = 0; |
static unsigned int x = 0; |
1357 |
lowest_index = (x % (end-start)) + start; |
lowest_index = (x++) % DYNTRANS_MAX_VPH_TLB_ENTRIES; |
|
x ++; |
|
1358 |
} |
} |
1359 |
#else |
#else |
1360 |
lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp; |
lowest = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[0].timestamp; |
1361 |
found = -1; |
found = -1; |
1362 |
for (r=start; r<end; r++) { |
for (r=0; r<DYNTRANS_MAX_VPH_TLB_ENTRIES; r++) { |
1363 |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) { |
if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].timestamp < lowest) { |
1364 |
lowest = cpu->cd.DYNTRANS_ARCH. |
lowest = cpu->cd.DYNTRANS_ARCH. |
1365 |
vph_tlb_entry[r].timestamp; |
vph_tlb_entry[r].timestamp; |
1539 |
" slot! Not yet supported.\n"); |
" slot! Not yet supported.\n"); |
1540 |
#endif |
#endif |
1541 |
single_step_breakpoint = 1; |
single_step_breakpoint = 1; |
1542 |
single_step = 1; |
single_step = ENTER_SINGLE_STEPPING; |
1543 |
goto stop_running_translated; |
goto stop_running_translated; |
1544 |
} |
} |
1545 |
} |
} |